SLOPSHOPPER

bitranox

Bitranox skill collection: software-engineering workflow skills (planning, debugging, code review, clean architecture, language and tool references…

newguardtoolprocess
★ 1v8.10.2MITupdated 2026-10-09bitranox/bitranox-skills/plugins/bitranox
A shopper browsing a rack in a slop shop
README

bitranox-skills

A Claude Code plugin that learns your way of working. It notices when a session teaches something - a correction, a rule you state, a mistake worth not repeating - captures it as durable memory, sleeps on it, and files each lesson exactly where it applies: this project, this group of projects, or everything you do. On top of that self-learning memory it ships 83 skills of software-engineering craft - planning, debugging, code review, clean architecture, language and tool references, humanizing prose - refined over real day-to-day work and growing with every lesson that proves broadly useful.

The result compounds: the same correction is never made twice, knowledge from one project is on the desk when a sibling project needs it, and routines harden into skills instead of being re-derived every time.

Quick start

/plugin marketplace add bitranox/bitranox-skills
/plugin install bitranox@bitranox-skills

Install at user scope (the default) - the memory files lessons across projects, so it must run everywhere. Then enable auto-update once via /plugin -> Marketplaces -> bitranox-skills -> Enable auto-update. Windows needs Git for Windows; details and verification in docs/installation.md.

Skills are invoked as /bitranox:<skill>, and Claude picks one up automatically whenever a task matches its description.

Without the plugin marketplace

The same skills also ship as a Python package, for a machine where you would rather not add a marketplace, or where you want a pinned version:

uv tool install bitranox-skills
bitranox-skills install

That copies all 83 skills into ~/.claude/skills/, where Claude Code picks them up as personal skills. It leaves anything already there alone unless you pass --force, --dry-run reports the plan without writing, and --dest targets a different directory. bitranox-skills path prints where the bundled copy lives, including the hooks/ directory - the hooks need entries in your settings.json, which this command deliberately does not write for you.

The package version and the plugin version are the same number, so uv tool install bitranox-skills==5.293.0 and the marketplace's 5.293.0 are the same skills.

The book

ChapterWhat it answers
ConceptsThe ideas: learn as you go, sleep on it, file knowledge by reach - in plain language
InstallationInstall, auto-update, Windows, verifying the setup
SetupFirst-session decisions: knobs, tree shape, iron rules, seeding a project
UsageThe daily flow: capture, recall, the nap/tree/crosstree consolidation ladder
Skill catalogAll 83 skills with their triggers, grouped by domain (generated, cannot rot)
ArchitectureStore format, the write engine, the hook pipeline, guards, delivery paths
ReferenceEvery knob, sentinel file, env var, CLI command, and quirk
ContributingAuthoring skills, the quality gates, proposing changes upstream
AI transparencyWhere AI is used in this repo, what is verified, and how to check it yourself

Repo layout

This repo is both the marketplace (.claude-plugin/marketplace.json) and the single plugin it ships (plugins/bitranox/): the skills live in plugins/bitranox/skills/, the hooks in plugins/bitranox/hooks/.

Credits

Most skills are custom-built or adapted. Some general workflow skills (brainstorming, systematic-debugging, test-driven-development, verification-before-completion) originate from public skill libraries (for example Obra Superpowers and the Vercel Agent Skills Directory) and have been adapted here. markitdown and rory build on upstream sources (the MarkItDown document converter and Rory Sutherland's public talks and writing, respectively). Skills adapted from a third-party source under a permissive license carry their original copyright and license text in plugins/bitranox/THIRD_PARTY_NOTICES.md.

License

MIT - see LICENSE. Adapted third-party skills retain their own permissive licenses; see plugins/bitranox/THIRD_PARTY_NOTICES.md.

Source 1 files
hooks/mods/register.ts 143 lines
1import type { Register } from "claude-code";
2
3// The tools' rules live in hooks/mod_bridge.py and the Python it calls; this module only relays.
4const TIMEOUT_MS = 60_000;
5// The keys tool.call carries beside the tool's own arguments (ToolCallReserved plus AgentLoop).
6const RESERVED = new Set(["tool", "tool_use_id", "consent", "agentId"]);
7
8const str = (description: string) => ({ type: "string", description });
9
10const TOOLS = [
11  {
12    name: "backlog_list",
13    description:
14      "List this repo's OPEN-WORK.md backlog items (open by default). Read it before backlog_add to choose a rank.",
15    inputSchema: { type: "object", properties: { state: { type: "string", enum: ["open", "closed", "all"] } } },
16  },
17  {
18    name: "backlog_add",
19    description:
20      "Add one item to this repo's OPEN-WORK.md backlog. YOU choose the rank: USER items above FOUND ones, a USER item the user deferred below the live USER items but above every FOUND one, bigger size first within an origin. The tool refuses a rank any line already holds (closed lines included) and suggests free tens. Omit `raised` unless you know when it was first raised: the tool then writes today's date with '?', never a guessed one.",
21    inputSchema: {
22      type: "object",
23      required: ["rank", "origin", "what", "size", "open", "next"],
24      properties: {
25        rank: { type: "integer", minimum: 1 },
26        origin: { type: "string", enum: ["USER", "FOUND"] },
27        what: str("what it is, one line (the user's own words for a USER item)"),
28        size: str("how much is left; 'unknown' is honest, an invented count is not"),
29        open: str("why it is still open"),
30        next: str("the concrete next action"),
31        raised: str("YYYY-MM-DD, YYYY-MM-DD? or unknown; omit for today with '?'"),
32      },
33    },
34  },
35  {
36    name: "backlog_close",
37    description: "Close one open OPEN-WORK.md item by rank with a reason. The line stays, marked [x].",
38    inputSchema: {
39      type: "object",
40      required: ["rank", "reason"],
41      properties: { rank: { type: "integer", minimum: 1 }, reason: str("why it is closed, one line") },
42    },
43  },
44  {
45    name: "memory_add",
46    description:
47      "Capture or update one curated bitranox memory fact (the memory engine's add). `level` is the directory whose subtree the fact concerns (default: the session cwd); an update must target the level that owns the fact, or it is refused as SlugCollision. The hook is trigger-first ('When <situation>, <directive>'), at most 500 chars; warnings come back in the result.",
48    inputSchema: {
49      type: "object",
50      required: ["title", "hook", "body"],
51      properties: {
52        title: str("short title"),
53        hook: str("one line, trigger-first"),
54        body: str("the fact body (multi-line allowed)"),
55        level: str("directory to capture at; default the session cwd"),
56        type: { type: "string", enum: ["user", "feedback", "project", "reference"] },
57        slug: str("target an existing fact explicitly"),
58      },
59    },
60  },
61  {
62    name: "contrib_add",
63    description:
64      "Queue one bitranox hook or skill contribution (contrib_queue add) instead of fixing the tool in place during unrelated work. A duplicate or an already closed intent is not re-queued; the result says why.",
65    inputSchema: {
66      type: "object",
67      required: ["what", "target", "why"],
68      properties: {
69        what: str("the change, one line"),
70        target: str("where it goes, e.g. hook or skill:<name>"),
71        why: str("the evidence it is needed"),
72      },
73    },
74  },
75] as const;
76
77function failure(tool: string, kind: string, message: string) {
78  return { ok: false, tool, error: { kind, message } };
79}
80
81function envelopeFrom(tool: string, run: { exitCode: number; stdout: string; stderr: string }) {
82  try {
83    const parsed: unknown = JSON.parse(run.stdout);
84    if (parsed !== null && typeof parsed === "object" && "ok" in parsed) return parsed;
85  } catch {
86    // not an envelope: report what the bridge printed instead
87  }
88  const said = (run.stderr || run.stdout).slice(0, 2000);
89  return failure(tool, "BridgeFailed", `exit ${run.exitCode}: ${said}`);
90}
91
92// The bridge's exit codes: 0 done, 1 refused (a normal answer the model acts on), anything else
93// could not run. Only a success or a refusal is a result.
94const ANSWERED = new Set([0, 1]);
95
96// A string, not the envelope object: core validates the result of a plugin-registered tool as a
97// string or an array of content blocks and turns anything else into a tool_use_error. The plugin
98// test kit has no engine beneath it and never runs that validation, so only a live session shows it.
99function answer(envelope: unknown) {
100  return { result: JSON.stringify(envelope) as never };
101}
102
103// A call that could not run reaches the model as a tool error, not as an ordinary answer: `deny`
104// is "the text ... as an error result" (ToolCallResult, claude-code/index.d.ts line 12633).
105function toolError(envelope: unknown) {
106  return { deny: JSON.stringify(envelope) };
107}
108
109function relay(tool: string, run: { exitCode: number; stdout: string; stderr: string }) {
110  const envelope = envelopeFrom(tool, run);
111  const unparsed = (envelope as { error?: { kind?: string } }).error?.kind === "BridgeFailed";
112  return ANSWERED.has(run.exitCode) && !unparsed ? answer(envelope) : toolError(envelope);
113}
114
115export const register: Register = (on) => {
116  on("session.start", async ($, e, next) => {
117    for (const spec of TOOLS) await $.tool.register(spec as never);
118    return next(e);
119  });
120
121  for (const spec of TOOLS) {
122    on("tool.call", { tool: `mcp__bitranox__${spec.name}` }, async ($, e) => {
123      const input = Object.fromEntries(
124        Object.entries(e as Record<string, unknown>).filter(([k]) => !RESERVED.has(k)),
125      );
126      // On Windows a bare "bash" can resolve to the WSL stub; Claude Code's own Git Bash setting wins.
127      const bash = (await $.env.get("CLAUDE_CODE_GIT_BASH_PATH")) || "bash";
128      const root = $.plugin.root;
129      try {
130        const run = await $.process.run(
131          [bash, `${root}/hooks/run-python.sh`, `${root}/hooks/mod_bridge.py`],
132          { stdin: JSON.stringify({ tool: spec.name, input }), timeoutMs: TIMEOUT_MS },
133        );
134        return relay(spec.name, run);
135      } catch (err) {
136        return toolError(failure(spec.name, "BridgeFailed", String(err)));
137      }
138    }).catch(($, e, next) =>
139      next.called ? next(e) : { deny: `bitranox: the ${spec.name} tool failed before it ran.` },
140    );
141  }
142};
143