Architecture
Three-Plane Separation
The system is divided into three planes with strict boundaries:
| Plane | Responsibility | Examples |
|---|---|---|
| Deterministic | Binary correctness | Normalization, dedup, commute calc, hard filters, scoring, state machine, idempotency |
| Agentic | Judgment & interpretation | Neighbourhood assessment, qualitative ranking, shortlist synthesis, message drafting |
| Human | External side-effect authority | Approve/reject realtor messages |
Component Ownership
| Directory | Owns | Rules |
|---|---|---|
contracts/ | Pydantic models for all domain types | No business logic; pure data models with validators |
workflow/ | State machine, step implementations, controller | Only this layer changes workflow state |
deterministic/ | Normalization, dedup, commute, filtering, scoring | Pure functions, no I/O, no LLM calls |
agents/ | Agent interfaces, mock/ADK runtimes | Agents produce typed outputs; never mutate state |
tools/ | Mock external services (listings, maps, email) | Only tool registry exposes tools; agents get read-only subset |
persistence/ | SQLAlchemy models, database, repositories, UoW | No business logic; pure data access |
security/ | Untrusted input wrapper, prompt injection scanner, redaction | Applied at system boundaries |
observability/ | Structured logging, audit events, tracing, metrics | All components emit events through this layer |
Data Flow
- User creates search with preferences → persisted to SQLite
- Workflow engine executes steps sequentially with validated transitions
- Deterministic pipeline fetches, normalizes, deduplicates, scores listings
- Agent runtime (mock or ADK/Gemini) provides qualitative assessments
- Approval gateway gates all external actions behind human review
- Audit logger records every event across all planes
Trust Boundaries
| # | Boundary | Protects |
|---|---|---|
| 1 | Untrusted Input → Agent | Agent prompt integrity |
| 2 | Agent → Workflow State | State consistency |
| 3 | Agent → External Tools | Side-effect safety |
| 4 | Human → Approval Gateway | Authorization |
| 5 | Approval → Execution | Payload integrity |
| 6 | Execution → External Service | Idempotency |
| 7 | All Components → Audit Log | Non-repudiation |
Agent Runtime Isolation
The AgentInterface protocol ensures the workflow engine never depends on a specific LLM:
class AgentInterface(Protocol):
async def research_neighbourhood(...) -> NeighbourhoodAssessment: ...
async def evaluate_qualitative_fit(...) -> dict: ...
async def synthesize_shortlist(...) -> dict: ...
async def draft_realtor_message(...) -> dict: ... Mock runtime: Deterministic canned responses. No API keys. CI, demos, development.
ADK runtime: Live Gemini 2.5 Flash via Google ADK. Same contracts, same validation, same security boundaries.
Threat Model
10 documented threats across 4 categories:
| Category | Threats | Controls |
|---|---|---|
| Prompt Injection | 3 | Input wrapping, system prompt defenses, scanner |
| Agent Misbehavior | 3 | Schema validation, no tool access, output repair |
| Authorization Bypass | 2 | Approval gateway, payload hash binding |
| Operational | 2 | Idempotency, crash recovery, audit trail |