AgentCore
     
Self-hosted AI incident triage with checkpointed resume and episodic memory.
When an alert fires, AgentCore runs a 4-step pipeline — recall similar past incidents, plan tool calls with an LLM, query your logs/metrics/runbooks via MCP, synthesize a post-mortem — and posts the result back to Slack in ~30 seconds. Every step is checkpointed to Postgres so a crash mid-investigation resumes from the failed step, not from scratch. Every resolved incident is written into pgvector memory so the second DB deadlock surfaces what fixed the first one.
Apache-2.0 · runs on your infra · works with local models · no incident data ever leaves your network
---
Table of Contents
- MCP — use from Claude / Cursor - Slack - Webhooks - Local models / Ollama - Project structure - Commands - Triage quality eval ---Quickstart
Every tool has a deterministic simulation fallback — the full stack runs with zero credentials.
Docker (recommended)
Pull and run — no build step, no .env required
curl -fsSL https://raw.githubusercontent.com/theprodsde/agentcore/main/docker-compose.demo.yml -o agentcore-demo.yml
docker compose -f agentcore-demo.yml up
Open http://localhost:3000, click Create Task, and describe an incident:
payments-service p99 latency at 4s after deploy
Or trigger via API:
curl -X POST http://localhost:3000/api/tasks \
-H "Content-Type: application/json" \
-d '{"goal": "payments-service p99 latency at 4s after deploy"}'
Watch the checkpoint timeline stream live. Grab the post-mortem at /api/tasks/.
Have an OpenAI key? OPENAI_API_KEY=sk-... docker compose -f agentcore-demo.yml up upgrades planning and synthesis to a real LLM.
Prefer building from source? git clone https://github.com/theprodsde/agentcore && cd agentcore && docker compose up --buildManual
npm install
cp .env.example .env # fill in DATABASE_URL + OPENAI_API_KEYStart Postgres with pgvector
docker run -d -e POSTGRES_USER=agentcore -e POSTGRES_PASSWORD=agentcore \
-e POSTGRES_DB=agentcore -p 5432:5432 pgvector/pgvector:pg16npm run db:migrate # creates the pgvector extension + applies migrations
npm run dev
Prebuilt images on GHCR: docker pull ghcr.io/theprodsde/agentcore:latest
Jaeger UI: http://localhost:16686Sample post-mortem output
Post-Mortem: payments-service p99 latency at 4s after deploy
Trace ID: tr-7q6d5xhl9-8193 Duration: 8.3s Retries: 0
Summary
The payments-service experienced a latency spike to 4230 ms, well above the 1000 ms SLO.
Deadlock conditions and lock wait timeouts were logged concurrently.Probable Cause
Resource contention in the payments-service database layer, specifically transaction locking
caused by insufficient connection pool sizing after the deploy.Affected Systems
payments-service
postgres-primary
Next Actions
1. Scale horizontal replicas of payments-service to reduce per-instance load.
2. Increase Postgres connection pool size and investigate slow-query patterns.
3. Consult the High Latency Runbook for payments-service.Checkpoint Timeline
| Step | Name | Status | Duration |
|------|-------------------|---------|----------|
| 1 | memory retrieval | success | 1.3s |
| 2 | planner | success | 4.7s |
| 3 | execution | success | 7ms |
| 4 | synthesizer | success | 2.4s |
---
Features
| Feature | Detail |
|---|---|
| Checkpointed orchestration | Every step persists input/output to Postgres; resumes from the last failed step — no re-running successful steps |
| Episodic memory | Incidents embedded with text-embedding-3-small, retrieved by pgvector cosine similarity with time-decay re-ranking |
| Dynamic MCP tool selection | LLM planner receives a live tool manifest and outputs per-tool args; 0/1 Knapsack DP prunes to fit a time budget |
| 5 built-in MCP tools | search_logs → Loki · get_metrics → Prometheus · search_runbook → runbook API · create_ticket → Linear · list_services |
| Incident deduplication | Jaccard + bounded Levenshtein DP + LCS — returns an existing task if a match is found within 10 minutes |
| OpenTelemetry tracing | Every task is a root span; every step a child span; trace_id/span_id in every Pino log line |
| JWT auth + multi-tenancy | HS256 tokens, per-team task/memory isolation; auth is a no-op when JWT_SECRET is unset |
| Webhook ingestion | PagerDuty, OpsGenie, Alertmanager — HMAC-verified payloads create tasks automatically |
| Slack integration | !incident triggers the full pipeline; result posted back to the thread |
| Post-mortem export | GET /api/tasks/:id/export.md — downloadable Markdown |
| Metrics dashboard | 30-day summary, step p95, weekly trend at /metrics |
| CLI | node scripts/run.mjs " — run investigations from the terminal with live streaming |
| MCP server | Expose AgentCore to Claude Code / Claude Desktop / Cursor — investigate, query memory, export post-mortems from any MCP client |
| Dry-run mode | Full pipeline without writing to memory or creating tickets |
| Graceful shutdown | SIGTERM → flush OTel spans → drain DB pool → close MCP subprocess |
---
How It Works
%%{init: {'theme': 'base', 'themeVariables': {
'primaryColor': '#dbeafe',
'primaryTextColor': '#1e3a5f',
'primaryBorderColor': '#3b82f6',
'lineColor': '#64748b',
'secondaryColor': '#ede9fe',
'tertiaryColor': '#f0fdf4',
'clusterBkg': '#f8fafc',
'clusterBorder': '#cbd5e1',
'edgeLabelBackground': '#ffffff',
'fontFamily': 'ui-sans-serif, system-ui, sans-serif'
}}}%%
flowchart LR
A["🔔 Alert fires
(Slack · PagerDuty · Alertmanager · API)"] --> B[Task Created]
B --> S1 subgraph pipeline ["Checkpointed pipeline — each step persists to Postgres"]
S1["1 · Memory Retrieval
pgvector cosine similarity
against past incidents"]
S2["2 · LLM Planner
selects tools from live manifest
with per-tool args"]
S3["3 · MCP Tool Execution
search_logs · get_metrics
search_runbook · create_ticket"]
S4["4 · Synthesizer
derives report from tool output
writes resolved incident to memory"]
S1 --> S2 --> S3 --> S4
end
S4 --> R["📋 Result
(Slack thread · Dashboard · export.md)"]
crash(["💥 crash / timeout"]) -. "resume from
failed step only" .-> pipeline
If any step fails the task pauses with the exact error surfaced. Resume replays from the failed step — completed steps are skipped and their outputs reused, so no LLM calls are duplicated.
---
Screenshots
| Dashboard | Task Detail | |---|---| | !Dashboard | !Task Detail |
| Create Task | Failed + Resume | |---|---| | !Create Task | !Failed |
| Memory Explorer | Scenarios Playground | |---|---| | !Memory | !Scenarios |
---
Configuration
| Variable | Required | Default | Description |
|---|---|---|---|
| DATABASE_URL | Yes | — | Postgres connection string (must have pgvector) |
| OPENAI_API_KEY | LLM steps | — | OpenAI-compatible key |
| OPENAI_BASE_URL | No | OpenAI | Override for local models, Azure, etc. |
| LLM_MODEL | No | gpt-4o-mini | Model for planner + synthesizer |
| EMBEDDING_MODEL | No | text-embedding-3-small | Embedding model (1536 dims) |
| JWT_SECRET | No | — | Enables JWT auth; unset = auth disabled |
| SLACK_BOT_TOKEN | No | — | Enables real Slack delivery |
| SLACK_SIGNING_SECRET | No | — | Verifies Slack event signatures |
| MCP_SERVER_URL | No | — | External MCP server (SSE); unset = spawns bundled server |
| LOKI_URL | No | simulation | Loki backend for search_logs |
| PROMETHEUS_URL | No | simulation | Prometheus backend for get_metrics |
| RUNBOOK_URL | No | simulation | Runbook search API |
| LINEAR_API_KEY | No | simulation | Linear ticket creation |
| LINEAR_TEAM_ID | No | — | Linear team ID |
| PAGERDUTY_WEBHOOK_SECRET | No | — | HMAC secret for PagerDuty webhooks |
| OPSGENIE_WEBHOOK_SECRET | No | — | HMAC secret for OpsGenie webhooks |
| ALERTMANAGER_SECRET | No | — | Shared secret for Alertmanager webhooks |
| TOOL_BUDGET_MS | No | 15000 | Max total tool execution time per task |
| TOOL_CALL_TIMEOUT_MS | No | 10000 | Hard timeout per MCP tool call |
| LLM_TIMEOUT_MS | No | 60000 | Timeout per LLM API call |
| RATE_LIMIT_RPM | No | 30 | Max task creations per minute (0 disables) |
| RETENTION_DAYS | No | forever | Purge tasks + checkpoints older than N days |
| MEMORY_RETENTION_DAYS | No | forever | Purge episodic memories older than N days |
| DEFAULT_TEAM_ID | No | — | Team for Slack/webhook tasks (single-tenant) |
| DISABLE_TEAM_SIGNUP | No | — | true blocks POST /api/teams after bootstrap |
| OTEL_EXPORTER_OTLP_ENDPOINT | No | — | OTLP endpoint for Jaeger / Grafana Tempo |
| LOG_LEVEL | No | warn | Pino log level |
---
Integrations
MCP — use from Claude / Cursor
AgentCore exposes itself as an MCP server. Add it to Claude Code or Claude Desktop and ask "investigate the latency spike on payments-service" — it runs the full checkpointed pipeline with your team's memory behind it.
Claude Code
claude mcp add agentcore --env AGENTCORE_URL=http://localhost:3000 \
-- node /path/to/agentcore/dist/tools/agentcore-mcp.cjs
// Claude Desktop — claude_desktop_config.json
{
"mcpServers": {
"agentcore": {
"command": "node",
"args": ["/path/to/agentcore/dist/tools/agentcore-mcp.cjs"],
"env": {
"AGENTCORE_URL": "http://localhost:3000",
"AGENTCORE_TOKEN": "eyJ..."
}
}
}
}
Exposed tools: investigate_incident · get_investigation · search_incident_memory · export_postmortem
During development: npm run mcp runs the server from source.
Slack
Set SLACK_BOT_TOKEN and SLACK_SIGNING_SECRET. In any channel the bot is in:
!incident payments-service p99 latency at 4s after deploy
AgentCore runs the full pipeline and replies in the thread with the structured analysis and ticket link.
Webhooks
HMAC-verified ingestion from three providers — no manual task creation required:
| Provider | Endpoint | Verification |
|---|---|---|
| PagerDuty | POST /api/webhooks/pagerduty | PAGERDUTY_WEBHOOK_SECRET |
| OpsGenie | POST /api/webhooks/opsgenie | OPSGENIE_WEBHOOK_SECRET |
| Alertmanager | POST /api/webhooks/alertmanager | ALERTMANAGER_SECRET header |
Local models / Ollama
AgentCore speaks the OpenAI API, so any compatible endpoint works:
ollama pull qwen2.5:14b # any tool-capable instruct model.env
OPENAI_BASE_URL=http://localhost:11434/v1
OPENAI_API_KEY=ollama
LLM_MODEL=qwen2.5:14b
Note: The memory store expects 1536-dimension embeddings (text-embedding-3-small). If your local endpoint can't serve them, embedding calls fail gracefully and memory retrieval falls back to recency + keyword ranking. Configurable embedding dimensions are on the roadmap.---
Auth & Multi-tenancy
Auth is disabled by default (JWT_SECRET unset) — all requests proceed. To enable:
1. Create a team
curl -X POST http://localhost:3000/api/teams \
-H "Content-Type: application/json" \
-d '{"name": "Platform Engineering"}'2. Exchange API key for a JWT
curl -X POST http://localhost:3000/api/auth/token \
-H "Content-Type: application/json" \
-d '{"api_key": "agentcore_..."}'3. Use the token
curl http://localhost:3000/api/tasks \
-H "Authorization: Bearer eyJ..."
Tasks and memories are isolated per team — a token from team A cannot read team B's data. The web dashboard shows a login screen automatically when auth is enabled.
Manage API keys via GET/POST/DELETE /api/teams/:id/api-keys. The last key on a team cannot be revoked. Set DISABLE_TEAM_SIGNUP=true after bootstrapping teams in production.
---
Development
Project structure
%%{init: {'theme': 'base', 'themeVariables': {
'primaryColor': '#dbeafe',
'primaryTextColor': '#1e3a5f',
'primaryBorderColor': '#3b82f6',
'lineColor': '#64748b',
'clusterBkg': '#f8fafc',
'clusterBorder': '#cbd5e1'
}}}%%
mindmap
root((AgentCore))
Entry
server.ts
Express · Slack · graceful shutdown
scripts/run.mjs
CLI with live streaming
src/routes
tasks.ts
CRUD · SSE · resume · dedup · export
auth.ts
teams · token exchange · API keys
memory.ts
pgvector semantic search
metrics.ts
30-day summary · step p95
webhooks.ts
PagerDuty · OpsGenie · Alertmanager
src/server
executor.ts
orchestrator · Knapsack tool selection
auth.ts
JWT · API key hashing
mcp.ts
stdio spawn · SSE client
cache.ts
LRU TTL · doubly-linked HashMap
embeddings.ts
text-embedding-3-small · LRU memo
db
Drizzle schema · pgvector · 5 indexes
src/utils
algorithms.ts
Levenshtein · LCS · Knapsack · Jaccard
synthesis.ts
pure deriveSynthesisFromOutput
tools
server.ts
MCP tool server · 5 built-in tools
tests/unit
algorithms · auth · executor · slack · tools · utils
Commands
npm run dev # Dev server with HMR
npm run build # Production build
npm run lint # TypeScript type check
npm test # Unit tests (Vitest)
npm run test:watch # Watch mode
npm run test:coverage # Coverage report
npm run test:integration # Checkpoint/resume integration tests (needs TEST_DATABASE_URL)
npm run db:migrate # Apply versioned migrations
npm run db:push # Push schema changes (dev)
npm run db:studio # Open Drizzle Studio
npm run eval # Golden-incident triage quality eval (needs running server)
npm run mcp # Run MCP server from source
Triage quality eval
The demo data is an adversarial world model (tools/simulation.ts): each simulated service has a fixed state (healthy or degraded with a specific failure mode), and log/metric output derives from that state — never from the query. Ask about a deadlock on a service that has a latency regression and the report describes the latency regression.
CI runs a golden-incident eval on every push covering true positives, false alarms on healthy services, an unknown-service case, and an anti-circularity case where the alert's claimed symptom is wrong. Scores gate on both identifying the real cause and not fabricating findings the data doesn't support.
Run it locally: npm run eval (needs a running server). Point scenarios at real backends to benchmark LLM or prompt changes.
Adding a new MCP tool
See tools/README.md. Add the tool definition to TOOL_REGISTRY in tools/server.ts — no other files change. The LLM planner picks it up automatically on the next run.
Further reading
| Doc | Contents | |---|---| | PRODUCTION.md | Swapping each stub for a real integration | | ARCHITECTURE.md | System map, extension points, scaling seams | | DEVELOPMENT.md | Phase roadmap and design decisions | | SECURITY.md | Threat model, prompt-injection bounds, responsible disclosure |
---
Contributing
Pull requests are welcome. See CONTRIBUTING.md for setup and conventions.
The easiest first contribution is a new tool backend — Elasticsearch, Grafana, Jira, Datadog. The whole pattern lives in one file and issues labeled good first issue + tool-integration have step-by-step specs.
- Bugs → bug report template
- New tools / features → feature request template
- Questions / deployment stories → Discussions
---
Roadmap
Tracked on GitHub Projects.
| Release | Highlights | |---|---| | v0.2 — Scale | Redis/BullMQ task queue · configurable embedding dims · pgvector-based dedup · ESLint in CI | | v0.3 — Intelligence | Runbook auto-import · Slack app-home tab · LLM-graded memory scoring | | Community | Elasticsearch · GitHub Issues · Grafana annotations · Datadog · Jira backends |
---
Support
AgentCore is free and open-source under Apache 2.0. If it's saving your team time on incidents:
 
You can also click Sponsor at the top of the repo on GitHub.
---
License
Apache 2.0 — see LICENSE.