deja
HTTP API for persistent agent memory. Two core operations: inject before a task, learn after.
Setup
Base URL
https://deja-worker.coy.workers.dev
Authentication — all requests
Authorization: Bearer YOUR_API_KEY
Self-host (optional)
git clone https://github.com/acoyfellow/deja cd deja && bun install wrangler vectorize create deja-embeddings --dimensions 384 --metric cosine wrangler secret put API_KEY wrangler deploy
Core loop
/inject — recall before curl -X POST https://deja-worker.coy.workers.dev/inject \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"context": "deploying the auth service", "scopes": ["shared"]}' {
"prompt": "Past learnings:\n- always run migrations inside a transaction\n...",
"learnings": [{ "id": "...", "trigger": "...", "learning": "...", "confidence": 0.9 }]
} /learn — store after curl -X POST https://deja-worker.coy.workers.dev/learn \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"trigger": "deploying auth service",
"learning": "always run migrations inside a transaction",
"confidence": 0.9,
"scope": "shared"
}' All endpoints
| Method | Path | Description |
|---|---|---|
| POST | /inject | Retrieve context-relevant memories, formatted for prompt injection |
| POST | /learn | Store a memory with semantic embedding |
| POST | /learning/:id/confirm | Increase one memory confidence by 0.1 |
| POST | /learning/:id/reject | Decrease confidence by 0.15; may invert into an anti-pattern |
| POST | /query | Semantic search over stored memories |
| POST | /inject/trace | Debug retrieval: full candidate list, scores, threshold pass/fail |
| POST | /cleanup | Run scheduled cleanup logic immediately |
| POST | /run | Record a loop run outcome (pass/fail/exhausted). Auto-fires learn. |
| POST | /state/:runId/events | Append an event to live working state |
| POST | /state/:runId/resolve | Resolve working state and optionally persist a summary |
| POST | /secret | Create or update a scoped secret |
| GET | /runs | Run history + convergence stats (mean attempts, trend) |
| GET | /learnings | List memories, optionally filtered by ?scope= |
| GET | /state/:runId | Fetch one working-state snapshot |
| GET | /secret/:name | Fetch one scoped secret |
| GET | /secrets | List scoped secrets |
| GET | /stats | Memory counts by scope |
| GET | /learning/:id/neighbors | Semantically similar memories — use to detect contradictions |
| PUT | /state/:runId | Replace or create a working-state snapshot |
| PATCH | /state/:runId | Patch an existing working-state snapshot |
| DELETE | /learning/:id | Delete one memory |
| DELETE | /learnings | Bulk delete by ?scope=, ?confidence_lt=, ?not_recalled_in_days= |
| DELETE | /secret/:name | Delete one scoped secret (?scope=...) |
POST /learn — body
{
"trigger": "string (required) — when this applies",
"learning": "string (required) — what was learned",
"confidence": 0.9, // 0–1, default 0.5
"scope": "shared", // "shared" | "agent:<id>" | "session:<id>"
"reason": "string", // optional
"source": "string", // optional
"proof_run_id": "string", // optional evidence link
"proof_iteration_id": "string" // optional evidence link
} POST /learning/:id/confirm or /reject — body
{
"proof_run_id": "string", // optional evidence link
"proof_iteration_id": "string" // optional evidence link
} POST /inject — body
{
"context": "string (required)",
"scopes": ["shared"], // default ["shared"]
"limit": 5, // default 5
"format": "prompt" // "prompt" | "learnings"
} POST /run — body
{
"outcome": "pass", // "pass" | "fail" | "exhausted"
"attempts": 3,
"scope": "shared",
"code": "string", // optional — stored truncated at 500 chars
"error": "string" // optional — included on fail/exhausted
} JS / TS client
npm install deja-client
import deja from 'deja-client'
const mem = deja('https://deja-worker.coy.workers.dev', { apiKey: process.env.API_KEY })
// before a task
const { learnings } = await mem.inject('deploying auth service')
// after a task, with proof metadata
await mem.learn('deploying auth service', 'always run migrations in a transaction', {
identity: { proofRunId: 'lab-run-42', proofIterationId: 'lab-run-42:3' }
})
await mem.confirm(learnings[0].id, {
identity: { proofRunId: 'lab-run-42', proofIterationId: 'lab-run-42:3' }
})
// live working state
await mem.putState('run-42', {
goal: 'ship the auth deploy',
openQuestions: ['did staging migration finish?']
}, { updatedBy: 'deploy-bot' })
// track loop convergence
await mem.recordRun('pass', 3, { scope: 'shared', code: '...' })
const { stats } = await mem.getRuns({ scope: 'shared' })
// stats.trend → 'improving' | 'regressing' | 'stable'
The client mirrors the hosted REST API, including confirm, reject, working-state routes, secrets, cleanup, inject tracing, and proof-linked identities. Client state payloads and trace results are exposed as camelCase even when the raw HTTP shape uses snake_case.
MCP
deja exposes its memory, working-state, and loop-run operations as MCP tools at /mcp. Secret CRUD remains HTTP-only. Works with Claude Code, Continue, Cursor, Cline, and any client that supports streamable HTTP MCP.
# Claude Code claude mcp add --transport http deja https://deja-worker.coy.workers.dev/mcp \ --header "Authorization: Bearer $API_KEY"
# Generic MCP config
{
"mcpServers": {
"deja": {
"type": "http",
"url": "https://deja-worker.coy.workers.dev/mcp",
"headers": { "Authorization": "Bearer YOUR_API_KEY" }
}
}
}
Available tools: learn, confirm, reject, inject, inject_trace, query, forget, forget_bulk, learning_neighbors, list, stats, state_put, state_get, state_patch, state_resolve, record_run, get_runs