Code Maintenance

Tasks that run periodically rather than continuously — audits, reports, and sweeps that catch drift, dead code, and knowledge gaps. They are deliberately not part of the per-commit gate (typecheck and lint already cover that).

The system carries a lot of agent-facing surface: CLAUDE.md and rule files, schemas with embedded instructions, prompt-builder code, connector rules, procedure templates. Ordinary code changes can quietly invalidate that surface — a refactor renames a method, a schema gains a field, a doc moves — and nothing in the type system or test suite catches it. A second category catches the code-health issues that pile up if nobody looks: dead exports, circular dependencies, unused dependencies.

What runs on its own: schedules

A schedule is one directory, schedules/<name>/ at the monorepo root: a schedule.yaml (cadence, and the agent to start if there is work), an executable run script, a prompt.md when the schedule can start a workstream, and an optional check. One launchd tick drives all of them, due-ness is computed from persisted state (so a laptop that slept catches up once rather than piling up), and each run's report is a durable alert record rather than a notification nobody can read back.

bin/schedules list is the catalog. It is the answer to "what is scheduled, when did it last run, and is anything overdue" — this document does not keep a second copy of it. bin/schedules logs <name> reads a run's output; bin/schedules install registers the tick, once per machine, from the main checkout.

The four enrolled today are the SDK release monitor, the Docling currency watch, the weekly manual test suite, and the weekly knip sweep.

Writing one: the bbx-authoring-schedules skill — when a task should be a schedule at all, what a run script owes (exit 0 in silence, hand off only when there is work, keep its own baseline so "new since last time" is real), what belongs in prompt.md, and how to rehearse with bin/schedules run <name> --dry-run. Design: docs/plans/scheduled-workstreams.md.

Not yet enrolled

Periodic tasks that still wait for someone to remember them. Each needs its own run design before it can become a schedule (issues/docs-and-chores/2026-08-08-maintenance-cadence-framework.md).

TaskCommandCadence it wants
Knowledge auditspnpm knowledge-auditAfter prompt/schema/CLAUDE.md changes; monthly otherwise. Guide: docs/knowledge-audits.md
Security overview regeneration/security-report (skill)At release boundaries, and when the staleness diff over the surface map is non-empty
Doc / prompt refreshpnpm prompt-report, pnpm prompt-viewer, pnpm doc-graphThe standing tension in issues/docs-and-chores/2026-07-04-doc-refresh-cadence.md
Feedback collectionfeedback-review/collect.tsissues/docs-and-chores/2026-07-14-feedback-collection-cadence.md — items rot before review
CSP violation reviewrunbook: docs/scheduled/csp-violation-review.mdAn agent analyzes new violations and proposes the harden flip; a human flips it

Run when you touch the thing

Not cadence tasks — tools you run because of a change you just made.

TaskCommandWhen
Agent SDK updatepnpm update-agent-sdk (monorepo root)Anytime; the sdk-update schedule does it automatically after the settling window
Dead-code sweeppnpm lint:knip (monorepo root)Before a release, or when code feels accumulated. Triage each finding: real dead code → delete; legitimate entry point → register it in knip.ts with a comment naming who reaches it
Supplemental lintpnpm lint:oxlintWeekly through schedules/supplemental-lint; also after broad lint-sensitive changes. Catches what ESLint misses (ambiguous constructors, useless spreads, identical ternary branches)
Circular depspnpm lint:circularWeekly through schedules/supplemental-lint; also after big refactors. .madgerc skips import type, so every line is a value cycle and means a module needs splitting. Currently zero — any output is news
Security regression scanpnpm security:opengrep (monorepo root)Before releases, and when touching auth/subprocess/temp-file/prompt boundaries. Discipline and how to add a rule: security/opengrep/README.md
Doc imagespnpm generate:doc-imagesAfter editing architecture-diagram text or .mmd sources. Pipeline: docs/architecture/CLAUDE.md
Box data migrationsbbx migrate (per box)After adding a migrator to src/core/migrations.ts. Author guide and rollout history: docs/migrations.md
Broken-ref cleanupnpx tsx scripts/clean-broken-refs.ts <boxRoot>One-off, when bbx validate shows ref errors that pre-date a migration. Dry-run by default; --apply to write
Mobile parity auditagent procedure (docs/implemented-plans/mobile-parity-sync.md §6)After a burst of mobile work; quarterly otherwise

Working with output

Most of these produce artifacts that get committed (the doc graph, the prompt report, regenerated images) or status updated in place (knowledge-audit comments). When the output diff is non-trivial:

  1. Triage first, fix second. Skim the diff and categorize: intended changes (commit), unintended changes you can explain (decide), unintended changes you can't explain (investigate).
  2. Don't reflexively suppress noise. When a periodic task starts producing diff noise that's hard to triage, that's a signal the task or its inputs need work — fix the upstream cause rather than tuning down the warning.
  3. Status notes are durable; reports are ephemeral. Knowledge-audit reports live in a gitignored directory; the durable record is the YAML status comment. Prefer a small in-place note over a large report file nobody reads later.