Connect Your Own Agent¶
Advanced path. Complete the Quickstart first. This page assumes
autonomyis installed andautonomy demo validateexits 0.
Two modes are available. Choose based on your workflow:
Mode |
Command |
Best for |
|---|---|---|
Subprocess wrap |
|
One-shot agent runs; runtime starts and stops with the process |
Persistent daemon |
|
Iterating on agent logic without restarting governance each time |
Mode 1 — Subprocess wrap¶
autonomy run python3 my_agent.py
ROS2 case. The same subprocess-wrap pattern is used for ROS2 governance via
autonomy run ros2.launch <package> <launch_file>. That dispatch path is CE-safe (runs on theautonomyCLI from the CE distribution; no orchestrator required) and emits the five WAL-backed PASS markers described in Markers and Observability. Full walkthrough: Robotics Quickstart.
What this does:
Loads the embedded demo policy.
Starts an in-process policy-gated runtime on a random localhost port.
Injects
AUTONOMY_RUNTIME_URL=http://127.0.0.1:<port>into the subprocess environment.Exec’s
python3 my_agent.pyas the subprocess.Shuts the runtime down when the subprocess exits.
Propagates the subprocess exit code.
Your agent reads AUTONOMY_RUNTIME_URL from the environment and calls the runtime over HTTP.
Minimal Python client¶
import json
import os
import urllib.error
import urllib.request
def call_tool(kind: str, params: dict) -> dict:
base_url = os.environ["AUTONOMY_RUNTIME_URL"].rstrip("/")
payload = json.dumps({"kind": kind, "params": params}).encode()
req = urllib.request.Request(
f"{base_url}/v1/tool",
data=payload,
headers={"Content-Type": "application/json"},
method="POST",
)
try:
with urllib.request.urlopen(req) as resp:
return json.loads(resp.read())
except urllib.error.HTTPError as exc:
return json.loads(exc.read())
A working reference implementation is at examples/agent.py.
Run it against the demo policy with:
autonomy run python3 examples/agent.py
Mode 2 — Persistent daemon¶
Start the runtime with the embedded demo policy and leave it running:
autonomy runtime start --demo
The runtime listens on 127.0.0.1:7777 by default.
# Override the listen address
autonomy runtime start --demo --listen 127.0.0.1:8888
To enable tool.http_get calls, pass an allowlist at startup (default includes
api.anthropic.com and ifconfig.me):
autonomy runtime start --demo --allowed-domains api.example.com,api.anthropic.com
Point your agent at the persistent runtime by setting the environment variable directly:
AUTONOMY_RUNTIME_URL=http://127.0.0.1:7777 python3 my_agent.py
Verify it is running before connecting:
curl http://127.0.0.1:7777/health
{"status":"ok"}
The tool call API¶
All policy-gated actions go through POST /v1/tool.
Request¶
{"kind": "tool.echo", "params": {"message": "hello"}}
Field |
Type |
Description |
|---|---|---|
|
string |
Dot-separated tool identifier, e.g. |
|
object |
Tool-specific parameters |
Response¶
{"decision": "allow", "output": "hello", "policy_ref": "embedded:demo", "audit_id": "..."}
Field |
Description |
|---|---|
|
|
|
Tool output, present on allow only |
|
Denial reason, present on deny |
|
Policy bundle that produced this decision |
|
WAL entry identifier for this decision |
HTTP status |
Meaning |
|---|---|
200 |
Tool call allowed and executed |
403 |
Tool call denied — the tool was never executed |
A 403 is not a server error. It means policy evaluated the call and denied it before execution.
Embedded demo policy behavior¶
When running without a custom policy (autonomy run with no --policy flag, or autonomy runtime start --demo), the embedded demo policy is active.
Tool kind |
Policy verdict |
|
|
|---|---|---|---|
|
allow |
Executed |
Executed |
|
allow at policy layer |
Fail-closed — no allowlist flag |
Allowed if endpoint is in |
|
deny |
Never executed |
Never executed |
anything else |
deny |
Never executed |
Never executed |
tool.http_get is fail-closed in subprocess wrap mode. autonomy run creates the runtime with
an empty allowlist and exposes no flag to override it. If your agent needs outbound HTTP calls,
use the persistent daemon (Mode 2) and pass --allowed-domains.
Using a custom policy¶
Pass a custom bundle OCI reference from the local managed cache:
autonomy run --policy oci://localhost:5000/my-policy:v1.0 python3 my_agent.py
Or load a bundle into the managed cache first and start the runtime against it:
autonomy policy load --bundle my-policy.tar.gz
autonomy runtime start --listen 127.0.0.1:7777
See policy.md for bundle authoring, versioning, and LKG rollback.
Next steps¶
policy.md — author and load your own policy bundle
security-model.md — trust boundaries and what the runtime guarantees
Inspect the WAL — audit every decision written at runtime