Skip to content

mkbhardwas12/IntakePilot

Repository files navigation

IntakePilot

CI License: MIT Python 3.11+

AI requirements-intake platform: a business user describes a need in plain language; a deterministic orchestrator (LLM as component, never in control) extracts structured requirement slots, resolves gaps by inference and precedent before ever asking a question, enforces a hard question budget, and — after human confirmation — runs a five-gate quality pipeline, routes the requirement to the right team queue with an explanation, and creates a ticket. Every human correction feeds a learning ledger that improves the next intake.

Built from docs/build-specification.txt (v1.0) plus docs/ADDENDUM-01-backend-aware-enrichment.md. See docs/SPEC-REVIEW.md for an honest review of the spec and the choices made where it was silent.

Quick look

One intake, end to end — real UI, offline mock model, 23 seconds:

IntakePilot demo: plain-language ask to routed ticket

A plain-language ask becomes a live Shadow Draft with provenance badges; two batched questions; confirm; five gates; routed to data-platform with a written explanation and a ticket. Higher-quality video: docs/assets/demo.mp4.

Contents

How it works

flowchart LR
    A["Plain-language ask<br/>(web chat or Slack/Teams bot)"] --> B["Shadow Draft<br/>extract + infer + retrieve<br/>provenance & confidence live"]
    B --> C{"Gaps left?"}
    C -- "yes, budget left" --> Q["≤ 3 questions/turn, ≤ 7 total<br/>(enforced in code)"] --> B
    C -- no --> D["Human confirm<br/>inline revisions → learning ledger"]
    D --> E["Backend enrichment<br/>systems & custom fields discovered,<br/>never asked"]
    E --> F["5 quality gates<br/>incl. near-duplicate check"]
    F -- pass --> G["Routed ticket<br/>queue + explanation + cost-of-delay<br/>+ acceptance criteria + collisions"]
    F -- fail --> H["Gated with reasons<br/>fix & reconfirm, or attach to duplicate"]
    G -. "reroutes, edits, validations" .-> B
Loading
  1. Describe — a requester types (or Slack/Teams-messages) a need in plain language. No form, no template, no backend vocabulary.
  2. Draft — the Shadow Draft builds live over SSE: extracted slots with provenance badges and confidence bars. Gaps are resolved by inference and precedent before asking anything; at most 3 questions per turn, 7 total — enforced in code, not in a prompt.
  3. Confirm — the requester reviews the shakiest fields first, revises any field inline (every correction is captured as a learning signal), and confirms. Nothing routes without a human confirmation.
  4. Enrich → gate → route — backend context (systems, tables, custom fields) is auto-discovered, never asked; five quality gates run (including near-duplicate detection against real past work); the requirement routes to a team queue with a written explanation, an annualized cost-of-delay, Given/When/Then acceptance criteria, and collision warnings when other open work touches the same entities.
  5. Learn — confirmation edits, queue relabels, and KB validations feed append-only ledgers that recalibrate extraction exemplars, question ranking, readiness weights, and routing — model-agnostic learning that lives in data, not weights.

Who uses it, and how

Role Surface What they do
Requester Web chat at /loop, or any Slack/Teams/mail bot via POST /api/channels/inbound describes the need in plain words, answers ≤7 targeted questions, pencil-edits draft fields, confirms
Analyst / BA Same UI + GET /api/requirements/{id}/render reviews the plain-language render and assumption register, corrects fields at confirm — each correction trains future intakes
Delivery team The routed ticket (local repo or GitHub Issues) gets business intent + auto-discovered system context + acceptance criteria in one ticket; relabels the queue if misrouted (webhook feeds routing_accuracy); validates KB discoveries (POST /api/kb/{system}/{entity}/validate)
Ops / admin /metrics dashboard, GET /api/graph, GET /api/evals/replay, GET /api/glossary/proposals watches ROI and backlog-by-value, collision hotspots, extraction accuracy over time; accepts mined glossary terms; one env var (INTAKEPILOT_ADMIN_TOKEN) locks all of it

The five-minute first run

Zero external dependencies — no model, no Docker, no database:

git clone https://github.com/mkbhardwas12/IntakePilot.git && cd IntakePilot
make dev            # backend :8000 (mock LLM + SQLite) and web :3000
open http://localhost:3000/loop
# type: "our monthly vendor report takes 3 days to compile by hand"
# watch the Shadow Draft build, answer <= 3 questions, confirm,
# see the ticket appear in examples/demo-repo/
#
# Note: run the SAME ask twice and gate 4 will (correctly) catch the second
# as a near-duplicate of the first — click "Attach to IPR-…" to see the
# dedup flow, reword the ask, or `make clean` to reset the demo database.

Or run the pieces separately:

python3 -m venv .venv && .venv/bin/pip install -r requirements-dev.txt
.venv/bin/uvicorn core.api.main:app --port 8000     # backend
cd web && npm install && npm run dev                # frontend on :3000
.venv/bin/python -m pytest -q                       # tests

Full stack per the spec (Postgres/pgvector + Ollama + api + web):

cd deploy && docker compose up
docker compose exec ollama ollama pull llama3.1     # first start only

Production deployment — on-premises, air-gapped, or any cloud — uses deploy/docker-compose.prod.yml (built web bundle behind nginx, env-driven secrets, non-root API, bring-your-own LLM endpoint). Every path is documented in docs/DEPLOYMENT.md; the system design lives in docs/ARCHITECTURE.md.

Providers are selected in intakepilot.yaml and can be overridden with env vars — see Bring your own AI for the one-line model switch. INTAKEPILOT_STORE=sqlite|postgres, INTAKEPILOT_VECTOR=local|pgvector; setting DATABASE_URL switches the store to Postgres automatically.

Bring your own AI

The demo runs on a deterministic mock so it works with zero setup — but the backend is built to run any AI you already have, enabled by environment variables alone. No code changes, no redeploy of anything else: set the vars, restart the API, done. Structured outputs are schema-validated with retry regardless of provider, so a weaker model degrades gracefully instead of corrupting a draft.

You want Set Notes
Offline demo (default) INTAKEPILOT_LLM=mock deterministic, no model, no network
Local / air-gapped (Ollama) INTAKEPILOT_LLM=ollama model per intakepilot.yaml (llama3.1 + nomic-embed-text); OLLAMA_BASE_URL to point elsewhere
OpenAI INTAKEPILOT_LLM=openai_compat
OPENAI_API_KEY=sk-…
OPENAI_MODEL to pick the model (default gpt-4o-mini)
Azure OpenAI / vLLM / LiteLLM / OpenRouter / TGI / llama.cpp / internal gateway INTAKEPILOT_LLM=openai_compat
OPENAI_BASE_URL=https://…/v1
OPENAI_MODEL=…
OPENAI_API_KEY=…
anything that speaks /v1/chat/completions works; Anthropic/Gemini/Bedrock via a LiteLLM or OpenRouter gateway
Hybrid: local first, frontier on hard turns any primary above + INTAKEPILOT_LLM_ESCALATION=openai_compat the stronger model answers only when the primary fails schema validation twice — local-first economics, frontier-grade interpretation where it matters
# example: local Ollama day-to-day, OpenAI only for the hard turns
export INTAKEPILOT_LLM=ollama
export INTAKEPILOT_LLM_ESCALATION=openai_compat
export OPENAI_API_KEY=sk-...
.venv/bin/uvicorn core.api.main:app --port 8000
curl -s localhost:8000/health   # -> "provider": "ollama+openai_compat"
flowchart LR
    T["Turn / gate / question call"] --> P["Primary model<br/>mock · ollama · openai_compat"]
    P -->|"valid JSON (schema-checked)"| OK["Proceed"]
    P -->|"invalid ×2"| E["Escalation model<br/>(optional, one attempt)"]
    E -->|valid| OK
    E -->|invalid| D["Graceful degrade:<br/>draft kept, turn flagged,<br/>no budget spent"]
    OK -. "every human correction" .-> L["Learning ledger<br/>exemplars → fewer escalations"]
    L -.-> P
Loading

Embeddings always stay on the primary so the vector index stays dimensionally consistent; escalation rate is measurable at /api/metrics and tapers as the learning ledger grows. Fine-grained settings (embed models, timeouts, per-tier overrides) live in intakepilot.yaml under llm: / llm_escalation:.

Demo via curl (no UI needed)

SID=$(curl -s -X POST localhost:8000/api/sessions -H 'content-type: application/json' \
  -d '{"requester":{"name":"Demo","dept":"Finance Ops","role":"Analyst"}}' | python3 -c 'import sys,json; print(json.load(sys.stdin)["session_id"])')
curl -s -X POST "localhost:8000/api/sessions/$SID/turns?stream=false" \
  -H 'content-type: application/json' \
  -d '{"message":"our monthly vendor report takes 3 days to compile by hand"}'
# ... answer the returned questions, then confirm. Requirements are bound to
# the session that created them (IDs are sequential, so this stops enumeration):
#   curl -X POST localhost:8000/api/requirements/{req_id}/confirm \
#     -H "X-Session-Id: $SID" -H 'content-type: application/json' -d '{"edits":{}}'

Architecture

flowchart TB
    subgraph clients["Clients"]
        direction LR
        WEB["Web UI<br/>React + Vite · live Shadow Draft (SSE)"]
        BOT["Chat bots<br/>Slack · Teams · mail"]
        REST["REST clients<br/>plain-JSON turns"]
    end

    subgraph core["Deterministic core — FastAPI (the LLM never controls the loop)"]
        direction LR
        ORCH["Orchestrator<br/>extract → infer → retrieve →<br/>budgeted questions → confirm"]
        GATES["5 gates + routing<br/>dedup against real past work"]
        ENRICH["Enrichment<br/>backend context discovered,<br/>never asked"]
        PORTF["Portfolio<br/>collisions · cost-of-delay ·<br/>acceptance criteria"]
    end

    subgraph protocols["Provider protocols — the only door out (no SDK imports in business logic)"]
        direction LR
        LLM["LLMProvider<br/>mock · Ollama · any OpenAI-compatible<br/>+ optional escalation tier"]
        STORE["Store<br/>SQLite · Postgres<br/>append-only versions"]
        VEC["VectorIndex<br/>local · pgvector"]
        CONN["SystemConnector<br/>SAP demo fixture · your ERP"]
        TGT["Target<br/>local repo · GitHub issues"]
    end

    subgraph learning["Ledgers & learning loops"]
        direction LR
        LED["edit_diffs · question_ledger · outcome_ledger · system_kb · glossary"]
        LOOP["exemplars · question ranking · readiness calibration ·<br/>routing precedent · corrections-as-evals · glossary proposals"]
    end

    clients -->|"REST + SSE · session-bound"| core
    core -->|"protocol calls only"| protocols
    core -->|"append-only writes · outcomes · discoveries"| LED
    LED --> LOOP
    LOOP -.->|"every human correction improves the next intake"| core
Loading

core/ is a FastAPI app. Three provider protocols (LLMProvider, Store, VectorIndex) are the portability contract — no business logic imports a provider SDK (enforced by a test). The orchestrator (core/agents/orchestrator.py) is the spec's Section 6.1 loop: extract → merge (ANSWERED/EDITED are never overwritten) → gap ladder (infer from requester context, retrieve from glossary/precedent) → budgeted questions (max 3/turn, 7 total, enforced in code) → stated-default assumptions → readiness score → append-only version write. Confirmation captures every human edit as an edit_diffs row (the learning asset) which core/learning/exemplars.py injects into future extraction prompts — model-agnostic learning. Gates 1/3 are deterministic pure functions; gates 2/4/5 use the LLM as a scored rubric behind one validate-and-retry wrapper. The routing classifier blends configured keyword signals with routed precedent from the vector index, plus confidence and a human-readable explanation. web/ is a React + TypeScript + Vite app that consumes the SSE turn stream to animate the Shadow Draft live.

The full design — component map, complete API surface with the auth model per endpoint, trust boundaries — lives in docs/ARCHITECTURE.md; every deployment path (laptop → docker → air-gapped prod) in docs/DEPLOYMENT.md.

Backend-aware enrichment and the system knowledge base

Business users never need to know backend details (ADDENDUM-01). After a requirement is confirmed — and before gates/routing — an enrichment step (core/agents/enrichment.py) resolves the business terms in the ask through the glossary and a SystemConnector provider (core/providers/connector/, protocol: resolve_entity / describe_entity / list_customizations). The shipped fixture connector reads YAML system definitions from core/schemas/systems/ — an example SAP S/4HANA system (sales orders VBAK/VBAP with Z-fields like ZZ_PRIORITY_CODE, material master MARA with append fields) and a non-SAP Postgres fulfillment DB with custom columns.

What the enrichment produces:

  • A backend_context slot (provenance retrieved, askable: false — the Question Composer can never ask the requester about backend detail; an invariant test enforces it) holding the matched entities, their backend names, and every customization with type, description, and owner.
  • A System context (auto-discovered) section on the routed ticket, so the assigned team sees e.g. ZZ_PRIORITY_CODE without re-interrogating the requester — try the ask "I need a report of goods details for product line X with the order info".
  • Rows in the system_kb ledger (entity schema, evidence_count, verified, last_refreshed, embedded into the vector index). The retrieval ladder reads system_kb on later intakes, so affected systems and backend context are pre-filled from cached discoveries; discoveries start unverified and are promoted via mark_validated when a human confirms them. /api/metrics reports entity/customization/verified counts.

Swap the fixture for a real connector (SAP OData/RFC, database catalog) by implementing the three-method protocol and pointing intakepilot.yaml (connector: / connectors:) at it.

Theming

The UI follows docs/DESIGN-GUIDELINES.md: every color flows through semantic CSS custom properties in web/src/styles.css, with first-class dark and light themes selected by html[data-theme]. The header toggle persists the choice to localStorage; the default follows the OS prefers-color-scheme (applied pre-paint by an inline script in web/index.html, so there is no flash). Accents are teal/cyan — no purple/violet/indigo anywhere — with amber for warnings, red for failures, green for success, and a distinct badge color per provenance value.

What's implemented vs. spec'd for later

Implemented and verified (spec milestones 1–5 core, plus gates/routing from 6):

  • Pydantic model per spec 4.1; slot schema loader with the askable:false rule (4.2)
  • Providers: mock (deterministic, offline), Ollama, OpenAI-compatible, plus an optional escalation tier (EscalatingLLM: a stronger model answers validation-failed turns — the hybrid local/cloud strategy); SQLite (default) and Postgres (4.3 DDL) stores, both append-only; local cosine vector index and pgvector
  • The full 6.1 turn loop with SSE streaming, budget enforcement, gap ladder, defaults with reasons, readiness scoring (rubric documented in core/agents/orchestrator.py — the spec omits one)
  • Confirmation with edit-diff capture, exemplar selection/injection (7.2)
  • Five-gate pipeline (1 & 3 deterministic; 2/4/5 LLM-rubric), routing classifier with explanation, ticket targets: local repo (default) or GitHub issues via provider.target / INTAKEPILOT_TARGET
  • /api/metrics computing Section 9 metrics from the ledgers (plus system-KB counts, escalation rate, duplicate catch rate, and routing accuracy from reroute ground truth)
  • Request-type schema forks (bug_report / data_request classified deterministically on the first turn; forks in core/schemas/*.yaml, learning buckets are dept×type), an opt-in dynamic question budget scaled by blast radius (budget.dynamic), and a generic chat-channel adapter (POST /api/channels/inbound) any Slack/Teams bot can call — numbered answers and a 'confirm' keyword complete the whole flow in chat
  • The portfolio layer: collision detection (open requirements touching the same backend entities are connected at confirm — ticket Impact section, GET /api/graph with hotspots), deterministic cost-of-delay pricing on every ticket (cost_of_delay slot + backlog-by-value in metrics), generated Given/When/Then acceptance criteria on routed tickets, and a stakeholder countersign ledger (/api/requirements/{id}/consent)
  • The learning & feedback surface: gate 4 checks real known work (vector candidates + deterministic near-duplicate fail) with one-click attach-as-duplicate; routing blends keyword and precedent signals and learns from reroutes (POST /api/requirements/{id}/reroute, GitHub webhook); question ranking and readiness weights calibrate from the ledgers; corrections replay as evals (GET /api/evals/replay); repeated corrections surface as glossary proposals (GET /api/glossary/proposals, human-accepted via POST /api/glossary); system-KB validation via POST /api/kb/{system}/{entity}/validate
  • ADDENDUM-01 backend-aware enrichment: SystemConnector protocol + fixture connector, post-confirm enrichment agent, system_kb ledger feeding the retrieval ladder, System-context section on routed tickets and in the confirm/post-confirm UI
  • Web UI: chat with streaming + question chips + budget meter, live Shadow Draft with provenance badges and confidence bars, readiness ring, confirm view with inline edits and assumption register, gate/routing/ticket results, metrics dashboard — all themed dark/light via semantic tokens
  • Tests for the Section 11 invariants plus the ADDENDUM-01 invariants and acceptance scenario (tests/)

Spec'd for later (honest gaps):

  • Milestone 6 remainder: triage queue UI (GitHub target + label-reroute webhook are shipped; full status sync is not)
  • Milestone 7: eval harness over a 40-scenario golden set (scenario #1 ships in evals/golden/ and runs as a pytest), nightly distillation jobs, prompt_configs promotion gate
  • Milestone 8: precedent backfill from targets, clone-and-modify UX, glossary importer CLI (a seed glossary ships for the demo)
  • Milestones 9–10: Bedrock/DynamoDB/Bedrock-KB providers, SAM template, Builder Agent
  • Auth/multi-tenancy (session binding + admin token + webhook signature are shipped; end-user SSO is your reverse proxy's job for now), schema migrations — see docs/SPEC-REVIEW.md

Repo layout

Matches spec Section 3: core/ (api, agents+prompts, gates, learning {exemplars, proposals, replay}, providers/{llm,store,vector,connector}, targets, schemas, models.py, config.py), web/, deploy/ (docker-compose + Dockerfiles + nginx), scripts/ (ops_check.py live-API readiness sweep), tests/ (117 tests: invariants, e2e, per-feature suites), evals/golden/, docs/, examples/demo-repo/.

License

MIT

About

AI requirements intake — plain words in, code-ready requirements out. Deterministic orchestrator (LLM proposes, code decides), question budget, five quality gates, backend-aware enrichment, learning ledgers. Local-first: mock/Ollama/any OpenAI-compatible endpoint.

Topics

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors