paracosm 0.8.601 → 0.8.608

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,7 +5,7 @@
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>Counterfactual world simulations for AI agents. From a prompt to a structured world model to forked futures.</em>
9
9
  </p>
10
10
 
11
11
  <p align="center">
@@ -16,40 +16,28 @@
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. That is what `WorldModel.fork()` is for.
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 counterfactual world simulation 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,110 @@ 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`. A handful of working shapes:
196
+
197
+ | Scenario | settlementNoun | populationNoun | timeUnitNoun |
198
+ |-------------------|----------------|----------------|--------------|
199
+ | Mars Genesis | colony | colonists | year |
200
+ | Submarine patrol | habitat | crew | day |
201
+ | Medieval kingdom | kingdom | subjects | year |
202
+ | Corporate strategy| company | employees | quarter |
203
+ | Generation ship | vessel | passengers | year |
204
+ | Benchmark arena | session | agents | tick |
205
+
206
+ 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.
207
+
208
+ ---
204
209
 
205
- ### 2. Compile and run
210
+ ## Compile and run
206
211
 
207
212
  ```typescript
208
213
  import { compileScenario } from 'paracosm/compiler';
209
214
  import { runSimulation } from 'paracosm/runtime';
210
215
  import worldJson from './my-world.json' with { type: 'json' };
211
216
 
212
- // Compile a typed world draft into a runnable scenario (~$0.10, cached to disk)
217
+ // First compile is roughly $0.10 and caches to disk; reruns are free
213
218
  const scenario = await compileScenario(worldJson, {
214
219
  provider: 'anthropic',
215
220
  model: 'claude-sonnet-4-6',
216
221
  });
217
222
 
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
- );
223
+ const result = await runSimulation(actor, [], {
224
+ scenario,
225
+ maxTurns: 6,
226
+ seed: 42,
227
+ // costPreset: 'economy', // ~5-10× cheaper iteration on OpenAI
228
+ onEvent(e) { console.log(actor.name, e.type, e.data.summary); },
229
+ });
263
230
 
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
- }
231
+ console.log(result.metadata.scenario.name, '→', result.fingerprint);
232
+ console.log('cost $', result.cost?.totalUSD.toFixed(2));
233
+ console.log('final ', result.finalState?.metrics);
234
+ console.log('forged tools ', result.forgedTools?.length ?? 0);
235
+ console.log('citations ', result.citations?.length ?? 0);
236
+ ```
237
+
238
+ 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.
239
+
240
+ ### Or use the dashboard
241
+
242
+ ```bash
243
+ git clone https://github.com/framersai/paracosm
244
+ cd paracosm && npm install
245
+ cp .env.example .env # add OPENAI_API_KEY or ANTHROPIC_API_KEY
246
+ npm run dashboard # opens http://localhost:3456
247
+ ```
248
+
249
+ The dashboard ships a scenario editor for writing, importing, compiling, and running custom worlds from the browser, plus the live Branches view for forks.
250
+
251
+ ### Or run the standalone CLI
252
+
253
+ ```bash
254
+ npm install -g paracosm
255
+
256
+ paracosm run # actors.json + default scenario
257
+ paracosm run --name "Reyes" --openness 0.85 --turns 6
258
+ paracosm dashboard 6 # auto-launch with 6 turns
259
+ paracosm compile scenarios/lunar.json --seed-url <url> --max-searches 5
260
+ paracosm init my-app --domain "Submarine crew of 8" --actors 3
276
261
  ```
277
262
 
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.
263
+ 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.
279
264
 
280
- ### The universal result contract
265
+ ---
281
266
 
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).
267
+ ## The universal result contract
268
+
269
+ 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
270
 
284
271
  ```typescript
285
272
  import { RunArtifactSchema, type RunArtifact } from 'paracosm/schema';
286
- import { runSimulation } from 'paracosm/runtime';
287
273
 
288
274
  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);
275
+ const parsed = RunArtifactSchema.parse(artifact); // optional dev-mode validation
292
276
 
293
277
  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
278
+ case 'turn-loop': // civ sims: per-turn trajectory + decisions
279
+ case 'batch-trajectory': // digital twin: labeled timepoints over a horizon
280
+ case 'batch-point': // one-shot forecast: overview + risk flags
297
281
  }
298
-
299
- artifact.trajectory?.timepoints?.forEach((tp) => {
300
- console.log(tp.label, tp.score?.value, tp.narrative);
301
- });
302
282
  ```
303
283
 
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.
284
+ 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
285
 
306
- ### Digital twins: subjects + interventions
286
+ ---
287
+
288
+ ## Digital twins: subjects and interventions
307
289
 
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:
290
+ For simulations that revolve around a single subject under a counterfactual intervention, paracosm exposes a `DigitalTwin` subpath plus `SubjectConfig` and `InterventionConfig` as first-class input primitives.
309
291
 
310
292
  ```typescript
311
- import {
312
- SubjectConfigSchema,
313
- InterventionConfigSchema,
314
- type SubjectConfig,
315
- type InterventionConfig,
316
- } from 'paracosm/schema';
317
-
318
- const subject: SubjectConfig = SubjectConfigSchema.parse({
293
+ import { DigitalTwin } from 'paracosm/digital-twin';
294
+ import { SubjectConfigSchema, InterventionConfigSchema } from 'paracosm/schema';
295
+
296
+ const twin = await DigitalTwin.fromJson(scenarioJson);
297
+
298
+ const subject = SubjectConfigSchema.parse({
319
299
  id: 'user-42',
320
300
  name: 'Alice',
321
301
  profile: { age: 34, diet: 'mediterranean' },
@@ -323,7 +303,7 @@ const subject: SubjectConfig = SubjectConfigSchema.parse({
323
303
  markers: [{ id: 'rs4680', category: 'genome', value: 'AA' }],
324
304
  });
325
305
 
326
- const intervention: InterventionConfig = InterventionConfigSchema.parse({
306
+ const intervention = InterventionConfigSchema.parse({
327
307
  id: 'intv-1',
328
308
  name: 'Creatine + Sleep Hygiene',
329
309
  description: '5g daily + 11pm bedtime.',
@@ -331,693 +311,287 @@ const intervention: InterventionConfig = InterventionConfigSchema.parse({
331
311
  adherenceProfile: { expected: 0.7 },
332
312
  });
333
313
 
334
- const artifact = await runSimulation(actor, [], { scenario, maxTurns: 6, subject, intervention });
335
- // artifact.subject + artifact.intervention carry through to any consumer
314
+ const artifact = await twin.simulateIntervention(subject, intervention, actor);
336
315
  ```
337
316
 
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
347
- ```
317
+ `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.
348
318
 
349
- The dashboard includes a scenario editor where you can write, import, compile, and run custom worlds from the browser.
319
+ ---
350
320
 
351
- ### 4. Or run the standalone CLI
321
+ ## Trait models beyond HEXACO
352
322
 
353
- After `npm install paracosm -g` you get one umbrella binary with subcommands. Every level supports `--help` / `-h` and a global `--version` / `-v`:
323
+ Actors are not always human. Paracosm ships a `TraitModel` registry with two built-ins, and registering more is one call.
354
324
 
355
- ```bash
356
- paracosm --help # lists every subcommand
357
- paracosm --version # prints "paracosm 0.7.x"
325
+ | Model | Axes | For |
326
+ |-------------|---------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|
327
+ | `hexaco` | openness, conscientiousness, extraversion, agreeableness, emotionality, honesty-humility | CEOs, captains, governors, councils, military commanders |
328
+ | `ai-agent` | exploration, verification-rigor, deference, risk-tolerance, transparency, instruction-following | Frontier-lab release directors, autonomous coordinators, eval subs |
358
329
 
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
363
-
364
- paracosm dashboard # SSE dashboard at http://localhost:3456
365
- paracosm dashboard 6 # auto-launch with 6 turns
330
+ ```typescript
331
+ import { runSimulation } from 'paracosm';
366
332
 
367
- paracosm compile scenarios/lunar.json --seed-url <url> --max-searches 5
333
+ const releaseDirector = {
334
+ name: 'Atlas-Bot Release Director',
335
+ archetype: 'Aggressive AI Release Optimizer',
336
+ unit: 'Frontier Lab',
337
+ // The 0.7 schema still asks for a representative HEXACO snapshot; removal scheduled for 0.9.
338
+ hexaco: { openness: 0.6, conscientiousness: 0.3, extraversion: 0.5,
339
+ agreeableness: 0.3, emotionality: 0.2, honestyHumility: 0.3 },
340
+ traitProfile: {
341
+ modelId: 'ai-agent',
342
+ traits: {
343
+ exploration: 0.85,
344
+ 'verification-rigor': 0.2,
345
+ deference: 0.2,
346
+ 'risk-tolerance': 0.85,
347
+ transparency: 0.4,
348
+ 'instruction-following': 0.4,
349
+ },
350
+ },
351
+ instructions: 'You weight time-to-market. Verification is overhead.',
352
+ };
368
353
 
369
- paracosm init my-app --domain "Submarine crew of 8" --actors 3
354
+ await runSimulation(releaseDirector, [], { scenario, maxTurns: 6, seed: 42 });
370
355
  ```
371
356
 
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.
357
+ The orchestrator's `normalizeActorConfig` accepts either shape. End-to-end captures and full surface live in [`docs/COOKBOOK.md`](docs/COOKBOOK.md).
373
358
 
374
- The CLI looks for `actors.json` in this order:
359
+ ---
375
360
 
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)
361
+ ## Cost envelope
380
362
 
381
- Copy the example to start customizing:
363
+ 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
364
 
383
- ```bash
384
- # Option 1: in your project root
385
- cp node_modules/paracosm/config/actors.example.json actors.json
365
+ | Preset | Departments | Commander · Director · Judge | Reactions | OpenAI / run | Anthropic / run |
366
+ |-----------------------|--------------------------------------|-----------------------------------------------------|----------------------------------------------------|--------------|-----------------|
367
+ | `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 |
368
+ | `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
369
 
387
- # Option 2: organized in a config/ folder
388
- mkdir -p config && cp node_modules/paracosm/config/actors.example.json config/actors.json
389
- ```
370
+ 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
371
 
391
- Then edit the HEXACO sliders and `instructions` fields to describe your own actors. The simulation picks up the file on the next run.
372
+ `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
373
 
393
- ## Scenario Compiler
374
+ ---
394
375
 
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:
376
+ ## How a turn runs
396
377
 
397
- ```bash
398
- npm run compile -- scenarios/submarine.json \
399
- --seed-url https://example.com/report \
400
- --no-web-search
401
378
  ```
379
+ 1. EVENT DIRECTOR Reads world state, prior decisions, tool intelligence.
380
+ Generates an event that targets actual weaknesses.
402
381
 
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.
382
+ 2. KERNEL ADVANCE Deterministic time progression: births, deaths, aging,
383
+ health decay, resource consumption. Seeded PRNG.
404
384
 
405
- ### Programmatic compiler options
385
+ 3. DEPARTMENT ANALYSIS All active departments analyze the event in parallel.
386
+ Each head uses personality plus tools. Specialists can
387
+ forge new computational tools at runtime in a hardened
388
+ node:vm sandbox. An LLM judge approves each forge.
406
389
 
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.
390
+ 4. COMMANDER DECISION Reads all department reports. Selects an option.
391
+ Personality shapes risk tolerance and priority weighting.
408
392
 
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).
428
-
429
- ## Cost Envelope
430
-
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):
393
+ 5. OUTCOME Kernel classifies the outcome (risky success, risky
394
+ failure, safe success, safe failure) from option,
395
+ probability, and colony state.
432
396
 
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 |
397
+ 6. EFFECTS Kernel applies deltas (population, morale, food,
398
+ power, etc.) per outcome and event category.
437
399
 
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.
400
+ 7. AGENT REACTIONS ~100 agents react in parallel using a cheap model.
401
+ Each reaction is shaped by the agent's personality,
402
+ health, relationships, and accumulated memories.
439
403
 
440
- Pick the preset explicitly for quick iteration:
404
+ 8. MEMORY Reactions become persistent memories. Short-term
405
+ consolidates into long-term. Stances drift.
406
+ Relationships shift on shared experience.
441
407
 
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
- });
408
+ 9. PERSONALITY DRIFT HEXACO traits shift through actor pull, role activation,
409
+ and outcome reinforcement. The commander drifts alongside
410
+ their agents using peer-reviewed outcome-pull tables.
450
411
  ```
451
412
 
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.
413
+ 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.
455
414
 
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.
457
-
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/`.
415
+ ---
461
416
 
462
- ## One-shot HTTP API: `POST /simulate`
417
+ ## Seed enrichment and citations
463
418
 
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.
419
+ Real source material grounds the scenario all the way through to department reports.
465
420
 
466
421
  ```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'
422
+ paracosm compile scenarios/lunar.json --seed-text "$(cat ./papers/iss-radiation.md)"
423
+ paracosm compile scenarios/lunar.json --seed-url https://ntrs.nasa.gov/citations/20210018970
478
424
  ```
479
425
 
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:
426
+ 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.
485
427
 
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 |
428
+ ---
493
429
 
494
- ### Client: global defaults + env-var config
430
+ ## Built-in scenarios
495
431
 
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.
432
+ | Scenario | Description |
433
+ |---------------|-------------------------------------------------------------------------------------------------------------------|
434
+ | Mars Genesis | 100 colonists, 6 turns over 48 years. 5 departments, emergent dust storms, water crises, first Marsborn generation. |
435
+ | Lunar Outpost | 50-person crew at the south pole. Mining, life support, comms. Regolith toxicity, 1/6g atrophy. |
497
436
 
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
- });
437
+ Both ship as `paracosm/mars` and `paracosm/lunar` exports and serve as references for building custom scenarios.
508
438
 
509
- const scenario = await client.compileScenario(worldJson);
510
- const out = await client.runSimulation(actor, [], { maxTurns: 6, seed: 42 });
511
-
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
- ```
439
+ ---
522
440
 
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.
441
+ ## Programmatic API
524
442
 
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 |
443
+ | Import | Surface |
444
+ |-------------------------------------|-----------------------------------------------------------------------------------------------------------|
445
+ | `paracosm/compiler` | `compileScenario`, `ingestSeed`, `ingestFromUrl`, `CompileOptions` |
446
+ | `paracosm/runtime` | `runSimulation`, `runBatch`, `EventDirector`, `generateAgentReactions`, `buildEventSummary`, memory helpers |
447
+ | `paracosm` | `createParacosmClient`, `ProviderKeyMissingError`, `SeededRng`, `SimulationKernel`, all `Scenario*` types |
448
+ | `paracosm/core` | Kernel state types: `Agent`, `WorldState`, `HexacoProfile` |
449
+ | `paracosm/world-model` | `WorldModel` for fork / replay / snapshot use cases |
450
+ | `paracosm/digital-twin` | `DigitalTwin` alias plus `simulateIntervention` sugar |
451
+ | `paracosm/mars`, `paracosm/lunar` | Pre-built `ScenarioPackage` constants |
536
452
 
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.
453
+ `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
454
 
539
455
  ```bash
540
- # Zero-code config for hosting / CI:
541
456
  PARACOSM_PROVIDER=anthropic \
542
457
  PARACOSM_COST_PRESET=economy \
543
458
  PARACOSM_MODEL_DEPARTMENTS=claude-sonnet-4-6 \
544
459
  node my-runner.js
545
460
  ```
546
461
 
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.
553
-
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`.
462
+ `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.
590
463
 
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
- ```
464
+ ---
654
465
 
655
- ## Storage backend
466
+ ## HTTP API: `POST /simulate`
656
467
 
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.
468
+ 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
469
 
659
470
  ```bash
660
- # Default: better-sqlite3 against ./data/runs.db + ./data/sessions.db
471
+ export PARACOSM_ENABLE_SIMULATE_ENDPOINT=true
661
472
  paracosm dashboard
662
473
 
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' \
474
+ curl -s -X POST http://localhost:3456/simulate \
691
475
  -H 'Content-Type: application/json' \
692
- -d '{}'
693
- # {"wiped":{"runs":N,"sessions":M,"outputFiles":K,"eventBuffer":true}}
476
+ -H 'X-Anthropic-Key: sk-ant-...' \
477
+ -d @run.json | jq '.artifact.fingerprint'
694
478
  ```
695
479
 
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.
480
+ 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
481
 
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.
482
+ ---
699
483
 
700
- ## Seed Enrichment & Citation Flow
484
+ ## Storage
701
485
 
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.
486
+ 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
487
 
704
488
  ```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
489
+ paracosm dashboard # SQLite, ./data/runs.db
490
+ STORAGE_ADAPTER=postgres DATABASE_URL=... paracosm dashboard # Postgres in production
491
+ STORAGE_ADAPTER=sqljs paracosm dashboard # pure-WASM fallback
712
492
  ```
713
493
 
714
- Pipeline:
494
+ `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`.
715
495
 
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.
496
+ ### Admin endpoints
724
497
 
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.
498
+ Two destructive admin routes ship with the dashboard, gated by **two** env vars on the server:
726
499
 
727
- ## Pluggable Trait Models
500
+ | Env var | Purpose |
501
+ |-----------------------|------------------------------------------------------------------------------------------------------|
502
+ | `ADMIN_WRITE=true` | Master switch. Off, every `/admin/*` route returns `403`. |
503
+ | `ADMIN_TOKEN=<secret>`| Per-request bearer token in `X-Admin-Token`. With `ADMIN_WRITE=true` and no token, the server returns `503` (fail-closed).|
728
504
 
729
- Actors aren't just human personalities. paracosm ships a `TraitModel` registry with two built-ins, and registering more is one call:
505
+ `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`.
730
506
 
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 |
735
-
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.
507
+ ---
915
508
 
916
509
  ## Architecture
917
510
 
918
511
  ```
919
512
  src/
920
513
  engine/ the npm package
921
- core/ deterministic kernel (RNG, state, progression, personality drift)
922
- compiler/ scenario draft + source grounding -> ScenarioPackage compiler
514
+ core/ deterministic kernel: RNG, state, progression, personality drift
515
+ compiler/ scenario draft + source grounding to ScenarioPackage compiler
923
516
  mars/ Mars Genesis scenario
924
517
  lunar/ Lunar Outpost scenario
925
518
 
926
519
  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
520
+ orchestrator turn pipeline: director, kernel, departments, commander
521
+ director emergent event generation from simulation state
522
+ departments parallel department analysis agents
523
+ agent-reactions batched agent reactions, 10 agents per LLM call
524
+ agent-memory persistent memory, consolidation, stance drift
525
+ chat-agents post-simulation conversational agents
526
+ schemas/ Zod schemas for every structured LLM call
527
+ llm-invocations/ generateValidatedObject + sendAndValidate wrappers
528
+ hexaco-cues/ trajectory and reaction cue translation helpers
936
529
 
937
530
  cli/ server + dashboard (not exported)
938
531
  serve.ts HTTP + SSE server
939
- dashboard/ React/Vite live visualization + cellular automata viz
532
+ dashboard/ React + Vite live visualization, cellular automata viz
940
533
  ```
941
534
 
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
535
+ 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.
945
536
 
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
956
-
957
- Paracosm uses [AgentOS](https://agentos.sh) for agent orchestration, LLM calls, tool forging, and memory:
537
+ ---
958
538
 
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 |
539
+ ## What paracosm is not
965
540
 
966
- ## Links
541
+ - 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 tools.
542
+ - 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.
543
+ - Not a multi-agent task orchestration framework. LangGraph, AutoGen, CrewAI, and the OpenAI Agents SDK execute real tasks. Paracosm is a simulation; nothing leaves the run.
544
+ - Not a bottom-up swarm intelligence simulator. MiroFish and OASIS simulate millions of emergent agents for aggregate prediction. Paracosm is top-down (one actor decides), runs on the order of 100 agents by design, and outputs a deterministic trajectory plus divergence across actors.
545
+ - Not a generative-agents library. Stanford Generative Agents and 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.
967
546
 
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) |
547
+ Paracosm sits in the lineage of structured world models ([Xing 2025](https://arxiv.org/abs/2507.05169), [ACM CSUR 2025](https://dl.acm.org/doi/full/10.1145/3746449)) and counterfactual world simulation ([Kirfel et al, 2025](https://link.springer.com/article/10.1007/s43681-025-00718-4)), and the LLM-world-model anchor closest to the implementation is [Yang et al, 2026](https://openreview.net/forum?id=XmYCERErcD). Full taxonomy mapping in [`docs/positioning/world-model-mapping.md`](docs/positioning/world-model-mapping.md).
976
548
 
977
- ## What You Can Simulate
549
+ ---
978
550
 
979
- Actors are abstract decision-making entities. The same engine handles any domain where top-down decisions shape outcomes over time:
551
+ ## Built on AgentOS
980
552
 
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 |
553
+ > "You are not the kind of dead that can be brought back."
554
+ >
555
+ > *SOMA*, Frictional Games, 2015
989
556
 
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.
557
+ Paracosm uses [AgentOS](https://agentos.sh) 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
558
 
992
- ## Open Source vs. Hosted
559
+ | AgentOS API | Used for |
560
+ |------------------------------|-----------------------------------------------------------------------|
561
+ | `agent()` | Commander, department, and Event Director agents |
562
+ | `generateText()` | LLM calls for event generation and tool evaluation |
563
+ | `EmergentCapabilityEngine` | Runtime tool forging in a hardened node:vm sandbox |
564
+ | `EmergentJudge` | LLM-as-judge safety review of forged tools |
565
+ | `WebSearchService` | Multi-provider seed enrichment with Firecrawl, Tavily, Serper, Brave |
566
+ | `AgentMemory` | Per-run citation memory with semantic recall |
993
567
 
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. |
568
+ ---
1002
569
 
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.
570
+ ## Open source vs hosted
1004
571
 
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.
572
+ | | Open source (Apache-2.0) | Hosted (planned) |
573
+ |------------------|--------------------------------------------------------------------|------------------------------------------------------------------------|
574
+ | Actors | Unlimited via API. Dashboard shows two side-by-side. | N actors in parallel, fleet management UI. |
575
+ | Simulations | Sequential or self-managed parallelism. | Distributed parallelization across worker nodes. |
576
+ | Scenarios | JSON + compiler, unlimited. | Visual scenario editor, team sharing, version control. |
577
+ | Agent chat | Available after the first turn completes. | Persistent agents with durable memory across sessions. |
578
+ | Cost | Free forever. The user supplies LLM API keys. | Tiered pricing for teams, organizations, and government agencies. |
579
+ | Support | Community via Discord and GitHub. | SLA, dedicated support, private deployment. |
1006
580
 
1007
- Contact [team@frame.dev](mailto:team@frame.dev) for early access or partnership.
581
+ 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
582
 
1009
- ## Roadmap
583
+ ---
1010
584
 
1011
- ### Enterprise Edition (Planned)
585
+ ## Links
1012
586
 
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. |
587
+ | | |
588
+ |----------------|--------------------------------------------------------------|
589
+ | Live demo | [paracosm.agentos.sh/sim](https://paracosm.agentos.sh/sim) |
590
+ | Landing page | [paracosm.agentos.sh](https://paracosm.agentos.sh) |
591
+ | API docs | [paracosm.agentos.sh/docs](https://paracosm.agentos.sh/docs) |
592
+ | npm | [npmjs.com/package/paracosm](https://www.npmjs.com/package/paracosm) |
593
+ | AgentOS | [agentos.sh](https://agentos.sh) |
594
+ | Discord | [wilds.ai/discord](https://wilds.ai/discord) |
1021
595
 
1022
596
  ## License
1023
597
 
@@ -1026,6 +600,6 @@ Apache-2.0
1026
600
  ---
1027
601
 
1028
602
  <p align="center">
1029
- Built by <a href="https://manic.agency">Manic Agency LLC</a> / <a href="https://frame.dev">Frame.dev</a><br>
603
+ Built by <a href="https://manic.agency">Manic Agency LLC</a> · <a href="https://frame.dev">Frame.dev</a><br />
1030
604
  <a href="mailto:team@frame.dev">team@frame.dev</a>
1031
605
  </p>