Portable dotfiles and Claude Code configuration. Clone to ~/.setup on any machine to get a consistent environment.
- install.sh — New-machine bootstrap: installs tooling and links Claude config (see below)
- omp-setup.sh — Installs and configures omp (oh-my-pi) against the Brev-hosted model endpoint (see below)
- pi-setup.sh — Same, for the pi coding agent; one-liner installable (see below)
- codex-setup.sh — Adds Webster models alongside OpenAI models in Codex CLI and Codex Desktop through a localhost-only proxy (see below)
- test.sh — Isolated negative tests for the installers, run by CI and safe to run locally
- STYLE_GUIDE.md — Required validation, portability, and agent-compatibility rules
- AGENTS.md — Codex repository instructions that reference the shared style guide
- CLAUDE.md — Claude Code instructions that reference the shared style guide
- claude/statusline.sh — Claude Code status line showing session id and context usage (see below)
- webshell/ — Browser terminal (ttyd + tmux) with persistent sessions, clickable tabs, and copy-to-clipboard (see below)
- .agent/skills/ — Custom agent skills (brev-cli, cluster-ops, inference-optimization, brev-hermes-agent, skill-creator, etc.)
- setup.md — Shell/zsh prompt configuration notes
One line to install everything and link the Claude config:
curl -fsSL https://raw.githubusercontent.com/theFong/setup/main/install.sh | bashThis installs Claude Code, Codex CLI, Brev CLI, Hugging Face CLI, opencode,
tmux, git, gh, jq, ripgrep, fzf, wget, curl, htop, Go, and Ookla speedtest,
then clones this repo to ~/.setup and symlinks the Claude config into
~/.claude. It works on macOS (Homebrew) and Linux (apt/dnf/apk), and is safe
to re-run — anything already present is skipped.
Each install is verified twice: the expected command must be on PATH, and the
CLIs this bootstrap exists to install must actually execute (assert_runs
invokes each one's version command, since a truncated download or a
wrong-architecture build still satisfies command -v). The bootstrap continues
attempting the remaining tools after a failure, then exits nonzero if anything
is still missing or does not run.
The repo-managed skills (brev-cli, cluster-ops,
inference-optimization, and brev-hermes-agent) are linked into Claude
Code (~/.claude/skills),
Codex (~/.codex/skills), and the shared agent skill directory
(~/.agents/skills). Existing skill installations are preserved. Each path is
then checked to resolve to a readable SKILL.md — a dangling symlink would
otherwise satisfy the create-if-absent guard and leave every agent silently
without the skill — along with every reference/ document that SKILL.md links,
and the cluster-ops discovery script is run in self-test mode against the local
machine. So a skill that reached only one agent, arrived without the reference
docs it defers to, or ships a probe script broken on this platform, fails the
bootstrap instead of surfacing later.
- brev-cli — manage GPU cloud instances.
- cluster-ops — cluster onboarding and portable fleet diagnostics.
- inference-optimization — diagnose and tune LLM inference throughput,
single-node or multi-node. Leads with GPU hardware validation, because a
throttled GPU makes every software measurement meaningless (see the skill's
reference/for a case study where identical GPUs differed 7x). Also covers sizing a model against the KV-cache budget, tensor-parallel and NCCL pitfalls, and validating that tool calling survives every hop to the client. - brev-hermes-agent — build a Hermes Agent on a Brev instance end to end: provision the VM in the region you actually want (the CLI cannot set one), install Hermes, point it at a self-hosted OpenAI-compatible model, expose the web UI behind SSO and a firewall, connect Telegram, write skills, and schedule jobs. Leads with the failure modes, because nearly all of them are silent — the installer "succeeds" having done nothing, the model rejects a key you never set, and a skill in the wrong directory is invisible to the agent while looking installed.
It also sets Claude Code's default permission mode to auto mode by writing
"permissions": {"defaultMode": "auto"} into ~/.claude/settings.json
(merged, never clobbering other settings; the legacy top-level defaultMode
key written by older bootstraps is removed since Claude Code does not read the
mode from there). To undo, set it to "default"; to only auto-accept
edits, use "acceptEdits"; for full skip-all-prompts mode, use
"bypassPermissions".
Codex gets the equivalent Auto approval preset by writing top-level
approval_policy = "on-request" and sandbox_mode = "workspace-write" into
~/.codex/config.toml: Codex works autonomously inside a workspace-write
sandbox and only prompts to escalate. The keys are inserted above any
[table] section (top-level TOML keys must precede table headers); everything
else in the file is preserved. To undo, delete both keys; for full
skip-all-prompts mode, use approval_policy = "never" with
sandbox_mode = "danger-full-access".
After it finishes, open a new shell so PATH changes take effect. Run claude
or codex to sign in, brev login to authenticate Brev, and hf auth login
to authenticate Hugging Face.
Claude Code has no built-in setting to always show the session id or context
usage, but it pipes both to the status line command, so the bootstrap points
statusLine.command at ~/.setup/claude/statusline.sh:
Opus 5 · ~/setup · ctx 24% (248k/1M) · 2fa86bc7-74ec-4c0d-bcd4-12cdb70798be
Model, working directory, context-window usage, and the full session id — full
rather than shortened so it can be pasted into claude --resume <id>. The
percentage turns yellow at 50% and red at 80%. Older Claude Code versions that
do not send context_window just drop that segment, and the line stays empty
rather than erroring if jq is missing.
Edit claude/statusline.sh to change what it renders; the bootstrap verifies
on every run that the script is wired into ~/.claude/settings.json and that
it actually renders a sample payload. Delete the statusLine key from
~/.claude/settings.json to undo. Like the permission mode above, this is
Claude Code-specific — Codex CLI has no status line hook. The equivalent Codex
workflow is codex resume, whose session picker (or --last) selects a past
session without needing the id in front of you.
A tmux-backed terminal in the browser: sessions survive refresh/disconnect
(and their layout survives reboots), the status bar acts as clickable tabs
(+ new shell / ✕ close, double-click to rename), and highlight-to-copy
lands on your local clipboard via OSC 52.
~/.setup/webshell/install.sh # private (default): 127.0.0.1 + password
~/.setup/webshell/install.sh --public # bind wt0 (Netbird), no password — needs an auth proxy in frontPrivate (default) binds 127.0.0.1:7681 with a generated password
(printed once); reach it with ssh -L 7681:127.0.0.1:7681 <host> →
http://localhost:7681. Public binds a mesh/private interface (default
wt0) with no password and assumes an authenticating HTTPS proxy in front —
don't use it without one. Flags: --iface, --port, --session,
--force-build; env: WEBSHELL_*. --verify-only health-checks an existing
install (service active, HTTP serving, auth enforced, the deployed unit still
matching the intended mode/interface/port, KillMode=process present, and
session restore actually working) and exits nonzero on failure — CI runs it,
and it works as a cron/liveness probe too.
Notes baked into the setup (hard-won):
- ttyd is built from source — release/apt builds bundle an xterm.js without the OSC 52 clipboard handler, so copy silently fails.
- tmux 3.2a never emits OSC 52 itself (even with
Ms/terminal-features set); copy bindings pipe throughwebshell/tmux-clip, which writes the escape straight to the client tty. - Clipboard needs a secure context (https or localhost) and the page focused.
~/.tmux.confis symlinked towebshell/tmux.conf.- Reboots restore your windows macOS-Terminal-style: tmux-resurrect +
tmux-continuum (via tpm) auto-save layout, working dirs, and visible pane
text every 15 min and replay them when the tmux server next starts —
ttyd.servicestarts one on connect, so just reopen the webshell. Processes are not resumed; panes reopen as fresh shells. Manual save/restore:prefix + Ctrl-s/prefix + Ctrl-r. ttyd.serviceusesKillMode=process: restarting/upgrading ttyd only bounces the browser connection — the tmux server (your shells) survives. Continuum only auto-saves/restores when its server is the machine's sole tmux server, so scratch servers on other sockets don't clobber saves.- Re-running the installer keeps the deployed mode, interface, and port
unless you pass
--private/--public(orWEBSHELL_*) explicitly. - Tab groups (tmux sessions) are mouse-driven: a second status row lists the groups with the current one highlighted. Click it (or any empty area of the tab row) for the groups picker — switch / new / rename / close. Click the tab you are already on to rename it, close it, or move it to another group; clicking any other tab just switches to it. Wheel over the bar cycles groups. Everything is reachable by left click: browsers hijack right-click before the terminal sees it.
- The pickers are
display-popup+fzf, not tmux'sdisplay-menu, and that is not cosmetic: a tmux menu is dismissed by any pointer-motion event, and xterm.js reports motion with no button held — so in a browser the menu vanishes as soon as you move the mouse toward it. A popup is a real pane, so motion goes to the program inside it (choose-treewas measured too and dies the same way). Inside the popup you get a real tty, so fzf handles mouse clicks and wheel, and prompts are plainread. Both helpers--printtheir labels so the installer andtest.shcan check the UI headlessly. - File browser/viewer:
prefix + f, or click the bar and pick📁 browse files…. Opens in the current pane's directory with a live preview beside the list — click a folder to descend,../to go up, a file to page it inless,escto close. Typing filters, hidden files are shown, and binary files are named rather than dumped. Viewer only: nothing there can modify a file. Implemented inwebshell/tmux-files. - Copying out of a file. Drag-select-to-copy works in a tmux pane but
does nothing inside a popup — popups are not panes and have no copy-mode on
this build (measured), so dragging inside the browser popup is a no-op.
ctrl-otherefore opens the file in a pane beside the current one, in the same tab, where the normal drag-select copy works (lessruns there without--mouseon purpose, so tmux keeps the drag).ctrl-tdoes the same as its own tab, andctrl-y/alt-ycopy the whole file / its path without selecting anything. All land in the browser clipboard viatmux-clip's OSC 52, which needs a secure context (the https app URL, or a tunnel to localhost). Paste back withprefix + ]or the browser's paste. - Tab groups (tmux sessions) are fully mouse-driven: a second status row
lists the groups with the current one highlighted. Click that row — or
right-click anywhere on the bar — for the groups menu (switch / new /
rename / close). Right-click a tab to rename it, close it, or move it to
another group; mouse-wheel over the bar cycles groups. Menus come from
webshell/tmux-groups. Groups survive reboots like everything else (resurrect saves and restores all sessions).
omp-setup.sh installs omp if it isn't already present, points
it at the Brev-hosted webster model proxy, discovers the models accessible to
the supplied key, and turns on nerd mode — Nerd Font symbols plus the nerd
status line preset (tok/sec spark, TTFT, context %, cost, cache reads, elapsed
time). OMP's model picker refreshes from the proxy, so newly granted models show
up without editing this repository or installer.
One line on a new machine — note the key goes on the right of the pipe, so
the bash running the script sees it:
curl -fsSL https://raw.githubusercontent.com/theFong/setup/main/omp-setup.sh | WEBSTER_API_KEY=sk-... bashPass flags after -s --:
curl -fsSL https://raw.githubusercontent.com/theFong/setup/main/omp-setup.sh | WEBSTER_API_KEY=sk-... bash -s -- --no-smokeFrom a local clone:
OMP_WEBSTER_API_KEY=sk-... ~/.setup/omp-setup.shThe installer preserves the current webster/... default when that model is
still accessible. On a fresh install it prefers glm-5.2 when available, then
falls back to the first accessible model. Set OMP_MODEL=<model-selector> to
require a particular accessible default (reasoning suffixes such as :max are
preserved); the install fails clearly if the key cannot use its base model.
Or without the env var — run from a terminal and it prompts for the key (hidden
input). Piping to bash consumes stdin, so a piped run cannot prompt and exits
non-zero instead of writing an empty key:
~/.setup/omp-setup.sh| Flag | Effect |
|---|---|
| (none) | Install + configure + verify |
--check |
Verify an existing install; changes nothing, exits non-zero on drift |
--no-smoke |
Skip the live model round-trip (still checks the endpoint) |
What it writes:
| Where | What |
|---|---|
~/.omp/agent/models.yml |
webster provider: base URL, API key, LiteLLM discovery (mode 0600) |
~/.omp/agent/config.yml |
symbolPreset: nerd, statusLine.preset: nerd, and the access-aware modelRoles.default |
It is idempotent and merge-safe: re-running reuses the key already on disk,
preserves other providers and other model roles (advisor, smol, tiny, …),
and backs up models.yml to models.yml.bak before any change.
The API key is never stored in this repo — pass it via OMP_WEBSTER_API_KEY
(or WEBSTER_API_KEY) or let the script prompt for it.
Verification runs on every install (assert_omp_config / assert_omp_endpoint /
assert_omp_smoke, per STYLE_GUIDE.md): it reads the settings
back out of omp, authenticates to the endpoint and confirms the configured
default is in that key's non-empty live model catalog, then sends a real one-shot
prompt through the configured default model and asserts the reply. Failure
paths — dead endpoint, empty or invalid catalog, inaccessible explicit/default
model, no API key, stale duplicate provider entry — are covered in test.sh.
It is not wired into install.sh, because it needs a secret the bootstrap does
not have. Run it separately after the bootstrap.
Nerd mode needs a Nerd Font selected in your terminal;
without one the status line renders as tofu boxes. Fall back with
omp config set symbolPreset unicode && omp config set statusLine.preset full.
codex-setup.sh installs a localhost-only Responses API router that keeps the
OpenAI/ChatGPT login already managed by Codex for OpenAI models and substitutes
the Webster API key only when a Webster model is selected. Both model families
then appear in the Codex CLI and Codex Desktop model picker. Setup queries
Webster's /v1/models endpoint with the supplied key, so each user sees only
the models that key can access; no Webster model IDs are hardcoded.
First sign in once with codex login, then run:
curl -fsSL https://raw.githubusercontent.com/theFong/setup/main/codex-setup.sh \
| WEBSTER_API_KEY=sk-... bashThe environment prefix belongs on bash, to the right of the pipe. The script
can also prompt for the key through /dev/tty, or read it with --key-file:
curl -fsSL https://raw.githubusercontent.com/theFong/setup/main/codex-setup.sh \
| bash -s -- --key-file /path/to/webster-key| Flag | Effect |
|---|---|
| (none) | Install + configure + verify |
--check |
Verify source, secret permissions, endpoint, service, catalog, and Codex config without changing anything |
--key-file PATH |
Read the Webster key from a file's first line |
What it writes:
| Where | What |
|---|---|
~/.codex/model-proxy/ |
Dependency-free proxy runtime and Webster key plus its discovered model list; the config is mode 0600 |
~/.codex/openai-webster-models.json |
Combined model catalog loaded by Codex at startup (mode 0600) |
~/.codex/config.toml |
Merge-safe openai_webster provider and model_catalog_json selection |
~/Library/LaunchAgents/com.thefong.codex-model-proxy.plist |
Always-on user service on macOS |
~/.config/systemd/user/codex-model-proxy.service |
Always-on user service on Linux |
The proxy listens only on 127.0.0.1:4815. It strips the incoming OpenAI
credential and ChatGPT account header before Webster requests, never logs
request bodies or headers, and never writes OpenAI credentials anywhere new.
The Webster key lives only in the owner-readable proxy config.
The installer preserves the current selected model and unrelated Codex config.
Re-run it to update the proxy and rediscover both the key's Webster access and
the OpenAI portion of the catalog. Setup fails instead of installing an empty
catalog when the key cannot access any models. Generated Webster entries clone
the complete stock Codex catalog shape so strict Codex Desktop versions can
deserialize every entry.
The installer changes the catalog only when its contents actually differ. If a
running Codex app-server has therefore become stale, setup detects whether it
is daemon-managed and prints the required order: restart it with
codex app-server daemon restart, then disconnect and reconnect that machine
in Codex Desktop (or fully quit and reopen Desktop). For a legacy unmanaged
server, disconnect Desktop before running the restart command. No restart
notice is printed when the catalog and managed provider configuration are
unchanged or when a newer daemon has already loaded them.
After setup or any required reconnect, start a new Codex task before selecting
a Webster model. Codex persists the model provider with each task, so a task
created before setup remains on the built-in openai provider even if its
model is later changed in the picker. Selecting a Webster model in that older
task sends it to the ChatGPT backend and produces a "model is not supported
when using Codex with a ChatGPT account" error.
It is not wired into install.sh, because it needs both a Webster secret and an
existing Codex login. Run it separately after the bootstrap.
claude-code-setup.sh installs a localhost-only Anthropic Messages gateway
that adds Webster models to Claude Code's /model picker without replacing the
built-in Claude choices. Normal Sonnet, Opus, Haiku, and other Claude requests
continue to Anthropic with the login already managed by Claude Code. Only model
IDs beginning with claude-webster- are translated to Webster's OpenAI Chat
Completions API, with the Webster key substituted at that boundary.
First run claude and sign in once. Claude Code 2.1.129 or newer is required
for gateway model discovery. Then run:
curl -fsSL https://raw.githubusercontent.com/theFong/setup/main/claude-code-setup.sh \
| WEBSTER_API_KEY=sk-... bashThe installer also reuses the Webster key installed by codex-setup.sh when it
is available, so a machine with the Codex proxy already configured can omit the
environment variable:
curl -fsSL https://raw.githubusercontent.com/theFong/setup/main/claude-code-setup.sh | bash| Flag | Effect |
|---|---|
| (none) | Install + configure + verify |
--check |
Verify Claude login, source, secret permissions, endpoint, service, catalog, and settings without changing anything |
--key-file PATH |
Read the Webster key from a file's first line |
What it writes:
| Where | What |
|---|---|
~/.claude/model-proxy/ |
Dependency-free proxy runtime and Webster config; the config is mode 0600 |
~/.claude/settings.json |
Merge-safe gateway URL, model-discovery switch, and tool-search setting |
~/.claude/cache/gateway-models.json |
Seeded Webster catalog for /model, including Claude.ai subscription logins |
~/Library/LaunchAgents/com.thefong.claude-code-model-proxy.plist |
Always-on user service on macOS |
~/.config/systemd/user/claude-code-model-proxy.service |
Always-on user service on Linux |
The installer seeds Claude Code's gateway cache as well as enabling live model
discovery. This keeps the Webster entries visible for Claude.ai subscription
logins, whose discovery request has no ANTHROPIC_AUTH_TOKEN or
ANTHROPIC_API_KEY environment credential to send.
The proxy listens only on 127.0.0.1:4816. It never logs request bodies or
headers. For Webster models it strips the incoming Claude bearer token, API
key, and Anthropic headers before adding the Webster credential. For Claude
models it passes the original request and login through unchanged. The
Webster key lives only in the owner-readable proxy config.
Start a new Claude Code process after installation and run /model. The four
Webster entries appear with the built-in Claude entries and are labeled
(Webster). You can also launch one directly:
claude --model claude-webster-glm-5-2The installer preserves unrelated Claude settings and is byte-identical on a
safe re-run. It is not wired into install.sh, because it needs a Webster
secret and an existing Claude login.
pi-setup.sh is the sibling of omp-setup.sh for the
pi coding
agent: same webster endpoint, every model accessible to the supplied key,
plus a footer status line showing generation speed, active model, and session
id. The installer preserves an accessible existing default, otherwise prefers
glm-5.2 when available, then falls back to the first discovered model.
Hand this to someone and they are set up in one command:
curl -fsSL https://raw.githubusercontent.com/theFong/setup/main/pi-setup.sh \
| WEBSTER_API_KEY=sk-... bashThe env prefix goes on bash, not before curl — WEBSTER_API_KEY=sk-... curl … | bash
sets a shell variable that never reaches the script. Omit it entirely and it
prompts for the key with hidden input, reading /dev/tty because stdin is the
pipe carrying the script.
| Flag | Effect |
|---|---|
| (none) | Install + configure + verify, merging into any existing config |
--exclusive |
Make webster the only provider in models.json |
--check |
Verify an existing install; changes nothing, exits non-zero on drift |
--key-file PATH |
Read the key from a file's first line |
What it writes:
| Where | What |
|---|---|
~/.pi/agent/models.json |
webster provider: base URL, API key, and the key's discovered models with per-model limits (mode 0600) |
~/.pi/agent/settings.json |
defaultProvider: webster, plus an accessible discovered default model |
~/.pi/agent/extensions/tokps-session.ts |
Footer line: 73.4 tok/s • webster/glm-5.2 • 019feddc-… |
pi needs Node.js ≥ 22.19, and the script installs or upgrades it
(NodeSource on apt/dnf, Homebrew on macOS) rather than trusting whatever node
is on PATH. The distro nodejs on Ubuntu 22.04/24.04 is 18.x, which is not
merely missing a feature: pi's ESM uses import attributes
(with { type: "json" }), so Node 18 fails to parse it. The package installs
cleanly through npm and then dies at startup with
SyntaxError: Unexpected token 'with'. The version is asserted up front so
that surfaces as a clear message here instead. A pi already on PATH that
cannot start is reinstalled rather than reported as present, so re-running
after a Node upgrade actually repairs it.
Pi itself has no endpoint discovery, so the installer queries the authenticated
/v1/models endpoint and writes every returned model into Pi's configuration.
Context windows come from each model's endpoint metadata, with the previous
320,000-token default used only when metadata is absent. Advertised output is
capped at 32,768 tokens by default because Pi reserves output inside the
context window; smaller advertised limits are honored. PI_CONTEXT_WINDOW and
PI_MAX_TOKENS override those values for every discovered model, while
PI_MODEL explicitly chooses the default and fails if that model is not
accessible. PI_PROVIDER and PI_BASE_URL can target another compatible
endpoint.
The footer rate is decode speed — output tokens over the time from first
streamed content to end of generation — so a turn that runs a slow bash command
doesn't dilute it. Providers only report usage on the final stream event, so it
lands at the end of each turn rather than ticking up live. The session id on
that line is what pi --session <partial-uuid> takes to resume (--fork to
branch instead of append).
The API key is never stored in this repo — pass it via WEBSTER_API_KEY
(shared with omp-setup.sh) or PI_API_KEY, use --key-file, or let it
prompt. PI_NO_PROMPT=1 makes a missing key a hard failure instead, for cron
and provisioning.
Verification runs on every install and under --check, per
STYLE_GUIDE.md: the provider and default model as they landed
on disk, that pi starts with the extension loaded, and that the installed
model list still exactly matches the key's current endpoint access. A rejected
key (HTTP 401/403) or an accepted key with no models is a failure. An offline
re-run preserves the previously installed list; a fresh offline install needs
an explicit PI_MODEL. PI_SKIP_ENDPOINT_CHECK=1 uses the same fallback.
Failure paths — no key, unreadable --key-file, unparseable models.json, a
rejected or empty-access key, and credential file permissions — are covered in
test.sh.
Re-running is safe: other providers survive a merge, an unparseable config is
left untouched, and the extension is only rewritten when its content differs.
Like omp-setup.sh, it is not wired into install.sh, because it needs a
secret the bootstrap does not have.
Evaluate internet throughput (download/upload/latency to an external server)
with the Ookla speedtest CLI installed above. One-liner:
speedtest --accept-license --accept-gdprThe flags auto-accept Ookla's license/GDPR prompt on first run so it works
non-interactively (in scripts or over SSH); after the first run plain
speedtest works too. Useful extras:
speedtest --servers # list nearby servers
speedtest --server-id=<id> # pin a specific server
speedtest --format=json # machine-readable output.agent/skills/cluster-ops/ turns an undocumented compute cluster into a
per-cluster operations skill an agent can trust, and carries the portable
GPU-fleet failure patterns that recur across every fleet.
Ask an agent to onboard a cluster, or drive the discovery sweep directly:
PROBE=~/.claude/skills/cluster-ops/scripts/probe-cluster.sh
$PROBE --self-test # verify the collector on this machine
$PROBE --brev --brev-instances -o /tmp/acme.json # enumerate + sweep a brev-managed fleet
$PROBE -o /tmp/acme.json head node-1 node-2 # or name hosts explicitly
$PROBE --hosts-file hosts.txt --include-local # or read them from a fileFor brev-managed fleets it drives the CLI directly: --brev enumerates physical
nodes and --brev-instances cloud instances, which are two separate lists
(brev ls --all is not a substitute for either). Names double as SSH aliases
via ~/.brev/ssh_config, and non-Connected nodes are swept anyway and flagged
up front, since Connected is control-plane registration rather than
reachability. The sweep never runs brev refresh itself — that writes to
~/.brev/, and it stays read-only.
The sweep is read-only by construction: it reads /proc, /sys,
/etc/os-release and /etc/docker/daemon.json, runs query-only commands (ip,
ss, docker ps, nvidia-smi, systemctl list-units), and uses sudo for
nothing but sudo -n true to detect passwordless sudo. It emits one JSON record
per host covering identity, GPUs, containers and their restart policies,
addresses on every plane (LAN / overlay / RDMA fabric), listening ports, and
per-node access shape. A host that cannot be reached still gets a record, with
an error field, and the sweep exits nonzero — an unprobed node is a finding,
not an omission.
The skill then walks a six-phase flow (scope → enumerate → probe → interview →
render → verify) and fills templates/ to produce a <cluster>-cluster skill,
installed for both Claude Code and Codex. Layout:
| Path | Holds |
|---|---|
SKILL.md |
Entry points, non-negotiables, symptom → diagnostics index |
reference/onboarding.md |
The six phases, the interview questions, how to read probe output |
reference/diagnostics.md |
Portable failure patterns: overlay collisions, reboot survival, RDMA verification, telemetry that lies, ingress and routing |
reference/contract.md |
Authoring rules, when to update, anti-drift, how to retire a skill |
templates/ |
The cluster skill, topology, and runbook templates |
scripts/probe-cluster.sh |
The read-only discovery sweep |
The split is deliberate: cluster-ops holds what is true of clusters in
general, a <cluster>-cluster skill holds what is true of one fleet. Keeping
facts on the right side of that line means a fix reaches every cluster instead
of one.
If you only want the Claude config (no tooling):
git clone https://github.com/theFong/setup ~/.setup
# Symlink Claude Code config
ln -s ~/.setup/CLAUDE.md ~/.claude/CLAUDE.md
ln -s ~/.setup/.agent/skills ~/.claude/skillsRather than storing Claude Code configuration directly in ~/.claude/, this repo acts as the source of truth. Symlinks point from ~/.claude/ back into this repo:
~/.claude/CLAUDE.md → ~/.setup/CLAUDE.md
~/.claude/skills/ → ~/.setup/.agent/skills/
This means all configuration is version-controlled and portable across machines. Edit files here, commit, and push — then pull on any other machine to stay in sync.