Personal agent skills and slash commands by uz, with a one-line installer that wires them into Claude Code. The skills follow the Agent Skills open standard, so they also work on any conformant tool (OpenCode, Codex CLI, Gemini CLI, Cursor, Copilot CLI, Kiro, and others).
curl -fsSL https://raw.githubusercontent.com/castocolina/ai-kit/main/tools/install.sh | bashor with wget:
wget -qO- https://raw.githubusercontent.com/castocolina/ai-kit/main/tools/install.sh | bashThe installer clones the repo into ~/.local/share/ai-kit, symlinks every skill,
command, and agent into ~/.claude/, and points your status line at the bundled
tools/claude-status-line.py. It is idempotent — re-run it any time to update.
| Name | Type | Use case |
|---|---|---|
ai-kit-spec-review-checklist |
skill | Audit-only reviewer for design/plan documents. Framework-aware (EARS, RFC-2119, Given/When/Then, OpenSpec, Spec Kit, GSD, …). |
ai-kit-spec-review-fixer |
skill | Fixer that addresses each finding from a ai-kit-spec-review-checklist report, in place. |
cst-refactor |
skill | LibCST-based Python codemod helper — multi-file renames and signature changes that survive comments and formatting. |
mermaid-audit |
skill | Render and review Mermaid diagrams embedded in Markdown — syntax, layout, color palette, node shapes, and aspect ratio; emits ready-to-paste classDef fixes and ships a consensus eval that checks the rules are reproducible across agents. |
markdown-to-pdf |
skill | Convert a Markdown document with embedded mermaid diagrams into a PDF (or a marp slide deck) — every ```mermaid block is auto-rendered with mmdc and embedded; auto-selects the best installed backend (Typst/Pandoc, LaTeX, WeasyPrint, Chromium) and never auto-installs. |
ai-kit-cross-ai |
skill | Canonical guide to calling, waiting for and chaining the cross-AI runner, with the caller-owned hard tier and never switching harness, provider or model. |
ai-kit-session-wake |
skill | Arms, checks and disarms a per-session systemd user-timer wake that resumes this exact session id after the orchestrating agent stalls on its own usage limit or its process dies. Not for cross-AI subprocess limits. |
ai-kit-spec-review |
skill | Review-and-fix loop over (runtime, model) pairs: native when the host can select the model, otherwise the supervised runner (claude is review-only). Loops until approved. |
ai-kit-spec-config |
skill | Wizard for the reviewer config: picks (runtime, model) pairs, writes review-spec.toml; a runtime outside the runner table is a trust-gated custom command. |
ai-kit-spec-execute |
skill | Router: detects which framework (GSD, superpowers, …) generated a plan/phase, then delegates execution to that framework's ai-kit-spec-execute-* adapter. |
ai-kit-spec-execute-gsd |
skill | Resolves the best available (runtime, model) pair for a GSD phase, prepares GSD's own .planning/config.json (a native-tier pin, or workflow.cross_ai_command naming the project's supervised runner), then hands off to GSD's own /gsd-execute-phase skill — never subprocess-dispatches GSD itself. |
ai-kit-spec-execute-superpowers |
skill | Resolves a live-quota-checked (runtime, model) pair for each task of a superpowers implementation plan and injects it at superpowers:subagent-driven-development's implementer-dispatch point, leaving that harness's TDD enforcement, review and fix-loop intact. Not for superpowers:executing-plans. |
ai-kit-opencode-providers |
skill | List and remove config-based custom opencode providers from opencode.jsonc without hand-editing JSONC or touching auth.json; remove scans each reviewer's runtime, legacy cli and model. |
ai-kit-project-rules-agents |
skill | Checks an AGENTS.md/CLAUDE.md file against ai-kit's own 20-rule house ruleset, then wraps /agent-md-refactor to remediate gaps. |
ai-kit-project-rules-makefile |
skill | Checks a target repo's Makefile target shape — validate- alias chain, recipe length, Docker build-before-up, shellcheck threshold. Detects and reports only. |
ai-kit-project-rules-precommit |
skill | Checks Makefile↔pre-commit parity (both directions), classifies pre-commit tooling into the 6-category taxonomy, and flags enable-everything configs, missing Duplicate-code/Dead-code tooling, and ruff/golangci-lint anti-patterns. Detects and reports only. |
ai-kit-project-rules-arch |
skill | Checks that a repo's arch-test-shaped Makefile target exists, is chained into test, and (where discoverable) is AST-only rather than importing/executing the module it architecturally checks; states the per-stack canonical-tool baseline. Detects and reports only. |
ai-kit-project-rules-docker |
skill | Checks a target repo's local-dev Docker Compose conventions — the eight-member docker-* Makefile target family, the local-dev runbook, healthcheck timing bounds, depends_on discipline, and hot-reload bind-mount-plus-override wiring. Detects and reports only. |
ai-kit-project-rules-cicd |
skill | Checks that a target repo's CI config (.github/workflows/*.yml/.gitlab-ci.yml) reuses commands already defined in a Makefile target, pre-commit hook, package.json script, or Gradle build task rather than duplicating a tool invocation inline. Detects and reports only. |
ai-kit-project-rules-all |
skill | Runs all 6 ai-kit-project-rules-* checkers (agents, makefile, precommit, arch, docker, cicd) against a target repo and merges their findings into one cross-domain, criticality-ordered report, preserving the AGENTS.md-only /agent-md-refactor hand-off. Detects and reports only. |
ai-kit-gsd-curated-config |
skill | v2-primary GSD config pipeline: inventory, recommend, plan-set/unset, apply (dry-run + backup), the template-8 cross-ai.mjs runner (ensure-runner, --prepend-file guidance, one CLI per call with a configurable soft ladder, no automatic fallback), skill wiring, and grouped follow-ups; kept v1 one-question model_profile path that writes the runner command; pi not live-validated; cursor validated headless (interactive confirmation pending); config keys written only through gsd-tools (a failed apply restores the backup bytes directly). |
ai-kit-gsd-spec-discuss |
skill | Chains GSD /gsd-spec-phase then /gsd-discuss-phase over a phase range in one of two run modes, auto (spec --auto, assumptions-mode discuss) or interactive (discuss with --analyze --all --batch, the user answering), settling gray areas through an optional local → consented-remote → own-reasoning decision ladder that runs through the shared jev-fast-decision client (scripts/decide.py validates summaries and maps the client's per-item trail to per-backend columns, stdlib, consent-gated), with decision logs, a deferred ledger, engine-checked Edge Coverage and a best-over-easy (or mvp_mode) design rule. Works with no decision backend. |
ai-kit-spec-goal-prompt |
skill | Builds a ready-to-paste /goal, /loop or /gsd-autonomous prompt file (one-shot goal, autonomous run) for GSD phases or superpowers plans, with rails, quota directives and e2e-based done. Detects host primitives (labelled verified or unverified), picks one to three strategies, writes a committable file. Never runs the prompt. |
ai-kit-usage-metrics |
skill | Runs the local capture-refine-dashboard pipeline over Claude Code, opencode, Codex, Cursor and rtk session logs, then opens a static, filterable HTML usage-metrics dashboard. Does not export or import data. |
jev-fast-decision |
skill | Shared System One client: one backend table (local Laya, TypeSafe, OpenCode Zen), --probe, one escalation ladder with a per-item trail, a consent record, an answer log, and a dated capability matrix — advisory only. Linked for claude/opencode and pi; codex is a documented gap (~/.agents/skills is shared by other hosts) and cursor is reached through its ~/.claude/skills compatibility read (cited in reference.md, not live-verified). |
ai-kit-judge |
agent | Read-only native judge lane for Claude Code (Opus; Read, Grep and Glob only): follows the given prompt and replies only with what it asks, such as verdict JSON lines. Linked to ~/.claude/agents/ai-kit-judge.md. |
The repo is the source of truth. tools/install.sh:
- fetch — clones (or
git pulls) the repo into~/.local/share/ai-kit; falls back to a tarball download whengitis absent. - verify — enumerates
skills/,commands/, andagents/and validates each entry's shape (skills need aSKILL.md; commands/agents need Markdown with frontmatter). Malformed entries are skipped with a warning. - link — symlinks each valid entry into
~/.claude/<category>/. Existing real files and symlinks that point outside ai-kit are never touched. Thejev-fast-decision,ai-kit-cross-aiandai-kit-session-wakeskills are additionally linked into${PI_CODING_AGENT_DIR:-~/.pi/agent}/skillsfor pi, derived from the same selection (opencode reads~/.claude/skills; nothing is ever linked under~/.agents/skills; codex and cursor have no link — see the skill's reference for their status). A missing pi agent dir is skipped with a message, never created. - prune — removes broken symlinks under
~/.claude/that point into the install dir, so deleting a skill from the repo and re-running cleans up after itself. - statusline — sets
statusLinein~/.claude/settings.jsonto the bundledtools/claude-status-line.py(a backup is written tosettings.json.bak).
Adding or removing skills/commands/agents needs no change to the script — entries are discovered dynamically. The interactive wizard asks before it touches real content at a link path: if a skill path holds a real directory or a foreign symlink, a confirmation gate (default No) offers to back it up into the same XDG-state backups dir and link the repo copy — the same move the headless --replace-existing flag makes, and the backup destination is printed after the wizard exits.
cursor-agents/ holds ai-kit's own Cursor executor subagents, composer-worker and grok-worker, each pinned to an explicit non-fast model id. They stay out of agents/ because that directory links into ~/.claude/agents, where Claude would load an unrunnable pin. The Cursor CLI reads subagents only from a project's .cursor/agents, so automated per-file linking is backlog 999.7. Until then, from a project root link one file by hand: ln -s <ai-kit checkout>/cursor-agents/composer-worker.md .cursor/agents/ (never link the directory; owner decision 2026-10-18).
After the repo is fetched, install.sh launches tools/setup.py — a
full-screen Textual wizard with two surfaces: an install-picks screen
(choose which skills, commands, agents, and example segments to install) and a
2-D layout board (arrange status-line segments visually instead of
hand-editing TOML). You can also reach it directly:
uv run tools/setup.py # interactive install
uv run tools/setup.py reconfigure # reload your current selection + layout
make install # same as install.sh — launches the wizardreconfigure pre-loads your current TOML layout so the board reflects reality
before you make changes.
uv and textual are wizard-only. The status-line render path
(tools/claude-status-line.py) stays plain python3 -S with zero dependencies —
uv/textual are never required at render time and are never installed into
your system Python. On first launch, if uv is missing, the wizard asks
consent and installs it via the official astral installer;
then re-execs itself under uv run so PEP-723 inline deps resolve textual
into an ephemeral environment.
Fail-closed / interactive-only. The wizard requires a real terminal. If
there is no usable TTY, or uv/textual cannot be obtained, or the terminal
is too small to render the TUI, it prints a clear reason and exits non-zero.
There is no plain-menu fallback, and the wizard itself never falls back to
headless defaults — this is deliberate. A separate, explicit
setup.py install --headless exists for CI and containers (see Headless
install below); it is opt-in per
piece and defaults to doing nothing, so it is not a "headless defaults" mode.
A clean Ctrl-C, q, or esc abort leaves the original config intact.
The picks screen includes a HOOKS group with one row per hook knob:
session-briefing, tool-advisor, tool-reminder, decision-probe,
precompact and session-wake. Defaults set the initial checkboxes. Checked rows are installed;
unchecked rows remove that ai-kit hook from every host where it is installed.
The precompact row wires Claude's PreCompact producer and compact
SessionStart injector, plus symlinks the pi extension and experimental
opencode plugin when those host directories exist. The review counts hook rows
separately from components.
| Key | Action |
|---|---|
space |
Toggle the focused pick on (◉) / off (◯) |
a |
Select all |
n |
Select none |
tab |
Go to the Layout Board |
enter |
Go to the summary / confirm |
q / esc |
Cancel — abort, nothing installed |
The board shows segments as chips ([>seg<] = focused). Active segments sit
on numbered lines; inactive ones drop into an off-tray (disabled). Moving
a chip up from the top line sends it to the off-tray; moving a tray chip down
re-activates it onto line 1.
| Key | Action |
|---|---|
← / h |
Move chip left (reorder within a line) |
→ / l |
Move chip right (reorder within a line) |
↑ / k |
Move chip up (or off → off-tray from top line) |
↓ / j |
Move chip down (or tray → line 1) |
space |
Toggle focused segment active / off-tray |
n |
Focus next chip |
p |
Focus previous chip |
tab / esc |
Back to install-picks |
enter |
Go to the summary / confirm |
enter / y confirms and writes ~/.config/ai-kit/claude-statusline.toml
(doctor-validated; auto-reverts a bad write). q / esc aborts. An empty
selection triggers a confirm modal ("install nothing?") defaulting to No
(y to proceed, n / esc / q to go back).
Per-host status-line flow. The wizard walks every detected status-line
host in order — Claude Code first, then the Cursor CLI — and asks each host
its own adoption gate ("Wire your Claude Code status line?", "Wire your
Cursor CLI status line?") before showing that host's layout board ("Arrange
your status line"). Esc on a later host's board steps back to the
previous host's board with its arrangement intact. One Review then lists
every host's writes (each adopted host's TOML plus its wiring file), and Done
reports each host's outcome — one host's failure never blocks the other.
Each host has its own config file: ~/.config/ai-kit/claude-statusline.toml
and ~/.config/ai-kit/cursor-statusline.toml. Declining a host at its gate
skips its board and leaves that host untouched — its TOML is never created
and its CLI config (settings.json / cli-config.json) stays byte-identical.
The board's live preview uses a representative fixture — it cannot show your live session's model/context/cost during a standalone wizard run, so it displays realistic sample values.
What the wizard does not cover. Adding/removing lines and editing per-segment min-width gates must be done by hand-editing the TOML (see Status-line configuration below for colors, ramps, and palette). The TOML file remains the authoritative source; the wizard writes standard TOML that you can continue to edit by hand.
The status line works with zero config. To customize it, edit
~/.config/ai-kit/claude-statusline.toml (the installer drops a fully-commented
starter there if you don't have one — as shipped it changes nothing). Settings
resolve built-in defaults < this file < environment variables.
Toggle segments — in the file:
[segments]
alt_cost = true # show the 🪙 cost segment (off by default)
alt_system_memory = false # hide the 🧮 process-memory segment
render_time = false # ⏱ hide the render-time mark (on by default)Segment keys follow a domain-family / dispensability scheme: a git_ or
system_ prefix names the domain, and an alt_ prefix marks a dispensable
segment (dropped first when the line is tight). The pre-2026-06 bare names
(cost, memory, branch, dirty, worktree, clock, time_ago,
total_time, api_time, dimensions) still load — each is
forwarded to its new key with a one-time deprecation note, in both the TOML and
the CC_AI_KIT_SEGMENT_<KEY> env form.
Diagnostic segments:
render_time(⏱, on by default) — how longclaude-status-line.pyitself took to run, from process start to render (the cost of itsgit/process/file probes), shown adaptively asns/µs/ms/s. This is the status line's own wall-clock — distinct fromalt_time_session(💬) andalt_time_api(📡), which report Claude's session and API durations from the input JSON. Its color is an SLO/SLA signal driven by the[ramp.render_time]ramp: green within the 50 ms SLO, yellow up to the 150 ms SLA, red+bold beyond (all configurable). Setrender_time = false(orCC_AI_KIT_SEGMENT_RENDER_TIME=0) to hide it.alt_term_dimensions(off by default) — the terminal size ascols×rows(?when the size had to be assumed). Enable via[segments]orCC_AI_KIT_SEGMENT_ALT_TERM_DIMENSIONS=1.
…or per-session via env (wins over the file):
CC_AI_KIT_SEGMENT_ALT_COST=1 # 1 true t y yes on / 0 false f n no offWorktree segment — alt_git_worktree (⎇, on by default) names the active
linked git worktree the session sits in, never a list: ⎇ <name> (the worktree
directory basename, truncated to 20 columns). On the main checkout it shows a
dimmed, struck-through ⎇ wt placeholder; outside any git repo it's hidden. The
git_branch segment shows only the branch — worktree state lives entirely in this
segment. Toggle it like any other segment ([segments] alt_git_worktree = false, or
CC_AI_KIT_SEGMENT_ALT_GIT_WORKTREE=0).
Rate-limit segments — split into alt_h_rate_limit (5-hour bucket) and alt_w_rate_limit
(7-day bucket), both off by default. Each renders {Nh|Nd}: {pct}% and degrades to that bare
form when space is tight; with room, the hourly segment adds a time-only reset stamp
(5h: 42% (↺ 14:10) — never a date, since a 5-hour window can't cross into a different day), and
the weekly segment adds a weekday + time stamp (7d: 13% (↺ Sun 14:10)). Color is an absolute
pace gap: |used% − elapsed%| in percentage points — ≤5 green, under 11 yellow, ≤15 orange, more
red. In the rich tier the percentage carries a pace sign: + when usage is at or behind the
window clock (under pace — 5h: +0% early in a window), - when it burns faster than the clock
(5h: -60% with 60% used and only 45% of the clock gone). The dead [ramp.rate] band was
removed: nothing read it, and a leftover [ramp.rate] block now reports an unknown-ramp
warning. An unreliable window (missing/past resets_at, clock skew) paints the
percentage white with no pace sign. In the diagnostics row,
alt_h_rate_limit sits to the left of alt_w_rate_limit, so the weekly segment is always the
first of the two dropped under column pressure.
chat_size vs context — these answer different questions. chat_size (💾) reads the
transcript .jsonl on disk, which is append-only and never shrinks — even a /compact only
adds a boundary marker + summary to the file, it never removes anything. So chat_size shows
bytes accumulated since the last compaction (falling back to the full total when there hasn't
been one yet), plus the total and how many compactions have happened once there's been at least
one: 313KB/4.1MB (3x) — narrower terminals drop to just the "since" figure. context (📊,
seg_context) is a different segment, unaffected by this: it reads Claude Code's own live
context_window.used_percentage, which already reflects the real, current context sent to the
model on the next turn. Use chat_size to gauge how much has piled up since your last compaction;
use context for what's actually in play right now.
Shared git probe + cache TTL — git_branch, git_dirty, and alt_git_worktree
read from one shared git probe (no duplicate querying). git_dirty is always read
fresh; the worktree rev-parse is cached (default 5 s) because it rarely changes.
Tune the cache:
[git]
cache_ttl = 5 # seconds the worktree probe is cached…or per-session: CC_AI_KIT_GIT_CACHE_TTL=10 (wins over the file). A legacy
[git] worktree key (and the old CC_AI_KIT_GIT_WORKTREE env) is silently
ignored — worktree display is now the alt_git_worktree segment.
Performance note — disabling a segment skips its work, not just its
display. On a very large repository, turning off git_dirty also skips git's
untracked-file scan (the slow part of git status); turning off alt_git_worktree
skips the rev-parse; turning off todo skips the task-state read. The status
line reads task/todo state from Claude's on-disk state, not by re-parsing the
transcript, so it stays fast as sessions grow.
Reorder / move rows — uncomment all [[line]] blocks and edit (layout
is all-or-nothing; a partial layout would silently drop segments):
[[line]]
min_rows = 0
segments = ["path", "git_branch", "alt_git_worktree", "git_dirty", "todo"]Recolor segments — colors are configured in the TOML file only (there is
no CC_AI_KIT_* override for palette or ramps, unlike the scalar settings
above). A color value is one of:
| Form | Example | Notes |
|---|---|---|
| palette NAME | RED, BLUE |
one of the named colors in [palette] |
| raw SGR params | 38;5;208 |
advanced; the part between ESC[ and m |
| hex color | #3399ff |
#rgb / #rrggbb / #rrggbbaa (alpha byte dropped) |
Any form may carry +bold / +dim / +italic / +underline modifiers, e.g.
RED+bold, #3399ff+bold. (Hex needs a truecolor terminal; italic/underline
rendering is terminal-dependent.)
[palette] MERGES over the defaults — override only the names you list (e.g.
pick a different blue):
[palette]
BLUE = "#3399ff"[ramp.*] REPLACES the whole ramp — you must list every band you want. A
ramp maps a value to a color by ascending threshold (first band the value is
strictly below wins). Threshold keys are percent integers for context and
rate, k/M/G byte suffixes (1024-based, quoted) for chat_size,
ns/µs/us/ms/s time suffixes (quoted) for render_time, and inf
for the final catch-all band:
[ramp.context]
20 = "BLUE"
50 = "RED+bold"
inf = "MAGENTA_DARK+bold"See tools/claude-statusline.toml.sample for the full default palette and ramps.
Inspect & validate: the render module claude-status-line.py is intentionally silent
— it never writes to stderr. All validation (bad config values, unknown keys,
bad env overrides) is surfaced by tools/statusline-doctor.py, which diagnoses
one status line at a time via --host claude|cursor (default claude):
python3 tools/statusline-doctor.py --print-config # resolved config as JSON (incl. ramps)
python3 tools/statusline-doctor.py --check # validate file + env overrides
python3 tools/statusline-doctor.py --doctor # validate + dry-render every segment
python3 tools/statusline-doctor.py --help # full env-var list for the selected host
python3 tools/statusline-doctor.py --host cursor --doctor # diagnose the Cursor CLI line insteadEnvironment variables: CC_AI_KIT_CONFIG_FILE (config path),
CC_AI_KIT_SEGMENT_<KEY> (per-segment toggle); the Cursor host uses the
AI_KIT_CURSOR_* names instead (see --host cursor --help). The Cursor
doctor also reports the quota fetch status, always labeled
inferred — undocumented Cursor API, and may attempt one foreground quota
refresh — save-time validation and previews never fetch. Requires Python 3.11+
for the TOML file; on older Python the file is ignored and only env toggles apply.
ai-kit renders a second, separate status line for the Cursor CLI (the
cursor-agent host) — its own entry, config and quota source, sharing only the
segment-layout and colour machinery with the Claude line. tools/setup.py install
and install.sh wire it next to the Claude one (--with-statusline=cursor picks
it alone; see Headless install).
- What it renders: working path, git branch + dirty count, model, context
remaining, and the quota group — included spend, API spend, on-demand/extra and
the reset time. Layout and colours come from
~/.config/ai-kit/cursor-statusline.toml(override the path withAI_KIT_CURSOR_CONFIG_FILE, toggle a segment withAI_KIT_CURSOR_SEGMENT_<KEY>); layout alternates (worktree path, render time, slowest segment, terminal size) are off by default. With no file the Cursor line renders ai-kit's defaults, andtools/cursor-statusline.toml.sampleis the starter to copy by hand — or adopt the Cursor host in the wizard, which writes and doctor-validates that TOML for you. See that sample andpython3 tools/statusline-doctor.py --host cursor --helpfor the full key and env list. - Quota is an inference, always marked as one. Cursor documents no quota API
for its CLI; the numbers come from ai-kit's own cache of the undocumented Cursor
Dashboard usage endpoint, refreshed by a detached helper — the render path
only reads that cache and never waits on the network. Every figure therefore
prints with a leading
≈and the doctor reports it asinferred — undocumented Cursor API.≈*means the cache is stale: the last refresh failed or never ran, so the number shown is the old one. - Where its config file lives:
cli-config.jsonunder the first Cursor directory that applies — a non-blankCURSOR_CONFIG_DIR, then$XDG_CONFIG_HOME/cursor, then~/.cursor; a blank or whitespace-only override falls through exactly like a missing one. Wiring writes thestatusLinekey and nothing else: unrelated keys and other top-level entries stay exactly as they are, and the fields Cursor owns (padding,updateIntervalMs,timeoutMs) are preserved when ai-kit's own entry is refreshed. An existing foreignstatusLineis shown and confirmed away interactively (default No) and refused headless — it is never replaced silently, and a concurrent change to the entry between the read and the write aborts the write. Known gap: acli-config.jsonthat carries JSONC comments is left completely untouched (a warning names the file and the run exits 1) — ai-kit's writer emits plain JSON and would delete those comments, and Cursor itself writes plain JSON, so this stays unread rather than rewritten lossy. Detection does read through comments, so the reported state is still accurate. - Unwiring is per host:
uninstallremoves ai-kit's entry from~/.claude/settings.jsonand fromcli-config.jsonindependently, matching the exact script argument rather than a substring, leaving the other host's file and both config TOMLs untouched.
Add a status-line segment without editing claude-status-line.py: drop an executable
into ~/.config/ai-kit/segments/ (override with CC_AI_KIT_EXTERNAL_DIR or
[external] dir). It is discovered on the next render, enabled by default,
and placed via a header in its first 10 lines:
# ai-kit-segment: line=<N> (after=<key>|before=<key>|start|end) [id=<slug>] [timeout=<s>] [ttl=<s>]
Defaults: line = last row, position = end, id = filename stem,
timeout = 2s, ttl = [external] ttl (10s).
Input. The provider receives the same status JSON Claude passes, augmented
with a segment block, on stdin — and the key scalars mirrored as env vars
so a shell one-liner needs no JSON parser:
{ "...": "normal status fields",
"segment": { "id": "aws", "avail_cols": 24, "line": 2, "position": "after:alt_time_clock" } }AI_KIT_SEGMENT_COLS, AI_KIT_SEGMENT_ID, AI_KIT_SEGMENT_LINE,
AI_KIT_SEGMENT_POSITION. The provider runs with cwd = the workspace directory.
Output. Print one line. SGR color escapes (\033[…m) are kept; any other
control sequence is stripped. Size it to AI_KIT_SEGMENT_COLS (long → medium →
short) — or print nothing to omit the segment. The core truncates as a safety net
and never lets an external push out a pinned segment. Output is cached per id
for ttl seconds (ttl=0 re-runs every render).
Worked example — AWS session expiry (~/.config/ai-kit/segments/aws-session):
#!/bin/sh
# ai-kit-segment: line=2 after=alt_time_clock id=aws-session ttl=30
left=$(your-aws-expiry-command) # e.g. "4h 44m 12s"
cols=${AI_KIT_SEGMENT_COLS:-80}
if [ "$cols" -ge 14 ]; then printf '\033[33m🔐 %s\033[0m\n' "$left"
elif [ "$cols" -ge 8 ]; then printf '\033[33m🔐 4h44m\033[0m\n'
elif [ "$cols" -ge 4 ]; then printf '\033[33m🔐4h\033[0m\n'
fi # else: nothing -> droppedA cross-platform Python reference (system available memory) ships at
examples/segments/system_memory — copy it as a starting point.
The installer offers to set these up for you. On an interactive install,
the wizard discovers every provider under the repo's examples/segments/,
presents them pre-checked (default-ON), and copies the ones you keep into
your config segments dir (executable, atomic, idempotent — re-running never
duplicates). Scripted runs are governed entirely by a flag and never prompt:
--examples=all|none|<ids> (<ids> is a comma/space list of segment ids). The
default differs by entry point: install.sh / make install default to all,
while python3 tools/setup.py install --headless installs no example
segments unless you pass --examples explicitly — nothing is wired or copied
headlessly unless asked. See "Headless install (CI / containers / no TTY)" below
for the full non-interactive flag set (--skills, --with-statusline,
--with-hooks). Disable an installed provider later like any segment:
[segments] system_memory = false.
Disable a provider explicitly: [segments] aws-session = false (or
CC_AI_KIT_SEGMENT_AWS_SESSION=0).
Trust model. Providers are arbitrary executables. ai-kit only ever installs
the bundled examples shipped in this repo, and only on your explicit opt-in
(the pre-checked offer, or --examples); it never fetches or runs remote code.
Anything else is something you place in your own directory. Keep them fast and
single-line. A failing, slow (past timeout), or empty provider is simply omitted.
install.sh --dry-run # show what would change, mutate nothing
install.sh --uninstall # remove ai-kit symlinks, statusLine and hook entries (keeps the install dir)
python3 tools/setup.py uninstall --hooks=tool-advisor,precompact # remove only selected hook rows/links
install.sh --examples=all|none|<ids> # which bundled example segments to install (default: all)
install.sh --branch <name> # fetch a specific branch (or --branch=<name>; fork via AI_KIT_REPO)
install.sh reconfigure # re-open the wizard pre-loaded with your current selection + layout--uninstall unwires each status-line host separately — it removes ai-kit's
statusLine from ~/.claude/settings.json and from the Cursor cli-config.json
only when that entry is ai-kit's own (exact script argument, not a substring),
never a foreign one, and never touches the other host's file while doing it. Both
config TOMLs stay in place. It exits 1, naming the file, when a Claude Code or
Cursor settings file could not be read or rewritten, so ai-kit may still be wired
there; fix the file and re-run it.
Try a branch without merging it. --branch <name> (or --branch=<name>, or the
AI_KIT_BRANCH env var) is consumed by the bootstrapper (not passed to the wizard) and overrides
which branch is fetched. It applies only when install.sh fetches (piped from curl/wget); run from a
local checkout it is ignored with a note. On an existing clone at the install dir, an explicit
branch runs this sequence:
git check-ref-format --branch Brejects a malformed name.- It refuses when the tree is dirty,
git statusfails, or a.git/index.lockis left over from an interrupted run, naminggit -C <dir> statusto inspect it. It never auto-recovers. - It refuses when local
Bhas commits that nooriginbranch has (checked before fetching, because a--depth 1fetch hides older history). --dry-runprints the remaining steps and stops here.git ls-remote --exit-code --heads origin Brefuses a branch that is not onorigin.git remote set-branches --add origin B, skipped when that refspec is already configured.git fetch --depth 1 origin B, thengit switch -C B --track origin/B. If either fails, the refspec added in step 6 is removed again.
The default main never triggers a switch: with no explicit branch an existing clone runs
git pull --ff-only origin <current branch>, and refuses on a detached HEAD. Naming the branch
means a refspec left over from a branch deleted upstream cannot break the update.
--dry-run mutates nothing on any path: it prints the planned git commands (the sequence above,
the pull, or the clone/tarball command) and runs no fetch, pull, switch, set-branches, clone or
download, including over an earlier tarball (non-git) install. On an existing install it still
hands --dry-run to the wizard; on a not-yet-fetched bootstrap it stops before running setup.py.
A fork is selected with the AI_KIT_REPO env var (default castocolina/ai-kit) for a new clone or
tarball download. An existing clone fetches from its own origin, and install.sh prints a note
that AI_KIT_REPO is ignored.
One catch: the install.sh you pipe must itself be a flag-aware version — --branch only exists
in install.sh from a branch that has it (or from main once it's merged there). So to bootstrap a
not-yet-merged branch, fetch its install.sh from that same branch:
# install branch feat/x from the canonical repo (its own install.sh understands --branch):
curl -fsSL https://raw.githubusercontent.com/castocolina/ai-kit/feat/x/tools/install.sh \
| bash -s -- --branch feat/x
# from a fork: pipe the fork's branch install.sh and point the clone at the fork via env:
# curl -fsSL https://raw.githubusercontent.com/you/ai-kit/feat/x/tools/install.sh \
# | AI_KIT_REPO=you/ai-kit bash -s -- --branch feat/x
# once --branch is on main, any branch works via the main install.sh:
# curl -fsSL …/ai-kit/main/tools/install.sh | bash -s -- --branch feat/xSimplest of all, no flag and no gotcha — clone the branch and run the local install (it skips the fetch and uses the checked-out files directly):
git clone -b feat/x https://github.com/castocolina/ai-kit && cd ai-kit && make installpython3 tools/setup.py install --headless skips the interactive wizard
entirely — no TTY, no Textual. Bare --headless links and wires nothing (a
pure no-op). Combine with the flags below to opt into specific pieces —
nothing is touched unless explicitly requested:
-
--skills all— link every skill (or--skills name1,name2for a subset). Additive only: never unlinks a skill already present from a prior run. Ajev-fast-decision,ai-kit-cross-aiandai-kit-session-wakelinks are mirrored into the pi agent skills dir (${PI_CODING_AGENT_DIR:-~/.pi/agent}/skills) when their claude link is made. -
--replace-existing— (requires--headless --skills) move a real directory or foreign symlink standing at one of the named skills' link paths into${XDG_STATE_HOME:-~/.local/state}/ai-kit/backups/<claude|pi>/<name>.bak-<timestamp>/(outside every scanned skills dir) and link the repo copy in its place. Without this flag such content is left alone with a warning and the run exits 1. -
--with-statusline— wire the ai-kit status line on every detected host, Claude first and then Cursor (--with-statusline=claude,cursorselects hosts explicitly). A host is "detected" by its config directory:~/.claude(orCLAUDE_CONFIG_DIR) and the Cursor config dir below. With neither directory present the run says there is nothing to wire and still exits 0; ai-kit never conjures a~/.claude/or a Cursor config dir on a machine that has no such host.--with-statusline=<hosts>fails before any write happens — no migration, no backup, no link, no hook, no example, no config file: an unknown name (--with-statusline=bogus) is a usage error (2), a valid name whose host isn't installed (--with-statusline=cursorwith no Cursor dir) prints one message and exits1. A foreignstatusLineis never replaced headless — that needs the interactive wizard's explicit yes — so such a run exits1and leaves the file untouched. -
--with-hooks— bare form wires every default-on hook knob, including the two per-call advisors; this is a behavior change from the briefing-only default. Defaults:session-briefing,tool-advisorandtool-reminderon;decision-probeoff;precompactfollows each host's recorded verdict.--with-hooks=<id[:host],...>(for example--with-hooks=tool-advisor) is additive: it only adds the named hooks and never removes existing ones. The six ids are documented here:Id What it does Hosts Default session-briefingInstalled-tool briefing to user/model Claude Code, Cursor on tool-advisorAdvice for grep/cat/sed/find and large reads Claude Code, pi; Cursor gap; opencode gap pending S-OC on tool-reminderOutput-size reminder with a better installed tool Claude Code, pi; Cursor gap; opencode gap pending S-OC on decision-probeReports usable decision backends Claude Code off precompactDecision-system pre-summary before compaction Claude Code, pi, experimental opencode Per recorded host verdict session-wakePasses a usage-limit reset to an armed session wake (experimental) Claude Code off python3 tools/setup.py uninstall --hooks=<ids>removes only those hook ids (comma-separated, with optional:hostselectors). Claude Code settings are wired per event; pi extensions and opencode plugins use symlinks. Absent hosts are skipped. The pre-summary fails open without blocking compaction. -
--examples=all|none|<ids>— the same pre-existing flaginstall.shand the interactive wizard use for bundled example segments; it works identically here, with or without--headless.
Example: python3 tools/setup.py install --headless --skills all --with-statusline --with-hooks --examples all
(same thing host-by-host: --with-statusline=claude,cursor)
Exit codes: 0 success (including "nothing requested" and "that host isn't
installed here"), 1 something you asked for did not happen — a config file
ai-kit refuses to overwrite because it cannot parse it, a foreign statusLine
it will not replace without a human saying yes, a skill whose link path is
occupied by a real file or a non-ai-kit symlink, or a failed example-segment
copy. 2 is a usage error (bad flag combination, or the interactive path
finding no TTY). A 1 leaves every other requested step still attempted.
This does not fetch or update the repo. --headless is a flag to
tools/setup.py, which never syncs anything itself — syncing is
tools/install.sh's job, and only in piped/bootstrap mode (curl ... | bash).
Running install.sh (or make install) from an existing local clone, or
invoking tools/setup.py directly as above, explicitly skips the fetch. For
a CI/container job that needs the latest kit, fetch or git pull the repo
yourself first, then run tools/setup.py install --headless ... against it —
or pipe the bootstrapper fresh each time if you want the fetch included:
curl -fsSL .../install.sh | bash -s -- install --headless --skills all.
Wizard modes. The interactive wizard requires a real terminal and a
sufficiently large window (see The install wizard above).
If either is missing, install.sh/make install exits non-zero with a clear
message — there is no plain-menu fallback inside the wizard itself. For a
fully non-interactive run instead, use python3 tools/setup.py install --headless (see "Headless install (CI / containers / no TTY)" above) — its
flags are the one non-interactive contract: --examples=all|none|<ids>
controls which example segments are copied (identically whether or not
--headless is also passed — it is a pre-existing top-level flag), and
--skills/--with-statusline/--with-hooks (headless-only) control
everything else the wizard would otherwise ask about interactively.
Environment overrides: AI_KIT_DIR, AI_KIT_REPO, AI_KIT_BRANCH, CLAUDE_CONFIG_DIR,
CURSOR_CONFIG_DIR.
Re-run the install command (or git -C ~/.local/share/ai-kit pull). New entries
are linked, removed ones are pruned, and skills re-read on next invocation.
The entry and sample were hard-renamed, with no compatibility shim. After fetching an update and before setup runs, an existing status line may be blank. Re-run setup or the installer: the migration rewrites only a recognized Python interpreter command whose exact script argument is ai-kit's old entry; data arguments, backup suffixes, other scripts and shell commands remain untouched. It moves the old TOML only when the new TOML is absent. If both TOMLs exist, neither is changed; merge them by hand.
Skill discovery follows the Agent Skills
spec — every conformant tool reads the name/description frontmatter from each
SKILL.md. For non-Claude tools, clone this repo into the tool's skills directory:
git clone https://github.com/castocolina/ai-kit ~/.opencode/skills/ai-kit # OpenCode
git clone https://github.com/castocolina/ai-kit ~/.gemini/skills/ai-kit # Gemini CLIai-kit-spec-review is a skill (not a slash command), so it is portable: on any
Agent-Skills-conformant tool its orchestrator logic in
skills/ai-kit-spec-review/SKILL.md is discovered and can be followed directly.
Session-start hooks in tools/hooks/ inject a live
briefing of which curated rtk substitutions are actually on PATH. Claude Code
and Cursor are wired. The same directory documents the pre-summary hook, which
uses the local decision backend to classify context before compaction.
tools/setup.py --config-doctor opens a read-only Checks Catalog for Claude
Code, opencode, Codex, and Cursor — retention, sandboxing, telemetry, and
permission settings across whichever of those runtimes have a config file on
this machine, plus a cross-runtime rtk-Cursor-integration check. A handful of
rows can be applied one at a time, each behind an explicit confirm screen that
shows the literal resulting config for security-relevant settings; there is no
bulk-apply.
ai-kit/
├── .claude-plugin/plugin.json # Claude Code manifest (other tools ignore)
├── README.md
├── skills/ # one directory per skill, each with SKILL.md
├── commands/ # one Markdown file per slash command
├── tools/
│ ├── install.sh # the installer above
│ ├── claude-status-line.py # responsive Claude Code status line
│ └── hooks/ # session-start substitution briefing
└── tests/ # test_install.sh, test_status_line.py
The shipped tools stay stdlib-only — tools/claude-status-line.py runs under the
user's own python3 with no dependencies. The lint/type toolchain below is
dev-only and never required at runtime.
make dev # uv sync + install pre-commit hooks (sets up the dev env)
make test # full suite in parallel, one subprocess per module, through tools/run_unittest_parallel.py (system python3 for the unit group)
make lint # shellcheck + py-compile hooks (pre-commit, all files)
make validate # the full quality gate (see below)The quality gate is pre-commit. .pre-commit-config.yaml is the single
source of truth: make validate runs each hook via the Makefile's per-tool
targets (same hooks as commit-time: ruff, pylint, pyright, vulture, shellcheck,
py-compile, unittest). Ruff, py-compile, pyright and vulture cover every shipped
Python file under tools/, skills/ and tests/; pylint covers tools/ and
skills/. Tool versions are pinned in uv.lock; make dev installs the hooks
so commits are gated even if you skip make validate. Run it once after cloning:
make dev # then commits are automatically gated- All
SKILL.mdfiles use the base Agent Skills frontmatter (name,description). No Claude-only fields, so the skills run unmodified on every conformant tool. - The
cst-refactorskill ships its template ascodemod_template.py.txt;SKILL.mdcopies it into the project astools/codemod_template.pyfrom the skill's own directory on any host (Claude Code:${CLAUDE_PLUGIN_ROOT}/skills/cst-refactor).
MIT.