410 lines
15 KiB
Markdown
410 lines
15 KiB
Markdown
# Birthing Plan: Child VMs Born of Hera
|
|
|
|
**Status:** DRAFT — requires Captain Bob approval before any implementation begins
|
|
**Branch:** `birthing` (off `lithosananke`)
|
|
**Authors:** Claude Code + Captain Bob
|
|
**Date:** 2026-05-24
|
|
|
|
---
|
|
|
|
## 1. Vision
|
|
|
|
Three named VMs form the initial constellation of LithosAnanke:
|
|
|
|
| VM Name | Role |
|
|
|---------|------|
|
|
| **Hera** | Mama VM — orchestrates all other VMs; runs `capsules/init.4th` |
|
|
| **Hermes** | Messaging stratum — pub/sub between VMs; runs `capsules/hermes/init.4th` |
|
|
| **Artemis** | Storage and memory manager; runs `capsules/artemis/init.4th` |
|
|
|
|
**Hades** remains the kernel + HAL substrate beneath all of them.
|
|
|
|
For now, Hera's job is simply: birth, start, stop, and kill VM instances.
|
|
Concurrent scheduling, inter-VM messaging, and storage management are later milestones.
|
|
|
|
Every VM — including Hermes and Artemis — carries the same lifecycle primitives.
|
|
A VM can birth and manage other VMs. The infrastructure is uniform.
|
|
|
|
---
|
|
|
|
## 2. Hard Constraints
|
|
|
|
Fixed by the execution model. Hera's implementation is not constrained — she expands
|
|
as the design requires.
|
|
|
|
| Constraint | Implication |
|
|
|------------|-------------|
|
|
| Same process as Hera | No `fork()`, no `pthread_create()` |
|
|
| No threads | Scheduling is cooperative, inside the interpreter loop |
|
|
| No OS processes | VMs share Hera's address space |
|
|
| ANSI C99, `-Wall -Werror` | No GNU extensions |
|
|
| Hades is the substrate | All I/O, timing, and memory from Hades (kernel+HAL) |
|
|
|
|
---
|
|
|
|
## 3. VM Identity and Naming
|
|
|
|
### 3.1 Every VM Has a Name
|
|
|
|
The current `VMRegistryEntry` tracks VMs by numeric ID only. This must be extended with a
|
|
symbolic name field. A VM's name:
|
|
|
|
- Is set at birth (derived from the capsule namespace — see §5)
|
|
- Is displayed in every log line emitted by that VM
|
|
- Is the argument to all lifecycle words: `S" Artemis" BIRTH`, `S" Artemis" KILL`, etc.
|
|
- Is unique within a session (no two live VMs share a name)
|
|
- Is case-preserved but case-insensitive for lookup
|
|
|
|
### 3.2 VM Registry Extension
|
|
|
|
`VMRegistryEntry` needs a `name` field (at minimum `char name[64]`). The name is:
|
|
- Set by `BIRTH` at VM creation time
|
|
- Cleared on `KILL` (slot becomes reusable)
|
|
- Logged in every parity record alongside the numeric VM ID
|
|
|
|
### 3.3 Log Prefix — Critical
|
|
|
|
Every line of console output emitted by a VM is prefixed with its name:
|
|
|
|
```
|
|
[Hera] ok
|
|
[Hermes] pub/sub ready
|
|
[Artemis] storage initialized
|
|
[Hera] 2 VMs alive
|
|
```
|
|
|
|
This applies to `EMIT`, `TYPE`, `.`, `.S`, `CR`, and all I/O words. The prefix is injected
|
|
at the HAL console layer — the VM does not format it; Hades prints it automatically based
|
|
on the current active VM context.
|
|
|
|
---
|
|
|
|
## 4. The Five Primitive Forth Words
|
|
|
|
These words are **built-in C primitives** registered in every VM's dictionary at startup.
|
|
They are not defined in Forth — they are part of the base word set, available to all VMs.
|
|
|
|
### Stack signatures use the counted-string convention: `( c-addr u -- )`
|
|
|
|
---
|
|
|
|
### `BIRTH ( c-addr u -- )`
|
|
|
|
Birth a new VM from the capsule whose namespace matches the given name.
|
|
|
|
**Mapping:** `S" Artemis"` → lowercase `"artemis"` → capsule name `artemis:init.4th`
|
|
(the standard capsule for a named VM is `<name>:init.4th`).
|
|
|
|
**Sequence:**
|
|
1. Lowercase the name string
|
|
2. Construct capsule name: `<name>:init.4th`
|
|
3. Look up capsule in the directory by name
|
|
4. Verify capsule is `FLAG_PRODUCTION` + `FLAG_ACTIVE` and not `FLAG_REVOKED`
|
|
5. Allocate a new VM context (full VM — Hera expands her pool as needed)
|
|
6. Execute the capsule init (via existing `capsule_exec_init` path)
|
|
7. Register VM under the symbolic name in the extended `VMRegistryEntry`
|
|
8. Log parity record: `PARITY:BIRTH name=Artemis vm_id=N capsule_id=X`
|
|
9. On success: push 0; on failure: push error code
|
|
|
|
**If a VM named "Artemis" is already alive:** check its health. If healthy, skip the birth
|
|
and log the fact. Do not error, do not replace. BIRTH is idempotent for healthy VMs.
|
|
|
|
---
|
|
|
|
### `KILL ( c-addr u -- )`
|
|
|
|
Destroy a named VM. The VM's resources are freed and its registry slot is cleared.
|
|
|
|
**Sequence:**
|
|
1. Look up VM by name in registry
|
|
2. If not found: push error code, return
|
|
3. Forcibly terminate any pending execution in that VM
|
|
4. Free the VM's stacks, dictionary, and memory
|
|
5. Clear registry slot (name + state = DEAD)
|
|
6. Log parity record: `PARITY:KILL name=Artemis vm_id=N`
|
|
7. Push 0 on success
|
|
|
|
**Note:** KILL is unconditional. It does not wait for the VM to reach a yield point.
|
|
At this phase (no concurrent execution), the VM is idle when KILL is called.
|
|
|
|
---
|
|
|
|
### `START ( c-addr u -- )`
|
|
|
|
Begin or resume execution of a named VM.
|
|
|
|
**At this phase:** `START` runs the VM to completion (or until it calls `STOP` on itself)
|
|
before returning control to the caller. Concurrent interleaved execution is a later milestone.
|
|
|
|
**Sequence:**
|
|
1. Look up VM by name
|
|
2. If state is EMBRYO or STOPPED: set state to LIVE, transfer execution
|
|
3. If state is LIVE: error (already running)
|
|
4. On VM completion or self-STOP: return control to the calling VM
|
|
5. Push 0 on success
|
|
|
|
---
|
|
|
|
### `STOP ( c-addr u -- )`
|
|
|
|
Suspend a named VM. Its execution state is preserved; `START` will resume it.
|
|
|
|
Any VM can STOP any other. Authority comes from identity — a VM may assume another
|
|
identity for failsafe and recovery. The identity assumption mechanism is a future
|
|
milestone; in Phase 1, cross-VM STOP is permitted without restriction.
|
|
|
|
**Sequence:**
|
|
1. Verify name matches the current VM
|
|
2. Save execution state (IP, stacks)
|
|
3. Set state to STOPPED
|
|
4. Return control to the VM that called `START`
|
|
|
|
---
|
|
|
|
### `USE ( c-addr u -- )`
|
|
|
|
Make a named VM the active console target. Subsequent REPL input and output is directed
|
|
to and from that VM until another `USE` call or the VM dies.
|
|
|
|
```forth
|
|
S" Hermes" USE \ REPL now talks to Hermes
|
|
: send-test S" hello" PUBLISH ;
|
|
S" Hera" USE \ REPL returns to Hera
|
|
```
|
|
|
|
USE is **system-wide** — it is not scoped to a capsule or identity. All REPL input and
|
|
output redirects to the named VM until the next `USE` call. The `[Name]` prefix in the
|
|
console reflects the active USE target.
|
|
|
|
**Sequence:**
|
|
1. Look up VM by name in registry
|
|
2. Set as the active system-wide REPL/console VM
|
|
3. Console prefix changes to `[VMName]`
|
|
4. Stack unchanged (no return value)
|
|
|
|
---
|
|
|
|
## 5. Capsule Namespace Convention
|
|
|
|
### 5.1 Directory Structure
|
|
|
|
Each named VM owns a subdirectory under `capsules/`:
|
|
|
|
```
|
|
capsules/
|
|
├── init.4th ← Hera's capsule ONLY (root level, no subdir)
|
|
├── hermes/
|
|
│ └── init.4th ← Hermes' capsule
|
|
└── artemis/
|
|
└── init.4th ← Artemis' capsule
|
|
```
|
|
|
|
**`capsules/init.4th` is Hera's exclusive init.** No other VM uses the root-level init.
|
|
Do not place general capsules there. Do not recreate the old `conf/` directory.
|
|
|
|
### 5.2 How mkcapsule Names Capsules
|
|
|
|
`tools/mkcapsule.c` scans `capsules/` recursively. It encodes relative paths by replacing
|
|
`/` with `:`. So:
|
|
|
|
| File path | Capsule name |
|
|
|-----------|-------------|
|
|
| `capsules/init.4th` | `init.4th` |
|
|
| `capsules/hermes/init.4th` | `hermes:init.4th` |
|
|
| `capsules/artemis/init.4th` | `artemis:init.4th` |
|
|
|
|
### 5.3 BIRTH Name → Capsule Name Mapping
|
|
|
|
`BIRTH` lowercases the VM name and appends `:init.4th`:
|
|
|
|
| Forth call | Capsule looked up |
|
|
|------------|------------------|
|
|
| `S" Hera" BIRTH` | `init.4th` (special case — root) |
|
|
| `S" Hermes" BIRTH` | `hermes:init.4th` |
|
|
| `S" Artemis" BIRTH` | `artemis:init.4th` |
|
|
| `S" MyWorker" BIRTH` | `myworker:init.4th` |
|
|
|
|
The root-level `init.4th` is a special case: `S" Hera" BIRTH` is how a future VM would
|
|
re-birth Hera; at bootstrap, Hera boots from it automatically.
|
|
|
|
### 5.4 mkcapsule Flag Mapping
|
|
|
|
The capsule flag (`FLAG_PRODUCTION` vs `FLAG_EXPERIMENT`) is determined by the directory
|
|
prefix — **not the file name**. Under the current `mkcapsule` logic:
|
|
|
|
- `capsules/hermes/init.4th` → does not match `production:*`, `core:*`, or `domains:*`
|
|
→ currently gets `FLAG_EXPERIMENT`
|
|
|
|
**All capsules carry both `FLAG_PRODUCTION` and `FLAG_EXPERIMENT`.** Birth eligibility is
|
|
not gated on the flag type — any capsule can be used for any identity. mkcapsule will be
|
|
updated to set both flags on every capsule it generates. The distinction between production
|
|
and experiment remains in the flags for audit/logging purposes but does not block BIRTH.
|
|
|
|
---
|
|
|
|
## 6. Capsule Content (Stubs)
|
|
|
|
Hermes and Artemis capsule directories exist but are empty (`.gitkeep` only). They need
|
|
`init.4th` stubs before the system can BIRTH them.
|
|
|
|
### `capsules/hermes/init.4th` (stub)
|
|
|
|
Should:
|
|
- Print `[Hermes] initializing` (or similar boot message)
|
|
- Define Hermes' pub/sub vocabulary (placeholder for now)
|
|
- Leave Hermes in a known state (not just empty)
|
|
|
|
### `capsules/artemis/init.4th` (stub)
|
|
|
|
Should:
|
|
- Print `[Artemis] initializing`
|
|
- Define Artemis' storage/memory vocabulary (placeholder)
|
|
|
|
**These stubs must be written before `make -f Makefile.starkernel` is run, because
|
|
mkcapsule runs at build time and produces `capsule_generated.c` from whatever is in
|
|
`capsules/` at that moment.**
|
|
|
|
---
|
|
|
|
## 7. VM Lifecycle Model
|
|
|
|
```
|
|
(capsule exists in directory)
|
|
│
|
|
▼
|
|
[BIRTH]
|
|
│
|
|
▼
|
|
EMBRYO ──────────────────[KILL]──────► DEAD
|
|
│ ▲
|
|
[START] │
|
|
│ [KILL]
|
|
▼ │
|
|
LIVE/RUNNING ──────────[STOP]──► STOPPED─┘
|
|
│
|
|
(completes)
|
|
│
|
|
▼
|
|
DEAD (natural)
|
|
```
|
|
|
|
States:
|
|
- **EMBRYO** — VM born (capsule executed) but `START` not yet called
|
|
- **LIVE** — executing (at this phase: running synchronously inside `START`)
|
|
- **STOPPED** — suspended; state saved; resumable via `START`
|
|
- **DEAD** — killed or naturally completed; slot reclaimable
|
|
|
|
---
|
|
|
|
## 8. Scheduling Model (Phase 1)
|
|
|
|
At this phase, scheduling is **sequential and explicit**:
|
|
|
|
- `START` runs a VM synchronously — the calling VM suspends while the started VM runs
|
|
- No round-robin, no time-slicing, no preemption
|
|
- The REPL is always in exactly one VM's context at a time
|
|
- `USE` switches the REPL/console target
|
|
|
|
**This is intentionally simple.** Cooperative concurrent scheduling (multiple VMs
|
|
interleaved in the interpreter loop) is a future milestone, designed separately after
|
|
the basic lifecycle works.
|
|
|
|
---
|
|
|
|
## 9. Dictionary and Namespace
|
|
|
|
The five lifecycle words (BIRTH, KILL, START, STOP, USE) are C primitives in **every VM's
|
|
base dictionary**. They are registered at VM initialization, before any capsule init runs.
|
|
|
|
A child VM born by Hermes or Artemis also has these words — all VMs can manage other VMs.
|
|
|
|
**Dictionary isolation:** Each VM has its own dictionary. Words defined by Artemis's
|
|
`init.4th` do not appear in Hera's dictionary or Hermes' dictionary. VMs communicate
|
|
through the messaging layer (Hermes), not shared dictionary state.
|
|
|
|
---
|
|
|
|
## 10. Hades Interface
|
|
|
|
All VMs access Hades through the same HAL interface. At this phase:
|
|
- No capability bitmask enforcement
|
|
- All VMs can call any HAL function (I/O, memory, time)
|
|
- The log prefix (`[VMName]`) is injected by the HAL console layer based on the currently
|
|
executing VM context — not by the VM itself
|
|
|
|
Capability enforcement (limiting what a child VM can do in Hades) is a future milestone.
|
|
|
|
---
|
|
|
|
## 11. Physics / SSM Integration
|
|
|
|
Each VM has its own independent SSM/L8 Jacquard state — this is already the natural
|
|
consequence of each VM being a full VM instance with its own `VM` struct. No shared physics.
|
|
|
|
The heartbeat runs per-VM. Hera's SSM does not observe Hermes' or Artemis' execution.
|
|
|
|
---
|
|
|
|
## 12. Decisions — RESOLVED
|
|
|
|
| # | Decision | Resolution |
|
|
|---|----------|-----------|
|
|
| D1 | BIRTH name collision | **Idempotent — check health of existing VM; if healthy, skip and log. No error, no replace.** |
|
|
| D2 | Production flag | **All capsules carry both `FLAG_PRODUCTION` and `FLAG_EXPERIMENT`. Birth eligibility is not gated on flag type. mkcapsule updated accordingly.** |
|
|
| D3 | `BIRTH` return value | **Nothing — BIRTH is a pure side-effect word, leaves stack clean.** |
|
|
| D4 | `USE` scope | **REPL only, but system-wide. Not bound to any specific capsule or identity. All REPL I/O redirects to the named VM.** |
|
|
| D5 | STOP across VMs | **Any VM may assume another identity for failsafe and recovery purposes, enabling cross-VM STOP. Identity assumption mechanism is a future milestone; Phase 1 allows any VM to STOP any other.** |
|
|
| D6 | Max named VMs | **Dynamic — Hera allocates as needed. No fixed ceiling.** |
|
|
| D7 | Log prefix format | **`[Name]`** — e.g., `[Hera]`, `[Hermes]`, `[Artemis]` |
|
|
|
|
---
|
|
|
|
## 13. What This Is NOT
|
|
|
|
- **Not a thread scheduler.** No preemption. Sequential execution at this phase.
|
|
- **Not a process model.** VMs share Hera's address space.
|
|
- **Not a security boundary yet.** No capability enforcement in this phase.
|
|
- **Not constrained by Hera's current implementation.** Hera expands as the design requires.
|
|
|
|
---
|
|
|
|
## 14. Implementation Phases
|
|
|
|
No code until Captain Bob approves the plan.
|
|
|
|
| Phase | Scope | Deliverable |
|
|
|-------|-------|-------------|
|
|
| 0 | Design approval | This document, signed off |
|
|
| 1 | VM registry naming | Add `name[64]` to `VMRegistryEntry`; name lookup functions |
|
|
| 2 | Log prefix | HAL console layer emits `[VMName]` prefix per active VM |
|
|
| 3 | Capsule stubs | Write `capsules/hermes/init.4th`, `capsules/artemis/init.4th` |
|
|
| 4 | mkcapsule flag update | Set both `FLAG_PRODUCTION` and `FLAG_EXPERIMENT` on all capsules |
|
|
| 5 | BIRTH word | C primitive; name→capsule lookup; health-check idempotence; full VM alloc |
|
|
| 6 | KILL word | C primitive; teardown; registry clear |
|
|
| 7 | START word | C primitive; synchronous execution hand-off |
|
|
| 8 | STOP word | C primitive; cross-VM; state save; return to caller |
|
|
| 9 | USE word | C primitive; system-wide REPL/console redirect |
|
|
| 10 | Hera init.4th update | Use new words to birth Hermes and Artemis at boot |
|
|
| 11 | Integration test | Boot sequence: Hera → BIRTH Hermes → BIRTH Artemis → `[Name]` in logs |
|
|
|
|
---
|
|
|
|
## 15. Mythological Framing Reference
|
|
|
|
| Name | Role |
|
|
|------|------|
|
|
| **Hades** | Kernel + HAL — the underworld substrate |
|
|
| **Hera** | Mama VM — queen, orchestrator, eternal; `capsules/init.4th` |
|
|
| **Hermes** | Messenger — pub/sub stratum; `capsules/hermes/init.4th` |
|
|
| **Artemis** | Hunter/keeper — storage and memory; `capsules/artemis/init.4th` |
|
|
| **BIRTH** | The word that brings a new VM into being |
|
|
| **KILL** | The word that destroys a VM |
|
|
| **START** | The word that gives a VM its first breath (or resumes it) |
|
|
| **STOP** | The word that suspends a VM |
|
|
| **USE** | The word that shifts the speaker's attention to a VM |
|
|
|
|
---
|
|
|
|
*This document is a planning artifact only. No code changes have been made.
|
|
Captain Bob's approval of the open decisions in §12 is required before Phase 1 begins.*
|