Project Info
Inspiration
A plumber, an HVAC tech, or an electrician spends 30 to 60 minutes after every job writing up an invoice: pulling rates from memory, tracking down what parts were used, formatting line items, emailing the vendor. It's the least skilled part of their day and the most likely to have errors that delay payment. We wanted to see how much of that could disappear if an AI agent had already read the work order, prefilled everything it could, and only asked the human for the two or three things it genuinely couldn't figure out on its own. What we built Foreman is a multi-agent pipeline that moves a field service work order from raw request to approved invoice. Intake reads the unstructured request, classifies the job type, pulls out the relevant entities (location, vendor, urgency), and flags anything missing before the order goes further. Scheduling proposes appointment windows, drafts customer outreach, and suggests parts likely needed for the job, clearly labeled as estimates rather than confirmed quotes. Invoicing is the deep stage. It prefills an invoice from everything already known, identifies the specific gaps (labor rate, hours, trip charge), has a natural-language conversation with the user to fill only those gaps, checks the draft against past invoices for rate consistency, renders a branded invoice, and drafts the vendor notification email. The human is in the loop at every commit point. Agents propose; a person confirms. No stage advances without explicit approval. The demo highlight is an ArmorIQ safety check blocking an off-plan action mid-invoice: the agent tries to commit, the gate fires, and the operator sees exactly why. The shared state is a single work-order object in Redis. Agents don't call each other; each one reads what came before it and writes its own section. That let four people build in parallel on day one without stepping on each other.
How we built it
Agents run on Anthropic Claude via the SDK, using tool use directly with no framework wrapper. Each agent has a focused set of tools, a system prompt that describes the turn-based flow, and a fallback to seeded data if an external call fails. Redis holds the work-order object and invoice history. Every agent reads from and writes to it; the pipeline advances when an approval gate opens. ArmorIQ wraps the committing actions (filling the template, drafting the vendor email). Every action is signed with a plan; off-plan actions are blocked at runtime and surfaced to the operator. Arize Phoenix instruments every Claude call. Each agent decision, including gap-fill questions asked, consistency flags raised, and ArmorIQ checks, appears as a span in the Phoenix UI and links back to the work order through a trace ID. The API is FastAPI with a locked OpenAPI contract that all four team members built against from the start. The frontend is Vite, React, Tailwind, and shadcn/ui. Challenges Conversation state across HTTP requests. The invoicing agent needs to pick up mid-conversation when the user responds. Naively, every POST to /invoice-chat restarted the agent from scratch and re-asked the same questions. We fixed this by persisting the full Claude message history in the Invoice object in Redis, so turn two resumes exactly where turn one left off. A broken Phoenix dependency. arize-phoenix 6.2.0 ships with a broken internal import when arize-phoenix-evals is installed separately. We had to pin compatible versions and wrap all Phoenix imports in graceful fallbacks so a missing tracing dependency never crashes the agent. Four people, one schema. Locking the work-order schema in the first 90 minutes was the right call. Every argument about field names happened before anyone wrote code, which meant no merge conflicts on the object everyone reads and writes.
What we learned
The human approval gate is not a feature you add to an agentic system. It's the architecture. Designing it as a real stop, not a cosmetic checkbox, forced every other decision: how state is held, how agents are prompted, how ArmorIQ fits in. Getting that right early made the rest of the build feel coherent. Conversation history is also load-bearing in a way we didn't fully appreciate at the start. An agent that asks the same question twice isn't just annoying; it breaks the user's trust that the system understood them. Persisting and resuming message history is the difference between something that feels like a product and something that feels like a prototype.
Foreman
Multi-agent field service invoicing. A work order flows through three AI agents (intake, scheduling, invoicing) with a human approving every step that actually commits anything.
How it works
Raw request → Intake → Scheduling → Invoicing → Approved invoice + vendor email
Each agent reads the shared work-order object in Redis, writes its own section, and stops at a human approval gate before the next stage runs. Agents don't call each other; they pass state through the object.
The invoicing stage is a multi-turn conversation. The agent prefills what it can from the work order, asks only for what's missing (labor rate, hours, trip charge), checks the draft against past invoices for rate consistency, then produces a branded invoice and vendor email draft. Nothing commits without human sign-off.
Quick start
You need Python 3.11, Redis Stack (not plain Redis), and an Anthropic API key. Redis Stack includes the vector search module required for invoice history. Install it with brew tap redis-stack/redis-stack && brew trust redis-stack/redis-stack && brew install redis-stack, then start it with redis-stack-server --port 6380 --daemonize yes.
cp backend/.env.example backend/.env
# fill in ANTHROPIC_API_KEY in backend/.env
make dev # starts Redis + Phoenix + uvicorn on :8001
make test # runs the smoke test suite (no API key needed)
API
| Endpoint | What it does |
|---|---|
POST /work-orders | Create a work order from a raw request |
GET /work-orders/{id} | Fetch current state |
POST /work-orders/{id}/approve | Approve a stage (triggers the next agent) |
POST /work-orders/{id}/invoice-chat | Send a message to the invoicing agent |
GET /work-orders/{id}/invoice-history | Pull past invoices for the consistency check |
Integrations
- Anthropic — all three agents use Claude with tool use
- Arize Phoenix — every Claude call is traced; spans link back to the work order via
trace_id, visible athttp://localhost:6006 - ArmorIQ — committing actions are signed and checked at runtime;
DEMO_BLOCKtriggers a visible operator alert - Redis — work-order state and invoice history
Environment variables
ANTHROPIC_API_KEY=
REDIS_URL=redis://localhost:6379
PHOENIX_COLLECTOR_ENDPOINT=http://localhost:6006/v1/traces
ARMORIQ_API_KEY= # optional; stub works without it for demo
ARIZE_SPACE_ID= # optional; local Phoenix works without it
ARIZE_API_KEY= # optional; local Phoenix works without it
Team
Eugene (invoicing agent + API spine), Bhoomika (orchestration + Redis), Harshita (intake + scheduling), Michelle (UI + demo)
Analysis
View
Metric
- 44
- 22
- 11
- 11
- 9
Figures cover GitHub contributors during the hackathon window. A co-authored commit counts in full for each author, so per-member totals add up to more than the whole-team figures.
Technology
- AnthropicIn code
- CSSIn code
- FastAPIIn code
- HTMLIn code
- JavaScriptIn code
- PythonIn code
- ReactIn code
- Tailwind CSSIn code
- TypeScriptIn code
- RedisClaimed
9 of 10 appear in the indexed code. 1 claimed on Devpost could not be matched to code, which may simply mean the tool leaves no trace in the repository.
AI coding agents
- Claude CodeConfig · Commits
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
523 KB
Source files
90
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
eugenelacatis/Foreman
136 files · 4.0 MB · @ 21fe337
Structure
Interface
24 files · 18%Screens, components and styles rendered to the user.
API & routing
4 files · 3%Request entry points: routes, handlers and controllers.
Application logic
24 files · 18%Domain rules, services and shared utilities.
+1 moreData & schema
4 files · 3%Schema definitions, migrations and data access.
Supporting
Layers are inferred from where files sit in the tree, not from reading the code. A project that names its directories unconventionally will read oddly here — open the file browser to check anything the diagram implies.
Languages
- TypeScript49%
- Python33%
- Markdown12%
- HTML4%
- CSS1%
- Shell0%
- Other (1)0%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
frontend/package.json
npm · 21- @radix-ui/react-dialog
- @radix-ui/react-slot
- @react-leaflet/core
- @sentry/react
- class-variance-authority
- clsx
- leaflet
- lucide-react
- react
- react-dom
- react-leaflet
- tailwind-merge
- +9 more
backend/requirements.txt
pypi · 18- anthropic
- arize-phoenix
- arize-phoenix-evals
- arize-phoenix-otel
- browserbase
- fastapi
- httpx
- openinference-instrumentation-anthropic
- playwright
- pydantic
- pytest
- pytest-asyncio
- python-dotenv
- redis[hiredis]
- sentence-transformers
- sentry-sdk[fastapi]
- uvicorn[standard]
- websockets
Declared in the repository’s manifests at the indexed commit. A declared package is not proof it is used, and runtime dependencies are listed first.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.