5.9 KiB
| description |
|---|
| Bring the current project up to the current cc-os approach by remediating whatever /os-status checks flag — idempotent, doubles as the update path. Invoked by /os-status:fix. |
fix
Unified project setup/update. Runs the same check registry the SessionStart hook
runs, then drives each failing check's remediation. Per ADR-026: fix orchestrates
existing per-plugin skills — it never reimplements them. Idempotent by construction:
re-running fix on an already-configured project is the update path, not a separate
command.
Scope: fix never stages or commits. It edits files and reports what changed —
staging and committing is always the user's call, even for mechanical remediations
like a .gitignore addition or a config stamp.
Flow
-
Get machine-readable results. From the project root, run:
python3 ${CLAUDE_PLUGIN_ROOT}/hooks/checks.py --jsonThis prints a JSON array of
{name, status, message, remediation}for every check applicable to the current project (project-scoped checks are skipped outside a git project, same rule the SessionStart hook uses). -
All
ok(and onlynote/ok)? Report "this project is up to date" and go straight to steps 3b–4 (gitignore + version stamp) — nothing else to remediate.
3a. Ensure .cc-os/ is gitignored. Check the project's .gitignore for a
.cc-os/ entry; add one if missing. Per ADR-027, this single entry covers every
cc-os plugin's per-project state (os-status's .cc-os/config + .cc-os/status/,
os-backlog's tracker key, etc.) — there is no separate .os-adr/ entry to add
anymore. This step runs every fix invocation, not just when a check flags it.
3b. Otherwise, walk the non-ok entries in this order (mechanical → decision-
bearing, so autonomous fixes land before anything needing a human gate):
a. adr-system-present → invoke /os-adr:init (or /os-adr:migrate if the
project already has decision-log-like content the message/context suggests —
use judgment, this is mechanical either way).
b. vault-hub-note-present → either invoke /os-vault:write to create a hub
note (tags type/hub + project/<name>), or if the user says a hub note
already exists under a different name, set hub = <slug> in .cc-os/config
via the config-write helper (see step 4).
c. project-graph-present → invoke /os-vault:onboard-project.
d. tracker-configured → invoke /os-backlog:route directly and let it run
its own inspect → propose → confirm flow. Per ADR-0042, one tracker holds both
task state and durable specs — there is no second surface to weigh, so don't
pre-ask the user "forgejo or github or repo?" either; the route skill owns that
decision conversation and its gates. A planka: value found in an existing
.cc-os/config is rejected fail-soft (one line citing ADR-0042) by both
config-write and this check — the fix is the same /os-backlog:route call.
If /os-backlog:route is not installed, tell the user and skip — do not
fabricate a .cc-os/config tracker value yourself.
e. subagent-model-env-override → human gate, and typically out of scope
for a project-level fix. This is an environment/settings.json condition, not
a per-project one. Report it and ask the user to remove the env var
themselves; do not edit ~/.claude/settings.json from this skill.
f. config-version-current → resolved automatically by step 4 below; no
separate action.
Re-run the JSON check after each remediation that plausibly changed check-registry
state (creating a hub note, running /os-adr:init, setting a config key), so later
steps see fresh results (e.g. don't act on a stale vault-hub-note-present warning
after already creating the note). Remediations that don't affect check-registry
state — step 3a's gitignore edit is the example — don't require a re-run.
Snoozed warns self-clear: whenever a check now evaluates to ok/note (whether
because this skill just fixed it or it was already fine), the next SessionStart
or fix run clears its stale snooze-<check> file automatically (state.py's
clear_snooze) — nothing to do here beyond re-running the JSON check per the
rule above.
-
Stamp the config version. Once the mechanical/human-gated fixes above are done (or were already
ok), write the current version into.cc-os/config, preserving every other key. Use the helper:import sys sys.path.insert(0, "${CLAUDE_PLUGIN_ROOT}/hooks") from state import write_config_value, find_project_root from checks import CURRENT_CONFIG_VERSION from pathlib import Path root = find_project_root(Path.cwd()) write_config_value(root, "version", str(CURRENT_CONFIG_VERSION))(Equivalently, run it as a one-off
python3 -c "..."from the project root.) This is what makesconfig-version-currentpass on the next run and what makes re-runningfixon a fully-configured project a fast, silent no-op. -
Report a short summary: which checks were already
ok, which were fixed and how, which were skipped pending a human decision, and confirm the config version was stamped.
Notes
- Never edit
.cc-os/configby hand-writing the whole file — always go throughwrite_config_value(or the equivalent read-modify-write) so unrelated keys (hub,tracker,vault_path, ...) are preserved. - Decision-bearing steps (tracker destination, anything destructive) keep their
human gate even when this skill is otherwise running autonomously. Mechanical
steps (running
/os-adr:init,/os-vault:onboard-project, stamping the version) proceed without asking. - This skill does not touch
subagent-model-env-overridestate — that's a machine environment condition, not a per-project one, and editing global settings.json is out of scope.