feat(phased-execution): harness commits each completed phase atomically
Children never commit (their prompts forbid git add/commit, overriding project instructions) so the commit is deterministic. At the phase commit point (00_phase.md final pass) the harness makes ONE atomic commit: the phase's code changes, the todo→complete file move, and the executor reports, together. - Scoped staging: a worktree snapshot taken at the phase's first unit (phase-sessions/dirty-<phase>, always kept) is subtracted, so the owner's pre-existing uncommitted work is left alone; runtime artifacts are never staged. The commit prints exactly what went in. - Verified: the moved phase file (and report, unless gitignored) must be in the index before committing. - Loud on failure: a commit failure prints the git error + hand-fix and stops the run; the phase stays complete, the miss is never swept into a later phase. - PHASE_COMMIT_SUBJECT (default 'phase: <phase>'); the executor's final report becomes the commit body; --no-gpg-sign always passed. - PHASE_COMMIT defaults to 1: completed phases are committed by default. Explicit PHASE_COMMIT=0 opts out with a loud warning that the phase is complete but uncommitted — a completed phase is never left uncommitted silently (that gap let four phases pile up uncommitted in brain_of_reese).
This commit is contained in:
@@ -20,7 +20,8 @@ process** (fresh context) with bounded fixer retries. A task only moves to
|
||||
final report, **and** `.agents/validate.sh` passes. When all of a phase's tasks
|
||||
are done, `00_phase.md` runs as the phase's **final pass** (remaining inline
|
||||
work + completion criteria + phase-level verification); moving it completes
|
||||
the phase and is the `PHASE_COMMIT` commit point. This chat only dispatches
|
||||
the phase and is the `PHASE_COMMIT` commit point (one atomic commit: code +
|
||||
phase files + reports — children never commit; see Commits below). This chat only dispatches
|
||||
and relays results — do not implement task code yourself; that is what the
|
||||
subprocesses are for.
|
||||
|
||||
@@ -77,6 +78,34 @@ the user at `.agents/reports/<phase>/<task>.a*.{md,err,validate}` (legacy
|
||||
phases: `.agents/reports/<phase>.a*.*`) — the script also prints a ready to run
|
||||
`pi --session … -c “…”` command to continue the failed session manually.
|
||||
|
||||
## Commits
|
||||
|
||||
Children never commit — their prompts forbid `git add`/`git commit`
|
||||
(overriding any project “commit per phase” instruction), which is what keeps
|
||||
the commit deterministic instead of intermittent. By default
|
||||
(`PHASE_COMMIT=1`) the harness makes **ONE atomic commit per completed
|
||||
phase** at its commit point: the phase's code changes, the
|
||||
`todo/`→`complete/` file move, and the executor reports, together.
|
||||
`PHASE_COMMIT=0` opts out — the phase is then left uncommitted with a loud
|
||||
warning, never silently.
|
||||
|
||||
- **Scoped staging**: a snapshot of the worktree taken at the phase's first
|
||||
unit (`.agents/phase-sessions/dirty-<phase>`, gitignored runtime storage)
|
||||
is subtracted, so the owner's pre-existing uncommitted work is left alone;
|
||||
pipeline runtime artifacts (`phase-sessions/`, `pipeline.log`) are never
|
||||
staged. The commit output prints exactly what went in.
|
||||
- **Verified**: the moved phase file (and the executor report, unless the
|
||||
project gitignores reports) is checked against the index *before*
|
||||
committing — the artifacts that used to go missing silently.
|
||||
- **Loud on failure**: a commit failure prints a `✗ ERROR:` block with the
|
||||
git error and the exact hand-fix command, and **stops the run**. The phase
|
||||
stays complete (the work passed validation) — re-running will not
|
||||
re-execute it, and a later phase's commit will not sweep the miss in: fix
|
||||
the commit first, then re-run.
|
||||
- Subject: `PHASE_COMMIT_SUBJECT` (default `phase: {{PHASE}}`); the
|
||||
executor's final report becomes the commit body. `--no-gpg-sign` is always
|
||||
passed.
|
||||
|
||||
## Configuration (environment variables)
|
||||
|
||||
| Var | Default | Meaning |
|
||||
@@ -84,7 +113,8 @@ phases: `.agents/reports/<phase>.a*.*`) — the script also prints a ready to ru
|
||||
| `MAX_FIX_ATTEMPTS` | `3` | Fixer retries per phase |
|
||||
| `PHASE_MODEL` | session default | `--model` for child executors (e.g. `anthropic/claude-sonnet-4-5`) |
|
||||
| `PHASE_THINKING` | session default | `--thinking` level for child executors |
|
||||
| `PHASE_COMMIT` | `0` | `1` = `git commit --no-gpg-sign` after each completed **phase** (when its `00_phase.md` final pass passes; legacy: when its file moves) |
|
||||
| `PHASE_COMMIT` | `1` | `1` (default) = the harness commits each completed **phase** as one atomic commit (code changes + the file move + executor reports) when its `00_phase.md` final pass passes (legacy: when its file moves). `0` = opt out: the phase is left uncommitted with a loud warning. See Commits above |
|
||||
| `PHASE_COMMIT_SUBJECT` | `phase: {{PHASE}}` | Commit subject template for `PHASE_COMMIT=1` (`{{PHASE}}` = the phase directory name); the executor's final report becomes the commit body |
|
||||
| `PI_TRUST` | `0` | `1` = pass `--approve` (load project `.pi/` settings/skills into children) |
|
||||
| `FRESH_FIX` | `0` | `1` = fixer retries start fresh instead of resuming the failed session |
|
||||
| `QUIET` | `0` | `1` = suppress live progress display (reports are still written) |
|
||||
@@ -104,6 +134,7 @@ phases: `.agents/reports/<phase>.a*.*`) — the script also prints a ready to ru
|
||||
- Child executor sessions are kept in `.agents/phase-sessions/` (plus
|
||||
`pipeline.log` in `.agents/`); if the project is versioned, git-ignore those
|
||||
runtime artifacts only — `.agents/` itself is tracked and committed.
|
||||
(The per-phase worktree snapshot `dirty-<phase>` is always kept there too.)
|
||||
- If you keep non-skill markdown (e.g. a `README.md`) in a skills directory
|
||||
(like `~/.pi/agent/skills/`), pi warns “description is required” for it.
|
||||
Add a `.gitignore` in that directory listing the file — pi's skill scanner
|
||||
|
||||
Reference in New Issue
Block a user