Non-human actors — bRRAIn Docs
Service and Agent sessions for robots, IoT, and automation: creation, workflows, audit trails, and rate limits.
Non-human actors
bRRAIn models non-human participants — robots, IoT sensors, batch jobs, AI agents — as first-class session types. This gives them distinct audit signatures, tailored rate limits, and explicit conflict-resolution rules.
Service vs Agent
| Attribute | Service | Agent |
| --- | --- | --- |
| Typical use | Cron jobs, ingesters, backend workers | Autonomous AI agents, robots, teleoperators |
| Autonomy | Scripted, predictable | Adaptive, may write arbitrary content |
| Conflict resolution | Escalates to supervisor user | Pauses, escalates immediately |
| Rate limit class | High volume, bounded | Moderate volume, bursty |
| Audit signature | svc:<name> | agt:<name> |
Use Service for any deterministic automation. Use Agent when the actor's behavior is not fully scripted — including LLM-driven agents with tool use.
Creating a Service session
svc, err := ws.CreateSession(sdk.SessionTypeService,
sdk.WithMetadata(map[string]string{
"name": "nightly-ingester",
"purpose": "ETL from Postgres",
"schedule": "0 2 * * *",
}),
)
if err != nil {
return err
}
defer svc.Close()
for _, row := range rows {
svc.Store(row)
}
Service sessions inherit permissions from the key type (sk_svc_...). They can run indefinitely — svc.Close() is polite but not required.
Creating an Agent session
agt, _ := ws.CreateSession(sdk.SessionTypeAgent,
sdk.WithMetadata(map[string]string{
"name": "mining-rig-3-teleoperator",
"supervisor": "operator-alice@miningco.io",
}),
)
Agent sessions require a supervisor — a human user who receives escalations. Any conflict detected in the Consolidator routes to the supervisor.
Autonomous workflows
A typical agent workflow:
for {
reading := sensor.Read()
if reading.Anomalous() {
_, err := agt.Store(reading.ToRecord(), sdk.WithContext(map[string]string{
"severity": reading.Severity(),
}))
if errors.Is(err, sdk.ErrAgentPaused) {
// Supervisor has paused this agent; wait before next iteration.
time.Sleep(1 * time.Minute)
continue
}
}
time.Sleep(reading.Period)
}
Error handling in automated processes
Because non-human actors run without a human in the loop, transient errors must be surfaced to someone. Use the built-in incident channel:
svc.ReportIncident(ctx, &sdk.Incident{
Severity: sdk.IncidentError,
Title: "ETL source unreachable",
Details: err.Error(),
})
Incidents appear in the supervisor's dashboard and, for Agent sessions, trigger immediate pause.
Audit trails
Every operation is tagged with the session type and identity:
{
"operation_id": "op_lh3f...",
"actor": "svc:nightly-ingester",
"timestamp": "2026-04-16T02:15:42Z",
"action": "store",
"record_id": "rec_lh3g..."
}
Audit queries can filter by actor type:
events, _ := client.Audit.Query(ctx, &sdk.AuditQuery{
ActorType: sdk.ActorAgent,
Since: time.Now().Add(-24 * time.Hour),
})
Rate limits and quotas
| Actor type | Default operations / min | Burst | | --- | --- | --- | | User (Personal) | 600 | 1,200 | | Service | 6,000 | 18,000 | | Agent | 1,800 | 3,000 |
Exceeding the limit returns sdk.ErrRateLimit with a Retry-After hint. Workspace admins can raise limits per actor from the dashboard.
Conflict escalation
When an Agent session writes a record that conflicts with an existing one:
- The Consolidator detects the conflict and creates a conflict record (Zone 4).
- The Agent's write is paused (returns
sdk.ErrAgentPaused). - The supervisor is notified via the configured channels (email, Slack, SMS).
- On resolution (accept agent, accept human, or merge), the agent is unpaused.
Service sessions follow the same path but don't auto-pause unless the conflict threshold is exceeded (default: 3 unresolved conflicts within 15 minutes).