Extraction API

The Extraction API converts an agent's tool-call trace into a replayable procedure. Parsing is deterministic — no generative model is involved, so the same input always produces byte-identical output. The API is stateless: request bodies are never stored or logged. The only server-side state is a hash of each issued key and anonymous per-request usage metrics. The resulting procedure is written into your own database, on your side, through your existing GBrain connection.

agent prompt — everything an integrating agent needs
You are integrating a harness or agent with the Memorable Extraction API.
Base URL: https://memorable-extraction-api.memorable.workers.dev

1. Get a key once (no account): POST /v1/keys with {} -> { "api_key": "mk_..." }.
   Store it; send it as "Authorization: Bearer mk_...". Issuance: 10/min and 50/hour per IP.
2. After each finished session, POST /v1/extract with:
   { "session_id": "<stable id>", "harness": "<your harness name, any string>",
     "task_description": "<one line: what the task was>", "skip_embedding": true,
     "tool_calls": [ { "name": "<tool>", "input": { "command"|"file_path"|"path"|
       "pattern"|"url"|"query": "<string>" }, "result": { "ok": true|false } |
       { "exit_code": 0 } } ] }
   Send ONLY these fields. Do not send conversation text, file contents, or
   credentials; include "result" only when the outcome is actually known.
3. Response: { "draft": { title, steps[{seq, action, activity_class, command?,
   repeat_count, targets?, creates?}], trigger_signature{entities, search_text}, preconditions,
   postconditions, ... }, "request_id": "..." }. Parsing is deterministic:
   identical input yields an identical draft. Store the draft yourself, on the
   user's side; the API keeps nothing.
4. Errors: 401 unauthorized, 400 invalid_json/invalid_request, 413 over 8MB,
   429 rate_limited (300/min per key). Every response carries request_id;
   include it when reporting problems.

Base URL

https://memorable-extraction-api.memorable.workers.dev

Authentication

Every request requires a bearer token in the Authorization header. Requests without a valid token return 401. Keys look like mk_… and are issued self-serve — there is no sign-up. Only a SHA-256 hash of your key is ever stored server-side.

Authorization headerhttp
Authorization: Bearer $MEMORABLE_API_KEY

Every response carries a request_id (also in the x-memorable-request-id header). Include it when reporting a problem — it lets us find your exact request.

Get a key

post/v1/keys

Issues a fresh API key. No authentication, no account, no email — the only unauthenticated endpoints are this and GET /healthz, and issuance is tightly rate-limited per IP. If you use the CLI you never call this yourself: memorable init issues a key automatically and saves it to ~/.memorable/config.json.

Requestcurl
curl -X POST https://memorable-extraction-api.memorable.workers.dev/v1/keys \
  -H "Content-Type: application/json" -d '{}'

# → { "api_key": "mk_…", "request_id": "…" }

Create a procedure

post/v1/extract

Converts a trace into a ProcedureDraft. Any harness is accepted: known harnesses (claude-code, codex, opencode) get curated activity registries; every other harness string is served by a generic tier that still infers execution from command-shaped input.

Body parameters

session_idstringrequired
Stable identifier for the session. Re-extracting the same session updates the same stored procedure rather than creating a duplicate.
tool_callsarray of ToolCallRecordrequired
The ordered tool calls the agent made. Each record:
namestringrequired
Tool name exactly as the harness emitted it.
inputobjectrequired
The tool's raw arguments, unmodified. Never summarized or rewritten.
resultobjectoptional
Structured outcome, when available: { ok?: boolean, exit_code?: number }. Powers postcondition detection — success is derived from real outcomes, never guessed from a command's name. Omitting it is valid; postconditions simply come back empty.
task_descriptionstringoptional
One-line description of the task. When present it becomes the procedure's title and primary matching text.
corpusstringoptional
Free-text transcript, if the agent keeps one. Cloud agents with only a structured trace omit this entirely.
harnessstringoptional
Which agent produced the trace. Any string is accepted.
skip_embeddingbooleanoptional
Skip the server-side embedding call because you embed locally with your own provider. The CLI sets this automatically when your GBrain has an embedding provider configured.

Response fields

draft.titlestringrequired
The procedure's title, from task_description or the first meaningful transcript line.
draft.stepsarrayrequired
Ordered steps: { seq, action, activity_class, command?, repeat_count, targets?, creates? }. Retry cycles collapse into one step with repeat_count recording the repetitions.
draft.steps[].activity_classstringrequired
One of read, write, search, execute, other. A shell line is classified from the command itself, deterministically: pure reads and searches are downgraded out of execute, file mutations are upgraded to write, and anything ambiguous stays execute. Without this a harness that funnels everything through one shell tool records no reads at all, and with no reads there are no dependencies between procedures.
draft.steps[].targetsarray of stringoptional
The files a shell line actually touched, parsed from real write destinations (redirect, tee, cp/mv destination, mkdir, touch, sed -i) and read operands — never from every path-shaped token, and never from inside a heredoc body. Absent when the tool named its own file in command; present but empty means the line was parsed and touched none.
draft.steps[].createsbooleanoptional
The shell construct brought the file into existence rather than modifying something already there. Only a creation makes a later reader depend on this procedure.
draft.trigger_signatureobjectrequired
What makes this task recognizable later: the summary text, plus structural entities — file paths touched, commands run, tools used.
draft.preconditionsarray of stringrequired
The files that had to exist before the first write or execute — the context the procedure assumed. These are file paths, not the shell lines that read them: a grep is a step, the file it searched is the precondition.
draft.postconditionsarray of stringrequired
Verified outcomes, derived from a real success signal (exit code 0 or an explicit ok flag) on the final executing step. Empty when no outcome data was provided.
draft.embeddingarray of numberrequired
Similarity vector for the trigger text, or [] when skipped or the provider failed. Failure never blocks the draft.
draft.embedding_modelstringrequired
The model that produced the vector. Vectors from different models are never compared at recall time.
Requestcurl
curl https://memorable-extraction-api.memorable.workers.dev/v1/extract \
  -H "Authorization: Bearer $MEMORABLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "session_id": "run-183",
    "task_description": "rotate the TLS cert for api.example.com",
    "harness": "my-python-orchestrator",
    "tool_calls": [
      {"name": "shell",
       "input": {"command": "certbot renew"},
       "result": {"ok": true}},
      {"name": "shell",
       "input": {"command": "nginx -s reload"},
       "result": {"ok": true}}
    ]
  }'
Response · 200json
{
  "draft": {
    "title": "rotate the TLS cert for api.example.com",
    "session_id": "run-183",
    "schema_version": "1.0.0",
    "trigger_signature": {
      "summary_text": "rotate the TLS cert for api.example.com",
      "entities": {
        "file_paths": [],
        "commands": ["certbot renew", "nginx -s reload"],
        "tool_names": ["shell"]
      },
      "search_text": "rotate the TLS cert ..."
    },
    "steps": [
      { "seq": 1, "action": "shell", "activity_class": "execute",
        "command": "certbot renew", "repeat_count": 1 },
      { "seq": 2, "action": "shell", "activity_class": "execute",
        "command": "nginx -s reload", "repeat_count": 1 }
    ],
    "preconditions": [],
    "postconditions": [
      "final command exited successfully: nginx -s reload"
    ],
    "embedding": [],
    "embedding_model": ""
  }
}

Embed a query

post/v1/embed

Query-side embedding for recall. Used only as a fallback — recall tries exact and lexical matching locally first (zero tokens, zero network), and the CLI prefers the embedding provider your GBrain already has configured.

textstringrequired
The task description to embed. Truncated to 8,000 characters.
Requestcurl
curl https://memorable-extraction-api.memorable.workers.dev/v1/embed \
  -H "Authorization: Bearer $MEMORABLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "rotate the TLS cert"}'

Errors

Errors return JSON with an error code and, where useful, a detail message.

StatusCodeMeaning
401unauthorizedMissing or invalid bearer token.
400invalid_requestMissing session_id or tool_calls; detail says what's expected.
400invalid_jsonThe request body is not valid JSON.
413payload_too_largeBody over 8 MB.
429rate_limitedOver the per-key limit (or key-issuance per-IP limit); body carries retry_after_s.
404not_foundUnknown path or method.
503keys_unavailableKey issuance temporarily unavailable.

An embedding-provider failure is not an error: the draft still returns with embedding: [] and an embedding_error field, and recall degrades to lexical and exact matching.

Rate limits

300 requests per 60 seconds per API key, and 3 key issuances per 60 seconds per IP, enforced at the edge. A typical integration makes one /v1/extract call per completed long-running session, which sits far below the limit.

Security

  • Stateless by design. No database, no persistence — request bodies are processed in memory and discarded. Bodies are never logged.
  • Your database stays yours. The API never receives connection credentials. Writes happen on your machine through your existing GBrain connection, into an isolated source.
  • Pre-scanned input only.The CLI sends only content that has already passed GBrain's secret scanner, and refuses to send a session that was written unscanned.
  • Injection-hardened recall.Stored procedures are re-rendered as explicitly inert reference data, stripped of control characters and size-capped, before they ever reach an agent's context.