Goal Mode (/goal)
Spettro can operate autonomously — you set an objective and the agent runs continuously until it is done, stalled, or hits a safety limit. This is called goal mode.
Goal mode works in both the TUI (via /goal) and the headless server (via the
--goal CLI flag). It is designed for multi-step tasks that need more than one
agent run: updating dependencies, migrating a codebase, implementing a feature
that spans multiple files and verification cycles.
Quickstart
Inside the TUI:
/goal update all npm dependencies to their latest major version
The agent begins working autonomously. It runs iterations — full LLM tool-loop turns — until one of these happens:
- The objective is met and the agent calls
goal-complete✅ - No progress is detected for several iterations in a row ⏹
- The iteration safety cap is reached ⏹
- You press
Escor send/goal stop✋
How it works
The goal loop
- You run
/goal <objective>. - Spettro dispatches the objective as a task to the coding orchestrator
with the
GoalModePreambleprepended: instructions to work autonomously, not ask for continuation, verify work, and callgoal-completewhen done. - That run completes — either because the agent finished, or because it hit
the per-iteration step cap (
goal_iteration_steps, default 25 LLM steps). The cap is what guarantees each iteration is bounded: the preamble tells the agent that onlygoal-completefinishes the run, so without it a single iteration could run forever and the checks below would never fire. If the agent calledgoal-complete, the goal ends. - If not, Spettro checks for progress (see below) and either:
- dispatches another iteration (the agent resumes where it left off), or
- stalls the goal and reports why.
- The loop repeats until one of the termination conditions fires.
Progress detection
Between iterations, Spettro fingerprints the workspace by hashing
git status --porcelain output. If the signature does not change across
consecutive iterations, the goal is considered stalled. The stall limit is
configurable (default: 3 iterations with no change).
This is conservative: false "progress" (a change that isn't actually progress) just lets the loop continue; false "stall" is the bad case, so the detection prefers to under-report stalls.
Conversation state across iterations
The LLM conversation from each iteration is fed back as the structured
Messages prefix for the next one. This keeps the provider request prefix
byte-stable so prompt caching hits and previously generated tokens are never
re-summarised or discarded between turns.
When the context window gets tight, Spettro auto-compacts between iterations (respecting your auto-compact threshold). The compaction preserves a summary that the next iteration extends.
Commands
| Command | Description |
|---|---|
/goal <objective> |
Start a new goal run with the given objective. |
/goal stop |
Abandon the active goal and cancel any in-flight run. |
/goal status |
Show the current goal's iteration count, no-progress counter, and elapsed time. |
/goal resume |
Resume an unfinished goal from a loaded session (shown via /resume). |
Only available in the TUI. Headless goal mode is started via the --goal CLI
flag (see below).
Configuration
These settings live in ~/.spettro/config.json:
| Setting | Config key | Default | Description |
|---|---|---|---|
| Shell timeout | goal_shell_timeout_sec |
600 (10 min) | Max wall-clock time per shell/bash tool call during goal runs. Longer than the default timeout to accommodate installs and builds. |
| Max iterations | goal_max_iterations |
0 (unlimited) | Safety cap on the total number of outer-loop iterations. Set to a positive integer to prevent runaway loops. |
| Stall limit | goal_no_progress_limit |
3 | Consecutive iterations with no workspace change before the goal is declared stalled. |
| Iteration steps | goal_iteration_steps |
25 | LLM steps per iteration before the run yields back to the goal loop for the progress check. |
Set them with:
/budget 0
/compact auto on
(The token budget and auto-compact settings apply to goal runs the same way they apply to ordinary runs — auto-compact is especially useful for long goal sessions.)
Permission mode and goal mode
Goal mode pauses on approval prompts the same way ordinary runs do. For
fully unattended operation, set permission to yolo before starting:
/permission yolo
/goal deploy the application to staging
When permission is ask-first or restricted, Spettro prints a warning
before starting the goal loop so you know what to expect.
Headless goal mode
Outside the TUI, start a goal run with:
spettro --goal "update all dependencies" --sandbox workspace-write
Flags available:
| Flag | Description |
|---|---|
--goal <objective> |
Start goal mode with the given objective. |
--cwd <path> |
Working directory (default: current directory). |
--sandbox <mode> |
OS sandbox mode: off, read-only, workspace-write. |
--sandbox-net <policy> |
Network policy: all, localhost, none, or ports:443,8080. |
--sandbox-allow-dir <path> |
Extra writable directory inside the sandbox (repeatable). |
--sandbox-allow-read-dir <path> |
Extra readable directory inside the sandbox (repeatable). |
In headless mode:
- Permission is forced to
yolo(unattended operation). - Tool traces are printed to stdout with
[✓]/[✗]markers. - The
ask-usertool is unavailable — if the agent tries to ask a question, the goal fails with an error. - Exit codes:
0for goal complete,1for stall/error/interrupt.
Output:
Starting goal mode: update all npm dependencies
Max iterations: 0 (unlimited), No-progress limit: 3
=== Iteration 1 ===
[✓] glob: success
[✓] file-read: success
...
=== Iteration 2 ===
...
✓ Goal complete: all dependencies updated and verified
Iterations: 3, Duration: 2m15s
Steering a running goal
You don't have to stop a goal to correct its course. Type a message while the run is active and press enter — Spettro asks how to deliver it:
- Steer now — the message is injected into the running conversation at the agent's next step boundary, as a user turn the model sees before its next action. The run continues without restarting, and the injection is append-only so the provider prompt cache keeps hitting.
- Queue for after the run — the previous behavior: the message becomes a normal prompt once the run finishes.
- Discard — closes the picker and puts the text back in the input box
(
Escdoes the same).
Steering works in normal runs too, not just goal mode. In goal mode the steering queue is shared across iterations, so a message typed between iterations is delivered to the next one. If a run finishes before a steering message could be delivered, the message is re-queued as an ordinary prompt so it is never lost. A "steering delivered" note appears in the transcript when the agent actually receives it.
ACP mode
Over the Agent Client Protocol (ACP), /goal <objective> is advertised as an
available command and runs the autonomous loop inside the prompt turn. Cancel
the turn (session/cancel) or send /goal stop as a new prompt to stop the
goal. Steering works here too: any prompt sent while the goal turn is running
is delivered to the agent at its next step boundary instead of interrupting
the loop (see ACP mode → Mid-run steering).
Caveats
- Long-running builds: set
goal_shell_timeout_sechigh enough (default 10 minutes is usually sufficient). The headless mode applies the timeout from config; the TUI applies it per shell/bash tool call. - Expensive models: goal mode can accumulate many iterations (and many LLM calls per iteration). Keep an eye on your token usage. The status bar context gauge and session cost counters update after every LLM request (not only when a goal iteration finishes), so you can interrupt early if a run is burning more budget than expected. See Session Lifecycle → Live updates during a run.
- No undo: goal mode makes real changes to your workspace. Use the sandbox
(
--sandbox workspace-writeorread-only) as a safety net, andgitto review what changed before committing. - Interrupting:
Escin the TUI orPOST /interruptover the remote control plane cancels the in-flight run and abandons the goal entirely.
