The AI close agent for finance teams: reconciliations, journal entries and ledger answers, grounded in your own books and cited every time.
Live demo: https://www.freelancerportfoliohub.com/jameslee/projects/closewell/index.html
This repository holds the Closewell marketing site and the agent service behind its Ledger Q&A and close workflows. The site walks a finance team from "what is it" to "book a demo", with separate paths for CFOs and controllers. The product mockups (policy workflow card, close run, policy library, cited ledger answers) are rendered from typed data in HTML and inline SVG rather than screenshots, so copy and examples can change without design work.
The agent service (agent/) is a Python FastAPI app that answers only from the company's ledger and written policies. It keeps a double-entry ledger model, matches bank lines to invoices, proposes and validates journal entries for approval, retrieves policy sections and ledger records with BM25, and streams its answer with the entries and policy sections it relied on. The Next.js site calls it server-side over HTTP.
- Four routes: homepage, Platform, For Controllers and Book a demo, each section backed by typed content in
lib/data - Interactive mockups: rotating policy workflow (Cash / Accrual / Revenue), before/after close board with reviewer sign-off, six-tab capability explorer, four-step How it works walkthrough
- Double-entry ledger model: accounts with normal balances, signed GL lines, balanced journal entries with reversals, trial balance, and approval-gated posting
- Bank-to-ledger reconciliation: matches receipts to open invoices by remittance reference, exact amount or the best many-to-one invoice set, with fuzzy payer names as a fallback
- Applies SHORT-PAY-01: small shortfalls close to 6150, larger ones and overpayments go to the Controller
- Batch runs apply each invoice to at most one receipt and flag ambiguous exact fits
- Journal entry proposals: cash application and short-pay write-offs from reconciliation, Day-1 accrual reversals, prepaid reclassifications with amortization schedules, and FLUX-01 flux review; every proposal is validated as balanced before it is returned
- Grounded close agent: streaming
/agentendpoint with a manual tool-use loopgetLedgerEntries,matchTransactions,draftJournalEntry,citePolicy,explainFlux,proposeJournalEntriestools with pydantic-validated inputs- Pluggable model interface: Claude through the Anthropic SDK, or a deterministic offline model when no API key is set
- Drafts never post; anything outside policy is routed to the named reviewer
- Cited ledger Q&A:
/qaretrieves policy sections, GL lines, bank lines, invoices and account summaries with BM25 and drops any citation that was not retrieved - Qualified demo requests: the form submits through a server action to the service, which validates it, scores the lead by close length, ERP and role, and forwards it to a CRM webhook
- Accessible by default: native
<details>FAQ, labelled form controls and radio chips, reduced-motion support, and pages that render fully without JavaScript
| Area | Choice |
|---|---|
| Site | Next.js 15 (App Router), React 19, TypeScript (strict) |
| Styling | Hand-written CSS with design tokens, next/font/local |
| Service | Python 3.12, FastAPI, pydantic v2, uvicorn |
| AI | anthropic Python SDK (Claude Opus 5, adaptive thinking), offline fallback model |
| Retrieval | Okapi BM25 over policy sections and ledger records |
| Tooling | uv, pytest, ruff; ESLint (flat config), Prettier, pnpm |
| Deploy | Dockerfile + railway.json for the service |
Run the agent service and the site in two terminals.
# 1. Agent service (http://localhost:8000)
cd agent
uv sync
uv run python -m closewell_agent # set ANTHROPIC_API_KEY to use Claude; offline model otherwise
# 2. Site (http://localhost:3000)
pnpm install
cp .env.example .env.local # API_URL points at the service
pnpm devOpen http://localhost:3000. The interactive API docs for the service are at http://localhost:8000/docs.
cd agent
uv run pytest # domain, reconciliation, journal, retrieval, agent and API tests
uv run ruff check .Site (.env.local):
| Variable | Required | Description |
|---|---|---|
API_URL |
Yes | Base URL of the agent service, used server-side only |
NEXT_PUBLIC_SITE_URL |
No | Canonical URL for metadata and the sitemap |
Agent service (see agent/.env.example):
| Variable | Required | Description |
|---|---|---|
ANTHROPIC_API_KEY |
No | Enables Claude; without it the deterministic offline model answers |
ANTHROPIC_MODEL |
No | Model id, defaults to claude-opus-5 |
LLM_PROVIDER |
No | auto (default), anthropic or offline |
AGENT_MAX_TURNS |
No | Tool-use turns per request, defaults to 8 |
DEMO_WEBHOOK_URL |
No | CRM webhook for demo requests; logged locally when unset |
CORS_ORIGINS |
No | Comma-separated browser origins, defaults to http://localhost:3000 |
PORT |
No | Port to listen on, defaults to 8000 |
curl -N http://localhost:8000/agent \
-H 'content-type: application/json' \
-d '{"messages":[{"role":"user","content":"Why did cloud infra rise in September?"}],"context":{"period":"2026-09"}}'The response is newline-delimited JSON: text deltas, tool_call / tool_result activity, citation events and a final done.
| Method | Path | Description |
|---|---|---|
| GET | /health |
Status and the active model |
| GET | /accounts |
Chart of accounts |
| GET | /ledger/entries |
GL lines filtered by account, period, counterparty, entity |
| GET | /ledger/trial-balance |
Trial balance up to a period |
| GET | /ledger/flux |
Period-over-period movements under FLUX-01 |
| GET | /bank-lines, /invoices |
Unreconciled bank lines and open invoices |
| GET | /policies, /policies/{id}, /policies/search |
Policy library and section search |
| POST | /reconciliation/match |
Match bank lines to open invoices |
| POST | /journal/validate |
Check journal lines for balance and known accounts |
| POST | /journal/drafts |
Draft an entry for approval |
| GET | /journal/proposals |
Proposed close entries for a period |
| POST | /qa |
Cited answer from retrieved ledger and policy passages |
| POST | /agent |
Streaming close agent (NDJSON) |
| POST | /demo-requests |
Validate, qualify and forward a demo request |
agent/Dockerfile builds the service with uv and serves it on $PORT. On Railway, point a service at this repository with the root directory set to agent; agent/railway.json selects the Dockerfile and the /health check. Set API_URL on the site to the service's URL.
.
├── agent/ # Python agent service
│ ├── src/closewell_agent/
│ │ ├── ledger/ # accounts, GL lines, journal entries, ledger store, policies
│ │ ├── reconciliation/ # remittance references, invoice sets, matcher
│ │ ├── journal/ # drafting, proposal engine, flux review
│ │ ├── retrieval/ # tokenizer, ledger documents, BM25 index
│ │ ├── llm/ # model interface, Anthropic client, offline model
│ │ ├── qa/ # cited ledger Q&A
│ │ ├── agent/ # tools, prompts, run loop, NDJSON events
│ │ ├── leads/ # demo request validation, scoring, delivery
│ │ ├── api/ # FastAPI app and routes
│ │ └── fixtures/ # sample company ledger and policies (JSON)
│ ├── tests/
│ ├── Dockerfile
│ └── pyproject.toml
├── app/
│ ├── controllers/ # For Controllers page
│ ├── get-started/ # Book a demo page and its server action
│ ├── platform/ # Platform page
│ ├── globals.css # tokens, primitives, mockups, sections
│ ├── layout.tsx
│ └── page.tsx # homepage
├── components/
│ ├── brand/ # logo mark
│ ├── capabilities/ # capability tabs and previews
│ ├── controller/ # For Controllers sections
│ ├── demo/ # demo intro and form
│ ├── home/ # hero workflow card, shift board, how it works…
│ ├── layout/ # header, footer, backdrop
│ ├── platform/ # Platform sections
│ ├── sections/ # shared sections (roles, security, FAQ, CTA)
│ └── ui/ # Button, Badge, Card, Avatar, Icon, Sparkline…
├── lib/
│ ├── api.ts # server-side client for the agent service
│ └── data/ # typed page content
├── public/ # fonts and images
└── types/ # content and demo-request types
| Script | Description |
|---|---|
pnpm dev |
Start the site dev server |
pnpm build |
Production build of the site |
pnpm start |
Serve the production build |
pnpm lint |
ESLint |
pnpm typecheck |
TypeScript, no emit |
pnpm format |
Prettier |
uv run python -m closewell_agent |
Start the agent service (in agent/) |
uv run pytest |
Agent service tests (in agent/) |
uv run ruff check . |
Lint the agent service (in agent/) |
