# Goal contracts and commands

## Contract shape

```ts
interface VerificationStep {
  executable: string;
  args: string[];
  cwd?: string;
  timeoutMs: number;
  expectedExitCodes: number[];
}
interface GoalContract {
  objective: string;
  criteria: string[];
  constraints: string[];
  verification: VerificationStep[];
}
```

`objective`, each criterion, and each constraint must be non-empty strings. If criteria are omitted, the objective becomes one criterion. Verification defaults to `[]`. Editing validates the same shape as creation.

## `/goal` subcommands

| Command | Effect |
| --- | --- |
| `/goal`, `/goal status` | Print/report state; if already active, attempt to schedule an initial turn. |
| `/goal <options> <objective>` | Replace the branch goal and start it. |
| `/goal edit` | Edit contract JSON in a TUI/RPC editor. Unavailable in print mode. Active goals get a new turn after an edit when possible. |
| `/goal pause` | Pause non-complete work. |
| `/goal resume` | Reactivate a non-complete goal and try to queue one turn. |
| `/goal archive` | Stop and persist the current goal as archived. Archived goals cannot resume. |
| `/goal clear` | Persist a null-state tombstone and remove branch UI. |
| `/goal judge same` | Use the active model as a separate fresh-context judge. |
| `/goal judge provider/model` | Select a configured model registry entry as judge. |

Errors are reported through the UI where available, as text in print mode, and do not mutate state. Command-name collisions are detected at restore time; Pi may suffix colliding extension commands numerically.

## LLM-driven creation with `goal_set`

The `goal_set` tool is available so the LLM can create or replace a goal when—and only when—the user's current message explicitly asks to set, create, or save something as a persistent goal. Phrases such as “set this as goal” qualify; an ordinary task request does not, even when it is complex or multi-step.

The tool accepts `objective`, optional `criteria` and `constraints`. Goals have no iteration or token budget and continue until completed, blocked, paused, or archived. Criteria default to the objective. It cannot add verification steps, because verifier commands must remain user-approved configuration. The run that invokes `goal_set` is not aborted and becomes the first goal run.

## Creation options

| Option | Meaning |
| --- | --- |
| `--criterion TEXT` | Repeatable completion criterion. |
| `--constraint TEXT` | Repeatable mandatory constraint. |
| `--verify COMMAND` | Repeatable approved verifier; default timeout is 120,000 ms. |
| `--timeout MS` | Timeout (100–1,800,000) for subsequent `--verify` options. |
| `--verify-cwd PATH` | Relative project cwd for the immediately preceding verifier. |
| `--verify-exit 0,1` | Accepted exit code(s) for the immediately preceding verifier. |
| `--` | Stop option parsing; later `--...` tokens belong to the objective. |

An option needing a value, `--verify-cwd`/`--verify-exit` without a prior verifier, unknown options, invalid integers, and a missing objective are rejected.

## Verifier safety

`COMMAND` is tokenized with simple quote and backslash handling, solely to create an executable plus argument list. It is not shell parsing or execution. Empty commands, trailing escapes, and unclosed quotes are rejected.

The executable cannot contain whitespace, control characters, or shell metacharacters. Standalone shell operators (`&&`, `||`, `;`, `|`, redirections, command substitution markers, and backticks) are rejected in arguments. `sh`, `bash`, `zsh`, `dash`, `fish`, `cmd`, `cmd.exe`, `powershell`, and `pwsh` are rejected when invoked with their command-string switches (`-c`, `-command`, `/c`). NUL bytes are never permitted.

`cwd` must be relative. At execution it is resolved with `realpath`; absolute paths, symlink escapes, and paths outside the real project root are rejected. To intentionally assert an empty search result, approve the tool’s non-zero success code:

```text
/goal --verify 'rg LegacyToken src/auth' --verify-exit 1 Remove LegacyToken
```
