Biweekly Update-Note Automation

July 12, 2026 ยท View on GitHub

LoopX update notes should be generated by a separate publication workflow, not by adding custom behavior to the active heartbeat automation.

Why Not The Heartbeat

The LoopX heartbeat advances active goals. It reads quota, gates, todos, scheduler hints, and recent state, then decides whether the current agent turn can produce a useful transition. A two-week publication note is different: it is calendar-driven release communication.

Mixing the two would create avoidable friction:

  • the heartbeat could spend or wake for a publishing task while it should be advancing project work;
  • publication cadence could be blocked by an unrelated active goal gate;
  • update-note generation could add project-specific watch logic to a generic scheduler prompt;
  • the user would have to debug whether a missed note was a scheduler problem or a release-note job problem.

Use a dedicated release-note job that uploads a reviewable draft artifact. The repository ships the first version as .github/workflows/update-notes.yml, backed by scripts/update_notes_release_job.py. A future loopx update-notes CLI subcommand can wrap the same contract once the generator is stable.

The GitHub Action does not have an LLM. It should therefore generate a factual source draft from public git history, not pretend to write final narrative. A maintainer or LoopX agent should refine the draft PR before marking it ready.

The job should:

  1. Determine the next window from existing note filenames in docs/update-notes/.
  2. Collect first-parent merged-PR evidence for that exact UTC window.
  3. Remove direct-commit and branch-merge noise, then rank the remaining PRs into compact product themes.
  4. Write a new note under docs/update-notes/.
  5. Update the archive table and latest-note pointer.
  6. Keep the root README as a compact pointer, not a long changelog.
  7. Run the update-note smoke and loopx check over the touched public docs.
  8. Upload the note, updated archive, and patch as a reviewable artifact. PR creation remains an explicit human action.

Trigger Policy

The cadence is anchored to the initial public scaffold on 2026-05-31. GitHub Actions cron cannot express a reviewable "every two weeks after this anchored window closes" rule cleanly, so the workflow runs weekly and lets the generator be the biweekly gate. If the next window is not due, the script exits without changes and no PR is opened.

Manual workflow_dispatch supports repair and backfill through optional since, until, and force inputs.

The recommended first scheduled publication after this archive is for 2026-06-28 to 2026-07-11, opened for review on or after 2026-07-12.

Guardrails

  • Use public repository history, shipped docs, public examples, and public PR metadata as sources.
  • Do not ingest raw chat history, private docs, raw benchmark traces, raw verifier output, local paths, credentials, or operator-only state.
  • Keep generated notes short enough to review manually.
  • Fail closed if the generator cannot determine the prior window.
  • Keep GitHub Actions permissions read-only and upload a draft artifact when classification confidence is low.
  • Do not require an LLM secret for the default job.
  • Treat update notes as a summary surface. They do not replace git history, review packets, or LoopX state.

Future CLI Contract

The current project-level command is:

python3 scripts/update_notes_release_job.py --dry-run
python3 scripts/update_notes_release_job.py --since 2026-06-28 --until 2026-07-11 --force

A future CLI surface could wrap the same generator:

loopx update-notes plan --since 2026-06-28 --until 2026-07-11
loopx update-notes write --since 2026-06-28 --until 2026-07-11 --dry-run
loopx update-notes write --since 2026-06-28 --until 2026-07-11 --open-pr

Publishing remains a reviewed human action until the public/private boundary and grouping quality are proven stable. If the project later wants fully written prose from CI, add an explicit optional LLM step with a repository secret and fail closed when that secret is absent; keep the deterministic source-draft mode as the default.