defineAgent API you write in agent.ts is covered in Agents as code.
Project Layout
simple init creates a starter project, and simple pull writes an agent from production into a directory, adding package.json and tsconfig.json if they are missing. Both use the same layout:
Check all of it into source control;
node_modules is the only thing to leave out. Edit handlers and prompts in their own files; publish reads them back through the references in agent.ts.
A handler may import other files in the project by relative path, such as a lib/ module several handlers share. Publish bundles such a handler into one file with the imported files inlined; a handler that imports nothing from the project is published exactly as written.
Prompt files are read verbatim, so the prompt is exactly the file’s bytes. An editor that appends a trailing newline on save changes the prompt, and simple diff will show it.
Pulling an Agent
--branch, the CLI pulls the branch that was updated most recently.
Pull writes idiomatic defineAgent(...) source: Actions come back as action.http(...), action.code(...), and friends with real z.object(...) schemas, platform built-ins come back as action.sendEmail(...), action.sendTextMessage(...), and action.validateAddress(...), prompt nodes become node.prompt(...), and extraction schemas become Zod again. Handlers and prompts are written to their own files, as described in Project layout.
Before writing, the CLI compiles the generated source and compares it with the commit it pulled, field by field. If anything would not round-trip, such as a legacy HTTP graph node or a schema shape Zod cannot express, the pull writes the lossless defineAgentSnapshot(...) form instead, a literal that reproduces the pulled commit exactly, and reports the field that diverged. A pull never writes a file that would publish something different from what was pulled. Pass --format snapshot to always take the lossless form.
Pull refuses to overwrite source or referenced files you have changed locally, and refuses to replace a file under actions/ or prompts/ that it did not write itself; when it refuses, it stops and writes nothing. Publish or discard those changes first, or pass --force only when you intentionally want production to replace them. A file an earlier pull wrote that the agent no longer references is left in place.
The Lock File
simple.lock.json records which agent and branch the project belongs to, the branch head the project was last synchronized with, the stable identities of the graph’s nodes and edges, and the exact version of every Action the agent uses. It is how diff knows what changed locally and how publish knows whether production moved since your last pull. Keep it in source control alongside agent.ts; never edit it by hand.
Validate and Publish
typecheck compiles the project, handlers included. diff lists the agent and Action changes between your source and the lock file; it is the review step before a publish.
Publish validates the complete project on the server before anything changes. It then creates or revises the Actions that changed, and finally creates one agent commit pinned to those exact Action versions. Each step has a stable identity, so a publish that is interrupted can be run again safely.
If the branch or an Action changed in production since your last pull, publish stops instead of overwriting it. To take those changes while keeping your own edits, save your edits in source control, run simple pull <agent-uuid> --branch <branch> --force, naming the project’s branch so the most recently updated one is not chosen instead, to bring the project up to date with production, then reapply your edits and publish. If only Actions changed, simple actions upgrade accepts their new versions without a pull.
simple actions upgrade accepts the newest production versions of the Actions your agent uses. A pulled defineAgentSnapshot(...) is rewritten with the accepted values and version pins. For defineAgent(...) source, update the Action definition to match production first; the CLI refuses to let the lock file disagree with your source.
Organization Resources
Tags, analyzers, scorecards, scorecard metrics, and post-call workflows belong to the organization rather than to an agent commit, so they are not part of the project.agent.ts references them by UUID, and the CLI lists and creates them directly; see Organization resources for the definitions and examples, and the CLI reference for the commands.