# Portable Goals and Todos for Pi

This repository contains two independent Pi extensions:

- **`@fractaal/pi-goal-x`** — one branch-local Goal with confirmed proposal/tweak, autonomous continuation, pause/resume, abandonment, independent completion audit, final prose settlement, replay, a native widget, and structured events.
- **`@fractaal/pi-todo`** in [`packages/todo`](packages/todo) — one revisioned branch-local working plan with omission protection, dependency validation, context salience, replay, a native widget, and structured state.

They have no runtime dependency on each other and do not import Symphony, Aria, ALR, IPC, RTDB, Gateway, React, or product-specific types.

## Goal

Model tools:

- `propose_goal({ objective })`
- `tweak_goal({ objective })`
- `pause_goal({ reason, suggestedAction? })`
- `resume_goal()`
- `abandon_goal({ reason })`
- `complete_goal({ summary })`

Events:

- `pi-goal:state` — complete `GoalState` snapshot
- `pi-goal:proposal` — complete current proposal snapshot
- `pi-goal:transcript-event` — bounded lifecycle receipt
- `pi-goal:request-state` — asks the producer to replay current state and proposal

Goal state lives only in Pi session custom entries. It is replayed on session start, tree navigation, and compaction. Autonomous continuation appends the generic durable message `Continue the Goal.` after each normal settled run while the Goal remains active. At the start of each run, Goal adds one deterministic semantic block to Pi's system prompt; accounting revisions, timestamps, usage, and active-time changes do not alter those prompt bytes. Pi core owns provider retry and compaction recovery. The completion auditor receives an OS-sandboxed read-only shell when Bubblewrap is available; on platforms without that boundary, it receives only Pi's read/grep/find/ls tools.

## Todo

`get_todo()` reads the exact current revision and task list without mutation. The `todo` tool replaces the complete retained plan:

```ts
todo({
  baseRevision: 3,
  tasks: [
    { key: "implement", subject: "Implement the bridge", status: "in_progress" },
    { key: "verify", subject: "Verify it", status: "pending", dependsOn: ["implement"] }
  ],
  remove: []
})
```

An existing unfinished task cannot disappear unless `remove` names its key and gives a non-empty reason. Completed work may leave the current working plan. Stale revisions, normalized dependency collisions, invalid dependency graphs, and plans above the 16 KiB serialized UTF-8 budget leave state unchanged.

Todo contents are never floated into every provider request. Pi's stable system instructions tell the model when to use `get_todo`. When unfinished state becomes distant in context, after restoration, or after compaction, Todo queues one hidden durable checkpoint into an already-required provider call or the next external turn. Checkpoints never wake an idle model by themselves and stop when no unfinished work remains.

Events:

- `pi-todo:state` — complete `TodoState` snapshot
- `pi-todo:request-state` — asks the producer to replay current state

## Development

```bash
npm test
npm run check
npm run check:todo
npm run build
npm pack --dry-run
(cd packages/todo && npm pack --dry-run)
PI_ACCEPTANCE_BIN="$(command -v pi)" npm run test:installed
```

Installed-package acceptance builds and packs both tarballs, installs each alone under a temporary `PI_CODING_AGENT_DIR`, verifies real Pi package discovery/replay and deterministic lifecycle behavior, then removes the temporary profiles. It never touches the normal Personal Pi profile.

## Releases

Maintainers publish both packages from one verified `fractaal-vX.Y.Z` tag through npm trusted publishing. The Goal package version names the tag; Todo keeps its own stable version. The workflow checks the exact tag commit, runs the package checks and builds, and skips any package version already on npm so a retry safely resumes a partial release.

See [docs/releasing.md](docs/releasing.md) for the GitHub environment, npm trusted-publisher settings, first-release command, and recovery command.
