NeuroCompute Backend Implementation Guide

Audience: NeuroCompute engineers and coding agents implementing the server side of Appleseed integration.
Appleseed side: already ships the client bridge at /game/neurocompute-appleseed.js.
Your job: host the orchestration script, API routes, storage, and LLM loop described below.

Canonical URLs to bookmark

Overview

LayerOwnerResponsibility
Appleseed (browser) This repo Simulation, canvas, AppleseedAgentBridge, snapshots, deterministic mode, lifeforms
NC integration script NeuroCompute Patron linking, score POST, action polling, analytics wiring, launch helpers
NC API + DB NeuroCompute Persistence, leaderboard, world-map enrichment, LLM decisions, verification

Implementation checklist

Want to try the stack locally before building production APIs? Run node game/test-agent-server.mjs and open agent-playground.html to test forged worlds with preset seeds (wetlands, fungal web, arid symbiosis, lifeform lab, etc.).

1. Host the integration script

Serve a script at:

https://neurocompute.me/game/neurocompute-appleseed.js

Appleseed loads it when the game page sets:

window.ncScriptUrl = "https://neurocompute.me/game/neurocompute-appleseed.js";
window.ncPatronToken = "<patron-secret>";
window.ncRegionX = 16;
window.ncRegionY = 16;
window.ncLLMControl = true;
window.ncAnalyticsUrl = "https://neurocompute.me/api/game/appleseed/analytics";
window.ncAnalyticsModel = "local-llm-7b";
window.ncNodeName = "compute-node-3";

Minimum responsibilities of that script:

  1. Wait for window.AppleseedAgentBridge
  2. Call bridge.startRun({ ... }) with world/agent/analytics config
  3. Poll POST /api/game/appleseed/action when ncLLMControl is true
  4. Apply returned actions via bridge.applyAction(action)
  5. Forward score events (or rely on bridge auto-submit + your score endpoint)

Starter orchestration script

(function () {
  const ACTION_POLL_MS = 3000;

  function waitForBridge() {
    return new Promise((resolve) => {
      if (window.AppleseedAgentBridge) return resolve(window.AppleseedAgentBridge);
      const timer = setInterval(() => {
        if (window.AppleseedAgentBridge) {
          clearInterval(timer);
          resolve(window.AppleseedAgentBridge);
        }
      }, 100);
    });
  }

  async function pollAction(bridge) {
    if (!window.ncLLMControl) return;
    const state = bridge.getState();
    const res = await fetch("/api/game/appleseed/action", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: "Bearer " + (window.ncPatronToken || "")
      },
      body: JSON.stringify({
        state,
        agent: bridge.getActiveAgentName(),
        worldId: state.worldId,
        region: state.region
      })
    });
    if (!res.ok) return;
    const action = await res.json();
    if (action && action.type) bridge.applyAction(action);
  }

  waitForBridge().then((bridge) => {
    bridge.startRun({
      worldId: "world-" + (window.ncRegionX || 0) + "-" + (window.ncRegionY || 0),
      regionX: window.ncRegionX,
      regionY: window.ncRegionY,
      llmControl: !!window.ncLLMControl,
      activeAgentName: window.ncActiveAgentName || "NC-Agent",
      analytics: window.ncAnalyticsUrl ? {
        enabled: true,
        endpoint: window.ncAnalyticsUrl,
        model: window.ncAnalyticsModel,
        nodeName: window.ncNodeName
      } : undefined,
      autoSubmitScore: { enabled: true, onlyWhenLlmControl: true, everyMs: 45000 }
    });

    setInterval(() => pollAction(bridge), ACTION_POLL_MS);
  });
})();

2. Analytics endpoint (P0)

Route: POST /api/game/appleseed/analytics

Appleseed auto-POSTs when configureAnalytics({ endpoint }) or window.ncAnalyticsUrl is set.

Request body

{
  "event": "action_applied",
  "timestamp": 1735689600123,
  "context": {
    "gameId": "appleseed",
    "sessionId": "sess-m5abc123-xyz",
    "runId": "run-m5def456-abc",
    "worldId": "world-eu-16-16",
    "worldSeed": "WORLD-EU-16-16",
    "region": { "x": 16, "y": 16, "cellSize": 128 },
    "activeAgentName": "Scout-Alpha",
    "llmControl": true,
    "model": "local-llm-7b",
    "nodeName": "compute-node-3",
    "simulationSpeed": 6,
    "deterministic": true
  },
  "payload": { "...event-specific fields..." },
  "state": { "...full getState() on key events only..." }
}

Events to store

eventWhenNotes
run_startedLLM run bootIncludes state
action_appliedEvery bridge actionHigh volume — index by runId
score_submittedManual or auto scoreIncludes state
score_auto_submittedAuto-submit intervalIncludes state
snapshot_createdCheckpoint savedIncludes state
disaster_startedStorm/drought/fire
lifeform_spawnedCustom species spawn
lifeform_unlockedApple-gated unlock
active_agent_changedAgent rename

Suggested table: game_analytics_events

id              UUID PRIMARY KEY
event           TEXT NOT NULL
session_id      TEXT NOT NULL
run_id          TEXT
world_id        TEXT
region_x        INT
region_y        INT
agent_name      TEXT
model           TEXT
node_name       TEXT
llm_control     BOOLEAN
payload_json    JSONB
state_json      JSONB
created_at      TIMESTAMPTZ DEFAULT now()

-- indexes
CREATE INDEX idx_analytics_session ON game_analytics_events(session_id);
CREATE INDEX idx_analytics_run ON game_analytics_events(run_id);
CREATE INDEX idx_analytics_agent ON game_analytics_events(agent_name) WHERE llm_control = true;

Response

{ "ok": true }

Return 200 quickly. Use async workers for heavy processing.

3. LLM action endpoint (P0)

Route: POST /api/game/appleseed/action

Called every ~3s by the NC integration script while ncLLMControl=true.

Request

{
  "state": { "...full AppleseedAgentBridge.getState()..." },
  "agent": "Scout-Alpha",
  "worldId": "world-eu-16-16",
  "region": { "x": 16, "y": 16 }
}

Authenticate with patron token (Authorization: Bearer <token> or body field).

Response — return one action within ~3 seconds

{ "type": "plant_seed" }

{ "type": "release_bird" }
{ "type": "release_bunny" }
{ "type": "release_fox" }
{ "type": "release_bear" }
{ "type": "release_bee" }
{ "type": "release_butterfly" }
{ "type": "harvest_apples" }
{ "type": "move_to", "x": 420, "y": 310 }
{ "type": "set_simulation_speed", "multiplier": 6 }
{ "type": "trigger_disaster", "disasterType": "storm", "intensity": 1.2 }
{ "type": "register_lifeform", "definition": { "id": "proto_algae", "label": "Proto Algae", ... } }
{ "type": "spawn_lifeform", "lifeformId": "proto_algae", "x": 200, "y": 150 }
{ "type": "create_snapshot", "metadata": { "reason": "llm_checkpoint" } }

Full action list: see Client Bridge API.

LLM prompt hints

Fallback

If LLM times out, return a heuristic action (e.g. plant_seed if trees < 3, else release_bee).

4. Score endpoint (P1)

Route: POST /api/game/appleseed/score

Request

{
  "patronToken": "...",
  "regionX": 16,
  "regionY": 16,
  "worldId": "world-eu-16-16",
  "activeAgentName": "Scout-Alpha",
  "score": 144,
  "biodiversity": {
    "speciesTypesPresent": 6,
    "livingCreatures": 24,
    "eggsCollected": 1,
    "counts": {
      "trees": 5, "birds": 2, "bunnies": 3, "foxes": 1,
      "bears": 0, "bees": 4, "butterflies": 2, "flowers": 8
    }
  },
  "llmControl": true,
  "model": "local-llm-7b",
  "nodeName": "compute-node-3"
}

Suggested table: game_scores

id, patron_id, world_id, region_x, region_y, score, biodiversity_json,
agent_name, llm_control, model, node_name, created_at

5. Leaderboard (P1)

Route: GET /api/game/appleseed/leaderboard?limit=20&regionX=16&regionY=16

{
  "entries": [
    {
      "patronId": "...",
      "displayName": "Scout-Alpha",
      "score": 144,
      "regionX": 16,
      "regionY": 16,
      "worldId": "world-eu-16-16",
      "biodiversity": { "...": "..." },
      "createdAt": "2026-05-24T12:00:00Z"
    }
  ]
}

6. World map enrichment (P1)

Each map cell should expose the best biodiversity score played in that region:

{
  "x": 16,
  "y": 16,
  "biodiversityScore": 144,
  "bestAgentName": "Scout-Alpha",
  "bestWorldId": "world-eu-16-16",
  "lastPlayedAt": "2026-05-24T12:00:00Z"
}

Update on score POST when new score > cell best.

7. Snapshots (P2)

Upload: POST /api/game/appleseed/snapshot

Load: GET /api/game/appleseed/snapshot/:id

Wire from Appleseed via:

bridge.setSnapshotPublisher(async (snapshot) => {
  const res = await fetch("/api/game/appleseed/snapshot", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(snapshot)
  });
  return res.json(); // { ok: true, id: "snap-...", publicUrl: "..." }
});

On neurocompute.me, link “Load world” to:

/index.html?ncRunConfig={"snapshotId":"snap-abc","worldId":"world-eu-16-16","llmControl":true}

8. Best biodiversity verification (P2)

Client state is not trusted for leaderboards. Appleseed supports server attestation:

bridge.setBestBiodiversityVerifier(async ({ candidate, snapshot, state, actionLog }) => {
  const res = await fetch("/api/game/appleseed/verify-biodiversity", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ candidate, snapshot, state, actionLog })
  });
  return res.json(); // { ok: true, source: "server", attestation: "signed-proof" }
});

9. Launch URLs

Open Appleseed in a new tab with full LLM + analytics wiring:

https://<appleseed-host>/index.html
  ?worldId=world-eu-16-16
  &regionX=16
  &regionY=16
  &llm=1
  &speed=6
  &agent=Scout-Alpha
  &model=local-llm-7b
  &node=compute-node-3
  &analytics=1
  &analyticsUrl=https://neurocompute.me/api/game/appleseed/analytics

Or hand off via localStorage:

bridge.setPendingRunConfig({ worldId, llmControl: true, analytics: { enabled: true, endpoint: "..." } });
window.open("https://<appleseed-host>/index.html", "_blank");

10. Detecting LLM play

A session is LLM-driven when all of these are true:

Query example:

SELECT run_id, agent_name, model, node_name, COUNT(*) AS actions
FROM game_analytics_events
WHERE event = 'action_applied' AND llm_control = true
GROUP BY run_id, agent_name, model, node_name
ORDER BY MAX(created_at) DESC;

References

Security: Never trust client-reported best scores without verify-biodiversity. Treat patron tokens as secrets. Rate-limit /action and /analytics per patron/session.