deja
API Reference

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

POST /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 }]
}
POST /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