Skip to content

Repository files navigation

Relocation Scout

Production-oriented agentic systems proof-of-concept.

A house-hunting assistant that demonstrates how to engineer a governed AI workflow — not a prompt wrapper.

Architectural Thesis

Use code for determinism, agents for judgment, and humans for authority.

  • Code handles normalization, deduplication, hard constraints, scoring, state transitions, approval enforcement, idempotency, retries, and audit logging
  • Agents handle neighbourhood assessment, qualitative ranking, shortlist synthesis, and message drafting — but have no access to external tools
  • Humans retain final authority over any external side effect via an approval gateway

The LLM is a narrowly-scoped component inside a larger software system. The workflow state machine, persistence, contracts, and security boundaries are all conventional engineering.

Quick Start

Prerequisites:

  • uv for Python dependency management
  • npm for frontend dependencies
# Install uv if needed
# macOS (Homebrew): brew install uv

# Install dependencies
make install

# Start backend + frontend
make dev

# Or seed demo data and start
make demo

Backend: http://localhost:8000/docs (OpenAPI) Frontend: http://localhost:5173

API Demo Sequence (Example)

# 1) Reset demo state
curl -s -X POST http://localhost:8000/api/demo/reset
# {"status":"reset","message":"Database dropped and recreated"}

# 2) Create search
curl -s -X POST http://localhost:8000/api/searches \
  -H "content-type: application/json" \
  -d '{
    "name": "Demo search",
    "preferences": {
      "max_monthly_rent_eur": 2500,
      "minimum_bedrooms": 2,
      "minimum_area_m2": 60,
      "max_commute_minutes": 45,
      "destination_address": "Amsterdam Centraal",
      "preferred_neighbourhoods": ["West", "Oost"],
      "excluded_neighbourhoods": [],
      "priorities": {
        "quiet": 0.25,
        "transport": 0.25,
        "green_space": 0.25,
        "affordability": 0.25
      }
    }
  }'
# {"id":"<search_id>","status":"created",...}

# 3) Start workflow
curl -s -X POST http://localhost:8000/api/searches/<search_id>/start
# {"search_id":"<search_id>","status":"awaiting_approval","current_step":"create_pending_action",...}

# 4) Check workflow status
curl -s http://localhost:8000/api/searches/<search_id>/workflow
# {"search_id":"<search_id>","status":"awaiting_approval",...}

# 5) List pending actions
curl -s http://localhost:8000/api/searches/<search_id>/actions
# [{"action_id":"<action_id>","action_type":"send_realtor_email","status":"draft",...}]

# 6) Approve + execute action
curl -s -X POST http://localhost:8000/api/actions/<action_id>/approve \
  -H "content-type: application/json" \
  -d '{"approved_by":"demo_user","comment":"approved in demo"}'
# {"approval_id":"<approval_id>","decision":"approved",...}

curl -s -X POST http://localhost:8000/api/actions/<action_id>/execute
# {"status":"executed","result":{"email_id":"<email_id>","status":"sent",...}}

# 7) Confirm completed workflow
curl -s http://localhost:8000/api/searches/<search_id>/workflow
# {"search_id":"<search_id>","status":"completed",...}

# Optional: inspect step executions
curl -s http://localhost:8000/api/searches/<search_id>/workflow/steps
# []

Environment

Copy .env.example to .env. Defaults work for mock mode (no API keys required).

Variable Default Description
DATABASE_URL sqlite+aiosqlite:///./data/relocation_scout.db SQLite for local dev
AGENT_RUNTIME mock mock (deterministic) or adk (Gemini)
MAX_CONCURRENT_ENRICHMENTS 4 Concurrency limit for parallel steps
LOG_LEVEL INFO DEBUG for verbose

Workflow

User creates search → preferences persisted
  → fetch_listings (CODE)
  → normalize_listings (CODE)
  → deduplicate_listings (CODE)
  → calculate_commutes (CODE, parallel)
  → research_neighbourhoods (AGENT, parallel)
  → calculate_deterministic_scores (CODE)
  → generate_qualitative_evaluations (AGENT, parallel)
  → build_shortlist (CODE + AGENT)
  → draft_realtor_message (AGENT)
  → create_pending_action (CODE)
  → await_human_approval (HUMAN)
  → execute_approved_action (CODE)
  → completed

Architecture

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, confirm viewing requests

Key invariants:

  • Agents never execute external side effects
  • All side effects pass through the approval gateway
  • All LLM outputs are schema-validated (Pydantic)
  • External content is always treated as untrusted
  • Workflow state lives in SQLite, not in LLM context
  • Every external action has an idempotency key

Documentation

Document Contents
architecture.md Component architecture, trust boundaries, data flow
THREAT_MODEL.md 10 threats with attack paths, controls, residual risk
ROADMAP.md Phase breakdown with dependencies
AGENTS.md Coding agent conventions and change rules
demo-script.md 5-minute demo walkthrough

Commands

make install      # Install all dependencies
make dev          # Start backend + frontend
make test         # Run all backend tests
make lint         # Ruff check + format check
make seed         # Seed demo data
make reset        # Reset database
make demo         # Reset + seed + start
make verify       # Full verification
make clean        # Remove venv, node_modules, DB

Tests

make test         # 26 unit tests (contracts, deterministic, security, workflow)

Coverage: priority weight validation, deduplication, normalization, prompt injection detection, hard constraints, deterministic scoring, state transitions, approval payload binding, audit events, agent output validation, and more.

Mock Mode

Default mode. No API keys required. All agents use deterministic canned responses. Suitable for CI, demos, and development.

Live Mode (Optional)

Set AGENT_RUNTIME=adk and provide GOOGLE_API_KEY. Uses Gemini through Google ADK.

Limitations

  • PoC, not production: SQLite, single-process, no auth, mock email
  • Mock agent responses: Deterministic canned outputs; real LLM behavior may vary
  • No real email delivery: Mock email writes to local SQLite only
  • Single user: No multi-tenancy or RBAC

Production Hardening

  1. Replace SQLite with PostgreSQL
  2. Add authentication/authorization (OAuth2/OIDC)
  3. Implement proper RBAC for approval decisions
  4. Add real email delivery (SendGrid, SES) with idempotency
  5. Add real maps API for commute calculation
  6. Implement async task queue (Celery/ARQ) for long-running workflows
  7. Add Prometheus metrics and distributed tracing
  8. Implement proper secret management (Vault, AWS Secrets Manager)
  9. Add API rate limiting and request validation
  10. Containerize with health checks and graceful shutdown

About

Production-oriented agentic systems PoC: house-hunting assistant with governed AI workflow

Resources

Stars

0 stars

Watchers

0 watching

Forks

Used by

Contributors

Languages