Core Concepts
CrewLayer organizes data around a handful of primitive concepts. Understanding how they relate to each other makes the API intuitive.
Tenant
A Tenant is the top-level isolation unit. Everything in CrewLayer — agents, memories, actions, API keys — belongs to a tenant. In a SaaS product, each customer is a separate tenant. In a personal project, you typically have a single tenant.
Tenants have a settings JSON field for configuration like memory decay thresholds. All resources are physically isolated by tenant ID in the database; queries never cross tenant boundaries.
Agent
An Agent is the entity whose memory, actions, and context you're tracking. It maps 1:1 to a logical AI agent in your system. An agent has:
- id — UUID, used in every API call
- name — human-readable label
- status —
idle|working|error(cached in Redis, 60s TTL) - tags — arbitrary string array for filtering
- config — arbitrary JSON for agent-specific settings
- current_session_id — which session is active right now
Agents can have relations to each other: supervisor, collaborator, or delegate. Relations enable propagating blackboard writes across the hierarchy.
Memory
CrewLayer has two distinct memory stores:
Short-term memory
Short-term memory is a list of messages (role + content) stored in Redis under a session key. It functions like the conversation history you'd pass to an LLM. Messages are fast to read/write and are scoped to a session. They expire when the session closes or the TTL elapses.
Use it for: the current conversation window. Append every user/assistant turn; feed it as context to the next LLM call.
Long-term memory
Long-term memory is a vector table in PostgreSQL (pgvector). Each memory record has:
- content — plain text
- embedding — 1536-dim float32 vector (Anthropic or local model)
- importance — float 0–1, used in decay scoring
- source —
manual|extracted|episode - access_count — bumped on every recall; used for decay
Recall uses cosine similarity: given a query, CrewLayer embeds it and returns the top-k most similar memories. Use this at the start of every LLM call to inject relevant context.
Extraction happens when you close a session (POST /v1/sessions/{id}/close). Claude reads the entire conversation and extracts new facts to persist as long-term memories. This is how the agent learns from conversations automatically.
Decay runs nightly at 03:00 UTC. Memories with low importance and low access count are archived or deleted, keeping the vector store lean over time.
Action
An Action is an immutable log entry representing a tool call the agent made. Every action stores:
tool_name— what was calledinput_params— full input JSONoutput_result— full output JSONstatus—success|error|timeoutduration_ms— wall-clock timesession_id— optional, links to the session it happened in
Use it for: debugging, auditing, replay, and anomaly detection. Actions are the source of truth for "what did the agent actually do?"
Session
A Session is a bounded conversation window. Think of it as a single user conversation or a single task run. A session:
- Has a start time and optional end time
- Holds short-term memory (messages) in Redis
- Links to zero or more actions that happened during it
- Belongs to one agent
- Can be closed to trigger memory extraction
Create a new session when a new conversation starts. Close it when the conversation ends to extract long-term memories from what was discussed.
Episode
An Episode is a higher-level grouping of sessions around a coherent task or goal. For example, "implement feature X" might span multiple chat sessions over several days — those all belong to the same episode.
Episodes have their own recall endpoint: you can search memories that are tagged to a specific episode, giving the agent focused context for the current task without noise from other work.
Blackboard (Shared Context)
The Blackboard is a multi-agent coordination store. It's a namespaced key-value store where any agent in the same tenant can read and write values. Every write is versioned, so you can see history and roll back.
The blackboard supports real-time pub/sub via SSE: agents can subscribe to a namespace and receive notifications when any key in it changes. This enables reactive multi-agent pipelines without polling.
# Agent A writes a result to the shared blackboard
client.context.write(namespace="pipeline", key="step1_result", value={"items": [...]})
# Agent B reads it (or receives it via SSE subscription)
result = client.context.read(namespace="pipeline", key="step1_result")
print(result["value"]) # {"items": [...]}API Key
API keys authenticate requests. They are prefixed with crwl_, hashed with bcrypt, and stored in the database. Each key has:
- scopes — fine-grained permissions like
memory:read,agents:write, or*for all - rate limit — optional per-key rate limiting (requests/minute)
- expires_at — optional expiry
Pass the key in every request as the X-API-Key header.
How it all fits together
Tenant
└── Agent (many)
├── Session (many)
│ ├── Short-term memory (Redis messages)
│ └── Actions (many)
├── Long-term memories (pgvector)
├── Episodes (many)
│ └── Sessions (many)
└── Relations → other Agents
Tenant
└── Blackboard (shared across all agents)
└── Namespace → Key → Value (versioned)