Collects the verified environment facts and traps from 2026-09-21: workstation vs railiance01 kube context, tunnels, harness permissions, change gate and rollout headroom, attended OpenBao login, secret-read hazards, ArgoCD layout, and vocabulary. Linked from AGENTS.md and the session protocol. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
9.8 KiB
Agent environment orientation
Audience: every coding agent working in this estate (Claude Code, Codex, Grok, custodian workers). It is tool-neutral. Owner: the-custodian. Last verified: 2026-09-21.
These are facts about the environment: where things run, how to reach them, and the traps that cost real time. Each section names its owner. When a fact changes, fix it here and in the owner's record.
Read this before touching railiance01, OpenBao, ArgoCD or credentials.
1. Where you are
- The workstation is WSL2 (Ubuntu on Windows). It is dev-only; production runs on railiance01. There is no
xdg-openby default: see §5. - railiance01 (
92.205.62.239) is production. It is a single-node k3s cluster, the only control-plane node.ssh railiance01reaches it as usertegwick. - The workstation's kube context is NOT railiance01. A
kubectlrun on the workstation talks to another cluster. On 2026-09-21 that sent an agent to the wrong conclusion about ArgoCD.- To read or change railiance01, run commands on the node:
ssh railiance01 'kubectl …'. - Before trusting any result, confirm the node IP is
92.205.62.239(kubectl get nodes -o wide).
- To read or change railiance01, run commands on the node:
- On railiance01,
kubectlworks directly.helmneedsexport KUBECONFIG=/etc/rancher/k3s/k3s.yaml, or it trieslocalhost:8080. - "railiance01" in older records sometimes means coulombcore. That usage predates the 2026-07-02 correction. coulombcore is the frozen old cluster; it still runs a stale ArgoCD.
2. Reaching services from the workstation
Services are private by default (railiance-master ADR-0008) and are reached through ops-bridge SSH tunnels. bridge status shows them; bridge up <name> restores one.
| Service | Address on the workstation | Tunnel |
|---|---|---|
| State Hub API | http://127.0.0.1:8000 (health: /state/health) |
state-hub-primary |
| OpenBao | http://127.0.0.1:18200 |
openbao-ui-railiance01 |
| k3s API | via k3s-api-railiance01 |
k3s-api-railiance01 |
Trap: the shell default BAO_ADDR=https://bao.coulomb.social is unreachable from the workstation. Use BAO_ADDR=http://127.0.0.1:18200 (and VAULT_ADDR the same) for any bao command.
3. Permissions and the agent harness (Claude Code)
- The project allows
Bash(ssh railiance01 *). A command that starts withssh railiance01 '…'matches that rule. A command that starts with anything else (timeout …,cd … && for …) goes to the auto-mode classifier. The classifier blocks cluster mutations as "Shared Cluster Mutation". - A block is a stop signal, not a puzzle to route around. Get the founder's go-ahead for the live change first, then run it in the
ssh railiance01 '…'form.scp <file> railiance01:/tmp/…followed byssh railiance01 'kubectl apply -f /tmp/…'is the working pattern for applying a file. - The harness blocks foreground
sleep. To wait on the cluster, loop inside the ssh command, e.g.for i in $(seq 1 20); do <check> && break; sleep 3; done.
4. Changing production (railiance01)
- Every live change needs the founder's go-ahead. Record it in Mode of Authority terms (§8):
ADMINISTER @ realm:kubernetes/railiance01,activation=APPROVED. - The change gate is tiered by ADR-0006
readiness_state, not by environment, because it is a single cluster. Record:the-custodian/docs/kubernetes-change-gate-decision.md.- Below
production-approved: direct apply under founder plan approval. - At
production-approved:CONSTRUCTthrough git and ArgoCD. - Emergency:
activation=BREAK_GLASS, recorded, then reconciled into git. - Unmapped targets count as production-tier. The
whitehatnamespace is explicitly non-production.
- Below
- Check CPU headroom before any rollout. The node runs near its limit (~85% of CPU requested).
- Command:
kubectl describe node | grep -A4 "Allocated resources". - A rolling update creates the new pod before stopping the old one. On a node with no requestable CPU, even a change that lowers requests deadlocks. This happened on 2026-09-21; freeing 50m elsewhere unblocked it.
- Free capacity first, then change requests.
- Command:
- Always dry-run and diff before applying:
kubectl diff(client-side) and--dry-run=server.- A server-side diff can report a field-ownership conflict where values are semantically equal, e.g.
1vs1000mCPU owned by an older client-side apply. - ArgoCD's apply strategy uses client-side apply, so check the client-side diff too.
- A server-side diff can report a field-ownership conflict where values are semantically equal, e.g.
- Helm releases: deploy through the owner's documented path, e.g. state-hub's
PROMOTE.md, with its headroom preflight and--atomic. Pin the image tag the release already runs unless the change is the image.- A release stuck in
pending-upgrade: compare the revisions' values and manifests with live first. If identical,helm rollback <rel> <last-deployed>clears it without touching objects.
- A release stuck in
- Declare what you change in the owner's repository in the same session. Otherwise the next upstream re-apply silently reverts it. On 2026-09-21 the Knative installer would have restored the CPU requests that had been starving the backups.
5. OpenBao admin actions (attended login)
Owner: railiance-platform (OpenBao) and ops-warden (the warden access lane).
- Admin actions go through
warden access openbao-platform-admin-login --exec -- <reviewed-command>.- The founder runs it in their own terminal (
! …in Claude Code). KeyCape OIDC/MFA needs a TTY and a browser; it fails from an agent's non-TTY shell. - Prefix
BAO_ADDR=http://127.0.0.1:18200 VAULT_ADDR=http://127.0.0.1:18200(§2).
- The founder runs it in their own terminal (
- Browser on WSL:
~/.local/bin/xdg-openis a one-line shim to/mnt/c/Windows/explorer.exe "$1", sobao login -method=oidccan open KeyCape. Without an opener, the login URL goes into warden's suppressed output and the login times out. - The reviewed command must be completely silent. warden fails closed on ANY child output, and
bao … writeprints "Success!". Start the child withexec >/dev/null 2>&1. Make it idempotent: compare before writing, never overwrite a differing object, and use distinct exit codes for "differs", "write failed" and "verify failed". A working example:railiance-platformRPF-WP-0045 execution record. - Do not trust warden's exit code; read the printed line. As of 2026-09-21:
- A failed login can exit 0, and the audit records every attempt as
ok. attended command completed but session revocation could not be confirmed(exit 1) means the child succeeded; only revocation is unconfirmed.attended login failed closed before command handoffmeans the child never ran.- Reported to ops-warden (hub message
6a1ce1bb).
- A failed login can exit 0, and the audit records every attempt as
6. Secrets and credentials
- Run the credential-routing check (
warden route find "<need>") before requesting anything. See the "Credential and access routing" section in every repo'sAGENTS.md. - Never read a Secret with
-o yaml,-o json,describe-style tools, or even-o jsonpath='{.metadata}'. A Secret created withkubectl applycarries its full data in thekubectl.kubernetes.io/last-applied-configurationannotation, so a metadata read prints the secret. To test for the annotation without printing a value:kubectl get secret <n> -o go-template='{{ if index .metadata.annotations "kubectl.kubernetes.io/last-applied-configuration" }}HAS-ANNOTATION{{ else }}clean{{ end }}' - ExternalSecrets use ClusterSecretStores. The target pattern is OpenBao Kubernetes auth: one ServiceAccount per consumer, 15-minute tokens, and a policy scoped to exact paths. Five stores still use static
*-eso-tokenSecrets, which expire. Do not re-run the old*-eso-token-applyscripts.
7. GitOps (ArgoCD) on railiance01
Owner: railiance-platform (Applications) and railiance-enablement (the ArgoCD install, S4).
- ArgoCD Core v3.5.3 (headless) runs in
argocd, installed 2026-09-21. Adoption is one app at a time, per RPF-WP-0044:- openbao-secretstore and target-revenue are adopted, with manual sync and automated sync off.
- issue-core and external-secrets are not yet adopted.
- Use
argocd/railiance01/bootstrap/. NEVER runmake argocd-bootstrap-deployagainst railiance01. It renders the old root, which has automated sync, prune and self-heal, and would adopt everything at once. argocd/applications/onmainis still read by coulombcore's ArgoCD. Editing it is a live change on coulombcore.- Adopted apps: a hand deploy (
make deploy,kubectl apply) now fights ArgoCD. Change git, then sync.
8. Vocabulary
- SecurityCanon Mode of Authority (
security-canon/infospace/vocabulary/mode-of-authority/):- Write authority as
MODE @ SCOPE. Modes: USE, OBSERVE, OPERATE, ADMINISTER, GOVERN, CONSTRUCT, SOVEREIGN. They are not a privilege ladder. activation: APPROVED, BREAK_GLASS, …BREAK_GLASSis an activation, not a mode.EvidenceBoundary:target-audited,external-audited.
- Write authority as
- Never write bare "operator".
Operatoris a CARING lifecycle role andOPERATEis an Auth Mode. Bernd's decisions are "the founder, exercisingGOVERN @ estate". - Security layer model (net-kingdom §11): a repository declares its own layer in
INTENT.mdfrontmatter, which governs.layer.yamlis derived. There is no version in the declaration, and case is folded. Rulings: gate-house GH-DEC-2026-017, 020 and 021.
9. Hub and workplan hygiene
- The State Hub is a read model. Write workplan files in the repo, then run
statehub fix-consistency --repo <repo>; its sync step pushes. Never register workplans or tasks by hand. - Do not run
git pushyourself unless asked. The fix-consistency sync push is fine. Leave other people's uncommitted files alone, and stage by explicit path. - The hub's needs-human prompt text (
intervention_note) is not synced by fix-consistency. If you change it in a workplan file, the dashboard keeps showing the old text.