agent-sim
Agent-first firmware SIL testing. Load compiled firmware as a shared library, control signals and time from the CLI or an AI agent.
Inspired by agent-browser.
Quick Start
# Build the HVAC example DLL
# Build the runtime
# Load the example, power on, step time, read state
||
# Run a recipe
# Done
Architecture
CLI client ◄── JSON lines over Unix sockets ──► Env daemon (optional, env-owned time/CAN control)
├─ Instance daemons
│ └─ Project (dlopen DLL, sim_api.h ABI)
└─ Env-owned logical time + CAN send/schedule/inspect
Single binary. No external runtime dependencies. Cross-platform (Linux, macOS, Windows).
DLLs are version-checked on load via sim_get_api_version(). The runtime accepts only the current ABI version.
Concepts
| Term | Meaning |
|---|---|
| Project | Loaded shared library (.so/.dylib/.dll) implementing sim_api.h |
| Signal | Named, typed value exposed by the project. Address by name, #id, or glob |
| Tick | One simulation quantum. Duration from sim_get_tick_duration_us() |
| Device | Reusable library + optional flash preload definition |
| Instance | Running simulated instance of a device |
| Env | Coordinated collection of instances with env-owned time and env CAN control |
| Recipe | Named command sequence in agent-sim.toml |
Commands
agent-sim load [libpath] # Start instance daemon bound to DLL
agent-sim info # Project metadata
agent-sim signals # List all signals
agent-sim reset # Reset device state to deterministic startup
agent-sim get <signal> [<signal>...] # Read signals (name, #id, or glob)
agent-sim set <sig>=<val> [...] # Write signals (batch supported)
agent-sim watch <signal> [ms] # Stream signal values
agent-sim time start|pause|step|speed|status
agent-sim env start <name>
agent-sim env status <name>
agent-sim env reset <name>
agent-sim env time <name> start|pause|step|speed|status
agent-sim env can <name> buses|inspect|send|load-dbc|schedule ...
agent-sim run <recipe> # Execute recipe from config
agent-sim instance [list] # Instance info
agent-sim close # Shut down daemon
Global flags: --json, --instance <name>, --config <path>.
load is a bootstrap command: one instance daemon is permanently bound to one DLL for its lifetime. To run a different DLL or a second device, use a different --instance.
Flash preloads are part of load/device startup:
Configuration
First-match priority:
--config <path>CLI flagAGENT_SIM_CONFIGenv var./agent-sim.tomlin working directory- Empty defaults
See examples/hvac/agent-sim.toml for device/env/recipe examples.
Creating a DLL
Use the template/ scaffold. Edit src/adapter.zig (logic + signals) and project.zig (name + includes).
- Human-oriented authoring guide:
docs/template-guide.md - Agent-oriented build/test guide:
docs/agent-guide.md
CAN transport notes:
- Linux: SocketCAN interface names
- Windows: Peak CAN channel names (
usb1,usb2,pci1, ...)
In env mode, mapped instances attach directly to the shared CAN interface. The env daemon still owns env time control, env can ... commands, schedules, and inspect/DBC helpers.
Project Structure
runtime/ Rust CLI + daemon (Cargo)
template/ Zig shared-library template
examples/hvac/ HVAC thermostat example DLL
include/ sim_api.h — shared C ABI contract
docs/ guides for DLL authors and agents
Toolchain
All toolchains managed via Nix (flake.nix). Install via nix build or develop with nix develop.
License
See LICENSE.md.