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 +322 -748
- package/dist/cli/server-app.d.ts.map +1 -1
- package/dist/cli/server-app.js +7 -0
- package/dist/cli/server-app.js.map +1 -1
- package/package.json +1 -1
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
|
|
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>
|
|
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>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
34
|
+
## Forking Paths
|
|
49
35
|
|
|
50
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
|
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);
|
|
61
|
+
console.log(trunk.fingerprint, branch.fingerprint);
|
|
75
62
|
```
|
|
76
63
|
|
|
77
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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 {
|
|
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
|
|
97
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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),
|
|
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,
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
{
|
|
224
|
-
|
|
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
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
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
|
-
|
|
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
|
-
|
|
265
|
+
---
|
|
281
266
|
|
|
282
|
-
|
|
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': //
|
|
295
|
-
case 'batch-trajectory': // digital
|
|
296
|
-
case 'batch-point': // one-shot forecast: overview + risk flags
|
|
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
|
|
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
|
-
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Digital twins: subjects and interventions
|
|
307
289
|
|
|
308
|
-
For simulations
|
|
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
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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
|
|
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
|
|
335
|
-
// artifact.subject + artifact.intervention carry through to any consumer
|
|
314
|
+
const artifact = await twin.simulateIntervention(subject, intervention, actor);
|
|
336
315
|
```
|
|
337
316
|
|
|
338
|
-
|
|
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
|
-
|
|
319
|
+
---
|
|
350
320
|
|
|
351
|
-
|
|
321
|
+
## Trait models beyond HEXACO
|
|
352
322
|
|
|
353
|
-
|
|
323
|
+
Actors are not always human. Paracosm ships a `TraitModel` registry with two built-ins, and registering more is one call.
|
|
354
324
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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
|
-
|
|
360
|
-
|
|
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
|
-
|
|
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
|
-
|
|
354
|
+
await runSimulation(releaseDirector, [], { scenario, maxTurns: 6, seed: 42 });
|
|
370
355
|
```
|
|
371
356
|
|
|
372
|
-
|
|
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
|
-
|
|
359
|
+
---
|
|
375
360
|
|
|
376
|
-
|
|
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
|
-
|
|
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
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
374
|
+
---
|
|
394
375
|
|
|
395
|
-
|
|
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
|
-
|
|
382
|
+
2. KERNEL ADVANCE Deterministic time progression: births, deaths, aging,
|
|
383
|
+
health decay, resource consumption. Seeded PRNG.
|
|
404
384
|
|
|
405
|
-
|
|
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
|
-
|
|
390
|
+
4. COMMANDER DECISION Reads all department reports. Selects an option.
|
|
391
|
+
Personality shapes risk tolerance and priority weighting.
|
|
408
392
|
|
|
409
|
-
|
|
410
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
443
|
-
|
|
444
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
417
|
+
## Seed enrichment and citations
|
|
463
418
|
|
|
464
|
-
|
|
419
|
+
Real source material grounds the scenario all the way through to department reports.
|
|
465
420
|
|
|
466
421
|
```bash
|
|
467
|
-
|
|
468
|
-
paracosm
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
430
|
+
## Built-in scenarios
|
|
495
431
|
|
|
496
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
441
|
+
## Programmatic API
|
|
524
442
|
|
|
525
|
-
|
|
|
526
|
-
|
|
527
|
-
| `
|
|
528
|
-
| `
|
|
529
|
-
| `
|
|
530
|
-
| `
|
|
531
|
-
| `
|
|
532
|
-
| `
|
|
533
|
-
| `
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
466
|
+
## HTTP API: `POST /simulate`
|
|
656
467
|
|
|
657
|
-
|
|
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
|
-
|
|
471
|
+
export PARACOSM_ENABLE_SIMULATE_ENDPOINT=true
|
|
661
472
|
paracosm dashboard
|
|
662
473
|
|
|
663
|
-
|
|
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
|
-
-
|
|
693
|
-
|
|
476
|
+
-H 'X-Anthropic-Key: sk-ant-...' \
|
|
477
|
+
-d @run.json | jq '.artifact.fingerprint'
|
|
694
478
|
```
|
|
695
479
|
|
|
696
|
-
The
|
|
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
|
-
|
|
482
|
+
---
|
|
699
483
|
|
|
700
|
-
##
|
|
484
|
+
## Storage
|
|
701
485
|
|
|
702
|
-
|
|
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
|
-
#
|
|
706
|
-
paracosm
|
|
707
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
498
|
+
Two destructive admin routes ship with the dashboard, gated by **two** env vars on the server:
|
|
726
499
|
|
|
727
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
922
|
-
compiler/ scenario draft + source grounding
|
|
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
|
|
928
|
-
director
|
|
929
|
-
departments
|
|
930
|
-
agent-reactions
|
|
931
|
-
agent-memory
|
|
932
|
-
chat-agents
|
|
933
|
-
schemas/
|
|
934
|
-
llm-invocations/
|
|
935
|
-
hexaco-cues/
|
|
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
|
|
532
|
+
dashboard/ React + Vite live visualization, cellular automata viz
|
|
940
533
|
```
|
|
941
534
|
|
|
942
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
549
|
+
---
|
|
978
550
|
|
|
979
|
-
|
|
551
|
+
## Built on AgentOS
|
|
980
552
|
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
570
|
+
## Open source vs hosted
|
|
1004
571
|
|
|
1005
|
-
|
|
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
|
|
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
|
-
|
|
583
|
+
---
|
|
1010
584
|
|
|
1011
|
-
|
|
585
|
+
## Links
|
|
1012
586
|
|
|
1013
|
-
|
|
|
1014
|
-
|
|
1015
|
-
|
|
|
1016
|
-
|
|
|
1017
|
-
|
|
|
1018
|
-
|
|
|
1019
|
-
|
|
|
1020
|
-
|
|
|
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>
|
|
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>
|