Sub-Daily Ingest Workflow

The four-hour capture loop keeps Slack, Gmail, X bookmarks, and local sessions close enough to current that the wiki can act as operational memory instead of a stale archive.

Trigger

Run this workflow when Kevin asks whether Slack, email, or X are being ingested every few hours, when scripts/check-freshness.ts flags the sub-daily loop, or when a scheduler audit touches source-compile, email-sync, or slack-sync.

The live jobs are intentionally staggered:

Job Owns Cadence Durable state
source-compile X bookmarks, enriched bookmark research, local AI sessions, repeated agent friction Every 4 hours automations.source-compile, syncs.x_bookmarks, compile.last_bookmark_*
email-sync Gmail collection, signatures, people/company/action-item extraction Every 4 hours automations.email-sync, syncs.email
slack-sync Slack activity review, action items, project decisions, durable chat facts Every 4 hours automations.slack-sync, syncs.slack

Invariant

Each run must separate collection from promotion:

  1. Collect fresh source material into raw/.
  2. Write an output report under outputs/<date>/<slug>/.
  3. Promote only durable facts into the wiki.
  4. Update state.json with ISO timestamps for sub-daily freshness.
  5. Append wiki/log.md.

If collection fails, the run still writes a blocker report and automation timestamp, but it must not update the corresponding syncs.* timestamp. That keeps freshness honest.

Run Order

  1. Check freshness:
    npx tsx scripts/check-freshness.ts
    
  2. Confirm live scheduler state when auditing:
    sqlite3 ~/.codex/sqlite/codex-dev.db "SELECT id, name, status, rrule, next_run_at FROM automations WHERE id IN ('source-compile-2','email-sync','slack-sync');"
    
  3. For source compile, follow Source Compile Workflow.
  4. For Gmail, follow Email Sync Workflow.
  5. For Slack, follow Slack Sync Workflow.
  6. Re-run freshness and verify the three jobs either advanced state or reported blockers.

Promotion Matrix

Source signal Promote to wiki? Target
New tool, paper, repo, demo, API change, or repeated X bookmark cluster Yes, when it changes future behavior tool/project/concept page plus relevant hub
Email from a real person with durable project, career, or action context Yes, when person/company/project context changes person, career, project, or decision page
Slack decision, launch status, blocker, or repeated workflow Yes, when it should be remembered outside Slack project, decision, workflow, skill, or log page
Signature request, reply-needed email, transient Slack nudge Usually output-only raw digest + output action list
Auth failure, missing browser session, empty inbox, no new bookmarks No output report with No durable wiki update needed or blocker

State Writes

Use ISO timestamps for the sub-daily automation keys:

{
  "syncs": {
    "x_bookmarks": "2026-06-30T18:00:00.000Z",
    "email": "2026-06-30T18:00:00.000Z",
    "slack": "2026-06-30T18:00:00.000Z"
  },
  "automations": {
    "source-compile": "2026-06-30T18:00:00.000Z",
    "email-sync": "2026-06-30T18:00:00.000Z",
    "slack-sync": "2026-06-30T18:00:00.000Z"
  }
}

Do not use date-only values for four-hour jobs. Date-only state makes check-freshness unable to distinguish a current run from a 23-hour-old run.

Closeout

The sub-daily workflow is complete only after the source-specific workflow reports either a successful collection/promotion run or a blocker/no-op. Do not advance all three jobs as a batch unless all three were actually checked. If any durable wiki page changed, run Build Index Workflow and QMD Embed Workflow. If a workflow, skill, scheduler prompt, or generated pack changed, follow Generated Surface Contract before declaring the loop current.

Failure Handling

Failure Correct behavior
Gmail OAuth missing or expired Run or request npx tsx scripts/sync-email.ts --auth; do not update syncs.email until collection succeeds.
Slack browser session missing Record the blocker, leave syncs.slack stale, and keep the automation active.
X bookmark sync fails Record the command/error, leave syncs.x_bookmarks or compile.last_bookmark_* unchanged, and avoid partial wiki promotion.
Wiki promotion is ambiguous Write output-only, say No durable wiki update needed, and leave a follow-up row.
Scheduler prompt drifts from automation file Update the live scheduler to read the canonical automations/<slug>.md contract.

Validation

After changing this loop:

npx tsx scripts/doctor.ts --only automations
npx tsx scripts/build-index.ts
qmd update && qmd embed
npx tsx scripts/check-freshness.ts

The healthy state is not necessarily all green. Immediately after creating a new sub-daily job, freshness should keep flagging it until the first successful run writes state. That is correct fail-visible behavior.

Run Contract

This workflow follows Workflow Run Contract: name the sources, write output or no-op proof, promote only durable facts, update state only when the run really completed, refresh generated surfaces when durable pages or skills change, and log user-visible work.


Timeline