paracosm 0.7.408 → 0.7.431

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.
Files changed (182) hide show
  1. package/README.md +150 -46
  2. package/dist/cli/compile.d.ts +1 -1
  3. package/dist/cli/compile.js +4 -4
  4. package/dist/cli/fetch-seed-url.d.ts +48 -0
  5. package/dist/cli/fetch-seed-url.d.ts.map +1 -0
  6. package/dist/cli/fetch-seed-url.js +109 -0
  7. package/dist/cli/fetch-seed-url.js.map +1 -0
  8. package/dist/cli/fork-preconditions.d.ts +17 -0
  9. package/dist/cli/fork-preconditions.d.ts.map +1 -0
  10. package/dist/cli/fork-preconditions.js +51 -0
  11. package/dist/cli/fork-preconditions.js.map +1 -0
  12. package/dist/cli/init-templates.d.ts +43 -0
  13. package/dist/cli/init-templates.d.ts.map +1 -0
  14. package/dist/cli/init-templates.js +141 -0
  15. package/dist/cli/init-templates.js.map +1 -0
  16. package/dist/cli/init.d.ts +46 -0
  17. package/dist/cli/init.d.ts.map +1 -0
  18. package/dist/cli/init.js +207 -0
  19. package/dist/cli/init.js.map +1 -0
  20. package/dist/cli/pair-runner.d.ts +41 -1
  21. package/dist/cli/pair-runner.d.ts.map +1 -1
  22. package/dist/cli/pair-runner.js +221 -4
  23. package/dist/cli/pair-runner.js.map +1 -1
  24. package/dist/cli/quickstart-routes.d.ts +35 -0
  25. package/dist/cli/quickstart-routes.d.ts.map +1 -0
  26. package/dist/cli/quickstart-routes.js +100 -0
  27. package/dist/cli/quickstart-routes.js.map +1 -0
  28. package/dist/cli/run.js +8 -0
  29. package/dist/cli/run.js.map +1 -1
  30. package/dist/cli/server/enrich-run-record.d.ts +22 -0
  31. package/dist/cli/server/enrich-run-record.d.ts.map +1 -0
  32. package/dist/cli/server/enrich-run-record.js +27 -0
  33. package/dist/cli/server/enrich-run-record.js.map +1 -0
  34. package/dist/cli/server/routes/platform-api.d.ts +19 -3
  35. package/dist/cli/server/routes/platform-api.d.ts.map +1 -1
  36. package/dist/cli/server/routes/platform-api.js +174 -5
  37. package/dist/cli/server/routes/platform-api.js.map +1 -1
  38. package/dist/cli/server/run-history-store.d.ts +27 -1
  39. package/dist/cli/server/run-history-store.d.ts.map +1 -1
  40. package/dist/cli/server/run-history-store.js +5 -0
  41. package/dist/cli/server/run-history-store.js.map +1 -1
  42. package/dist/cli/server/run-record.d.ts +13 -0
  43. package/dist/cli/server/run-record.d.ts.map +1 -1
  44. package/dist/cli/server/run-record.js.map +1 -1
  45. package/dist/cli/server/sqlite-run-history-store.d.ts +6 -0
  46. package/dist/cli/server/sqlite-run-history-store.d.ts.map +1 -0
  47. package/dist/cli/server/sqlite-run-history-store.js +226 -0
  48. package/dist/cli/server/sqlite-run-history-store.js.map +1 -0
  49. package/dist/cli/server-app.d.ts +73 -2
  50. package/dist/cli/server-app.d.ts.map +1 -1
  51. package/dist/cli/server-app.js +441 -150
  52. package/dist/cli/server-app.js.map +1 -1
  53. package/dist/cli/session-title.js +1 -1
  54. package/dist/cli/sim-config.d.ts +36 -0
  55. package/dist/cli/sim-config.d.ts.map +1 -1
  56. package/dist/cli/sim-config.js +18 -2
  57. package/dist/cli/sim-config.js.map +1 -1
  58. package/dist/cli/simulate-route.d.ts +103 -0
  59. package/dist/cli/simulate-route.d.ts.map +1 -0
  60. package/dist/cli/simulate-route.js +95 -0
  61. package/dist/cli/simulate-route.js.map +1 -0
  62. package/dist/engine/compiler/cache.d.ts +2 -2
  63. package/dist/engine/compiler/cache.js +2 -2
  64. package/dist/engine/compiler/compile-from-seed.d.ts +78 -0
  65. package/dist/engine/compiler/compile-from-seed.d.ts.map +1 -0
  66. package/dist/engine/compiler/compile-from-seed.js +93 -0
  67. package/dist/engine/compiler/compile-from-seed.js.map +1 -0
  68. package/dist/engine/compiler/generate-fingerprint.d.ts.map +1 -1
  69. package/dist/engine/compiler/generate-fingerprint.js +3 -6
  70. package/dist/engine/compiler/generate-fingerprint.js.map +1 -1
  71. package/dist/engine/compiler/generate-politics.d.ts.map +1 -1
  72. package/dist/engine/compiler/generate-politics.js +3 -6
  73. package/dist/engine/compiler/generate-politics.js.map +1 -1
  74. package/dist/engine/compiler/generate-progression.d.ts +10 -1
  75. package/dist/engine/compiler/generate-progression.d.ts.map +1 -1
  76. package/dist/engine/compiler/generate-progression.js +15 -15
  77. package/dist/engine/compiler/generate-progression.js.map +1 -1
  78. package/dist/engine/compiler/generate-prompts.d.ts.map +1 -1
  79. package/dist/engine/compiler/generate-prompts.js +4 -7
  80. package/dist/engine/compiler/generate-prompts.js.map +1 -1
  81. package/dist/engine/compiler/generate-reactions.d.ts.map +1 -1
  82. package/dist/engine/compiler/generate-reactions.js +3 -6
  83. package/dist/engine/compiler/generate-reactions.js.map +1 -1
  84. package/dist/engine/compiler/index.d.ts +9 -6
  85. package/dist/engine/compiler/index.d.ts.map +1 -1
  86. package/dist/engine/compiler/index.js +9 -6
  87. package/dist/engine/compiler/index.js.map +1 -1
  88. package/dist/engine/compiler/sandbox-runner.d.ts +40 -0
  89. package/dist/engine/compiler/sandbox-runner.d.ts.map +1 -0
  90. package/dist/engine/compiler/sandbox-runner.js +278 -0
  91. package/dist/engine/compiler/sandbox-runner.js.map +1 -0
  92. package/dist/engine/compiler/scenario-fixture.d.ts +4 -4
  93. package/dist/engine/compiler/scenario-fixture.js +4 -4
  94. package/dist/engine/compiler/seed-ingestion.d.ts +2 -2
  95. package/dist/engine/compiler/seed-ingestion.js +2 -2
  96. package/dist/engine/compiler/state-shape-block.d.ts +1 -1
  97. package/dist/engine/compiler/state-shape-block.js +5 -5
  98. package/dist/engine/compiler/types.d.ts +2 -2
  99. package/dist/engine/compiler/types.d.ts.map +1 -1
  100. package/dist/engine/compiler/validate.js +1 -1
  101. package/dist/engine/core/kernel.d.ts +32 -4
  102. package/dist/engine/core/kernel.d.ts.map +1 -1
  103. package/dist/engine/core/kernel.js +68 -6
  104. package/dist/engine/core/kernel.js.map +1 -1
  105. package/dist/engine/core/progression.d.ts +3 -3
  106. package/dist/engine/core/progression.js +21 -21
  107. package/dist/engine/core/rng.d.ts +10 -2
  108. package/dist/engine/core/rng.d.ts.map +1 -1
  109. package/dist/engine/core/rng.js +20 -6
  110. package/dist/engine/core/rng.js.map +1 -1
  111. package/dist/engine/core/snapshot.d.ts +53 -0
  112. package/dist/engine/core/snapshot.d.ts.map +1 -0
  113. package/dist/engine/core/snapshot.js +6 -0
  114. package/dist/engine/core/snapshot.js.map +1 -0
  115. package/dist/engine/core/state.d.ts +7 -5
  116. package/dist/engine/core/state.d.ts.map +1 -1
  117. package/dist/engine/digital-twin/index.d.ts +41 -0
  118. package/dist/engine/digital-twin/index.d.ts.map +1 -0
  119. package/dist/engine/digital-twin/index.js +40 -0
  120. package/dist/engine/digital-twin/index.js.map +1 -0
  121. package/dist/engine/index.d.ts +1 -1
  122. package/dist/engine/leader-presets.d.ts +39 -0
  123. package/dist/engine/leader-presets.d.ts.map +1 -0
  124. package/dist/engine/leader-presets.js +118 -0
  125. package/dist/engine/leader-presets.js.map +1 -0
  126. package/dist/engine/lunar/fingerprint.js +2 -2
  127. package/dist/engine/lunar/prompts.js +2 -2
  128. package/dist/engine/mars/fingerprint.js +1 -1
  129. package/dist/engine/mars/metrics.d.ts +2 -2
  130. package/dist/engine/mars/metrics.js +2 -2
  131. package/dist/engine/mars/prompts.js +3 -3
  132. package/dist/engine/schema/artifact.d.ts +4 -0
  133. package/dist/engine/schema/artifact.d.ts.map +1 -1
  134. package/dist/engine/schema/primitives.d.ts +4 -0
  135. package/dist/engine/schema/primitives.d.ts.map +1 -1
  136. package/dist/engine/schema/primitives.js +13 -0
  137. package/dist/engine/schema/primitives.js.map +1 -1
  138. package/dist/engine/schema/stream.d.ts +2 -0
  139. package/dist/engine/schema/stream.d.ts.map +1 -1
  140. package/dist/engine/schema/stream.js +14 -0
  141. package/dist/engine/schema/stream.js.map +1 -1
  142. package/dist/runtime/agent-memory.d.ts +1 -1
  143. package/dist/runtime/agent-memory.d.ts.map +1 -1
  144. package/dist/runtime/agent-memory.js +4 -2
  145. package/dist/runtime/agent-memory.js.map +1 -1
  146. package/dist/runtime/agent-reactions.d.ts +6 -1
  147. package/dist/runtime/agent-reactions.d.ts.map +1 -1
  148. package/dist/runtime/agent-reactions.js +3 -1
  149. package/dist/runtime/agent-reactions.js.map +1 -1
  150. package/dist/runtime/build-artifact.d.ts +26 -3
  151. package/dist/runtime/build-artifact.d.ts.map +1 -1
  152. package/dist/runtime/build-artifact.js +22 -3
  153. package/dist/runtime/build-artifact.js.map +1 -1
  154. package/dist/runtime/canonical-json.d.ts +25 -0
  155. package/dist/runtime/canonical-json.d.ts.map +1 -0
  156. package/dist/runtime/canonical-json.js +46 -0
  157. package/dist/runtime/canonical-json.js.map +1 -0
  158. package/dist/runtime/chat-agents.d.ts +9 -1
  159. package/dist/runtime/chat-agents.d.ts.map +1 -1
  160. package/dist/runtime/chat-agents.js +13 -3
  161. package/dist/runtime/chat-agents.js.map +1 -1
  162. package/dist/runtime/contracts.d.ts +25 -7
  163. package/dist/runtime/contracts.d.ts.map +1 -1
  164. package/dist/runtime/departments.js +1 -1
  165. package/dist/runtime/orchestrator.d.ts +69 -4
  166. package/dist/runtime/orchestrator.d.ts.map +1 -1
  167. package/dist/runtime/orchestrator.js +198 -54
  168. package/dist/runtime/orchestrator.js.map +1 -1
  169. package/dist/runtime/parsers.js +5 -5
  170. package/dist/runtime/reaction-step.d.ts +8 -0
  171. package/dist/runtime/reaction-step.d.ts.map +1 -1
  172. package/dist/runtime/reaction-step.js +3 -2
  173. package/dist/runtime/reaction-step.js.map +1 -1
  174. package/dist/runtime/world-model/index.d.ts +415 -0
  175. package/dist/runtime/world-model/index.d.ts.map +1 -0
  176. package/dist/runtime/world-model/index.js +523 -0
  177. package/dist/runtime/world-model/index.js.map +1 -0
  178. package/dist/runtime/world-snapshot.d.ts +13 -0
  179. package/dist/runtime/world-snapshot.d.ts.map +1 -0
  180. package/dist/runtime/world-snapshot.js +19 -0
  181. package/dist/runtime/world-snapshot.js.map +1 -0
  182. package/package.json +32 -4
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  <h1 align="center">PARACOSM</h1>
6
6
 
7
7
  <p align="center">
8
- <em>AI Agent Swarm Simulation Engine</em>
8
+ <em>From prompt to world model to forked futures. Structured counterfactual simulations for AI agents.</em>
9
9
  </p>
10
10
 
11
11
  <p align="center">
@@ -25,26 +25,110 @@
25
25
 
26
26
  ---
27
27
 
28
- ## What Is Paracosm
28
+ ## What paracosm is
29
29
 
30
- Define a world as JSON. Assign AI leaders with distinct personalities. Watch their decisions compound into divergent outcomes from identical starting conditions.
30
+ Paracosm starts from a prompt, brief, URL, or hand-written scenario draft; every path compiles down to an LLM-readable world contract before simulation. The durable contract is still JSON: a typed `ScenarioPackage` with five state bags, labels, departments, metrics, setup defaults, and generated hooks. A leader with a HEXACO personality profile runs that world. A deterministic kernel drives state, time, and randomness. An LLM generates events, specialist analyses, and the leader's decisions. Specialists can forge new computational tools at runtime inside a V8 sandbox; an LLM judge approves each forge before it enters the decision pipeline. The kernel applies consequences. Personality traits drift. One turn ends, the next begins.
31
31
 
32
- Leaders are top-down decision makers. They can be colony commanders, CEOs, generals, ship captains, department heads, AI systems, governing councils, or any entity that receives information, evaluates options, and makes choices that shape the world. The simulation doesn't care what they represent. It cares how they decide.
32
+ **JSON is the contract, not the product boundary.** Today, `compileScenario()` accepts a scenario JSON draft and can ground it with `seedText` or `seedUrl`. The next API layer should be a one-call prompt/document wrapper that asks an LLM to propose that same JSON contract, validates it, then compiles and runs it. It should not bypass the schema, the kernel, or the artifact.
33
33
 
34
- Each turn: a Event Director generates events based on the world's current state. Department agents analyze the situation and forge computational tools at runtime. Leaders decide. A deterministic kernel applies consequences. Personality traits drift from experience. The world evolves.
34
+ **Same seed. Different leader. Different world.**
35
35
 
36
- Same seed, same starting conditions, different leaders, different civilizations.
36
+ Two runs against an identical seed, starting from the same compiled world contract, produce measurably divergent trajectories when you swap one variable: the leader'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
37
 
38
- ## Quickstart
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 leader decides), runs ~100 agents by design, and outputs a deterministic trajectory plus divergence across leaders.
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.
47
+
48
+ Leaders can be colony commanders, CEOs, generals, ship captains, department heads, AI systems, governing councils, or any entity that receives information, evaluates options, and makes choices that shape the world. The simulation does not care what they represent. It cares how they decide.
49
+
50
+ ### Counterfactual simulations with `WorldModel.fork()`
51
+
52
+ The CWSM positioning is operationalized through `WorldModel.fork()`: run a simulation with snapshots enabled, then branch at any past turn with a different leader or seed, and compare. On resumed runs, `maxTurns` remains the absolute final turn index. To run three additional turns from turn 3, pass `maxTurns: 6`.
53
+
54
+ ```typescript
55
+ import { WorldModel } from 'paracosm/world-model';
56
+ import worldJson from './my-world.json' with { type: 'json' };
57
+
58
+ const wm = await WorldModel.fromJson(worldJson);
59
+
60
+ // Run the trunk with per-turn snapshots captured.
61
+ const trunk = await wm.simulate(visionaryLeader, {
62
+ maxTurns: 6, seed: 42, captureSnapshots: true,
63
+ });
64
+
65
+ // Branch at turn 3 with a different leader. No re-compute of turns 1-3;
66
+ // the forked kernel resumes from the captured state.
67
+ const branch = await (await wm.forkFromArtifact(trunk, 3)).simulate(
68
+ pragmatistLeader,
69
+ { maxTurns: 6, seed: 42 },
70
+ );
71
+
72
+ console.log(trunk.metadata.runId); // parent run-id
73
+ console.log(branch.metadata.forkedFrom); // { parentRunId, atTurn: 3 }
74
+ console.log(trunk.fingerprint, branch.fingerprint); // divergent futures from the same turn-3 state
75
+ ```
76
+
77
+ The kernel round-trips through `JSON.stringify`, so snapshots persist to disk cleanly for later replay or audit. `captureSnapshots` defaults to `false` to keep normal artifacts lean; set it when you want fork capability.
78
+
79
+ The paracosm dashboard exposes the same mechanism end-to-end. Every UI-initiated run captures snapshots by default, so the Reports tab shows a `↳ Fork at {Time} N` button on each completed turn. Clicking it opens a fork modal (leader 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.
80
+
81
+ ### Replay any run for audit
82
+
83
+ ```typescript
84
+ const replay = await wm.replay(storedArtifact);
85
+ console.log(replay.matches); // true when the kernel produces byte-equal output
86
+ console.log(replay.divergence); // first-mismatch JSON pointer when matches=false
87
+ ```
88
+
89
+ The kernel's between-turn progression hook re-runs deterministically from each recorded snapshot; LLM stages are not invoked, so replay is free and fast. Use it for regression testing (replay golden artifacts in CI) or forensic comparison (find the first kernel-state divergence between two versions of paracosm). Pillar 2 (Reproducible) becomes verifiable in code rather than promised in copy.
90
+
91
+ ### Subpath for digital-twin use cases
92
+
93
+ ```typescript
94
+ import { DigitalTwin, type SubjectConfig, type InterventionConfig } from 'paracosm/digital-twin';
95
+
96
+ const twin = await DigitalTwin.fromJson(scenarioJson);
97
+ const artifact = await twin.simulateIntervention(subject, intervention, leader);
98
+ ```
99
+
100
+ `DigitalTwin` is an alias of `WorldModel`; the subpath names the use case in the import path. The new `simulateIntervention()` sugar populates `RunArtifact.subject` and `RunArtifact.intervention` for traceability.
101
+
102
+ ### Quickstart: prompt or document to running simulation
103
+
104
+ `WorldModel.fromPrompt` compiles a scenario from seed source material (paste, URL, or extracted PDF text), then `wm.quickstart` generates N contextual HEXACO leaders and runs them in parallel. Every prompt/document path validates against `DraftScenarioSchema` and routes into the existing `compileScenario` pipeline: the canonical `ScenarioPackage` contract is never bypassed.
105
+
106
+ ```typescript
107
+ import { WorldModel } from 'paracosm/world-model';
108
+
109
+ const wm = await WorldModel.fromPrompt({
110
+ seedText: 'Q3 board brief: the company must decide between...',
111
+ domainHint: 'corporate strategic decision',
112
+ });
113
+
114
+ const { leaders, artifacts } = await wm.quickstart({ leaderCount: 3 });
115
+ artifacts.forEach((a, i) => console.log(leaders[i].name, a.fingerprint));
116
+ ```
117
+
118
+ In the dashboard, the Quickstart tab is the default landing view. A user pastes a brief (or drops a PDF, or supplies a URL) and receives three streaming-live leaders plus per-card Download JSON, Copy shareable link, and Fork-in-Branches actions within a minute of first click. A curated library of 10 HEXACO archetypes is exported at `paracosm/leader-presets` for programmatic `runBatch` sweeps or Swap-leader controls in downstream UIs.
119
+
120
+ ## Install
39
121
 
40
122
  ```bash
41
123
  npm install paracosm # also works: pnpm add paracosm / bun add paracosm
42
124
  ```
43
125
 
44
- Paracosm ships as pure ESM with subpath exports (`paracosm/compiler`, `paracosm/runtime`, `paracosm/mars`, `paracosm/lunar`, `paracosm/core`, `paracosm/schema`). Node 20+, Bun 1.x, and any TypeScript runner with ESM + import-attributes support (`tsx`, `ts-node --esm`) resolve them out of the box. If `import ... from 'paracosm/compiler'` fails with a module-not-found error, the dependency was never installed in that project `cd` into the right directory and run one of the commands above.
126
+ Paracosm ships as pure ESM with subpath exports (`paracosm/compiler`, `paracosm/runtime`, `paracosm/mars`, `paracosm/lunar`, `paracosm/core`, `paracosm/schema`). Node 20+, Bun 1.x, and any TypeScript runner with ESM + import-attributes support (`tsx`, `ts-node --esm`) resolve them out of the box. If `import ... from 'paracosm/compiler'` fails with a module-not-found error, the dependency was never installed in that project. `cd` into the right directory and run one of the commands above.
45
127
 
46
128
  ### 1. Define your world
47
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.
131
+
48
132
  Every scenario declares its own vocabulary via `labels.populationNoun`
49
133
  (plural, e.g. `"colonists"` / `"crew"` / `"citizens"`) and
50
134
  `labels.settlementNoun` (singular, e.g. `"colony"` / `"habitat"` /
@@ -52,7 +136,7 @@ Every scenario declares its own vocabulary via `labels.populationNoun`
52
136
  user-facing copy renders.
53
137
 
54
138
  If you omit `labels`, Paracosm falls back to `"colonists"` /
55
- `"colony"` defaults that read fine across most domains but usually
139
+ `"colony"`. Defaults that read fine across most domains but usually
56
140
  feel sharper when you pick your own. "Colony" is the default because
57
141
  it's narratively richer than a neutral "group" / "unit" while still
58
142
  translating to Mars habitats, medieval holds, corporate teams, or any
@@ -94,7 +178,7 @@ bounded collective under a leader's decisions.
94
178
  }
95
179
  ```
96
180
 
97
- > **Terminology `labels.populationNoun` + `settlementNoun` + `timeUnitNoun`**
181
+ > **Terminology: `labels.populationNoun` + `settlementNoun` + `timeUnitNoun`**
98
182
  >
99
183
  > The engine defaults to **`colonists` / `colony` / `tick`** when a scenario omits these
100
184
  > fields, but every scenario can and should override them. The dashboard uses the overridden
@@ -114,9 +198,9 @@ bounded collective under a leader's decisions.
114
198
  > `populationNoun` is the **plural** form; the dashboard derives the singular (`colonists` →
115
199
  > `colonist`) and capitalised variants automatically. `settlementNoun` is **singular** (`colony`,
116
200
  > not `colonies`). `timeUnitNoun` is **singular** and pairs with `timeUnitNounPlural` for
117
- > grammatical display; both are optional and fall back to `tick` / `ticks`. Paracosm the engine
118
- > is an "AI agent swarm" at the meta layer; what it simulates inside each run is scenario-
119
- > flavoured via these fields.
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.
120
204
 
121
205
  ### 2. Compile and run
122
206
 
@@ -125,7 +209,7 @@ import { compileScenario } from 'paracosm/compiler';
125
209
  import { runSimulation } from 'paracosm/runtime';
126
210
  import worldJson from './my-world.json' with { type: 'json' };
127
211
 
128
- // Compile JSON into a runnable scenario (~$0.10, cached to disk)
212
+ // Compile a typed world draft into a runnable scenario (~$0.10, cached to disk)
129
213
  const scenario = await compileScenario(worldJson, {
130
214
  provider: 'anthropic',
131
215
  model: 'claude-sonnet-4-6',
@@ -165,7 +249,7 @@ const results = await Promise.all(
165
249
  seed: 42,
166
250
  // costPreset: 'economy', // uncomment for ~5-10× cheaper iteration on OpenAI
167
251
  // Every event carries a universal `e.data.summary` one-liner the
168
- // runtime populates for you prints cleanly for all 17 event
252
+ // runtime populates for you; prints cleanly for all 17 event
169
253
  // types without guessing which fields exist where.
170
254
  //
171
255
  // For full intellisense on per-event data, narrow via e.type:
@@ -195,7 +279,7 @@ Each call to `runSimulation` takes one leader. Run one, two, or twenty. The dash
195
279
 
196
280
  ### The universal result contract
197
281
 
198
- Every simulation returns a `RunArtifact` one universal Zod-validated shape exported from `paracosm/schema`. The same shape covers civilization sims (turn-loop), digital-twin simulations (batch-trajectory), and one-shot forecasts (batch-point).
282
+ Every simulation returns a `RunArtifact`: one universal Zod-validated shape exported from `paracosm/schema`. The same shape covers civilization sims (turn-loop), digital-twin simulations (batch-trajectory), and one-shot forecasts (batch-point).
199
283
 
200
284
  ```typescript
201
285
  import { RunArtifactSchema, type RunArtifact } from 'paracosm/schema';
@@ -290,11 +374,11 @@ cp node_modules/paracosm/config/leaders.example.json leaders.json
290
374
  mkdir -p config && cp node_modules/paracosm/config/leaders.example.json config/leaders.json
291
375
  ```
292
376
 
293
- Then edit the HEXACO sliders and `instructions` fields to describe your own leaders the simulation picks up the file on the next run.
377
+ Then edit the HEXACO sliders and `instructions` fields to describe your own leaders. The simulation picks up the file on the next run.
294
378
 
295
379
  ## Scenario Compiler
296
380
 
297
- The compiler turns your JSON into a runnable scenario by generating TypeScript hooks via LLM calls:
381
+ The compiler turns a typed world draft plus optional prompt/document/URL grounding into a runnable scenario by generating TypeScript hooks via LLM calls:
298
382
 
299
383
  ```bash
300
384
  npm run compile -- scenarios/submarine.json \
@@ -302,7 +386,7 @@ npm run compile -- scenarios/submarine.json \
302
386
  --no-web-search
303
387
  ```
304
388
 
305
- Options: `--seed-text`, `--seed-url`, `--no-web-search`, `--max-searches`. Compiled scenarios appear in the dashboard selector. Cost is roughly $0.10 per compile, cached to disk after first generation.
389
+ Options: `--seed-text`, `--seed-url`, `--no-web-search`, `--max-searches`. Use `--seed-text` for a pasted brief or prompt, and `--seed-url` for a report, paper, or web page. The JSON file remains the contract that gets validated and cached; seed material grounds the world before hook generation. Compiled scenarios appear in the dashboard selector. Cost is roughly $0.10 per compile, cached to disk after first generation.
306
390
 
307
391
  ### Programmatic compiler options
308
392
 
@@ -326,7 +410,7 @@ const scenario = await compileScenario(worldJson, {
326
410
  });
327
411
  ```
328
412
 
329
- 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).
413
+ 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).
330
414
 
331
415
  ## Cost Envelope
332
416
 
@@ -337,7 +421,7 @@ Running a simulation calls real LLM APIs against your key. Paracosm assigns a di
337
421
  | **`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** |
338
422
  | **`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 |
339
423
 
340
- Numbers assume 6 turns, 5 departments, 100 agents, up to 3 events per turn. An 8-turn run on OpenAI `quality` tends to land at ~$1.50-2.00 per leader the call budget is ~10/turn (1 director + ~5 dept + 1 commander + ~3 reaction batches + 0-2 forges + 0-1 judge), and departments on flagship carry most of the cost.
424
+ Numbers assume 6 turns, 5 departments, 100 agents, up to 3 events per turn. An 8-turn run on OpenAI `quality` tends to land at ~$1.50-2.00 per leader. The call budget is ~10/turn (1 director + ~5 dept + 1 commander + ~3 reaction batches + 0-2 forges + 0-1 judge), and departments on flagship carry most of the cost.
341
425
 
342
426
  Pick the preset explicitly for quick iteration:
343
427
 
@@ -353,13 +437,33 @@ const output = await runSimulation(leader, [], {
353
437
 
354
438
  Forge approval rate drops roughly 10-20pp on `economy` because the mid-tier department model occasionally violates structured-output schemas the judge rejects. Use `'economy'` for iteration / CI / debugging; use `'quality'` (default) for publishable or production runs.
355
439
 
356
- 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.
440
+ 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.
357
441
 
358
442
  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.
359
443
 
360
444
  ### Prompt caching
361
445
 
362
- 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/`.
446
+ 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/`.
447
+
448
+ ## One-shot HTTP API: `POST /simulate`
449
+
450
+ Non-SSE consumers (curl, Python integrations, third-party dashboards) can run a simulation through a plain request-response endpoint. Gated behind `PARACOSM_ENABLE_SIMULATE_ENDPOINT=true` so the hosted demo's SSE-first path stays the default; self-hosted deployments flip the flag on.
451
+
452
+ ```bash
453
+ export PARACOSM_ENABLE_SIMULATE_ENDPOINT=true
454
+ npx paracosm serve # or bring up your own server via createMarsServer
455
+
456
+ curl -s -X POST http://localhost:5188/simulate \
457
+ -H 'Content-Type: application/json' \
458
+ -H 'X-Anthropic-Key: sk-ant-...' \
459
+ -d '{
460
+ "scenario": { "id": "submarine-habitat", "labels": { "name": "Deep Ocean Habitat", "populationNoun": "crew", "settlementNoun": "habitat", "timeUnitNoun": "day" }, "setup": { "defaultTurns": 4, "defaultPopulation": 25, "defaultStartTime": 2040 }, "departments": [...], "metrics": [...] },
461
+ "leader": { "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": "" },
462
+ "options": { "maxTurns": 4, "seed": 42, "captureSnapshots": true, "provider": "anthropic" }
463
+ }' | jq '.artifact.fingerprint'
464
+ ```
465
+
466
+ The request body accepts either a pre-compiled `ScenarioPackage` (has `.hooks`) or a raw scenario draft the compiler accepts; raw drafts are auto-compiled server-side with optional `options.seedText` / `options.seedUrl` grounding. The response body is `{ artifact: RunArtifact, scenario: ScenarioPackage, durationMs: number }`. Rate limiting shares the same IP bucket as `/setup`; request-body size uses the same 5 MiB cap.
363
467
 
364
468
  ## Programmatic API
365
469
 
@@ -373,7 +477,7 @@ Everything the dashboard does is also available as library calls. The exports fa
373
477
  | `paracosm/core` | Kernel state types (`Agent`, `WorldState`, `HexacoProfile`, …) |
374
478
  | `paracosm/mars`, `paracosm/lunar` | Pre-built `ScenarioPackage` constants to use or fork |
375
479
 
376
- ### Client global defaults + env-var config
480
+ ### Client: global defaults + env-var config
377
481
 
378
482
  `createParacosmClient` pins `provider`, `costPreset`, per-role `models`, and compile-time options once, then hands back `runSimulation` / `runBatch` / `compileScenario` methods that inherit those defaults. Per-call overrides still win, merged at the per-role level so `models: { departments: 'gpt-5.4' }` at the client and `models: { judge: 'gpt-5.4' }` at the call combine to pin both roles instead of one replacing the other.
379
483
 
@@ -416,7 +520,7 @@ Env vars feed the same defaults and are read once at `createParacosmClient` cons
416
520
  | `PARACOSM_COMPILER_PROVIDER` | `compilerProvider` | `openai` / `anthropic` |
417
521
  | `PARACOSM_COMPILER_MODEL` | `compilerModel` | any provider-valid model id |
418
522
 
419
- Invalid values (typos, unknown providers) are silently ignored so bad env state can't crash boot the client falls back to the next layer. Empty or whitespace-only env values are treated as unset.
523
+ Invalid values (typos, unknown providers) are silently ignored so bad env state can't crash boot. The client falls back to the next layer. Empty or whitespace-only env values are treated as unset.
420
524
 
421
525
  ```bash
422
526
  # Zero-code config for hosting / CI:
@@ -431,9 +535,9 @@ PARACOSM_MODEL_DEPARTMENTS=claude-sonnet-4-6 \
431
535
  const client = createParacosmClient(); // no args, pulls from env
432
536
  ```
433
537
 
434
- Direct `runSimulation(...)` / `runBatch(...)` / `compileScenario(...)` calls without a client are still fully supported the client is purely additive for multi-run workflows.
538
+ Direct `runSimulation(...)` / `runBatch(...)` / `compileScenario(...)` calls without a client are still fully supported. The client is purely additive for multi-run workflows.
435
539
 
436
- ### Batch runner N scenarios × M leaders
540
+ ### Batch runner: N scenarios × M leaders
437
541
 
438
542
  ```typescript
439
543
  import { runBatch } from 'paracosm/runtime';
@@ -441,7 +545,7 @@ import { marsScenario, lunarScenario } from 'paracosm';
441
545
 
442
546
  const manifest = await runBatch({
443
547
  scenarios: [marsScenario, lunarScenario],
444
- leaders, // LeaderConfig[] same shape as runSimulation
548
+ leaders, // LeaderConfig[], same shape as runSimulation
445
549
  turns: 6,
446
550
  seed: 950,
447
551
  maxConcurrency: 2, // how many sims to run in parallel
@@ -504,7 +608,7 @@ import { runSimulation, ProviderKeyMissingError } from 'paracosm';
504
608
  try {
505
609
  const output = await runSimulation(leader, [], { scenario, maxTurns: 8, seed: 42 });
506
610
  if (output.providerError) {
507
- // Terminal provider failure (invalid key, quota exhausted) the run
611
+ // Terminal provider failure (invalid key, quota exhausted). The run
508
612
  // aborted mid-way. turnArtifacts / finalState are partial.
509
613
  console.error(output.providerError.kind, // 'auth' | 'quota' | 'rate_limit' | 'network' | 'unknown'
510
614
  output.providerError.provider,
@@ -524,7 +628,7 @@ The resolver inspects `process.env` once up front, so a missing key fails loudly
524
628
 
525
629
  ### Where run output lands
526
630
 
527
- 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.
631
+ 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.
528
632
 
529
633
  ```bash
530
634
  # Default: ./output/v3-the-pragmatist-2026-04-21T16-02-41-550Z.json
@@ -550,14 +654,14 @@ npx paracosm compile scenarios/lunar.json \
550
654
 
551
655
  Pipeline:
552
656
 
553
- 1. **Extract** LLM reads the seed, returns `topics`, `facts`, `searchQueries`, `crisisCategories`.
554
- 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.
555
- 3. **Assemble** extracted facts plus search hits become a `KnowledgeBundle` with `topics[].canonicalFacts[]` and `categoryMapping`.
556
- 4. **Ingest** at runtime, `initResearchMemory` writes every citation into an AgentOS `AgentMemory.sqlite()` store keyed by topic tags.
557
- 5. **Recall** for each event, `recallResearch(query, keywords)` runs semantic recall over the memory store. Live web search fills in when memory is sparse.
558
- 6. **Inject** citations land in each department's prompt under `RESEARCH:` as `[claim](url)` markdown links.
559
- 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.
560
- 8. **Render** the dashboard "Reports" tab renders citations as clickable links with optional DOIs.
657
+ 1. **Extract.** LLM reads the seed, returns `topics`, `facts`, `searchQueries`, `crisisCategories`.
658
+ 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.
659
+ 3. **Assemble.** Extracted facts plus search hits become a `KnowledgeBundle` with `topics[].canonicalFacts[]` and `categoryMapping`.
660
+ 4. **Ingest.** At runtime, `initResearchMemory` writes every citation into an AgentOS `AgentMemory.sqlite()` store keyed by topic tags.
661
+ 5. **Recall.** For each event, `recallResearch(query, keywords)` runs semantic recall over the memory store. Live web search fills in when memory is sparse.
662
+ 6. **Inject.** Citations land in each department's prompt under `RESEARCH:` as `[claim](url)` markdown links.
663
+ 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.
664
+ 8. **Render.** The dashboard "Reports" tab renders citations as clickable links with optional DOIs.
561
665
 
562
666
  The Event Director also receives the bundle's `topics` and `categories`, so its `researchKeywords` and `category` fields stay grounded in entries that actually exist in your knowledge bundle.
563
667
 
@@ -575,7 +679,7 @@ Both are included as `paracosm/mars` and `paracosm/lunar` exports. Use them as r
575
679
  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:
576
680
 
577
681
  ```jsonc
578
- // A) Corporate strategy quarterly cadence over 3 years
682
+ // A) Corporate strategy: quarterly cadence over 3 years
579
683
  {
580
684
  "id": "corp-strategy",
581
685
  "labels": {
@@ -588,7 +692,7 @@ The engine is time-unit agnostic. `setup.defaultStartTime` and `setup.defaultTim
588
692
  "setup": { "defaultTurns": 12, "defaultStartTime": 1, "defaultTimePerTurn": 1, "defaultPopulation": 40 }
589
693
  }
590
694
 
591
- // B) Submarine patrol daily cadence over six months
695
+ // B) Submarine patrol: daily cadence over six months
592
696
  {
593
697
  "id": "submarine-daily",
594
698
  "labels": {
@@ -601,7 +705,7 @@ The engine is time-unit agnostic. `setup.defaultStartTime` and `setup.defaultTim
601
705
  "setup": { "defaultTurns": 24, "defaultStartTime": 1, "defaultTimePerTurn": 7, "defaultPopulation": 60 }
602
706
  }
603
707
 
604
- // C) Benchmark arena abstract tick cadence
708
+ // C) Benchmark arena: abstract tick cadence
605
709
  {
606
710
  "id": "arena-session",
607
711
  "labels": {
@@ -614,7 +718,7 @@ The engine is time-unit agnostic. `setup.defaultStartTime` and `setup.defaultTim
614
718
  "setup": { "defaultTurns": 50, "defaultStartTime": 0, "defaultTimePerTurn": 1, "defaultPopulation": 8 }
615
719
  }
616
720
 
617
- // D) Mars Genesis year cadence (the built-in reference)
721
+ // D) Mars Genesis: year cadence (the built-in reference)
618
722
  {
619
723
  "id": "mars-genesis",
620
724
  "labels": {
@@ -654,7 +758,7 @@ Each turn represents a configurable time period. Mars and Lunar tick in years (M
654
758
  3. DEPARTMENT ANALYSIS All active departments analyze the event in parallel.
655
759
  Each department head (promoted at turn 0) uses their
656
760
  personality and tools. Departments can forge new
657
- computational tools at runtime (sandboxed V8, LLM-judged).
761
+ computational tools at runtime (hardened node:vm, LLM-judged).
658
762
 
659
763
  4. COMMANDER DECISION Reads all department reports. Selects an option.
660
764
  Personality shapes risk tolerance and priority weighting.
@@ -690,7 +794,7 @@ Department heads are LLM agents with domain-specific instructions, access to res
690
794
 
691
795
  - Analyze the event against their department's research knowledge
692
796
  - Cite relevant scientific literature (DOI-linked)
693
- - Forge computational tools (e.g., a radiation dose calculator) in a sandboxed V8 environment
797
+ - Forge computational tools (e.g., a radiation dose calculator) in a hardened node:vm sandbox
694
798
  - An LLM judge reviews each tool for safety and correctness
695
799
  - Produce a structured report: summary, risks, recommended actions, proposed colony state changes
696
800
 
@@ -702,7 +806,7 @@ The commander sees all department reports and makes a decision. Different comman
702
806
  src/
703
807
  engine/ the npm package
704
808
  core/ deterministic kernel (RNG, state, progression, personality drift)
705
- compiler/ JSON -> ScenarioPackage compiler
809
+ compiler/ scenario draft + source grounding -> ScenarioPackage compiler
706
810
  mars/ Mars Genesis scenario
707
811
  lunar/ Lunar Outpost scenario
708
812
 
@@ -743,7 +847,7 @@ Paracosm uses [AgentOS](https://agentos.sh) for agent orchestration, LLM calls,
743
847
  |------------|----------|
744
848
  | `agent()` | Commander, department, and Event Director agents |
745
849
  | `generateText()` | LLM calls for event generation and tool evaluation |
746
- | `EmergentCapabilityEngine` | Runtime tool forging in sandboxed V8 |
850
+ | `EmergentCapabilityEngine` | Runtime tool forging in a hardened node:vm sandbox |
747
851
  | `EmergentJudge` | LLM-as-judge safety review of forged tools |
748
852
 
749
853
  ## Links
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * CLI: Compile a scenario JSON into a runnable ScenarioPackage.
3
+ * CLI: Compile a scenario JSON draft into a runnable ScenarioPackage.
4
4
  *
5
5
  * Usage:
6
6
  * npx tsx src/cli/compile.ts scenarios/submarine.json
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * CLI: Compile a scenario JSON into a runnable ScenarioPackage.
3
+ * CLI: Compile a scenario JSON draft into a runnable ScenarioPackage.
4
4
  *
5
5
  * Usage:
6
6
  * npx tsx src/cli/compile.ts scenarios/submarine.json
@@ -16,7 +16,7 @@ async function main() {
16
16
  const options = parseCompileCliOptions(rawArgs);
17
17
  if (rawArgs.length === 0 || rawArgs.includes('--help') || rawArgs.includes('-h')) {
18
18
  console.log(`
19
- paracosm compile Generate runtime hooks for a scenario JSON
19
+ paracosm compile - Generate runtime hooks for a scenario JSON draft
20
20
 
21
21
  Usage:
22
22
  npx tsx src/cli/compile.ts <scenario.json> [options]
@@ -26,8 +26,8 @@ Options:
26
26
  --model <model> Model name (default: claude-sonnet-4-6)
27
27
  --no-cache Skip disk cache
28
28
  --cache-dir <dir> Cache directory (default: .paracosm/cache)
29
- --seed-text <text> Seed scenario knowledge from inline text before hook generation
30
- --seed-url <url> Seed scenario knowledge from a URL before hook generation
29
+ --seed-text <text> Ground the scenario with an inline prompt, brief, or document
30
+ --seed-url <url> Ground the scenario with a URL before hook generation
31
31
  --no-web-search Skip live citation grounding during seed ingestion
32
32
  --max-searches <n> Cap the number of live grounding searches during seed ingestion
33
33
  -h, --help Show this help
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Shared URL fetcher for CLI init + dashboard quickstart flows.
3
+ *
4
+ * AgentOS exposes WebSearchService from the `@framers/agentos/web-search`
5
+ * subpath. The package root does not export it, and the service is a
6
+ * search API rather than a single-URL scraper. This helper uses the real
7
+ * search API when provider keys are configured, then falls back to direct
8
+ * text/HTML fetch for ordinary public URLs.
9
+ *
10
+ * @module paracosm/cli/fetch-seed-url
11
+ */
12
+ export interface FetchedSeedUrl {
13
+ text: string;
14
+ title: string;
15
+ sourceUrl: string;
16
+ }
17
+ export interface WebSearchResultLike {
18
+ url: string;
19
+ title: string;
20
+ snippet: string;
21
+ content?: string;
22
+ }
23
+ export interface WebSearchClient {
24
+ registerProvider: (provider: any) => void;
25
+ hasProviders: () => boolean;
26
+ search: (query: string, options?: {
27
+ maxResults?: number;
28
+ rerank?: boolean;
29
+ }) => Promise<WebSearchResultLike[]>;
30
+ }
31
+ export type WebSearchServiceCtor = new (opts?: any) => WebSearchClient;
32
+ export type WebSearchProviderCtor = new (apiKey: string) => unknown;
33
+ export interface WebSearchModule {
34
+ WebSearchService: WebSearchServiceCtor;
35
+ FirecrawlProvider: WebSearchProviderCtor;
36
+ TavilyProvider: WebSearchProviderCtor;
37
+ SerperProvider: WebSearchProviderCtor;
38
+ BraveProvider: WebSearchProviderCtor;
39
+ }
40
+ export type WebSearchImporter = () => Promise<WebSearchModule>;
41
+ export interface FetchSeedFromUrlOptions {
42
+ importWebSearch?: WebSearchImporter;
43
+ env?: NodeJS.ProcessEnv | Record<string, string | undefined>;
44
+ fetchImpl?: typeof fetch;
45
+ }
46
+ export declare function loadWebSearchModule(importWebSearch?: WebSearchImporter): Promise<WebSearchModule>;
47
+ export declare function fetchSeedFromUrl(url: string, options?: FetchSeedFromUrlOptions): Promise<FetchedSeedUrl>;
48
+ //# sourceMappingURL=fetch-seed-url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-seed-url.d.ts","sourceRoot":"","sources":["../../src/cli/fetch-seed-url.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,gBAAgB,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,CAAC;IAC1C,YAAY,EAAE,MAAM,OAAO,CAAC;IAC5B,MAAM,EAAE,CACN,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAChD,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;CACrC;AAED,MAAM,MAAM,oBAAoB,GAAG,KAAK,IAAI,CAAC,EAAE,GAAG,KAAK,eAAe,CAAC;AACvE,MAAM,MAAM,qBAAqB,GAAG,KAAK,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;AAEpE,MAAM,WAAW,eAAe;IAC9B,gBAAgB,EAAE,oBAAoB,CAAC;IACvC,iBAAiB,EAAE,qBAAqB,CAAC;IACzC,cAAc,EAAE,qBAAqB,CAAC;IACtC,cAAc,EAAE,qBAAqB,CAAC;IACtC,aAAa,EAAE,qBAAqB,CAAC;CACtC;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;AAE/D,MAAM,WAAW,uBAAuB;IACtC,eAAe,CAAC,EAAE,iBAAiB,CAAC;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7D,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,wBAAsB,mBAAmB,CACvC,eAAe,GAAE,iBAA+D,GAC/E,OAAO,CAAC,eAAe,CAAC,CAE1B;AAiGD,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,cAAc,CAAC,CASzB"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Shared URL fetcher for CLI init + dashboard quickstart flows.
3
+ *
4
+ * AgentOS exposes WebSearchService from the `@framers/agentos/web-search`
5
+ * subpath. The package root does not export it, and the service is a
6
+ * search API rather than a single-URL scraper. This helper uses the real
7
+ * search API when provider keys are configured, then falls back to direct
8
+ * text/HTML fetch for ordinary public URLs.
9
+ *
10
+ * @module paracosm/cli/fetch-seed-url
11
+ */
12
+ export async function loadWebSearchModule(importWebSearch = () => import('@framers/agentos/web-search')) {
13
+ return importWebSearch();
14
+ }
15
+ function registerConfiguredProviders(service, mod, env) {
16
+ if (env.FIRECRAWL_API_KEY)
17
+ service.registerProvider(new mod.FirecrawlProvider(env.FIRECRAWL_API_KEY));
18
+ if (env.TAVILY_API_KEY)
19
+ service.registerProvider(new mod.TavilyProvider(env.TAVILY_API_KEY));
20
+ if (env.SERPER_API_KEY)
21
+ service.registerProvider(new mod.SerperProvider(env.SERPER_API_KEY));
22
+ if (env.BRAVE_API_KEY)
23
+ service.registerProvider(new mod.BraveProvider(env.BRAVE_API_KEY));
24
+ }
25
+ function normalizeUrlForCompare(raw) {
26
+ try {
27
+ const url = new URL(raw);
28
+ url.hash = '';
29
+ return url.toString().replace(/\/$/, '');
30
+ }
31
+ catch {
32
+ return raw.replace(/\/$/, '');
33
+ }
34
+ }
35
+ async function fetchViaAgentOSSearch(url, options) {
36
+ const mod = await loadWebSearchModule(options.importWebSearch);
37
+ const service = new mod.WebSearchService({ maxResults: 5 });
38
+ registerConfiguredProviders(service, mod, options.env ?? process.env);
39
+ if (!service.hasProviders())
40
+ return null;
41
+ const results = await service.search(url, { maxResults: 5, rerank: false });
42
+ if (results.length === 0)
43
+ return null;
44
+ const wanted = normalizeUrlForCompare(url);
45
+ const exact = results.find((result) => normalizeUrlForCompare(result.url) === wanted);
46
+ const withContent = results.find((result) => typeof result.content === 'string' && result.content.trim().length > 0);
47
+ const result = exact ?? withContent ?? results[0];
48
+ const text = (result.content || result.snippet || '').trim();
49
+ if (!text)
50
+ return null;
51
+ return {
52
+ text,
53
+ title: result.title || '',
54
+ sourceUrl: url,
55
+ };
56
+ }
57
+ function decodeBasicHtmlEntities(text) {
58
+ return text
59
+ .replace(/&nbsp;/g, ' ')
60
+ .replace(/&amp;/g, '&')
61
+ .replace(/&lt;/g, '<')
62
+ .replace(/&gt;/g, '>')
63
+ .replace(/&quot;/g, '"')
64
+ .replace(/&#39;/g, "'");
65
+ }
66
+ function extractTitleFromHtml(html) {
67
+ const match = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
68
+ return match ? decodeBasicHtmlEntities(match[1].replace(/\s+/g, ' ').trim()) : '';
69
+ }
70
+ function stripHtmlToText(html) {
71
+ return decodeBasicHtmlEntities(html
72
+ .replace(/<head[\s\S]*?<\/head>/gi, ' ')
73
+ .replace(/<script[\s\S]*?<\/script>/gi, ' ')
74
+ .replace(/<style[\s\S]*?<\/style>/gi, ' ')
75
+ .replace(/<noscript[\s\S]*?<\/noscript>/gi, ' ')
76
+ .replace(/<[^>]+>/g, ' ')
77
+ .replace(/\s+/g, ' ')
78
+ .trim());
79
+ }
80
+ async function fetchDirectly(url, fetchImpl = fetch) {
81
+ const res = await fetchImpl(url, {
82
+ headers: { Accept: 'text/html,text/plain,application/xhtml+xml;q=0.9,*/*;q=0.1' },
83
+ signal: AbortSignal.timeout(15_000),
84
+ });
85
+ if (!res.ok) {
86
+ throw new Error(`HTTP ${res.status}`);
87
+ }
88
+ const contentType = res.headers.get('content-type') || '';
89
+ const raw = await res.text();
90
+ const isHtml = /\bhtml\b/i.test(contentType) || /<html[\s>]/i.test(raw);
91
+ return {
92
+ text: isHtml ? stripHtmlToText(raw) : raw.trim(),
93
+ title: isHtml ? extractTitleFromHtml(raw) : '',
94
+ sourceUrl: url,
95
+ };
96
+ }
97
+ export async function fetchSeedFromUrl(url, options = {}) {
98
+ try {
99
+ const viaSearch = await fetchViaAgentOSSearch(url, options);
100
+ if (viaSearch)
101
+ return viaSearch;
102
+ }
103
+ catch {
104
+ // Fall through to direct fetch. Some AgentOS providers are search-only
105
+ // and may reject exact URL lookups; public URLs can still be fetched.
106
+ }
107
+ return fetchDirectly(url, options.fetchImpl);
108
+ }
109
+ //# sourceMappingURL=fetch-seed-url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-seed-url.js","sourceRoot":"","sources":["../../src/cli/fetch-seed-url.ts"],"names":[],"mappings":"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"}