Horizons is self-hosted. The server you run locally is the same API surface your deployment will expose.
This quickstart uses the dev backends included with horizons_server.
Run the server
From the Horizons/ repo:
cargo run -p horizons_server -- serve --host 0.0.0.0 --port 8000
Pick a tenant org id
By default (dev mode), Horizons enforces tenant isolation via x-org-id.
For local dev, generate a UUID (any UUID works):
Export it for convenience:
export HORIZONS_ORG_ID="<uuid>"
For production-style auth, create an API key and require bearer auth:
# create a key (stored in the Central DB)
cargo run -p horizons_server -- create-api-key --org-id "$HORIZONS_ORG_ID" --name dev
# then run the server with:
export HORIZONS_REQUIRE_AUTH=true
export HORIZONS_ALLOW_INSECURE_HEADERS=false
Create a project
curl -sS -X POST \
-H "x-org-id: $HORIZONS_ORG_ID" \
-H "content-type: application/json" \
http://localhost:8000/api/v1/projects \
-d '{}'
Publish an event
curl -sS -X POST \
-H "x-org-id: $HORIZONS_ORG_ID" \
-H "content-type: application/json" \
http://localhost:8000/api/v1/events/publish \
-d '{
"direction": "outbound",
"topic": "demo.hello",
"source": "demo",
"payload": {"hello": "world"},
"dedupe_key": "demo:1"
}'
Run an agent
Horizons uses identity headers for audit logging and action approvals.
curl -sS -X POST \
-H "x-org-id: $HORIZONS_ORG_ID" \
-H "x-agent-id: agent:demo" \
-H "x-project-id: <project_uuid>" \
-H "content-type: application/json" \
http://localhost:8000/api/v1/agents/run \
-d '{
"agent_id": "dev.noop",
"inputs": {"prompt": "hello"}
}'
Propose and approve an action
Actions are the governance primitive in Horizons. Agents propose actions, and
reviewers or policy approve/deny before execution.
ACTION_ID=$(curl -sS -X POST \
-H "x-org-id: $HORIZONS_ORG_ID" \
-H "x-project-id: <project_uuid>" \
-H "x-agent-id: agent:demo" \
-H "content-type: application/json" \
http://localhost:8000/api/v1/actions/propose \
-d '{
"agent_id": "agent:demo",
"action_type": "demo.notify",
"payload": {"message": "hello from quickstart"},
"risk_level": "low",
"context": {"source": "quickstart"},
"dedupe_key": "quickstart-action-1"
}' | jq -r '.action_id')
curl -sS -X POST \
-H "x-org-id: $HORIZONS_ORG_ID" \
-H "x-project-id: <project_uuid>" \
-H "content-type: application/json" \
http://localhost:8000/api/v1/actions/$ACTION_ID/approve \
-d '{"reason":"quickstart approval"}'
Verify action state and audit:
curl -sS \
-H "x-org-id: $HORIZONS_ORG_ID" \
-H "x-project-id: <project_uuid>" \
"http://localhost:8000/api/v1/actions/pending?limit=20"
curl -sS \
-H "x-org-id: $HORIZONS_ORG_ID" \
-H "x-project-id: <project_uuid>" \
"http://localhost:8000/api/v1/audit?limit=20"
Next: