diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 8ba2907..7586c2f 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -22,7 +22,7 @@ { "name": "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", diff --git a/CLAUDE.md b/CLAUDE.md index f48f712..550fd92 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -80,8 +80,9 @@ before modifying any of these: design-template skills, SessionStart/End hooks, memsearch + vault git sync. Write-behavior eval harness in `plugins/os-vault/eval/`. - **os-context** (`plugins/os-context/`, renamed 2026-07-13 from os-orchestration) — a - prompt-composer SessionStart plugin: concatenates `prompts/session-start/*.md` (currently - just `10-orchestration.md`, the session-orchestration + delegation-economics rules) into + prompt-composer SessionStart plugin: concatenates `prompts/session-start/*.md` + (orchestration/delegation rules, kickoff conventions, standing safety, decision-memo + format) into one additionalContext block for all sessions; this repo carries no local override. Eval harness in `plugins/os-context/eval/`. - **os-status** (`plugins/os-status/`) — aggregated deterministic SessionStart checks @@ -148,7 +149,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` signal (400 lines / ~4k tokens) enforces this. - **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 `/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). diff --git a/bin/test b/bin/test new file mode 100755 index 0000000..ee3546f --- /dev/null +++ b/bin/test @@ -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 diff --git a/docs/implementation-status.md b/docs/implementation-status.md index f5516ef..45ad156 100644 --- a/docs/implementation-status.md +++ b/docs/implementation-status.md @@ -1,6 +1,6 @@ # 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; 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 @@ -84,6 +84,11 @@ entry is in the leaf file named. ovh-vps `~/planka-final-snapshot-2026-07-16/`). Server decommissioned same day (containers/cron/creds removed); planka gem repo archived read-only. Detail: os-backlog 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); bulk vault migration; os-adr rollout to pilot projects; os-backlog routing rollout (#14); diff --git a/docs/implementation-status/standards-audit.md b/docs/implementation-status/standards-audit.md new file mode 100644 index 0000000..ef04d98 --- /dev/null +++ b/docs/implementation-status/standards-audit.md @@ -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 1–2 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. diff --git a/plugins/cc-architect/references/conventions/cc-os-naming.md b/plugins/cc-architect/references/conventions/cc-os-naming.md new file mode 100644 index 0000000..d7996c0 --- /dev/null +++ b/plugins/cc-architect/references/conventions/cc-os-naming.md @@ -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` diff --git a/plugins/os-adr/CLAUDE.md b/plugins/os-adr/CLAUDE.md new file mode 100644 index 0000000..1ff34d8 --- /dev/null +++ b/plugins/os-adr/CLAUDE.md @@ -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:`: `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-` 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`. diff --git a/plugins/os-backlog/CLAUDE.md b/plugins/os-backlog/CLAUDE.md new file mode 100644 index 0000000..d542cc8 --- /dev/null +++ b/plugins/os-backlog/CLAUDE.md @@ -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. diff --git a/plugins/os-context/.claude-plugin/plugin.json b/plugins/os-context/.claude-plugin/plugin.json index 5f71e8a..570ba21 100644 --- a/plugins/os-context/.claude-plugin/plugin.json +++ b/plugins/os-context/.claude-plugin/plugin.json @@ -1,5 +1,5 @@ { "name": "os-context", "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." } diff --git a/plugins/os-context/CLAUDE.md b/plugins/os-context/CLAUDE.md new file mode 100644 index 0000000..ed8bd4f --- /dev/null +++ b/plugins/os-context/CLAUDE.md @@ -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`. diff --git a/plugins/os-doc-hygiene/CLAUDE.md b/plugins/os-doc-hygiene/CLAUDE.md index 392b0ab..5b31cf9 100644 --- a/plugins/os-doc-hygiene/CLAUDE.md +++ b/plugins/os-doc-hygiene/CLAUDE.md @@ -4,21 +4,13 @@ Claude Code plugin that monitors and manages **stale** and **bloated** project documentation. Installed globally, operates per-project. Reminds (deterministic, 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 -> rationale. This file is the build map. +> `PRD.md` is the historical source-of-truth design doc (see its top-of-file +> 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): > `~/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-0038–0041. - ## Core distinction (do not conflate) - **Stale** = the doc is *wrong* (contradicted, orphaned, superseded, @@ -29,99 +21,39 @@ lifecycle signals, or the calibrate skill; decisions are ADR-0038–0041. 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. -## Design invariants (see PRD + reversion-protection pattern) +## Component map -1. The `SessionStart` hook **only reminds** — it never runs analysis or mutates - anything, and spends no AI tokens. All mutation is user-invoked. -2. Reminder **snoozes** (≤ once/day while stale) via `last_reminded`. -3. State lives **in-project** under gitignored `.cc-os/dochygiene/` (ADR-0027; - legacy `.dochygiene/` is fallback-read only). No global index. -4. **Report rollover**: keep only the latest report. The tool must not become - the bloat it polices. -5. Cleanup is **git-safe**: clean/committed tree required (or auto WIP - checkpoint), each run is one reviewable commit. -6. **Deterministic-first**: scan/state/patch-apply/token-estimate are scripts - (no model). AI does only classification and prose distillation. -7. **Safety tiers**: `auto` (deterministic+reversible+objective) runs without - prompt; `confirm` (destructive/subjective/generative) escalates for approval. -8. **mtime guard**: never apply a cached edit to a file changed since the check. -9. Frozen/ignored files (`hygiene: frozen` frontmatter, `.dochygiene-ignore`, - append-only logs) are never flagged. +- `skills/` — five skills: `check`, `clean`, `status`, `sweep`, `calibrate` + (each `SKILL.md` + `workflows/`); see `skills/CONTEXT.md` for the index. +- `scripts/` — deterministic Python core (scanner, state store, reminder, + report builder, validator, patch applier, token estimator, rulebook, + calibrate helpers); see `scripts/CONTEXT.md`. +- `hooks/hooks.json` — `SessionStart` → `scripts/reminder.py` (banner only, + no analysis, no mutation beyond `last_reminded`). +- `tests/` — pytest suite covering every deterministic seam; see + `tests/CONTEXT.md`. +- `invariants.md` — the reversion-protection contract (numbered behavioral + invariants); read before changing scanner, state, or safety-tier logic. +- `examples/golden/` — golden classifier fixtures (Layer 2 of reversion + protection, paired with `invariants.md`). +- `lifecycle-spec.md` — the rulebook layer (global `rulebook.json` + + per-project `.dochygiene-rules.json`) feeding tier derivation and the + `calibrate` skill; decisions are ADR-0038–0041. +- `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 -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: -│ ├── 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) +## Conventions - **Language**: Python, OOP — small single-responsibility classes, dependency injection, immutable transforms where possible. See `../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 → - Opus); generative distillation = Sonnet (NOT Haiku); orchestration = Opus. -- **Reversion protection**: `invariants.md` + `examples/golden/` + change-impact - analysis + human gate for golden-example changes. See + Opus); generative distillation = Sonnet (NOT Haiku). +- **Reversion protection**: `invariants.md` + `examples/golden/` + human gate + for changes to either. See `../cc-architect/references/tool-patterns/reversion-protection.md`. - 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) - -1. Add `invariants.md` and 3–5 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`. +Changing any invariant requires updating `invariants.md` and the golden +examples, with explicit human approval — do not restate the invariants here. diff --git a/plugins/os-doc-hygiene/PRD.md b/plugins/os-doc-hygiene/PRD.md index 85dd5a5..e54408f 100644 --- a/plugins/os-doc-hygiene/PRD.md +++ b/plugins/os-doc-hygiene/PRD.md @@ -1,6 +1,8 @@ # 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 @@ -144,7 +146,8 @@ prose distillation). This keeps it fast, cheap, and trustworthy. ## Implementation Decisions **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 projects globally" is dissolved by per-project storage. - Marketplace registration deferred until the plugin is functional (documented diff --git a/plugins/os-sdlc/CLAUDE.md b/plugins/os-sdlc/CLAUDE.md new file mode 100644 index 0000000..f484d31 --- /dev/null +++ b/plugins/os-sdlc/CLAUDE.md @@ -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. diff --git a/plugins/os-shortcuts/CLAUDE.md b/plugins/os-shortcuts/CLAUDE.md new file mode 100644 index 0000000..595493f --- /dev/null +++ b/plugins/os-shortcuts/CLAUDE.md @@ -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. diff --git a/plugins/os-shortcuts/invariants.md b/plugins/os-shortcuts/invariants.md new file mode 100644 index 0000000..f5ea85f --- /dev/null +++ b/plugins/os-shortcuts/invariants.md @@ -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 2–3 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. diff --git a/plugins/os-status/CLAUDE.md b/plugins/os-status/CLAUDE.md new file mode 100644 index 0000000..d9a211c --- /dev/null +++ b/plugins/os-status/CLAUDE.md @@ -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. diff --git a/plugins/os-vault/CLAUDE.md b/plugins/os-vault/CLAUDE.md new file mode 100644 index 0000000..035f1d0 --- /dev/null +++ b/plugins/os-vault/CLAUDE.md @@ -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`. diff --git a/plugins/os-vault/README.md b/plugins/os-vault/README.md index af96beb..97b1aad 100644 --- a/plugins/os-vault/README.md +++ b/plugins/os-vault/README.md @@ -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/write/SKILL.md` — When and how to write to the vault - `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 diff --git a/plugins/os-vault/invariants.md b/plugins/os-vault/invariants.md new file mode 100644 index 0000000..1060525 --- /dev/null +++ b/plugins/os-vault/invariants.md @@ -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.