Based on @ponder.ooo's "snake pit agent orchestrator" idea (bsky 2026-05-28) and Claude's metaphor-mapping elaboration: agents are snakes, tasks are food tossed into a shared pit; snakes devour/digest/regurgitate/excrete. A worker-pool-over-a-shared-queue topology (contrast the builder-adversary phase machine): - pit/ is a filesystem queue; snakes claim by atomic mv (no two eat the same food) - species = specialized agents: keeper (zookeeper), planner (regurgitation IS task decomposition), snake-1..3 (worker pool), cleanup (scavenger + coprophagy) - no [loop] phase machine; persistent agents self-pace via /loop - README carries the full bio→compute mapping table from the thread image Verified: `agents.py status --config agents.toml` lists all 6 agents + service. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
127 lines
7.7 KiB
TOML
127 lines
7.7 KiB
TOML
# 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-<id>-<slug>.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 = "."
|