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/ with a
main.py at its top, and that file declares the agents:
programs/splox is the program a Splox
chat is answered by — the name is fixed, because a person opens a harness rather
than a program — and handle(msg) is asked, per message, which agent takes it.
The directory
main.py and hooks/<point>.py are the only names the platform knows. It
imports main.py to ask who an agent is and who answers a message, it imports
the hooks to run the points of the loop, and it opens nothing else in the
directory. Prompts, data, a second script, a package of helpers are yours.
A program’s directory joins sys.path for the length of the import of its
main.py, so a file beside it is imported by its plain name:
shared.py and neither should answer the other’s import.
handle(msg)
msg carries exactly three fields: text, chat_id and user_id. Answer with
an agent this program declared, with its name as a string, or with an object
naming one.
message handed back replaces what that agent is given,
which is how a program rewrites what arrived before anybody sees it; what the
person actually said is what the chat holds either way.
The choice is a function rather than a setting because it is the one thing only
your harness can know. Read msg.text and route on a command; read msg.user_id
and give a colleague a different agent from a customer; read msg.chat_id and
keep a per-conversation decision in a file.
Its hooks are its own
programs/<name>/hooks/<point>.py shapes every run that program starts, and a
sub-agent spawned from inside one runs on the same files, because it is the same
program still working.
There is exactly one place a point can live: no tree-wide hooks/ above the
programs, and nothing under an individual agent. A program that keeps none of
them runs every point on the platform’s own answer. See Hooks.
Adding a second program
Everything above holds for any other directory here, minus the chat: itsmain.py declares agents, its hooks/ shape their turns, and nobody asks it who
answers a message, because no message arrives on its own.
A Telegram loop, a watcher on a repository, a nightly job — each is a program,
and each belongs here rather than on your laptop because it is useless without
its agents: it calls them by name, expects the tools they have, and has to change
in the same commit they do.
README.md saying
what it does.
How a program calls an agent
A declaration is callable, and calling it starts a run.AgentRun: it names the run and the chat it belongs to,
and wait=True blocks until there is an answer to read with .output(). Pass
that chat_id back on a later call to continue the same conversation.
The other keywords are schema= (a shape the answer has to match), workspace=
(a git worktree of its own), attempts= (replace a failed agent with a fresh
one) and destination_number= (make the run a phone call). A keyword agent()
does not know is refused where it is written. Sub-agents
covers all of them.
A script that is not a program — the kind an agent writes in its sandbox on the
spot — asks a program for its agents, because a bare name says nothing about
whose agent it is:
program(name) reads programs/<name>/main.py and hands back what that file
declared, as ordinary attributes. program() with no name is the program this
run belongs to. Both fail in the script, before anything is spent:
while True, a queue, a retry, a database — the
things a program is made of. Nothing here replaces them.
Who starts a long-running program
You do, or an agent does, in the sandbox, with the ordinary command it would use for any script:Its life is the machine’s life
The sandbox belongs to the machine — not to the run, and not to the chat. A program started in one turn keeps running after that turn ends: the next run in this chat finds it going, and so does the next chat on this machine, tomorrow. It stops when the machine stops, and only then: somebody presses Stop, or the plan behind the account stops keeping machines running. Nothing reaps it on a schedule and no conversation ending takes it down. State that has to survive a restart belongs in a file the program writes and re-reads on start. Write the loop so that starting it twice is harmless and starting it again after a stop picks up where it left off; then “has it stopped?” stops being a question anybody has to answer.Reading what it did
A program’s output is a file, and a file is read by the agent that started it:Worked examples
A triage router, a nightly job, a bot that answers from outside a chat, and a
fan-out over many items — all as programs.

