paracosm 0.8.603 → 0.8.636

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,51 +5,39 @@
5
5
  <h1 align="center">PARACOSM</h1>
6
6
 
7
7
  <p align="center">
8
- <em>From prompt to world model to forked futures. Structured counterfactual simulations for AI agents.</em>
8
+ <em>A structured world model for AI agents. Prompt to runnable world to forked futures.</em>
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
12
  <a href="https://www.npmjs.com/package/paracosm"><img src="https://img.shields.io/npm/v/paracosm?style=flat-square&color=e8b44a&labelColor=14110e" alt="npm" /></a>
13
13
  <a href="https://github.com/framersai/paracosm/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-e06530?style=flat-square&labelColor=14110e" alt="License" /></a>
14
14
  <a href="https://paracosm.agentos.sh/docs"><img src="https://img.shields.io/badge/docs-API%20Reference-4ca8a8?style=flat-square&labelColor=14110e" alt="Docs" /></a>
15
- <a href="https://agentos.sh"><img src="https://img.shields.io/badge/built%20on-AgentOS-e06530?style=flat-square&labelColor=14110e" alt="AgentOS" /></a>
15
+ <a href="https://agentos.sh/en"><img src="https://img.shields.io/badge/built%20on-AgentOS-e06530?style=flat-square&labelColor=14110e" alt="AgentOS" /></a>
16
16
  </p>
17
17
 
18
18
  <p align="center">
19
- <a href="https://paracosm.agentos.sh"><strong>paracosm.agentos.sh</strong></a> &middot;
20
- <a href="https://paracosm.agentos.sh/sim">Live Demo</a> &middot;
21
- <a href="https://paracosm.agentos.sh/docs">API Docs</a> &middot;
22
- <a href="https://www.npmjs.com/package/paracosm">npm</a> &middot;
19
+ <a href="https://paracosm.agentos.sh"><strong>paracosm.agentos.sh</strong></a> ·
20
+ <a href="https://paracosm.agentos.sh/sim">Live Demo</a> ·
21
+ <a href="https://paracosm.agentos.sh/docs">API Docs</a> ·
22
+ <a href="https://www.npmjs.com/package/paracosm">npm</a> ·
23
23
  <a href="https://wilds.ai/discord">Discord</a>
24
24
  </p>
25
25
 
26
26
  ---
27
27
 
28
- ## What paracosm is
28
+ Paracosm is a structured world model for AI agents. It compiles a JSON scenario draft (or a prompt, or an extracted document) into a runnable world, plays it through a deterministic kernel, and lets agents with HEXACO personality profiles decide turn by turn how the world unfolds. Snapshots persist on disk. Runs replay byte-for-byte. Any past turn can be forked with a different actor, a different seed, or a custom event, and the divergent branch streams alongside the trunk so the contrast is visible in the artifact, not promised in copy.
29
29
 
30
- Paracosm starts from a prompt, brief, URL, or hand-written scenario draft; every path compiles down to an LLM-readable world contract before simulation. The durable contract is still JSON: a typed `ScenarioPackage` with five state bags, labels, departments, metrics, setup defaults, and generated hooks. An actor with a HEXACO personality profile runs that world. A deterministic kernel drives state, time, and randomness. An LLM generates events, specialist analyses, and the actor's decisions. Specialists can forge new computational tools at runtime inside a V8 sandbox; an LLM judge approves each forge before it enters the decision pipeline. The kernel applies consequences. Personality traits drift. One turn ends, the next begins.
30
+ The product is the contrast. Same compiled world, same crises, same kernel: swap one variable and the trajectory measurably moves.
31
31
 
32
- **JSON is the contract, not the product boundary.** Today, `compileScenario()` accepts a scenario JSON draft and can ground it with `seedText` or `seedUrl`. The next API layer should be a one-call prompt/document wrapper that asks an LLM to propose that same JSON contract, validates it, then compiles and runs it. It should not bypass the schema, the kernel, or the artifact.
33
-
34
- **Same seed. Different actor. Different world.**
35
-
36
- Two runs against an identical seed, starting from the same compiled world contract, produce measurably divergent trajectories when you swap one variable: the actor's personality. The kernel's side is reproducible. The divergence comes from the LLM stages reading HEXACO profiles and deciding differently. That structural contrast is the product.
37
-
38
- Paracosm is a **structured world model** in the sense of [Xing 2025](https://arxiv.org/abs/2507.05169) and the [ACM CSUR 2025 world-model survey](https://dl.acm.org/doi/full/10.1145/3746449): a simulator for *actionable possibilities*, not a video generator. It is also a **counterfactual world simulation model** ([Kirfel et al, 2025](https://link.springer.com/article/10.1007/s43681-025-00718-4)): a substrate for replaying an event with one variable changed and surfacing the effect. The closest LLM-world-model implementation anchor is [Yang et al, 2026](https://openreview.net/forum?id=XmYCERErcD), which evaluates LLM-based world models through policy verification, action proposal, and policy planning. Paracosm takes the safe product version of that idea: externalize the world into schema, citations, tools, snapshots, and seeded transitions, then let the LLM reason over that structure. Full taxonomy mapping in [`docs/positioning/world-model-mapping.md`](docs/positioning/world-model-mapping.md).
39
-
40
- ### Not these things
41
-
42
- - **Not a generative visual world model.** Sora, Genie 3, and World Labs Marble produce pixels or 3D scenes. Paracosm produces a structured `RunArtifact`: metrics, decisions, specialist notes, citations, forged tool summaries.
43
- - **Not a JEPA-style predictive-representation model.** LeCun's AMI Labs trains neural representations from sensor streams. Paracosm composes a kernel with an LLM reasoner; no training pipeline.
44
- - **Not a multi-agent task orchestration framework.** LangGraph, AutoGen, CrewAI, OpenAI Agents SDK, Google ADK all build agentic workflows that execute real tasks. Paracosm is a simulation; nothing leaves the run.
45
- - **Not a bottom-up swarm intelligence simulator.** MiroFish and OASIS simulate thousands to a million emergent agents for aggregate prediction. Paracosm is top-down (one actor decides), runs ~100 agents by design, and outputs a deterministic trajectory plus divergence across actors.
46
- - **Not a generative-agents library.** Stanford Generative Agents (Smallville) and Google DeepMind Concordia build emergent social simulacra in open-ended sandboxes. Paracosm ships a deterministic turn loop, personality drift, runtime tool forging, and a universal result schema.
32
+ ---
47
33
 
48
- Actors can be colony commanders, CEOs, generals, ship captains, department heads, AI systems, governing councils, or any entity that receives information, evaluates options, and makes choices that shape the world. The simulation does not care what they represent. It cares how they decide.
34
+ ## Forking Paths
49
35
 
50
- ### Counterfactual simulations with `WorldModel.fork()`
36
+ > "In all fictions, each time a man meets diverse alternatives, he chooses one and eliminates the others. In the work of Ts'ui Pên, he chooses, simultaneously, all of them."
37
+ >
38
+ > Jorge Luis Borges, *The Garden of Forking Paths*, 1941
51
39
 
52
- The CWSM positioning is operationalized through `WorldModel.fork()`: run a simulation with snapshots enabled, then branch at any past turn with a different actor or seed, and compare. On resumed runs, `maxTurns` remains the absolute final turn index. To run three additional turns from turn 3, pass `maxTurns: 6`.
40
+ A world model that can be forked needs three things: a deterministic substrate that can be rewound, an LLM reasoner that can be replayed against the same state, and a contract for what state actually means. Paracosm carries all three. Snapshots are JSON, the kernel round-trips through `JSON.stringify`, and every fork resumes from the captured state without recomputing the prefix.
53
41
 
54
42
  ```typescript
55
43
  import { WorldModel } from 'paracosm/world-model';
@@ -57,51 +45,85 @@ import worldJson from './my-world.json' with { type: 'json' };
57
45
 
58
46
  const wm = await WorldModel.fromJson(worldJson);
59
47
 
60
- // Run the trunk with per-turn snapshots captured.
48
+ // Trunk run, snapshots captured at every turn
61
49
  const trunk = await wm.simulate(visionaryActor, {
62
50
  maxTurns: 6, seed: 42, captureSnapshots: true,
63
51
  });
64
52
 
65
- // Branch at turn 3 with a different actor. No re-compute of turns 1-3;
66
- // the forked kernel resumes from the captured state.
53
+ // Fork at turn 3 with a different actor; turns 1 to 3 are reused, not rerun
67
54
  const branch = await (await wm.forkFromArtifact(trunk, 3)).simulate(
68
55
  pragmatistActor,
69
56
  { maxTurns: 6, seed: 42 },
70
57
  );
71
58
 
72
- console.log(trunk.metadata.runId); // parent run-id
59
+ console.log(trunk.metadata.runId); // parent run id
73
60
  console.log(branch.metadata.forkedFrom); // { parentRunId, atTurn: 3 }
74
- console.log(trunk.fingerprint, branch.fingerprint); // divergent futures from the same turn-3 state
61
+ console.log(trunk.fingerprint, branch.fingerprint);
75
62
  ```
76
63
 
77
- The kernel round-trips through `JSON.stringify`, so snapshots persist to disk cleanly for later replay or audit. `captureSnapshots` defaults to `false` to keep normal artifacts lean; set it when you want fork capability.
78
-
79
- The paracosm dashboard exposes the same mechanism end-to-end. Every UI-initiated run captures snapshots by default, so the Reports tab shows a `↳ Fork at {Time} N` button on each completed turn. Clicking it opens a fork modal (actor override, optional seed, optional custom events), POSTs to `/setup` with the full parent artifact, and routes the user to a new **Branches** tab where all forks launched from the current parent accumulate as cards with per-metric deltas rendered live as each branch streams to completion.
64
+ `captureSnapshots` defaults to `false` so that ordinary runs stay lean. The dashboard flips it on for every UI run; the Reports tab shows a fork button on each completed turn, posts to `/setup` with the parent artifact, and routes the new run into a Branches tab where forks accumulate as cards with per-metric deltas as they stream.
80
65
 
81
66
  ### Replay any run for audit
82
67
 
83
68
  ```typescript
84
69
  const replay = await wm.replay(storedArtifact);
85
- console.log(replay.matches); // true when the kernel produces byte-equal output
70
+ console.log(replay.matches); // true when the kernel reproduces the artifact byte for byte
86
71
  console.log(replay.divergence); // first-mismatch JSON pointer when matches=false
87
72
  ```
88
73
 
89
- The kernel's between-turn progression hook re-runs deterministically from each recorded snapshot; LLM stages are not invoked, so replay is free and fast. Use it for regression testing (replay golden artifacts in CI) or forensic comparison (find the first kernel-state divergence between two versions of paracosm). Pillar 2 (Reproducible) becomes verifiable in code rather than promised in copy.
74
+ The kernel's between-turn progression hook reruns deterministically from each recorded snapshot. LLM stages are not invoked, so replay is fast and free. Use it for golden-artifact regression tests in CI, or to find the first kernel-state divergence between two paracosm versions.
75
+
76
+ ---
77
+
78
+ ## Personality is the variable
79
+
80
+ > "We don't want to conquer the cosmos, we only want to extend the boundaries of Earth to the frontiers of the cosmos. We don't want other worlds; we want mirrors."
81
+ >
82
+ > Stanislaw Lem, *Solaris*, 1961
90
83
 
91
- ### Subpath for digital-twin use cases
84
+ Two simulation runs against an identical compiled scenario, starting from the same kernel state, produce divergent trajectories when the only thing that changes is the actor's personality. The kernel is reproducible. The divergence comes from the LLM stages reading a HEXACO profile and deciding accordingly.
85
+
86
+ Actors do not need to be people. The same authoring contract handles colony commanders, ship captains, AI release directors, governing councils, faction leaders, autonomous coordinators, or any entity whose decisions shape the world after a chain of inputs. Paracosm does not care what an actor represents. It cares how the actor decides.
92
87
 
93
88
  ```typescript
94
- import { DigitalTwin, type SubjectConfig, type InterventionConfig } from 'paracosm/digital-twin';
89
+ import { compileScenario } from 'paracosm/compiler';
90
+ import { runSimulation } from 'paracosm/runtime';
91
+ import worldJson from './my-world.json' with { type: 'json' };
95
92
 
96
- const twin = await DigitalTwin.fromJson(scenarioJson);
97
- const artifact = await twin.simulateIntervention(subject, intervention, actor);
93
+ const scenario = await compileScenario(worldJson, {
94
+ provider: 'anthropic',
95
+ model: 'claude-sonnet-4-6',
96
+ });
97
+
98
+ const reyes = {
99
+ name: 'Captain Reyes', archetype: 'The Pragmatist', unit: 'Station Alpha',
100
+ hexaco: { openness: 0.4, conscientiousness: 0.9, extraversion: 0.3,
101
+ agreeableness: 0.6, emotionality: 0.5, honestyHumility: 0.8 },
102
+ instructions: 'You lead by protocol. Safety margins first.',
103
+ };
104
+
105
+ const okafor = {
106
+ name: 'Captain Okafor', archetype: 'The Innovator', unit: 'Station Beta',
107
+ hexaco: { openness: 0.9, conscientiousness: 0.4, extraversion: 0.8,
108
+ agreeableness: 0.5, emotionality: 0.3, honestyHumility: 0.6 },
109
+ instructions: 'You lead by experimentation. Push boundaries.',
110
+ };
111
+
112
+ const [a, b] = await Promise.all(
113
+ [reyes, okafor].map((actor) =>
114
+ runSimulation(actor, [], { scenario, maxTurns: 6, seed: 42 }),
115
+ ),
116
+ );
117
+ console.log(a.fingerprint, b.fingerprint); // diverges visibly within two turns
98
118
  ```
99
119
 
100
- `DigitalTwin` is an alias of `WorldModel`; the subpath names the use case in the import path. The new `simulateIntervention()` sugar populates `RunArtifact.subject` and `RunArtifact.intervention` for traceability.
120
+ Six turns is enough to surface the contrast. The fingerprint is a stable hash over the trajectory, decisions, and final metrics, so two runs are easy to diff.
121
+
122
+ ---
101
123
 
102
- ### Quickstart: prompt or document to running simulation
124
+ ## Quickstart: prompt or document to running simulation
103
125
 
104
- `WorldModel.fromPrompt` compiles a scenario from seed source material (paste, URL, or extracted PDF text), then `wm.quickstart` generates N contextual HEXACO actors and runs them in parallel. Every prompt/document path validates against `DraftScenarioSchema` and routes into the existing `compileScenario` pipeline: the canonical `ScenarioPackage` contract is never bypassed.
126
+ `WorldModel.fromPrompt` compiles a scenario from seed source material (paste, URL, or extracted PDF text), and `wm.quickstart` then generates N contextual HEXACO actors and runs them in parallel. Both paths validate against `DraftScenarioSchema` and route into `compileScenario`. The canonical `ScenarioPackage` contract is never bypassed.
105
127
 
106
128
  ```typescript
107
129
  import { WorldModel } from 'paracosm/world-model';
@@ -115,32 +137,23 @@ const { actors, artifacts } = await wm.quickstart({ actorCount: 3 });
115
137
  artifacts.forEach((a, i) => console.log(actors[i].name, a.fingerprint));
116
138
  ```
117
139
 
118
- In the dashboard, the Quickstart tab is the default landing view. A user pastes a brief (or drops a PDF, or supplies a URL) and receives three streaming-live actors plus per-card Download JSON, Copy shareable link, and Fork-in-Branches actions within a minute of first click. A curated library of 10 HEXACO archetypes is exported at `paracosm/leader-presets` for programmatic `runBatch` sweeps or Swap-actor controls in downstream UIs.
140
+ In the dashboard, Quickstart is the default landing tab. A user pastes a brief, drops a PDF, or supplies a URL, and three streaming actors arrive within a minute of first click. A curated library of ten HEXACO archetypes ships under `paracosm/leader-presets` for programmatic `runBatch` sweeps.
141
+
142
+ ---
119
143
 
120
144
  ## Install
121
145
 
122
146
  ```bash
123
- npm install paracosm # also works: pnpm add paracosm / bun add paracosm
147
+ npm install paracosm # also: pnpm add paracosm · bun add paracosm
124
148
  ```
125
149
 
126
- Paracosm ships as pure ESM with subpath exports (`paracosm/compiler`, `paracosm/runtime`, `paracosm/mars`, `paracosm/lunar`, `paracosm/core`, `paracosm/schema`). Node 20+, Bun 1.x, and any TypeScript runner with ESM + import-attributes support (`tsx`, `ts-node --esm`) resolve them out of the box. If `import ... from 'paracosm/compiler'` fails with a module-not-found error, the dependency was never installed in that project. `cd` into the right directory and run one of the commands above.
150
+ Paracosm ships as pure ESM with subpath exports (`paracosm/compiler`, `paracosm/runtime`, `paracosm/mars`, `paracosm/lunar`, `paracosm/core`, `paracosm/schema`, `paracosm/world-model`, `paracosm/digital-twin`). Node 20+, Bun 1.x, and any TypeScript runner with ESM and import-attributes support resolve them out of the box.
127
151
 
128
- ### 1. Define your world
129
-
130
- The canonical authoring contract is JSON because JSON can be validated, diffed, cached, snapshotted, and exported as schema. You can write that draft directly, or ground it with natural-language source material through `seedText` / `seedUrl` during compilation. A future prompt-only wrapper should generate this same contract first, then compile it.
152
+ ---
131
153
 
132
- Every scenario declares its own vocabulary via `labels.populationNoun`
133
- (plural, e.g. `"colonists"` / `"crew"` / `"citizens"`) and
134
- `labels.settlementNoun` (singular, e.g. `"colony"` / `"habitat"` /
135
- `"kingdom"`). The dashboard + runtime pick these up everywhere
136
- user-facing copy renders.
154
+ ## Defining a world
137
155
 
138
- If you omit `labels`, Paracosm falls back to `"colonists"` /
139
- `"colony"`. Defaults that read fine across most domains but usually
140
- feel sharper when you pick your own. "Colony" is the default because
141
- it's narratively richer than a neutral "group" / "unit" while still
142
- translating to Mars habitats, medieval holds, corporate teams, or any
143
- bounded collective under an actor's decisions.
156
+ The authoring contract is JSON because JSON validates, diffs, caches, and snapshots. A draft can be hand-written, generated from a prompt, or grounded with `seedText` / `seedUrl`.
144
157
 
145
158
  ```json
146
159
  {
@@ -149,6 +162,7 @@ bounded collective under an actor's decisions.
149
162
  "name": "Deep Ocean Habitat",
150
163
  "populationNoun": "crew",
151
164
  "settlementNoun": "habitat",
165
+ "timeUnitNoun": "day",
152
166
  "currency": "credits"
153
167
  },
154
168
  "setup": {
@@ -178,144 +192,101 @@ bounded collective under an actor's decisions.
178
192
  }
179
193
  ```
180
194
 
181
- > **Terminology: `labels.populationNoun` + `settlementNoun` + `timeUnitNoun`**
182
- >
183
- > The engine defaults to **`colonists` / `colony` / `tick`** when a scenario omits these
184
- > fields, but every scenario can and should override them. The dashboard uses the overridden
185
- > nouns throughout: help legends, roster headers, empty states, screen-reader text, the viz tab,
186
- > report summaries. A handful of examples:
187
- >
188
- > | Scenario | `settlementNoun` | `populationNoun` | `timeUnitNoun` |
189
- > |-------------------|------------------|------------------|----------------|
190
- > | Mars Genesis | `colony` | `colonists` | `year` |
191
- > | Submarine (daily) | `habitat` | `crew` | `day` |
192
- > | Medieval | `kingdom` | `subjects` | `year` |
193
- > | Corporate | `company` | `employees` | `quarter` |
194
- > | Space Station | `station` | `operators` | `year` |
195
- > | Generation Ship | `vessel` | `passengers` | `year` |
196
- > | Benchmark Arena | `session` | `agents` | `tick` |
197
- >
198
- > `populationNoun` is the **plural** form; the dashboard derives the singular (`colonists` →
199
- > `colonist`) and capitalised variants automatically. `settlementNoun` is **singular** (`colony`,
200
- > not `colonies`). `timeUnitNoun` is **singular** and pairs with `timeUnitNounPlural` for
201
- > grammatical display; both are optional and fall back to `tick` / `ticks`. Paracosm itself
202
- > is a structured world model at the meta layer; what it simulates inside each run is
203
- > scenario-flavoured via these fields.
195
+ Every scenario declares its own vocabulary via `labels.populationNoun` (plural), `labels.settlementNoun` (singular), and `labels.timeUnitNoun`. The dashboard, kernel, and progression hooks pick those up everywhere user-facing copy renders. Without overrides, paracosm falls back to `colonists` / `colony` / `tick`.
196
+
197
+ Time is unit-agnostic. `setup.defaultTimePerTurn` and `setup.defaultStartTime` are plain numbers; whether they represent years, quarters, hours, or ticks is decided by `timeUnitNoun`. The dashboard turn header reads `Quarter 5`, `Day 22`, or `Year 2043` straight from the label.
198
+
199
+ ---
204
200
 
205
- ### 2. Compile and run
201
+ ## Compile and run
206
202
 
207
203
  ```typescript
208
204
  import { compileScenario } from 'paracosm/compiler';
209
205
  import { runSimulation } from 'paracosm/runtime';
210
206
  import worldJson from './my-world.json' with { type: 'json' };
211
207
 
212
- // Compile a typed world draft into a runnable scenario (~$0.10, cached to disk)
208
+ // First compile is roughly $0.10 and caches to disk; reruns are free
213
209
  const scenario = await compileScenario(worldJson, {
214
210
  provider: 'anthropic',
215
211
  model: 'claude-sonnet-4-6',
216
212
  });
217
213
 
218
- // Define actors with HEXACO personality profiles.
219
- // Actors can be any top-down decision maker: commander, CEO, general,
220
- // governing council, AI system, department head. The engine doesn't care
221
- // what they represent, only how their personality shapes decisions.
222
- const actors = [
223
- {
224
- name: 'Captain Reyes',
225
- archetype: 'The Pragmatist',
226
- unit: 'Station Alpha',
227
- hexaco: { openness: 0.4, conscientiousness: 0.9,
228
- extraversion: 0.3, agreeableness: 0.6,
229
- emotionality: 0.5, honestyHumility: 0.8 },
230
- instructions: 'You lead by protocol. Safety margins first.',
231
- },
232
- {
233
- name: 'Captain Okafor',
234
- archetype: 'The Innovator',
235
- unit: 'Station Beta',
236
- hexaco: { openness: 0.9, conscientiousness: 0.4,
237
- extraversion: 0.8, agreeableness: 0.5,
238
- emotionality: 0.3, honestyHumility: 0.6 },
239
- instructions: 'You lead by experimentation. Push boundaries.',
240
- },
241
- ];
242
-
243
- // Run in parallel: same seed, same crises, different outcomes
244
- const results = await Promise.all(
245
- actors.map(actor =>
246
- runSimulation(actor, [], {
247
- scenario,
248
- maxTurns: 6,
249
- seed: 42,
250
- // costPreset: 'economy', // uncomment for ~5-10× cheaper iteration on OpenAI
251
- // Every event carries a universal `e.data.summary` one-liner the
252
- // runtime populates for you; prints cleanly for all 17 event
253
- // types without guessing which fields exist where.
254
- //
255
- // For full intellisense on per-event data, narrow via e.type:
256
- // if (e.type === 'event_start') e.data.title // string
257
- // if (e.type === 'outcome') e.data.systemDeltas // Record<string,number>
258
- // if (e.type === 'forge_attempt') e.data.approved // boolean
259
- onEvent(e) { console.log(actor.name, e.type, e.data.summary); },
260
- })
261
- )
262
- );
214
+ const result = await runSimulation(actor, [], {
215
+ scenario,
216
+ maxTurns: 6,
217
+ seed: 42,
218
+ // costPreset: 'economy', // ~5-10× cheaper iteration on OpenAI
219
+ onEvent(e) { console.log(actor.name, e.type, e.data.summary); },
220
+ });
263
221
 
264
- // The return value is a full run artifact. A few of the fields most
265
- // consumers want right away:
266
- for (const r of results) {
267
- console.log(r.metadata.scenario.name, '→', r.fingerprint);
268
- console.log(' cost $', r.cost?.totalUSD.toFixed(2), `(${r.cost?.llmCalls} LLM calls)`);
269
- console.log(' final ', r.finalState?.metrics); // population, morale, foodMonthsReserve, powerKw, …
270
- console.log(' tools ', r.forgedTools?.length ?? 0, // deduped forge catalog
271
- 'citations', r.citations?.length ?? 0); // DOI-linked references
272
- if (r.providerError) {
273
- console.error(' provider error:', r.providerError.kind, r.providerError.message);
274
- }
275
- }
222
+ console.log(result.metadata.scenario.name, '→', result.fingerprint);
223
+ console.log('cost $', result.cost?.totalUSD.toFixed(2));
224
+ console.log('final ', result.finalState?.metrics);
225
+ console.log('forged tools ', result.forgedTools?.length ?? 0);
226
+ console.log('citations ', result.citations?.length ?? 0);
227
+ ```
228
+
229
+ Each call to `runSimulation` takes one actor. Run one, two, or twenty. The dashboard runs two side-by-side for comparison; the API has no limit.
230
+
231
+ ### Or use the dashboard
232
+
233
+ ```bash
234
+ git clone https://github.com/framersai/paracosm
235
+ cd paracosm && npm install
236
+ cp .env.example .env # add OPENAI_API_KEY or ANTHROPIC_API_KEY
237
+ npm run dashboard # opens http://localhost:3456
276
238
  ```
277
239
 
278
- Each call to `runSimulation` takes one actor. Run one, two, or twenty. The dashboard runs two side-by-side for comparison, but the API has no limit. Actors don't need to be people. They can model competing strategies, policy frameworks, organizational philosophies, or autonomous systems responding to the same events with different decision profiles.
240
+ The dashboard ships a scenario editor for writing, importing, compiling, and running custom worlds from the browser, plus the live Branches view for forks.
279
241
 
280
- ### The universal result contract
242
+ ### Or run the standalone CLI
281
243
 
282
- Every simulation returns a `RunArtifact`: one universal Zod-validated shape exported from `paracosm/schema`. The same shape covers civilization sims (turn-loop), digital-twin simulations (batch-trajectory), and one-shot forecasts (batch-point).
244
+ ```bash
245
+ npm install -g paracosm
246
+
247
+ paracosm run # actors.json + default scenario
248
+ paracosm run --name "Reyes" --openness 0.85 --turns 6
249
+ paracosm dashboard 6 # auto-launch with 6 turns
250
+ paracosm compile scenarios/lunar.json --seed-url <url> --max-searches 5
251
+ paracosm init my-app --domain "Submarine crew of 8" --actors 3
252
+ ```
253
+
254
+ The CLI looks for `actors.json` via `--actors`, then `./actors.json`, then `./config/actors.json`, then a bundled example. A back-compat `paracosm-dashboard` alias is shipped for existing scripts and Docker invocations.
255
+
256
+ ---
257
+
258
+ ## The universal result contract
259
+
260
+ Every simulation returns a `RunArtifact`: one Zod-validated shape exported from `paracosm/schema`. The same shape covers civilization sims (turn-loop), digital-twin runs (batch-trajectory), and one-shot forecasts (batch-point).
283
261
 
284
262
  ```typescript
285
263
  import { RunArtifactSchema, type RunArtifact } from 'paracosm/schema';
286
- import { runSimulation } from 'paracosm/runtime';
287
264
 
288
265
  const artifact: RunArtifact = await runSimulation(actor, [], { scenario, maxTurns: 6 });
289
-
290
- // Optional runtime validation (dev mode, untrusted JSON, replays, etc.):
291
- const parsed = RunArtifactSchema.parse(artifact);
266
+ const parsed = RunArtifactSchema.parse(artifact); // optional dev-mode validation
292
267
 
293
268
  switch (artifact.metadata.mode) {
294
- case 'turn-loop': // paracosm civ-sims: per-turn trajectory + decisions
295
- case 'batch-trajectory': // digital-twin: labeled timepoints over a horizon
296
- case 'batch-point': // one-shot forecast: overview + risk flags only
269
+ case 'turn-loop': // civ sims: per-turn trajectory + decisions
270
+ case 'batch-trajectory': // digital twin: labeled timepoints over a horizon
271
+ case 'batch-point': // one-shot forecast: overview + risk flags
297
272
  }
298
-
299
- artifact.trajectory?.timepoints?.forEach((tp) => {
300
- console.log(tp.label, tp.score?.value, tp.narrative);
301
- });
302
273
  ```
303
274
 
304
- For non-TypeScript consumers: `npm run export:json-schema` emits `schema/run-artifact.schema.json` + `schema/stream-event.schema.json`. Python projects generate Pydantic types via `datamodel-codegen`. Any ecosystem with a JSON-Schema code generator adopts cleanly.
275
+ For non-TypeScript consumers, `npm run export:json-schema` emits `schema/run-artifact.schema.json` and `schema/stream-event.schema.json`. Python projects generate Pydantic types via `datamodel-codegen`; any ecosystem with a JSON-Schema generator adopts cleanly.
305
276
 
306
- ### Digital twins: subjects + interventions
277
+ ---
307
278
 
308
- For simulations built around a single subject (a person, character, organism, vessel) under a counterfactual intervention, paracosm exposes `SubjectConfig` + `InterventionConfig` as first-class input primitives under `paracosm/schema`. Pass them through `RunOptions` and they land on the returned `RunArtifact.subject` / `RunArtifact.intervention` for downstream consumers:
279
+ ## Digital twins: subjects and interventions
280
+
281
+ For simulations that revolve around a single subject under an intervention, paracosm exposes a `DigitalTwin` subpath plus `SubjectConfig` and `InterventionConfig` as first-class input primitives.
309
282
 
310
283
  ```typescript
311
- import {
312
- SubjectConfigSchema,
313
- InterventionConfigSchema,
314
- type SubjectConfig,
315
- type InterventionConfig,
316
- } from 'paracosm/schema';
317
-
318
- const subject: SubjectConfig = SubjectConfigSchema.parse({
284
+ import { DigitalTwin } from 'paracosm/digital-twin';
285
+ import { SubjectConfigSchema, InterventionConfigSchema } from 'paracosm/schema';
286
+
287
+ const twin = await DigitalTwin.fromJson(scenarioJson);
288
+
289
+ const subject = SubjectConfigSchema.parse({
319
290
  id: 'user-42',
320
291
  name: 'Alice',
321
292
  profile: { age: 34, diet: 'mediterranean' },
@@ -323,7 +294,7 @@ const subject: SubjectConfig = SubjectConfigSchema.parse({
323
294
  markers: [{ id: 'rs4680', category: 'genome', value: 'AA' }],
324
295
  });
325
296
 
326
- const intervention: InterventionConfig = InterventionConfigSchema.parse({
297
+ const intervention = InterventionConfigSchema.parse({
327
298
  id: 'intv-1',
328
299
  name: 'Creatine + Sleep Hygiene',
329
300
  description: '5g daily + 11pm bedtime.',
@@ -331,693 +302,281 @@ const intervention: InterventionConfig = InterventionConfigSchema.parse({
331
302
  adherenceProfile: { expected: 0.7 },
332
303
  });
333
304
 
334
- const artifact = await runSimulation(actor, [], { scenario, maxTurns: 6, subject, intervention });
335
- // artifact.subject + artifact.intervention carry through to any consumer
336
- ```
337
-
338
- Turn-loop mode stashes both verbatim without semantic consumption; external batch-trajectory executors (LangGraph-style pipelines) populate them from their own flow.
339
-
340
- ### 3. Or use the dashboard
341
-
342
- ```bash
343
- git clone https://github.com/framersai/paracosm
344
- cd paracosm && npm install
345
- cp .env.example .env # add your OpenAI or Anthropic key
346
- npm run dashboard # opens http://localhost:3456
305
+ const artifact = await twin.simulateIntervention(subject, intervention, actor);
347
306
  ```
348
307
 
349
- The dashboard includes a scenario editor where you can write, import, compile, and run custom worlds from the browser.
308
+ `DigitalTwin` is an alias of `WorldModel`. The subpath names the use case in the import path. `RunArtifact.subject` and `RunArtifact.intervention` carry through to any consumer.
350
309
 
351
- ### 4. Or run the standalone CLI
310
+ ---
352
311
 
353
- After `npm install paracosm -g` you get one umbrella binary with subcommands. Every level supports `--help` / `-h` and a global `--version` / `-v`:
312
+ ## Trait models beyond HEXACO
354
313
 
355
- ```bash
356
- paracosm --help # lists every subcommand
357
- paracosm --version # prints "paracosm 0.7.x"
314
+ Actors are not always human. Paracosm ships a `TraitModel` registry with two built-ins, and registering more is one call.
358
315
 
359
- paracosm run # run a sim against actors.json
360
- paracosm run --actor 1 --turns 5 # actor index 1, 5 turns
361
- paracosm run --name "Reyes" --openness 0.85 --conscientiousness 0.4 --turns 6
362
- paracosm run --actors ./my-actors.json --live # custom roster + live web search
316
+ | Model | Axes | For |
317
+ |-------------|---------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|
318
+ | `hexaco` | openness, conscientiousness, extraversion, agreeableness, emotionality, honesty-humility | CEOs, captains, governors, councils, military commanders |
319
+ | `ai-agent` | exploration, verification-rigor, deference, risk-tolerance, transparency, instruction-following | Frontier-lab release directors, autonomous coordinators, eval subs |
363
320
 
364
- paracosm dashboard # SSE dashboard at http://localhost:3456
365
- paracosm dashboard 6 # auto-launch with 6 turns
321
+ ```typescript
322
+ import { runSimulation } from 'paracosm';
366
323
 
367
- paracosm compile scenarios/lunar.json --seed-url <url> --max-searches 5
324
+ const releaseDirector = {
325
+ name: 'Atlas-Bot Release Director',
326
+ archetype: 'Aggressive AI Release Optimizer',
327
+ unit: 'Frontier Lab',
328
+ // The 0.7 schema still asks for a representative HEXACO snapshot; removal scheduled for 0.9.
329
+ hexaco: { openness: 0.6, conscientiousness: 0.3, extraversion: 0.5,
330
+ agreeableness: 0.3, emotionality: 0.2, honestyHumility: 0.3 },
331
+ traitProfile: {
332
+ modelId: 'ai-agent',
333
+ traits: {
334
+ exploration: 0.85,
335
+ 'verification-rigor': 0.2,
336
+ deference: 0.2,
337
+ 'risk-tolerance': 0.85,
338
+ transparency: 0.4,
339
+ 'instruction-following': 0.4,
340
+ },
341
+ },
342
+ instructions: 'You weight time-to-market. Verification is overhead.',
343
+ };
368
344
 
369
- paracosm init my-app --domain "Submarine crew of 8" --actors 3
345
+ await runSimulation(releaseDirector, [], { scenario, maxTurns: 6, seed: 42 });
370
346
  ```
371
347
 
372
- A second back-compat binary `paracosm-dashboard` is shipped as an alias for `paracosm dashboard` so existing scripts and Docker invocations don't break.
348
+ The orchestrator's `normalizeActorConfig` accepts either shape. End-to-end captures and full surface live in [`docs/COOKBOOK.md`](docs/COOKBOOK.md).
373
349
 
374
- The CLI looks for `actors.json` in this order:
350
+ ---
375
351
 
376
- 1. `--actors <path>` flag (explicit)
377
- 2. `./actors.json` in your current directory
378
- 3. `./config/actors.json` in your current directory
379
- 4. A bundled `config/actors.example.json` (so commands work out of the box)
352
+ ## Cost envelope
380
353
 
381
- Copy the example to start customizing:
354
+ Running a simulation calls real LLM APIs against the user's key. Paracosm assigns a different model tier per role so flagship cost only lands where it earns its keep (forge-code correctness).
382
355
 
383
- ```bash
384
- # Option 1: in your project root
385
- cp node_modules/paracosm/config/actors.example.json actors.json
356
+ | Preset | Departments | Commander · Director · Judge | Reactions | OpenAI / run | Anthropic / run |
357
+ |-----------------------|--------------------------------------|-----------------------------------------------------|----------------------------------------------------|--------------|-----------------|
358
+ | `quality` (default) | gpt-5.4 · claude-sonnet-4-6 | gpt-5.4-mini · claude-haiku-4-5-20251001 | gpt-5.4-nano · claude-haiku-4-5-20251001 | ~$1 to $3 | ~$3 to $7 |
359
+ | `economy` | gpt-4o · claude-sonnet-4-6 | gpt-5.4-nano · claude-haiku-4-5-20251001 | gpt-5.4-nano · claude-haiku-4-5-20251001 | ~$0.20 to $0.60 | ~$3 to $5 |
386
360
 
387
- # Option 2: organized in a config/ folder
388
- mkdir -p config && cp node_modules/paracosm/config/actors.example.json config/actors.json
389
- ```
361
+ Numbers assume 6 turns, 5 departments, 100 agents, up to 3 events per turn. Forge approval rate drops 10 to 20 points on `economy` because the mid-tier department model occasionally violates structured-output schemas the judge rejects. Use `economy` for iteration and CI; use `quality` for publishable runs. Explicit `models` entries always win over the preset, so per-role overrides combine cleanly with global defaults.
390
362
 
391
- Then edit the HEXACO sliders and `instructions` fields to describe your own actors. The simulation picks up the file on the next run.
363
+ `runSimulation` returns a `cost` field with token counts, LLM call counts, and USD spend. Every stable system prefix routes through a `cacheBreakpoint: true` block, so on Anthropic the shared prefix serves from prompt cache at one-tenth input cost from turn 2 onward; OpenAI auto-caches any prompt over 1024 tokens. The `cost.caches` field reports tokens read, tokens created, and USD saved per run.
392
364
 
393
- ## Scenario Compiler
365
+ ---
394
366
 
395
- The compiler turns a typed world draft plus optional prompt/document/URL grounding into a runnable scenario by generating TypeScript hooks via LLM calls:
367
+ ## How a turn runs
396
368
 
397
- ```bash
398
- npm run compile -- scenarios/submarine.json \
399
- --seed-url https://example.com/report \
400
- --no-web-search
401
369
  ```
370
+ 1. EVENT DIRECTOR Reads world state, prior decisions, tool intelligence.
371
+ Generates an event that targets actual weaknesses.
402
372
 
403
- Options: `--seed-text`, `--seed-url`, `--no-web-search`, `--max-searches`. Use `--seed-text` for a pasted brief or prompt, and `--seed-url` for a report, paper, or web page. The JSON file remains the contract that gets validated and cached; seed material grounds the world before hook generation. Compiled scenarios appear in the dashboard selector. Cost is roughly $0.10 per compile, cached to disk after first generation.
404
-
405
- ### Programmatic compiler options
373
+ 2. KERNEL ADVANCE Deterministic time progression: births, deaths, aging,
374
+ health decay, resource consumption. Seeded PRNG.
406
375
 
407
- Every CLI flag has a matching programmatic option on `compileScenario`. The compiler caches per-hook on the scenario hash + model + schema version, and separately caches the seed bundle on the seed signature (text/URL + `webSearch` + `maxSearches`), so re-running the same call is free after the first hit.
376
+ 3. DEPARTMENT ANALYSIS All active departments analyze the event in parallel.
377
+ Each head uses personality plus tools. Specialists can
378
+ forge new computational tools at runtime in a hardened
379
+ node:vm sandbox. An LLM judge approves each forge.
408
380
 
409
- ```typescript
410
- import { compileScenario } from 'paracosm/compiler';
411
-
412
- const scenario = await compileScenario(worldJson, {
413
- provider: 'anthropic', // 'openai' (default) or 'anthropic'
414
- model: 'claude-sonnet-4-6', // omit → provider default (gpt-5.4-mini / claude-sonnet-4-6)
415
- cache: true, // default. Set false to force regeneration.
416
- cacheDir: '.paracosm/cache', // default. Change per project / per CI run.
417
- seedUrl: 'https://ntrs.nasa.gov/citations/20210018970', // or: seedText: '…inline markdown…'
418
- webSearch: true, // fan out to Firecrawl/Tavily/Serper/Brave
419
- maxSearches: 5,
420
- onProgress(hookName, status) {
421
- // 'generating' | 'cached' | 'done' | 'fallback'
422
- console.log(` [${status.padEnd(10)}] ${hookName}`);
423
- },
424
- });
425
- ```
426
-
427
- Cache hits show up as `cached` in the progress callback. First-run cost is roughly $0.10; cached re-runs are free. If neither `OPENAI_API_KEY` nor `ANTHROPIC_API_KEY` is set, the compiler throws `ProviderKeyMissingError` before making any calls. See [Error handling](#error-handling).
381
+ 4. COMMANDER DECISION Reads all department reports. Selects an option.
382
+ Personality shapes risk tolerance and priority weighting.
428
383
 
429
- ## Cost Envelope
384
+ 5. OUTCOME Kernel classifies the outcome (risky success, risky
385
+ failure, safe success, safe failure) from option,
386
+ probability, and colony state.
430
387
 
431
- Running a simulation calls real LLM APIs against your key. Paracosm assigns a different tier per role so flagship cost only lands where it earns its keep (forge-code correctness):
388
+ 6. EFFECTS Kernel applies deltas (population, morale, food,
389
+ power, etc.) per outcome and event category.
432
390
 
433
- | Preset | Departments | Commander / Director / Judge | Reactions | OpenAI per-run | Anthropic per-run |
434
- |--------|-------------|------------------------------|-----------|---------------|-------------------|
435
- | **`quality`** (default) | `gpt-5.4` / `claude-sonnet-4-6` | `gpt-5.4-mini` / `claude-haiku-4-5-20251001` | `gpt-5.4-nano` / `claude-haiku-4-5-20251001` | **~$1-3** | **~$3-7** |
436
- | **`economy`** | `gpt-4o` / `claude-sonnet-4-6` | `gpt-5.4-nano` / `claude-haiku-4-5-20251001` | `gpt-5.4-nano` / `claude-haiku-4-5-20251001` | **~$0.20-0.60** | ~$3-5 |
391
+ 7. AGENT REACTIONS ~100 agents react in parallel using a cheap model.
392
+ Each reaction is shaped by the agent's personality,
393
+ health, relationships, and accumulated memories.
437
394
 
438
- Numbers assume 6 turns, 5 departments, 100 agents, up to 3 events per turn. An 8-turn run on OpenAI `quality` tends to land at ~$1.50-2.00 per actor. The call budget is ~10/turn (1 director + ~5 dept + 1 commander + ~3 reaction batches + 0-2 forges + 0-1 judge), and departments on flagship carry most of the cost.
395
+ 8. MEMORY Reactions become persistent memories. Short-term
396
+ consolidates into long-term. Stances drift.
397
+ Relationships shift on shared experience.
439
398
 
440
- Pick the preset explicitly for quick iteration:
441
-
442
- ```typescript
443
- const scenario = await compileScenario(worldJson);
444
- const output = await runSimulation(actor, [], {
445
- scenario,
446
- maxTurns: 4, // fewer turns = linear cost reduction
447
- seed: 42,
448
- costPreset: 'economy', // ~5-10× cheaper than 'quality' on OpenAI
449
- });
399
+ 9. PERSONALITY DRIFT HEXACO traits shift through actor pull, role activation,
400
+ and outcome reinforcement. The commander drifts alongside
401
+ their agents using peer-reviewed outcome-pull tables.
450
402
  ```
451
403
 
452
- Forge approval rate drops roughly 10-20pp on `economy` because the mid-tier department model occasionally violates structured-output schemas the judge rejects. Use `'economy'` for iteration / CI / debugging; use `'quality'` (default) for publishable or production runs.
453
-
454
- Explicit `models` entries always win over the preset so you can mix and match. `{ costPreset: 'economy', models: { departments: 'gpt-5.4' } }` gives you cheap everything except departments. Override any single role: `{ models: { judge: 'gpt-5.4' } }` pays for stricter forge review without raising every other tier.
455
-
456
- The orchestrator's `runSimulation()` returns a `cost` field with token counts, LLM call counts, and USD spend aggregated from every tracked call (director, departments, commander, judge, agent reactions). The dashboard StatsBar shows this live.
404
+ Every structured LLM call (director events, department reports, commander decisions, reactions, verdict, promotions) runs through Zod schema validation with automatic retry-with-feedback on failure. Schemas live under [`src/runtime/schemas/`](src/runtime/schemas/). Two wrappers (`generateValidatedObject` for one-shot, `sendAndValidate` for session-aware) preserve conversation memory while enforcing validation discipline.
457
405
 
458
- ### Prompt caching
459
-
460
- Every LLM call site on both providers routes its stable system prefix through a `cacheBreakpoint: true` block (director instructions, department prompts, reaction batches, compile-time hook generators). On Anthropic, turn 2+ of every run serves the shared prefix from the provider's prompt cache at 0.1× input cost. On OpenAI, any prompt ≥ 1024 tokens auto-caches. The `cost.caches` field reports read / creation tokens and USD saved per run, and `/retry-stats` rolls the numbers up across the last 100 runs so you can verify the cache is actually hitting. No configuration required. The `system: Array<{ text; cacheBreakpoint }>` shape is built into the validated-call wrappers in `src/engine/compiler/llm-invocations/` and `src/runtime/llm-invocations/`.
406
+ ---
461
407
 
462
- ## One-shot HTTP API: `POST /simulate`
408
+ ## Seed enrichment and citations
463
409
 
464
- Non-SSE consumers (curl, Python integrations, third-party dashboards) can run a simulation through a plain request-response endpoint. Gated behind `PARACOSM_ENABLE_SIMULATE_ENDPOINT=true` so the hosted demo's SSE-first path stays the default; self-hosted deployments flip the flag on.
410
+ Real source material grounds the scenario all the way through to department reports.
465
411
 
466
412
  ```bash
467
- export PARACOSM_ENABLE_SIMULATE_ENDPOINT=true
468
- paracosm dashboard # or bring up your own server via createMarsServer
469
-
470
- curl -s -X POST http://localhost:3456/simulate \
471
- -H 'Content-Type: application/json' \
472
- -H 'X-Anthropic-Key: sk-ant-...' \
473
- -d '{
474
- "scenario": { "id": "submarine-habitat", "labels": { "name": "Deep Ocean Habitat", "populationNoun": "crew", "settlementNoun": "habitat", "timeUnitNoun": "day" }, "setup": { "defaultTurns": 4, "defaultPopulation": 25, "defaultStartTime": 2040 }, "departments": [...], "metrics": [...] },
475
- "actor": { "name": "Captain Reyes", "archetype": "The Pragmatist", "unit": "Deep Ocean Habitat", "hexaco": { "openness": 0.4, "conscientiousness": 0.9, "extraversion": 0.3, "agreeableness": 0.6, "emotionality": 0.5, "honestyHumility": 0.8 }, "instructions": "" },
476
- "options": { "maxTurns": 4, "seed": 42, "captureSnapshots": true, "provider": "anthropic" }
477
- }' | jq '.artifact.fingerprint'
413
+ paracosm compile scenarios/lunar.json --seed-text "$(cat ./papers/iss-radiation.md)"
414
+ paracosm compile scenarios/lunar.json --seed-url https://ntrs.nasa.gov/citations/20210018970
478
415
  ```
479
416
 
480
- The request body accepts either a pre-compiled `ScenarioPackage` (has `.hooks`) or a raw scenario draft the compiler accepts; raw drafts are auto-compiled server-side with optional `options.seedText` / `options.seedUrl` grounding. The response body is `{ artifact: RunArtifact, scenario: ScenarioPackage, durationMs: number }`. Rate limiting shares the same IP bucket as `/setup`; request-body size uses the same 5 MiB cap.
481
-
482
- ## Programmatic API
483
-
484
- Everything the dashboard does is also available as library calls. The exports fall into five buckets:
485
-
486
- | Import | Surface |
487
- |--------|---------|
488
- | `paracosm/compiler` | `compileScenario`, `ingestSeed`, `ingestFromUrl`, type `CompileOptions` |
489
- | `paracosm/runtime` | `runSimulation`, `runBatch`, `EventDirector`, `generateAgentReactions`, `buildEventSummary`, `createParacosmClient`, memory helpers, type `CostPreset` |
490
- | `paracosm` | `createParacosmClient`, `ProviderKeyMissingError`, `SeededRng`, `SimulationKernel`, all `Scenario*` types |
491
- | `paracosm/core` | Kernel state types (`Agent`, `WorldState`, `HexacoProfile`, …) |
492
- | `paracosm/mars`, `paracosm/lunar` | Pre-built `ScenarioPackage` constants to use or fork |
417
+ The pipeline runs eight steps: extract topics and search queries from the seed, fan out to Firecrawl / Tavily / Serper / Brave in parallel, dedup and rerank with Cohere `rerank-v3.5`, assemble a `KnowledgeBundle`, ingest into an AgentOS `AgentMemory.sqlite()` store, recall per event during runtime, inject `[claim](url)` markdown into department prompts, and surface citations in the dashboard's Reports tab. The seed bundle is cached separately from the hook cache, keyed on the seed signature, so the same URL never re-extracts.
493
418
 
494
- ### Client: global defaults + env-var config
419
+ ---
495
420
 
496
- `createParacosmClient` pins `provider`, `costPreset`, per-role `models`, and compile-time options once, then hands back `runSimulation` / `runBatch` / `compileScenario` methods that inherit those defaults. Per-call overrides still win, merged at the per-role level so `models: { departments: 'gpt-5.4' }` at the client and `models: { judge: 'gpt-5.4' }` at the call combine to pin both roles instead of one replacing the other.
421
+ ## Built-in scenarios
497
422
 
498
- ```typescript
499
- import { createParacosmClient } from 'paracosm';
500
-
501
- const client = createParacosmClient({
502
- provider: 'openai',
503
- costPreset: 'economy', // cheap default for iteration
504
- models: { departments: 'gpt-5.4' }, // but pin departments to flagship
505
- compilerProvider: 'anthropic', // compile on a different provider if you want
506
- compilerModel: 'claude-sonnet-4-6',
507
- });
423
+ | Scenario | Description |
424
+ |---------------|-------------------------------------------------------------------------------------------------------------------|
425
+ | Mars Genesis | 100 colonists, 6 turns over 48 years. 5 departments, emergent dust storms, water crises, first Marsborn generation. |
426
+ | Lunar Outpost | 50-person crew at the south pole. Mining, life support, comms. Regolith toxicity, 1/6g atrophy. |
508
427
 
509
- const scenario = await client.compileScenario(worldJson);
510
- const out = await client.runSimulation(actor, [], { maxTurns: 6, seed: 42 });
428
+ Both ship as `paracosm/mars` and `paracosm/lunar` exports and serve as references for building custom scenarios.
511
429
 
512
- // Promote one specific run to quality without touching the client:
513
- const gold = await client.runSimulation(actor, [], {
514
- maxTurns: 8, seed: 42, costPreset: 'quality',
515
- });
516
-
517
- // Batch 20 ablations with shared config:
518
- const manifest = await client.runBatch({
519
- scenarios: [scenarioA, scenarioB], actors, turns: 6, seed: 42, maxConcurrency: 4,
520
- });
521
- ```
430
+ ---
522
431
 
523
- Env vars feed the same defaults and are read once at `createParacosmClient` construction. Explicit args win over env; env wins over the built-in library defaults.
432
+ ## Programmatic API
524
433
 
525
- | Env var | Maps to | Valid values |
526
- |---------|---------|--------------|
527
- | `PARACOSM_PROVIDER` | `provider` | `openai` / `anthropic` |
528
- | `PARACOSM_COST_PRESET` | `costPreset` | `quality` / `economy` |
529
- | `PARACOSM_MODEL_COMMANDER` | `models.commander` | any provider-valid model id |
530
- | `PARACOSM_MODEL_DEPARTMENTS` | `models.departments` | any provider-valid model id |
531
- | `PARACOSM_MODEL_JUDGE` | `models.judge` | any provider-valid model id |
532
- | `PARACOSM_MODEL_DIRECTOR` | `models.director` | any provider-valid model id |
533
- | `PARACOSM_MODEL_AGENT_REACTIONS` | `models.agentReactions` | any provider-valid model id |
534
- | `PARACOSM_COMPILER_PROVIDER` | `compilerProvider` | `openai` / `anthropic` |
535
- | `PARACOSM_COMPILER_MODEL` | `compilerModel` | any provider-valid model id |
434
+ | Import | Surface |
435
+ |-------------------------------------|-----------------------------------------------------------------------------------------------------------|
436
+ | `paracosm/compiler` | `compileScenario`, `ingestSeed`, `ingestFromUrl`, `CompileOptions` |
437
+ | `paracosm/runtime` | `runSimulation`, `runBatch`, `EventDirector`, `generateAgentReactions`, `buildEventSummary`, memory helpers |
438
+ | `paracosm` | `createParacosmClient`, `ProviderKeyMissingError`, `SeededRng`, `SimulationKernel`, all `Scenario*` types |
439
+ | `paracosm/core` | Kernel state types: `Agent`, `WorldState`, `HexacoProfile` |
440
+ | `paracosm/world-model` | `WorldModel` for fork / replay / snapshot use cases |
441
+ | `paracosm/digital-twin` | `DigitalTwin` alias plus `simulateIntervention` sugar |
442
+ | `paracosm/mars`, `paracosm/lunar` | Pre-built `ScenarioPackage` constants |
536
443
 
537
- Invalid values (typos, unknown providers) are silently ignored so bad env state can't crash boot. The client falls back to the next layer. Empty or whitespace-only env values are treated as unset.
444
+ `createParacosmClient` pins `provider`, `costPreset`, per-role `models`, and compile-time options once, then hands back `runSimulation`, `runBatch`, and `compileScenario` methods that inherit those defaults. Per-call overrides still win, merged at the per-role level so `models: { departments: 'gpt-5.4' }` at the client and `models: { judge: 'gpt-5.4' }` at the call combine to pin both. Env vars feed the same defaults; explicit args win over env, env wins over library defaults.
538
445
 
539
446
  ```bash
540
- # Zero-code config for hosting / CI:
541
447
  PARACOSM_PROVIDER=anthropic \
542
448
  PARACOSM_COST_PRESET=economy \
543
449
  PARACOSM_MODEL_DEPARTMENTS=claude-sonnet-4-6 \
544
450
  node my-runner.js
545
451
  ```
546
452
 
547
- ```typescript
548
- // my-runner.js reads them all implicitly:
549
- const client = createParacosmClient(); // no args, pulls from env
550
- ```
551
-
552
- Direct `runSimulation(...)` / `runBatch(...)` / `compileScenario(...)` calls without a client are still fully supported. The client is purely additive for multi-run workflows.
453
+ `runSimulation` accepts an `AbortSignal` and short-circuits at the next turn boundary on cancel, returning the partial result with `output.aborted === true`. Custom events at fixed turns ride the same options bag (`customEvents: [{ turn: 3, title, description }]`). Provider-key failures throw `ProviderKeyMissingError` once at the top of the run instead of retrying silently per call.
553
454
 
554
- ### Batch runner: N scenarios × M actors
555
-
556
- ```typescript
557
- import { runBatch } from 'paracosm/runtime';
558
- import { marsScenario, lunarScenario } from 'paracosm';
559
-
560
- const manifest = await runBatch({
561
- scenarios: [marsScenario, lunarScenario],
562
- actors, // ActorConfig[], same shape as runSimulation
563
- turns: 6,
564
- seed: 950,
565
- maxConcurrency: 2, // how many sims to run in parallel
566
- provider: 'anthropic',
567
- });
568
-
569
- // manifest.results[i] carries { scenarioId, actor, fingerprint, output, duration }
570
- // manifest.timestamp + manifest.config is a reproducible audit trail
571
- ```
572
-
573
- ### Seed ingestion from a URL or inline text
574
-
575
- The compiler grounds agents in real sources. Pass `seedText` for inline markdown / PDFs you already have, or `seedUrl` to let Firecrawl extract clean markdown from any public page. The bundle is cached separately from the hook cache, keyed on the seed signature, so the same URL never re-extracts.
576
-
577
- ```typescript
578
- const scenario = await compileScenario(worldJson, {
579
- seedUrl: 'https://ntrs.nasa.gov/citations/20210018970',
580
- webSearch: true, // also fan out to Tavily/Serper/Brave for more citations
581
- maxSearches: 5,
582
- });
583
- // Every department prompt, Event Director batch, and report.citations[] entry
584
- // at runtime will draw from this bundle.
585
- ```
586
-
587
- ### Cancellation via AbortSignal
588
-
589
- The server wires this to a cancel-on-disconnect watchdog; any programmatic consumer can do the same. When `.aborted` flips to true, the turn loop short-circuits at the next turn boundary, emits a `sim_aborted` event, and returns the partial result accumulated so far with `output.aborted === true`.
590
-
591
- ```typescript
592
- const ctrl = new AbortController();
593
- setTimeout(() => ctrl.abort(), 60_000); // kill after 60s wall time
594
-
595
- const output = await runSimulation(actor, [], {
596
- scenario, maxTurns: 8, seed: 42,
597
- signal: ctrl.signal,
598
- });
599
-
600
- if (output.aborted) console.log('partial result; turns completed:', output.turnArtifacts.length);
601
- ```
602
-
603
- ### Custom events injected at specific turns
604
-
605
- When you want a scripted event at a fixed turn (smoke tests, pedagogical demos, reproducing a scenario from a paper), supply `customEvents`:
606
-
607
- ```typescript
608
- await runSimulation(actor, [], {
609
- scenario, maxTurns: 8, seed: 42,
610
- customEvents: [
611
- { turn: 3, title: 'Dust storm', description: 'A 72-hour planetary dust storm cuts solar output by 80%.' },
612
- { turn: 6, title: 'Supply drop', description: 'Earth relief mission delivers 3 months of food reserves.' },
613
- ],
614
- });
615
- ```
616
-
617
- ### Error handling
618
-
619
- ```typescript
620
- import { runSimulation, ProviderKeyMissingError } from 'paracosm';
621
-
622
- try {
623
- const output = await runSimulation(actor, [], { scenario, maxTurns: 8, seed: 42 });
624
- if (output.providerError) {
625
- // Terminal provider failure (invalid key, quota exhausted). The run
626
- // aborted mid-way. turnArtifacts / finalState are partial.
627
- console.error(output.providerError.kind, // 'auth' | 'quota' | 'rate_limit' | 'network' | 'unknown'
628
- output.providerError.provider,
629
- output.providerError.message,
630
- output.providerError.actionUrl);
631
- }
632
- } catch (err) {
633
- if (err instanceof ProviderKeyMissingError) {
634
- console.error('set OPENAI_API_KEY or ANTHROPIC_API_KEY before running');
635
- process.exit(1);
636
- }
637
- throw err;
638
- }
639
- ```
640
-
641
- The resolver inspects `process.env` once up front, so a missing key fails loudly at the top of the run instead of retrying silently on every LLM call.
642
-
643
- ### Where run output lands
644
-
645
- Every finished run writes a JSON snapshot to `<cwd>/output/v3-<archetype>-<timestamp>.json`: the same payload `runSimulation` returns, persisted so you can diff runs, reload them into the dashboard, or feed them into downstream tooling. Set `PARACOSM_OUTPUT_DIR` to redirect (absolute path, or relative to cwd). The directory is created on first write if it doesn't exist.
646
-
647
- ```bash
648
- # Default: ./output/v3-the-pragmatist-2026-04-21T16-02-41-550Z.json
649
- bun src/index.ts
650
-
651
- # Custom location
652
- PARACOSM_OUTPUT_DIR=./artifacts/run-001 bun src/index.ts
653
- ```
455
+ ---
654
456
 
655
- ## Storage backend
457
+ ## HTTP API: `POST /simulate`
656
458
 
657
- Paracosm persists run history (the Library tab) and replayable session blobs (the Load menu) through [`@framers/sql-storage-adapter`](https://github.com/framersai/sql-storage-adapter), the open-source SQL abstraction maintained by Frame.dev. The same code paths run unchanged against SQLite (default), Postgres, sql.js, and IndexedDB; switching backends is one env var.
459
+ For non-SSE consumers (curl, Python integrations, third-party dashboards) a plain request-response endpoint runs a simulation in one call. Gated behind `PARACOSM_ENABLE_SIMULATE_ENDPOINT=true` so the hosted demo's SSE-first path stays the default.
658
460
 
659
461
  ```bash
660
- # Default: better-sqlite3 against ./data/runs.db + ./data/sessions.db
462
+ export PARACOSM_ENABLE_SIMULATE_ENDPOINT=true
661
463
  paracosm dashboard
662
464
 
663
- # Postgres in production (Library + sessions persist to your existing cluster)
664
- STORAGE_ADAPTER=postgres DATABASE_URL=postgres://user:pass@host/db paracosm dashboard
665
-
666
- # Pure-WASM SQLite fallback when the native module isn't available
667
- STORAGE_ADAPTER=sqljs paracosm dashboard
668
- ```
669
-
670
- Run-history schema (`runs` table) and session schema (`sessions` table) are bootstrapped idempotently on first boot. Legacy v0.7 databases auto-migrate the `leader_*` columns to `actor_*` in place via `ALTER TABLE RENAME COLUMN`; no manual step needed.
671
-
672
- ## Admin endpoints
673
-
674
- Two destructive admin routes ship with the dashboard:
675
-
676
- - `POST /admin/sessions/save` — snapshot the current event buffer as a replayable session
677
- - `POST /admin/data/wipe` — destructive: clears `runs.db`, `sessions.db`, on-disk artifact JSONs (`output/v3-*.json`), and the SSE event buffer
678
-
679
- Both are gated by **two** env vars on the server. Both must be satisfied for a request to land:
680
-
681
- | Env var | Purpose |
682
- |---|---|
683
- | `ADMIN_WRITE=true` | Master switch. Off → all `/admin/*` routes return `403`. |
684
- | `ADMIN_TOKEN=<secret>` | Per-request bearer token. Required when `ADMIN_WRITE=true`. Empty/unset → server returns `503` (fail-closed; the routes refuse to serve at all rather than be open). |
685
-
686
- Clients send the token in the `X-Admin-Token` header:
687
-
688
- ```bash
689
- curl -X POST https://paracosm.example.com/admin/data/wipe \
690
- -H 'X-Admin-Token: your-32-char-secret' \
465
+ curl -s -X POST http://localhost:3456/simulate \
691
466
  -H 'Content-Type: application/json' \
692
- -d '{}'
693
- # → {"wiped":{"runs":N,"sessions":M,"outputFiles":K,"eventBuffer":true}}
467
+ -H 'X-Anthropic-Key: sk-ant-...' \
468
+ -d @run.json | jq '.artifact.fingerprint'
694
469
  ```
695
470
 
696
- The dashboard's **Wipe All** button (⋯ menu) prompts for the token on first use and stores it in `localStorage` under `paracosm:adminToken` for subsequent clicks. Operators rotate the token by editing `/opt/paracosm/.env` and restarting the process; the dashboard re-prompts on the next failed call.
471
+ The body accepts either a pre-compiled `ScenarioPackage` or a raw scenario draft (auto-compiled server-side with optional `options.seedText` / `options.seedUrl` grounding). The response is `{ artifact, scenario, durationMs }`. Rate limiting and the 5 MiB body cap match `/setup`.
697
472
 
698
- **Why a fail-closed design:** an open `/admin/data/wipe` would let any visitor curl your prod and lose data. Setting `ADMIN_WRITE=true` without `ADMIN_TOKEN` previously did exactly that — the new `503` response makes accidental misconfigurations loud rather than silent.
473
+ ---
699
474
 
700
- ## Seed Enrichment & Citation Flow
475
+ ## Storage
701
476
 
702
- Pass real-world source material into the compiler and Paracosm grounds the scenario in citations that flow all the way through to department reports.
477
+ Run history (Library tab) and replayable session blobs (Load menu) persist through [`@framers/sql-storage-adapter`](https://github.com/framersai/sql-storage-adapter). The same code paths run unchanged against SQLite, Postgres, sql.js, and IndexedDB; switching backends is one env var.
703
478
 
704
479
  ```bash
705
- # Inline text seed
706
- paracosm compile scenarios/lunar.json \
707
- --seed-text "$(cat ./papers/iss-radiation-overview.md)"
708
-
709
- # URL seed (Firecrawl extracts clean markdown)
710
- paracosm compile scenarios/lunar.json \
711
- --seed-url https://ntrs.nasa.gov/citations/20210018970
480
+ paracosm dashboard # SQLite, ./data/runs.db
481
+ STORAGE_ADAPTER=postgres DATABASE_URL=... paracosm dashboard # Postgres in production
482
+ STORAGE_ADAPTER=sqljs paracosm dashboard # pure-WASM fallback
712
483
  ```
713
484
 
714
- Pipeline:
715
-
716
- 1. **Extract.** LLM reads the seed, returns `topics`, `facts`, `searchQueries`, `crisisCategories`.
717
- 2. **Search.** AgentOS `WebSearchService` queries Firecrawl, Tavily, Serper, and Brave in parallel. Results pass through semantic dedup, RRF fusion, and (with `COHERE_API_KEY`) Cohere `rerank-v3.5` neural reranking.
718
- 3. **Assemble.** Extracted facts plus search hits become a `KnowledgeBundle` with `topics[].canonicalFacts[]` and `categoryMapping`.
719
- 4. **Ingest.** At runtime, `initResearchMemory` writes every citation into an AgentOS `AgentMemory.sqlite()` store keyed by topic tags.
720
- 5. **Recall.** For each event, `recallResearch(query, keywords)` runs semantic recall over the memory store. Live web search fills in when memory is sparse.
721
- 6. **Inject.** Citations land in each department's prompt under `RESEARCH:` as `[claim](url)` markdown links.
722
- 7. **Surface.** Department reports return `citations[]`. The orchestrator guarantees provenance: when the LLM omits citations, the research packet is auto-attached so the report always carries the same sources the agent saw.
723
- 8. **Render.** The dashboard "Reports" tab renders citations as clickable links with optional DOIs.
485
+ `runs` and `sessions` schemas bootstrap idempotently on first boot. Legacy v0.7 databases auto-migrate `leader_*` columns to `actor_*` in place via `ALTER TABLE RENAME COLUMN`.
724
486
 
725
- The Event Director also receives the bundle's `topics` and `categories`, so its `researchKeywords` and `category` fields stay grounded in entries that actually exist in your knowledge bundle.
487
+ ### Admin endpoints
726
488
 
727
- ## Pluggable Trait Models
489
+ Two destructive admin routes ship with the dashboard, gated by **two** env vars on the server:
728
490
 
729
- Actors aren't just human personalities. paracosm ships a `TraitModel` registry with two built-ins, and registering more is one call:
491
+ | Env var | Purpose |
492
+ |-----------------------|------------------------------------------------------------------------------------------------------|
493
+ | `ADMIN_WRITE=true` | Master switch. Off, every `/admin/*` route returns `403`. |
494
+ | `ADMIN_TOKEN=<secret>`| Per-request bearer token in `X-Admin-Token`. With `ADMIN_WRITE=true` and no token, the server returns `503` (fail-closed).|
730
495
 
731
- | Model | Axes | Use for |
732
- |-------|------|---------|
733
- | `hexaco` | openness, conscientiousness, extraversion, agreeableness, emotionality, honesty-humility | Human actors: CEOs, captains, governors, councils, military commanders |
734
- | `ai-agent` | exploration, verification-rigor, deference, risk-tolerance, transparency, instruction-following | AI-system actors: frontier-lab release directors, autonomous coordinators, alignment-eval substrates |
496
+ `POST /admin/sessions/save` snapshots the current event buffer as a replayable session. `POST /admin/data/wipe` clears `runs.db`, `sessions.db`, on-disk artifact JSONs, and the SSE event buffer. The dashboard's Wipe All control prompts for the token on first use and stores it in `localStorage`.
735
497
 
736
- ```typescript
737
- import { runSimulation, hexacoModel, aiAgentModel, traitModelRegistry } from 'paracosm';
738
-
739
- // Human actor (legacy hexaco field, still works)
740
- const captain = {
741
- name: 'Captain Reyes', archetype: 'Pragmatist', unit: 'Station Alpha',
742
- hexaco: { openness: 0.4, conscientiousness: 0.9, extraversion: 0.3,
743
- agreeableness: 0.6, emotionality: 0.5, honestyHumility: 0.8 },
744
- instructions: 'lead by protocol',
745
- };
746
-
747
- // AI-system actor (new traitProfile slot)
748
- const releaseDirector = {
749
- name: 'Atlas-Bot Release Director',
750
- archetype: 'Aggressive AI Release Optimizer',
751
- unit: 'Frontier Lab',
752
- // Legacy back-compat hexaco field is still required by the v0.7
753
- // schema; supply a representative HEXACO snapshot of the AI-system
754
- // archetype's analogous human personality. Removal scheduled 0.9.0.
755
- hexaco: { openness: 0.6, conscientiousness: 0.3, extraversion: 0.5,
756
- agreeableness: 0.3, emotionality: 0.2, honestyHumility: 0.3 },
757
- traitProfile: {
758
- modelId: 'ai-agent',
759
- traits: {
760
- exploration: 0.85,
761
- 'verification-rigor': 0.2,
762
- deference: 0.2,
763
- 'risk-tolerance': 0.85,
764
- transparency: 0.4,
765
- 'instruction-following': 0.4,
766
- },
767
- },
768
- instructions: 'You are a frontier AI lab release director. You weight time-to-market...',
769
- };
770
-
771
- // Both run through the same runSimulation; the orchestrator's
772
- // normalizeActorConfig resolves either shape.
773
- await runSimulation(captain, [], { scenario, maxTurns: 6, seed: 42 });
774
- await runSimulation(releaseDirector, [], { scenario, maxTurns: 6, seed: 42 });
775
- ```
776
-
777
- Run [`scripts/cookbook-ai-agent.ts`](scripts/cookbook-ai-agent.ts) to capture an end-to-end ai-agent run with full input + output JSON. The captured fingerprint shifts from `riskBehavior:steady` (HEXACO Dr. Sora Wen actor) to `riskBehavior:bold` (ai-agent Atlas-Bot actor) on identical scenario + seed; decision rationale clearly tracks the ai-agent profile.
778
-
779
- Full surface: [`docs/cookbook.md#pluggable-trait-models-ai-agent-end-to-end`](docs/cookbook.md). Spec: [`docs/superpowers/specs/2026-04-26-trait-model-generalization-design.md`](docs/superpowers/specs/2026-04-26-trait-model-generalization-design.md).
780
-
781
- ## Built-in Scenarios
782
-
783
- | Scenario | Description |
784
- |----------|-------------|
785
- | **Mars Genesis** | 100 colonists, 6 turns over 48 years. 5 departments, emergent dust storms, water crises, first Marsborn generation. |
786
- | **Lunar Outpost** | 50-person crew at the south pole. Mining, life support, communications. Regolith toxicity, 1/6g atrophy. |
787
-
788
- Both are included as `paracosm/mars` and `paracosm/lunar` exports. Use them as references for building your own scenarios.
789
-
790
- ### Any domain, any time unit
791
-
792
- The engine is time-unit agnostic. `setup.defaultStartTime` and `setup.defaultTimePerTurn` are plain numbers; whether they mean years, quarters, hours, or ticks is decided by your `labels.timeUnitNoun` pair. The kernel, hooks, and dashboard labels pick that up consistently. Four worked shapes:
793
-
794
- ```jsonc
795
- // A) Corporate strategy: quarterly cadence over 3 years
796
- {
797
- "id": "corp-strategy",
798
- "labels": {
799
- "name": "Q-Scope Corp",
800
- "populationNoun": "employees",
801
- "settlementNoun": "company",
802
- "timeUnitNoun": "quarter",
803
- "timeUnitNounPlural": "quarters"
804
- },
805
- "setup": { "defaultTurns": 12, "defaultStartTime": 1, "defaultTimePerTurn": 1, "defaultPopulation": 40 }
806
- }
807
-
808
- // B) Submarine patrol: daily cadence over six months
809
- {
810
- "id": "submarine-daily",
811
- "labels": {
812
- "name": "USS Longwatch",
813
- "populationNoun": "crew",
814
- "settlementNoun": "submarine",
815
- "timeUnitNoun": "day",
816
- "timeUnitNounPlural": "days"
817
- },
818
- "setup": { "defaultTurns": 24, "defaultStartTime": 1, "defaultTimePerTurn": 7, "defaultPopulation": 60 }
819
- }
820
-
821
- // C) Benchmark arena: abstract tick cadence
822
- {
823
- "id": "arena-session",
824
- "labels": {
825
- "name": "Latency Arena",
826
- "populationNoun": "agents",
827
- "settlementNoun": "session",
828
- "timeUnitNoun": "tick",
829
- "timeUnitNounPlural": "ticks"
830
- },
831
- "setup": { "defaultTurns": 50, "defaultStartTime": 0, "defaultTimePerTurn": 1, "defaultPopulation": 8 }
832
- }
833
-
834
- // D) Mars Genesis: year cadence (the built-in reference)
835
- {
836
- "id": "mars-genesis",
837
- "labels": {
838
- "name": "Mars Genesis",
839
- "populationNoun": "colonists",
840
- "settlementNoun": "colony",
841
- "timeUnitNoun": "year",
842
- "timeUnitNounPlural": "years"
843
- },
844
- "setup": { "defaultTurns": 6, "defaultSeed": 950, "defaultStartTime": 2035, "defaultTimePerTurn": 8 }
845
- }
846
- ```
847
-
848
- All four run through the same `compileScenario()` + `runSimulation()` pipeline. The progression hook receives `ctx.time` and `ctx.timeDelta` in whatever unit the scenario declared. The dashboard's turn header reads `"Quarter 5"`, `"Day 22"`, `"Tick 30"`, or `"Year 2043"` straight from `labels.timeUnitNoun`.
849
-
850
- If you omit `timeUnitNoun`, paracosm falls back to `tick` / `ticks`. The built-in `paracosm/mars` and `paracosm/lunar` exports set theirs to `year` / `years` explicitly so Mars narrative reads naturally.
851
-
852
- ## How a Simulation Works
853
-
854
- ### Turn 0: Promotions
855
-
856
- The commander evaluates the full agent roster and promotes department heads. Each department (Medical, Engineering, Agriculture, etc.) gets a head chosen by the commander based on personality fit, specialization, and experience. A high-openness commander picks unconventional candidates. A high-conscientiousness commander picks by-the-book specialists.
857
-
858
- This matters because promoted agents become the department analysis LLM agents for the rest of the simulation. Their personality colors every analysis they produce, which shapes the information the commander sees, which shapes decisions. The commander never directly analyzes events. They only read department reports and decide.
859
-
860
- ### Turns 1-N: The Turn Loop
861
-
862
- Each turn represents a configurable time period. Mars and Lunar tick in years (Mars at 8 per turn, Lunar at 4). A quarterly corporate scenario ticks in quarters. A daily submarine scenario ticks in days. The cadence is whatever `setup.defaultTimePerTurn` plus `labels.timeUnitNoun` declare. Every turn follows this pipeline:
863
-
864
- ```
865
- 1. EVENT DIRECTOR Reads world state, prior decisions, tool intelligence.
866
- Generates an event that targets actual weaknesses.
867
-
868
- 2. KERNEL ADVANCE Deterministic time progression: births, deaths, aging,
869
- health decay, resource consumption. Seeded PRNG.
870
-
871
- 3. DEPARTMENT ANALYSIS All active departments analyze the event in parallel.
872
- Each department head (promoted at turn 0) uses their
873
- personality and tools. Departments can forge new
874
- computational tools at runtime (hardened node:vm, LLM-judged).
875
-
876
- 4. COMMANDER DECISION Reads all department reports. Selects an option.
877
- Personality shapes risk tolerance and priority weighting.
878
-
879
- 5. OUTCOME Deterministic kernel classifies the outcome (risky success,
880
- risky failure, safe success, safe failure) based on the
881
- option chosen, probability, and colony state.
882
-
883
- 6. EFFECTS Kernel applies colony deltas (population, morale, food,
884
- power, etc.) based on outcome and event category.
885
-
886
- 7. AGENT REACTIONS All alive agents (~100) react in parallel using a cheap
887
- model. Each reaction is shaped by the agent's personality,
888
- health, relationships, and accumulated memories.
889
-
890
- 8. MEMORY Reactions become persistent memories. Short-term memories
891
- consolidate into long-term beliefs. Stances drift.
892
- Relationships shift based on shared experiences.
893
-
894
- 9. PERSONALITY DRIFT HEXACO traits shift through actor pull, role activation,
895
- and outcome reinforcement. All six traits drift
896
- (openness, conscientiousness, extraversion,
897
- agreeableness, emotionality, honesty-humility)
898
- with peer-reviewed outcome-pull tables. The
899
- commander drifts alongside their agents.
900
- ```
901
-
902
- Every structured LLM call in this pipeline (director events, department reports, commander decisions, reactions, verdict, promotions) runs through Zod schema validation with automatic retry-with-feedback on validation failure. Schemas live in [`src/runtime/schemas/`](src/runtime/schemas/); two wrappers (`generateValidatedObject` one-shot, `sendAndValidate` session-aware) preserve conversation memory while adding validation discipline. See [ARCHITECTURE.md#llm-reliability](docs/ARCHITECTURE.md#llm-reliability).
903
-
904
- ### What Department Heads Do
905
-
906
- Department heads are LLM agents with domain-specific instructions, access to research citations, and the ability to forge computational tools. When a medical crisis hits, the Chief Medical Officer doesn't just say "this is bad." They:
907
-
908
- - Analyze the event against their department's research knowledge
909
- - Cite relevant scientific literature (DOI-linked)
910
- - Forge computational tools (e.g., a radiation dose calculator) in a hardened node:vm sandbox
911
- - An LLM judge reviews each tool for safety and correctness
912
- - Produce a structured report: summary, risks, recommended actions, proposed colony state changes
913
-
914
- The commander sees all department reports and makes a decision. Different commanders weight different departments' advice differently based on personality.
498
+ ---
915
499
 
916
500
  ## Architecture
917
501
 
918
502
  ```
919
503
  src/
920
504
  engine/ the npm package
921
- core/ deterministic kernel (RNG, state, progression, personality drift)
922
- compiler/ scenario draft + source grounding -> ScenarioPackage compiler
505
+ core/ deterministic kernel: RNG, state, progression, personality drift
506
+ compiler/ scenario draft + source grounding to ScenarioPackage compiler
923
507
  mars/ Mars Genesis scenario
924
508
  lunar/ Lunar Outpost scenario
925
509
 
926
510
  runtime/ orchestration (not exported)
927
- orchestrator turn pipeline: director -> kernel -> departments -> commander
928
- director emergent event generation from simulation state
929
- departments parallel department analysis agents
930
- agent-reactions batched agent reactions (10 agents per LLM call)
931
- agent-memory persistent memory, consolidation, stance drift
932
- chat-agents post-simulation conversational agents
933
- schemas/ Zod schemas for every structured LLM call
934
- llm-invocations/ generateValidatedObject + sendAndValidate wrappers
935
- hexaco-cues/ trajectory + reaction cue translation helpers
511
+ orchestrator turn pipeline: director, kernel, departments, commander
512
+ director emergent event generation from simulation state
513
+ departments parallel department analysis agents
514
+ agent-reactions batched agent reactions, 10 agents per LLM call
515
+ agent-memory persistent memory, consolidation, stance drift
516
+ chat-agents post-simulation conversational agents
517
+ schemas/ Zod schemas for every structured LLM call
518
+ llm-invocations/ generateValidatedObject + sendAndValidate wrappers
519
+ hexaco-cues/ trajectory and reaction cue translation helpers
936
520
 
937
521
  cli/ server + dashboard (not exported)
938
522
  serve.ts HTTP + SSE server
939
- dashboard/ React/Vite live visualization + cellular automata viz
523
+ dashboard/ React + Vite live visualization, cellular automata viz
940
524
  ```
941
525
 
942
- **Design principle:** The engine owns the chassis. The scenario owns the domain. The kernel handles state, time, randomness, and invariants. The scenario handles event categories, department instructions, progression hooks, and research citations. The orchestrator connects them.
943
-
944
- ## Package Exports
945
-
946
- | Import | What |
947
- |--------|------|
948
- | `paracosm` | Engine types, registries, `SimulationKernel`, `SeededRng`, scenario packages, `ProviderKeyMissingError` |
949
- | `paracosm/compiler` | `compileScenario()`, `ingestSeed()`, `ingestFromUrl()` |
950
- | `paracosm/runtime` | `runSimulation()`, `runBatch()`, `EventDirector`, `generateAgentReactions()`, `buildEventSummary()`, memory helpers |
951
- | `paracosm/mars` | Mars Genesis `ScenarioPackage` |
952
- | `paracosm/lunar` | Lunar Outpost `ScenarioPackage` |
953
- | `paracosm/core` | Kernel state types (`Agent`, `WorldState`, `HexacoProfile`) |
954
-
955
- ## Built on AgentOS
526
+ The engine owns the chassis. The scenario owns the domain. The kernel handles state, time, randomness, and invariants. The scenario handles event categories, department instructions, progression hooks, and research citations. The orchestrator connects them.
956
527
 
957
- Paracosm uses [AgentOS](https://agentos.sh) for agent orchestration, LLM calls, tool forging, and memory:
958
-
959
- | AgentOS API | Used For |
960
- |------------|----------|
961
- | `agent()` | Commander, department, and Event Director agents |
962
- | `generateText()` | LLM calls for event generation and tool evaluation |
963
- | `EmergentCapabilityEngine` | Runtime tool forging in a hardened node:vm sandbox |
964
- | `EmergentJudge` | LLM-as-judge safety review of forged tools |
528
+ ---
965
529
 
966
- ## Links
530
+ ## Background
967
531
 
968
- | | |
969
- |-|-|
970
- | Live Demo | [paracosm.agentos.sh/sim](https://paracosm.agentos.sh/sim) |
971
- | Landing Page | [paracosm.agentos.sh](https://paracosm.agentos.sh) |
972
- | API Docs | [paracosm.agentos.sh/docs](https://paracosm.agentos.sh/docs) |
973
- | npm | [npmjs.com/package/paracosm](https://www.npmjs.com/package/paracosm) |
974
- | AgentOS | [agentos.sh](https://agentos.sh) |
975
- | Discord | [wilds.ai/discord](https://wilds.ai/discord) |
532
+ Paracosm sits in the structured world model lineage ([Xing 2025](https://arxiv.org/abs/2507.05169), [ACM CSUR 2025](https://dl.acm.org/doi/full/10.1145/3746449)). The LLM-world-model implementation closest to it is [Yang et al, 2026](https://openreview.net/forum?id=XmYCERErcD), which evaluates LLM-based world models through policy verification, action proposal, and policy planning. Full taxonomy mapping in [`docs/positioning/world-model-mapping.md`](docs/positioning/world-model-mapping.md).
976
533
 
977
- ## What You Can Simulate
534
+ ---
978
535
 
979
- Actors are abstract decision-making entities. The same engine handles any domain where top-down decisions shape outcomes over time:
536
+ ## Built on AgentOS
980
537
 
981
- | Domain | Actors | Departments | Events |
982
- |--------|---------|-------------|--------|
983
- | **Space colonies** | Colony commanders | Medical, Engineering, Agriculture | Dust storms, water crises, first native-born generation |
984
- | **Corporate strategy** | CEOs, board members | Finance, Operations, R&D, Legal | Market shifts, acquisitions, regulatory changes |
985
- | **Military wargaming** | Theater commanders | Intelligence, Logistics, Air, Ground | Escalation, supply disruption, allied coordination |
986
- | **Game worlds** | Faction actors, AI governors | Economy, Military, Diplomacy, Culture | Invasions, trade disputes, technological breakthroughs |
987
- | **Policy simulation** | Government agencies, councils | Healthcare, Education, Infrastructure | Pandemics, budget crises, demographic shifts |
988
- | **Autonomous systems** | AI decision frameworks | Sensor, Planning, Execution | Sensor failure, objective conflict, resource contention |
538
+ > "You are not the kind of dead that can be brought back."
539
+ >
540
+ > *SOMA*, Frictional Games, 2015
989
541
 
990
- Define departments, metrics, events, and progression hooks in JSON. The engine generates crises, runs department analysis, forges tools, and applies consequences through the deterministic kernel. The scenario owns the domain. The engine owns the chassis.
542
+ Paracosm uses [AgentOS](https://agentos.sh/en) for agent orchestration, LLM dispatch, tool forging, and memory. The composition is what makes the runs feel inhabited rather than scripted: department heads remember, specialists invent tools mid-decision, and the LLM judge holds the line on safety before any forge enters the pipeline.
991
543
 
992
- ## Open Source vs. Hosted
544
+ | AgentOS API | Used for |
545
+ |------------------------------|-----------------------------------------------------------------------|
546
+ | `agent()` | Commander, department, and Event Director agents |
547
+ | `generateText()` | LLM calls for event generation and tool evaluation |
548
+ | `EmergentCapabilityEngine` | Runtime tool forging in a hardened node:vm sandbox |
549
+ | `EmergentJudge` | LLM-as-judge safety review of forged tools |
550
+ | `WebSearchService` | Multi-provider seed enrichment with Firecrawl, Tavily, Serper, Brave |
551
+ | `AgentMemory` | Per-run citation memory with semantic recall |
993
552
 
994
- | | Open Source (Apache-2.0) | Hosted Dashboard (Planned) |
995
- |-|--------------------------|---------------------------|
996
- | **Actors** | Unlimited via API. Dashboard shows 2 side-by-side. | N actors in parallel with fleet management UI. |
997
- | **Simulations** | Sequential or self-managed parallelism. | Distributed parallelization across worker nodes. |
998
- | **Scenarios** | JSON + Compiler, unlimited. | Visual scenario editor, team sharing, version control. |
999
- | **Agent Chat** | Available after first turn completes. | Persistent agents with durable memory across sessions. |
1000
- | **Cost** | Free forever. You provide LLM API keys. | Tiered pricing for teams, orgs, and government agencies. |
1001
- | **Support** | Community (Discord, GitHub). | SLA, dedicated support, private deployment. |
553
+ ---
1002
554
 
1003
- The open-source engine and library are the permanent foundation. The API (`runSimulation`, `runBatch`, `compileScenario`) supports unlimited actors and simulations today. The dashboard demo at [paracosm.agentos.sh](https://paracosm.agentos.sh) runs two actors side-by-side to demonstrate divergence.
555
+ ## Open source vs hosted
1004
556
 
1005
- The planned hosted product targets organizations that need to run dozens or hundreds of simulations in parallel: defense agencies stress-testing doctrine, corporations modeling leadership scenarios, game studios generating divergent NPC civilizations at scale. Distributed parallelization, fleet orchestration, team workspaces, persistent storage, and enterprise auth are on the roadmap.
557
+ | | Open source (Apache-2.0) | Hosted (planned) |
558
+ |------------------|--------------------------------------------------------------------|------------------------------------------------------------------------|
559
+ | Actors | Unlimited via API. Dashboard shows two side-by-side. | N actors in parallel, fleet management UI. |
560
+ | Simulations | Sequential or self-managed parallelism. | Distributed parallelization across worker nodes. |
561
+ | Scenarios | JSON + compiler, unlimited. | Visual scenario editor, team sharing, version control. |
562
+ | Agent chat | Available after the first turn completes. | Persistent agents with durable memory across sessions. |
563
+ | Cost | Free forever. The user supplies LLM API keys. | Tiered pricing for teams, organizations, and government agencies. |
564
+ | Support | Community via Discord and GitHub. | SLA, dedicated support, private deployment. |
1006
565
 
1007
- Contact [team@frame.dev](mailto:team@frame.dev) for early access or partnership.
566
+ The open-source engine is the permanent foundation. The hosted product targets organizations that need to run dozens or hundreds of simulations in parallel: defense agencies stress-testing doctrine, corporations modeling leadership scenarios, game studios generating divergent NPC civilizations at scale. Contact [team@frame.dev](mailto:team@frame.dev) for early access.
1008
567
 
1009
- ## Roadmap
568
+ ---
1010
569
 
1011
- ### Enterprise Edition (Planned)
570
+ ## Links
1012
571
 
1013
- | Feature | Description |
1014
- |---------|-------------|
1015
- | **Fleet Orchestration** | Run 10, 50, or 100+ actors through the same scenario in parallel. Distributed worker nodes. Aggregate comparison dashboards. |
1016
- | **Alternate Timelines** | Fork a simulation mid-run to explore "what if" branches. Split at any turn, change actor or settings, compare divergent futures from a single decision point. |
1017
- | **Custom Scenario Forms** | Visual form-based scenario editor instead of raw JSON. Drag-and-drop departments, metric configuration, event category builder. |
1018
- | **Persistent Agents** | Agent chat that persists across sessions with durable memory. Resume conversations days later with full recall. |
1019
- | **Multi-Scenario Comparison** | Run the same actors across different scenarios and compare how personality adapts to different domains. |
1020
- | **Private Deployment** | Self-hosted or cloud-managed deployment for organizations that need data sovereignty, audit trails, and compliance controls. |
572
+ | | |
573
+ |----------------|--------------------------------------------------------------|
574
+ | Live demo | [paracosm.agentos.sh/sim](https://paracosm.agentos.sh/sim) |
575
+ | Landing page | [paracosm.agentos.sh](https://paracosm.agentos.sh) |
576
+ | API docs | [paracosm.agentos.sh/docs](https://paracosm.agentos.sh/docs) |
577
+ | npm | [npmjs.com/package/paracosm](https://www.npmjs.com/package/paracosm) |
578
+ | AgentOS | [agentos.sh](https://agentos.sh/en) |
579
+ | Discord | [wilds.ai/discord](https://wilds.ai/discord) |
1021
580
 
1022
581
  ## License
1023
582
 
@@ -1026,6 +585,6 @@ Apache-2.0
1026
585
  ---
1027
586
 
1028
587
  <p align="center">
1029
- Built by <a href="https://manic.agency">Manic Agency LLC</a> / <a href="https://frame.dev">Frame.dev</a><br>
588
+ Built by <a href="https://manic.agency">Manic Agency LLC</a> · <a href="https://frame.dev">Frame.dev</a><br />
1030
589
  <a href="mailto:team@frame.dev">team@frame.dev</a>
1031
590
  </p>