Capture atomic learning insights into .workflow/learning/lessons.jsonl. Lightweight CRUD over the shared learning store — supports capture, list, search, and show modes. No LLM or CLI calls; all operations are pure file reads and writes.
$manage-learn "Always read state.json before planning to detect current phase"
$manage-learn "list --limit 10 --category antipattern"
$manage-learn "search context propagation"
$manage-learn "show INS-a3f7b2c1"
$manage-learn "\"Zod v4 breaks z.object().strict() API\" --category gotcha --tag zod,typescript"
Flags (capture mode):
--category <name> — pattern|antipattern|decision|tool|gotcha|technique. Default: inferred from text keywords.--tag t1,t2 — Comma-separated tags. Always adds manual implicitly.--phase <N> — Override auto-detected current phase. --phase 0 forces no phase link.--confidence high|medium|low — Default: medium.Flags (list/search mode):
--tag t1,t2 — Filter by tag--category <name> — Filter by category--phase <N> — Filter by phase--lens <name> — Filter by retrospective lens (technical|process|quality|decision)--limit <N> — Row limit (default 20)Storage:
.workflow/learning/lessons.jsonl — append-only JSONL (shared with quality-retrospective).workflow/learning/learning-index.json — searchable indexPure file-operation CRUD skill for the workflow learning library. No agent spawning, no CLI calls, no LLM inference — just parse-infer-append-confirm. Complements quality-retrospective: where retrospective extracts insights in bulk from completed phases, manage-learn captures one timeless insight at a time during active work. Both write to the same lessons.jsonl store, disambiguated by source and lens fields.
Parse Mode → Bootstrap Store → Execute Mode → Confirm
(capture / (on first use) (Bash/Read/ (INS-id
list / Bash+Write) Write/Grep) + hints)
search /
show)
Parse the first non-flag token from $ARGUMENTS:
| First token | Mode |
|---|---|
list | list |
search followed by query | search |
show followed by INS-id | show |
| Empty | Prompt with functions.request_user_input |
| Any other text (quoted or not) | capture |
Validate --category if provided (allowed: pattern, antipattern, decision, tool, gotcha, technique). E002 if unknown.
Check if .workflow/learning/lessons.jsonl exists. If not:
// Create directory and empty files — use Bash + Write (apply_patch cannot create empty files reliably)
Bash('mkdir -p .workflow/learning && touch .workflow/learning/lessons.jsonl')
Write('.workflow/learning/learning-index.json', '{"version":1,"entries":[]}\n')
Verify .workflow/ exists (E001 if not).
| Keywords present in text | Inferred category |
|---|---|
| always, should, prefer, best practice | pattern |
| never, avoid, don't, pitfall, breaks | antipattern |
| decided, chose, tradeoff, because, reason | decision |
| tool, library, framework, package, cli | tool |
| gotcha, surprising, unexpected, watch out | gotcha |
| technique, approach, method, pattern for | technique |
Auto-link phase: Read .workflow/state.json for current_phase. Resolve matching directory slug from .workflow/phases/. --phase 0 forces null.
Generate stable INS-id: INS-{8 lowercase hex} from hash(insightText + timestamp).
Build lessons.jsonl row:
{
"id": "INS-a3f7b2c1",
"title": "<first 80 chars of insight>",
"summary": "<full insight text>",
"source": "manual",
"lens": null,
"category": "<inferred or explicit>",
"tags": ["manual", "<user tags...>"],
"phase": <N or null>,
"phase_slug": "<slug or null>",
"confidence": "<high|medium|low>",
"routed_to": null,
"routed_id": null,
"created_at": "<ISO>"
}
// Append single JSON line — Bash echo avoids rewriting the whole file
Bash(`echo '${JSON.stringify(insightRow)}' >> .workflow/learning/lessons.jsonl`)
const index = JSON.parse(Read('.workflow/learning/learning-index.json'))
index.entries.push({ id: insightRow.id, title: insightRow.title, category: insightRow.category, tags: insightRow.tags, phase: insightRow.phase, created_at: insightRow.created_at })
Write('.workflow/learning/learning-index.json', JSON.stringify(index, null, 2) + '\n')
Read learning-index.json entries array. Apply filters (--tag, --category, --phase, --lens). Sort newest-first. Display up to --limit rows (default 20):
ID Category Phase Tags Title
INS-a3f7b2c1 gotcha 3 manual,zod Zod v4 breaks z.object().strict() API
INS-b1c2d3e4 pattern 2 manual Always read state.json before planning
Grep across lessons.jsonl for the query string. Rank by field match weight: title (3) > tags (2) > summary (1). Display top matches with ID, category, phase, title.
Validate INS-id format INS-[0-9a-f]{8}. Find row in lessons.jsonl where id matches. Display full record with all fields. If routed_to is set, display the linked artifact path.
Capture mode:
=== INSIGHT CAPTURED ===
ID: INS-a3f7b2c1
Category: gotcha
Phase: 3 (phase-03-api-layer)
Confidence: medium
Tags: manual, zod, typescript
Next: $manage-learn "list" or $manage-learn "search zod"
| Code | Severity | Description | Stage |
|---|---|---|---|
| E001 | error | .workflow/ not initialized — run $maestro-init first | parse_input |
| E002 | error | Unknown --category value | parse_input |
| E003 | error | show mode requires INS-id argument | show |
| E004 | error | INS-id not found in lessons.jsonl | show |
| W001 | warning | Auto-phase detection: current_phase found but no matching directory; phase set to null | capture |
| W002 | warning | learning-index.json row count differs from lessons.jsonl; offer to rebuild index | list/search |
exec_command, no spawn_agent..workflow/learning/ structure on first use; do not require it to exist.INS-{8hex} from hash(insightText + timestamp) — same text at different times gets different ids."manual" for captures from this skill; "retrospective" is reserved for quality-retrospective.state.json automatically; --phase 0 is the only way to force null.pattern category rather than prompting user.