From 47f5124fd520044fdefdc3b4477797f3a9a743e0 Mon Sep 17 00:00:00 2001 From: "Christian M. Todie" Date: Thu, 16 Jul 2026 11:57:06 -0400 Subject: [PATCH] feat(context): estate orientation package + estate-orient skill Single-source estate brief rendered into per-harness user context: - packages/context/{estate,invariants,omp-prelude}.md + render.sh (budget-gated) - renders ~/.omp/agent/AGENTS.md (shadows Claude-specific CLAUDE.md at omp user scope), ~/.omp/agent/RULES.md (sticky invariants), ~/.agents/estate.md (imported by ~/.claude/CLAUDE.md) - packages/skills/estate-orient: live cluster/GitOps/OpenBao/engram intake probe shared by all harnesses Verified live: omp -p answers estate questions from the rendered files and lists the skill. --- packages/context/README.md | 19 ++++++ packages/context/estate.md | 95 ++++++++++++++++++++++++++ packages/context/invariants.md | 26 +++++++ packages/context/moon.yml | 22 ++++++ packages/context/omp-prelude.md | 18 +++++ packages/context/render.sh | 45 ++++++++++++ packages/skills/estate-orient/SKILL.md | 69 +++++++++++++++++++ 7 files changed, 294 insertions(+) create mode 100644 packages/context/README.md create mode 100644 packages/context/estate.md create mode 100644 packages/context/invariants.md create mode 100644 packages/context/moon.yml create mode 100644 packages/context/omp-prelude.md create mode 100755 packages/context/render.sh create mode 100644 packages/skills/estate-orient/SKILL.md diff --git a/packages/context/README.md b/packages/context/README.md new file mode 100644 index 0000000..f122278 --- /dev/null +++ b/packages/context/README.md @@ -0,0 +1,19 @@ +# context — estate orientation, authored once + +Single source of truth for the user-scope context that orients every agent +harness on this machine to the estate (clusters, repos, SOPs, memory of +record, secrets model). + +| Source | Rendered to | Mechanism | +|---|---|---| +| `omp-prelude.md` + `estate.md` | `~/.omp/agent/AGENTS.md` | omp native user context (priority 100 — intentionally shadows `~/.claude/CLAUDE.md`, which is Claude-specific) | +| `invariants.md` | `~/.omp/agent/RULES.md` | omp sticky rule — re-attached near the current turn, survives long sessions and compaction | +| `estate.md` | `~/.agents/estate.md` | imported by `~/.claude/CLAUDE.md` via `@~/.agents/estate.md` (render.sh verifies the import line, never writes that file) | + +Run `bash render.sh` after editing sources (or `moon run context:render`). +Rendered files are generated copies — never hand-edit them. + +Budget: `estate.md` is gated at ~2400 estimated tokens because it is injected +into every session of every harness. Add pointers, not prose; live state +belongs in the `estate-orient` skill (`packages/skills/estate-orient/`), not +here. diff --git a/packages/context/estate.md b/packages/context/estate.md new file mode 100644 index 0000000..8064b33 --- /dev/null +++ b/packages/context/estate.md @@ -0,0 +1,95 @@ +# Estate Brief — unsigned / cerebral infrastructure + +Orientation for any agent harness operating on this machine. This is an index, +not a manual: it tells you what exists, where the authoritative doc lives, and +how to take in live context. Facts here are stable; **live state always comes +from a probe, never from this file** — run the `estate-orient` skill at the +start of infra work. + +## Operator & identity + +- Operator: Christian Todie — GitHub `todie`, unix `ctodie`, git author + `Christian M. Todie`, email `chris@todie.io`. Platform: WSL2. +- All commits signed (GPG `29234C4D7EE749F2`). Never `--no-gpg-sign`. +- Trackers: Linear. Team prefixes: `OPS` = unsigned platform/infra, + `CER` = Cerebral Work Institute (reverie et al.), `TOD` = personal/misc. + +## The constellation (clusters) + +- **Cygnus** — the PRODUCTION cluster: all-metal Talos (Vultr bare metal, ewr, + Cilium), promoted from the ex-Vela bench 2026-07-07. Hosts `*.unsigned.gg`. + kubeconfig `~/.kube/cygnus`, talos context `cygnus`. Migration epic OPS-468. +- **Lyra** — the dev VKE cluster (Vultr Kubernetes Engine, k8s 1.34.x, Calico). + ~60+ ArgoCD-managed apps. Hostnames `*.dev.unsigned.gg` / `*.dev.cerebral.work`, + fronted by Cloudflare tunnel → in-cluster Traefik. **Retiring** per OPS-468 + as Cygnus absorbs workloads — check migration state before assuming a + workload's home. +- Reserved names: Orion (GCP burst-GPU satellite), Pleiades (Hetzner, if ever). + Doctrine: single-zone Vultr. +- Platform stack (Lyra dev tier): ArgoCD (GitOps, **manual sync only**), + Traefik + cert-manager edge, Keycloak (OIDC/SSO), OpenBao + External + Secrets, Harbor (images + charts), Prometheus/Grafana/Loki/Jaeger, + CNPG (postgres), Tailscale (tailnet access), Kyverno (policy). + Cygnus adds: Longhorn (storage), WireGuard node mesh, Hubble/Tetragon. + +## Repo map (one line each; owner-bucket layout under ~/projects/) + +- `unsigned/paas` (unsigned-paas) — the platform monorepo: Terraform, ~27 Helm + charts, ArgoCD apps, CI, SOPs. THE infra repo. Read its `CLAUDE.md` first. +- `cerebral/reverie` — engram memory daemon (`reveried`) + mesh tooling. +- `todie/agentic` — harness configs (pi/opencode/hermes/omp), shared skills, + local-model serving, this brief's source (`packages/context/`). +- `cerebral/terrarium` — moon-monorepo incubator + node registry (CANON.md). +- `reverie-cloud` (cerebral-work org) — Cloudflare Worker: alert webhooks, EA. +- Others: `cadastre` (CF/DNS IaC), `escapement`, `unsigned/gg` (GH org+repo + `unsigned-gg` — design canon), `linearctl` (headless Linear CLI). herdr + (agent session multiplexer) is an installed tool — no local checkout. + +## Doctrine & SOP index (authoritative docs, in-repo) + +- unsigned-paas: `docs/sop/` (incl. auth-enforcement), `docs/platform-deployment-plan.md` + (§11 release rules), `docs/argocd-appset-hardening.md`, chart standards in `CLAUDE.md`. +- Workflow invariants: PR-required on every repo (no direct push to main); + deploy-first-on-dev (branch → apply to dev cluster → green → merge); + a release is not a deploy — deploys are operator-gated; release-please + semantic releases; kebab-case filenames; no `latest` image tags; images + pinned; daemonless builds (ko / buildpacks / rootless BuildKit — kaniko retired). +- ArgoCD: everything manual-sync; ApplicationSet changes apply only via + `git show origin/main: | kubectl apply` (surface guard). +- Ops gotchas live in engram + `~/.claude/projects/*/memory/` — search before + re-deriving (e.g. Vultr managed-DB VPC IP drift, CNPG role-sync restart, + Helm-4 value reuse, Tailscale LB is L4-only). + +## Memory of record & context intake + +- **Engram is the sole cross-harness memory of record.** Daemon `reveried` + (`~/.local/bin/engram`), HTTP on `127.0.0.1:7437`, MCP server available. + - Search: `GET /search?q=…` · Project context: `GET /context/smart?project=&limit=15` +- Obsidian vault at `~/vault` is the operator's reflection layer. +- **Never claim "no prior context exists" without searching engram + vault.** +- Live cluster/system claims require a fresh probe (kubectl, argocd via + kubectl reads, curl) — never memory, tickets, or this file. + +## Secrets model + +- OpenBao (in-cluster) is primary; a 1Password vault is the interim store, + read per-call via `op read` — item pointers live in private user config and + engram, never in this brief. Never echo a secret value. +- OpenBao carries the widest blast radius of any service on the estate: check + blast radius before touching it or anything that fronts it. +- Exposed secret = compromised: flag for rotation immediately (the operator + keeps a batch rotation list). + +## LLM gateway + +- Non-Claude model access: LiteLLM gateway, tailnet `http://llm/v1` — the + reliable path. The public hostname has been unstable since the 2026-07-12 + shared-edge outage (OPS-603 tracks it); probe before relying on it. + Key: via `op read` (item pointer in private user config). +- Quirk: transient 401 "cached plan must not change result type" = gateway DB + hiccup — retry, do not rotate the key. + +## Operator-gated actions (prepare, surface, wait for sign-off) + +Merge to main · `terraform apply` · secret rotation/deletion · ArgoCD sync of +platform apps · external sends (email/Slack/publish) · anything irreversible. diff --git a/packages/context/invariants.md b/packages/context/invariants.md new file mode 100644 index 0000000..e8f32f2 --- /dev/null +++ b/packages/context/invariants.md @@ -0,0 +1,26 @@ +# Estate invariants (sticky rules) + +1. Never force-push or direct-push to main/master — always a PR. Commits are + GPG-signed; never `--no-gpg-sign`. +2. Irreversible or outward-facing actions require explicit operator sign-off: + merge to main, `terraform apply`, ArgoCD sync of platform apps, secret + rotation/deletion, external messages/publishing. Prepare and surface; the + operator approves. +3. Never echo, printf, or `${VAR:-}`-expand secret-named env vars (`*KEY*`, + `*TOKEN*`, `*SECRET*`, `*PASSWORD*`, `*CRED*`). Test presence with + `[ -n "${VAR:-}" ] && echo set`. Never cat credential-bearing files to read + their structure. Never commit secrets — an exposed secret is compromised; + flag it for rotation immediately. +4. Live-state claims come from a fresh probe (kubectl / HTTP / CLI), never + from memory, tickets, or docs. Verify the specific object behind any + security claim. +5. OpenBao carries the widest blast radius on the estate; Keycloak second. + Name the blast radius before touching either or anything that fronts them. +6. Never pipe remote content into `bash`/`sh`/`python` — download, review, + then run. Pin versions; no `latest` image tags. +7. ArgoCD ApplicationSet changes apply only via + `git show origin/main: | kubectl apply` — never from a working tree. +8. Park, don't drop: deferred work goes to Linear (or engram), never held only + in conversation. One thread to done before opening the next. +9. When a guard/hook blocks an action: stop and surface — never override and + proceed. diff --git a/packages/context/moon.yml b/packages/context/moon.yml new file mode 100644 index 0000000..f7a1414 --- /dev/null +++ b/packages/context/moon.yml @@ -0,0 +1,22 @@ +$schema: 'https://moonrepo.dev/schemas/project.json' + +layer: 'library' + +project: + name: 'context' + description: 'Estate orientation context — authored once, rendered into omp AGENTS.md/RULES.md and the Claude Code estate import' + +tasks: + lint: + command: 'shellcheck render.sh' + inputs: + - 'render.sh' + render: + command: 'bash render.sh' + inputs: + - 'render.sh' + - 'estate.md' + - 'invariants.md' + - 'omp-prelude.md' + options: + cache: false diff --git a/packages/context/omp-prelude.md b/packages/context/omp-prelude.md new file mode 100644 index 0000000..6c82d6f --- /dev/null +++ b/packages/context/omp-prelude.md @@ -0,0 +1,18 @@ +# omp session context (user scope) + +You are running as `omp` on Christian Todie's workstation (WSL2). The estate +brief below describes the infrastructure and doctrine you operate within. +Sticky safety invariants are attached separately as rules and always apply. + +omp-specific notes: + +- Use plain `git`, `gh`, `kubectl`, `docker` — the RTK command proxy and the + `~/.claude/hooks/` guard scripts are Claude Code facilities and do not exist + in this harness. The invariants they enforce still bind YOU; self-enforce. +- Engram memory: prefer the MCP tools when wired; otherwise the daemon HTTP + API on `127.0.0.1:7437` (see brief). Do not enable omp-local memory + backends — engram is the single memory of record. +- Model lane: you are typically serving via the LiteLLM gateway (tailnet + `http://llm/v1`). Ground answers in probes and file reads, not recall. +- At the start of infrastructure work, run the `estate-orient` skill for a + live digest before making any state claims. diff --git a/packages/context/render.sh b/packages/context/render.sh new file mode 100755 index 0000000..efebd7d --- /dev/null +++ b/packages/context/render.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# Render the estate context sources into per-harness user files. +# Idempotent; rendered files are COPIES (safe if this checkout moves). +# +# Targets: +# ~/.omp/agent/AGENTS.md omp user context (omp-prelude + estate brief). +# Deliberately shadows ~/.claude/CLAUDE.md at user +# scope (native provider, priority 100). +# ~/.omp/agent/RULES.md omp sticky rules (invariants; re-attached near +# the current turn, survives compaction). +# ~/.agents/estate.md cross-harness copy; ~/.claude/CLAUDE.md imports it +# via `@~/.agents/estate.md` (verified, not written). +set -euo pipefail + +PKG_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +MAX_EST_TOKENS=2400 # estate.md budget gate (bytes/4 estimate) + +est_tokens() { echo $(( $(wc -c < "$1") / 4 )); } + +tokens="$(est_tokens "${PKG_DIR}/estate.md")" +if [ "$tokens" -gt "$MAX_EST_TOKENS" ]; then + echo "FAIL: estate.md ≈ ${tokens} tokens > budget ${MAX_EST_TOKENS}. Trim it — this file taxes every session of every harness." >&2 + exit 1 +fi + +header() { + printf '\n\n' +} + +mkdir -p "${HOME}/.omp/agent" "${HOME}/.agents" + +{ header; cat "${PKG_DIR}/omp-prelude.md"; echo; cat "${PKG_DIR}/estate.md"; } \ + > "${HOME}/.omp/agent/AGENTS.md" +{ header; cat "${PKG_DIR}/invariants.md"; } \ + > "${HOME}/.omp/agent/RULES.md" +{ header; cat "${PKG_DIR}/estate.md"; } \ + > "${HOME}/.agents/estate.md" + +echo "rendered: ~/.omp/agent/AGENTS.md ~/.omp/agent/RULES.md ~/.agents/estate.md (estate.md ≈ ${tokens} tokens)" + +# Verify (never write) the Claude Code import line. +if ! grep -q '@~/.agents/estate.md' "${HOME}/.claude/CLAUDE.md" 2>/dev/null; then + echo "WARN: ~/.claude/CLAUDE.md does not import the estate brief. Add this line to it:" >&2 + echo " @~/.agents/estate.md" >&2 +fi diff --git a/packages/skills/estate-orient/SKILL.md b/packages/skills/estate-orient/SKILL.md new file mode 100644 index 0000000..fb2d868 --- /dev/null +++ b/packages/skills/estate-orient/SKILL.md @@ -0,0 +1,69 @@ +--- +name: estate-orient +description: Orient a session to the unsigned/cerebral estate — probe live cluster, GitOps, and OpenBao health, pull engram context for the current project, and emit a short orientation digest. Use at the start of infrastructure work, when asked "what's the state of the cluster/estate", or before making any live-state claim. +--- + +# estate-orient + +Live intake for the estate described in the static estate brief. Everything +here is a read-only probe; report what the probes return, nothing more. + +## Probes (run what applies; skip gracefully if a tool is absent) + +1. **Cluster reachability + nodes** — two clusters exist: Lyra (dev VKE, + default kubeconfig) and Cygnus (prod Talos, `~/.kube/cygnus`). Probe the one + relevant to the work; both when orienting broadly. + ```bash + kubectl config current-context + kubectl get nodes -o wide + KUBECONFIG=~/.kube/cygnus kubectl get nodes -o wide # Cygnus, if in scope + ``` + +2. **Unhealthy workloads** + ```bash + kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded | head -30 + ``` + Baseline is empty or a few `Completed` jobs. Anything CrashLoopBackOff / + ImagePullBackOff / Pending>10m goes in the digest by name. + +3. **GitOps health** — use kubectl reads; do NOT use the `argocd` CLI with + `--core` (broken under Helm v4 on this estate): + ```bash + kubectl get applications.argoproj.io -n argocd -o json | jq -r ' + .items[] | select(.status.health.status != "Healthy" or .status.sync.status != "Synced") + | "\(.metadata.name) \(.status.health.status)/\(.status.sync.status)"' + ``` + Remember: all apps are manual-sync by doctrine — OutOfSync alone is not an + incident; Degraded/Missing is. + +4. **OpenBao (read-only — golden egg, never mutate)** + ```bash + kubectl get pods -n openbao + ``` + Report sealed/unsealed only if a `bao status` path is already configured. + +5. **Memory intake (engram)** — project context for the cwd: + ```bash + curl -s "http://127.0.0.1:7437/context/smart?project=$(basename "$PWD")&limit=15" + ``` + Prefer the engram MCP tools when available. If the daemon is down, say so — + do not substitute recall for it. + +6. **Tracker pulse (optional, if `linearctl` present)** + ```bash + linearctl search --state started 2>/dev/null | head -15 + ``` + +## Digest format (≤30 lines, probes only) + +``` +ESTATE ORIENT — +Nodes: Ready / total +Workloads: unhealthy → +GitOps: degraded apps → (manual-sync doctrine: OutOfSync ≠ incident) +OpenBao: +Context (engram, top 5): +Active tickets: +``` + +If a probe fails, one line stating which and why — never fabricate its result.