This document is the technical, developer-facing companion to the public/project README.
It is intentionally more detailed than the root README.md, and it is written for engineers who need to:
- understand what this repository actually is today;
- run it locally in its different modes;
- debug or extend the simulation runtime;
- work on the Electron shell, AI provider integrations, or experiment pipeline;
- inherit the codebase without relying on outdated assumptions.
This file is based on the repository state inspected on 2026-03-28.
At a high level, this repository is a hybrid codebase that combines:
- a React application for interactive AI-driven social simulation;
- an Electron shell for desktop delivery;
- local AI integration through Ollama;
- cloud AI integration through Gemini;
- browser-side AI and translation support through WebGPU/WebLLM and
@huggingface/transformers; - a multi-agent simulation runtime with world state, memory, social state, and experiment orchestration;
- a local HTTP API and batch runner for protocol, benchmark, replay, and ablation workflows.
This is not just a chat UI.
It is closer to a combined product made of:
- an interactive simulation frontend;
- a local-first AI client;
- a desktop app wrapper;
- a social/agent runtime;
- an experiment harness for reproducible runs and metrics.
The codebase reflects that history. Some parts are cohesive and actively used. Some parts are legacy carryovers from earlier iterations. Some configuration and documentation still reference older tooling or older naming.
This README tries to describe the project as it really exists, not as a cleaned-up idealized architecture.
The repository uses multiple names for overlapping concepts. This is important because it can confuse both onboarding and release discussions.
| Name | Where it appears | What it means in practice |
|---|---|---|
aiagent-app |
repo folder, package.json name |
repository/package identity |
AI Social Lab |
UI, package.json product name, index.html, Electron window title, docs |
current product name |
AI Agent Ultra |
cleanup fallback in packaging script, historical references in old artifacts/history | previous desktop/product label |
AI Family Simulation |
main component/file naming and some older concepts | older or narrower framing of the simulation use case |
Recommended internal language:
- use
aiagent-appfor repository discussions; - use
AI Social Labfor the current application and packaging discussions; - treat
AI Agent UltraandAI Family Simulationas legacy names that may still appear in older code paths.
If this project continues to evolve, naming should be normalized. Right now it is functional but inconsistent.
The following checks were run directly against the repository on 2026-03-28:
node scripts/world-validate.cjs: passednpm test: passed (33files,115tests)npm run build: passednpm run electron:build: passed
Also observed during inspection:
src/contains about156files- there are at least
33test files insrc/(32.test.jsfiles and1.test.jsxfile)
What was not fully verified in the same pass:
- the Git object store still needs deeper cleanup even though normal
git statusaccess was restored by repairingHEAD - cross-platform packaging outside the current Windows environment was not verified
Git state after the cleanup pass:
HEADnow points back torefs/heads/maingit statusworks againgit fsck --fullstill reports missing historical objects plus an index cache-tree warning, so the repository is operational again but not fully pristine
Build-time observations from the verified Vite build:
- the client build is successful but heavy
- a large WASM asset is emitted from the browser AI stack
- Vite reports several modules that are both dynamically and statically imported, so some intended chunk-splitting does not fully materialize
Modules flagged by Vite in the inspected build:
src/services/AIAdapter.jssrc/services/DirectorService.jssrc/services/BioEngine.jssrc/utils/vectorEngine.jssrc/services/webLlmService.js
- React
19.x - React DOM
19.x - React Router DOM
6.x - Vite
7.x - Tailwind CSS
3.x - Lucide React icons
- Electron
39.x - Electron Packager
16.0.0
- Ollama HTTP API for local models
- Google Gemini via
@google/generative-ai @huggingface/transformersfor browser translation/model features- browser-side vector-memory ranking worker
- Vitest
- Testing Library
- JSDOM
- no
enginesfield is enforced inpackage.json - existing docs assume
Node.js 18+andnpm 9+ - Vite is the active frontend dev/build toolchain
- some repository files still reflect prior Create React App assumptions
This section focuses on the directories that matter to developers.
| Path | Role | Notes |
|---|---|---|
src/ |
primary source code | most of the active logic lives here |
public/ |
public assets and synced worker output | public/vector.worker.js is generated from source |
scripts/ |
validation, batch, API, sync, and repair scripts | includes both active and legacy-support scripts |
build/ |
Vite production build output | generated artifact |
dist/ |
packaged or distributable output | generated artifact |
build_check_orchestrator/ |
example run outputs for orchestrator/pipeline checks | generated data |
build_check_worker/ |
distributed/worker smoke output | generated data |
_recovery_snapshots/ |
recovery or replay-related output | generated data |
AgentSociety/ |
currently empty in the inspected state | no active role was identified |
electron.cjs |
Electron main process | window creation, Ollama IPC bridge, devtools shortcuts |
preload.cjs |
Electron preload bridge | exposes restricted Ollama stream APIs |
AIagent.jsx |
standalone mount/API bridge module | not the main app entrypoint |
Primary flow:
src/index.jsxsrc/App.jsxsrc/AIFamilySimulation.jsx
What each file does:
-
src/index.jsx- creates the React root
- wraps the app in
ErrorBoundary - disables most console output in production
- removes the splash screen after load
-
src/App.jsx- uses
HashRouter - renders the simulation container
- this is appropriate for file-based/Electron routing
- uses
-
src/AIFamilySimulation.jsx- the top-level application container
- orchestrates most UI state, persistence, modals, onboarding, import/export, simulation controls, and settings
Important architectural fact:
src/AIFamilySimulation.jsxis approximately1898lines long- it functions as a large "god component"
- many cross-cutting concerns still converge there
Desktop flow:
electron.cjspreload.cjs- renderer loaded from
http://127.0.0.1:3000in dev - renderer loaded from
build/index.htmlin production
Important Electron behavior:
- the BrowserWindow uses
contextIsolation: true,sandbox: true, andnodeIntegration: false - external links are opened in the system browser
- trusted renderer origin is restricted:
- dev:
http://localhost:3000andhttp://127.0.0.1:3000 - prod:
file://
- dev:
- the app auto-checks whether Ollama is running and attempts to start it locally
- global shortcuts are registered for DevTools:
Ctrl/Cmd + Shift + IF12
These are the non-UI execution surfaces:
scripts/society-api-server.cjsscripts/society-batch-runner.cjsscripts/world-validate.cjs
These scripts instantiate the runtime and experiment pipeline directly from source modules in src/agent/ and src/experiments/.
Important note:
- these scripts use
require('sucrase/register') sucraseis now declared directly inpackage.json- that removes the old hidden-dependency problem from clean installs
The codebase is easiest to understand as a set of layers rather than a strict clean architecture.
The UI lives mostly in src/components/ and src/AIFamilySimulation.jsx.
Main responsibilities:
- timeline display
- agent panels and detail modals
- settings, onboarding, and help flows
- overlays for Ollama connection and generation state
- world generation and feedback panels
- God Mode, debugging, and operational controls
Notable components:
SettingsModal.jsxTimeline.jsxAgentPanel.jsxAgentDetailModal.jsxOllamaConnectOverlay.jsxHelpGuide.jsxWorldGenesisModal.jsxAgentDebugPanel.jsxGodModePanel.jsx
SettingsModal.jsx matters more than a normal settings screen because it controls real runtime behavior:
- provider mode
- model selection
- map pack
- orchestration history limit
- translation-related features
- data reset
- connection testing
Primary hooks:
src/hooks/useAIGeneration.jssrc/hooks/useOllamaConnection.jssrc/hooks/useSimulationEngineRuntime.jssrc/hooks/useSimulationEngineStore.jssrc/hooks/useAutoConnect.js
Roles:
-
useAIGeneration.js- main generation runtime
- executes the simulation turn pipeline
- integrates AI provider calls, retries, quality gates, memory diffusion, consolidation, and orchestration logging
-
useOllamaConnection.js- tests provider availability
- handles WebGPU/Gemini/Ollama mode checks
- surfaces latency, connection errors, and model availability
-
useSimulationEngineRuntime.js- wraps the simulation task queue
- manages immediate reaction and forced turn requests
-
useSimulationEngineStore.js- holds app-visible simulation state such as timeline, agents, world state, social state, bio state, and UI state
-
useAutoConnect.js- scans for likely local AI endpoints
- mainly used to discover Ollama-like services
Important architectural fact:
src/hooks/useAIGeneration.jsis approximately1796lines long- it is another "god module" in the current codebase
- large changes in simulation behavior usually involve this file
The simulation engine is spread across:
src/engine/src/engine/phases/
Main concerns:
- simulation task queue
- world schema validation
- map and world rules
- response parsing
- scheduling
- planning
- evaluation
- governance/institution phases
- error and retry policy
Representative files:
src/engine/SimulationRuntime.jssrc/engine/WorldSchemaValidator.jssrc/engine/WorldRules.jssrc/engine/UrbanMapEngine.jssrc/engine/phases/perceivePhase.jssrc/engine/phases/schedulePhase.jssrc/engine/phases/planPhase.jssrc/engine/phases/actPhase.jssrc/engine/phases/evaluationPhase.jssrc/engine/phases/qualityGatePhase.js
This layer is where "simulation turn" logic lives, distinct from raw UI control.
Primary directories:
src/agent/src/experiments/
Main agent/runtime responsibilities:
- message bus
- agent memory
- agent policy and context dispatch
- intervention handling
- runtime metrics
- agent selection by role or cohort
Representative files:
src/agent/SocietyRuntime.jssrc/agent/message/MessageBus.jssrc/agent/core/FamilyAgentKernel.jssrc/agent/core/AgentPolicyEngine.jssrc/agent/core/AgentContextDispatcher.js
Experiment/orchestration responsibilities:
- seed scenarios
- run pipeline batches
- deterministic replay
- protocol runs
- ablation suites
- benchmarks and Monte Carlo variants
- job management for async local API execution
Representative files:
src/experiments/SocietyExperimentPipeline.jssrc/experiments/ExperimentOrchestrator.jssrc/experiments/ExperimentJobManager.jssrc/experiments/ExperimentKpiService.jssrc/experiments/ProtocolRegistry.js
This is one of the most important distinctions in the repository:
- the UI is only one surface
- the social runtime and experiment pipeline are real reusable subsystems
Key files:
src/services/AIAdapter.jssrc/services/RequestQueue.jssrc/services/aiConnection.jssrc/services/webLlmService.js
Provider model:
-
Local Ollama
- default local-first path
- accessed via HTTP in browser mode
- accessed via Electron IPC bridge in desktop mode when URL is local
-
Gemini
- cloud provider path via SDK
- also used as fallback in some failure scenarios if a key exists
-
WebGPU/WebLLM
- supported as a browser-side path
- contributes significantly to bundle size and build output
RequestQueue.js is important because it serializes asynchronous provider calls. This matters for Ollama and similar local runtimes that can degrade under concurrent requests.
Key files:
src/translations.jssrc/services/LanguageGuardService.jssrc/services/TranslationGlossary.js
What this layer does in practice:
- stores UI text bundles
- attempts to keep model output in the selected target language
- supports browser translation via HuggingFace runtime when available
- falls back to LLM-driven translation when necessary
- persists translation cache locally
- applies glossary consistency and override rules
Important reality:
- the repository also contains
src/locales/*.json - however, the primary app flow imports
src/translations.js src/locales/*.jsonare now synced/generated mirrors viascripts/sync-locales.cjs- so
src/translations.jsis the practical source of truth for UI strings
Key files:
src/services/WorldSystemService.jssrc/services/MapPackService.jssrc/engine/WorldSchemaValidator.jssrc/data/urbanMap.default.jsonsrc/data/urbanMap.megacity.jsonsrc/data/worldRules.default.jsonsrc/data/experimentProtocols.default.jsonsrc/data/benchmarkProfiles.default.json
Responsibilities:
- validate map and world rules
- initialize or repair world state
- apply map packs
- relocate agents/objects when a pack changes and current locations are invalid
- expose diagnostics and descriptions for runtime use
Current built-in map packs:
default->MetroLitemegacity->MetroMega100
Primary persistence utilities:
src/utils.jssrc/services/OrchestrationStorageService.js
The application is local-first. There is no backend database for normal app state.
Most persistent state is stored through an IndexedDB wrapper in src/utils.js.
Important note:
src/idb-local.jscontains the low-level key/value IndexedDB helperssrc/utils.jsnow delegates the baseget/setoperations tosrc/idb-local.js- the main application flow still consumes the higher-level utilities exported from
src/utils.js
Source flow:
- source of truth:
src/services/vector.worker.js - synced output:
public/vector.worker.js - sync script:
scripts/sync-vector-worker.cjs
Rule:
- edit
src/services/vector.worker.js - do not manually edit
public/vector.worker.js
The following scripts already sync it for you:
npm run sync:generatednpm startnpm run build
The app does not only track text messages. It maintains several related state domains.
Main state slices visible in the UI/runtime:
- timeline
- agents
- family knowledge
- world state
- social state
- bio state
- UI state
Key defaults live in src/constants.js:
- world presets
- initial agents
- initial world state
- initial relationships
- initial bio state
- recommended models
- default settings
Default setting highlights:
ollamaUrl: http://localhost:11434model: hermes3:latesttheme: darklanguage: vimodelLanguage: engenerationInterval: 10000mapPackId: defaultorchestrationHistoryLimit: 120
Interpretation:
- the product is still local-first by default
- Vietnamese is the default UI language
- model-facing language is still biased toward English
- Ollama on localhost is the baseline assumption
npm installnpm startWhat it does:
- syncs generated locale mirrors from
src/translations.js - syncs
vector.worker.js - runs Vite on
127.0.0.1:3000 - enforces
strictPort
Expected URL:
http://127.0.0.1:3000
Important note:
- the active dev server binds to
127.0.0.1, not0.0.0.0
npm run electron:devWhat it does:
- starts the Vite dev server
- waits for TCP port
3000 - launches Electron
This is the primary way to test the desktop shell during development.
npm run buildOutput:
build/
Vite build settings in vite.config.js:
base: './'outDir: 'build'emptyOutDir: true
npm run electron:buildWhat it currently does:
- runs
clean - syncs generated locale/worker assets
- runs the web build
- packages the app with
electron-packager
Important note:
- packaging is now described directly by the
electron:buildscript plus top-level package metadata - the old unused desktop-builder-style
"build"block was removed during cleanup
npm run society:apiDefault server:
http://localhost:4488
Quick health check:
curl http://localhost:4488/healthGeneric command:
npm run society:batch -- --ticks 200 --agents 100 --output build_check_orchestrator/result.jsonUseful examples:
Basic batch run:
npm run society:batch -- --ticks 200 --agents 100 --output build_check_orchestrator/result.jsonDeterministic replay check:
npm run society:batch -- --ticks 120 --agents 80 --replay-runs 3 --output build_check_orchestrator/replay_result.jsonProtocol suite:
npm run society:batch -- --mode protocol --agents 80 --baseline-ticks 60 --followup-ticks 60 --seed 2026 --replay-runs 3 --output build_check_orchestrator/protocol_result.jsonProtocol by registry ID:
npm run society:batch -- --mode protocol --protocol-id stability_recovery --agents 80 --replay-runs 3 --output build_check_orchestrator/protocol_registry_result.jsonAblation suite:
npm run society:batch -- --mode ablation --agents 80 --ticks 60 --include-roles government,bank --treatment-ratio 0.5 --replay-runs 2 --output build_check_orchestrator/ablation_result.jsonBenchmark suite:
npm run society:batch -- --mode benchmark --agents 80 --protocol-ids stability_recovery,employment_shock,inflation_guardrail --output build_check_orchestrator/benchmark_result.jsonBenchmark profile:
npm run society:batch -- --mode benchmark --profile-id core_city --agents 80 --output build_check_orchestrator/benchmark_profile_result.jsonMonte Carlo benchmark:
npm run society:batch -- --mode benchmark-mc --agents 80 --protocol-ids stability_recovery,employment_shock --runs-per-protocol 4 --base-seed 2026 --output build_check_orchestrator/benchmark_mc_result.jsonDistributed benchmark:
npm run society:batch -- --mode benchmark-distributed --profile-id core_city --workers 3 --agents 100 --output build_check_orchestrator/benchmark_distributed_result.json| Command | What it really does | Notes |
|---|---|---|
npm start |
starts Vite dev server after syncing generated locale/worker assets | active frontend dev entry |
npm run dev |
alias of npm start |
same behavior |
npm run electron:dev |
runs Vite and Electron together | main desktop dev flow |
npm run build |
syncs generated locale/worker assets, then runs the production web build | writes to build/ |
npm run electron:build |
web build plus desktop packaging | uses electron-packager |
npm run electron:pack |
alias of electron:build |
same behavior |
npm run clean |
kills running packaged app process and removes dist/ |
Windows-oriented script |
npm run world:validate |
validates map/rule JSON | useful quick safety check |
npm run society:batch |
runs the experiment pipeline from CLI | supports multiple modes |
npm run society:distributed |
distributed benchmark preset | uses profile core_city |
npm run society:api |
local HTTP API for experiments and jobs | default port 4488 |
npm run lang:scan |
scans for mojibake/corrupted text | maintenance utility |
npm run lang:repair |
repairs known mojibake patterns | maintenance utility |
npm test |
runs the Vitest suite | full suite not revalidated in one pass |
npm run test:watch |
runs Vitest in watch mode | normal dev test mode |
| Port | Purpose |
|---|---|
3000 |
Vite dev server |
11434 |
Ollama default local server |
4488 |
local society API server |
| Variable | Used by | Purpose |
|---|---|---|
REACT_APP_OLLAMA_URL |
vite.config.js, src/constants.js |
default Ollama base URL |
PUBLIC_URL |
vite.config.js, src/utils.js |
affects public asset paths, including worker path |
PORT |
scripts/society-api-server.cjs |
local API server port |
OLLAMA_ORIGINS |
external environment / helper scripts | CORS allowlist for browser-to-Ollama access |
OLLAMA_HOST |
external Ollama config | bind host for Ollama |
The repository now uses one main default pattern:
Default local-development allowlist:
fix_cors_windows.ps1sets:OLLAMA_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
dev.batandlauncher.batnow use the same localhost-only allowlist for their session environment
That means:
- the repo no longer defaults to
OLLAMA_ORIGINS=* - local development still works without widening browser access more than necessary
- LAN/mobile access now requires an intentional Ollama configuration change instead of being opened implicitly
Purpose:
- configure Ollama for localhost browser access with a safer allowlist
- restart Ollama
Behavior:
- sets
OLLAMA_ORIGINSat user level - stops existing Ollama processes
- attempts to restart
ollama serve
Purpose:
- convenience launcher for Windows development
Behavior:
- installs dependencies if
node_modulesis missing - sets the localhost-only
OLLAMA_ORIGINSallowlist for the session - starts the dev server
Purpose:
- older Windows launcher for dev/prod/build/check workflows
Behavior:
- offers a simple menu
- can run dev mode
- can serve the
build/folder - can build
- can run a basic Ollama connectivity check
Important note:
- this script has been brought closer to the current repository identity
- it still remains a thin Windows helper, not the canonical source of operational behavior
The app persists a meaningful amount of local state.
Main storage wrapper:
src/utils.js
Storage backend:
- IndexedDB for most structured app state
localStoragefor some flags, caches, and glossary-related entries
| Key | Purpose |
|---|---|
ai_family_settings_v2 |
app settings |
ai_family_agents_v2 |
persisted agents state |
ai_family_timeline_v2 |
persisted timeline |
ai_family_knowledge |
family knowledge store |
ai_orchestration_runs_v1 |
orchestration history |
ai_family_save_{slot} |
slot-based saves used directly by the main app |
ai_family_saves_v2 |
older/parallel save-manager style aggregate storage |
| Key | Purpose |
|---|---|
language_auto_set |
tracks whether initial language auto-detection already ran |
ai_onboarding_completed |
onboarding completion flag |
training_dataset |
training/debug dataset collection used by the app |
ai_translation_cache_v1 |
persisted translation cache |
ai_translation_glossary_overrides_v1 |
persisted glossary override data |
The repository currently has some overlap in persistence patterns:
- slot saves are stored individually as
ai_family_save_{slot} SaveManageralso usesai_family_saves_v2src/utils.jsandsrc/idb-local.jsstill split high-level vs low-level persistence responsibilities
This is workable, but it is still not a single clean persistence abstraction.
The simulation runtime is not a single provider call.
At a high level, a typical generation cycle goes through something like this:
- Read current settings and simulation state.
- Sync the active agent/runtime view.
- Resolve language handling between UI language and model language.
- Determine whether there is a pending reaction event or forced turn.
- Run perception/context assembly.
- Run scheduling to choose the next speaker.
- Build prompt context from timeline, agents, world state, and memory.
- Call the AI provider.
- Parse the response into structured output.
- Apply timeline, memory, bio, social, and world updates.
- Run diffusion and consolidation phases.
- Run evaluation and possible interventions.
- Persist or append orchestration metadata where appropriate.
Key files involved:
src/hooks/useAIGeneration.jssrc/engine/phases/*src/services/AIAdapter.jssrc/services/LanguageGuardService.jssrc/services/RequestQueue.js
The app supports several runtime modes, but they are not all equal in maturity or complexity.
This is the default local-first path.
Behavior:
- default URL is
http://localhost:11434 - in browser mode, it uses direct HTTP requests
- in Electron with a local URL, it can route stream requests through the preload/main-process IPC bridge
Why the IPC bridge exists:
- it avoids some browser/CORS friction for localhost access
- it restricts the exposed surface to approved endpoints
Gemini is supported as a cloud mode.
Behavior:
- configured through
geminiKey - used explicitly when provider/mode indicates Gemini
- may also become a fallback through queue/circuit-breaker logic if a local path fails and a key is present
This mode is supported in the app and contributes to:
- large build output
- large WASM payloads
- more demanding browser runtime requirements
It is useful, but it also raises bundle and runtime complexity compared with the pure local-Ollama path.
This app does more than simply switch UI labels.
It attempts to:
- keep generated output in the selected user language
- translate between UI-facing and model-facing language contexts
- cache translations locally
- apply glossary consistency to reduce terminology drift
- repair mojibake or corrupted text where possible
Main implementation files:
src/services/LanguageGuardService.jssrc/services/TranslationGlossary.jssrc/utils/mojibakeFix.jssrc/translations.js
Operational takeaway:
- translation is part of the runtime behavior, not just a presentation layer concern
- bugs in language enforcement can affect agent behavior, memory contents, and UI text
The simulation includes a structured world model.
That world includes:
- objects and object states
- maps and places
- roads and reachability
- institutional/economic state
- world rules and action categories
Validation:
scripts/world-validate.cjsvalidates:- default map
- megacity map
- world rules
- institution rule structure
If you change any of the following, run validation:
src/data/urbanMap.default.jsonsrc/data/urbanMap.megacity.jsonsrc/data/worldRules.default.json
Map-pack behavior:
- changing the map pack in settings can relocate agents and objects to valid fallback places
- this relocation is explicit behavior, not an accidental side effect
One of the most important parts of the repository is that it supports reproducible experiment-style execution, not just interactive UI simulation.
Core concepts:
- protocol run
- benchmark run
- ablation run
- deterministic replay
- Monte Carlo benchmark
- distributed benchmark
- async local job execution through the API server
Key files:
src/experiments/SocietyExperimentPipeline.jssrc/experiments/ProtocolRegistry.jssrc/experiments/ExperimentOrchestrator.jssrc/experiments/ExperimentJobManager.jssrc/services/SocietyApiClient.js
The experiment pipeline is capable of:
- seeding agent populations
- running ticks in batch
- comparing before/after intervention behavior
- computing protocol KPIs
- aggregating benchmark statistics across runs
This is one of the strongest parts of the repository from an engineering/product perspective.
The local HTTP API in scripts/society-api-server.cjs exposes runtime and experiment capabilities without requiring the browser UI.
Default base URL:
http://localhost:4488
| Route | Purpose |
|---|---|
/health |
server health and agent count |
/metrics |
runtime metrics snapshot |
/protocols |
list available protocols |
/benchmark-profiles |
list available benchmark profiles |
/jobs |
list recent jobs |
/jobs/:id |
inspect one job |
| Route | Purpose |
|---|---|
/syncAgents |
seed/sync runtime agents and social/institution state |
/tick |
run tick batch |
/experiment/survey |
run survey experiment |
/experiment/interview |
run interview experiment |
/experiment/intervention |
run intervention experiment |
/pipeline/run |
run full pipeline |
/pipeline/protocol |
run protocol suite or protocol by ID |
/pipeline/replay |
run deterministic replay |
/pipeline/ablation |
run ablation suite |
/pipeline/benchmark |
run benchmark suite |
/pipeline/benchmark-mc |
run Monte Carlo benchmark |
/pipeline/benchmark-distributed |
run distributed benchmark |
/jobs/run |
queue an async job |
Health:
curl http://localhost:4488/healthList protocols:
curl http://localhost:4488/protocolsReplay:
curl -X POST http://localhost:4488/pipeline/replay -H "Content-Type: application/json" -d "{\"tickCount\":40,\"seed\":2026,\"runs\":3}"Protocol:
curl -X POST http://localhost:4488/pipeline/protocol -H "Content-Type: application/json" -d "{\"protocolId\":\"stability_recovery\",\"replayRuns\":3}"Ablation:
curl -X POST http://localhost:4488/pipeline/ablation -H "Content-Type: application/json" -d "{\"ticks\":50,\"includeRoles\":[\"government\",\"bank\"],\"treatmentRatio\":0.5,\"replayRuns\":2}"Benchmark:
curl -X POST http://localhost:4488/pipeline/benchmark -H "Content-Type: application/json" -d "{\"protocolIds\":[\"stability_recovery\",\"employment_shock\",\"inflation_guardrail\"]}"Async job:
curl -X POST http://localhost:4488/jobs/run -H "Content-Type: application/json" -d "{\"taskType\":\"benchmark-mc\",\"payload\":{\"protocolIds\":[\"stability_recovery\"],\"runsPerProtocol\":2,\"baseSeed\":2026}}"Use this section as a fast navigation map.
Read first:
src/AIFamilySimulation.jsxsrc/App.jsxsrc/components/*
Read first:
src/services/AIAdapter.jssrc/hooks/useOllamaConnection.jssrc/services/RequestQueue.jselectron.cjspreload.cjs
Read first:
src/hooks/useAIGeneration.jssrc/engine/phases/*src/engine/SimulationRuntime.js
Read first:
src/agent/SocietyRuntime.jssrc/agent/core/*src/agent/message/MessageBus.js
Read first:
src/experiments/SocietyExperimentPipeline.jssrc/experiments/ProtocolRegistry.jssrc/experiments/ExperimentOrchestrator.jsscripts/society-batch-runner.cjsscripts/society-api-server.cjs
Read first:
src/data/*src/services/WorldSystemService.jssrc/services/MapPackService.jssrc/engine/WorldSchemaValidator.jsscripts/world-validate.cjs
Read first:
src/services/LanguageGuardService.jssrc/services/TranslationGlossary.jssrc/translations.jssrc/utils/mojibakeFix.js
Read first:
src/utils.jssrc/services/OrchestrationStorageService.jssrc/idb-local.js
This is the section that matters most for honest onboarding.
The root README.md and TROUBLESHOOTING.md were cleaned up to match the current Vite/Electron flow and to remove the previous encoding drift in troubleshooting content.
They are now substantially closer to the truth of the current repo.
The old compatibility files:
scripts/start.jssrc/setupProxy.js
were removed because they no longer matched the live Vite workflow.
If you are debugging startup or proxy behavior, treat:
package.jsonscriptsvite.config.js
as the actual source of truth.
The repository still contains:
src/translations.jssrc/locales/*.json
But the relationship is clearer now:
src/translations.jsremains the editable source of truthsrc/locales/*.jsonare synced/generated mirrors viascripts/sync-locales.cjs- dev/build flows call
npm run sync:generatedbefore running Vite
Two central files are especially large:
src/AIFamilySimulation.jsx(~1.9k lines)src/hooks/useAIGeneration.js(~1.8k lines)
Practical impact:
- changes often have broad side effects
- regressions can be easy to introduce
- large refactors should be done in narrow, testable slices
The old unused desktop-builder-style package.json "build" metadata was removed.
Current packaging truth:
npm run electron:buildelectron-packager
This is clearer than before, but still intentionally lightweight rather than a formal release pipeline.
Generated or output-heavy directories include:
build/dist/build_check_orchestrator/build_check_worker/_recovery_snapshots/
This is convenient for quick local use, but it also increases noise and makes source/output boundaries less clear.
The direct HEAD breakage was repaired, so normal git status access works again.
However:
git fsck --fullstill reports missing historical objects- the index cache-tree still shows a warning
So the repo is operational again for normal day-to-day inspection, but not fully pristine at the object-store level.
The directory exists but was effectively empty in the inspected state.
If it is intended as a future module boundary, it should be documented. If not, it should be cleaned up.
The batch/API scripts still use sucrase/register, but sucrase is now declared directly in package.json.
That particular install-time ambiguity has been removed.
The app is not lightweight.
From the inspected build:
- a browser AI WASM artifact above
21 MBwas emitted - the main JS bundle is large
- the
transformersbundle is also large
Practical consequences:
- slower cold starts
- slower builds
- larger desktop/web footprint
- more memory pressure in the browser
If performance work becomes a priority, these are likely first areas to investigate:
- WebGPU/WebLLM dependencies
- translation/runtime chunking
- static-plus-dynamic import overlap
- the size and breadth of
useAIGeneration.js
The repository has a meaningful amount of test coverage, especially around:
- world schema validation
- simulation engine pieces
- experiments
- runtime services
- reducers
- translation/mojibake utilities
Useful targeted checks:
node scripts/world-validate.cjsnpx vitest run src/services/SocietyApiClient.test.jsnpx vitest run src/engine/WorldSchemaValidator.test.jsFull suite:
npm testWatch mode:
npm run test:watchRecommendation:
- run the targeted tests closest to the subsystem you changed
- run
world:validatewhen touching map/rules data - run a build when touching provider or bundling behavior
Recommended onboarding sequence:
- Read this file.
- Read
package.jsonto understand scripts and runtime surfaces. - Read
src/constants.jsto understand defaults and baseline data assumptions. - Read
src/App.jsxandsrc/AIFamilySimulation.jsxto understand the main app shell. - Read
src/hooks/useAIGeneration.jsto understand the simulation runtime. - Read
src/agent/SocietyRuntime.jsandsrc/experiments/SocietyExperimentPipeline.jsto understand the non-UI core. - Run
node scripts/world-validate.cjs. - Run
npm startornpm run electron:dev. - If working on providers, read
src/services/AIAdapter.js,src/hooks/useOllamaConnection.js, andsrc/services/RequestQueue.js. - If working on world or protocol data, read
src/data/*,src/services/WorldSystemService.js, andsrc/engine/WorldSchemaValidator.js.
Look at:
src/engine/phases/*src/hooks/useAIGeneration.js
Look at:
src/experiments/SocietyExperimentPipeline.jssrc/experiments/ProtocolRegistry.jsscripts/society-batch-runner.cjsscripts/society-api-server.cjs
Look at:
src/components/SettingsModal.jsxsrc/constants.jssrc/AIFamilySimulation.jsx
Look at:
src/services/MapPackService.jssrc/services/WorldSystemService.jssrc/data/urbanMap*.jsonscripts/world-validate.cjs
Look at:
src/services/AIAdapter.jssrc/services/RequestQueue.jselectron.cjspreload.cjs
Look at:
src/services/LanguageGuardService.jssrc/services/TranslationGlossary.jssrc/translations.js
If the project is going to be actively developed further, the highest-value maintenance tasks are probably:
- Finish the deeper Git object-store cleanup so
git fsck --fullis clean, not justgit status. - Continue normalizing legacy internal naming (
AIFamilySimulation, older labels, historical artifacts). - Break down
AIFamilySimulation.jsxanduseAIGeneration.jsinto smaller units. - Reduce bundle weight and investigate the dynamic/static import overlap warnings from the browser AI stack.
- Clarify source vs generated artifacts in the repository layout.
- Keep translation edits centered in
src/translations.jsand treatsrc/locales/*.jsonas generated output.
This repository is strong in a few important ways:
- it already contains a real multi-agent simulation runtime
- it has more than one execution surface: web, Electron, batch, and local API
- it includes world validation and experiment orchestration, not just UI
- it has non-trivial tests across several subsystems
- it still builds successfully in its current inspected state
It is also uneven in predictable ways:
- naming is inconsistent
- documentation drift exists
- a few central modules are too large
- some legacy tooling/configuration remains
- some dependencies and generated artifacts are not managed as cleanly as they could be
The right way to work in this codebase is not to assume it is already tidy. The right way is:
- use this file as the engineering map
- verify behavior against the live code
- make changes in narrow slices
- prefer local truth over inherited assumptions
That approach fits the actual state of the project much better than treating it like a clean-slate application.
This appendix is meant to reduce first-contact friction when someone opens the repository for the first time.
Top-level subdirectories:
src/agent/src/components/src/data/src/engine/src/experiments/src/hooks/src/locales/src/services/src/utils/
Top-level source files worth knowing:
src/index.jsxsrc/App.jsxsrc/AIFamilySimulation.jsxsrc/constants.jssrc/reducers.jssrc/translations.jssrc/utils.jssrc/idb-local.jssrc/index.css
Role:
- agent runtime, memory kernel, message bus, and policy dispatching
Important files:
src/agent/SocietyRuntime.jssrc/agent/message/MessageBus.jssrc/agent/core/FamilyAgentKernel.jssrc/agent/core/AgentKernel.jssrc/agent/core/AgentMemory.jssrc/agent/core/AgentPolicyEngine.jssrc/agent/core/AgentContextDispatcher.jssrc/agent/core/defaultBlocks.js
What to expect here:
- the agent layer is not just a display model
- it contains runnable behavior and diagnostics
- interventions and dialogue distribution eventually pass through this layer
Role:
- user-facing UI components and control surfaces
Current component list observed in the repo:
AgentDebugPanel.jsxAgentDetailModal.jsxAgentPanel.jsxAvatar.jsxChaosDiceButton.jsxConnectionStatusBadge.jsxErrorBoundary.jsxFeedbackModal.jsxGenerativeOverlay.jsxGodModePanel.jsxHelpGuide.jsxModelLibraryModal.jsxOllamaConnectOverlay.jsxSettingsModal.jsxSignalStatus.jsxSmartDoctorModal.jsxSoulManagerModal.jsxTimeline.jsxToast.jsxWorldGenesisModal.jsx
Operationally important UI components:
SettingsModal.jsx: behavior and runtime configurationTimeline.jsx: event renderingAgentPanel.jsxandAgentDetailModal.jsx: character managementOllamaConnectOverlay.jsx: connection bootstrap and guidanceSmartDoctorModal.jsx: onboarding and environment diagnosisAgentDebugPanel.jsx: debug surface
Role:
- built-in simulation data and benchmark defaults
Current built-in data files:
worldRules.default.jsonurbanMap.default.jsonurbanMap.megacity.jsonexperimentProtocols.default.jsonbenchmarkProfiles.default.json
This directory is effectively the baseline content/config package for the simulation runtime.
Role:
- simulation engine primitives, world validation/rules, and turn runtime support
Important files:
SimulationEngine.jsSimulationRuntime.jsSimulationInputTypes.jsWorldSchemaValidator.jsWorldRules.jsWorldRulePack.jsUrbanMapEngine.jsSocietyRoleService.js
The internal store engine:
SimulationEngine.jsis a small custom state container- it supports slice reducers and batch dispatching
- React hooks consume it through
useSyncExternalStore
Simulation input types currently defined:
immediate_reactionforce_speaker_turngenerate_tick
Role:
- the staged generation/simulation pipeline
Current phase and support files observed:
actPhase.jsconsolidationPhase.jsdiffusionPhase.jserrorPolicy.jsevaluationPhase.jsgovernPhase.jsinstitutionPhase.jsperceivePhase.jsplanPhase.jspromptBuilderPhase.jsqualityGatePhase.jsrecallPhase.jsresponseParser.jsretryPolicy.jsschedulePhase.js
When the app "takes a turn", this directory is where most of the staged runtime behavior is defined.
Role:
- orchestration, benchmarks, protocols, KPIs, and experiment job management
Important files:
SocietyExperimentPipeline.jsProtocolRegistry.jsExperimentOrchestrator.jsExperimentJobManager.jsExperimentKpiService.jsExperimentStatsService.js
If you are trying to understand how benchmark or replay modes work, this is the first directory to study.
Role:
- connects React to the simulation runtime and provider state
Important files:
useAIGeneration.jsuseOllamaConnection.jsuseSimulationEngineState.jsuseSimulationEngineStore.jsuseSimulationEngineRuntime.jsuseAutoConnect.js
The most important relationships are:
useSimulationEngineState.jscreates the internal slice-based simulation storeuseSimulationEngineStore.jsexposes state plus refs to the latest valuesuseSimulationEngineRuntime.jsadds queue-based input executionuseAIGeneration.jsuses all of the above to run the actual simulation loop
Role:
- runtime services, provider adapters, diagnostics, persistence helpers, and sidecar systems
Current service files observed:
AgentPlanner.jsAIAdapter.jsaiConnection.jsBioEngine.jsCharacterFactory.jsConsolidationService.jsCriticAgent.jsDirectorService.jsGpuCapabilityService.jsLanguageGuardService.jsMapPackService.jsNetworkGuardService.jsNewsService.jsOrchestrationStorageService.jsRequestQueue.jsSocietyApiClient.jsTimeService.jsTranslationGlossary.jsvector.worker.jsWeatherService.jswebLlmService.jsWorldSystemService.js
This is the most mixed directory in the repository. It contains:
- AI adapter logic
- language tooling
- hardware diagnostics
- orchestration persistence
- world/map services
- external-data-like services
Role:
- lower-level helpers and specialized utilities
Examples:
vectorEngine.jshardwareBenchmarker.jstimeEngine.jsmojibakeFix.jsgeoLocator.jsdreamEngine.jsconfigGenerator.js
This folder overlaps conceptually with src/services/ in places. The separation is not always strict.
The runtime store is not Redux, Zustand, or MobX. It is a custom slice-based store implemented with:
src/engine/SimulationEngine.jssrc/hooks/useSimulationEngineState.jssrc/hooks/useSimulationEngineStore.js
The internal simulation state is initialized with:
timelineagentsfamilyKnowledgeworldStatesocialStatebioStateuiState
Initial values come from:
INITIAL_AGENTSINITIAL_WORLD_STATEINITIAL_RELATIONSHIPSINITIAL_BIO_STATE- empty defaults for timeline, family knowledge, and UI widgets
SimulationEngine.js:
- stores a plain JS object of slices
- maps each slice to a reducer
- supports
dispatchTo(sliceKey, action) - supports
dispatchBatch(batch) - notifies subscribers via a simple listener set
useSimulationEngineState.js:
- creates one
SimulationEngineinstance - exposes each slice through
useSyncExternalStore - provides dispatch helpers for each slice
useSimulationEngineStore.js:
- wraps
useSimulationEngineState.js - mirrors current slice values into refs
- gives runtime code access to the latest state without stale closure issues
Important timeline actions observed:
ADD_EVENTREMOVE_LAST_EVENTUPDATE_EVENTRESET_TO_INDEXCLEARINITTOGGLE_LIKETRUNCATE_TIMELINEUPDATE_EVENT_TEXTUPDATE_EVENT_BY_IDREMOVE_EVENT_BY_ID
Non-obvious behavior:
- updating system events tends to re-arm reaction flags such as
requiresReactionandreactionHandled - timeline truncation is used by rewind/butterfly-effect behavior
Important agent actions observed:
ADD_AGENTDELETE_AGENTUPDATE_MEMORIESUPDATE_MEMORY_INDEXUPDATE_MEMORY_TYPEDELETE_MEMORY_INDEXADD_SINGLE_MEMORYUPDATE_AGENT_DETAILSUPDATE_PERSONALITYUPDATE_AGENTADD_MEMORYADD_REFLECTIONADD_MEMORIES_ALLSUMMARIZE_MEMORIESROLLBACK_MEMORIESCLEAR_MEMORIESREBUILD_MEMORIESINITRESTORE_SNAPSHOT
Important constraints:
- agent count is capped by
MAX_AGENT_COUNT - memory trimming happens through
trimMemories(...) - system agent handling is special-cased in several places
Important actions:
ADD_KNOWLEDGEINIT
Important behavior:
- deduplicates entries
- normalizes capitalization
- keeps only the latest
KNOWLEDGE_WINDOWentries
Important actions:
INITADD_GHOSTDELETE_GHOSTUPDATE_OBJECTUPDATE_INSTITUTIONSRESTORE_SNAPSHOT
Important behavior:
- delegates to
WorldSystemService - world init merges and sanitizes map/rule payloads
Important actions:
INITUPDATE_RELATIONSHIPRESTORE_SNAPSHOT
Important behavior:
- scores are clamped
- relationship labels are derived from score bands
- relation change reasons can be stored
Important actions:
INITUPDATE_ALL_BIOUPDATE_BIORESTORE_SNAPSHOTTRUNCATE_TIMELINETICK_METABOLISM
Important behavior:
- energy, dopamine, and cortisol are bounded values
- there is both direct update behavior and periodic metabolism-like decay behavior
Important actions:
INITADD_WIDGETREMOVE_WIDGETUPDATE_WIDGETCLEAR_ALL
This slice represents transient UI widgets, not the whole visual app state.
The repository contains multiple layers of provider and network logic:
- selection of provider mode
- connectivity checks
- request serialization
- transport-specific behavior
- fallback or degraded-mode handling
In practice, provider routing is determined by the current settings and some convenience heuristics.
High-level paths:
- WebGPU path
- active when
apiProvider === 'webgpu'ormode === 'webgpu'
- active when
- Gemini path
- active when
apiProvider === 'gemini' - also inferred in some cases when a Gemini-like key is present
- active when
- Ollama path
- used as the default local path when not in a cloud/WebGPU path
From useOllamaConnection.js, the check order is effectively:
- WebGPU shortcut
- Gemini check
- Ollama/local endpoint check
useOllamaConnection manages:
connectionStatuserrorCountlastErrorlatencyavailableModels
It also exposes checkConnection(...).
Special behaviors:
- WebGPU mode is treated as ready without a network roundtrip
- Gemini mode tests several model candidates until one succeeds
- Ollama mode:
- checks
/api/tags - checks whether the endpoint is actually Ollama
- then performs a lightweight generation call to verify the selected model path
- checks
Observed categories include:
CHECK_IN_PROGRESSAUTH_MISSINGQUOTA_EXCEEDEDPERMISSION_DENIEDMODEL_NOT_FOUNDMIXED_CONTENTTIMEOUTREMOTE_ACCESS_DENIEDOLLAMA_NOT_RUNNINGMODEL_ERRORUNKNOWN
These categories matter because:
- they affect toast text
- they affect whether the app pauses or retries
- they affect how much guidance the UI can provide
The app explicitly checks for this scenario:
- browser page is served over
https: - Ollama endpoint is
http:
If that is true, the browser path is considered blocked by mixed-content policy.
This is surfaced as:
- code:
MIXED_CONTENT - message: HTTPS app cannot call HTTP endpoint
Remote endpoint handling is also treated differently from localhost:
- remote failure gets more explicit "remote access" guidance
- localhost failure gets more "is Ollama running?" guidance
src/services/RequestQueue.js is the queue that prevents runaway concurrent provider calls.
Important behavior:
- serial execution
- retry with backoff
- cancellation/debounce by task ID
- queue clearing
- a "circuit breaker" that can switch persisted provider settings to Gemini if Ollama is failing and a Gemini key already exists
This is one of the most operationally important services in the repository.
When AIAdapter uses the Ollama path:
- if
window.electronAPIexists - and the base URL looks local (
localhostor127.0.0.1) - then the adapter can use the Electron IPC bridge for streaming
Why that matters:
- it reduces some browser CORS friction
- it keeps the renderer-side API narrow
- it only applies to local URLs, not arbitrary remote endpoints
The CLI batch runner is scripts/society-batch-runner.cjs.
It supports:
- inline flags
- optional config file input
- output file writing
Observed flags:
--config--output--mode--protocol-id--protocol-ids--profile-id--include-roles--exclude-roles--treatment-ratio--runs-per-protocol--base-seed--workers--ticks--baseline-ticks--followup-ticks--seed--agents--replay-runs
| Flag | Meaning |
|---|---|
--config |
path to JSON config file |
--output |
output JSON path |
--mode |
pipeline mode such as pipeline, protocol, ablation, benchmark, benchmark-mc, benchmark-distributed |
--protocol-id |
single protocol registry ID |
--protocol-ids |
comma-separated list of protocol IDs |
--profile-id |
benchmark profile ID |
--include-roles |
comma-separated role filter |
--exclude-roles |
comma-separated exclusion filter |
--treatment-ratio |
ablation treatment ratio |
--runs-per-protocol |
Monte Carlo/distributed runs per protocol |
--base-seed |
base seed for repeated benchmark runs |
--workers |
worker count for distributed or Monte Carlo flows |
--ticks |
generic tick count |
--baseline-ticks |
protocol baseline window |
--followup-ticks |
protocol follow-up window |
--seed |
deterministic seed |
--agents |
seeded agent count |
--replay-runs |
deterministic replay repetition count |
The runner can also read a JSON config file containing fields such as:
agentssocialStateinstitutionStateagentCountbaseNamemodeprotocolIdprofileIdticksbaselineTicksfollowupTicksseedreplayRunsincludeRolesexcludeRolestreatmentRatiorunsPerProtocolbaseSeedworkersoverrides
The runner writes a JSON file containing:
- normalized run config
- result payload
- optional deterministic replay summary
The CLI also logs:
- mode
- protocol/profile info where relevant
- agent count
- tick counts
- replay status where relevant
- output path
The client wrapper for the local API is src/services/SocietyApiClient.js.
Defaults observed:
- base URL:
http://localhost:4488 - timeout:
15000ms - retry count:
2 - retry delay:
350ms - retry backoff:
1.8
Retryable HTTP statuses:
408425429500502503504
Observed client methods:
health()metrics()listProtocols()listBenchmarkProfiles()syncAgents(payload)tick(payload)runSurvey(payload)runInterview(payload)runIntervention(payload)runPipeline(payload)runProtocol(payload)runReplay(payload)runAblation(payload)runBenchmark(payload)runBenchmarkMonteCarlo(payload)runBenchmarkDistributed(payload)runJob(taskType, payload)listJobs()getJob(jobId)waitForJob(jobId, options)
These are the practical payload fields accepted by the local server, based on server-side parsing logic.
POST /syncAgents
agentssocialStateinstitutionStateagentCountbaseName
POST /tick
tickCountseed
POST /experiment/survey
surveysampleSizetag
POST /experiment/interview
questionsampleSizetag
POST /experiment/intervention
interventionfollowupSurveytag
POST /pipeline/run
tickssurveyEveryinterviewSampleSizeintervention
POST /pipeline/protocol
protocolIdbaselineTicksfollowupTicksseedreplayRunssurveyinterventioninterviewQuestioninterviewSampleSizesampleSizeresetToSeed
POST /pipeline/replay
tickCountseedruns
POST /pipeline/ablation
ticksseedincludeRolesexcludeRolestreatmentRatiointerventionfollowupSurveyreplayRunsresetToSeed
POST /pipeline/benchmark
protocolIdsprofileIdoverridesresetToSeed
POST /pipeline/benchmark-mc
protocolIdsprofileIdoverridesrunsPerProtocolbaseSeedworkersresetToSeed
POST /pipeline/benchmark-distributed
protocolIdsprofileIdoverridesrunsPerProtocolbaseSeedworkersresetToSeed
POST /jobs/run
taskTypepayload
waitForJob(jobId, options):
- polls every
1200msby default - defaults to a
300000mstimeout - can stop on failed status
- supports
onUpdate - throws on timeout or failed final state
The current protocol registry comes from:
src/data/experimentProtocols.default.jsonsrc/data/benchmarkProfiles.default.json
stability_recovery
- title:
Stability Recovery - purpose: baseline run, policy intervention, follow-up for social risk stabilization
- defaults:
baselineTicks: 40followupTicks: 40seed: 2026replayRuns: 3
employment_shock
- title:
Employment Shock - purpose: stress labor response under low employment pressure
- defaults:
baselineTicks: 50followupTicks: 50seed: 2027replayRuns: 2
inflation_guardrail
- title:
Inflation Guardrail - purpose: track citizen pressure and policy compliance under inflation
- defaults:
baselineTicks: 45followupTicks: 45seed: 2028replayRuns: 2
core_city
- title:
Core City Baseline - protocol IDs:
stability_recoveryemployment_shockinflation_guardrail
- defaults:
runsPerProtocol: 3baseSeed: 2026workers: 2
macro_policy_stress
- title:
Macro Policy Stress - protocol IDs:
employment_shockinflation_guardrailstability_recovery
- defaults:
runsPerProtocol: 4baseSeed: 3040workers: 3
rapid_regression
- title:
Rapid Regression - purpose: fast smoke-style benchmark profile
- protocol IDs:
stability_recovery
- defaults:
runsPerProtocol: 2baseSeed: 1500workers: 2
ProtocolRegistry.js provides:
- listing
- lookup by ID
- normalization of IDs
- fallback behavior
Observed defaults:
- protocol fallback resolves toward
stability_recovery - benchmark profile fallback resolves toward
core_city
The Electron preload exposes a deliberately narrow API under window.electronAPI.
Observed methods:
ollamaStreamRequest(payload)ollamaStreamCancel(requestId)onOllamaReply(handler)onOllamaReplyEnd(handler)onOllamaError(handler)
electron.cjs enforces:
- trusted sender URL only
- payload shape checks
- request ID validation
- endpoint allowlist
Allowed endpoints:
/api/generate/api/chat
Request constraints:
requestIdmust be a non-empty string- max
requestIdlength is constrained - duplicate in-flight IDs are aborted before replacement
The main-process bridge always sends to:
- protocol:
http: - host:
localhost - port:
11434
That means:
- the IPC bridge is a localhost-only Ollama bridge
- it is not a generic remote proxy
This design narrows the attack surface compared with exposing broad file or network access to the renderer.
At the same time, it means:
- remote Ollama endpoints will still go through browser fetch logic, not the Electron local bridge
- debugging local vs remote provider behavior requires understanding both code paths
This section gives practical "what happens if..." summaries.
Scenario:
- run
npm start - app served on
http://127.0.0.1:3000 - Ollama on
http://localhost:11434
Behavior:
- Vite serves the app
- browser uses direct fetch to Ollama
- CORS matters
- no Electron IPC bridge is involved
Scenario:
- run
npm run electron:dev - renderer from localhost dev server
- Ollama local
Behavior:
- browser UI still runs via Vite
- Electron preload exists
- local Ollama streaming can use IPC instead of raw fetch in some flows
Scenario:
- static build hosted over HTTPS
- Ollama endpoint remains HTTP
Behavior:
- browser mixed-content rules block the connection
- app surfaces
MIXED_CONTENT
Scenario:
- custom remote host entered in settings
Behavior:
- browser fetch is used
- remote access/CORS/firewall concerns apply
- Electron localhost bridge does not act as a remote tunnel
Scenario:
- Gemini key configured
- provider/mode points to Gemini
Behavior:
- connection check tests Gemini models
- generation bypasses Ollama
- some local-first assumptions still exist elsewhere in the app, so test carefully after switching modes
Scenario:
- WebGPU mode selected
Behavior:
- connection is treated as available without network probing
- browser runtime complexity increases
- bundle and hardware capability concerns become more relevant
These are behaviors that are easy to miss if you only skim the code.
Updating a system event may reset:
requiresReactionreactionHandledreactionHandledAt
This is deliberate and affects replay/reactivity behavior.
The app enforces MAX_AGENT_COUNT.
If new agent payloads exceed that cap, extra agents can be dropped silently at reducer/runtime boundaries.
When adding memories:
- reducers may trim and archive memory data
- not every append results in an unbounded growth of the memory list
Changing the map pack is not a cosmetic change. It can actively relocate:
- agents
- world objects
This is good for consistency, but it means map changes can have meaningful simulation consequences.
RequestQueue.js contains circuit-breaker behavior that may:
- switch
apiProviderto Gemini - save that updated setting to storage
This is operationally useful, but it also means provider choice is not always purely manual.
Examples:
src/translations.jsis the editable translation source whilesrc/locales/*.jsonare generated mirrorssrc/utils.jsstill holds higher-level helpers, but low-level key/value access now delegates tosrc/idb-local.js- generated assets still live alongside source in the repo tree, which can blur the source/output boundary
That means code search can still reveal more than one path for a concern, but the dominant path is clearer than it was before the cleanup pass.
If you are debugging a specific class of issue, this reading order can save time.
Read in this order:
src/hooks/useAIGeneration.jssrc/services/AIAdapter.jssrc/services/RequestQueue.jssrc/hooks/useOllamaConnection.jssrc/engine/phases/errorPolicy.jssrc/engine/phases/retryPolicy.js
Read in this order:
electron.cjspreload.cjssrc/services/AIAdapter.jssrc/App.jsxsrc/index.jsx
Read in this order:
src/experiments/SocietyExperimentPipeline.jssrc/experiments/ProtocolRegistry.jssrc/data/experimentProtocols.default.jsonsrc/data/benchmarkProfiles.default.jsonscripts/society-batch-runner.cjsscripts/society-api-server.cjs
Read in this order:
src/engine/WorldSchemaValidator.jssrc/services/WorldSystemService.jssrc/services/MapPackService.jssrc/data/urbanMap.default.jsonsrc/data/worldRules.default.jsonscripts/world-validate.cjs