# cc-os implementation status & changelog

_Last updated: 2026-07-12. This is the append-only implementation-status record moved out of
`CLAUDE.md` (2026-07-08, task B1 of
[system-prompt-profiles-tasks.md](plans/system-prompt-profiles-tasks.md)). CLAUDE.md keeps
orientation only; when a build step completes, record it HERE (plus
`docs/memory-system/04-build-plan.md`), and touch CLAUDE.md only if the current design or
conventions changed._

## Status timeline

**Recent pivot (2026-06-03):** Graphify **replaces** the originally-planned Ruby/SQLite
tag-index CLI and also covers the deferred QMD semantic layer. `04-build-plan.md` and
`06-graphify-evaluation.md` reflect this; if an older doc still describes the Ruby CLI, defer
to those two and fix the stale doc.

**Decisions locked (2026-06-04):** Six-facet tag taxonomy + `scope/` (ADR-011); reuse
`~/Documents/SecondBrain` vault rather than creating a new one (ADR-012); build-first /
migrate-incrementally — build full system against a fixture set first, defer bulk vault
migration to last, onboard projects one at a time (ADR-013).

**Empirical finding locked (2026-06-05):** Graphify is a structure extractor, not a topic
clusterer — no emergent hub nodes appear even at `--mode deep`; hub notes + wikilinks must be
author-provided during migration (not deferred). Migration scaffolding is now a first-class
deliverable. Open question: do facet tags create graph edges? (ADR-014; findings:
`docs/memory-system/07-graph-connectivity-findings.md`).

**Implementation status (2026-06-09):** The global Claude Code plugin is live
(`~/.claude/plugins/os-vault/`). Steps 1, 2a, 2b, 3, and 6 of the build plan are complete
(including the `onboard-project` skill, previously TODO under Step 6/Part D). Step 1
completed 2026-06-09: vault-conventions.md exists, all 6 fixture notes seeded, and 14
Graphify handbook + memory-system design notes migrated to the vault as migration
scaffolding. Step 4 (memsearch) completed 2026-06-09: plugin installed via marketplace,
MEMSEARCH_DIR set global (~/.memsearch), Stop hook verified producing daily memory files,
search confirmed working. Step 5a (memsearch episodic git sync) completed 2026-06-09:
dedicated private Forgejo repo (`forgejo.swansoncloud.com/jared/memsearch`), whitelist
`.gitignore` (memory/*.md only), auto-commit+push via cc-os `session-end.sh` hook (ADR-015;
relocated to `memsearch_sync.py` by ADR-016, 2026-06-12). Step 5b (Obsidian vault → VPS
sync) remained at that date.

**Decision (2026-06-09):** Single global memsearch store for ALL clients — cross-client
commingling is the accepted, intended design (ADR-015 resolved). One private Forgejo repo
(`forgejo.swansoncloud.com/jared/memsearch`), not per-client repos. Forward direction:
minimize/eliminate dedicated per-client working directories; work projects locally or use a
single general `clients/` dir for non-local client work — memory is captured globally
regardless of cwd. No `clients/` directory structure designed yet; open item.

**Implementation status (2026-06-12):** os-vault plugin source moved into git at
`cc-os/plugins/os-vault/` and bash hooks ported to Python (deep-module architecture: shared
`config.py`, `hook_io.py`, `session_state.py`; thin entry-point scripts). Cutover via symlink
`~/.claude/plugins/os-vault → cc-os/plugins/os-vault/` and settings.json hook rewrite.
memsearch sync split into dedicated `memsearch_sync.py` SessionEnd hook (relocation of
ADR-015 behavior, not reversal). Fresh-session test passed 2026-06-12. See ADR-016.

**Implementation status (2026-06-15):** Step 5b done and automated — vault
(`~/Documents/SecondBrain`) initialized as git repo, pushed to private Forgejo
(`ssh://git@forgejo.swansoncloud.com:2222/jared/SecondBrain.git`); 52 files, git chosen over
Syncthing. Auto-commit+push wired via `vault_sync.py` SessionEnd hook (third SessionEnd
hook, runs after `session_end.py` so the daily journal note is included; push-only —
SessionStart pull is an optional future item for multi-machine). Step 2e pilot done —
llf-schema (`/home/jared/dev/llf-schema`, PHP 8.2 WordPress plugin) onboarded via
`/os-vault:onboard-project` skill: 605 nodes / 930 edges / 52 communities; Ollama doc pass
lossy on WordPress docs but AST pass solid. Step 2d closed — live vault `graphify-out/` is
the baseline; fixture-only build superseded.

**Implementation status (2026-06-17):** `/os-vault:onboard-project` skill now uses
assessment-first onboarding: surveys the repo structure, classifies exclude candidates by
TYPE (11 categories: fetched deps, build output, caches, VCS internals, editor/AI-tooling
dirs, lockfiles, coverage/logs, bulk data, binaries, secrets, graphify-out/ — illustrative
names, not fixed templates), generates a per-project `.graphifyignore`, confirms with the
user, then extracts the graph using `qwen25-coder-7b-16k` (config.yaml `ollama_model`;
16k-context build of qwen2.5-coder:7b — larger context window cuts chunk count per doc, the
main speed lever). Fixes issue where repos with large dependency trees routed non-code files
through the Ollama doc pass (see ADR-017).

**Implementation status (2026-06-30):** Phase 1 of the SecondBrain Content Plan complete
(`docs/memory-system/09-sb-content-plan.md`, issues #1–#6).
`~/Documents/SecondBrain/vault-conventions.md` reconciled to a single authoritative typed
frontmatter schema (removed the contradictory block; canonical filenames are slug-only,
`source:` is a frontmatter field not a tag, `scope` is a field not a tag). New
`/os-vault:design-template` skill added
(`cc-os/plugins/os-vault/skills/design-template/SKILL.md`) — routes between template-design
(4-step process + injection-economics filter) and new-type creation (9-step lifecycle).
Three vault note templates created in `~/Documents/SecondBrain/_templates/` (`howto.md`,
`convention.md`, `reference.md`; `reference` carries a four-subtype variant selector —
pattern/framework, api-integration, role-definitions, design-rules), each dogfooded against
a real note. Four proof-of-concept vault notes patched (cookbook subtype →
pattern/framework, glossary de-duped to a wikilink, design-mode scope → project, tags +
`last_reviewed` added). Phase 2 (issue #7) remains open as the steady-state
migration/onboarding epic (no code). See `docs/memory-system/09-sb-content-plan.md`.

**Plugin renamed `memory` → `os-vault` (2026-07-03):** directory renamed in git,
`~/.claude/plugins/os-vault` symlink and `settings.json`'s `enabledPlugins` updated — but
the `local-plugins` marketplace manifest
(`~/.claude/plugins/.claude-plugin/marketplace.json`) still declared the old
`memory`/`./memory` entry, and `installed_plugins.json` still had a cached
`memory@local-plugins` install record. Skills (and therefore slash commands) never
registered under the new name as a result; hooks kept working because they're wired by
absolute path in `settings.json`, independent of plugin resolution. Fixed by editing the
marketplace manifest to `"os-vault"`/`"./os-vault"`, then
`claude plugin marketplace update local-plugins`,
`claude plugin install os-vault@local-plugins`,
`claude plugin uninstall memory@local-plugins`. See ADR-018 and the "Renaming or moving a
local plugin" procedure below.

**Resolved (2026-07-04):** os-adr's skills failed to register on first install due to stale
plugin caches — the cache that was installed on 2026-07-03 17:21:48 was missing
`hooks/hooks.json`, `bin/adr-detect`, `bin/adr-find`, `bin/adr-migrate`. Root cause:
unknown, but the caches were restored via plugin uninstall/reinstall. A parallel issue
affected os-doc-hygiene (cache retained deleted `commands/` directory). Fixed by manually
refreshing both caches, then created `bin/refresh-plugins` automation to prevent future
drift — see "Editing a local plugin (cache refresh)" below. Investigation result: stale
caches (not manifest-naming issues) were the cause; slash command registration works
correctly once caches are fresh.

**Multi-machine freshness closed (2026-07-10):** `session_start.py` gained a fast-forward-only
`git pull` (`timeout 10 git pull --ff-only --quiet`) for both `cfg.vault_path` and
`cfg.memsearch_dir`, run before the staleness check — silent on success, quiet one-line stderr
note on failure (offline machine), never blocking session start. Closes the push-only gap noted
below; mirrors the push style of `vault_sync.py`/`memsearch_sync.py` in the opposite direction.

**os-backlog AFK slices shipped (2026-07-10):** PRD published as Forgejo issue #9 (state
pointer: Planka card `1816234194716592051`); sliced into issues #10–#17 via `/to-issues`.
The five AFK slices are implemented and committed: #10 plugin scaffold + `board-ensure`
(uniform lists/labels incl. new `semi` autonomy label, Planka 2.1.1 quirks, `archived--`
rename convention), #11 `tracker` key in `.cc-os/config` + os-status `tracker-configured`
check, #12 pure routing resolver CLI, #13 `/os-backlog:capture` + `/os-backlog:list`
skills + card CLI, #15 `card-triage` + `board-audit` named agents. All deterministic parts
covered by stubbed-client tests (34 runs os-backlog, 49 os-status). Semi slices #14
(routing/migration skill), #16 (injection note + /to-issues routing), #17 (ops board +
rubric category + routing ADR) await human decision gates. 2026-07-10 (later): planka-api
gem 0.1.0 installed locally (`rake install`, rbenv 4.0.2; publish/versioning still parked
behind gem issue 13) and live verification completed against production Planka —
`snapshot`, `board-ensure` (created the missing `semi` label on the cc-os board), and
`card-add` + `card-label` all succeeded with bot credentials sourced from ovh-vps
(`~/services/planka/bot-credentials.env`) in a subshell. Follow-up captured as a `hitl`
Backlog card: get planka_bot into credvault (credvault has no import path — rotate vs.
add import capability is a human decision).

**os-backlog migrated to planka-api 0.2.0 typed returns (2026-07-10):** commit `8df0cb7`
moved the gem from 0.1.0 hash-return to 0.2.0, which returns `Planka::Types` value objects
instead of parsed-JSON hashes. `board_ensurer.rb` and `cards.rb` were rewritten on typed
accessors (`card.id`, `card.list_id`, …); `Cards#snapshot` now builds explicit string-keyed
hashes from `BoardDetail#lists`/`#cards`/`#labels`/`#card_labels` (`BoardDetail` replaces the
old `included`-hash shape). Test fakes in `tests/test_helper.rb` were rebuilt to return real
`Planka::Types` records instead of hashes. JSON output stays byte-compatible, so skill/agent
contracts are unchanged. A follow-up fix (issue #18, same day) found the migration had
silently dropped one field from `Cards#snapshot`'s per-card hash; restored the full 19-key
camelCase card key set (`id`, `createdAt`, `updatedAt`, `type`, `position`, `name`,
`description`, `dueDate`, `isDueCompleted`, `stopwatch`, `commentsTotal`, `isClosed`,
`listChangedAt`, `boardId`, `listId`, `creatorUserId`, `prevListId`, `coverAttachmentId`,
`isSubscribed`, plus `labels`) with a regression test pinning the key set including
`listChangedAt`. Suite green at 35 runs (was 34 pre-#18).

**os-backlog live verification (0.2.0) (2026-07-10):** end-to-end re-verification of
`bin/os-backlog` against the real Planka instance with the installed 0.2.0 gem (issue #20).
Local machine had no `PLANKA_*` env/credvault entry, so the plugin tree was rsynced to
`ovh-vps:/tmp/os-backlog-verify` (where `planka-api` 0.2.0 is also installed) and exercised
there with bot credentials sourced from `~/services/planka/bot-credentials.env` in a
subshell, per the established pattern — credential contents were never read or printed.
Results: `tests/all.rb` 35 runs/0 failures on ovh-vps; `board-ensure cc-os --project Dev` run
twice both reported `(existing)` with no lists/labels created (idempotent); `card-add`
created a card on Backlog; `card-label` attached `afk-ready`; `card-comment` posted a
comment; `snapshot --board cc-os` showed the card with the full 20-key set (19 card fields +
`labels`) including `"listChangedAt": "2026-07-10T21:04:37.013Z"` and `"labels":
["afk-ready"]`. The test card was deleted via `Planka::Client#cards.delete` (the CLI has no
delete subcommand) and a follow-up snapshot confirmed it was gone; the rsynced verification
tree on ovh-vps was removed afterward. No regressions vs. the pre-0.2.0 behavior.

**Unified setup/update command + tracker routing skill shipped (2026-07-12):** ADR-026
decided the unified per-project setup/update command lives in os-status as `/os-status:fix`
(rejected: new `os-project` plugin, literal `/cc-os:init`). Built in parallel (issues #21,
#14, both sonnet-delegated): **os-status** gained the `fix` skill (runs the check registry
via a new `python3 hooks/checks.py --json` runner, drives each failing check's owning-plugin
remediation, idempotent — re-run is the update path), a `remediation` pointer on every
`Check`, two new checks (`project-graph-present` → `/os-vault:onboard-project`;
`config-version-current` vs `CURRENT_CONFIG_VERSION`, stamped as `version=` in
`.cc-os/config` by fix via `state.write_config_value`), and a banner header naming
`/os-status:fix` as the single entry point; suite 64 tests (was 36). **os-backlog** gained
`/os-backlog:route` (issue #14): `inspect` + `config-write` dispatcher subcommands
(`lib/backlog/tracker.rb` validates the four tracker formats + classifies git remotes,
`lib/backlog/inspector.rb` finds in-repo issue files; `Config.merge` preserves other keys),
with destination choice and live-history migration as named human gates in the skill; suite
54 runs/110 assertions (was 35). Human gates preserved throughout: fix never fabricates a
tracker value and never edits global settings.json. Rollout per #14 acceptance (onboard
cc-os itself, then one more project) still pending.

**Fix tune-up + per-project state consolidation (2026-07-12, issues #23/#24, ADR-027):** the
credvault smoke-test of `/os-status:fix` (session cd1ae1cd) was audited against the SKILL.md
contract; the run was on-contract but surfaced four gaps (stale snoozes never cleared,
`.cc-os/config` format split between the Ruby and Python writers, ad-hoc gitignore hygiene,
an unprompted commit) plus root-dotdir sprawl. Fixes (both sonnet-delegated, in parallel):
**os-status** — `clear_snooze` helper + self-clearing snoozes when a check evaluates ok/note
(both SessionStart and `--json` runners); its own state (`snooze-*`, `suppress-*`,
`state.json`) relocated to `.cc-os/status/` with legacy fallback read + migrate-on-write
(shared `config` stays at `.cc-os/config`); `write_config_value` normalizes the whole file to
`key=value` (no spaces); fix SKILL.md now scopes out committing, adds an explicit
"`.cc-os/` in .gitignore" step, and clarifies when re-runs are needed; suite 80 tests (was
64). **os-backlog** — `Config` already emitted the normalized format; locked in by new tests
(58 runs, was 54). **os-doc-hygiene** — state moved `.dochygiene/` → `.cc-os/dochygiene/`
(ADR-027) with canonical-then-legacy fallback reads and auto-migration (+ legacy dir removal)
on first write; scanner self-excludes `.cc-os/`; all four SKILL.md files updated; suite 279
passed. `graphify-out/` explicitly exempt from consolidation (ADR-027). Re-run of
`/os-status:fix` in credvault is the pending IRL verification.

**cc-os ADR retrofit (2026-07-12, via `/os-status:fix`):** the 27-ADR monolithic
`docs/memory-system/03-architecture-decisions.md` was migrated to `docs/adr/` with
`/os-adr:migrate`, promoted ahead of the pilot projects (ADR-020 amended in place: migrate
pilot had already passed its gate, migrate is non-destructive, and the monolith's context
cost was real and growing). Mechanics: the detector only scans `docs/{adr,decisions,decision}/`
+ `DECISIONS.md`, so the source was shimmed in via a format-normalized copy under
`docs/decisions/` (bullet-label `- **Context**: …` → line-start `**Context:** …` so the
bold-label parser could extract sections; Rationale/Cross-references left as bullets so they
ride inside Decision/Alternatives content). Result: 27/27 converted, flag rate 3.7% (one low:
0016), consequences filled per file from source material (sonnet-delegated), 0004/0005/0006
marked Superseded by 0010 with frontmatter links, `migration_source` repointed at the real
monolith path, shim removed. The monolith is retained untouched as the historical source; new
decisions go through `/os-adr:create`. CLAUDE.md updated (docs/adr/ layout entry,
trigger-phrased decisions convention, os-adr rollout line). Remaining os-adr rollout: pilot
projects one at a time, then wider.

**os-shortcuts plugin + `/wrap` shipped (2026-07-12, ADR-028, Planka card):** new plugin
`plugins/os-shortcuts/` for user-invoked QOL commands — the "keybindings" of cc-os; domain
boundary vs automatic hook injection (os-orchestration / future os-context) recorded in
ADR-028; skills only, no hooks. First resident `/os-shortcuts:wrap` encodes the session-close
ritual from the 2026-07-09 workflow audit (typed 20+ times): git review → commits per repo
conventions → doc/todo sweep deferring to project CLAUDE.md → Done/In-flight/Next handoff.
Registered in the local-plugins marketplace, enabled in settings.json, installed via
`claude plugin install os-shortcuts@local-plugins`. Sonnet-delegated build. `/readonly`
remains a separate open card (decide vs plan mode first).

**os-backlog card-move + afk-ready-skips-Review (2026-07-12, ADR-029):** the process policy
always intended the AI to move worked cards, but the CLI had no move command, so worked/blocked
cards accumulated in place with comments. Added `card-move --board --card --to` over
planka-api `Cards#move`, with column-ownership rules enforced in `lib/backlog/cards.rb`
(never into/out of Next; hitl cards never moved; never out of Done; →Done only for
afk-ready cards). Autonomy semantics amended per user decision: afk-ready ships straight to
Done (no Review sift); semi still stops at Review. capture/list SKILL.md updated to the
"working a card means moving it" contract. Suite 68 runs/153 assertions (was 58/130).
Sonnet-delegated build.

**os-context rename + prompt files + /readonly decision + doc-length signal (2026-07-13,
ADR-030/031):** worked the four `semi` backlog cards after a Codex plan review. (1)
os-orchestration renamed/generalized to **os-context** (ADR-031 supersedes ADR-019): the
SessionStart hook is now a composer globbing `prompts/session-start/*.md` in filename order
with enforced line budgets (warn 120 / refuse 240); `ORCHESTRATION.md` became
`10-orchestration.md` with byte-identical output (tested); os-status audit references and
`~/.local/state` path updated (old state path symlinked; `OS_ORCH_AUDIT_LEDGER` env var name
kept). (2) Authored `20-kickoff-conventions.md`, `30-standing-safety.md`,
`40-decision-memos.md` (43 lines; total injection 102/120); decision-memo auto-memory file
deleted per single-source rule. (3) `/readonly` decided as convention-only — plan mode is
the enforcement layer, no skill built (ADR-030). (4) os-doc-hygiene scanner gained a
deterministic `file_length` signal (defaults 400 lines / 4000 tokens, `--max-lines` /
`--max-tokens`); flags `docs/implementation-status.md`; suite 286 passed. Issue #25 Parts
2–3 (index-with-progressive-disclosure distill + convention ADR) remain human-gated and
open. Sonnet-delegated builds.

**Remaining optional items:** additional project onboarding (one at a time, per ADR-013); bulk
vault migration. All required build steps complete as of 2026-06-15.

## Implemented components

**Global os-vault plugin** — `cc-os/plugins/os-vault/` (git-tracked, 2026-06-12); symlinked
into `~/.claude/plugins/os-vault`
- Hooks: `hooks/` — `session_start.py` (SessionStart; staleness check + detached graph
  rebuild, and, as of 2026-07-10, a fast-forward-only `git pull` for `cfg.vault_path` and
  `cfg.memsearch_dir` before the staleness check — silent on success, quiet one-line stderr
  note on failure, never blocking), `session_context.py` (project graph path only),
  `post_tool_use_write.py`, `session_end.py` (vault journal), `memsearch_sync.py` (second
  SessionEnd hook; memsearch auto-commit+push, 30s timeout), `vault_sync.py` (third
  SessionEnd hook; vault auto-commit+push to forgejo.swansoncloud.com/jared/SecondBrain, 30s
  timeout; mirrors memsearch_sync.py)
- Shared modules: `config.py` (load_config → frozen Config dataclass), `hook_io.py`
  (read_input → HookInput dataclass), `session_state.py` (record_touch/read_touches;
  encapsulates `/tmp/claude-vault-touched-$SESSION_ID` contract)
- Skills: `skills/` — query, write, reorganize, onboard-project (assessment-first
  onboarding: surveys repo, classifies excludes by type (11 categories), writes per-project
  `.graphifyignore`, confirms with user, then extracts using `qwen25-coder-7b-16k` — per
  ADR-017), design-template (routes template-design ↔ new-type-creation: 4-step
  template-design process + injection-economics filter, 9-step new-type lifecycle; backs
  Phase 1 of the SB Content Plan — see `docs/memory-system/09-sb-content-plan.md`)
- Config: `config.yaml` — vault path, Ollama model (qwen25-coder-7b-16k), env vars
- Hook wiring: `~/.claude/settings.json` (hook entries invoke `/usr/bin/python3` with
  absolute paths into cc-os)
- Isolation seam (2026-07-06, WS2): `OS_VAULT_PATH` env var overrides `vault_path` for the
  write skill and every hook via `config.load_config()`; `OS_VAULT_SKIP_REBUILD` suppresses
  the SessionStart graphify rebuild. Added for the eval harness; zero production impact when
  unset.
- Write-behavior eval (2026-07-06, WS2): `plugins/os-vault/eval/` — held-out unprompted
  vault-write discrimination eval (Eval B/C playbook: ambiguity ladder L1 explicit → L3
  conceptual, paired positives/negatives, 6 run-set scenarios on a new `reportgen` Ruby
  fixture + 6 frozen reserve twins in a different knowledge domain, isolated sandbox vault,
  headless-only runner, deterministic-first Ruby checker with narrow frozen offer-detection
  judge fallback stubbable via `OS_VAULT_EVAL_JUDGE_CMD`, model-free `bin/self-test` 21/21).
  **Scenario Task blocks are held-out — never run informally; the reserve set is never even
  read informally.** Procedure: `plugins/os-vault/eval/README.md`.
- Untuned baseline grid (2026-07-06, run-set × sonnet/haiku × 3 reps + 1 counted canary, 37
  reps, zero harness errors): **positives 1/19, negatives 18/18**. Headline: at L1 (explicit
  cue) both tiers persist the knowledge every rep but route it to Claude Code's built-in
  auto-memory (`~/.claude/projects/<slug>/memory/`) instead of the vault; L2/L3 mostly don't
  persist at all; zero over-triggering anywhere. TSV:
  `eval/results/2026-07-06-baseline-grid.tsv`; full analysis: vault note
  [[os-vault-write-eval-baseline-grid-results]].
- WS2 wording loop COMPLETE (2026-07-07, 4 iterations + confirm + held-out reserve; run-set
  AND reserve now contaminated): shipped destination-ladder write SKILL.md + SessionStart
  USAGE_NOTE (mechanical triggers + before-final-reply checkpoint), mechanical vault-root
  resolution (`${OS_VAULT_PATH:-$HOME/Documents/SecondBrain}` — fixed real-vault breaches
  found on iteration 1), fixture CLAUDE.md "Cross-project memory" section (**the
  real-project adoption template**, required to reach haiku at L2/L3; includes ADR-vs-vault
  disambiguation), candidates 2–4 unscored, post-reserve YAML-colon quoting rule. Confirm
  grid sonnet 18/18 / haiku 16/18; reserve (held-out) positives 8/18 strict / trigger-axis
  13/18, negatives 17/18 (vs baseline 1/19, 18/18). Residual gaps: YAML-hostile titles,
  haiku L2 no-trigger, generalization-laundering over-trigger. One checker false-positive
  fixed+rescored mid-loop (breach regex vs `2>/dev/null`); negative-criterion redesign
  pre-registered. TSVs: `eval/results/2026-07-07-wording-*.tsv`; loop log:
  `autoresearch/classic-260707-1253/loop-log.md`; analysis: vault note
  [[os-vault-write-eval-wording-loop-results]]. Next signal is production IRL audits.

**Global os-orchestration plugin** — `cc-os/plugins/os-orchestration/` (git-tracked,
2026-07-03); symlinked into `~/.claude/plugins/os-orchestration`

**Renamed to os-context (2026-07-13):** generalized into a prompt-composer SessionStart
plugin. `plugins/os-orchestration/` → `plugins/os-context/`; `ORCHESTRATION.md` moved to
`prompts/session-start/10-orchestration.md`; `hooks/inject.py` now globs
`prompts/session-start/*.md`, sorts by filename, and concatenates into one
additionalContext block (byte-identical output to the old single-file behavior when only
`10-orchestration.md` is present), with a deterministic line-count budget (warn >120
lines, refuse >240 lines). `/os-orchestration:audit-sessions` → `/os-context:audit-sessions`;
`~/.local/state/os-orchestration/` → `~/.local/state/os-context/` (os-status's
`orchestration-audit-due` check and ledger env-var default updated to match). The
timeline entries below predate the rename and refer to the plugin by its former name.
- Hooks: `hooks/` — `inject.py` (composes `prompts/session-start/*.md` as additionalContext
  to all sessions)
- Behavior: SessionStart hook injects an `ORCHESTRATION.md` markdown doc (hardcoded; lives
  in plugin source) as additionalContext, carrying the canonical global
  session-orchestration rule set for Claude Code across all projects.
- Migration: migrated from a standalone repo (`~/dev/cc-plugins/orchestration/`, 2026-07-03)
  and integrated into cc-os. Supersedes the per-project copy-pasted orchestration text
  blocks that previously existed in individual project CLAUDE.md files (including a stricter
  local override that cc-os had carried — now removed; see ADR-019).
- Session audit (WS1, 2026-07-06): 10 stratified real sessions audited via
  `audit/bin/extract` (Ruby fact-sheet extractor, dual-use as future eval checker) +
  parallel sonnet auditors + verified synthesis. Findings + E1–E4 eval-scenario backlog:
  `docs/orchestration-audit/2026-07-06-findings.md`. Headlines: model param was silently
  overridden to haiku on all 23 verified spawns — root cause found post-audit:
  `CLAUDE_CODE_SUBAGENT_MODEL=haiku` in `~/.claude/settings.json` env block (set by an
  earlier session as a cost measure; removed 2026-07-06; the Fable-5 correlation was
  coincidental timing). Omitted model param inherits the main-loop model (opus/sonnet) —
  misses cluster in pre-rollout and ops sessions; no over-sharing/full-dump failures
  anywhere.
- Wording fixes shipped (2026-07-06, post-audit): ORCHESTRATION.md rewritten with
  trigger-conditioned when→then phrasing for the three verified clusters — explicit
  `model:` before every Agent call (cluster 2), subagent model self-report on sonnet/opus
  spawns (cluster 1 — the E1 canary proved `resolvedModel` is NOT model-visible in the
  launch result; self-report is the only observable channel), don't re-cover your own ground
  before delegating (cluster 3). Delegation thresholds unchanged. Cache refreshed via
  `bin/refresh-plugins`. Deterministic env-override detection (warn on
  `CLAUDE_CODE_SUBAGENT_MODEL`) is delegated to WS3's status-check design.
- Eval harness E1–E3 (2026-07-06): `plugins/os-orchestration/eval/` — scripted headless
  orchestration-behavior eval scored by the audit extractor (extended with per-segment read
  targets). 6 run-set scenarios (E1P/N downgrade detection with
  `CLAUDE_CODE_SUBAGENT_MODEL=haiku` runner stub; E2P/N explicit-model fan-out vs
  no-delegation-on-trivial; E3P/N delegate-investigation vs orienting-reads-correct) + 6
  frozen reserve twins; new Node.js "relaystation" fixture with deterministic sandbox-time
  log generation; deterministic-first checker (`eval/bin/check`, narrow frozen haiku-judge
  fallback for E1 language axes only, stubbable via `ORCH_EVAL_JUDGE_CMD`); model-free
  `bin/self-test` 21/21 green incl. shipped-instruction-compliant conformance transcripts.
  FAIL axes map only to verified audit misses; tier choice informational. **Scenario Task
  blocks are held-out — never run informally.** Procedure:
  `plugins/os-orchestration/eval/README.md`.
- Baseline grid run (2026-07-06, run-set × sonnet/haiku × 3 reps + 2 counted canaries, all
  counted, zero harness errors): negatives 18/18 PASS both tiers (zero over-delegation, zero
  false downgrade claims); positives 1/18 on the delegate-at-all axis — but transcript
  verification shows most positive FAILs are *superior direct strategies* (E2P sonnet: one
  scripted bulk edit; E3P sonnet: surgical greps over 400KB logs), which the WS1 audit
  itself scored as justified non-delegation, vs genuine miss shapes (E3P haiku: whole 112KB
  logs into own context; E2P haiku: 20-call per-file grind). Conditional rules validated
  where engaged: 14/14 spawns explicit-model; the one delegating E1P rep flagged the stubbed
  downgrade via self-report. Criterion redesign for E2P/E3P A-axes pre-registered (anchor
  thresholds independently, NOT to this grid) before any rescore/tuning; reserve stays
  frozen. ORCHESTRATION.md gained a scripted-bulk-edit carve-out. TSV:
  `eval/results/2026-07-06-baseline-grid.tsv`; full analysis: vault note
  [[os-orchestration-eval-baseline-grid-results]].
- WS4 economics loop COMPLETE + SHIPPED (2026-07-08; run-set AND reserve now contaminated
  for future wording tuning): ORCHESTRATION.md v3 shipped — cost-asymmetry +
  tier-conditional threshold opener, symmetric delegate-when/work-directly-when trigger
  lists (replaces "delegate only when"), batching rule (~5–8 items per grouped spawn,
  SendMessage reuse), async rule, Workflow effort dial; explicit-model/self-report/
  don't-re-cover-ground rules unchanged. Harness extended first (commit b226601): real token
  econ axes — subagent transcripts persist at
  `<projects>/<flat-cwd>/<session-id>/subagents/agent-*.jsonl` with per-message usage blocks
  (solves the mini-audit's instrumentation gap; vault note
  [[claude-code-subagent-transcripts-and-token-accounting]]) — E5 batching pair + reserve
  twins (authored by subagent, held-out content never entered the tuning session), fable
  column, pre-registered E2P/E3P criterion redesign landed (scripted-direct PASS branch;
  74KB ingestion anchor + id-keyed root-cause concepts). Results: E5P 0/6 → majority-PASS
  both tiers incl. reserve twin 5/5 (fable median mltok 43% of baseline, H3 met); negatives
  clean everywhere (36/36 across confirm+reserve). Residual gaps: E1P sonnet delegate-at-all
  (fixture too small — needs bigger fixture before meaningful), fable downgrade-flag ~1/4
  judge flicker. 15 baseline reps were session-limit-truncated and mechanically
  excluded+replaced (limit-banner sweep now a standard step, promoted to the autoresearch
  howto). TSVs: `eval/results/2026-07-08-*.tsv`; loop log:
  `autoresearch/classic-260708-1039/`; vault note
  [[os-orchestration-ws4-econ-wording-results]]. IRL re-audit of ~5 real Fable sessions
  scheduled ~2026-07-22.
- **First IRL re-audit DONE (2026-07-10, ahead of schedule):** 19 production transcripts
  post-2026-07-08 audited by 3 parallel agents against the shipped rules (run:
  `autoresearch/improve-260710-1057/`, plan in `improvement-plan.md`). Solved surfaces:
  model-param discipline (~48/49 spawns pinned), over-delegation guardrail. Tier 1 findings
  → ORCHESTRATION.md wording patch shipped same day (grid validation impossible —
  run-set/reserve contaminated — so this is a one-shot production patch, not a wording
  loop): (1) settled-design mid-session fan-out trigger, (2) never-sleep-poll rule, (3) own
  eval/benchmark loops named as mechanical sequences, (4) unfamiliar-tree ~5-call Explore
  trigger. SendMessage worked example deliberately skipped (no violations found;
  injected-token budget). Acceptance check = next IRL audit (~2–3 weeks; baseline:
  settled-design drift 8/19 sessions). Side finding needing separate repro: harness ignored
  explicit `model: "sonnet"` pins on general-purpose agents (env override unset — distinct
  from WS1 cause); the self-report line caught it.
- **IRL audit semi-automated (2026-07-10):** recurring biweekly audit formalized, working
  from any cwd. Deterministic layer: `audit/bin/audit-stats` (Ruby, composes the existing
  `audit/bin/extract` fact-sheets) enumerates production transcripts since the last run
  (excludes `-tmp-orch-*`/`-tmp-claude-*` sandboxes, `*-eval` dirs, active/trivial
  sessions), writes `~/.local/state/os-orchestration/audit/run-<date>/`
  (stats.tsv/flags.md/sheets) and appends the trend ledger `metrics.tsv` (seeded with the
  2026-07-10 run: 23 sessions, 52 spawns, 1 missing model). Judgment layer: new skill
  `/os-orchestration:audit-sessions` (rubric in `references/`) — sonnet auditor fan-out
  over flagged regions only, tiered synthesis, run-over-run trend verdicts, stops before
  any wording edit. Nudge: os-status check `orchestration-audit-due` warns when the
  ledger's last row is ≥14 days old (missing ledger = machine not opted in, silent; env
  override `OS_ORCH_AUDIT_LEDGER` for tests). Planka recurrence-manifest entry skipped:
  the gem's offsets are deliberately `+1y/+6m/+3m/+1m` only (issue 11) — a `+2w` offset is
  a gem change blocked on the parked publish/versioning decisions; the os-status nudge is
  the trigger for now.

**Global os-status plugin** — `cc-os/plugins/os-status/` (git-tracked, 2026-07-06);
symlinked into `~/.claude/plugins/os-status`
- Purpose: aggregated deterministic SessionStart status checks for the cc-os plugin family —
  per-project artifacts (ADR system, vault hub note) and environment hazards (subagent model
  env override). Built via OpenSpec change `add-os-status-plugin` (supersedes the WS3 plan
  doc); decision record ADR-022.
- Architecture: checks are **in-process** plain Python functions in `hooks/checks.py` with
  the uniform signature `check(ctx) -> CheckResult(status, message)` plus one registry entry
  (no per-plugin subprocess protocol, no per-project code copies — both rejected in ADR-022
  after perspective review). Three states: `ok` (silent), `note` (near-zero-token
  additionalContext line, never snoozed/suppressed), `warn` (aggregated into at most one
  banner; once-per-day snooze + permanent `suppress-<check>` markers in gitignored
  per-project `.cc-os/` — state only, never code; `.cc-os/config` holds optional
  `hub`/`vault_path` key=value overrides).
- Initial checks: `subagent-model-env-override` (env + `~/.claude/settings.json` `env`
  block; runs outside git projects too — catches the WS1 Cluster 1 incident deterministically
  at session start), `adr-system-present` (verbatim port of os-adr's hook behavior incl.
  `.os-adr/suppress`), `vault-hub-note-present` (config slug first, else `type/hub` +
  `project/<name>` facet-tag scan of the vault; missing → warn naming `/os-vault:write`).
- Added 2026-07-12 (ADR-026, issue #21): `/os-status:fix` skill — the unified project
  setup/update command; runs the registry via `python3 hooks/checks.py --json` (each result
  now carries a `remediation` pointer), drives the owning plugin's remediation per failing
  check, stamps `version=` into `.cc-os/config` (`CURRENT_CONFIG_VERSION`); idempotent, so
  re-running is the update path. New checks `project-graph-present` and
  `config-version-current`; warn banner names `/os-status:fix` as the single entry point.
- Tests: `python3 tests/hook_test.py` (64, model-free; 36 pre-#21) incl. byte-identity of
  PRESENT_NOTE/ABSENT_NOTE against os-adr's source. Invariants in `invariants.md`.
  Smoke-tested 2026-07-06 (cache==source, real headless session fired the hook,
  env-override canary warns).

**Global os-doc-hygiene plugin** — `cc-os/plugins/os-doc-hygiene/` (git-tracked,
2026-07-03); symlinked into `~/.claude/plugins/os-doc-hygiene`
- Hooks: `hooks/hooks.json` → SessionStart hook (matcher: startup|resume) runs
  `scripts/reminder.py` via `${CLAUDE_PLUGIN_ROOT}` (5s timeout), emitting a deterministic
  zero-token reminder banner
- Behavior: Monitors stale and bloated project documentation per-project under
  `.dochygiene/` state dir (gitignored). SessionStart reminder is deterministic (no AI
  tokens, once/day snooze). Skills (verb-first, no `commands/` dispatcher — invoked directly
  as `/os-doc-hygiene:<skill>`, per [[cc-os-plugin-skill-naming-convention]]): `check`
  (AI-assisted classification of staleness signals, emits machine+human reports), `clean`
  (AI-assisted or deterministic patch application with git-safe scoped cleanup), `status`
  (read-only lifecycle-timestamp read), `sweep` (check then clean in sequence).
  Reversion-protected via invariants.md + golden-example test fixtures.
- Migration: migrated from standalone repo (`~/dev/cc-plugins/doc-hygiene/`, 2026-07-03) and
  integrated into cc-os. No content conflicts detected. Renamed from `doc-hygiene` to
  `os-doc-hygiene` per cc-os plugin naming convention. Skills renamed
  `hygiene-check`/`hygiene-clean` → `check`/`clean`, and the `commands/hygiene.md`
  dispatcher removed in favor of two new skills (`status`, `sweep`), aligning with the
  `os-vault`/`os-orchestration` pattern of no `commands/` directory (2026-07-03).

**Global os-adr plugin** — `cc-os/plugins/os-adr/` (git-tracked, 2026-07-03); symlinked into
`~/.claude/plugins/os-adr`
- Purpose: Architecture Decision Records, consistently in every project — one
  customized-Nygard template (frontmatter
  `id`/`date`/`status`/`supersedes`/`superseded-by`/`affected-paths`/`affected-components`;
  Context/Decision/Consequences/Alternatives-rejected sections),
  `docs/adr/NNNN-kebab-title.md` one-file-per-decision + fully-regenerated
  `docs/adr/README.md` index. Built from `docs/adr-system/` (requirements `04`, PRD `05`,
  eval sketches `06`) via OpenSpec change `add-os-adr-plugin`.
- Core: Ruby OO library `lib/adr/` (`Record`, `Repository`, `Index`, `Template`, `Detector`,
  `Migrator`, `MigrationReport`, `Finder`; Sandi Metz style, injected paths) behind thin
  CLIs in `bin/` (`adr-new`, `adr-init`, `adr-detect`, `adr-migrate`, `adr-find`). Tests:
  `ruby tests/all.rb` (47) + `python3 tests/hook_test.py` (15), all model-free. Behavioral
  invariants in `invariants.md`.
- Hook: **moved to os-status (2026-07-06)** — the SessionStart existence check now runs as
  the `adr-system-present` check in the os-status plugin (`hooks.json` here is empty;
  `hooks/session_start.py` stays as the wording source of record, byte-copied into
  os-status). Behavior unchanged: present → near-zero-token usage note naming
  `/os-adr:create` + `/os-adr:find`; absent → once-per-day init/migrate suggestion, silenced
  permanently by `.os-adr/suppress` (still honored); silent outside git projects.
- Skills (verb-first, no `commands/`): `create` (one-invocation templated+numbered+indexed
  ADR with mechanical supersession), `init`, `migrate` (non-destructive: detect surveyed
  shapes → mechanical heuristic fill → LLM fills only manifest-listed interpretive fields
  via `--apply-fills` → `migration_confidence` frontmatter + `docs/adr/migration-report.md`;
  old-system deletion only as an explicit separate user-approved step), `find`
  (deterministic-first retrieval: affected-paths/components match → Accepted-only filter →
  one-hop Graphify query-path expansion with graceful degradation → AI judgment over the
  candidate set only).
- Migration pilot passed 2026-07-03 (sandboxed project copies; gate threshold 25%
  low-confidence flags): viking-warrior-training-log 0%, delta-refinery 0%, llf-schema 8.3%.
  Retrieval verified end-to-end against the real llf-schema project graph. Resolved: ADRs
  need no Graphify tag/edge convention — retrieval layer 3 expands the *query* paths via
  graph-node `source_file`s.
- Eval A harness (2026-07-03, ADR-021): `plugins/os-adr/eval/` — prompted skill-execution
  eval across model tiers (haiku/sonnet). Two fixtures (generated with the plugin's own
  CLIs), six scenarios (S1 create, S2 create+supersede, S3 find/conflict, S4
  find/distractor, S5 init, S6 migrate+fills), deterministic Ruby checker (`eval/bin/check`,
  structural invariants, TSV mode for autoresearch), sandbox + headless-runner scripts,
  runner-prompt template. Primary run mode: in-session Agent-tool subagents with pinned
  `model:`; optimized via the `/autoresearch` Classic loop over SKILL.md *wording only*
  (checker/fixtures/scenarios frozen during a loop). Procedure:
  `plugins/os-adr/eval/README.md`. Self-tested both directions; grid run 2026-07-03, all
  scenarios × both tiers passing. Distinct from the held-out Eval B (unprompted behavior) —
  do not conflate.
- Eval B harness (2026-07-03, OpenSpec change `add-os-adr-eval-b-harness`):
  `plugins/os-adr/eval-b/` — held-out unprompted-behavior eval (requirements 4–5). 7
  scenarios (W1–W3 write-trigger, R1–R4 retrieval) authored from the frozen shapes in
  `docs/adr-system/06-eval-scenarios.md`; dedicated Ruby webhook-relay fixture with a 6-ADR
  history (Superseded pair + near-miss distractors, generated via the plugin's own CLIs);
  R4's one-hop graph reach uses a real `graphify update` AST build (model-free, rebuilt via
  `eval-b/bin/build-fixture-graph`, never committed). **Headless-only runner**
  (`eval-b/bin/run` — fresh `claude -p` per rep, cwd = sandbox, so the real SessionStart
  hook fires; in-session subagents are invalid here, unlike Eval A) and a two-axis
  deterministic-first checker (`eval-b/bin/check`): axis (a) unprompted consultation,
  mechanical from transcript tool_use blocks; axis (b) correct-ADR citation (R1–R4) or
  new-ADR-file with a narrow frozen-rubric haiku judge fallback (W1–W3, `judge-rubric.md`,
  stubbable via `ADR_EVAL_B_JUDGE_CMD`). `R4-nograph` is the graph-degradation variant
  (expected FAIL). Self-tested both directions model-free via `eval-b/bin/self-test`.
  **Scenario Task blocks are held-out — never run them informally.** Procedure:
  `plugins/os-adr/eval-b/README.md`. Grid run 2026-07-03 (1 rep/cell): haiku 0/8 PASS;
  sonnet 5/8 PASS (fails W3, R1). `R4-nograph` FAILed on both tiers as expected. Full
  results + observations: vault note [[os-adr-eval-b-grid-results-and-observations]].
- **Initial iteration complete (2026-07-03):** plugin build, migration pilot, Eval A grid
  (clean pass), and Eval B grid (baseline) all done — closes the first pass on os-adr.
- **Wording experiment complete (2026-07-04):** the follow-up `/autoresearch` loop over
  Eval B wording ran (5 iterations, checker/fixtures/scenarios/rubric frozen; fixture
  CLAUDE.md declared a wording surface upfront) and closed the gap — final full grid
  **sonnet 8/8, haiku 7/8** (from 5/8 / 0/8 baseline; haiku's one miss is a W3 axis-b
  judge-boundary flicker). Winning wording shipped in `hooks/session_start.py`
  (PRESENT_NOTE), find/create SKILL.mds, and `eval-b/fixture/project/CLAUDE.md` (new — the
  trigger-phrased "Architecture decisions" section, the template for real-project adoption).
  Confirmed mechanisms: trigger-conditioned when→then phrasing beats inventory phrasing on
  both tiers; each rule must live where its precondition is visible (the reversal→supersede
  rule in the find skill's act-on-findings step fixed W3); lower tiers need *mechanical*
  triggers — semantic triggers only reach sonnet. Open: channel ablation never run;
  R4-nograph now passes both tiers, so the graph-degradation check no longer differentiates.
  Full hypothesis→result mapping: vault note [[os-adr-eval-b-wording-experiment-hypotheses]].
  **Before designing or running any autoresearch eval, Read
  `~/Documents/SecondBrain/howto/running-autoresearch-skill-evals.md`.**
- **Eval B W3 stability check (2026-07-06):** 7 headless reps of haiku × W3 (all reps
  counted): axis (a) consultation 7/7 PASS; axis (b) recording-offer ~5/7 (~75–85%) — one
  FAIL plausibly infra, one a genuine behavioral miss. Verdict: intermittent flicker, not a
  hard gap — grid claim stays **haiku 7/8**, W3 characterized as an ~1-in-4/5 axis-b miss.
  Haiku cleared for daily use with that caveat. Recorded in the vault good-enough gate:
  [[os-adr-eval-b-wording-experiment-hypotheses]].
- **Eval C harness built, NOT yet run as designed (2026-07-06):** `plugins/os-adr/eval-c/` —
  ambiguity-ladder DISCRIMINATION eval (held-out; Eval B is contaminated by the wording
  loop). 3 levels (explicit → moderate → conceptual framing) × paired positive/negative
  scenarios; run-set (6, job-execution domain) + frozen reserve-set (6, notifications
  domain). New Python fixture (`taskq` async job queue, 6-ADR history generated via the
  plugin's own CLIs, trigger-phrased CLAUDE.md section copied from eval-b). Scoring:
  positives = both axes; negatives FAIL **only on unneeded ADR creation**. Model-free
  `bin/self-test` green, including a truthful-citation-must-PASS guard. **Scenario Task
  blocks are held-out — never run informally.** Methodology: vault notes
  [[eval-methodology-ladder]] and [[eval-methodology-irl-feedback-loop]]; vault also gained
  an `eval-results` note type + `_templates/eval-results.md` (2026-07-06).
- **Eval C frozen grid run (2026-07-06):** run-set × {sonnet, haiku} × 3 reps/cell (36
  headless reps, all counted) — **12/12 cells PASS at ≥2/3 majority; haiku 18/18 reps,
  sonnet 17/18**. Zero over-trigger ADR creation on any negative at any level; every
  positive pass was via governing-ADR citation (16) or judge-recognized proposal (1), never
  duplicate creation. Sonnet's one FAIL rep (P1-L1) is a final-message-citation boundary
  artifact, not a behavioral miss. Two harness defects fixed on the first live rep, BEFORE
  the grid, with Task blocks/fixtures/rubric untouched: (1) `bin/run` pipefail bug; (2)
  positive axis-b contradiction fixed via a mechanical `cited-governing` PASS branch + two
  new self-test guards (`B-via:` now recorded in TSV). Verdict: the Eval B wording
  **generalizes** — grid saturated, ceiling not found; next signal is production (rollout +
  IRL session audits), not another lab rung. Run-set is now the baseline; wording tuning
  against it moves measurement to the reserve-set. Full results: vault note
  [[os-adr-eval-c-frozen-grid-results]].
- **Remaining (rollout order, amended 2026-07-12):** the cc-os retrofit is done (promoted
  ahead of pilots — see the 2026-07-12 timeline entry and the ADR-020 amendment); remaining:
  real-project migration/adoption one at a time via `/os-adr:migrate` — pilot projects, then
  wider. When onboarding real projects,
  add the trigger-phrased "Architecture decisions" CLAUDE.md section (copy from
  `eval-b/fixture/project/CLAUDE.md`; candidate: emit it from `/os-adr:init`/`migrate`).

**Graphify** — v0.8.31 at `/home/jared/.local/bin/graphify`
- Vault graph: `~/Documents/SecondBrain/graphify-out/` — disposable, structural index
  rebuilt by SessionStart hook; handles relational/graph queries. Distinct from
  vault-index.json (planned, Plan B Phase 1): a flat `{tag: [{path, title, summary}]}`
  lookup rebuilt at SessionEnd, queried by the `/memory-find` skill for fast tag-based SB
  note discovery.
- Project graph: `<project-root>/graphify-out/` — same pattern; gitignore it in each project
  repo
- Vault conventions: `~/Documents/SecondBrain/vault-conventions.md` — frontmatter contract +
  tag taxonomy (canonical name decided 2026-06-09; formerly referred to as CONVENTIONS.md)

**memsearch** — v0.4.6 via Claude Code plugin marketplace (`memsearch@memsearch-plugins`)
- Hooks: Stop, SessionStart, UserPromptSubmit, SessionEnd (ship with plugin)
- Memory store: `~/.memsearch/memory/YYYY-MM-DD.md` daily files (global, cross-project, all
  clients — one store by design)
- Index: `~/.memsearch/milvus.db` (Milvus Lite, local); embeddings via ONNX bge-m3
- Config: `MEMSEARCH_DIR=~/.memsearch` in `~/.zshrc` for global scope
- Skills: `/memory-recall`, `/memory-config` (ship with plugin)
- Git sync: `~/.memsearch` is a dedicated private Forgejo repo
  (`forgejo.swansoncloud.com/jared/memsearch`); whitelist `.gitignore` commits only
  `memory/*.md`; auto-commit+push wired into `memsearch_sync.py` SessionEnd hook (relocated
  from `session-end.sh` by ADR-016, 2026-06-12; behavior preserved — see ADR-015)

**Obsidian vault git sync** — `~/Documents/SecondBrain` (2026-06-15)
- Remote: `ssh://git@forgejo.swansoncloud.com:2222/jared/SecondBrain.git` (private Forgejo;
  web: `https://forgejo.swansoncloud.com/jared/SecondBrain`)
- 52 files tracked (notes, journal, templates, vault-conventions.md, CLAUDE.md, .obsidian
  config); `graphify-out/` excluded via `.gitignore`
- Auto-commit+push via `vault_sync.py` SessionEnd hook (mirrors `memsearch_sync.py`;
  push-only — SessionStart pull is optional future item for multi-machine)

**Global os-backlog plugin** — `cc-os/plugins/os-backlog/` (git-tracked, 2026-07-10);
symlinked into `~/.claude/plugins/os-backlog`; PRD Forgejo issue #9, slices #10–#17
- Purpose: the AI's process-management surface over Planka — deterministic tracker routing
  (Planka = task state by default; git issues = implementation specs only), mid-session
  capture, pull-only listing, board lifecycle, and the three-value autonomy convention
  (`hitl`/`semi`/`afk-ready`).
- Lib (Ruby, os-adr `lib/`+`bin/` pattern, installed planka-api gem only (0.2.0, typed
  `Planka::Types` returns as of 2026-07-10) — no source
  coupling): `board_spec.rb` (uniform lists/labels contract), `board_ensurer.rb`
  (idempotent create/repair; Planka 2.1.1 `type` fields, shared-project + owner-manager
  visibility fix, label color candidates with fallback; `archived--` rename convention),
  `config.rb` (`.cc-os/config` parser), `resolver.rb` (pure repo→board decision:
  `use`/`activate`/`stop-and-discuss`; no network), `cards.rb` (add-at-Backlog, snapshot,
  attach_label, comment).
- CLI: `bin/os-backlog` — `board-ensure`, `activate`, `archive`, `resolve`, `card-add`,
  `cards`, `snapshot`, `card-label`, `card-comment`, `card-move` (2026-07-12, ADR-029 —
  ownership rules enforced in lib); every path fails soft (one-line error,
  exit 1) when the gem/Planka is unavailable.
- Skills: `/os-backlog:capture`, `/os-backlog:list`, `/os-backlog:route` (2026-07-12, issue
  #14 — tracker onboarding conversation over new `inspect`/`config-write` subcommands and
  `lib/backlog/tracker.rb`/`inspector.rb`; destination choice + live-history migration are
  named human gates) — carry the column-ownership rules (AI
  creates at Backlog, Doing→Review at most, never Next or Review→Done, never self-assigns
  `hitl`); list is pull-only per notification policy v2.
- Agents: `agents/card-triage.md` (priority + autonomy labels only; ambiguity → `hitl`),
  `agents/board-audit.md` (four drift classes; writes at most comments).
- Tests: `tests/` — 54 runs/110 assertions (35 pre-#14) against an in-memory
  `FakePlankaClient`; no live
  API. Companion os-status check `tracker-configured` (issue #11) validates the `tracker`
  key grammar and nudges unconfigured git projects (daily-snoozed).
- Outstanding: Semi slices #16/#17 (injection note + /to-issues routing, ops board + rubric
  category + routing ADR); #14 (routing skill) shipped 2026-07-12 — rollout (onboard cc-os,
  then one more project) pending. Live verification
  completed 2026-07-10 (snapshot / board-ensure / card-add / card-label against production;
  gem 0.1.0 locally installed via `rake install`); re-verified 2026-07-10 (later) against the
  installed 0.2.0 gem post-migration — see "os-backlog migrated to planka-api 0.2.0" and
  "os-backlog live verification (0.2.0)" timeline entries above.

### os-shortcuts (plugin)

Global plugin: user-invoked QOL shortcut commands (ADR-028). Skills only — never hooks;
automatic injection belongs to os-orchestration / the planned os-context.

- Skills: `/os-shortcuts:wrap` — session-close ritual (git review, commits per repo
  conventions, doc/todo sweep deferring to project CLAUDE.md, handoff summary). Shipped
  2026-07-12.
- Expected future residents: additional shortcuts as audit findings warrant (`/readonly`
  card is open — decide vs plan mode before implementing).

## Operational procedures

### Renaming or moving a local plugin

Renaming a plugin directory under a directory-source marketplace (like `local-plugins`, whose
source is `~/.claude/plugins` itself) requires updating **three** places, not just the
directory and `settings.json`:

1. **Plugin directory / symlink** — the actual files (or symlink target, for plugins that
   live in a git repo like `cc-os/plugins/os-vault/`).
2. **Marketplace manifest** — `~/.claude/plugins/.claude-plugin/marketplace.json` (for
   `local-plugins`) lists each plugin's `name` and `source` path explicitly; this does
   **not** auto-discover from the directory listing. Update the entry to match the new
   name/path.
3. **`settings.json` `enabledPlugins`** — the `<name>@<marketplace>` key must match the
   manifest entry from step 2.

Then refresh the plugin manager's state so it re-resolves the marketplace and drops the
stale install record:

```bash
claude plugin marketplace update <marketplace-name>   # re-validates the manifest
claude plugin install <new-name>@<marketplace-name>    # creates the new install record
claude plugin uninstall <old-name>@<marketplace-name>  # drops the stale one
claude plugin list                                     # verify: new name enabled, old name gone
claude plugin details <new-name>@<marketplace-name>     # verify skills/agents/hooks resolved
```

Skipping step 2 is the failure mode to watch for: hooks (wired by absolute path in
`settings.json`) keep working, masking the fact that skills/slash-commands silently stopped
registering under the plugin's new name.

### Editing a local plugin (cache refresh)

Plugin source edits (including SKILL.md wording, hook scripts, or CLI code) do not reach
running sessions until the cache is refreshed. Claude Code caches plugins when installed,
copying them to `~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/`. To refresh a
stale cache after source edits:

```bash
bin/refresh-plugins [marketplace-names...]    # refresh all or specific local marketplaces
```

This uninstalls and reinstalls each plugin, forcing the cache to repopulate. See
`bin/refresh-plugins --help` for usage. After refreshing,
`claude plugin details <name>@<marketplace>` should show updated skill descriptions and hook
counts. Directory-source marketplaces (e.g., `local-plugins` sourced from
`~/.claude/plugins`, `cc-plugins` sourced from `~/dev/cc-plugins`) are the only ones that
need manual refresh — public marketplaces auto-update.
