paracosm 0.8.603 → 0.8.636
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +309 -750
- package/dist/cli/server-app.js +3 -3
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -5,51 +5,39 @@
|
|
|
5
5
|
<h1 align="center">PARACOSM</h1>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<em>
|
|
8
|
+
<em>A structured world model for AI agents. Prompt to runnable world to forked futures.</em>
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
12
|
<a href="https://www.npmjs.com/package/paracosm"><img src="https://img.shields.io/npm/v/paracosm?style=flat-square&color=e8b44a&labelColor=14110e" alt="npm" /></a>
|
|
13
13
|
<a href="https://github.com/framersai/paracosm/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-e06530?style=flat-square&labelColor=14110e" alt="License" /></a>
|
|
14
14
|
<a href="https://paracosm.agentos.sh/docs"><img src="https://img.shields.io/badge/docs-API%20Reference-4ca8a8?style=flat-square&labelColor=14110e" alt="Docs" /></a>
|
|
15
|
-
<a href="https://agentos.sh"><img src="https://img.shields.io/badge/built%20on-AgentOS-e06530?style=flat-square&labelColor=14110e" alt="AgentOS" /></a>
|
|
15
|
+
<a href="https://agentos.sh/en"><img src="https://img.shields.io/badge/built%20on-AgentOS-e06530?style=flat-square&labelColor=14110e" alt="AgentOS" /></a>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
18
|
<p align="center">
|
|
19
|
-
<a href="https://paracosm.agentos.sh"><strong>paracosm.agentos.sh</strong></a>
|
|
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.
|
|
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 world model that can be forked needs three things: a deterministic substrate that can be rewound, an LLM reasoner that can be replayed against the same state, and a contract for what state actually means. Paracosm carries all three. Snapshots are JSON, the kernel round-trips through `JSON.stringify`, and every fork resumes from the captured state without recomputing the prefix.
|
|
53
41
|
|
|
54
42
|
```typescript
|
|
55
43
|
import { WorldModel } from 'paracosm/world-model';
|
|
@@ -57,51 +45,85 @@ import worldJson from './my-world.json' with { type: 'json' };
|
|
|
57
45
|
|
|
58
46
|
const wm = await WorldModel.fromJson(worldJson);
|
|
59
47
|
|
|
60
|
-
//
|
|
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,101 @@ bounded collective under an actor's decisions.
|
|
|
178
192
|
}
|
|
179
193
|
```
|
|
180
194
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
> report summaries. A handful of examples:
|
|
187
|
-
>
|
|
188
|
-
> | Scenario | `settlementNoun` | `populationNoun` | `timeUnitNoun` |
|
|
189
|
-
> |-------------------|------------------|------------------|----------------|
|
|
190
|
-
> | Mars Genesis | `colony` | `colonists` | `year` |
|
|
191
|
-
> | Submarine (daily) | `habitat` | `crew` | `day` |
|
|
192
|
-
> | Medieval | `kingdom` | `subjects` | `year` |
|
|
193
|
-
> | Corporate | `company` | `employees` | `quarter` |
|
|
194
|
-
> | Space Station | `station` | `operators` | `year` |
|
|
195
|
-
> | Generation Ship | `vessel` | `passengers` | `year` |
|
|
196
|
-
> | Benchmark Arena | `session` | `agents` | `tick` |
|
|
197
|
-
>
|
|
198
|
-
> `populationNoun` is the **plural** form; the dashboard derives the singular (`colonists` →
|
|
199
|
-
> `colonist`) and capitalised variants automatically. `settlementNoun` is **singular** (`colony`,
|
|
200
|
-
> not `colonies`). `timeUnitNoun` is **singular** and pairs with `timeUnitNounPlural` for
|
|
201
|
-
> grammatical display; both are optional and fall back to `tick` / `ticks`. Paracosm itself
|
|
202
|
-
> is a structured world model at the meta layer; what it simulates inside each run is
|
|
203
|
-
> scenario-flavoured via these fields.
|
|
195
|
+
Every scenario declares its own vocabulary via `labels.populationNoun` (plural), `labels.settlementNoun` (singular), and `labels.timeUnitNoun`. The dashboard, kernel, and progression hooks pick those up everywhere user-facing copy renders. Without overrides, paracosm falls back to `colonists` / `colony` / `tick`.
|
|
196
|
+
|
|
197
|
+
Time is unit-agnostic. `setup.defaultTimePerTurn` and `setup.defaultStartTime` are plain numbers; whether they represent years, quarters, hours, or ticks is decided by `timeUnitNoun`. The dashboard turn header reads `Quarter 5`, `Day 22`, or `Year 2043` straight from the label.
|
|
198
|
+
|
|
199
|
+
---
|
|
204
200
|
|
|
205
|
-
|
|
201
|
+
## Compile and run
|
|
206
202
|
|
|
207
203
|
```typescript
|
|
208
204
|
import { compileScenario } from 'paracosm/compiler';
|
|
209
205
|
import { runSimulation } from 'paracosm/runtime';
|
|
210
206
|
import worldJson from './my-world.json' with { type: 'json' };
|
|
211
207
|
|
|
212
|
-
//
|
|
208
|
+
// First compile is roughly $0.10 and caches to disk; reruns are free
|
|
213
209
|
const scenario = await compileScenario(worldJson, {
|
|
214
210
|
provider: 'anthropic',
|
|
215
211
|
model: 'claude-sonnet-4-6',
|
|
216
212
|
});
|
|
217
213
|
|
|
218
|
-
|
|
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
|
-
);
|
|
214
|
+
const result = await runSimulation(actor, [], {
|
|
215
|
+
scenario,
|
|
216
|
+
maxTurns: 6,
|
|
217
|
+
seed: 42,
|
|
218
|
+
// costPreset: 'economy', // ~5-10× cheaper iteration on OpenAI
|
|
219
|
+
onEvent(e) { console.log(actor.name, e.type, e.data.summary); },
|
|
220
|
+
});
|
|
263
221
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
222
|
+
console.log(result.metadata.scenario.name, '→', result.fingerprint);
|
|
223
|
+
console.log('cost $', result.cost?.totalUSD.toFixed(2));
|
|
224
|
+
console.log('final ', result.finalState?.metrics);
|
|
225
|
+
console.log('forged tools ', result.forgedTools?.length ?? 0);
|
|
226
|
+
console.log('citations ', result.citations?.length ?? 0);
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Each call to `runSimulation` takes one actor. Run one, two, or twenty. The dashboard runs two side-by-side for comparison; the API has no limit.
|
|
230
|
+
|
|
231
|
+
### Or use the dashboard
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
git clone https://github.com/framersai/paracosm
|
|
235
|
+
cd paracosm && npm install
|
|
236
|
+
cp .env.example .env # add OPENAI_API_KEY or ANTHROPIC_API_KEY
|
|
237
|
+
npm run dashboard # opens http://localhost:3456
|
|
276
238
|
```
|
|
277
239
|
|
|
278
|
-
|
|
240
|
+
The dashboard ships a scenario editor for writing, importing, compiling, and running custom worlds from the browser, plus the live Branches view for forks.
|
|
279
241
|
|
|
280
|
-
###
|
|
242
|
+
### Or run the standalone CLI
|
|
281
243
|
|
|
282
|
-
|
|
244
|
+
```bash
|
|
245
|
+
npm install -g paracosm
|
|
246
|
+
|
|
247
|
+
paracosm run # actors.json + default scenario
|
|
248
|
+
paracosm run --name "Reyes" --openness 0.85 --turns 6
|
|
249
|
+
paracosm dashboard 6 # auto-launch with 6 turns
|
|
250
|
+
paracosm compile scenarios/lunar.json --seed-url <url> --max-searches 5
|
|
251
|
+
paracosm init my-app --domain "Submarine crew of 8" --actors 3
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
The CLI looks for `actors.json` via `--actors`, then `./actors.json`, then `./config/actors.json`, then a bundled example. A back-compat `paracosm-dashboard` alias is shipped for existing scripts and Docker invocations.
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## The universal result contract
|
|
259
|
+
|
|
260
|
+
Every simulation returns a `RunArtifact`: one Zod-validated shape exported from `paracosm/schema`. The same shape covers civilization sims (turn-loop), digital-twin runs (batch-trajectory), and one-shot forecasts (batch-point).
|
|
283
261
|
|
|
284
262
|
```typescript
|
|
285
263
|
import { RunArtifactSchema, type RunArtifact } from 'paracosm/schema';
|
|
286
|
-
import { runSimulation } from 'paracosm/runtime';
|
|
287
264
|
|
|
288
265
|
const artifact: RunArtifact = await runSimulation(actor, [], { scenario, maxTurns: 6 });
|
|
289
|
-
|
|
290
|
-
// Optional runtime validation (dev mode, untrusted JSON, replays, etc.):
|
|
291
|
-
const parsed = RunArtifactSchema.parse(artifact);
|
|
266
|
+
const parsed = RunArtifactSchema.parse(artifact); // optional dev-mode validation
|
|
292
267
|
|
|
293
268
|
switch (artifact.metadata.mode) {
|
|
294
|
-
case 'turn-loop': //
|
|
295
|
-
case 'batch-trajectory': // digital
|
|
296
|
-
case 'batch-point': // one-shot forecast: overview + risk flags
|
|
269
|
+
case 'turn-loop': // civ sims: per-turn trajectory + decisions
|
|
270
|
+
case 'batch-trajectory': // digital twin: labeled timepoints over a horizon
|
|
271
|
+
case 'batch-point': // one-shot forecast: overview + risk flags
|
|
297
272
|
}
|
|
298
|
-
|
|
299
|
-
artifact.trajectory?.timepoints?.forEach((tp) => {
|
|
300
|
-
console.log(tp.label, tp.score?.value, tp.narrative);
|
|
301
|
-
});
|
|
302
273
|
```
|
|
303
274
|
|
|
304
|
-
For non-TypeScript consumers
|
|
275
|
+
For non-TypeScript consumers, `npm run export:json-schema` emits `schema/run-artifact.schema.json` and `schema/stream-event.schema.json`. Python projects generate Pydantic types via `datamodel-codegen`; any ecosystem with a JSON-Schema generator adopts cleanly.
|
|
305
276
|
|
|
306
|
-
|
|
277
|
+
---
|
|
307
278
|
|
|
308
|
-
|
|
279
|
+
## Digital twins: subjects and interventions
|
|
280
|
+
|
|
281
|
+
For simulations that revolve around a single subject under an intervention, paracosm exposes a `DigitalTwin` subpath plus `SubjectConfig` and `InterventionConfig` as first-class input primitives.
|
|
309
282
|
|
|
310
283
|
```typescript
|
|
311
|
-
import {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
const subject: SubjectConfig = SubjectConfigSchema.parse({
|
|
284
|
+
import { DigitalTwin } from 'paracosm/digital-twin';
|
|
285
|
+
import { SubjectConfigSchema, InterventionConfigSchema } from 'paracosm/schema';
|
|
286
|
+
|
|
287
|
+
const twin = await DigitalTwin.fromJson(scenarioJson);
|
|
288
|
+
|
|
289
|
+
const subject = SubjectConfigSchema.parse({
|
|
319
290
|
id: 'user-42',
|
|
320
291
|
name: 'Alice',
|
|
321
292
|
profile: { age: 34, diet: 'mediterranean' },
|
|
@@ -323,7 +294,7 @@ const subject: SubjectConfig = SubjectConfigSchema.parse({
|
|
|
323
294
|
markers: [{ id: 'rs4680', category: 'genome', value: 'AA' }],
|
|
324
295
|
});
|
|
325
296
|
|
|
326
|
-
const intervention
|
|
297
|
+
const intervention = InterventionConfigSchema.parse({
|
|
327
298
|
id: 'intv-1',
|
|
328
299
|
name: 'Creatine + Sleep Hygiene',
|
|
329
300
|
description: '5g daily + 11pm bedtime.',
|
|
@@ -331,693 +302,281 @@ const intervention: InterventionConfig = InterventionConfigSchema.parse({
|
|
|
331
302
|
adherenceProfile: { expected: 0.7 },
|
|
332
303
|
});
|
|
333
304
|
|
|
334
|
-
const artifact = await
|
|
335
|
-
// artifact.subject + artifact.intervention carry through to any consumer
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
Turn-loop mode stashes both verbatim without semantic consumption; external batch-trajectory executors (LangGraph-style pipelines) populate them from their own flow.
|
|
339
|
-
|
|
340
|
-
### 3. Or use the dashboard
|
|
341
|
-
|
|
342
|
-
```bash
|
|
343
|
-
git clone https://github.com/framersai/paracosm
|
|
344
|
-
cd paracosm && npm install
|
|
345
|
-
cp .env.example .env # add your OpenAI or Anthropic key
|
|
346
|
-
npm run dashboard # opens http://localhost:3456
|
|
305
|
+
const artifact = await twin.simulateIntervention(subject, intervention, actor);
|
|
347
306
|
```
|
|
348
307
|
|
|
349
|
-
|
|
308
|
+
`DigitalTwin` is an alias of `WorldModel`. The subpath names the use case in the import path. `RunArtifact.subject` and `RunArtifact.intervention` carry through to any consumer.
|
|
350
309
|
|
|
351
|
-
|
|
310
|
+
---
|
|
352
311
|
|
|
353
|
-
|
|
312
|
+
## Trait models beyond HEXACO
|
|
354
313
|
|
|
355
|
-
|
|
356
|
-
paracosm --help # lists every subcommand
|
|
357
|
-
paracosm --version # prints "paracosm 0.7.x"
|
|
314
|
+
Actors are not always human. Paracosm ships a `TraitModel` registry with two built-ins, and registering more is one call.
|
|
358
315
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
316
|
+
| Model | Axes | For |
|
|
317
|
+
|-------------|---------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|
|
|
318
|
+
| `hexaco` | openness, conscientiousness, extraversion, agreeableness, emotionality, honesty-humility | CEOs, captains, governors, councils, military commanders |
|
|
319
|
+
| `ai-agent` | exploration, verification-rigor, deference, risk-tolerance, transparency, instruction-following | Frontier-lab release directors, autonomous coordinators, eval subs |
|
|
363
320
|
|
|
364
|
-
|
|
365
|
-
|
|
321
|
+
```typescript
|
|
322
|
+
import { runSimulation } from 'paracosm';
|
|
366
323
|
|
|
367
|
-
|
|
324
|
+
const releaseDirector = {
|
|
325
|
+
name: 'Atlas-Bot Release Director',
|
|
326
|
+
archetype: 'Aggressive AI Release Optimizer',
|
|
327
|
+
unit: 'Frontier Lab',
|
|
328
|
+
// The 0.7 schema still asks for a representative HEXACO snapshot; removal scheduled for 0.9.
|
|
329
|
+
hexaco: { openness: 0.6, conscientiousness: 0.3, extraversion: 0.5,
|
|
330
|
+
agreeableness: 0.3, emotionality: 0.2, honestyHumility: 0.3 },
|
|
331
|
+
traitProfile: {
|
|
332
|
+
modelId: 'ai-agent',
|
|
333
|
+
traits: {
|
|
334
|
+
exploration: 0.85,
|
|
335
|
+
'verification-rigor': 0.2,
|
|
336
|
+
deference: 0.2,
|
|
337
|
+
'risk-tolerance': 0.85,
|
|
338
|
+
transparency: 0.4,
|
|
339
|
+
'instruction-following': 0.4,
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
instructions: 'You weight time-to-market. Verification is overhead.',
|
|
343
|
+
};
|
|
368
344
|
|
|
369
|
-
|
|
345
|
+
await runSimulation(releaseDirector, [], { scenario, maxTurns: 6, seed: 42 });
|
|
370
346
|
```
|
|
371
347
|
|
|
372
|
-
|
|
348
|
+
The orchestrator's `normalizeActorConfig` accepts either shape. End-to-end captures and full surface live in [`docs/COOKBOOK.md`](docs/COOKBOOK.md).
|
|
373
349
|
|
|
374
|
-
|
|
350
|
+
---
|
|
375
351
|
|
|
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)
|
|
352
|
+
## Cost envelope
|
|
380
353
|
|
|
381
|
-
|
|
354
|
+
Running a simulation calls real LLM APIs against the user's key. Paracosm assigns a different model tier per role so flagship cost only lands where it earns its keep (forge-code correctness).
|
|
382
355
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
356
|
+
| Preset | Departments | Commander · Director · Judge | Reactions | OpenAI / run | Anthropic / run |
|
|
357
|
+
|-----------------------|--------------------------------------|-----------------------------------------------------|----------------------------------------------------|--------------|-----------------|
|
|
358
|
+
| `quality` (default) | gpt-5.4 · claude-sonnet-4-6 | gpt-5.4-mini · claude-haiku-4-5-20251001 | gpt-5.4-nano · claude-haiku-4-5-20251001 | ~$1 to $3 | ~$3 to $7 |
|
|
359
|
+
| `economy` | gpt-4o · claude-sonnet-4-6 | gpt-5.4-nano · claude-haiku-4-5-20251001 | gpt-5.4-nano · claude-haiku-4-5-20251001 | ~$0.20 to $0.60 | ~$3 to $5 |
|
|
386
360
|
|
|
387
|
-
|
|
388
|
-
mkdir -p config && cp node_modules/paracosm/config/actors.example.json config/actors.json
|
|
389
|
-
```
|
|
361
|
+
Numbers assume 6 turns, 5 departments, 100 agents, up to 3 events per turn. Forge approval rate drops 10 to 20 points on `economy` because the mid-tier department model occasionally violates structured-output schemas the judge rejects. Use `economy` for iteration and CI; use `quality` for publishable runs. Explicit `models` entries always win over the preset, so per-role overrides combine cleanly with global defaults.
|
|
390
362
|
|
|
391
|
-
|
|
363
|
+
`runSimulation` returns a `cost` field with token counts, LLM call counts, and USD spend. Every stable system prefix routes through a `cacheBreakpoint: true` block, so on Anthropic the shared prefix serves from prompt cache at one-tenth input cost from turn 2 onward; OpenAI auto-caches any prompt over 1024 tokens. The `cost.caches` field reports tokens read, tokens created, and USD saved per run.
|
|
392
364
|
|
|
393
|
-
|
|
365
|
+
---
|
|
394
366
|
|
|
395
|
-
|
|
367
|
+
## How a turn runs
|
|
396
368
|
|
|
397
|
-
```bash
|
|
398
|
-
npm run compile -- scenarios/submarine.json \
|
|
399
|
-
--seed-url https://example.com/report \
|
|
400
|
-
--no-web-search
|
|
401
369
|
```
|
|
370
|
+
1. EVENT DIRECTOR Reads world state, prior decisions, tool intelligence.
|
|
371
|
+
Generates an event that targets actual weaknesses.
|
|
402
372
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
### Programmatic compiler options
|
|
373
|
+
2. KERNEL ADVANCE Deterministic time progression: births, deaths, aging,
|
|
374
|
+
health decay, resource consumption. Seeded PRNG.
|
|
406
375
|
|
|
407
|
-
|
|
376
|
+
3. DEPARTMENT ANALYSIS All active departments analyze the event in parallel.
|
|
377
|
+
Each head uses personality plus tools. Specialists can
|
|
378
|
+
forge new computational tools at runtime in a hardened
|
|
379
|
+
node:vm sandbox. An LLM judge approves each forge.
|
|
408
380
|
|
|
409
|
-
|
|
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).
|
|
381
|
+
4. COMMANDER DECISION Reads all department reports. Selects an option.
|
|
382
|
+
Personality shapes risk tolerance and priority weighting.
|
|
428
383
|
|
|
429
|
-
|
|
384
|
+
5. OUTCOME Kernel classifies the outcome (risky success, risky
|
|
385
|
+
failure, safe success, safe failure) from option,
|
|
386
|
+
probability, and colony state.
|
|
430
387
|
|
|
431
|
-
|
|
388
|
+
6. EFFECTS Kernel applies deltas (population, morale, food,
|
|
389
|
+
power, etc.) per outcome and event category.
|
|
432
390
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
| **`economy`** | `gpt-4o` / `claude-sonnet-4-6` | `gpt-5.4-nano` / `claude-haiku-4-5-20251001` | `gpt-5.4-nano` / `claude-haiku-4-5-20251001` | **~$0.20-0.60** | ~$3-5 |
|
|
391
|
+
7. AGENT REACTIONS ~100 agents react in parallel using a cheap model.
|
|
392
|
+
Each reaction is shaped by the agent's personality,
|
|
393
|
+
health, relationships, and accumulated memories.
|
|
437
394
|
|
|
438
|
-
|
|
395
|
+
8. MEMORY Reactions become persistent memories. Short-term
|
|
396
|
+
consolidates into long-term. Stances drift.
|
|
397
|
+
Relationships shift on shared experience.
|
|
439
398
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
const scenario = await compileScenario(worldJson);
|
|
444
|
-
const output = await runSimulation(actor, [], {
|
|
445
|
-
scenario,
|
|
446
|
-
maxTurns: 4, // fewer turns = linear cost reduction
|
|
447
|
-
seed: 42,
|
|
448
|
-
costPreset: 'economy', // ~5-10× cheaper than 'quality' on OpenAI
|
|
449
|
-
});
|
|
399
|
+
9. PERSONALITY DRIFT HEXACO traits shift through actor pull, role activation,
|
|
400
|
+
and outcome reinforcement. The commander drifts alongside
|
|
401
|
+
their agents using peer-reviewed outcome-pull tables.
|
|
450
402
|
```
|
|
451
403
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
Explicit `models` entries always win over the preset so you can mix and match. `{ costPreset: 'economy', models: { departments: 'gpt-5.4' } }` gives you cheap everything except departments. Override any single role: `{ models: { judge: 'gpt-5.4' } }` pays for stricter forge review without raising every other tier.
|
|
455
|
-
|
|
456
|
-
The orchestrator's `runSimulation()` returns a `cost` field with token counts, LLM call counts, and USD spend aggregated from every tracked call (director, departments, commander, judge, agent reactions). The dashboard StatsBar shows this live.
|
|
404
|
+
Every structured LLM call (director events, department reports, commander decisions, reactions, verdict, promotions) runs through Zod schema validation with automatic retry-with-feedback on failure. Schemas live under [`src/runtime/schemas/`](src/runtime/schemas/). Two wrappers (`generateValidatedObject` for one-shot, `sendAndValidate` for session-aware) preserve conversation memory while enforcing validation discipline.
|
|
457
405
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
Every LLM call site on both providers routes its stable system prefix through a `cacheBreakpoint: true` block (director instructions, department prompts, reaction batches, compile-time hook generators). On Anthropic, turn 2+ of every run serves the shared prefix from the provider's prompt cache at 0.1× input cost. On OpenAI, any prompt ≥ 1024 tokens auto-caches. The `cost.caches` field reports read / creation tokens and USD saved per run, and `/retry-stats` rolls the numbers up across the last 100 runs so you can verify the cache is actually hitting. No configuration required. The `system: Array<{ text; cacheBreakpoint }>` shape is built into the validated-call wrappers in `src/engine/compiler/llm-invocations/` and `src/runtime/llm-invocations/`.
|
|
406
|
+
---
|
|
461
407
|
|
|
462
|
-
##
|
|
408
|
+
## Seed enrichment and citations
|
|
463
409
|
|
|
464
|
-
|
|
410
|
+
Real source material grounds the scenario all the way through to department reports.
|
|
465
411
|
|
|
466
412
|
```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'
|
|
413
|
+
paracosm compile scenarios/lunar.json --seed-text "$(cat ./papers/iss-radiation.md)"
|
|
414
|
+
paracosm compile scenarios/lunar.json --seed-url https://ntrs.nasa.gov/citations/20210018970
|
|
478
415
|
```
|
|
479
416
|
|
|
480
|
-
The
|
|
481
|
-
|
|
482
|
-
## Programmatic API
|
|
483
|
-
|
|
484
|
-
Everything the dashboard does is also available as library calls. The exports fall into five buckets:
|
|
485
|
-
|
|
486
|
-
| Import | Surface |
|
|
487
|
-
|--------|---------|
|
|
488
|
-
| `paracosm/compiler` | `compileScenario`, `ingestSeed`, `ingestFromUrl`, type `CompileOptions` |
|
|
489
|
-
| `paracosm/runtime` | `runSimulation`, `runBatch`, `EventDirector`, `generateAgentReactions`, `buildEventSummary`, `createParacosmClient`, memory helpers, type `CostPreset` |
|
|
490
|
-
| `paracosm` | `createParacosmClient`, `ProviderKeyMissingError`, `SeededRng`, `SimulationKernel`, all `Scenario*` types |
|
|
491
|
-
| `paracosm/core` | Kernel state types (`Agent`, `WorldState`, `HexacoProfile`, …) |
|
|
492
|
-
| `paracosm/mars`, `paracosm/lunar` | Pre-built `ScenarioPackage` constants to use or fork |
|
|
417
|
+
The pipeline runs eight steps: extract topics and search queries from the seed, fan out to Firecrawl / Tavily / Serper / Brave in parallel, dedup and rerank with Cohere `rerank-v3.5`, assemble a `KnowledgeBundle`, ingest into an AgentOS `AgentMemory.sqlite()` store, recall per event during runtime, inject `[claim](url)` markdown into department prompts, and surface citations in the dashboard's Reports tab. The seed bundle is cached separately from the hook cache, keyed on the seed signature, so the same URL never re-extracts.
|
|
493
418
|
|
|
494
|
-
|
|
419
|
+
---
|
|
495
420
|
|
|
496
|
-
|
|
421
|
+
## Built-in scenarios
|
|
497
422
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
provider: 'openai',
|
|
503
|
-
costPreset: 'economy', // cheap default for iteration
|
|
504
|
-
models: { departments: 'gpt-5.4' }, // but pin departments to flagship
|
|
505
|
-
compilerProvider: 'anthropic', // compile on a different provider if you want
|
|
506
|
-
compilerModel: 'claude-sonnet-4-6',
|
|
507
|
-
});
|
|
423
|
+
| Scenario | Description |
|
|
424
|
+
|---------------|-------------------------------------------------------------------------------------------------------------------|
|
|
425
|
+
| Mars Genesis | 100 colonists, 6 turns over 48 years. 5 departments, emergent dust storms, water crises, first Marsborn generation. |
|
|
426
|
+
| Lunar Outpost | 50-person crew at the south pole. Mining, life support, comms. Regolith toxicity, 1/6g atrophy. |
|
|
508
427
|
|
|
509
|
-
|
|
510
|
-
const out = await client.runSimulation(actor, [], { maxTurns: 6, seed: 42 });
|
|
428
|
+
Both ship as `paracosm/mars` and `paracosm/lunar` exports and serve as references for building custom scenarios.
|
|
511
429
|
|
|
512
|
-
|
|
513
|
-
const gold = await client.runSimulation(actor, [], {
|
|
514
|
-
maxTurns: 8, seed: 42, costPreset: 'quality',
|
|
515
|
-
});
|
|
516
|
-
|
|
517
|
-
// Batch 20 ablations with shared config:
|
|
518
|
-
const manifest = await client.runBatch({
|
|
519
|
-
scenarios: [scenarioA, scenarioB], actors, turns: 6, seed: 42, maxConcurrency: 4,
|
|
520
|
-
});
|
|
521
|
-
```
|
|
430
|
+
---
|
|
522
431
|
|
|
523
|
-
|
|
432
|
+
## Programmatic API
|
|
524
433
|
|
|
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 |
|
|
434
|
+
| Import | Surface |
|
|
435
|
+
|-------------------------------------|-----------------------------------------------------------------------------------------------------------|
|
|
436
|
+
| `paracosm/compiler` | `compileScenario`, `ingestSeed`, `ingestFromUrl`, `CompileOptions` |
|
|
437
|
+
| `paracosm/runtime` | `runSimulation`, `runBatch`, `EventDirector`, `generateAgentReactions`, `buildEventSummary`, memory helpers |
|
|
438
|
+
| `paracosm` | `createParacosmClient`, `ProviderKeyMissingError`, `SeededRng`, `SimulationKernel`, all `Scenario*` types |
|
|
439
|
+
| `paracosm/core` | Kernel state types: `Agent`, `WorldState`, `HexacoProfile` |
|
|
440
|
+
| `paracosm/world-model` | `WorldModel` for fork / replay / snapshot use cases |
|
|
441
|
+
| `paracosm/digital-twin` | `DigitalTwin` alias plus `simulateIntervention` sugar |
|
|
442
|
+
| `paracosm/mars`, `paracosm/lunar` | Pre-built `ScenarioPackage` constants |
|
|
536
443
|
|
|
537
|
-
|
|
444
|
+
`createParacosmClient` pins `provider`, `costPreset`, per-role `models`, and compile-time options once, then hands back `runSimulation`, `runBatch`, and `compileScenario` methods that inherit those defaults. Per-call overrides still win, merged at the per-role level so `models: { departments: 'gpt-5.4' }` at the client and `models: { judge: 'gpt-5.4' }` at the call combine to pin both. Env vars feed the same defaults; explicit args win over env, env wins over library defaults.
|
|
538
445
|
|
|
539
446
|
```bash
|
|
540
|
-
# Zero-code config for hosting / CI:
|
|
541
447
|
PARACOSM_PROVIDER=anthropic \
|
|
542
448
|
PARACOSM_COST_PRESET=economy \
|
|
543
449
|
PARACOSM_MODEL_DEPARTMENTS=claude-sonnet-4-6 \
|
|
544
450
|
node my-runner.js
|
|
545
451
|
```
|
|
546
452
|
|
|
547
|
-
|
|
548
|
-
// my-runner.js reads them all implicitly:
|
|
549
|
-
const client = createParacosmClient(); // no args, pulls from env
|
|
550
|
-
```
|
|
551
|
-
|
|
552
|
-
Direct `runSimulation(...)` / `runBatch(...)` / `compileScenario(...)` calls without a client are still fully supported. The client is purely additive for multi-run workflows.
|
|
453
|
+
`runSimulation` accepts an `AbortSignal` and short-circuits at the next turn boundary on cancel, returning the partial result with `output.aborted === true`. Custom events at fixed turns ride the same options bag (`customEvents: [{ turn: 3, title, description }]`). Provider-key failures throw `ProviderKeyMissingError` once at the top of the run instead of retrying silently per call.
|
|
553
454
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
```typescript
|
|
557
|
-
import { runBatch } from 'paracosm/runtime';
|
|
558
|
-
import { marsScenario, lunarScenario } from 'paracosm';
|
|
559
|
-
|
|
560
|
-
const manifest = await runBatch({
|
|
561
|
-
scenarios: [marsScenario, lunarScenario],
|
|
562
|
-
actors, // ActorConfig[], same shape as runSimulation
|
|
563
|
-
turns: 6,
|
|
564
|
-
seed: 950,
|
|
565
|
-
maxConcurrency: 2, // how many sims to run in parallel
|
|
566
|
-
provider: 'anthropic',
|
|
567
|
-
});
|
|
568
|
-
|
|
569
|
-
// manifest.results[i] carries { scenarioId, actor, fingerprint, output, duration }
|
|
570
|
-
// manifest.timestamp + manifest.config is a reproducible audit trail
|
|
571
|
-
```
|
|
572
|
-
|
|
573
|
-
### Seed ingestion from a URL or inline text
|
|
574
|
-
|
|
575
|
-
The compiler grounds agents in real sources. Pass `seedText` for inline markdown / PDFs you already have, or `seedUrl` to let Firecrawl extract clean markdown from any public page. The bundle is cached separately from the hook cache, keyed on the seed signature, so the same URL never re-extracts.
|
|
576
|
-
|
|
577
|
-
```typescript
|
|
578
|
-
const scenario = await compileScenario(worldJson, {
|
|
579
|
-
seedUrl: 'https://ntrs.nasa.gov/citations/20210018970',
|
|
580
|
-
webSearch: true, // also fan out to Tavily/Serper/Brave for more citations
|
|
581
|
-
maxSearches: 5,
|
|
582
|
-
});
|
|
583
|
-
// Every department prompt, Event Director batch, and report.citations[] entry
|
|
584
|
-
// at runtime will draw from this bundle.
|
|
585
|
-
```
|
|
586
|
-
|
|
587
|
-
### Cancellation via AbortSignal
|
|
588
|
-
|
|
589
|
-
The server wires this to a cancel-on-disconnect watchdog; any programmatic consumer can do the same. When `.aborted` flips to true, the turn loop short-circuits at the next turn boundary, emits a `sim_aborted` event, and returns the partial result accumulated so far with `output.aborted === true`.
|
|
590
|
-
|
|
591
|
-
```typescript
|
|
592
|
-
const ctrl = new AbortController();
|
|
593
|
-
setTimeout(() => ctrl.abort(), 60_000); // kill after 60s wall time
|
|
594
|
-
|
|
595
|
-
const output = await runSimulation(actor, [], {
|
|
596
|
-
scenario, maxTurns: 8, seed: 42,
|
|
597
|
-
signal: ctrl.signal,
|
|
598
|
-
});
|
|
599
|
-
|
|
600
|
-
if (output.aborted) console.log('partial result; turns completed:', output.turnArtifacts.length);
|
|
601
|
-
```
|
|
602
|
-
|
|
603
|
-
### Custom events injected at specific turns
|
|
604
|
-
|
|
605
|
-
When you want a scripted event at a fixed turn (smoke tests, pedagogical demos, reproducing a scenario from a paper), supply `customEvents`:
|
|
606
|
-
|
|
607
|
-
```typescript
|
|
608
|
-
await runSimulation(actor, [], {
|
|
609
|
-
scenario, maxTurns: 8, seed: 42,
|
|
610
|
-
customEvents: [
|
|
611
|
-
{ turn: 3, title: 'Dust storm', description: 'A 72-hour planetary dust storm cuts solar output by 80%.' },
|
|
612
|
-
{ turn: 6, title: 'Supply drop', description: 'Earth relief mission delivers 3 months of food reserves.' },
|
|
613
|
-
],
|
|
614
|
-
});
|
|
615
|
-
```
|
|
616
|
-
|
|
617
|
-
### Error handling
|
|
618
|
-
|
|
619
|
-
```typescript
|
|
620
|
-
import { runSimulation, ProviderKeyMissingError } from 'paracosm';
|
|
621
|
-
|
|
622
|
-
try {
|
|
623
|
-
const output = await runSimulation(actor, [], { scenario, maxTurns: 8, seed: 42 });
|
|
624
|
-
if (output.providerError) {
|
|
625
|
-
// Terminal provider failure (invalid key, quota exhausted). The run
|
|
626
|
-
// aborted mid-way. turnArtifacts / finalState are partial.
|
|
627
|
-
console.error(output.providerError.kind, // 'auth' | 'quota' | 'rate_limit' | 'network' | 'unknown'
|
|
628
|
-
output.providerError.provider,
|
|
629
|
-
output.providerError.message,
|
|
630
|
-
output.providerError.actionUrl);
|
|
631
|
-
}
|
|
632
|
-
} catch (err) {
|
|
633
|
-
if (err instanceof ProviderKeyMissingError) {
|
|
634
|
-
console.error('set OPENAI_API_KEY or ANTHROPIC_API_KEY before running');
|
|
635
|
-
process.exit(1);
|
|
636
|
-
}
|
|
637
|
-
throw err;
|
|
638
|
-
}
|
|
639
|
-
```
|
|
640
|
-
|
|
641
|
-
The resolver inspects `process.env` once up front, so a missing key fails loudly at the top of the run instead of retrying silently on every LLM call.
|
|
642
|
-
|
|
643
|
-
### Where run output lands
|
|
644
|
-
|
|
645
|
-
Every finished run writes a JSON snapshot to `<cwd>/output/v3-<archetype>-<timestamp>.json`: the same payload `runSimulation` returns, persisted so you can diff runs, reload them into the dashboard, or feed them into downstream tooling. Set `PARACOSM_OUTPUT_DIR` to redirect (absolute path, or relative to cwd). The directory is created on first write if it doesn't exist.
|
|
646
|
-
|
|
647
|
-
```bash
|
|
648
|
-
# Default: ./output/v3-the-pragmatist-2026-04-21T16-02-41-550Z.json
|
|
649
|
-
bun src/index.ts
|
|
650
|
-
|
|
651
|
-
# Custom location
|
|
652
|
-
PARACOSM_OUTPUT_DIR=./artifacts/run-001 bun src/index.ts
|
|
653
|
-
```
|
|
455
|
+
---
|
|
654
456
|
|
|
655
|
-
##
|
|
457
|
+
## HTTP API: `POST /simulate`
|
|
656
458
|
|
|
657
|
-
|
|
459
|
+
For non-SSE consumers (curl, Python integrations, third-party dashboards) a plain request-response endpoint runs a simulation in one call. Gated behind `PARACOSM_ENABLE_SIMULATE_ENDPOINT=true` so the hosted demo's SSE-first path stays the default.
|
|
658
460
|
|
|
659
461
|
```bash
|
|
660
|
-
|
|
462
|
+
export PARACOSM_ENABLE_SIMULATE_ENDPOINT=true
|
|
661
463
|
paracosm dashboard
|
|
662
464
|
|
|
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' \
|
|
465
|
+
curl -s -X POST http://localhost:3456/simulate \
|
|
691
466
|
-H 'Content-Type: application/json' \
|
|
692
|
-
-
|
|
693
|
-
|
|
467
|
+
-H 'X-Anthropic-Key: sk-ant-...' \
|
|
468
|
+
-d @run.json | jq '.artifact.fingerprint'
|
|
694
469
|
```
|
|
695
470
|
|
|
696
|
-
The
|
|
471
|
+
The body accepts either a pre-compiled `ScenarioPackage` or a raw scenario draft (auto-compiled server-side with optional `options.seedText` / `options.seedUrl` grounding). The response is `{ artifact, scenario, durationMs }`. Rate limiting and the 5 MiB body cap match `/setup`.
|
|
697
472
|
|
|
698
|
-
|
|
473
|
+
---
|
|
699
474
|
|
|
700
|
-
##
|
|
475
|
+
## Storage
|
|
701
476
|
|
|
702
|
-
|
|
477
|
+
Run history (Library tab) and replayable session blobs (Load menu) persist through [`@framers/sql-storage-adapter`](https://github.com/framersai/sql-storage-adapter). The same code paths run unchanged against SQLite, Postgres, sql.js, and IndexedDB; switching backends is one env var.
|
|
703
478
|
|
|
704
479
|
```bash
|
|
705
|
-
#
|
|
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
|
|
480
|
+
paracosm dashboard # SQLite, ./data/runs.db
|
|
481
|
+
STORAGE_ADAPTER=postgres DATABASE_URL=... paracosm dashboard # Postgres in production
|
|
482
|
+
STORAGE_ADAPTER=sqljs paracosm dashboard # pure-WASM fallback
|
|
712
483
|
```
|
|
713
484
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
1. **Extract.** LLM reads the seed, returns `topics`, `facts`, `searchQueries`, `crisisCategories`.
|
|
717
|
-
2. **Search.** AgentOS `WebSearchService` queries Firecrawl, Tavily, Serper, and Brave in parallel. Results pass through semantic dedup, RRF fusion, and (with `COHERE_API_KEY`) Cohere `rerank-v3.5` neural reranking.
|
|
718
|
-
3. **Assemble.** Extracted facts plus search hits become a `KnowledgeBundle` with `topics[].canonicalFacts[]` and `categoryMapping`.
|
|
719
|
-
4. **Ingest.** At runtime, `initResearchMemory` writes every citation into an AgentOS `AgentMemory.sqlite()` store keyed by topic tags.
|
|
720
|
-
5. **Recall.** For each event, `recallResearch(query, keywords)` runs semantic recall over the memory store. Live web search fills in when memory is sparse.
|
|
721
|
-
6. **Inject.** Citations land in each department's prompt under `RESEARCH:` as `[claim](url)` markdown links.
|
|
722
|
-
7. **Surface.** Department reports return `citations[]`. The orchestrator guarantees provenance: when the LLM omits citations, the research packet is auto-attached so the report always carries the same sources the agent saw.
|
|
723
|
-
8. **Render.** The dashboard "Reports" tab renders citations as clickable links with optional DOIs.
|
|
485
|
+
`runs` and `sessions` schemas bootstrap idempotently on first boot. Legacy v0.7 databases auto-migrate `leader_*` columns to `actor_*` in place via `ALTER TABLE RENAME COLUMN`.
|
|
724
486
|
|
|
725
|
-
|
|
487
|
+
### Admin endpoints
|
|
726
488
|
|
|
727
|
-
|
|
489
|
+
Two destructive admin routes ship with the dashboard, gated by **two** env vars on the server:
|
|
728
490
|
|
|
729
|
-
|
|
491
|
+
| Env var | Purpose |
|
|
492
|
+
|-----------------------|------------------------------------------------------------------------------------------------------|
|
|
493
|
+
| `ADMIN_WRITE=true` | Master switch. Off, every `/admin/*` route returns `403`. |
|
|
494
|
+
| `ADMIN_TOKEN=<secret>`| Per-request bearer token in `X-Admin-Token`. With `ADMIN_WRITE=true` and no token, the server returns `503` (fail-closed).|
|
|
730
495
|
|
|
731
|
-
|
|
732
|
-
|-------|------|---------|
|
|
733
|
-
| `hexaco` | openness, conscientiousness, extraversion, agreeableness, emotionality, honesty-humility | Human actors: CEOs, captains, governors, councils, military commanders |
|
|
734
|
-
| `ai-agent` | exploration, verification-rigor, deference, risk-tolerance, transparency, instruction-following | AI-system actors: frontier-lab release directors, autonomous coordinators, alignment-eval substrates |
|
|
496
|
+
`POST /admin/sessions/save` snapshots the current event buffer as a replayable session. `POST /admin/data/wipe` clears `runs.db`, `sessions.db`, on-disk artifact JSONs, and the SSE event buffer. The dashboard's Wipe All control prompts for the token on first use and stores it in `localStorage`.
|
|
735
497
|
|
|
736
|
-
|
|
737
|
-
import { runSimulation, hexacoModel, aiAgentModel, traitModelRegistry } from 'paracosm';
|
|
738
|
-
|
|
739
|
-
// Human actor (legacy hexaco field, still works)
|
|
740
|
-
const captain = {
|
|
741
|
-
name: 'Captain Reyes', archetype: 'Pragmatist', unit: 'Station Alpha',
|
|
742
|
-
hexaco: { openness: 0.4, conscientiousness: 0.9, extraversion: 0.3,
|
|
743
|
-
agreeableness: 0.6, emotionality: 0.5, honestyHumility: 0.8 },
|
|
744
|
-
instructions: 'lead by protocol',
|
|
745
|
-
};
|
|
746
|
-
|
|
747
|
-
// AI-system actor (new traitProfile slot)
|
|
748
|
-
const releaseDirector = {
|
|
749
|
-
name: 'Atlas-Bot Release Director',
|
|
750
|
-
archetype: 'Aggressive AI Release Optimizer',
|
|
751
|
-
unit: 'Frontier Lab',
|
|
752
|
-
// Legacy back-compat hexaco field is still required by the v0.7
|
|
753
|
-
// schema; supply a representative HEXACO snapshot of the AI-system
|
|
754
|
-
// archetype's analogous human personality. Removal scheduled 0.9.0.
|
|
755
|
-
hexaco: { openness: 0.6, conscientiousness: 0.3, extraversion: 0.5,
|
|
756
|
-
agreeableness: 0.3, emotionality: 0.2, honestyHumility: 0.3 },
|
|
757
|
-
traitProfile: {
|
|
758
|
-
modelId: 'ai-agent',
|
|
759
|
-
traits: {
|
|
760
|
-
exploration: 0.85,
|
|
761
|
-
'verification-rigor': 0.2,
|
|
762
|
-
deference: 0.2,
|
|
763
|
-
'risk-tolerance': 0.85,
|
|
764
|
-
transparency: 0.4,
|
|
765
|
-
'instruction-following': 0.4,
|
|
766
|
-
},
|
|
767
|
-
},
|
|
768
|
-
instructions: 'You are a frontier AI lab release director. You weight time-to-market...',
|
|
769
|
-
};
|
|
770
|
-
|
|
771
|
-
// Both run through the same runSimulation; the orchestrator's
|
|
772
|
-
// normalizeActorConfig resolves either shape.
|
|
773
|
-
await runSimulation(captain, [], { scenario, maxTurns: 6, seed: 42 });
|
|
774
|
-
await runSimulation(releaseDirector, [], { scenario, maxTurns: 6, seed: 42 });
|
|
775
|
-
```
|
|
776
|
-
|
|
777
|
-
Run [`scripts/cookbook-ai-agent.ts`](scripts/cookbook-ai-agent.ts) to capture an end-to-end ai-agent run with full input + output JSON. The captured fingerprint shifts from `riskBehavior:steady` (HEXACO Dr. Sora Wen actor) to `riskBehavior:bold` (ai-agent Atlas-Bot actor) on identical scenario + seed; decision rationale clearly tracks the ai-agent profile.
|
|
778
|
-
|
|
779
|
-
Full surface: [`docs/cookbook.md#pluggable-trait-models-ai-agent-end-to-end`](docs/cookbook.md). Spec: [`docs/superpowers/specs/2026-04-26-trait-model-generalization-design.md`](docs/superpowers/specs/2026-04-26-trait-model-generalization-design.md).
|
|
780
|
-
|
|
781
|
-
## Built-in Scenarios
|
|
782
|
-
|
|
783
|
-
| Scenario | Description |
|
|
784
|
-
|----------|-------------|
|
|
785
|
-
| **Mars Genesis** | 100 colonists, 6 turns over 48 years. 5 departments, emergent dust storms, water crises, first Marsborn generation. |
|
|
786
|
-
| **Lunar Outpost** | 50-person crew at the south pole. Mining, life support, communications. Regolith toxicity, 1/6g atrophy. |
|
|
787
|
-
|
|
788
|
-
Both are included as `paracosm/mars` and `paracosm/lunar` exports. Use them as references for building your own scenarios.
|
|
789
|
-
|
|
790
|
-
### Any domain, any time unit
|
|
791
|
-
|
|
792
|
-
The engine is time-unit agnostic. `setup.defaultStartTime` and `setup.defaultTimePerTurn` are plain numbers; whether they mean years, quarters, hours, or ticks is decided by your `labels.timeUnitNoun` pair. The kernel, hooks, and dashboard labels pick that up consistently. Four worked shapes:
|
|
793
|
-
|
|
794
|
-
```jsonc
|
|
795
|
-
// A) Corporate strategy: quarterly cadence over 3 years
|
|
796
|
-
{
|
|
797
|
-
"id": "corp-strategy",
|
|
798
|
-
"labels": {
|
|
799
|
-
"name": "Q-Scope Corp",
|
|
800
|
-
"populationNoun": "employees",
|
|
801
|
-
"settlementNoun": "company",
|
|
802
|
-
"timeUnitNoun": "quarter",
|
|
803
|
-
"timeUnitNounPlural": "quarters"
|
|
804
|
-
},
|
|
805
|
-
"setup": { "defaultTurns": 12, "defaultStartTime": 1, "defaultTimePerTurn": 1, "defaultPopulation": 40 }
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
// B) Submarine patrol: daily cadence over six months
|
|
809
|
-
{
|
|
810
|
-
"id": "submarine-daily",
|
|
811
|
-
"labels": {
|
|
812
|
-
"name": "USS Longwatch",
|
|
813
|
-
"populationNoun": "crew",
|
|
814
|
-
"settlementNoun": "submarine",
|
|
815
|
-
"timeUnitNoun": "day",
|
|
816
|
-
"timeUnitNounPlural": "days"
|
|
817
|
-
},
|
|
818
|
-
"setup": { "defaultTurns": 24, "defaultStartTime": 1, "defaultTimePerTurn": 7, "defaultPopulation": 60 }
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
// C) Benchmark arena: abstract tick cadence
|
|
822
|
-
{
|
|
823
|
-
"id": "arena-session",
|
|
824
|
-
"labels": {
|
|
825
|
-
"name": "Latency Arena",
|
|
826
|
-
"populationNoun": "agents",
|
|
827
|
-
"settlementNoun": "session",
|
|
828
|
-
"timeUnitNoun": "tick",
|
|
829
|
-
"timeUnitNounPlural": "ticks"
|
|
830
|
-
},
|
|
831
|
-
"setup": { "defaultTurns": 50, "defaultStartTime": 0, "defaultTimePerTurn": 1, "defaultPopulation": 8 }
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
// D) Mars Genesis: year cadence (the built-in reference)
|
|
835
|
-
{
|
|
836
|
-
"id": "mars-genesis",
|
|
837
|
-
"labels": {
|
|
838
|
-
"name": "Mars Genesis",
|
|
839
|
-
"populationNoun": "colonists",
|
|
840
|
-
"settlementNoun": "colony",
|
|
841
|
-
"timeUnitNoun": "year",
|
|
842
|
-
"timeUnitNounPlural": "years"
|
|
843
|
-
},
|
|
844
|
-
"setup": { "defaultTurns": 6, "defaultSeed": 950, "defaultStartTime": 2035, "defaultTimePerTurn": 8 }
|
|
845
|
-
}
|
|
846
|
-
```
|
|
847
|
-
|
|
848
|
-
All four run through the same `compileScenario()` + `runSimulation()` pipeline. The progression hook receives `ctx.time` and `ctx.timeDelta` in whatever unit the scenario declared. The dashboard's turn header reads `"Quarter 5"`, `"Day 22"`, `"Tick 30"`, or `"Year 2043"` straight from `labels.timeUnitNoun`.
|
|
849
|
-
|
|
850
|
-
If you omit `timeUnitNoun`, paracosm falls back to `tick` / `ticks`. The built-in `paracosm/mars` and `paracosm/lunar` exports set theirs to `year` / `years` explicitly so Mars narrative reads naturally.
|
|
851
|
-
|
|
852
|
-
## How a Simulation Works
|
|
853
|
-
|
|
854
|
-
### Turn 0: Promotions
|
|
855
|
-
|
|
856
|
-
The commander evaluates the full agent roster and promotes department heads. Each department (Medical, Engineering, Agriculture, etc.) gets a head chosen by the commander based on personality fit, specialization, and experience. A high-openness commander picks unconventional candidates. A high-conscientiousness commander picks by-the-book specialists.
|
|
857
|
-
|
|
858
|
-
This matters because promoted agents become the department analysis LLM agents for the rest of the simulation. Their personality colors every analysis they produce, which shapes the information the commander sees, which shapes decisions. The commander never directly analyzes events. They only read department reports and decide.
|
|
859
|
-
|
|
860
|
-
### Turns 1-N: The Turn Loop
|
|
861
|
-
|
|
862
|
-
Each turn represents a configurable time period. Mars and Lunar tick in years (Mars at 8 per turn, Lunar at 4). A quarterly corporate scenario ticks in quarters. A daily submarine scenario ticks in days. The cadence is whatever `setup.defaultTimePerTurn` plus `labels.timeUnitNoun` declare. Every turn follows this pipeline:
|
|
863
|
-
|
|
864
|
-
```
|
|
865
|
-
1. EVENT DIRECTOR Reads world state, prior decisions, tool intelligence.
|
|
866
|
-
Generates an event that targets actual weaknesses.
|
|
867
|
-
|
|
868
|
-
2. KERNEL ADVANCE Deterministic time progression: births, deaths, aging,
|
|
869
|
-
health decay, resource consumption. Seeded PRNG.
|
|
870
|
-
|
|
871
|
-
3. DEPARTMENT ANALYSIS All active departments analyze the event in parallel.
|
|
872
|
-
Each department head (promoted at turn 0) uses their
|
|
873
|
-
personality and tools. Departments can forge new
|
|
874
|
-
computational tools at runtime (hardened node:vm, LLM-judged).
|
|
875
|
-
|
|
876
|
-
4. COMMANDER DECISION Reads all department reports. Selects an option.
|
|
877
|
-
Personality shapes risk tolerance and priority weighting.
|
|
878
|
-
|
|
879
|
-
5. OUTCOME Deterministic kernel classifies the outcome (risky success,
|
|
880
|
-
risky failure, safe success, safe failure) based on the
|
|
881
|
-
option chosen, probability, and colony state.
|
|
882
|
-
|
|
883
|
-
6. EFFECTS Kernel applies colony deltas (population, morale, food,
|
|
884
|
-
power, etc.) based on outcome and event category.
|
|
885
|
-
|
|
886
|
-
7. AGENT REACTIONS All alive agents (~100) react in parallel using a cheap
|
|
887
|
-
model. Each reaction is shaped by the agent's personality,
|
|
888
|
-
health, relationships, and accumulated memories.
|
|
889
|
-
|
|
890
|
-
8. MEMORY Reactions become persistent memories. Short-term memories
|
|
891
|
-
consolidate into long-term beliefs. Stances drift.
|
|
892
|
-
Relationships shift based on shared experiences.
|
|
893
|
-
|
|
894
|
-
9. PERSONALITY DRIFT HEXACO traits shift through actor pull, role activation,
|
|
895
|
-
and outcome reinforcement. All six traits drift
|
|
896
|
-
(openness, conscientiousness, extraversion,
|
|
897
|
-
agreeableness, emotionality, honesty-humility)
|
|
898
|
-
with peer-reviewed outcome-pull tables. The
|
|
899
|
-
commander drifts alongside their agents.
|
|
900
|
-
```
|
|
901
|
-
|
|
902
|
-
Every structured LLM call in this pipeline (director events, department reports, commander decisions, reactions, verdict, promotions) runs through Zod schema validation with automatic retry-with-feedback on validation failure. Schemas live in [`src/runtime/schemas/`](src/runtime/schemas/); two wrappers (`generateValidatedObject` one-shot, `sendAndValidate` session-aware) preserve conversation memory while adding validation discipline. See [ARCHITECTURE.md#llm-reliability](docs/ARCHITECTURE.md#llm-reliability).
|
|
903
|
-
|
|
904
|
-
### What Department Heads Do
|
|
905
|
-
|
|
906
|
-
Department heads are LLM agents with domain-specific instructions, access to research citations, and the ability to forge computational tools. When a medical crisis hits, the Chief Medical Officer doesn't just say "this is bad." They:
|
|
907
|
-
|
|
908
|
-
- Analyze the event against their department's research knowledge
|
|
909
|
-
- Cite relevant scientific literature (DOI-linked)
|
|
910
|
-
- Forge computational tools (e.g., a radiation dose calculator) in a hardened node:vm sandbox
|
|
911
|
-
- An LLM judge reviews each tool for safety and correctness
|
|
912
|
-
- Produce a structured report: summary, risks, recommended actions, proposed colony state changes
|
|
913
|
-
|
|
914
|
-
The commander sees all department reports and makes a decision. Different commanders weight different departments' advice differently based on personality.
|
|
498
|
+
---
|
|
915
499
|
|
|
916
500
|
## Architecture
|
|
917
501
|
|
|
918
502
|
```
|
|
919
503
|
src/
|
|
920
504
|
engine/ the npm package
|
|
921
|
-
core/ deterministic kernel
|
|
922
|
-
compiler/ scenario draft + source grounding
|
|
505
|
+
core/ deterministic kernel: RNG, state, progression, personality drift
|
|
506
|
+
compiler/ scenario draft + source grounding to ScenarioPackage compiler
|
|
923
507
|
mars/ Mars Genesis scenario
|
|
924
508
|
lunar/ Lunar Outpost scenario
|
|
925
509
|
|
|
926
510
|
runtime/ orchestration (not exported)
|
|
927
|
-
orchestrator
|
|
928
|
-
director
|
|
929
|
-
departments
|
|
930
|
-
agent-reactions
|
|
931
|
-
agent-memory
|
|
932
|
-
chat-agents
|
|
933
|
-
schemas/
|
|
934
|
-
llm-invocations/
|
|
935
|
-
hexaco-cues/
|
|
511
|
+
orchestrator turn pipeline: director, kernel, departments, commander
|
|
512
|
+
director emergent event generation from simulation state
|
|
513
|
+
departments parallel department analysis agents
|
|
514
|
+
agent-reactions batched agent reactions, 10 agents per LLM call
|
|
515
|
+
agent-memory persistent memory, consolidation, stance drift
|
|
516
|
+
chat-agents post-simulation conversational agents
|
|
517
|
+
schemas/ Zod schemas for every structured LLM call
|
|
518
|
+
llm-invocations/ generateValidatedObject + sendAndValidate wrappers
|
|
519
|
+
hexaco-cues/ trajectory and reaction cue translation helpers
|
|
936
520
|
|
|
937
521
|
cli/ server + dashboard (not exported)
|
|
938
522
|
serve.ts HTTP + SSE server
|
|
939
|
-
dashboard/ React
|
|
523
|
+
dashboard/ React + Vite live visualization, cellular automata viz
|
|
940
524
|
```
|
|
941
525
|
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
## Package Exports
|
|
945
|
-
|
|
946
|
-
| Import | What |
|
|
947
|
-
|--------|------|
|
|
948
|
-
| `paracosm` | Engine types, registries, `SimulationKernel`, `SeededRng`, scenario packages, `ProviderKeyMissingError` |
|
|
949
|
-
| `paracosm/compiler` | `compileScenario()`, `ingestSeed()`, `ingestFromUrl()` |
|
|
950
|
-
| `paracosm/runtime` | `runSimulation()`, `runBatch()`, `EventDirector`, `generateAgentReactions()`, `buildEventSummary()`, memory helpers |
|
|
951
|
-
| `paracosm/mars` | Mars Genesis `ScenarioPackage` |
|
|
952
|
-
| `paracosm/lunar` | Lunar Outpost `ScenarioPackage` |
|
|
953
|
-
| `paracosm/core` | Kernel state types (`Agent`, `WorldState`, `HexacoProfile`) |
|
|
954
|
-
|
|
955
|
-
## Built on AgentOS
|
|
526
|
+
The engine owns the chassis. The scenario owns the domain. The kernel handles state, time, randomness, and invariants. The scenario handles event categories, department instructions, progression hooks, and research citations. The orchestrator connects them.
|
|
956
527
|
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
| AgentOS API | Used For |
|
|
960
|
-
|------------|----------|
|
|
961
|
-
| `agent()` | Commander, department, and Event Director agents |
|
|
962
|
-
| `generateText()` | LLM calls for event generation and tool evaluation |
|
|
963
|
-
| `EmergentCapabilityEngine` | Runtime tool forging in a hardened node:vm sandbox |
|
|
964
|
-
| `EmergentJudge` | LLM-as-judge safety review of forged tools |
|
|
528
|
+
---
|
|
965
529
|
|
|
966
|
-
##
|
|
530
|
+
## Background
|
|
967
531
|
|
|
968
|
-
|
|
969
|
-
|-|-|
|
|
970
|
-
| Live Demo | [paracosm.agentos.sh/sim](https://paracosm.agentos.sh/sim) |
|
|
971
|
-
| Landing Page | [paracosm.agentos.sh](https://paracosm.agentos.sh) |
|
|
972
|
-
| API Docs | [paracosm.agentos.sh/docs](https://paracosm.agentos.sh/docs) |
|
|
973
|
-
| npm | [npmjs.com/package/paracosm](https://www.npmjs.com/package/paracosm) |
|
|
974
|
-
| AgentOS | [agentos.sh](https://agentos.sh) |
|
|
975
|
-
| Discord | [wilds.ai/discord](https://wilds.ai/discord) |
|
|
532
|
+
Paracosm sits in the structured world model lineage ([Xing 2025](https://arxiv.org/abs/2507.05169), [ACM CSUR 2025](https://dl.acm.org/doi/full/10.1145/3746449)). The LLM-world-model implementation closest to it is [Yang et al, 2026](https://openreview.net/forum?id=XmYCERErcD), which evaluates LLM-based world models through policy verification, action proposal, and policy planning. Full taxonomy mapping in [`docs/positioning/world-model-mapping.md`](docs/positioning/world-model-mapping.md).
|
|
976
533
|
|
|
977
|
-
|
|
534
|
+
---
|
|
978
535
|
|
|
979
|
-
|
|
536
|
+
## Built on AgentOS
|
|
980
537
|
|
|
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 |
|
|
538
|
+
> "You are not the kind of dead that can be brought back."
|
|
539
|
+
>
|
|
540
|
+
> *SOMA*, Frictional Games, 2015
|
|
989
541
|
|
|
990
|
-
|
|
542
|
+
Paracosm uses [AgentOS](https://agentos.sh/en) for agent orchestration, LLM dispatch, tool forging, and memory. The composition is what makes the runs feel inhabited rather than scripted: department heads remember, specialists invent tools mid-decision, and the LLM judge holds the line on safety before any forge enters the pipeline.
|
|
991
543
|
|
|
992
|
-
|
|
544
|
+
| AgentOS API | Used for |
|
|
545
|
+
|------------------------------|-----------------------------------------------------------------------|
|
|
546
|
+
| `agent()` | Commander, department, and Event Director agents |
|
|
547
|
+
| `generateText()` | LLM calls for event generation and tool evaluation |
|
|
548
|
+
| `EmergentCapabilityEngine` | Runtime tool forging in a hardened node:vm sandbox |
|
|
549
|
+
| `EmergentJudge` | LLM-as-judge safety review of forged tools |
|
|
550
|
+
| `WebSearchService` | Multi-provider seed enrichment with Firecrawl, Tavily, Serper, Brave |
|
|
551
|
+
| `AgentMemory` | Per-run citation memory with semantic recall |
|
|
993
552
|
|
|
994
|
-
|
|
995
|
-
|-|--------------------------|---------------------------|
|
|
996
|
-
| **Actors** | Unlimited via API. Dashboard shows 2 side-by-side. | N actors in parallel with fleet management UI. |
|
|
997
|
-
| **Simulations** | Sequential or self-managed parallelism. | Distributed parallelization across worker nodes. |
|
|
998
|
-
| **Scenarios** | JSON + Compiler, unlimited. | Visual scenario editor, team sharing, version control. |
|
|
999
|
-
| **Agent Chat** | Available after first turn completes. | Persistent agents with durable memory across sessions. |
|
|
1000
|
-
| **Cost** | Free forever. You provide LLM API keys. | Tiered pricing for teams, orgs, and government agencies. |
|
|
1001
|
-
| **Support** | Community (Discord, GitHub). | SLA, dedicated support, private deployment. |
|
|
553
|
+
---
|
|
1002
554
|
|
|
1003
|
-
|
|
555
|
+
## Open source vs hosted
|
|
1004
556
|
|
|
1005
|
-
|
|
557
|
+
| | Open source (Apache-2.0) | Hosted (planned) |
|
|
558
|
+
|------------------|--------------------------------------------------------------------|------------------------------------------------------------------------|
|
|
559
|
+
| Actors | Unlimited via API. Dashboard shows two side-by-side. | N actors in parallel, fleet management UI. |
|
|
560
|
+
| Simulations | Sequential or self-managed parallelism. | Distributed parallelization across worker nodes. |
|
|
561
|
+
| Scenarios | JSON + compiler, unlimited. | Visual scenario editor, team sharing, version control. |
|
|
562
|
+
| Agent chat | Available after the first turn completes. | Persistent agents with durable memory across sessions. |
|
|
563
|
+
| Cost | Free forever. The user supplies LLM API keys. | Tiered pricing for teams, organizations, and government agencies. |
|
|
564
|
+
| Support | Community via Discord and GitHub. | SLA, dedicated support, private deployment. |
|
|
1006
565
|
|
|
1007
|
-
Contact [team@frame.dev](mailto:team@frame.dev) for early access
|
|
566
|
+
The open-source engine is the permanent foundation. The hosted product targets organizations that need to run dozens or hundreds of simulations in parallel: defense agencies stress-testing doctrine, corporations modeling leadership scenarios, game studios generating divergent NPC civilizations at scale. Contact [team@frame.dev](mailto:team@frame.dev) for early access.
|
|
1008
567
|
|
|
1009
|
-
|
|
568
|
+
---
|
|
1010
569
|
|
|
1011
|
-
|
|
570
|
+
## Links
|
|
1012
571
|
|
|
1013
|
-
|
|
|
1014
|
-
|
|
1015
|
-
|
|
|
1016
|
-
|
|
|
1017
|
-
|
|
|
1018
|
-
|
|
|
1019
|
-
|
|
|
1020
|
-
|
|
|
572
|
+
| | |
|
|
573
|
+
|----------------|--------------------------------------------------------------|
|
|
574
|
+
| Live demo | [paracosm.agentos.sh/sim](https://paracosm.agentos.sh/sim) |
|
|
575
|
+
| Landing page | [paracosm.agentos.sh](https://paracosm.agentos.sh) |
|
|
576
|
+
| API docs | [paracosm.agentos.sh/docs](https://paracosm.agentos.sh/docs) |
|
|
577
|
+
| npm | [npmjs.com/package/paracosm](https://www.npmjs.com/package/paracosm) |
|
|
578
|
+
| AgentOS | [agentos.sh](https://agentos.sh/en) |
|
|
579
|
+
| Discord | [wilds.ai/discord](https://wilds.ai/discord) |
|
|
1021
580
|
|
|
1022
581
|
## License
|
|
1023
582
|
|
|
@@ -1026,6 +585,6 @@ Apache-2.0
|
|
|
1026
585
|
---
|
|
1027
586
|
|
|
1028
587
|
<p align="center">
|
|
1029
|
-
Built by <a href="https://manic.agency">Manic Agency LLC</a>
|
|
588
|
+
Built by <a href="https://manic.agency">Manic Agency LLC</a> · <a href="https://frame.dev">Frame.dev</a><br />
|
|
1030
589
|
<a href="mailto:team@frame.dev">team@frame.dev</a>
|
|
1031
590
|
</p>
|