Observe¶
Connectors pull new messages, email, and calendar records into a local append-only archive. Everything is archived; later stages decide what deserves attention.
The archive¶
Each archived row keeps source time separate from collection time: when a message was written versus when memcal collected it. A delayed old message is new to the archive even though its source timestamp is old — per-field precedence later runs on when evidence was said, so the distinction matters.
Rows deduplicate on (stream, external_id), so re-runs and redelivery are safe.
Source and thread identity travel with every row, which is what lets later stages
link an event's supporting evidence back to the exact thread it came from. The
archive is full-text indexed (SQLite FTS5) and searchable at any time:
memcal search "dinner next week"
Nothing lives only in a derived store. A wrong gate decision costs a search later, never a loss.
Transports¶
A new platform implements hooks, not another ingest loop. There are two shapes:
| Shape | Behavior | Sources |
|---|---|---|
PolledSource |
Enumerates conversations, reads each forward from a per-chat watermark | Slack, Telegram, GroupMe |
StreamSource |
Drains one ordered queue from a single cursor | Signal, iMessage, WhatsApp, BlueBubbles |
Per-conversation watermarks mean quiet chats cost nothing on re-runs; destructive queues (Signal) drain whole by design. See Sources for per-platform behavior, budgets, and rounds.
Collection without a model¶
memcal ingest only moves bytes: fetch, deduplicate, archive, spool. It never
calls dream, extraction, semantic matching, or a model:
memcal ingest slack --limit 20 # one source, small first sip
memcal ingest all # everything configured
--limit caps items per round and --rounds (default 25) repeats while more work
waits. During the day, collection runs on a short cadence (minutes, while the host
and source are reachable) so fresh traffic is archived long before the next dream.
Daytime collection and the nightly pass share this path — collection never triggers
consolidation by itself.
Lines that pass the gate are spooled for the model pass. Lines older
than the spool horizon (MEMCAL_SPOOL_HORIZON_DAYS, default 30) stay archived and
searchable but are not queued for extraction. Muted and platform-muted threads are
still collected; muting shapes priority and presentation, never collection.
Due-only collection¶
Daytime collection asks what is due, not what is new. Each source records a durable outcome per attempt — complete, incomplete, or failed — with the last time it was completely checked. A later failure never erases the earlier successful check, and an interrupted attempt never reads as complete:
memcal ingest all --due # collect only sources due for another check
Due means the configured interval (MEMCAL_COLLECT_INTERVAL_MINUTES, default
5 minutes) has elapsed since the source's last attempt — even if no recent
messages exist. A quiet inbox checked at 11:00 is due again at 11:05 regardless
of when its newest message was written. Failed, unavailable, and incomplete
attempts wait at least the interval before automatic retry, and stronger
connector backoff still applies.
Ingest summaries and the queue view report the same per-source outcome:
[complete] for an exhausted source, [incomplete — more waiting] when work
remains, plus failed, unavailable, and unknown for the rest. A quiet final
page never erases earlier pages' counts; an error preserves partial counts.
When nothing is due, the command is a genuine no-op: no source checks, no
collection records, no brief rewrite, no model work. An explicit ordinary ingest
always forces collection and records its outcome. --due and --stale do not
combine. A due run that leaves a source unavailable, failed, or incomplete exits
nonzero with the reason.
Agent conversations¶
Inbound user turns from the Hermes and OpenClaw integrations archive the same way, under the agent stream. Only the user's original message is kept as user-authored evidence — assistant replies, injected snapshots, and tool output are excluded so they can never become "facts" later. See Agent conversations and Daytime freshness.