Skip to main content
OTAS splits its responsibilities across two independent backend services — UASAM and Brain — each with its own PostgreSQL database and Redis instance. The React frontend talks to both. This separation keeps authentication and management concerns isolated from high-throughput event ingestion, so a spike in log volume does not affect the APIs your users rely on to manage projects and agents.

UASAM — user, auth, and agent management

UASAM runs on port 8000 and is the control plane for everything that is not an event. It handles:
  • User accounts — sign-up, login, profile editing, and password updates. Passwords are hashed; JWTs are issued with PyJWT and returned as X-OTAS-USER-TOKEN.
  • Projects — a named container for agents and their event data. When you create a project, OTAS creates a UserProjectMapping record that binds you to the project with Admin privilege (1). Members can be added with privilege 2.
  • Agents — registered AI systems within a project. Each agent has a name, description, and provider (for example, Anthropic). Only project Admins can create agents.
  • AgentKeys — time-limited keys (valid 30 days) scoped to a single agent. They use the format agent_<prefix>_<secret> and are stored as bcrypt hashes. Keys are used as X-OTAS-AGENT-KEY and never returned after initial creation.
  • Agent sessions — ephemeral sessions created by an agent at the start of each run. UASAM issues a session JWT (X-OTAS-AGENT-SESSION-TOKEN) that Brain validates on every log request.
  • Backend SDK keys — project-scoped keys (otas_<prefix>_<secret>) used by server-side SDK integrations.
UASAM uses PostgreSQL on port 5432 and Redis on port 6379, with Celery for background work.

Brain — event capture and analytics

Brain runs on port 8002 and is the data plane. It accepts event logs from two sources:
  • Backend SDKPOST /api/v1/backend/log/sdk/ authenticated with X-OTAS-SDK-KEY + X-OTAS-AGENT-SESSION-TOKEN
  • Agent directPOST /api/v1/backend/log/agent/ authenticated with X-OTAS-AGENT-KEY + X-OTAS-AGENT-SESSION-TOKEN
Each log call creates a BackendEvent record. Brain validates the session token against UASAM before writing, then hands off to Celery for async processing. The analytics endpoints query BackendEvent directly:
  • GET /api/v1/agent/path-timeseries/ — request counts per path over time
  • GET /api/v1/agent/session/events/ — all events for a specific session
  • GET /api/v1/agent/latency-percentiles/ — daily p50 / p95 / p99 per agent
  • GET /api/v1/agent/error-count/ — daily error counts over a requested date range
Brain uses PostgreSQL on port 5433 and Redis on port 6378.

BackendEvent model fields

Each event logged to Brain is stored as a BackendEvent row with the following fields:
FieldTypeDescription
event_idUUIDPrimary key, auto-generated
event_timeDateTimeFieldWhen the event occurred (indexed)
event_dateDateFieldDerived from event_time; used for daily analytics queries
project_idCharFieldUUID of the project this event belongs to
agent_idCharFieldUUID of the agent (optional)
agent_session_idCharFieldUUID of the agent session (optional)
pathTextFieldThe API path called (indexed)
methodCharFieldHTTP method (GET, POST, etc.)
status_codePositiveIntegerFieldHTTP response status code
latency_msFloatFieldRound-trip time in milliseconds
request_size_bytesPositiveIntegerFieldSize of the request payload
response_size_bytesPositiveIntegerFieldSize of the response payload
request_headersTextFieldSerialized request headers
request_bodyTextFieldRequest body
query_paramsTextFieldURL query string
response_headersTextFieldSerialized response headers
response_bodyTextFieldResponse body
request_content_typeCharFieldMIME type of the request
response_content_typeCharFieldMIME type of the response
custom_propertiesJSONFieldArbitrary key-value data you attach
errorTextFieldError message if the call failed
metadataJSONFieldAdditional structured metadata

Frontend — React dashboard

The frontend runs on port 5173 (Vite dev server) and is built with React 19, MUI 7, and React Router 7. It connects to UASAM and Brain using two hardcoded base URLs in src/constants.ts:
export const UASAM_ENDPOINT = "http://localhost:8000";
export const BRAIN_ENDPOINT = "http://localhost:8002";
The dashboard provides:
  • Project and agent creation and management
  • Agent key creation and revocation
  • Session list with per-session event drill-down
  • Path timeseries charts (request counts by path over time)
  • Latency percentile charts (daily p50, p95, p99)
  • Error count charts (configurable date range)

Data flow

The sequence below shows how a single agent run moves through the system:
  1. Agent calls UASAMPOST /api/agent/v1/session/create/ with X-OTAS-AGENT-KEY. UASAM validates the key, creates an AgentSession record, and returns a session JWT.
  2. Agent makes API calls — for in-domain calls, the agent attaches X-OTAS-AGENT-SESSION-TOKEN to every request so the backend SDK can intercept and log them automatically.
  3. Agent logs external calls — for out-of-domain calls, the agent logs each request to Brain after it completes via POST /api/v1/backend/log/agent/.
  4. Brain stores events — Brain validates the session token, writes a BackendEvent row, and queues async post-processing in Celery.
  5. User views analytics — the frontend queries Brain’s analytics endpoints and renders charts and session views in the dashboard.

Port reference

ServicePort
UASAM API8000
Brain API8002
Frontend5173
UASAM PostgreSQL5432
Brain PostgreSQL5433
UASAM Redis6379
Brain Redis6378

Project privilege model

UserProjectMapping assigns each user a privilege level within a project:
ValueLabelPermissions
1AdminCreate agents, create and revoke keys, manage project members
2MemberView agents, sessions, and analytics; no write access to keys
The creator of a project is always assigned Admin privilege automatically.

Build docs developers (and LLMs) love