Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions .context/DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,62 @@ For significant decisions:

-->

## [2026-07-25-190410] Beyond a byte ceiling, knowledge content should become tooling, not more Markdown

**Status**: Accepted

**Context**: Designing M5's heavy-page signal; the failure case is a convention theme file growing toward ~1MB.

**Decision**: Beyond a byte ceiling, knowledge content should become tooling, not more Markdown

**Rationale**: An LLM is a poor linter: it cannot reliably apply a large ruleset expressed as prose. Past a ceiling, recursive folding (more Markdown) is the wrong fix; the right move is extracting the content to actual tooling (a linter), code, or docs. So the heavy-page remedy is an advisory 'split OR extract to tooling', decided by the human, not tier-2 auto-fold.

**Consequence**: The heavy-page nudge frames the ceiling as a smell ('a context file this heavy is a linter in prose'), prompting extraction rather than endless subdivision. Tier-2 theme recursion remains deferred, not precluded.

---

## [2026-07-25-190410] M5 knowledge health is two suggest-only signals: foldable root (staging count) and heavy page (bytes)

**Status**: Accepted

**Context**: M5 wires the growth nudge, /ctx-remember, and /ctx-wrap-up to progressive disclosure. The 2026-07-16 foundational decision already fixed staging-as-watermark, the three surfaces, and suggest-only. Left open: the signal/threshold, and that the original root-only measure was blind to theme-file bloat that folding itself creates.

**Decision**: M5 knowledge health is two suggest-only signals: foldable root (staging count) and heavy page (bytes)

**Rationale**: Two questions need two measures. 'Should I fold?' is a COUNT of staged entries/sections via disclosure.StagedEntries (suggest /ctx-digest). 'Is this page too heavy to be useful context?' is a BYTE count, scanned over the root AND every theme file under .context/<noun>/ (suggest split or extract). Folding relocates bulk into theme files, so a root-only signal is blind to the bloat it creates. One knowledge.Health function feeds all three surfaces so hook and skills cannot drift. No state file: staging plus on-disk bytes are self-describing.

**Consequence**: convention_line_count (200 lines) is replaced by convention_section_count (foldability) plus a shared theme_page_byte_ceiling (weight); a deliberate behavior change, framed as user education. Theme files are now scanned. Reuses disclosure.StagedEntries and the check-knowledge daily-throttle / log-first plumbing.

---

## [2026-07-25-132759] Theme declaration via the Themes section keyword, on all three canonical kinds

**Status**: Accepted

**Context**: pd-m4 needed a way to NAME a theme up front (ctx <kind> add --section Themes), distinct from folding entries into it. The section-vs-entry distinction in conventions surfaced the need.

**Decision**: Theme declaration via the Themes section keyword, on all three canonical kinds

**Rationale**: Content is '<name> — <gist>', split on the same em-dash separator the theme parser reads back, so it round-trips. It writes BOTH the gist bullet and the theme file, because a bullet without its file fails the gist-to-file pairing invariant and would leave a root ctx disclosure refuses to touch. Generalized to learnings/decisions since they also have a ## Themes region.

**Consequence**: New internal/write/theme package + disclosure.AddTheme; theme adds bypass the per-kind body-flag gate (a theme has only a name and gist); a new user-facing CLI surface across all three canonical kinds.

---

## [2026-07-25-132719] ctx convention add requires --section; no default; placeholders rejected (strict)

**Status**: Accepted

**Context**: The convention add-path (pd-m4). A default or catch-all section is where an undecided caller dumps every convention, defeating the H2-section grouping the digest pass folds on.

**Decision**: ctx convention add requires --section; no default; placeholders rejected (strict)

**Rationale**: Choosing the section IS the thinking; the CLI refuses to do it for the caller. Enforced strictly via validate.RejectPlaceholder, which rejects empty/whitespace AND the shipped placeholder set (TBD, n/a, none, pending, …). Deviates deliberately from the plan's original T16 ('just move the anchor').

**Consequence**: ctx convention add errors without a concrete --section; agents and scripts must name the target H2 section. Pinned by TestConventionAddRequiresSection (7 cases); a refused add leaves the root byte-identical.

---

## [2026-07-19-100259] M4 conventions digestion: curated ## -section taxonomy, unified into the entry-kind mover

**Status**: Accepted
Expand Down
30 changes: 30 additions & 0 deletions .context/LEARNINGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,36 @@ DO NOT UPDATE FOR:
-->


## [2026-07-25-124457] Using the proprietary sibling repo as design evidence leaks its internals into tracked files

**Context**: While deciding the pd-m4 add-path shape, I read the sibling repo's convention file to settle the question, then quoted its guide text and attributed the decision to it in a tracked plan file. An unrelated build warning prompted the sweep that caught it.

**Lesson**: The leak vector is not NAMING the sibling (allowed) — it is citing its designs or guide text as evidence in tracked specs/plans. Both the quote and the attribution are leaks.

**Application**: Cite ctx's OWN files as design evidence and describe designs on their merits; never quote or attribute to the sibling in tracked files; git grep the staged tree before committing any spec authored while consulting it. Per specs/public-repo-hygiene.md.

---

## [2026-07-25-124457] Skill and doc examples of a serialized structure must round-trip through the real parser

**Context**: The ctx-digest skill documented digest-plan entries as JSON strings, but Assignment.Entries is []StagedEntry{timestamp,title}; the documented form failed json.Unmarshal. Latent since M3 — any agent following the skill verbatim failed at the apply step.

**Lesson**: A hand-authored example of a serialized structure drifts from the code silently; nothing tests the prose.

**Application**: Verify skill/doc JSON/YAML examples against the actual unmarshal target — build the binary and run the exact documented command — before shipping the skill.

---

## [2026-07-25-124457] A guard derived from a capability accessor silently lifts when the accessor is extended

**Context**: pd-m4 T04 made ThemeDir(convention) return true; Apply's refusal of the convention kind was DERIVED from ThemeDir returning false. That one-line 'vocabulary' change silently opened the destructive mover to CONVENTIONS.md before the convention parse/validate/dup-title paths existed. Caught by TestApply_Refusals.

**Lesson**: When a refusal is derived from a capability check (if !capable { refuse }) instead of an explicit guard, extending that capability lifts the refusal as an invisible side effect — and the two tasks look independent in the plan.

**Application**: Before extending a capability accessor, grep for guards that read it. When a multi-task arc will open a destructive path, add an EXPLICIT gate that the opening task removes deliberately, so it cannot open early.

---

## [2026-07-19-210439] The disclosure parser is a deliberately dumb line-scanner (skips <!-- --> comments, not code fences)

**Context**: M4 unifies conventions into the ## -section entry model, where ## collides far more than ## [. Fence detection was considered and rejected.
Expand Down
26 changes: 26 additions & 0 deletions .context/TASKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3046,3 +3046,29 @@ E5[T16–17] E6[T18–19] E7[T20–22] = 22.
- [ ] Drift path-checker false-positives on angle-bracket placeholders: `ctx drift` flags CONVENTIONS.md template placeholders (`internal/assets/claude/skills/ctx-<area>/SKILL.md`, `docs/recipes/<related-recipe>.md`, `docs/cli/<command>.md`) as missing path references. These are illustrative `<…>` placeholders, not real paths — the path checker should skip any path segment containing `<`/`>`. (Same class as the just-consolidated "detection scripts flag illustrative examples" learning.) #priority:low #session:87e465a0 #branch:main #added:2026-07-16

- [ ] ARCHITECTURE.md package-doc drift: `ctx drift` reports ~44 internal/ packages "not documented" in ARCHITECTURE.md (incl. the renamed internal/heading). Either backfill the package coverage via /ctx-architecture, or reframe ARCHITECTURE.md's scope so the drift check doesn't expect exhaustive per-package coverage. #priority:low #session:87e465a0 #branch:main #added:2026-07-16

### Progressive disclosure — Milestone 5 (suggest-only triggers)

- [ ] M5: suggest-only trigger wiring for progressive disclosure — growth nudge points at /ctx-digest; /ctx-remember surfaces oversized roots; /ctx-wrap-up surfaces them at session end. Suggest only, never auto-fold. Plan: specs/plans/pd-m5.md #session:951e1535 #branch:main #commit:1a880bf3 #added:2026-07-25-132759

Plan: `specs/plans/pd-m5.md` · Spec: `specs/progressive-disclosure.md`
Two suggest-only signals from one `knowledge.Health`: **foldable root**
(staging count → `/ctx-digest`) and **heavy page** (bytes over root +
theme files → split/extract). No auto-fold, no state file.

**Completion rule**: an epic is `[x]` only when every task in its range is
`[x]`/`[o]` in `specs/plans/pd-m5.md` (the plan is the source of truth).
Epics partition T01–T23: E1[T01–03] E2[T04–08] E3[T09–12] E4[T13–14]
E5[T15–20] E6[T21–23] = 23.

- [ ] [E1] Config: retire `ConventionLineCount`; add `ConventionSectionCount` + `ThemePageByteCeiling` + runtime defaults (T01–T03). Plan: specs/plans/pd-m5.md #priority:medium #session:951e1535 #branch:design/pd-m5-triggers #added:2026-07-25

- [ ] [E2] Health core: `finding` Kind/Path; foldable signal via `disclosure.StagedEntries`; heavy signal over root + theme-file bytes; combine with foldable-first ordering (T04–T08). Plan: specs/plans/pd-m5.md #priority:medium #session:951e1535 #branch:design/pd-m5-triggers #added:2026-07-25

- [ ] [E3] Wiring: warning text (`/ctx-digest` primary + split/extract); format routing by kind; `check-knowledge` report path; hook uses `Health` (T09–T12). Plan: specs/plans/pd-m5.md #priority:medium #session:951e1535 #branch:design/pd-m5-triggers #added:2026-07-25

- [ ] [E4] Skills: `/ctx-remember` + `/ctx-wrap-up` surface foldable/heavy, suggest-only (T13–T14). Plan: specs/plans/pd-m5.md #priority:medium #session:951e1535 #branch:design/pd-m5-triggers #added:2026-07-25

- [ ] [E5] Tests: health fixtures, heavy root + theme file, both-fire ordering, convention measure, boundary/disable, surface parity (T15–T20). Plan: specs/plans/pd-m5.md #priority:medium #session:951e1535 #branch:design/pd-m5-triggers #added:2026-07-25

- [ ] [E6] Sync + gates: copilot skill sync, measurement gate (T22), milestone gate (T21–T23). Plan: specs/plans/pd-m5.md #priority:medium #session:951e1535 #branch:design/pd-m5-triggers #added:2026-07-25
22 changes: 21 additions & 1 deletion internal/assets/claude/skills/ctx-remember/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,21 @@ feel like a file search rather than genuine recall:
`/ctx-remember` does not run any editorial pass. If the
directory does not exist or holds no postdated entries,
skip the step.
6. **Present the structured readback** (see format below)
6. **Check knowledge health (read-only).** Run:

```bash
ctx system check-knowledge --report
```

It prints nothing when every canonical root is within limits.
When it prints findings, surface them in the readback's
**Knowledge health** line: a *foldable* root suggests
`/ctx-digest` (fold the staging zone into themes); a *heavy*
page suggests splitting the theme or extracting it to tooling.
Suggest only — never run `/ctx-digest` or edit a file here.
If it prints nothing, omit the line.

7. **Present the structured readback** (see format below)

## Readback Format

Expand All @@ -80,6 +94,12 @@ relevant. Pick the most recent or most impactful.
**Next step**: Suggest what to work on next based on the active
tasks, or ask the user for direction if priorities are unclear.

**Knowledge health** (only when `ctx system check-knowledge
--report` printed findings): name the foldable roots and/or heavy
pages it reported and the suggested remedy (`/ctx-digest`, or
split/extract). Suggestion only; omit the line entirely when the
report was empty.

## Readback Rules

- Open directly with the readback: instead of "I don't have memory",
Expand Down
18 changes: 18 additions & 0 deletions internal/assets/claude/skills/ctx-wrap-up/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,24 @@ Do not auto-commit; the user decides. But always run the
`git status` check and always surface non-empty output. Do
not skip this phase silently when the working tree is dirty.

### Phase 4.4: Surface knowledge health (suggest-only)

Run:

```bash
ctx system check-knowledge --report
```

When it prints findings, surface them as a closing suggestion:
a *foldable* root → run `/ctx-digest` **next session**; a *heavy*
page → split the theme or extract it to tooling. Prints nothing
when every root is within limits — then say nothing.

**Never fold inline here.** The human is closing the laptop to go
live their life; running a semantic pass at wrap-up is against
their interest (spec: progressive-disclosure `### Triggers`). This
phase suggests for *next* session; it does not act.

### Phase 4.5: Capture the session journal (best-effort)

Before handing over, sweep this session — and any others that
Expand Down
2 changes: 2 additions & 0 deletions internal/assets/commands/flags.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,8 @@ usage.last:
short: Show last N entries
usage.session:
short: Filter by session ID (prefix match)
system.checkknowledge.report:
short: Print current knowledge-health findings on demand (skills), bypassing the daily throttle
system.markjournal.check:
short: Check if stage is set (exit 1 if not)
system.pause.session-id:
Expand Down
15 changes: 8 additions & 7 deletions internal/assets/commands/text/hooks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,16 +166,17 @@ check-journal.relay-prefix:
short: 'IMPORTANT: Relay this journal reminder to the user VERBATIM before answering their question.'
check-knowledge.box-title:
short: Knowledge File Growth
check-knowledge.fallback:
short: |-
Large knowledge files dilute agent context. Consider:
• Review and remove outdated entries
• Use /ctx-consolidate to merge overlapping entries
• Use /ctx-drift for semantic drift (stale patterns)
• Move stale entries to .context/archive/ manually
check-knowledge.finding-format:
short: |
%s has %d %s (recommended: ≤%d).
check-knowledge.remedy-foldable:
short: |2
• Run /ctx-digest to fold the staging zone into themes
• /ctx-consolidate or /ctx-drift if entries overlap rather than accrete
check-knowledge.remedy-heavy:
short: |2
• Split the theme, or extract it to tooling — a context file this
heavy is a linter in prose, and an LLM is a poor linter
check-knowledge.relay-message:
short: Knowledge file growth detected
check-knowledge.relay-prefix:
Expand Down
6 changes: 4 additions & 2 deletions internal/assets/commands/text/write.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -932,8 +932,10 @@ write.provenance-context:

write.knowledge-unit-entries:
short: "entries"
write.knowledge-unit-lines:
short: "lines"
write.knowledge-unit-sections:
short: "sections"
write.knowledge-unit-bytes:
short: "bytes"

write.version-drift-fallback:
short: "VERSION (%s), plugin.json (%s), marketplace.json (%s) are out of sync. Update all three before releasing."
Expand Down
5 changes: 0 additions & 5 deletions internal/assets/hooks/messages/check-knowledge/warning.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
{{.FileWarnings}}
Large knowledge files dilute agent context. Consider:
• Review and remove outdated entries
• Use /ctx-consolidate to merge overlapping entries
• Use /ctx-drift for semantic drift (stale patterns)
• Move stale entries to .context/archive/ manually
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,21 @@ feel like a file search rather than genuine recall:
`/ctx-remember` does not run any editorial pass. If the
directory does not exist or holds no postdated entries,
skip the step.
6. **Present the structured readback** (see format below)
6. **Check knowledge health (read-only).** Run:

```bash
ctx system check-knowledge --report
```

It prints nothing when every canonical root is within limits.
When it prints findings, surface them in the readback's
**Knowledge health** line: a *foldable* root suggests
`/ctx-digest` (fold the staging zone into themes); a *heavy*
page suggests splitting the theme or extracting it to tooling.
Suggest only — never run `/ctx-digest` or edit a file here.
If it prints nothing, omit the line.

7. **Present the structured readback** (see format below)

## Readback Format

Expand All @@ -79,6 +93,12 @@ relevant. Pick the most recent or most impactful.
**Next step**: Suggest what to work on next based on the active
tasks, or ask the user for direction if priorities are unclear.

**Knowledge health** (only when `ctx system check-knowledge
--report` printed findings): name the foldable roots and/or heavy
pages it reported and the suggested remedy (`/ctx-digest`, or
split/extract). Suggestion only; omit the line entirely when the
report was empty.

## Readback Rules

- Open directly with the readback: instead of "I don't have memory",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,24 @@ Do not auto-commit; the user decides. But always run the
`git status` check and always surface non-empty output. Do
not skip this phase silently when the working tree is dirty.

### Phase 4.4: Surface knowledge health (suggest-only)

Run:

```bash
ctx system check-knowledge --report
```

When it prints findings, surface them as a closing suggestion:
a *foldable* root → run `/ctx-digest` **next session**; a *heavy*
page → split the theme or extract it to tooling. Prints nothing
when every root is within limits — then say nothing.

**Never fold inline here.** The human is closing the laptop to go
live their life; running a semantic pass at wrap-up is against
their interest (spec: progressive-disclosure `### Triggers`). This
phase suggests for *next* session; it does not act.

### Phase 4.5: Capture the session journal (best-effort)

Before handing over, sweep this session — and any others that
Expand Down
9 changes: 7 additions & 2 deletions internal/assets/schema/ctxrc.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,14 @@
"description": "Entry count threshold for DECISIONS.md drift warning. Default: 20. 0 disables.",
"minimum": 0
},
"convention_line_count": {
"convention_section_count": {
"type": "integer",
"description": "Line count threshold for CONVENTIONS.md drift warning. Default: 200. 0 disables.",
"description": "Staged-section count threshold for CONVENTIONS.md before a fold nudge (/ctx-digest). The foldability watermark unit; replaces convention_line_count. Default: 12. 0 disables.",
"minimum": 0
},
"theme_page_byte_ceiling": {
"type": "integer",
"description": "Byte ceiling above which a root or theme file is flagged heavy (split or extract-to-tooling). Default: 65536. 0 disables.",
"minimum": 0
},
"injection_token_warn": {
Expand Down
14 changes: 13 additions & 1 deletion internal/cli/system/cmd/checkknowledge/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import (

"github.com/ActiveMemory/ctx/internal/assets/read/desc"
"github.com/ActiveMemory/ctx/internal/config/embed/cmd"
embedFlag "github.com/ActiveMemory/ctx/internal/config/embed/flag"
cFlag "github.com/ActiveMemory/ctx/internal/config/flag"
"github.com/ActiveMemory/ctx/internal/flagbind"
)

// Cmd returns the "ctx system check-knowledge" subcommand.
Expand All @@ -22,14 +25,23 @@ import (
func Cmd() *cobra.Command {
short, long := desc.Command(cmd.DescKeySystemCheckKnowledge)

return &cobra.Command{
var report bool
c := &cobra.Command{
Use: cmd.UseSystemCheckKnowledge,
Short: short,
Long: long,
Example: desc.Example(cmd.DescKeySystemCheckKnowledge),
Hidden: true,
RunE: func(cmd *cobra.Command, _ []string) error {
// --report is the on-demand skill path (no stdin, no
// throttle, no relay); bare invocation is the hook path.
if report {
return RunReport(cmd)
}
return Run(cmd, os.Stdin)
},
}
flagbind.BoolFlag(c, &report,
cFlag.Report, embedFlag.DescKeySystemCheckKnowledgeReport)
return c
}
Loading
Loading