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

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.
/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.
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.
| Chapter | What it answers |
|---|---|
| Concepts | The ideas: learn as you go, sleep on it, file knowledge by reach - in plain language |
| Installation | Install, auto-update, Windows, verifying the setup |
| Setup | First-session decisions: knobs, tree shape, iron rules, seeding a project |
| Usage | The daily flow: capture, recall, the nap/tree/crosstree consolidation ladder |
| Skill catalog | All 83 skills with their triggers, grouped by domain (generated, cannot rot) |
| Architecture | Store format, the write engine, the hook pipeline, guards, delivery paths |
| Reference | Every knob, sentinel file, env var, CLI command, and quirk |
| Contributing | Authoring skills, the quality gates, proposing changes upstream |
| AI transparency | Where AI is used in this repo, what is verified, and how to check it yourself |
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/.
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.
MIT - see LICENSE. Adapted third-party skills retain their own permissive licenses; see plugins/bitranox/THIRD_PARTY_NOTICES.md.
hooks/mods/register.ts 143 lines1import 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