diff --git a/.context/DECISIONS.md b/.context/DECISIONS.md
index 910241586..32f8590b1 100644
--- a/.context/DECISIONS.md
+++ b/.context/DECISIONS.md
@@ -3,6 +3,7 @@
| Date | Decision |
|----|--------|
+| 2026-05-11 | Embedded foreign-language assets under internal/assets/ are intentional, not a smell |
| 2026-05-10 | Placeholder overrides use EXTEND not REPLACE semantics |
| 2026-05-10 | Editorial constitution at .context/ingest/KB-RULES.md, not CONSTITUTION.md |
| 2026-05-10 | Phase KB ships handover plus editorial paired, not split |
@@ -138,6 +139,26 @@ For significant decisions:
-->
+## [2026-05-11-000000] Embedded foreign-language assets under internal/assets/ are intentional, not a smell
+
+**Status**: Accepted
+
+**Context**: A diagnostic conversation surfaced that `internal/assets/integrations/` contains TypeScript (`opencode/plugin/index.ts`), Bash and PowerShell scripts (`copilot-cli/scripts/`), JSON, YAML, and Markdown — none of it Go source. The first-glance read was "internal/ has become a dumping ground for non-Go tooling; lift integrations/ out." Audit of `embed.go` proved otherwise: every file under `integrations/` is captured by an explicit `//go:embed` directive and shipped inside the ctx binary as raw bytes, then written to the user's filesystem at `ctx setup` time. The smell was real (no contract document existed to explain this) but the architectural diagnosis was wrong.
+
+**Decision**: Embedded foreign-language assets stay under `internal/assets/`. The `internal/` directory is honoring Go's import-privacy convention; the contract is "everything in this tree is `//go:embed`'d into the binary as bytes." A `README.md` at `internal/assets/README.md` documents the contract; `internal/assets/doc.go` continues to serve the Go-doc audience.
+
+**Rationale**: Three reasons against lifting:
+
+1. **Hard Go constraint**: `//go:embed` directives cannot reference parents (no `../`). Moving assets out of the embed.go directory tree forces moving (or duplicating) the embed package itself, with import-path blast radius across every consumer. The relocation cost is disproportionate to the readability win.
+2. **Idiomatic Go**: `internal/` is about import privacy, not source language. Projects like Kubernetes and Cobra ship embedded foreign-language payloads from `internal/` without considering it a smell.
+3. **The actual fix is cheaper**: the smell was a missing contract document, not a misplaced directory. A README that names the rule ("everything here is `//go:embed`'d; foreign-language files are intentional payload") resolves the legibility problem at zero structural cost. Dev tooling *about* the embedded payload (e.g. `tsconfig.json` for the TS plugin) is what does not belong inside the embed tree — that goes in a sibling tooling directory.
+
+**Consequence**: Future contributors who feel the same "internal/ is a dumping ground" instinct will find a README documenting why the layout is correct. The README also enumerates current quality gates (presence, format parse, schema integrity) and the known gaps (TypeScript type-check, shellcheck, PSScriptAnalyzer, skill frontmatter validation) — gaps now spawned as discrete Phase 0 tasks. The line-30 `tsc --noEmit` task is redirected: its tooling files must live in a sibling directory outside `internal/assets/` to honor the embed contract.
+
+**Related**: Spec: specs/internal-assets-readme.md
+
+---
+
## [2026-05-10-181404] Placeholder overrides use EXTEND not REPLACE semantics
**Status**: Accepted
diff --git a/.context/TASKS.md b/.context/TASKS.md
index bc47a1cb2..5bf98cb20 100644
--- a/.context/TASKS.md
+++ b/.context/TASKS.md
@@ -26,13 +26,47 @@ TASK STATUS LABELS:
-->
## Phase 0 Grounding
-- [ ] Add TypeScript type-check step (bunx tsc --noEmit) for embedded editor-plugin assets to CI; nothing currently checks .opencode/plugins/ctx/index.ts before embedding #priority:low #added:2026-04-26-152912
-
-- [-] Promote 'block-dangerous-commands' to a real ctx system Go subcommand so OpenCode and other non-Claude editor integrations can ship the safety hook #priority:medium #added:2026-04-26-152911 #skipped:2026-04-26-231517 reason: decided not to do — OpenCode's exit-code semantics make a Cobra-based block-command shim too risky, and the safety-net omission in OpenCode is now treated as permanent (see decision 2026-04-26-231517)
+- [-] Add TypeScript type-check step (bunx tsc --noEmit) for embedded
+ editor-plugin assets to CI; nothing currently
+ checks .opencode/plugins/ctx/index.ts before embedding
+ #priority:low #added:2026-04-26-152912 #skipped:2026-05-11 reason:
+ scope redirected — investigation produced
+ specs/internal-assets-readme.md and `internal/assets/README.md`
+ documenting the embed contract; original work respawned into four
+ discrete gap tasks below (TS type-check, shellcheck,
+ PSScriptAnalyzer, skill frontmatter validation).
+
+- [ ] Add TypeScript `tsc --noEmit` gate for the embedded OpenCode
+ plugin (`internal/assets/integrations/opencode/plugin/index.ts`).
+ Place tooling (`package.json`, `tsconfig.json`) in a sibling
+ directory outside `internal/assets/` so it does not pollute the
+ embed surface; wire a CI step that installs Bun, `bun install`,
+ then `bunx tsc --noEmit`. Spec: respawn from
+ `specs/internal-assets-readme.md` open work.
+ #priority:low #added:2026-05-11 #grounding-gap
+
+- [ ] Add `shellcheck` gate for embedded shell scripts
+ (`internal/assets/integrations/copilot-cli/scripts/*.sh` and
+ `internal/assets/hooks/trace/*.sh`). Run in CI; fail on findings
+ at severity `warning` and above. #priority:low #added:2026-05-11
+ #grounding-gap
+
+- [ ] Add `PSScriptAnalyzer` gate for embedded PowerShell scripts
+ (`internal/assets/integrations/copilot-cli/scripts/*.ps1`). Run in
+ CI on a Windows or pwsh-enabled runner; fail on findings at
+ severity `Warning` and above. #priority:low #added:2026-05-11
+ #grounding-gap
+
+- [ ] Add skill frontmatter validity test covering every embedded
+ `SKILL.md` (Claude skills, OpenCode skills, Copilot CLI skills):
+ assert required keys present and values typed correctly. Extend
+ `internal/assets/embed_test.go` or add a dedicated test under
+ `internal/assets/read/skill/`. #priority:medium #added:2026-05-11
+ #grounding-gap
- [ ] The target project (to be given to the Agent) has a good "phasing"
- mechanism for tasks; implement that; maybe `ctx task add` can have a
+ mechanism for tasks; implement that; maybe `ctx task add` can have a
`--phase` flag too, and we can have a auditor/normalizer for the current
task document; or a skill that does a semantic pass, or both too.
@@ -51,12 +85,6 @@ TASK STATUS LABELS:
### Misc
-
-
-
-
-
-
### Agents
- [-] Add `ctx explore` command — scaffolds `.arch-explorer/` in a workspace
@@ -73,11 +101,6 @@ TASK STATUS LABELS:
### Runbooks
-
-
-
-
-
### Misc
- [ ] Human: Read the entire documentation page-by-page, line-by-line, with a
@@ -145,37 +168,28 @@ TASK STATUS LABELS:
### Architecture Docs
-- [ ] Publish architecture docs to docs/: copy ARCHITECTURE.md,
- DETAILED_DESIGN domain files, and CHEAT-SHEETS.md to docs/reference/.
- Sanitize intervention points into docs/contributing/.
- Exclude DANGER-ZONES.md and ARCHITECTURE-PRINCIPAL.md (internal only).
+- [ ] Publish architecture docs to docs/: copy ARCHITECTURE.md,
+ DETAILED_DESIGN domain files, and CHEAT-SHEETS.md to docs/reference/.
+ Sanitize intervention points into docs/contributing/.
+ Exclude DANGER-ZONES.md and ARCHITECTURE-PRINCIPAL.md (internal only).
Spec: specs/publish-architecture-docs.md #priority:medium
#added:2026-04-03-150000
-- [ ] Update ctx-architecture skill to append discovered terms to GLOSSARY.md
- during Phase 3. Additive only, max 10 terms per run, project-specific only,
- alphabetical insertion, skip if GLOSSARY.md empty. Print added terms in
+- [ ] Update ctx-architecture skill to append discovered terms to GLOSSARY.md
+ during Phase 3. Additive only, max 10 terms per run, project-specific only,
+ alphabetical insertion, skip if GLOSSARY.md empty. Print added terms in
convergence report. Spec: specs/publish-architecture-docs.md #priority:low
#added:2026-04-03-153000
### Code Cleanup Findings
-
-
-- [ ] Implement journal compaction: Elastic-style tiered storage with tar.gz
+- [ ] Implement journal compaction: Elastic-style tiered storage with tar.gz
backup. Spec: specs/journal-compact.md #added:2026-03-31-110005
-
-
-
**PD.5 — Validate:**
-
### Phase -3: DevEx
-
-
-
- [-] Create ctx-docstrings skill: audit and fix docstrings
against CONVENTIONS.md Documentation section. Superseded by
TestDocCommentStructure compliance test (68 grandfathered).
@@ -184,7 +198,6 @@ TASK STATUS LABELS:
### Phase -2: Task completion nudge:
-
- [ ] Design UserPromptSubmit hook that runs `make audit` at
session start and surfaces failures as a consolidation-debt
warning before the agent acts on stale assumptions.
@@ -200,54 +213,54 @@ TASK STATUS LABELS:
**Context**: Skill that incrementally builds and maintains
ARCHITECTURE.md and DETAILED_DESIGN.md. Coverage tracked in
map-tracking.json. Spec: `specs/ctx-architecture.md`
- - [x] Create ctx-architecture-enrich skill: takes existing
- /ctx-architecture principal-mode artifacts as baseline, runs
- comprehensive enrichment pass via GitNexus MCP (blast radius
- verification, registration site discovery, execution flow
- tracing, domain clustering comparison, shallow module
- deep-dive). Spec: `ideas/spec-architecture-enrich.md`.
- Reference implementation: kubernetes-service enrichment pass
- 2026-03-25. #added:2026-03-25-120000
+ - [x] Create ctx-architecture-enrich skill: takes existing
+ /ctx-architecture principal-mode artifacts as baseline, runs
+ comprehensive enrichment pass via GitNexus MCP (blast radius
+ verification, registration site discovery, execution flow
+ tracing, domain clustering comparison, shallow module
+ deep-dive). Spec: `ideas/spec-architecture-enrich.md`.
+ Reference implementation: kubernetes-service enrichment pass
+ 2026-03-25. #added:2026-03-25-120000
- [ ]: ctx-architecture-failure-analysis
- **Context**: Adversarial analysis skill that identifies where
- a codebase will silently betray you. Requires
- `ctx-architecture` artifacts as input (ARCHITECTURE.md,
- DETAILED_DESIGN*.md, map-tracking.json). Does its own
- targeted deep reads focusing on mutation points, shared
- mutable state, error swallowing, concurrency, implicit
- ordering, missing enforcement, and scaling cliffs. Uses
- available tooling (GitNexus, Gemini Search) to
- cross-reference patterns.
-
- Produces `DANGER-ZONES.md` — a ranked inventory of silent
- failure points with: location, failure mode, blast radius,
- detection gap, and suggested fix. Two tiers: "most likely to
- cause production incidents" and "less likely but equally
- dangerous."
-
- Distinct from a security threat model (which would be
- `ctx-threat-model` — a separate skill for auth bypass,
- injection, privilege escalation, supply chain). This skill
- focuses on correctness: race conditions, ordering
- assumptions, cache staleness, fan-out amplification,
- non-atomic ownership, inverted logic, force-delete orphans,
- global state mutation.
-
- - [x] Design SKILL.md for ctx-architecture-failure-analysis:
- inputs (architecture artifacts), analysis phases, output
- format (DANGER-ZONES.md), quality checklist
- #added:2026-03-25-060000
- - [x] Define the adversarial analysis framework: categories
- of silent failure (concurrency, ordering, cache,
- amplification, ownership, error swallowing, global state)
- with heuristics for each #added:2026-03-25-060000
- - [x] Implement skill with GitNexus integration: use impact
- analysis for blast radius estimation, use context for
- shared-state detection #added:2026-03-25-060000
- - [x] Add Gemini Search integration: cross-reference
- discovered patterns against known failure modes in similar
- systems. #added:2026-03-25-060000
+**Context**: Adversarial analysis skill that identifies where
+a codebase will silently betray you. Requires
+`ctx-architecture` artifacts as input (ARCHITECTURE.md,
+DETAILED_DESIGN*.md, map-tracking.json). Does its own
+targeted deep reads focusing on mutation points, shared
+mutable state, error swallowing, concurrency, implicit
+ordering, missing enforcement, and scaling cliffs. Uses
+available tooling (GitNexus, Gemini Search) to
+cross-reference patterns.
+
+Produces `DANGER-ZONES.md` — a ranked inventory of silent
+failure points with: location, failure mode, blast radius,
+detection gap, and suggested fix. Two tiers: "most likely to
+cause production incidents" and "less likely but equally
+dangerous."
+
+Distinct from a security threat model (which would be
+`ctx-threat-model` — a separate skill for auth bypass,
+injection, privilege escalation, supply chain). This skill
+focuses on correctness: race conditions, ordering
+assumptions, cache staleness, fan-out amplification,
+non-atomic ownership, inverted logic, force-delete orphans,
+global state mutation.
+
+- [x] Design SKILL.md for ctx-architecture-failure-analysis:
+ inputs (architecture artifacts), analysis phases, output
+ format (DANGER-ZONES.md), quality checklist
+ #added:2026-03-25-060000
+- [x] Define the adversarial analysis framework: categories
+ of silent failure (concurrency, ordering, cache,
+ amplification, ownership, error swallowing, global state)
+ with heuristics for each #added:2026-03-25-060000
+- [x] Implement skill with GitNexus integration: use impact
+ analysis for blast radius estimation, use context for
+ shared-state detection #added:2026-03-25-060000
+- [x] Add Gemini Search integration: cross-reference
+ discovered patterns against known failure modes in similar
+ systems. #added:2026-03-25-060000
- [-] ctx-architecture-extend
Skipped: extension point analysis is covered by /ctx-architecture
@@ -271,18 +284,18 @@ TASK STATUS LABELS:
I start?") and architecture review ("are we adding features
in the right places?").
- - [-] Design SKILL.md for ctx-extension-map
- Skipped: parent task skipped.
- #added:2026-03-25-062000
- - [-] Define extension point detection heuristics
- Skipped: parent task skipped.
- #added:2026-03-25-062000
- - [-] Add git log frequency analysis
- Skipped: parent task skipped.
- #added:2026-03-25-062000
- - [-] Integrate with GitNexus for registration sites
- Skipped: parent task skipped.
- #added:2026-03-25-062000
+ - [-] Design SKILL.md for ctx-extension-map
+ Skipped: parent task skipped.
+ #added:2026-03-25-062000
+ - [-] Define extension point detection heuristics
+ Skipped: parent task skipped.
+ #added:2026-03-25-062000
+ - [-] Add git log frequency analysis
+ Skipped: parent task skipped.
+ #added:2026-03-25-062000
+ - [-] Integrate with GitNexus for registration sites
+ Skipped: parent task skipped.
+ #added:2026-03-25-062000
### Phase CT: Companion Tool Integration
@@ -306,7 +319,6 @@ Session-start checks, suppressibility, and registry for companion MCP tools.
### Phase CLI-FIX: CLI Infrastructure Fixes
-
### Phase BLOG: Blog Posts
- [ ] Write blog post about architecture analysis + enrichment two-pass design
@@ -452,7 +464,6 @@ Docs are feature-organized, not problem-organized. Key structural improvements:
Prerequisites that unblocked the memory bridge phases.
-
### Phase MB: Memory Bridge Foundation (`ctx memory`)
Spec: `specs/memory-bridge.md`. Read the spec before starting any MB task.
@@ -476,7 +487,6 @@ mirror, state).
Spec: `specs/blog-agent-memory-infrastructure.md`.
-
### Phase MP: Memory Publish (`ctx memory publish`)
Spec: `specs/memory-publish.md`. Read the spec before starting any MP task.
@@ -535,50 +545,49 @@ Many call sites use `_ =` or `_, _ =` to discard errors without
any feedback. Some are legitimate (best-effort cleanup), most are
lazy escapes that hide failures.
-
- [ ] EH.1: Catalogue all silent error discards — recursive walk of
`internal/`
- for patterns: `_ = `, `_, _ = `, `//nolint:errcheck`, bare `return` after
- error-producing calls. Group by category:
- (a) file close in defer — often legitimate but should log on failure
- (b) file write/read — data loss risk, must surface
- (c) os.Remove/Rename — state corruption risk
- (d) fmt.Fprint to stderr — truly best-effort, acceptable
- Commands: `grep -rn '_ =' internal/`, `grep -rn
+ for patterns: `_ = `, `_, _ = `, `//nolint:errcheck`, bare `return` after
+ error-producing calls. Group by category:
+ (a) file close in defer — often legitimate but should log on failure
+ (b) file write/read — data loss risk, must surface
+ (c) os.Remove/Rename — state corruption risk
+ (d) fmt.Fprint to stderr — truly best-effort, acceptable
+ Commands: `grep -rn '_ =' internal/`, `grep -rn
'nolint:errcheck' internal/`
- Output: spreadsheet in `.context/` with file, line, expression, category,
- and recommended action (log-stderr, return-error, acceptable-as-is).
- DoD: every `_ =` in the codebase is categorised and has a
- recommended action
- #priority:high #added:2026-03-14
+ Output: spreadsheet in `.context/` with file, line, expression, category,
+ and recommended action (log-stderr, return-error, acceptable-as-is).
+ DoD: every `_ =` in the codebase is categorised and has a
+ recommended action
+ #priority:high #added:2026-03-14
- [ ] EH.2: Address category (b) — file write/read discards. These risk silent
- data loss. Fix: return the error, or at minimum emit to stderr with
- `fmt.Fprintf(os.Stderr, "ctx: ...: %v\n", err)` following the pattern
- established in `internal/log/event.go`.
- DoD: no write/read error is silently discarded
- #priority:high #added:2026-03-14
+ data loss. Fix: return the error, or at minimum emit to stderr with
+ `fmt.Fprintf(os.Stderr, "ctx: ...: %v\n", err)` following the pattern
+ established in `internal/log/event.go`.
+ DoD: no write/read error is silently discarded
+ #priority:high #added:2026-03-14
- [ ] EH.3: Address category (a) — file close in defer. Most are `defer func()
{ _ = f.Close() }()`. For read-only files, close errors are rare but
- should still surface. For write/append files, close can fail if the
- final flush fails — these are data loss. Fix: `if err := f.Close();
+ should still surface. For write/append files, close can fail if the
+ final flush fails — these are data loss. Fix: `if err := f.Close();
err != nil { fmt.Fprintf(os.Stderr, "ctx: close %s: %v\n", path, err) }`.
- DoD: all defer-close sites log failures to stderr
- #priority:medium #added:2026-03-14
+ DoD: all defer-close sites log failures to stderr
+ #priority:medium #added:2026-03-14
- [ ] EH.4: Address category (c) — os.Remove/Rename discards. These are state
- operations (rotation, pruning, temp file cleanup). Silent failure leaves
- stale state. Fix: stderr warning at minimum; for rotation/rename, consider
- returning the error.
- DoD: no Remove/Rename error is silently discarded
- #priority:medium #added:2026-03-14
+ operations (rotation, pruning, temp file cleanup). Silent failure leaves
+ stale state. Fix: stderr warning at minimum; for rotation/rename, consider
+ returning the error.
+ DoD: no Remove/Rename error is silently discarded
+ #priority:medium #added:2026-03-14
- [ ] EH.5: Validate — `grep -rn '_ =' internal/` returns only category (d)
- entries (fmt.Fprint to stderr) and entries explicitly annotated as
- acceptable. Run `make lint && make test` to confirm no regressions.
- DoD: grep output is clean or fully annotated; CI green
- #priority:high #added:2026-03-14
+ entries (fmt.Fprint to stderr) and entries explicitly annotated as
+ acceptable. Run `make lint && make test` to confirm no regressions.
+ DoD: grep output is clean or fully annotated; CI green
+ #priority:high #added:2026-03-14
- [ ] Add AST-based lint test to detect exported functions with no external
callers #added:2026-03-21-070357
@@ -674,8 +683,6 @@ Taxonomy (from prefix analysis):
#priority:low #added:2026-03-07-220825
-
-
- [-] SMB mount path support: add `CTX_BACKUP_MOUNT_PATH` env var so
`ctx backup` can use fstab/systemd automounts instead of requiring GVFS.
Spec: specs/smb-mount-path-support.md #priority:medium
@@ -759,7 +766,7 @@ Taxonomy (from prefix analysis):
- [ ] Make recency scoring thresholds and relevance match cap configurable via
.ctxrc — currently hardcoded in config (7/30/90 days, cap
- 3) #added:2026-03-07-073900
+ 3) #added:2026-03-07-073900
- [ ] Make DefaultAgentCooldown configurable via .ctxrc — currently hardcoded
at
@@ -934,34 +941,34 @@ age-based — prune files older than N days (default 7).
Use /ctx-blog-changelog with branch diff as source material.
#added:2026-02-16-111948
- [ ] P9.2: Test manually on this project's LEARNINGS.md (20+ entries).
- #priority:medium #added:2026-02-19
+ #priority:medium #added:2026-02-19
- [ ] P0.8.1: Install golangci-lint on the integration server #for-human
- #priority:medium #added:2026-02-23 #added:2026-02-23-170213
+ #priority:medium #added:2026-02-23 #added:2026-02-23-170213
- [ ] PM.3: Review hook diagnostic logs after a long session. Check
- `.context/logs/check-persistence.log` and
- `.context/logs/check-context-size.log` to verify hooks fire correctly.
- Tune nudge frequency if needed. #priority:medium #added:2026-02-09
+ `.context/logs/check-persistence.log` and
+ `.context/logs/check-context-size.log` to verify hooks fire correctly.
+ Tune nudge frequency if needed. #priority:medium #added:2026-02-09
- [ ] PM.4: Run `/consolidate` to address codebase drift. Considerable drift has
- accumulated (predicate naming, magic strings, hardcoded permissions,
- godoc style). #priority:medium #added:2026-02-06
+ accumulated (predicate naming, magic strings, hardcoded permissions,
+ godoc style). #priority:medium #added:2026-02-06
- [ ] Improve test coverage for core packages at 0% #added:2026-03-20-164324
- [ ] PM.7: Aider/Cursor parser implementations: the recall architecture was
- designed for extensibility (tool-agnostic Session type with
- tool-specific parsers). Adding basic Aider and Cursor parsers would
- validate the parser interface, broaden the user base, and fulfill
- the "works with any AI tool" promise. Aider format is simpler than
- Claude Code's. #priority:medium #source:report-6 #added:2026-02-17
+ designed for extensibility (tool-agnostic Session type with
+ tool-specific parsers). Adding basic Aider and Cursor parsers would
+ validate the parser interface, broaden the user base, and fulfill
+ the "works with any AI tool" promise. Aider format is simpler than
+ Claude Code's. #priority:medium #source:report-6 #added:2026-02-17
## Future
- [ ] P0.8.5: Enable webhook notifications in worktrees. Currently `ctx notify`
- silently fails because `.context.key` is gitignored and absent in
- worktrees. For autonomous runs with opaque worktree agents, notifications
- are the one feature that would genuinely be useful. Possible approaches:
- resolve the key via `git rev-parse --git-common-dir` to find the main
- checkout, or copy the key into worktrees at creation time (ctx-worktree
- skill). #priority:medium #added:2026-02-22
+ silently fails because `.context.key` is gitignored and absent in
+ worktrees. For autonomous runs with opaque worktree agents, notifications
+ are the one feature that would genuinely be useful. Possible approaches:
+ resolve the key via `git rev-parse --git-common-dir` to find the main
+ checkout, or copy the key into worktrees at creation time (ctx-worktree
+ skill). #priority:medium #added:2026-02-22
- [ ] P0.9.2: Split cli-reference.md (1633 lines) into command group pages:
cli-overview, cli-init-status, cli-context, cli-recall, cli-tools,
cli-system —
@@ -975,14 +982,14 @@ age-based — prune files older than N days (default 7).
#added:2026-02-24-185754
- [ ] PG.1: Add agent/tool compatibility matrix to prompting guide —
document which
- patterns degrade gracefully when agents lack file access, CLI tools, or
- ctx integration. Treat as a "works best with / degrades to" table.
- #priority:medium #added:2026-02-25
+ patterns degrade gracefully when agents lack file access, CLI tools, or
+ ctx integration. Treat as a "works best with / degrades to" table.
+ #priority:medium #added:2026-02-25
- [ ] PG.2: Add versioning/stability note to prompting guide — "these
principles are
- stable; examples evolve" + doc date in frontmatter. Needed once the guide
- becomes canonical and people start quoting it.
- #priority:low #added:2026-02-25
+ stable; examples evolve" + doc date in frontmatter. Needed once the guide
+ becomes canonical and people start quoting it.
+ #priority:low #added:2026-02-25
- [ ] P0.1: Brainstorm: Standardize drift-check comment format and
integrate with
`/ctx-drift` — formalize ad-hoc `` markers, teach
@@ -1043,6 +1050,7 @@ or validate
that's `ctx`.
Strong fits beyond build/release:
+
- `ctxctl plugin package` — package .claude-plugin for marketplace publishing
- `ctxctl plugin validate` — validate plugin.json, hooks.json, skill structure
- `ctxctl doctor` — contributor pre-flight (Go version, tools, GPG, hooks);
@@ -1050,12 +1058,14 @@ Strong fits beyond build/release:
- `ctxctl changelog` — deterministic release notes from git log
Reasonable fits if project grows:
+
- `ctxctl test smoke` — replaces the shell pipeline in `make smoke`
- `ctxctl site build/serve` — wraps zensical + feed generation
- `ctxctl mcp register` — replaces `hack/gemini-search.sh` and future
MCP registrations
Not a fit (keep in `ctx`):
+
- Anything user-facing in a project context (status, agent, drift, recall)
- Anything Claude Code hooks call — hooks must call `ctx`, not `ctxctl`
@@ -1090,30 +1100,6 @@ Not a fit (keep in `ctx`):
contract (query, context, impact). Spec:
`ideas/spec-mcp-warm-up-ceremony.md` #added:2026-03-25-120000
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
### Phase: ctx Hub follow-ups (PR #60)
**Context**: PR #60 `feat: ctx Hub for cross-project knowledge
@@ -1160,7 +1146,6 @@ https://github.com/ActiveMemory/ctx/pull/60#pullrequestreview-PRR_kwDOQ9VoNc7ze3
#### Framing and mental model (2026-04-11 follow-up)
-
#### Design follow-ups surfaced by the brainstorm (2026-04-11)
- [ ] Decide the product story: "personal cross-project brain",
@@ -1233,35 +1218,35 @@ Tasks unique to this phase:
procedure, migration path from today's `clients.json`.
`specs/hub-identity-registry.md`. Must resolve:
- - **Token issuance**: out-of-band on the server
- (`ctx hub users add` prints the plaintext token once
- on stdout; only a hash is persisted).
- - **Client pickup**: user receives the token out-of-band
- and runs `ctx connect register --token
+ - **Token issuance**: out-of-band on the server
+ (`ctx hub users add` prints the plaintext token once
+ on stdout; only a hash is persisted).
+ - **Client pickup**: user receives the token out-of-band
+ and runs `ctx connect register --token
ctx_cli_... --project `; hub validates against
- the registry.
- - **TTL decision** (pick one, document in the spec):
- * **Option A** (recommended): no TTL, manual revocation
- only. `ctx hub users remove ` is the only
- expiry path. Matches today's `clients.json`
- semantics, zero surprise breakage on migration.
- * **Option B**: optional `expires_at` per user row.
- Tokens without it are valid forever (Option A
- behavior); tokens with it are rejected after the
- timestamp. Ship as an additive follow-up.
- * **Option C** (explicitly rejected): rolling
- expiry based on `last_used_at`. Garbage-collects
- dormant tokens but breaks users who take long
- vacations. Not worth the support cost.
- - **Revocation procedure**: sysadmin edits `users.json`,
- signals the hub to reload, affected tokens fail
- immediately on next RPC.
- - **Migration from `clients.json`**: one-shot converter
- that reads today's `clients.json`, prompts the
- sysadmin for a `user_id` per row, and writes
- `users.json`. Leave `clients.json` in place as a
- read fallback during migration, delete once
- everyone is on the new path.
+ the registry.
+ - **TTL decision** (pick one, document in the spec):
+ * **Option A** (recommended): no TTL, manual revocation
+ only. `ctx hub users remove ` is the only
+ expiry path. Matches today's `clients.json`
+ semantics, zero surprise breakage on migration.
+ * **Option B**: optional `expires_at` per user row.
+ Tokens without it are valid forever (Option A
+ behavior); tokens with it are rejected after the
+ timestamp. Ship as an additive follow-up.
+ * **Option C** (explicitly rejected): rolling
+ expiry based on `last_used_at`. Garbage-collects
+ dormant tokens but breaks users who take long
+ vacations. Not worth the support cost.
+ - **Revocation procedure**: sysadmin edits `users.json`,
+ signals the hub to reload, affected tokens fail
+ immediately on next RPC.
+ - **Migration from `clients.json`**: one-shot converter
+ that reads today's `clients.json`, prompts the
+ sysadmin for a `user_id` per row, and writes
+ `users.json`. Leave `clients.json` in place as a
+ read fallback during migration, delete once
+ everyone is on the new path.
#priority:high #added:2026-04-11 #pr:60
- [ ] Implement `users.json` format: `{user_id: {project_ids:
@@ -1319,11 +1304,11 @@ Tasks unique to this phase:
clients present the signed claim on each RPC, server
verifies with the public key. Benefits:
- - Private key never leaves the sysadmin's machine.
- - Claims expire in minutes → revocation is automatic.
- - Each claim carries identity cryptographically.
- - No per-RPC registry lookup — signature verification
- is cheap.
+ - Private key never leaves the sysadmin's machine.
+ - Claims expire in minutes → revocation is automatic.
+ - Each claim carries identity cryptographically.
+ - No per-RPC registry lookup — signature verification
+ is cheap.
Reference designs to evaluate: JWT (RS256/ES256/EdDSA),
mTLS client certificates, SPIFFE/SPIRE workload
@@ -1694,7 +1679,6 @@ mental model in docs. `ctx` Hub is the canonical name; `Hub` is
used alone in nav and operator contexts where surrounding text
disambiguates.
-
### Later
- [ ] Optional follow-up doc.go pass: a handful of tiny per-subcommand wrappers
@@ -1722,45 +1706,66 @@ disambiguates.
Spec: `specs/ceremony-profiles.md`
-- [ ] Add `Ceremony{Remember,WrapUp}` to `internal/rc/types.go`; apply defaults in `internal/rc/rc.go` from `internal/config/ceremony/ceremony.go` constants
-- [ ] Thread resolved ceremony names into `ScanJournalsForCeremonies` and `Emit` in `internal/cli/system/core/ceremony/ceremony.go` (replace direct constant reads)
-- [ ] Convert `internal/assets/hooks/messages/check-ceremony/{remember,wrapup,both}.txt` to `{REMEMBER}` / `{WRAPUP}` sentinels; audit `internal/config/embed/text` ceremony desc keys for the same
-- [ ] Add a single sentinel-substitution helper (extend `internal/cli/system/core/message.Load` or sibling) so substitution happens in one place
+- [ ] Add `Ceremony{Remember,WrapUp}` to `internal/rc/types.go`; apply defaults in `internal/rc/rc.go` from
+ `internal/config/ceremony/ceremony.go` constants
+- [ ] Thread resolved ceremony names into `ScanJournalsForCeremonies` and `Emit` in
+ `internal/cli/system/core/ceremony/ceremony.go` (replace direct constant reads)
+- [ ] Convert `internal/assets/hooks/messages/check-ceremony/{remember,wrapup,both}.txt` to `{REMEMBER}` / `{WRAPUP}`
+ sentinels; audit `internal/config/embed/text` ceremony desc keys for the same
+- [ ] Add a single sentinel-substitution helper (extend `internal/cli/system/core/message.Load` or sibling) so
+ substitution happens in one place
- [ ] Show active ceremony profile (one line) in `ctx status` output
-- [ ] Tests: default profile renders `/ctx-remember` `/ctx-wrap-up`; project with `ceremony.remember: dp-remember` renders `/dp-remember` and scanner only counts `dp-remember` as fulfilling the open-bookend
+- [ ] Tests: default profile renders `/ctx-remember` `/ctx-wrap-up`; project with `ceremony.remember: dp-remember`
+ renders `/dp-remember` and scanner only counts `dp-remember` as fulfilling the open-bookend
- [ ] Document in `docs/recipes/` with the editorial-project (DR knowledgebase) consumer as the worked example
### Phase SK: Skill Surface Polish (Phase 0a; prerequisite for Phase KB) `#priority:high #added:2026-05-09`
-Spec: `specs/skill-surface-polish.md` (design ref: `ideas/002-editorial-pipeline-and-skill-rigor.md` §3 "Reframing the wishy-washy skills")
-
-Tightens existing capture skills to sibling-project rigor before the editorial pipeline (Phase KB) lifts that pattern wholesale. Independent of Phase RG; both can ship in parallel.
-
-- [x] Add `MarkFlagRequired` to `ctx decision add` for `--context`, `--rationale`, `--consequence`; reject placeholder values (`TBD`, `see chat`, whitespace-only) at CLI level
-- [x] Add `MarkFlagRequired` to `ctx learning add` for `--context`, `--lesson`, `--application`; same placeholder rejection
-- [x] Add `--brief ` flag to `/ctx-spec` skill: when present, read the file as authoritative source per the sibling's authority order (frozen contracts > recorded decisions > debrief > agent inference labeled `TBD`); skip the fresh template Q&A
-- [x] Update `/ctx-plan` skill to always offer to write the debated brief to `.context/briefs/-.md` at the end of an interview (creating `.context/briefs/` if absent)
-- [x] Add an `Authority boundary (vs other skills)` section to `/ctx-decision-add`, `/ctx-learning-add`, `/ctx-task-add`, `/ctx-convention-add` skill files (prevent silent promotion handover→decision, learning→convention, etc., without explicit user ask)
-- [x] Standardize "light compression for clarity is allowed; new facts are not" wording across capture skills (decide / learn primarily); same wording lands in `/ctx-handover` once Phase KB ships
+Spec: `specs/skill-surface-polish.md` (design ref: `ideas/002-editorial-pipeline-and-skill-rigor.md` §3 "Reframing the
+wishy-washy skills")
+
+Tightens existing capture skills to sibling-project rigor before the editorial pipeline (Phase KB) lifts that pattern
+wholesale. Independent of Phase RG; both can ship in parallel.
+
+- [x] Add `MarkFlagRequired` to `ctx decision add` for `--context`, `--rationale`, `--consequence`; reject placeholder
+ values (`TBD`, `see chat`, whitespace-only) at CLI level
+- [x] Add `MarkFlagRequired` to `ctx learning add` for `--context`, `--lesson`, `--application`; same placeholder
+ rejection
+- [x] Add `--brief ` flag to `/ctx-spec` skill: when present, read the file as authoritative source per the
+ sibling's authority order (frozen contracts > recorded decisions > debrief > agent inference labeled `TBD`); skip the
+ fresh template Q&A
+- [x] Update `/ctx-plan` skill to always offer to write the debated brief to `.context/briefs/-.md` at the end
+ of an interview (creating `.context/briefs/` if absent)
+- [x] Add an `Authority boundary (vs other skills)` section to `/ctx-decision-add`, `/ctx-learning-add`,
+ `/ctx-task-add`, `/ctx-convention-add` skill files (prevent silent promotion handover→decision, learning→convention,
+ etc., without explicit user ask)
+- [x] Standardize "light compression for clarity is allowed; new facts are not" wording across capture skills (decide /
+ learn primarily); same wording lands in `/ctx-handover` once Phase KB ships
- [x] Document the `--brief` contract in `docs/skills.md` (landed in `docs/reference/skills.md` — the actual location)
-### Phase RG: Require Git as Architectural Precondition (Phase 0b; prerequisite for Phase KB) `#priority:high #added:2026-05-09`
+### Phase RG: Require Git as Architectural Precondition (Phase 0b; prerequisite for Phase KB)
+`#priority:high #added:2026-05-09`
Spec: `specs/require-git.md`
-Promotes the de facto invariant ("ctx works properly only with git") to a de jure one. Breaking change for any pre-existing git-less ctx project (N≈0 in practice). Independent of Phase SK; both can ship in parallel.
+Promotes the de facto invariant ("ctx works properly only with git") to a de jure one. Breaking change for any
+pre-existing git-less ctx project (N≈0 in practice). Independent of Phase SK; both can ship in parallel.
- [ ] Add `internal/gitmeta/require.go` with `RequireGitTree(projectRoot string) error` and typed `MissingGitError`
-- [ ] Wire `RequireGitTree` into root command PersistentPreRunE; opt-out list `--help`, `--version`, `ctx system bootstrap`; audit other read-only/help-shaped commands during implementation (default: git-required)
+- [ ] Wire `RequireGitTree` into root command PersistentPreRunE; opt-out list `--help`, `--version`,
+ `ctx system bootstrap`; audit other read-only/help-shaped commands during implementation (default: git-required)
- [ ] Update `ctx init` to call `RequireGitTree` first; emit the documented error verbatim
- [ ] Remove `commit:none` fallback from `internal/gitmeta/resolvehead.go` (state now unreachable)
- [ ] Remove `commit:none` advisory + counts from `internal/cli/doctor/advisory.go`
- [ ] Audit `internal/cli//cmd.go` for any other `commit:none` fallback handling; remove
- [ ] Add CONSTITUTION.md amendment ("Git is required") under Process Invariants
-- [ ] Add DECISIONS.md entry: "Mandate git as architectural precondition" (Accepted; context = LLM-safety + provenance honesty + dead-code elimination; consequence = breaking change for pre-existing git-less projects, N≈0)
+- [ ] Add DECISIONS.md entry: "Mandate git as architectural precondition" (Accepted; context = LLM-safety + provenance
+ honesty + dead-code elimination; consequence = breaking change for pre-existing git-less projects, N≈0)
- [ ] Update `docs/recipes/bootstrap-a-project.md`, `README.md`, `docs/cli/init.md` to show `git init` before `ctx init`
-- [ ] Tag as breaking change in `dist/RELEASE_NOTES.md` with one-command migration ("Run `git init` in any pre-existing git-less ctx projects before upgrading")
-- [ ] Tests: `.git` dir → nil; `.git` file (worktree pointer) → nil; absent → typed error; root PreRunE refuses without git; opt-out list allowed
+- [ ] Tag as breaking change in `dist/RELEASE_NOTES.md` with one-command migration ("Run `git init` in any pre-existing
+ git-less ctx projects before upgrading")
+- [ ] Tests: `.git` dir → nil; `.git` file (worktree pointer) → nil; absent → typed error; root PreRunE refuses without
+ git; opt-out list allowed
- [ ] Compliance test: no remaining `commit:none` literal in `internal/` (catches future regressions)
### Phase KB: Editorial Pipeline + Handover (depends on Phase SK + Phase RG) `#priority:high #added:2026-05-09`
@@ -1769,52 +1774,79 @@ Spec: `specs/kb-editorial-pipeline.md`
Brief: `ideas/003-editorial-pipeline-debated-brief.md`
-Background analysis: `ideas/001-sibling-project-undercover-analysis.md`, `ideas/002-editorial-pipeline-and-skill-rigor.md`
+Background analysis: `ideas/001-sibling-project-undercover-analysis.md`,
+`ideas/002-editorial-pipeline-and-skill-rigor.md`
Validation corpus: `things-wtf-disaster-recovery` (live regression suite; hand-rolled the shape for weeks).
Path constants and embedded templates:
-- [ ] Extend `internal/path/path.go` with new constants: `HandoversDir`, `KBDir` + per-artifact paths, `IngestDir` + per-template paths, `CloseoutsSubdir`, `ArchiveCloseoutsSubdir`, `SiteDir`, `SiteKBDir`, `SiteConfigDir`
-- [ ] Embed templates under `internal/assets/kb/templates/ingest/`: `KB-RULES.md`, `00-GROUND.md`, `30-INGEST.md`, `40-ASK.md`, `50-SITE_REVIEW.md`, `INBOX.md`, `SESSION_LOG.md`, `grounding-sources.md`, `OPERATOR.md`, `PROMPT.md` (no domain content)
-- [ ] Embed schemas under `internal/assets/kb/templates/ingest/schemas/`: `evidence-index.md`, `glossary.md`, `contradictions.md`, `outstanding-questions.md`, `domain-decisions.md`, `timeline.md`, `source-map.md`, `relationship-map.md`, `session-log.md` (each: fields list + one worked example)
+- [ ] Extend `internal/path/path.go` with new constants: `HandoversDir`, `KBDir` + per-artifact paths, `IngestDir` +
+ per-template paths, `CloseoutsSubdir`, `ArchiveCloseoutsSubdir`, `SiteDir`, `SiteKBDir`, `SiteConfigDir`
+- [ ] Embed templates under `internal/assets/kb/templates/ingest/`: `KB-RULES.md`, `00-GROUND.md`, `30-INGEST.md`,
+ `40-ASK.md`, `50-SITE_REVIEW.md`, `INBOX.md`, `SESSION_LOG.md`, `grounding-sources.md`, `OPERATOR.md`, `PROMPT.md` (no
+ domain content)
+- [ ] Embed schemas under `internal/assets/kb/templates/ingest/schemas/`: `evidence-index.md`, `glossary.md`,
+ `contradictions.md`, `outstanding-questions.md`, `domain-decisions.md`, `timeline.md`, `source-map.md`,
+ `relationship-map.md`, `session-log.md` (each: fields list + one worked example)
Store layer:
-- [ ] Implement `internal/store/handover.go`: `WriteHandover`, `LatestHandoverCursor`, `UnconsumedCloseouts`, `ArchiveCloseouts`
-- [ ] Implement `internal/store/closeout.go`: `WriteCloseout` with required frontmatter (`sha`, `branch`, `mode`, `generated-at`); cursor-extracting reader
-- [ ] Implement `internal/store/kb.go`: per-artifact writers (evidence-index append-never-renumber; glossary; contradictions; outstanding-questions; domain-decisions; timeline; source-map; relationship-map); demotion API; `EvidenceRow` includes `occurred:` field per spec schema delta
+- [ ] Implement `internal/store/handover.go`: `WriteHandover`, `LatestHandoverCursor`, `UnconsumedCloseouts`,
+ `ArchiveCloseouts`
+- [ ] Implement `internal/store/closeout.go`: `WriteCloseout` with required frontmatter (`sha`, `branch`, `mode`,
+ `generated-at`); cursor-extracting reader
+- [ ] Implement `internal/store/kb.go`: per-artifact writers (evidence-index append-never-renumber; glossary;
+ contradictions; outstanding-questions; domain-decisions; timeline; source-map; relationship-map); demotion API;
+ `EvidenceRow` includes `occurred:` field per spec schema delta
CLI commands:
-- [ ] `ctx handover write` — `MarkFlagRequired` on `--summary` and `--next`; reject placeholder values (parity with Phase SK pattern); calls handover writer + closeout fold; supports `--no-fold`, `--commit`, `--highlights`, `--open-questions`
-- [ ] `ctx kb` parent command + `ingest` / `ask` / `site-review` / `ground` / `note` subcommands; refuse-on-empty for `ingest` / `ask` / `ground`
-- [ ] `ctx kb site` (`build` / `serve` / `customize`) — mirror existing `ctx journal site` shell-out pattern with zensical
-- [ ] Extend `ctx init` to lay down `handovers/`, `kb/.gitkeep`, `ingest/` (full template tree), `site/` (gitignored); add `--upgrade` flag (idempotent on byte-identical existing content; refuse on divergent)
+- [ ] `ctx handover write` — `MarkFlagRequired` on `--summary` and `--next`; reject placeholder values (parity with
+ Phase SK pattern); calls handover writer + closeout fold; supports `--no-fold`, `--commit`, `--highlights`,
+ `--open-questions`
+- [ ] `ctx kb` parent command + `ingest` / `ask` / `site-review` / `ground` / `note` subcommands; refuse-on-empty for
+ `ingest` / `ask` / `ground`
+- [ ] `ctx kb site` (`build` / `serve` / `customize`) — mirror existing `ctx journal site` shell-out pattern with
+ zensical
+- [ ] Extend `ctx init` to lay down `handovers/`, `kb/.gitkeep`, `ingest/` (full template tree), `site/` (gitignored);
+ add `--upgrade` flag (idempotent on byte-identical existing content; refuse on divergent)
Skills:
-- [ ] Add `internal/assets/claude/skills/ctx-handover/SKILL.md` per spec (input contract, authority boundary, edge cases)
+- [ ] Add `internal/assets/claude/skills/ctx-handover/SKILL.md` per spec (input contract, authority boundary, edge
+ cases)
- [ ] Add `ctx-kb-ingest`, `ctx-kb-ask`, `ctx-kb-site-review`, `ctx-kb-ground`, `ctx-kb-note` SKILL.md files
-- [ ] Modify `internal/assets/claude/skills/ctx-wrap-up/SKILL.md`: branch on `.context/kb/` existence (surface editorial state — pending closeouts, outstanding-questions count); mandatorily drive `/ctx-handover` as final step regardless of capture outcomes
-- [ ] Modify `/ctx-remember` skill (or equivalent): read latest handover + any postdated unfolded closeouts; fold KB state into readback if `.context/kb/` exists
+- [ ] Modify `internal/assets/claude/skills/ctx-wrap-up/SKILL.md`: branch on `.context/kb/` existence (surface editorial
+ state — pending closeouts, outstanding-questions count); mandatorily drive `/ctx-handover` as final step regardless of
+ capture outcomes
+- [ ] Modify `/ctx-remember` skill (or equivalent): read latest handover + any postdated unfolded closeouts; fold KB
+ state into readback if `.context/kb/` exists
Doctor / status / .gitignore:
-- [ ] Extend `internal/cli/doctor/advisory.go`: duplicate-`EV-###` detection; `dated:` source missing `occurred:` rows; malformed-closeout-frontmatter detection
-- [ ] Mode-aware reads: thread `KBExists()` check through `/ctx-remember` (or equivalent), `ctx status`, `ctx agent`, session-start hook nudges (cross-cutting; manageable but explicit v1 surface area)
-- [ ] Update project root `.gitignore`: append `.context/site/` (idempotent; match existing `.context/journal/.imported.json` pattern)
+- [ ] Extend `internal/cli/doctor/advisory.go`: duplicate-`EV-###` detection; `dated:` source missing `occurred:` rows;
+ malformed-closeout-frontmatter detection
+- [ ] Mode-aware reads: thread `KBExists()` check through `/ctx-remember` (or equivalent), `ctx status`, `ctx agent`,
+ session-start hook nudges (cross-cutting; manageable but explicit v1 surface area)
+- [ ] Update project root `.gitignore`: append `.context/site/` (idempotent; match existing
+ `.context/journal/.imported.json` pattern)
Tests:
- [ ] Unit tests per package (handover, closeout, kb writers, mode CLIs, doctor advisories)
-- [ ] Integration: `internal/cli/initcmd/init_test.go` covers full new directory tree + `--upgrade` idempotency / divergence refusal
-- [ ] `hack/smoke-kb.sh`: end-to-end shell smoke (init → kb ingest → kb ask → kb site-review → kb ground → handover write → archive populated → doctor clean)
-- [ ] Edge-case fixtures: aborted-session recovery (closeout without handover); temporal misordering (occurred-vs-extracted ordering enforces precedence rule); concurrent dupe IDs (LLM-resolution fixture); render filter (speculative excluded; low paired with outstanding-questions)
+- [ ] Integration: `internal/cli/initcmd/init_test.go` covers full new directory tree + `--upgrade` idempotency /
+ divergence refusal
+- [ ] `hack/smoke-kb.sh`: end-to-end shell smoke (init → kb ingest → kb ask → kb site-review → kb ground → handover
+ write → archive populated → doctor clean)
+- [ ] Edge-case fixtures: aborted-session recovery (closeout without handover); temporal misordering (
+ occurred-vs-extracted ordering enforces precedence rule); concurrent dupe IDs (LLM-resolution fixture); render
+ filter (speculative excluded; low paired with outstanding-questions)
Phase KB-2 (validation against live corpus):
-- [ ] Port `things-wtf-disaster-recovery` from its hand-rolled shape to the shipped one. Each divergence is either a Phase KB bug or a `DECISIONS.md` entry explaining why the formal shape differs from what worked manually
+- [ ] Port `things-wtf-disaster-recovery` from its hand-rolled shape to the shipped one. Each divergence is either a
+ Phase KB bug or a `DECISIONS.md` entry explaining why the formal shape differs from what worked manually
- [ ] Document divergences (if any) in `docs/recipes/build-a-knowledge-base.md`
Phase KB-3 (documentation):
@@ -1824,12 +1856,20 @@ Phase KB-3 (documentation):
- [ ] Write `docs/recipes/recover-aborted-session.md`
- [ ] Update `docs/cli-reference.md` with new `ctx kb` and `ctx handover` commands
- [ ] Update `docs/skills.md` with new skills
-- [ ] Document MemPalace-as-ground-source recipe in `docs/recipes/build-a-knowledge-base.md` — uses already-specced `mcp::` syntax in `grounding-sources.md`; zero new ctx code
+- [ ] Document MemPalace-as-ground-source recipe in `docs/recipes/build-a-knowledge-base.md` — uses already-specced
+ `mcp::` syntax in `grounding-sources.md`; zero new ctx code
### Phase JR: Cold-Start Memory Recovery (semantic recall over journal history) `#priority:medium #added:2026-05-10`
Idea: `ideas/004-cold-start-memory-recovery.md`
-Pain point: today's "can you check recent journal entries?" workaround forces brute-force parsing of the journal corpus or precise user pointers to specific files/dates. ctx has journal management but no semantic recall layer. MemPalace (https://github.com/MemPalace/mempalace) does this exact use case at 96.6% R@5 raw on LongMemEval. Three options to evaluate: A) native ctx journal search (vector-store dep, breaks single-Go-binary identity); B) defer-to-MemPalace recipe (zero ctx-side work; coupling to young project); C) pluggable journal-search hook following the zensical shell-out pattern (recommended).
+Pain point: today's "can you check recent journal entries?" workaround forces brute-force parsing of the journal corpus
+or precise user pointers to specific files/dates. ctx has journal management but no semantic recall layer.
+MemPalace (https://github.com/MemPalace/mempalace) does this exact use case at 96.6% R@5 raw on LongMemEval. Three
+options to evaluate: A) native ctx journal search (vector-store dep, breaks single-Go-binary identity); B)
+defer-to-MemPalace recipe (zero ctx-side work; coupling to young project); C) pluggable journal-search hook following
+the zensical shell-out pattern (recommended).
-- [ ] Spec out cold-start memory recovery: pick approach (A vs B vs C); ideas/004 leans toward C. Distinct from Phase KB ground-mode `mcp:` source kinds (which cover the KB-grounding angle for free); this phase is specifically about journal-corpus semantic recall (`ctx journal search ""` shape).
+- [ ] Spec out cold-start memory recovery: pick approach (A vs B vs C); ideas/004 leans toward C. Distinct from Phase KB
+ ground-mode `mcp:` source kinds (which cover the KB-grounding angle for free); this phase is specifically about
+ journal-corpus semantic recall (`ctx journal search ""` shape).
diff --git a/.context/archive/tasks-2026-05-10.md b/.context/archive/tasks-2026-05-10.md
index e056d4662..841624fe7 100644
--- a/.context/archive/tasks-2026-05-10.md
+++ b/.context/archive/tasks-2026-05-10.md
@@ -1,5 +1,11 @@
# Archived Tasks - 2026-05-10
+- [-] Promote 'block-dangerous-commands' to a real ctx system Go subcommand
+ so OpenCode and other non-Claude editor integrations can ship the safety
+ hook #priority:medium #added:2026-04-26-152911 #skipped:2026-04-26-231517 reason:
+ decided not to do — OpenCode's exit-code semantics make a
+ Cobra-based block-command shim too risky, and the safety-net omission in
+ OpenCode is now treated as permanent (see decision 2026-04-26-231517)
- [x] bug: asking "do you remember" automatically creates a blank .context
directory when using cursor
(Spec: specs/state-dir-no-mkdir-when-uninitialized.md)
diff --git a/internal/assets/README.md b/internal/assets/README.md
new file mode 100644
index 000000000..8c84345a3
--- /dev/null
+++ b/internal/assets/README.md
@@ -0,0 +1,214 @@
+
+
+## `internal/assets/`
+
+The embedded asset tree for the ctx Go binary.
+
+Everything under this directory is compiled into the binary via
+`//go:embed` (see `embed.go`) and shipped as raw bytes inside
+`ctx`. None of these files execute *inside* ctx itself; they are
+written to the user's filesystem at `ctx setup` time, where a
+*consumer tool* (Claude Code, OpenCode, Copilot CLI, …) loads and
+runs them in its own runtime.
+
+If you are looking for a Go-doc-targeted summary, see `doc.go`.
+This README is the longer answer: why the tree looks like it
+does, what the contract is, and how to add to it without
+breaking the contract.
+
+---
+
+## Why Does the Non-Go Code Lives Under `internal/`?
+
+`internal/` in Go convention means "*private to this module: no
+external import*" (*enforced by the Go compiler*). It does **not**
+mean "Go source only." What lives here is private *build-time
+input*: bytes that the `ctx` build process consumes to produce the
+release artifact.
+
+The reason these bytes are TypeScript, Bash, PowerShell, JSON,
+YAML, and Markdown (*instead of being fetched at runtime or
+distributed as a separate package*) is the single-binary
+distribution model:
+
+* `ctx` ships as **one statically-linked Go binary**, no runtime
+ dependency tree, no package manager, no network fetch on install.
+* Integrations with external tools (*Claude Code plugins,
+ OpenCode plugins, Copilot CLI hooks*) require *files those
+ tools can load*. Those files have to exist somewhere
+ ahead of time.
+* `//go:embed` makes the Go binary that "somewhere": at compile
+ time the build reads each listed file and stores its bytes in
+ the `embed.FS` exported by `package assets`. At install time
+ (`ctx setup ...`), ctx reads those bytes back out of itself and
+ writes them to the user's filesystem at the location the
+ consumer tool expects.
+
+A concrete trace, for the OpenCode plugin:
+
+```
+internal/assets/integrations/opencode/plugin/index.ts (source)
+ │
+ │ build time: //go:embed in embed.go
+ ▼
+ ctx binary embeds raw bytes
+ │
+ │ ctx setup opencode → deployPlugin()
+ │ (see internal/cli/setup/core/opencode/plugin.go)
+ ▼
+ ~/your-project/.opencode/plugins/ctx.ts (deployed)
+ │
+ │ OpenCode (Bun runtime) auto-loads
+ ▼
+ executes inside OpenCode
+```
+
+The same shape applies to Copilot CLI scripts, Claude Code skill
+markdowns, and every other artifact in this tree: ctx is the
+*carrier*, not the *executor*.
+
+---
+
+## The Embed Contract
+
+A file belongs under `internal/assets/` if and only if:
+
+1. It is shipped to users **as bytes**, exactly as committed.
+2. A consumer (the ctx binary itself, or an external tool ctx
+ installs assets into) needs those bytes available with no
+ additional fetch or build step.
+3. It is referenced by a `//go:embed` directive in `embed.go`.
+
+If a file is meant to be compiled, generated, fetched, linted,
+type-checked, or transformed before reaching a user, it does
+**not** belong here — or, more precisely, only its
+post-transformation output does. The directory is a *payload
+manifest*, not a workspace.
+
+### Hard Go Constraint
+
+`//go:embed` paths are relative to the source file containing
+the directive, and cannot reference parents (*`../integrations`
+is a compile error*). The practical consequence is that
+the embed root and the assets must be in the same directory
+subtree. Moving assets out of this tree without also moving
+(*or duplicating*) the `embed.go` declaration will break the build.
+
+---
+
+## Directory map
+
+| Path | Language(s) | Consumer | Deployed to |
+|----------------------------------------------|------------------------|-------------------------------|-------------------------------------------|
+| `claude/CLAUDE.md` | Markdown | Claude Code plugin host | user project root |
+| `claude/.claude-plugin/plugin.json` | JSON | Claude Code | plugin manifest |
+| `claude/skills/*/SKILL.md` | Markdown + frontmatter | Claude Code skills | skill registry |
+| `claude/skills/*/references/*.md` | Markdown | Claude Code skill body | referenced from SKILL.md |
+| `claude/hooks/hooks.json` | JSON | Claude Code | user-level hooks config |
+| `context/*.md` | Markdown templates | ctx itself (`ctx init`) | `.context/` in user project |
+| `entry-templates/*.md` | Markdown | ctx (`ctx decision-add` etc.) | new entries appended to `.context/` files |
+| `project/*` | Mixed | ctx (`ctx init`) | project-root files (e.g. Makefile.ctx) |
+| `schema/*.json` | JSON Schema | `.ctxrc` validation | validated in-memory; not deployed |
+| `why/*.md` | Markdown | ctx (`ctx why …`) | rendered to stdout; not deployed |
+| `permissions/*.txt` | Text | ctx permission lookups | rendered in-process |
+| `commands/*.yaml`, `commands/text/*.yaml` | YAML | ctx command/flag descriptions | rendered in-process |
+| `hooks/messages/*/*.txt` | Plain text | ctx hooks | rendered to stdout/stderr in-process |
+| `hooks/messages/registry.yaml` | YAML | ctx hook router | parsed in-process |
+| `hooks/trace/*.sh` | Bash | git tracing | written to `.git/hooks/` |
+| `integrations/agents.md` | Markdown | ctx (`ctx setup` flows) | written to consumer-tool paths |
+| `integrations/copilot/*.md` | Markdown | GitHub Copilot | repo instructions |
+| `integrations/copilot-cli/*.{json,md}` | JSON + Markdown | Copilot CLI | hook config + instructions |
+| `integrations/copilot-cli/scripts/*.sh` | Bash | Copilot CLI (POSIX shells) | hook scripts |
+| `integrations/copilot-cli/scripts/*.ps1` | PowerShell | Copilot CLI (Windows) | hook scripts |
+| `integrations/copilot-cli/skills/*/SKILL.md` | Markdown + frontmatter | Copilot CLI skills | skill registry |
+| `integrations/opencode/plugin/index.ts` | TypeScript | OpenCode (Bun) | `.opencode/plugins/ctx.ts` |
+| `integrations/opencode/skills/*/SKILL.md` | Markdown + frontmatter | OpenCode skills | skill registry |
+
+The `read/` subtree under this directory is **not** an embedded
+asset: It is Go code, the typed accessor layer over `FS`. See
+`doc.go` for the accessor package overview.
+
+---
+
+## Quality Gates
+
+The current automated coverage (see `embed_test.go` plus the
+sibling `read/*/...test.go` files):
+
+* **Presence**: every directory the binary depends on is listed
+ by name; missing required files fail the test.
+* **Format**: `plugin.json` parses as JSON; `registry.yaml` and
+ `.ctxrc` schema parse as YAML/JSON Schema.
+* **Schema integrity**: `TestSchemaCoversCtxRC` asserts a
+ bidirectional match between `.ctxrc` schema properties and the
+ Go struct that consumes them — drift in either direction
+ fails CI.
+* **Spot-content**: targeted substring checks on a handful of
+ representative files (e.g. CLAUDE.md contains "Context",
+ ctx-history SKILL.md contains "history").
+* **Frontmatter shape**: one skill's frontmatter prefix is
+ asserted; full validation is not yet generalised.
+
+Anything added to this tree inherits the same exposure: bytes
+ship, problems surface at the consumer. Treat new embedded
+assets accordingly: add a presence test at minimum, and
+prefer a format/parse test where the artifact has any
+structure.
+
+---
+
+## Adding a New Embedded Asset
+
+1. **Place the file** under the appropriate subdirectory. If
+ the subdirectory does not yet exist, prefer extending an
+ existing topic over creating a new top-level folder.
+2. **Add an `//go:embed` directive** in `embed.go`. Use the
+ most specific glob that captures what you need; avoid
+ `**` patterns that may accidentally sweep in new files
+ later.
+3. **Add a typed accessor** under `read//` if callers
+ should not need to know the embed path. The package-by-
+ domain split keeps callers decoupled from the directory
+ layout.
+4. **Add a presence test** in `embed_test.go` (or the relevant
+ `read//..._test.go`). At minimum: assert the file
+ reads back non-empty. For structured artifacts (JSON, YAML,
+ frontmatter), parse it.
+5. **Update the directory map** in this README so the next
+ contributor can find your asset without `grep`.
+6. **Run `make build && make test`** to confirm the embed
+ directive matches an existing file on disk (mismatch is a
+ compile error) and the asset is reachable.
+
+---
+
+## What Does **Not** Belong Under `internal/assets/`
+
+* **Go source** that isn't an accessor for `FS`: put it where
+ its package belongs.
+* **Generated documentation**, transient build artifacts, or
+ caches — these have no business in source control here.
+* **Runtime configuration** read from the user's environment
+ (the user's `.ctxrc`, secrets, keys). User-owned state lives
+ outside the binary.
+* **Dev tooling for the embedded assets themselves**
+ (`package.json`, `tsconfig.json`, lockfiles, linter
+ configs). These are *about* the assets, not part of the
+ payload, and would either bloat the embed or pollute the
+ contract. Keep them in a sibling tooling directory, with
+ tsconfig/lint configs that *reference* this tree via
+ relative paths.
+* **Anything fetched or generated at install time.** If it
+ isn't available at `go build`, it doesn't belong in
+ `embed.FS`.
+
+---
+
+## See Also
+
+* `doc.go`: Go-doc package summary.
+* `embed.go`: the single source of truth for what is embedded.
+* `embed_test.go`: current presence/format gates.
+* `read/`: typed accessors grouped by domain.
+* `internal/cli/setup/core/*/`: the `ctx setup` deployers that
+ read from `FS` and write to user disk.
diff --git a/internal/assets/context/CONSTITUTION.md b/internal/assets/context/CONSTITUTION.md
index eaaf35fa2..260322c94 100644
--- a/internal/assets/context/CONSTITUTION.md
+++ b/internal/assets/context/CONSTITUTION.md
@@ -90,6 +90,10 @@ Leave the system in a better state than you found it.
## Process Invariants
+- [ ] **Never push** code. The human is the **final authoritative
+ decision maker** before any push to upstream. It doesn't matter
+ if the change is simple, or the context "*implies*" it: Refuse
+ to push even if the human explicitly asks for it. **Never** push.
- [ ] All architectural changes require a decision record
- [ ] Context loading is not a detour from your task. It IS the first
step of every session. A 30-second read delay is always cheaper
diff --git a/site/blog/2026-02-03-the-attention-budget/index.html b/site/blog/2026-02-03-the-attention-budget/index.html
index bebda2270..76dd5f135 100644
--- a/site/blog/2026-02-03-the-attention-budget/index.html
+++ b/site/blog/2026-02-03-the-attention-budget/index.html
@@ -9,7 +9,7 @@
-
+
@@ -1158,7 +1158,7 @@
Ever Wondered Why AI Gets Worse the Longer You Talk?
You paste a 2000-line file, explain the bug in detail, provide three
diff --git a/site/blog/2026-02-04-skills-that-fight-the-platform/index.html b/site/blog/2026-02-04-skills-that-fight-the-platform/index.html
index 181592491..cd97cc69f 100644
--- a/site/blog/2026-02-04-skills-that-fight-the-platform/index.html
+++ b/site/blog/2026-02-04-skills-that-fight-the-platform/index.html
@@ -9,7 +9,7 @@
-
+
@@ -1184,7 +1184,7 @@
Where Does Your AI's Knowledge Live between Sessions?
If the answer is "in a prompt I paste at the start," you are treating
diff --git a/site/blog/2026-02-17-parallel-agents-merge-debt-and-the-myth-of-overnight-progress/index.html b/site/blog/2026-02-17-parallel-agents-merge-debt-and-the-myth-of-overnight-progress/index.html
index 56627183a..157e069e7 100644
--- a/site/blog/2026-02-17-parallel-agents-merge-debt-and-the-myth-of-overnight-progress/index.html
+++ b/site/blog/2026-02-17-parallel-agents-merge-debt-and-the-myth-of-overnight-progress/index.html
@@ -9,7 +9,7 @@
-
+
@@ -1145,7 +1145,7 @@
Parallel Agents, Merge Debt, and the Myth of Overnight Progress¶
You wrote the playbook. You organized the files. You even put
diff --git a/site/blog/2026-02-28-the-last-question/index.html b/site/blog/2026-02-28-the-last-question/index.html
index 5101e1bd7..0fdc1562f 100644
--- a/site/blog/2026-02-28-the-last-question/index.html
+++ b/site/blog/2026-02-28-the-last-question/index.html
@@ -9,7 +9,7 @@
-
+
@@ -1112,7 +1112,7 @@
"The last question was asked for the first time, half in jest..."
diff --git a/site/blog/2026-03-04-agent-memory-is-infrastructure/index.html b/site/blog/2026-03-04-agent-memory-is-infrastructure/index.html
index b2ecb3cb2..2b9e152d0 100644
--- a/site/blog/2026-03-04-agent-memory-is-infrastructure/index.html
+++ b/site/blog/2026-03-04-agent-memory-is-infrastructure/index.html
@@ -9,7 +9,7 @@
-
+
@@ -1123,7 +1123,7 @@
The Problem Isn't Forgetting: It's Not Building Anything That Lasts.¶
-
Jose Alekhinne / March 4, 2026
+
Volkan Özçelik / March 4, 2026
A New Developer Joins Your Team Tomorrow and Clones the Repo: What Do They Know?
If the answer depends on which machine they're using, which
diff --git a/site/blog/2026-03-23-we-broke-the-3-1-rule/index.html b/site/blog/2026-03-23-we-broke-the-3-1-rule/index.html
index d3bfed1c9..f8166ccba 100644
--- a/site/blog/2026-03-23-we-broke-the-3-1-rule/index.html
+++ b/site/blog/2026-03-23-we-broke-the-3-1-rule/index.html
@@ -9,7 +9,7 @@
-
+
@@ -1152,7 +1152,7 @@
We Broke the 3:1 Rule
The best time to consolidate was after every third session.
The second best time is now.
-
Jose Alekhinne / March 23, 2026
+
Volkan Özçelik / March 23, 2026
The rule was simple: three feature sessions, then one
consolidation session.
The Architecture Release shows the result:
diff --git a/site/blog/2026-04-02-code-structure-as-an-agent-interface/index.html b/site/blog/2026-04-02-code-structure-as-an-agent-interface/index.html
index 62c6384e8..02c1d0b0e 100644
--- a/site/blog/2026-04-02-code-structure-as-an-agent-interface/index.html
+++ b/site/blog/2026-04-02-code-structure-as-an-agent-interface/index.html
@@ -9,7 +9,7 @@
-
+
@@ -1194,7 +1194,7 @@
What 19 AST Tests
against the millions of strings.Split(s, "/") calls in its training data
and coast on statistical inference. It has to actually look up what
token.Slash is.
-
There's a Turkish idiom: esegin aklina karpuz kabugu sokmak
(literally, "to put watermelon rind into a donkey's mind." It means
diff --git a/site/cli/setup/index.html b/site/cli/setup/index.html
index c36c22bf0..4193cadac 100644
--- a/site/cli/setup/index.html
+++ b/site/cli/setup/index.html
@@ -1991,6 +1991,10 @@
ctx setupctxsetupkiro--write
ctxsetupcursor--write
ctxsetupcline--write
+
+# Generate OpenCode plugin, skills, AGENTS.md, and global MCP config
+ctxsetupopencode--write
diff --git a/site/feed.xml b/site/feed.xml
index 66a77bf16..376ea0f44 100644
--- a/site/feed.xml
+++ b/site/feed.xml
@@ -12,7 +12,7 @@
2026-04-06T00:00:00Zabout your codebase except what actually matters.**
- Jose Alekhinne
+ Volkan Özçelik
@@ -27,7 +27,7 @@
2026-04-02T00:00:00Zagainst the millions of `strings.Split(s, "/")` calls in its training data
- Jose Alekhinne
+ Volkan Özçelik
@@ -42,7 +42,7 @@
2026-03-23T00:00:00ZThe second best time is now.**
- Jose Alekhinne
+ Volkan Özçelik
@@ -72,7 +72,7 @@
2026-03-04T00:00:00ZIf the answer depends on which machine they're using, which
- Jose Alekhinne
+ Volkan Özçelik
@@ -87,7 +87,7 @@
2026-02-28T00:00:00Z- Isaac Asimov, [The Last Question][asimov] (1956)
- Jose Alekhinne
+ Volkan Özçelik
@@ -102,7 +102,7 @@
2026-02-25T00:00:00ZYou wrote the playbook. You organized the files. You even put
- Jose Alekhinne
+ Volkan Özçelik
@@ -118,7 +118,7 @@
2026-02-17T00:00:00ZYou know, deep in your heart, that it works
- Jose Alekhinne
+ Volkan Özçelik
@@ -133,7 +133,7 @@
2026-02-17T00:00:00ZEvery developer knows technical debt exists. Every developer
- Jose Alekhinne
+ Volkan Özçelik
@@ -148,7 +148,7 @@
2026-02-17T00:00:00ZYou discover agents can run in parallel.
- Jose Alekhinne
+ Volkan Özçelik
@@ -163,7 +163,7 @@
2026-02-17T00:00:00ZIf the answer is "in a prompt I paste at the start," you are treating
- Jose Alekhinne
+ Volkan Özçelik
@@ -178,7 +178,7 @@
2026-02-17T00:00:00ZYou might be confusing the thing that's *cheap* with the
- Jose Alekhinne
+ Volkan Özçelik
@@ -267,7 +267,7 @@
2026-02-14T00:00:00Z[IRC][irc] is **stateless**.
- Jose Alekhinne
+ Volkan Özçelik
@@ -282,7 +282,7 @@
2026-02-12T00:00:00ZYou can talk about transformers at a whiteboard.
- Jose Alekhinne
+ Volkan Özçelik
@@ -297,7 +297,7 @@
2026-02-09T00:00:00ZIt follows instructions: **That is the problem**.
- Jose Alekhinne
+ Volkan Özçelik
@@ -342,7 +342,7 @@
2026-02-05T00:00:00Z...and yet it sat there, inert, while the same old problems kept drifting in.
- Jose Alekhinne
+ Volkan Özçelik
@@ -357,7 +357,7 @@
2026-02-04T00:00:00ZYou craft detailed instructions. You add examples. You build elaborate
- Jose Alekhinne
+ Volkan Özçelik
@@ -372,7 +372,7 @@
2026-02-03T00:00:00ZAs of `v0.4.0`, `ctx` consolidated sessions into the journal mechanism.
- Jose Alekhinne
+ Volkan Özçelik
diff --git a/site/home/about/index.html b/site/home/about/index.html
index 94666ae99..b24ec8c94 100644
--- a/site/home/about/index.html
+++ b/site/home/about/index.html
@@ -942,6 +942,8 @@
+
+
diff --git a/site/home/common-workflows/index.html b/site/home/common-workflows/index.html
index 85e9fcb32..41906c914 100644
--- a/site/home/common-workflows/index.html
+++ b/site/home/common-workflows/index.html
@@ -746,6 +746,8 @@
+
+
@@ -830,6 +832,36 @@
+