Steward is an Elixir-based control plane for orchestrating remediation runs across managed agents.
It now supports an API-first integration model, so you can run it without the Rust mock binary.
- OTP-managed orchestration and run lifecycle.
- Distributed run fan-out via
:erpc. - API-based action dispatch to external agents.
- Real-time observability API + LiveView dashboard.
- Agent telemetry ingestion (
register,heartbeat,events).
- Control Plane (Elixir): Run registry, fan-out, status aggregation, dashboard.
- Agent API Backend: Steward dispatches actions to agent HTTP endpoints.
- Observability Layer:
/api/v1/state, run APIs, and dashboard projections. - Optional Port Backend: Local Port workers are still supported when explicitly configured.
- Elixir 1.16+
- Node.js (if you build frontend assets)
mix deps.get
export STEWARD_SERVER_ENABLED=true
export STEWARD_SERVER_PORT=4000
iex -S mixOpen http://localhost:4000/.
Configuration is in config/config.exs.
STEWARD_SERVER_ENABLED(defaultfalse)STEWARD_SERVER_HOST(default127.0.0.1)STEWARD_SERVER_PORT(default4000)STEWARD_SECRET_KEY_BASE(optional, has a dev fallback)
STEWARD_AGENT_API_TIMEOUT_MS(default5000)STEWARD_AGENT_API_AUTH_TOKEN(optional bearer token for outbound calls)
API workers are configured under :workers, for example:
config :steward,
workers: [
%{process_id: "agent-a", transport: :api, base_url: "http://127.0.0.1:5051"},
%{process_id: "agent-b", transport: :api, base_url: "http://127.0.0.1:5052"}
]You can also provide agent_api.targets map overrides by process_id.
If you want to run the old Port-based integration for local debugging, configure a Port worker explicitly:
config :steward,
workers: [
%{
process_id: "mock_agent",
binary_path: "native/steward_mock_agent/target/debug/steward_mock_agent",
args: []
}
],
run: [
actions_module: Steward.Actions.MockAgentActions
]Then build the binary:
cd native/steward_mock_agent
cargo buildGET /healthGET /api/v1/stateGET /api/v1/runs/:run_idPOST /api/v1/runs
POST /api/v1/agents/registerPOST /api/v1/agents/:process_id/heartbeatPOST /api/v1/agents/:process_id/events
Build:
mix escript.buildCommands:
./steward start --port 4000./steward workers list./steward run --action panic_fail_open --targets agent-a,agent-b --params '{"mode":"safe"}'
Steward does not auto-load a .env file today.
It reads environment variables via System.get_env/2 from config/config.exs.
Use one of these patterns:
source .envbefore starting.direnv/ shell profile exports.- Docker/Kubernetes environment injection.
If you want auto .env loading, add a dotenv loader in your dev startup workflow.
mix testlib/steward/: core orchestration and worker controllib/steward_web/: endpoint, controllers, LiveViewnative/steward_mock_agent/: optional mock binarytest/: test suite