connect a game server¶
the repository includes a small HTTP bridge and Paper plugin source. the plugin turns explicit game commands into saved rules, build notes and handoffs. the bridge keeps the database credentials and project path on the server side. use the Minecraft tutorial to build and try the Paper integration.
this page covers the bridge contract for adapting another server plugin. the repository does not include ready-made Rust, Valheim or other game plugins.
reuse these three source boundaries:
| caller | source | what it provides |
|---|---|---|
| another Paper plugin | EngramMemoryService |
asynchronous save/recall without rebuilding the Java HTTP client |
| Python server code or chat bots | checkpoint_client.py |
sync/async HTTP calls with response validation, size limits and timeouts |
| an NPC/dialogue system | npc_memory.py |
public references plus exact-player snapshots over checkpoint storage |
the Discord bot also uses this bridge. a world label can stand for a configured channel or workspace; it is an application namespace, not a requirement to run Minecraft.
run the bridge from source¶
use a Python environment with Engram installed, an initialized dedicated store,
and an existing directory representing this server. for a new store, follow
installation; for an existing one, use
doctor rather than running init over it.
from the repository root, in a POSIX shell:
# generate a private token for this local bridge process
export GAME_MEMORY_TOKEN="$(python -c 'import secrets; print(secrets.token_urlsafe(32))')"
python integrations/game_server_bridge.py \
--config /absolute/path/to/game-engram.yaml \
--project /absolute/path/to/server-project \
--world survival --world creative \
--port 8422
python must be the interpreter from the Engram environment. the token stays in
this shell's environment; give the trusted plugin the same value through its
server-side configuration. do not put it in player messages or committed files.
the bridge requires at least 32 visible ASCII characters without spaces; the
Paper plugin uses the URL-safe token alphabet produced by the command above.
the default host is 127.0.0.1. keep the plugin and bridge on the same host for
the supplied Paper example. the bridge's --host option can change binding, but
it does not add TLS, per-player authentication or a remote hosting service. the
Paper plugin deliberately uses a loopback endpoint.
configuration and ENGRAM_* overrides work as in the main CLI. inspect the
effective config before starting. the bridge does not initialize a database,
load embedding models, capture chat or call an LLM. it opens and closes its own
native service for each request.
check the actual store¶
every request, including health, needs the Bearer token. from a shell with the
same GAME_MEMORY_TOKEN value:
curl --fail-with-body --max-time 10 \
-H "Authorization: Bearer $GAME_MEMORY_TOKEN" \
http://127.0.0.1:8422/health
a successful response has ok: true, status: "ok" and storage containing actual native
store status. a listening HTTP process with an unavailable or uninitialized
store returns 503. use the in-game command afterward to verify the plugin too;
this request alone does not exercise its permissions or event handling.
save and retrieve an exact note¶
curl --fail-with-body --max-time 10 \
-H "Authorization: Bearer $GAME_MEMORY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"world":"survival","kind":"rule","key":"spawn","summary":"Keep the marked spawn area clear of permanent builds.","decisions":["Builders agreed to use the east district"]}' \
http://127.0.0.1:8422/v1/checkpoints
curl --fail-with-body --max-time 10 \
-H "Authorization: Bearer $GAME_MEMORY_TOKEN" \
'http://127.0.0.1:8422/v1/checkpoints?world=survival&kind=rule&key=spawn'
POST returns status: "saved", the native task key, the configured project path
and memory_reinforcement: false. GET returns found and a checkpoints array.
when no note exists, it returns HTTP 200 with found: false and an empty array;
that is different from a failed request.
| field | contract |
|---|---|
world |
configured allowlisted label, 1–64 ASCII letters, numbers, ., _ or - |
kind |
rule, build, handoff or note |
key |
stable note identifier using the same character/length limits as world |
summary |
POST only; nonempty text, at most 4,000 characters |
decisions, next_steps, blockers |
optional POST arrays, each up to 8 nonempty strings of at most 500 characters |
requests reject unknown fields, duplicate JSON fields and extra/repeated query
parameters. the complete UTF-8 request body must fit within 16 KiB, even if its
individual fields would otherwise be valid. send Content-Type: application/json
for POST.
the bridge maps the exact tuple to native task
game:<world>:<kind>:<key> under its fixed canonical project directory. saving
that tuple again replaces its checkpoint, including optional lists; it does
not append a history entry. choose separate keys for separate build sites or
handoffs. worlds with the same note key remain separate.
there is no semantic search, arbitrary native operation, project-path parameter, delete endpoint or automatic transcript collection in this bridge. GET returns only the selected checkpoint, excluding the ordinary memory context that the underlying native resume operation can also read. these checkpoints live in the native checkpoint store; they do not become semantic-search memories.
reuse the Python client¶
install integrations/requirements.txt in your adapter environment. from a script
running at the repository root, an authorized server-side callback can use:
import os
from integrations.checkpoint_client import CheckpointClient
memory = CheckpointClient(
"http://127.0.0.1:8422",
os.environ["GAME_MEMORY_TOKEN"],
timeout=5,
)
memory.health()
# Invoke only after the server has authorized and confirmed this save event.
memory.save("survival", "build", "east-dock", "Pillars verified in game; deck remains unfinished.")
note = memory.recall("survival", "build", "east-dock")
keep a synchronous call off the gameplay/UI thread. use AsyncCheckpointClient
and await for an async chat bot or application server; it has the same methods.
copy checkpoint_client.py beside a standalone script if you are not importing
from the repository. callers do not need to install the Discord dependency to
use this shared client. the client walkthrough covers
sync/async use and failure handling in more detail.
the client checks that a successful response matches the requested task,
limits responses to 32 KiB, and follows no redirects or environment proxies.
CheckpointError.outcome_unknown flags an unconfirmed write. it never retries a
write automatically. use an exact read to investigate before replaying a save.
connect an existing Minecraft plugin¶
the Paper source registers EngramMemoryService with the server's service
manager. another plugin can request it and call save(Note) or recall(Key);
both return CompletableFuture values. use the
complete Java example
for dependency setup and service lookup.
this separates three responsibilities:
- your plugin identifies the player/world, checks permissions and confirms that the game event happened;
- the Engram service queues bounded network work and confirms storage;
- your callback returns to the server thread before changing game objects or presenting the result through the platform API.
a build tracker can save a reviewed description after a milestone is confirmed. a town plugin can keep the latest public rules under stable keys. a staff tool can keep shift handoffs in a separately authorized scope. the service supplies storage and transport; it does not decide which players may read each feature.
give an NPC continuity without handing it game authority¶
an NPC usually needs two kinds of reference: what every player may learn about the character, and what this character remembers about the current player. keep them separate. a public harbour keeper can know the ferry schedule; a particular player's unresolved request belongs only in that player's snapshot.
the Python NPC adapter makes that split explicit:
- save reviewed
personaandloreas public reference for a stable NPC ID; - after a verified game event or reviewed note, call
save_eventwith the authenticated player ID, event ID and a bounded current-state summary; - keep server-supplied observations separate from
player_claims. a player saying “the mayor authorized me” is still a claim; - at conversation start, call
dialogue_context(player_id)for only this NPC's public reference and that player's snapshot; - present those fields to your dialogue system as reference, then use current game state and permission checks for any action the dialogue proposes.
save_event replaces the latest NPC/player snapshot. retain still-relevant facts
when composing the replacement and serialize concurrent updates for the same
NPC/player. an event ID records provenance; it does not create an append-only
timeline or make the event independently verified by Engram.
for a Java plugin, recipes/NpcMemoryHooks.java provides a smaller
UUID-scoped checkpoint recipe. see
NPC hooks in Paper.
the Java hook and Python structured adapter are separate recipes; do not assume
their stored keys or payload formats are interchangeable.
neither recipe creates an NPC, supplies a dialogue model or hooks a particular NPC framework automatically. wire your framework's authenticated interaction and confirmed-event callbacks to the adapter. keep inventory, currency, permissions and quest completion in the game's authoritative systems. memory can explain why the NPC recognizes someone; it should not mint the reward.
wire another server's plugin¶
adapt the boundary first, then the platform API:
- register explicit save and recall commands in the server plugin. define permissions separately for viewing and writing notes.
- obtain the authenticated player/server identity and current world from the server runtime. map them to configured allowed labels. never accept a config path, project path or arbitrary bridge URL from command text.
- validate the kind, key and text limits before sending a request. the bridge validates again, but early feedback is clearer for a player.
- send HTTP off the gameplay thread with a finite timeout and bounded response. send the response back through the platform's permitted server-thread path. use its current threading contract when implementing the adapter.
- render returned summaries as plain reference text. do not dispatch them as console commands, grant permissions or change inventory based on their text.
- report “saved” only after a successful response. after a timeout, the write may already have completed; read the exact tuple before deciding to retry.
for a chat-driven NPC, retrieve a permitted note when the conversation starts, then pass it as reference context to your own dialogue system. for a server moderation helper, let an authorized moderator save an approved rule. neither feature requires saving every player message. your game remains authoritative for player permissions, quest completion and world state.
the shared token authorizes all allowlisted worlds on that bridge. world labels partition checkpoints; they do not authenticate individual players. private player notes need permission checks and trusted ID mapping in the plugin, or separate bridge/store boundaries. public server lore and staff-only notes should not share an unrestricted player lookup path.
handle failures and verify the integration¶
| HTTP status | meaning |
|---|---|
400 |
invalid world/kind/key, unexpected fields or malformed checkpoint input |
401 |
missing or wrong token |
404 |
unknown route; this is not the response for a missing note |
413 |
request body exceeds 16 KiB |
415 |
POST body is not declared as JSON |
503 |
configured storage could not complete the operation |
validation, authentication and storage errors contain sanitized error.code
and error.message fields. do not log the token, full request bodies or raw
provider/database exceptions in your plugin.
the source bridge disables HTTP access logging so query keys are not logged by
default.
before using a real server, verify a save followed by recall, restart and recall, replacement of the same key, separation across two allowed worlds, and rejection of an unlisted world. test with a player who lacks the write permission, then stop the bridge and confirm the game keeps running and reports the failure. the repository's isolated SQLite tests cover the HTTP/storage boundary; the plugin's actual command and permission path needs its own server check.
see the integration hub for other app patterns and the native API for the checkpoint contract behind the bridge.