/goal-test
Local sandbox for experimenting with Claude Code's /goal command (stop-hook condition + LLM-evaluator driving autonomous work toward a verifiable end state) applied to LETS workflows. Use when the user says "goal test", "goal-test", "test the goal skill", "stop hook experiment",
Claude Code
$ npx -y skills add restarter/lets-workflow --skill goal-test --agent claude-code
Codex
$ npx skills add restarter/lets-workflow --skill goal-test -a codex -y
Cursor
$ npx skills add restarter/lets-workflow --skill goal-test -a cursor -y
Gemini CLI
$ npx skills add restarter/lets-workflow --skill goal-test -a gemini-cli -y
GitHub Copilot
$ npx skills add restarter/lets-workflow --skill goal-test -a github-copilot -y
OpenCode
$ npx skills add restarter/lets-workflow --skill goal-test -a opencode -y
Windsurf
$ npx skills add restarter/lets-workflow --skill goal-test -a windsurf -y
SKILL.md
goal-test.SKILL.mdname: goal-test
description: Local sandbox for experimenting with Claude Code's /goal command (stop-hook condition + LLM-evaluator driving autonomous work toward a verifiable end state) applied to LETS workflows. Use when the user says "goal test", "goal-test", "test the goal skill", "stop hook experiment", "автономна задача", "long-running goal", or wants to design a /goal contract that chains /lets:* commands (plan → execute → check → commit → done) toward a defined termination. Local-only — not part of the lets plugin payload. For periodic polling/babysitting, use sibling skill `loop-test` (which covers /loop).
goal-test (local experiment)
`/goal` installs a **session-scoped Stop hook with an LLM-evaluated termination condition**. After every model turn, an evaluator-LLM reads the transcript and judges whether the goal is met. If not, the turn is rejected and the model must keep working. Best fit: convergent autonomous work (drive a task / epic / PR to a defined end state).
**Not for periodic polling** — that's `/loop`'s job (see `loop-test` skill).
How `/goal` actually works
Sources: `claude` binary v2.1.150 strings + official docs ([code.claude.com/docs/en/goal](https://code.claude.com/docs/en/goal)) + community write-ups (see References).
Mechanics
1. User runs `/goal <condition>`. Stored as session-scoped state. **Cap: 4000 characters** per condition. 2. After every model turn (assistant message that would normally yield), evaluator-LLM is invoked with the condition + transcript.
- **Evaluator runs on your configured "small fast model"** (Haiku by default). Eval tokens are billed separately; Anthropic describes them as "typically negligible" but they accumulate on long runs.
- Evaluator reads the **transcript only** — assistant text + user messages. Tool inputs/outputs ARE in transcript, but you must surface evidence in your assistant text for the evaluator to weight it heavily. "Quote specific text from transcript whenever possible" is in its system prompt.
3. Evaluator returns JSON:
- `{"ok": true, "reason": "<quote evidence>"}` → goal achieved, session yields, UI shows `✔ Goal achieved (Ns · N turn · N tokens)` (user-visible only; **not surfaced into assistant transcript** — empirically confirmed Experiment 1).
- `{"ok": false, "reason": "<why not>"}` → Stop hook rejects, model gets a system message and must continue. Common reason text: `insufficient evidence in transcript`.
- `{"ok": false, "impossible": true, "reason": "..."}` → only when genuinely unachievable (self-contradictory condition, missing resource, exhausted approaches). **Evaluator is instructed to NOT trust the model's self-assessment** — it must independently judge whether the goal is structurally impossible.
4. Hard cap: `CLAUDE_CODE_STOP_HOOK_BLOCK_CAP` env var (present in binary, **undocumented publicly**; the community-cited "500" comes from the unofficial `jthack/claude-goal` precursor, not from official `/goal`). After N blocks the loop force-yields. Actual default unknown.
Lifecycle commands
- `/goal <cond>` — set/replace. Setting a new goal silently replaces the current one (no confirmation).
- `/goal` (bare) — status. Shows condition, elapsed time, turns evaluated, token spend, evaluator's **most recent rejection reason** ← scrape this during long runs as an early-warning of vague conditions.
- `/goal clear` (aliases: `stop`, `off`, `reset`, `none`, `cancel`) — abort current goal.
- `/clear` (session clear) **silently nukes the active goal**. Easy to lose state — be aware.
- No `/goal pause` / `/goal resume`. The unofficial precursor had them; Anthropic's version does not.
Constraints
- **Trusted workspace only** — `/goal is only available in trusted workspaces. Restart, accept the trust dialog, and try again.`
- **Hooks must be enabled** — fails if `disableAllHooks` or `allowManagedHooksOnly` is set.
- **Version floor:** Claude Code v2.1.139+ (we're on 2.1.150 — fine).
- One active goal per session. New `/goal` replaces.
- **Resume behavior:** `--resume` / `--continue` restores the goal *condition* but **resets turn count, timer, and token baseline**. Achieved-and-cleared goals are NOT restored.
- **Headless mode works:** `claude -p "/goal <cond>"` runs the loop to completion in one invocation; Ctrl+C is the only interrupt.
Visibility asymmetry (Experiment 1 finding)
`✔ Goal achieved (Ns · N turn · N tokens)` is shown in the **user's terminal UI only**. The model's transcript receives no signal that its goal cleared. Implication: **the model cannot programmatically detect "I just satisfied a goal"** — so chained `/goal1 → /goal2` flows cannot be auto-triggered from the model side. Either the user types the next `/goal`, or use a state-file checkpoint that the next-goal-tick reads.
Telemetry
`tengu_goal_achieved`, `tengu_goal_failed`, `tengu_stop_hook_block_count`, `tengu_stop_hook_added/removed`. Useful when designing — if your goals always end via `impossible` or block-cap, your condition is mis-specified. None of these events are referenced in any public write-up I found; private to Anthropic.
Complementarity with auto-mode
Auto-mode removes **per-tool** approval prompts. `/goal` removes **per-turn** yield prompts. They're complementary, not redundant. Common pairing: `auto` + `/goal` for fully unattended runs. **Caveat:** AUTO MODE rule in this project still requires explicit user approval for `git push`, `gh pr create`, `bd close` — encode those gates inside the goal text (e.g. "stop one step before pushing"), don't let either feature paper over them.
Designing a `/goal` for LETS — distilled rules
Distilled from binary research + the 9h-session reddit retex + Croucher's games field-guide + Praison's evidence-based pattern + Daily-Dose-of-DS failure-mode write-up.
Rules that make goals actually converge
1. **Three-part evidence-based condition (Praison / industry standard).** Every goal has three pieces:
- **Name the
Read more
name: goal-test description: Local sandbox for experimenting with Claude Code's /goal command (stop-hook condition + LLM-evaluator driving autonomous work toward a verifiable end state) applied to LETS workflows. Use when the user says "goal test", "goal-test", "test the goal skill", "stop hook experiment", "автономна задача", "long-running goal", or wants to design a /goal contract that chains /lets:* commands (plan → execute → check → commit → done) toward a defined termination. Local-only — not part of the lets plugin payload. For periodic polling/babysitting, use sibling skill `loop-test` (which covers /loop).
goal-test (local experiment)
`/goal` installs a **session-scoped Stop hook with an LLM-evaluated termination condition**. After every model turn, an evaluator-LLM reads the transcript and judges whether the goal is met. If not, the turn is rejected and the model must keep working. Best fit: convergent autonomous work (drive a task / epic / PR to a defined end state).
**Not for periodic polling** — that's `/loop`'s job (see `loop-test` skill).
How `/goal` actually works
Sources: `claude` binary v2.1.150 strings + official docs ([code.claude.com/docs/en/goal](https://code.claude.com/docs/en/goal)) + community write-ups (see References).
Mechanics
1. User runs `/goal <condition>`. Stored as session-scoped state. **Cap: 4000 characters** per condition. 2. After every model turn (assistant message that would normally yield), evaluator-LLM is invoked with the condition + transcript.
- **Evaluator runs on your configured "small fast model"** (Haiku by default). Eval tokens are billed separately; Anthropic describes them as "typically negligible" but they accumulate on long runs.
- Evaluator reads the **transcript only** — assistant text + user messages. Tool inputs/outputs ARE in transcript, but you must surface evidence in your assistant text for the evaluator to weight it heavily. "Quote specific text from transcript whenever possible" is in its system prompt.
3. Evaluator returns JSON:
- `{"ok": true, "reason": "<quote evidence>"}` → goal achieved, session yields, UI shows `✔ Goal achieved (Ns · N turn · N tokens)` (user-visible only; **not surfaced into assistant transcript** — empirically confirmed Experiment 1).
- `{"ok": false, "reason": "<why not>"}` → Stop hook rejects, model gets a system message and must continue. Common reason text: `insufficient evidence in transcript`.
- `{"ok": false, "impossible": true, "reason": "..."}` → only when genuinely unachievable (self-contradictory condition, missing resource, exhausted approaches). **Evaluator is instructed to NOT trust the model's self-assessment** — it must independently judge whether the goal is structurally impossible.
4. Hard cap: `CLAUDE_CODE_STOP_HOOK_BLOCK_CAP` env var (present in binary, **undocumented publicly**; the community-cited "500" comes from the unofficial `jthack/claude-goal` precursor, not from official `/goal`). After N blocks the loop force-yields. Actual default unknown.
Lifecycle commands
- `/goal <cond>` — set/replace. Setting a new goal silently replaces the current one (no confirmation).
- `/goal` (bare) — status. Shows condition, elapsed time, turns evaluated, token spend, evaluator's **most recent rejection reason** ← scrape this during long runs as an early-warning of vague conditions.
- `/goal clear` (aliases: `stop`, `off`, `reset`, `none`, `cancel`) — abort current goal.
- `/clear` (session clear) **silently nukes the active goal**. Easy to lose state — be aware.
- No `/goal pause` / `/goal resume`. The unofficial precursor had them; Anthropic's version does not.
Constraints
- **Trusted workspace only** — `/goal is only available in trusted workspaces. Restart, accept the trust dialog, and try again.`
- **Hooks must be enabled** — fails if `disableAllHooks` or `allowManagedHooksOnly` is set.
- **Version floor:** Claude Code v2.1.139+ (we're on 2.1.150 — fine).
- One active goal per session. New `/goal` replaces.
- **Resume behavior:** `--resume` / `--continue` restores the goal *condition* but **resets turn count, timer, and token baseline**. Achieved-and-cleared goals are NOT restored.
- **Headless mode works:** `claude -p "/goal <cond>"` runs the loop to completion in one invocation; Ctrl+C is the only interrupt.
Visibility asymmetry (Experiment 1 finding)
`✔ Goal achieved (Ns · N turn · N tokens)` is shown in the **user's terminal UI only**. The model's transcript receives no signal that its goal cleared. Implication: **the model cannot programmatically detect "I just satisfied a goal"** — so chained `/goal1 → /goal2` flows cannot be auto-triggered from the model side. Either the user types the next `/goal`, or use a state-file checkpoint that the next-goal-tick reads.
Telemetry
`tengu_goal_achieved`, `tengu_goal_failed`, `tengu_stop_hook_block_count`, `tengu_stop_hook_added/removed`. Useful when designing — if your goals always end via `impossible` or block-cap, your condition is mis-specified. None of these events are referenced in any public write-up I found; private to Anthropic.
Complementarity with auto-mode
Auto-mode removes **per-tool** approval prompts. `/goal` removes **per-turn** yield prompts. They're complementary, not redundant. Common pairing: `auto` + `/goal` for fully unattended runs. **Caveat:** AUTO MODE rule in this project still requires explicit user approval for `git push`, `gh pr create`, `bd close` — encode those gates inside the goal text (e.g. "stop one step before pushing"), don't let either feature paper over them.
Designing a `/goal` for LETS — distilled rules
Distilled from binary research + the 9h-session reddit retex + Croucher's games field-guide + Praison's evidence-based pattern + Daily-Dose-of-DS failure-mode write-up.
Rules that make goals actually converge
1. **Three-part evidence-based condition (Praison / industry standard).** Every goal has three pieces:
- **Name the
A development workflow plugin for Claude Code Stop babysitting your AI. Start shipping with it.
Other skills on lets-workflow.
loop-bb-pr
Compose a /loop that monitors a Bitbucket PR for activity (new comments, review state changes, merge, decline) via the bb-api…
loop-gh-pr
Compose a /loop that watches all open GitHub PRs for activity (new PRs, new commits, new comments) and auto-prepares a READ-ONLY…
loop-test
Local sandbox for experimenting with Claude Code's /loop command (interval + dynamic/self-paced scheduling) applied to LETS…
actor-fetch-personalit…
Internal skill for commands. Fetch and validate personality from URL or file path for Actor agent. Do not trigger on user…
agent-report
Internal skill for commands. The file transport for agent reports - hand every Task-dispatched agent a REPORT_FILE, then collect…
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about goal-test.
- Which coding agents can use goal-test?
- goal-test installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

