Manage the user's project registry. Each project lives at ~/.pal/memory/projects/{slug}/ISA.md. Frontmatter holds operational state (next steps, blockers, handoff); the body holds ISA spec sections (Problem, Goal, Criteria, Context, Decisions, etc.). The Stop hook auto-touches updated whenever the cwd resolves into a registered project — just being in the project keeps it warm.
CLI
All operations go through the canonical CLI:
pal cli project <command> [args]
Output is JSON.
| Command |
Purpose |
list |
All registered projects with status, path, updated, stale flag, and counts |
create [name] [--path PATH] [--objectives "a;b;c"] [--serves KIND] [--serves-note "..."] |
Register a project. Defaults: name=basename(cwd), path=cwd. Slug must be [a-z0-9_-]+. KIND is goal, revenue or fun |
serves <name> <goal|revenue|fun> [note] |
Set what the project is for, after the fact |
resume <name> |
Print the lean project view — frontmatter, body sections, and open-ISC titles (full ISC text via show-isc) |
add-next <name> "text" |
Append a next step (array, instantly appendable) |
add-blocker <name> "text" |
Append a blocker (array, instantly appendable) |
add-decision <name> "decision" "rationale" |
Log a timestamped decision entry to the Decisions section |
add-handoff <name> "text" |
Overwrite the handoff field (single-value, replaces) |
rm-next | rm-blocker <name> <index> |
Remove a next/blocker entry by zero-based index |
update-section <name> <section> "content" |
Set an ISA body section (problem, goal, criteria, vision, constraints, out_of_scope, context, decisions, changelog) |
criteria <name> |
Print the Criteria section (verifiable success conditions) |
set-path <name> <new-path> |
Update the registered path |
add-isc <name> "title" |
Append a new open ISC to Criteria |
list-isc <name> [--all | --closed | --retired] |
List open ISCs (default), or the archived/retired sets |
show-isc <name> <id> |
Print one ISC's full text |
edit-isc <name> <id> "new text" |
Rewrite an ISC's wording, keeping its id and state |
complete-isc | reopen-isc <name> <id> |
Archive a finished ISC, or pull one back into the open set |
retire-isc <name> <id> [--by <id>] |
Close an ISC that stopped being valid, not as done |
prune-isc <name> |
Sweep legacy done ISCs from Criteria into the Changelog archive |
scaffold-task-isa <title> / complete-task-isa <slug> |
Create and close a one-shot task ISA in memory/work/ |
isa-init <name> |
Mark a project as ISA-initialized |
complete <name> / archive <name> / pause <name> / unpause <name> |
Status transitions |
rm <name> |
Delete the project directory entirely |
ISA Sections
The body of each ISA.md holds spec sections. Use update-section to set them:
| Section |
Key |
What goes here |
| Problem |
problem |
Why this project exists; the pain or gap being addressed |
| Goal |
goal |
What success looks like (may be bullet list) |
| Criteria |
criteria |
Open ISCs (Ideal State Criteria) — testable done conditions. Holds only the open set; completing an ISC moves it to the Changelog |
| Vision |
vision |
Long-horizon aspiration beyond the immediate goal |
| Constraints |
constraints |
Non-negotiable limits (budget, time, tech, compatibility) |
| Out of Scope |
out_of_scope |
What this project explicitly does NOT cover |
| Context |
context |
Stable facts / references (e.g. "reference impl lives at ~/pai") |
| Decisions |
decisions |
Auto-managed by add-decision; dated bullet list |
| Changelog |
changelog |
Archive of completed ISCs (complete-isc moves them here under a dated ### Archived heading) plus any milestone notes |
ISC archive model. complete-isc does not just check a box — it moves the ISC line out of Criteria and into the Changelog archive, so Criteria always reflects exactly the open work and never bloats the context loaded at session start. list-isc <name> shows open ISCs by default; pass --closed (archived only) or --all (open + archived) to read finished ones. reopen-isc pulls an archived or retired ISC back into the open set. edit-isc <name> <id> "new text" rewrites an ISC's wording in place, keeping its id and state — use it to sharpen a vague criterion instead of closing and refiling. retire-isc <name> <id> [--by <id>] closes an ISC that stopped being valid: it files under a ### Retired heading as [~] rather than claiming the work was done, and --by records the superseding ISC. A retired ISC counts as neither open nor done, is listed with --retired, and keeps its id reserved so no future ISC can reuse it. prune-isc <name> backfills legacy projects by sweeping any done ISCs still sitting in Criteria into the archive in one pass.
Routing
| Intent |
Action |
| "what am I working on", "my projects", "priorities" |
list — summarize active and recently-touched projects |
| "tell me about " |
resume <name> — present current state, highlight blockers and next steps |
| "register this" / "track this" / cwd is unregistered work |
create (default the name from cwd basename, confirm before writing) |
| "store under : X" / "note on : X" |
Pick the field — durable reference → update-section <slug> context "...", work item → add-next, obstacle → add-blocker. If unclear, ask. |
| "we decided X because Y" |
add-decision <name> "X" "Y" |
| "handoff for " / "next session pick up at X" |
add-handoff <name> "<text>" |
| "set the goal for " / "describe the problem" |
update-section <name> goal "..." or update-section <name> problem "..." |
| "what are the criteria for " / "what counts as done" |
criteria <name> |
| "mark X complete" / "X is done" |
complete <name> |
| "park " / "pause " |
pause <name> |
| "archive " |
archive <name> |
Proactive registration
When SessionStart context flags the current cwd as unregistered (e.g. 💡 cwd <path> is not yet registered; suggest registering if substantive work begins) and the user starts substantive work (not just "hi"), surface the suggestion conversationally before the second tool call:
"I see we're in <basename> and it's not registered yet — want me to add it as a project?"
- Default name = the FULL last path segment of cwd, lowercased. For
/repos/portable-agent-layer → portable-agent-layer. Never split on -.
- Confirm before creating. Never auto-create without explicit user approval ("yes", "do it", "register").
- Capture context in conversation. If the user accepts but doesn't volunteer a goal, ask one short question, or infer from the last few messages and confirm.
- Ask what it serves. One question, at registration: is this moving a stated goal forward, a way the work could pay, or kept for its own sake? Pass the answer as
--serves goal|revenue|fun with a six-word --serves-note. It is the only thing that ranks the project against the others, and PAL will guess it later if you skip it — a guess the user then has to correct.
When NOT to suggest registration
- cwd has no project marker (
.git, package.json, pyproject.toml, Cargo.toml, go.mod, etc.) — it's a notes folder, not a project.
- The user is clearly browsing or doing a one-off task.
- An ancestor of multiple registered projects is the cwd (e.g. a generic dev root) — that's browse mode by design.
- You're unsure. Err toward not registering.
Append-as-you-go
When the user describes next steps, blockers, or decisions during normal work, invoke the relevant subcommand to keep state current — that's the dynamism this system is built for. Don't invoke for fleeting comments, hypotheticals, or things the user is just thinking through. Wait for a clear declarative ("let's add X", "Z is blocking us"), not a question or musing.
Examples
Storing a reference under an existing project
User: "store under <project> that a reference implementation exists in this repo"
→ Identify the project from `list` (or by name)
→ Durable reference, not a task → update-section
→ pal cli project update-section <slug> context "Reference implementation lives in this repo"
Registering the current repo
User: "track this project"
→ Default name from cwd basename, confirm with user
→ Ask what it serves: a goal, a way it could pay, or fun
→ pal cli project create --path "$(pwd)" --objectives "first objective; second objective" --serves revenue --serves-note "could be sold as a service"
Correcting what a project is for
User: "<project> isn't a toy, it's the thing I'd actually sell"
→ pal cli project serves <slug> revenue "the one I would sell"
Logging a decision
User: "we decided <decision> because <reason>"
→ pal cli project add-decision <slug> "<decision>" "<reason>"
Setting the goal and criteria
User: "set the goal for pal to 'ship ISA support with full test coverage'"
→ pal cli project update-section pal goal "ship ISA support with full test coverage"
Completing a project
User: "mark <project> as complete"
→ Confirm
→ pal cli project complete <slug>
Anti-patterns
- Don't dump the full ISA.md. Summarize. The user can ask for the raw payload.
- Don't write without confirming the field choice on ambiguous "store" requests. A context fact sticks forever; a next step implies follow-up — these are different commitments.
- Don't edit ISA.md files directly. Always use the CLI — it timestamps
updated and keeps the schema valid.
Rules
- Always check
list (or resume <name>) before writing — match an existing project rather than spawning a near-duplicate.
- Slugs are
[a-z0-9_-]+. Never rename a slug; if the display name needs to change, that's a code-side concern, not a slug change.
- The Stop hook handles
updated automatically when cwd matches path — no manual touch needed just to mark a project alive.
- Always announce a new ISC with the 🎟️ emoji — every single time, no exceptions. Whenever you open an ISC (
add-isc), report it back to the user on its own line prefixed with the ticket emoji and the ISC number, e.g. 🎟️ ISC #71 — <title>. This holds in every response mode and context (ALGORITHM, NATIVE, or a bare reply); opening an ISC without the 🎟️ marker is a defect.
1---2name: projects3description: Project context management. PROACTIVE — use when the user references a project (by name or as "this repo", "current work"), asks to add/update/complete a project, says "store under a named project", "track this", "what am I working on", "my projects", "my priorities". Also triggered by ISC/ISA terminology — ISC stands for Ideal State Criteria, a project's verifiable done-conditions stored as `ISC-N:` lines in the Criteria section of its ISA.md spec. Phrases like "ISC", "open/opening the ISC", "open ISCs" (unfinished criteria), "create/creating a ticket for a project", "new ticket", or "project ticket" all map here: use `list-isc` to read them, `add-isc` to create one, `complete-isc`/`reopen-isc` to change status.4license: MIT5---67Manage the user's project registry. Each project lives at `~/.pal/memory/projects/{slug}/ISA.md`. Frontmatter holds operational state (next steps, blockers, handoff); the body holds ISA spec sections (Problem, Goal, Criteria, Context, Decisions, etc.). The Stop hook auto-touches `updated` whenever the cwd resolves into a registered project — just *being* in the project keeps it warm.89## CLI1011All operations go through the canonical CLI:1213```bash14pal cli project <command> [args]15```1617Output is JSON.1819| Command | Purpose |20|---------|---------|21| `list` | All registered projects with status, path, updated, stale flag, and counts |22| `create [name] [--path PATH] [--objectives "a;b;c"] [--serves KIND] [--serves-note "..."]` | Register a project. Defaults: name=basename(cwd), path=cwd. Slug must be `[a-z0-9_-]+`. KIND is `goal`, `revenue` or `fun` |23| `serves <name> <goal\|revenue\|fun> [note]` | Set what the project is for, after the fact |24| `resume <name>` | Print the lean project view — frontmatter, body sections, and open-ISC titles (full ISC text via `show-isc`) |25| `add-next <name> "text"` | Append a next step (array, instantly appendable) |26| `add-blocker <name> "text"` | Append a blocker (array, instantly appendable) |27| `add-decision <name> "decision" "rationale"` | Log a timestamped decision entry to the Decisions section |28| `add-handoff <name> "text"` | Overwrite the handoff field (single-value, replaces) |29| `rm-next \| rm-blocker <name> <index>` | Remove a next/blocker entry by zero-based index |30| `update-section <name> <section> "content"` | Set an ISA body section (problem, goal, criteria, vision, constraints, out_of_scope, context, decisions, changelog) |31| `criteria <name>` | Print the Criteria section (verifiable success conditions) |32| `set-path <name> <new-path>` | Update the registered path |33| `add-isc <name> "title"` | Append a new open ISC to Criteria |34| `list-isc <name> [--all \| --closed \| --retired]` | List open ISCs (default), or the archived/retired sets |35| `show-isc <name> <id>` | Print one ISC's full text |36| `edit-isc <name> <id> "new text"` | Rewrite an ISC's wording, keeping its id and state |37| `complete-isc \| reopen-isc <name> <id>` | Archive a finished ISC, or pull one back into the open set |38| `retire-isc <name> <id> [--by <id>]` | Close an ISC that stopped being valid, not as done |39| `prune-isc <name>` | Sweep legacy done ISCs from Criteria into the Changelog archive |40| `scaffold-task-isa <title>` / `complete-task-isa <slug>` | Create and close a one-shot task ISA in `memory/work/` |41| `isa-init <name>` | Mark a project as ISA-initialized |42| `complete <name>` / `archive <name>` / `pause <name>` / `unpause <name>` | Status transitions |43| `rm <name>` | Delete the project directory entirely |4445## ISA Sections4647The body of each ISA.md holds spec sections. Use `update-section` to set them:4849| Section | Key | What goes here |50|---------|-----|---------------|51| Problem | `problem` | Why this project exists; the pain or gap being addressed |52| Goal | `goal` | What success looks like (may be bullet list) |53| Criteria | `criteria` | Open ISCs (Ideal State Criteria) — testable done conditions. Holds only the open set; completing an ISC moves it to the Changelog |54| Vision | `vision` | Long-horizon aspiration beyond the immediate goal |55| Constraints | `constraints` | Non-negotiable limits (budget, time, tech, compatibility) |56| Out of Scope | `out_of_scope` | What this project explicitly does NOT cover |57| Context | `context` | Stable facts / references (e.g. "reference impl lives at ~/pai") |58| Decisions | `decisions` | Auto-managed by `add-decision`; dated bullet list |59| Changelog | `changelog` | Archive of completed ISCs (`complete-isc` moves them here under a dated `### Archived` heading) plus any milestone notes |6061**ISC archive model.** `complete-isc` does not just check a box — it moves the ISC line out of Criteria and into the Changelog archive, so Criteria always reflects exactly the open work and never bloats the context loaded at session start. `list-isc <name>` shows open ISCs by default; pass `--closed` (archived only) or `--all` (open + archived) to read finished ones. `reopen-isc` pulls an archived or retired ISC back into the open set. `edit-isc <name> <id> "new text"` rewrites an ISC's wording in place, keeping its id and state — use it to sharpen a vague criterion instead of closing and refiling. `retire-isc <name> <id> [--by <id>]` closes an ISC that stopped being valid: it files under a `### Retired` heading as `[~]` rather than claiming the work was done, and `--by` records the superseding ISC. A retired ISC counts as neither open nor done, is listed with `--retired`, and keeps its id reserved so no future ISC can reuse it. `prune-isc <name>` backfills legacy projects by sweeping any done ISCs still sitting in Criteria into the archive in one pass.6263## Routing6465| Intent | Action |66|--------|--------|67| "what am I working on", "my projects", "priorities" | `list` — summarize active and recently-touched projects |68| "tell me about <project>" | `resume <name>` — present current state, highlight blockers and next steps |69| "register this" / "track this" / cwd is unregistered work | `create` (default the name from cwd basename, confirm before writing) |70| "store under <project>: X" / "note on <project>: X" | Pick the field — durable reference → `update-section <slug> context "..."`, work item → `add-next`, obstacle → `add-blocker`. If unclear, ask. |71| "we decided X because Y" | `add-decision <name> "X" "Y"` |72| "handoff for <project>" / "next session pick up at X" | `add-handoff <name> "<text>"` |73| "set the goal for <project>" / "describe the problem" | `update-section <name> goal "..."` or `update-section <name> problem "..."` |74| "what are the criteria for <project>" / "what counts as done" | `criteria <name>` |75| "mark X complete" / "X is done" | `complete <name>` |76| "park <project>" / "pause <project>" | `pause <name>` |77| "archive <project>" | `archive <name>` |7879## Proactive registration8081When SessionStart context flags the current cwd as unregistered (e.g. `💡 cwd <path> is not yet registered; suggest registering if substantive work begins`) **and** the user starts substantive work (not just "hi"), surface the suggestion conversationally before the second tool call:8283> "I see we're in `<basename>` and it's not registered yet — want me to add it as a project?"8485- **Default name** = the FULL last path segment of cwd, lowercased. For `/repos/portable-agent-layer` → `portable-agent-layer`. Never split on `-`.86- **Confirm before creating.** Never auto-create without explicit user approval ("yes", "do it", "register").87- **Capture context in conversation.** If the user accepts but doesn't volunteer a goal, ask one short question, or infer from the last few messages and confirm.88- **Ask what it serves.** One question, at registration: is this moving a stated goal forward, a way the work could pay, or kept for its own sake? Pass the answer as `--serves goal|revenue|fun` with a six-word `--serves-note`. It is the only thing that ranks the project against the others, and PAL will guess it later if you skip it — a guess the user then has to correct.8990### When NOT to suggest registration9192- cwd has no project marker (`.git`, `package.json`, `pyproject.toml`, `Cargo.toml`, `go.mod`, etc.) — it's a notes folder, not a project.93- The user is clearly browsing or doing a one-off task.94- An ancestor of multiple registered projects is the cwd (e.g. a generic dev root) — that's browse mode by design.95- You're unsure. Err toward not registering.9697## Append-as-you-go9899When the user describes next steps, blockers, or decisions during normal work, invoke the relevant subcommand to keep state current — that's the dynamism this system is built for. Don't invoke for fleeting comments, hypotheticals, or things the user is just thinking through. Wait for a clear declarative ("let's add X", "Z is blocking us"), not a question or musing.100101## Examples102103**Storing a reference under an existing project**104```105User: "store under <project> that a reference implementation exists in this repo"106→ Identify the project from `list` (or by name)107→ Durable reference, not a task → update-section108→ pal cli project update-section <slug> context "Reference implementation lives in this repo"109```110111**Registering the current repo**112```113User: "track this project"114→ Default name from cwd basename, confirm with user115→ Ask what it serves: a goal, a way it could pay, or fun116→ pal cli project create --path "$(pwd)" --objectives "first objective; second objective" --serves revenue --serves-note "could be sold as a service"117```118119**Correcting what a project is for**120```121User: "<project> isn't a toy, it's the thing I'd actually sell"122→ pal cli project serves <slug> revenue "the one I would sell"123```124125**Logging a decision**126```127User: "we decided <decision> because <reason>"128→ pal cli project add-decision <slug> "<decision>" "<reason>"129```130131**Setting the goal and criteria**132```133User: "set the goal for pal to 'ship ISA support with full test coverage'"134→ pal cli project update-section pal goal "ship ISA support with full test coverage"135```136137**Completing a project**138```139User: "mark <project> as complete"140→ Confirm141→ pal cli project complete <slug>142```143144## Anti-patterns145146- **Don't dump the full ISA.md.** Summarize. The user can ask for the raw payload.147- **Don't write without confirming the field choice on ambiguous "store" requests.** A context fact sticks forever; a next step implies follow-up — these are different commitments.148- **Don't edit ISA.md files directly.** Always use the CLI — it timestamps `updated` and keeps the schema valid.149150## Rules151152- Always check `list` (or `resume <name>`) before writing — match an existing project rather than spawning a near-duplicate.153- Slugs are `[a-z0-9_-]+`. Never rename a slug; if the display name needs to change, that's a code-side concern, not a slug change.154- The Stop hook handles `updated` automatically when cwd matches `path` — no manual touch needed just to mark a project alive.155- **Always announce a new ISC with the 🎟️ emoji — every single time, no exceptions.** Whenever you open an ISC (`add-isc`), report it back to the user on its own line prefixed with the ticket emoji and the ISC number, e.g. `🎟️ ISC #71 — <title>`. This holds in every response mode and context (ALGORITHM, NATIVE, or a bare reply); opening an ISC without the 🎟️ marker is a defect.