cc-os/docs/plans/ws3-status-convention-plugi...

5.5 KiB

WS3 — per-plugin SessionStart status-check convention + glue plugin

Created: 2026-07-06. Status: proposed. Prereq: none (parallel with WS1). 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).