autolearn
Use when a verified non-trivial fix lands or existing solution docs need refresh. Not for unverified fixes.
Install
npx skills add https://github.com/OutlineDriven/outline-driven-development/tree/main/.devin/skills/autolearn
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install outlinedriven-outline-driven-development@llmmart
git clone https://github.com/OutlineDriven/outline-driven-development.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole outlinedriven/outline-driven-development collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Autolearn
Contract
| Field | Bound contract |
|---|---|
| Trigger | A non-trivial fix has been verified (observed working, not hoped working), or explicit autolearn or refresh invocation. |
| Authority | Reversible local: writes only the operating repo's docs/solutions/ and repo-root CONCEPTS.md; rollback is version control. No remote mutation. |
| Side effect | Writes or refreshes docs/solutions/ learning docs and CONCEPTS.md; stages only the surfaces this skill wrote or edited. |
| Done | A validated learning or concept entry exists, or an explicit determination that nothing qualifies. |
Inputs
- The verified fix or solved problem, from conversation history or codebase. Must be supplied or derivable from context.
- Optional:
mode:refresh [scope]to maintain existing docs;mode:headlessfor non-interactive operation. - Optional: an injected auto-memory block (supplementary context, not primary evidence).
Procedure
0. Route the mode
Strip mode: tokens from arguments before treating the remainder as context or scope.
- Capture (default): document one solved problem into docs/solutions/.
- Vocabulary capture: a durable, reusable project term surfaces; reconcile CONCEPTS.md.
- Memory handoff: a fact about the user, preferences, or cross-project context surfaces; do not write it into docs/solutions/ or CONCEPTS.md; surface it as a memory-handoff candidate for the memory system to capture.
- Refresh: maintain existing docs/solutions/ and CONCEPTS.md.
- Headless: overlays any mode; skip all questions, never pause, apply safe actions, mark uncertain as stale.
Fire automatically on a trigger phrase ("that worked", "it's fixed", "working now", "problem solved", "verified the fix", "tests pass now", "build succeeds", "that approach failed") or after a verified non-trivial fix. Auto-firing is permission to evaluate, not permission to fabricate.
One run can do all three repo-scoped actions: write a learning doc, reconcile a concept, and flag a memory-handoff candidate.
Done when: the mode is routed and mode: tokens are stripped from arguments.
1. Reject-by-default gate
A doc is earned, not assumed. Verify all three preconditions:
- The problem is solved, not in progress. An abandoned attempt counts as solved once it is finished (branch dead, decision to stop made); its learning is the anti-pattern: what was tried, the specific reason it failed, and the condition under which it would be worth trying again.
- The solution is verified: observed working, not hoped working.
- It was non-trivial, not a typo or obvious one-liner.
Then apply the reject-by-default gate (all three filters in order):
- Would I forget this? Skip baseline knowledge anyone in this codebase already carries.
- Already covered? If an existing docs/solutions/ doc covers it, updating that doc beats spawning a second one. A duplicate is drift, not knowledge.
- Universal or local? Scope-qualify the claim. Say when a quirk is repo-specific and when a truth is general. An unqualified claim is a future trap.
The gate governs CONCEPTS.md entries too: a term earns a slot only when its precise local meaning would otherwise be forgotten, it is not already defined there, and it is scope-qualified to this project rather than general programming or domain English.
If nothing clears the gate, say so in one line and exit. A clean "nothing worth capturing here" is a valid, correct result.
Done when: all three preconditions and all three gate filters are evaluated, with a pass or a one-line "nothing qualifies" exit.
2. Capture: research (parallel, read-only)
Scan any injected auto-memory block for entries related to the problem. If it is absent or empty, skip it. If relevant entries exist, carry them as a labeled supplementary context block. Memory is supplementary; when it conflicts with the codebase or conversation, prefer the codebase or conversation. Tag any memory-derived line that lands in the final doc with (auto memory [claude]).
Dispatch three subagents in parallel. Each returns text and writes nothing.
- Context Analyzer: from the problem, decide the track (bug vs knowledge), the problem_type, the category directory, and a slug filename (
[sanitized-problem-slug].md, no date suffix). Return a frontmatter skeleton and which track applies. Do not invent enum values or fields. - Solution Extractor: extract the substance from the conversation, folding in the auto-memory excerpt as supplementary evidence. Bug track: Problem, Symptoms, What Didn't Work, Solution (with code), Why This Works, Prevention. Knowledge track: Context, Guidance, Why This Matters, When to Apply, Examples.
- Related-Docs Finder: grep docs/solutions/ (
title:,tags:,module:,component:on extracted keywords; narrow to the candidate subdirectory when known), read only frontmatter of candidates, fully read only strong matches. Score overlap across problem statement, root cause, solution approach, referenced files, prevention rules: High (4-5 dimensions), Moderate (2-3), Low (0-1). Return links and the overlap verdict.
Wait for all three before assembling.
Done when: all three subagents return and their results are assembled for the write step.
3. Capture: assemble and write
- Overlap gate: High (4-5) → update the existing doc, keep its path and frontmatter, add
last_updated: YYYY-MM-DD. Moderate (2-3) → create normally; note as a refresh/consolidation candidate. Low or none → create normally. Done when: the overlap gate decision is made. - Read
assets/solution-template.md; assemble the doc with the track's section structure. Done when: the doc is assembled with the correct track structure. - Frontmatter per the Solution schema section; apply the YAML-safety quoting rule to array items. Done when: frontmatter follows the Solution schema with YAML-safe quoting.
mkdir -p docs/solutions/<category>/, writedocs/solutions/<category>/<slug>.md. Done when: the doc file is written to the correct category directory.- Validate:
python3 scripts/validate-frontmatter.py <path>. Exit 0 = parser-safe; exit 1 names the offending field. Quote, re-write, re-run until 0. Done when: the validator exits 0. - Read the file back to confirm it landed as intended. Done when: the file is read back and confirmed correct.
- Concept reconciliation (optional, when warranted): if the run surfaced a durable project term that clears the gate, reconcile CONCEPTS.md per step 5. Done when: concept reconciliation is performed or skipped.
4. Refresh check (selective, not automatic)
Suggest refresh with a narrow scope only when the new fix contradicts or supersedes an older doc, the work was a refactor/migration/rename/dependency-bump that likely invalidated references, or the Related-Docs Finder surfaced strong refresh candidates or moderate overlap. Otherwise do not. Capture the new learning first; refresh is targeted maintenance after.
Done when: a refresh recommendation is made or explicitly skipped.
5. Vocabulary capture: CONCEPTS.md
CONCEPTS.md at the operating repo root is the shared-vocabulary glossary. It holds words with a precise meaning in this codebase, with one definition per concept. Other knowledge-capture processes may also write to this shared surface; always follow the one-definition-per-concept discipline.
- Locate the file:
fd -g 'CONCEPTS.md' --max-depth 2. Absent and a term clears the gate → create it. Absent and nothing clears → write nothing; never scaffold an empty file. Done when: the file is located or its absence is handled. - Search for the term and its synonyms:
git grep -ni '<term>' CONCEPTS.md. A hit means the concept exists: refresh on drift, never add a second entry. Done when: the term is searched and existing entries are identified. - New term → add one entry: a one-sentence definition of what it means here and what distinguishes it from neighbors; a second paragraph only for non-obvious behavioral rules. Retire synonyms as an
*Avoid:*aliases line. No file paths, dates, owners, or version-specific claims. The file stands on its own. Done when: the new entry is written with its definition and alias line. - Read the file back to confirm the merge landed and created no duplicate heading. Done when: the file is read back with no duplicate headings.
6. Refresh: maintain existing docs
Find every .md under docs/solutions/, excluding README.md and anything under _archived/. Top-level records written by compound carry that skill's own seven-field schema (type, tags, confidence, date, source, Context, Implication); the Solution schema below does not apply to them. Read them for overlap and contradiction, and never rewrite one to the Solution schema or mark it stale for lacking those fields. A [scope] hint narrows it: try in order, stop at first hit: (1) subdirectory name, (2) frontmatter module/component/tags match, (3) filename partial match, (4) content keyword. No match → report the miss and exit. No scope hint → process everything.
Classify every candidate doc into exactly one outcome:
| Outcome | When | Action |
|---|---|---|
| Keep | Still accurate and useful | No edit. Report reviewed-and-trustworthy. |
| Update | Core solution correct, references drifted | Evidence-backed in-place edits. |
| Consolidate | Two or more docs overlap heavily, both correct | Merge unique content into the canonical doc, delete the subsumed one. |
| Replace | Old guidance is now misleading, better answer known | Write a trustworthy successor, then delete the old. |
| Delete | No longer useful, applicable, or distinct | Delete the file. |
Core rules: evidence informs judgment, not a mechanical scorecard; prefer no-write Keep; match docs to reality, not the reverse; be decisive; no low-value churn (no typo fixes, prose polish, cosmetic edits); delete, don't archive (no _archived/, git history preserves everything).
Investigate each doc: read it, cross-reference claims against current codebase. Check references (file paths, symbols, modules: still exist or moved?), solution (does the fix still match how the code works today?), code examples (do snippets reflect current implementation?), related docs (cross-referenced learnings still present and consistent?), overlap (another in-scope doc covering the same domain?). Update vs Replace boundary: references moved but approach still correct → Update; recommended solution conflicts with current code or architecture changed → Replace; if rewriting the Solution section, it is Replace, not Update. Age alone is not a stale signal. Check for a successor before deleting.
Document-set analysis: step back and judge the set as a whole. High overlap across 3+ dimensions → strong Consolidate signal. Older narrow precursor vs newer canonical doc → consolidation candidate. Retrieval-value test: does keeping these separate help discoverability or just create drift risk? Cross-doc contradictions are more urgent than individual staleness.
Execute per action:
- Keep: no edit, summarize why it remains trustworthy.
- Update: in-place edits only when solution is still substantively correct. Not Update territory: typo/style-only edits, or old fix is now an anti-pattern → Replace.
- Consolidate: confirm canonical doc (broader, more current); extract unique content from subsumed doc(s); merge into canonical; repoint cross-references; delete subsumed. Three or more overlapping → process pairwise.
- Replace: process one at a time. Write a successor, validate with
scripts/validate-frontmatter.pyuntil exit 0, then delete the old file. Evidence insufficient → mark stale in place: addstatus: stale,stale_reason,stale_date: YYYY-MM-DD. - Delete: only when referenced code/workflow is gone, problem domain no longer exists, and inbound links absent or unambiguously decorative. Before unlinking, grep repo markdown for citations. Decorative → delete fine, clean up citation; substantive → Replace signal; mixed/unclear → stale-mark. A late-discovered citation that is anything but unambiguously decorative stops the Delete.
Headless variant: skip all questions, never pause. Process every in-scope doc. Attempt all safe actions. Uncertain → mark status: stale. A write that fails is recorded as Recommended, not retried. Emit a report split into Applied and Recommended.
Report:
Refresh Summary
===============
Scanned: N docs
Kept: X Updated: Y Consolidated: C Replaced: Z Deleted: W Marked stale: S
Then per file: path, classification, evidence, action taken or recommended.
After refreshing, check whether the repo's documentation would lead an agent to discover and search docs/solutions/. If not, surface a discoverability recommendation in the report. Do not edit instruction files.
Done when: every in-scope doc is classified and acted on, and the refresh report is emitted.
7. Commit
One learning per commit. Stage only the surfaces this skill wrote or edited (a solution doc, CONCEPTS.md, or both). Never stage other dirty files. Commit locally by the operating repo's normal flow. Skip the commit if nothing was modified.
Done when: the commit is made with only this skill's surfaces staged, or skipped when nothing was modified.
Failure and recovery
- Nothing qualifies: if no fix clears the reject-by-default gate, state "nothing worth capturing here" in one line and exit. This is a valid result, not a failure.
- Validation failure:
scripts/validate-frontmatter.pyexits 1 naming the offending field. Quote the value, re-write the file, re-run until exit 0. Do not declare success while validation fails. - Overlap collision: High overlap with an existing doc → update the existing doc, do not create a duplicate. Creating a duplicate when an update was warranted is drift, not knowledge.
- Insufficient evidence for Replace: mark the doc stale in place (
status: stale,stale_reason,stale_date) rather than guessing a successor. - Late-discovered citation blocks Delete: reclassify to stale-mark or Replace; do not delete.
- Partial-result rule: if a write fails during refresh, record it as Recommended, do not retry into a mess.
- Rollback: all writes are to local files under version control. Revert the commit or restore the file from git history.
Output
One validated learning doc at docs/solutions/<category>/<slug>.md (or updated existing doc), optionally a CONCEPTS.md entry and a memory-handoff candidate, or a one-line "nothing qualifies" determination: in refresh mode, a report classifying every scanned doc into Keep/Update/Consolidate/Replace/Delete/stale with applied and recommended actions.
Solution schema
Owner of the field contract is references/schema.md. Do not recopy.
Canonical frontmatter contract for docs/solutions/ learning docs. The validator (scripts/validate-frontmatter.py) only catches silent YAML corruption; the field and enum rules below remain binding.
Two tracks
problem_type picks the track. The track decides which extra fields are required. Pick the narrowest value; best_practice is the Knowledge fallback.
| Track | problem_types |
|---|---|
| Bug | build_error, test_failure, runtime_error, performance_issue, database_issue, security_issue, ui_bug, integration_issue, logic_error |
| Knowledge | best_practice, documentation_gap, workflow_issue, developer_experience, architecture_pattern, design_pattern, tooling_decision, convention |
Required fields (both tracks)
title: clear problem/topic title (string).date:YYYY-MM-DD.category: thedocs/solutions/subdirectory (see Category map).module: module or area affected (string).problem_type: one enum value from the tracks table; determines the track.component: component or subsystem involved (free-form string; keep consistent within a repo so frontmatter search works).severity: one ofcritical,high,medium,low.
Bug-track required fields
symptoms: array, 1-5 observable symptoms (errors, broken behavior).root_cause: one of:missing_association,missing_include,missing_index,wrong_api,scope_issue,thread_violation,async_timing,memory_leak,config_error,logic_error,test_isolation,missing_validation,missing_permission,missing_workflow_step,inadequate_documentation,missing_tooling,incomplete_setup.resolution_type: one of:code_fix,migration,config_change,test_fix,dependency_update,environment_setup,workflow_improvement,documentation_update,tooling_addition,seed_data_update.
Knowledge-track fields
No required fields beyond the shared core. All optional:
applies_when: array (≤5), conditions where the guidance applies.symptoms: array (≤5), the gap or friction that prompted the guidance.root_cause: from the bug-track enum, if there is a specific one.resolution_type: from the bug-track enum, if a change was applied.
Optional fields (both tracks)
related_components: array of other components involved.tags: array (≤8) of search keywords, lowercase and hyphen-separated.
Category map (problem_type → directory)
| problem_type | directory |
|---|---|
build_error |
docs/solutions/build-errors/ |
test_failure |
docs/solutions/test-failures/ |
runtime_error |
docs/solutions/runtime-errors/ |
performance_issue |
docs/solutions/performance-issues/ |
database_issue |
docs/solutions/database-issues/ |
security_issue |
docs/solutions/security-issues/ |
ui_bug |
docs/solutions/ui-bugs/ |
integration_issue |
docs/solutions/integration-issues/ |
logic_error |
docs/solutions/logic-errors/ |
developer_experience |
docs/solutions/developer-experience/ |
workflow_issue |
docs/solutions/workflow-issues/ |
best_practice |
docs/solutions/best-practices/ |
documentation_gap |
docs/solutions/documentation-gaps/ |
architecture_pattern |
docs/solutions/architecture-patterns/ |
design_pattern |
docs/solutions/design-patterns/ |
tooling_decision |
docs/solutions/tooling-decisions/ |
convention |
docs/solutions/conventions/ |
Filename: [sanitized-problem-slug].md, no date suffix (the date field carries that).
Validation rules
Track from problem_type; shared required fields always present; bug track also requires symptoms, root_cause, resolution_type; knowledge track adds none. Enums match allowed values exactly, arrays respect item counts, date matches YYYY-MM-DD.
YAML safety (array items)
Strict YAML parsers misread array items that start with a reserved indicator as unquoted scalars. For any array-of-strings field (symptoms, applies_when, tags, related_components), wrap the value in double quotes when it starts with any of: ` [ ] { } , * & ! | > % @ ?. Also quote when the value contains ": ". Scalar fields (title:, module:) have a separate failure mode: an unquoted # truncates at the comment, an unquoted : reframes as a mapping. scripts/validate-frontmatter.py catches those; quote and re-run until it exits 0.
Files (outline-driven-development)
-
agents
-
openai.yaml 144 B
interface: display_name: "Autolearn" short_description: "Use when a verified non-trivial fix lands or existing solution docs need refresh."
-
-
assets
-
solution-template.md 2.6 KB
# Solution doc templates Pick the template for the `problem_type` track (see the solution-schema section in `../SKILL.md`). Replace every bracketed placeholder. Delete sections with no real content instead of leaving placeholders. --- ## Bug track For: `build_error`, `test_failure`, `runtime_error`, `performance_issue`, `database_issue`, `security_issue`, `ui_bug`, `integration_issue`, `logic_error` <!-- YAML safety: array items (symptoms, applies_when, tags, related_components) that start with ` [ ] { } , * & ! | > % @ ? or contain ": " must be double-quoted. See `../SKILL.md#solution-schema`. --> ```markdown --- title: [Clear problem title] date: [YYYY-MM-DD] category: [docs/solutions subdirectory] module: [Module or area] problem_type: [schema enum] component: [component or subsystem] symptoms: - [Observable symptom 1] root_cause: [schema enum] resolution_type: [schema enum] severity: [schema enum] tags: [keyword-one, keyword-two] --- # [Clear problem title] ## Problem [1-2 sentences: the issue and its user-visible impact] ## Symptoms - [Observable symptom or error] ## What Didn't Work - [Attempted fix and why it failed] ## Solution [The fix that worked, with code snippets when they carry weight] ## Why This Works [Root cause, and why the fix addresses it, the WHY, not a restatement of the diff] ## Prevention - [Concrete practice, test, or guardrail that stops a recurrence] ## Related - [Related docs or issues, if any] ``` --- ## Knowledge track For: `best_practice`, `documentation_gap`, `workflow_issue`, `developer_experience`, `architecture_pattern`, `design_pattern`, `tooling_decision`, `convention` <!-- YAML safety: array items (symptoms, applies_when, tags, related_components) that start with ` [ ] { } , * & ! | > % @ ? or contain ": " must be double-quoted. See `../SKILL.md#solution-schema`. --> ```markdown --- title: [Clear, descriptive title] date: [YYYY-MM-DD] category: [docs/solutions subdirectory] module: [Module or area] problem_type: [schema enum] component: [component or subsystem] severity: [schema enum] applies_when: - [Condition where this applies] tags: [keyword-one, keyword-two] --- # [Clear, descriptive title] ## Context [What situation, gap, or friction prompted this guidance] ## Guidance [The practice or recommendation, with code examples when useful] ## Why This Matters [Rationale and impact of following, or not following, this] ## When to Apply - [Conditions or situations where this applies] ## Examples [Concrete before/after or usage example showing the practice in action] ## Related - [Related docs or issues, if any] ```
-
-
references
-
concepts.md 5.1 KB
# `CONCEPTS.md`: entry schema and reconciliation rules Sync-lineage note: `skills/compound/references/concepts.md` is an independent sibling file. It defines compound's own accretion and seeding model for the same `CONCEPTS.md` surface; it is not a copy of this file. Don't merge them. Read this in Mode 4 (Concepts capture) and when refreshing `CONCEPTS.md`. It defines the entry shape and the reconciliation and refresh loop that enforces one definition per concept. The file lives at the **operating repo root**. It is one glossary shared by autolearn and `compound`, its second legitimate writer. This document covers autolearn's entry schema and reconciliation loop. Create the file only when a term clears the gate; never scaffold an empty file. ## What earns a slot: the reject-by-default gate, applied to vocabulary A term earns an entry only if it clears all three filters in order, the same gate that governs a learning doc: 1. **Would I forget its precise local meaning?** Define only words whose meaning *here* is precise enough that a new engineer needs it spelled out to follow code, tickets, or conversation. General programming vocabulary (cache, queue, job, session) and everyday domain English never qualify, however heavily used. 2. **Already defined?** Search `CONCEPTS.md` for the term and its synonyms before adding. If it is already there, this is not a new entry; refresh on drift, never duplicate. One definition per concept. 3. **Scope-qualified to this project?** The bar is "specific to this codebase," not "a generic CS term." An unqualified import of general vocabulary is noise. Nothing clears the gate → write nothing. A clean "no durable term here" is correct. ## Per entry: the shape - Definition is one sentence: what the term means in this domain and what distinguishes it from its neighbors. Not a tutorial. - Second paragraph only for non-obvious behavioral rules: lifecycle, ownership invariants, cancellation/transition semantics. Never to elaborate the definition itself. - Retired synonyms → an aliases line directly under the definition: `*Avoid:* OldName, otherword`. When the team uses several words for one concept, pick the best and retire the rest; the glossary is the agreed vocabulary, not a record of every word ever used. ## The file stands on its own Each entry must teach its concept to a reader without access to the codebase, PR history, or chat. This rules out: - Implementation specifics: file paths, class/function names, table names, library calls. - Status fields, dates, owners on entries. - Current-config values that will change: specific thresholds, counts, enum values. State the behavior, not the number. - Links to PRs, issues, channels, milestones; version-specific claims ("currently X, migrating to Y"). Cross-references between entries *within* the file are fine; they resolve internally. If an entry leans on another **project-specific** term to make sense, that sibling term must also be defined here (an undefined project-specific sibling is itself a candidate). ## Organization Cluster concepts by domain relationship so the structure is easy to see: entities with their states, and processes with their stages. A flat list is fine while the file is small; reshape it as it grows. When relationships carry load-bearing meaning (ownership, cardinality, cross-entry lifecycle), capture them in a short `## Relationships` section near the top. Skip that section when entries stand alone. **Flagged ambiguities (tail of file):** when two terms were used interchangeably and the team settled a distinction, record it as a one-line note: *"'account' had been used for both Customer and User; these are distinct."* This tail is the audit trail for settled opinions. ## Reconciliation: idempotent merge, one definition per concept Reconcile; never append blindly. 1. Locate the file: `fd -g 'CONCEPTS.md' --max-depth 2`. Absent + a term clears the gate → create it; absent + nothing clears → do nothing. 2. Search for the term and its synonyms: `git grep -ni '<term>' CONCEPTS.md`. A hit means the concept exists: go to refresh, do not add a second entry. 3. New term → add one entry in the right cluster, per the schema above. 4. **Read the file back** to confirm the merge landed and created no duplicate or near-duplicate heading. ## Refresh: keep definitions matched to reality In `mode:refresh [scope]`, maintain `CONCEPTS.md` alongside `docs/solutions/`. Per in-scope concept, re-derive the meaning against current code and pick one outcome: | Outcome | When | Action | |---------|------|--------| | **Keep** | Definition still matches the code | No edit. Prefer no-write. | | **Refresh** | Meaning drifted; the term still exists | Rewrite the definition to current reality. | | **Consolidate** | Two entries name the same concept | Merge into the better name, retire the other as an alias. | | **Delete** | The concept's domain is gone from the code | Remove the entry. Age alone is never a reason. | Match the glossary to the code, not the reverse. No cosmetic churn: typo and prose-polish edits are not refreshes. Headless: skip questions, apply safe refreshes/deletes, leave genuinely ambiguous concepts untouched and report them. -
refresh.md 2.5 KB
# Refresh: maintain `docs/solutions/` against the current code Owner. autolearn/SKILL.md section 6 inlines the refresh loop. Do not recopy. Read this for `autolearn mode:refresh [scope]`. Classify every candidate doc into exactly one outcome: | Outcome | Meaning | Default action | |---------|---------|----------------| | **Keep** | Still accurate and useful | No edit. Report reviewed-and-trustworthy. | | **Update** | Core solution correct, references drifted | Evidence-backed in-place edits | | **Consolidate** | Two+ docs overlap heavily, both correct | Merge unique content into the canonical doc, delete the subsumed one | | **Replace** | Old guidance is now misleading, better answer known | Write a trustworthy successor, then delete the old | | **Delete** | No longer useful, applicable, or distinct | Delete the file | ## Execution notes - No candidate docs at all → report it and point the user at create mode. - Pick the lightest interaction path: Focused (1-2 files) → investigate, then recommend; Batch (up to ~8 mostly-independent docs) → grouped recommendations; Broad (9+, ambiguous, or repo-wide) → triage first (inventory frontmatter, cluster by area, spot-check whether referenced files still exist), then investigate in batches. - Investigators are read-only subagents: return path, evidence, recommended action, confidence, open questions; never write. Deletes, commits, and frontmatter metadata stay with the orchestrator. The one writing subagent is the Replace successor-drafter; even there the orchestrator validates the result, deletes the old file, and commits. - Tag memory-sourced findings `(auto memory [claude])`. - Consolidate reverse case: a doc that grew to cover several genuinely independent problems is a split candidate. - Replace successor-drafter input: the old doc's full content, an investigation-evidence summary (what changed, what the code does now, why the old guidance misleads), the target path + category, and the contents of `references/schema.md` + `assets/solution-template.md` (never invented from memory). `supersedes: [old-filename]` in the successor is optional. ## Interactive questions Most Updates and Consolidations apply directly without asking. Ask only when: the right action is genuinely ambiguous; about to Delete without all auto-delete criteria met; about to Consolidate with no clear-cut canonical; about to Replace. One question at a time, prefer multiple choice, lead with the recommended option. ## Commit One concern per commit, ODIN `Op:` trailer in the body. -
schema.md 5.3 KB
# Frontmatter contract: `docs/solutions/` Owner. autolearn/SKILL.md inlines the field contract. Do not recopy. Canonical schema for learning docs written by `autolearn`. Read this when classifying a track, assembling frontmatter, or validating. The validator (`scripts/validate-frontmatter.py`) catches only silent YAML corruption; you must still enforce the field and enum rules below. ## Two tracks `problem_type` picks the track. The track decides which extra fields are required. Pick the narrowest value; `best_practice` is the Knowledge fallback. | Track | problem_types | |-------|---------------| | **Bug** | `build_error`, `test_failure`, `runtime_error`, `performance_issue`, `database_issue`, `security_issue`, `ui_bug`, `integration_issue`, `logic_error` | | **Knowledge** | `best_practice`, `documentation_gap`, `workflow_issue`, `developer_experience`, `architecture_pattern`, `design_pattern`, `tooling_decision`, `convention` | ## Required fields (both tracks) - title: clear problem/topic title (string). - date: `YYYY-MM-DD`. - category: the `docs/solutions/` subdirectory (see Category map). - module: module or area affected (string). - problem_type: one enum value from the tracks table; determines the track. - component: component or subsystem involved (free-form string; keep consistent within a repo so frontmatter search works). - severity: one of `critical`, `high`, `medium`, `low`. ## Bug-track required fields - symptoms: array, 1-5 observable symptoms (errors, broken behavior). - root_cause: one of: `missing_association`, `missing_include`, `missing_index`, `wrong_api`, `scope_issue`, `thread_violation`, `async_timing`, `memory_leak`, `config_error`, `logic_error`, `test_isolation`, `missing_validation`, `missing_permission`, `missing_workflow_step`, `inadequate_documentation`, `missing_tooling`, `incomplete_setup`. - resolution_type: one of: `code_fix`, `migration`, `config_change`, `test_fix`, `dependency_update`, `environment_setup`, `workflow_improvement`, `documentation_update`, `tooling_addition`, `seed_data_update`. ## Knowledge-track fields No required fields beyond the shared core. All optional: - applies_when: array (≤5), conditions where the guidance applies. - symptoms: array (≤5), the gap or friction that prompted the guidance. - root_cause: from the bug-track enum, if there is a specific one. - resolution_type: from the bug-track enum, if a change was applied. ## Optional fields (both tracks) - related_components: array of other components involved. - tags: array (≤8) of search keywords, lowercase and hyphen-separated. ## Category map (problem_type → directory) | problem_type | directory | |---|---| | `build_error` | `docs/solutions/build-errors/` | | `test_failure` | `docs/solutions/test-failures/` | | `runtime_error` | `docs/solutions/runtime-errors/` | | `performance_issue` | `docs/solutions/performance-issues/` | | `database_issue` | `docs/solutions/database-issues/` | | `security_issue` | `docs/solutions/security-issues/` | | `ui_bug` | `docs/solutions/ui-bugs/` | | `integration_issue` | `docs/solutions/integration-issues/` | | `logic_error` | `docs/solutions/logic-errors/` | | `developer_experience` | `docs/solutions/developer-experience/` | | `workflow_issue` | `docs/solutions/workflow-issues/` | | `best_practice` | `docs/solutions/best-practices/` | | `documentation_gap` | `docs/solutions/documentation-gaps/` | | `architecture_pattern` | `docs/solutions/architecture-patterns/` | | `design_pattern` | `docs/solutions/design-patterns/` | | `tooling_decision` | `docs/solutions/tooling-decisions/` | | `convention` | `docs/solutions/conventions/` | Filename: `[sanitized-problem-slug].md`: no date suffix (the `date` field carries that). ## Validation rules Track from `problem_type`; shared required fields always present; bug track also requires `symptoms`, `root_cause`, `resolution_type`; knowledge track adds none. Enums match allowed values exactly, arrays respect item counts, `date` matches `YYYY-MM-DD`. ## Backward compatibility Pre-existing docs may carry bug-track fields (`symptoms`/`root_cause`/`resolution_type`) on a knowledge-track `problem_type`. These fields are harmless; leave them. Strip them only when rewriting the doc for other reasons. New docs follow the track rules above. ## YAML safety (array items) Strict YAML parsers (`yq`, `js-yaml` strict, PyYAML) misread array items that *start* with a reserved indicator as unquoted scalars. For any array-of-strings field (`symptoms`, `applies_when`, `tags`, `related_components`), wrap the value in double quotes when it starts with any of these commonly-hit indicators: `` ` `` `[` `]` `{` `}` `,` `*` `&` `!` `|` `>` `%` `@` `?` Also quote when the value contains `": "`: that punctuation confuses flow-style parsers. The list above is the set that actually shows up at the front of solution-doc values, not an exhaustive YAML indicator catalogue; when unsure, just quote, and let a real YAML parse be the backstop. Before (breaks strict YAML): ```yaml symptoms: - `flush-cache` does not restore in-container mDNS ``` After (parses cleanly): ```yaml symptoms: - "`flush-cache` does not restore in-container mDNS" ``` Scalar fields (`title:`, `module:`) have a separate failure mode, an unquoted ` #` truncates at the comment, an unquoted `: ` reframes as a mapping. `scripts/validate-frontmatter.py` catches those; quote and re-run until it exits 0.
-
-
scripts
-
validate-frontmatter.py 4.9 KB
#!/usr/bin/env python3 """Validate autolearn docs/solutions/ frontmatter for parser-safety issues. Usage: python3 validate-frontmatter.py <doc-path> Exit codes: 0 — frontmatter passes all checks 1 — validation failure (diagnostics on stderr) 2 — usage error (bad arguments, missing file) Scope: catches *parser-safety* issues — frontmatter that strict YAML parsers silently misread. It does NOT validate against the schema's required-field or enum-value rules (read references/schema.md for those). The intent is to prevent the silent-data-loss bug class where YAML's quoting rules truncate or reframe scalar values without raising. Checks (regex-based, no YAML parser dependency): 1. File starts and ends frontmatter with `---` lines (matched as full lines, not substrings — `----` and `---extra` are rejected) 2. No top-level scalar value contains ` #` unquoted — YAML reads space-then-# as a comment delimiter and silently drops the rest of the value 3. No top-level scalar value contains `: ` unquoted — strict parsers may read this as a nested mapping and reframe the value Reserved-indicator characters (`` ` ``, `*`, `&`, `!`, etc.) are deliberately NOT flagged: those produce loud parser errors downstream rather than silent corruption, so whatever consumes the doc already catches them. This validator exists for silent-corruption prevention, not lint. Pure-stdlib (no PyYAML or other third-party deps). Runs in <50ms typical. Error messages are concrete and actionable so the calling agent can fix and retry without ambiguity. """ import os import re import sys def usage_fail(msg: str) -> "NoReturn": sys.stderr.write(f"validate-frontmatter: {msg}\n") sys.exit(2) def main(argv: list[str]) -> int: if len(argv) != 2: usage_fail(f"usage: {os.path.basename(argv[0])} <doc-path>") doc_path = argv[1] if not os.path.isfile(doc_path): usage_fail(f"file not found: {doc_path}") with open(doc_path) as f: text = f.read() issues: list[str] = [] # Check 1: frontmatter delimiters. Match the delimiter as a complete line # whose stripped content is exactly `---`. Substring matching (e.g. # text.find("\n---", 4)) would falsely accept `----` or `---extra` as a # terminator and let malformed docs slip through to downstream parsers # that require a strict `---` line. lines = text.split("\n") if not lines or lines[0].rstrip() != "---": sys.stderr.write( f"FAIL: {doc_path}\n" f" file does not start with '---' frontmatter delimiter line\n" ) return 1 end_idx: int | None = None for i in range(1, len(lines)): if lines[i].rstrip() == "---": end_idx = i break if end_idx is None: sys.stderr.write( f"FAIL: {doc_path}\n" f" frontmatter not closed (no '---' line after the opening delimiter)\n" ) return 1 fm_text = "\n".join(lines[1:end_idx]) # Checks 2 & 3: silent-corruption quoting risks on top-level scalar fields. # Scan line-by-line and only flag top-level mapping entries (no leading # whitespace) whose value isn't already quoted/structured. for lineno, line in enumerate(fm_text.split("\n"), start=2): stripped = line.lstrip() if not stripped or stripped.startswith("#"): continue if ":" not in line: continue # Top-level mapping keys only — skip nested values and array items if line.startswith((" ", "\t")): continue # Skip pure list-marker lines like "- item" (can't be top-level in our # frontmatter convention, but be defensive) if stripped.startswith("- "): continue key, _, val = line.partition(":") val_stripped = val.strip() if not val_stripped: # Key with no value on this line — likely a parent of a nested # block (`tags:` followed by `- foo`). Nothing to validate here. continue # Already quoted or structured (block scalar, flow collection) if val_stripped[0] in '"\'[{|>': continue if re.search(r"\s#", val_stripped): issues.append( f"line {lineno}: '{key.strip()}' value contains ' #' — quote it. " "YAML treats space-then-# as a comment delimiter and silently " "drops the rest of the value." ) if re.search(r":\s", val_stripped): issues.append( f"line {lineno}: '{key.strip()}' value contains ': ' — quote it. " "Strict YAML parsers may treat this as a nested mapping." ) if issues: sys.stderr.write(f"FAIL: {doc_path}\n") for issue in issues: sys.stderr.write(f" {issue}\n") return 1 print(f"OK: {doc_path}") return 0 if __name__ == "__main__": sys.exit(main(sys.argv))
-
-
SKILL.md 19 KB
--- name: autolearn description: 'Use when a verified non-trivial fix lands or existing solution docs need refresh. Not for unverified fixes.' --- # Autolearn ## Contract | Field | Bound contract | |---|---| | Trigger | A non-trivial fix has been verified (observed working, not hoped working), or explicit autolearn or refresh invocation. | | Authority | Reversible local: writes only the operating repo's docs/solutions/ and repo-root CONCEPTS.md; rollback is version control. No remote mutation. | | Side effect | Writes or refreshes docs/solutions/ learning docs and CONCEPTS.md; stages only the surfaces this skill wrote or edited. | | Done | A validated learning or concept entry exists, or an explicit determination that nothing qualifies. | ## Inputs - The verified fix or solved problem, from conversation history or codebase. Must be supplied or derivable from context. - Optional: `mode:refresh [scope]` to maintain existing docs; `mode:headless` for non-interactive operation. - Optional: an injected auto-memory block (supplementary context, not primary evidence). ## Procedure ### 0. Route the mode Strip `mode:` tokens from arguments before treating the remainder as context or scope. - **Capture** (default): document one solved problem into docs/solutions/. - Vocabulary capture: a durable, reusable project term surfaces; reconcile CONCEPTS.md. - Memory handoff: a fact about the user, preferences, or cross-project context surfaces; do not write it into docs/solutions/ or CONCEPTS.md; surface it as a memory-handoff candidate for the memory system to capture. - Refresh: maintain existing docs/solutions/ and CONCEPTS.md. - Headless: overlays any mode; skip all questions, never pause, apply safe actions, mark uncertain as stale. Fire automatically on a trigger phrase ("that worked", "it's fixed", "working now", "problem solved", "verified the fix", "tests pass now", "build succeeds", "that approach failed") or after a verified non-trivial fix. Auto-firing is permission to evaluate, not permission to fabricate. One run can do all three repo-scoped actions: write a learning doc, reconcile a concept, and flag a memory-handoff candidate. Done when: the mode is routed and `mode:` tokens are stripped from arguments. ### 1. Reject-by-default gate A doc is earned, not assumed. Verify all three preconditions: 1. The problem is solved, not in progress. An abandoned attempt counts as solved once it is finished (branch dead, decision to stop made); its learning is the anti-pattern: what was tried, the specific reason it failed, and the condition under which it would be worth trying again. 2. The solution is verified: observed working, not hoped working. 3. It was non-trivial, not a typo or obvious one-liner. Then apply the reject-by-default gate (all three filters in order): 1. **Would I forget this?** Skip baseline knowledge anyone in this codebase already carries. 2. **Already covered?** If an existing docs/solutions/ doc covers it, updating that doc beats spawning a second one. A duplicate is drift, not knowledge. 3. **Universal or local?** Scope-qualify the claim. Say when a quirk is repo-specific and when a truth is general. An unqualified claim is a future trap. The gate governs CONCEPTS.md entries too: a term earns a slot only when its precise local meaning would otherwise be forgotten, it is not already defined there, and it is scope-qualified to this project rather than general programming or domain English. If nothing clears the gate, say so in one line and exit. A clean "nothing worth capturing here" is a valid, correct result. Done when: all three preconditions and all three gate filters are evaluated, with a pass or a one-line "nothing qualifies" exit. ### 2. Capture: research (parallel, read-only) Scan any injected auto-memory block for entries related to the problem. If it is absent or empty, skip it. If relevant entries exist, carry them as a labeled supplementary context block. Memory is supplementary; when it conflicts with the codebase or conversation, prefer the codebase or conversation. Tag any memory-derived line that lands in the final doc with `(auto memory [claude])`. Dispatch three subagents in parallel. Each returns text and writes nothing. 1. **Context Analyzer**: from the problem, decide the track (bug vs knowledge), the problem_type, the category directory, and a slug filename (`[sanitized-problem-slug].md`, no date suffix). Return a frontmatter skeleton and which track applies. Do not invent enum values or fields. 2. **Solution Extractor**: extract the substance from the conversation, folding in the auto-memory excerpt as supplementary evidence. Bug track: Problem, Symptoms, What Didn't Work, Solution (with code), Why This Works, Prevention. Knowledge track: Context, Guidance, Why This Matters, When to Apply, Examples. 3. **Related-Docs Finder**: grep docs/solutions/ (`title:`, `tags:`, `module:`, `component:` on extracted keywords; narrow to the candidate subdirectory when known), read only frontmatter of candidates, fully read only strong matches. Score overlap across problem statement, root cause, solution approach, referenced files, prevention rules: High (4-5 dimensions), Moderate (2-3), Low (0-1). Return links and the overlap verdict. Wait for all three before assembling. Done when: all three subagents return and their results are assembled for the write step. ### 3. Capture: assemble and write 1. **Overlap gate**: High (4-5) → update the existing doc, keep its path and frontmatter, add `last_updated: YYYY-MM-DD`. Moderate (2-3) → create normally; note as a refresh/consolidation candidate. Low or none → create normally. Done when: the overlap gate decision is made. 2. Read `assets/solution-template.md`; assemble the doc with the track's section structure. Done when: the doc is assembled with the correct track structure. 3. Frontmatter per the Solution schema section; apply the YAML-safety quoting rule to array items. Done when: frontmatter follows the Solution schema with YAML-safe quoting. 4. `mkdir -p docs/solutions/<category>/`, write `docs/solutions/<category>/<slug>.md`. Done when: the doc file is written to the correct category directory. 5. Validate: `python3 scripts/validate-frontmatter.py <path>`. Exit 0 = parser-safe; exit 1 names the offending field. Quote, re-write, re-run until 0. Done when: the validator exits 0. 6. Read the file back to confirm it landed as intended. Done when: the file is read back and confirmed correct. 7. **Concept reconciliation** (optional, when warranted): if the run surfaced a durable project term that clears the gate, reconcile CONCEPTS.md per step 5. Done when: concept reconciliation is performed or skipped. ### 4. Refresh check (selective, not automatic) Suggest refresh with a narrow scope only when the new fix contradicts or supersedes an older doc, the work was a refactor/migration/rename/dependency-bump that likely invalidated references, or the Related-Docs Finder surfaced strong refresh candidates or moderate overlap. Otherwise do not. Capture the new learning first; refresh is targeted maintenance after. Done when: a refresh recommendation is made or explicitly skipped. ### 5. Vocabulary capture: CONCEPTS.md CONCEPTS.md at the operating repo root is the shared-vocabulary glossary. It holds words with a precise meaning in this codebase, with one definition per concept. Other knowledge-capture processes may also write to this shared surface; always follow the one-definition-per-concept discipline. 1. Locate the file: `fd -g 'CONCEPTS.md' --max-depth 2`. Absent and a term clears the gate → create it. Absent and nothing clears → write nothing; never scaffold an empty file. Done when: the file is located or its absence is handled. 2. Search for the term and its synonyms: `git grep -ni '<term>' CONCEPTS.md`. A hit means the concept exists: refresh on drift, never add a second entry. Done when: the term is searched and existing entries are identified. 3. New term → add one entry: a one-sentence definition of what it means here and what distinguishes it from neighbors; a second paragraph only for non-obvious behavioral rules. Retire synonyms as an `*Avoid:*` aliases line. No file paths, dates, owners, or version-specific claims. The file stands on its own. Done when: the new entry is written with its definition and alias line. 4. Read the file back to confirm the merge landed and created no duplicate heading. Done when: the file is read back with no duplicate headings. ### 6. Refresh: maintain existing docs Find every `.md` under `docs/solutions/`, excluding `README.md` and anything under `_archived/`. Top-level records written by `compound` carry that skill's own seven-field schema (`type`, `tags`, `confidence`, `date`, `source`, `Context`, `Implication`); the Solution schema below does not apply to them. Read them for overlap and contradiction, and never rewrite one to the Solution schema or mark it stale for lacking those fields. A `[scope]` hint narrows it: try in order, stop at first hit: (1) subdirectory name, (2) frontmatter `module`/`component`/`tags` match, (3) filename partial match, (4) content keyword. No match → report the miss and exit. No scope hint → process everything. Classify every candidate doc into exactly one outcome: | Outcome | When | Action | |---------|------|--------| | Keep | Still accurate and useful | No edit. Report reviewed-and-trustworthy. | | Update | Core solution correct, references drifted | Evidence-backed in-place edits. | | Consolidate | Two or more docs overlap heavily, both correct | Merge unique content into the canonical doc, delete the subsumed one. | | Replace | Old guidance is now misleading, better answer known | Write a trustworthy successor, then delete the old. | | Delete | No longer useful, applicable, or distinct | Delete the file. | Core rules: evidence informs judgment, not a mechanical scorecard; prefer no-write Keep; match docs to reality, not the reverse; be decisive; no low-value churn (no typo fixes, prose polish, cosmetic edits); delete, don't archive (no `_archived/`, git history preserves everything). Investigate each doc: read it, cross-reference claims against current codebase. Check references (file paths, symbols, modules: still exist or moved?), solution (does the fix still match how the code works today?), code examples (do snippets reflect current implementation?), related docs (cross-referenced learnings still present and consistent?), overlap (another in-scope doc covering the same domain?). Update vs Replace boundary: references moved but approach still correct → Update; recommended solution conflicts with current code or architecture changed → Replace; if rewriting the Solution section, it is Replace, not Update. Age alone is not a stale signal. Check for a successor before deleting. Document-set analysis: step back and judge the set as a whole. High overlap across 3+ dimensions → strong Consolidate signal. Older narrow precursor vs newer canonical doc → consolidation candidate. Retrieval-value test: does keeping these separate help discoverability or just create drift risk? Cross-doc contradictions are more urgent than individual staleness. Execute per action: - Keep: no edit, summarize why it remains trustworthy. - Update: in-place edits only when solution is still substantively correct. Not Update territory: typo/style-only edits, or old fix is now an anti-pattern → Replace. - Consolidate: confirm canonical doc (broader, more current); extract unique content from subsumed doc(s); merge into canonical; repoint cross-references; delete subsumed. Three or more overlapping → process pairwise. - Replace: process one at a time. Write a successor, validate with `scripts/validate-frontmatter.py` until exit 0, then delete the old file. Evidence insufficient → mark stale in place: add `status: stale`, `stale_reason`, `stale_date: YYYY-MM-DD`. - Delete: only when referenced code/workflow is gone, problem domain no longer exists, and inbound links absent or unambiguously decorative. Before unlinking, grep repo markdown for citations. Decorative → delete fine, clean up citation; substantive → Replace signal; mixed/unclear → stale-mark. A late-discovered citation that is anything but unambiguously decorative stops the Delete. Headless variant: skip all questions, never pause. Process every in-scope doc. Attempt all safe actions. Uncertain → mark `status: stale`. A write that fails is recorded as Recommended, not retried. Emit a report split into Applied and Recommended. Report: ``` Refresh Summary =============== Scanned: N docs Kept: X Updated: Y Consolidated: C Replaced: Z Deleted: W Marked stale: S ``` Then per file: path, classification, evidence, action taken or recommended. After refreshing, check whether the repo's documentation would lead an agent to discover and search `docs/solutions/`. If not, surface a discoverability recommendation in the report. Do not edit instruction files. Done when: every in-scope doc is classified and acted on, and the refresh report is emitted. ### 7. Commit One learning per commit. Stage only the surfaces this skill wrote or edited (a solution doc, CONCEPTS.md, or both). Never stage other dirty files. Commit locally by the operating repo's normal flow. Skip the commit if nothing was modified. Done when: the commit is made with only this skill's surfaces staged, or skipped when nothing was modified. ## Failure and recovery - Nothing qualifies: if no fix clears the reject-by-default gate, state "nothing worth capturing here" in one line and exit. This is a valid result, not a failure. - Validation failure: `scripts/validate-frontmatter.py` exits 1 naming the offending field. Quote the value, re-write the file, re-run until exit 0. Do not declare success while validation fails. - Overlap collision: High overlap with an existing doc → update the existing doc, do not create a duplicate. Creating a duplicate when an update was warranted is drift, not knowledge. - Insufficient evidence for Replace: mark the doc stale in place (`status: stale`, `stale_reason`, `stale_date`) rather than guessing a successor. - Late-discovered citation blocks Delete: reclassify to stale-mark or Replace; do not delete. - Partial-result rule: if a write fails during refresh, record it as Recommended, do not retry into a mess. - Rollback: all writes are to local files under version control. Revert the commit or restore the file from git history. ## Output One validated learning doc at `docs/solutions/<category>/<slug>.md` (or updated existing doc), optionally a CONCEPTS.md entry and a memory-handoff candidate, or a one-line "nothing qualifies" determination: in refresh mode, a report classifying every scanned doc into Keep/Update/Consolidate/Replace/Delete/stale with applied and recommended actions. ## Solution schema Owner of the field contract is references/schema.md. Do not recopy. Canonical frontmatter contract for `docs/solutions/` learning docs. The validator (`scripts/validate-frontmatter.py`) only catches silent YAML corruption; the field and enum rules below remain binding. ### Two tracks `problem_type` picks the track. The track decides which extra fields are required. Pick the narrowest value; `best_practice` is the Knowledge fallback. | Track | problem_types | |-------|---------------| | Bug | `build_error`, `test_failure`, `runtime_error`, `performance_issue`, `database_issue`, `security_issue`, `ui_bug`, `integration_issue`, `logic_error` | | Knowledge | `best_practice`, `documentation_gap`, `workflow_issue`, `developer_experience`, `architecture_pattern`, `design_pattern`, `tooling_decision`, `convention` | ### Required fields (both tracks) - `title`: clear problem/topic title (string). - `date`: `YYYY-MM-DD`. - `category`: the `docs/solutions/` subdirectory (see Category map). - `module`: module or area affected (string). - `problem_type`: one enum value from the tracks table; determines the track. - `component`: component or subsystem involved (free-form string; keep consistent within a repo so frontmatter search works). - `severity`: one of `critical`, `high`, `medium`, `low`. ### Bug-track required fields - `symptoms`: array, 1-5 observable symptoms (errors, broken behavior). - `root_cause`: one of: `missing_association`, `missing_include`, `missing_index`, `wrong_api`, `scope_issue`, `thread_violation`, `async_timing`, `memory_leak`, `config_error`, `logic_error`, `test_isolation`, `missing_validation`, `missing_permission`, `missing_workflow_step`, `inadequate_documentation`, `missing_tooling`, `incomplete_setup`. - `resolution_type`: one of: `code_fix`, `migration`, `config_change`, `test_fix`, `dependency_update`, `environment_setup`, `workflow_improvement`, `documentation_update`, `tooling_addition`, `seed_data_update`. ### Knowledge-track fields No required fields beyond the shared core. All optional: - `applies_when`: array (≤5), conditions where the guidance applies. - `symptoms`: array (≤5), the gap or friction that prompted the guidance. - `root_cause`: from the bug-track enum, if there is a specific one. - `resolution_type`: from the bug-track enum, if a change was applied. ### Optional fields (both tracks) - `related_components`: array of other components involved. - `tags`: array (≤8) of search keywords, lowercase and hyphen-separated. ### Category map (problem_type → directory) | problem_type | directory | |---|---| | `build_error` | `docs/solutions/build-errors/` | | `test_failure` | `docs/solutions/test-failures/` | | `runtime_error` | `docs/solutions/runtime-errors/` | | `performance_issue` | `docs/solutions/performance-issues/` | | `database_issue` | `docs/solutions/database-issues/` | | `security_issue` | `docs/solutions/security-issues/` | | `ui_bug` | `docs/solutions/ui-bugs/` | | `integration_issue` | `docs/solutions/integration-issues/` | | `logic_error` | `docs/solutions/logic-errors/` | | `developer_experience` | `docs/solutions/developer-experience/` | | `workflow_issue` | `docs/solutions/workflow-issues/` | | `best_practice` | `docs/solutions/best-practices/` | | `documentation_gap` | `docs/solutions/documentation-gaps/` | | `architecture_pattern` | `docs/solutions/architecture-patterns/` | | `design_pattern` | `docs/solutions/design-patterns/` | | `tooling_decision` | `docs/solutions/tooling-decisions/` | | `convention` | `docs/solutions/conventions/` | Filename: `[sanitized-problem-slug].md`, no date suffix (the `date` field carries that). ### Validation rules Track from `problem_type`; shared required fields always present; bug track also requires `symptoms`, `root_cause`, `resolution_type`; knowledge track adds none. Enums match allowed values exactly, arrays respect item counts, `date` matches `YYYY-MM-DD`. ### YAML safety (array items) Strict YAML parsers misread array items that start with a reserved indicator as unquoted scalars. For any array-of-strings field (`symptoms`, `applies_when`, `tags`, `related_components`), wrap the value in double quotes when it starts with any of: `` ` `` `[` `]` `{` `}` `,` `*` `&` `!` `|` `>` `%` `@` `?`. Also quote when the value contains `": "`. Scalar fields (`title:`, `module:`) have a separate failure mode: an unquoted ` #` truncates at the comment, an unquoted `: ` reframes as a mapping. `scripts/validate-frontmatter.py` catches those; quote and re-run until it exits 0.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.