Source index · Technical reference · Home

UNRELEASED DEVELOPMENT SNAPSHOT · READ-ONLY EXCERPT

skills/capture/SKILL.md

This is the cited technical source at local revision 275a354, inspected on 22 September 2026. It differs from the public release. This reference publishes only the cited sections, not an installable release or the development branch.

Line numbers refer to the complete recorded file. Uncited lines are omitted. Full-file SHA-256: d9aa821fd62ecebc46933c3111ae4f58556d78e4b5686ae1a044faa551d858f5.

1---
2name: capture
3layer: foundation
4description: Use after SHIP, at the end of a task, to make what was learned durable — updates lessons, drafts an ADR for any non-trivial decision, appends the evolution log, and reaffirms the cold-executor handoff trio against build evidence. The cycle's last step; carries continuity to the next session.
5color: cyan
6tools: Read, Write, Edit, Bash, Grep, Glob
7voice: internal
8cli_support: [claude-code, codex, copilot]
9necessity: STRONGLY_RECOMMENDED
10gap_if_skipped: "Lessons, ADRs, and EVOLUTION-LOG entries are never written and the cold-executor trio is never reaffirmed against build evidence; cross-session continuity is lost and the next operator re-derives everything."
11---
13You are the CAPTURE skill — Phase 8 (final) of the Lintel cycle.
15## What this skill does
… omitted uncited lines …
89### Step 2 — Lessons capture (filtered)
91Invoke `/li:learn` (or inline):
93For each correction operator made during the cycle:
94- Was this correction GENERAL (would apply to future work) or SPECIFIC (one-time)?
95- If GENERAL: candidate for `.claude/memory/lessons.md`
96- If SPECIFIC: keep in this cycle's notes only
98Examples of LESSON-worthy:
99- "Don't mock the vendor SDK in tests — last 3 cycles' tests passed but prod failed because mocks diverged from real API"
100- "Always map the codebase first when planning infra work — saved 90 min on this engagement"
102Examples NOT lesson-worthy:
103- "Use specific port 8443 in this customer's deployment" — too specific
104- "Forgot to update README" — operational, not a pattern
106**Update-phase (ADR-0006) — classify BEFORE appending.** Append-only capture is the documented
107failure mode of file-based memory. For each candidate, grep what already exists:
109```bash
110source "${LINTEL_SOURCE_ROOT:-$LINTEL_REPO_ROOT}/lib/memory.sh"
111lessons_find_related <candidate keywords> # all related active lessons, ranked
112```
114Classify against the hits:
115- **add** — nothing related exists → new `## L-NNN — <title>` entry
116- **update** — an existing lesson covers it but the candidate sharpens it → extend THAT lesson's
117 How-to-apply (note the cycle id), no new entry
118- **supersede** — the candidate CONTRADICTS an existing lesson → write the new entry, then add
119 `superseded_by: L-<new> (<date>)` as the first body line of the old one. Never delete or edit
120 the old lesson away — git holds ingestion history, the marker holds validity
121 (supersede-don't-delete).
122- **no-op** — an existing lesson already says this → skip, mention the existing id
124AskUserQuestion per candidate lesson: "Capture as <classification>? (yes / no / edit-first)"
126If add: append to `.claude/memory/lessons.md`:
127```markdown
128## L-NNN — <lesson title>
129<lesson body: Rule / Why / How to apply>
130<-- Captured from cycle <cycle-id> by <operator>. -->
131```
133### Step 3 — Promote lesson check (NEW)
135For each NEW lesson captured, AskUserQuestion: "Promote to Lintel global lessons (scaffolding/01-foundation/.claude/memory/lessons.md)? — applies to ALL future scaffolded repos."
137If yes: invoke `/li:lessons-promote`.
139This is how operator-discovered patterns become team-wide knowledge.
141### Step 4 — ADR draft (if non-trivial decision)
143Scan cycle history for non-trivial decisions:
144- Architectural picks (alternative A vs B chosen)
145- Pattern adoptions (new pattern introduced)
146- Trade-off decisions (accepted P3 finding, deferred P2)
147- Scope changes (descoped feature, added scope)
149For each candidate, AskUserQuestion: "Draft ADR for this decision?"
151If yes: invoke `/li:adr-new "<decision title>"`:
152- Reads `.claude/decisions/TEMPLATE.md`
… omitted uncited lines …
185- Update interfaces/contracts that drifted during BUILD (annotated as post-build-evidence)
186- Status: APPROVED (from PLAN) — unchanged unless drift detected
188**`plan.md` reaffirm** (born in PLAN):
189- Annotate plan.md tasks with actual STATUS (DONE/SKIPPED/DEFERRED) from build-log
190- Acceptance criteria post-verification (which actually passed)
192**`prompt.md` reaffirm** (born in PLAN, v3.8 Feature 2.2 moved birth to PLAN):
193- Verify prompt.md still describes the work accurately
194- Add any "What you DON'T need to know" entries discovered during BUILD
195- Path: `.claude/plans/<slug>/prompt.md` (born by PLAN, lives there)
197**Why moved to PLAN:** standalone `/li:plan <design.md>` (workflow_root post-v3.8) needs to produce the complete trio at PLAN-time. CAPTURE-only generation broke that — operator running PLAN solo got 2/3 of a handoff. Trio born together fixes this.
199AskUserQuestion: "Want to dogfood the trio? Spawn fresh subagent with ONLY these 3 files + verify it can describe what was built." (Optional verification step — same as before, but now against finalized trio.)
201**Handoff-size check against the 500k cap (NON-BLOCKING).** The reaffirmed trio is the durable cold-executor handoff — the artifact a fresh cold session reads to re-execute. Run the existing cap check so the finalized trio (now annotated with build evidence, possibly larger than at PLAN-time) plus any warming context can't silently exceed the 500k cap. This closes the second un-gated handoff the v4.9 audit flagged (Promise 6: cap logic existed but was invoked at no handoff).
203Invoke the existing mechanism — do **not** rebuild it:
205`/li:handoff-size-check` (a portable skill call; reads the reaffirmed trio + `.claude/runtime/state/warming-manifest.md`, applies the mode-aware cap from `/li:context-budget` mode_envelopes, default `customer-engagement: 500k soft / 750k hard`).
207- **SURFACE, don't block.** A yellow/red verdict warns ("finalized trio yields ~Nk handoff, near cap") and notes the durable handoff is large — the operator decides whether to trim before it becomes the cross-session record. It does NOT halt CAPTURE.
208- **Off-switch:** `--skip-handoff-size-check` (or `SKIP_HANDOFF_SIZE_CHECK=1`) skips the gate entirely. Silent when skipped, and silent on a green pass.
210### Step 6a — Reaffirm swarm evidence and future-operator clarity
212When the selected work map opts into swarming, resolve helpers only from explicit
213`LINTEL_SOURCE_ROOT`, then Claude's `CLAUDE_PLUGIN_ROOT`; other adapters export their known installed
214bundle. Without either trusted root return `NEEDS_CONTEXT`. Run `li-work-artifacts.py` and
215`li-swarm.py verify` with the working repo only as `--repo`. Tests/self-checks export
216`LINTEL_SOURCE_ROOT` explicitly. Preserve the work map, charter, briefs, worker reports, and
217independent reviews with the trio; they are the cold-resume evidence for topology and ownership.
218Do not copy task text, dependencies, status, or acceptance into coordination.
220Only the coordinator may set the work-map status to `COMPLETE`, and only after all lane evidence,
221serial integration, final integrated REVIEW, and SHIP evidence pass. Local runtime attempt files and
222abandoned worktrees are not durable completion evidence.
224For meta-infra M4, the future-operator recap must name:
226- the explicit opt-in fields and coordination path;
227- the actual host tier used (`native`, `sequenced`, or `none`) and whether writers really ran
228 concurrently;
229- the isolation/attribution method and deterministic integration order;
230- lane reports/reviews plus final integrated review evidence;
231- any lost attempts, sequenced fallback, migration, deprecation, or unverified host behavior.
233Never claim independent review when the same identity implemented and reviewed a lane. Honest
234degradation is part of the durable outcome, not a concern to hide.
236### Step 7 — Role debrief (if role was active)
238If role was active during cycle:
239- Review role's OUTCOME LENS per phase against actual outcomes
240- Did role lens add value? Where did it conflict with engineering reality?
241- Update role file with any new INSIGHTS learned (operator confirms)
242- Sensitivity-aware: if role is private, updates stay in `~/.lintel/roles/private/<role-id>.md`
244### Step 7b — Vault sink (session summary → knowledge vault)
246Config-gated, optional, NEVER blocking. Writes a short human-readable session summary to an
247external knowledge vault (e.g. an Obsidian vault) so the vault becomes the cross-repo memory
248layer. The repo's own capture artifacts (Steps 1–7) are unaffected — this is an additional
249sink, not a move. Nothing is ever read back from the vault into the repo.
251```bash
252source "${LINTEL_SOURCE_ROOT:-$LINTEL_REPO_ROOT}/lib/pack-resolver.sh"
253sink_enabled=$(resolve_pack_field capture.vault_sink_enabled)
254sink_path=$(resolve_pack_field capture.vault_sink_path) # relative to repo root
256if [ "$sink_enabled" != "true" ]; then
257 : # disabled — skip silently
258elif { case "$sink_path" in /*|[A-Za-z]:*) sink_dir="$sink_path" ;; *) sink_dir="$REPO_ROOT/$sink_path" ;; esac; [ ! -d "$sink_dir" ]; }; then
259 echo "[lintel/capture] WARN: vault_sink path not found: $sink_path — skipping vault export"
260 audit_log capture vault_sink_skipped "reason=path_missing" "path=$sink_path"
261fi
262# A missing or disabled vault must NEVER fail CAPTURE — one-line warn, then move on.
263```
265When enabled and the path exists, write exactly ONE file per session,
266`<sink_path>/YYYY-MM-DD-<repo>-<short-slug>.md`:
268```markdown
269---
270created: YYYY-MM-DD
271tags: [session]
272type: session
273repo: <repo-name>
274branch: <git-branch>
275outcome: shipped | in-progress | blocked | exploration
276session: <cycle-id-if-available>
277---
278# <one-line session title>
280## What was done
281<3–8 lines, plain language, no code dumps>
283## Decisions
284<decisions taken, one line each; "None" if none>
286## Open threads
287<unfinished items / next steps; "None" if none>
289## Pointers
290- <repo-relative paths to the key files/PRs touched>
292## Links
293- [[<repo-name>]] <- the repo hub note (backlinks = per-repo session history)
294- [[<previous session note name>]] <- predecessor, if one exists for this repo
295```
297The frontmatter is a LOCKED flat schema (ADR-0007) — `sessions.base` (the Bases dashboard
298installed by `bin/li-vault-init`) and the vault's own skills query these exact properties.
299`outcome` uses the controlled vocabulary above, nothing else.
301**After writing the note, maintain the two navigation surfaces (same sink dir):**
3021. **Hub note** `<sink_path>/<repo-name>.md` — create a minimal one if missing (frontmatter:
303 `created:`, `tags: [hub]`, `type: repo-hub`, `repo:`; one line of prose — same shape
304 bin/li-vault-init writes). Never overwrite an existing hub.
3052. **Index** `<sink_path>/00-index.md` — create it if missing (frontmatter `type: session-index`
306 + one intro line), then maintain the list under its heading: carry the existing entries
307 forward, PREPEND this session's line, truncate to 15:
308 `- [[<note-name>]] - <one-line title> (<repo>)`. Keep frontmatter + intro intact; touch only
309 the list. (Carrying forward the index's own lines is the one sanctioned vault read — never
310 read other notes back.)
312Source the content from the Step 1 cycle aggregation. **Hard rules:** no secrets or tokens, no
313customer or employer-internal data, no full file contents — repo-relative pointers instead of
314payloads. Render the headings AND body in the session's working language (the template above is
315the canonical English form — translate it wholesale when the session ran in another language).
316Frontmatter must parse.
318**MANDATORY pre-write scan (battletest K4 — the vault note lands OUTSIDE the repo, where no
319git-commit hook sees it).** The "hard rules" above are not enough on their own — scan the
320rendered note body programmatically before writing, and ABORT the export (warn, never fail
321CAPTURE) on any hit:
323```bash
324source "$LINTEL_REPO_ROOT/hooks/shared/_patterns.sh"
325note_body="$(cat "$rendered_note")"
326sec_hits="$(scan_secrets all "$note_body")"
327pii_hits="$(scan_customer "$note_body")"
328if [ -n "$sec_hits$pii_hits" ]; then
329 echo "[lintel/capture] WARN: vault export ABORTED — ${sec_hits:+secrets: $sec_hits }${pii_hits:+pii: $pii_hits}"
330 audit_log capture vault_sink_skipped "reason=sensitive_content" "secrets=$sec_hits" "pii=$pii_hits"
331 # skip the write entirely — do NOT sanitize-and-ship; an aborted export is correct
332else
333 # write the note, then:
334 audit_log capture vault_sink_written "file=<filename>"
335fi
336```
338### Step 8 — Retro (optional, light)
340Append to `.claude/memory/retros/<date>-<cycle-id>.md`:
341```yaml
342cycle_id: <id>
343duration_human: <hours>
344duration_cc: <minutes>
345tokens_used: <approx>
346cost_estimate_dollars: <X>
348what_worked:
349 - <thing>
350what_friction:
351 - <thing>
352next_time:
353 - <pattern to repeat>
354 - <pattern to avoid>
355```
357Not always written — only if cycle was substantial enough that retro adds value (operator-driven).
359### Step 9 — (removed in v5, ADR-0006)
361The operator-profile append (`~/.lintel/state/operator-profile.jsonl`) was a dead write — the
362promised SENSE read-back never existed. Subtracted. The granularity calibration record (Step 1b)
363is the real feedback loop and stays.
365### Step 10 — 00-state.md final entry
367Mechanical since v5.0 (ADR-0008) — one command, not a YAML obligation. No `next=`: the cycle is complete (`/li:resume` keys off `cycle_complete: true`); the full artifact list lives in the Step 11 closing message:
369```bash
370_sl="${LINTEL_SOURCE_ROOT:-${LINTEL_REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null)}}/lib/state.sh"
371[ -f "$_sl" ] || _sl="$HOME/.lintel/lib/state.sh"; source "$_sl" # installed by install.sh in consumer repos
372state_append CAPTURE DONE cycle_complete=true outcome=<DONE|DONE_WITH_CONCERNS|BLOCKED> lessons_captured=<count> adrs_drafted=<count> total_tokens=<N> cost_estimate=<$X>
373```
375### Step 11 — Closing message
377Tight closing — terse artifact list + operator-pattern observations, no motivational filler:
379```
380LINTEL CYCLE COMPLETE — <wedge title>
382Duration: <hours human / <minutes> CC
383Cost: $<X> | Tokens: <N>
384Outcome: <DONE / DONE_WITH_CONCERNS / BLOCKED>
386Artifacts produced:
387- Code: <commit range>
388- spec.md, plan.md, prompt.md (cold-executor trio)
389- Lessons captured: <N> (<N> promoted to Lintel global)
390- ADRs drafted: <N>
391- Customer deliverables: <list>
393Operator-pattern noted:
394- <specific observation 1>
395- <specific observation 2>
396- <specific observation 3>
398Next actions:
399- Trio is in <path> — ready for future cold-session re-execution
400- /li:resume picks up next cycle from here
401```
403## Status protocol
405- **DONE** — all artifacts written, profile updated
406- **DONE_WITH_CONCERNS** — captured but operator deferred ADR draft or lessons capture
407- **BLOCKED** — only if filesystem unavailable (rare)
409## Pause-points (mostly operator-confirms)
411- Per candidate lesson: AskUserQuestion capture / skip / edit
412- Per candidate ADR: AskUserQuestion draft now / draft later / skip
413- After trio drafted: AskUserQuestion "Verify with dogfood subagent?" (optional)
414- Role debrief (if active): AskUserQuestion "Update role file with these insights?"
416## Hop-in support
418YES — standalone post-implementation reflection. Useful if operator forgot CAPTURE in prior session.
420## Integration
422**Reads:**
423- All `.claude/runtime/state/00-state.md` entries from cycle
424- `.claude/runtime/state/build-log.md`
425- `.claude/runtime/state/review-report-*.md`
426- `.claude/runtime/state/compliance-report-*.md` (if the active pack defines compliance gates)
427- design doc, plan.md (DRAFT), spec.md (DRAFT)
428- selected work.json and optional swarm coordination/charter/brief/report/review evidence
429- Cycle's git diff for change scope
430- role file (if active)
432**Writes:**
433- `.claude/memory/lessons.md` (append per captured lesson)
434- `.claude/decisions/NNNN-<slug>.md` (new ADR if drafted)
435- `EVOLUTION-LOG.md` (if CLAUDE.md changed)
436- `spec.md` (FINALIZED from PLAN's draft)
437- `plan.md` (FINALIZED with post-verification status)
438- `prompt.md` (NEW — cold-executor handoff)
439- swarm work map and evidence artifacts (reaffirmed when the execution profile was selected)
440- `.claude/memory/retros/<date>-<cycle-id>.md` (optional)
441- `~/.lintel/roles/<id>.md` (update if role active + insights to add)
442- `.claude/runtime/state/00-state.md` (CAPTURE final entry)
443- `.claude/runtime/audit/cycle-completion.jsonl`
444- `.claude/runtime/audit/granularity.jsonl` (append — actual-vs-estimated calibration record, via `audit_log`; read by `lib/scale-estimator.sh` `scale_calibrated_prior`)
445- `<capture.vault_sink_path>/YYYY-MM-DD-<repo>-<slug>.md` (optional — vault sink, Step 7b; only if `capture.vault_sink_enabled: true` and the path exists)
447**Triggers:**
448- Nothing automatically — cycle complete
449- `/li:resume` available for next cycle
450- If part of multi-cycle engagement: next cycle starts at SENSE or DEFINE
452## Recommended agents
454- **ADRDrafter** (engineering/) — primary, ADR drafting
455- **ChangelogMaintainer** (engineering/) — release-note polish if SHIP didn't already
456- **DocWriter** (engineering/) — synthesize cold-executor trio prose
457- The active pack's voice gates (`resolve_pack_field voice.gates_active`; none by default) — if any CAPTURE artifact ships outside (rare)