Draft — needs review
What a source is
A source is a configured producer owned by a team or a person. It wakes on a schedule, asks an upstream what’s new, and lands what it finds as facts (artifacts deposited into a brain) and/or tasks. The motivating case: point a source at Fathom, and every call your team records lands as a transcript in the company brain with aprocess-call task filed against it — so the work of turning that call into a dossier and a set of decisions is sitting in the queue by the time anyone opens a session.
Sources pull. There is no webhook ingress and no push endpoint, so a source is exactly as fresh as its interval and never depends on an upstream being able to reach us.
Nothing in this path does inference. The runner moves bytes and writes rows. Judgment about what a transcript means happens later, in whichever mounted skill claims the task the landing filed. That separation is what makes the runner safe to re-run.
The pieces
Everything else is adapter-specific
config.
Adapters
fathom — needs a connection and a brain. Lists meetings since a watermark, then fetches each transcript (plus the summary, when you ask for it) once the recording has finished processing. Lands markdown: frontmatter with title, date, duration, attendees and links, then ## Summary and ## Transcript as timestamped speaker lines. Config: recordedBy (up to 20 emails to filter on), includeSummary, maxHeavyCallsPerTick, readinessTimeoutHours.
cron — needs nothing external; it schedules itself, so it carries no interval. Files a task on a cron expression in a timezone you choose. Config: cron, tz, catchUp (latest or all), and the task template. {{date}} and {{week}} in the title and body are interpolated in the source’s own timezone, so a Monday 09:00 Auckland tick says the Monday’s date.
The item ledger
Everything a source discovers becomes a row in an item ledger, and the ledger — not the page just fetched — drives what happens next. Each item moves throughseen → awaiting_content → landed, or ends at skipped or failed.
That ledger is what makes the whole thing idempotent. It dedupes by the upstream’s own id, so a re-run re-discovers rather than double-landing; it remembers what’s still waiting on the upstream, so a recording that isn’t processed yet is retried with a backoff instead of being lost; and it records what each item produced, so you can trace a dossier back to the meeting it came from.
Health and backoff
A failed run backs off exponentially (capped at 24 hours) and increments a failure counter. Twenty consecutive failures auto-disables the source and emails the person who created it. Two things deliberately don’t count as failures: upstream throttling (a429 is the upstream’s business, so the source is simply rescheduled behind its Retry-After) and a missing connection (capped at a 15-minute backoff instead of doubling, so an operator’s re-bind is picked up quickly).
enable clears the counter and schedules an immediate run.
How agents use it
How operators see it
/operator/sources lists every source with its schedule, health and last run. The detail page is where a source is actually configured — connection and brain pickers, interval, task kind, assignee rule — alongside its item ledger and its activity timeline.
Limits and gotchas
- Landed facts are private. A customer-call transcript was never consciously shared by a human, so it doesn’t get a link-anyone-can-open URL. Members read it through the brain.
- Deleting a source deletes its ledger, which is the dedupe history. The tasks and artifacts it already produced are kept — but a recreated source will land the same items again.
- A team source runs as its creator. If that person leaves the team, the source is disabled (unless it’s an owner handover, where it’s reassigned to the new owner).
- Bindings an adapter doesn’t need are rejected with
400 INVALID_SOURCE_CONFIG— a connection on an adapter that never calls out, or a brain on an adapter that lands no content. A binding nothing reads looks configured while being inert. - A
cronsource must have a task kind. It has no content to land, so a task is the only thing it can produce; without one it would tick forever and emit nothing. This is re-checked on every update, run, enable and disable. - A source with a
runrequest doesn’t run immediately — it runs on the next runner tick. - A brain that no longer exists disables the source rather than quietly landing private artifacts nobody can find.
Tasks
What a source files, and how it gets claimed
Connections
The stored credential a source calls out through
Brain
Where landed facts are deposited
Activity & wake
Runs, landings and failures in the feed