omp packages

dynamic-goal1.0.0

Dynamic replanning extension for the Pi coding agent: persistent goal, evidence-driven plan revision, phase-scoped tools, ADaPT-style as-needed decomposition, staleness detection, and isolated completion verification.

neoguri7 Published 10 days ago MIT ~189 downloads/mo

Untested on omp

This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

goal-mode — dynamic replanning for the Pi coding agent

A Pi extension for goal-directed execution with dynamic replanning: it keeps a persistent goal, tracks a revisable plan with provenance, classifies evidence, enforces approval boundaries per feedback mode, and survives session restarts.

It is not a TODO manager, a static plan mode, or a blind retry loop:

  • The goal is the stable reference point. It is never silently redefined and its mandatory acceptance criteria are never silently weakened.
  • The plan is a first-class, revisable artifact. Every revision records its trigger, evidence, affected tasks, and approval status.
  • Replanning is evidence-driven and bounded: revisions must cite evidence; repeated/oscillating plans and exhausted budgets are rejected, not looped.

Requirements

  • Pi coding agent v1.1.0 (verified against @earendil-works/pi-coding-agent@1.1.0 extension APIs). Minimum supported: 1.1.0.
  • Node.js ≥ 22.18 (type-stripping for local TS, no build step needed).

Install

From npm (published package):

pi install npm:dynamic-goal

Or from git:

pi install git:github.com/neoguri7/dynamic-goal@v1.0.0
# or unversioned: pi install https://github.com/neoguri7/dynamic-goal

Or locally during development:

git clone https://github.com/neoguri7/dynamic-goal
cd dynamic-goal && npm install --no-audit --no-fund
pi install ./dynamic-goal            # as a package
# or: pi --extension ./dynamic-goal/src/index.ts   # one-off
# or: node scripts/install.mjs                       # junction into ~/.pi/agent/extensions/

Host-provided imports (@earendil-works/*, typebox) are peerDependencies resolved by Pi itself — no bundled copies, no duplicate registries.

The extension registers its tools inactive; they activate when a run starts (/goal, or the model calling goal_define) and deactivate on completion or cancellation, so normal conversations are untouched.

Quick start

/goal Add an export button to the settings page, wired to the new API

The agent then researches (normal tools), records evidence (goal_evidence), plans (goal_plan with assumptions), executes tasks, updates statuses with verification evidence (goal_task_update), and finally calls goal_complete, which independently checks that every non-superseded task is completed and every mandatory acceptance criterion has supporting evidence.

User commands:

Command Purpose
/goal <text> Start a run (also shows current goal when bare)
/goal-plan Inspect plan + task statuses
/goal-constraints <text> Add acceptance criterion (optional: prefix → preference)
/goal-questions Review/answer open questions
/goal-mode Switch feedback mode + question policy
/goal-approve, /goal-reject Decide a pending plan revision
/goal-pause, /goal-resume Pause/resume
/goal-cancel Cancel (history retained via /goal-history)
/goal-history Revision history with triggers + approval status
/goal-report Final status + verification report

Model tools (active only during a run): goal_define, goal_plan, goal_state, goal_evidence, goal_task_update, goal_question, goal_answer, goal_assumption, goal_propose, goal_decompose, goal_complete.

Task decomposition (function-split refinement)

Once the plan is confirmed — feedback rounds settled, revision approved, evidence covering the tasks — top-level tasks can be split into concrete subtasks (t1 → t1-1, t1-2, …), recursively up to depth 3 (t1-1-1), like function decomposition.

  • Confidence gate. goal_decompose is allowed only when a deterministic plan-confidence score ≥ decomposeThreshold (default 0.7): 0.25 approved/auto-applied latest revision + 0.25 no open high-impact questions + 0.25 resolved-assumption ratio + 0.25 evidence coverage of top-level tasks. A pending proposal is a hard zero. /goal-decompose (no args) shows the current score and its reasons.
  • Forcing. /goal-decompose <taskId> bypasses the gate once (consumed on the next goal_decompose call) and asks the agent to decompose immediately.
  • Same approval pipeline. A decomposition is a revision like any other (trigger: decompose): human mode queues it for /goal-approve, ai auto-applies within boundaries, hybrid auto-applies (subtasks default to low impact) unless a subtask is high impact.
  • Stable ids + inheritance. Subtask ids are stable across revisions; subtasks inherit the parent's dependsOn, acceptance, verification, and assumptions unless overridden — the model typically chains them (t1-2 dependsOn [t1-1]).
  • Guards. No double-decomposition (refine via goal_propose instead), completed/superseded parents refuse, and a parent cannot be completed via goal_task_update while subtasks remain open — completion of every leaf is verified first.
/goal-decompose          → plan confidence: 0.50 (threshold 0.7)
                          assumptions resolved: 0% …
/goal-decompose t1       → gate bypassed once; agent decomposes t1 now

Feedback modes

Mode Behavior
human Every plan revision requires explicit approval (/goal-approve, /goal-reject). Questions are prompted at tool-call time (never mid-stream).
ai Revisions auto-apply within mandatory boundaries: goal changes, mandatory-acceptance changes, and mandatory-constraint changes always require approval regardless of mode. Retries and low-impact revisions proceed autonomously.
hybrid (default) Low/medium-impact revisions auto-apply; high-impact revisions queue for approval.

Question policies (/goal-mode):

Policy Behavior
off Never interrupt; make conservative assumptions and record them.
on-demand (default) Prompt only for high-impact blocking decisions.
checkpoint Prompt at high-impact ambiguity, always for high impact.
proactive Also prompt for medium-impact opportunities.

Mode changes preserve goal, plan, history, and progress.

Token efficiency

A goal-mode run never duplicates the plan into every request:

  • Compact per-turn context. before_agent_start injects ~8 lines (goal, progress counters, in-progress + next-ready tasks ≤5, pending proposal notice) instead of the full plan. The full render lives behind goal_state, called on demand.
  • Delta tool results. goal_task_update, goal_propose, goal_decompose return the change + compact summary, not the whole document — the model just authored the change, it doesn't need it echoed.
  • Phase-scoped tools. 10 of 11 tools are defaultActive: false; only goal_define (a few lines) is declared before a run starts. During a run the model sees planning tools (goal_plan…) or executing tools (goal_task_update, goal_propose, goal_decompose, goal_complete…), never both sets, never off-phase schemas. Cancel/complete removes them all.
  • Bounded full renders. goal_state//goal-plan cap at 40 tasks, 10 questions, 10 assumptions (with +N more markers); completed tasks collapse to one line (no acceptance text).
  • No persistence overhead. State snapshots are session entries, which are excluded from LLM context by design — they cost disk, not tokens.

Result: per-request cost stays roughly constant as plans grow (O(next-ready) instead of O(plan size)).

Research-grounded mechanisms (2025–26 literature)

Grounded in docs/research-feedback.md (ALAS, ADaPT, AdaPlan-H, SyncPlan, Reflexion, CART/BacktrackAgent):

  • ADaPT as-needed decomposition. When a task exhausts its retry budget and can still be decomposed, decideRetry routes to decompose instead of blind escalation, and the failure unlocks the confidence gate once — failure itself is the evidence the task was too coarse.
  • AdaPlan-H complexity trigger. goal_task_update results name high-impact / previously-failed undecomposed tasks as decomposition candidates (decompositionCandidates).
  • ALAS isolated verification. goal_complete performs a fresh-context check: goal + criteria + evidence summaries in a bounded prompt via a nested provider-neutral model call — never the transcript — so the run is not graded by the same context that produced the work. Falls back to the deterministic evidence check when no model/auth is available.
  • SyncPlan staleness detection. Every render surfaces PLAN STALE: when an invalidated assumption touches a ready/in-progress/failed task (deterministic, zero extra tokens).
  • Reflexion-style reflections. Failures accept a one-line reflection (what to try differently); recent ones surface in the compact render and persist across sessions.
  • CART proposal parking. /goal-reject parks the rejected proposal (bounded, last 5); /goal-revert <rev> re-promotes it with a fresh revision number and re-keyed fingerprint (oscillation-safe trajectory resume).

Interoperability (agents, skills, MCP, classifiers)

goal-mode is deliberately composable instead of self-contained:

  • Optional classifier-assisted confidence (e.g. Jev). By default the decomposition gate uses the deterministic score above. To blend in a structured classifier — such as a Jev system-one model registered by another extension — set confidenceClassifier: { provider, model } on the policy (persisted with the goal state). The classifier scores plan settledness via ctx.modelRegistry.classify(); the gate uses 0.5·deterministic + 0.5·classifier, and falls back to deterministic-only when the model is unregistered or the call fails. The classifier never touches approval decisions — those stay deterministic for safety.
  • Research-first questions. The tools instruct the agent to resolve uncertainties itself before interrupting the user: code inspection, tests, available skills, web research, MCP tools — findings recorded via goal_evidence (kind=research), answers via goal_answer (source=research).
  • Compaction-safe. State lives in session entries and is re-injected fresh each turn (before_agent_start), so compaction extensions (e.g. pi-blackhole) can compress old turns freely — goal-mode rebuilds its context from the persisted snapshot, not from conversation history.
  • Cross-extension hook point. pi.events remains available for other extensions to observe goal-mode activity; goal-mode itself registers no MCP servers and adds no network dependencies.

State + persistence design

  • Schema version 3 (older data migrates up automatically: v2 added parentTaskId + decomposeThreshold, v3 added failure reflection + parked rejected proposals; all optional with defaults).

  • In-memory StateStore with an enforced lifecycle: draft → planning → (awaiting_approval)? → executing → paused/blocked → completed/cancelled. Transitions are validated in code; invalid transitions throw.

  • Persistence via pi.appendEntry("goal-mode-state", <JSON snapshot>) — Pi session entries, branch-sensitive. On session_start / session_tree the extension restores the last state entry on the active branch. Snapshots are validated (src/validate.ts) before loading: corrupt state, dependency cycles, unknown deps, or a newer schema version are rejected safely and the run starts fresh with a warning instead of corrupting.

  • Schema is versioned (schemaVersion: 3); older versions migrate up, newer ones are refused. No secrets, env vars, or raw conversation are persisted.

  • Model context injection is per-run (before_agent_start) and deduplicated in context: the model always sees the current goal/plan snapshot, and stale snapshots from earlier turns are stripped.

Evidence-driven replanning — worked example

  1. Goal. /goal Ship the CSV export feature with criterion "tests + lint pass" (mandatory).
  2. Research. The agent records goal_evidence: kind=research, verdict=invalidates, assumptionId=a1 ("we assumed a CSV writer exists in the repo"). Assumption a1 flips to invalidated.
  3. Proposal. The agent proposes via goal_propose (trigger=research-invalidated-assumption): add a task t4 write minimal CSV serializer, cite evidence e1, keep completed unrelated tasks untouched. In hybrid mode a low/medium-impact revision auto-applies; a revision touching high-impact tasks queues for approval.
  4. User review. /goal-plan, then /goal-approve (or /goal-reject — the current plan stands, and the rejection is recorded in history).
  5. Implementation. Task executed; verification attempt fails a test → goal_task_update status=failed classification=transient reason="...". Retry is allowed under maxRetriesPerTask (default 3); repeated failures escalate instead of looping. classification=invalid-assumption never retries: it asks for a plan revision instead.
  6. Targeted replan. New proposal cites the failing-test evidence; completed-but-unaffected tasks stay completed. An upstream change to a completed task reopens only its transitive dependents (invalidateDownstream).
  7. Completion. goal_complete independently verifies: open tasks? Mandatory criteria without supporting evidence? Pending proposal? Only a clean state completes — completing the checklist is not enough.

Safeguards

  • No shell command runs just because a plan mentions it; normal Pi tools and permission hooks still gate every call.
  • Replans are bounded (maxReplans, default 12) and oscillation-guarded (recent proposal fingerprints cannot repeat).
  • Question flow uses supported dialogs at tool-call time (ctx.hasUI guarded) with a text fallback (goal_answer from chat). The extension never aborts an in-flight model request; checkpoints happen between tool calls, which is the boundary Pi supports.
  • Cancel/pause are pure state transitions — always consistent.

Tests

npm install
npm run typecheck   # tsc --noEmit
npm test            # 26 deterministic unit tests, no model required

Covered: topological planning, readiness derivation, downstream invalidation, approval boundaries per mode, mandatory-criteria/goal protection, oscillation and budget guards, bounded retries, persistence round-trips, corrupt/legacy schema rejection, cycle/unknown-dep rejection, lifecycle enforcement, and resume-from-persisted-state.

Known limitations

  • Question prompting happens at tool-call boundaries, not mid-stream (Pi extension API boundary; documented behavior, not a bug).
  • human mode relies on the user running /goal-approve//goal-reject; execution of unaffected tasks may continue meanwhile.
  • One goal run per session (by design; start a new session or /goal-cancel for a fresh goal).
  • AI question routing to web_search/research tools is the model's choice via prompt guidance; the extension records the answer source for auditability.