Harness
Guides

Alerts and recurring checks become tracked issues — deduplicated, with evidence, inside the same loop.

View raw Markdown · llms.txt · For agents

These two stages are what close the cycle: without them the loop only drains a queue somebody else fills.

intake — an alert becomes an issue

intake:
  enabled: true
  sources:
    - id: sentry
      argv: [sentry-cli, issues, list, --json]
    - id: posthog
      argv: [node, scripts/posthog-errors.mjs]
  flowLabelForSeverity:
    critical: 'flow:incident'

Each source is argv that prints JSON alerts. The stage parses them, fingerprints each one, and files only what it has not filed before. The fingerprint is the whole mechanism: the same error firing two hundred times overnight is one issue, and the second night does not reopen it.

A filed issue carries the evidence that produced it — the alert payload, the source, the severity — and the flow label its severity maps to. That last part is how an incident flow starts without a human typing anything.

maintain — the checks nobody remembers to run

maintain:
  enabled: true
  checks:
    - id: audit
      argv: [pnpm, audit, --json]
    - id: outdated
      argv: [pnpm, outdated, --json]
    - id: licences
      argv: [node, scripts/check-licences.mjs]

The same shape, with a different trigger: a check runs, and an issue is filed only when there is a decision to take. A clean audit files nothing. This is what an external dependency bot does from outside, done inside the loop and held to the same definition of done — so the update is a pull request that proves the suite is green, not a pull request somebody has to babysit.

Both are scheduled, and both are read-mostly

They create issues and nothing else: no dispatch, no merge, no deploy. Like every scheduled stage they exit 1 so the scheduler records the run, and their events (intake.filed, maintain.filed) carry the issue, the source or check id, and the fingerprint.

GitHub intake, which is a different thing

deliver can also adopt pull requests the loop did not dispatch — opened by a human or another tool — when they carry the configured label. They go through the same gates and reach the same outcomes, reported under github-intake.* events so the two populations stay distinguishable in a retro.

On this page