feat(skills): hygiene — repo hygiene + crash-safe capture as a callable skill - #89
Conversation
…able skill
`can hygiene` and `can wip` are merged and live in chittycan (dd2cfc9, c72c2b4,
eefe146) but reachable only as shell commands. The original ask was a capability
callable by user OR synth depending on entry point; this is the skill projection
of that same core.
Routed through chittymarket canonical rather than ~/.claude/skills/ — 58 of 156
local skills there are unmanaged orphans (CFDXN-127), so a 59th would be the
problem rather than the fix.
The body is mostly about READING THE OUTPUT correctly, because that is where an
agent goes wrong rather than in the invocation:
- `can hygiene` exits 1 on findings. Correct for a gate; not an error.
- Zero findings is not automatically good news. A harness that read
`.findings` off a `Finding[]` reported 0 findings across four repos minutes
after the same code reported six, and it looked entirely plausible.
- Two rules fire on ~99% of repos and must not dominate a report.
- capture REFUSES mid-merge — a conflicted tree is a partial result, not a
state anyone chose. Do not work around it.
- refs/wip, never refs/heads: a snapshot in the branch list reads as pending
work someone should merge.
- never `git stash` as an alternative — the stash is repository-global and can
pop an entry another session depends on.
- branches judged by mergeability, never age; never archive a `closing`
branch, the only actionable band.
- fleet scope requires explicit authorization naming the action.
Existing-first search performed: no hygiene/wip/branch skill in canonical/.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EtosSqJ6sL5dMyeHfkNrTe
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📝 WalkthroughWalkthroughAdded the ChangesHygiene skill
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The overlay coverage gate failed on this PR because marketplace.json gained an
artifact (skill-hygiene) with no matching record in capabilities.generated.json.
The gate is correct and the failure was real — 106 artifacts, 105 records.
Authored by hand because the overlay has no generator: every script in scripts/
is a validator (coverage, schema, provenance, freshness), so a new artifact's
record has no automated author. Content hash stamped by
scripts/overlay-provenance.py.
Two field choices worth stating, since both differ from the majority of records:
execution.default_surface = "local" / local_allowed = true
Capture writes refs through an isolated GIT_INDEX_FILE against a real
working tree. There is no remote surface that could perform it, so the
ch1tty default (90/105 records) would be a false claim.
execution.mutation_risk = "medium"
`wip capture` is provably non-mutating, but the record also covers
`wip branches --prune-merged`, which deletes refs after archiving them.
One record, two surfaces — it takes the higher risk.
source_links initially used chittycanon:// and https:// and were rejected by
check-source-freshness.sh, which gates only marketplace:// , local:// and
ch1tty:// . Corrected to local:// paths that the checker actually resolves.
Verified locally, all green: coverage 106/106, §16 schema, provenance verify,
source freshness, lint-plugins, test-plugins 86/86, dispatch audit 119 cells /
0 drift.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EtosSqJ6sL5dMyeHfkNrTe
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@marketplace.json`:
- Around line 560-588: Update the marketplace catalog to contain exactly 104
unique artifact IDs by removing the two extraneous artifact entries. Preserve a
single skill-hygiene entry with installMode set to standalone, and validate that
every remaining installMode value is only ch1tty, standalone, or both.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 6b6ee285-33f2-4f81-a343-0df47ef76f5a
⛔ Files ignored due to path filters (1)
capabilities.generated.jsonis excluded by!**/*.generated.*
📒 Files selected for processing (5)
canonical/.dispatch-state/skills/hygiene.jsoncanonical/skills/hygiene.mdmarketplace.jsonplugins/chittyos-core/codex-skills/hygiene/SKILL.mdplugins/chittyos-core/skills/hygiene/SKILL.md
| { | ||
| "id": "skill-hygiene", | ||
| "name": "Repository Hygiene", | ||
| "description": "Repository hygiene and crash-safe work capture for any repo. Wraps the merged `can hygiene` and `can wip` surfaces so a synth can run them against a target repo \u2014 config auditing, uncommitted-work capture to refs/wip, orphan recovery, and mergeability-based branch lifecycle with archive-before-delete.", | ||
| "type": "skill", | ||
| "category": "ecosystem", | ||
| "access": "readwrite", | ||
| "enabled": true, | ||
| "installMode": "standalone", | ||
| "standalone": { | ||
| "available": true, | ||
| "type": "skill", | ||
| "path": "plugins/chittyos-core/skills/hygiene", | ||
| "plugin": "chittyos-core" | ||
| }, | ||
| "canonical": "canonical/skills/hygiene.md", | ||
| "ch1tty": { | ||
| "available": false | ||
| }, | ||
| "canon_uri": "chittycanon://core/services/chittymarket#skills/hygiene", | ||
| "tags": [ | ||
| "skill", | ||
| "hygiene", | ||
| "git", | ||
| "branches", | ||
| "capture", | ||
| "governance" | ||
| ] | ||
| }, |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
python - <<'PY'
import json
from pathlib import Path
data = json.loads(Path("marketplace.json").read_text())
artifacts = [item for item in data["artifacts"] if "id" in item]
ids = [item["id"] for item in artifacts]
assert len(artifacts) == 104, len(artifacts)
assert len(ids) == len(set(ids)), "duplicate artifact IDs"
assert ids.count("skill-hygiene") == 1
assert all(
item.get("installMode") in {"ch1tty", "standalone", "both"}
for item in artifacts
)
PYRepository: chittyos/chittymarket
Length of output: 252
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
python - <<'PY'
import json
from pathlib import Path
data = json.loads(Path("marketplace.json").read_text())
artifacts = data.get("artifacts", [])
print("total artifacts:", len(artifacts))
print("items with id:", len([item for item in artifacts if "id" in item]))
ids = [item["id"] for item in artifacts if "id" in item]
print("id count:", len(ids))
print("unique id count:", len(set(ids)))
dup_counts = {}
for aid in ids:
dup_counts.setdefault(aid, 0)
dup_counts[aid] += 1
dups = {k: v for k, v in dup_counts.items() if v != 1}
print("duplicate ids:", dups)
hygiene_items = [item for item in artifacts if item.get("id") == "skill-hygiene"]
print("skill-hygiene occurrences:", len(hygiene_items))
for idx, item in enumerate(hygiene_items):
print("skill-hygiene", idx, "installMode:", item.get("installMode"), "keys:", list(item.keys())[:15])
install_counts = {}
for item in artifacts:
mode = item.get("installMode", "<missing>")
install_counts.setdefault(mode, 0)
install_counts[mode] += 1
print("installMode occurrences:", install_counts)
for idx, item in enumerate(artifacts):
mode = item.get("installMode")
if mode not in {"ch1tty", "standalone", "both"}:
print("invalid installMode", idx, item.get("id"), repr(mode))
PYRepository: chittyos/chittymarket
Length of output: 786
Bring marketplace.json into compliance with the 104-capability inventory rule.
The catalog currently contains 106 artifact IDs with unique IDs, so the /market inventory is oversized. Remove the two extraneous artifacts, keeping skill-hygiene once at installMode: standalone, and ensure only ch1tty, standalone, or both values remain for artifacts that list installMode.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@marketplace.json` around lines 560 - 588, Update the marketplace catalog to
contain exactly 104 unique artifact IDs by removing the two extraneous artifact
entries. Preserve a single skill-hygiene entry with installMode set to
standalone, and validate that every remaining installMode value is only ch1tty,
standalone, or both.
Source: Coding guidelines
…oute by shape (#92) * docs: stop hardcoding the artifact count in CLAUDE.md CLAUDE.md asserted "104 capabilities" in three places. marketplace.json holds 106. The number was correct when written and stopped being true the moment an artifact was added — which is what a count in prose always does. This was not cosmetic. CodeRabbit cited these lines as "Coding guidelines" on PR #89 and raised a Major / Data Integrity finding instructing: "The catalog currently contains 106 artifact IDs with unique IDs, so the /market inventory is oversized. Remove the two extraneous artifacts." Following it would have deleted two real, live artifacts to make reality agree with a stale sentence. The reviewer was reasoning correctly from a false premise, and the premise was this file. The real invariant is already mechanized and needs no restating: scripts/check-overlay-coverage.sh asserts marketplace.json and capabilities.generated.json project the same id set, whatever its size. That gate is what caught the genuinely missing skill-hygiene record on #89. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EtosSqJ6sL5dMyeHfkNrTe * feat(nb-defaults): ultracode-shaped execution — fan out by default, route by shape Separation of concerns between AI was already the quality mechanism here, but it only governed *review*. This extends it to execution: orchestrate by default, solo only for conversational turns and trivial mechanical edits. The carve-out is written explicitly so it cannot be argued away, and the sentence that precedes every violation — "I can just do this quickly" — is named as the trigger to fan out rather than proceed. Routing is by shape, not convenience. chittyclaw runs Workers AI models (llama-3.3-70b-fp8-fast, llama-3.1-8b, qwen2.5-coder-32b), which makes it two things at once: a SEPARATE QUOTA POOL from the viewport session, and lower capability. The first is the actual efficiency win and it is about context, not just budget — a 40-file sweep run on claw keeps 40 files of tool output out of the viewport, so the session stays legible. The second is why breadth goes there and depth does not. A table draws the line, and the tell for a violation is named: a claw result that reads as a conclusion rather than as gathered material. Per-projection mechanism, because the shape is constant and the primitive is not: Claude Code has Workflow + the ultracode keyword; Codex/OpenClaw/ChatGPT/Notion have neither, so their ultracode-like shape is a claw CLI fan-out via the CLI container (not the gateway HTTP API). Fan-out width is discovered from the local budget, never hardcoded — a width tuned for one projection starves or overruns another. The health check is part of the BINDING rule, not an aside. A binding rule pointing at a dead endpoint fails closed on every task, and claw has been dead for 46 days before without anyone noticing. Two claw landmines are recorded because both were hit in practice: - chittyclaw is its own tailnet node (100.69.69.7), NOT chittyserv-vm. Running `docker ps` on the VM finds no openclaw containers and yields a false "claw is down". Verified today: the VM check reported dead; `ssh chittyclaw` reported two containers up and /health 200. - Restart gateway FIRST, then CLI — shared netns means restarting the gateway alone kills the CLI into a fake "network connection error". Fallback to local subagents must be stated out loud, since a silent fallback hides both the outage and the fact that the fan-out spent viewport budget rather than the separate pool. Projections are dispatch.sh output, not hand edits: the pre-commit drift hook caught that I had regenerated only the claude-code projection and rejected the commit, which surfaced a codex-skills projection I had not found. Canonical plus all three dispatch outputs (claude-code SKILL.md, codex-skills SKILL.md, .dispatch-state) move together here. The diff is purely additive — zero removed lines in any projection. Not fixed here: ~/.claude/skills/nb-development-defaults/SKILL.md is a STALE projection (2026-07-30, 219 lines vs canonical's 328 pre-change) and the 32 copies under ~/.claude/remote/plugins/ are staler still (2026-06-18, all identical). Editing those directly is the catalog.json landmine — canonical overwrites them. Syncing the installed copies is a separate change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H6EB22mDgirBYomHn3hfyJ * fix(nb-defaults): route by gathering vs judgment — the cheap-reviewer trap, recorded The routing table this replaces was not merely wrong, it was actively harmful: it sent "adversarial refutation votes (N skeptics)" to the cheap column. That is precisely the failure that has already happened here once. What happened: adversarial review was routed to Workers AI models, they were inadequate for the task, the findings they produced were not worth acting on, and so the findings got ignored. Note the shape of that failure — it is SILENT and SELF-REINFORCING. An under-powered reviewer does not error. It returns a confident, empty-looking review that reads as "nothing important found", which trains the operator and every downstream agent to discount the review lane. The quality mechanism does not fail loudly; it quietly becomes theater while still appearing in every workflow diagram. Given one human operator, Separated Adversarial Review IS the quality mechanism, so a doctrine that under-powers it attacks the load-bearing wall. So the axis was wrong. Breadth/depth couples fan-out width to model capability, and those are orthogonal. The axis is what the output IS: gathering - mechanical, independently verifiable, low-judgment. A wrong answer is CAUGHT by the next step because it is checkable. Cheap is fine here at any width. judgment - anything acted on as a finding. A wrong answer is NOT caught, it is absorbed. Needs a capable model REGARDLESS of fan-out width. Ten cheap skeptics are not one competent one; they are ten pieces of noise. The tell is recorded too, because it is counter-intuitive: the symptom is not a bad finding, it is findings being IGNORED. If review output is being skimmed past rather than acted on, suspect the reviewer's model before its prompt. Two premises corrected against live state: - chittyclaw is NOT a synonym for cheap. The prior text asserted it runs only Workers AI (llama-3.3-70b / llama-3.1-8b / qwen-coder-32b) and derived the whole split from that. Live 2026-08-12: the gateway it routes through served claude-sonnet-4-5 via the anthropic provider, 51,766 tokens in, real spend. Frontier-class. Capability is a property of the route requested, not of having left the viewport. The offload argument now stands on quota + context alone, which is where it always belonged. - The AI Gateway must never be addressed by name. The gateway formerly named `chittyclaw` was renamed DELIBERATELY because sessions kept wiring straight to it and bypassing the assistant. The missing slug is selection pressure, not drift — it is supposed to feel like a wall. Reaching for its current name to "fix" a broken URL is the exact failure the rename exists to catch. Recorded explicitly because I walked into it while writing this change. Projections regenerated by dispatch.sh, not hand-edited — the pre-commit drift hook rejected the first attempt and named the codex-skills projection I would otherwise have missed again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H6EB22mDgirBYomHn3hfyJ --------- Co-authored-by: NB <nb@chitty.cc> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
can hygieneandcan wipare merged and live inchittycan(dd2cfc9, c72c2b4, eefe146) but reachable only as shell commands. The original ask was a capability callable by user or synth depending on entry point — this is the skill projection of the same core.Routed through
canonical/rather than~/.claude/skills/: 58 of 156 local skills there are unmanaged orphans (CFDXN-127), so a 59th would be the problem, not the fix. Dispatch projected it tochittyos-coreskills + codex-skills.The body is mostly about reading the output
That's where an agent goes wrong — not in the invocation:
can hygieneexits 1 on findings. Correct for a gate; not an error..findingsoff aFinding[]reported 0 findings across four repos minutes after the same code reported six — and it looked entirely plausible.no-commit-msg-lint137/138,no-local-hook-layer135/138) and must not dominate a report. The signal isdeployed-without-source(7/138, zero false positives).refs/wip, neverrefs/heads: a snapshot in the branch list reads as pending work someone should merge.git stashas an alternative — it is repository-global and can pop an entry another session depends on.closingbranch — the only actionable band.Existing-first search performed: no hygiene/wip/branch skill in
canonical/.🤖 Generated with Claude Code
https://claude.ai/code/session_01EtosSqJ6sL5dMyeHfkNrTe
Summary by CodeRabbit
can hygieneandcan wipusage guidance, including output interpretation and crash-safe work capture.