ce-compound
Document a recently solved problem as a durable repo learning, or capture project vocabulary in CONCEPTS.md. Use when capturing a learning after work.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Document a recently solved problem as a durable repo learning, or capture project vocabulary in CONCEPTS.md. Use when capturing a learning after work.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Explore vague or ambitious ideas into a right-sized requirements-only unified plan. Use when the user wants to brainstorm, think through scope, decide what to build, or needs collaborative product framing before planning. Also use when the user must scope work in territory they say they do not know ("I know nothing about X but need to...") or asks for a blindspot pass — mapping the decision surface before questions begin. Not for executing already-specified work — direct implementation, debugging, or code review where no product scope is left to decide. Not for a decisive verdict on whether to adopt or switch to a specific external technology, library, or platform — brainstorming scopes what to build, not whether to commit to an outside option.
Structured code review for bugs, regressions, tests, and standards. Use before PRs or when asked for review; report-only by default, with explicit local apply available for user-directed fix workflows.
Refresh the repo's captured learnings against the current codebase. Use when auditing stale, overlapping, superseded, or drifted learnings; avoid general refactor, debugging, or code review unless the learnings store is explicit.
Diagnosis loop for bugs and failing behavior. Use for errors, stack traces, regressions, failed tests, issue-tracker bugs, stuck investigations after failed fixes, or asks to debug/fix a bug.
Review requirements, plans, or specs with role-specific lenses. Use when the user wants to improve an existing planning document.
Create a durable, visual teaching artifact — plus an optional check-in (predict-then-reveal for diffs, corrected exercises) that makes it stick — for something worth learning: a concept, a diff, an idea, or a window of your own recent work. Use when the user wants to be taught, wants a deep explainer, wants to understand a substantial change, or wants a work recap built for retention. Not for ordinary Q&A, brief 'why?' follow-ups, operational diagnosis, status updates, or a concise trade-off answer that belongs inline in chat. For learning, not repo docs or verdicts.
| name | ce-compound |
| description | Document a recently solved problem as a durable repo learning, or capture project vocabulary in CONCEPTS.md. Use when capturing a learning after work. |
| argument-hint | [optional: brief context] [mode:headless] [depth:lightweight|full] |
Coordinate multiple subagents working in parallel to document a recently solved problem.
Captures problem solutions while context is fresh, creating structured documentation in <root>/solutions/ with YAML frontmatter for searchability and future reference. Uses parallel subagents.
Why "compound"? Each documented solution compounds your team's knowledge. The first time you solve a problem takes research. Document it, and the next occurrence takes minutes. Knowledge compounds.
/ce-compound # Document the most recent fix
/ce-compound [brief context] # Provide additional context hint
/ce-compound mode:headless # Non-interactive run for automations
/ce-compound mode:headless [context] # Non-interactive run with context hint
/ce-compound mode:headless depth:lightweight [context] # Lower-overhead non-interactive run
/ce-compound mode:headless depth:full [context] # Full non-interactive run
One learning per run. The workflow's grounding, overlap detection, and cross-referencing all assume a single solved problem. When a session produced multiple distinct learnings, run the skill once per learning, sequentially — each run grounds fresh against the tree. Do not batch several learnings through one run and stitch cross-references between the drafts afterward; drafting-context numbering ("Learning 3") leaking into written docs is the failure this rule prevents.
If invoked specifically to create or bootstrap CONCEPTS.md from scratch rather than to document a solved problem, do not run the normal phases — ce-compound populates CONCEPTS.md only as a side effect of documenting a real learning (it seeds the learning's area, not the whole repo; see Phase 2.4). Repo-wide concept-map creation is ce-compound-refresh's job. Redirect a standalone bootstrap request to ce-compound-refresh (which asks whether to build the concept map or run a refresh cycle), then exit.
Enter headless mode when either holds: the arguments you were invoked with contain the mode:headless token, or the invocation makes non-interactive intent unmistakable — a caller or standing instruction asking to run ce-compound "headless", "non-interactively", "unattended", or "without prompts/questions". The token is the explicit form; a clear natural-language request for a non-interactive run is equivalent. Bare "automatically" or "auto-run" is not on its own a headless signal — it speaks to invoking the skill, not to suppressing its prompts — so an ambiguous or absent signal defaults to interactive. Tokens starting with mode: or depth: are flags, not context — strip them before treating the remainder as the brief context hint.
Depth is an explicit headless-only selector. In headless mode, accept at most one depth token: depth:lightweight routes directly to Lightweight Mode, while depth:full routes to Full Mode with its automatic session-history probe. mode:headless without a depth: token remains backward compatible and runs Full Mode. Headless lightweight asks no blocking questions and launches no subagents. If the invocation contains an unknown depth: token, multiple depth: tokens, or a depth: token without headless intent, do not guess; emit the headless failure report with the reason and end with Documentation skipped.
| Mode | When | Behavior |
|---|---|---|
| Interactive (default) | No headless token or clear non-interactive intent | Auto-pick Full vs Lightweight and report the choice; run session history as an automatic probe (Full only); prompt for Discoverability Check consent; end with a plain summary (no "What's next?" menu) |
| Headless | mode:headless token present, or the invocation makes non-interactive intent unmistakable | No blocking questions. Run the explicitly requested depth, defaulting to Full mode with the automatic session-history probe. If the Discoverability Check finds a gap, report it without editing instruction files. Skip Phase 3 specialized reviews. End with a structured terminal report — no "What's next?" menu. |
Headless mode is intended for automations and skill-to-skill invocation where no human is present to answer questions. Once detected, headless mode applies for the entire run.
Resolve two values at runtime with the shell tool before Phase 1 session-history filtering. Run each as its own command and read its exit status — a non-zero exit is a normal state here, not an error to route around:
git rev-parse --abbrev-ref HEAD. Use the branch name to filter session history in Phase 1. If it returns HEAD (detached) or exits non-zero (not a git repo), skip branch filtering.git rev-parse --show-toplevel. Use it as the session-history repo filter in Phase 1. If it exits non-zero (not a git repo), fall back to the working directory.These files are the durable contract for the workflow. Read them on-demand at the step that needs them — do not bulk-load at skill start.
references/schema.yaml — canonical frontmatter fields and enum values (read when validating YAML)references/yaml-schema.md — category mapping from problem_type to directory (read when classifying)references/concepts-vocabulary.md — CONCEPTS.md format and inclusion rules (read in Phase 2.4 when domain terms surface)references/agents/session-historian.md — skill-local synthesis prompt for optional session-history compounding context (read only when the user opts into session history)references/grounding-validation.md — grounding-validation protocol: flag adjudication rules and the semantic validator prompt (read in Phase 2.45)assets/resolution-template.md — section structure for new docs (read when assembling)scripts/session-history/ — session discovery and extraction scripts bundled into this skill so session-history support is fully self-containedscripts/validate-frontmatter.py — frontmatter parser-safety validator (run in Phase 2 step 8 through the existence guard documented there; resolves only on Claude Code via ${CLAUDE_SKILL_DIR}, with a manual-checklist fallback elsewhere)scripts/validate-doc-claims.py — mechanical claims validator: cited paths, commit SHAs, relative links, dangling drafting scaffold (run in Phase 2.45 via the SKILL_DIR anchor)When spawning subagents, pass the relevant file contents into the task prompt so they have the contract without needing cross-skill paths.
This skill writes and reads learnings under <root>/solutions/. Resolve <root> when you first compose a <root>/solutions/ path (per the block below); when passing search or write scope to a subagent, pass the resolved <root>/solutions/ path, not the config.
Resolve the CE artifact root <root> before composing any artifact path.
docs_root from <repo-root>/.compound-engineering/config.local.yaml, then config.yaml; first non-empty value wins (<repo-root> = git rev-parse --show-toplevel). Unset -> <root> is docs, exactly as before..git/. Otherwise stop with an error naming docs_root and the value -- never fall back to docs.<root> as the sole artifact location: create it if absent, compose each path as <root>/<subdir> with this skill's own subdirectory, and never also read docs.ce-compound does not ask the user which mode to run or whether to search session history. Both are decisions the agent is better positioned to make: mode depends on context budget the agent can observe, and session-history value is unknowable a priori to either party (the payoff is an unrelated earlier session the current agent was never in), so it is resolved by a cheap probe rather than a question. The only interactive prompt in the whole workflow is the Discoverability Check consent, because that one edits a tracked instruction file.
Mode selection (Full vs Lightweight) — decide it, don't ask it.
In headless mode, skip automatic mode selection. Run the depth selected during Mode Detection: depth:lightweight enters Lightweight Mode; depth:full or no depth token enters Full Mode, including the automatic session-history probe (Phase 1 step 4).
Session history — an automatic probe in Full mode, never a question. The point of searching prior sessions is that an unrelated earlier session may hold related problem-solving; neither the agent nor the user can know that a priori, so asking is pointless. Instead, Full mode always runs the cheap discovery+metadata probe (Phase 1 step 4) — it runs in parallel with the research subagents, so it is near-free on wall-clock — and escalates to the expensive extraction+synthesis only when the probe surfaces genuinely relevant candidate sessions. Lightweight mode skips session history entirely; headless Full runs the same automatic probe, since it prompts for nothing and so keeps headless non-interactive. This support exists only inside the compounding workflow; there is no standalone session-history product surface.
<critical_requirement> The primary deliverable is ONE file - the final documentation.
Phase 1 subagents write their full structured output to a per-run scratch artifact under <run-dir>/ and return only a compact confirmation containing the artifact path. The orchestrator Reads those artifacts back in Phase 2 assembly. This is scratch space, identical in spirit to ce-code-review's per-reviewer run artifacts; it does not make the scratch files additional deliverables. Only the orchestrator writes product files — the final solution doc and the maintenance side effects below. Subagents must not touch docs/, project instruction files, or any tracked path. Beyond the Phase 2 solution doc, the orchestrator may also write maintenance side effects — not additional deliverables, and creating one when absent is expected, not a violation of this rule. There are three write-target classes; only the first two are unconditional:
<root>/solutions/... — the primary deliverable (always).CONCEPTS.md — create or update in Phase 2.4 (Vocabulary Capture) when a qualifying domain term surfaces (Full mode; every mode that reaches vocabulary capture may refine an existing file).CONCEPTS.md and the instruction-file edit ensure future agents can discover and ground in the knowledge store; neither makes the documentation any less the single deliverable.
Why the scratch artifact (issue #956): a subagent asked to return a long prose body as its inline response intermittently returns an executive summary instead ("Doc body complete — six sections filled. Returning above."), and the original prose is then unrecoverable from the orchestrator side. Writing to disk first means the full output always survives; the inline confirmation is just a pointer, and the orchestrator falls back to whatever the subagent did return inline only when the artifact is missing. </critical_requirement>
Before launching Phase 1 subagents, check the auto-memory block injected into your system prompt for notes relevant to the problem being documented.
## Supplementary notes from auto memory
Treat as additional context, not primary evidence. Conversation history
and codebase findings take priority over these notes.
[relevant entries here]
If no relevant entries are found, proceed to Phase 1 without passing memory context.
Launch research subagents. Each writes its full output to a per-run scratch artifact and returns only the artifact path to the orchestrator.
Run ID and run dir (before dispatching any subagent): generate a unique run identifier and create the run directory. This scopes every Phase 1 artifact file to the same directory so the orchestrator can Read them back in Phase 2.
SCRATCH_ROOT="/tmp/compound-engineering-$(id -u)";
if [ -L "$SCRATCH_ROOT" ]; then echo "unsafe scratch root symlink: $SCRATCH_ROOT" >&2; exit 1; fi;
install -d -m 700 "$SCRATCH_ROOT" || exit 1;
if [ -L "$SCRATCH_ROOT" ] || [ ! -O "$SCRATCH_ROOT" ]; then echo "scratch root is not owned by the current user: $SCRATCH_ROOT" >&2; exit 1; fi;
chmod 700 "$SCRATCH_ROOT" || exit 1;
RUN_ID=$(date +%Y%m%d-%H%M%S)-$(head -c4 /dev/urandom | od -An -tx1 | tr -d ' ');
RUN_DIR="$SCRATCH_ROOT/ce-compound/$RUN_ID";
(umask 077; mkdir -p "$RUN_DIR") || exit 1; chmod 700 "$RUN_DIR" || exit 1;
echo "$RUN_DIR";
Resolve current vocabulary and conventions before dispatching subagents. Use the project's active instructions and conventions already in your context. If CONCEPTS.md exists, read its relevant terms and pass them to the Context Analyzer.
CRITICAL — glob <root>/solutions/ fresh every run. The current vocabulary and conventions above do not substitute for the live-tree search in step 3.
Pass {run_id} and the resolved absolute {run_dir} into every Phase 1 subagent prompt. Each subagent writes its full structured output to its own file under {run_dir}/, confirms the write succeeded (the file exists and is non-empty), and then returns only a one-line confirmation containing the artifact path — not the prose body inline. Artifact filenames by subagent:
{run_dir}/context.json (frontmatter skeleton, category path, filename, track){run_dir}/solution.md (the full doc-body prose sections){run_dir}/related.json (links, refresh candidates, overlap assessment){run_dir}/session-history.md (prose findings)Return the full output inline whenever the artifact write did not succeed. This covers both cases where the orchestrator's Phase 2 inline fallback would otherwise have nothing to read: (a) {run_id} is empty or did not resolve (non-Claude-Code platforms where the pre-resolution failed), so there is no path to write to; and (b) {run_id} resolved but the write itself failed — tool permission denied, absolute-path writes unavailable, disk error, or the post-write existence check came back empty. In either case the subagent must return its complete structured output inline instead of a path, because the path would point at a file that does not exist. Return only the bare path when — and only when — the write is confirmed on disk. The artifact pattern is a reliability improvement, not a hard requirement; the orchestrator handles a missing artifact in Phase 2 by using the inline return.
Dispatch order:
Context Analyzer, Solution Extractor, and Related Docs Finder in parallel (background)max(session-history, slowest background subagent), not their sum). Running session history before the parallel block would serialize it in front of the research subagents and regress wall-clock time.<parallel_tasks>
references/schema.yaml for enum validation and track classificationreferences/yaml-schema.md for category mapping into <root>/solutions/[sanitized-problem-slug].md — no date suffix, even if existing files in the target directory have one; the date: frontmatter field is the canonical creation datecontext.json: YAML frontmatter skeleton (must include category: field mapped from problem_type), category directory path, suggested filename, and which track applies. Returns only the artifact path.references/schema.yaml for track classification (bug vs knowledge)solution.md and returns only the artifact path. This is the subagent most prone to the issue #956 summary-collapse, so its prose must land on disk rather than only in the inline return.file:line alongside the claim. A claim that cannot be verified against the tree is softened or attributed ("per this session's conclusion…"), never stated as factBug track output sections:
Knowledge track output sections:
<root>/solutions/ for related documentationrelated.json: Links, relationships, refresh candidates, and overlap assessment (score + which dimensions matched). Returns only the artifact path.Search strategy (grep-first filtering for efficiency):
<root>/solutions/<category>/ directorytitle:.*<keyword>tags:.*(<keyword1>|<keyword2>)module:.*<module name>component:.*<component>GitHub issue search:
Prefer the gh CLI for searching related issues: gh issue list --search "<keywords>" --state all --limit 5. If gh is not installed, fall back to the GitHub MCP tools (e.g., unblocked data_retrieval) if available. If neither is available, skip GitHub issue search and note it was skipped in the output.
</parallel_tasks>
scripts/session-history/.references/agents/session-historian.md, then dispatch a generic subagent using that prompt content. Do not dispatch a standalone agent by type/name.Session-history payload — keep tight. A long, keyword-rich payload licenses widening. Use this shape:
Session context (only if the values resolved cleanly above; otherwise omit): repo name, current git branch.
Time window: explicit 7 days unless the documented problem clearly spans a longer arc.
Problem topic: one sentence naming the concrete issue — error message, module name, what broke and how it was fixed. Not a paragraph; not a bullet list of related topics.
Filter rule (one line): "Only surface findings directly relevant to this specific problem. Ignore unrelated work from the same sessions or branches."
Output schema:
Structure your response with these sections (omit any with no findings):
- What was tried before
- What didn't work
- Key decisions
- Related context
Do not append additional context blocks, exclusion lists, or topic-keyword bullets — verbose payloads give the session-history flow license to keep widening the search and rapidly compound wall time. If keyword search is needed, the internal flow owns that decision based on the topic.
Script resolution. Set SKILL_DIR to the absolute path of the directory containing the SKILL.md you just read, and run the bundled scripts from "$SKILL_DIR/scripts/session-history/". Set SKILL_DIR inline in each bash block below (shell state does not persist between commands). If the bundled scripts are genuinely not present on disk under "$SKILL_DIR/scripts/session-history/", skip session history visibly with: "Session history bundled scripts were not found in this skill's directory; skipping the session-history probe for this run." Continue Phase 2 without session context.
Discovery pipeline. Infer the scan window from the problem topic, starting with 7 days. Run discovery and metadata extraction:
SKILL_DIR="<absolute path of the directory containing the SKILL.md you just read>";
if [ -f "$SKILL_DIR/scripts/session-history/discover-sessions.sh" ] && [ -f "$SKILL_DIR/scripts/session-history/extract-metadata.py" ]; then REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd); REPO_NAME=$(basename "$REPO_ROOT"); SCAN_DAYS="7"; bash "$SKILL_DIR/scripts/session-history/discover-sessions.sh" "$REPO_NAME" "$SCAN_DAYS" --cwd "$REPO_ROOT" | tr '\n' '\0' | xargs -0 python3 "$SKILL_DIR/scripts/session-history/extract-metadata.py" --cwd-filter "$REPO_ROOT"; else echo "Session history bundled scripts were not found in this skill's directory; skipping the session-history probe for this run."; fi
Pi sessions are included when present under ~/.pi/agent/sessions/; they carry cwd like Codex but no git branch. If _meta.files_processed is 0, return no relevant prior sessions. If the first pass finds no relevant branch matches, or if processing Codex or Pi sessions, derive 2-4 keywords from the topic and re-run metadata extraction with --keyword K1,K2,.... Keep at most 5 sessions across Claude Code, Codex, Cursor, and Pi, ranked by branch match, keyword match count, file size over 30KB, and recency. Exclude the current session.
Escalation gate. The discovery+metadata pass above is the cheap probe and always runs in Full mode. Escalate to the extraction and synthesis stages below only when at least one retained candidate clears the relevance bar: a current-branch match, or ≥2 topic-keyword matches. If no candidate clears the bar (including the _meta.files_processed is 0 case), stop here, record no relevant prior sessions as the session-history input, and skip extraction and synthesis. This gate is what keeps the always-on probe cheap — the expensive synthesis is paid for only when a prior session is genuinely relevant.
Extraction pipeline. Create SCRATCH=$(mktemp -d -t ce-compound-sessions-XXXXXX). For each selected session, write extracted content to scratch files:
SKILL_DIR="<absolute path of the directory containing the SKILL.md you just read>";
if [ -f "$SKILL_DIR/scripts/session-history/extract-skeleton.py" ]; then python3 "$SKILL_DIR/scripts/session-history/extract-skeleton.py" --output "$SCRATCH/<session-id>.skeleton.txt" < <session-file>; else echo "Session history bundled scripts were not found in this skill's directory; skipping the session-history probe for this run."; fi
Use extract-errors.py selectively when dead ends or recurring errors are likely useful. Pass only the scratch file paths and metadata to the synthesis subagent.
Synthesis dispatch. Build a generic subagent prompt containing:
references/agents/session-historian.mdproblem_topicscratch_dirsessions array with extracted file paths and metadataThe subagent reads only the scratch paths, writes its prose findings to {run_dir}/session-history.md, and returns only that artifact path once the write is confirmed (same #956 reliability rationale — session-history findings are long-form prose prone to summary-collapse). If {run_id} did not resolve or the artifact write failed, it returns the prose inline instead (per the inline-fallback rule above). If synthesis fails, note the failure and continue without session context.
<sequential_tasks>
WAIT for all Phase 1 inputs to complete before proceeding — the three parallel subagents and, in Full mode, the internal session-history flow (which may have stopped at the probe with no relevant prior sessions). Session history is a Phase 1 input even though it runs in the orchestrator rather than as a public skill.
The orchestrating agent (main conversation) performs these steps:
Collect Phase 1 results from the run artifacts. For each Phase 1 subagent, Read its artifact file under {run_dir}/ (context.json, solution.md, related.json, and session-history.md when session history ran). The artifact holds the subagent's full output. Fall back to the subagent's inline return only when its artifact file is absent or empty (e.g., {run_id} did not resolve, or the subagent failed to write). The artifact is authoritative when present — this is what makes the workflow resilient to the issue #956 summary-collapse, where the inline return is only an executive summary.
Check the overlap assessment from the Related Docs Finder before deciding what to write:
| Overlap | Action |
|---|---|
| High — existing doc covers the same problem, root cause, and solution | Update the existing doc with fresher context (new code examples, updated references, additional prevention tips) rather than creating a duplicate. The existing doc's path and structure stay the same. |
| Moderate — same problem area but different angle, root cause, or solution | Create the new doc normally. Flag the overlap for Phase 2.5 to recommend consolidation review. |
| Low or none | Create the new doc normally. |
The reason to update rather than create: two docs describing the same problem and solution will inevitably drift apart. The newer context is fresher and more trustworthy, so fold it into the existing doc rather than creating a second one that immediately needs consolidation.
When updating an existing doc, preserve its file path and frontmatter structure. Update the solution, code examples, prevention tips, and any stale references. Add a last_updated: YYYY-MM-DD field to the frontmatter. Do not change the title unless the problem framing has materially shifted.
Incorporate session history findings (if available). When the internal session-history flow returned relevant prior-session context:
Assemble complete markdown file from the collected pieces, reading assets/resolution-template.md for the section structure of new docs
Validate YAML frontmatter against references/schema.yaml, including the YAML-safety quoting rule for array items (see references/yaml-schema.md > YAML Safety Rules)
Create directory if needed: mkdir -p <root>/solutions/[category]/
Write the file: either the updated existing doc or the new <root>/solutions/[category]/[filename].md
Validate parser-safety of the written frontmatter to catch silent-corruption issues the prose rules miss: malformed --- delimiter lines, unquoted # in scalar values (silent comment truncation), and unquoted : in scalar values (silent mapping confusion). The bundled validator ships inside the skill bundle; on Claude Code ${CLAUDE_SKILL_DIR} resolves to the skill directory, but the runtime Bash tool's CWD is the user's project, so a project-relative path (without the ${CLAUDE_SKILL_DIR} prefix) would miss. Run it through an existence guard so platforms that cannot locate the script (e.g. native Codex/Gemini installs, where ${CLAUDE_SKILL_DIR} is unset) fall back to a manual check instead of silently skipping the protection:
if [ -n "${CLAUDE_SKILL_DIR}" ] && [ -f "${CLAUDE_SKILL_DIR}/scripts/validate-frontmatter.py" ]; then
python3 "${CLAUDE_SKILL_DIR}/scripts/validate-frontmatter.py" <output-path>;
else
echo "Bundled validate-frontmatter.py not resolvable on this platform; applying the parser-safety checklist manually.";
fi
--- (trailing whitespace is fine; ---- or ---extra is not a valid delimiter).key: value, no leading indentation) whose value is not already quoted or structured (does not start with ", ', [, {, |, or >): the value must contain no unquoted # (space-then-hash — YAML treats it as a comment and silently truncates) and no unquoted : (colon-then-space — strict YAML may read it as a nested mapping). Quote the whole value if either appears.
Nested values, array items, and already-quoted values are out of scope here (array-item quoting is handled by the schema/YAML-safety step above). Then state in the completion output that the bundled script validator was unavailable on this platform and the checks were applied manually.The validator does not enforce schema rules and does not flag YAML reserved-indicator characters (those produce loud parser errors downstream rather than silent corruption — out of scope). Uses Python 3 stdlib only (no PyYAML or other deps).
When creating a new doc, preserve the section order from assets/resolution-template.md unless the user explicitly asks for a different structure.
</sequential_tasks>
First, read references/concepts-vocabulary.md. This is unconditional. Do not pre-judge from memory that nothing qualifies — the reference's criteria are non-obvious and qualifying terms often live in the surrounding conversation rather than the new doc itself. Reading the reference is what makes the rest of the phase possible.
Then, applying those criteria, scan the new doc and the surrounding conversation for qualifying domain terms. If CONCEPTS.md exists at repo root, add missing qualifying terms and refine existing entries when new precision surfaced. If it does not exist and at least one qualifying term surfaced, create it.
Verify behavior assertions against source before writing them. When an entry asserts how code behaves (states, transitions, limits, semantics), Read the defining source at the current tree first — an entry drafted from a session-level summary is exactly how wrong semantics enter the glossary. Phase 2.45 re-checks these entries, but the cheap fix is to not write the error.
Seed the learning's area at creation — don't write a lone term. When CONCEPTS.md does not yet exist, alongside the surfaced term also seed the core domain nouns of the area this learning touched, following the Seed goal and Scope of a seed rules in references/concepts-vocabulary.md. The seed is scoped to the learning's area (the modules and domain the fix touched) and defines only terms investigated here — it does not reach for repo-wide nouns. This anchors the surfaced term so it does not dangle against undefined siblings. A repo-wide concept map is ce-compound-refresh's bootstrap path, not this one.
At creation, hold the qualifying bar conservatively for borderline terms. A borderline term, or a class/table/file name dressed up as an entity, defers to a later run — clear core nouns are seeded, borderline ones wait. The conservatism is about quality, not count; updates to an existing file follow the normal criteria.
When bootstrapping the file, start with this preamble under the # Concepts heading, then add the qualifying entries below it:
Shared domain vocabulary for this project — entities, named processes, and status concepts with project-specific meaning. Seeded with core domain vocabulary, then accretes as ce-compound and ce-compound-refresh process learnings; direct edits are fine. Glossary only, not a spec or catch-all.
Refresh the coherence neighborhood of any entry you touch. When adding or editing an entry, also inspect its coherence neighborhood — its cluster siblings and the terms it cross-references or that reference it. Within that neighborhood, do two things: fix glossary violations (implementation specifics — file paths, class names, function signatures, current-config values), and refresh entries the learning's own evidence shows have drifted. Bounds: neighborhood only, never a full-file audit; refresh only on evidence already in hand; if judging a neighbor would require investigation this learning did not do, flag it for ce-compound-refresh rather than editing on a guess. The test: after the edit, would a reader find the touched entry's siblings or referenced terms inconsistent with it? Broader audit is ce-compound-refresh's job.
If no terms qualified after applying the reference's criteria, record that outcome explicitly in the success output (e.g., "Vocabulary capture: scanned, no qualifying terms"). Do not silently skip — the visible scan-and-no-result record is the audit signal that the reference was consulted.
Apply edits silently in every mode — no user prompt in interactive, lightweight, or headless. Vocabulary capture is a side effect of compounding, not a decision the user makes per run. Lightweight mode reaches this through its own single-pass step (see Lightweight Mode), and runs an update-only version — it refines an existing CONCEPTS.md but defers creation/seeding to a Full run.
The doc (and any CONCEPTS.md entries from Phase 2.4) is about to become permanent, trusted knowledge. Validate its claims against the tree before it compounds. Read references/grounding-validation.md now — it holds the adjudication rules and the validator prompt; the steps below are only the trigger.
Mechanical claims check (every mode, including headless). Optionally run git fetch --quiet first (best-effort — skip silently offline; the network is never a correctness dependency). Then run the bundled validator against the written doc:
SKILL_DIR="<absolute path of the directory containing the SKILL.md you just read>";
python3 "$SKILL_DIR/scripts/validate-doc-claims.py" <doc-path>
Exit 0 means nothing flagged. Exit 1 means flags to adjudicate, not auto-fix — each flagged path, SHA, link, or scaffold pattern is fixed, annotated as historical, or confirmed intentional per the reference's adjudication table. A doc may legitimately cite a path deleted by the very fix it documents; a flag is a question, not a failure. If the script cannot be resolved on this platform, apply the reference's manual checklist and say so in the output — never silently skip.
Semantic grounding validator (Full mode, including headless Full; lightweight skips it). Dispatch one read-only generic subagent built from the prompt template in the reference, covering the written doc plus any CONCEPTS.md entries added or edited this run. It verifies code-behavior claims by quoting the defining source line, merge-state claims against remote truth (gh primary, git reachability fallback), and internal completeness of countable assertions. Apply its verdicts per the reference (fix contradicted claims from the quoted evidence; soften or drop unverifiable ones; mark offline merge-state checks as degraded), then re-run the mechanical check if the body changed.
After writing the new learning, decide whether this new solution is evidence that older docs should be refreshed.
ce-compound-refresh is not a default follow-up. Use it selectively when the new learning suggests an older learning or pattern doc may now be inaccurate.
It makes sense to invoke ce-compound-refresh when one or more of these are true:
It does not make sense to invoke ce-compound-refresh when:
Use these rules:
ce-compound-refresh with a narrow scope hint after the new learning is writtence-compound-refresh as the next step with a scope hintce-compound-refresh and never ask the user. Surface the recommended scope hint in the terminal report's "Refresh recommendation" line and let the caller decideUser-runnable refresh rendering. When recommending rather than directly invoking ce-compound-refresh, default to /ce-compound-refresh <scope>; use $ce-compound-refresh <scope> only when the active host is Codex or explicitly documents dollar-prefixed skill invocation. Render only the invocation as inline code and output one form only. Agent-to-agent invocation remains semantic.
When invoking or recommending ce-compound-refresh, be explicit about the argument to pass. Prefer the narrowest useful scope:
<root>/solutions/patterns/Examples:
ce-compound-refresh plugin-versioning-requirementsce-compound-refresh paymentsce-compound-refresh performance-issuesce-compound-refresh critical-patternsA single scope hint may still expand to multiple related docs when the change is cross-cutting within one domain, category, or pattern area.
Do not invoke ce-compound-refresh without an argument unless the user explicitly wants a broad sweep.
Always capture the new learning first. Refresh is a targeted maintenance follow-up, not a prerequisite for documentation.
After the learning is written and the refresh decision is made, check whether the project's instruction files would lead an agent to discover and search <root>/solutions/ before starting work in a documented area. This runs every time — the knowledge store only compounds value when agents can find it.
Identify which root-level instruction files exist (AGENTS.md, CLAUDE.md, or both). Read the file(s) and determine which holds the substantive content — one file may just be a shim that @-includes the other (e.g., CLAUDE.md containing only @AGENTS.md, or vice versa). The substantive file is the assessment and edit target; ignore shims. If neither file exists, skip this check entirely.
Assess whether an agent reading the instruction files would learn three things:
module, tags, problem_type)This is a semantic assessment, not a string match. The information could be a line in an architecture section, a bullet in a gotchas section, spread across multiple places, or expressed without ever using the exact path <root>/solutions/. Use judgment — if an agent would reasonably discover and use the knowledge store after reading the file, the check passes.
If the spirit is already met, no action needed — move on.
If not: a. Based on the file's existing structure, tone, and density, identify where a mention fits naturally. Before creating a new section, check whether the information could be a single line in the closest related section — an architecture tree, a directory listing, a documentation section, or a conventions block. A line added to an existing section is almost always better than a new headed section. Only add a new section as a last resort when the file has clear sectioned structure and nothing is even remotely related. b. Draft the smallest addition that communicates the three things. Match the file's existing style and density. The addition should describe the knowledge store itself, not the plugin — an agent without the plugin should still find value in it.
Keep the tone informational, not imperative. Express timing as description, not instruction — "relevant when implementing or debugging in documented areas" rather than "check before implementing or debugging." Imperative directives like "always search before implementing" cause redundant reads when a workflow already includes a dedicated search step. The goal is awareness: agents learn the folder exists and what's in it, then use their own judgment about when to consult it.
Substitute the concrete root in what you write. The examples below show <root>/solutions/, but the instruction file is read by agents without this plugin (and by people), who cannot resolve <root>. When you insert the text, replace <root> with the resolved concrete path — the actual artifact directory, which is the default docs root's solutions/ unless a docs_root is configured — never the literal placeholder.
Examples of calibration (not templates — adapt to the file):
When there's an existing directory listing or architecture section — add a line:
<root>/solutions/ # documented solutions to past problems (bugs, best practices, workflow patterns), organized by category with YAML frontmatter (module, tags, problem_type)
When nothing in the file is a natural fit — a small headed section is appropriate:
## Documented Solutions
`<root>/solutions/` — documented solutions to past problems (bugs, best practices, workflow patterns), organized by category with YAML frontmatter (`module`, `tags`, `problem_type`). Relevant when implementing or debugging in documented areas.
c. In full interactive mode, explain to the user why this matters — agents working in this repo (including fresh sessions, other tools, or collaborators without the plugin) won't know to check <root>/solutions/ unless the instruction file surfaces it. Show the proposed change and where it would go, then use the platform's blocking question tool to get consent before making the edit: AskUserQuestion in Claude Code (call ToolSearch with select:AskUserQuestion first if its schema isn't loaded), request_user_input in Codex, ask_question in Antigravity CLI (agy), ask_user in Pi (requires the pi-ask-user extension). Fall back to presenting the proposal in chat only when no blocking tool exists in the harness or the call errors (e.g., Codex edit modes) — not because a schema load is required. Never silently skip the question. In lightweight mode (interactive or headless), output a one-liner note and move on. In full headless mode, do not edit instruction files — surface the gap in the terminal report as Instruction-file edit: gap noted, not applied (headless scope is documentation capture, not project-config edits; a human-invoked interactive run applies the edit with consent)
If CONCEPTS.md exists at repo root, run a parallel discoverability check for it. Assess whether the instruction file would lead an agent to discover the project's shared domain vocabulary. Use the same workflow as the <root>/solutions/ check above: same target file, same edit-placement judgment, same consent-then-edit interaction shape per mode. A line in an existing section is almost always better than a new headed section. Example calibration when nothing else fits:
CONCEPTS.md # shared domain vocabulary (entities, named processes, status concepts) — relevant when orienting to the codebase or discussing domain concepts
Skip this step entirely if CONCEPTS.md does not exist — never nag for an artifact the project has not adopted. When skipped, this step produces no output and no edit.
WAIT for Phase 2 to complete before proceeding.
Skip Phase 3 entirely in headless mode to bound token usage — the caller does not have a human-in-the-loop to act on reviewer findings, and downstream automations can run specialized reviewers themselves if they want that pass.
<parallel_tasks>
Based on problem type, optionally dispatch generic subagents seeded with local prompt assets from references/agents/ to review the documentation. Do not dispatch standalone agents by type/name.
references/agents/performance-oracle.mdreferences/agents/security-sentinel.mdreferences/agents/data-integrity-guardian.mdce-simplify-code from this phase and do not mutate product code unless the user explicitly asks for a separate code-simplification pass. Do not use the deleted code-simplicity-reviewer.
Example: review the solution draft's examples for speculative abstractions, redundant wrappers, dead branches, and just-in-case parameters. Apply edits only to the documentation/examples being written by ce-compound; leave any branch code changes untouched.</parallel_tasks>
<critical_requirement> Single-pass alternative — same artifact type, reduced research and validation.
This mode skips parallel subagents entirely. The orchestrator performs all work in a single pass and writes the same solution-doc artifact type, but omits cross-referencing, duplicate detection, session-history research, and semantic grounding validation.
Headless mode enters Lightweight only when explicitly invoked with depth:lightweight; otherwise it defaults to Full for backward compatibility.
</critical_requirement>
The orchestrator (main conversation) performs ALL of the following in one sequential pass:
references/schema.yaml and references/yaml-schema.md, then determine track (bug vs knowledge), category, and filename<root>/solutions/[category]/[filename].md path exists. If it exists, read it: update it only when it covers the same problem, preserving its path and frontmatter structure and adding last_updated: YYYY-MM-DD; otherwise choose a distinct, descriptive filename and re-check that exact path is absent before writing. This is exact-path collision handling only — do not run Full mode's semantic overlap research or dispatch subagents. Create or update the doc using the appropriate track template from assets/resolution-template.md, with:
references/yaml-schema.md > YAML Safety Rules)CONCEPTS.md exists at repo root, read references/concepts-vocabulary.md, then scan the new doc and the conversation for qualifying terms and add/refine entries silently (same criteria as Phase 2.4). Do not bootstrap or seed in lightweight mode — if CONCEPTS.md does not exist, defer creation to a Full run, which owns seeding. Record the outcome in the output (e.g., "Vocabulary: 1 entry refined" or "scanned, no qualifying terms"). If you refined CONCEPTS.md and the project's active instructions and conventions already in your context do not surface it, add the discoverability tip to the output below — lightweight tips, it does not edit instruction files (an interactive Full run owns that edit after consent; headless Full also tips/reports only).<root>/solutions/ against the three criteria under Discoverability Check above. Do not open, offer to edit, or edit instruction files; Lightweight only reports the result. Record one of:
no gap when active project instructions surface the knowledge storegap noted — instruction-file tip emitted when active project instructions exist but do not surface itnot applicable — no active project instructions when no project instructions are active; emit no discoverability tipscripts/validate-doc-claims.py against the written doc exactly as in Phase 2.45 step 1 (same SKILL_DIR anchor, same adjudicate-not-auto-fix rule — read references/grounding-validation.md for the adjudication table when it flags anything). Lightweight skips only the semantic validator subagent, not this deterministic check.User-runnable retry rendering. In the lightweight completion output below, default to /ce-compound; use $ce-compound only when the active host is Codex or explicitly documents dollar-prefixed skill invocation. Render only the invocation as inline code and output one form only.
Lightweight completion output: In headless Lightweight, do not emit this interactive block; use the depth-specific report under Success Output > Headless mode instead. In interactive Lightweight, emit:
✓ Documentation complete (lightweight mode)
File created:
- <root>/solutions/[category]/[filename].md
[If discoverability check found instruction files don't surface the knowledge store:]
Tip: Your AGENTS.md/CLAUDE.md doesn't surface <root>/solutions/ to agents —
a brief mention helps all agents discover these learnings.
[If CONCEPTS.md was refined this run and isn't surfaced in the instruction files:]
Tip: Your AGENTS.md/CLAUDE.md doesn't surface CONCEPTS.md —
a one-line mention helps agents find the shared vocabulary.
Note: This was created in lightweight mode. For richer documentation
(cross-references, detailed prevention strategies, specialized reviews,
semantic grounding validation), re-run <rendered invocation> in a fresh session.
No subagents are launched. No parallel tasks. The solution doc is the one deliverable (Phase 2.4's update-only vocabulary capture may also refine an existing CONCEPTS.md).
In lightweight mode, the overlap check is skipped (no Related Docs Finder subagent). This means lightweight mode may create a doc that overlaps with an existing one. That is acceptable — ce-compound-refresh will catch it later. Only suggest ce-compound-refresh if there is an obvious narrow refresh target. Do not broaden into a large refresh sweep from a lightweight session.
Organized documentation:
<root>/solutions/[category]/[filename].mdCategories auto-detected from problem:
Bug track:
Knowledge track:
| ❌ Wrong | ✅ Correct |
|---|---|
Subagents write product files into docs/ or edit tracked paths | Subagents write only scratch artifacts under <run-dir>/ and return the path; orchestrator writes the one final doc |
| Subagent returns a long prose body only as its inline response | Subagent writes full output to its run artifact; orchestrator Reads it back (inline return is fallback only) |
| Research and assembly run in parallel | Research completes → then assembly runs |
| Multiple files created during workflow | One solution doc written or updated: <root>/solutions/[category]/[filename].md (plus optional maintenance writes: a CONCEPTS.md create/update from Phase 2.4, and — interactive Full only, after consent — a small instruction-file edit for discoverability) |
| Headless Discoverability Check edits AGENTS.md/CLAUDE.md | Headless Full reports Instruction-file edit: gap noted, not applied; headless Lightweight emits a discoverability tip; only interactive Full applies the edit after consent |
| Creating a new doc when an existing doc covers the same problem | Check overlap assessment; update the existing doc when overlap is high |
| Asserting code behavior or merge-state from conversation memory | Read the defining source line before asserting; cite PR numbers over SHAs; soften unverifiable claims (Phase 1 extractor rules, re-checked in Phase 2.45) |
| Batching several learnings through one run and stitching cross-references between drafts | One learning per run; run the skill sequentially for each additional learning |
Emit a structured terminal report and end the turn. No "What's next?" question, no blocking prompt. End with Documentation complete as the terminal signal so callers can detect completion.
For depth:lightweight, use this lower-overhead report after the Lightweight Mode workflow:
✓ Documentation complete (headless lightweight mode)
File: <root>/solutions/<category>/<filename>.md (created | updated)
Track: <bug | knowledge>
Category: <category>
Grounding: <mechanical check clean | N flags adjudicated>
Discoverability: <no gap | gap noted — instruction-file tip emitted | not applicable — no active project instructions>
CONCEPTS.md: <not present | scanned, no qualifying terms | updated — N added, N refined>
CONCEPTS.md discoverability: <not checked — CONCEPTS.md not refined | no gap | gap noted — instruction-file tip emitted | not applicable — no active project instructions>
Refresh recommendation: <none | scope hint for /ce-compound-refresh>
Documentation complete
For depth:full or backward-compatible headless calls with no depth token, use the Full report:
✓ Documentation complete (headless mode)
File: <root>/solutions/<category>/<filename>.md (created | updated)
Track: <bug | knowledge>
Category: <category>
Overlap: <none | low | moderate — see <path> | high — existing doc updated>
Grounding: <clean | N flags adjudicated (X fixed, Y annotated, Z confirmed) | N claims softened or corrected | degraded — merge-state claims unverified offline>
Instruction-file edit: <none needed | gap noted, not applied>
CONCEPTS.md: <scanned, no qualifying terms | created with N entries (M seeded from the learning's area) | updated — N added, N refined>
Refresh recommendation: <none | scope hint for /ce-compound-refresh>
Documentation complete
When no doc was written (e.g., headless invoked on a session where the problem is not yet solved), emit a structured failure instead and end with Documentation skipped so callers can distinguish success from no-op:
✗ Documentation skipped (headless mode)
Reason: <one-sentence explanation — e.g., "no solved problem detected in
conversation history" or "solution not yet verified">
Documentation skipped
✓ Documentation complete
Ran Full mode.
Auto memory: 2 relevant entries used as supplementary evidence
Subagent Results:
✓ Context Analyzer: Identified performance_issue in brief_system, category: performance-issues/
✓ Solution Extractor: 3 code fixes, prevention strategies
✓ Related Docs Finder: 2 related issues
✓ Session History: 3 prior sessions on same branch, 2 failed approaches surfaced
Grounding Validation:
✓ Mechanical check: 14 paths, 2 SHAs, 3 links checked — 1 flag annotated as historical
✓ Semantic validator: 9 claims verified, 1 merge-state claim softened to pending
Specialized Agent Reviews (Auto-Triggered):
✓ performance-oracle: Validated query optimization approach
✓ Code simplification review: Code examples are appropriately minimal
Files written:
- <root>/solutions/performance-issues/n-plus-one-brief-generation.md (created)
- CONCEPTS.md (created with 3 entries: BriefSystem, EmailQueue, Brief Status)
This documentation will be searchable for future reference when similar
issues occur in the Email Processing or Brief System modules.
Refresh recommendation: none
End the turn after the summary — ce-compound does not present a "What's next?" menu. The doc is written and any cross-references the workflow found are already in it. Cross-doc maintenance (fixing references in other docs, consolidation) is deferred to ce-compound-refresh via the Refresh recommendation line above — the skill designed for it — not auto-applied here, which would edit tracked docs beyond the one deliverable. If the user wants to view the file or take a follow-up action, they will ask. (Interactive mode only.)
Alternate interactive output (when updating an existing doc due to high overlap): in headless mode, this case is communicated via the Overlap: high — existing doc updated line of the headless terminal report above, not as a separate output block.
✓ Documentation updated (existing doc refreshed with current context)
Overlap detected: <root>/solutions/performance-issues/n-plus-one-queries.md
Matched dimensions: problem statement, root cause, solution, referenced files
Action: Updated existing doc with fresher code examples and prevention tips
File updated:
- <root>/solutions/performance-issues/n-plus-one-queries.md (added last_updated: 2026-03-24)
This creates a compounding knowledge system:
The feedback loop:
Build → Test → Find Issue → Research → Improve → Document → Validate → Deploy
↑ ↓
└──────────────────────────────────────────────────────────────────────┘
Each unit of engineering work should make subsequent units of work easier—not harder.
<auto_invoke> <trigger_phrases> - "that worked" - "it's fixed" - "working now" - "problem solved" </trigger_phrases>
<manual_override> Invoke ce-compound with optional context to document immediately without waiting for auto-detection. </manual_override> </auto_invoke>
Writes the final learning directly into <root>/solutions/.
Based on problem type, these local prompt assets can enhance documentation:
ce-simplify-code after ce-compound completes for deeper code review and mutation/research [topic] - Deep investigation (searches /solutions/ for patterns)ce-plan - Planning workflow (references documented solutions)