1. Start Actae
Actae is one server: the HTTP API, WebSocket endpoint, health checks, and dashboard all run on a single port. Pick a setup that matches where you are.
Actae Cloud
After subscribing in the portal, your instance URL is shown in the dashboard — e.g. https://your-org.actae.app. Create an API key in the portal (Settings → API keys); the key prints once, so store it immediately.
Local development (embedded)
The dev binary is self-contained: it embeds a managed PostgreSQL instance and needs no Docker or external services. Data persists across restarts.
# from the actae checkout $ cargo run -- --embedded # the banner prints the endpoint, port, and dev API key $ http://localhost:8002 · api key sk-dev-0000000000000000000000
Self-hosted (docker compose)
The production stack adds PostgreSQL 16, TLS, API-key auth, and rate limiting. See the deployment guide in the portal for secrets and certificate rotation.
$ docker compose up -d --build
2. Get credentials
You need two things: the endpoint (where Actae runs) and an API key (who you are).
sk-… created in the portalhttp://localhost:8002sk-dev-0000000000000000000000https://your-server:8002Provisioned ACTAE_API_KEYThe API key is the only credential most users touch. Every HTTP call and the WebSocket authentication use it.
3. Install an SDK
pip install actae-clientPython 3.9+, aiohttpgo get github.com/BViganotti/new_actae/sdks/goGo 1.25+npm install @actae/sdkNode 20+ (ESM)4. Record and replay
Channels are named event streams; events are immutable JSON blobs with a monotonic, per-channel cursor; replay reads them back. That is the whole core loop.
pythonimport asyncio
from actae_client import ActaeClient
async def main():
async with ActaeClient(
endpoint="http://localhost:8002",
api_key="sk-dev-0000000000000000000000",
) as client:
event = await client.record(
"my-channel", "tool.completed",
payload={"result": "success"}, actor="my-agent",
)
print(f"Recorded: cursor={event.cursor}")
events = await client.replay("my-channel", cursor=0)
for e in events:
print(f" [{e.cursor}] {e.event_type}")
asyncio.run(main())Replay uses exclusive cursor semantics: events with a cursor strictly greater than the given value are returned. Cursors are per-channel and gapless, so cursor is always relative to a single channel.
5. Go live
Subscribe to a channel to catch up from a cursor and then receive live delivery — no application-built handoff between replay and live.
pythonasync with ActaeClient(endpoint=..., api_key=..., echo_self=True) as client:
client.on_message(lambda topic, event: print(topic, event.event_type))
await client.subscribe("my-channel")
await client.publish("my-channel", {"hello": "world"})
await asyncio.sleep(1)Echo gotcha
The server never broadcasts a publish back to the connection that sent it. For single-client demos, construct the client with echo_self=True — then your own publishes are delivered to your callbacks too.
6. What next
Once you have events flowing, the core concepts page explains state transitions, guards, and idempotency. From there: forking & recovery for branch-and-resume workflows, coordination for durable workers and exactly-once tool calls, and sessions & adapters to instrument entire agent runs.