[rust] T6-1: CODE verb layer + starter harness in al-sdk (Rust CODE should read like JS CODE, not a graphics driver) #37

Closed
opened 2026-09-22 21:09:14 +02:00 by sleepy · 0 comments
Owner

Problem

The JS CODE starter (see js/runner_functions.js) ships a tick driver (setInterval(cb, 250)) plus a combat verb layer — loot(), get_nearest_monster({min_xp,max_att}), change_target(t), is_moving(t), is_in_range(t), can_attack(t), use_hp_or_mp(), set_message(s), attack(t) — so a combat loop is ~15 lines of body.

The Rust SDK (T3-4 / T5-1) exposes only the wire-level primitives (walk, attack, nearest_monster, is_in_range, use_hp_or_mp, Snapshot) and no verb layer and no starter harness. So examples/hello is ~300 lines of scaffold (connect_env → set_sink → on_death → auto_respawn → on_tick_async → run_for → exit-code table) before a single tick runs, and the predicates force the user to hand-build RangeInput/AttackInput/MonsterArgs structs. It reads like writing your own graphics driver to render shapes, not using raylib to draw shapes (sleepy's words).

Goal

A convenience layer so a combat/farming loop is ~15-25 lines of user code, and a fresh crate does not re-derive the connect/sink/death/respawn/run/exit scaffold.

Design (guidance, not a mandate)

  • Lives in al-sdk (a new al_sdk::code module) so the layering rule holds: a user crate depends only on al-sdk. Do not add a crate user crates must depend on.
  • Starter harness: one entry (e.g. al_sdk::code::run(|snap| async move {…}) or a Code::new().on_tick(…).run()) that does connect_env + stdout set_sink + on_death + auto_respawn + the run loop + the exit-code table, and hands the user just the tick body (the async slot, so it can await verbs).
  • Combat verbs (thin, async where they wrap an action): loot, get_nearest_monster(args) -> Option<Monster>, change_target, is_moving, is_in_range, can_attack, use_hp_or_mp, set_message, walk_to/toward. Keep the existing predicate structs as the implementation; the verbs are the ergonomic front. Scope is the combat/farming core that T5-1 + the starter use — NOT a 1:1 port of banking/crafting/duels/shops (that is T5-2 / later).
  • A starter template crate (or examples/starter) that a human opens and edits: the harness + a commented combat body, ~30 lines total.

Acceptance

  • A real combat loop (approach nearest monster, attack in range, potion when low, respawn on death) is ≤ ~25 lines of user code in the starter crate.
  • examples/hello and examples/farm_basic are ported onto the harness+verbs (their hand-rolled scaffold collapses to the harness) and still pass their gates.
  • The layering rule is preserved (user crate depends only on al-sdk); the quality gate (offline + live) is green.

File by orchestrator, 2026-09-22. Re-scoped from the /rust-code PoC after sleepy's 'graphics driver vs raylib' feedback.

## Problem The JS CODE starter (see `js/runner_functions.js`) ships a **tick driver** (`setInterval(cb, 250)`) plus a **combat verb layer** — `loot()`, `get_nearest_monster({min_xp,max_att})`, `change_target(t)`, `is_moving(t)`, `is_in_range(t)`, `can_attack(t)`, `use_hp_or_mp()`, `set_message(s)`, `attack(t)` — so a combat loop is ~15 lines of *body*. The Rust SDK (T3-4 / T5-1) exposes only the **wire-level primitives** (`walk`, `attack`, `nearest_monster`, `is_in_range`, `use_hp_or_mp`, `Snapshot`) and **no verb layer and no starter harness**. So `examples/hello` is ~300 lines of scaffold (connect_env → set_sink → on_death → auto_respawn → on_tick_async → run_for → exit-code table) before a single tick runs, and the predicates force the user to hand-build `RangeInput`/`AttackInput`/`MonsterArgs` structs. It reads like *writing your own graphics driver to render shapes*, not *using raylib to draw shapes* (sleepy's words). ## Goal A convenience layer so a combat/farming loop is ~15-25 lines of user code, and a fresh crate does not re-derive the connect/sink/death/respawn/run/exit scaffold. ## Design (guidance, not a mandate) - Lives in `al-sdk` (a new `al_sdk::code` module) so the layering rule holds: **a user crate depends only on `al-sdk`.** Do not add a crate user crates must depend on. - **Starter harness**: one entry (e.g. `al_sdk::code::run(|snap| async move {…})` or a `Code::new().on_tick(…).run()`) that does `connect_env` + stdout `set_sink` + `on_death` + `auto_respawn` + the run loop + the exit-code table, and hands the user just the tick body (the async slot, so it can `await` verbs). - **Combat verbs** (thin, async where they wrap an action): `loot`, `get_nearest_monster(args) -> Option<Monster>`, `change_target`, `is_moving`, `is_in_range`, `can_attack`, `use_hp_or_mp`, `set_message`, `walk_to`/`toward`. Keep the existing predicate structs as the *implementation*; the verbs are the ergonomic front. Scope is the **combat/farming core** that T5-1 + the starter use — NOT a 1:1 port of banking/crafting/duels/shops (that is T5-2 / later). - A **starter template** crate (or `examples/starter`) that a human opens and edits: the harness + a commented combat body, ~30 lines total. ## Acceptance - A real combat loop (approach nearest monster, attack in range, potion when low, respawn on death) is **≤ ~25 lines of user code** in the starter crate. - `examples/hello` and `examples/farm_basic` are ported onto the harness+verbs (their hand-rolled scaffold collapses to the harness) and still pass their gates. - The layering rule is preserved (user crate depends only on `al-sdk`); the quality gate (offline + live) is green. _File by orchestrator, 2026-09-22. Re-scoped from the /rust-code PoC after sleepy's 'graphics driver vs raylib' feedback._
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sleepy/adventureland_mongodb#37
No description provided.