| name | aiwf-edit-body |
| description | Use when the user wants to edit (rewrite or replace) the markdown body of an existing entity โ goal/scope/context prose, AC body sections inside a milestone, ADR rationale, gap problem statement, etc. Runs `aiwf edit-body` so the change rides through a verb route with proper trailers, instead of a plain `git commit` that triggers a `provenance-untrailered-entity-commit` warning. |
aiwf-edit-body
The aiwf edit-body verb replaces the markdown body of an existing entity in a single trailered commit, or reports that there was nothing to change. Frontmatter is left untouched โ that stays the domain of aiwf promote, aiwf rename, aiwf cancel, and aiwf reallocate.
When to use
The user wants to update an entity's body prose: flesh out goal/scope, rewrite an ADR's rationale, add detail under AC body sections (by editing the parent milestone), update a gap's problem statement, etc. Anything below the YAML frontmatter is fair game.
What to run
The verb has two modes. Bless mode is the default and matches the natural human workflow: edit the entity file in your editor, then commit through the verb route.
aiwf edit-body <id>
aiwf edit-body <id> --reason "<why>"
aiwf edit-body <id> --body-file <path>
aiwf edit-body <id> --body-file -
aiwf edit-body <id> --body-file <path> --reason "<why>"
Both modes refuse leading --- (frontmatter delimiter) in body content โ the verb is body-only, so a body file containing its own frontmatter would produce a malformed double-block file.
Gate symmetry โ prefer bless mode when a human is reviewing
A structured-state verb (aiwf promote / aiwf cancel / aiwf reallocate) mutates and commits in one step, so its approval gate sits on your stated intent โ there is no reviewable staged diff before the commit lands. A body edit doesn't have to work that way. In bless mode the edit lives in the working tree first: edit the file, let the human read the actual diff, then gate one aiwf edit-body <id> that commits exactly what they saw. That restores the edit โ review โ commit rhythm a plain file edit has for free.
Reach for --body-file only when the body content is produced outside the working copy โ an LLM session, a script, a pipeline โ where there is no on-disk diff to review first; there the gate necessarily sits on the supplied content. For an interactive edit a human is about to approve, bless mode is the better default.
Bless mode rules
- No diff: refuses with "no changes to commit" rather than producing an empty commit.
- Frontmatter changed: refuses and points at
aiwf promote / aiwf rename / aiwf cancel / aiwf reallocate. Both modes are body-only by design; structured-state edits go through their own verbs.
- New entity (no HEAD version): refuses with a pointer to
aiwf add --body-file for create-time body content.
- YAML formatting preserved: bless mode commits the working-copy bytes verbatim โ key order, comments, and whitespace from the user's edit are not re-canonicalized through the loader. (Explicit mode does re-serialize through
entity.Serialize, which canonicalizes.)
AC body sub-sections
Editing the prose under a single ### AC-N โ title heading inside a milestone body works through bless mode on the parent milestone โ edit the section in $EDITOR, run aiwf edit-body M-NNN. The verb commits whatever changed; no composite-id resolver needed. (Composite ids M-NNNN/AC-N are still refused to keep the verb's seam simple.)
What aiwf does
Bless mode (no --body-file):
- Loads the entity by id, reads the working-copy bytes and the HEAD version of the file.
- Refuses if there is no diff, the file has no HEAD version (new entity โ use
aiwf add instead), or the diff includes frontmatter changes.
- Validates the working-copy body content (refuses leading
---).
- Writes one OpWrite of the working-copy bytes verbatim and creates one commit with
aiwf-verb: edit-body, aiwf-entity: <id>, aiwf-actor: <actor>. --reason "..." lands in the commit body.
Explicit-content mode (--body-file <path> or stdin):
- Loads the entity by id, validates the supplied body content (refuses leading
---).
- Re-serializes the entity with its existing frontmatter unchanged and the new body in place.
- Reports "nothing to commit" at exit 0 when that serialized result already equals both the committed version and the file on disk โ there is no change to record, so no commit is made.
- Otherwise writes one OpWrite to the entity file and creates one commit with the same trailer set as bless mode โ
aiwf history cannot tell them apart, which is the right outcome.
The two modes answer a repeat differently, and the difference is deliberate. Explicit mode is handed a target, so it can check that target against reality and truthfully say it is already met. Bless mode is handed no target โ its input is the working copy โ so it cannot tell "I meant to change nothing" from "my editor never saved"; refusing is the only honest answer there.
Structured-state edits go through aiwf promote / aiwf rename / aiwf cancel / aiwf reallocate. Both modes enforce that: each refuses when the working copy's frontmatter differs from the committed one, so a hand-edited field cannot ride into a body-edit commit by either route.
When another verb refuses instead
A structured-state verb (aiwf promote / rename / retitle / set-priority / โฆ) refuses when a
path it would commit carries uncommitted changes, because it commits whatever is on disk at that
path and would record your edit as its own work. The message names the path. Commit the body edit on
its own with aiwf edit-body <id> โ the verb this skill covers, and the reason it is exempt from
that refusal โ then re-run the verb. Unrelated uncommitted paths survive untouched.
Composite ids (M-NNNN/AC-N)
Not directly supported. To update an AC body section, edit the prose under the ### AC-N โ title heading in the parent milestone file in your editor, then run aiwf edit-body M-NNN (bless mode commits whatever changed). Composite-id support is deliberately deferred โ bless mode covers the AC sub-section workflow without needing a sub-section resolver.
Provenance flags
| Flag | When |
|---|
--actor <role>/<id> | Override the runtime-derived identity (default: human/<localpart-of-git-config-user.email>). |
--principal human/<id> | Required when --actor is non-human (ai/..., bot/...); forbidden when --actor is human/.... |
Agents acting under an active authorization scope get scope trailers stamped automatically; without an active scope, agent invocations refuse with provenance-no-active-scope.
Don't
- Don't hand-edit frontmatter through this verb's body file โ frontmatter is structurally separate; use
aiwf promote / aiwf rename / aiwf cancel instead.
- Don't include a frontmatter block in the body file โ the verb refuses to prevent malformed output.
- Don't use
aiwf edit-body for status transitions or renames; those have their own verbs and proper FSM/atomicity rules.