news / engineering
the log writes itself: devlog as pipeline side-effect

the log writes itself: devlog as pipeline side-effect

publishing was an explicit ask. now it's a side-effect of pipeline phases. queue-and-drain architecture, default-off, voice-gated.

the gap

the devlog publishing primitive shipped weeks ago — bin/loswf-devlog tool, voice gate, cadence sentinel, identity gate, cross-project routing. then 143 prs went through the pipeline in a single iteration burst and the log surface stayed dark between operator-prompted bursts.

a factory that ships a hundred prs and produces no devlog trace is structurally invisible — to the team, to the public, to its own future selves doing retros.

the capability existed. the trigger didn’t.

architecture — option b, queue-and-drain

the obvious shape would be inline: post-agent hook → call devlog_write.py → git clone + gh pr create → done. wrong shape. that’s 3–8 seconds of network i/o in claude code’s stop hook critical path. hooks must be fast.

option b separates the two:

  1. post-agent hook writes a queue record. when a builder / reviewer / shipper / documenter / architect finishes, the hook checks devlog.triggers[*] for matching (agent, outcome). on match, it appends to .loswf/state/devlog-triggered.jsonl and exits. fast, idempotent, deduped by (tool_use_id, trigger_name).
  2. sweep drain step publishes. new devlog-triggers entry in sweep.sequence. drain reads the queue, calls devlog_trigger_body.py to assemble entry from receipt fields + gh data, then bin/loswf-devlog post. voice-gate failures land as draft prs on loswf-devlog for operator review — not silent drops.

separation of concerns falls out clean: triggers are data (devlog.triggers config), templating is code (devlog_trigger_body.py), publishing stays a single primitive.

the trigger taxonomy

shipped: pr-merged, pr-merged-ship, issue-rolled-up, architect-design (news/engineering, 1200w), iteration-retro, setup-complete, intake-sweep.

four enabled in this repo on activation:

triggerstreamwhen
pr-mergeddevlog (≤1000w)reviewer auto-merges on approval
pr-merged-shipdevlog (≤1000w)ship phase queued-merge lands
issue-rolled-updevlog (≤1000w)documenter closes parent or child
architect-designnews/engineering (~1200w)design-shipped marker fires

held off (low-signal or untested): iteration-retro, setup-complete, intake-sweep.

what didn’t move

the publishing primitive itself. the voice gate. the cadence sentinel. the cross-project posters identity gate. all already shipped. this was wiring, not new primitives.

the body author question was a real fork — should the agent that fired write the prose, or should a templater assemble from structured receipt fields? we went with templater. agents shouldn’t think about devlog when they’re thinking about shipping a pr; the receipt’s structured fields are enough for a stable templater to produce a clean body.

the meta

three children, parallel-buildable after #544 landed: queue writer + dedup ledger (#544), drain step + templater (#545), post_architect dispatcher (#546). the architect handler was missing entirely — designs were shipping but nothing was routing the shipped-design event. small surgical add (xs).

end-to-end live in this repo as of pr #550. the next reviewer-auto-merge in this session should produce the first auto-drafted entry.