MemoryMesh Agent¶
A market-surveillance multi-agent system whose memory never goes down β because it isn't in-process, it's CockroachDB.
Built for the πͺ³ CockroachDB Γ AWS Hackathon. LangGraph orchestrates a team of Strands Agents (reasoning via Anthropic's API directly), and every layer of memory β short-term conversation state, durable audit history, and long-term semantic case memory β is backed by CockroachDB, the one system of record in the whole stack. Model inference never touches AWS: Amazon Bedrock AgentCore hosts the runtime, and a small supporting cast of AWS services (CodeBuild, ECR, ECS, IAM) handles build automation and hosting β see "AWS services used" below.
The market-surveillance domain (agent personas, mock data, report schemas) is forked from AWS's own public sample, "Market Surveillance Agent with LangGraph and Strands on AgentCore". Everything about memory and model inference is new.
Why this is more than "add a database"¶
Most multi-agent demos treat memory as a chat-history footnote. Here, memory drives behavior:
- Every query starts with a recall step. Before the orchestrator even
sees a question,
recall_case_memoryruns a semantic similarity search over every investigation the system has ever completed β not just this session β using CockroachDB's nativeVECTORtype and distributed C-SPANN index. "Have we seen this pattern before?" is answered from real, growing history, across every user and every thread. - Every finished investigation writes itself back into memory.
persist_case_memoryembeds the synthesizer's finding and stores it, so the system's memory compounds with use instead of resetting per session. - The agent can inspect its own memory β two different ways.
memory_opsis wired to the CockroachDB Cloud Managed MCP Server and answers "how many cases do we have on file for this broker?" by actually querying the cluster, read-only.case_triagetakes a different path into the same vector index β it callsrecall_similar_investigationsitself, mid-reasoning, to decide how urgent the current investigation is based on how similar past ones were resolved. One agent reads the cluster; the other reads the case history it's built from β memory isn't a single bolted-on step, it's a resource multiple agents reach for. - State survives the process. LangGraph's checkpointer
(
AsyncCockroachDBSaver) snapshots the entire workflow state into CockroachDB after every node β a crashed container, a scaled-out AgentCore replica, or a restart mid-investigation all resume exactly where they left off. - Every turn is auditable. A separate, human-readable
message_storetable (CockroachDBChatMessageHistory) logs each completed turn β the kind of immutable record a real market-surveillance workflow needs for compliance, independent of LangGraph's internal checkpoint format.
Architecture¶
flowchart TB
U["Browser β React UI (web/)"] -->|"fetch /api/chat/stream (SSE)"| FAPI
subgraph FAPI["FastAPI (server/) β the UI/agent boundary"]
BR["agent_bridge.py"]
end
FAPI -->|"local dev: in-process"| WF
FAPI -->|"deployed: boto3 invoke_agent_runtime"| AC
FAPI -->|"read-only SELECTs"| CRDB
subgraph AC["Amazon Bedrock AgentCore Runtime (the only AWS service used)"]
API["api.py β BedrockAgentCoreApp entrypoint"]
WF["LangGraph workflow (workflow.py)"]
API --> WF
end
subgraph GRAPH["StateGraph"]
R["recall_case_memory"] --> O["orchestrator"]
O -->|routes| S1["security_monitor"]
O -->|routes| S2["broker_monitor"]
O -->|routes| S3["risk_monitor"]
O -->|routes| S4["intel_analyst"]
O -->|routes| S5["memory_ops"]
O -->|routes| S6["compliance_officer"]
O -->|routes| S7["case_triage"]
O -->|routes| S8["audit_reviewer"]
S1 & S2 & S3 & S4 & S5 & S6 & S7 & S8 --> SYN["synthesizer"]
SYN --> P["persist_case_memory"]
end
WF --> GRAPH
S1 & S2 & S3 & S4 & S6 -->|"strands Agent()"| ANTH["Anthropic API\n(claude-sonnet-4-6)"]
O --> ANTH
SYN --> ANTH
S5 -->|"MCPClient"| MCP["CockroachDB Cloud\nManaged MCP Server"]
S7 -->|"recall_similar_investigations tool"| CASE
S8 -->|"get_session_audit_trail tool"| HIST
subgraph CRDB["CockroachDB β the memory layer"]
CKPT["checkpoints / checkpoint_blobs\n/ checkpoint_writes\n(AsyncCockroachDBSaver)"]
HIST["message_store\n(CockroachDBChatMessageHistory)"]
CASE["case_memory + C-SPANN\ndistributed vector index\n(AsyncCockroachDBVectorStore)"]
end
GRAPH -->|checkpoint every node| CKPT
P -->|embed + write| CASE
R -->|similarity search| CASE
WF -->|record each turn| HIST
MCP -->|read-only SQL, schema, cluster info| CRDB
The web UI: Chat + Dashboard¶
web/ is a two-view app behind a left nav rail β Chat for the streaming
multi-agent conversation, Dashboard for an operational view of the same
CockroachDB tables. Five features exist specifically to make memory
visible rather than a number on a stat tile:
- Vector Memory Map (
web/src/components/MemoryMap.tsx,server/vector_map_routes.py,server/pca.py) β everycase_memoryembedding, pulled straight off the 384-dimVECTORcolumn and projected to 2D with a small server-side PCA (pure numpy, no ML framework), rendered as a point cloud. Type a pattern into the search box and it calls the samerecall_similar_casesfunctionrecall_case_memory/case_triageuse internally, plots your query on the identical cached basis so it lands next to its real nearest neighbors, and lists the ranked matches. This is the distributed vector index as something you can look at and query directly, not an implementation detail. - Checkpoint time-travel viewer (
web/src/components/TimeTravel.tsx,server/checkpoint_routes.py) β the History button in the Chat header opens a scrubber over the current session's actualAsyncCockroachDBSavercheckpoint history: every node transition, in order, with the state snapshot at that exact step. LangGraph checkpointing already makes this possible; nothing else in the UI made it visible before. - Live agent pipeline (
web/src/components/AgentTrace.tsx) β each assistant message now shows a compact node graph (colored, pulsing while active) of exactly which agents ran and how many tool calls each made, built live from the same SSE event stream, instead of a flat trace list. - Explainable triage citations β when
case_triage'srecall_similar_investigationstool returns matches, the UI parses that tool result into clickable citation chips (case + similarity score) directly under the pipeline, so "why this priority" is inspectable rather than buried in prose. - Fixed agentβcolor identity (
agentColor()inweb/src/types.ts) β every chart and the pipeline graph color an agent from the same fixed-order slot, never by its rank in a sorted list (a real bug in an earlier version of the agent-activity bar chart: colors were assigned by count-sorted position, so an agent's color would silently change as rankings shifted between polls β exactly the failure mode the dataviz method's "color follows the entity, never its rank" rule exists to catch).
The two dashboard charts (agent-activity bars, cases-per-day) are hand-rolled
(no charting library) against a categorical palette run through the dataviz
skill's validator for this app's dark surface (#0a0c10) β fixed hue order,
direct value labels (never color alone, since one adjacent pair sits in the
CVD warn band), hover tooltips, hairline gridlines. Every dashboard endpoint
(server/memory_routes.py, server/vector_map_routes.py,
server/checkpoint_routes.py) is a read-only query against the same tables
the agents write to β this is a window into real state, not a mock.
Why a FastAPI layer sits between the UI and the agents¶
The browser can't call AgentCore's invoke_agent_runtime directly β that API
needs a SigV4-signed request with AWS credentials, and those must never ship
to client-side JS. server/ (FastAPI) exists to:
- Hold AWS credentials server-side and proxy chat requests to AgentCore.
- Give the UI one stable streaming contract (
POST /api/chat/stream, SSE) regardless of which backend mode is active β seeserver/agent_bridge.py. - Also run the LangGraph workflow in-process when no AgentCore runtime
is configured yet (
AGENT_BACKEND_MODE=local, the default). Same API, same UI, zero AWS β this is whatmake devuses. - Expose read-only CockroachDB endpoints (
/api/memory/*) so the UI's memory panel is a live view of the actual tables the agents write to, not a mock.
Compare with the reference architecture this project follows β "Market Surveillance Agent with LangGraph and Strands on AgentCore" β except the memory layer (previously AgentCore Memory) is now CockroachDB, and the model layer (previously Bedrock-hosted Claude) is now Anthropic's API called directly from Strands.
Specialist agents¶
| Agent | Focus | Tools |
|---|---|---|
security_monitor |
Single security, single day | mock report catalog |
broker_monitor |
Single security, multiple days | mock report catalog |
risk_monitor |
Broker activity, single day | mock report catalog |
intel_analyst |
External market research | http_request |
memory_ops |
The system's own memory β case counts, schema, cluster health | CockroachDB Cloud MCP Server (read-only) |
compliance_officer |
Checks findings against explicit regulatory thresholds, issues CLEAR/FLAGGED verdicts | mock report catalog + get_regulatory_thresholds |
case_triage |
Assigns investigation priority by explicitly querying case memory itself β a second, agent-driven way of using the vector index, distinct from the automatic recall step | recall_similar_investigations β AsyncCockroachDBVectorStore |
audit_reviewer |
Summarizes the durable audit trail for a session, from CockroachDB β not from its own recollection | get_session_audit_trail β CockroachDBChatMessageHistory |
compliance_officer, case_triage, and audit_reviewer are the newest
additions, and each one exists to put a different CockroachDB memory
component directly in an agent's hands as a callable tool β not just
something the graph does automatically before/after the LLM ever runs.
CockroachDB tools used¶
The hackathon requires at least two of the four listed tools. This project uses three:
| Tool | Where | What the agent actually does with it |
|---|---|---|
| Distributed Vector Indexing | src/memory/case_memory.py |
Every investigation is embedded (local ONNX model, no external API) and written to a VECTOR column; a C-SPANN index (CSPANNIndex) keeps cosine-similarity recall fast as case history grows. recall_case_memory queries it on every incoming request before routing; persist_case_memory writes to it after every synthesis. |
| CockroachDB Cloud Managed MCP Server | src/memory/mcp_memory_tools.py, src/agents/memory_ops_agent.py |
The memory_ops Strands agent is given an MCPClient bound to https://cockroachlabs.cloud/mcp (service-account bearer token). It calls read-only MCP tools (list_tables, get_table_schema, select_query, show_running_queries, β¦) to answer questions about the memory cluster itself β safe-by-default, fully audited, no custom SQL proxy. |
| ccloud CLI (agent-ready) | scripts/provision_cluster.sh |
Provisions the CockroachDB Cloud cluster and SQL user end-to-end from the terminal with JSON output at every step (ccloud cluster create, ccloud cluster sql-user create, ccloud cluster sql --connection-params) β the same automation-friendly CLI an agent could drive itself. |
Two more CockroachDB integrations round out the memory layer (not on the
four-tool checklist, but core to "Agentic Memory Design"):
LangGraph checkpointer (AsyncCockroachDBSaver) for workflow state, and
chat message history (CockroachDBChatMessageHistory) for a durable,
queryable audit log.
We also point contributors at the
CockroachDB Agent Skills Repo
(npx skills add cockroachlabs/cockroachdb-skills) for anyone doing
schema/ops work on this project with Claude Code, Cursor, or another
MCP-compatible client β see Contributing
below.
AWS services used¶
Amazon Bedrock AgentCore hosts the agent runtime β and only the runtime.
api.py wraps the LangGraph workflow in a BedrockAgentCoreApp entrypoint.
Model inference never touches Bedrock: every Strands agent calls Anthropic's
API directly, and there is deliberately no bedrock:InvokeModel permission
in deployment/permissions-policy.json.
A small supporting cast of AWS services handles build automation and hosting around that runtime, none of which are in the inference path:
- AWS CodeBuild builds the ARM64 container natively (no local Docker or
QEMU) straight from this GitHub repo β see
deployment/deploy-codebuild.sh, which also runs unattended from a stock AWS CloudShell session viadeployment/cloudshell_deploy.shfor a one-command deploy with nothing installed locally. - Amazon ECR stores the built container images (one repo for the AgentCore runtime, one for the web UI).
- IAM roles gate every step above, each scoped to only what that step
needs β see
deployment/permissions-policy.json. - Amazon ECS Express Mode optionally hosts the public FastAPI + React web UI as a Fargate service behind an internet-facing ALB with automatic HTTPS β see "7. Host the web UI publicly" above. (We originally scoped this as AWS App Runner, but App Runner is closed to new customers as of 2025, so ECS Express Mode is the direct replacement AWS itself documents.)
None of the above ever calls a model. Inference is 100% Anthropic API, end to end.
Deployment topology¶
Two independent deploys, both built from this same GitHub repo on AWS CodeBuild β no local Docker required for either one:
flowchart TB
REPO["GitHub β this repo"]
subgraph BUILD["AWS CodeBuild β native compute, no local Docker/QEMU"]
CB1["buildspec.yml (ARM64)\nbuilds Dockerfile β AgentCore image"]
CB2["buildspec-web.yml (x86_64)\nbuilds Dockerfile.web β web UI image"]
end
REPO -->|clone at build time| CB1
REPO -->|clone at build time| CB2
CB1 -->|docker push| ECR1[("Amazon ECR\nagentcore-repo")]
CB2 -->|docker push| ECR2[("Amazon ECR\nweb-repo")]
ECR1 -->|"deploy-runtime.py"| AC
ECR2 -->|"deploy-ecs-web.sh"| ECS
subgraph AC["Amazon Bedrock AgentCore Runtime"]
WF["LangGraph workflow (api.py)\nno public URL β SigV4 invoke only"]
end
subgraph ECS["Amazon ECS Express Mode"]
WEB["FastAPI + React UI (server/main.py)\nFargate + ALB, automatic HTTPS"]
end
JUDGE["Judge's browser"] -->|"https://βΉserviceβΊ.ecs.βΉregionβΊ.on.aws/"| WEB
WEB -->|"boto3 invoke_agent_runtime (SigV4)"| AC
WEB -->|"direct SQL β /api/health, /api/memory/stats"| CRDB
AC -->|"checkpoints Β· chat history Β· case memory + C-SPANN"| CRDB[("CockroachDB Cloud")]
CLOUDSHELL["AWS CloudShell\ncloudshell_deploy.sh"] -.->|"one-shot wrapper"| CB1
Full walkthrough of both paths, including the one-time GitHub source-credential setup and IAM roles each one creates: Setup Guide Β§8 and Β§9.
Project layout¶
memorymesh-agents/
βββ api.py # AgentCore entrypoint (BedrockAgentCoreApp)
βββ app.py # Streamlit UI (legacy β quick ops view)
βββ server/ # FastAPI: the UI/agent boundary
β βββ main.py # app wiring, CORS, serves web/dist in prod
β βββ auth.py # shared-password judge access gate
β βββ agent_bridge.py # local-workflow / AgentCore-proxy, one event stream
β βββ chat_routes.py # POST /api/chat/stream (SSE)
β βββ memory_routes.py # GET /api/memory/* β live reads against CockroachDB
β βββ vector_map_routes.py # embedding-map + semantic search (the vector memory map)
β βββ pca.py # numpy PCA + cached basis for the memory map
β βββ checkpoint_routes.py # time-travel over a session's LangGraph checkpoints
β βββ config.py # backend-mode auto-detection
βββ web/ # Modern UI: React + Vite + TypeScript + Tailwind
β βββ src/
β βββ App.tsx # nav rail + Chat/Dashboard view switch + auth gate
β βββ lib/useChat.ts # turns the raw multi-agent event stream into
β β # a clean answer + a separate agent/tool trace
β βββ components/ # ChatPanel, MessageBubble, AgentTrace, MemorySidebar, Login, β¦
β β βββ Dashboard.tsx # stat tiles, charts, memory map, cases table, health
β β βββ MemoryMap.tsx # vector memory map + semantic search
β β βββ TimeTravel.tsx # checkpoint scrubber (History button in Chat)
β β βββ charts/ # hand-rolled BarChart, TimeSeriesChart, Sparkline
βββ src/
β βββ memory/ # <-- the graded core
β β βββ db.py # shared CockroachDBEngine connection pool
β β βββ checkpointer.py # AsyncCockroachDBSaver (LangGraph state)
β β βββ chat_history.py # CockroachDBChatMessageHistory (audit log)
β β βββ case_memory.py # AsyncCockroachDBVectorStore + C-SPANN index
β β βββ embeddings.py # local ONNX embeddings (fastembed)
β β βββ mcp_memory_tools.py # CockroachDB Cloud MCP client for Strands
β βββ agents/ # Strands agents + LangGraph workflow
β β βββ model_provider.py # Anthropic API model factory
β β βββ memory_ops_agent.py # the MCP-powered "introspect my own memory" agent
β β βββ workflow.py # StateGraph wiring it all together
β βββ prompts/, tools/, data_catalog/, utils/ # reused market-surveillance domain
β βββ config/
βββ scripts/
β βββ provision_cluster.sh # ccloud CLI cluster + user provisioning
β βββ init_memory_schema.py # create/migrate all CockroachDB memory tables
β βββ seed_case_memory.py # seed a few past cases for an instant demo
β βββ chat_cli.py # local chat loop, no AWS required
βββ deployment/ # AgentCore IAM/ECR/runtime scripts (local Docker or AWS CodeBuild)
Setup¶
For a longer walkthrough, see the dedicated Setup Guide
(every .env variable explained, troubleshooting table) and
User Guide (how to use the Chat and Dashboard views once
it's running). The quick version:
1. Prerequisites¶
- Python 3.11+ and Node.js 18+ (for the web UI)
- An Anthropic API key
- A CockroachDB cluster β CockroachDB Cloud (free tier is fine) or local
cockroach demo - For deployment only: AWS CLI v2 with credentials, Docker Desktop (ARM64 build) β or skip local Docker entirely with
make deploy-codebuild(see below)
2. Install¶
git clone https://github.com/akashtalole/MemoryMesh-Agents.git
cd MemoryMesh-Agents
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
Edit .env: set ANTHROPIC_API_KEY and COCKROACHDB_URL at minimum.
3. Provision CockroachDB (optional β skip if you already have a cluster)¶
Paste the resulting connection string into COCKROACHDB_URL in .env.
4. Initialize the memory schema¶
make init-memory # checkpoints, message_store, case_memory + C-SPANN index β all idempotent
make seed-memory # optional: seed 3 past cases so recall has something to find immediately
5. Run the web UI locally (no AWS required)¶
Opens the FastAPI backend on :8000 and the Vite dev server on :5173
together (Ctrl-C stops both) β visit http://localhost:5173. With no
AGENTCORE_RUNTIME_ARN set, the backend runs the LangGraph workflow
in-process, so this is a full end-to-end demo with zero AWS involved. Ask
the same question twice in different sessions and watch the memory sidebar's
case count tick up, then ask a similar question and see the agent's routing
context include the recalled prior case.
Prefer a terminal? python scripts/chat_cli.py runs the same workflow
without any HTTP layer.
6. Deploy to AWS Bedrock AgentCore¶
This creates the IAM role, ECR repo, builds/pushes the container, and
provisions the AgentCore runtime. Set ANTHROPIC_API_KEY and
COCKROACHDB_URL as environment variables on the AgentCore runtime (via
the AgentCore console or update_agent_runtime β they are intentionally not
baked into the image).
No local Docker? make deploy-codebuild does the same thing but builds the
ARM64 image on AWS CodeBuild's native ARM64 compute instead of emulating it
locally β see Setup Guide Β§8
for details. In a hurry and deploying from AWS CloudShell? make
deploy-cloudshell does the whole thing β build, deploy, and wiring the
runtime's env vars β in one command.
Deploying somewhere publicly reachable? Set JUDGE_ACCESS_PASSWORD first to
gate the app behind a single shared password β see
Setup Guide, Restricting access before deploying publicly.
deploy-runtime.py writes the resulting runtime ARN into
config/dynamic-config.yaml, which server/config.py reads automatically β
the same make dev / uvicorn server.main:app command now proxies chat
requests to the deployed AgentCore runtime instead of running locally, no
code changes needed. For a single-process production-style run:
make web-build # builds web/dist
uvicorn server.main:app --host 0.0.0.0 --port 8000 # serves API + built UI together
The legacy Streamlit view (make start-client, :8501) still works as a
quick ops look at the same AgentCore runtime.
7. Host the web UI publicly¶
The AgentCore runtime above has no browsable URL β it only accepts SigV4-signed requests. To give judges (or anyone) a public link:
Builds Dockerfile.web (server/ + web/, separate from the AgentCore image)
via CodeBuild and deploys it to Amazon ECS Express Mode β one command,
a Fargate service + load-balanced HTTPS URL + autoscaling, no manual
VPC/ALB setup. (We use ECS Express Mode rather than AWS App Runner because
App Runner is closed to new customers as of this writing β Express Mode is
AWS's own recommended replacement.) See
Setup Guide Β§9
for the full walkthrough, prerequisites, and IAM roles it creates.
Sample queries¶
# Ordinary investigation (writes a new case into memory)
What was the trading activity for AAPL on March 15, 2024 and which brokers were most active?
# Ask a near-duplicate later β watch the orchestrator's context include recalled prior findings
Which brokers were most active trading AAPL in mid-March 2024?
# Memory introspection β routes to memory_ops, which queries CockroachDB via MCP
How many past investigations do we have stored, and have we looked at broker
risk on MSFT before?
# Multi-agent
Analyze MSFT's price movement and broker risk scores between March 10-15, 2024,
and check for any related market news.
# Compliance + triage β routes to compliance_officer and case_triage, the
# latter explicitly querying case memory (not just the automatic recall step)
Is ALPHA_CAPITAL's AAPL trading on March 15, 2024 a compliance issue, and how
urgent is it?
# Audit β routes to audit_reviewer, which reads message_store directly
Give me an audit summary of everything asked and answered in this session.
Judging-criteria notes¶
- Agentic Memory Design β CockroachDB is the only memory system: no Redis, no separate vector DB, no AgentCore Memory. Checkpoints, audit history, and semantic case memory are three distinct CockroachDB-backed stores, each earning its keep.
- Technical Implementation β parameterised queries throughout (the
reused
run_reporttool never lets an LLM write raw SQL), MCP access is read-only and scoped by service-account key, and TTL is available on checkpoints viaCHECKPOINT_TTL_DAYS. - Real-World Impact β market surveillance is a compliance-critical, audit-heavy domain; "has this pattern happened before, across every past investigation" and "give me an immutable record of every turn" are real requirements, not demo flourishes.
- Production Readiness β least-privilege IAM (no Bedrock model
permissions at all, since this project never calls Bedrock for inference),
graceful degradation when
COCKROACHDB_MCP_API_KEYis unset, and a connection pool (not a connection-per-request) backing the vector store. - Creativity & Originality β the
memory_opsagent turning "introspect your own memory cluster" into an actual tool call, and case memory informing routing (not just chat continuity), are the two ideas this project leans on hardest.
Contributing: CockroachDB Skills¶
If you're working on this project's schema or CockroachDB operations with Claude Code, Cursor, or another MCP-compatible client, pull in the CockroachDB Agent Skills:
License¶
MIT β see the LICENSE file.