Reference for your agent. The precise shape of things — signatures, fields,
rules — written so an agent can read it and act. You do not need to: ask your
agent for what you want in words, and if it needs this page, hand it the URL or
use Copy page. What to ask for, and how to check it, is in Ask;
how to see what changed is in Look inside.
programs/ in your harness,
and each is here because the shape is what is hard, not the code.
A router: different agents for different messages
handle(msg) is a function rather than a setting because who should answer is the
one thing only your harness can know. Read msg.text for a command, msg.user_id
for who is asking, msg.chat_id for where.
Support agent has no shell — system:search
narrowed to two tools is the whole of what it can do, so a customer question cannot
turn into a command. Engineer can spawn the Executor and Support cannot,
because agents= is per agent. And the /support branch hands back a rewritten
message, which is what that agent is given; the chat still holds what the person
actually typed.
All three run on the same
programs/splox/hooks/, because hooks belong to the
program. If Support needs a guard Engineer does not, the guard reads t.agent.A bot that answers from outside a chat
There is no connections page for this. A Telegram bot, a webhook, a mailbox watcher — each is a program in your harness, started once, running as long as the machine does.Secrets are environment variables
TELEGRAM_BOT_TOKEN is injected into every exec on this machine, and the
program reads os.environ — nothing writes a token into a file in git. Read
it inside the function that needs it: the platform imports main.py every
time it needs to know who an agent is, and it imports from processes that do
not carry your secrets. The trap, in full.Restarting it is harmless
The offset is on disk and the loop reads it on start, so starting the program
twice does not answer anything twice. Write every loop this way and “has it
stopped?” stops being a question anybody has to answer.
support(...) calls is a real run: it appears in the chat list with
its whole conversation, and it is billed like any other. So the program logs its
inputs, the run records its own reasoning, and together they say what happened:
A nightly job
Same shape, different trigger. There is no scheduler to register with: the program is the scheduler, and the thing that makes it correct is the state file.due() asks about the calendar, not about the loop:
A fan-out over many items
Work that produces many results at once is a program, not a chat turn: it needs a loop, a ledger and a place to put what came back.schema=. A violation is shown back to the same agent and retried inside its own
run, so a constraint costs one more turn instead of a lost phase. Do not hand-write
a validator over ids an agent invented.
A failure is a hole, not an exception. parallel puts None in the slot and
the exception in .errors[i], and nothing after it shifts. The ledger says which
items are missing, by name, which is the only honest thing to report when 47 of 50
pages came back.
The readers write nothing. Each auditor is told to write nothing to disk, and
only the final executor gets a workspace=. A reviewer that can commit into the
tree it is judging is not a reviewer. Read-only is not a parameter; it is what the
message says.
Three at a time unless you say otherwise. Pool(8) raises the live-agent cap
for that block. Without it, eight parallel units still run three at a time.
When the fan-out needs phases
An audit is one round. Work that plans, builds in parallel, integrates and then verifies until the tests pass is the same idea with a make-review-repair cycle around it, and that shape is worked out in full in your own checkout:ask() is one typed task,
map() is parallel work with one worktree each, and a checked ask() is the same
call with until= and repair= around it:
orchestrator.py sits in the program rather than on the platform on purpose: how
a job is cut into phases, what invalidates a checkpoint, when a repair loop is
declared stuck are decisions a program should be able to disagree with. Copy the
directory and rewrite the file when your work wants a different shape.

