Audit os-* plugins against cc-architect standards + remediate

Post-Phase-B standards audit (backlog ticket): ran cc-architect's
audit-plugin checklist against all 8 os-* plugins and remediated:

- index-style CLAUDE.md (ADR-0032) for every plugin; os-doc-hygiene's
  stale cc-plugins-era CLAUDE.md/PRD.md reconciled
- invariants.md added for os-shortcuts and os-vault
- naming convention folded into cc-architect references (canonical:
  references/conventions/cc-os-naming.md); CLAUDE.md + vault note point there
- repo-level bin/test runner for the mixed minitest/pytest suites (6 pass)
- os-vault settings.json hook wiring documented as deliberate
- ADR-0025/os-adr: exemption already recorded in the ADR; no retrofit
- deferred to retire-planka rework: os-backlog ADR-0025 deviations
  (Forgejo jared/cc-os#74), Planka refs in os-context/os-status

Detail: docs/implementation-status/standards-audit.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NCs64GAhRWrnjwfGwS4biX
This commit is contained in:
jared 2026-07-16 15:34:41 -04:00
parent 3f76755e85
commit a2b329dd7f
19 changed files with 489 additions and 105 deletions

View File

@ -22,7 +22,7 @@
{ {
"name": "os-context", "name": "os-context",
"source": "./plugins/os-context", "source": "./plugins/os-context",
"description": "Prompt-composer SessionStart plugin: concatenates prompts/session-start/*.md (currently session-orchestration rules — delegation threshold, explicit model routing on Agent spawns) into one additionalContext block, injected at session start and after compaction." "description": "Prompt-composer SessionStart plugin: concatenates prompts/session-start/*.md (session-orchestration + delegation-economics rules, kickoff conventions, standing safety rules, decision-memo format) into one additionalContext block, injected at session start and after compaction."
}, },
{ {
"name": "os-doc-hygiene", "name": "os-doc-hygiene",

View File

@ -80,8 +80,9 @@ before modifying any of these:
design-template skills, SessionStart/End hooks, memsearch + vault git sync. Write-behavior design-template skills, SessionStart/End hooks, memsearch + vault git sync. Write-behavior
eval harness in `plugins/os-vault/eval/`. eval harness in `plugins/os-vault/eval/`.
- **os-context** (`plugins/os-context/`, renamed 2026-07-13 from os-orchestration) — a - **os-context** (`plugins/os-context/`, renamed 2026-07-13 from os-orchestration) — a
prompt-composer SessionStart plugin: concatenates `prompts/session-start/*.md` (currently prompt-composer SessionStart plugin: concatenates `prompts/session-start/*.md`
just `10-orchestration.md`, the session-orchestration + delegation-economics rules) into (orchestration/delegation rules, kickoff conventions, standing safety, decision-memo
format) into
one additionalContext block for all sessions; this repo carries no local override. Eval one additionalContext block for all sessions; this repo carries no local override. Eval
harness in `plugins/os-context/eval/`. harness in `plugins/os-context/eval/`.
- **os-status** (`plugins/os-status/`) — aggregated deterministic SessionStart checks - **os-status** (`plugins/os-status/`) — aggregated deterministic SessionStart checks
@ -144,7 +145,8 @@ OpenSpec artifacts comes from `docs/` and this file.
and never let the index file regrow into a changelog — the os-doc-hygiene `file_length` and never let the index file regrow into a changelog — the os-doc-hygiene `file_length`
signal (400 lines / ~4k tokens) enforces this. signal (400 lines / ~4k tokens) enforces this.
- **Plugin and skill naming:** before naming ANY new cc-os plugin, skill, or slash command, - **Plugin and skill naming:** before naming ANY new cc-os plugin, skill, or slash command,
Read `~/Documents/SecondBrain/cc-os-plugin-skill-naming-convention.md` and follow it. In Read `plugins/cc-architect/references/conventions/cc-os-naming.md` (canonical repo copy;
the SecondBrain vault note of the same name now defers to it) and follow it. In
brief: plugins are `os-[domain]`; skills are verb-first kebab-case, invoked as brief: plugins are `os-[domain]`; skills are verb-first kebab-case, invoked as
`/os-[domain]:[verb]`; no `commands/` dispatcher directories; **never set a `name:` field `/os-[domain]:[verb]`; no `commands/` dispatcher directories; **never set a `name:` field
in SKILL.md frontmatter** (it collapses the slash command to a bare unnamespaced form). in SKILL.md frontmatter** (it collapses the slash command to a bare unnamespaced form).

82
bin/test Executable file
View File

@ -0,0 +1,82 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
# Repo-level test runner for the mixed minitest/pytest suites under plugins/.
#
# bin/test # run every plugin suite
# bin/test os-backlog # run one plugin's suites (repeatable)
#
# Per plugin it runs `ruby tests/all.rb` when present (minitest) and
# `pytest tests/` when any tests/*_test.py or tests/test_*.py exists.
# pytest runs once per plugin so same-named test files (hook_test.py in
# several plugins) never collide on module import.
# os-vault's tests/ is an eval harness (harness.sh), not a unit suite,
# and is intentionally not run here.
require "open3"
class PluginSuite
RUNNERS = {
minitest: ->(dir) { ["ruby", "tests/all.rb"] },
pytest: ->(dir) { ["pytest", "-q", "tests"] }
}.freeze
attr_reader :name
def initialize(dir)
@dir = dir
@name = File.basename(dir)
end
def kinds
kinds = []
kinds << :minitest if File.exist?(File.join(@dir, "tests", "all.rb"))
kinds << :pytest if pytest_files?
kinds
end
def run(kind)
command = RUNNERS.fetch(kind).call(@dir)
stdout, status = Open3.capture2e(*command, chdir: @dir)
[status.success?, stdout]
end
private
def pytest_files?
Dir.glob(File.join(@dir, "tests", "{test_*,*_test}.py")).any?
end
end
repo_root = File.expand_path("..", __dir__)
requested = ARGV
suites = Dir.glob(File.join(repo_root, "plugins", "*"))
.select { |d| File.directory?(d) }
.map { |d| PluginSuite.new(d) }
.select { |s| requested.empty? || requested.include?(s.name) }
.sort_by(&:name)
unknown = requested - suites.map(&:name)
abort "bin/test: no such plugin(s): #{unknown.join(", ")}" unless unknown.empty?
failures = []
ran = 0
suites.each do |suite|
suite.kinds.each do |kind|
ran += 1
ok, output = suite.run(kind)
puts "#{ok ? "PASS" : "FAIL"} #{suite.name} (#{kind})"
unless ok
failures << "#{suite.name} (#{kind})"
puts output.lines.map { |l| " #{l}" }.join
end
end
end
if ran.zero?
puts "bin/test: no test suites found"
elsif failures.empty?
puts "#{ran} suites passed"
else
abort "#{failures.size}/#{ran} suites failed: #{failures.join(", ")}"
end

View File

@ -1,6 +1,6 @@
# cc-os implementation status — index # cc-os implementation status — index
_Last updated: 2026-07-13. This file is an **index with progressive disclosure** (see the _Last updated: 2026-07-16. This file is an **index with progressive disclosure** (see the
index+PD convention ADR): headline timeline entries and per-component one-liners live here; index+PD convention ADR): headline timeline entries and per-component one-liners live here;
full per-component detail lives in leaf files under `docs/implementation-status/`, read on full per-component detail lives in leaf files under `docs/implementation-status/`, read on
demand. When a build step completes, add a **one-line** timeline entry here and put the demand. When a build step completes, add a **one-line** timeline entry here and put the
@ -76,6 +76,11 @@ entry is in the leaf file named.
- **2026-07-15** — os-doc-hygiene lifecycle-aware hygiene shipped (ADR-00380041): rulebook - **2026-07-15** — os-doc-hygiene lifecycle-aware hygiene shipped (ADR-00380041): rulebook
layer, lifetime taxonomy + tier matrix, no-ignore-propagation, conventions.json promotion, layer, lifetime taxonomy + tier matrix, no-ignore-propagation, conventions.json promotion,
new `:calibrate` skill; calibration pass #1 (cc-os) passed. Detail: os-doc-hygiene leaf. new `:calibrate` skill; calibration pass #1 (cc-os) passed. Detail: os-doc-hygiene leaf.
- **2026-07-16** — os-* standards audit vs cc-architect (post Phase B): every plugin got an
index-style CLAUDE.md, os-doc-hygiene's cc-plugins-era docs reconciled, invariants.md
added (os-shortcuts, os-vault), naming convention folded into cc-architect references,
repo-level `bin/test` runner added. Detail:
[implementation-status/standards-audit.md](implementation-status/standards-audit.md).
**Remaining optional items:** additional project onboarding (one at a time, per ADR-0013); **Remaining optional items:** additional project onboarding (one at a time, per ADR-0013);
bulk vault migration; os-adr rollout to pilot projects; os-backlog routing rollout (#14); bulk vault migration; os-adr rollout to pilot projects; os-backlog routing rollout (#14);

View File

@ -0,0 +1,47 @@
# os-* standards audit vs cc-architect — 2026-07-16
One-time audit executed after cc-architect's Phase B migration into cc-os (commit
3f76755), per the backlog ticket "Audit os-* plugins against cc-architect standards
(post standards-centralization)". Ran cc-architect's `workflows/audit-plugin.md`
Phase 12 checklist against all eight os-* plugins, then remediated.
## Results
All eight plugins pass manifest validation (name/version/description, kebab-case,
semver), have no `name:` fields in SKILL.md frontmatter, and have no `commands/`
dispatcher directories.
Remediation shipped:
- **Per-plugin CLAUDE.md indexes** (ADR-0032 index+PD style) created for os-adr,
os-backlog (minimal — Planka-retirement rework in flight), os-context, os-sdlc,
os-shortcuts, os-status, os-vault; os-doc-hygiene's stale pre-build cc-plugins-era
CLAUDE.md rewritten.
- **os-doc-hygiene cc-plugins references reconciled**: PRD.md target path and
marketplace naming corrected; broken `../.claude/references/` path and retired
`/install doc-hygiene@cc-plugins` instructions removed.
- **invariants.md** added for os-shortcuts (4 invariants) and os-vault (8); already
existed for os-adr, os-doc-hygiene, os-status. os-backlog deferred (rework in
flight); os-sdlc/os-context not warranted yet.
- **ADR-0025 / os-adr**: no action — the ADR itself records the per-verb-`bin/`
exemption ("grandfathered... until os-adr is next touched for other reasons").
- **Naming convention** folded into the repo:
`plugins/cc-architect/references/conventions/cc-os-naming.md` is now canonical;
the SecondBrain vault note and root CLAUDE.md point to it.
- **Repo-level test runner**: `bin/test` runs every plugin's minitest
(`tests/all.rb`) and pytest suite, one pytest invocation per plugin (avoids
same-named `hook_test.py` module collisions). os-vault's `tests/` is an eval
harness, deliberately excluded.
- **os-vault hook wiring documented**: hooks are intentionally wired via user-level
`~/.claude/settings.json` pointing at repo source scripts, not a plugin
`hooks/hooks.json`; recorded in os-vault/CLAUDE.md so the absent hooks.json stops
reading as a defect.
## Deferred (filed, not fixed)
- os-backlog ADR-0025 deviations (second entry point `bin/wakeup-poll`; no README
naming gem deps) → Forgejo issue jared/cc-os#74, to be folded into the
retire-planka-git-issues-only rework.
- os-context `skills/audit-sessions/SKILL.md` stale Planka references and os-status
`planka:` tracker-scheme handling — both already being fixed by the in-flight
ADR-0042 rework on main; not touched here to avoid conflicts.

View File

@ -0,0 +1,46 @@
# cc-os Plugin and Skill Naming Convention
Canonical repo copy of the convention established 2026-07-02 (previously only in the
SecondBrain vault note `cc-os-plugin-skill-naming-convention.md`, which now points here).
Read this before naming ANY new cc-os plugin, skill, or slash command.
## Core principles
1. **Plugins use an `os-` prefix**: `os-[domain]` (e.g. `os-vault`, `os-backlog`). The
prefix ties the plugin to cc-os and distinguishes it from unrelated tools
(`memsearch` is NOT cc-os).
2. **Skills are verb-first**: the plugin namespace answers "what is this about?", the
skill name answers "what action?" — `query`, `write`, `reorganize`, producing
invocations like `/os-vault:query`.
3. **Multi-word skills are kebab-case, verb + noun**: `design-template`,
`onboard-project`. Kebab-case in plugin `name` fields is a Claude Code requirement;
cc-os extends it to skill names by convention.
4. **No `commands/` dispatcher directories** — skills are the only invocation surface.
## Registration mechanics
**Never set a `name:` field in SKILL.md frontmatter.** The directory name is the skill
name; with `name:` absent, Claude Code registers the namespaced `/plugin:skill` form.
An explicit `name: find` collapses the command to bare unnamespaced `/find`
(discovered 2026-07-04 in os-adr and os-doc-hygiene; fixed by deleting the lines).
After any SKILL.md edit, run `bin/refresh-plugins` — installs copy files into
`~/.claude/plugins/cache/`, so source edits don't reach sessions until refreshed.
## Anti-patterns
- Plugin name without the `os-` prefix (`vault` instead of `os-vault`).
- Noun-stacked skill names (`vault-query` instead of `query`).
- Generic verbs duplicating the namespace context (`/memory-find` instead of
`/os-vault:find` — the namespace provides the context).
- CamelCase or snake_case in plugin or skill names.
## Open questions
Agent-name and hook-script-name governance are deferred until their use patterns
stabilize; hook scripts currently use snake_case (Python convention) and are not
externally visible.
## Cross-references
- ADR-0025 (Ruby structure standard — the structural layer below this naming layer)
- `references/layout/plugin-structure.md`, `references/layout/skill-structure.md`

43
plugins/os-adr/CLAUDE.md Normal file
View File

@ -0,0 +1,43 @@
# os-adr
ADR (architecture decision record) system for cc-os and pilot projects: numbered
`docs/adr/` files + generated index, migration of legacy decision logs, deterministic
find/create/init workflows. Full design/build history: `docs/implementation-status/os-adr.md`.
## Component map
- `skills/` — four verbs, each `/os-adr:<verb>`: `create`, `find`, `init`, `migrate`.
- `lib/adr.rb` + `lib/adr/{detector,finder,index,migration_report,migrator,record,
repository,template}.rb` — single `Adr` namespace, `require_relative` loading,
stdlib-only (no external gems).
- `bin/`**per-verb scripts** (`adr-new`, `adr-find`, `adr-init`, `adr-migrate`,
`adr-detect`), invoked as `ruby ${CLAUDE_PLUGIN_ROOT}/bin/adr-<verb>` from skills.
This is **not** the single-dispatcher pattern ADR-0025 requires of newer plugins —
os-adr is explicitly grandfathered (see below).
- `templates/adr.md` — the ADR template migration and creation write against.
- `hooks/hooks.json` — SessionStart entry is intentionally empty; the check itself
moved to os-status's `adr-system-present` (`hooks/session_start.py` here is kept
only as the wording source of record).
- `tests/` — minitest, `ruby tests/all.rb` (glob-runs `*_test.rb`) + `test_helper.rb`
tmpdir fixtures; `hook_test.py` covers the hooks-parity case.
- `invariants.md` — reversion-protection contract; read before touching detection,
migration, indexing, or find-filtering logic.
- `eval/`, `eval-b/`, `eval-c/` — Eval A/B/C harnesses (prompted grid, held-out
unprompted-behavior, ambiguity-ladder). See `docs/implementation-status/os-adr.md`
for what each measures; eval discipline (reserves never read informally) per root
`CLAUDE.md`.
## ADR-0025 exemption
The per-verb `bin/` layout (rather than a single `bin/os-adr` dispatcher) is
**grandfathered by
[ADR-0025](../../docs/adr/0025-standard-ruby-structure-for-cc-os-plugins-lib-single-dispatcher-bin-fail-soft-installed-gem-only-dependencies.md)**:
the exemption is recorded there explicitly ("not worth a retrofit until os-adr is
next touched for other reasons"), not an oversight. Don't "fix" the dispatcher shape
as a drive-by — fold it into whatever unrelated work next touches os-adr's `bin/`.
## Pointers
- Decisions: `docs/adr/0025-...md` (Ruby structure), `docs/adr/0020` and its
amendment (cc-os retrofit).
- Status/build history: `docs/implementation-status/os-adr.md`.

View File

@ -0,0 +1,14 @@
# os-backlog
Git-issues backlog surface: per-repo tracker routing (`forgejo:`/`github:`/`repo:` in
`.cc-os/config`), issue create/list/route skills, ten-label taxonomy.
Entry points: `bin/os-backlog` (dispatcher CLI), skills `capture`/`list`/`route`,
`hooks/` (SessionStart wiring).
Full detail: `docs/implementation-status/os-backlog.md`. No `invariants.md` yet —
see NOTE below.
NOTE (2026-07-16): a major rework retiring Planka in favor of git-issues-only
(ADR-0042, OpenSpec change retire-planka-git-issues-only) is in flight on main;
this index intentionally avoids enumerating internals that rework replaces.

View File

@ -1,5 +1,5 @@
{ {
"name": "os-context", "name": "os-context",
"version": "0.1.0", "version": "0.1.0",
"description": "Prompt-composer SessionStart plugin: concatenates prompts/session-start/*.md (currently session-orchestration rules — delegation threshold, explicit model routing on Agent spawns) into one additionalContext block, injected at session start and after compaction." "description": "Prompt-composer SessionStart plugin: concatenates prompts/session-start/*.md (session-orchestration + delegation-economics rules, kickoff conventions, standing safety rules, decision-memo format) into one additionalContext block, injected at session start and after compaction."
} }

View File

@ -0,0 +1,28 @@
# os-context
Prompt-composer `SessionStart` plugin (renamed 2026-07-13 from os-orchestration):
concatenates `prompts/session-start/*.md` into one `additionalContext` block,
injected at session start and after compaction/resume.
## Component map
- `prompts/session-start/` — 4 files, concatenated in filename order:
`10-orchestration.md` (session-orchestration + delegation-economics rules — do
not edit without explicit approval, per eval-wording sensitivity),
`20-kickoff-conventions.md`, `30-standing-safety.md`, `40-decision-memos.md`.
- `hooks/inject.py` — the composer; enforces the line-budget guard (120/240).
- `hooks/hooks.json` — SessionStart wiring, matcher `startup|resume|clear|compact`.
- `skills/audit-sessions/SKILL.md``/os-context:audit-sessions`, the biweekly
orchestration IRL audit against `10-orchestration.md`'s shipped rules; see
`skills/audit-sessions/references/rubric.md`.
- `audit/bin/{audit-stats,extract}` — deterministic driver scripts the audit
skill calls; skill-local, not a plugin-root `bin/`.
- `tests/hook_test.py` — unittest, covers compose order + budget logic.
- `eval/` — Eval harness (prompted grid, scenarios + `scenarios-reserve/`); eval
discipline (reserves never read informally) per root `CLAUDE.md`.
## Pointers
- Decision: [docs/adr/0031](../../docs/adr/0031-os-context-prompt-composer-plugin-supersedes-single-file-os-orchestration.md)
(prompt-composer plugin, supersedes the single-file os-orchestration approach).
- Status/build history: `docs/implementation-status/os-context.md`.

View File

@ -4,21 +4,13 @@ Claude Code plugin that monitors and manages **stale** and **bloated** project
documentation. Installed globally, operates per-project. Reminds (deterministic, documentation. Installed globally, operates per-project. Reminds (deterministic,
zero-token) on `SessionStart`; checks and cleans on demand via skills. zero-token) on `SessionStart`; checks and cleans on demand via skills.
> Read `PRD.md` first — it is the source of truth for scope, decisions, and > `PRD.md` is the historical source-of-truth design doc (see its top-of-file
> rationale. This file is the build map. > migration note for current location). This file is a current-state index,
> not a build map — the plugin is fully built (5 skills, tests passing).
> Vault user guide (nuance/mental-model, not a how-to): > Vault user guide (nuance/mental-model, not a how-to):
> `~/Documents/SecondBrain/user-guide/os-doc-hygiene-user-guide.md`. > `~/Documents/SecondBrain/user-guide/os-doc-hygiene-user-guide.md`.
## Lifecycle layer (2026-07-15)
A rulebook layer sits on top of the scan/classify/clean core: global
`rulebook.json` + optional per-project `.dochygiene-rules.json` declare
lifetime rules for known-temporary artifacts, feeding tier derivation and a
`/os-doc-hygiene:calibrate` skill for tuning rules against a real project.
Read `lifecycle-spec.md` before touching `rulebook.py`, the scanner's
lifecycle signals, or the calibrate skill; decisions are ADR-00380041.
## Core distinction (do not conflate) ## Core distinction (do not conflate)
- **Stale** = the doc is *wrong* (contradicted, orphaned, superseded, - **Stale** = the doc is *wrong* (contradicted, orphaned, superseded,
@ -29,99 +21,39 @@ lifecycle signals, or the calibrate skill; decisions are ADR-00380041.
Severity scales with **injection frequency** — a stale line in `CLAUDE.md` (auto Severity scales with **injection frequency** — a stale line in `CLAUDE.md` (auto
-injected every session) is worse than the same line in a doc nobody opens. -injected every session) is worse than the same line in a doc nobody opens.
## Design invariants (see PRD + reversion-protection pattern) ## Component map
1. The `SessionStart` hook **only reminds** — it never runs analysis or mutates - `skills/` — five skills: `check`, `clean`, `status`, `sweep`, `calibrate`
anything, and spends no AI tokens. All mutation is user-invoked. (each `SKILL.md` + `workflows/`); see `skills/CONTEXT.md` for the index.
2. Reminder **snoozes** (≤ once/day while stale) via `last_reminded`. - `scripts/` — deterministic Python core (scanner, state store, reminder,
3. State lives **in-project** under gitignored `.cc-os/dochygiene/` (ADR-0027; report builder, validator, patch applier, token estimator, rulebook,
legacy `.dochygiene/` is fallback-read only). No global index. calibrate helpers); see `scripts/CONTEXT.md`.
4. **Report rollover**: keep only the latest report. The tool must not become - `hooks/hooks.json``SessionStart``scripts/reminder.py` (banner only,
the bloat it polices. no analysis, no mutation beyond `last_reminded`).
5. Cleanup is **git-safe**: clean/committed tree required (or auto WIP - `tests/` — pytest suite covering every deterministic seam; see
checkpoint), each run is one reviewable commit. `tests/CONTEXT.md`.
6. **Deterministic-first**: scan/state/patch-apply/token-estimate are scripts - `invariants.md` — the reversion-protection contract (numbered behavioral
(no model). AI does only classification and prose distillation. invariants); read before changing scanner, state, or safety-tier logic.
7. **Safety tiers**: `auto` (deterministic+reversible+objective) runs without - `examples/golden/` — golden classifier fixtures (Layer 2 of reversion
prompt; `confirm` (destructive/subjective/generative) escalates for approval. protection, paired with `invariants.md`).
8. **mtime guard**: never apply a cached edit to a file changed since the check. - `lifecycle-spec.md` — the rulebook layer (global `rulebook.json` +
9. Frozen/ignored files (`hygiene: frozen` frontmatter, `.dochygiene-ignore`, per-project `.dochygiene-rules.json`) feeding tier derivation and the
append-only logs) are never flagged. `calibrate` skill; decisions are ADR-00380041.
- `openspec/` — this plugin's own OpenSpec changes/specs tree (archived
changes correspond to shipped features).
Changing any invariant requires updating `invariants.md` and the golden ## Conventions
examples, with explicit human approval.
## Build order (report schema gates everything)
1. **Machine report schema** — the contract every component consumes. Freeze
first. (per-file: category, signals, op, op-type, safety tier, optional
exact-edit, token estimate.)
2. **Deterministic core***build-spike #1 first*: a trivial `hooks/hooks.json`
emitting a `systemMessage` banner on `SessionStart`, confirmed to render
visibly in a real session (no plugin in this collection wires a CC hook yet).
Then: scanner (signals + shortlist), state store (timestamps, rollover,
snooze, atomic writes, project-root resolution), reminder hook
(`SessionStart`, `matcher: startup|resume`, injected-clock testable).
3. **`check` skill** — scanner shortlist → AI classify (Sonnet, judgment only) →
**`report_builder.py`** deterministic finalize pass → human + machine reports →
update `last_check`. The finalize pass sits **between** model classification and
the report write (invariants #6, #10): it computes `expected_sha256`, looks up
`is_destructive`/`is_reversible` from `exact_edit.kind`, derives `safety_tier`
via `validate_report.py`'s single-source `derive_safety_tier(...)`, sources
`raw_tokens` from the token estimator, and assembles the schema-valid machine
report + human-report skeleton. The model authors none of those four fields.
4. **`clean` skill + patch-applier** — consume report, mtime-guard, apply
`deterministic` ops mechanically, delegate `generative` to Sonnet, gate
`confirm`, git checkpoint + single commit, scopable by category/file →
update `last_clean`. Then **`sweep`** = check-then-clean.
- **RESOLVED (Phase 4):** `insert-frontmatter` ops have `has_anchor=False` and
carry **no** `expected_sha256`, so invariant #8's content hash cannot protect
them. The applier re-derives frontmatter freshness at apply time: re-read the
file, parse frontmatter; key present with target value → idempotent no-op; key
present with different value → skip (`frontmatter-key-conflict`); key absent →
insert. No cached hash is trusted. This resolves the deferred hole noted in
`add-check`.
5. **Bonus (v2)** — deterministic patch-apply hardening + token estimator
(local tokenizer, injection-frequency weighting, bottom-up rollup).
## Intended layout (per cc-plugins conventions)
```
doc-hygiene/
├── .claude-plugin/plugin.json # done
├── PRD.md # done — source of truth
├── CLAUDE.md # this file
├── invariants.md # TODO — declare behavioral invariants
├── skills/ # slash-command entry points: /os-doc-hygiene:<skill>
│ ├── check/SKILL.md
│ ├── clean/SKILL.md
│ ├── status/SKILL.md
│ └── sweep/SKILL.md
├── scripts/ # Python OOP — scanner, state, reminder, estimator, report_builder, applier
│ └── ...
├── hooks/hooks.json # SessionStart wiring → reminder script (systemMessage banner)
├── examples/golden/ # classifier golden examples (input tree → expected report)
└── tests/ # unit tests per deterministic seam + fixture doc trees
```
## Conventions (inherited from cc-plugins)
- **Language**: Python, OOP — small single-responsibility classes, dependency - **Language**: Python, OOP — small single-responsibility classes, dependency
injection, immutable transforms where possible. See injection, immutable transforms where possible. See
`../cc-architect/references/tool-patterns/deterministic-scripting.md`. `../cc-architect/references/tool-patterns/deterministic-scripting.md`.
- **Scripts**: structured JSON output, correct exit codes, idempotent, testable
in isolation with injected clock/filesystem.
- **Model routing**: scripts = no model; classification = Sonnet (hard cases → - **Model routing**: scripts = no model; classification = Sonnet (hard cases →
Opus); generative distillation = Sonnet (NOT Haiku); orchestration = Opus. Opus); generative distillation = Sonnet (NOT Haiku).
- **Reversion protection**: `invariants.md` + `examples/golden/` + change-impact - **Reversion protection**: `invariants.md` + `examples/golden/` + human gate
analysis + human gate for golden-example changes. See for changes to either. See
`../cc-architect/references/tool-patterns/reversion-protection.md`. `../cc-architect/references/tool-patterns/reversion-protection.md`.
- Read a directory's `CONTEXT.md` before its source files (progressive - Read a directory's `CONTEXT.md` before its source files (progressive
disclosure); generate one per directory as it's built. disclosure).
## Completion steps (do NOT do until functional) Changing any invariant requires updating `invariants.md` and the golden
examples, with explicit human approval — do not restate the invariants here.
1. Add `invariants.md` and 35 golden examples.
2. Register in `../.claude-plugin/marketplace.json` (name + source + description,
matching `plugin.json`). See `../.claude/references/plugin-registration.md`.
3. Verify installable via `/install doc-hygiene@cc-plugins`.

View File

@ -1,6 +1,8 @@
# PRD: `doc-hygiene` plugin # PRD: `doc-hygiene` plugin
> Status: `ready-for-agent` · Working name: `doc-hygiene` · Target: `~/dev/cc-plugins/doc-hygiene/` > Status: shipped · Built at `plugins/os-doc-hygiene/` in cc-os, not the
> `cc-plugins` target/marketplace named below. Historical design doc — kept
> as-is except this note and the location/marketplace corrections below.
## Problem Statement ## Problem Statement
@ -144,7 +146,8 @@ prose distillation). This keeps it fast, cheap, and trustworthy.
## Implementation Decisions ## Implementation Decisions
**Distribution & activation** **Distribution & activation**
- New plugin `doc-hygiene` in the `cc-plugins` marketplace. Installed globally, - New plugin `os-doc-hygiene` in the cc-os marketplace (built at
`plugins/os-doc-hygiene/`; see migration note above). Installed globally,
operates per-project. No global state index — the question of "how to key operates per-project. No global state index — the question of "how to key
projects globally" is dissolved by per-project storage. projects globally" is dissolved by per-project storage.
- Marketplace registration deferred until the plugin is functional (documented - Marketplace registration deferred until the plugin is functional (documented

18
plugins/os-sdlc/CLAUDE.md Normal file
View File

@ -0,0 +1,18 @@
# os-sdlc
Status: scaffold only — no skills/agents/hooks/scripts exist yet. Only
`.claude-plugin/plugin.json` and `OVERVIEW.md` are present.
This will be cc-os's lifecycle/SDLC plugin: a lightweight
grill → to-spec → to-tickets → implement → review → ship pipeline, adapted
from Matt Pocock's skill set and Delta Refinery's multi-level handoff
discipline, wired to `os-backlog` (tickets) and `os-adr` (decisions) rather
than reinventing either.
Read `OVERVIEW.md` for the full design brief (why this plugin exists, scope,
working philosophy, first-iteration build plan, open questions) and
[docs/adr/0037](../../docs/adr/0037-os-sdlc-lives-inside-cc-os-as-a-new-plugin-not-a-separate-cc-sdlc-marketplace.md)
for why it lives inside cc-os as a plugin rather than a separate marketplace.
Expand this file into a real component-map index once skills/agents/hooks
first land, per this repo's plugin conventions.

View File

@ -0,0 +1,20 @@
# os-shortcuts
The "keybindings" of cc-os: user-invoked QOL shortcut commands — ritual
multi-step sequences run on demand, never via hook injection. See
[docs/adr/0028](../../docs/adr/0028-os-shortcuts-plugin-for-user-invoked-qol-commands-bounded-against-hook-injection-plugins.md)
for the boundary this plugin is scoped against: it exists specifically to
hold user-invoked commands so hook-injection plugins (os-context, os-status,
etc.) don't accumulate them.
## Component map
- `skills/wrap/SKILL.md` — the only skill so far: the session-close ritual
(review changes → commit → sweep affected docs/todos → handoff summary).
Invoked by `/os-shortcuts:wrap`. No hooks — runs only when explicitly
invoked.
- `invariants.md` — reversion-protection contract for `wrap`'s guarantees.
More shortcuts are expected to accumulate here (per `plugin.json`'s own
description) — add a line above per skill as they land, and a matching
section in `invariants.md` once its behavior is worth protecting.

View File

@ -0,0 +1,21 @@
# os-shortcuts behavioral invariants
Reversion protection for the `wrap` skill. Any change that breaks one of these
is a regression, not a refactor. No automated test suite exists yet (the
skill is prompt-only, no scripts) — enforced by review of `skills/wrap/SKILL.md`
against this list.
1. **Never auto-invoked.** `wrap` has no hook wiring and runs only when the
user explicitly triggers it ("wrap up", "wrap", end-of-session). It must
never fire from a `SessionStart`/`SessionEnd`/other hook.
2. **Never force-pushes or skips hooks.** Commits made during `wrap` follow
this repo's standing git-safety rules: never `--no-verify`, never force-push,
new commits rather than amends.
3. **Session-close ritual runs in order: review → commit → sweep → handoff.**
The handoff summary (step 4) is always the final message, and always
covers Done / In flight / Next steps — it must not be skipped even when
steps 23 found nothing to do.
4. **No fabricated doc-update conventions.** The docs/todo sweep (step 3)
only touches files a project's own `CLAUDE.md` (or discernible existing
convention) identifies as a source of truth; if none exists, `wrap` skips
the step and says so rather than inventing structure.

View File

@ -0,0 +1,40 @@
# os-status
Aggregated, in-process `SessionStart` status checks for the cc-os plugin
family: per-project artifact checks (ADR system, vault hub note, project
graph, tracker config, config version) and environment hazard checks
(subagent model env override). See
[docs/adr/0022](../../docs/adr/0022-os-status-plugin-aggregated-in-process-sessionstart-status-checks.md)
for why checks are aggregated into one plugin instead of scattered per-plugin
hooks.
At most one `systemMessage` banner per session (one line per surviving warn);
`note`-level results bypass snooze/suppress and go out as `additionalContext`.
Snooze/suppress state lives under `.cc-os/status/` (ADR-027, with legacy
top-level fallback read).
## Component map
- `hooks/checks.py` — the check registry (`REGISTRY` at the bottom of the
file) plus each check function and the `--json` CLI entry point the `fix`
skill drives. Current checks: `subagent-model-env-override`,
`adr-system-present`, `vault-hub-note-present`, `orchestration-audit-due`,
`tracker-configured`, `config-version-current`, `project-graph-present`.
Read `checks.py` directly for exact check logic — this list is a pointer,
not a restatement.
- `hooks/session_start.py` — the `SessionStart` hook entry point; runs the
registry, applies snooze/suppress, emits the single banner.
- `hooks/state.py` — project-root resolution, `.cc-os/config` read, snooze/
suppress state read/write.
- `hooks/hooks.json``SessionStart` wiring.
- `skills/fix/SKILL.md``/os-status:fix`: remediates whatever the registry
flags, idempotent, doubles as the update-to-current-approach path
(ADR-026).
- `invariants.md` — the reversion-protection contract (8 numbered
invariants, including byte-identical wording parity with os-adr's
session_start.py); enforced by `tests/hook_test.py`.
- `tests/hook_test.py` — 80 tests, model-free (`python3 tests/hook_test.py`).
Adding a check means adding a function + a `Check(...)` entry to `REGISTRY` in
`checks.py`, following the uniform `check(ctx) -> CheckResult` signature
(invariant #8) — do not special-case a new check's wiring elsewhere.

View File

@ -0,0 +1,39 @@
# os-vault
Integrates the SecondBrain Obsidian vault (semantic/knowledge memory, ADR-012) and
per-project Graphify knowledge graphs into Claude sessions. Episodic memory is a
separate system (memsearch, ADR-015) — see `README.md` for the requirements/version
pins and `config.yaml` for vault path, model, and threshold knobs.
## Component map
- `skills/` — five skills: `query`, `write`, `reorganize`, `onboard-project`,
`design-template`.
- `hooks/``session_start.py` (SessionStart), `session_context.py`
(UserPromptSubmit), `post_tool_use_write.py` (PostToolUse), `session_end.py` +
`memsearch_sync.py` + `vault_sync.py` (SessionEnd); shared `config.py`,
`hook_io.py`, `session_state.py`. See "Hook wiring" below.
- `tests/` — golden-file harness (`harness.sh`, `golden/`, `inputs/`,
`python-wrappers/`); own `tests/README.md`.
- `eval/` — write-behavior eval harness (scenarios + `scenarios-reserve/`,
judge-rubric, results); eval discipline (reserves never read informally) per
root `CLAUDE.md`.
- `invariants.md` — reversion-protection contract; read before changing frontmatter
facets, hook fail-soft behavior, or sync timing.
- `config.yaml` — vault_path, graphify model, thresholds, env overrides.
## Hook wiring
os-vault's hooks are **not** wired via a plugin `hooks/hooks.json` — there isn't
one, and this is deliberate, not a defect. They're registered at user level in
`~/.claude/settings.json`, pointing at the repo source scripts directly:
`SessionStart``hooks/session_start.py`, `UserPromptSubmit`
`hooks/session_context.py`, `PostToolUse``hooks/post_tool_use_write.py`,
`SessionEnd``hooks/session_end.py` + `hooks/memsearch_sync.py` +
`hooks/vault_sync.py`.
## Pointers
- Design: `docs/memory-system/02-system-design.md`. Decisions: ADR-011 (facets),
ADR-012 (vault as semantic source of truth), ADR-015 (memsearch split).
- Status/build history: `docs/implementation-status/os-vault.md`.

View File

@ -40,6 +40,10 @@ Shared modules: `hooks/config.py`, `hooks/hook_io.py`, `hooks/session_state.py`.
- `skills/query/SKILL.md` — When and how to query the vault graph - `skills/query/SKILL.md` — When and how to query the vault graph
- `skills/write/SKILL.md` — When and how to write to the vault - `skills/write/SKILL.md` — When and how to write to the vault
- `skills/reorganize/SKILL.md` — Plan-mode vault consolidation - `skills/reorganize/SKILL.md` — Plan-mode vault consolidation
- `skills/onboard-project/SKILL.md` — Onboard, update, remove, or query the
per-project Graphify knowledge graph (codebase structure, this repo only)
- `skills/design-template/SKILL.md` — Design or revise SecondBrain note-type
templates, including new-type creation
## Configuration ## Configuration

View File

@ -0,0 +1,40 @@
# os-vault invariants
Behavioral invariants of the plugin. Changing any of these requires explicit human approval.
Enforced by `tests/harness.sh` (golden fixtures) unless noted otherwise.
1. **Episodic and semantic memory stay separate systems.** Vault notes hold evergreen,
cross-project knowledge (ADR-012); session/event history goes to memsearch (ADR-015).
`/os-vault:query` never answers "what happened when" questions — those route to memsearch.
2. **Six flat namespaced facets, plus `scope`.** Note frontmatter tags are
`type/`/`client/`/`project/`/`domain/`/`tool/`/`convention/` (ADR-011); `scope`
(`global`/`project`/`client`) is a frontmatter field, not a tag. `type/` is required on
every note. Source of truth for the schema is `vault-conventions.md` at the vault root —
never duplicated or paraphrased into plugin code or skills.
3. **Hooks are fail-open, never block a session.** Every hook
(`session_start.py`, `session_context.py`, `post_tool_use_write.py`, `session_end.py`,
`memsearch_sync.py`, `vault_sync.py`) degrades silently on error; none may disrupt session
startup or shutdown.
4. **SessionStart returns sub-second.** Heavy work (graph rebuild) is detached to the
background; `session_start.py` only does the staleness check and kicks off the detached
rebuild. Context injection is a separate hook (`session_context.py`, UserPromptSubmit).
5. **Sync happens only at SessionEnd, in a fixed order.** `vault_sync.py` must run after
`session_end.py` so the daily journal note it writes is included in the commit;
`memsearch_sync.py` is a separate, independent SessionEnd entry (split by ADR-016) for the
memsearch repo. Neither auto-commit runs mid-session.
6. **Vault-not-repo rule.** `/os-vault:write` writes only to the resolved vault root
(`${OS_VAULT_PATH:-$HOME/Documents/SecondBrain}`), never to a project repository. The vault
path is resolved mechanically at the start of every write — never hardcoded.
7. **Write is query-first.** Before creating a new note, check for an existing note on the
same subject; a contradicting/extending fact updates the existing note (bumping
`last_updated`) rather than creating a duplicate.
8. **No silent new note types.** A fact that fits no existing type is filed under the closest
existing type with a visible `## Type-fit note` misfit marker, or escalated to
`/os-vault:design-template` — never given an invented type silently.