GoalAutonomous@piex-dev/goal

goal — Run the Agent to Verifiable Completion

Lead

/goal stops the agent from halting at a plan or partial work: after you set a goal it auto-continues from the idle boundary until completion is proven with evidence, a true blocker hits, or the token budget runs out.

Overview

Long coding-agent tasks fail two ways: they stop at a plan or half-finished work waiting for confirmation (premature yield), or they claim done without verification (false completion). goal mode guards both — it forces continuation until verifiable completion, and requires the completion call to carry the current goal_id and a summary of completion evidence.

Pi has no built-in autonomous completion loop. @piex-dev/goal adds one as a pure extension: it registers a /goal command and two terminal tools (goal_complete / goal_blocked), and dispatches continuation from the fully-settled idle boundary via pi's agent_settled lifecycle — only after retries, compaction, steering, and follow-ups have drained, with no duplicate dispatch.

How it works

The agent_settled continuation model

Continuation is not dispatched immediately at agent_end. After an agent turn, pi may still be retrying, auto-compacting, steering, or queuing follow-ups; firing continuation then would collide with that work. goal records the continuation intent as a ticket and dispatches it once at agent_settled (agent truly idle, no pending message). Repeated settled events cannot dispatch the same intent twice. Manual compaction does not emit agent_settled, so the compaction hook reuses the same single-flight dispatcher as a narrow fallback.

Stale-continuation guard: owned-prompt markers

Goal-owned prompts (kickoff, resume, continuation) inject a marker comment. If a delayed old prompt arrives after the goal is replaced or paused, the marker match is consumed and fires no model turn, so an old goal's continuation cannot override a newer goal. A stale tool-call block also intercepts stale tool calls after a goal stops, until fresh non-goal user input or a successful resume.

The goal_id stale guard

goal_complete / goal_blocked must carry the current goal_id and are rejected on mismatch. resume / edit rotate the goal_id so a delayed turn from a previous generation cannot complete the newer goal. This is the second line of defense beyond owned-prompt markers, blocking cross-generation false completion.

The blocked channel: real impasses need evidence

goal_blocked is not an ordinary pause. It requires the current goal_id, a specific reason, concrete evidence, and the same blocker recurring for at least three consecutive goal turns (repeated_turns ≥ 3). Empty reason/evidence, stale id, non-integer, or fewer than three turns are all rejected. Its value is not just the tool itself — the audit wording is repeated in every goal prompt, continually shaping a "don't yield lightly, impasses need evidence" behavior even when the tool is never called.

Accounting: cumulative totalTokens − baseline

For each persisted assistant message it uses usage.totalTokens (falling back to input + output + cacheRead + cacheWrite when unavailable). Goal usage = the current session branch's cumulative assistant total minus the baseline captured at start, clamped to zero after a rewind. Provider usage is authoritative only when an assistant message finishes, so a budget can overshoot by one model call.

Budget wrap-up

When exhaustion is first exposed after completed tool activity, the goal transitions once to budget_limited, cancels continuation, and queues one bounded wrap-up instruction: summarize progress/results/blockers only, no substantive tools. A tool-seeking model that calls a substantive tool during wrap-up is aborted to prevent an unbounded loop. A rejected goal_complete also terminates the wrap-up; an accepted completion still requires existing evidence proving every requirement — budget exhaustion itself is never completion.

Usage

Install

bash
pi install npm:@piex-dev/goal

Source: extensions/goal

Commands

text
/goal                          # show current goal, status, turns, time, tokens
/goal implement snake game     # start goal mode
/goal --tokens 100k fix tests  # start with a token budget
/goal edit ship smaller fix    # change the objective, keep counters
/goal pause                    # pause continuation
/goal resume                   # resume
/goal clear                    # clear the goal

--tokens accepts k/m suffixes (100k, 1.5m). Objective text is capped at 4,000 characters; for longer instructions put them in a file and reference the path from /goal.

Verification flow

flow
1. /goal <objective> starts; agent gets the kickoff prompt and goal_id
2. agent works autonomously; if incomplete at turn end, agent_settled auto-continues
3. on completion call goal_complete({ goal_id, summary }); summary is audited
4. on a real impasse call goal_blocked({ goal_id, reason, evidence, repeated_turns })

Configuration

json
{
  "toolVisibility": "always"
}

Path ~/.pi/piex-dev/goal/goal.json. toolVisibility: "always" (default, tools stay in the schema) or "after-first-goal" (revealed only after the first activation or an unfinished-goal restore, keeping non-goal sessions prompt-cache stable). Invalid config falls back to defaults with a warning; the extension never creates the file.

Implementation

Ported from @narumitw/pi-goal (pi-extensions) as a baseline rewrite, not a reference.

ModuleResponsibility
goal.tsentry: tool definitions + /goal command + lifecycle hook orchestration
runtime.tsper-session state, accounting, continuation dispatch, prompt ownership, tool policy
persistence.tsActiveGoal type + session-entry serialize/load
settings.tsread ~/.pi/piex-dev/goal/goal.json
prompts.tsinline prompt builders (trust boundary + completion audit + continuation)

Trimmed

RemovedReason
Experimental ordered queue (add/prioritize/drop-last/skip)pi-goal itself marks it experimental; not in v1
Cross-extension RPC contract (rpc:start/pause, state events)piex has no subagent extension consumer yet — YAGNI
/guided-goal LLM interviewcouples oh-my-pi internals; it is objective refinement, not completion; deferred to a later prompt package

piex-ified

Package name @piex-dev/goal (drops the pi- prefix, matching hashline/plan); config lives under ~/.pi/piex-dev/goal/; double quotes + semicolons, node: prefix, relative imports .js; does not read the upstream ~/.pi/agent/pi-goal-state.json (new package, no legacy users, clean slate).

Design notes

ProjectMechanismpiex decision
pi-extensions/pi-goalpure pi extension: two tools + agent_settled continuation + goal_id guard + status taxonomy + recoveryadopted: extension mechanism, two tools, continuation model, state machine ported wholesale as the baseline
oh-my-pigoal built into the coding-agent core (ToolSession/obfuscator/framedBlock/provider transport)not adopted: cannot run without the core, violating piex's "100% Extension API" constraint. Borrowed its completion-audit prompt wording and token-delta accounting idea

Key tradeoff: an autonomous loop's worst failures are false completion and infinite spinning, so the schema-level enforcement of goal_id guard, summary contradiction check, and blocked evidence threshold are all kept; a single op tool is simpler but leaves these three bare, so it is not chosen.

Changelog

Versions

VersionDateChanges
0.1.02026-07-19Initial release: single-goal lifecycle + agent_settled continuation + token budget + wrap-up; two tools (goal_complete/goal_blocked) + goal_id guard; experimental queue and RPC contract trimmed

Roadmap

DirectionPlan
Evaluationcompare single op vs two tools on false-completion / spin rates; let data decide whether to simplify
Ordered queueadd experimental add/prioritize/drop-last/skip on demand
RPC contractadd rpc:start/pause + state events once a subagent extension consumer exists
guided-goalintroduce objective-refinement interview as a separate prompt package