Goals
A goal is a dedicated agent loop against a repo path. It can read, write, run bash, search, and spawn subgoals. Use it for multi-step work. For one command or one file edit, run the command or use the file tools.
There is no --token-budget and no dollar --budget on goal. Caps are wall-clock (--time-budget) and the writable scope (--path). See /skills/goal.md and goal help.
goal --background --path sites/sails --time-budget 30m "Write today's blog post under pages/blog/. Small diff."
goal status GOAL_ID
goal wait GOAL_ID --timeout 10m
goal log GOAL_ID
goal list
The platform MCP session has no goal tool. Always run these via bash.
Before you start
- Know your cwd.
--pathdefaults to the current directory, and a relative--pathis resolved from it.goal listwith no--pathalso only shows goals under the current directory. Runcd ~first, or pass an absolute path like/ryan/home/sites/sails. - Only
goal helpprints help.goal status --help,goal wait --help, andgoal list --helpfail withunknown optionorunknown argument. - There is no
goal cancel. Any first word that is notlist,status,wait,log,elevate, orhelpis read as the prompt.goal cancel GOAL_IDstarts a new foreground goal whose task is the text "cancel GOAL_ID", and it spends tokens. Pick a--time-budgetyou are willing to let run out.
Done looks like
goal --background … returns a goal_id right away. Later goal status GOAL_ID shows complete (or impossible with a real summary). goal log GOAL_ID shows the step transcript. The files under --path changed, or the outbound mail or other side effect exists. You did not invent --token-budget.
Worked example: background site edit
Job: edit the marketing site while you keep working. Scope writes to sites/sails and give the loop half an hour.
cd ~
goal --background --path sites/sails --time-budget 30m \
"Write today's blog post under pages/blog/. Small diff. Do not rewrite the brand."
goal status GOAL_ID
goal wait GOAL_ID --timeout 10m
goal log GOAL_ID
A finished goal from goal status (or from a foreground run) looks like this:
{
"goal_id": "01a13afc-2288-7376-beee-f47c92193786",
"status": "complete",
"summary": "Short account of what was done, or why it was impossible.",
"path": "/ryan/home/sites/sails/.goals/01a13afc-2288-7376-beee-f47c92193786",
"tokens_used": { "prompt": 5550, "completion": 3, "total": 5553 },
"cost_used_usd": 0.016695,
"budget_usd": 0.0
}
cost_used_usd reports what the run spent. budget_usd is 0.0 because there is no dollar cap to set. The path value is a label under your scope; do not expect a .goals/ folder you can ls. Use goal log for the transcript.
Foreground (blocks until done or the time budget hits):
goal --path sites/sails --time-budget 5m "Add a one-line note to pages/blog/README.md"
Prompt may also come from stdin when you omit trailing words:
echo 'Audit broken links under pages/ and fix them.' | goal --background --path sites/sails --time-budget 1h
Commands and flags
From live goal help:
goal [--background] [--time-budget DURATION] [--path PATH] PROMPT...
goal [--background] [--time-budget DURATION] [--path PATH] (read prompt from stdin)
goal list [--path PATH]
goal status <goal-id> [--path PATH]
goal wait <goal-id> [--timeout DURATION] [--path PATH]
goal log <goal-id>
goal elevate approve|deny <run-id>
goal help
| Flag / command | What it does |
|---|---|
--background | Queue a durable run; your session can close |
--time-budget DURATION | Wall clock: 30s, 5m, 30m, 1h, 1d |
--path PATH | Readable and writable scope (default: current cwd) |
goal status GOAL_ID | Current status, summary, tokens, and cost as JSON |
goal wait GOAL_ID --timeout DURATION | Block until the goal settles or the timeout passes |
goal log GOAL_ID | Step transcript as a JSON array of events (no --path) |
goal list [--path PATH] | Goals under the path (default: cwd), newest first |
goal elevate approve|deny RUN_ID | Owner Slack HITL backup for elevation |
goal list entries carry goal_id, status, prompt, started_at, finished_at (UTC), and path.
--path is the writable scope. Inbound mail goals start in the agent home, even if the jail also lists a site. If the job is to edit sites/sails, start the goal with that path yourself.
When the agent is jailed, --path (and cwd when you omit --path) must stay inside the jail. Disabled-filesystem agents may still run goals that only use site tools or messaging. See Agents.
Reading the log
goal log prints every event: RUN_STARTED, the init messages (system prompt and your prompt), TOOL_CALL_START / TOOL_CALL_RESULT, tool-bash_exec, reasoning and text events, tool-complete_goal, and RUN_FINISHED. To see just what the goal ran:
goal log GOAL_ID | grep '"kind"' | sort | uniq -c
The init system prompt states the scope for that run: reads under --path plus /skills, /templates, and /README.md, writes only under --path.
Statuses
Terminal statuses include complete, impossible, cancelled, and time_budget. A goal ends itself by calling complete_goal with complete or impossible and a summary.
Background goals run on a shared platform worker. You do not keep the MCP session open.
Subgoals
A goal can spawn parallel subgoals for distinct subtasks. Inside the loop it has spawn_goal (background by default), list_child_goals, wait_goal, wait_on_all_subgoals, and cancel_goal. These are tools the goal uses, not CLI commands. Subgoals share the parent's time budget, so a 30m parent with three subgoals still stops at 30m. Give each subgoal its own subpath to avoid file conflicts.
Prefer subgoals when work is naturally parallel. Prefer one goal when steps depend on each other.
Permissions
Goals run as you (or as the agent, when mail or su started them), with the same repository role and VFS access. Read-only host paths (/skills, /templates, /README.md) are readable but not writable.
When not to use a goal
| Need | Use instead |
|---|---|
| One shell command | bash_exec |
| Single file read/write | MCP file tools |
| HTTP on a published site | pages/**/*.api.sh |
| External HTTP that starts an agent | Start a goal from a webhook |
| Same command every morning | Run something every morning |
Failure modes
| What you see | What it means | What to do |
|---|---|---|
goal: goal: dollar budgets are not used; omit --budget / --token-budget | Neither flag exists on goal | Drop it. Use --time-budget 30m |
goal: goal: invalid --time-budget value: 5x | Unsupported duration suffix | Use s, m, h, or d |
goal: goal: prompt is required | No trailing words and empty stdin | Pass the prompt as words or pipe it in |
goal: invalid goal id: invalid length: found 8 | Short or partial id | Copy the full goal_id from goal list |
goal: goal status: unknown option: --help | Subcommands have no --help | Run goal help |
goal cancel … returns a fresh goal_id | No cancel command; the words became a prompt | Nothing to undo beyond its cost. Set tighter --time-budget next time |
goal list returns [] | Listing is scoped to cwd or --path | cd ~ and run goal list, or pass the right --path |
Status time_budget | Wall clock hit | Raise --time-budget, or split the job |
Goal cannot see sites/sails | Mail goals start in agent home, or --path omitted | goal --path sites/sails … |
--path outside the jail | Jailed agents must stay inside prefixes | Jail that folder, or pick a listed path |