Skip to content

Repository files navigation

comb

comb logo

Minimal code and minimal words, combined — a YAGNI/terse-prose persona plus a deterministic tool-output compressor, for Claude Code and Hermes.

License: MIT tests dependencies network

Quick start · What's inside · Tuning · When to skip · Uninstall


Two blades: what you build, how you talk about it.

  • Blade 1 — code: an efficiency ladder (YAGNI → reuse → stdlib → native → existing dep → one line → minimum code). Stop at the first rung that holds.
  • Blade 2 — prose: facts and code, no preamble, no restating the ask, no trailing summary. Fragments over sentences where meaning survives.

Supports Claude Code and Hermes — the two agents this was built for, both of which support the full feature set (persona skill + tool-output compression hook).

Quick start

Claude Code:

claude plugin marketplace add maxkilla/comb
claude plugin install comb@comb

Restart Claude Code (or start a new session) and it's live — no config file to edit, no restart flags.

Hermes:

hermes plugins install maxkilla/comb --enable

(Manual install: cp plugin.yaml __init__.py ~/.hermes/plugins/comb/, then add comb under plugins.enabled in your Hermes config — Plugin's kind is omitted in plugin.yaml, so Hermes defaults it to standalone, which is what makes that enabled entry required. Project-local install: ./comb/, requires HERMES_ENABLE_PROJECT_PLUGINS=1. The persona skill is separate from the plugin — copy skills/comb/SKILL.hermes.md to ~/.hermes/skills/software-development/comb/SKILL.md if you want comb mode without the always-on SOUL.md edit described below.)

That's the whole install. Everything below is what it does and how to tune it — skip straight to Uninstall if you just want to try it and back out cleanly.

Default-on, no trigger word needed — see "Always-on persona" below. Off: "stop comb" / "normal mode". One blade only: "comb code" or "comb prose".

Full rules: skills/comb/SKILL.md.

What's in this repo

Piece Where
Claude Code skill (source of truth) skills/comb/SKILL.md
Claude Code plugin manifest .claude-plugin/
Claude Code compression hook hooks/hooks.json + scripts/compress-tool-output.js
Claude Code always-on persona hook hooks/hooks.json + scripts/inject-comb-mode.js
Hermes skill skills/comb/SKILL.hermes.md
Hermes compression plugin plugin.yaml + __init__.py (repo root)
Benchmark vs rdxmin benchmarks/vs-rdxmin.js
Tests test/compress.test.js, test/test_compress.py — 48 passing

The persona rules are the same content in both. The tool-output compressor (elides oversized Bash/Agent/WebFetch/WebSearch/Grep/Glob/MCP output, keeps head/tail/error lines) is ported to both hosts' equivalent hook point — Claude Code's PostToolUse and Hermes' transform_tool_result. Deterministic, zero-dependency, zero-network — no external service required.

If a middle section has more distinct error-looking lines than the compressor can salvage (MAX_ERROR_LINES, 15), it leaves the output whole instead of guessing which errors to drop — a critical-gate pattern from TACO (arXiv:2604.19572), adapted here as a static rule rather than their self-evolving one. That full bypass only applies below GATE_MAX_CHARS (20000 chars) — above it, a dense-error output still needs elision, so it falls back to the normal salvage cap instead of passing an arbitrarily large blob through untouched.

For JSON tool output specifically, the head/tail cut snaps to the nearest complete element boundary (a line that's just a closing brace/bracket) instead of an arbitrary character index — a raw char cut lands mid-object about as often as not on pretty-printed JSON, which produces invalid JSON and context-free error salvage. Not a JSON parser, just a bounded search for the common pretty-printed shape; falls back to a raw cut if no boundary is found nearby.

Always-on persona

Comb doesn't wait for the model to notice a trigger word or choose to load a skill:

  • Claude Code: the plugin's UserPromptSubmit hook (scripts/inject-comb-mode.js) injects the persona rules as additionalContext on every turn.
  • Hermes: installed by appending the same rules to ~/.hermes/SOUL.md, the agent's identity slot — loaded unconditionally every session, no skill load required. (This edits a file outside the repo; if you don't want that, delete the appended block from SOUL.md and rely on skills/comb/SKILL.hermes.md instead, trigger-word activated.)

Either way, skills/comb/SKILL.md / SKILL.hermes.md stay as the source of truth and remain independently loadable.

Tool-output compressor tuning (Claude Code + Hermes)

Env vars, both ports:

COMB_COMPRESS_HEAD       # chars kept from the start (default 1200)
COMB_COMPRESS_TAIL       # chars kept from the end (default 800)
COMB_COMPRESS_THRESHOLD  # only compress above this size (default 3000)
COMB_COMPRESS_GATE_MAX   # size ceiling for the error-count full-bypass gate (default 20000)
COMB_COMPRESS=0          # kill switch (Hermes only; 0/false/no/off) — disables without touching config.yaml
COMB_COMPRESS_SAVE_FULL=0  # Claude Code only: disable saving the full untouched output to disk on elision

Elided output recovery (Claude Code only). Elision is otherwise irreversible, so by default (COMB_COMPRESS_SAVE_FULL unset or 1) the full original text is saved to ~/.claude/comb/tool-output/ (mode 0600, capped at 1MB per file, head75/tail25 if larger) and the elided marker includes the recovery path. Files older than 7 days are swept opportunistically (2% chance per save, no dedicated hot-path scan) rather than requiring a cron job. Since this persists full tool output — including anything sensitive that appeared in it — to disk, set COMB_COMPRESS_SAVE_FULL=0 if you'd rather lose the recovery file than keep it around.

Statusline (Claude Code)

scripts/comb-statusline.sh renders a [COMB] badge showing rate-limit usage (5h/weekly bars, same data /usage shows) and cumulative compressor savings (⇣~NNk tok (Nx), read from ~/.claude/comb/stats.json, written by compress-tool-output.js on every elision). The char count is measured exactly; the token figure is the standard ~4-chars-per-token estimate, hence the ~. Bash-only, no jq/node dependency, symlink-refused reads.

Claude Code allows exactly one statusLine command — wire it in ~/.claude/settings.json:

"statusLine": {
  "type": "command",
  "command": "bash \"/absolute/path/to/comb/scripts/comb-statusline.sh\""
}

When to use / when to skip

Use it if you…

  • run Claude Code or Hermes and want oversized tool output compressed without giving up recoverability (elided text is saved to disk by default, see Tuning above)
  • want a terse-prose/YAGNI persona that's on by default, not opt-in per message
  • work with JSON-heavy tool output (MCP calls, API responses) and want elision that respects element boundaries instead of an arbitrary character cut

Skip it if you…

  • are on a Claude Code version whose tool_response shape comb's field-guessing (output/stdout/content/text/result) doesn't match — it no-ops safely rather than guessing wrong, but you won't get compression either
  • want ML-based or fully content-type-routed compression (JSON-specific crushing, AST-aware code compression) — comb is a deterministic head/tail/error-line rule with a JSON-boundary heuristic bolted on, not a routed pipeline with a trained model behind it

Test

npm test                       # Claude Code compressor (scripts/compress-tool-output.js)
python3 test/test_compress.py  # Hermes plugin (comb/__init__.py)

Uninstall

Claude Code:

claude plugin uninstall comb@comb
claude plugin marketplace remove comb

Nothing else to clean up — the plugin doesn't touch any file outside its own install directory except the optional scratch dirs it created (~/.claude/comb/, holding stats.json and elided-output recovery files under tool-output/; safe to rm -rf if you don't want them kept). If you wired the statusline, remove the statusLine block from ~/.claude/settings.json.

Known Claude Code issue, not comb-specific: marketplace remove doesn't always clear the extraKnownMarketplaces entry from ~/.claude/settings.json (anthropics/claude-code#9537), which can cause the marketplace to silently reappear on next launch. If that happens, check ~/.claude/settings.json for a leftover comb entry under extraKnownMarketplaces and remove it by hand.

Hermes:

hermes plugins uninstall comb

Or manually: delete ~/.hermes/plugins/comb/ and remove comb from plugins.enabled. If you installed the always-on persona (which edits ~/.hermes/SOUL.md directly), delete the appended comb block from that file — it's a plain text append, easy to spot and remove.

License

MIT — see LICENSE.

About

comb — YAGNI persona + tool-output compressor that trims oversized agent output (Hermes/Claude). Minimal code, minimal words.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages