pi-goal-expander

extensionmaintained

Grok-style goal harness for Pi: expand objectives into frozen plans, drive multi-turn pursuit, harness-owned verification with optional pi-subagents skeptics.

by · v0.2.1 · published 1w ago

$ pi install npm:pi-goal-expander
downloads/mo
496
stars
0
last push
1w ago
open issues
0

Signals

license: Unlicensetestspi manifest: missinginstall size: —deps: 0peer deps: 0

Download trend

496 downloads · last 12 weeks (weekly)

README

pi-goal-expander

Grok-style goal harness for Pi: expand a rough objective into a frozen plan, drive multi-turn pursuit, and harness-own verification so the model cannot self-certify.

Optional soft integration with @clanker-code/pi-subagents / upstream for planner/skeptic roles (degrades without it).

Install

pi install npm:pi-goal-expander
# local:
# pi install /path/to/pi-goal-expander
# pi install git:github.com/clankercode/pi-goal-expander

Smoke:

pi -ne -e ./src/index.ts

Surfaces

SurfacePurpose
/goal <objective>Start harness (research → expand plan → execute)
/goal-expand <text> / /goal expand <text>Same as /goal (starts harness)
/goal status | pause | resume [--takeover] | clear | helpLifecycle + help
update_goal toolmessage / completed / blocked_reason
goal_expand toolSame as /goal for the model

Session ownership

Each active goal is owned by the Pi session that created it, scoped to that repository's .pi/goal/ state. Other top-level sessions in the same repository are read-only and do not restore the goal or receive goal injections. Plain /goal resume never takes another session's goal; use /goal resume --takeover only for a deliberate handoff. Ownership includes a 15-minute diagnostic lease, but lease expiry never transfers a goal automatically.

How it works

  1. Start — create goal state under .pi/goal/<id>/, inject a slim goal_set notice while the planner runs, then write plan.md (planner subagent if available, else structural draft on disk only). When pi-subagents is available, the planner spawn sets inheritContext: true (session fork / parent conversation inheritance) and also hands off a compact parent-branch transcript into the planner prompt when sessionManager.getBranch() is available — so the planner sees prior chat/research, not only the objective string.
  2. Execute kickoff — short message with objective + plan/evidence paths + steps (triggerTurn: true). The full plan body stays on disk; kickoff does not paste the draft skeleton into the transcript
  3. Execute — agent reads/rewrites plan.md as needed, works the checklist, keeps evidence/index.md filled
  4. Verifyupdate_goal({ completed: true }) runs pre-verify + evidence-index gate (bias: not achieved without proof), then a blocking skeptic panel when pi-subagents is available (spawn → wait → aggregate before Achieved)
  5. Continue / stall / complete — gaps replayed; same gap fingerprint twice → pause; verify cap → pause; success → receipt + user-visible completion summary (reload hint)

Statusline: ◎ plan · ◎ plan <agentId> (while planning) · ● active · 🔬 verify · ⏸ pause · ✓ done

Progress milestones

While executing, call update_goal({ message }) at least for:

  • researched — codebase/context research done
  • implementing — implementation underway
  • pre-complete — work done, about to request verify

Optional mid-checklist notes are fine. History stores these as typed progress events.

Lifecycle events

The harness emits custom session messages (customType: pi-goal-expander:event, usually display: false) with a details.kind field. Useful for dogfood logs and dashboards.

kindWhen
session_restoreActive goal reloaded on session_start when the current Pi session owns it
goal_setGoal created; planner may still be running (display message)
planning_startedPhase → planning
planning_completedPlan written; phase → executing
planning_failedPlanner hard-failed
goal_startExecute kickoff injected
progressupdate_goal({ message }) logged
verify_startedVerify round begins (may re-emit with panel agentIds)
verify_not_achievedVerify failed; gaps recorded
verify_achievedVerify passed
goal_completedGoal status complete (after verify_achieved)
verify_pausedVerify cap hit → pause
paused / resumed / cleared/goal pause|resume|clear
blocked_attemptupdate_goal({ blocked_reason })
goal_complete_summaryUser-facing completion blurb (pi-goal-expander:complete, display true)

Verify policy (goal kind → skeptic N)

Panel size is derived from plan.md Goal kind (see src/loop/verify-policy.ts):

Goal kindDefault skeptic N
analysis / research1
code-change3
missing / unknownconfig skepticN (default 3, clamp 1–5)

Config skepticN is the fallback when kind is absent, not a hard override of kind defaults. Kind is read from the ## Goal kind section of the active plan at completed:true time.

Panel timeout / infra policy

ConditionOutcome
No event bus / pi-subagents ping failsDegraded path — Achieved only if preverify + evidence gates pass (no false “panel passed”)
Bus alive but all spawns fail, all waits timeout, or no usable verdict textFail-closedNotAchieved with gap verifier panel unavailable
Partial verdictsAggregate what arrived (parseVerifierVerdict + aggregateVerdicts, bias-to-refute; malformed/empty = refute)

Per-skeptic wait uses config subagentsTimeoutMs (default 600s). The panel is on the critical path: verify_achieved is not emitted until wait+aggregate finish or the fail-closed policy applies.

Planner timeout / degrade policy

ConditionOutcome
No bus / pi-subagents ping failsDegraded structural draft (when soft mode); kickoff notes the real reason (ping_failed / unavailable)
Planner spawned but wait times outFail-closedplanning_failed, goal user_paused; planner agent stopped; no execute kickoff; no draft baseline as “success”
Structural draft writeNever overwrites a non-draft plan.md already on disk

Planner wait uses config plannerTimeoutMs (default 30m), separate from panel subagentsTimeoutMs (default 10m). Lifecycle events planning_completed / planning_failed include plannerReason (ok | no_bus | ping_failed | wait_timeout | spawn_error | agent_failed | structural_fallback).

Completion UX

On Achieved the harness emits a user-visible notify + display summary (pi-goal-expander:complete) with objective, receipt path (when receipts enabled), and a generic reload hint (/reload if UI settings look stale). That is the last goal-owned UI action for the goal; further continuation / next-step injects for that goalId are suppressed. Other extensions may still emit after; the goal harness itself stays quiet.

Goal state location vs edit scope

WhatWhere
Goal store (plan.md, state.json, evidence/, receipts)<cwd>/.pi/goal/<id>/ by default
Override store rootPI_GOAL_ROOT (absolute path used as the goal root)
Override cwd used for store resolutionPI_GOAL_CWD (falls back to extension ctx.cwd, then process.cwd())

Edit scope is not limited to the goal store. Objectives often name files outside the session cwd (e.g. ~/.pi/agent/settings.json). Agents should treat .pi/goal/ as harness bookkeeping only; allowed write targets follow the objective.

Evidence

Before completion succeeds, write:

.pi/goal/<id>/evidence/index.md

| Criterion | Artifact | Notes |
|-----------|----------|-------|
| 1 | tests/foo.test.ts | … |
| 2 | json:path/to/settings.json#powerline.cost.subscriptionDisplay=reported-cost | config assert |

Artifact forms

  • Path — any path-like string is checked for existence (tests/…, src/…, absolute paths).
  • JSON assertjson:<filePath>#<dotted.path>=<expected> reads the file, walks the dotted path, and requires an exact value match. Completion fails if the assertion fails even when the file exists (useful for config/settings goals).

Draft plan gate: update_goal(completed:true) returns NotAchieved with plan not expanded beyond draft if plan.md still matches the structural expand skeleton. Rewrite the plan with real criteria before completing.

Development

npm install
just check

Harness contract test (tests/harness-contract.test.ts): memory bus + installMockSubagentsRpc asserts the dogfood event order goal_set → planning events → goal_startverify_started → complete (no live LLM).

Release

See RELEASE.md:

just release patch   # or minor | major | 0.2.0

Design

docs/superpowers/specs/2026-07-20-goal-harness-design.md

License

Unlicense (public domain).