For AI agents: a documentation index is available at https://www.plungeai.com/docs/llms.txt. Append .md to any page URL, or send Accept: text/markdown, to get markdown. Setup instructions for agents are at https://www.plungeai.com/docs/agents.md. One ozk_ key opens every plane, models included.

Documentation Index: fetch the complete documentation index at /llms.txt. Use this file to discover all available pages before exploring further.

PlungeAI has TWO memory systems with different jobs:

SharedMemoryLong-term memory
HoldsEvery task's output within/after a runWhat the agent LEARNED about the user and its work
Keyed by(workflow_id, task_id, user)Per user (or per bot namespace)
LifetimePer execution, durable for retrievalStanding, across all runs
You read it viaplungeai_get_result, /v1/*/results/…Automatic recall in runs; plungeai_memory
You write it viaNever directly — agents store resultsplungeai_memory remember; the agent's own memory tool

"Fetch what that run produced" is SharedMemory. "Remember that the user prefers weekly summaries" is long-term memory.

SharedMemory — the run-data fabric

Every task result — including single agent calls — is stored under (workflow_id, task_id) scoped to your user. That is why every execution acknowledgement returns those ids: they are redemption tickets.

# MCP — final result (full conversation thread for conversational runs)
plungeai_get_result {execution_id: "exec-…"}
# One step of a fan-out
plungeai_get_result {execution_id: "exec-…", task_id: "web"}
# One API
curl -s https://api.plungeai.com/v1/workflows/results/{workflowId}/{taskId} \
  -H "Authorization: Bearer ozk_YOUR_KEY"
curl -s https://api.plungeai.com/v1/agents/results/{workflowId}/{taskId} \
  -H "Authorization: Bearer ozk_YOUR_KEY"
# 200 {content, content_type, workflow_id, task_id} | 404 not_ready

Facts to rely on:

  • 404 not_ready = still running (or a beat behind) — poll; not an error.
  • Results are scoped to the executing user — you cannot redeem another user's ids.
  • The final result of a run lists its steps (MCP renders them); open any step in full with its task_id. Use this to inspect ONE branch of a parallel block instead of re-running.
  • Within a workflow, data handoff between tasks IS SharedMemory — automatic; never hand-wire results between tasks in YAML.
  • A scheduler run id is not a SharedMemory id: go through plungeai_schedule {action: "runs"} and use its Execution ID column (plungeai-scheduling).

Long-term memory — the agent's durable brain

Per user, three layers of plain markdown:

LayerFileWhat it holds
L3USER.mdThe agent's learned model of the user (preferences, context)
L2MEMORY.mdCurated agent notes shared across this user's missions
L1episodes.mdAppend-only run log: goal + self-reported outcome per mission

Recall — a frozen snapshot per run

At mission start the platform builds ONE snapshot of the curated stores only — MEMORY.md + USER.md. episodes.md is never injected (task outcomes go stale; pull run history explicitly with search_runs or the mission's recall tool). The snapshot is prepended to the agent's system prompt. Mid-run writes are durable but do not mutate the running prompt (prompt-prefix stays cache-stable). So: what a mission "knows" is fixed at launch; what it learns benefits the NEXT run. Two missions launched together do not see each other's writes.

Writing

  • In-loop: the agent's memory tool (missions write learnings as they work; episodes append automatically at run end).
  • From outside: plungeai_memory (MCP), ocean-cli memory, or the One API (next section):
plungeai_memory {action: "recall"}                       # read the durable store
plungeai_memory {action: "remember", target: "user",     # user | memory
                 operation: "add",                       # add | replace | remove | read
                 content: "Prefers weekly summaries, no emojis in reports"}
plungeai_memory {action: "search_runs", query: "competitor analysis"}
plungeai_memory {action: "get_run", run_id: "…"}

Use remember whenever the user says "remember this". Note the split: recall reads the curated stores; the run journal (search_runs/get_run) is separate and deliberately NOT part of recall — history is queried, not ambient.

Budgets — memory is curated, not a dump

The stores are small on purpose (defaults: MEMORY ~2200 chars, USER ~1375; configurable per user, clamped to 500–20000). Writes beyond the limit force curation — replace/remove stale entries rather than appending forever. Write memory like an engineer writes a runbook: few, load-bearing, current facts. Ten vague notes crowd out the one that matters.

Safety

Every entry is threat-scanned twice: at write (a prompt-injection-looking entry is rejected) and at snapshot build (a poisoned stored entry is replaced with a [BLOCKED] placeholder; the raw text stays inspectable by the user). Do not try to store instructions-to-future-agents phrased as commands — that is exactly the pattern the scanner exists to stop. Store facts.

Over the One API — /v1/memory, /v1/skills

Auth: Authorization: Bearer ozk_YOUR_KEY. Every call acts on the key's own user; format (json default, yaml, markdown, text) is accepted in the body or as ?format=.

curl -s "https://api.plungeai.com/v1/memory/recall?q=weekly&limit=20" -H "Authorization: Bearer ozk_YOUR_KEY"
# 200 {"entries":[{"id":"mem_3f2a9c01b7de","scope":"user","text":"Prefers weekly summaries"}],"count":1}

curl -s -X POST https://api.plungeai.com/v1/memory/remember -H "Authorization: Bearer ozk_YOUR_KEY" \
  -H "Content-Type: application/json" -d '{"text":"Prefers weekly summaries, no emojis","scope":"user"}'
# 201 {"id":"mem_…","scope":"user","text":"…","usage":"…","message":"added"}   (200 when already stored)

curl -s -X POST https://api.plungeai.com/v1/memory/forget -H "Authorization: Bearer ozk_YOUR_KEY" \
  -H "Content-Type: application/json" -d '{"id":"mem_3f2a9c01b7de"}'          # or {"text":"weekly"}
# 200 {"removed":1}
RouteNotes
GET /v1/memory/recallq keeps entries containing it (case-insensitive) across the MEMORY and USER stores; limit 1–100, default 50
POST /v1/memory/remembertext 1–65,536 chars; scope memory (default) or user; 422 memory_rejected carries current_entries
POST /v1/memory/forgetexactly one of id / text (else 422 invalid_params); 404 memory_not_found; 409 memory_conflict
GET /v1/memory/runsq required (422 invalid_params); hits are {run_id, ts, goal, snippet}
GET /v1/memory/runs/{id}{run_id, content}; 404 run_not_found, also for another user's run
GET /v1/skills, POST /v1/skills/learn, DELETE /v1/skills/{id}your private skills only ({skills: [{id, description}], count}); learn saves the markdown body you send under name — it does not distil a source

An entry's id is mem_ plus twelve hex characters derived from its scope and text, so it is stable between reads and cannot name an entry your stores do not hold. REST recall returns structured entries; MCP recall returns the MEMORY.md + USER.md snapshot a mission starts with.

Namespaces and special runs

  • Bots: policy since 2026-08-23 is to omit memory_owner entirely (a saved workflow/agent/bot/campaign YAML carrying it is refused, 422 invalid_workflow) — the first 20 bots were authored with a hardcoded memory_owner: "<ownerUserId>:bot:<workflowId>" and all had it stripped. Without it, a bot run reads/writes the owner's general memory namespace, shared across all their bots and runs ("check memory" / "store in memory" phrasing still works; prompts are a bit larger since the recall snapshot is built from the whole store). The harness guard (resolveMemoryUser) honors a hardcoded memory_owner only when it names the runner's own identity — anything else is rejected with a warning and falls back to the owner's store, so a copied YAML can never read or write another user's memory even if it tries. Full policy and rationale: orchestration/BOT-CREATION.md. (Do not confuse this with a workflow's followup.memory_scope: all_tasks|last_task, which only scopes follow-up chat context.)
  • Scheduled runs keep the full per-user memory lifecycle — a daily mission genuinely accumulates. Only system jobs and heartbeat condition checks are memory-free (heartbeat is a user-facing job type — see plungeai-scheduling — whose ticks are watch-and-notify checks, not learning runs).
  • Delegate children never write memory: the memory tool is stripped from fan-out children by design — one writer per run.

Choosing the right memory move

NeedMove
Output of a run/stepplungeai_get_result (+ task_id)
Pass data between workflow stepsNothing — automatic
"Remember X about me/us"plungeai_memory remember
Mission should apply past learningsAutomatic recall — just run it; curate memory if recall is noisy
"What did we do about X before?"plungeai_memory search_runs → get_run
Standing company/product context for many runsNot memory — a background card (plungeai-skills-plugins)
Reusable method/knowledge packNot memory — a skill, created with plungeai_learn (below)

The last two rows matter: memory is per-user learned state. Shared, versioned, deliberately-authored context belongs in backgrounds and skills, where injection is explicit and reviewable.


MCP tool: plungeai_memory

Purpose: the user's long-term memory. Two stores, deliberately separate: the durable memory that recall reads (and remember writes), and the run journal of past mission runs (search_runs/get_run).

Actions

ActionRequiresNotes
recall—Everything the platform remembers about the user (the same recall missions get automatically).
remembercontent (add/replace) or old_text (remove); neither for readDurable write. target: user (profile facts) | memory (working knowledge, default). operation: add (default) | replace (needs old_text + content) | remove (needs old_text) | read. recall sees writes immediately.
search_runsquerySearch the run journal (optional limit, default 10).
get_runrun_idOne journal entry in full.

Example: {"user_request": "remember that I prefer summaries under 200 words", "action": "remember", "target": "user", "content": "Prefers summaries under 200 words"}

Returns: recall → the memory document (or "No memory recorded yet."); remember → "Saved to your user profile/memory ... recall will see it immediately."; failed writes return the error plus the CURRENT entries so a replace/remove can be retried with an exact old_text.

Failures & fixes: "content is required for remember" / "query is required for search_runs" / "run_id is required for get_run" → supply them. A replace/remove that misses names the current entries — copy old_text verbatim from that list and retry. Use remember whenever the user says "remember this" — chat context alone does not persist.


MCP tool: plungeai_learn

Purpose: distill a source into a reusable skill, saved PRIVATE to the user — future runs can inject it. The source can be a URL, pasted text/markdown, or a description of what was just accomplished in this chat (learn-back). Runs the platform's learn agent card, which resolves live at run time. Async by default.

Parameters

ParamTypeNotes
actionlearn (default) | list | forgetlearn: distill source into a skill. list: your learned skills. forget: delete one (name required).
sourcestringRequired for action: learn (a URL, pasted text/markdown to distill, or a description of what you just did). Not used by list/forget.
namestring (kebab-case)On learn: optional skill id — the agent picks one if omitted. On forget: required (the id from action: list).
modesync | asyncOnly applies to learn; default async.

Example (learn): {"user_request": "save what we learned about CNL debugging as a skill", "source": "Distilled findings from this session: ...", "name": "cnl-debugging"}

Example (list): {"user_request": "what skills have I saved?", "action": "list"}

Example (forget): {"user_request": "delete my cnl-debugging skill", "action": "forget", "name": "cnl-debugging"}

Returns:

  • learn, async (default): "Started distilling <id> (async)..." → poll plungeai_get_workflow_status, fetch with plungeai_get_result (the result names the saved skill).
  • list: a table of your learned skills (- \id` — description`), or "No learned skills yet."
  • forget: "Forgot skill <name>."

Failures & fixes: learn without source → needs_input. forget without name → "forget needs name (the skill id from action: list)." forget on an id you don't own, or that doesn't exist → "Not yours to delete" / "No skill named <name>. Use action: list to see yours." Authentication required (needs a real user key); unreachable URLs on learn surface in the run result — retry with pasted text instead.

This is the "learn-back" move: when a session produced real research, offer to distill it so future runs can inject it as a skill — see plungeai-skills-plugins for how a saved skill gets declared and injected on later runs.

Planned: TI-34

The docs assistant is not available yet. You can hand these docs to your own assistant instead.