Obscurum AI
Guides

Live bring-up

Take the bots from tested logic to alive on a server — the full runbook.

Take the bots from "tested logic" to "alive on a server." Everything up to the in-client test can be done by anyone with server access; the final in-game verification (joining, seeing a bot move/react, hearing its voice) has to be done by a human in the DayZ client.

   DayZ server (your private box)
   ├─ DayZServer  + @ObscurumAI  (server-side mod: PlayerBase bot, perception, combat, bridge)
   └─ obscurum-brain sidecar      (Rust HTTP service on 127.0.0.1:8088)
            │  POST /tick  {snapshot, profile}  ->  {agent, intents:[...]}

        the brain (reactive core + optional LLM tier + voice)

The mod calls the sidecar each low-cadence tick; reflexes (locomotion/aim) run every frame locally, so a slow/dropped reply just means "keep the last intents." Never blocks the game.

1. Build + run the brain sidecar

Matches the project convention. The dev overlay publishes 127.0.0.1:8088 only (loopback, not public).

cd obscurum-ai
docker compose -f docker-compose.yml -f docker-compose.dev.yml --env-file .env.dev up -d --build
curl -fsS http://127.0.0.1:8088/health        # -> ok

Fastest to iterate.

cd obscurum-ai/brain
RUSTC_WRAPPER="" cargo build --release --features "server llm-http"
OBSCURUM_BRAIN_ADDR=127.0.0.1:8088 \
OBSCURUM_LLM_BASE_URL=$OBSCURUM_LLM_BASE_URL \
OBSCURUM_LLM_MODEL=$OBSCURUM_LLM_MODEL \
OBSCURUM_LLM_KEY=$OBSCURUM_LLM_KEY \
  ./target/release/obscurum-brain
# -> "obscurum-brain listening 127.0.0.1:8088"

Env: OBSCURUM_BRAIN_ADDR (bind), OBSCURUM_BRAIN_TOKEN (optional bearer gate), OBSCURUM_LLM_* (enable the dialogue tier; omit for silent reactive-only bots).

Config: the sidecar loads a ServerConfig — either from a local bundle dir (self-host) or pulled from the SaaS control-plane by key (see the API reference). Scaffold a local bundle with:

python3 ops/tools/voice/obsconfig.py init --game dayz --preset hardcore-pvp --out ./serverconfig

Smoke-test the wire contract without the game:

curl -s localhost:8088/tick -H 'content-type: application/json' \
  -d '{"snapshot":{"agent":1,"time_s":0,"self_state":{"pos":{"x":0,"y":0,"z":0},"heading_deg":0,"health":1,"blood":1,"hunger":0.5,"thirst":0.5,"has_weapon":true,"ammo":30},"targets":[]},"profile":{}}'
# -> {"agent":1,"intents":[ ... ]}

2. Install the @ObscurumAI mod on the server

It is a server-side mod (no client download needed for the bot logic).

# copy the mod folder next to the server binary
cp -r obscurum-ai/dayz/mod/@ObscurumAI  /path/to/DayZServer/
# add it to the SERVER mod list (note -servermod, not -mod)
./DayZServer -config=serverDZ.cfg -servermod=@ObscurumAI -profiles=profiles

The mod's config.cpp registers the scripts under 4_World/ObscurumAI/. The obscurumai_bridge.c points at http://127.0.0.1:8088/tick — same box as the sidecar.

3. Spawn bots + verify the loop

The bots are modded PlayerBase survivors made via ObscurumAI_MakeBot(a, b) (obscurumai_bot.c). Trigger a spawn from your mission init.c or an admin tool, then watch:

  • Server RPT log: [OAI] lines (perceived counts, brain steps).
  • Sidecar log: incoming POST /tick once per bot per cadence.
  • A bot should start patrolling between its two waypoints and face/engage a hostile that comes into line of sight (reactive tier — works even with the LLM off).

If the sidecar sees no requests: check the bridge URL/port, the server's outbound loopback, and that -servermod=@ObscurumAI actually loaded (RPT "Loading mod").

4. In-game verification (you, in the client)

Join your private server and confirm, in this order (cheapest first):

  1. A bot moves (patrol) and turns to face you.
  2. A hostile bot engages (closes/aims/fires); a coward flees; a wounded one investigates a lost contact.
  3. With the LLM tier on: the bot talks (an Intent::Say line) in character.
  4. Voice (advanced, see §5): you hear the bot over proximity voice, and it reacts to what you say.

Tactics (tactics.rs) — flank-behind, ambush a waterhole, hold a prone snipe, conceal when outmatched — surface as MoveTo/Engage targets the bridge already actuates; the only addition the embodiment still needs is a posture channel to play prone/crouch animations (see §6).

5. Voice bring-up (advanced)

Voice is proven offline; live wiring on the server:

  • Voice-IN (bots hear players): the eBPF uprobe on VoNServer::retranslateVoiceData
    • ops/tools/voice/von_stream.py (Opus decode -> STT) -> POST utterances onto the bot's heard_speech. Root + an STT key.
  • Voice-OUT (bots speak): von_tts.py (TTS, with provider failover) -> encode Opus -> inject a VoNControlPacket via the server relay. Per-voice consistency + emotes.

Run the voice sidecars on the same box; keep them off the hot path.

6. Known remaining work before "perfect live"

  • Posture channel — DONE: IntentSet.posture (standing/crouched/prone) is now in the wire contract and set by the brain (a bot crouches up close, drops prone for a long shot). The mod just reads intentset.posture and plays the matching stance animation.
  • Loadout application: loadout.rs presets exist; wire the mod to equip them at spawn.
  • Waypoint routes / formations / hearing: waypoint.rs/formation.rs/hearing.rs logic is ready; feed routes + POIs into the snapshot and consume the resulting targets.
  • These are embodiment wiring, not new brain logic — the decisions already exist and pass tests.

Checklist

  • curl localhost:8088/health ok
  • /tick smoke test returns intents
  • @ObscurumAI loads (RPT) and bots spawn
  • sidecar receives /tick per bot
  • bot patrols + faces + engages (reactive)
  • bot talks (LLM tier)
  • voice in/out (advanced)

On this page