Current Agent Loop

How a work order moves from AppFolio to dispatched — and exactly where Andrew (Jose) has to tap. State of agent/ on agentv1, 2026‑05‑31.

Fully automated — runs with no human Andrew in the loop — gated on a human tap Described but not built

FlowBootIntakeTriagePing gateReplyDispatchLearningFollow‑upInvariant

The shape of it

Two pollers feed one orchestrator. Every PM‑, tenant‑, and vendor‑facing message is staged as a draft; the only human gates are the two amber boxes.

AppFolio WO issues_v2 row issue‑poller + enrich unit, title, urgency, vendors orchestrator · new_issue read_memory→set_vendor→draft Drafts UI — PM ping Andrew taps Send iMessage → PM groupchat dylib send chat‑poller reads chat.db, read‑receipt orchestrator · incoming_user_message ack + draft_tenant + draft_vendor + learn Drafts UI — dispatch Andrew sends via AppFolio write_memory → belief‑former + sessionizer beliefs feed read_memory next time ↺ follow‑up poller not built yet

1 · Boot & transport automated

server.mjs wires everything together at startup. No decisions — pure plumbing.

2 · Work‑order intake + enrich automated

triggers/issue-poller.mjs + triggers/enrich-issue.mjs. Polls Supabase issues_v2 every 5s. Sets the WO up before the LLM ever sees it.

3 · Triage + PM‑ping draft automated (generation)

core/orchestrator.mjs running the process_work_order skill, new_issue phase. One LLM turn (gpt‑5.4) on the enriched issue.

4 · The PM‑ping gate Andrew in the loop

ui/index.mjs Drafts UI. Nothing reaches the PM groupchat without a human tap here.

5 · PM reply handling automated (generation) draft‑gated

triggers/chat-poller.mjs polls chat.db every 1s; runs the incoming_user_message phase. Key fact: this whole path is sendMode:'draft' — even a one‑word "got it" ack is staged, never auto‑texted.

6 · Tenant / vendor dispatch Andrew in the loop

Drafts UI again. AppFolio has no write API, so the actual send is human‑driven — assisted by the Playwright runner.

7 · The learning loop automated (background)

Runs fire‑and‑forget off the same PM‑reply turn. Closes the loop back into stage 3's read_memory.

8 · Proactive follow‑up not built

CLAUDE.md describes the agent "keeping tabs on open work orders, following up in a few days." There is no follow‑up / stale‑WO poller in the code today.

The invariant that defines the product today

The agent drafts; the human sends. Every PM-, tenant-, and vendor-facing message is staged for review.

send_text hard‑refuses a live send to a PM handle, and both pollers run sendMode:'draft'. The only things that touch the wire unattended are read receipts, typing dots, and approved scheduled sends. So the agent is fully autonomous at perceiving, enriching, deciding, and drafting — and gated at the two moments a message would leave the building.

CapabilityStatusWhere
Detect + enrich new WOautomatedissue-poller, enrich-issue
Pick vendor + draft PM summaryautomatedorchestrator · new_issue
Send PM the summaryhuman tapDrafts UI
Read + interpret PM replyautomatedchat-poller · incoming_user_message
Ack + draft tenant/vendor msgsautomateddraft_tenant / draft_vendor
Send tenant/vendor into AppFoliohuman tapDrafts UI + Playwright runner
Record decisions → beliefsautomatedwrite_memory → belief‑former
Follow up on stale WOsnot built

Note: the incoming_anon_messagedemo skill path is the one live‑send surface (1:1 chats with unknown numbers, for demos). It's a separate surface from the production work‑order loop above and is excluded here.