new_issue: agent → programmatic pipeline

The outbound work-order summary doesn't need an agent. It's a deterministic trigger that calls the model exactly once. This memo banks the decision — and the decision is: not yet.

May 31, 2026 · grounded in issue-poller.mjs, router.mjs, orchestrator.mjs, skills/process_work_order/SKILL.md
PARKED — low priorityrevisit on a concrete trigger (below), not a date
The insight Before → after Why it's a win Why it's parked
The new_issue phase (poller fires → summarize WO → suggest a vendor → text the PM) has no agent decision-making. Control flow is fixed; the model is only needed for one thing — turning a raw PMS title into a natural sentence. So it should be a programmatic pipeline with a single constrained model call, not an orchestrator turn with a 200-line skill. But it works today, and a refactor isn't the bottleneck — so park it.

The insight

The work order skill bundles two phases that are opposite in nature:

PhaseNatureNeeds the model?
new_issue
poller fires, WO summary out
Workflow / state machine. Fixed sequence, templated output.Once — to write one natural sentence. No agent loop.
incoming_user_message
PM replies in the chat
Agent. Intent-reading over free-form human text.Yes, fully — this is the real agent. Leave it alone.
The tell that new_issue was never agentic

Its "Hard rules" — "after send_text, STOP," "ONE send_text call," "always read_memory first," no greetings, no urgency prefix — are all the prompt fighting the model to behave like a state machine. When you need eight rules to force determinism, the flow should be code. Each rule becomes a line that structurally can't be violated.

Before → after

BEFORE — MODEL DRIVES THE FLOW orchestrator loop · gpt-5.4 · ≤8 iters + process_work_order SKILL.md (~200 lines) + ALL_TOOLS visible + 8 "Hard rules" forcing determinism model decides the sequence each turn poller → full agent turn → send cost: a full multi-iteration turn · can break format AFTER — CODE DRIVES, MODEL CALLED ONCE poller → read_memory → candidates[0] → set_vendor → writeSentence(title)·1 LLM call → render template → deterministic; the only model call is the green one (line 2). format can't break.
The intelligence moves out of "which step next" and into the memory ranking + one sentence.

Why it's a win (when we do it)

No conflict with the "one skill per domain, don't split by trigger" rule: we're not splitting the skill, we're removing a phase that was never agentic. process_work_order becomes purely the reply runbook — cleaner, not fragmented.

Why it's parked

It works today. A refactor of something that works swaps "works" for "works + cheaper + safer" — real, but marginal, and not the bottleneck. The scoreboard is paying PMs running the loop, not architectural cleanliness. The memory-quality check doesn't even require the refactor: grep the turn logs for cases where the model's vendor pick ≠ candidates[0] — an afternoon of analysis, not a rebuild.

Do it when one of these trips

Until one trips: it's polish. Build dispatch/follow-up instead.