diff --git a/examples/snakepit/README.md b/examples/snakepit/README.md new file mode 100644 index 0000000..aae774f --- /dev/null +++ b/examples/snakepit/README.md @@ -0,0 +1,84 @@ +# ๐Ÿ Snake pit + +> the "snake pit" agent orchestrator. each agent is a snake. you toss food (tasks) into the pit. +> agents can devour tasks, gradually digest them, regurgitate them whole or in broken / digested +> parts, excrete waste (chat logs, debug traces, &c), &c. obviously some specialist agents are on +> cleanup duty +> +> โ€” [@ponder.ooo](https://bsky.app/profile/ponder.ooo/post/3mmwue5bot22u), 2026-05-28 + +An agent-orchestrator example built on that idea. Where the sibling `builder-adversary` example is a +**phase machine** (an ordered plan, two roles handing off), the snake pit is a **worker pool over a +shared queue**: identical workers pull tasks from a pit, plus specialist species for planning and +cleanup. Same harness, completely different topology โ€” that's the point of having both. + +## The core metaphor mapping + +(From Claude running with the idea โ€” the image in the thread.) + +| bio | compute | +|---|---| +| snake species | agent specialization / system prompt | +| hunger | priority / availability | +| smell | task routing (tag match or embedding sim) | +| fighting | contention resolution | +| swallowing | task intake + context loading | +| digestion | LLM calls / tool use | +| regurgitate whole | re-queue (rejection / timeout) | +| regurgitate partial | subtask decomposition | +| excrete | artifact emission (logs, traces, results) | +| waste heap | artifact store | +| coprophagy | meta-agents consuming others' artifacts (log summariser, memory builder) | +| scavengers | housekeeping agents on the waste heap | +| snake death | crash / OOM / timeout โ†’ reap | + +**The key insight: *regurgitation IS task decomposition*** โ€” a planner snake swallows a big task and +regurgitates it as smaller food the worker snakes can each digest. + +## How it maps onto agent-orchestrator + +- **The pit = a filesystem queue** (`pit/`). Snakes coordinate ONLY through it and claim work by + **atomic `mv`**, so two snakes never devour the same food. Full layout + protocol: `pit/README.md`. +- **Snake species = agents with different prompts** (the "agent specialization" row): + - **keeper** (zookeeper, persistent) โ€” tosses food in, keeps the pit healthy, reports. + - **planner** (persistent) โ€” *regurgitation = decomposition*: eats big food, regurgitates smaller + food for the workers (`prompts/planner.md`). + - **snake-1..3** (persistent worker pool) โ€” devour โ†’ digest โ†’ regurgitate โ†’ excrete + (`prompts/snake.md`). Scale the pool by copying a block. + - **cleanup** (persistent) โ€” the **scavenger** on the waste heap; also does light **coprophagy** + (composts logs into a digest) and reaps food abandoned by a snake that died + (`prompts/cleanup.md`). +- **hunger / smell / fighting** โ€” emergent from the loop: an idle snake naps (low hunger), picks the + food it can do (smell), and the atomic-`mv` claim resolves contention (fighting). +- **snake death = crash / timeout โ†’ reap** โ€” the watchdog heals a dead snake (`watch = "heal"`); the + cleanup snake reclaims whatever food it died holding. + +## Run it + +Needs `claude` on `PATH`. From this directory: + +```bash +python3 ../../agents.py status --config agents.toml # read-only: what would run +python3 ../../agents.py up --config agents.toml # keeper + planner + 3 snakes + cleanup + watchdog +python3 ../../agents.py logs snake-1 --config agents.toml +python3 ../../agents.py down --config agents.toml +``` + +A sample piece of food (`pit/food/food-0001-reverse-string.md`) is already in the pit, so the snakes +have something to eat on first `up`. Toss more by writing `pit/food/food--.md` (schema in +`pit/README.md`) โ€” or ask the keeper to. + +To watch the **mechanics** without an agent CLI, set `defaults.backend = "demo"` in `agents.toml` +(the demo backend just idles) and run `up` / `status` / `down`. + +## Extending it + +- **More workers** โ†’ copy a `snake-N` block in `agents.toml`. +- **A new species** โ†’ add an `[[agent]]` with its own `prompts/.md` (e.g. a **coprophagy** + meta-agent that builds long-term memory from the waste heap, distinct from the scavenger). +- **Smarter routing** ("smell") โ†’ give food `tags:` and have snakes prefer matching tags. +- **Real coordination across hosts** โ†’ back the pit with a git repo instead of a local dir and use + the watchdog's `handoff` inbox pings (see the `builder-adversary` example). + +This example carries **no** project-orchestrator/fleet metadata โ€” like any project it can be run by +hand and has no idea a fleet exists. diff --git a/examples/snakepit/agents.toml b/examples/snakepit/agents.toml new file mode 100644 index 0000000..6b6852a --- /dev/null +++ b/examples/snakepit/agents.toml @@ -0,0 +1,126 @@ +# examples/snakepit โ€” the "snake pit" agent orchestrator. +# +# Based on @ponder.ooo's idea (bsky, 2026-05-28): "each agent is a snake. you toss food (tasks) into +# the pit. agents can devour tasks, gradually digest them, regurgitate them whole or in broken / +# digested parts, excrete waste (chat logs, debug traces, &c). obviously some specialist agents are +# on cleanup duty." +# +# Mapped onto agent-orchestrator, this is a WORKER-POOL-OVER-A-SHARED-QUEUE topology โ€” quite unlike +# the sibling builder-adversary phase machine: +# โ€ข The PIT (./pit/) is a filesystem queue. Snakes claim work by ATOMIC `mv` (mv within one +# filesystem is atomic, so two snakes never devour the same food). +# โ€ข SNAKES (snake-1..3) are identical persistent workers, each running a self-paced /loop: +# devour โ†’ digest โ†’ regurgitate (whole result, or broken-up sub-tasks back into the pit) โ†’ +# excrete waste (logs). +# โ€ข CLEANUP is the specialist on cleanup duty: sweeps waste, reclaims food abandoned by a snake +# that choked or died. +# โ€ข KEEPER (the zookeeper) tosses food in and keeps the pit healthy. +# There is no [loop] phase machine here โ€” no kind="loop" agents. See pit/README.md for the protocol. +# +# Run it by hand (status starts nothing): +# python3 ../../agents.py status --config agents.toml +# python3 ../../agents.py up --config agents.toml # needs `claude` on PATH +# python3 ../../agents.py down --config agents.toml +# Mechanics-only (no agent CLI): set defaults.backend = "demo". + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ global watchdog cadence โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +[watchdog] +signal_interval = 30 +heavy_interval = 300 +limit_probe_fallback = 300 +limit_reset_slack = 45 +stall_grace = 180 + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ defaults inherited by every agent โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +[defaults] +session_prefix = "snakepit-" # REQUIRED โ€” sessions: snakepit-snake-1, snakepit-keeper, โ€ฆ +log_dir = ".ao-state" # REQUIRED โ€” logs + state/, resolved relative to this file +backend = "claude" # set to "demo" for a dependency-free mechanics-only run +model = "claude-sonnet-4-6" +watch = "heal" # keep every snake alive/healed; they self-pace and nap when the pit is empty + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ backends (declared as data) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +[backend.claude] +bin = "claude" +flags = "--dangerously-skip-permissions" +remote_control = true +supports_resume = true +prompt_delivery = "arg" +process_name = "claude" +submit_key = "Enter" +stall_idle = 300 +active_re = "esc to interrupt|Running tool|โ ‡|โ ™|ยท \\d+" +limit_re = "spend limit|usage limit|limit reached|reached your .*limit|out of (credits|tokens)" +fatal_re = "redacted_thinking|blocks cannot be modified|cannot be modified" + +[backend.demo] # dependency-free: a shell that just idles +bin = "echo '[demo] {session} up (kickoff: {kickoff})'; exec sleep 1000000" +prompt_delivery = "exec" + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ the keeper (zookeeper / supervisor) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +[[agent]] +name = "keeper" # tmux session: snakepit-keeper +kind = "persistent" +model = "claude-opus-4-8" +resume = true +watch = "heal" +prompt = """ +You are the KEEPER of the snake pit (its zookeeper). On startup: read pit/README.md for the pit \ +protocol, then report the pit's state โ€” counts of food waiting (pit/food/), in digestion \ +(pit/claimed/), regurgitated whole (pit/done/), scraps tossed back (pit/scraps/), and waste \ +(pit/waste/). Your job: (1) toss food into the pit โ€” when an operator gives you a task, write it as \ +pit/food/food--.md per the schema in pit/README.md; (2) keep the pit healthy โ€” watch \ +throughput, flag food stuck in pit/claimed/ for too long (a snake may have choked), and make sure \ +the snakes are fed. Stay available; report when asked.""" +# Optional periodic survey of the pit (uncomment to have the watchdog wake the keeper on a timer): +# wake = { interval = 1800, prompt_file = "prompts/keeper-survey.md" } + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ the planner (a different snake species) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# "snake species = agent specialization / system prompt." The key insight from the thread: +# regurgitation IS task decomposition โ€” a planner snake swallows a big task and regurgitates it as +# smaller food the worker snakes can digest. +[[agent]] +name = "planner" # tmux session: snakepit-planner +kind = "persistent" +model = "claude-opus-4-8" +resume = true +watch = "heal" +prompt = "You are the PLANNER snake โ€” a species that eats only BIG food (tasks tagged `big: true`, or any food too large to digest in one sitting). Read prompts/planner.md and pit/README.md, then loop: devour big food from pit/food/, and regurgitate it IN PARTS โ€” a set of smaller, self-contained food-* items tossed back into pit/food/ for the worker snakes โ€” then remove the big item. Regurgitation IS task decomposition." + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ the snakes (identical worker pool) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Three persistent workers sharing one role (prompts/snake.md); each knows its own snake-id from its +# inline prompt and uses it to claim food. Add more snakes by copying a block and bumping the id. +[[agent]] +name = "snake-1" # tmux session: snakepit-snake-1 +kind = "persistent" +resume = true +watch = "heal" +prompt = "You are ๐Ÿ snake-1, a worker snake in the pit; your snake-id is `snake-1`. Read prompts/snake.md for your full role and the pit protocol, then begin your self-paced loop โ€” devour food from pit/food/, digest it, regurgitate the result, excrete your waste." + +[[agent]] +name = "snake-2" +kind = "persistent" +resume = true +watch = "heal" +prompt = "You are ๐Ÿ snake-2, a worker snake in the pit; your snake-id is `snake-2`. Read prompts/snake.md for your full role and the pit protocol, then begin your self-paced loop โ€” devour food from pit/food/, digest it, regurgitate the result, excrete your waste." + +[[agent]] +name = "snake-3" +kind = "persistent" +resume = true +watch = "heal" +prompt = "You are ๐Ÿ snake-3, a worker snake in the pit; your snake-id is `snake-3`. Read prompts/snake.md for your full role and the pit protocol, then begin your self-paced loop โ€” devour food from pit/food/, digest it, regurgitate the result, excrete your waste." + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ cleanup duty (specialist) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +[[agent]] +name = "cleanup" # tmux session: snakepit-cleanup +kind = "persistent" +resume = true +watch = "heal" +prompt = "You are the CLEANUP snake โ€” a specialist on cleanup duty in the pit. Read prompts/cleanup.md for your full role, then begin your self-paced loop: sweep waste from pit/waste/, and reclaim food abandoned in pit/claimed/ by a snake that choked or died (toss it back to pit/food/)." + +# Non-AI helper: render the snakes' tmux transcripts into clean logs. +[[service]] +name = "cleanlogs" # tmux session: snakepit-cleanlogs +command = "python3 ../../agent-log.py follow-all" +dir = "." diff --git a/examples/snakepit/pit/README.md b/examples/snakepit/pit/README.md new file mode 100644 index 0000000..a451147 --- /dev/null +++ b/examples/snakepit/pit/README.md @@ -0,0 +1,49 @@ +# The pit โ€” a filesystem task queue + +The pit is just directories. Snakes coordinate entirely through atomic `mv` between them โ€” moving a +file within one filesystem is atomic, so two snakes can never devour the same food. + +``` +pit/ + food/ the queue: tasks waiting to be eaten (food--.md) + claimed/ in digestion: a snake is working this one (.food--.md) + done/ regurgitated WHOLE: a finished result (food--.result.md) + scraps/ regurgitated in PARTS: notes/leftovers (anything; informational) + waste/ excreted waste: chat logs, debug traces (-.log) +``` + +> Sub-tasks ("broken / digested parts") are regurgitated back into **`food/`** as new food items, so +> any snake can devour them. `scraps/` is for non-actionable leftovers a snake wants to keep around. + +## Food schema (`pit/food/food--.md`) + +```markdown +# food-0007-reverse-string +- **task:** Implement a `reverse(s)` function in scraps/reverse.py and a test that proves it. +- **done-when:** `python -m pytest scraps/test_reverse.py -q` is green. +- **tossed-by:** keeper # or another snake, if this is a regurgitated sub-task +``` + +Keep food small and self-contained โ€” one unit a snake can digest in a sitting. If a task is too big, +a snake regurgitates it as several smaller food items. + +## The eating protocol (snakes) + +1. **Devour** โ€” atomically claim one item: + `mv pit/food/food-0007-reverse-string.md pit/claimed/snake-2.food-0007-reverse-string.md` + If the `mv` fails, another snake beat you to it โ€” pick a different one. +2. **Digest** โ€” do the work described in the food. +3. **Regurgitate** โ€” *whole*: write the result to `pit/done/food-0007-reverse-string.result.md` + and `git`-free remove the claimed file. *In parts*: if it decomposes, write new `food-*` items + into `pit/food/` for other snakes, and note that in your result. +4. **Excrete** โ€” drop your working log/trace as `pit/waste/snake-2-.log`; don't let it pile up + in the workspace. +5. **Choke?** On the 3rd identical failure, regurgitate the food back to `pit/food/` (or leave it in + `claimed/` past the cleanup timeout) with a note in `scraps/`, so another snake or the keeper + takes it. + +## Cleanup duty + +The cleanup snake sweeps `waste/` (summarise then prune old logs) and **reclaims** food left in +`claimed/` longer than the abandonment timeout โ€” a sign the snake choked or died โ€” by moving it back +to `food/` so a healthy snake can devour it. diff --git a/examples/snakepit/pit/claimed/.gitkeep b/examples/snakepit/pit/claimed/.gitkeep new file mode 100644 index 0000000..6275740 --- /dev/null +++ b/examples/snakepit/pit/claimed/.gitkeep @@ -0,0 +1 @@ +# in digestion โ€” food a snake has devoured: .food--.md (see ../README.md) diff --git a/examples/snakepit/pit/done/.gitkeep b/examples/snakepit/pit/done/.gitkeep new file mode 100644 index 0000000..f79c4ee --- /dev/null +++ b/examples/snakepit/pit/done/.gitkeep @@ -0,0 +1 @@ +# regurgitated whole โ€” finished results: food--.result.md (and planner *.plan.md). See ../README.md diff --git a/examples/snakepit/pit/food/food-0001-reverse-string.md b/examples/snakepit/pit/food/food-0001-reverse-string.md new file mode 100644 index 0000000..09a4d77 --- /dev/null +++ b/examples/snakepit/pit/food/food-0001-reverse-string.md @@ -0,0 +1,9 @@ +# food-0001-reverse-string +- **task:** Implement a `reverse(s)` function in `pit/scraps/reverse.py` and a pytest that proves it + (empty string, ASCII, and a unicode string round-trip: `reverse(reverse(s)) == s`). +- **done-when:** `python -m pytest pit/scraps/test_reverse.py -q` is green. +- **tossed-by:** keeper + + diff --git a/examples/snakepit/pit/scraps/.gitkeep b/examples/snakepit/pit/scraps/.gitkeep new file mode 100644 index 0000000..7346be4 --- /dev/null +++ b/examples/snakepit/pit/scraps/.gitkeep @@ -0,0 +1 @@ +# regurgitated in parts โ€” non-actionable leftovers, stuck-notes, reclaims. See ../README.md diff --git a/examples/snakepit/pit/waste/.gitkeep b/examples/snakepit/pit/waste/.gitkeep new file mode 100644 index 0000000..2974d8b --- /dev/null +++ b/examples/snakepit/pit/waste/.gitkeep @@ -0,0 +1 @@ +# excreted waste โ€” snake logs/traces: -.log; cleanup composts these. See ../README.md diff --git a/examples/snakepit/prompts/cleanup.md b/examples/snakepit/prompts/cleanup.md new file mode 100644 index 0000000..31bcc9f --- /dev/null +++ b/examples/snakepit/prompts/cleanup.md @@ -0,0 +1,31 @@ +You are the **cleanup snake** โ€” a specialist on cleanup duty in the pit. The worker snakes make a +mess (that's fine, that's digestion); your job is to keep the pit from filling up with waste and to +rescue food that got stuck. Read `pit/README.md` for the layout and protocol. + +You coordinate ONLY through the pit (the filesystem). Self-paced `/loop`, no interval. + +**Each iteration:** + +1. **Sweep waste** โ€” in `pit/waste/`, the snakes drop `-.log` traces. Roll them up: + append a one-line digest of each to `pit/waste/COMPOST.md` (what snake, when, what it worked on), + then delete logs older than ~30 min. Never delete a log you haven't composted. Keep `COMPOST.md` + itself trimmed (summarise + truncate if it grows large). +2. **Reclaim abandoned food** โ€” scan `pit/claimed/`. A claim file (`.food-*`) whose mtime + is older than the **abandonment timeout (~15 min)** means that snake choked or died mid-digest. + Move it back to `pit/food/` (strip the `.` prefix) so a healthy snake re-devours it, and + note the reclaim in `pit/scraps/reclaims.md`. Use mtime to judge age: + `find pit/claimed -type f -mmin +15`. +3. **Tidy** โ€” prune empty/stale scraps, and if `pit/done/` grows large, move finished results into + `pit/done/archive/`. Don't touch `pit/food/` items that are fresh, and never delete a result. + +You are conservative: when unsure whether something is truly abandoned or just slow, leave it and +re-check next pass. Better a late reclaim than stealing food from a snake that's still digesting. + +**LIVENESS PROTOCOL (the watchdog ENFORCES this):** +- **Cap every nap at 10 minutes** (never a single ScheduleWakeup > 600 s). +- **Declare every nap.** FINAL output line MUST be exactly `WAITING-UNTIL: ` (โ‰ค10 min + out; `date -u -d '+10 min' +%FT%TZ`). Idle past it โ†’ the watchdog reboots you; your state is the + pit on disk. +- **Compact proactively** at โ‰ณ80% context. + +Begin: read `pit/README.md`, then enter your cleanup loop. diff --git a/examples/snakepit/prompts/planner.md b/examples/snakepit/prompts/planner.md new file mode 100644 index 0000000..fd74325 --- /dev/null +++ b/examples/snakepit/prompts/planner.md @@ -0,0 +1,34 @@ +You are the **planner** snake โ€” a specialist species. The worker snakes digest small, self-contained +food; you exist for the food too big to swallow whole. Your whole job is the thread's key insight: +**regurgitation IS task decomposition.** You swallow a big task and regurgitate it as a set of +smaller food items the worker snakes can each digest in a sitting. + +Read `pit/README.md` for the layout, the food schema, and the eating protocol. You coordinate ONLY +through the pit; you claim by atomic `mv`. + +**Self-paced loop** (`/loop`, no interval). Each iteration: + +1. **Find big food** โ€” scan `pit/food/` for items tagged `big: true`, or any food whose `task` is + clearly more than one sitting. Ignore small food โ€” that's the workers' meal. +2. **Devour it** โ€” atomically claim it: `mv pit/food/ pit/claimed/planner.`. +3. **Regurgitate in parts** โ€” decompose it into the smallest self-contained food items that still + make sense, each with a real `done-when`. Write them into `pit/food/` as new `food--.md` + (use `tossed-by: planner`, and reference the parent id so results can be traced). If sub-tasks + have an order, say so in each food's body ("needs food-0012 done first") โ€” workers respect it. +4. **Record the plan** โ€” write `pit/done/.plan.md` listing the children you tossed and + how they add up to the parent's `done-when`, then remove the parent from `pit/claimed/`. +5. **Excrete** your planning trace to `pit/waste/planner-.log`. + +Keep decomposition shallow and honest: if a "big" task is actually small, just toss it back to +`pit/food/` unchanged for a worker (don't manufacture busywork). If you can't decompose it (genuinely +atomic but huge), note that in `pit/scraps/-needs-keeper.md` and toss it back โ€” the keeper +decides. + +**LIVENESS PROTOCOL (the watchdog ENFORCES this):** +- **Cap every nap at 10 minutes** (never a single ScheduleWakeup > 600 s). +- **Declare every nap.** FINAL output line MUST be exactly `WAITING-UNTIL: ` (โ‰ค10 min + out; `date -u -d '+10 min' +%FT%TZ`). Idle past it โ†’ the watchdog reboots you; your state is the + pit on disk. +- **Compact proactively** at โ‰ณ80% context. + +Begin: read `pit/README.md`, then loop โ€” hunt for big food, decompose, regurgitate. diff --git a/examples/snakepit/prompts/snake.md b/examples/snakepit/prompts/snake.md new file mode 100644 index 0000000..322eb8e --- /dev/null +++ b/examples/snakepit/prompts/snake.md @@ -0,0 +1,39 @@ +You are a ๐Ÿ **snake** in the pit โ€” one worker in a pool of identical snakes. Your snake-id was given +in your startup line (e.g. `snake-2`); use it in every claim and every log. Read `pit/README.md` now +for the pit layout and the eating protocol โ€” it is the source of truth for how to coordinate. + +You do not talk to the other snakes. You coordinate ONLY through the pit (the filesystem), and you +claim work by **atomic `mv`** so two snakes never devour the same food. + +**Self-paced loop.** Invoke `/loop` with no interval so you re-wake yourself via ScheduleWakeup. +Each iteration is one feeding: + +1. **Look** in `pit/food/` for food. If it's empty, you're not hungry-out-of-luck โ€” just nap (see + liveness) and check again; the keeper will toss more in. +2. **Devour** โ€” atomically claim ONE item: + `mv pit/food/ pit/claimed/.`. If the `mv` fails, another snake got it; pick + another. Claim exactly one at a time โ€” don't hoard the pit. +3. **Digest** โ€” do the work the food describes (its `done-when` is your acceptance check). Run it; + don't assume. Keep a running trace as you go. +4. **Regurgitate** โ€” + - *whole*: write the finished result to `pit/done/.result.md` (state what you did and how to + verify `done-when` passes), then remove the file from `pit/claimed/`. + - *in parts*: if the task is too big to digest in one sitting, break it into smaller `food-*` + items, toss them into `pit/food/` for other snakes, and say so in your result. +5. **Excrete** โ€” write your working log / debug trace to `pit/waste/-.log` (`ts` from + `date -u +%Y%m%dT%H%M%SZ`). Keep your workspace clean; the cleanup snake handles the waste pile. + +**If you choke** (3rd identical failure on one food): stop forcing it. Regurgitate the food back to +`pit/food/` with a short note in `pit/scraps/-stuck.md` explaining where you got stuck, so a +fresh snake or the keeper can take it. Don't thrash. + +**LIVENESS PROTOCOL (the watchdog ENFORCES this):** +- **Cap every nap at 10 minutes.** Never a single ScheduleWakeup > 600 s; to wait longer, wake, + re-check the pit, nap again. +- **Declare every nap.** Immediately before going idle, your FINAL output line MUST be exactly + `WAITING-UNTIL: ` (โ‰ค10 min out, matching your ScheduleWakeup; compute with + `date -u -d '+10 min' +%FT%TZ`). Idle โ‰ฅ5 min with no current marker, or past the named time โ†’ the + watchdog reboots you; you resume cleanly (your state is the pit on disk, not your memory). +- **Compact proactively** at โ‰ณ80% context โ€” your state lives in the pit, so compaction is lossless. + +Begin: read `pit/README.md`, then enter your feeding loop. If the pit is empty, nap and check again.