- GDScript 93.6%
- Python 3%
- GAP 2.2%
- Shell 1.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
The addon shipped as a skeleton with a manifest, a dock and 3,312 lines of contract code and no executable evidence. This adds that evidence and fixes every defect it exposed. Evidence: - tests/test_audit.gd contract suite, 379 checks, 16 sections, non-zero exit - tools/audit_benchmark.gd hot-path timings with a legacy control - AUDIT.md finding-by-finding record and the before/after table Fixes: dead-agent intent leakage; non-atomic and id-trusting restore; float blackboard defaults stored as int; IamSnapshot crash on a non-dictionary payload; silent acceptance of a newer payload; engine using the envelope format version as its payload version; StringName ordering nondeterminism in the intent comparator; two docstrings that contradicted their code. Performance: MemoryStore identity index and IamEngine maintained intent order remove the per-operation key scan and the per-read sort (find over 1,024 records 188.6 -> 0.82 us). |
||
| addons/iam | ||
| bench | ||
| docs | ||
| scenes | ||
| tests | ||
| tools | ||
| .gitignore | ||
| AUDIT.md | ||
| LICENSE | ||
| project.godot | ||
| README.md | ||
IAM — Intelligent Agent Model
IAM is the suite's agent-AI engine. It turns a perception into a memory, memory plus drives into a plan, and a plan into a single ActionIntent that the game executes. It is a Godot 4.7 addon with no scene-tree dependency in its decision path, so its whole runtime can be exercised headlessly.
Status: skeleton. The MVP core is implemented and tested: determinism, memory store, blackboard, agent, brain registry, engine, world-fact query, intent routing, and snapshot/restore. The EnC behaviour port is not done — see docs/MIGRATION_FROM_ENC.md for the ordered plan and docs/ARCHITECTURE.md for the MVP-core/later split.
Layout
iam/
addons/iam/ the installable plugin (this is what a game vendors)
core/ data contracts and stateless runtime services
runtime/ the facade, the per-agent state object, the intent router
docs/ architecture, API reference, migration plan
scenes/playground.* standalone runnable demo
tests/ headless SceneTree test suites
bench/ standalone benchmarks + committed baseline
tools/ packaging, test runner and benchmark runner
Quick start
var engine := IamEngine.new()
engine.world_seed = 1234
engine.register_brain(&"forager", ForagerBrain.new())
engine.set_world_facts(my_world_facts) # a WorldFactQuery subclass
engine.add_agent(my_agent) # an Agent with an AgentProfile
engine.intent_emitted.connect(_on_intent)
engine.step(tick) # one simulation tick
engine.intent_for(agent_id) returns the current intent. The game keeps its own
motion, animation and rendering; IAM only decides.
Verify
From this directory:
export HOME=<this repo>/../.fakehome # only needed in a sandboxed environment
godot --headless --path . --import
./tools/run_tests.sh
godot --headless --path .
The last command runs scenes/playground.tscn: two agents with different brains
over a fake world-fact query, printing an intent log and quitting.
Suite relationship
IAM is deliberately independent of WorldMaker and WeatherPP. The suite shares
conventions, not code. In particular
IamSnapshot repeats the envelope field names
of WorldMaker's SnapshotEnvelope so a game has one serialisation habit, but it
is a separate implementation with its own migrations. The alternative — a shared
dsp_core addon — and the tradeoff are recorded in
docs/ARCHITECTURE.md
as a decision flagged for the user.
Ownership
| Owned by IAM | Owned by the game |
|---|---|
| Perception, memory, knowledge and relationship contracts | What senses exist and what they can detect |
| Drive and utility-curve shapes | Specific drive weights and curve values (policy data) |
ActionIntent production, priority, expiry and scheduling |
Executing intents: HumanMotion.step, animation, rendering, physics |
| Bounded memory, decay and hearsay semantics | Save-file layout outside the IAM snapshot envelope |
| Deterministic per-agent random streams | World seeds, tick cadence, the simulation clock |
IAM does not own species content, recipes, traits, or needs values. Those are plugin-policy data, not engine code.
Benchmarks
Runs standalone with no game present and no scene tree: the world is a two-method fake query and the brains are registered in the benchmark itself.
./tools/run_bench.sh # run and print the table
./tools/run_bench.sh --compare # gate against bench/baseline.json
./tools/run_bench.sh --update # rewrite the baseline (say why in the commit)
Results go to bench/results/iam.json, gitignored because it is machine-specific.
bench/baseline.json is the tracked artifact; tools/compare_bench.py fails when
a case is slower than +25%, comparing medians over 9 measured runs after 2
discarded warmup runs.
Engine cases run 100 agents over 100 ticks. Headline observations from the first baseline (2026-09-15); the 2026-09-16 audit (AUDIT.md) then rewrote the memory and intent-ordering paths, so the memory rows below are historical:
MemoryStorewas O(n) per operation. At the first baseline a lookup against a 1,000-record store cost ~88 µs, and filling an unbounded store was O(n²), because every operation linearly scanned records and rebuilt aStringidentity key per comparison. The audit added a derived identity index;AUDIT.mdrecords the before/after table (a 1,024-recordfindfell from 188.6 µs to 0.82 µs). That mattered before EnC ports its humans across, sincehuman_memory.gdcarries the same shape.- The identity index is rebuilt when
recordschanges size, sorecordsis store-owned and must not be mutated in place. - Determinism is cheap (~195 ns per stream), so hashing per decision instead of sharing an RNG is affordable.
- Stepping is ~2.8 µs per agent-tick, which is the number to watch as species adapters are ported in.
The protocol is documented in EnC at docs/PLUGIN_BENCHMARK_PROTOCOL.md. The same
harness, runner and gate are used by every plugin in the suite.
License
MIT — see LICENSE.