251 lines
7.8 KiB
Markdown
251 lines
7.8 KiB
Markdown
# HERMES.md — Hermes VM Architecture
|
||
# StarshipOS / StarForth — Captain Bob (Robert Allan James)
|
||
# This document constrains Claude Code behavior. Read it completely before touching Hermes.
|
||
|
||
---
|
||
|
||
## Language Constraint — Non-Negotiable
|
||
|
||
All Hermes implementation is in StarForth dialect ONLY.
|
||
|
||
This includes:
|
||
- Data structures
|
||
- Constants
|
||
- Variables
|
||
- Control flow
|
||
- Everything
|
||
|
||
C99 is forbidden unless explicitly blocked in StarForth AND explicit written permission
|
||
is given by Captain Bob for that specific construct. "I could not figure out how to do
|
||
this in StarForth" is not permission. Ask first. Wait for the answer.
|
||
|
||
If you are about to write a C struct, a #define, or a C variable — stop.
|
||
Implement it in StarForth or ask.
|
||
|
||
---
|
||
|
||
## What Hermes Is
|
||
|
||
Hermes is the messenger. He moves messages between VMs and manages channels.
|
||
That is his complete contract.
|
||
|
||
Hermes does **not** store persistent data — that is Artemis.
|
||
Hermes does **not** make lifecycle decisions — that is Hera.
|
||
Hermes does **not** route by load or heat — dispatch is capability-based, always.
|
||
|
||
Capsules are baked into the OS blob by mkcapsule.c at build time.
|
||
Hermes has no capsule cache, no fetch logic, no repository concern.
|
||
That is a future chapter.
|
||
|
||
---
|
||
|
||
## The Event Loop
|
||
|
||
Hermes runs a compudynamic event loop. Every message is a compudynamic object:
|
||
|
||
- Born hot (full heat at creation)
|
||
- Cools each heartbeat tick
|
||
- ACK received → clean death, K redistributed to fleet
|
||
- NACK received → requeue with reduced heat, or reaped if heat floor reached
|
||
- TTL expires (heat → 0) → Hermes reaps the message, K rebalanced
|
||
|
||
There is no special timeout logic. The physics handles it.
|
||
A message that nobody answers simply cools to death.
|
||
|
||
---
|
||
|
||
## Message Structure
|
||
|
||
Every message carries:
|
||
|
||
```
|
||
type — work type tag (determines recipient)
|
||
sender — originating VM identity
|
||
recipient — destination VM identity
|
||
payload — message body
|
||
heat — current thermal value (compudynamic)
|
||
sequence — monotonic sequence number
|
||
```
|
||
|
||
Point-to-point only. Sender addresses recipient directly.
|
||
Hermes delivers and tracks thermal state. He does not inspect payload.
|
||
|
||
---
|
||
|
||
## ACK/NACK Protocol
|
||
|
||
- ACK → message dies cleanly, K redistributed
|
||
- NACK → message requeued with reduced heat
|
||
- No response → message cools naturally to death via TTL
|
||
|
||
The binary receipt of a response IS the ACK where applicable.
|
||
No separate acknowledgement frame needed in those cases.
|
||
|
||
---
|
||
|
||
## PubSub — Channels
|
||
|
||
Hermes implements a publish/subscribe model. Topics are called **channels**.
|
||
|
||
### The Common Channel
|
||
|
||
There is one permanent channel: `COMMON`.
|
||
|
||
- Always exists, always hot
|
||
- Any VM can publish to it
|
||
- Used for negotiation and channel establishment only
|
||
- Not for business transactions — those happen on ephemeral channels
|
||
|
||
### Ephemeral Channels
|
||
|
||
Ephemeral channels are compudynamic objects — born hot, reaped when cold or closed.
|
||
|
||
**Channel structure:**
|
||
|
||
```
|
||
channel_id — owner VM identity + monotonic sequence number
|
||
owner — VM that created the channel (always the responder)
|
||
members[] — participant list
|
||
heat — compudynamic, born hot at creation
|
||
state — NEGOTIATING | OPEN | CLOSING
|
||
```
|
||
|
||
### The Negotiation Protocol
|
||
|
||
```
|
||
1. X publishes request on COMMON — born hot, TTL ticking
|
||
2. Y sees request, responds yes/no on COMMON
|
||
— No response → message cools to death → implicit NACK to X
|
||
3. Y accepts → Y creates ephemeral channel
|
||
→ Y publishes channel_id to X over COMMON
|
||
4. X and Y conduct business on ephemeral channel
|
||
5. Business concluded → owner Y reaps channel → K rebalanced
|
||
```
|
||
|
||
Y owns channel creation and destruction. Always the responder, never the requester.
|
||
A channel dying of cold (abandoned transaction) is not an error — the physics handles it.
|
||
|
||
### Multi-Party Channels
|
||
|
||
Channels are bilateral by default. The owner may invite additional VMs:
|
||
|
||
```
|
||
1. Owner publishes invite to candidate VM on COMMON
|
||
2. Candidate accepts or declines on COMMON — same TTL/cool protocol
|
||
3. Accept → candidate added to members[]
|
||
4. Decline or timeout → candidate never joins, channel continues bilateral
|
||
```
|
||
|
||
Multi-party is designed for but not implemented yet.
|
||
Do not implement invite logic until explicitly instructed.
|
||
The members[] structure must exist from the start to avoid future redesign.
|
||
|
||
### Channel Identity
|
||
|
||
`channel_id` = owner VM identity + monotonic sequence number.
|
||
Unforgeable by non-owners. Hermes mints it. No VM constructs its own channel_id.
|
||
|
||
### Compudynamic Invariant for Channels
|
||
|
||
Channels participate in K≡1.0.
|
||
An open channel with active messages holds heat.
|
||
Channel reap must redistribute K correctly to the fleet.
|
||
A channel cannot be reaped while messages on it are still in flight —
|
||
drain first, then reap.
|
||
|
||
---
|
||
|
||
## What Is Not Hermes
|
||
|
||
- **Capsule cache** — future chapter, not now
|
||
- **Remote fetch** — future chapter, not now
|
||
- **UDP server / client** — future chapter, not now
|
||
- **Instance authentication** — future chapter, not now
|
||
- **Persistent block storage** — that is Artemis
|
||
- **VM lifecycle decisions** — that is Hera
|
||
- **Heat-based routing** — wrong model, never implement
|
||
|
||
---
|
||
|
||
## Compudynamic Invariant
|
||
|
||
Every object Hermes manages — messages and channels — participates in K≡1.0.
|
||
Fleet K includes the thermal contribution of in-flight messages and open channels.
|
||
Hermes reaping a message or channel must rebalance K correctly.
|
||
|
||
Do not write code that breaks K≡1.0 and add a comment explaining why it's okay.
|
||
|
||
---
|
||
|
||
## Current Scope
|
||
|
||
1. Compudynamic event loop — message emit, drain, TTL, ACK/NACK, reap
|
||
2. COMMON channel — permanent, always hot, negotiation only
|
||
3. Ephemeral channels — compudynamic lifecycle, owner=responder, bilateral default
|
||
4. Channel negotiation protocol — request on COMMON, Y creates, Y reaps
|
||
5. members[] structure — present from the start, multi-party invite not yet implemented
|
||
|
||
Capsule management is a future chapter.
|
||
Remote repository is a future chapter.
|
||
Multi-party channel invite is a future chapter.
|
||
|
||
---
|
||
|
||
## v1 Block Map — LOCKED
|
||
|
||
Blocks 4110–4113 are Artemis. NEVER touch them.
|
||
|
||
```
|
||
4100 Constants: event codes, channel states, node sizes, arena sizes
|
||
4101 Arena CREATE: MSG-ARENA CH-ARENA MBR-ARENA; free-list vars; MSG-SEQ CH-ACTIVE
|
||
4102 MSG-INIT-FREE + CH-INIT-FREE
|
||
4103 MBR-INIT-FREE + MSG-ALLOC + MSG-FREE-NODE
|
||
4104 CH-ALLOC + CH-FREE-NODE + MBR-ALLOC + MBR-FREE-NODE
|
||
4105 Message field accessors: MSG-TYPE@/! MSG-FROM@/! MSG-TO@/! MSG-PADDR@/! MSG-PLEN@/! MSG-HEAT@/! MSG-SEQ@/!
|
||
4106 Channel+member accessors: CH-ID@/! CH-OWNER@/! CH-STATE@/! CH-HEAT@/! CH-MBRS@/! CH-NEXT@/! MBR-NEXT@ MBR-VM@
|
||
4107 IDX>NAME + MSG-DELIVER + MSG-SEND
|
||
4108 VARIABLE MSG-SCAN + MSG-COOL-ONE + MSG-COOL-ALL
|
||
4109 MSG-REAP
|
||
---- 4110–4113: ARTEMIS — DO NOT TOUCH ----
|
||
4114 VARIABLE CH-SCAN + CH-COOL-ALL
|
||
4115 CH-REAP-SAFE
|
||
4116 VARIABLE COMMON-CH + COMMON-INIT + HERMES-TICK
|
||
4117 EVENT-EMIT + EVENT-WAIT + EVENT-DRAIN (backward compat)
|
||
4118 HERA-NOTIFY-SPAWN + HERA-NOTIFY-KILL + HERA-DISPATCH-ONE + HERA-DISPATCH
|
||
4119 CH-REQUEST + CH-ACCEPT + CH-CLOSE
|
||
4120 WELCOME + CD-INIT
|
||
```
|
||
|
||
### Node layouts (cells)
|
||
|
||
**Message node — 7 cells:**
|
||
- 0: type (in-use) / next-free ptr (free)
|
||
- 1: sender VM index
|
||
- 2: recipient VM index
|
||
- 3: payload addr (FORTH string addr)
|
||
- 4: payload len
|
||
- 5: heat (Q48.16)
|
||
- 6: seq
|
||
|
||
**Channel node — 6 cells:**
|
||
- 0: channel-id (in-use) / next-free ptr (free)
|
||
- 1: owner VM index
|
||
- 2: state (0=NEGOTIATING 1=OPEN 2=CLOSING)
|
||
- 3: heat (Q48.16)
|
||
- 4: members-head (→ member list)
|
||
- 5: next-active (active channel list link)
|
||
|
||
**Member node — 2 cells:**
|
||
- 0: next-ptr
|
||
- 1: vm-id
|
||
|
||
### Physics
|
||
|
||
Cooling constant: Q-DECAY (65208) from compudynamics.4th — same as VM-DECAY-ONE.
|
||
Messages and VMs cool at identical rates. Fleet is thermodynamically consistent.
|
||
|
||
---
|
||
|
||
*This document is authoritative. If it conflicts with something in the codebase,
|
||
the codebase is wrong.*
|