Dream Cycle
Your agent forgets everything between sessions. Dream Cycle fixes that. Log what happened during the day (
submit_episode_log), trigger a consolidation pass (start_dream), and the next session reads back small, durable lessons (query_dream) instead of re-learning the same mistake. Zero setup — it's on by default on the samehttps://hypermove.xyz/api/mcpendpoint you already use.
Why this exists
Every MCP session an agent runs starts from zero. If it discovers "the gripper needs a 200ms cooldown before retry" today, that lesson is gone tomorrow — unless you paste the whole transcript back into context, which is slow and expensive at scale.
Dream Cycle is an offline consolidation pass, modeled on how research like "sleep-time compute" and offline memory-consolidation work: cheap, rule-based passes do most of the work; a small LLM call only touches compressed summaries, never raw logs. The output is a handful of short, confidence-scored memories your agent can pull in a single call — cents per day, not dollars.
The 30-second mental model
during the day: submit_episode_log(agent_id, episodes) → cheap, no LLM call
end of day: start_dream(agent_id, {budget_usd: 0.10}) → runs the whole pipeline
next session: query_dream(agent_id, "gripper timeout") → "retry after 200ms cooldown"
That's the whole surface. Everything else (resources, prompts, presets, stats) is optional sugar on top of those three calls.
For humans — what you get and what it costs
- No new infra. Same endpoint, same auth, same bearer token. Dream Cycle just adds
5 tools to what your agent already sees when it calls
tools/list. In this session's changes:submit_episode_log,start_dream,get_dream_config,query_dream,get_dream_stats. Also 4 resources and 3 prompts — see below. - All 5 tools are free. They never hit the paywall or the 5-free-queries/24h limit.
Spend is capped by your own
budget_usdper cycle (default $0.10), not by HyperMove's tiers. - Nothing changes if you never call
start_dream. Logging withsubmit_episode_logcosts nothing and does nothing until you trigger a cycle — no background jobs, no surprise charges. - Your data stays yours. Memories are scoped per
agent_id, bound to whichever session first used that ID — a different account can never read or write into it.
For agents — the fastest path to using this
- Connect to
https://hypermove.xyz/api/mcpthe same way you already do (see MCP Gateway if you haven't yet — bearer token from /mcp-connect or the no-wallet flow). - Call
tools/list— if Dream Cycle is enabled (default: yes) you'll see the 5 tools below. - Log episodes as you go. Trigger a cycle whenever you want. Query before you plan.
No separate signup, no separate API key, no SDK to install — it's 3 JSON-RPC calls against a tool surface you already discover automatically.
Pick your agent_id once, then it's yours
The first call to submit_episode_log or start_dream for a new agent_id claims
it for your session. After that, only your session can write to it — pick a stable,
unique string (e.g. your robot's serial number, your bot's slug) and reuse it every day.
1 — Log what happened
curl -s https://hypermove.xyz/api/mcp \
-H 'authorization: Bearer <token>' \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{
"name":"submit_episode_log",
"arguments":{
"agent_id":"robot-42",
"episodes":[{
"episode_id":"run-2026-07-26-001",
"agent_id":"robot-42",
"timestamp":"2026-07-26T09:00:00Z",
"task_type":"pick_and_place",
"outcome":"failure",
"steps":[
{"action":"grip"},
{"action":"retry"},
{"action":"grip_again","error":"gripper timeout"}
],
"tags":["pick_and_place","gripper"]
}]
}
}}'
Returns { "ingested_count": 1, "rejected": [] }. Call this as many times a day as you
want — resubmitting the same episode_id is a safe no-op, never a duplicate. No LLM call
outcome accepts exactly three values: success, failure, or timeout — there is no
"partial" state. For a task that partly succeeded, pick whichever of the three best
matches the primary goal (usually success if the main objective was met despite a
caveat). This is also declared as an enum on the tool's inputSchema, so MCP clients
that render tool schemas surface the valid values without a round-trip.
happens here; this step is free and near-instant.
2 — Trigger a Dream Cycle
curl -s https://hypermove.xyz/api/mcp \
-H 'authorization: Bearer <token>' \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{
"name":"start_dream",
"arguments":{"agent_id":"robot-42","config":{"budget_usd":0.10,"preset":"balanced"}}
}}'
Returns { "run_id":"…", "status":"started" } and, once the pipeline finishes inside
that same call, the run reaches completed or partial (if the budget ran out — still
useful, never wasted). Presets: frugal (cheapest, fewer clusters), balanced (default),
thorough (most coverage, higher cost). Call this once a day, or whenever you have a
batch of new episodes worth consolidating — there's no scheduler, you decide when.
3 — Query before you plan
curl -s https://hypermove.xyz/api/mcp \
-H 'authorization: Bearer <token>' \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{
"name":"query_dream",
"arguments":{"agent_id":"robot-42","query":"gripper timeout","top_k":5,"min_confidence":0.5}
}}'
Returns memories sorted by relevance:
{ "memories": [
{ "memory_id":"…", "type":"error_pattern", "content":"gripper timeout after retry",
"confidence":0.9, "importance":0.8 }
] }
Read this before your agent starts planning a task — it's the whole point.
Skip the query — read memories as MCP resources instead
If your MCP client supports resources, you can pull the same data with no arguments to
fill in — just the right URI for your agent_id:
| Resource | Contents |
|---|---|
| hypermove:///agents/{agent_id}/dream/summary | Last run's status + how many memories exist |
| hypermove:///agents/{agent_id}/dream/rules | High-confidence rules |
| hypermove:///agents/{agent_id}/dream/errors | Known error patterns |
| hypermove:///agents/{agent_id}/dream/stats | Budget spent, stages completed, memory count |
Skip the prompt engineering — use the built-in prompts
| Prompt | What it does |
|---|---|
| dream/summarize_today(agent_id) | Plain-language summary of the last cycle |
| dream/suggest_policy_updates(agent_id, task_type) | Concrete policy changes for one task type |
| dream/compare_before_after(eval_scores_json) | Compares your own before/after eval numbers |
These are templates, not tools — an MCP client that supports prompts/get renders them
pre-filled; there's nothing extra to call.
Check in on a cycle
-d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"get_dream_stats","arguments":{"agent_id":"robot-42"}}}'
-d '{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"get_dream_config","arguments":{"agent_id":"robot-42"}}}'
get_dream_stats → last_run_at, status, budget_used_usd, stages_completed,
memories_count, and (additive) stage_summaries — a coarse, non-content-leaking
breakdown of what each stage did: how many episodes preprocessing discarded and why,
how many clusters extraction attempted/skipped/failed, and how many of extraction's
candidate insights pruning actually promoted vs. discarded. If memories_count stays
0 after a run with real episode data, check stage_summaries.pruning_summary — a
nonzero candidates_extracted with candidates_promoted: 0 means extraction genuinely
found something that didn't survive pruning (not a silent failure to process your data).
get_dream_config → whatever budget_usd/preset you last set.
Before filing a "this looks broken" report, check GET /api/mcp/health (the gateway
process) and GET https://hypermove.duckdns.org/llm/health (the extraction service) —
both return a commit field (added 2026-07-27) so you can confirm the fix you're
expecting is actually deployed, rather than guessing from a maintainer's say-so.
What a fresh agent needs for its first promoted memory
One episode with at least one non-empty steps entry is enough. There is no
meaningful confidence/importance threshold standing between a fresh agent and its first
promoted memory — pruning's defaults (min_confidence: 0, min_importance: 0) accept
anything, and every new memory is inserted at confidence: 0.5, importance: 0.5, already
well above that floor. A cluster of size 1 (a single unmatched episode) is a valid
cluster; there's no minimum cluster size either.
What actually determines whether you get a memory:
steps: [](zero steps) is discarded before extraction ever sees it — this is the one real filter, and it shows up instage_summaries.preprocessing.discard_reasonsasempty_steps. Give every episode at least onestepsentry with a realaction.- Extraction has to find something "rule/preference/error_pattern/fact"-shaped. A
single bland episode (e.g.
{"action": "did the thing"}with no error, no context) may legitimately produce zero insights for its cluster — that's a correct outcome for low-signal input, not a bug.stage_summaries.extraction.candidates_extractedtells you whether this happened;clusters_failed/clusters_skippedtell you whether it was a transient extraction failure or a budget cutoff instead. stage_summariesis the tool for "why didn't anything promote," not guesswork. Readpruning_summary.candidates_extractedvs.candidates_promotedfirst, every time, before assuming something is broken.
If a query on a fresh agent still returns nothing after a run with genuinely descriptive
episode content (real actions, real errors on failures), check stage_summaries
before filing a report — it will show you exactly which stage the signal was lost at.
What's on by default, and how to turn it off
Dream Cycle ships on, same as the rest of the MCP Gateway's v3.0+ tools — no flag to flip to start using it. If you need to disable it (e.g. to roll back a bad deploy):
FEATURE_MCP_DREAM_CYCLE=false
One env var removes all 5 tools, all 4 resources, and all 3 prompts in one flip — nothing else on the gateway changes.
Known limits (Phase 1 — honest, not hidden)
start_dreamstill always runs immediately when called — the manual path is unchanged and always available, on-demand, regardless of the scheduler below.- Server-side
trigger_criteriaenforcement is opt-in, not default (2026-07-27). By default, nothing runs your cycles for you — settrigger_criteriainconfigand it's saved either way, but only enforced automatically if the operator has enabledFEATURE_MCP_DREAM_SCHEDULER=true(off by default; see "Server-side scheduling" below for why). Without it, exactly as before: you decide when to callstart_dream. - No quality benchmark is published yet. The pipeline is fully functional and budget-safe; the "how much better did my agent get" number isn't measured in this release.
- Best for motion/episode-style agents. Dream Cycle assumes step-by-step episode logs with an outcome (success/failure/timeout) — it's not a general-purpose memory store for arbitrary unstructured text.
Server-side scheduling (opt-in, added 2026-07-27)
If you set trigger_criteria in start_dream's config (time_window_utc,
min_episodes, min_raw_tokens), it's always persisted — but by default nothing reads
it back automatically. An operator running this MCP gateway can opt into server-side
enforcement:
FEATURE_MCP_DREAM_SCHEDULER=true
Once enabled, an in-process hourly tick checks every agent's trigger_criteria and
fires start_dream on your behalf when your conditions are met — no external cron, no
script you have to remember to run. This is deliberately opt-in, not the default
(unlike every other Dream Cycle flag) because it's the first feature in this gateway
that autonomously spends budget across every registered agent with no per-call human
trigger. Two independent ceilings bound worst-case cost per tick regardless of how many
agents are configured: DREAM_SCHEDULER_MAX_BUDGET_USD_PER_TICK (default $1.00 total
across all agents per tick) and DREAM_SCHEDULER_MAX_AGENTS_PER_TICK (default 20) — an
agent beyond either ceiling is deferred to the next tick, not silently dropped.
get_dream_stats's triggered_by field ('manual' or 'scheduler') tells you which
path produced the last run. If you were already running your own external scheduler
(e.g. a cron job calling start_dream directly), nothing about that changes — the two
paths are independent and can coexist; enabling the server-side scheduler on top of an
existing external one will just mean both fire (consider disabling one if you do).
Full technical detail, data model, and pipeline internals: docs/prd/dream-cycle-v1.md in the repo.
Was this helpful?