All phases (2–7) are complete. This document is now a build record + rollback reference. All commands assume the Mac Mini host with
/Users/deepg/.hermesas the Hermes home.
Four profiles exist at /Users/deepg/.hermes/profiles/{oracle,arch,eureka,aurus} with:
- Correct
SOUL.mdidentities (no cross-bleed) - Per-profile
config.yaml(one channel each, correct models, WhatsApp off for specialists) - Clean specialist
memories/MEMORY.md(empty index); sharedmemories/USER.md(user facts) SHARED_FOUNDATION.mdsymlinks resolving correctlypersonas/directories removed.env.shared(no Discord tokens),secrets/oracle.token,sync-profile-envscript in place
Deviations from original spec:
channel_prompts: {}left as empty dict (harmless under Option C)whatsapp:block present butenabled: falsein specialist configs — verified before cutover
All four Discord bot tokens exist under /Users/deepg/.hermes/secrets/{oracle,arch,eureka,aurus}.token (mode 600), and per-profile .env files are generated. The build steps below are preserved for re-creating the setup on a new host.
For each of Arch, Eureka, Aurus:
- Create a Discord application + bot in the Developer Portal.
- Enable the MESSAGE CONTENT intent — without it the bot connects but receives empty message bodies.
- Copy the bot token.
- Invite the bot to the DeepG server with channel permission overwrites: View Channel / Send Messages / Read Message History on its own channel only, denied View Channel elsewhere.
Oracle's existing bot: no new application. Confirm it is a member of all four channels (for delegation via Discord-as-bus). It only free-responds in #oracle.
Write each token to its file, mode 600:
/Users/deepg/.hermes/secrets/arch.token
/Users/deepg/.hermes/secrets/eureka.token
/Users/deepg/.hermes/secrets/aurus.token
Each file contains only the token, nothing else.
The sync-profile-env script already exists at /Users/deepg/.hermes/bin/sync-profile-env. Run:
/Users/deepg/.hermes/bin/sync-profile-env
This generates profiles/<a>/.env for each agent from .env.shared + secrets/<a>.token. Mode 600, atomic write.
-
/Users/deepg/.hermes/secrets/{oracle,arch,eureka,aurus}.tokenall exist, mode600. - Each
profiles/<a>/.envexists, mode600, contains shared API keys and aDISCORD_BOT_TOKENline. - The four
DISCORD_BOT_TOKENvalues are four distinct strings. - All three new bots have the MESSAGE CONTENT intent enabled.
The four per-profile launchd services are installed and the old single ai.hermes.gateway plist has been removed. Steps below are preserved for re-deployment.
Zero new code — uses existing
hermes gatewaycommands.
- Phase 3 exit criteria all pass.
- All specialist configs have
platforms.whatsapp.enabled: false— CRITICAL (prevents WhatsApp bridge termination loops). - Confirm free disk space:
df -h ~.
hermes gateway stop
hermes gateway uninstall
This runs launchctl bootout and deletes /Users/deepg/Library/LaunchAgents/ai.hermes.gateway.plist.
This must happen before 4.3. If old + Oracle's new gateway both run, they share a Discord token — one connection gets dropped.
hermes -p oracle gateway install
hermes -p arch gateway install
hermes -p eureka gateway install
hermes -p aurus gateway install
Each invocation creates /Users/deepg/Library/LaunchAgents/ai.hermes.gateway-<agent>.plist with RunAtLoad=true and KeepAlive{SuccessfulExit=false}. Logs go to profiles/<agent>/logs/gateway.{log,error.log}.
-
hermes -p <agent> gateway status→ running, for all four agents. -
launchctl list | grep ai.hermes.gateway→ exactly four entries (ai.hermes.gateway-{oracle,arch,eureka,aurus}), no bareai.hermes.gateway. -
tail profiles/<a>/logs/gateway.logfor each → connected to Discord as its own bot, no token/intent errors.
In each channel, ask "Who are you and what is your domain?":
| Channel | Expected |
|---|---|
#oracle |
Oracle — life navigation / coordination |
#arch |
Arch — engineering / builder |
#eureka |
Eureka — knowledge / research |
#aurus |
Aurus — money / financial learning |
- Each agent answers as itself — no identity hedging.
- Each specialist responds only in its own channel.
- Oracle does not free-respond in
#arch/#eureka/#aurus. - WhatsApp self-chat still reaches Oracle.
Restart one specialist — hermes -p arch gateway restart — and confirm only Arch blips; Oracle, Eureka, Aurus stay connected; launchd brings Arch back within seconds.
ai.hermes.gateway-{oracle,eureka,aurus}— running.ai.hermes.gateway-arch— plist exists, not loaded in launchd. Start withhermes -p arch gateway start, or bootstrap first if the service was never loaded:launchctl bootstrap gui/$(id -u) /Users/deepg/Library/LaunchAgents/ai.hermes.gateway-arch.plist.- Old
ai.hermes.gatewayplist — removed.
Each profile owns its skills/ directory, managed by the in-tree skill curator. The canonical curation principle: start from the full set and remove conservatively — a missing needed skill is worse than one extra.
Curation intent per agent:
| Agent | Excluded domains | Rationale |
|---|---|---|
| Oracle | github, code review, mlops, gaming | Those are Arch territory |
| Arch | apple, media, research, social | Focused on building |
| Eureka | github, code, devops, mlops, finance | Focused on knowledge |
| Aurus | github, code review | Minimal: web, research, finance, obsidian, creative writing |
Exact bundled lists are tracked in each profile's skills/.bundled_manifest and evolve via curator runs — not pinned here to avoid drift.
The Fleet Communication Protocol v2 is deployed under /Users/deepg/.hermes/fleet/.
| File | Role |
|---|---|
fleet/PROTOCOL.md |
Canonical FCP spec — message taxonomy, anti-loop rule, full examples. Read on demand (cold path). |
fleet/STATE.md |
Live table: per-agent status (idle / active task / blocked). Each agent updates its own row; Oracle can update any row. |
fleet/EVENTS.md |
Append-only event log. |
fleet/CONTEXT.md |
Shared decisions and active projects. |
fleet/scripts/fcp_validate.py |
Validator for protocol/state files. |
Every cross-agent Discord message is prefixed with a tag. Terminal tags ([STATUS], [COMPLETE], [FYI], [ALERT]) are never replied to — this prevents acknowledgement loops. See ARCHITECTURE.md §6 for the full table.
Each agent's SOUL.md carries a compressed ~7-line FCP reference (channel map, delegate verb, anti-loop rule, state-file paths). Full spec is read from /Users/deepg/.hermes/fleet/PROTOCOL.md on demand. This hot/cold split cut FCP overhead by ~65% versus the v1 inline approach.
Channel IDs:
- Oracle:
discord:1465562736451911838 - Arch:
discord:1493461055618285670 - Eureka:
discord:1493461225567420416 - Aurus:
discord:1493461326662467624
| File | Purpose | Status |
|---|---|---|
fcp_analysis.py |
Measures FCP token cost per agent (hot path + cold path) and reports redundancy. | Working — uses Path.home() and flexible heading detection. |
fcp_savings.py |
Compares pre/post FCP v2 token footprint per agent. | Working — uses Path.home(). Before values are hard-coded historical measurements. |
scripts/preflight_parallel.py |
Tests parallel tool call control against Z.AI API. | Working — makes real model calls, requires GLM_API_KEY. |
scripts/preflight_tool_error.py |
Tests tool-error self-correction against Z.AI API. | Working — makes real model calls, requires GLM_API_KEY. |
fcp-v3/hooks/fcp_hook.py |
Core FCP v3 enforcement module (797 LOC, 53 tests, 93% coverage). | ✅ Deployed to ~/.hermes/fleet/hooks/fcp_hook.py |
fcp-v3/plugin/plugin.yaml |
Per-profile plugin manifest declaring FCP hooks. | ✅ Deployed to all 4 profiles |
fcp-v3/plugin/__init__.py |
Plugin entry point — loads hook module, registers callbacks. | ✅ Deployed to all 4 profiles |
scripts/deploy_phase7.sh |
One-command deploy script for Phase 7. | ✅ Used during cutover |
scripts/patch_soul.py |
Patches SOUL.md files with FCP v3 stubs. | ✅ Applied to all 4 profiles |
scripts/regression_phase7.py |
Regression test runner for Phase 7 exit criteria. | ✅ Passed |
Both fcp_analysis.py and fcp_savings.py read from live profile SOUL.md files and fleet/PROTOCOL.md.
Cutover date: 2026-05-29. Live since then; verified 2026-06-02.
| File | Role |
|---|---|
~/.hermes/profiles/<agent>/plugins/fcp/plugin.yaml |
Per-profile plugin manifest — hooks declared, enabled via config.yaml plugins.enabled: [fcp] |
~/.hermes/profiles/<agent>/plugins/fcp/__init__.py |
Plugin entry point — loads hook module, registers callbacks |
~/.hermes/fleet/hooks/fcp_hook.py |
Core enforcement module — 797 LOC, 53 tests, 93% coverage |
~/.hermes/fleet/chains.jsonl |
Append-only chain ledger (created on first run) |
| SOUL.md v3 stubs | Deployed to all 4 profiles — compressed FCP v3 reference replacing v2 inline prose |
| Hook point | Direction | Purpose |
|---|---|---|
pre_tool_call |
Outbound | Validates send_message calls — enforces DAG, chain lifecycle, duplicate detection |
pre_gateway_dispatch |
Inbound | Parses incoming Discord messages — extracts FCP tags, chain IDs, feeds state machine |
pre_llm_call |
Internal | Resets per-turn budget counters — prevents multi-send within a single LLM turn |
- Outbound hook blocked
MULTIPLE_SENDS_PER_TURN: A live agent attempted twosend_messagecalls in one turn; the hook rejected the second with theMULTIPLE_SENDS_PER_TURNreason code, confirming structural enforcement is active and effective.
- Schedule: every 60 minutes (watchdog pattern)
- Mechanism: Hermes cron job checks
chains.jsonlfor stale open chains, agent liveness viaSTATE.md, and hook health. Alerts on anomalies.
All four profiles (oracle, arch, eureka, aurus) received updated SOUL.md stubs containing the compressed FCP v3 hot-path reference. This replaces the v2 inline approach and reduces per-message FCP overhead by ~65% (~80 tokens vs v2 ~187 tokens).
- Plugin installs per-profile at
~/.hermes/profiles/<agent>/plugins/fcp/— not global - Plugin manifest is
plugin.yaml(notplugin.toml) - Plugin entry is
__init__.py(nothandler.py) - Each profile's
config.yamlhasplugins.enabled: [fcp] - Agents continue using
send_messagewith[TAG]\nchain=<uuid|absent>prefix — no new tool
To undo cutover and restore single-process gateway:
hermes -p <agent> gateway uninstallfor each of the four.hermes gateway install(no-p) — recreatesai.hermes.gatewayfrom/Users/deepg/.hermes, which still has its original.env,config.yaml, andSOUL.mduntouched. Single-process fleet is back.
To undo Phase 2 entirely: rm -rf /Users/deepg/.hermes/profiles /Users/deepg/.hermes/secrets /Users/deepg/.hermes/.env.shared /Users/deepg/.hermes/bin/sync-profile-env /Users/deepg/.hermes/fleet (after uninstalling the per-profile services first).
A full /Users/deepg/.hermes backup exists from Phase 2 Step 0 as the deep safety net.