Skip to main content

Find Trigger task groups

Trigger.dev tasks live in trigger/*.ts and are the production scheduler for connector refreshes, reports, document lifecycle, and health watchdogs. This page indexes every task; four groups get their own deeper page.

Customer portal delivery​

All portal tasks share the sable-portal-notifications queue with concurrency one:

Task idCadencePurpose
sable.portal.notifications.dispatch*/2 * * * *Materialize outbox events and deliver immediate email
sable.portal.notifications.digest.dailyDaily, 08:15 America/New_YorkDeliver due daily digest batches
sable.portal.notifications.digest.weeklyMonday, 08:30 America/New_YorkDeliver due weekly digest batches
sable.portal.notifications.digest.retry*/15 * * * *Reclaim due daily and weekly digest retries
sable.portal.notifications.remindersWeekdays, 09:05 America/New_YorkEnqueue due request, review, and milestone reminders, then dispatch
sable.portal.attachments.cleanupDaily, 03:35 America/New_YorkRemove unpublished private file drafts older than 24 hours
sable.portal.notifications.healthNot scheduled; run by handReport delivery readiness (gate, Resend key and sender, provider reachable, sender domain verified) without sending anything

Each task invokes the scheduled-caller-only portal-notifications Edge Function and retries the invocation up to five times. The database owns outbox, delivery, digest-batch, and attachment-cleanup leases. See Release the customer portal for production checks.

Customer portal automation​

Two opt-in automations, each set per client in Customer tabs & automation. A client with no policy row, or with the switch off, is skipped. Neither automation approves or publishes a draft. Both act as the lead who last saved the settings; if that person loses the admin/lead role, nothing is drafted or released until another lead saves the settings.

Task idCadencePurpose
sable.weekly-update.draftFriday 12:00 America/New_YorkPlan pass: list clients with "auto draft weekly update" on and fan out one child run per active, current, non-internal project
sable.weekly-update.draft.projectChild of the aboveCreate the weekly update draft for one project through the same path as POST /api/weekly-update. It lands as a pending_approval draft; a person still approves it
sable.portal.auto-releaseHourly (0 * * * *)For every client with automatic meeting sharing on, write a short AI client summary for qualifying meetings that have none (at most 10 per run, 3 per client, rotating which client goes first each hour), then ask auto_release_client_meetings to share them
sable.portal.auto-release.clientOn demand, payload { clientId }The same pass for one client. Saving the policy with sharing newly on starts it so the lead does not wait for the hour

The drafting tasks run on their own queues and dedupe per project and ISO week, so a retry never creates a second draft. Auto-release shares meeting title and summary as ordinary, withdrawable portal publications; the recording link is included only when the client's recording-link setting is on (off by default). When a qualifying meeting has no summary of its own, the task first writes a short client summary (2–4 sentences) with the portal-draft AI's auto_release mode (web/api/_portal_drafts.js), acting as the lead who saved the policy. That mode reads only the note-taker's summary (metadata.default_summary), never the transcript or meeting record. It discards output that runs over 1,200 characters or contains any of the following:

  • an email address, including spelled-out or mixed forms ((at), [at] or @, then (dot), [dot], dot or .; or at with a spelled-out dot)
  • a phone number: 10 or more digits, unless they are made up only of ISO dates and 19xx/20xx years
  • any percentage: a number with %, or the words percent, per cent or pct with or without a number
  • a currency symbol next to a number, an uppercase ISO currency code next to a number (so lowercase words such as "try" and "cad" pass), or a currency word (dollars, euros, pounds, bucks, cents, pence, rupees, yen, francs)
  • an amount with a size word or suffix (k, m, mm, bn, thousand, million, billion)
  • a rate: per followed by hour, day, week, month, year, annum, seat, user, license, head or person; a slash rate (/hr, /hour, /day, /wk, /week, /mo, /month, /yr, /year, /seat, /user); or a number followed by a/an and hour, day, week, month or year

Only meetings from the last 30 days are drafted. The task stores the summary in sources.metadata.portal_summary with portal_summary_generated_at. The release function shares it for 7 days; after that, an unshared meeting is drafted again. It never overwrites a meeting's own summary, a staff-written portal_summary, or a meeting with any publication. Writing the summary does not share the meeting; the release function does that. Without ANTHROPIC_API_KEY the task skips drafting with a warning. Every failed attempt is counted (portal_summary_attempts): a transient failure is retried next run until the third attempt, then daily. A permanent failure (ineligible, no note-taker summary, rejected or unusable output) waits a day at once. After 5 attempts the meeting is never drafted again; staff can still publish it manually. Both automations stand down quietly until the portal_policies migration has been applied.

Find connector refresh tasks​

Task idCadence
sable.fathom.reconcile15 * * * *
sable.granola.poll5,35 * * * *
sable.asana.sync25 */2 * * *
sable.toggl.hours55 */4 * * *
sable.calendar.freebusy40 * * * *
sable.drive.refresh (+ .continue)Not scheduled; retired in #217 and kept invokable by hand
sable.email.ingest*/10 * * * *
sable.email.drain35 */2 * * *

Find report and board tasks​

Task idCadence
sable.report.morningweekdays, 06:00 America/New_York
sable.report.eodweekdays, 16:30 America/New_York
sable.learning.dailyweekdays, 17:00 America/New_York
sable.report.deliverinvoked by the above, not independently scheduled

Find document and cleanup tasks​

Task idCadence
sable.document.reconcile-ingest-jobs*/15 * * * *
sable.document.storage-purge-sweep*/10 * * * *
sable.document.storage-purgeinvoked per tombstone, not on a schedule
sable.document.backfill-index-batchinvoked, not scheduled
sable.feedback.retentiondaily, 15 3 * * *
sable.file-build.runinvoked per chat build request, payload { buildId }; off unless SABLE_FILE_BUILDS=on. Builds one .xlsx, a .pptx when SABLE_FILE_BUILD_PPTX=on too, or a .docx when SABLE_FILE_BUILD_DOCX=on (cleaned of comments, custom properties and author names before the check), or, when SABLE_FILE_BUILD_PDF=on and the request asks for it, a PDF of that file converted in the same sandbox run (or a document's brief as a web page when SABLE_FILE_BUILD_HTML=on, with no sandbox), with Anthropic's Agent Skills, checks it, and saves it as the requester's Library draft (spec)

Find watchdog tasks​

Task idCadence
sable.report.watchdog.morningweekdays, 06:45 America/New_York
sable.report.watchdog.eodweekdays, 17:15 America/New_York

Approvals, chat, portfolio, and smoke​

These tasks run on demand:

TaskPurpose
sable.approval.executeClaims and executes an approved Asana/Calendar write, replacing the emergency-fallback direct asana-act call path
sable.chatThe durable Trigger chat agent (chat.agent), using a Trigger-managed prompt (sableChatSystemPrompt) rather than an inline string
sable.portfolio.ingest-baseline, sable.portfolio.dailyPreview-only diff of the retired Drive workbook (manual; never writes project records), and daily reconciliation
sable.smokeThe minimal live-environment check described in Observability

Where the code lives​

  • trigger/*.ts: one file for each task group
  • trigger/queues.ts: the two shared queues (sable-connectors, sable-connector-writes) most connector and write tasks run through, controlling concurrency independently of scheduling.
  • trigger/lib/: shared helpers (supabase.ts, edge.ts, env.ts, document-runtime-deps, portfolio-workbook, etc.).