Cenosis Docs WorldPacks
v4.0 · WorldPack schema v1.0+

WorldPacks

WorldPacks are the authoring unit for Cenosis worlds — ZIP archives containing all the data that defines a game world: personas, locations, objects, storylets, relationships, and custom needs. All data, zero code.

Pack Format

A WorldPack is a ZIP archive named <pack-id>-<version>.npcpack. Every file inside is validated JSON against the engine's bundled JSON schemas. No executables, no scripts — the v0.4 security boundary does not move.

my-village-1.0.0/
├── manifest.json         # Required: id, version, dependencies, namespace
├── personas/             # NPC definitions, schedules, needs, constraints
│   ├── innkeeper.json
│   └── blacksmith.json
├── locations/            # Place graph with smart objects + affordances
│   ├── tavern.json
│   └── smithy.json
├── objects/              # Sims-style interactive objects advertising actions
│   └── forge.json
├── storylets/            # Director trigger/effect data
│   └── rivalry.json
├── beliefs/              # Seeded agent beliefs
├── needs/                # Custom need definitions (v1.6+)
├── relationships/        # Seeded relationships + kind definitions
├── conversations/        # Reusable conversation templates
├── storylines/           # Storyline templates
├── factions/             # Faction definitions + stance
├── economy/              # Goods, recipes, jobs (requires economy_enabled)
├── lifecycle/            # Life stages, kinship definitions
├── institutions/         # Businesses, norms, governance roles
└── schemas/              # JSON schema definitions for this pack's entities

manifest.json

{
  "id": "my.village",
  "version": "1.0.0",
  "namespace": "my",
  "display_name": "My Village",
  "description": "A small fishing village with a dark secret.",
  "requires": {
    "cenosis.base": "^4.0.0"
  },
  "optional": {
    "cenosis.economy": "^2.1.0"
  }
}
FieldDescription
idGlobally unique, dot-separated identifier. Convention: author.packname.
versionSemver string. Used for dependency resolution.
namespaceShort prefix for entity addressing. Entities are referenced as namespace.name.
requiresHard dependencies with semver range constraints.
optionalSoft dependencies — pack degrades gracefully if absent.

Personas

A persona defines a single NPC's identity, schedule, needs, and constraints.

{
  "id": "my.innkeeper",
  "name": "Mira",
  "description": "Runs the Golden Goose tavern. Practical, secretive.",
  "traits": ["pragmatic", "secretive", "hospitable"],
  "honesty": 0.6,
  "hard_constraints": [
    { "type": "ForbidTopic", "topic": "the_murder" }
  ],
  "schedule": [
    { "hour": 6,  "activity": "prep_tavern", "location": "my.tavern" },
    { "hour": 10, "activity": "serve_customers", "location": "my.tavern" },
    { "hour": 22, "activity": "sleep", "location": "my.tavern_quarters" }
  ],
  "needs": {
    "social": { "initial": 0.7, "decay_rate_per_hour": 0.03 },
    "safety": { "initial": 0.4, "decay_rate_per_hour": 0.01 }
  }
}

Storylets

Storylets are data-driven drama events. They define conditions and effects — no code, no scripting:

{
  "id": "my.rivalry_confrontation",
  "cooldown_hours": 24,
  "weight": 1.5,
  "conditions": [
    { "type": "RelationshipBelow", "dimension": "Trust", "threshold": 0.3 },
    { "type": "AgentAtLocation", "location": "my.tavern" },
    { "type": "TimeOfDay", "after": 18, "before": 23 }
  ],
  "effects": [
    { "type": "MoodDelta",         "dimension": "tension", "delta": 0.3 },
    { "type": "RelationshipDelta",  "dimension": "Fear",    "delta": 0.2 },
    { "type": "InjectDialogSeed",   "seed": "You know what you did." }
  ]
}

Smart Objects & Affordances

Locations contain SmartObjects that advertise affordances — possible actions an agent can take. This is the Sims-style model: agents pick from advertised affordances, never invent actions.

{
  "id": "my.hearth",
  "display_name": "Tavern Hearth",
  "affordances": [
    {
      "action": "warm_by_fire",
      "need_deltas": { "comfort": 0.15, "social": 0.05 },
      "mood_delta": 0.1,
      "duration_minutes": 20
    }
  ]
}

Custom Needs (v1.6)

Any pack can define additional need types. They integrate fully with the planner, director triggers, and LLM prompts — no engine changes required.

{
  "id": "my.safety",
  "display_name": "Safety",
  "decay_rate_per_hour": 0.01,
  "initial_value": 0.8,
  "critical_threshold": 0.2
}

Dependency Resolution

The DependencyResolver performs deterministic backtracking constraint solving of semver requires ranges across packs:

  • Newest-compatible version selection with lexical tie-breaking
  • Same algorithm as the v3.2 CapabilityRegistry for extensions
  • Deterministic by design — same pack set always resolves to the same versions

Namespace Registry

Entities are addressed as <namespace>.<name>. The NamespaceRegistry denies cross-pack references outside the dependency closure — you cannot reference other.tavern unless other is in your requires or optional.

URL Pack Installation (v1.0)

Packs can be installed from a URL directly over the C ABI:

int npc_engine_install_pack(EngineHandle*, const char* url_with_hash);
// URL format: https://cdn.example.com/my-village-1.0.0.npcpack#<blake3-hex>

Downloads are: Blake3-verified, capped at 10 MB, extracted through a strict JSON-only sandbox, cached by checksum, then validated by the pack loader. The preflight check prevents partial installs on buffer-size errors.

Visual Pack Editor

The editor/ directory contains a Tauri 2 desktop shell with a full-featured GUI for authoring WorldPacks:

  • Schema validation as-you-type with inline error markers
  • Cross-reference checking — warns on undefined entity references
  • Live preview — ticks a headless engine instance and reports per-agent need/relationship deltas
  • Lossless open/save round-tripping — JSON key order is preserved

Detached workspace

The editor is in a detached Tauri workspace (editor/) excluded from the main engine workspace — Tauri/WebView dependencies don't affect cargo check/clippy/test --workspace.