Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Please choose versions by [Semantic Versioning](http://semver.org/).

## Unreleased

- feat: Add `GoalApproveOperation` and `TopicApproveOperation`, which move a `phase: todo` row to `phase: planning` and record `approved_by` / `approved_at` in one write; a row outside the approval inbox, or one already carrying an approval record, is refused with nothing written.
- feat: Add `vault-cli goal approve` and `vault-cli topic approve`, the CLI surface over those operations (`--by` defaults to `operator`, an empty `--by` is refused, and a refusal exits non-zero in both plain and `--output json` modes). `goal set … phase planning` and `topic set … phase planning` on a `todo` row are now refused and point at the approve verb.
- fix: `scripts/session-self-exit.py` lets a session that was handed off from a task exit. When `claude_session_id` has moved to another session, the task is resolved through its `metrics_sessions` instead, and that branch skips the terminal check — its own work is already on the record. The pane-ownership and open-card guards still refuse.

## v0.175.0
Expand Down
4 changes: 2 additions & 2 deletions commands/execute-topic.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ vault-cli topic get "<name>" phase --output json

Refuse and STOP if any apply:

- `status: completed` OR `status: aborted` → `❌ Topic closed (status: <value>). Reopen: vault-cli topic set "<name>" status in_progress; vault-cli topic set "<name>" phase planning — there is no reopen subcommand.`
- `status: completed` OR `status: aborted` → `❌ Topic closed (status: <value>). Reopen: vault-cli topic set "<name>" status in_progress; vault-cli topic set "<name>" phase planning — there is no reopen subcommand.` (the phase set is legal here because the topic is not in the inbox)
- `phase: done` → `❌ Topic phase is done. Reopen with the same two commands as above.`
- `phase: todo` OR `phase` empty AND `status: in_progress` → `❌ Topic has no plan yet (phase: todo). Set it with vault-cli topic set "<name>" phase planning once the topic passes /verify-topic.` (planning is non-skippable)
- `phase: todo` OR `phase` empty AND `status: in_progress` → `❌ Topic has no plan yet (phase: todo). Approve it with vault-cli topic approve "<name>" once the topic passes /verify-topic.` (planning is non-skippable; a topic with no `phase` key is exempt from the gate, so set `phase: todo` first with `vault-cli topic set "<name>" phase todo`)

### 4. Status entry contract (mutate, then continue)

Expand Down
8 changes: 6 additions & 2 deletions commands/plan-goal.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,12 @@ vault-cli goal get "<name>" phase --output json

The goal is to land at `status: in_progress, phase: planning` for fresh goals; respect a deliberate post-planning phase setting.

- `status` in `next`/`todo`/`backlog` → flip status AND phase together: `vault-cli goal set "<name>" status in_progress` + `vault-cli goal set "<name>" phase planning` (if phase is empty/`todo`/`planning`). Skip the phase flip if phase is `execution` / `done` (treat as deliberate — sharpen but don't move phase backward).
- `status` already `in_progress` and `phase` is `todo`/empty → `vault-cli goal set "<name>" phase planning`
- `status` in `next`/`todo`/`backlog` → `vault-cli goal set "<name>" status in_progress`, then the phase entry:
- `phase: todo` → `vault-cli goal approve "<name>"` — the approval records `approved_by` and `approved_at` and flips to `planning` in one write; `vault-cli goal set "<name>" phase planning` is refused on a `todo` row.
- `phase` empty → `vault-cli goal set "<name>" phase todo`, then `vault-cli goal approve "<name>"` — a goal with no phase is exempt from the gate and cannot be approved until it is in the inbox.
- `phase: planning` → no flip.
- `phase` is `execution` / `done` → skip the flip (treat as deliberate — sharpen but don't move phase backward).
- `status` already `in_progress` and `phase` is `todo` → `vault-cli goal approve "<name>"`; `phase` empty → `vault-cli goal set "<name>" phase todo`, then `vault-cli goal approve "<name>"`.
- `status` already `in_progress` and `phase` is past planning → continue without flip; step 7 will skip the phase transition.

### 4. Run goal-auditor
Expand Down
6 changes: 6 additions & 0 deletions docs/goal-writing.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ manager_session_id: <session id> # optional — written by claud

`status` valid values: `next`, `in_progress`, `backlog`, `hold`, `completed`, `aborted`. `todo` is accepted as a legacy alias for `next` on read; do not write it.

### Phase and approval

`phase` walks `todo → planning → execution → done`, and `todo` is the operator's approval inbox — the same phase lifecycle tasks carry. `vault-cli goal approve "<name>"` performs the `todo → planning` transition and records `approved_by` (default `operator`; `--by <name>` names another) and `approved_at` in the same write. `vault-cli goal set "<name>" phase planning` is refused on a `todo` goal, and the refusal points at `goal approve`: a phase set without an approval record is not an approval. This is the same contract as `task approve`, stated in full in `task-writing.md` § Phase transitions.

A goal with no `phase` key is exempt from the gate and cannot be approved; set `phase: todo` first. A goal that already carries `approved_by` or `approved_at` is refused rather than re-approved, and the refusal writes nothing.

### Dependencies (`blocked_by`)

`blocked_by` declares the goals this goal cannot start before. It is a YAML list of goal names; each entry may be a plain name (`Blocker Goal`) or a wikilink (`[[Blocker Goal]]`) — both forms resolve the same way. A scalar value (`blocked_by: Blocker Goal`) is malformed and reads as an empty list, so it never blocks. `vault-cli goal lint` reports a goal whose `blocked_by` is shaped this way; `vault-cli task validate` and `vault-cli task lint` report the task-side equivalent.
Expand Down
Loading
Loading