Persistent memory, shared context, and full action history for any agent framework. Drop-in backend in minutes.
git clone https://github.com/GerardSole/CrewLayer
cd CrewLayer && cp .env.example .env
docker compose up -d
# ✓ API ready at http://localhost:8000
# ✓ Dashboard at http://localhost:8000/dashboard
Works with your stack
Features
One backend. Every capability you need to ship production-grade agents.
Short-term in Redis, long-term in pgvector. Semantic recall by similarity. Auto-extracted from conversations with Claude.
Immutable append-only log of every tool call. Debug, audit, and replay any agent action with full input/output context.
Key-value store for multi-agent coordination with real-time pub/sub over Redis. Agents communicate without polling.
Every resource isolated per tenant. API key auth with granular scopes. Built for teams and SaaS products from day one.
Rate agent responses, detect anomalies automatically, and run A/B tests on prompts with built-in LLM-as-a-judge scoring.
Use CrewLayer directly from Claude Code and Claude Desktop as MCP tools. No HTTP code. Just call the tools.
How it works
CrewLayer sits behind your agent as a stateful backend. You bring the logic; we handle everything else.
Register your agent in CrewLayer to get a unique agent_id. One API call — that's it.
Use our Python SDK, TypeScript SDK, REST API, or MCP server. Works with any agent framework.
Memories, actions, and context are stored automatically. Your agent remembers across every session.
from crewlayer import CrewLayerClient
client = CrewLayerClient(api_key="crwl_...")
# Your agent learns something important
client.memory.save(
agent_id="...",
content="User prefers concise answers",
importance=0.9
)
# Next session — it remembers
memories = client.memory.recall(
agent_id="...",
query="user preferences"
)
# → [{"content": "User prefers concise answers",
# "similarity": 0.97}]
# Log every tool call automatically
client.actions.log(
agent_id="...",
tool_name="web_search",
input_params={"query": "latest AI news"},
output_result={"count": 12},
status="success"
)
Production ready
No toy features. Every capability is production-grade and covered by 441 tests.
Integrations
Copy-paste examples. No boilerplate. Wire in your agent_id and go.
Add persistent memory to any LangChain agent in under 10 lines.
from langchain.agents import AgentExecutor
from crewlayer import CrewLayerClient
cl = CrewLayerClient(api_key="crwl_...")
AGENT_ID = "550e8400-e29b-41d4-a716-446655440000"
def enrich_with_memory(query: str) -> str:
memories = cl.memory.recall(AGENT_ID, query=query, top_k=5)
context = "\n".join(f"- {m['content']}" for m in memories)
return f"Relevant context:\n{context}\n\nQuery: {query}"
# Wrap your existing AgentExecutor
executor = AgentExecutor.from_agent_and_tools(agent, tools)
response = executor.invoke({"input": enrich_with_memory(user_query)})
# Persist new memories after the call
cl.memory.save(AGENT_ID, content=response["output"], importance=0.7)
Plug CrewLayer into AutoGen agents as a stateful memory backend.
import autogen
from crewlayer import CrewLayerClient
cl = CrewLayerClient(api_key="crwl_...")
AGENT_ID = "550e8400-e29b-41d4-a716-446655440000"
class MemoryAssistant(autogen.AssistantAgent):
def generate_reply(self, messages, sender, **kwargs):
last_msg = messages[-1]["content"]
# Pull relevant memories before responding
memories = cl.memory.recall(AGENT_ID, query=last_msg, top_k=5)
if memories:
mem_ctx = "\n".join(f"- {m['content']}" for m in memories)
messages = [
{"role": "system", "content": f"Memory:\n{mem_ctx}"}
] + messages
reply = super().generate_reply(messages, sender, **kwargs)
# Log the action
cl.actions.log(AGENT_ID, tool_name="generate_reply",
input_params={"query": last_msg},
output_result={"reply": reply}, status="success")
return reply
Use CrewLayer alongside LlamaIndex's query engine for persistent cross-session context.
from llama_index.core import VectorStoreIndex
from crewlayer import CrewLayerClient
cl = CrewLayerClient(api_key="crwl_...")
AGENT_ID = "550e8400-e29b-41d4-a716-446655440000"
index = VectorStoreIndex.from_documents(docs)
query_engine = index.as_query_engine()
def query_with_memory(question: str) -> str:
# Enrich query with agent's long-term memory
past = cl.memory.recall(AGENT_ID, query=question, top_k=3)
enriched = question
if past:
enriched += "\n\n[Agent memory]\n"
enriched += "\n".join(m["content"] for m in past)
response = query_engine.query(enriched)
# Persist response as a new memory
cl.memory.save(AGENT_ID, content=str(response), importance=0.7)
return str(response)
Add stateful memory to Vercel AI SDK routes in a few lines of TypeScript.
import { streamText } from 'ai'
import { openai } from '@ai-sdk/openai'
import { CrewLayerClient } from '@crewlayer/sdk'
const cl = new CrewLayerClient({ apiKey: process.env.CREWLAYER_API_KEY! })
const AGENT_ID = '550e8400-e29b-41d4-a716-446655440000'
export async function POST(req: Request) {
const { messages } = await req.json()
const lastMsg = messages.at(-1)?.content ?? ''
// Pull relevant memories for context
const memories = await cl.memory.recall(AGENT_ID, {
query: lastMsg, topK: 5
})
const memCtx = memories.map(m => `- ${m.content}`).join('\n')
const result = streamText({
model: openai('gpt-4o'),
system: `You are a helpful assistant.\n\nMemory:\n${memCtx}`,
messages,
onFinish: async ({ text }) => {
// Persist assistant reply as a new memory
await cl.memory.save(AGENT_ID, { content: text, importance: 0.6 })
}
})
return result.toDataStreamResponse()
}
Dashboard
Web dashboard included. See memories, actions, evaluations, and agent status in real time. No extra setup required.
Self-host
No SaaS pricing. No data leaving your infrastructure. Deploy on any machine that runs Docker — your VPS, AWS, bare metal, or local dev machine. CrewLayer is MIT-licensed and always will be.
# 1. Clone and configure
git clone https://github.com/GerardSole/CrewLayer
cd CrewLayer
cp .env.example .env
# Edit .env — add your ANTHROPIC_API_KEY
# 2. Start everything with one command
docker compose up -d
# Starts: PostgreSQL · Redis · API · Dashboard
# API → http://localhost:8000
# Dashboard → http://localhost:8000/dashboard
# 3. Optional: observability stack
docker compose -f docker-compose.observability.yml up -d
# Prometheus → :9090 Grafana → :3000
Comparison
The only solution that gives you everything in one self-hosted package.
| Feature | CrewLayer | Mem0 | Zep | Build it yourself |
|---|---|---|---|---|
| Persistent memory | ✓ | ✓ | ✓ | weeks |
| Semantic recall | ✓ | ✓ | ✓ | weeks |
| Action logging | ✓ | ✗ | ✗ | weeks |
| Multi-agent context | ✓ | ✗ | partial | weeks |
| Evaluations & A/B testing | ✓ | ✗ | ✗ | ✗ |
| Self-hosteable | ✓ | paid plan | ✓ | ✓ |
| Open source | ✓ | ✓ | ✓ | ✓ |
| MCP server | ✓ | ✗ | ✗ | ✗ |