# WS3 — per-plugin SessionStart status-check convention + glue plugin _Created: 2026-07-06. Status: **superseded 2026-07-06** by the OpenSpec change `add-os-status-plugin` (implemented as `plugins/os-status/`; decision record: ADR-022 in `docs/memory-system/03-architecture-decisions.md`). The perspective reviews kept the Option B direction but replaced the per-plugin enumeration protocol with in-process checks in a single plugin; this doc is the historical starting sketch only. See `2026-07-06-plugin-evals-overview.md`._ ## Goal A convention-over-configuration status system: at SessionStart, every installed cc-os plugin verifies its expected per-project artifacts exist (adr: ADR system present; vault: project hub note exists — optionally injecting it as context). All good → silent. Problem → one short banner prompting corrective action (" missing — run /os-vault:… to fix"). Plugins stay independent; new plugins get picked up automatically by following the convention; only the glue plugin is mandatory for the collection. This is architecture → **OpenSpec change + ADR** (use `openspec-propose`; decisions land in `docs/memory-system/03-architecture-decisions.md`). Do not build outside that workflow. ## User's sketch (the starting design) Per-plugin Python status scripts following a cc-os convention (naming, interface, location), living in a specific gitignored hidden directory in the project. SessionStart fires a cc-os master status script that enumerates all status scripts in that directory (excluding itself) and runs them. Adding a plugin later = drop in a conforming script; no global rewrites. ## The one design tension the proposal must settle (pressure-test, don't fiat) **Where does status-check CODE live?** - **Option A (user sketch): project-local dir** (e.g. `.cc-os/status.d/*.py`, gitignored). Pro: per-project opt-in/customization. Con: code copies drift across projects; needs an install/update step per project per plugin; the 2026-07-04 stale-cache incident shows copy-drift is a real failure class here. - **Option B: plugin-source enumeration** — each plugin ships `status/check.py` in its own source; the master enumerates installed `os-*` plugins at session start. Same modularity and zero-global-rewrite extension; no copies, no drift, no install step. Project-local `.cc-os/` still exists but holds STATE only (suppress files, per-project config like "this project opts out of hub-note checks"), mirroring os-adr's `.os-adr/` and os-doc-hygiene's `.dochygiene/` — consolidating those is itself a candidate scope item. Run `perspectives:simplifier` and `perspectives:implementer` (both sonnet) against both shapes inside the proposal. Lean: B for code, A-style dir for state. ## Interface contract (draft for the proposal) - Each check: stdin/argv gets project root + plugin config; stdout JSON `{"status": "ok"|"warn", "message": str, "context": str|null}`; hard timeout (~5s); non-zero exit or timeout = treated as warn with a generic message, never blocks session. - **Silent on ok** — os-adr's near-zero-token SessionStart discipline is the template. Master aggregates warns into ONE short banner; per-project once-per-day snooze + permanent suppress via state dir (pattern already proven in os-adr/os-doc-hygiene). - `context` field = optional session-context injection (the "pull the hub note into context if useful" idea) — but gate it through injection-economics thinking (see the design-template skill's filter); default null. ## Glue plugin scope ("cc-os collection manager") Naming: per `~/Documents/SecondBrain/cc-os-plugin-skill-naming-convention.md` (read before naming; `os-[domain]`, verb-first skills, NO `name:` frontmatter). Candidates: `os-core` (lean) or `os-status` (narrower). Settle in the proposal. Phase 1 (this change): master SessionStart hook + enumeration + interface contract + convert the two existing consumers: - os-adr: refactor its existing existence-check hook into a conforming status check (it is already exactly this pattern — present→usage note, absent→once-per-day suggestion). - os-vault: new hub-note check (project hub note exists for the current project; missing → prompt to run onboarding/creation; optionally inject on present). - os-orchestration: env-override check — warn when `CLAUDE_CODE_SUBAGENT_MODEL` (or similar model-forcing env) is set in `~/.claude/settings.json` or the environment. Added 2026-07-06: the E1 canary proved the orchestrator cannot observe resolved models at spawn time (`resolvedModel` is harness-side only), so silent-override protection must be deterministic, not model behavior. This check would have caught the WS1 Cluster 1 incident at SessionStart. Phase 2 (separate change, later): collection-manager duties — verify installed cc-os plugin caches are fresh vs source (would have auto-caught the 2026-07-04 stale-cache incident), migrations complete, conventions followed (e.g. no `name:` in SKILL.md frontmatter). Effectively an automated `bin/refresh-plugins` advisor. ## Deliverables 1. OpenSpec change (design.md resolving the tension above + specs + tasks) — via `openspec-propose`. 2. ADR in `docs/memory-system/03-architecture-decisions.md` (status-check convention + code-location decision). 3. Implementation via `openspec-apply-change`: master hook + shared contract module (Python, matching os-vault's deep-module style: thin entry points, shared config/io modules), conforming checks for os-adr + os-vault, model-free tests (Python, mirroring `tests/hook_test.py` style) + invariants.md. 4. `bin/refresh-plugins`, `claude plugin details` verification, fresh-session smoke test. ## Models Design synthesis + ADR: orchestrator. Perspective reviews: sonnet. Implementation: haiku for thin scripts/tests, sonnet for the shared contract module. No behavioral eval needed — deterministic code; invariants + model-free tests suffice (same rationale as the os-adr hook).