QuoxDream
A scheduled pass that turns raw Qortex notes into confidence-scored, deduped memory, the difference between a chunk-search index and a second brain that actually learns.
Maturity: Beta. Statements on this page were checked against QuoxCORE code on 2026-10-30.
Qortex stores raw notes: conversations, transcripts, git history, connector documents, chunked and searchable. That is retrieval, not judgement. QuoxDream is the server-side pass that reads those notes and asks a narrower question of each one: what is actually worth remembering long-term, as a standalone, confidence-scored belief in QuoxMemory?
It was written to close a gap in the second-brain design: without a consolidation pass, the store is a chunk search index with a good name. QuoxDream is what turns that chunk index into consolidation.
What it does
On each scheduled run, QuoxDream:
- Reads Qortex notes written since the last run for a given tenant slice, in strict order. Infrastructure failures hold the cursor and are retried; a note whose extraction is malformed or times out is retried (up to 3 attempts), then retired loudly and recorded, not silently skipped.
- Sends each note's text to a strict fact-extraction prompt (via the collector's
/chat/completeseam), asking for a JSON array of durable beliefs: facts, preferences, decisions, entities, constraints, or observations, each with a confidence score and an importance tag. - For every extracted claim, checks QuoxMemory for a near-duplicate before writing. A duplicate from the same source is skipped (noop); a duplicate from a new source corroborates the existing belief (the source is appended and confidence rises by 0.02); a genuinely new claim is written with its confidence, a stability tier, provenance marked
model_inference, and a source pointer back to the originating note. Claims that do not carry a verbatim quote from the note are dropped. - Advances a durable cursor so a service restart never reprocesses old notes.
Extraction is best-effort throughout: a malformed completion, a timed-out request, or a bad note is logged and retried or retired as described above, rather than aborting the run or crashing the service.
The cursor and batch model
Two tables carry the state (migration 005-dream.sql, additive-only):
dream_cursor(one row per(org_id, scope, owner_user_id)tenant slice): holds an ingestion-sequence position (withlast_occurred_atandlast_note_idkept for reference). Notes are read in ingestion order after the cursor, so edited notes and back-dated imports are not skipped, and pagination stays deterministic even when two notes share a timestamp.dream_runs(one row per consolidation run): records notes read, beliefs written, beliefs deduped, and any error, for observability, readable throughGET /brain/dream/status(coverage counts, cursor, last run and recent run count).
A single pass works through bounded batches (consolidateSlice), advancing the cursor after each batch rather than only at the end, so a crash mid-run loses at most one batch of progress, not the whole run. consolidateOrg runs this for an organisation's own notes and for private (per-user) slices, into their owner's beliefs (capped at 200 users). Shared-scope consolidation is opt-in and the scheduler never requests it.
Dedup: Jaccard first, semantic second
The default dedup check is word-overlap (Jaccard similarity) between a new claim and the top search results for its content, the same technique the collector's memory-consolidation scheduler already uses, so "near-duplicate" means the same thing across both consolidation paths.
An optional second pass, gated by QUOXDREAM_SEMANTIC_DEDUP, embeds the claim and compares it by cosine similarity against the same candidate set, widened to the 25 most recent beliefs of the same type. It respects the embedding-exclusion setting and fails closed. This only ever adds a second chance to catch a paraphrase Jaccard missed (for example "the org migrated its datastore to Postgres" versus "the team decided to use Postgres"); it never overrides a Jaccard match, and any embedder failure falls back cleanly to the Jaccard-only result. With the flag off, behaviour is byte-identical to the Jaccard-only path.
Env flags
QuoxDream ships dark. The environment variables below are defaults: a per-organisation stored setting overrides them in either direction, and most of these knobs are also available as stored settings. By default nothing runs until both of the first two are set:
| Flag | Purpose | Default |
|---|---|---|
QUOXDREAM_ENABLED | Default switch. Scheduler does nothing unless exactly 'true' or the organisation enables it in settings. | false |
QUOXDREAM_ORGS | Comma-separated org IDs to consolidate. Empty means no orgs run even if enabled. | empty |
QUOXDREAM_WARMUP_MS | Delay before the first tick after boot, so the service finishes health-checking first. | 5 minutes |
QUOXDREAM_INTERVAL_MS | Interval between ticks. | 6 hours |
QUOXDREAM_BATCH_SIZE | Notes read per batch within a run. | 40 |
QUOXDREAM_MAX_BATCHES | Batches per run per tenant slice. | 5 |
QUOXDREAM_SEMANTIC_DEDUP | Turns on the cosine-similarity second pass described above. | off |
QUOXDREAM_SEMANTIC_DEDUP_THRESHOLD | Cosine similarity floor for a semantic match. | 0.90 |
QUOXDREAM_EXTRACT_TIMEOUT_MS | Per-note extraction timeout, so one slow note cannot wedge a whole pass. | 90 seconds |
Settings: whether Dream may send note text to the chat model (QUOXDREAM_ALLOW_LLM_TEXT) is a per-organisation platform setting (settable, audited, re-read every scheduler tick, fails closed), and the Qortex privacy panel shows it. Run history is available from GET /brain/dream/status; a dashboard timeline of runs is not built yet. Enrolling an organisation still uses QUOXDREAM_ORGS.
Maturity
| Capability | Status | Notes |
|---|---|---|
dream_cursor / dream_runs schema | Stable | Additive migration. |
extractBeliefs (LLM extraction) | Beta | Unit-tested with a mocked collector; best-effort by design. |
writeBelief (Jaccard dedup + write) | Beta | Unit-tested with a mocked memory service. |
Semantic dedup (QUOXDREAM_SEMANTIC_DEDUP) | Beta | Still additive on top of Jaccard, not a replacement. |
Scheduler (startDreamScheduler) | Beta | Dark by default. |
| Dashboard visibility | Partial | Whether Dream may send note text to the chat model is a per-organisation setting shown in the Qortex privacy panel. A dashboard timeline of runs is not built; run history is via GET /brain/dream/status. |
| Per-user-scoped consolidation | Built | Private (per-user) slices consolidate into their owner's beliefs, with their own cursor row per slice. |
| Supersede-on-update | Built | A contradicting claim (polarity reversal per clause, or a changed number, date or named value) marks the older belief superseded_by; a correction that adds an exception or condition also replaces the older belief, and a belief the user has reinstated is respected; private notes consolidate into their owner's beliefs. |
Related
- Memory System: the QuoxMemory store QuoxDream writes beliefs into.
- Qortex: the second-brain plugin QuoxDream consolidates notes from.
- Schedulers: the other server-side background passes QuoxDream's scheduler shape is mirrored from. </content>
Last verified 2026-10-30 against QuoxCORE origin/main.