Property-Report-Skill-Judges

Property Buying Agent — Subagent Architecture Design

Status: FINALIZED & IMPLEMENTED (2026-07-27). Decisions recorded in §9. The orchestrator (SKILL.md) and five subagents under agents/ are built; Phases 4.5 and 8–11 are now delegation stubs.


1. Goals

  1. Independent use — a user can jump straight to “compare my loans”, “review my inspection”, or “compare home insurance” without running the whole journey.
  2. Orchestrated use — a buyer starting from scratch is guided through the full purchase, and the main agent invokes the right subagent at the right stage.
  3. Shared context — subagents reuse one property folder and one journey state so numbers stay consistent (a seller repair credit, an insurance premium, and a loan’s escrow all affect each other).
  4. No regression — every existing capability, template, and guardrail (isolation, “not advice”, document-traceable figures, HTML-by-default) is preserved.

Why one orchestrator plus specialists

A single general agent would carry unrelated evidence, calculations, and regulatory boundaries through every turn. The modular design instead provides focused context, domain-specific schemas and guardrails, selective activation, independent evaluation, reusable direct invocation, and a smaller blast radius when a prompt or model changes. The six agents are logical workflow modules; they do not require six simultaneous or unconstrained model calls.

Non-goals: cross-property data mixing, personal/background dossiers, legal/financial advice, or changing the reusable templates we just built (loan/insurance/inspection dashboards stay as-is).


2. How a buyer actually buys a home (the journey)

The subagents map onto the natural stages of a purchase. Not every buyer does every stage, and stages overlap, so the orchestrator treats these as a checklist with dependencies, not a rigid wizard.

flowchart TD
  A[0. Readiness\nbudget, pre-approval] --> B[1. Discovery\nfind a house, listing sheet]
  B --> C[2. Investigation\ndisclosures, survey, title, photos]
  C --> D[3. Neighborhood & value\ncomps / appraisal district]
  C --> E[4. Financing\nloan shopping]
  D --> F[5. Offer & contract\nnegotiate, execute]
  E --> F
  F --> G[6. Option period\ninspection + repair negotiation]
  F --> H[7. Insurance\nquotes, bind before closing]
  G --> I[8. Closing prep\nfinal walkthrough, cash-to-close]
  H --> I
  I --> J[9. Post-closing\nmove-in, repairs]
Stage What the buyer is doing Which agent leads Existing phase
0 Readiness Sets budget, gets pre-approved Loan (light) Phase 9 (early)
1 Discovery Picks a property, gathers docs Orchestrator Phase 0–1
2 Investigation Reads disclosures/survey/title Orchestrator Phase 2–6
3 Neighborhood & value Comps, is the price fair Orchestrator (Neighborhood) Phase 4.5
4 Financing Compares Loan Estimates Loan subagent Phase 9
5 Offer & contract Negotiates, executes contract Orchestrator (contract capture)
6 Option period Inspection → repair asks Inspection subagent Phase 11
7 Insurance Gets quotes, binds Insurance subagent Phase 10
8 Closing prep Reconciles cash-to-close Orchestrator (checklist)
9 Post-closing Move-in / repairs Orchestrator (move-in plan)

3. Proposed architecture

One orchestrator (the current Property Investigator) plus three domain subagents. Each subagent is a self-contained module with its own trigger phrases, its own templates, and its own outputs — but all of them read and write a single shared journey state for the property.

flowchart LR
  U([User]) --> R{Router\ntrigger phrases}
  R -->|full journey / property docs| ORCH[Property Investigator\nORCHESTRATOR]
  R -->|"compare loans"| LOAN[Loan Advisor]
  R -->|"review inspection"| INSP[Inspection Advisor]
  R -->|"compare insurance"| INS[Insurance Advisor]

  ORCH -.invokes at stage 4.-> LOAN
  ORCH -.invokes at stage 6.-> INSP
  ORCH -.invokes at stage 7.-> INS

  LOAN <--> STATE[(.property/journey.json\nshared state)]
  INSP <--> STATE
  INS <--> STATE
  ORCH <--> STATE

3.1 Orchestrator — “Property Investigator”

3.2 Loan Advisor subagent (Phase 9)

3.3 Insurance Advisor subagent (Phase 10)

3.4 Inspection Advisor subagent (Phase 11)


4. Shared journey state — .property/journey.json

A single per-property file is the “spine”. Each subagent reads it for context and writes back its results. It never contains another property’s data (isolation preserved).

{
  "property": { "address": "…", "slug": "…", "purchasePrice": 0, "county": "…" },
  "stage": "option-period",              // current journey stage
  "contract": {
    "effectiveDate": null, "optionDeadline": null, "financingApprovalDate": null,
    "closingDate": null, "asIs": true, "status": "verified|unverified"
  },
  "value": { "estimatedValue": null, "cushion": null },     // from Neighborhood/Investigation
  "loan":  { "ran": false, "bestLender": null, "rate": null, "monthlyPITI": null,
             "escrowMonthly": null, "cashToClose": null, "maxRateFlag": null },
  "insurance": { "ran": false, "carrier": null, "annualPremium": null,
                 "roofSettlement": null, "deductibles": null },
  "inspection": { "ran": false, "exposureBase": null, "sellerScope": null,
                  "buyerCredit": null, "dealBreaker": "no|conditional|yes|pending" },
  "openRisks": [],
  "updated": "ISO-8601"
}

Rules: every write is timestamped; a subagent only overwrites its own section + openRisks; the orchestrator is the only writer of stage and contract; missing values stay null (never invented).


5. Cross-agent data flow (why the spine matters)

The three domains are financially coupled. The orchestrator reconciles these after any subagent runs:

  1. Insurance → Loan. The real annual premium sets escrow, which changes monthly PITI and cash-to-close. When Insurance updates annualPremium, prompt Loan to recompute escrow and re-flag the best pick; tell the user to give the lender the final premium.
  2. Inspection → Loan / Closing. A seller repair credit reduces cash-to-close but is capped by the lender; a price reduction changes the loan amount. When Inspection updates buyerCredit, Loan and the closing checklist must reflect it.
  3. Contract deadlines → everyone. Option deadline (Inspection), financing approval (Loan), and closing (all) come from the executed contract. The orchestrator owns them; subagents read but never invent them, and vendor/quote delays never silently extend a deadline.
  4. Value cushion ↔ Inspection. Repair exposure is compared to the negotiated cushion, but a good price never cures a safety/structural/insurability defect (kept as separate concepts).
flowchart LR
  INS[Insurance\nannual premium] -->|escrow| LOAN[Loan\nPITI + cash-to-close]
  INSP[Inspection\ncredit / price cut] -->|cash-to-close / loan amt| LOAN
  CON[(Contract deadlines)] --> INSP
  CON --> LOAN
  CON --> CLOSE[Closing prep]
  LOAN --> CLOSE
  INS --> CLOSE

6. Invocation modes

A. Independent (direct). User triggers a subagent by phrase. The subagent:

  1. Resolves/creates the property folder (asks if ambiguous).
  2. Loads journey.json for context if present; otherwise runs standalone with what it can extract.
  3. Produces its outputs and writes its state section.
  4. Surfaces one line of cross-effect if relevant (“this premium changes your loan escrow — want me to refresh the loan comparison?”).

B. Orchestrated (journey). The main agent:

  1. Determines the stage from journey.json + available docs.
  2. Invokes the subagent for that stage, passing context.
  3. On return, reconciles cross-effects (§5) and updates the main report + README + openRisks.
  4. Recommends the next stage.

Routing is by trigger phrase first; if a property journey is active and the request is ambiguous, the orchestrator picks the stage-appropriate subagent.

Coordination sequence

sequenceDiagram
  actor Buyer
  participant O as Orchestrator
  participant R as Property-scoped retrieval
  participant A as Domain advisor
  participant S as Journey state
  Buyer->>O: question + new evidence
  O->>S: load stage, deadlines, and open risks
  O->>R: retrieve with tenant/engagement/property filters
  R-->>O: evidence chunks + source locators
  O->>A: bounded evidence + owned schema
  A-->>O: structured result + citations + confidence
  O->>O: validate schema, calculations, and evidence coverage
  O->>S: update advisor-owned section
  O->>O: reconcile dependent values
  O-->>Buyer: decision, evidence, uncertainty, and next action

The orchestrator must reject invalid schemas, unsupported material claims, cross-property evidence, and stale results. A failed specialist remains failed/blocked; it must not be converted into a success-shaped fallback.


7. Production model, grounding, and scale

The prototype keeps a provider adapter and deterministic local fallback. Azure OpenAI is the production target because it can share the Azure identity, private-network, regional, governance, safety, and monitoring boundary; the architecture remains model-portable so deployments are selected by evaluation rather than hard-coded preference.

Production grounding uses engagement-scoped Blob Storage plus Azure AI Search hybrid retrieval. Indexed chunks carry property, document, page/record, authority, effective-date, jurisdiction, and retrieval metadata. Mandatory security filters are applied before retrieval, and every material output cites the retrieved evidence.

For thousands of users:


8. Repo / file structure changes

Option chosen for discussion — modular skill folder (keeps everything in this repo, no external agent registry needed):

Property-Report-Skill/
  SKILL.md                       # becomes the ORCHESTRATOR (journey + routing + reconciliation)
  agents/
    loan-advisor/SKILL.md        # Phase 9 content, self-contained, independently triggerable
    insurance-advisor/SKILL.md   # Phase 10 content
    inspection-advisor/SKILL.md  # Phase 11 content
  templates/                     # unchanged (loan/insurance/inspection dashboards already reusable)
  properties/<slug>/
    .property/journey.json       # NEW shared state spine
    …                            # existing per-domain folders unchanged

9. Implementation plan (after approval)

  1. Add the spine. Define journey.json schema + a short “read/update state” contract in SKILL.md.
  2. Extract subagents. Move Phase 9/10/11 into agents/loan-advisor, agents/insurance-advisor, agents/inspection-advisor (verbatim behavior + their template references), each independently triggerable.
  3. Slim the orchestrator. Replace Phases 9–11 in SKILL.md with delegation stubs + the journey checklist, routing table, and the §5 reconciliation rules.
  4. Wire cross-effects. Add the insurance→loan escrow refresh, inspection→cash-to-close, and contract-deadline propagation as explicit orchestrator steps.
  5. Validate. Dry-run each subagent independently and one full journey on a scratch property; confirm no cross-folder reads and that state stays consistent.
  6. Update memory with the new architecture.

10. Decisions (finalized 2026-07-27)

  1. Agent mechanism: ✅ modular skill folders — agents/<name>-advisor/SKILL.md (recommended option).
  2. Scope: ✅ five subagents — Loan, Insurance, Inspection plus Neighborhood and Comparison (multi-property).
  3. State file: ✅ dedicated .property/journey.json (kept separate from manifest.json, which tracks doc hashes — separation of concerns).
  4. Reconciliation autonomy: ✅ auto-refresh the loan when insurance/inspection change numbers, and keep a new timestamped version in loan/history/ (never silently discard the prior one).
  5. Naming: ✅ “ Advisor" — Neighborhood Advisor, Comparison Advisor, Loan Advisor, Inspection Advisor, Insurance Advisor.
  6. Journey entry point: ✅ added — “help me buy a house / start buying a home / first-time buyer” launches the guided journey, which explicitly handles first-time buyers (readiness, pre-approval-first, team, stage-by-stage guidance).

11. Implementation status


Decision-support tooling only — not legal, financial, lending, insurance, or professional-inspection advice. Each property remains an isolated, confidential engagement.