Skip to content

feat(skills): hygiene — repo hygiene + crash-safe capture as a callable skill - #89

Merged
chitcommit merged 2 commits into
mainfrom
feat/hygiene-skill
Aug 3, 2026
Merged

chitcommit merged 2 commits into
mainfrom
feat/hygiene-skill

Conversation

@chitcommit

@chitcommit chitcommit commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

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 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 to chittyos-core skills + codex-skills.

The body is mostly about reading the output

That's where an agent goes wrong — not 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 (no-commit-msg-lint 137/138, no-local-hook-layer 135/138) and must not dominate a report. The signal is deployed-without-source (7/138, zero false positives).
  • 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 — it 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. A 147-repo sweep was blocked by a safety classifier for want of it, correctly.

Existing-first search performed: no hygiene/wip/branch skill in canonical/.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EtosSqJ6sL5dMyeHfkNrTe

Summary by CodeRabbit

  • New Features
    • Added a repository hygiene capability for configuration audits, work-in-progress capture, branch lifecycle management, and orphan recovery.
    • Added can hygiene and can wip usage guidance, including output interpretation and crash-safe work capture.
    • Added safeguards and authorization requirements for fleet-wide operations and branch archival.
  • Documentation
    • Documented hygiene workflows across supported skill surfaces.
    • Registered the standalone hygiene skill in the marketplace.

…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
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Added the hygiene skill definition, runtime projections, marketplace registration, and dispatch state. The documentation covers hygiene scans, WIP capture, branch lifecycle operations, and authorization for fleet-wide requests.

Changes

Hygiene skill

Layer / File(s) Summary
Canonical hygiene definition
canonical/skills/hygiene.md
Defines skill metadata, command selection, output handling, crash-safe WIP capture, branch classification, archival rules, and fleet authorization.
Runtime skill projections
plugins/chittyos-core/skills/hygiene/SKILL.md, plugins/chittyos-core/codex-skills/hygiene/SKILL.md
Adds Claude Code and Codex skill documentation with matching hygiene, WIP, branch, and authorization guidance.
Marketplace and dispatch registration
marketplace.json, canonical/.dispatch-state/skills/hygiene.json
Registers the enabled standalone skill-hygiene artifact and records canonical, Claude Code, and Codex revisions.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the new callable hygiene skill and its main repository hygiene and crash-safe capture capabilities.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/hygiene-skill

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 56e3784 and 4915203.

⛔ Files ignored due to path filters (1)
  • capabilities.generated.json is excluded by !**/*.generated.*
📒 Files selected for processing (5)
  • canonical/.dispatch-state/skills/hygiene.json
  • canonical/skills/hygiene.md
  • marketplace.json
  • plugins/chittyos-core/codex-skills/hygiene/SKILL.md
  • plugins/chittyos-core/skills/hygiene/SKILL.md

Comment thread marketplace.json
Comment on lines +560 to +588
{
"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"
]
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ 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
)
PY

Repository: 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))
PY

Repository: 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

@chitcommit
chitcommit enabled auto-merge (squash) August 3, 2026 03:35
@chitcommit
chitcommit merged commit 66d77f0 into main Aug 3, 2026
10 checks passed
@chitcommit
chitcommit deleted the feat/hygiene-skill branch August 3, 2026 03:42
chitcommit added a commit that referenced this pull request Aug 12, 2026
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant