# M140 Bundle B — make /goal real

Turns the M137 inline recipes into a data-driven primitive. 3 items+3 hooks+1 skill

## 1. /goal convergence telemetry (G3)

user: /goal until findings.critical == 0 prompt/goal-tracker: → appends to .claude/state/goal-history.jsonl → { session_id, condition, started_at, started_token_estimate } ... 8 turns later ... stop/goal-tracker: → matches open record by session_id → appends close: status=converged turn_count=8 tokens_estimate=42100
Two hooks (UserPromptSubmit + Stop), one append-only JSONL ledger. The first read-consumer of /goal in OrchestKit.

## 2. Monitor surfaces convergence rate

statusline: last 10 /goal: 8✓ 1↻ 1✗ avg 6t ✓ = converged (model self-stopped, condition met) ↻ = spun (high turn count, no natural stop) ✗ = aborted (user Esc / Ctrl+F) Aggregated from .claude/state/goal-history.jsonl src/monitors/goal-convergence.json
Surfaced in the OrchestKit statusline so you see /goal health at-a-glance, not just per-run.

## 3. Cost circuit-breaker (G5)

SessionEnd: Σ(this session's /goal turns) = 34 ⚠ over 30 Σ(this session's /goal tokens) = 287k ⚠ over 250k → write .claude/state/goal-budget-tripped.json { tripped_at, reason: "turns_cap", turns, tokens } next session: user: /goal until ... prompt/goal-tracker (continueOnBlock: true): ⛔ previous session burned 34 turns / 287k tokens on /goal. Cool-down active. Delete .claude/state/goal-budget-tripped.json to override.
Soft cap — refuses NEW /goal, doesn't interrupt in-flight. Env: ORK_GOAL_MAX_TURNS_PER_SESSION (30), ORK_GOAL_MAX_TOKENS_PER_SESSION (250k).

## 4. prd-to-goal skill (G2)

$ /ork:prd-to-goal "fix login fails on email with +" decomposed: ✓ failing test passes ✓ no regressions in suite ✓ commit + PR opened output: /goal until test_passes("test_login_email_plus") AND ci.failures == 0 AND gh.pr.exists("fix/login-email-plus") /goal abort-if turns > 15 OR tokens > 100000 OR no_progress_for_3_turns
3 worked examples in the skill body: bug fix, feature, refactor. Each shows acceptance criteria → boolean assertions over observable state.

## 5. closes "emit-only" gap

M137 (#1773): /goal recipes in 4 SKILL.md files emit-only — nothing reads what happens M139 #1784: PR template "Consumer" checkbox cultural fix — surface the question M140 Bundle B: /goal gets 3 consumers G3 logs every run G3 stop closes with status G5 caps cumulative session cost → /goal is now load-bearing instead of decorative
First cohort that ships explicitly with the M139 Consumer answer wired in.

## 6. counts + verification

Metric | Before | After
--- | --- | ---
hooks (global) | 123 | 126 +3
hooks (total) | 191 | 194
async hooks | 81 | 83
skills | 108 | 109 +1

✓ vitest: 8158 passed, 2 skipped (290 files) · ✓ npm run build: clean · ✓ validate-counts.sh: PASS