npm.io
0.3.7 • Published 3h ago

@hank-warren/pi-goal

Licence
MIT
Version
0.3.7
Deps
1
Size
258 kB
Vulns
0
Weekly
0

pi-goal (fork) — Goal Mode for the Pi Coding Agent

Fork of @narumitw/pi-goal with inline /goal invocation. See NOTICE.md for attribution, the exact upstream base, and the itemized fork changes.

Goal mode adds a session-scoped /goal command, goal_complete / goal_blocked / goal_wait tools, and guarded automatic continuation from Pi's settled idle boundary until the agent completes the goal, waits for an external event, is paused, hits a safety circuit breaker, or exhausts an optional token budget. For the full feature reference, see the upstream README — this fork is behavior-identical apart from the changes below.

Fork feature: inline /goal, tool-mediated

Upstream (like Pi itself) only dispatches /goal when it starts the message. This fork makes mid-prompt invocations work the way Claude Code skills do — the model invokes them:

I am making a test /goal say hello
goal: get CI green

Both start goal mode with the objective after the token. Mechanics:

  • A new goal_start tool reuses the exact activation path of the /goal command (replacement confirmation, kickoff guards, persistence, --tokens budgets). Its prompt guidelines restrict it to explicit /goal or goal: invocations — the model never starts goals from general conversation.
  • When a user-typed message contains a mid-prompt /goal <objective> or a line starting with goal: <objective> (outside backtick code and quoted spans), a one-line reminder is appended to that turn's system prompt so the model reliably calls goal_start. It is stored nowhere, so it cannot linger in the conversation and fire on a later turn, and the message itself is never touched — no cutting, splitting, re-sending, or visible annotation. Invocations typed while the agent is streaming (steered or queued messages) get no reminder; the tool's own prompt guidelines cover them.
  • A leading /goal still dispatches natively, exactly as upstream.
  • Controlled by the inlineInvocation settings key (default true) in ~/.pi/agent/pi-goal.json, or the Inline /goal toggle in /goalSettings… (the toggle gates the reminder; the tool itself stays registered).

Fork feature: cache-safe, token-lean injections

Goal mode has to keep the objective and its rules in front of the model on every turn. This fork splits that job by how often each part changes, so the provider's prompt cache survives a long goal:

  • Static per goal — the system prompt. The trust boundary, <goal_objective>, <goal_id>, and the goal-mode rules are appended to the system prompt on every goal turn, and that append is byte-identical across turns of the same goal. Anthropic caches tools → system → messages as one prefix, so a moving counter in the system block would invalidate the cache for the entire conversation on every turn. A budgeted goal therefore states its budget total ("a token budget of 100k applies"), never the running usage. The append changes only when the goal itself does — start, edit, clear — which is one accepted cache rewrite per boundary. test/goal-contracts.test.ts pins this as the cache-stability contract.
  • Dynamic per wake — the continuation messages. Automatic-continuation messages are pointer-sized (~54 tokens): which continuation it is, the current budget usage, a pointer to the system prompt for the rules, and the provenance marker. Appending to the conversation tail never invalidates the cached prefix. Previously each continuation stored a near-complete copy of the goal block, so a 25-iteration goal wrote roughly 21k tokens of duplicated instructions into the conversation; it now writes about 1.5k.
  • The kickoff message anchors the objective — and must. The system append above is emitted only on active goal turns: before_agent_start returns early for a budget wrap-up and for every non-active status. So a turn that runs after the goal stops — the budget wrap-up itself, or the user simply replying afterwards — receives no goal system content at all, and sees the objective only if a stored message still holds it. The kickoff therefore repeats the objective data (trust boundary, <goal_objective>, <goal_id>) even though the active-turn system prompt also carries it. It omits the goal-mode rules, which only govern active turns. That is ~164 tokens once per goal, not per turn.
  • Display. Those markers are also what the transcript renders: kickoff and continuation messages collapse to one-line chips (⟳ goal continuation #4 · budget 12k/100k) through a markdown transformer. That hook is display-only by Pi's contract — the stored message and the model's context are untouched.
  • Widget. The counters removed from the system prompt did not disappear: the goal widget above the editor shows the objective, budget fraction, iteration, and automatic-turn count, alongside the existing footer status.

This follows Anthropic's own guidance from Lessons from building Claude Code: prompt caching is everything — static content first, dynamic state delivered as messages rather than system-prompt edits.

Cross-extension assumption: @hank-warren/pi-loop relies on this. Its pokes no longer restate the objective, because a loop requires an active goal, so every poke turn carries this system append.

Install

pi install npm:@hank-warren/pi-goal

Never install this fork alongside upstream @narumitw/pi-goal. Both register the /goal command, the same three tools, the same goal-state session entries, and the same ~/.pi/agent/pi-goal.json settings file; co-installation collides on all of them. This fork is a drop-in replacement — uninstall upstream first.

Configuration

Identical to upstream (~/.pi/agent/pi-goal.json, absent file = defaults) plus the fork key:

{
  "toolVisibility": "after-first-goal",
  "inlineInvocation": true,
  "rpc": { "enabled": false },
  "continuationLimits": { "automaticTurns": 25, "noProgressTurns": 3 }
}

Upstream sync

This is a tracking fork with a minimal diff: upstream src/ files are kept byte-identical where possible and fork logic lives in src/inline-command.ts, src/inline-invocation.ts, and src/goal-start-tool.ts. The sync runbook — including the recorded upstream base tag and commit — is in NOTICE.md.

License

MIT. Original work Copyright (c) 2026 narumiruna; fork changes Copyright (c) 2026 Hank Warren. See LICENSE and NOTICE.md.

Keywords