ax:narrate - write the session's story as a structured narration
You were there. This skill turns YOUR OWN memory of the session into a
reviewable artifact: 3-7 stops in reading-flow order, each anchored to
real evidence - code hunks, turn numbers, user quotes, failures. The
point is to capture what a PR diff never shows: the corrections, the
dead ends, the recoveries.
The artifact validates against SessionNarration in
apps/studio/src/routes/narration-types.ts and renders in ax studio.
Step 1 - identify the session
- Preferred:
ax sessions here --days=1 --json and pick the current
session's id (the one matching this conversation). Use the short id.
- If
ax is unavailable or the session isn't ingested yet, derive a
slug: <repo>-<YYYYMMDD-HHmm>. Note in meta that turn seqs are
best-effort ordinals in that case.
- If available,
ax sessions show <id> --json gives you the real turn
seqs to anchor against. Prefer real seqs over guesses.
Step 2 - reconstruct the story from your own context
Re-read the conversation in your head before writing anything:
- What did the user originally ask for? (intent)
- What existed before, what exists now? (before/after)
- Where did the user redirect or correct you? EVERY one of these
becomes a
correction anchor. No exceptions.
- Which tool failures actually mattered (changed your approach, cost
real time, forced a workaround)? Each becomes a
tool_failure
anchor. Skip trivial retries that changed nothing.
- Which attempts were abandoned? They get a stop or at least a
turn anchor - abandonment is part of the story.
Step 3 - choose 3-7 stops, in reading-flow order
A stop is a LOGICAL unit of change, not a file. If three files changed
for one reason, that is ONE stop with several anchors. Order rules
(stolen from the code-tour playbook because they work):
- Entry point first: the change that, understood alone, unlocks the rest.
- Cause before effect: the correction comes before the code it caused.
- Definitions before consumers: types/schema stops before usage stops.
- Verification last: tests, typecheck, and the failures hit on the way.
- Combine trivial housekeeping into one final stop, or omit it.
Step 4 - write each stop
- title: short and friendly. "Call counts become a char diffstat",
not "Changes to files-touched.ts".
- gist: ONE sentence. Not two. A reader who reads nothing else must
get the stop from the gist. Conversational, the way you'd say it to
a colleague.
- detail: 2-4 sentences of markdown (paragraphs,
inline code,
bold). Say WHY the change looks the way it does; "we did X
instead of Y because Z" is exactly what the reader wants.
- transition: a short connective phrase to the next stop; empty
string
"" for the last stop.
- anchors: MUST be non-empty. An unanchored stop is an unsupported
claim. Anchor kinds:
| kind |
required fields |
use for |
file_hunk |
file, old_text, new_text, label, opt turn_seq |
a real code change |
code_state |
artifact, label, lang, code, opt turn_seq |
the evolving architecture snapshot |
turn |
turn_seq, label |
a plain moment in the transcript |
user_direction |
turn_seq, quote |
user steering (not correcting) |
correction |
turn_seq, quote, outcome |
user correcting course |
tool_failure |
turn_seq, tool, error_excerpt, recovery |
consequential failure |
term |
name, definition |
a domain term the story leans on |
Hard anchor rules
file_hunk carries VERBATIM old/new fragments from the actual edits
you made - copy the real text, never paraphrase code. Keep hunks
short (5-15 lines per side); pick the most telling fragment, not the
whole edit. old_text: null for pure insertions, new_text: null
for pure deletions. Never both null.
- Every user correction/redirect in the session gets a
correction
anchor with a verbatim (trimmed) quote and a concrete outcome -
what actually changed because of it.
- Every consequential tool failure gets a
tool_failure anchor with a
real error_excerpt and how you recovered (or "abandoned").
- Never fabricate turn seqs. Use
ax sessions show seqs when you have
them; otherwise count user turns from the start of the conversation
and say so in the detail.
code_state is the architecture spine of the narration: pick ONE
stable artifact id (e.g. "review-architecture") and restate the
FULL snapshot at each stop where the design moved - pseudo-code of
types/interfaces, how they compose, and the call stack (plan-style:
Caller -> Callee // note). Consecutive snapshots of the same
artifact animate token-by-token in studio, so KEEP shared lines
byte-identical between stops and let only the real delta differ - a
new method, a renamed shape, an added edge case. Use code_state
for the evolving design; use file_hunk for one-off code jumps
(those render as static before/after diffs, not motion).
Step 5 - emit the artifact
Write .ax/narrations/<session-id>.json (create the directory if
needed) with exactly this top-level shape:
{
"schema_version": 1,
"kind": "narration",
"meta": {
"session_id": "<id>",
"generated_at": "<ISO-8601 now>",
"generator": "skill",
"model": "<your model id>"
},
"title": "...",
"intent": "...",
"before": "...",
"after": "...",
"stops": [ { "title": "...", "gist": "...", "detail": "...", "transition": "...", "anchors": [ ... ] } ]
}
Before finishing, self-check against the validator's rules:
stops non-empty (3-7), every stop's anchors non-empty.
- Every gist is one sentence; every
correction has an outcome;
every tool_failure has a recovery; no file_hunk with both
sides null or empty.
- Strings are plain JSON strings (escape newlines in hunks as
\n).
Then tell the user where the file landed and give a 2-line summary of
the story you wrote. Do not paste the whole JSON into chat.
1---2name: ax-narrate3description: Write the agent-generated narration of the current session - the reviewable story of what changed, including what never reaches a PR (user corrections, abandoned attempts, tool failures). Triggers on "narrate this session", "summarize what changed", "write the session story", "narrate what we did", "session narration". Output is .ax/narrations/<session-id>.json for the ax studio narration view. Do NOT fire on "summarize this file" or generic recap questions answered inline - this skill writes a structured artifact.4---56# ax:narrate - write the session's story as a structured narration78You were there. This skill turns YOUR OWN memory of the session into a9reviewable artifact: 3-7 stops in reading-flow order, each anchored to10real evidence - code hunks, turn numbers, user quotes, failures. The11point is to capture what a PR diff never shows: the corrections, the12dead ends, the recoveries.1314The artifact validates against `SessionNarration` in15`apps/studio/src/routes/narration-types.ts` and renders in ax studio.1617## Step 1 - identify the session1819- Preferred: `ax sessions here --days=1 --json` and pick the current20 session's id (the one matching this conversation). Use the short id.21- If `ax` is unavailable or the session isn't ingested yet, derive a22 slug: `<repo>-<YYYYMMDD-HHmm>`. Note in `meta` that turn seqs are23 best-effort ordinals in that case.24- If available, `ax sessions show <id> --json` gives you the real turn25 seqs to anchor against. Prefer real seqs over guesses.2627## Step 2 - reconstruct the story from your own context2829Re-read the conversation in your head before writing anything:30311. What did the user originally ask for? (intent)322. What existed before, what exists now? (before/after)333. Where did the user redirect or correct you? EVERY one of these34 becomes a `correction` anchor. No exceptions.354. Which tool failures actually mattered (changed your approach, cost36 real time, forced a workaround)? Each becomes a `tool_failure`37 anchor. Skip trivial retries that changed nothing.385. Which attempts were abandoned? They get a stop or at least a39 `turn` anchor - abandonment is part of the story.4041## Step 3 - choose 3-7 stops, in reading-flow order4243A stop is a LOGICAL unit of change, not a file. If three files changed44for one reason, that is ONE stop with several anchors. Order rules45(stolen from the code-tour playbook because they work):4647- Entry point first: the change that, understood alone, unlocks the rest.48- Cause before effect: the correction comes before the code it caused.49- Definitions before consumers: types/schema stops before usage stops.50- Verification last: tests, typecheck, and the failures hit on the way.51- Combine trivial housekeeping into one final stop, or omit it.5253## Step 4 - write each stop5455- **title**: short and friendly. "Call counts become a char diffstat",56 not "Changes to files-touched.ts".57- **gist**: ONE sentence. Not two. A reader who reads nothing else must58 get the stop from the gist. Conversational, the way you'd say it to59 a colleague.60- **detail**: 2-4 sentences of markdown (paragraphs, `inline code`,61 **bold**). Say WHY the change looks the way it does; "we did X62 instead of Y because Z" is exactly what the reader wants.63- **transition**: a short connective phrase to the next stop; empty64 string `""` for the last stop.65- **anchors**: MUST be non-empty. An unanchored stop is an unsupported66 claim. Anchor kinds:6768| kind | required fields | use for |69|---|---|---|70| `file_hunk` | `file`, `old_text`, `new_text`, `label`, opt `turn_seq` | a real code change |71| `code_state` | `artifact`, `label`, `lang`, `code`, opt `turn_seq` | the evolving architecture snapshot |72| `turn` | `turn_seq`, `label` | a plain moment in the transcript |73| `user_direction` | `turn_seq`, `quote` | user steering (not correcting) |74| `correction` | `turn_seq`, `quote`, `outcome` | user correcting course |75| `tool_failure` | `turn_seq`, `tool`, `error_excerpt`, `recovery` | consequential failure |76| `term` | `name`, `definition` | a domain term the story leans on |7778### Hard anchor rules7980- `file_hunk` carries VERBATIM old/new fragments from the actual edits81 you made - copy the real text, never paraphrase code. Keep hunks82 short (5-15 lines per side); pick the most telling fragment, not the83 whole edit. `old_text: null` for pure insertions, `new_text: null`84 for pure deletions. Never both null.85- Every user correction/redirect in the session gets a `correction`86 anchor with a verbatim (trimmed) `quote` and a concrete `outcome` -87 what actually changed because of it.88- Every consequential tool failure gets a `tool_failure` anchor with a89 real `error_excerpt` and how you recovered (or `"abandoned"`).90- Never fabricate turn seqs. Use `ax sessions show` seqs when you have91 them; otherwise count user turns from the start of the conversation92 and say so in the detail.93- `code_state` is the architecture spine of the narration: pick ONE94 stable `artifact` id (e.g. `"review-architecture"`) and restate the95 FULL snapshot at each stop where the design moved - pseudo-code of96 types/interfaces, how they compose, and the call stack (plan-style:97 `Caller -> Callee // note`). Consecutive snapshots of the same98 artifact animate token-by-token in studio, so KEEP shared lines99 byte-identical between stops and let only the real delta differ - a100 new method, a renamed shape, an added edge case. Use `code_state`101 for the evolving design; use `file_hunk` for one-off code jumps102 (those render as static before/after diffs, not motion).103104## Step 5 - emit the artifact105106Write `.ax/narrations/<session-id>.json` (create the directory if107needed) with exactly this top-level shape:108109```json110{111 "schema_version": 1,112 "kind": "narration",113 "meta": {114 "session_id": "<id>",115 "generated_at": "<ISO-8601 now>",116 "generator": "skill",117 "model": "<your model id>"118 },119 "title": "...",120 "intent": "...",121 "before": "...",122 "after": "...",123 "stops": [ { "title": "...", "gist": "...", "detail": "...", "transition": "...", "anchors": [ ... ] } ]124}125```126127Before finishing, self-check against the validator's rules:128129- `stops` non-empty (3-7), every stop's `anchors` non-empty.130- Every gist is one sentence; every `correction` has an `outcome`;131 every `tool_failure` has a `recovery`; no `file_hunk` with both132 sides null or empty.133- Strings are plain JSON strings (escape newlines in hunks as `\n`).134135Then tell the user where the file landed and give a 2-line summary of136the story you wrote. Do not paste the whole JSON into chat.