pi-goals-extension

Standalone Pi extension for parent-owned goal/TODO work graphs with delegated claims, CAS receipts, and oracle-gated completion. Zero runtime dependencies.

Packages

Package details

extensionskill

Install pi-goals-extension from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:pi-goals-extension
Package
pi-goals-extension
Version
0.1.0
Published
Aug 15, 2026
Downloads
127/mo · 11/wk
Author
cgarrot
License
MIT
Types
extension, skill
Size
1,022.7 KB
Dependencies
0 dependencies · 0 peers
Pi manifest JSON
{
  "extensions": [
    "./index.ts"
  ],
  "skills": [
    "./skills"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-goals

Standalone Pi extension for parent-owned goal/TODO work graphs: one active runtime goal, a sub-TODO tree under it, delegated lanes that return claims, CAS-guarded mutations with replay receipts, and oracle-gated completion. Extracted from zob-harness following the pi-mesh pattern — one concern, one package, zero runtime dependencies, usable à la carte in any Pi install. The full goal lifecycle lives here without assuming the rest of the harness: no delegation runtime, no coms, no factory — just the goal engine, its store, and a thin Pi adapter.

              ┌──────────────────────────────────────────────────┐
              │  GoalRuntimeEngine (src/runtime)                 │
              │  create/pause/resume · todos · delegation/claims │
              │  propose → oracle → complete (gates)             │
              └───────────────▲──────────────────────────────────┘
                              │ same engine calls (no separate logic)
     ┌────────────────────────┴───────────────┐   ┌────────────────┐
     │ Pi extension (src/extension)           │   │ CLI (src/cli)  │
     │ 19 tools + /goal /todo + HUD           │   │ status/tree/   │
     │ session mirror (body-free)             │   │ list/stats/    │
     └────────────────────────▲───────────────┘   │ export         │
                              │                   └───────▲────────┘
   model loop (tools, CAS params)                           │ read-only
              ┌───────────────▼─────────────────────────────┴────────┐
              │  store (src/store): <cwd>/.goals                    │
              │  goals/<id>/{goal,todos,claims}.log.jsonl (streams) │
              │  goals/<id>/runtime-goal.json (overlay)             │
              │  cas-receipts.jsonl · snapshot+marker · quarantine/ │
              └─────────────────────────────────────────────────────┘

Install / use

As a Pi package (auto-loads the extension, tools, commands, and skill):

pi install npm:pi-goals-extension
# or pinned to a release tag
pi install git:github.com/cgarrot/pi-goals@v0.1.0

From source:

git clone git@github.com:cgarrot/pi-goals.git
cd pi-goals && npm install
npm run build        # tsc → dist/ (needed for CLI + tests + smoke)

State lives under <cwd>/.goals (override with GOALS_STATE_DIR, or pass --state-dir to the CLI). Try the headless end-to-end demo:

npm run smoke        # lifecycle + delegation claim + crash quarantine, exit 0
npm run cli -- status --state-dir /tmp/some-store

Tools (19)

tool purpose
create_goal create the single active runtime goal
resume_goal resume paused/blocked/oracle_failed/budget_limited with a reason
get_goal status block: objective, TODO summary, usage, oracle, next action
get_goal_todos TODO tree with icons ○ ● ✓ ⊘ ⤫ and progress (bare call = full tree; optional todo_id/todo_path ref narrows)
add_goal_todo add ONE todo
add_goal_todos atomic batch (single persisted snapshot)
update_goal_todo patch metadata only — a status param is explicitly rejected (use resolve_goal_todo)
resolve_goal_todo primary transition API: auto/complete/accept_claim/reject_claim/block/skip/reopen
complete_goal_todo complete (or skip with reason)
block_goal_todo mark blocked with a reason — available from EVERY non-terminal status (claim-returning states included when no claim is bound)
split_goal_todo split into required child subtodos (one atomic batch)
link_goal_todo_delegation launch a delegation attempt (policy frozen at launch, node → delegated)
return_goal_todo_claim child returns a claim (claim_text or exact claim_hash; stored hash-only)
validate_goal_todo_claim record oracle validation of a returned claim (strict-PASS composition; optional agent/run_id provenance persisted; blocking issues stored hash-only)
accept_goal_todo_claim parent accepts a returned claim (exact binding echo; oracle_required claims additionally require a recorded strict-PASS validation)
reject_goal_todo_claim parent rejects a returned claim with a reason
propose_goal_completion goal → ready_for_oracle (blocked while required todos are open; an empty tree lists an explicit "todo tree is empty" blocker)
record_goal_oracle bind the immutable oracle decision (PASS/no_ship=false to ship)
update_goal complete the goal — only after a bound strict-PASS decision

cas is OPTIONAL on every mutation (zob parity): absent revision slots are simply unchecked, and a call without cas applies under a fresh auto-generated mutation id. Pass cas.mutation_id (revisions optional) for idempotent mutations: exact replay is a no-op replayed result, a stale PROVIDED revision fails cas_stale with the current-revision hint, and every applied mutation lands a hash-chained receipt in cas-receipts.jsonl.

Commands

/goal                    status (objective/usage/oracle/next)
/goal <objective>        create the runtime goal
/goal pause <reason>     pause the active goal (loop off)
/goal resume <reason>    resume a paused/blocked/oracle_failed goal
/goal clear              clear the current goal view (streams stay append-only)
/goal mode [manual|validation|auto]
/todo                    render the TODO tree
/todo add <title>        add one TODO

Read-only CLI (built outputs, no Pi needed). The package exposes a goals bin (shebang entry, npx/global-install friendly):

npm exec -- goals [--state-dir <dir>] status|tree|list|stats|export [goalId]
# or directly:
node dist/src/cli/goals.js [--state-dir <dir>] status|tree|list|stats|export [goalId]

A corrupt store answers honestly: restore-blocked diagnostics on stderr and exit 1 (fail-closed, never a partial view).

export dumps deterministic JSON (goal + todos + claims + receipts); a restore-blocked store prints diagnostics and exits 1 — fail-closed.

Uniform CLI exit codes (batch-#2 fix):

code meaning
0 ok — list/stats/export still print a stderr warning (warning: N quarantined stream(s) — goals may be incomplete) when quarantine/ is non-empty
1 store blocked or unavailable — restore-blocked diagnostics, missing store/goal
2 usage error — unknown command/flag or bad arguments, usage hint on stderr

Store layout

.goals/
  cas-receipts.jsonl            global CAS receipts (replay + audit)
  goals/<goalId>/
    goal.log.jsonl              goal lineage: goal_set / goal_clear events (revision 1..N)
    todos.log.jsonl             todos_snapshot / todo_updated events
    claims.log.jsonl            delegation attempts, claims, validations, settlements
    runtime-goal.json           engine overlay (usage, loop, proposal, oracle decision)
    snapshot.json + marker      compaction baseline (optional)
  quarantine/<goalId>/          torn/corrupt streams moved here with a diagnostic json

Restore is fail-closed: revision gaps/conflicts, malformed lines, unknown schemas, and truncated tails (crash simulation) quarantine the offending stream and block mutations — never a partial replay.

Parity with zob-harness

Semantics are distilled from the zob-harness goal/TODO runtime with deliberate reworks ("en mieux"). The invariant-by-invariant mapping and the full deviations table live in docs/PARITY.md. Summary of deviations: tightened reopen gate, empty-tree-not-shippable, strict-PASS auto-accept, precise tamper codes, 16-tool CAS core (import/handoff out of core), complete/clear/pause under update_goal, at-least-once receipt window, and the explicit pauseGoal engine mutation.

Development

npm run build     # tsc → dist/
npm test          # build + node:test over dist/test (304 tests)
npm run smoke     # headless E2E demo against a temp store
npm run cli -- list

Layering: src/core is pure (no fs/env/clock); src/store owns .goals I/O (append-only streams, lock, receipts); src/runtime composes them into the engine (stateless per mutation); src/extension is a thin Pi adapter; src/cli is a read-only view. Node ≥ 22, MIT.

Releases & publishing

  • Versioning follows semver from package.json (v0.1.0 = tag + npm version).
  • The Release GitHub Action publishes to npm automatically on v* tags (requires the NPM_TOKEN repository secret): npm version patch|minor|major && git push && git push --tags.
  • prepublishOnly runs the full build + test suite before every publish.
  • The package is published as pi-goals-extension on npmjs.org (publishConfig.access is public; the plain pi-goals name is taken on npm by another project) and is a Pi package (pi manifest + pi-package keyword), so pi install npm:pi-goals-extension works on any machine and the package appears in the pi.dev gallery automatically.

Status

v0.1.0 — Phase 1–6 complete: scaffold, core (tree/transition/completion/ claims/proposal/CAS), store (streams/restore/snapshot), runtime engine (+ pause), Pi extension (19 tools + commands + HUD), CLI, smoke, skill, parity matrix. No commit/tag/publish until the tree review approves.