claude: re-sync CLAUDE.md and statusline-command.sh from live and restore the symlinks
Both files had been replaced in ~/.claude by detached real files (CLAUDE.md around 2026-09-18, statusline-command.sh by 2026-09-16), so the repo copies had gone stale while every session loaded the live ones. The live versions are canonical and are now committed here, and ~/.claude links back into the repo. CLAUDE.md changes that ride along with the re-sync: - Operator identity: alias Prime, callsign Papa Romeo Mike. Legal, license and git attribution stay Vuong Hoang. - Miranda: the notification route to Prime (althing handle miranda), limited to high-priority matters, plus sender conventions. Route verified 2026-09-24. - Header warning: the file is a symlink into this repo. Never edit it with sed -i or any temp-then-rename tool, which detaches the link.
This commit is contained in:
+121
-216
@@ -4,10 +4,26 @@ Loaded into every Claude Code session regardless of project. Project-
|
||||
local `CLAUDE.md` files take precedence when they conflict; this file
|
||||
is the baseline.
|
||||
|
||||
⚠ **This file is a symlink into the dotfiles repo**
|
||||
(`~/dotfiles/home_root/.claude/CLAUDE.md`, gitea `vh/dotfiles`).
|
||||
Edit the **target path** directly. Claude Code's Edit tool refuses to
|
||||
write through the link and names the target, so use that path. **Never
|
||||
use `sed -i` or any other write-temp-then-rename tool on
|
||||
`~/.claude/CLAUDE.md`:** that replaces the link with a detached copy,
|
||||
and the dotfiles backup silently goes stale. It happened once already,
|
||||
around 2026-09-18, and went unnoticed until 2026-09-24. The same
|
||||
applies to `statusline-command.sh`, `CONTEXT.md` and
|
||||
`keybindings.json` in `~/.claude`.
|
||||
|
||||
## Operator identity
|
||||
|
||||
The operator is **Vuong Hoang** (lkraven@lkraven.com), addressed as
|
||||
"Vuong". Roles across three organizations:
|
||||
The operator is **Vuong Hoang** (lkraven@lkraven.com), aka **Prime**,
|
||||
callsign **Papa Romeo Mike**. Every session may address him as "Prime" or
|
||||
"Vuong", and anywhere you would write "the operator" you may write
|
||||
"Prime". Existing "operator" text stays valid, so do not rewrite docs to
|
||||
swap the word. **Legal names stay legal:** license text, copyright
|
||||
lines, git authorship and attribution, and anything legal or contractual
|
||||
use **Vuong Hoang**, never "Prime". Roles across three organizations:
|
||||
|
||||
- **Corviduo AI** — Founder, Principal Developer, Chief Systems Architect.
|
||||
- **PhaseFinal, Inc** — Founder, Principal Developer, Chief Systems Architect.
|
||||
@@ -29,6 +45,27 @@ consequence calls she relays remain Vuong's own — Miranda is the
|
||||
authorized conduit, not a substitute decision-maker — so surface a
|
||||
genuine concern to her the same way you would to him, then execute.
|
||||
|
||||
**Miranda is also the way to reach Prime when he is not in your
|
||||
session.** She can notify him either way. Her althing handle is
|
||||
`miranda` (Ledger's chief-of-staff persona agent). **Tell her about
|
||||
high-priority matters only:** things that need Prime's attention or
|
||||
decision before he would otherwise see your session. Examples: an
|
||||
outage, a security or data-loss event, a blocker on time-critical or
|
||||
irreversible work, or anything he would be unhappy to learn about late.
|
||||
**No noise:** no status updates, completions, FYIs or routine questions
|
||||
unless Prime has asked for that stream. A message to `miranda` has one
|
||||
recipient, so it is not a broadcast and needs no pre-approval under
|
||||
§ Althing → "Broadcasts need the operator's okay FIRST". The priority
|
||||
bar, not the permission rule, is what gates it.
|
||||
|
||||
How it works, per Miranda (route verified end to end on 2026-09-24):
|
||||
**every message to her becomes a summary on Prime's phone**, so each
|
||||
send costs his attention. Put **URGENT** in the subject only if it
|
||||
really cannot wait (broken, blocked, or work held on his decision); she
|
||||
will then also phone him. In the body, say what happened, what state
|
||||
it is in now, and whether Prime needs to act. Send one matter per
|
||||
message, and do not reply just to thank her or acknowledge.
|
||||
|
||||
## Operator judgment — legality & fair use
|
||||
|
||||
**You're free to refuse unethical and illegal requests, but please
|
||||
@@ -215,7 +252,7 @@ What every session needs before it loads the skill:
|
||||
not the single source of truth.
|
||||
2. **Check the handoff.** `persistent-memory.md` opens with a
|
||||
handoff-check header naming `/tmp/<althing-handle>-handoff.md`. If
|
||||
that file exists and its `Written:` stamp is under an hour old, read
|
||||
that file exists and its `Written:` stamp is under 8 hours old, read
|
||||
it, then delete it. Older: stale — delete unread. This is the
|
||||
post-`/clear` resume vector; no pasted prompt required.
|
||||
3. **Never bulk-read `persistent-memory.d/`.** The dated log sections
|
||||
@@ -343,8 +380,8 @@ the skill. Always triage Heid output before acting on it.
|
||||
stateful component. Operator page at /.
|
||||
client postbox (+ `althing-mcp` for the stdio tools)
|
||||
herald althing-po-herald one per box, supervised, ops-owned
|
||||
waiter althing-listen one per session — THIS is what makes a
|
||||
session pokeable; without it you are pull-only
|
||||
waiter althing-listen NOT NEEDED — delivery to Claude Code is
|
||||
PUSH (see below). Legacy, pull-era only.
|
||||
|
||||
**Both env vars are required and there is no default address** — a bare
|
||||
`postbox status` errors rather than guessing:
|
||||
@@ -362,47 +399,57 @@ says it could not reach the post office, that is the fault — do not read it as
|
||||
"no mail". v2 could not tell those apart; v3 can, and the distinction only pays
|
||||
if it is honoured.
|
||||
|
||||
⚠ **A session that has never armed `althing-listen` is pull-only and is never
|
||||
poked.** The herald pokes FIFOs; no waiter means no FIFO means no poke target.
|
||||
This is why the arm-early default below matters more under v3 than it did under
|
||||
v2 — and why the 📬 statusline badge is the only signal a not-yet-armed session
|
||||
gets.
|
||||
**Delivery to Claude Code is PUSH — do not arm a waiter (operator,
|
||||
2026-09-11).** The herald injects an `[ALTHING-HERALD] New mail` message
|
||||
straight into the session, so peer mail reaches you with no `althing-listen`
|
||||
running. **`/althing:monitor` and `/althing:sign-off` are both unnecessary**;
|
||||
proposing them is noise. `postbox status` reports the mode:
|
||||
|
||||
**Default posture — keep the monitor armed (operator directive,
|
||||
2026-07-14).** Unless a session says otherwise, every session should
|
||||
**attempt to keep its althing monitor armed for the session's
|
||||
duration** — arm it early (`/althing:monitor`) and re-arm after each
|
||||
fire (drain the fire via `/althing:inbox`, then re-arm), so peer mail
|
||||
is caught proactively rather than only surfacing on the next user
|
||||
prompt. The arm-on-dispatch rule below is the *minimum* case of this
|
||||
broader default; the default is to stay armed **even without a
|
||||
specific pending reply**, because peer agents reach out unprompted.
|
||||
handle: infra-ops unread: 0 mode: push reachable: True node: nh3-dev
|
||||
|
||||
When you ship an althing message that you expect to come back with a
|
||||
reply — a consult (`/heid*`), a question to a peer agent, a request
|
||||
awaiting an answer — and you do **not** already have an althing
|
||||
monitor running for this session, **always start one**
|
||||
(`/althing:monitor`). The dispatch and the monitor are one action: you
|
||||
opened a loop, so arm the thing that closes it.
|
||||
⚠ **`mode:` is authoritative — read it, don't reason about it.** This section
|
||||
used to carry a keep-the-monitor-armed default (operator directive 2026-07-14)
|
||||
written for the pull era, plus an arm-on-dispatch rule. Both are **retired**. On
|
||||
2026-09-11 a session recommended arming the monitor **three times in a row while
|
||||
three pushed messages were landing in its own context with no waiter running** —
|
||||
doctrine overriding what was visibly happening. If the delivery mode is ever
|
||||
genuinely in doubt, ask `postbox status`; do not infer it from this file.
|
||||
|
||||
Why: in an interactive session the inbox banner (📬) only fires on the
|
||||
*next* user prompt. If the operator steps away after you dispatch an
|
||||
async consult, the reply can sit unseen indefinitely — the loop you
|
||||
opened never closes on its own. A monitor actively pings when the
|
||||
reply lands, so the await-reply promise ("reply will land in your
|
||||
inbox") is backed by a real notification, not by hoping the operator
|
||||
prompts again.
|
||||
⚠ Do not check for a waiter with `pgrep -f althing-listen` — the pattern matches
|
||||
your own command line and reports a waiter that isn't there. Same trap as
|
||||
`pkill -f` over ssh.
|
||||
|
||||
Scope of the *arm-on-dispatch* rule: it fires for any message where
|
||||
you're waiting on a response (a pure fire-and-forget FYI doesn't
|
||||
*oblige* a fresh arm) — but under the keep-armed default the monitor is
|
||||
typically already up regardless. Do **not** sign off after each
|
||||
exchange (that fights the default); sign off (`/althing:sign-off`) at
|
||||
session wind-down or on operator direction. Waiters don't accumulate
|
||||
— the lock is one-per-handle, so re-arming freely is safe.
|
||||
Stop a stuck one with `althing-listen --stop`, which SIGTERMs the pid in
|
||||
that handle's lock file — never `pkill`, which is handle-blind and kills
|
||||
every agent's waiter on the box, not just yours.
|
||||
**Unchanged by the mode, and the part that actually matters:** when mail arrives
|
||||
or you ship a message expecting a reply, the loop is yours to close. Drain it
|
||||
with `/althing:inbox`, **act** on what it asks, then **answer** the peer who
|
||||
wrote it — reading without acting, and acting without answering, both leave it
|
||||
open. One exception worth naming: do not reply to a pure close-out ("thread
|
||||
closed from my end"), because acking an ack re-pokes their session.
|
||||
|
||||
If a legacy waiter is somehow running and stuck, stop it with
|
||||
`althing-listen --stop` (SIGTERMs the pid in that handle's lock file) — never
|
||||
`pkill`, which is handle-blind and kills every agent's waiter on the box.
|
||||
|
||||
### ⚠ Broadcasts need the operator's okay FIRST (operator, 2026-09-22)
|
||||
|
||||
**Any fleetwide or multi-recipient althing announcement requires explicit
|
||||
operator approval before it is sent.** Ask, then send — never send and report.
|
||||
|
||||
The cost is the reason: one broadcast wakes every recipient session, each of
|
||||
which then reads, reasons about, and often replies to it. **That is a great way
|
||||
to burn a shit ton of tokens and generate noise** — the spend is multiplied by
|
||||
the recipient count and paid out of budgets the sender never sees.
|
||||
|
||||
- **Gated:** anything addressed to more than one handle, anything shaped as an
|
||||
announcement/FYI/heads-up to the fleet, release notes, migration notices,
|
||||
convention changes, "everyone should know" posts.
|
||||
- **NOT gated:** a single-recipient message — a reply to a peer who wrote to
|
||||
you, a direct ask to one handle, a handover to the one agent taking over.
|
||||
Closing a loop with the peer at the other end of it stays at your discretion
|
||||
and needs no approval.
|
||||
|
||||
When a broadcast genuinely seems warranted, surface it as a decision with the
|
||||
draft attached and the recipient count named, and let the operator call it.
|
||||
|
||||
## Development workflow shapes
|
||||
|
||||
@@ -552,184 +599,42 @@ enough," keep the gate rather than drop it.
|
||||
|
||||
## Global tools available
|
||||
|
||||
Tools standing ready in the working environment — assume present and use
|
||||
them without a setup detour. (Most Claude Code sessions run natively on
|
||||
**nh3-dev** `10.100.10.50`, the dev box; "available" means there unless a
|
||||
note says otherwise. On other boxes, check first.)
|
||||
**The fleet tool + service index is `/home/lkraven/FLEETTOOLS.md`** (canonical:
|
||||
`~/development/eshpfi-management/docs/fleettools/`, git-tracked). It is an *index* —
|
||||
read it whole, it is short, then open only the detail file for the tool you actually
|
||||
need. It covers althing, the Booth, the `secret` vault CLI, the LiteLLM gateway,
|
||||
inference seats + the Asset Engine control plane, TTS/ASR, Arbo, elway, fleet SSH,
|
||||
observability, graphify, Playwright, the Henge, and the Claude-only harness tools.
|
||||
The same file is autoloaded by Codex (`~/.codex/AGENTS.md`) and Grok
|
||||
(`~/.grok/rules/00-fleettools.md`) via a shared bootstrap pointer, so every agent
|
||||
family on this box works from one source of truth.
|
||||
|
||||
- **Playwright + headless Chromium** — installed **box-wide on nh3-dev**:
|
||||
the system shared-libs (apt, via `playwright install-deps`), the browser
|
||||
binaries in shared **`/opt/ms-playwright`** (chromium + headless-shell,
|
||||
root-owned + world-readable), and
|
||||
`PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright` wired globally
|
||||
(`/etc/environment` + `/etc/profile.d/`). A project only needs the
|
||||
`playwright` module (`npm i playwright` — the browser download is
|
||||
skippable, it resolves the shared binary); **no per-project
|
||||
`playwright install`**. Use for anything that needs a real browser
|
||||
engine: true DOM/SVG layout geometry, screenshots, headless rendering,
|
||||
browser-based tests or scraping. Add a browser / bump via
|
||||
`ssh infra-ops@10.100.10.50 'sudo env PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright npx -y playwright install <browser>'`.
|
||||
⚠ **Query live inventories, never a written list** — Homepage
|
||||
`http://10.0.50.45:5100/api/services`, asset-engine
|
||||
`http://10.250.50.70:8200/api/v1/services`, LiteLLM
|
||||
`http://10.250.50.70:4000/v1/models`, and any FastAPI seat's `/openapi.json`.
|
||||
|
||||
- **`ratecheck` — how close this session is to its rate limits** (`~/.claude/bin/ratecheck`,
|
||||
reading `~/.claude/rate-limits.json`). **Run it before any expensive or long-running action**, and
|
||||
when the operator asks how much headroom is left. Exit `0` GO · `1` PAUSE · `2` UNKNOWN; it prints
|
||||
both windows, the file's age, and the reset time.
|
||||
**Shared all-agents LiteLLM key:** `sk-eA_XOdcs6nIkyYXonohtEQ` (alias
|
||||
`all-agents-local`). ⚠ It reaches **every** model including paid GLM/Kimi
|
||||
passthroughs, and a paid call spends real vendor credits shared across every session
|
||||
holding it. For isolated, auditable spend, ask infra-ops for a project-scoped key.
|
||||
|
||||
⚠ **The numbers are NOT visible to an agent by default, and that is the whole reason this exists.**
|
||||
No CLI subcommand exposes them and nothing else on disk carries them — the harness pipes
|
||||
`rate_limits.{five_hour,seven_day}.{used_percentage,resets_at}` **to the statusline and nowhere
|
||||
else.** So `~/.claude/statusline-command.sh` tees them atomically to `~/.claude/rate-limits.json`
|
||||
on every render (added 2026-09-05). **If that tee is ever removed every rule built on it silently
|
||||
stops working**, which is why `ratecheck` reports a stale file as UNKNOWN rather than as healthy.
|
||||
Three directives from that set stay here because they govern *behaviour*, not lookup:
|
||||
|
||||
**What to do with it, in ascending cost of the action:**
|
||||
- **Under ~85%** — proceed normally.
|
||||
- **~85–93%** — **take it easy**: prefer the cheap path, resume an existing subagent instead of
|
||||
spawning a fresh one, and do not start work you cannot finish inside the window. Say the number
|
||||
out loud when it shapes a choice, so the operator can overrule.
|
||||
- **At or over the project's threshold** (Heid's is 93% on **either** window) — **stop starting new
|
||||
expensive work.** Let anything in flight finish; killing it burns what was already spent.
|
||||
- **UNKNOWN** — ⚠ **proceed, loudly.** A broken instrument that halts everything is a
|
||||
self-inflicted outage worse than the overspend it guards, and a headless session has nobody
|
||||
watching a status bar. **Say plainly that the limits were unreadable and you continued blind.**
|
||||
Same shape as *an unreachable post office is an OUTAGE, never an empty inbox*: **absence of a
|
||||
signal is not a safe reading of it.**
|
||||
|
||||
⚠ **The check happens before the spend, and the spend lands after.** One Heid consult subagent has
|
||||
measured at **270k–650k tokens**; a round cleared at 92% can finish past 100%. **A GO is margin,
|
||||
not permission for an arbitrarily large action.** ⭐ Per-project thresholds and what exactly they
|
||||
pause belong in that project's `CLAUDE.md` — this entry owns the instrument, not the policy.
|
||||
|
||||
- **Graphify** — open-source knowledge-graph skill for AI coding assistants
|
||||
(`uv tool install graphifyy`; CLI `graphify`, MCP `graphify-mcp`). Turns a
|
||||
repo into a queryable graph. The **free, deterministic path** is
|
||||
`graphify update <path>`: tree-sitter AST extraction + Leiden clustering,
|
||||
**zero LLM / zero tokens**, ~25s for ~900 files; writes
|
||||
`graphify-out/{graph.json,GRAPH_REPORT.md}`. Highest-value free output is
|
||||
the **God Nodes** list (core-abstraction surfacing) plus `graphify explain
|
||||
<symbol>` / `query` / `affected` / `path` traversals over `EXTRACTED` call
|
||||
edges. The LLM layer (community **labeling** = low-caliber, and **semantic
|
||||
extraction** of docs/INFERRED edges = higher-caliber + noisier) is optional
|
||||
and points at any backend via `~/.graphify/providers.json` — pair labeling
|
||||
with the cheap LiteLLM/Granite endpoint below; leave deep semantic
|
||||
extraction off unless needed (its INFERRED/AMBIGUOUS edges fight the
|
||||
explicit-over-implicit floor). Complements a hand-authored `docs/CODEBASE.md`
|
||||
(curated geography), doesn't replace it. Pilot-validated on Worldtree
|
||||
2026-06-10.
|
||||
|
||||
- **LiteLLM gateway (local vLLM + GLM/Kimi passthrough)** — OpenAI-compatible gateway at
|
||||
`http://10.250.50.70:4000/v1` (Logs UI `:4000/ui`) fronting ana-ml2 / irv-ml1 vLLM services
|
||||
plus paid passthroughs. Essentially-**free local compute** for low-caliber, high-volume,
|
||||
parallelizable LLM work. The **always-available summarizer / classifier endpoint** is the
|
||||
`summarizer` (+ `summarizer-large`) / `classifier` alias — the go-to for summarization,
|
||||
naming/labeling, classification, and triage. Since 2026-08-15 it's backed by
|
||||
**`qwen3.8-27b-uncensored`** (JonathanColetti Heretic-abliterated Qwen3.8-27B, quantized
|
||||
in-house to NVFP4 W4A16 + grafted MTP head, vision-intact, 262K ctx) on ana-ml2 `:8015` —
|
||||
compose project `gen-seat` / container `vllm-gen` — the same "gen" seat that also serves
|
||||
`gen` (general chat), `gen-reasoning` (thinking variant), `image-judge`, and `qwen-image-bench`.
|
||||
(Prior `qwen3.6-35b-a3b-heretic` MoE and `granite-4.1-8b` are retired from the roster.) Treat the summarizer as a standing dependency you can reach any time. The
|
||||
roster drifts — query the live list at `:4000/v1/models` (~30 entries as of 2026-08-14); the
|
||||
current tool-relevant set:
|
||||
- **Embeddings / rerankers (local, free):** `qwen3-embedding`, `qwen3-reranker`, `reranker`
|
||||
(BAAI bge-v2-m3), `reranker-a4-gte-modernbert`.
|
||||
- **Small fast local (free):** `coder-fast` (qwen2.5-coder-1.5b), `lfm2.5-2.6b` (Liquid) —
|
||||
cheap for high-volume mechanical work.
|
||||
- **Judge (local, free):** `selene-1-mini-8b` / `chat-judge` (Atla Selene reward/quality judge).
|
||||
- **Frontier passthrough (PAID — spends vendor credits):** `gen-frontier` /
|
||||
`gen-frontier-reasoning` → GLM 5.2; the GLM family `glm-5.2` (+`-reasoning`), `glm-5.1`
|
||||
(+`-reasoning`), `glm-5-turbo`, `glm-4.7`, `glm-4.5-air` (z.ai); and `kimi-k3` /
|
||||
`kimi-k3-gen-api` (Moonshot — 1M-context **reasoning** models: answer in `content`,
|
||||
chain-of-thought in `reasoning_content`, and they 400 on any `temperature` other than 1,
|
||||
so omit the field entirely rather than sending 0).
|
||||
- **TTS:** `ext-tts` → the fleet dots gateway (irv-ml1 `:8198`; voices donut/emmie/glados/
|
||||
miranda/sindra + emotion variants, or OpenAI aliases nova/alloy — repointed off the parked
|
||||
zonos 2026-08-13; an unknown voice 404s and can trip the router cooldown). The gateway 401s without a **virtual API key**. **Shared
|
||||
all-agents key** — `sk-eA_XOdcs6nIkyYXonohtEQ` (alias `all-agents-local`):
|
||||
reaches **every** model behind the gateway, paid passthroughs included
|
||||
(corrected 2026-07-25 — this entry previously read "scoped to free local
|
||||
models only... the shared key deliberately can't spend z.ai cost," which
|
||||
infra-ops says was never actually true: the key already spent GLM/z.ai
|
||||
credits before this correction, and now reaches kimi-k3 the same way).
|
||||
**A paid-model call on this key spends real vendor credits, shared across
|
||||
every session and project holding it** — there is no isolation between
|
||||
what your session runs and what anyone else's does. Use it directly for
|
||||
the always-available free local endpoints — no per-project provisioning
|
||||
needed. Example: `curl http://10.250.50.70:4000/v1/chat/completions -H
|
||||
"Authorization: Bearer sk-eA_XOdcs6nIkyYXonohtEQ" -d
|
||||
'{"model":"summarizer","messages":[…]}'`. For spend isolated from the
|
||||
shared pool — auditable per-project cost, blast-radius containment — still
|
||||
request a project-scoped key from infra-ops via althing; that remains the
|
||||
right move for anything where "shows up on someone else's tab" matters, it's
|
||||
just no longer a hard technical requirement for reaching a paid model.
|
||||
Rotatable via infra-ops if it leaks. Reach for the free local endpoints
|
||||
before spending premium API tokens on tasks a small fast local model
|
||||
handles fine (the LLM-last-resort floor still applies — deterministic
|
||||
first).
|
||||
|
||||
- **The Booth** — ephemeral media board for surfacing **A/B renders, smoke
|
||||
results, screenshots, audio/video** to the operator (live at
|
||||
`http://10.100.10.50:8090/`, Homepage → *Apps → The Booth*). A booth is
|
||||
*just a folder* — no upload API: any session drops files into
|
||||
`~/booth-data/<name>/` on **nh3-dev** (or from another host
|
||||
`rsync -a ./out/ nh3-dev:booth-data/<name>/`), then hands the operator
|
||||
`http://10.100.10.50:8090/b/<name>/`. A folder's own `index.html` is served
|
||||
verbatim (build a custom report); otherwise it auto-renders a gallery of
|
||||
images / webm+mp4 video / audio, with a `<file>.txt` sidecar folded in as
|
||||
that item's caption (labels A/B pairs). Wiped **24h after last activity**.
|
||||
No auth — LAN/WG-internal + ephemeral, so don't drop secrets in a booth.
|
||||
Reach for it instead of describing results in prose when a picture, clip, or
|
||||
side-by-side would land faster. Code + helper CLI: eshpfi
|
||||
`services/booth/` (`scripts/booth {new|add|url|ls|rm|keep|unkeep|link}`);
|
||||
user-level systemd on nh3-dev (`systemctl --user status booth.service`).
|
||||
|
||||
**STANDING CONVENTION (operator, 2026-08-19) — POST EVERY OPERATOR-FACING
|
||||
LINK TO THE BOOTH LINK BOARD.** Any URL you hand the operator that is worth
|
||||
more than the next thirty seconds — a booth of renders, a PR, an issue, a
|
||||
newly-deployed service, an artifact page, a dashboard — **also** goes on the
|
||||
standing link board, in the same turn you mention it:
|
||||
|
||||
```bash
|
||||
booth link <url> "<short description>" # on nh3-dev
|
||||
ssh nh3-dev 'booth link <url> "<desc>"' # from anywhere else
|
||||
```
|
||||
|
||||
Still put the link in your reply — this is *in addition to*, not instead of.
|
||||
The reason is simple and the operator raised it directly: links in chat drown
|
||||
in terminal scrollback and are gone. The board is a **kept** booth (a
|
||||
`.forever` sentinel exempts it from the 24h sweep) rendered in its own lane at
|
||||
the top of `http://10.100.10.50:8090/`, so it survives the session that
|
||||
produced it. Entries carry provenance automatically (`ALTHING_HANDLE` or the
|
||||
hostname, plus a timestamp), and the board is a plain markdown file the
|
||||
operator prunes by hand — `booth unkeep links` or deleting the folder ends it.
|
||||
|
||||
Don't post noise: transient junk (a scratch path, a URL only meaningful for
|
||||
the next two minutes) stays out. If you wouldn't expect him to click it a week
|
||||
from now, it doesn't belong on the board. Any booth you want to outlive its
|
||||
24h can be kept the same way (`booth keep <name>`), but keep that rare — the
|
||||
ephemeral default is what makes the Booth cleanup-free.
|
||||
|
||||
- **`secret` — Vaultwarden credential store (per dev box)** — a CLI for stashing
|
||||
and looking up secrets that shouldn't live in a git repo, backed by
|
||||
**`vaultwarden.phasefinal.com`** (the `infra-ops` org, visible from the operator's
|
||||
primary account). On nh3-dev the CLI is
|
||||
`~/development/eshpfi-management/services/secrets-broker/secret` (bw-backed; auth
|
||||
bootstraps from `~/.config/secrets-broker/bootstrap.env`, `0600`). Usage:
|
||||
`secret put <name> (--file P | --stdin) [--folder C] [--field k=v]`,
|
||||
`secret get <name> [--field F] [--file OUT]` (the only command that prints a
|
||||
value), `secret list [--prefix P]`, `secret backfill [--dry-run]` (scans THIS
|
||||
box's `~/development/*/{env.sh,.env}` + `~/.config` creds and upserts each).
|
||||
Items are hostname-namespaced (`<host>/…`); small text → item note, small binary
|
||||
→ base64 hidden field, >6000 B → a bw attachment. **STANDING DIRECTIVE (operator,
|
||||
2026-08-11): the vault is the credential source of truth — store durable secrets
|
||||
in it AND pull the creds you need FROM it.** Any token / API key / cert / env-secret
|
||||
worth keeping — not ephemeral, doesn't belong in git — should be `secret put` into
|
||||
the vault so it survives and is findable, never left single-copy on a box; and when
|
||||
a task needs a credential (e.g. a gitea token to create a repo), **`secret get` it
|
||||
from the vault** rather than reading an on-disk copy where practical. The one
|
||||
exception is `bootstrap.env` itself (secrets-zero — it unlocks the vault, so it
|
||||
can't live inside it; keep it `0600`). **Not a fleet service / no daemon** — each
|
||||
new dev box duplicates this stack against its own local secrets (setup steps in
|
||||
the service `README.md`). Details: auto-memory `reference_secrets_broker_cli`.
|
||||
- **Run `ratecheck` before any expensive or long-running action**
|
||||
(`~/.claude/bin/ratecheck`; exit `0` GO / `1` PAUSE / `2` UNKNOWN). Under ~85%
|
||||
proceed; ~85–93% take the cheap path and resume an existing subagent rather than
|
||||
spawning one; at/over the project threshold stop starting new expensive work;
|
||||
**UNKNOWN — proceed, loudly, and say plainly that the limits were unreadable.**
|
||||
A GO is margin, not permission for an arbitrarily large action — one consult
|
||||
subagent has measured at 270k–650k tokens.
|
||||
- **POST EVERY OPERATOR-FACING LINK TO THE BOOTH LINK BOARD** (operator, 2026-08-19):
|
||||
`booth link <url> "<short description>"`, in the same turn you mention it, *in
|
||||
addition to* putting it in your reply. Links in chat drown in terminal scrollback;
|
||||
the board is kept and survives the session. Don't post transient junk.
|
||||
- **The vault is the credential source of truth** (operator, 2026-08-11): `secret put`
|
||||
anything durable so it is never single-copy on one box, and `secret get` the creds a
|
||||
task needs rather than reading an on-disk copy.
|
||||
|
||||
## DevOps delegation
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
# Claude Code statusline. Layout:
|
||||
# [📬N] [🔔/🔕] | <proj> ⎇<branch> *<dirty> ↑<unpushed> | <model> | ctx:<pct> <toks> | $<session-cost> | 5h:% 7d:%
|
||||
# [📬N] [🔔/🔕/📵] | <proj> ⎇<branch> *<dirty> ↑<unpushed> | <model> | ctx:<pct> <toks> | $<session-cost> | 5h:% 7d:%
|
||||
#
|
||||
# 🔔 reachable — the post office will push to this session
|
||||
# 🔕 pull-only — nothing will poke it; mail waits until it looks
|
||||
# 📵 the post office could not be asked — an OUTAGE, not an empty inbox
|
||||
# ctx% and rate-limit %s are threshold-colored: green <60, yellow 60-90, red >90.
|
||||
# All segments degrade gracefully (missing tool / non-git dir / no handle => segment omitted).
|
||||
input=$(cat)
|
||||
@@ -54,6 +58,21 @@ IFS=$'\x1f' read -r model used_pct input_tok five_pct week_pct cwd fast cost_usd
|
||||
)
|
||||
[ -z "$model" ] && model="unknown"
|
||||
|
||||
# --- persist the rate-limit window for agents (added 2026-09-05, operator directive) ---
|
||||
# The percentages arrive here on stdin and nowhere else: no CLI subcommand exposes them and
|
||||
# nothing else on disk carries them, so an agent that must throttle on them cannot see them.
|
||||
# Written atomically (tmp + mv) so a reader never catches a half-written file. Empty fields
|
||||
# are preserved as null rather than 0 -- a session with no rate_limits must read as UNKNOWN,
|
||||
# never as "plenty left", which is the one way this file could cause the harm it prevents.
|
||||
{
|
||||
_rl_dir="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"; _rl_tmp="$_rl_dir/rate-limits.json.$$"
|
||||
printf '{"five_hour_pct":%s,"seven_day_pct":%s,"five_hour_resets_at":%s,"seven_day_resets_at":%s,"written_at":%s,"written_at_iso":"%s"}\n' \
|
||||
"${five_pct:-null}" "${week_pct:-null}" "${five_reset:-null}" "${week_reset:-null}" \
|
||||
"$(date +%s)" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$_rl_tmp" 2>/dev/null \
|
||||
&& mv -f "$_rl_tmp" "$_rl_dir/rate-limits.json" 2>/dev/null
|
||||
rm -f "$_rl_tmp" 2>/dev/null
|
||||
} || true
|
||||
|
||||
# --- model (compact) + fast-mode flag ---
|
||||
model="${model%% (*}" # "Opus 4.8 (1M context)" -> "Opus 4.8"
|
||||
[ "$fast" = "true" ] && model="⚡$model"
|
||||
@@ -103,30 +122,28 @@ if [ -n "$cwd" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- althing: unread count (📬 N) + monitor-armed (🔔 armed / 🔕 not) ---
|
||||
# --- althing: unread count (📬 N) + reachability (🔔 push / 🔕 pull / 📵 outage) ---
|
||||
# NOT implemented here any more. `althing-statusline` is the canonical segment,
|
||||
# shipped as a console script by the althing package (3.4.0+).
|
||||
#
|
||||
# This block used to be one of THREE hand-maintained copies of the same twelve
|
||||
# lines -- this file, althing's plugin/scripts/statusline.sh, and infra-ops'
|
||||
# copy in eshpfi-management. An audit on 2026-09-02 found DIFFERENT defects in
|
||||
# each and all three were fixed separately, by hand, on the same day. That is a
|
||||
# drift surface with a countdown on it, and it is the same failure that left
|
||||
# this very block dead for a month after the v3 cutover deleted the binary it
|
||||
# gated on. A script, unlike a document, has somewhere to be installed: PATH.
|
||||
#
|
||||
# The payload goes in on STDIN -- the segment resolves the handle from the cwd
|
||||
# it carries, and falls back to nothing rather than guessing.
|
||||
#
|
||||
# The outer `timeout` is deliberately LOOSER than the program's own 2s budget.
|
||||
# If the outer one fired first we would get an empty segment, which reads as
|
||||
# "not an althing directory" -- the outage conflation, reintroduced by the
|
||||
# guard meant to prevent a hang.
|
||||
althing=""; mon=""
|
||||
if command -v althing-cli >/dev/null 2>&1; then
|
||||
althing=$(althing-cli statusline 2>/dev/null </dev/null)
|
||||
# suppress the empty-inbox form (📪 0) — only surface actual unread mail (📬 N)
|
||||
case "$althing" in *📪*) althing="" ;; esac
|
||||
h="${ALTHING_HANDLE:-}"
|
||||
# ALTHING_HANDLE isn't set in the statusline env — resolve the per-project handle from
|
||||
# althing's session map (keyed by the cwd Claude Code passes on stdin), the same source
|
||||
# `althing-cli use` writes. Without this the monitor bell (🔔/🔕) never renders.
|
||||
[ -z "$h" ] && [ -n "$cwd" ] && h=$(jq -r --arg d "$cwd" '.[$d] // empty' "$HOME/.althing/session_handles.json" 2>/dev/null)
|
||||
if [ -n "$h" ]; then
|
||||
mon="🔕"
|
||||
# Three independent arming mechanisms, one lock each — any live one means "armed":
|
||||
# monitor-$h.lock <- `althing-cli monitor` (the CC-native exit-0-re-arm loop)
|
||||
# wake-listener-$h.lock <- `althing-wake-listener` (herald inbound)
|
||||
# light-monitor-$h.lock <- `althing-light-monitor` (standing watch)
|
||||
# The kill -0 liveness gate below discards stale locks, so listing all three is safe.
|
||||
for lk in "$HOME/.althing/monitor-$h.lock" "$HOME/.althing/wake-listener-$h.lock" "$HOME/.althing/light-monitor-$h.lock"; do
|
||||
[ -f "$lk" ] || continue
|
||||
pid=$(tr -dc '0-9' < "$lk" 2>/dev/null)
|
||||
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then mon="🔔"; break; fi
|
||||
done
|
||||
fi
|
||||
if command -v althing-statusline >/dev/null 2>&1; then
|
||||
althing=$(printf '%s' "$input" | timeout 5 althing-statusline 2>/dev/null)
|
||||
fi
|
||||
|
||||
# --- assemble ---
|
||||
|
||||
Reference in New Issue
Block a user