Kevin Veen-BirkenbachandClaude Opus 5.5 afd96fcd72 fix(hub): close seven bugs found in the refactor review
The PermissionRequest hook posted asks cut to the hub's field limits, so a signature covered less than Claude Code would run; it now posts nothing it cannot sign in full and leaves the decision to Claude Code with a reason on stderr. fields.seconds names the field the caller used in its error. Serving a stored page maps an OSError to 500 instead of a dropped connection. The natural-language line marks the register as seen before it builds the inbox, like the page does. do_POST runs every header guard (host, origin, client, content type, MCP) before it reads the body, so a refused request never costs its upload. The runner's reader closes stdout at EOF, because a close from the executing thread blocked on the buffer lock and could SIGPIPE a command still running. The page title counts only inbox items that are not snoozed.

Committed on the operator's word despite the gate: cost and time are estimates under 98 % other load and include eight new test cases.

🎯 Fix: 88 %
💥 Break: 3 %
💸 Cost: 106 %
⏱️ Time: 113 %
🛡️ Security: 100 %
🏆 Score: 71
🚦 Gate: ⛔ fix 88 % < 90; cost 106 % > 100, time 113 % > 100: ask the operator before the commit

```
/home/kevinveenbirkenbach/Repositories/github.com/kevinveenbirkenbach/skills/.worktrees/feature/kvb-hub
```

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 18:46:40 +00:00
2026-11-03 16:18:09 +01:00

skills 🧠

GitHub Sponsors Patreon Buy Me a Coffee PayPal

The agent skill collection of Kevin Veen-Birkenbach. Every skill is pinned in skills-lock.json for reproducible installs. First-party skills live under skills/ and are layered on top of the locked ones at install time. Compatible with Claude Code, Codex, Gemini CLI, Cursor, Copilot, Windsurf, Cline, and other agents.

Naming 🏷️

Every first-party skill is named kvb-<category>-<name> with one of these categories: think, create, code, ci, git, check, org, agent, skill, coach: think thinks without producing a file, create produces an artifact, code works on code, ci on pipelines, git on history and forges, check analyses and reports findings, org coordinates agents, agent acts on one agent itself: its repository setup (code index, agent instructions) and its state (relax, sleep, wake up), skill works on skills themselves, coach serves the operator's wellbeing. Only kvb-cleanup, kvb-coach, kvb-help and the collectors kvb-dream, kvb-optimize and kvb-transcend stand without a category. Names use a-z, 0-9 and single hyphens, at most 64 characters, and equal their directory name. tests/test_naming.py enforces all of it, including that the organigram below lists every skill under its category.

Organigram 🏛️

Every first-party skill under its category.

flowchart LR
  kvb((kvb))
  kvb --> think[think]
  kvb --> create[create]
  kvb --> code[code]
  kvb --> ci[ci]
  kvb --> git[git]
  kvb --> check[check]
  kvb --> org[org]
  kvb --> agent[agent]
  kvb --> skill[skill]
  kvb --> coach[coach]
  kvb --> none[no category]
  think --> think_listen[kvb-think-listen]
  think --> think_explain[kvb-think-explain]
  think --> think_dialectic[kvb-think-dialectic]
  think --> think_criticize[kvb-think-criticize]
  think --> think_brainstorm[kvb-think-brainstorm]
  think --> think_gaps[kvb-think-gaps]
  create --> create_plan[kvb-create-plan]
  create --> create_requirement[kvb-create-requirement]
  code --> code_scope_guard[kvb-code-scope-guard]
  code --> code_clean[kvb-code-clean]
  code --> code_refactor[kvb-code-refactor]
  code --> code_test[kvb-code-test]
  code --> code_tune[kvb-code-tune]
  code --> code_transcend[kvb-code-transcend]
  ci --> ci_triage[kvb-ci-triage]
  ci --> ci_artifacts[kvb-ci-artifacts]
  ci --> ci_observe[kvb-ci-observe]
  git --> git_commit_next[kvb-git-commit-next]
  git --> git_commit_no_verify[kvb-git-commit-no-verify]
  git --> git_merge_fix[kvb-git-merge-fix]
  git --> git_issue_close[kvb-git-issue-close]
  git --> git_issue_solve[kvb-git-issue-solve]
  git --> git_pr_create[kvb-git-pr-create]
  git --> git_pr_label[kvb-git-pr-label]
  git --> git_update_branches[kvb-git-update-branches]
  git --> git_branch_gc[kvb-git-branch-gc]
  git --> git_orphans_find[kvb-git-orphans-find]
  git --> git_changelog[kvb-git-changelog]
  git --> git_hotfix[kvb-git-hotfix]
  git --> git_push[kvb-git-push]
  git --> git_diff[kvb-git-diff]
  check --> check_legal[kvb-check-legal]
  check --> check_security[kvb-check-security]
  check --> check_principles[kvb-check-principles]
  check --> check_confidence[kvb-check-confidence]
  check --> check_break_risk[kvb-check-break-risk]
  check --> check_gate[kvb-check-gate]
  check --> check_efficiency[kvb-check-efficiency]
  check --> check_speed[kvb-check-speed]
  check --> check_score[kvb-check-score]
  org --> org_organize[kvb-org-organize]
  org --> org_split[kvb-org-split]
  org --> org_coordinate[kvb-org-coordinate]
  org --> org_perform[kvb-org-perform]
  org --> org_matrix[kvb-org-matrix]
  org --> org_rasci[kvb-org-rasci]
  org --> org_artefacts[kvb-org-artefacts]
  org --> org_wsjf[kvb-org-wsjf]
  org --> org_robot[kvb-org-robot]
  org --> org_operator[kvb-org-operator]
  org --> org_priority[kvb-org-priority]
  org --> org_evening[kvb-org-evening]
  org --> org_sunset[kvb-org-sunset]
  org --> org_sunrise[kvb-org-sunrise]
  think --> think_choice[kvb-think-choice]
  org --> org_radio[kvb-org-radio]
  org --> org_queue[kvb-org-queue]
  org --> org_update[kvb-org-update]
  agent --> agent_optimize[kvb-agent-optimize]
  agent --> agent_relax[kvb-agent-relax]
  agent --> agent_sleep[kvb-agent-sleep]
  agent --> agent_wakeup[kvb-agent-wakeup]
  skill --> skill_tune[kvb-skill-tune]
  skill --> skill_auto[kvb-skill-auto]
  skill --> skill_essence[kvb-skill-essence]
  skill --> skill_transcend[kvb-skill-transcend]
  skill --> skill_compile[kvb-skill-compile]
  skill --> skill_cleanup[kvb-skill-cleanup]
  skill --> skill_silence[kvb-skill-silence]
  none --> cleanup[kvb-cleanup]
  none --> help[kvb-help]
  none --> transcend_all[kvb-transcend]
  none --> dream_all[kvb-dream]
  none --> optimize_all[kvb-optimize]
  none --> coach_all[kvb-coach]
  coach --> coach_meditation[kvb-coach-meditation]

Skill map 🗺️

How the first-party skills work together. A solid arrow means the skill invokes or relies on the other one; a dotted arrow means it fires automatically. Every skill that reports a result closes with the kvb-check-confidence block; those arrows are left out. The locked third-party skills (caveman, ponytail, archify) are not drawn.

flowchart LR
  subgraph triggers [Triggers]
    commit_req([commit request])
    stage_req([staging or fix ready])
    edit_hook([edit in a git worktree])
    reminders([12 h agent hint, 17:00 GNOME popup])
    full_hour([full hour])
    code_task([code task])
    spawn([subagent spawn])
  end
  subgraph cat_think [think]
    active_listening[kvb-think-listen]
    explain[kvb-think-explain]
    dialectic[kvb-think-dialectic]
    criticize[kvb-think-criticize]
    brainstorm[kvb-think-brainstorm]
    gaps[kvb-think-gaps]
    choice[kvb-think-choice]
  end
  subgraph cat_create [create]
    plan[kvb-create-plan]
    requirement[kvb-create-requirement]
  end
  subgraph cat_code [code]
    scope_guard[kvb-code-scope-guard]
    clean[kvb-code-clean]
    refactor[kvb-code-refactor]
    test[kvb-code-test]
    tune[kvb-code-tune]
    code_transcend[kvb-code-transcend]
  end
  subgraph cat_ci [ci]
    triage[kvb-ci-triage]
    ci_artifacts[kvb-ci-artifacts]
    observe[kvb-ci-observe]
  end
  subgraph cat_git [git]
    commit_next[kvb-git-commit-next]
    commit_no_verify[kvb-git-commit-no-verify]
    merge_fix[kvb-git-merge-fix]
    issue_close[kvb-git-issue-close]
    issue_solve[kvb-git-issue-solve]
    pr_create[kvb-git-pr-create]
    pr_label[kvb-git-pr-label]
    update_branches[kvb-git-update-branches]
    branch_gc[kvb-git-branch-gc]
    orphans_find[kvb-git-orphans-find]
    changelog[kvb-git-changelog]
    hotfix[kvb-git-hotfix]
    git_push[kvb-git-push]
    git_diff[kvb-git-diff]
  end
  subgraph cat_check [check]
    advocate[kvb-check-legal]
    medusa[kvb-check-security]
    sceptic[kvb-check-principles]
    confidence[kvb-check-confidence]
    break_risk[kvb-check-break-risk]
    gate[kvb-check-gate]
    efficiency[kvb-check-efficiency]
    speed[kvb-check-speed]
    score[kvb-check-score]
  end
  subgraph cat_org [org]
    democracy[kvb-org-organize]
    funnel[kvb-org-split]
    coordinate[kvb-org-coordinate]
    subagent_model[kvb-org-perform]
    status_matrix[kvb-org-matrix]
    rasci[kvb-org-rasci]
    artefacts[kvb-org-artefacts]
    wsjf[kvb-org-wsjf]
    robot[kvb-org-robot]
    operator[kvb-org-operator]
    priority[kvb-org-priority]
    evening[kvb-org-evening]
    sunset[kvb-org-sunset]
    sunrise[kvb-org-sunrise]
    radio[kvb-org-radio]
    queue[kvb-org-queue]
    org_update[kvb-org-update]
  end
  subgraph cat_agent [agent]
    agent_optimize[kvb-agent-optimize]
    relax[kvb-agent-relax]
    sleep[kvb-agent-sleep]
    wakeup[kvb-agent-wakeup]
  end
  subgraph cat_skill [skill]
    autotune[kvb-skill-tune]
    autoskill[kvb-skill-auto]
    essence[kvb-skill-essence]
    skill_transcend[kvb-skill-transcend]
    compile[kvb-skill-compile]
    skill_cleanup[kvb-skill-cleanup]
    silence[kvb-skill-silence]
  end
  subgraph cat_none [no category]
    cleanup[kvb-cleanup]
    help_skills[kvb-help]
    transcend[kvb-transcend]
    dream[kvb-dream]
    optimize[kvb-optimize]
    coach[kvb-coach]
  end
  subgraph cat_coach [coach]
    meditation[kvb-coach-meditation]
  end

  commit_req -.-> commit_next
  commit_req -.-> commit_no_verify
  stage_req -.-> confidence
  edit_hook -. council gate .-> democracy
  reminders -.-> dream
  full_hour -.-> coach
  code_task -.-> clean
  code_task -.-> scope_guard
  spawn -.-> subagent_model

  commit_next --> merge_fix
  commit_next --> commit_no_verify
  commit_next --> explain
  commit_next --> dialectic
  issue_close --> confidence
  issue_solve --> issue_close
  issue_solve --> funnel
  issue_solve --> pr_create
  pr_create --> issue_close
  pr_create --> pr_label
  pr_create -. push .-> operator
  update_branches --> active_listening
  update_branches -. conflicts .-> merge_fix
  update_branches -. pushes .-> operator
  commit_no_verify --> clean
  commit_next --> clean
  clean --> sceptic
  clean --> refactor
  commit_no_verify --> advocate
  commit_next --> git_diff
  commit_no_verify --> git_diff
  advocate --> dialectic
  confidence --> break_risk
  confidence --> gate
  pr_label --> gate
  stage_req -.-> score
  score --> confidence
  score --> break_risk
  score --> efficiency
  score --> speed
  speed --> efficiency
  efficiency -. heavy commands .-> queue
  gate --> democracy
  gate --> hotfix
  triage --> hotfix
  democracy --> hotfix
  hotfix --> rasci
  confidence -. objective .-> autotune

  coordinate --> democracy
  cleanup --> democracy
  cleanup --> orphans_find
  branch_gc --> democracy
  orphans_find --> branch_gc
  orphans_find --> choice
  orphans_find --> operator
  funnel --> democracy
  funnel --> dialectic
  funnel --> subagent_model
  dialectic --> subagent_model
  democracy --> merge_fix
  democracy -. claim and release .-> rasci
  funnel --> rasci
  status_matrix --> rasci
  cleanup --> artefacts
  artefacts --> rasci
  democracy --> wsjf
  wsjf --> rasci
  priority --> rasci
  priority -. pins outrank .-> wsjf
  operator --> rasci
  dream --> rasci
  org_update -. newsletter .-> radio

  observe --> triage
  observe --> ci_artifacts
  triage --> ci_artifacts
  triage --> democracy
  triage --> dialectic
  triage --> funnel
  triage --> tune
  tune --> democracy
  tune --> funnel
  tune --> merge_fix
  tune --> dialectic

  dialectic --> active_listening
  criticize --> dialectic
  criticize --> active_listening
  sceptic --> dialectic
  gaps --> sceptic
  gaps --> active_listening
  gaps --> requirement
  requirement --> active_listening
  requirement --> brainstorm
  requirement -. offer .-> plan
  brainstorm --> dialectic

  plan --> robot
  plan --> active_listening
  robot --> dialectic

  dream --> dialectic
  dream --> optimize
  dream --> cleanup
  dream --> orphans_find
  optimize --> skill_cleanup
  optimize --> transcend
  optimize --> autoskill
  optimize --> autotune
  optimize --> compile
  optimize --> essence
  optimize --> refactor
  optimize --> tune
  optimize --> silence
  silence -. peer protocol .-> democracy
  optimize --> agent_optimize
  optimize --> gaps
  agent_optimize -. install .-> operator
  agent_optimize -. domain graphs .-> rasci
  evening -. message .-> relax
  sunset -. message .-> sleep
  sunrise -. message .-> wakeup
  relax --> sleep
  sunset -. hold and accept .-> operator
  sunrise -. hold and accept .-> operator
  sleep -. stops .-> robot
  coach --> active_listening
  coach --> operator
  coach --> rasci
  coach --> meditation
  meditation --> active_listening
  autoskill --> autotune
  autotune --> essence
  transcend --> skill_transcend
  transcend --> code_transcend
  skill_transcend --> active_listening
  skill_transcend --> autotune
  code_transcend --> active_listening
  autotune -. own scripts .-> skill_transcend
  autotune -. deterministic prose .-> compile
  autoskill -. deterministic steps .-> compile
  skill_transcend -. deterministic moves .-> compile
  essence -. procedures .-> compile
  compile --> active_listening
  skill_cleanup --> operator
  skill_cleanup -. unknown skills .-> transcend
  tune -. measurements .-> code_transcend

  test --> triage
  test --> dialectic
  test --> clean
  refactor --> clean

Requirements 📦

  • Node.js (provides npx skills).
  • jq (only required for make update).
  • Python jinja2 for make test (pinned in hub/requirements.txt).
  • Docker with the compose plugin (optional, runs the kvb-hub review hub).

Installation 🚀

Install the skills globally into your home (~/.agents/skills and ~/.claude/skills):

make install

Copy the skills into a specific project (<repo>/.agents/skills and <repo>/.claude/skills):

make project TARGET=/path/to/repo

Both commands also patch the target's .claude/settings.local.json — the machine-local, untracked file, so a project's reviewed .claude/settings.json is never rewritten by an install: the caveman and ponytail plugins are enabled so their modes auto-activate on session start, and two reminder hooks are registered — kvb-dream points each agent at /kvb-dream at most once every twelve hours (stamped per session in ~/.claude/.dream-stamps/), and kvb-coach runs its short form at the first prompt of every full hour, once across all agents (stamped in ~/.claude/.coach-hours/); the global install also enables the kvb-dream-notify.timer systemd user timer, which recommends /kvb-dream in a GNOME notification daily at 17:00 local time and catches up once after a missed run. A PreToolUse gate from the kvb-org-organize skill blocks edits to files in a git worktree until the session holds a claim (skills/kvb-org-organize/scripts/council.py), and its resource watch (skills/kvb-org-organize/scripts/watch.py) measures disk, Docker and caches, cleans up low-risk data and blocks new heavy jobs before the disk runs out; it stays inactive until ~/.claude/agents-council/config.json exists, and because its hooks run that config's commands outside the sandbox, the install adds Edit(~/.claude/agents-council/**) to permissions.deny, which also covers Write in every permission mode. The kvb-org-radio skill registers five hooks: its prompt hook and a PostToolBatch hook deliver the immediate radio (call, broadcast, security, pan-pan, mayday) mid-turn, a Stop hook delivers the post (post, newsletter and call receipts) when the turn ends, an asyncRewake Stop hook wakes an idle session for the radio, and a PreToolUse hook refuses every writing action while a mayday holds, except those of its sender and of the agents that join it with radio.py assist. The PreToolUse hook of the kvb-org-queue skill sends heavy commands through queue.py hold once the config sets queue_enforce, and holds a held command to the settings' Bash deny and ask rules, which see only queue.py hold. The global install also installs the MEDUSA security scanner with pipx for kvb-check-security, unless medusa is already on the PATH. Two hooks of the kvb-org-perform skill (skills/kvb-org-perform/scripts/log.py) log every Agent spawn with its task class, model and effort, and store the quality feedback a sandboxed session prints, in ~/.local/state/agents-council/subagent-model.jsonl. Every hook runs /usr/bin/python3 -I, so neither the python3 of a sandbox-writable virtualenv on the PATH nor PYTHONPATH reaches the hooks, which run outside the sandbox; older bare python3 hook entries are rewritten. The reminder hooks run /usr/bin/bash and pin PATH=/usr/bin:/bin, and the council scripts keep only the PATH directories this uid cannot write (skills/kvb-org-organize/scripts/hookpath.py), so no binary an agent plants on the inherited PATH runs outside the sandbox. Existing settings are preserved.

The global install also runs the kvb-hub, a local review page in which the operator approves or rejects the agents' staged commits (the kvb-git-diff skill): it copies hub/ to ~/.local/share/kvb-hub, starts it there with docker compose up -d --build (restart unless-stopped, bound to 127.0.0.1 only, state in ~/.local/state/kvb-hub) and registers its MCP server for Claude Code at user scope. Its port is KVB_HUB_PORT in hub/.env; the hub page is http://localhost:<port>/, the MCP endpoint /mcp. Without docker the hub is skipped and the commit skills ask in chat. The hub reads new radio traffic aloud in maritime phraseology and takes push-to-talk input; its image builds both engines from pinned, sha256-verified sources and runs each as a separate process: Piper (piper-tts, GPL-3.0-or-later) with the en_US-libritts-high voice (904 speakers, trained on LibriTTS, CC BY 4.0, from rhasspy/piper-voices) and whisper.cpp (MIT) with the multilingual ggml-base-q8_0 model (OpenAI Whisper weights, MIT). The operator's own voice is KVB_HUB_OPERATOR_VOICE in hub/.env.

Without reinstalling the skills, make hub-install installs, builds and starts only the hub, make hub-check checks the installed hub (image, container, logs, HTTP, pinned keys, hook, runner, disk; exit 1 on a failure), make hub-pin CREDENTIAL=<blob> pins the passkey that "Passkey registrieren" shows, make hub-runner enables the runner service, and make hub-hook registers the PermissionRequest hook in ~/.claude/settings.json, replacing an earlier kvb-hub entry and keeping the file mode, after a copy to settings.json.before-kvb-hub-hook (Claude Code reads ~/.claude/settings.local.json only in sessions started in the home directory). Agents that reach the Docker socket are root-equivalent: until the agent VMs of core requirement 093 isolate them, the signatures do not hold against such an agent. make watch-check shows whether the resource watch hook is stuck (running hooks, holders of the kept queue history, age of the stored stage).

The hub is only a relay: every approval of an ask, a staged commit or an operator command is signed end to end with a WebAuthn passkey held in KeePassXC (through KeePassXC-Browser, relying party localhost, origin http://localhost:<port>; ES256, EdDSA and RS256, so a hardware key can be pinned beside it). To register, open the hub at http://localhost:<port>/ (WebAuthn needs the domain; on 127.0.0.1 the page links there), choose "Passkey registrieren" in the settings and run the host command the page shows, python3 ~/.local/share/kvb-hub/client/approval.py pin --port <port> --approvers ~/.config/kvb-hub/approvers.json --credential '<blob>', in a terminal outside every sandbox: it pins the key in ~/.config/kvb-hub/approvers.json with mode 0600, a file no sandboxed agent can write and the hub mounts read-only; the hub never pins. Each approval, or one bulk selection, is one signature over the hashes of every item, a nonce and an expiry; each auto-approval rule is signed once. The executors verify it themselves against the pinned keys and fail closed: the runner (client/runner.py, the kvb-hub-runner user service) runs only signed commands, each signature once, recorded in ~/.local/state/kvb-hub-approvals/runner.json; the PermissionRequest hook (client/permission_hook.py --port <port> --timeout <seconds> --approvers ~/.config/kvb-hub/approvers.json --replay ~/.local/state/kvb-hub-approvals/hook.json) allows only a signed item that matches its own tool, command, cwd and session, else it leaves the decision to Claude Code's own prompt; the commit skills run approval.py verify on the staged tree before committing, else they ask in the terminal. With no key pinned, every executor refuses; decisions and rejections stay unsigned. A signed rule never covers a command holding ;, &, |, a backtick, $, <, >, parentheses or a line break: such a command always asks. The hub page is trusted while it asks for a signature or shows the blob to pin: whoever controls the hub container can show one item and have another signed, or hand over a key of its own. Any local process, sandboxed agents included, can also send the unsigned operator actions (messages, decision choices and rules, board actions, rejections) with the hub's guard headers, and the container reads the host /tmp for the review pages in /tmp/kvb-git-diff. All three close with the agent VMs of core requirement 093, like the Docker-socket gap.

Restart your agent afterwards so it loads the new skills.

Maintenance 🔧

Refresh every skill to its latest version and rewrite skills-lock.json:

make update

Validate skills-lock.json and shellcheck the scripts (also run by CI on every push and after every update):

make test

This collection is part of a wider toolset for managing IT and infrastructure:

  • alias — shell aliases for common commands.
  • package-manager — pkgmgr, a single command to install and manage these repositories.
  • infinito-nexus — automation platform for self-hosted infrastructure.

License 📜

MIT License, Copyright (c) 2026 Kevin Veen-Birkenbach.

Author 👤

Kevin Veen-Birkenbach kevin@veen.world

Thanks 🙏

Thanks to the #ai:infinito.nexus community, and especially to Paulinhx for the inspiration.

Donation ❤️

If these tools help you, consider supporting their development:

S
Description
No description provided
Readme MIT
1.7 MiB
0 Stars 1 Watchers 0 Forks
Languages
Python 80.3%
JavaScript 14.8%
Jinja 2.4%
Shell 1.5%
HTML 0.7%
Other 0.3%