diff --git a/README.md b/README.md
index c2f38a7..fec42e8 100644
--- a/README.md
+++ b/README.md
@@ -35,6 +35,22 @@ Local package surfaces:
- Avatar asset: `assets/personas/gjallar-avatar.png`
- Pixel avatar: `assets/personas/gjallar-avatar-pixel-256.png`
+## Idunn
+
+Idunn is Odin's keepalive organ: the daemon package that should keep the known
+swarm alive after Odin has accepted where each daemon lives and what authority
+path may touch it. Individual daemons publish health and command boundaries;
+Idunn brings them up after reboots or crashes, watches health, and escalates
+operator-needed failures through VoidBot's CultMesh owner-DM command. Odin sees
+the daemons; Idunn keeps the apples from rotting.
+
+Local package surfaces:
+
+- Organ contract: `docs/idunn.md`
+- C# CultMesh organ: `src/Idunn/Idunn.csproj`
+- Runtime store: `scratch/idunn/idunn.keepalive.cc`
+- Operator escalation: `voidbot.operator-dm` command `owner.dm.send`
+
## Authority Map
- Owner: Odin owns the network-wide Verse registry, schema catalog index, translation map, and the accepted `odin.allseer` Eve surface.
diff --git a/docs/architecture.md b/docs/architecture.md
index fa7a5dc..0ad163c 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -78,6 +78,18 @@ Odin's coordinator. Gjallar may read Odin-owned state and emit affordance
packets; it must not own the underlying registry, probe, provider, layout, or
translation decisions.
+Idunn is the named keepalive organ for daemon continuity. Its current package
+lives in `docs/idunn.md` and `src/Idunn/Idunn.csproj`. Idunn may read
+Odin-owned service records and provider advertisements, then bring daemons up
+after reboots or crashes, watch health, emit keepalive observations, restart
+requests, denied-action records, and operator alarms. When human action is
+needed, Idunn should use CultMesh to request VoidBot's provider-owned
+`voidbot.operator-dm` command `owner.dm.send` with payload schema
+`gamecult.operator_dm_request.v1`. It must not own Verse discovery, schema
+truth, provider dashboards, identity grants, Discord delivery, or renderer
+layout. Keepalive loops should move into Idunn instead of accumulating inside
+Odin's coordinator or individual daemons.
+
## Target Mechanism
```text
diff --git a/docs/idunn.md b/docs/idunn.md
new file mode 100644
index 0000000..5887f95
--- /dev/null
+++ b/docs/idunn.md
@@ -0,0 +1,102 @@
+# Idunn
+
+Idunn is Odin's keepalive organ.
+
+Odin is the all-seer: it accepts Verse discovery, schema catalogs, translation
+routes, provider surfaces, and observation projections. Idunn keeps the daemon
+swarm alive from that accepted map. It is not a second Odin, not a dashboard,
+and not a heroic supervisor with secret service truth in its pockets.
+
+Idunn keeps the apples: desired daemon presence, boot recovery, crash recovery,
+health freshness, restart intent, operator escalation, and continuity witness
+state.
+
+## Authority Map
+
+- Owner: Idunn owns daemon lifecycle management after Odin has accepted where a
+ daemon lives: bring-up after host reboot, crash recovery, health watching,
+ restart policy, and operator escalation.
+- Inputs: Odin's accepted service records, provider advertisements, `.cc`
+ witnesses, advertised command boundaries, freshness windows, operator policy,
+ local service manager state, and direct local service probes only when no
+ provider advertisement exists.
+- Outputs: typed keepalive observations, restart requests, denied-action
+ records, operator alarms, owner-DM escalation requests through VoidBot, and an
+ Eve/CultUI keepalive surface.
+- Derived state: dashboard cells, Discord speech, agent summaries, and Odin
+ service projections are notification-only views of Idunn-owned keepalive
+ records.
+- Forbidden writers: Idunn does not decide which Verses exist, invent provider
+ schemas, mutate provider dashboards, own identity/session grants, or hide
+ restarts behind Odin refresh logic. Individual daemons should not carry
+ independent crash-recovery loops once Idunn owns their lifecycle path; they
+ publish health, surfaces, state witnesses, and command boundaries instead.
+- Shared paths: manual operator restart, scheduled restart, degraded-health
+ repair, boot rehydration, and future remote worker recovery must pass through
+ the same keepalive command primitive.
+- Deletion line: any keepalive loop inside Odin, Gjallar, Eve lowerers, or
+ renderer code should be cut or demoted to a probe that names Idunn as the
+ restart owner.
+
+## Body
+
+The initial local package is deliberately small:
+
+- `src/Idunn/Idunn.csproj` is the first C# CultMesh organ.
+- `src/Idunn/Program.cs` opens or creates Idunn's local CultCache/CultMesh
+ store at `scratch/idunn/idunn.keepalive.cc`.
+- `npm run idunn:build` builds the organ beside `gjallar:build`.
+- `npm run idunn:start -- --serve` starts the resident keepalive process.
+
+This is the organ contract and runtime foothold. It does not yet restart
+anything. The first real keepalive cut should add typed records before adding
+actuators:
+
+```text
+idunn.desired_daemon.v1
+idunn.daemon_health.v1
+idunn.keepalive_decision.v1
+idunn.restart_request.v1
+idunn.restart_result.v1
+idunn.operator_alarm.v1
+idunn.owner_dm_escalation.v1
+```
+
+## Invariants
+
+- Odin remains the accepted owner of Verse and service discovery.
+- Idunn owns continuity decisions after a daemon is known.
+- Individual daemons own their work and their health publication, not their
+ surrounding lifecycle. They should be simple to kill and simple for Idunn to
+ bring back.
+- Providers own their own command boundaries. Idunn requests restart through
+ advertised authority or a named local service manager adapter.
+- Host reboot recovery, crash recovery, stale-health recovery, and manual
+ operator restart must share the same Idunn command primitive.
+- A repair loop is not an owner. If a daemon becomes healthy only after a later
+ Odin refresh or manual click, Idunn's ownership path is still incomplete.
+- Restart attempts must be witnessed: requested by whom, against which service,
+ through which command boundary, with what result and timestamp.
+- Idunn should fail closed when authority is unclear. Unknown ownership,
+ repeated restart failure, missing command authority, or degraded health that
+ needs a human becomes an operator alarm.
+- Operator alarms use CultMesh to request VoidBot owner notification through
+ the provider-owned `voidbot.operator-dm` command `owner.dm.send` with payload
+ schema `gamecult.operator_dm_request.v1`. Idunn must not learn Discord token
+ handling or DM delivery internals.
+
+## First Runtime Direction
+
+Idunn's C# runtime should grow in this order:
+
+1. Read Odin-owned service and provider-advertisement records through CultMesh.
+2. Normalize them into `idunn.desired_daemon.v1` records.
+3. Observe freshness and process state through narrow probe ports.
+4. Emit `idunn.keepalive_decision.v1` records without acting.
+5. Add restart adapters only for named authority boundaries: local systemd,
+ Windows service control, Docker, or provider-advertised commands.
+6. Add `voidbot.operator-dm` escalation for cases that need operator action.
+7. Publish an Eve/CultUI keepalive surface from Idunn-owned records.
+
+No ad hoc JSON manifest should become the live state owner. Debug projections
+are fine when they name the `.cc` record or CultMesh document behind them.
diff --git a/package.json b/package.json
index c5680b2..28f5d55 100644
--- a/package.json
+++ b/package.json
@@ -8,6 +8,8 @@
"gjallar:persona": "node scripts/write-gjallar-persona-cc.mjs inspect",
"gjallar:persona:write": "node scripts/write-gjallar-persona-cc.mjs write",
"gjallar:build": "dotnet build src/Gjallar/Gjallar.csproj",
+ "idunn:build": "dotnet build src/Idunn/Idunn.csproj",
+ "idunn:start": "dotnet run --project src/Idunn/Idunn.csproj --",
"rust:test": "cargo test --workspace",
"check": "node scripts/check-syntax.cjs",
"start": "node src/odin-coordinator.cjs"
diff --git a/src/Idunn/Idunn.csproj b/src/Idunn/Idunn.csproj
new file mode 100644
index 0000000..0ad5a93
--- /dev/null
+++ b/src/Idunn/Idunn.csproj
@@ -0,0 +1,12 @@
+
+
+ Exe
+ net10.0
+ enable
+ enable
+
+
+
+
+
+
diff --git a/src/Idunn/Program.cs b/src/Idunn/Program.cs
new file mode 100644
index 0000000..6973255
--- /dev/null
+++ b/src/Idunn/Program.cs
@@ -0,0 +1,102 @@
+using GameCult.Caching.MessagePack;
+using GameCult.Mesh;
+
+var options = IdunnOptions.Parse(args);
+var cachePath = Path.GetFullPath(options.CachePath);
+var cacheDirectory = Path.GetDirectoryName(cachePath);
+
+if (!string.IsNullOrWhiteSpace(cacheDirectory))
+{
+ Directory.CreateDirectory(cacheDirectory);
+}
+
+using var node = await CultMesh.CreateNodeAsync(
+ cachePath,
+ new CultMeshNodeOptions
+ {
+ StartServer = options.Serve,
+ CacheOptions = new CultCacheOpenOptions
+ {
+ PullOnOpen = false
+ }
+ }).ConfigureAwait(false);
+
+Console.WriteLine("Idunn CultMesh organ initialized.");
+Console.WriteLine($"Keepalive store: {cachePath}");
+Console.WriteLine("Provider id: idunn.keepalive");
+Console.WriteLine("Authority: daemon lifecycle, health watching, restart intent, and operator escalation for Odin-known daemons");
+Console.WriteLine("Owner escalation: CultMesh command voidbot.operator-dm owner.dm.send");
+Console.WriteLine($"CultMesh server: {(options.Serve ? "started" : "disabled")}");
+Console.WriteLine("Typed keepalive records and restart adapters are the next cut.");
+
+if (!options.Serve)
+{
+ return 0;
+}
+
+var stopping = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
+Console.CancelKeyPress += (_, eventArgs) =>
+{
+ eventArgs.Cancel = true;
+ stopping.TrySetResult();
+};
+
+Console.WriteLine("Press Ctrl+C to stop Idunn.");
+await stopping.Task.ConfigureAwait(false);
+return 0;
+
+internal sealed record IdunnOptions(string CachePath, bool Serve)
+{
+ public static IdunnOptions Parse(string[] args)
+ {
+ var repoRoot = FindRepoRoot(Directory.GetCurrentDirectory());
+ var cachePath = Path.Combine(repoRoot, "scratch", "idunn", "idunn.keepalive.cc");
+ var serve = false;
+
+ for (var index = 0; index < args.Length; index++)
+ {
+ switch (args[index])
+ {
+ case "--serve":
+ serve = true;
+ break;
+ case "--cache" when index + 1 < args.Length:
+ cachePath = args[++index];
+ break;
+ case "--help":
+ case "-h":
+ PrintUsage();
+ Environment.Exit(0);
+ break;
+ default:
+ throw new ArgumentException($"Unknown Idunn argument: {args[index]}");
+ }
+ }
+
+ return new IdunnOptions(cachePath, serve);
+ }
+
+ private static string FindRepoRoot(string start)
+ {
+ var current = new DirectoryInfo(start);
+ while (current != null)
+ {
+ if (File.Exists(Path.Combine(current.FullName, "package.json")) &&
+ Directory.Exists(Path.Combine(current.FullName, "src", "Gjallar")))
+ {
+ return current.FullName;
+ }
+
+ current = current.Parent;
+ }
+
+ return start;
+ }
+
+ private static void PrintUsage()
+ {
+ Console.WriteLine("Idunn");
+ Console.WriteLine(" --cache Keepalive CultCache store path.");
+ Console.WriteLine(" --serve Start the CultMesh server instead of only opening the node.");
+ }
+}