# Dissecting the Implementation of the /goal Command

# Dissecting the Implementation of the `/goal` Command (from Claude Code 2.1.139, headless version)

> Source file: `2.1.139-unbundled/extracted/src/entrypoints/cli.js`
>
> Reproduction goal: make the Agent **keep working until the condition is met**.
>
> Implementation principle in one sentence: **`/goal <cond>` registers `cond` as a session-level `Stop` hook (`type: "prompt"`)**. Each time the Agent wants to end a turn, this hook is evaluated; if the condition is not met, the model’s stop reason is fed back in so it keeps working, and once the condition is met, the hook is automatically cleared.
>
> Naming convention: when each identifier appears for the first time, a `/* original obfuscated name */` comment is attached to make it easier to trace back to the original bundle.

---

## 1. Data Model

```ts
type ActiveGoal = {
  condition: string;        // Goal condition entered by the user
  iterations: number;       // Number of unmet attempts (Stop hook interception +1 each time)
  setAt: number;            // Date.now() creation time
  tokensAtStart: number;    // "Cumulative output token count" at creation (⚠ output tokens only; see §10)
  lastReason?: string;      // Stop reason provided by the model in the previous turn
};

type GoalStatusAttachment = {
  type: "goal_status";
  met: boolean;
  condition: string;
  sentinel?: boolean;       // true = user-state set/clear anchor; UI does not render it, but resume flow searches for it
  reason?: string;          // Stop reason when unmet
  iterations?: number;      // Statistics when met
  durationMs?: number;
  tokens?: number;          // Output tokens consumed during the period
};
```

The initial value of `appState.activeGoal` is `undefined` (`cli.js` L456934).

---

## 2. Constants and Copy

```ts
const MAX_CONDITION_LENGTH /* $oH */ = 4000;

const CLEAR_KEYWORDS /* l23 */ = new Set([
  "clear", "stop", "off", "reset", "none", "cancel",
]);

const POLICY_GATE_MESSAGE /* i23 */ =
  "/goal is disabled by your organization's policy (disableAllHooks).";

const TRUST_GATE_MESSAGE /* n23 */ =
  "/goal is only available in trusted workspaces. " +
  "Restart, accept the trust dialog, and try again.";

// ⭐ Runtime instruction sent to the model immediately after setting a goal (copy verbatim)
const buildGoalDirective /* uD6 */ = (condition: string): string =>
  `A session-scoped Stop hook is now active with condition: "${condition}". ` +
  `Briefly acknowledge the goal, then immediately start (or continue) working toward it ` +
  `— treat the condition itself as your directive and do not pause to ask the user what to do. ` +
  `The hook will block stopping until the condition holds. ` +
  `It auto-clears once the condition is met — do not tell the user to run \`/goal clear\` after success; ` +
  `that's only for clearing a goal early.`;
```

---

## 3. Host-Framework Contract

The target project must expose the following capabilities. `/goal` itself is ~150 lines; this contract layer is where the real engineering effort lies.

### 3.1 Session & Resource Access

```ts
function getSessionId /* k_ */ (): string;            // cli.js L2288

// ⚠ Note: this is "cumulative output tokens", not "total tokens or context usage"
function getOutputTokenCount /* Wf */ (): number;     // cli.js L2409
```

### 3.2 Admission Gates

```ts
function isNonInteractive /* Z8 */ (): boolean;       // cli.js L2656 —— !isInteractive
function isRemoteWorkspace /* V8 */ (): boolean;      // cli.js L3076
function isWorkspaceTrusted /* q3 */ (): boolean;     // cli.js L149640
function isHooksDisabledByPolicy /* eu */ (): boolean;// cli.js L255357
```

### 3.3 Session-Scoped Hook Registry

This is the core of the whole mechanism. Hooks must support `type: "prompt"`, and when the Stop hook fires, the framework must let the LLM determine whether that prompt is satisfied, then convert the result into success/blocking.

```ts
type SessionHook =
  | { type: "prompt"; prompt: string }
  | { type: "function"; id: string; timeout: number; callback: Function; errorMessage?: string }
  | { type: "command"; command: string; /* … */ };

type HookEntry = {
  matcher: string;                    // empty string means "no matcher" → /goal uses empty string
  skillRoot?: string;                 // /goal uses undefined (distinct from skill-injected hooks)
  hooks: SessionHook[];
};

interface SessionHooksRegistry {
  add(sessionId: string, event: "Stop" | "SubagentStop" | /* … */,
      matcher: string, hook: SessionHook, skillRoot?: string): void;
  remove(sessionId: string, event: string, hook: SessionHook): void;
}

// See cli.js L376600 iD_ → OI7: upsert by (matcher, skillRoot)
function installHook /* iD_ */ (
  setAppState: AppStateSetter,
  sessionId: string,
  event: "Stop",
  matcher: string,
  hook: SessionHook,
): void;

// Get all HookEntry items for this session and event
function getHooksForEvent /* twH */ (
  state: AppState, sessionId: string, event: string,
): Map<string, HookEntry[]>;
```

**Key semantics** (contract relied on by cli.js L418198–418265):

- After a Stop hook runs, the framework yields an attachment in the message stream:
  - condition satisfied → `{ type: "hook_success", stdout?, stderr? }`
  - condition not satisfied → also includes `blockingError: { blockingError: string }`, and `b.stopReason` gives the reason
- The same frame’s `b.hook` field must be able to locate the corresponding `{ type: "prompt", prompt: cond }` hook, so `/goal` can compare `prompt === activeGoal.condition`.

### 3.4 App State

```ts
interface AppStateCtx {
  getAppState(): AppState;
  setAppState(updater: (s: AppState) => AppState): void;
  applyMessageOp(op: { type: "append"; messages: Message[] }): void;
  sessionHooksRegistry: SessionHooksRegistry;
  messages: Message[];
}

interface AppState {
  activeGoal: ActiveGoal | undefined;
  // … other fields
}
```

### 3.5 Message Helpers

```ts
function wrapAttachmentAsMessage /* z9 */ (att: GoalStatusAttachment): Message; // cli.js L423101

function makeUserMessage /* $6 */ (opts: {
  content: string | ContentBlock[];
  isMeta?: boolean;
  // …
}): Message;                                                                    // cli.js L450191

function formatBlockingError /* oV8 */ (err: { blockingError: string }): string;
// Implementation: return `Stop hook feedback:\n${err.blockingError}`            // cli.js L554731
```

### 3.6 Utility Functions

```ts
function pluralize /* x6 */ (n: number, singular: string, plural?: string): string; // cli.js L9966
function firstLine /* s5 */ (text: string): string;        // cut at the first \n // cli.js L10026
function formatDuration /* r7 */ (ms: number, opts: { mostSignificantOnly?: boolean }): string;
function formatTokenCount /* F4 */ (n: number): string;
```

### 3.7 Telemetry & UI Feedback

```ts
function track /* Q */ (event: string, props: Record<string, unknown>): void;       // cli.js L3256
function trackWithCode /* j6 */ (event: string, code: string): void;                // cli.js L43254
function showToast /* yH */ (id: "goal_set" | "goal_met"): void;                    // cli.js L43248
```

Events triggered by `/goal`: `tengu_stop_hook_added`, `tengu_stop_hook_removed`, `tengu_goal_achieved`, `tengu_goal_restored_on_resume`; failure prefixes: `goal_set:{policy_gate|trust_gate|too_long}`.

---

## 4. Command Registration (headless cares about the `local` shape)

```ts
// cli.js L540226–540237
const goalCommandNonInteractive /* gV3 */ = {
  type: "local" as const,
  name: "goal",
  supportsNonInteractive: true,
  thinClientDispatch: "post-text" as const,
  description: "Set a goal — keep working until the condition is met",
  argumentHint: "[<condition> | clear]",
  get isHidden() { return !isNonInteractive(); },
  isEnabled:  () => isNonInteractive() || isRemoteWorkspace(),
  load: () => Promise.resolve({ call: handleGoalText }),
};
```

> ⚠ Correction: `isNonInteractive()` ≠ "remote client". It is simply `!g_.isInteractive`. This command is **shown by default in non-interactive mode** and enabled in **non-interactive mode or remote workspaces**.

---

## 5. Command Entry Point `handleGoalText` (`cli.js` L540182–540207)

```ts
type GoalReply =
  | { type: "text";  value: string }
  | { type: "query"; value: string; prompt: string };

async function handleGoalText /* UV3 */ (input: string, ctx: AppStateCtx): Promise<GoalReply> {
  const q = input.trim();

  // (1) Empty input → show current status
  if (q === "") {
    const goal = ctx.getAppState().activeGoal;
    if (!goal) return { type: "text", value: "No goal set. Usage: `/goal <condition>`" };

    const turns = goal.iterations === 0
      ? "not yet evaluated"
      : `${goal.iterations} ${pluralize(goal.iterations, "turn")}`;
    const tail = goal.lastReason ? `\n${formatLastCheckLine(goal.lastReason)}` : "";
    return { type: "text", value: `Goal active: ${goal.condition} (${turns})${tail}` };
  }

  // (2) clear/stop/off/reset/none/cancel → clear
  if (isClearKeyword(q)) {
    const cleared = clearGoal(ctx);
    return { type: "text", value: cleared === null ? "No goal set" : `Goal cleared: ${cleared}` };
  }

  // (3) Character limit
  if (q.length > MAX_CONDITION_LENGTH) {
    trackWithCode("goal_set", "too_long");
    return {
      type: "text",
      value: `Goal condition is limited to ${MAX_CONDITION_LENGTH} characters (got ${q.length})`,
    };
  }

  // (4) Set → on failure, return error text; on success, immediately trigger a query with runtime instructions
  const errMsg = setGoal(q, ctx);
  if (errMsg !== null) return { type: "text", value: errMsg };
  return { type: "query", value: `Goal set: ${q}`, prompt: buildGoalDirective(q) };
}
```

---

## 6. Core set/clear Logic (`cli.js` L517416–517504)

```ts
function isClearKeyword /* xD6 */ (s: string): boolean {
  return CLEAR_KEYWORDS.has(s.toLowerCase());
}

function formatLastCheckLine /* hjK */ (reason: string): string {
  return `Last check: ${firstLine(reason.trim())}`;
}

// Admission gate
function checkGoalGate /* Wu8 */ (): { message: string; code: "policy_gate" | "trust_gate" } | null {
  if (isHooksDisabledByPolicy()) return { message: POLICY_GATE_MESSAGE, code: "policy_gate" };
  if (!isNonInteractive() && !isWorkspaceTrusted()) {
    return { message: TRUST_GATE_MESSAGE, code: "trust_gate" };
  }
  return null;
}

// List all Stop hooks in this session that were "injected by /goal"
function listGoalStopHooks /* mD6 */ (state: AppState, sessionId: string): SessionHook[] {
  const out: SessionHook[] = [];
  for (const entry of getHooksForEvent(state, sessionId, "Stop").get("Stop") ?? []) {
    if (entry.matcher !== "" || entry.skillRoot !== undefined) continue; // user-mode goal marker
    for (const hook of entry.hooks) if (hook.type === "prompt") out.push(hook);
  }
  return out;
}

// Construct a sentinel attachment message (not rendered by the UI; only used as a resume anchor)
function makeGoalSentinelMessage /* EjK */ (met: boolean, condition: string): Message {
  return {
    type: "attachment",
    uuid: crypto.randomUUID(),
    timestamp: new Date().toISOString(),
    attachment: { type: "goal_status", met, sentinel: true, condition },
  };
}

// Set goal — returns null on success; returns error text to display to the user on failure
function setGoal /* YoH */ (condition: string, ctx: AppStateCtx): string | null {
  const gate = checkGoalGate();
  if (gate !== null) {
    trackWithCode("goal_set", gate.code);
    return gate.message;
  }

  const sessionId = getSessionId();

  // Only one goal hook is allowed at a time: clear the old one first
  for (const old of listGoalStopHooks(ctx.getAppState(), sessionId)) {
    ctx.sessionHooksRegistry.remove(sessionId, "Stop", old);
  }

  // ⭐ Inject condition as a prompt-type Stop hook
  ctx.sessionHooksRegistry.add(
    sessionId, "Stop", "",
    { type: "prompt", prompt: condition },
  );

  const goal: ActiveGoal = {
    condition,
    iterations: 0,
    setAt: Date.now(),
    tokensAtStart: getOutputTokenCount(),
  };
  ctx.setAppState(s => ({ ...s, activeGoal: goal }));
  ctx.applyMessageOp({ type: "append", messages: [makeGoalSentinelMessage(false, condition)] });

  track("tengu_stop_hook_added", { promptLength: condition.length, via: "goal" });
  showToast("goal_set");
  return null;
}

// Clear goal — returns null if none exists; otherwise returns the cleared condition
function clearGoal /* woH */ (ctx: AppStateCtx): string | null {
  const sessionId = getSessionId();
  const existing = listGoalStopHooks(ctx.getAppState(), sessionId);
  if (existing.length === 0) return null;

  const cleared = (existing[0] as { type: "prompt"; prompt: string }).prompt;
  for (const h of existing) ctx.sessionHooksRegistry.remove(sessionId, "Stop", h);

  ctx.setAppState(s => (s.activeGoal === undefined ? s : { ...s, activeGoal: undefined }));
  ctx.applyMessageOp({ type: "append", messages: [makeGoalSentinelMessage(true, cleared)] });

  track("tengu_stop_hook_removed", { via: "goal" });
  return cleared;
}
```

---

## 7. Runtime: Stop Hook Feedback Loop (`cli.js` L418198–418265)

This is where “keep working until …” actually takes effect. Below are the two goal-related paths extracted from the main query loop:

```ts
// The main loop consumes the message stream produced by the hook
for await (const frame of hookStream) {
  // Helper: maps the hook descriptor on the frame back to the currently registered hook
  // (Z = (b) => { … }, corresponding to cli.js L418182)
  const matchedHook = (frame.hook && hookStillRegistered(frame.hook)) ? frame.hook : undefined;

  // ── Success path: hook did not block → treat goal as achieved ───────────────
  if (frame.message?.type === "attachment") {
    const att = frame.message.attachment;
    const isStop = att.hookEvent === "Stop" || att.hookEvent === "SubagentStop";

    if (isStop && att.type === "hook_success" && matchedHook?.type === "prompt") {
      ctx.sessionHooksRegistry.remove(getSessionId(), "Stop", matchedHook);
      const cur = ctx.getAppState().activeGoal;

      if (cur?.condition === matchedHook.prompt) {
        const iterations = cur.iterations + 1;
        const durationMs = Date.now() - cur.setAt;
        const tokens     = getOutputTokenCount() - cur.tokensAtStart;

        yield { type: "active_goal", value: undefined };       // Clear state
        yield wrapAttachmentAsMessage({
          type: "goal_status",
          met: true,
          condition: matchedHook.prompt,
          reason: frame.stopReason,
          iterations, durationMs, tokens,
        });

        track("tengu_goal_achieved", {
          promptLength: matchedHook.prompt.length, iterations, durationMs, tokens,
        });
        showToast("goal_met");
      }
    }
  }

  // ── Failure path: hook blocks → not achieved; feed reason back to model to continue work ──
  if (frame.blockingError) {
    // This meta message is injected as a system prompt into the next LLM call
    const feedback = makeUserMessage({
      content: formatBlockingError(frame.blockingError),   // "Stop hook feedback:\n<reason>"
      isMeta: true,
    });
    yield feedback;

    const cur = ctx.getAppState().activeGoal;
    if (matchedHook?.type === "prompt" && cur?.condition === matchedHook.prompt) {
      yield {
        type: "active_goal",
        value: { ...cur, iterations: cur.iterations + 1, lastReason: frame.stopReason },
      };
      yield wrapAttachmentAsMessage({
        type: "goal_status",
        met: false,
        condition: matchedHook.prompt,
        reason: frame.stopReason,
      });
    }
  }
}
```

> Key dependency (reiterated; already listed in §3.3): your Stop hook subsystem must support **`type: "prompt"`**. The framework needs to use a small LLM call to determine whether that prompt is satisfied, then choose either to “allow” (`hook_success`) or “block” (`blockingError`) accordingly. If your project currently only supports shell/function-style hooks, this is **required prerequisite work that must be completed first**.

---

## 8. Session Resume: Reattach the Goal on `resume` (`cli.js` L601434–601456)

Rebuild only when an **unfinished** `goal_status` is found at the end of the transcript; otherwise clear it.

```ts
// Find the most recent unmet goal anchor (including sentinel and failure feedback)
export function findGoalToRestore /* _mK */ (messages: Message[] | undefined): string | null {
  if (!messages) return null;
  for (let i = messages.length - 1; i >= 0; i--) {
    const m = messages[i];
    if (m?.type !== "attachment" || m.attachment.type !== "goal_status") continue;
    return m.attachment.met ? null : m.attachment.condition;
  }
  return null;
}

export function restoreGoalFromTranscript /* Rg3 */ (
  messages: Message[],
  setAppState: AppStateSetter,
): void {
  const condition = findGoalToRestore(messages);
  const gate = condition !== null ? checkGoalGate() : null;
  if (gate !== null) trackWithCode("goal_set", gate.code);

  if (condition === null || gate !== null) {
    setAppState(s => (s.activeGoal === undefined ? s : { ...s, activeGoal: undefined }));
    return;
  }

  installHook(setAppState, getSessionId(), "Stop", "",
              { type: "prompt", prompt: condition });

  setAppState(s => ({
    ...s,
    activeGoal: {
      condition,
      iterations: 0,
      setAt: Date.now(),
      tokensAtStart: getOutputTokenCount(),
    },
  }));

  track("tengu_goal_restored_on_resume", { promptLength: condition.length });
}
```

---

## 9. End-to-End Sequence

```
user> /goal write a passing test for foo.ts
  └─ setGoal(cond, ctx)
       ├─ checkGoalGate() OK
       ├─ sessionHooksRegistry.add(sid, "Stop", "", { type:"prompt", prompt: cond })
       ├─ setAppState: activeGoal = { cond, iter:0, setAt, tokensAtStart }
       ├─ append sentinel attachment (met:false)
       └─ telemetry tengu_stop_hook_added
  └─ immediately trigger query, prompt = buildGoalDirective(cond)
       └─ model: "Acknowledged. Starting now…" + tool call…

model attempts to end turn
  └─ Stop hook evaluates prompt
       ├─ met=false → blockingError(reason)
       │    ├─ yield meta message "Stop hook feedback:\n<reason>"
       │    ├─ activeGoal.iterations++, lastReason=reason
       │    ├─ yield goal_status{met:false, reason}
       │    └─ model continues working based on this
       └─ met=true  → hook_success
            ├─ sessionHooksRegistry.remove(...)
            ├─ activeGoal = undefined
            ├─ yield goal_status{met:true, iterations, durationMs, tokens}
            ├─ telemetry tengu_goal_achieved
            └─ toast goal_met

user> /goal clear
  └─ clearGoal(ctx) → remove hook + clear activeGoal + append sentinel(met:true)
```

---

## 10. Known Pitfalls / Correction Log

1. **`getOutputTokenCount` is output tokens only** — both `cur.tokensAtStart` and `goal_status.tokens` are “cumulative output tokens since the goal was set”; do not treat it as context usage.
2. **`isNonInteractive()` ≠ remote client** — it is simply `!g_.isInteractive`. The command display/enable rules are therefore: show by default in non-interactive mode; enable when non-interactive or in a remote workspace.
3. **Semantics of the trust gate** — note that `checkGoalGate` blocks only when `!isNonInteractive() && !isWorkspaceTrusted()`, i.e. it blocks `/goal` only “in interactive mode and when the workspace is untrusted”; non-interactive mode is not subject to the trust restriction.
4. **`/goal` coexists with other Stop hooks** — `listGoalStopHooks` uses `matcher === "" && skillRoot === undefined && type === "prompt"` to distinguish user-level goals, and will not clear Stop hooks injected by settings. When replicating this, this combination **must not be changed**.
5. **The sentinel must be stored in the transcript** — resume relies entirely on `findGoalToRestore` scanning `goal_status` attachments in reverse to decide whether to reattach the hook.

---

## 11. Minimal Implementation Checklist for Porting to Other Projects

In dependency order:

1. **Stop / SubagentStop hook subsystem** (most important):
   - Registry `add/remove` (supporting the `matcher` + `skillRoot` dimensions).
   - Support `{ type: "prompt", prompt }` hooks — when triggered, use a small LLM call to determine whether the prompt holds; convert the result into `hook_success` or `blockingError`.
   - The main query loop consumes these results and feeds blocking feedback into the next round as a system prompt.
2. **AppState field** `activeGoal`, with corresponding `setAppState/applyMessageOp` entry points.
3. **`goal_status` attachment type in the message stream**, at minimum persisted into the transcript (rendering is not required).
4. **The `/goal` command itself** (§5 + §6) — copy and paste is sufficient.
5. **Session resume flow** (§8) — call `restoreGoalFromTranscript` once after loading the historical transcript.
6. **Gate** (`checkGoalGate` from §6) — even for an MVP, connecting at least the trust gate is recommended.
7. **Telemetry/Toast** — optional; empty stubs are sufficient.

---

## 12. Symbol Mapping Quick Reference

| Clear Name in This Document | Original Obfuscated Name | Definition Location |
|---|---|---|
| `MAX_CONDITION_LENGTH` | `$oH` | L517487 |
| `CLEAR_KEYWORDS` | `l23` | L517503 |
| `POLICY_GATE_MESSAGE` | `i23` | L517493 |
| `TRUST_GATE_MESSAGE` | `n23` | L517491 |
| `buildGoalDirective` | `uD6` | L517489 |
| `isClearKeyword` | `xD6` | L517416 |
| `formatLastCheckLine` | `hjK` | L517434 |
| `checkGoalGate` | `Wu8` | L517445 |
| `listGoalStopHooks` | `mD6` | L517437 |
| `makeGoalSentinelMessage` | `EjK` | L517478 |
| `setGoal` | `YoH` | L517450 |
| `clearGoal` | `woH` | L517465 |
| `handleGoalText` | `UV3` | L540182 |
| `findGoalToRestore` | `_mK` | L601434 |
| `restoreGoalFromTranscript` | `Rg3` | L601443 |
| `getSessionId` | `k_` | L2288 |
| `getOutputTokenCount` | `Wf` | L2409 |
| `isNonInteractive` | `Z8` | L2656 |
| `isRemoteWorkspace` | `V8` | L3076 |
| `isWorkspaceTrusted` | `q3` | L149640 |
| `isHooksDisabledByPolicy` | `eu` | L255357 |
| `track` | `Q` | L3256 |
| `trackWithCode` | `j6` | L43254 |
| `showToast` | `yH` | L43248 |
| `pluralize` | `x6` | L9966 |
| `firstLine` | `s5` | L10026 |
| `formatDuration` | `r7` | L10804 |
| `formatTokenCount` | `F4` | L10844 |
| `getHooksForEvent` | `twH` | L376651 |
| `installHook` | `iD_` | L376600 |
| `wrapAttachmentAsMessage` | `z9` | L423101 |
| `makeUserMessage` | `$6` | L450191 |
| `formatBlockingError` | `oV8` | L554731 |
