Subsystem Architecture — The Map
High-level only: what each subsystem is and how it behaves. No prompt tuning, no chat-behavior details. The point is the shape they share.
6 minSteps ② and ⑤ talk to the brain; ③ and ④ ride the queue; ⑤ uses the hands. Three shared spines, one actor, reused by every vertical.
The shared spines
Not subsystems that "run" — they're infrastructure every vertical leans on. A library, a queue, a set of hands.
Policy Graph
BRAIN · librarybuiltdarkfind_policy(trigger)→ a tiered answer (rule / observed default / nothing) plus any emerging-pattern observation.log_event(...)→ append one decision; re-fold the projection.policies = fold(events), recomputable and rollback-able.
Jobs Queue
ATTENTION · busbuiltdark- Idempotent enqueue (one open job per
dedupe_key), priority, andnot_beforetiming. - Lifecycle:
pending → asking → awaiting_reply → resolved. Carriessource(route the answer home) +resume(rebuild the work).
Workflows
HANDS · execution unittools existrunner neededdispatch_vendor, text_tenant, update_issue — live inside workflows; nothing reaches them directly.- A workflow is an ordered recipe of tool steps with bound args. You reach action only by naming a workflow (
run_workflow), never by calling a raw tool. - Deterministic — no model in the loop. The policy graph already speaks this language: a rule says "run workflow Z," and Z is exactly this.
The actor
The one subsystem that thinks and speaks. Everything above is passive until it acts.
Conductor
VOICE · the one-job agentto build- Paces the queue — surfaces one ask at a time per chat, respects priority + quiet hours, batches related asks.
- Asks & interprets — phrases a job's question in voice, then turns the PM's reply into a structured
resolution. - Handles spontaneous statements — recognizes "always use Kori for handyman" as a rule and records it via the graph. Recognizing it is its job.
find_policy (read memory), log_event (write memory), and run_workflow (act, gated) — plus plain talk. It can never name a raw action like dispatch_vendor. That one chokepoint is the safety property: the agent goes through memory and workflows for everything, so a misfire is a bad workflow call, never a rogue tool call.The reasoning workers
The conductor stays conversational because it is not the only thing that can think. Reasoning is distributed: a vertical may own a headless, scoped worker that resolves things in its own lane — and bothers the conductor only when a human is genuinely needed.
Worker
REASONING · headless · per-vertical, optionalclassifier exists- Anything from a single structured LLM call (your trade classifier) to a small tool-using loop. Returns structured data to its vertical.
- Escalates by enqueueing a job, never by talking. "Thursday instead?" it resolves itself; a cancellation with no backup becomes a job for the conductor.
- Still behind the chokepoint — when a worker acts, it runs a workflow, never a raw tool. The invariant binds everyone, not just the conductor.
The verticals
Each owns one kind of work and follows the five-step contract identically. This is where new capability gets added.
PMS Intake
VERTICAL- Sense: a new
issues_v2row. Consult: classify the trade →find_policy. - Enqueue: a
confirm_dispatchjob. Finish: on yes, dispatch + log the decision.
Memory Curation
VERTICAL- Sense: an
observationfromfind_policy(one vendor dominating ≥2 scopes, no rule yet). - Enqueue: an
ask_promotionjob. Finish: on yes,log_event(create_policy)— authority gets a name.
Clock / Vigilance
VERTICAL- Sense: a tick. Scan for stale states — WO awaiting the PM too long, vendor gone quiet, follow-up due.
- Enqueue: nudge jobs idempotently. Finish: the conductor handles them like any other job.
Ingest
VERTICAL · senses- Members: chat-poller (PM texts), issue-poller (PMS work orders), clock (time), reply-watchers (vendor/tenant — later).
- Behavior: detect, debounce, route to the right workspace, hand off. PM chat goes straight to the conductor; the rest feed a vertical.
The contract every vertical shares
This is the actual architecture — not the boxes, but the fact that they're the same box. Any new capability (lease renewals, owner reporting, inspection scheduling) is just another vertical that implements these five steps. None of them touch the conductor's code.
- Sense — a source produces a typed event.
- Consult —
find_policy(trigger)when the decision has a policy dimension (skip if it doesn't). - Enqueue — drop a job with
source,askhint, andresumepayload. - Conduct — the conductor asks the PM and writes a structured
resolution. (Shared; not yours to build.) - Finish — your
sourcehandler executes the work andlog_events the decision, so step ② is smarter next time.