Skip to content

Agents as a primitive kind; listing cost and budget in doctor; review fixes - #11

Merged
ConnorBritain merged 3 commits into
mainfrom
ccr-777bc14a-uh72lo
Oct 21, 2026
Merged

ConnorBritain merged 3 commits into
mainfrom
ccr-777bc14a-uh72lo

Conversation

@ConnorBritain

@ConnorBritain ConnorBritain commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

Two of Gestalt's upstream asks, folded into the unpublished 0.1.0 (version unchanged), plus fixes from a review of the 0.1.0 commits that CodeRabbit never covered.

agent kind

  • Warehouse layout: primitives/agents/<name>.yaml, plus <name>/claude.md and/or <name>/codex.toml rendered by the author. Loadouts and profiles list them under agents:.
  • Apply: kitctl copies the files without converting them, to .claude/agents/<name>.md and .codex/agents/<name>.toml, under ~ with --user. They are owned whole files with LF line endings, and update, drift, conflict and off behave as they do for skills.
  • Harness support:
    • Claude Code: documented.
    • Codex user scope: verified, by a sibling project.
    • Codex project scope: an unverified gap.
    • Cursor: an unsupported gap.
  • Validation: catches a missing asset folder, a missing harness file, bad TOML, missing Codex fields, and a frontmatter name that doesn't match. Each has a planted-defect fixture.
  • Elsewhere: inventory lists agent files, init creates primitives/agents/, and forge and vendor refuse agents with a clear message.

Listing cost and budget

  • kitctl doctor reports an estimated always-on listing cost (ceil(chars/4), the same method as Gestalt) for each harness. It counts:

    • the instruction block;
    • each listed skill, as name: description;
    • plugin skills, read from installed plugins;
    • agents.

    It doesn't count skills that run only by name or skills the loadout disables. MCP servers, and plugin skills it can't read, are listed as not measured.

  • budget: {tokens, skills} is a new loadout and profile field. The strictest budget across the active set produces a budget warning, never an error.

Review fixes (each with a test that fails without the fix)

  • eject refused the starter loadout.
  • A malformed kit.yaml crashed status, use and off with a traceback.
  • Two whole files landing on the same target overwrote each other silently. This is now a conflict.
  • A folder sitting where a file goes failed halfway through apply. This is now a conflict at plan time.
  • A .git folder inside a warehouse skill was copied.

Verification

  • Gate: ruff check, ruff format, mypy, pytest (175 passed, up from 136) and the secret check.
  • Round trip with the real agent-kits warehouse (gestalt-flow, which now lists agent:linear):
    • Project scope:
      • use wrote 14 files, including .claude/agents/linear.md, .codex/agents/linear.toml and the vendored humanizer skill.
      • status showed all 18 entries ok.
      • doctor printed the listing cost.
      • off left the repo byte-identical.
    • User scope, in a temporary HOME: use, then off, left home byte-identical.

The docs/publishing.md tag SHA changes to this PR's merge commit.


Generated by Claude Code

Summary by CodeRabbit

  • New Features
    • Added worker-agent support for Claude and Codex, including discovery, validation, initialization, copying, updating, and conflict handling.
    • Loadouts and profiles can now include agents and token or skill budgets.
    • kitctl doctor reports listing-cost estimates and warns when configured budgets are exceeded.
  • Bug Fixes
    • Improved malformed configuration errors, duplicate-target and non-file conflicts, eject behavior, and nested .git handling.
    • Agents are excluded from automatic Forge and vendor workflows and must be rendered manually.

A new `agent` kind: primitives/agents/<name>.yaml plus a <name>/ folder holding
the author's ready claude.md and/or codex.toml. Loadouts and profiles get an
`agents:` list with set semantics like skills.

Kit copies the file for each harness as an owned whole file (LF), reusing the
skill-directory machinery: .claude/agents/<name>.md and .codex/agents/<name>.toml,
moved under ~/.claude and $CODEX_HOME in user scope. It never converts formats.
Codex project agents carry an unverified gap (only $CODEX_HOME/agents has been
seen loading); Cursor gets an unsupported gap.

validate reports a missing folder or harness file, TOML that does not parse, a
missing Codex name/description/developer_instructions and a claude.md frontmatter
name that differs from the target file. Inventory lists agent files, init makes
primitives/agents/, and forge and vendor refuse agents.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012DwdRhzK229skW1NZca5wm
doctor now estimates what each harness lists in every session for the active
set (--loadout plus every loadout in the kit.yaml of an inspected root, user
scope included): the instruction block, each model-invocable skill and each
agent as `name: description`, at ceil(chars / 4), the method Gestalt uses.
Warehouse skills read their SKILL.md frontmatter; a plugin's skills are read
from the installed Claude Code plugin when home is a root. Skills with
disable-model-invocation: true and skills the loadout disables cost nothing.
What doctor cannot read (plugin skills it cannot see, MCP tool lists) is named
under not_measured instead of guessed. Without --loadout, a Kit-managed repo
still gets its listing cost.

A loadout or profile `budget: {tokens, skills}` (positive integers) caps the
listing; each number comes from the most specific layer or profile. Over the
strictest budget in force, doctor adds a `budget` warning naming the number
and the excess. It is never an error, so exit codes do not change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012DwdRhzK229skW1NZca5wm
From an adversarial review of this branch and of the 0.1.0 work (init, skill
copying and setup steps, user scope). Each fix has a test that fails without it.

- eject refused any entry whose value mentions "kitctl", so the starter
  loadout (whose instructions name `kitctl status`) could never be ejected.
  Only a JSON/TOML value that runs kitctl is a dependency now.
- A malformed kit.yaml raised a ruamel traceback from status, use, off and
  (new on this branch) doctor; it is an EngineError with the parse error now.
- Two primitives whose names end alike (acme/review, team/review) both claimed
  the same whole file; the second overwrote the first in one plan and the
  ledger recorded two owners. It is a conflict now.
- A folder where Kit would write a file passed planning and failed in the
  middle of apply, leaving a journal that recovery could not finish. Doc now
  reports a non-regular target as a conflict before anything is written.
- A .git folder inside a warehouse skill (a skill cloned in place) was copied,
  and its binary objects blocked the apply; the content hash already skips it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012DwdRhzK229skW1NZca5wm
@coderabbitai

coderabbitai Bot commented Oct 21, 2026

Copy link
Copy Markdown

Review in Change Stack →

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 22578b80-667e-4836-b4a2-895a56f59390
📥 Commits

Reviewing files that changed from the base of the PR and between f07179b and f4969b3.

📒 Files selected for processing: 35
  • CHANGELOG.md
  • README.md
  • docs/apply.md
  • docs/harness-reference.md
  • docs/model.md
  • src/kitctl/cli.py
  • src/kitctl/cost.py
  • src/kitctl/doctor.py
  • src/kitctl/engine.py
  • src/kitctl/forge.py
  • src/kitctl/harness.py
  • src/kitctl/inventory.py
  • src/kitctl/model.py
  • src/kitctl/resolve.py
  • src/kitctl/scout.py
  • src/kitctl/starter.py
  • src/kitctl/validate.py
  • tests/fixtures/cases/primitives/agents/bad-toml.yaml
  • tests/fixtures/cases/primitives/agents/bad-toml/claude.md
  • tests/fixtures/cases/primitives/agents/bad-toml/codex.toml
  • tests/fixtures/cases/primitives/agents/no-assets.yaml
  • tests/fixtures/cases/primitives/agents/no-codex.yaml
  • tests/fixtures/cases/primitives/agents/no-codex/claude.md
  • tests/fixtures/cases/primitives/agents/no-instructions.yaml
  • tests/fixtures/cases/primitives/agents/no-instructions/claude.md
  • tests/fixtures/cases/primitives/agents/no-instructions/codex.toml
  • tests/fixtures/cases/primitives/agents/wrong-name.yaml
  • tests/fixtures/cases/primitives/agents/wrong-name/claude.md
  • tests/fixtures/cases/primitives/agents/wrong-name/codex.toml
  • tests/test_agents.py
  • tests/test_cost.py
  • tests/test_engine.py
  • tests/test_forge.py
  • tests/test_resolve.py
  • tests/test_skills.py
+------------------------------------+
| My Motto: Semper Bug Exterminatus. |
+------------------------------------+
  \
   \     /)/)
        ( '')
        /  |
      o(___)
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@ConnorBritain
ConnorBritain merged commit 4235124 into main Oct 21, 2026
9 of 10 checks passed
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.

2 participants