codexspec 0.7.11__tar.gz → 0.7.12__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. {codexspec-0.7.11 → codexspec-0.7.12}/PKG-INFO +1 -1
  2. {codexspec-0.7.11 → codexspec-0.7.12}/pyproject.toml +1 -1
  3. {codexspec-0.7.11 → codexspec-0.7.12}/src/codexspec/__init__.py +1 -1
  4. {codexspec-0.7.11 → codexspec-0.7.12}/src/codexspec/profile.py +30 -11
  5. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/distill.md +72 -2
  6. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/evolve.md +2 -0
  7. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/onboard.md +4 -4
  8. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/specify.md +1 -1
  9. {codexspec-0.7.11 → codexspec-0.7.12}/.gitignore +0 -0
  10. {codexspec-0.7.11 → codexspec-0.7.12}/LICENSE +0 -0
  11. {codexspec-0.7.11 → codexspec-0.7.12}/README.md +0 -0
  12. {codexspec-0.7.11 → codexspec-0.7.12}/codexspec-icon.svg +0 -0
  13. {codexspec-0.7.11 → codexspec-0.7.12}/codexspec-logo-dark.svg +0 -0
  14. {codexspec-0.7.11 → codexspec-0.7.12}/codexspec-logo-light.svg +0 -0
  15. {codexspec-0.7.11 → codexspec-0.7.12}/scripts/bash/check-i18n-completeness.sh +0 -0
  16. {codexspec-0.7.11 → codexspec-0.7.12}/scripts/bash/check-i18n-structure.sh +0 -0
  17. {codexspec-0.7.11 → codexspec-0.7.12}/scripts/bash/check-prerequisites.sh +0 -0
  18. {codexspec-0.7.11 → codexspec-0.7.12}/scripts/bash/common.sh +0 -0
  19. {codexspec-0.7.11 → codexspec-0.7.12}/scripts/bash/create-new-feature.sh +0 -0
  20. {codexspec-0.7.11 → codexspec-0.7.12}/scripts/bash/review-context.sh +0 -0
  21. {codexspec-0.7.11 → codexspec-0.7.12}/scripts/powershell/check-prerequisites.ps1 +0 -0
  22. {codexspec-0.7.11 → codexspec-0.7.12}/scripts/powershell/common.ps1 +0 -0
  23. {codexspec-0.7.11 → codexspec-0.7.12}/scripts/powershell/create-new-feature.ps1 +0 -0
  24. {codexspec-0.7.11 → codexspec-0.7.12}/scripts/powershell/review-context.ps1 +0 -0
  25. {codexspec-0.7.11 → codexspec-0.7.12}/src/codexspec/commands/__init__.py +0 -0
  26. {codexspec-0.7.11 → codexspec-0.7.12}/src/codexspec/commands/installer.py +0 -0
  27. {codexspec-0.7.11 → codexspec-0.7.12}/src/codexspec/i18n.py +0 -0
  28. {codexspec-0.7.11 → codexspec-0.7.12}/src/codexspec/idea.md +0 -0
  29. {codexspec-0.7.11 → codexspec-0.7.12}/src/codexspec/integrations/__init__.py +0 -0
  30. {codexspec-0.7.11 → codexspec-0.7.12}/src/codexspec/integrations/base.py +0 -0
  31. {codexspec-0.7.11 → codexspec-0.7.12}/src/codexspec/integrations/claude.py +0 -0
  32. {codexspec-0.7.11 → codexspec-0.7.12}/src/codexspec/integrations/codex.py +0 -0
  33. {codexspec-0.7.11 → codexspec-0.7.12}/src/codexspec/translator.py +0 -0
  34. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/analyze.md +0 -0
  35. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/checklist.md +0 -0
  36. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/clarify.md +0 -0
  37. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/commit-staged.md +0 -0
  38. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/config.md +0 -0
  39. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/constitution.md +0 -0
  40. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/debug.md +0 -0
  41. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/generate-spec.md +0 -0
  42. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/implement-tasks.md +0 -0
  43. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/plan-to-tasks.md +0 -0
  44. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/pr.md +0 -0
  45. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/quick.md +0 -0
  46. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/release-notes.md +0 -0
  47. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/review-code.md +0 -0
  48. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/review-design.md +0 -0
  49. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/review-plan.md +0 -0
  50. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/review-spec.md +0 -0
  51. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/review-tasks.md +0 -0
  52. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/spec-to-design.md +0 -0
  53. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/spec-to-plan.md +0 -0
  54. {codexspec-0.7.11 → codexspec-0.7.12}/templates/commands/tasks-to-issues.md +0 -0
  55. {codexspec-0.7.11 → codexspec-0.7.12}/templates/docs/checklist-template.md +0 -0
  56. {codexspec-0.7.11 → codexspec-0.7.12}/templates/docs/constitution-template.md +0 -0
  57. {codexspec-0.7.11 → codexspec-0.7.12}/templates/docs/design-template.md +0 -0
  58. {codexspec-0.7.11 → codexspec-0.7.12}/templates/docs/plan-template-detailed.md +0 -0
  59. {codexspec-0.7.11 → codexspec-0.7.12}/templates/docs/plan-template-simple.md +0 -0
  60. {codexspec-0.7.11 → codexspec-0.7.12}/templates/docs/requirements-template.md +0 -0
  61. {codexspec-0.7.11 → codexspec-0.7.12}/templates/docs/spec-template-detailed.md +0 -0
  62. {codexspec-0.7.11 → codexspec-0.7.12}/templates/docs/spec-template-simple.md +0 -0
  63. {codexspec-0.7.11 → codexspec-0.7.12}/templates/docs/tasks-template-detailed.md +0 -0
  64. {codexspec-0.7.11 → codexspec-0.7.12}/templates/docs/tasks-template-simple.md +0 -0
  65. {codexspec-0.7.11 → codexspec-0.7.12}/templates/translations/de.json +0 -0
  66. {codexspec-0.7.11 → codexspec-0.7.12}/templates/translations/en.json +0 -0
  67. {codexspec-0.7.11 → codexspec-0.7.12}/templates/translations/es.json +0 -0
  68. {codexspec-0.7.11 → codexspec-0.7.12}/templates/translations/fr.json +0 -0
  69. {codexspec-0.7.11 → codexspec-0.7.12}/templates/translations/ja.json +0 -0
  70. {codexspec-0.7.11 → codexspec-0.7.12}/templates/translations/ko.json +0 -0
  71. {codexspec-0.7.11 → codexspec-0.7.12}/templates/translations/pt-BR.json +0 -0
  72. {codexspec-0.7.11 → codexspec-0.7.12}/templates/translations/zh-CN.json +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: codexspec
3
- Version: 0.7.11
3
+ Version: 0.7.12
4
4
  Summary: CodexSpec - A Requirements-First SDD toolkit for Claude Code
5
5
  Project-URL: Homepage, https://github.com/Zts0hg/codexspec
6
6
  Project-URL: Repository, https://github.com/Zts0hg/codexspec
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "codexspec"
3
- version = "0.7.11"
3
+ version = "0.7.12"
4
4
  description = "CodexSpec - A Requirements-First SDD toolkit for Claude Code"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -44,7 +44,7 @@ from .profile import ensure_profile_scaffold, inject_profile_block
44
44
  from .translator import SUPPORTED_LANGUAGES, translate
45
45
 
46
46
  # Version info
47
- __version__ = "0.7.11"
47
+ __version__ = "0.7.12"
48
48
  __author__ = "CodexSpec Team"
49
49
 
50
50
  # Constitution file path constants
@@ -4,13 +4,13 @@ Wires a user project's ``.codexspec/profile/`` into the AI context files so that
4
4
  knowledge distilled by ``/codexspec:distill`` is consulted in later work.
5
5
 
6
6
  Store layout: **one record per file** under a per-category directory
7
- (``constraints/`` ``conventions/`` ``pitfalls/`` ``decisions/``). Because parallel
8
- feature branches each add differently-named record files, their distilled
9
- knowledge merges without conflict.
7
+ (``constraints/`` ``conventions/`` ``pitfalls/`` ``decisions/`` ``strategies/``
8
+ ``runbooks/``). Because parallel feature branches each add differently-named
9
+ record files, their distilled knowledge merges without conflict.
10
10
 
11
11
  Two concerns live here:
12
12
 
13
- - ``ensure_profile_scaffold`` — create the four category directories (each kept
13
+ - ``ensure_profile_scaffold`` — create the six category directories (each kept
14
14
  by a ``.gitkeep``) so every injected reference resolves, independent of whether
15
15
  any knowledge has been distilled yet.
16
16
  - ``render_profile_block`` / ``inject_profile_block`` — render a bounded,
@@ -27,7 +27,14 @@ from pathlib import Path
27
27
 
28
28
  # Ordered: constraints first (highest weight, honored first). Each is a directory
29
29
  # holding one record per file.
30
- PROFILE_CATEGORIES = ("constraints", "conventions", "pitfalls", "decisions")
30
+ PROFILE_CATEGORIES = (
31
+ "constraints",
32
+ "conventions",
33
+ "pitfalls",
34
+ "decisions",
35
+ "strategies",
36
+ "runbooks",
37
+ )
31
38
 
32
39
  PROFILE_BLOCK_START = "<!-- CODEXSPEC PROFILE START -->"
33
40
  PROFILE_BLOCK_END = "<!-- CODEXSPEC PROFILE END -->"
@@ -43,24 +50,33 @@ _PROFILE_BLOCK = "".join(
43
50
  "**Project constraints (highest priority — read these FIRST):** before any non-trivial work you MUST ",
44
51
  "read every record under `.codexspec/profile/constraints/` — the project's hard prohibitions ",
45
52
  "(严禁 / 仅允许). Honor them before anything else.\n\n",
46
- "**Project profile — consult on demand when relevant to the task** ",
53
+ "**Actively recall relevant knowledge before non-trivial work.** Do not wait to stumble on it: ",
54
+ "scan the record headings and their `scope/when` (and, for strategies, `trigger`) lines across the ",
55
+ "categories below, and read every record whose condition matches the task you are about to start ",
47
56
  "(each directory holds one record per file):\n\n",
48
57
  "- `.codexspec/profile/conventions/` — cross-feature conventions / steering; ",
49
58
  "read before adopting a pattern, structure, or naming choice.\n",
50
59
  "- `.codexspec/profile/pitfalls/` — known traps and their workarounds; ",
51
60
  "read before implementing or debugging in an area that may have bitten before.\n",
52
61
  "- `.codexspec/profile/decisions/` — past cross-feature / architectural decisions; ",
53
- "read before deciding in the same area, to reuse prior rationale rather than re-litigate it.\n\n",
62
+ "read before deciding in the same area, to reuse prior rationale rather than re-litigate it.\n",
63
+ "- `.codexspec/profile/strategies/` — metacognitive trigger→action rules (and `scope: self` notes on ",
64
+ "the agent's own recurring slips); read before choosing an approach or when a fix is not converging.\n",
65
+ "- `.codexspec/profile/runbooks/` — ordered multi-step procedures with failure recovery; ",
66
+ "read before carrying out a known multi-step task.\n\n",
54
67
  "Read the full record — each carries a `status` of `candidate` or `vetted`; ",
55
68
  "weight `candidate` items with appropriate caution. A directory may be empty ",
56
- "until `/codexspec:distill` has captured knowledge.\n",
69
+ "until `/codexspec:distill` has captured knowledge.\n\n",
70
+ "**Capture knowledge as you go.** When this session produces reusable cross-feature knowledge — even ",
71
+ "in plain chat or a non-SDD fix — run `/codexspec:distill` near that moment rather than only at ",
72
+ "wrap-up. It is non-blocking and early-exits when there is nothing new.\n",
57
73
  f"{PROFILE_BLOCK_END}\n",
58
74
  ]
59
75
  )
60
76
 
61
77
 
62
78
  def ensure_profile_scaffold(target_dir: Path) -> Path:
63
- """Create ``.codexspec/profile/`` and its four category directories if absent.
79
+ """Create ``.codexspec/profile/`` and its six category directories if absent.
64
80
 
65
81
  Each category is a directory of one-record-per-file entries; a ``.gitkeep``
66
82
  keeps an empty category tracked so every pointer resolves. Idempotent and
@@ -79,10 +95,13 @@ def ensure_profile_scaffold(target_dir: Path) -> Path:
79
95
  def render_profile_block() -> str:
80
96
  """Render the bounded managed profile block.
81
97
 
82
- Identical for CLAUDE.md and AGENTS.md: constraints and the three on-demand
98
+ Identical for CLAUDE.md and AGENTS.md: constraints and the five on-demand
83
99
  categories are all delivered as pointers to their directories — no ``@import``
84
100
  anywhere — so the block is channel-neutral and the store can be
85
- one-file-per-record directories that merge without conflict.
101
+ one-file-per-record directories that merge without conflict. The block also
102
+ directs active recall (scan record ``scope/when``/``trigger`` and read matches
103
+ before non-trivial work) and near-moment ``distill`` capture; it is a fixed
104
+ directive whose size is independent of how many records the profile holds.
86
105
  """
87
106
  return _PROFILE_BLOCK
88
107
 
@@ -23,6 +23,8 @@ Converse in the interaction language and author artifacts in the document langua
23
23
  `distill` extracts the reusable, cross-feature knowledge produced during work and persists it to the project-level store `.codexspec/profile/`. It runs two ways:
24
24
 
25
25
  - **Auto (primary)**: embedded in wrap-up commands (`implement-tasks` on completion, `commit-staged`, `pr`), gated by `workflow.auto_distill` in `.codexspec/config.yml` (**default enabled**; disabled only when explicitly set to the literal `false`).
26
+ - **Near-moment (ambient)**: driven by the profile block's "capture knowledge as you go" rule, distill may be invoked **near the moment** reusable cross-feature knowledge is produced — in **any session**, including plain chat or a **non-SDD fix** that never reaches a wrap-up command. This is the primary way knowledge from ad-hoc work is captured at all.
27
+ - **Long-run**: in a long-running `implement-tasks`, distill **along the way** near each knowledge-producing event rather than only at the very end, so mid-task evidence is not lost to context compaction; the end-of-task `auto_distill` still runs as a **backstop**.
26
28
  - **Manual (fallback)**: invoked directly on the supplied or most-recent interaction segment.
27
29
 
28
30
  distill is **non-blocking and non-interactive**: it never prompts, never gates another command, and **early-exits without writing** when the delta contains nothing reusable.
@@ -42,12 +44,16 @@ Apply this boundary test to every candidate: **"Would a single feature's `requir
42
44
 
43
45
  ## The profile store: `.codexspec/profile/`
44
46
 
45
- Four **category directories**, each holding **one record per file** (`<id>.md`) with **only current-effective** knowledge — dense, with no "retired" section (git history is the ledger). One-file-per-record is deliberate: parallel feature branches each add differently-named files, so distilled knowledge merges without conflict. Create the directory and record file on first write.
47
+ Six **category directories**, each holding **one record per file** (`<id>.md`) with **only current-effective** knowledge — dense, with no "retired" section (git history is the ledger). One-file-per-record is deliberate: parallel feature branches each add differently-named files, so distilled knowledge merges without conflict. Create the directory and record file on first write.
46
48
 
47
49
  - `constraints/` — negative constraints (`严禁 / 仅允许`). These carry the **highest** weight and MUST be honored first.
48
50
  - `conventions/` — positive cross-feature conventions / steering.
49
51
  - `pitfalls/` — cross-feature traps and their workarounds.
50
52
  - `decisions/` — cross-feature / architectural decisions only (ADR-lite). **Never** single-feature requirement rationale.
53
+ - `strategies/` — metacognitive `trigger → action` rules: when you recognize signal X, switch to approach Y. A **self-model** (knowledge about the agent's own recurring slips in this project) lives here too, marked `scope: self`. A strategy is the layer **above** a pitfall — the transferable "what to do when" generalized across many specific traps.
54
+ - `runbooks/` — ordered multi-step procedures with failure recovery: how to carry out a known multi-step task (e.g. a release), step by step, including what to do when a step fails.
55
+
56
+ There is **no** `facts/` category — a bare fact with no "therefore do X" is either feature-scoped (leave it in `requirements.md`) or belongs as a `convention`/`constraint` with an evidence anchor.
51
57
 
52
58
  ### Record format — `claim` and `evidence` physically separated
53
59
 
@@ -55,7 +61,7 @@ Every record MUST separate the distilled claim from the evidence it rests on:
55
61
 
56
62
  - `id` — **type letter + full source-feature id + local sequence**, e.g. `P-2026-0812-14054p-1` or `Con-2026-0812-14054p-1`. It is **both** the record's `### <id>: <title>` heading **and its filename** (`pitfalls/P-2026-0812-14054p-1.md`). The **source-feature id** is the distilling feature's full spec-dir id `{YYYY-MMDD-HHMM}{rr}` (e.g. `2026-0812-14054p`); it is globally unique by the timestamp+random scheme spec directories use, so records distilled on parallel feature branches never collide on id **or filename** (they merge with no conflict). Keep the **full** id (not a short tail) so the record is self-describing: the date supports recency/staleness reading, and the feature id ties the record to its originating change for decision context and scope. When distilling with no feature context, generate a fresh `{YYYY-MMDD-HHMM}{rr}` id now (same convention as create-new-feature). **Never** use a bare sequential id such as `P-001` — those collide across parallel branches.
57
63
  - `claim` — one-sentence reusable **summary** (a title line, not the actionable body — for a `pitfall` the usable content lives in the three body parts below, not in this sentence).
58
- - `type` — `convention` | `constraint` | `pitfall` | `decision` (`constraint` = highest priority).
64
+ - `type` — `convention` | `constraint` | `pitfall` | `decision` | `strategy` | `runbook` (`constraint` = highest priority).
59
65
  - `scope/when` — natural-language applicability condition (e.g. "when editing Python code"); omit for global. **No formal syntax.**
60
66
  - `evidence.facts` — the concrete observations behind it; **quote the user's original words, do not paraphrase**.
61
67
  - `evidence.state` — the context/validity when true (feature / commit / config; still valid?).
@@ -70,6 +76,20 @@ Every record MUST separate the distilled claim from the evidence it rests on:
70
76
 
71
77
  If you cannot state all three, the pitfall is not yet understood well enough to record. `convention` / `constraint` / `decision` records usually need only `claim` + `evidence`; this three-part body is required specifically for traps.
72
78
 
79
+ **Strategy records carry a `trigger → action` body.** A `strategy` MUST, beyond `claim` and `evidence`, spell out two parts:
80
+
81
+ - `trigger` — the **signature** by which you recognize you are in this situation (e.g. "a substring contract test fails", "a fix is not converging after several attempts"). This is what lets the strategy be recalled by the situation, not by remembering the one incident that produced it.
82
+ - `action` — what to do when the trigger fires.
83
+
84
+ A **self-model** — a strategy about your *own* recurring slip (e.g. "I keep forgetting to regenerate derived forms") — is a strategy marked `scope: self`; its `trigger` is self-referential but the body is identical.
85
+
86
+ **Runbook records carry an ordered body.** A `runbook` MUST, beyond `claim` and `evidence`, spell out:
87
+
88
+ - `steps` — the ordered steps to carry out the task.
89
+ - `failure-recovery` — for the steps that can fail, what to do to recover (the branch that a flat one-line record loses).
90
+
91
+ If you cannot state these parts, the strategy or runbook is not yet worth recording — the same anti-hollow bar as pitfalls.
92
+
73
93
  > **onboard variant**: `/codexspec:onboard` writes to this same store and format, with one difference — its records are inferred from code, so `evidence.facts` holds a verbatim **code observation** (path + snippet) instead of a user quote, `provenance` marks the onboard scan, and `derivation` is always `inferred`. onboard therefore writes `status: candidate` **at write time** (it never writes `vetted` itself); such a record can still be promoted to `vetted` later once it is outcome-verified and approved in `/distill review` — its `inferred` origin is not a barrier (per the `status` rule above).
74
94
 
75
95
  This separation is what makes a later error locatable as **misread** (facts wrong) vs **overreach** (claim over-generalized) vs **stale** (state no longer holds).
@@ -103,12 +123,50 @@ Example — a `pitfall` (note the required `root-cause` / `workaround` / `lesson
103
123
  - status: candidate
104
124
  ```
105
125
 
126
+ Example — a `strategy` (note the `trigger` / `action` body), file `strategies/S-2026-0813-1606fz-1.md`:
127
+
128
+ ```markdown
129
+ ### S-2026-0813-1606fz-1: When a substring contract test fails, suspect markdown emphasis first
130
+ - claim: A failing substring assertion over a prose template is usually a wrong assertion, not a wrong template.
131
+ - type: strategy
132
+ - scope/when: writing or debugging substring contract tests over `templates/commands/*.md`
133
+ - trigger: a `test_*_template.py` substring assertion fails on a phrase you believe the template contains.
134
+ - action: check whether the template wrote inline `**`/`*`/backticks inside the asserted span before touching the template; re-target the assertion at an emphasis-free span.
135
+ - evidence.facts: "断言 span 里含 `**not**` 导致子串匹配失败"
136
+ - evidence.state: confirmed at feature 2026-0813-1606fz; still valid.
137
+ - provenance: distill @implement-tasks, 2026-08-13, derivation: inferred, confidence: high
138
+ - status: candidate
139
+ ```
140
+
141
+ Example — a `runbook` (note the ordered `steps` + `failure-recovery` body), file `runbooks/R-2026-0813-1143el-1.md`:
142
+
143
+ ```markdown
144
+ ### R-2026-0813-1143el-1: Release a new CodexSpec version
145
+ - claim: The end-to-end steps (and failure recovery) to cut a release.
146
+ - type: runbook
147
+ - scope/when: publishing a new version of this repo
148
+ - steps: 1) bump the version manually in `pyproject.toml`, `__version__`, and `uv.lock`; 2) run `publish.sh`; 3) push the tag; 4) commit the marketplace update.
149
+ - failure-recovery: if the `pip-audit` pre-commit hook aborts on a transient SSL error, reset the half-applied bump and re-run with `SKIP=pip-audit`.
150
+ - evidence.facts: "publish.sh 不自动 bump __version__;pip-audit 偶发 SSL 失败中止发布"
151
+ - evidence.state: confirmed at feature 2026-0813-1143el; still valid.
152
+ - provenance: distill @implement-tasks, 2026-08-13, derivation: inferred, confidence: high
153
+ - status: candidate
154
+ ```
155
+
106
156
  ## Extraction
107
157
 
108
158
  Read the interaction segment and extract, per the dimensions above, only **verified** knowledge — prefer facts confirmed by outcomes over speculation; speculation MUST NOT become `vetted`.
109
159
 
110
160
  Before writing, **read the current profile** (the record files under each category directory) and skip anything already covered; update anything changed via `replace`. **This is how deduplication is done — by judgment, not an algorithm.**
111
161
 
162
+ ## Debounce across the trigger surface
163
+
164
+ distill can now fire from several points close together — the near-moment ambient rule, the long-run along-the-way calls, and the wrap-up hooks (`implement-tasks` → `commit-staged` → `pr`) — often over largely the **same** work. To avoid re-distilling and near-duplicate records, apply a lightweight debounce:
165
+
166
+ - **Session-local boundary.** Keep a **session-local already-distilled boundary** — your own memory, in this conversation's context, of what you have already distilled this session and up to which point of the interaction. This is held **in conversation context**; introduce **no persistent runtime state** (no marker file, no counter on disk).
167
+ - **Delta-only.** On a later trigger, distill only the **substantive new delta** since that boundary. If nothing substantive was produced since, **early-exit** (report "nothing to distill") without deep-reading the whole profile.
168
+ - **Cross-session fallback.** When the boundary is unavailable — a new session, or context was compacted — there is no session memory to lean on, so distill **falls back to reading the profile and skipping covered records** (the judgment dedup above). Worst case is one extra early-exiting scan, never a duplicate.
169
+
112
170
  ## Conflict adjudication
113
171
 
114
172
  When a new item conflicts with an existing rule, resolve in this order:
@@ -128,12 +186,24 @@ Change the profile **only** through three conceptual operations (you edit the fi
128
186
 
129
187
  git history is the audit ledger. Do **NOT** keep a retired file or a retired section.
130
188
 
189
+ ## Consolidation (compress narrow records into general rules)
190
+
191
+ Growth is not just accumulation: many narrow records on one theme should compress into **one general rule plus its exceptions** (the way experience compacts into judgment). distill performs the **detect-and-mark** half automatically; a human performs the **merge** half in `/distill review`.
192
+
193
+ - **Mark, don't merge.** When you notice a cluster of narrow records sharing a generalization (e.g. several derived-artifact pitfalls, or several lockstep conventions), **mark** them as **consolidation candidates** by writing a **per-record field** into each member's own file — `consolidation: candidate; cluster: <short-theme-key>` — using the same shared `<short-theme-key>` on every member. This is judgment, not an algorithm. It is **non-destructive**: marking **does not auto-rewrite or delete** any record.
194
+ - **No central index.** The cluster lives only as that shared key across the members' own files — there is **no central index** or manifest file (which would be a merge-conflict magnet and break the conflict-free store). `/distill review` discovers a cluster by scanning for records that share a `cluster:` key.
195
+ - **Cross-category promotion.** A consolidation may cross categories — e.g. **promoting several** `pitfalls` **into one** `strategy` (the transferable "what to do when" above the individual traps). The general record is written in whichever category fits the generalized claim.
196
+
197
+ The merge itself is confirmed by a human in `/distill review` (below); distill never merges unattended.
198
+
131
199
  ## Vetting candidates (manual, interactive)
132
200
 
133
201
  Auto-distill writes `candidate` records non-interactively and **never prompts**. Promote them through the **manual review mode** — `/distill review` (or `/distill` with no new segment to distill): list every pending `candidate` compactly (claim + evidence + provenance) and let the user approve inline — "vet all", "vet 1,3", "edit 2", "drop 4". Apply the choices by editing each record's `status` (a `replace`). **The user never hand-edits the profile files.**
134
202
 
135
203
  The user's approval here **is** the human endorsement half of the `vetted` gate: an approved `candidate` that is already outcome-verified becomes `vetted` **regardless of its original `derivation`** (an `inferred` record is not blocked from vetting). If a candidate has not yet been outcome-verified, approval keeps it `candidate` (or the user may attest the outcome to complete the gate). This is the path by which `inferred` knowledge — including everything `/codexspec:onboard` writes — reaches `vetted` and becomes `evolve`-eligible.
136
204
 
205
+ **Consolidation review.** In the same review mode, also surface any **consolidation candidate** clusters (records sharing a `cluster:` key, from the Consolidation section above): show the cluster's members compactly and let the user confirm the merge inline — "merge 1", "merge all", "keep separate". On confirmation, write the single general record (a **general rule plus its exceptions**), `remove` the superseded members, and clear the `cluster:`/`consolidation:` marker from anything that survives so no stale flag lingers. If the user declines, leave every member untouched. distill only ever **marked** the cluster; the merge happens **only** here, on explicit confirmation.
206
+
137
207
  ## Self-check before finishing
138
208
 
139
209
  A lightweight judgment pass (not an engineered lint) over what you just wrote:
@@ -31,6 +31,8 @@ Promote only records that are **both**:
31
31
 
32
32
  Project-specific knowledge **stays** in the profile. Only generally-useful capability is promoted upstream. When nothing qualifies, stop and report — do not force a promotion.
33
33
 
34
+ This selection spans **all six** profile categories. `strategies/` (metacognitive `trigger → action` rules) and `runbooks/` (ordered multi-step procedures) are often the **most** promotable material — a vetted, general strategy or runbook compiles cleanly into a reusable skill/command — but they clear the **same** `vetted` gate as every other category; the gate is unchanged.
35
+
34
36
  ## Compiling the draft
35
37
 
36
38
  Compile the selected sediment into a SKILL.md / command-template draft that conforms to both:
@@ -30,7 +30,7 @@ Converse in the interaction language and author artifacts in the document langua
30
30
  Before scanning:
31
31
 
32
32
  - If `.codexspec/` is **absent**, the project is not codexspec-initialized. **Stop** and direct the user to run `codexspec init`. Do not scaffold a whole project.
33
- - If `.codexspec/` is present but the profile store is missing, **ensure the canonical scaffold** — the four category directories `.codexspec/profile/{constraints,conventions,pitfalls,decisions}/` (matching what `codexspec init` produces) — before writing.
33
+ - If `.codexspec/` is present but the profile store is missing, **ensure the canonical scaffold** — the six category directories `.codexspec/profile/{constraints,conventions,pitfalls,decisions,strategies,runbooks}/` (matching what `codexspec init` produces) — before writing.
34
34
  - git is **not required**. onboard runs on a plain directory.
35
35
 
36
36
  ## Codebase Scan
@@ -45,12 +45,12 @@ Scan strategy is **high-signal-first over the whole repository in a single pass*
45
45
 
46
46
  ## What onboard Extracts — and What It Must NOT
47
47
 
48
- Extraction uses your **flexible judgment over what the code actually shows** — not a fixed checklist of filenames or markers. onboard actively extracts **only two** of the four profile categories:
48
+ Extraction uses your **flexible judgment over what the code actually shows** — not a fixed checklist of filenames or markers. onboard actively extracts **only two** of the six profile categories:
49
49
 
50
50
  - **`conventions`** (the primary yield) — the code's observable regularities: directory/module structure, naming schemes, import style, the tech stack and toolchain (read from manifests), lint/format/type configuration, test framework and layout, and patterns repeated across the codebase. **Observable architecture / tech-stack facts** are captured here as fact-plus-steering, not as ADR-style decisions.
51
51
  - **`constraints`** (narrow, high-risk) — **only** config-level **explicit hard prohibitions**: lint/type rules set to *error* that ban imports or APIs, `do not edit` / generated-file / managed-block markers, and CODEOWNERS / protected-path conventions. Every constraint candidate carries a **precise evidence anchor** (`file:line` or a config snippet). **Absent an explicit prohibition signal, propose no constraint** — silence, never a guess.
52
52
 
53
- onboard **never** extracts `decisions` or `pitfalls`. A documented decision or pitfall is already readable in the repo (redundant to copy); an undocumented one is unreliable to infer from a cold scan (pitfalls are experiential; decision rationale would be fabricated). Those two categories remain `distill`'s channels, where the rationale and lived experience are available.
53
+ onboard **never** extracts `decisions`, `pitfalls`, `strategies`, or `runbooks`. A documented decision or pitfall is already readable in the repo (redundant to copy); an undocumented one is unreliable to infer from a cold scan (pitfalls are experiential; decision rationale would be fabricated). `strategies` (metacognitive trigger→action rules) and `runbooks` (lived multi-step procedures) are likewise experiential — a cold scan cannot reliably infer either. All four remain `distill`'s channels, where the rationale and lived experience are available.
54
54
 
55
55
  ## Record Format
56
56
 
@@ -85,5 +85,5 @@ Report concisely in the interaction language: the records added / updated per ca
85
85
 
86
86
  - Read-only on code; write-only to `.codexspec/profile/`; no source / test / git / constitution mutation.
87
87
  - Standalone: no auto-next, no automatic hook, and **no Automatic Distillation step** (onboard is not a wrap-up command).
88
- - Writes only `conventions` and `constraints`; never `decisions` or `pitfalls`.
88
+ - Writes only `conventions` and `constraints`; never `decisions`, `pitfalls`, `strategies`, or `runbooks`.
89
89
  - Produces no persistent document beyond profile records.
@@ -55,7 +55,7 @@ When the argument identifies an existing feature:
55
55
  Before discussing and finalizing requirements, read the project profile under `.codexspec/profile/` when it exists so the confirmed `requirements.md` is a synthesis that already accounts for accumulated project knowledge. Each category is a directory holding one record per file:
56
56
 
57
57
  - `constraints/` first — the project's hard prohibitions (highest weight); requirements MUST NOT contradict them.
58
- - `pitfalls/`, `conventions/`, `decisions/` — read the records relevant to this feature's area, to avoid re-hitting known traps, to follow established conventions, and to reuse past cross-feature/architectural decisions rather than re-litigating them.
58
+ - `pitfalls/`, `conventions/`, `decisions/`, `strategies/`, `runbooks/` — read the records relevant to this feature's area, to avoid re-hitting known traps, to follow established conventions, to reuse past cross-feature/architectural decisions rather than re-litigating them, and to apply proven strategies and procedures.
59
59
 
60
60
  Each record carries a `status` (`candidate` or `vetted`); weight `candidate` entries with appropriate caution. Fold what is relevant into the discussion and the resulting entries; cite a profile record as evidence when it materially shapes a decision. This is the single point where the profile enters the SDD pipeline — downstream stages keep `requirements.md` as authority and do not re-read the profile. Degrade silently when the profile is absent or empty (nothing to apply); never block on it.
61
61
 
File without changes
File without changes
File without changes