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.
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 work order skill bundles two phases that are opposite in nature:
| Phase | Nature | Needs the model? |
|---|---|---|
new_issuepoller fires, WO summary out | Workflow / state machine. Fixed sequence, templated output. | Once — to write one natural sentence. No agent loop. |
incoming_user_messagePM replies in the chat | Agent. Intent-reading over free-form human text. | Yes, fully — this is the real agent. Leave it alone. |
new_issue was never agenticIts "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.
read_memory, no double send_text, no greeting/format drift. That's the cross-customer reliability the loop is judged on.candidates[0] and a wrong top pick becomes a ranking bug you can see — the exact memory proof we want, not hidden by the LLM's judgment.process_work_order becomes purely the reply runbook — cleaner, not fragmented.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.
read_memory);new_issue for another reason;Until one trips: it's polish. Build dispatch/follow-up instead.