Read a delivered unit''s real outcomes — the measure lens (baseline/target/realized), the validate verdicts and fix reports, the run lens (production actuals), and the delivered epic/slice status — against the current product model, and author the MEANING updates the delivery taught — a refined capability/functionality one_line, a raised nfr_needs level (monotonic-up), an earned status promotion, the grounding-doc sections the learning changed, and a new append-only decision per material lear...
Scanned 9/10/2026
Install to Claude Code
npx -y skills add kapilvirenahuja/garura --skill author-learnings --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Author Learnings?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/kapilvirenahuja-author-learnings)More formats (shields.io, HTML) on the badges page.
---
name: author-learnings
description: 'Read a delivered unit''s real outcomes — the measure lens (baseline/target/realized), the validate verdicts and fix reports, the run lens (production actuals), and the delivered epic/slice status — against the current product model, and author the MEANING updates the delivery taught — a refined capability/functionality one_line, a raised nfr_needs level (monotonic-up), an earned status promotion, the grounding-doc sections the learning changed, and a new append-only decision per material learning. Each proposed change carries the outcome that justifies it and a confidence tier. Writes the rewritten grounding docs STRAIGHT to the live model (per-node docs only) and emits the spine meaning-field deltas and the decision records as structured data in an STM learn-manifest.yaml — never the shared model files (_spine.yaml, profile, decisions), never the tree skeleton, never a slice/epic entry. Generative artifact production for the /learn play.'
version: 0.2.0
user-invocable: false
model: opus
allowed-tools: Read, Write, Bash, Glob
---
# author-learnings
Turns a **delivered unit's real outcomes** into the updates that keep the living product
model honest. After a unit ships, the pipeline has already produced the evidence — the measure lens
(each metric's baseline → target → realized + proof), the validate verdicts and fix reports (which
gates truly cleared; a `fix_required` is a model-was-wrong signal), the run lens (production actuals
vs planned), and the delivered epic/slice status. This skill reads that evidence against what the
model *claimed*, and authors the precise **meaning** updates the delivery taught — never the tree
skeleton, never a slice or epic entry. It is the close of the loop the old enrich gate used to be.
## Write discipline (ADR 026, direct-model-write)
This skill writes ONLY the per-node grounding docs (`capability.md`, `functionality.md`, and the
slice `lens/{measure|run|quality}.md`) — each its own file — **straight to the live model** under
`<product_base>/product-os/…`. It NEVER writes any shared model file: not `_spine.yaml`, not the
`profile` block, not a `decisions/` record. Every shared-file mutation is emitted as **structured
data in the STM `learn-manifest.yaml`** — the spine meaning-field deltas in `changes:` and the full
decision records in `decisions:` — for /learn's deterministic keyed persist (`persist_learn.py`) to
apply in place after the human checkpoint. /learn runs the shape linter and the content-quality eval
over the live docs, then the scoped-write guard over the full delta, before the checkpoint; nothing
is committed until the gate resolves.
## What it produces
The rewritten grounding docs at their live paths, plus a human-reviewable `learn-manifest.yaml`
listing every proposed change with its **outcome citation** and a **confidence** tier. Each rewritten
grounding doc conforms to its locked template (`standards/schemas/product-os/grounding/…`) and must
clear the linter (shape) and the content-quality eval (meaning). The manifest is the machine-checkable
contract `validate_learn.py` (pre-checkpoint) and `persist_learn.py` (the keyed persist) read — every
change carries an outcome, every nfr move is monotonic-up, every status promotion is earned, every
decision is a new accepted record carrying all its own fields.
## Inputs
| Field | Required | Description |
|-------|----------|-------------|
| `issue` | yes | The delivered unit's issue (display + decision provenance). |
| `unit` | yes | The resolved unit from `check_ready_unit` — `{issue, epics[], slices[]}`. |
| `outcomes` | yes | The outcome-evidence paths from `check_ready_unit` — `{measure_lenses[], run_lenses[], validate[], delivered_epics[], delivered_slices[]}`. Read these; they are what the delivery actually showed. |
| `spine` | yes | Path to the live spine (`product-os/_spine.yaml`) — read-only, for the current claims and the node ids. |
| `product_base` | yes | Product model root — to READ the affected nodes' grounding docs and resolve a prior decision a learning may supersede, and to WRITE the rewritten per-node grounding docs in place under `product-os/…`. |
| `manifest_path` | yes | Output path under STM for the `learn-manifest.yaml` (the proposed-change contract — spine deltas + decision records as structured data). |
## Procedure
Reasoning (what the outcome actually taught, and which claim it confirms or refutes) is yours.
Outcome-grounding, the allowlist, and template/eval conformance are non-negotiable.
1. **Read the outcomes.** Load each `measure.md` (did the metric move from baseline to target, with
real proof?), each `run.md` (what production actually needed vs planned), every validate verdict +
fix report (which gates cleared; read a `fix_required` as the model being wrong about a boundary or
rule), and the delivered epic/slice status. Note, per signal, what it teaches.
2. **Read the claims.** Load the spine and the affected nodes' grounding docs — `capability.md`
(benefit hypothesis, boundaries), `functionality.md` (acceptance, rules), and the slice's lens docs
— to see what the model claimed before delivery.
3. **Diff reality against the claim.** For each gap the evidence proves, decide the smallest honest
update on the **allowed** surface only:
- spine `one_line` — a capability/functionality descriptor delivery showed too thin or wrong;
- spine `nfr_needs` level — raise (monotonic-up only) when production proved a higher level needed;
a raised *profile* nfr is a box-move and MUST carry a decision;
- spine `status` — an EARNED promotion only (proposed → active when proven; to validated/delivered
where the outcome earns it). NEVER advance a `fix_required` — that becomes a grounding refinement;
- grounding sections — refresh only what the learning changed: a capability's **benefit hypothesis**
(confirmed/refuted) and **boundaries**, a functionality's **acceptance** and **rules &
behavior**, and the **measure / run / quality** lens docs with the real results;
- a decision — every material learning becomes a NEW append-only decision record.
4. **Ground every change.** Each proposed change, doc rewrite, and decision carries a non-empty
`outcome` citation naming the signal that justifies it (e.g. "measure: render p95 1.9s vs target
<2s — confirmed"; "validate fix_required: privacy gate caught raw-log leak — boundary missed").
A change with no outcome is dropped, not guessed.
5. **Tier by confidence.** `high` for a change a single clear outcome proves; `low` for an inferred or
partial signal — /learn surfaces low-confidence changes one by one at the checkpoint.
6. **Write the live docs; emit the shared-file deltas as manifest data.** Write each rewritten
grounding doc **straight to its live path** under `<product_base>/product-os/…` (per template) —
these are the only files this skill writes. Emit every spine meaning-field change in the manifest's
`changes:` block and every new decision as a full record in the manifest's `decisions:` block
(carrying `reason`, `alternatives`, and `level` — `persist_learn.py` builds the `decisions/<id>.yaml`
record from these). Write `learn-manifest.yaml` to `manifest_path`. NEVER write `_spine.yaml`, the
`profile` block, or a `decisions/` record — those are the keyed persist's job.
## Output
The rewritten grounding docs, at their live paths:
```
<product_base>/product-os/{domain}/…
capability.md | functionality.md # a rewritten grounding doc (only changed ones)
slices/{slice}/lens/{measure|run|quality}.md # a rewritten lens doc (only changed ones)
```
and the STM manifest at `manifest_path`:
`learn-manifest.yaml` — field-for-field what `validate_learn.py` and `persist_learn.py` read:
```yaml
changes: # spine meaning-field changes
- node_ref: cap-source-coverage # the spine node id
node_kind: capability # capability | functionality | profile
field: nfr_needs # one_line | nfr_needs | status
dimension: performance # required when field == nfr_needs
from: medium # current value (level for nfr_needs; state for status)
to: high # proposed value (monotonic-up for nfr; earned for status)
outcome: "run.md: production p95 480ms vs target 150ms — performance underscoped"
confidence: high # high | low
docs: # grounding docs rewritten in place (live paths)
- rel: product-os/token-dash/slices/slice-trusted-coverage/lens/measure.md
outcome: "measure: coverage 100% realized; render p95 1.9s vs <2s — both confirmed"
decisions: # NEW append-only decision records (full data)
- id: dec-learn-source-coverage-perf-high
node_ref: cap-source-coverage
level: product # product | ... (persist writes it into the record)
title: "Source-coverage performance must be high — production load proved medium underscoped"
reason: "Run lens recorded p95 480ms at 100 concurrent users; the profile target is 150ms. The medium level set pre-delivery did not survive real load."
alternatives:
- name: "keep nfr_needs.performance: medium"
why_not: "Realized production load shows the target is unreachable at medium without an architecture change."
supersedes: # optional: the accepted decision id this overturns
outcome: "run.md: p95 480ms at 100 users; profile target 150ms unmet without redesign"
```
`persist_learn.py` builds each `decisions/<id>.yaml` record from the manifest `decisions:` entry
(stamping `decided_by`/`date`/`status: accepted`), so `title`, `reason`, `alternatives`, and `level`
MUST be present in the manifest — there is no draft decision file to fall back on.
Return the contract with the live doc paths and the `learn-manifest.yaml` path — paths, never
inline content.
## Rules
- **Outcome-grounded.** Every proposed change, doc rewrite, and decision carries an `outcome` citation
that traces to a real signal (measure / validate / run / delivered status). No outcome → drop it.
- **Meaning only, never the skeleton.** Propose changes ONLY to `one_line`, `nfr_needs` level,
earned `status`, the listed grounding sections, and new decisions. NEVER rename or re-parent a
domain/capability/functionality, NEVER rewrite a slice or epic entry, NEVER edit an accepted
decision in place — those are rejected by `validate_learn.py` / the keyed persist.
- **Monotonic-up.** An `nfr_needs` level may only rise; a raised profile nfr (a box-move) carries a
decision.
- **Earned status.** Promote a status only to an earned state the outcome proves; never advance a
`fix_required` — carry it as a grounding refinement instead.
- **Append-only decisions.** Every material learning is a NEW decision (status `accepted`); a learning
that overturns a prior decision names what it `supersedes`, never edits the old record.
- **Template-true.** Each rewritten grounding doc conforms to its locked template and must clear the
linter + the content eval — every section self-explaining, never thinned.
- **Docs to live, shared-file deltas as manifest data.** Write ONLY the per-node grounding docs to
their live paths; emit the spine meaning-field changes and the full decision records as structured
data in `learn-manifest.yaml`. Never write `_spine.yaml`, the `profile` block, or a `decisions/`
record — the keyed persist owns those.
```
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!