awslabs / awslabs/aidlc-workflows
[RFC]: Opt-in per-stage/phase auto-commit for git-native review and handoff
- Dominant language
- TypeScript
- Stars
- 4.7k
- Forks
- 853
- Avg merge
- 1d 21h
- Merged PRs (30d)
- 165
Description
### Summary
Add an opt-in mechanism that creates a git commit in the workspace after each
stage (and, optionally, each phase) completes, so a run's progress becomes a
browsable, bisectable git history — one commit per stage, its message carrying
the `/` slug and the audit event. Off by default; enabled with an
environment flag (e.g. `AIDLC_AUTOCOMMIT=stage`). The commit is triggered
deterministically at the point where the engine emits `STAGE_COMPLETED` /
`PHASE_COMPLETED`, not by any LLM-authored prose instruction. Its primary, repeatedly requested
driver is collaboration: with commits already in place, a run is immediately
`git push`-able and reviewable stage-by-stage through a normal pull request,
instead of arriving as one undifferentiated pile of working-tree changes.
### Motivation
The most frequently requested reason is **collaboration and handoff**. Teams
already coordinate through git — commit, push, review. Today an AI-DLC run lands
as one undifferentiated set of uncommitted working-tree changes; to share it or
get it reviewed, a user has to manually stage, split, and commit it by hand. If
the workflow committed per stage on its own branch, a run would be immediately
`git push`-able and reviewable **stage by stage** through a standard pull
request — a teammate could comment on the exact stage where something went
wrong, approve, or request changes, using the review tools they already use.
This is the collaboration story users have asked for repeatedly.
The same per-stage commits also help unattended and solo work, where the only
progress signals today are `audit.md` and the live state file and there is no
per-stage checkpoint you can `git show`:
- **Evals / experiments** measuring per-stage behavior (cost, artifacts, edits)
need a clean boundary per stage, not one blob at the end.
- **Debugging** a stage that went wrong: today you cannot isolate its diff.
- **Reviewing** an autonomous run after the fact: no stage-by-stage timeline.
- **Fork / resume** ideas (reuse a run's prefix up to the first changed stage)
want a natural per-stage checkpoint to fork from.
A commit-per-stage turns any run into a shareable, reviewable, inspectable
timeline essentially for free, and does so uniformly across harnesses.
### Detailed Proposal
Opt-in behavior gated by `AIDLC_AUTOCOMMIT` (unset/`0` = off — the default;
`stage` = commit per completed stage; `phase` = commit only at phase
boundaries). Off by default: the feature never touches a user's repository
without explicit opt-in.
- **Deterministic trigger.** All stage/phase completion events flow through a
single choke point — `emitAudit()` in `core/tools/aidlc-state.ts`, where
`STAGE_COMPLETED` / `PHASE_COMPLETED` / `WORKFLOW_COMPLETED` are emitted. The
auto-commit fires off that event so it cannot drift from the real transition
and does not depend on the model remembering to do anything. To keep git
side-effects out of the state tool, the proposed form is a dedicated
lifecycle hook fed by the completion event (mirroring the existing
`core/hooks/*` + per-harness manifest wiring).
- **What it commits.** `git add -A` in the workspace root, then a commit with a
structured message: subject `aidlc(/): ` plus trailers
(`Intent:`, `Space:`, `Scope:`, `Stage-slug:`) so `git log --oneline` reads as
the stage timeline and the trailers stay machine-parseable. A baseline commit
is made on the first transition so subsequent per-stage diffs are clean.
- **Branch per run, for handoff.** Commit onto a dedicated run branch (default
derived from the intent/space, e.g. `aidlc/`), so the whole workflow
is a self-contained branch the user can `git push -u` and open as a review PR
in one step. Pushing stays opt-in: an optional `AIDLC_AUTOCOMMIT_PUSH` can
push the branch after each commit for live remote review, but the default
never contacts a remote.
- **Safety / scope.** No-op unless the feature is enabled **and** the workspace
is a git repo. Uses a scoped identity via `-c user.name/-c user.email` so it
neither depends on nor mutates global git config. Never rebases, never
force-anything, and never pushes unless `AIDLC_AUTOCOMMIT_PUSH` is explicitly
set; a clean no-op when there is nothing to commit.
- **Harness-agnostic.** Because it keys off the audit event rather than a driver
detail, it behaves identically on Claude, Kiro, and Codex.
### Alternatives Considered
- **Ship it as a plugin.** Rejected: the plugin surface projects
`stages/sensors/tools/contributions/scopes/agents/knowledge` and has **no
lifecycle-hook surface**; plugins are additive-only and by contract never edit
core config (e.g. harness `settings.json`). The only plugin-shaped
approximations are a prose fragment spliced into every stage body (relies on
the LLM to actually run the commit — non-deterministic, and awkward to anchor
after a hard-stop gate) or a `Write|Edit` sensor (wrong granularity and wrong
semantics — sensors are advisory checks, not repo mutations). Deterministic
auto-commit therefore belongs in core, not a plugin.
- **LLM-prose instruction per stage.** Same non-determinism as above; a run can
silently skip commits.
- **External watcher** that polls `audit.md` and commits on each new completion.
Excellent for a single consumer like the eval harness (zero core changes), but
not reusable/shipped, and polling adds latency and races. Good as a
tool-local solution; not a framework capability.
- **Commit only at workflow end.** Loses the per-stage granularity that is the
entire point.
### Drawbacks
- Auto-committing into a user's repository is opinionated; it must be strictly
opt-in and clearly documented (hence env-gated and off by default).
- Adds git side-effects to the workflow run; requires care to be a true no-op
outside a git repo and to never touch remotes.
- Commit noise: a full run adds roughly one commit per in-scope stage (~30 for
`feature`). Mitigated by opt-in, by squash-on-merge already being the team
norm, and by the commits typically living on a run/worktree branch.
- It is an observability/checkpoint aid, not a reproducibility guarantee —
workflow non-determinism is unchanged.
### Additional Context
This surfaced both from users asking repeatedly for a git-native collaboration
loop (push a run, hand it to a teammate for stage-by-stage PR review) and from
building an eval harness that drives full `feature` runs and needs per-stage
inspection. The eval side can ship an external commit-watcher today, but the
capability is broadly and repeatedly requested — primarily for collaboration,
and secondarily for debugging, post-hoc review, and fork/resume checkpoints —
which is why it is proposed as an opt-in core feature rather than a local hack.
Implementation notes: the single trigger point is `emitAudit()` in
`core/tools/aidlc-state.ts`; hook wiring follows the existing `core/hooks/*`
plus per-harness manifest settings. A first PR would be intentionally focused:
env-gated hook, branch-per-run, message convention, and docs, single-repo
workspaces first. Automatic push is deferred to a follow-up behind its own flag
(`AIDLC_AUTOCOMMIT_PUSH`); the v1 primitive just makes each run a clean,
pushable branch a teammate can review as a PR.
Contributor guide
Research direction
Start with emitAudit() in core/tools/aidlc-state.ts, then read the existing core/hooks/* implementation and per-harness manifest wiring. Trace how STAGE_COMPLETED and PHASE_COMPLETED flow through the lifecycle before settling the hook boundary. The v1 is done when the env-gated, branch-per-run behavior is deterministic, off by default, safe outside Git repositories, and documented; automatic push is explicitly deferred.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- git, typescript
- Domain
- developer-experience, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100