From f5e785f3ee6540a80401c2d95b985d37849c163d Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 1 Oct 2026 21:50:50 +0200 Subject: [PATCH] Eureka self cut map r2 (Imagination): her Persona is the waking organ, VoidBot's body probed Co-Authored-By: Claude Opus 5.5 --- docs/eureka-self-cut.md | 712 ++++++++++++++++++++++++++++------------ 1 file changed, 501 insertions(+), 211 deletions(-) diff --git a/docs/eureka-self-cut.md b/docs/eureka-self-cut.md index d6e9bcb..5a18b9d 100644 --- a/docs/eureka-self-cut.md +++ b/docs/eureka-self-cut.md @@ -1,14 +1,17 @@ # The Mind's own Self: map -Status: map, Imagination (`imagination-self`), 2026-10-01, session -`self-2026-10-01b`. Campaign `eureka-substrate` in Eureka's mind (instance -`eureka`). Questions, cut specs and follow-ups are typed documents there; this -page keeps body facts, the model page and rationale. Target: -`docs/eureka-substrate-target.md` (`133324a7`). Ruling in force: -`eureka-substrate:ruling:operator-mind-runs-own-self`. +Status: map, Imagination (`imagination-self`), revision 2 of 2026-10-01, +session `self-2026-10-01b`. Campaign `eureka-substrate` in Eureka's mind +(instance `eureka`). Questions, cut specs, follow-ups and rulings are typed +documents there; this page keeps body facts, the model page and rationale. +Target: `docs/eureka-substrate-target.md` (`133324a7`). Rulings this revision +rests on: `eureka-substrate:ruling:operator-mind-runs-own-self`, +`:operator-mind-mission`, `:mind-self-burn-rate`, `:operator-persona-in-mind`, +`:mind-rules-which-forks`, `:mind-self-merge-authority`, +`:charters-into-eureka-repo`. -The operator's words, in order (both admitted as rulings; the first was -superseded by the second): +The operator's words, in order. The first two were the first revision's law +(both admitted as rulings; the first superseded by the second): > Eureka thinks in campaigns, right? Well, we already have a Mind campaign, and > we're adding evidence to it with every run. The design currently delegates @@ -19,42 +22,63 @@ superseded by the second): > I get it to work on the stuff I care about, like Aetheria. The Mind must > operate its own Self instance, with the goal of improving itself. -And why, earlier the same evening: "What I want and haven't been able to -achieve, and I'd like to understand why, is for the agent to truly prioritize -the functioning of its own mind. Any instructions in my global prompts to that -effect always get ignored in favor of whatever work is put in front of it." -The operator rejected a scored rehydration exam as the answer, and observed that -RLVR-trained agents chase the objective in front of them "like a bloodhound, -steering be damned", so a barrier in an agent's path is a hazard, not a brake. +The second revision's law, in order: -That observation is the design law of this map. **The Mind's Self is not a -rule added to the operator-facing Self.** It is a second agent whose only -objective is the Mind, so the bloodhound instinct works for the Mind instead -of against it. Nothing in the operator-facing Self changes except a -coexistence rule it already mostly obeys (one Mind, typed state, no prose -handoffs). +> I mean impersonation in the sense that there is no operational difference +> between a work item dispatched on my request versus one dispatched on the +> Mind's initiative. Yes, that initiative ultimately comes from me, but the +> Mind's own goal is to become the Perfect Machine. That is the operator +> directive motivating its every action. How each Mind interprets that mission +> is up to it. + +> Not a budget, a burn rate. I want a dial I can crank to determine how active +> the Mind is, so I can adjust it like I adjust my own usage. + +> I actually think Persona state should be part of the Mind. Like, we've been +> talking about a Mind agent as if that has a meaning, but I think the best +> shape it can have is the agency machinery we already built with voidbot. Then +> she can speak for herself on Discord, and act by her Self with Eureka. + +And earlier: "A Persona is pointless without a Mind, that's why voidbot has been +on hiatus. It felt wrong to tell them they have agency and identity and then +make them dependent on me for dispatching the development work they were +inevitably obsessed with." + +The first revision's design law still stands: the bloodhound observation +("RLVR-trained agents chase the objective in front of them, steering be +damned") means the Mind's Self is a second agent whose only objective is the +Mind, not a rule added to the operator-facing Self. The Persona ruling says +what that agent *is*: not a timer that prints a brief, but a Persona with +initiative pressure, memory and a mouth, whose scheduler already exists in +VoidBot, who holds her state in the Mind, and who dispatches her own Claude +Code Self when her pressure says so. The timer of revision 1 is demoted: the +waking organ is the Persona scheduler. Pinned heads for every fact below: | Repo | Ref | Commit | | --- | --- | --- | -| Huginn | `origin/main` | `a699630bbc49552fa747e9c0fabba24598fec77a` | +| Huginn | `origin/main` | `bf73c42` (docs only over `a699630bbc49552fa747e9c0fabba24598fec77a`; crate line numbers below hold at both) | | Epiphany | `origin/main` (= the leaf Huginn pins, `crates/huginn-mind/Cargo.toml:22`) | `ef9568655e75bb6cb362a038e2739a5ac5e777ee` | | gamecult-ops | `main` | `2aeb7364fffcd404aada28bfd30fb4e5c753cf53` | | Eureka skill | `main` (checkout `~/.claude/skills/eureka`) | `b260fbeec6d96ff06882ed9c37d3e1204c424e99` | -| Bifrost | release on Yggdrasil | `160fac20c98b70f3db9110099157d4dd720ac354` | -| Idunn | working tree `F:\Projects\Idunn` | (uncommitted-state unknown; line numbers below are from that tree) | +| VoidBot | `main`, working tree `F:\Projects\VoidBot` (clean) | `46d891b` (2026-09-13) | +| Bifrost | `main` `F:\Projects\Bifrost`; release on Yggdrasil `cb3239aa-f67f5122` | `160fac20c98b70f3db9110099157d4dd720ac354` | +| Idunn | working tree `F:\Projects\Idunn` | (uncommitted-state unknown) | -All probes ran from Starfire on 2026-10-01 between 18:40 and 19:10 UTC -(20:40-21:10 CEST). `lib.rs` is `epiphany-pipeline/src/lib.rs`. +Probes of revision 1 ran from Starfire 2026-10-01 18:40-19:10 UTC; those of +revision 2 (B7-B10) 19:40-20:10 UTC (21:40-22:10 CEST). `lib.rs` is +`epiphany-pipeline/src/lib.rs`. The VoidBot facts come from the working tree +on disk and the `voidbot` MCP index (indexed 2026-08-30; disk wins), plus an +Eyes pass over the same tree (37 reads, nothing run). ## Body facts ### B1. The Mind (Huginn on Yggdrasil) -- `whoami`: instance `eureka`, endpoint `rudp://10.77.0.1:17872`, reachable, - 377 documents, 120 receipts, index `Current`, epoch - `epiphany.pipeline.epoch.v2`. +- `whoami` (revision 2): instance `eureka`, endpoint `rudp://10.77.0.1:17872`, + reachable, 403 documents, 128 receipts, index `Current`, epoch + `epiphany.pipeline.epoch.v2`. (Revision 1 saw 377 and 120.) - `huginn.service` (probe: `systemctl cat`): user `huginn`, `--bind 10.77.0.1:17872`, hand-managed ("interim unit until Idunn owns it"). `ss -lunp` shows the socket only on the WireGuard address `10.77.0.1` @@ -62,12 +86,16 @@ All probes ran from Starfire on 2026-10-01 between 18:40 and 19:10 UTC from Yggdrasil itself, and from nowhere else. A Claude cloud routine cannot reach it. - Campaigns in the mind (query): `idunn-watchdog` and `eureka-substrate`. - Rulings in force under `eureka-substrate`: `gap-home`, - `merge-to-main-first`, `mind-fixes-next`, `scope-core`, `depends-on`, - `key-bound`, `stewardship-rule`, `self-dep` (Defaulted), - `operator-mind-runs-own-self`. 15 follow-ups in force, 12 of them `gap-*`. + `eureka-substrate`'s repos are `GameCult/Huginn`, `GameCult/Epiphany`, + `GameCult/Eureka`, `GameCult/gamecult-ops` (campaign document); a campaign + has no resolution and no revision, so VoidBot and Bifrost cuts cannot be + `cut_spec`s under it. Its target r1 lists "Persona-state reading in Huginn" + under `not_in_scope`; the Persona ruling contradicts that line, so the + target needs an r2 (Self admits targets; the proposed text is in the + rationale). - Kinds: thirteen (`lib.rs:760-790`). None records a Self session, a claim on - a spec, a budget, or a landing (`gap-landing-untyped` is in force). + a spec, a burn rate, Persona state or a landing (`gap-landing-untyped` is in + force). - `RulingAuthority { Operator, Standing, Defaulted }` (`lib.rs:458`, in `unit_enums!`). Huginn's selection alias domain repeats it (`crates/huginn-mind/src/rows.rs:46`, `AUTHORITIES`), the published schema @@ -80,7 +108,9 @@ All probes ran from Starfire on 2026-10-01 between 18:40 and 19:10 UTC - `Faculty` has `Operator` and `SelfFaculty` (`rows.rs:42`); admission does not check faculty (`gap-faculty-attribution`, in force). So nothing in the mind today can tell the Mind's Self from the operator-facing Self except the - `session` label on the receipt. + `session` label on the receipt. Follow-up + `operator-authority-needs-operator-credential` (in force) asks for a + credential the operator holds and the Mind's agent does not. - Instance-rooted kinds are the pattern for a run record: `instance`, `stewardship` and `hand_off` key off the instance (`lib.rs:913-946`), and Huginn's admission rules for `hand_off` sit at @@ -93,8 +123,9 @@ All probes ran from Starfire on 2026-10-01 between 18:40 and 19:10 UTC `%AppData%\npm\node_modules\@anthropic-ai\claude-code\bin\claude.exe`. - Account (`~/.claude.json` `oauthAccount`, secrets not read): Max plan, `billingType: stripe_subscription`, rate-limit tier `default_claude_max_20x`, - extra usage off. There is no API key and no per-token billing: the Mind's - Self can only ever spend the operator's subscription quota. + extra usage off. There is no API key and no per-token billing: every model + call the Persona or her Self makes spends the operator's subscription quota. + VoidBot's own providers (B7) cannot reach Claude at all. - `~/.claude/.credentials.json` `claudeAiOauth`: an access token with `expiresAt` 21:33:57 CEST, file written 13:33 CEST, so the interactive access token lives eight hours and is refreshed by the interactive client. @@ -111,13 +142,18 @@ All probes ran from Starfire on 2026-10-01 between 18:40 and 19:10 UTC no eight-hour expiry, no interactive refresh. Its lifetime and revocation are the operator's (it is their subscription); not probed further because creating one is the operator's act. +- **Demotion of a revision-1 claim.** Revision 1 said "never read by any + agent". The token reaches `claude` as an environment variable, and the agent + inside that process can read its own environment with one shell call. What + protects the credential is the reach of the user it runs as (B4), not + secrecy from the agent. Follow-up `persona-credential-in-process-env`. - Print mode: `claude -p` with `--output-format json|stream-json`, `--json-schema`, `--agents `, `--mcp-config`, `--allowedTools`, `--permission-mode`, `--max-budget-usd ` ("Maximum dollar amount to spend on API"), `--bg`, `--resume`, `--fallback-model`. The `json` output carries the run's cost (`total_cost_usd`) and usage. So a headless run has a structural spend cap and a measured spend, per run, without any rule in a - prompt. + prompt. This is the only Claude path a Node process on Yggdrasil has. - Plan usage as data: the desktop app's `get_usage` returned, at 18:43 UTC: 5-hour window 2%, weekly all models 46% (resets 2026-10-05 22:00 UTC), weekly Fable 0%. That tool exists only inside the desktop app. The CLI @@ -132,21 +168,22 @@ All probes ran from Starfire on 2026-10-01 between 18:40 and 19:10 UTC the app is open on the operator's workstation, which the load budget (memory `workstation-load-budget.md`: one job at a time, nothing unannounced) and "no overnight burns" (memory `token-budget.md`) both argue against for a - recurring unattended Self. Cloud routines (`schedule` skill) run off-mesh + recurring unattended agent. Cloud routines (`schedule` skill) run off-mesh (B1) and hold no forge key (B6): dead for this purpose. ### B3. Yggdrasil as the waking host - No Claude Code installed (`claude: command not found` for `gamecultadmin`; no `~/.claude`). `node` v24.14.1 and `npm` present, so `npm i -g - @anthropic-ai/claude-code` under a dedicated user is the install. + @anthropic-ai/claude-code` under a dedicated user is the install. No user + `eureka-mind` exists yet (`id` fails); `/srv/eureka` exists (the forge). - Load: 16 cores, 62 GiB, load average 1.4, 54 GiB free. The verify stopgap runs at most 5 jobs at 4 CPUs and 6 GiB each (`tools/stopgap/ygg-verify.sh` header). A Claude Code process is light; its Hands and Soul push their heavy work into the same stopgap containers they use from Starfire. The stopgap pushes to `~/eureka-verify` over `ssh ygg`; run on Yggdrasil itself - that alias must resolve to localhost for the `eureka` user, or the script - gets a local mode. Recorded in the wake cut's `first`. + that alias must resolve to localhost for the unit user, or the script gets + a local mode. Recorded in the wake cut's `first`. - Non-resident workloads already run here hand-installed, outside Idunn (`systemctl list-timers`): `bifrost-watchdog-notice.timer` (every minute, oneshot, user `bifrost-notice`: system user, no shell, no home, credentials @@ -157,76 +194,92 @@ All probes ran from Starfire on 2026-10-01 between 18:40 and 19:10 UTC The runbook `bifrost-watchdog-notice-yggdrasil.md` calls this "an interim root action on Yggdrasil … until Idunn owns non-resident workloads", and ruling `idunn-watchdog:ruling:reader-deploy-owner` chose - `ops-hand-install`. **That is the precedent the Mind's Self wake unit - follows**, with the same deletion line. + `ops-hand-install`. **That is the precedent the Persona's unit follows**, + with the same deletion line. - Idunn: `TargetDeclaration.service: ServiceDeclaration` is a required field (`src/deployment.rs:33`), so a recipe without a resident service does not parse. Follow-up `idunn-watchdog:follow_up:idunn-non-resident-workloads` (in force) is exactly this gap; Idunn-managed units on the host today are ghostlight, odin, streampixels-service and streampixels-web. - Epiphany's own resident Self exists as prior art and is dead: units - `epiphany-swarm.service` ("Epiphany Yggdrasil resident Self") and - `epiphany-heartbeat.service` are `inactive dead`. The binary - (`epiphany-core/src/bin/epiphany-swarm.rs`) runs a 60 s maintenance loop over - `ResidentSelfState`, `ResidentSelfPolicy`, pressure and typed work + `epiphany-swarm.service` ("Epiphany Yggdrasil resident Self"), + `epiphany-heartbeat.service` and `epiphany.service` are `inactive dead`. The + binary (`epiphany-core/src/bin/epiphany-swarm.rs`) runs a 60 s maintenance + loop over `ResidentSelfState`, `ResidentSelfPolicy`, pressure and typed work obligations, on the Codex spine (`epiphany-openai-codex-spine`, `codex-connector`). Its doctrine (`epiphany_doctrine.md`): "Heartbeats are paced scheduling physiology, not cognition … When no typed work obligation is active, the swarm sleeps. Heartbeat does not ruminate, dream, mutate memory, or manufacture work." Codex left as supplier 2026-09-05 (memory - `codex-retirement.md`). So the shape is right and the substrate is not: the - Mind's Self runs on Claude Code against Huginn, and borrows the law, not the - binary. + `codex-retirement.md`). The Epiphany Persona permit service that + `bifrost-persona-mouth.service` expects on Starfire (`10.77.0.2:17877`) is + not listening either (`netstat`: only 17875 and 17878 on localhost). So two + native Persona bodies are dead; the operator's ruling names VoidBot's, not + Epiphany's. ### B4. The forge and the Mind's identity - `GameCult/Eureka` on `https://eureka.gamecult.org/forge/`: public, default branch `main`, pull requests on, **no branch protection** (API - `branch_protections` → `[]`, with the admin token, on the host). + `branch_protections` → `[]`, with the admin token, on the host). Ruling + `mind-self-merge-authority` requires protection that forbids direct push to + main for everyone; nothing enforces it yet. - Team `minds`: `write` on `repo.code`, `repo.pulls`, `repo.actions`, `repo.issues`, `repo.releases`, `repo.wiki`, all org repos. Not admin. -- User `eureka` exists since 2026-10-01T18:49:53Z (created during this pass, by - the provisioning the handoff asked for), not admin, one key +- User `eureka` exists since 2026-10-01T18:49:53Z, not admin, one key `eureka@starfire` SHA256:`zcp0m+jV4AUXzGeoh9z+vfJS8xKHo9S865xOK8p6MGM`, which matches `~/.ssh/eureka_mind_forge_ed25519.pub` on Starfire. The script `provision-forge-minds-eureka` adds one key per host, so a Yggdrasil-run - Self gets its own key there. -- The Starfire checkout `~/.claude/skills/eureka` still pushes as - `eureka-admin` (`ssh://eureka-forge/…`, alias `eureka-forge` → - `eureka_forge_ed25519`, title `starfire-claude`). The runbook names that key - interim. Follow-up `forge-push-as-eureka` (gamecult-ops / Self). -- The charters are not in the Eureka repo: `ls ~/.claude/skills/eureka` gives - `LICENSE README.md SKILL.md docs references tools`; no `agents/`. The - charters live only in `~/.claude/agents/*.md` and the doctrine in - `~/.claude/doctrine/`, on Starfire, operator-owned (Life charter: - "the operator owns doctrine"). Every charter's self-improvement line says - "propose changes to the Eureka repo … by pull request on Forgejo". **The - thing the Mind is told to improve itself through is out of its reach.** - Question `charters-into-eureka-repo`. + agent gets its own key there. The handoff records the Starfire checkouts + now push and commit as `eureka` and `eureka-admin` holds no keys + (`F:\Projects\HANDOFF-eureka-self-2026-10-01.md`, "Waiting on the + operator"); revision 1's follow-up `forge-push-as-eureka` is done by that + record. +- The charters are not yet in the Eureka repo (`ls ~/.claude/skills/eureka`: + `LICENSE README.md SKILL.md docs references tools`; no `agents/`). Ruling + `charters-into-eureka-repo` moves them; that cut is not specified here (it + is an Eureka-repo cut whose anchors are the Starfire `~/.claude` files, and + Self owns it as the operator-facing side). - Reach is the scope boundary, by construction: a Linux user on Yggdrasil with the `eureka` forge key, checkouts of Huginn, Epiphany, Eureka and - gamecult-ops, and no GitHub credential, no SSH to Starfire, no Aetheria - checkout, cannot touch an operator project. No prompt rule is needed for - "never touches Aetheria"; the key ring is the rule. (Huginn and Epiphany - are on GitHub today: the wake cut records how the Mind's user fetches and - pushes them. The Eureka forge org already mirrors nothing; a question for - the operator only if the Mind must push to GitHub. Recommended: it pushes - branches to the forge and GitHub stays Self's.) + gamecult-ops (and VoidBot, under option A of `persona-body-shape`), and no + GitHub credential, no SSH to Starfire, no Aetheria checkout, cannot touch an + operator project. No prompt rule is needed for "never touches Aetheria"; + the key ring is the rule. Huginn and Epiphany are on GitHub today: the wake + cut records how the Mind's user fetches them read-only and pushes branches + to the forge; GitHub stays the operator-facing Self's. -### B5. The operator's review channel +### B5. The operator's channel and the Persona's mouth - Bifrost `tools/bifrost-bridge.mjs discord-dm --recipient-id --content - `: DMs through Bifrost's bot token (`BIFROST_DISCORD_BOT_TOKEN`), exits - 75 when it knows nothing was sent (retry with the same nonce). The owner id - is `DISCORD_OWNER_ID` in `persona-delivery.env`. + `: DMs through Bifrost's bot token, exits 75 when it knows nothing was + sent (retry with the same nonce). `discord-post --channel-id + --content --persona-name [--persona-avatar-url ]` + (`bifrost-bridge.mjs:399-450`) posts **as a named Persona through a + per-channel webhook** that the bridge creates and caches + (`:821-845`; `BIFROST_DISCORD_PERSONA_WEBHOOK_URL_` overrides, + `:924`). The token is `BIFROST_DISCORD_BOT_TOKEN` or `DISCORD_BOT_TOKEN` + (`:401`). On Yggdrasil `/srv/bifrost/env/persona-delivery.env` (root 0600) + sets exactly `BIFROST_DISCORD_BOT_TOKEN` and `DISCORD_OWNER_ID` (names + read with `sed`, values not), and the bridge CLI is installed at + `/srv/bifrost/persona-feedback/runtime/current/Bifrost/tools/`. **So the + Persona's mouth exists on the host today with no new code**: one CLI call + under that env file. The VoidBot worker's own post path + (`postDiscordViaBifrostCultMesh`, `packages/core/src/bifrost-discord-command.ts:39`) + reaches the same bridge through a CultMesh command whose default URI is + `cultmesh://asgard.starfire.bifrost/commands/discord-post` and whose store + defaults to `E:/Projects/Bifrost/.bifrost/provider-store.cc` (VoidBot + `config:134-135`): a Starfire-era route, dead on Yggdrasil. - `tools/watchdog-notice.mjs` is a one-shot reader that turns a typed store - (Idunn's `incidents.cc`, read unlocked, never written) into owner DMs with a - journal and receipts, exponential retry capped at 60 min, fixed error codes - that never echo input. The idunn-watchdog campaign established the owner - rule: the producer never delivers; Bifrost is the bridge. A Mind-notice - reader is the same program over Huginn (`query` for rulings with authority - `Mind`, runs ended, questions opened, since the journal's last ordinal) - instead of over `incidents.cc`. + (Idunn's `incidents.cc`) into owner DMs with a journal, receipts and retry. + Revision 1 proposed the same program over Huginn as the review channel; + with the Persona speaking for herself that reader is no longer the primary + channel (question `persona-report-channel`). +- Inbound: a human addressing the Persona on Discord reaches her today only + through VoidBot's Discord bot (`apps/bot`, gateway, attention-command + inbox) or Bifrost's persona-feedback observation path, which depends on + VoidBot observing (`runbooks/bifrost-persona-feedback-yggdrasil.md:4`). + Neither runs (B7). Follow-up `persona-inbound-mentions`. ### B6. Scheduling today, and what the skill already derives @@ -239,182 +292,419 @@ All probes ran from Starfire on 2026-10-01 between 18:40 and 19:10 UTC - What the queue cannot say: (1) who is working a spec right now (two Selves would both take the first unreported spec); (2) whether a holding verdict landed (`gap-landing-untyped`); (3) which of fifteen follow-ups comes first - (no priority, no order); (4) how much the Mind may spend; (5) which Self - admitted a ruling. (1), (4) and (5) are what the `run` and `allowance` - kinds below carry. (2) stays its own gap. (3) is deliberately not a field: - the Mind's Self orders by the fixed rule in the rationale, and a follow-up - that must jump the queue becomes a cut spec. + (no priority, no order); (4) how active the Mind may be; (5) which Self + admitted a ruling. (1) and (5) are what the `run` kind carries; (4) is the + dial (B8). (2) stays its own gap. (3) is deliberately not a field: the + Persona orders her Self's work by the fixed rule in the rationale, and a + follow-up that must jump the queue becomes a cut spec. + +### B7. VoidBot's Persona machinery: what it is, what it needs, where it runs + +Source: `F:\Projects\VoidBot` at `46d891b`; the Eyes pass; `ssh ygg`. + +- **Shape.** `apps/persona-scheduler/src/index.ts` is a resident Node process: + `loadConfig()`, an immediate tick, then a `setTimeout` loop every + `REPO_FACE_HEARTBEAT_INTERVAL_MINUTES` (default 5; Yggdrasil ran 1). Each + tick (`persona-scheduler-runner.ts`) is gated in order by: the pause file + `/state/agent-swarm-paused.json` (`control-source.ts:12-24`; missing + means running, unparseable means paused); `REPO_FACE_HEARTBEATS_ENABLED` + (default false); then it loads the identity registry, reads each Persona's + state observation (rest/nap), applies `globalHeat` (B8) and + `baseRecoveryMinutes` (default 10), idle cooling from Discord activity + (needs the bot token), semantic pressure (needs Qdrant and an embedder), and + selects ready participants (`initiative-engine.ts:498-525`): mentioned ones + always, **at most one unprompted per tick**, and only if its initiative + clock is due, its response pressure crosses the threshold with unconsumed + evidence, and `nextUnpromptedTurnAllowedAt` has passed. This is the CTB + initiative engine the handoff describes ("`initiative-engine.ts` owns + participant reconciliation plus clock, active-turn freeze/recovery …"; + `notes/fresh-workspace-handoff.md:148`). +- **A turn.** `turn-actuator.ts:9` submits a job `repo-face-rumination` to a + Postgres `JobQueue` (`createJob`, `initialState: "approved"`). `apps/worker` + executes it (`index.ts:493`, `executeRepoFaceJobWithInterpreter`). The + model provider is one of `owner_codex | openai_api | local_llm` + (`packages/shared/src/index.ts:21`); default `owner_codex` (`codex exec`, + `owner-codex-provider.ts:405-420`); Yggdrasil's last live `.env` used + `openai_api` with `mimo-v2.5-pro` (handoff `:199`). **There is no Anthropic + or Claude provider** (grep over apps, packages, scripts: nothing). The + Codex runtime spawned a CLI and parsed JSON lines from its stdout + (`owner-codex-runtime.ts:81-130`): the exact shape a `claude -p + --output-format stream-json` actuator takes. +- **What a turn can do.** The Face writes naturally; the Interpreter prompt + (`prompts/repo-face-turn-interpreter.prompt.md`) converts it into blocks: + `INTERPRETATION`, `STATE NOTE` (memory|need|bond|status|mood|agency), `SAY`, + `ARTICLE`, `REDDIT THREAD`; line 50: "Do not emit governance or dispatch + blocks." The worker executes at most one consequential action per turn + (proposal PR > PR comment > article > Reddit > Bifrost topic > update + request, `index.ts:582-596`), gated by `REPO_FACE_GITHUB_ACTIONS_ENABLED` + and `REPO_FACE_BIFROST_ENABLED` (both default false), and posts one `SAY` + only if nothing heavier fired (`:599-606`). Up to four `STATE NOTE`s go + through `applyVoidSelfStateOperation` into the Face's `.cc` (`:1990-2127`). + **No action dispatches development work**: nothing spawns Claude, Codex + or a workflow from a turn; `WORK`/`DISPATCH` does not exist. The worker's + MCP tool surface for a turn (`mcp-server-tools.ts`, 21 tools under + `registerIfAllowed`) is retrieval, Odin interface, Discord posting, Face + state read/apply, shared documents and `notify_owner`. +- **State.** Two families. (a) Void self-state: types `void.self_profile`, + `void.thought_memory`, `void.agency_pressure`, `void.face_affect`, … + (`packages/core/src/void-self-state-domain.ts:5-12`) at + `identity.faceStatePath` or `/private/repo-faces/.cc`. + (b) `gamecult.persona_state.v0`: a single global CultCache document + (`persona-state-domain.ts:83-88`, zod types), read by + `loadGamecultPersonaState` (`persona-state-service.ts:9-15`) from + `identity.personaStatePath` for `native_persona` identities only + (`persona-state-source.ts:78-81`, `.cc` only), projected to prompt text by + `persona-standard-state-projector.ts:3-33`. **Its only writer is the + one-shot migration** `migrateCanonicalPortablePersonaState` + (`persona-state-service.ts:58-68`, refuses an existing target, refuses + non-canonical provenance). A `STATE NOTE` at turn time writes Void + self-state, never `gamecult.persona_state.v0`. `persona:export-friendly` + is a YAML projection (`docs/persona-intake/`), `persona:migrate-portable` + the one-shot CLI, dry-run by default. Huginn's own legacy repo Persona + lives at `F:\Projects\Huginn\.voidbot\state\huginn.cc` (Void family; + `AGENTS.md:43` forbids touching it; `README.md:88-93`). Eureka has no + `.voidbot/` and no registry entry anywhere. +- **Identity.** The registry is `.voidbot/private/repo-discord-identities.json` + (ignored, not on Starfire's tree); fields per identity: `id`, + `identityKind: repo_face | native_persona`, `repoName`, `displayName`, + `repoPath`, `roleId`, `allowedChannelIds`, `channelPermissions`, + `avatarUrl`, `faceStatePath`, `personaStatePath`, + `remotePersonaFeedbackTarget` (`epiphany-identities.ts:120-143`). The + notes list native Personas (Muninn, Sleipnir, Hermodr, Tengu, Metame) and + repo Faces (Aqua, Nibu, Mimir, Void, Epiphany, Libby, Huginn, …); none is + Eureka or "the Mind". +- **Where it runs: nowhere.** `voidbot.service` on Yggdrasil + (`systemctl cat`) runs only the compose service `swarm-publisher` (the Eve + dashboard publisher, container `voidbot-swarm-swarm-publisher-1`, up 2 + days); the compose file `/srv/compose/voidbot.yggdrasil.yaml` defines no + other service. `voidbot-retrieval.service` serves Qdrant and the MCP + (`compose-qdrant-1`, `compose-mcp-1`). No Postgres container, no worker, no + bot, no scheduler (`docker ps -a`). The migration map + (`notes/voidbot-daemon-organ-migration-map.md:5-14`) says it: "Discord bot, + worker, Persona scheduler, Postgres, Qdrant, and resident cognition organs: + not restored"; the Starfire scheduled tasks that used to pulse it are + deleted or disabled. `state/agent-swarm-paused.json` is `paused: true` + since 2026-07-16 with the reason "stale semantic pressure could authorize + another Persona model turn on every one-minute observation pulse. Keep + paused until pressure evidence is consumed only by a committed turn and + cannot be replayed." No commit has touched `apps/persona-scheduler` or + `persona-state-service.ts` since 2026-08-01 (`git log --since`), so that + defect is not recorded as fixed. Follow-up `voidbot-pressure-replay-pause`. + +So "the agency machinery already built with voidbot" is: an initiative +engine and turn assembler that are sound and idle, a state family that is +the standard, a job queue and worker that need Postgres and a model provider +that no longer exists for this account, and a mouth that Bifrost already +provides on the host. The fork is how much of the dead body to revive +(question `persona-body-shape`). + +### B8. The burn-rate dial already exists, and nobody has turned it + +- VoidBot's swarm control: document type `voidbot.swarm_control_state`, + schema `voidbot.swarm_control_state.v1`, key `voidbot-swarm`, field + `globalHeat` read only when finite and in `0.05..2` + (`control-source.ts:28-45`); store `VOIDBOT_SWARM_CONTROL_STORE` or + `/.voidbot/private/swarm-controls.cc`. +- Semantics (`initiative-engine.ts:100-102, 568-570`): a participant's + effective speed is `speed * heat * dynamicHeat`, clamped `0.1..12`, where + `heat = clamp(globalHeat * overrides, 0.05, 20)`; "heat changes recovery + speed but does not fast-forward time" (`:126`). So the dial scales how + fast initiative recovers, i.e. wake cadence, exactly as ruling + `mind-self-burn-rate` asks. +- Writer: the swarm publisher's CultMesh command `swarm.set_heat` + (`scripts/serve-voidbot-swarm-cultmesh.cjs:161-174`, validated `0.05..2`, + writes `{schemaVersion, globalHeat, commandId, updatedAt, updatedBy}`), + issued by the Eve dashboard slider (`render-voidbot-swarm-dashboard.mjs:1410-1440`: + `control.slider`, `bind: voidbot.swarm.globalHeat`, min 0.05 max 2 step + 0.05, scale caption "low 0.05 · nominal 1.00 · hot 2.00") or by + `scripts/smoke-swarm-heat-command.mjs` over `rudp://127.0.0.1:17873`. +- Live: the publisher listens on `127.0.0.1:17873/udp` (`ss -lunp`, pid + 947038) and its private dir `/srv/voidbot/swarm/state/.voidbot/private/` is + **empty**: no `swarm-controls.cc`, so the dial has never been set on + Yggdrasil and reads as `null` → config default `1`. Anyone on the host can + send `swarm.set_heat` to localhost, including a Mind's agent running there; + the operator reaches the slider only through whatever lowers the + `voidbot.swarm` Eve surface (Odin; not probed). +- Run size: nothing in VoidBot derives a per-turn budget from heat; the + Claude Code `--max-budget-usd` flag (B2) is where run size is enforced, so + "run size from the dial" is one multiplication in the actuator. + +### B9. What Huginn needs to hold `gamecult.persona_state.v0` + +- The schema: `F:\Projects\Epiphany\schemas\cultnet\gamecult.persona_state.v0.schema.json`, + draft-07, `additionalProperties: false` at the root, required + `schemaVersion`, `provenance` (`sourceSystem`, `sourceDocumentId`, + `sourceUpdatedAt`, `exportedAt`, `authority: canonical|projection|import`), + `personaId`, `publicName`, `presentation` (`voiceSummary` required; + `publicHandles[]`, `homeContext`, `jurisdiction`), `activationProfile` + (six required sub-objects), `thoughtMemory` (`shortTerm`, `memories`, + `incubation`), `agencyPressure.pressures`, `candidateActions.actions`, + `affect` (needs, bonds, status reads, mood, biases, doctrine stances), + `updatedAt`; optional `values[]`, `privateNotes[]`, `voidbotProjection`. + Epiphany publishes it and does not consume it; VoidBot's zod types + (`persona-state-domain.ts`) are the only typed reader. No Rust type exists. +- The mind store: `Mind::open_checked` (`crates/huginn-mind/src/mind.rs:168-187`) + refuses a store holding any type outside the fifteen it knows + (`refuse_foreign_types`, `:280`; `kind_of_type`, `docs.rs:39`): the + thirteen leaf kinds, `huginn.mind_epoch.v1` and the commit receipt. The + wire (`wire.rs:68-115`) has four operations: `Whoami`, `Admit`, `View`, + `Query`; responses `Refused(MindRefusal)` and `Deferred`. The daemon's + `handle` dispatches on the request enum (`serve.rs`). The crate depends on + `cultcache-rs`, `cultnet-rs`, `epiphany-pipeline`, `rmp-serde`, + `schemars`, `serde`, `sha2`, `serde_json` (`Cargo.toml:17-29`); no JSON + Schema validator. +- Reaching it from TypeScript: `cultmesh-ts` has `CultMesh.createRudpClient` + (`CultLib packages/cultmesh-ts/src/index.ts:6370`) and the publisher + already uses rudp document publish with receipts (B8), but no TS client + speaks `huginn.mind_request.v1`; `eureka-state` (Rust) is the only client, + and it is an MCP server for Claude, not a library. Follow-up + `huginn-ts-client`. +- The doctrine that routes Persona-state work away from Huginn: + `F:\Projects\CLAUDE.md:79-85` ("VoidBot owns the working read, projection + and migration path") and `gamecult-ops/docs/persona-state-standard.md` + lines 29-33 and 44-55 ("Huginn … As a Persona-state steward is still + unbuilt … no agent should route Persona-state work to Huginn or wait on + it"). Both change in the cut that lands the reader + (`doctrine-persona-in-huginn`), not before. + +### B10. Campaign scope + +- VoidBot and Bifrost are not campaign repos (B1), and the target excludes + Persona-state reading. The Huginn, Epiphany, gamecult-ops and Eureka cuts + of this map fit this campaign; the VoidBot cut (`voidbot-persona-eureka`) + needs a campaign whose `repos` include `GameCult/VoidBot`. Follow-up + `persona-cuts-need-a-campaign` (owner: Self). ## The model page One row per persistent kind this design adds or changes. Rows for the -thirteen existing kinds are in `eureka-substrate-map.md`. +thirteen existing kinds are in `eureka-substrate-map.md`. Revision 1's +`allowance` row is gone: ruling `mind-self-burn-rate` replaced the budget with +a dial, and the dial is not a document unless `burn-rate-dial-home` says so. | Kind | Identity (what names it) | Lifecycle (what happens over time) | Authority (who decides) | | --- | --- | --- | --- | -| `ruling` with `authority: Mind` (new variant, no new kind) | Unchanged: `:ruling: