Rajarshi Nandi (he/him) Applied AI and software engineer, Sheffield, UK

The model proposes, code validates and a person decides.

I build software on that rule, most recently AI Accountant, a review layer for AI-categorised Xero books. Its demo opens in your browser with no account.

Recorded in the public demo, where a person approves a suggested line.

AI Accountant

On the review screen a transaction shows up as a proposed category with written reasoning, a confidence tier and a risk flag. The reviewer approves, corrects or rejects it, and the app records each call.

Since Making Tax Digital for Income Tax began on 6 April 2026, sign-off on Xero has come round every quarter for UK sole traders, small businesses and their bookkeepers. It is made for that quarterly job. I designed and built it between March and October 2026; it is deployed on Vercel and Railway and open source under MIT.

Xero's own AI now categorises and reconciles. A person still has to catch the handful of wrong lines in every hundred and show later who made each decision, and AI Accountant takes on that work, after Xero's AI and before the sign-off.

Design decisions

I picked the stack, the two LangGraph workflows and Haiku first with Sonnet on low confidence.

  1. Haiku first, Sonnet below 0.85

    Claude Sonnet 4.6 costs about 3x the list price of Claude Haiku 4.5. Haiku therefore sees every transaction first, and a line it scores below 0.85 confidence goes to Sonnet with the same prompt. Only the uncertain lines cost Sonnet rates, and the audit row keeps both models and both confidences.

  2. The firm's own precedents

    I designed around Xero's 2026 developer terms, so categorisation trains no model on client data and evaluation uses no Xero data. Corrections from reviewers still shape what comes next. pgvector finds the firm's five closest past decisions for each new proposal and passes them to the model as few-shot precedents, with MiniLM embeddings computed locally and kept in the same Postgres.

More trade-offs have rows in the README's decisions table.

Who decided what

An audit row is written for every AI proposal and for every approval, correction or rejection, with the model, the confidence, the reasoning and the decision in it. Any decision, with its reason, can be traced in one database query.

Backend detail, starting with the risk engine

Behind the risk flag is a Mamdani-style fuzzy inference engine written from scratch for the app. It applies eight plain-language rules, among them an unusual amount and an unseen vendor, and every flag it raises names the rules that fired, beside a score and a label.

One fixed workflow per job

Categorising and reconciling are separate jobs whose shape is known in advance, so each runs as its own fixed LangGraph workflow, and every run finishes by writing one audit row.

Money in code, books read-only

Amounts are Decimal end to end. Code produces every figure in the management letter, the profit and loss and the VAT summary, and the model's share is the narrative around them. Bank reconciliation calls no model at all; it scores candidates on amount, date and description similarity with weights of 0.5, 0.2 and 0.3, and near-ties go to review.

AI Accountant holds read-only Xero scopes and never writes back; its Xero tokens are Fernet-encrypted at rest, webhooks are HMAC-verified, and every authenticated operation takes its organisation from the session.

My calls on it, and what the repository holds

Claude Code is part of how I build, and the product, the architecture and the verification stay mine.

Here that meant framing AI Accountant around UK MTD and Xero, positioning it as a review layer, and choosing what to build and what to cut. To verify it I read the diffs, ran and tested the app, and decided which review findings and which claims to accept.

Its stack is Python 3.12, FastAPI, SQLAlchemy 2.0 async, PostgreSQL 16 with pgvector, Redis and Alembic, with Next.js 14, TypeScript and Tailwind on the front, Docker and GitHub Actions. The repository holds 34 API routes, 8 tables, 6 migrations and 117 backend tests running in CI.

An in-browser server behind the frontend's single apiFetch choke point runs the demo, simulating every endpoint the console calls and sending no request to the API or Xero. Ported to the browser as well, the reconciler's scoring is checked against RapidFuzz to four decimal places.

The two-minute walkthrough

AI Accountant's transactions list in the demo, each line with its category, confidence and status. Play the walkthrough

Pressing play loads the video from YouTube.

Checking the work

Provenance and the eval harness

No number goes out from me without a provenance file beside it, recording the commit, fixture version, prompt version, model id and date.

AI Accountant's repository ships an offline eval harness with pass/fail gates, a calibration table, per-category precision, recall and F1, and a response cache. Once a live run's recorded spend passes the cap, a budget guard halts it.

Reviewing my own repository

My own review of the AI Accountant repository ran as six parallel agent passes under one evidence standard of file, line, quoted code and severity, and I reproduced the numerical findings.

I fixed five defects from that review test-first. Each fix has a test that failed before it, and the 24 tests added cover spend-subtype signs, risk-engine edge cases, chart-canonical validation, PDF autoescaping with a restricted URL fetcher and read-only Xero scopes.

Gate first, code second

Before any ChronoAgent signal code ran, I set the decision gate and its fallback pivot, then followed the evidence through that pre-specified pivot to concurrent detection with reliability-weighted allocation.

When the signals were validated, memory-poisoned steps stood apart from clean ones on KL divergence from a clean embedding baseline, with Cohen's d above 1.3 under both MINJA and AgentPoison attacks.

Statistics in the routing study

Rates in the routing study carry Wilson score intervals. I chose Wilson over the Wald interval because the auto-approval subsets hold 81 and 113 items and some error rates sit near 0 or 1, and each threshold-versus-PPO comparison has a two-proportion z-test.

Continuous integration

Migrations are applied to a live pgvector database before any AI Accountant test starts. ChronoAgent's pipeline builds its Docker image and reruns the signal-validation experiment inside it, the RL routing repo regenerates every evaluation result from the committed models, and ledgerkb's offline workflow runs the whole suite with the network cut.

Types are checked too, with mypy in strict mode over the whole ChronoAgent package and a strict TypeScript check on AI Accountant's frontend.

When a dependency goes missing

Take Redis away and AI Accountant serves uncached. ChronoAgent drops to an in-process bus and in-memory SQLite, and its health endpoint reports the switch. The RL router falls back to its hand-tuned thresholds, and voice-loop speaks through Windows SAPI when the Kokoro model is absent.

Outputs held to valid values

Only an account that exists in the firm's own chart is stored from a model's answer, and anything else goes to a person. Decoding through a trie keeps my Banking77 model inside its 77 labels.

If a person in your product signs off what a model proposes, email rajarshin264@gmail.com for a 15-minute call, and we can follow one transaction through this repository together, from the Xero sync to its audit row.

One transaction's path through AI Accountant From Xero, a transaction synced read-only goes to the model, which proposes a category with reasoning and a confidence. Next, code validates the answer against a Pydantic schema and the chart of accounts. Then the answer gets a confidence tier and a fuzzy risk flag. After that a person approves, corrects or rejects it, and the decision is written to an audit row. If an answer fails a check it goes straight to the person, and a correction returns as a precedent for later proposals. fails a check correction returns as precedent Transaction synced read-only from Xero Model proposes category, reasoning, confidence Code validates Pydantic schema, chart check Tier and risk flag confidence tier, fuzzy rules A person decides approve, correct or reject Decision recorded one audit row per decision
Confidence sets the tier, auto-accept above 0.85, suggested from 0.5 and needs review below, so the reviewer knows where to look.

How I work

Who keeps the final call has been the design question in three roles now.

  • IBM, 2021 to 2023. The insurer's underwriters kept every high-exposure risk. My human-in-the-loop backlog workflow for that US property and casualty client auto-approved the low-risk standard policies and escalated the high-exposure ones to them.
  • ADHDNET, 2025. I kept AI there to admin work, drafting and summarising, and nothing it produced reached a patient until the contracted physician had reviewed and signed it off.
  • AI Accountant, 2026. Its model answers count only once they clear a Pydantic schema, a chart-of-accounts check and a confidence tier, and any that fail are routed to a person.

What running it turned up

Xero's OAuth scope scheme changed partway through the build. Testing scopes against the token endpoint showed which granular ones worked, and when a later commit slipped a broad scope back in, cross-checking git history against Xero's scope table caught it.

SQLAlchemy 2.1 arrived upstream one day and took the deployed API down with it. Pinning below 2.1 and redeploying had health and the OAuth redirect verified within the afternoon.

A CORS change once made the deployed dashboard report Xero as disconnected; I told the CORS error in the browser apart from a 401 and fixed it the same day.

Bank lines in Xero's Demo Company were invisible to the API, so I added Payments as a third sync source, deduplicated against invoices. Both of these are written up in the engineering record.

Also built

  • ChronoAgent keeps a live health score per agent in multi-agent LLM systems.
  • With voice-loop I speak to the Claude Code CLI and hear it reply.
  • My Banking77 adapter takes Llama-3.2-1B-Instruct to 90.21% exact match (Hugging Face).
  • In my routing study the PPO policy refused to auto-approve the medium tier, where fixed thresholds auto-approved with a 54.8% error rate, cutting auto-approvals from 63.8% to 45.8% (p < 0.001).
  • ledgerkb is open-source Python for searching mixed documents in eleven formats.
  • I put k-means and hierarchical clustering through bootstrap resampling in a stability study.

Before this

  1. Application Developer, IBM

    Feb 2021 to Aug 2023, IBM Consulting, India

    I built data pipelines, dashboards and ML models for a US property and casualty insurer. Backlog customer satisfaction rose 22%, by the client's own survey before and after. The churn models I built and deployed ran on XGBoost with SHAP, my pick over deep neural networks because the data was tabular and US state insurance regulators expect transparent risk drivers. Attrition fell 9 percentage points.

    My staged micro-batch ETL pipeline in Snowflake fed the insurer's Duck Creek policy platform behind pre-ingestion schema validation, a dead-letter queue and automated row-count, null, duplicate and range checks, and it cut processing time by 23%. Promoted in 2022, I led a demand-forecasting engagement end to end with six analysts reporting to me. Afterwards the client redirected where its marketing money went; marketing ROI rose 14% and revenue 6%. Between an offshore development team and the insurer's US business stakeholder I was a regular point of contact, and I ran the requirements workshops and the monthly sprint reporting, with findings rewritten for each audience.

  2. Data Analyst, ADHDNET

    Jan 2025 to Sep 2025, a UK healthcare provider delivering NHS-funded ADHD and autism assessments

    Lawful basis, data minimisation and access control came first, worked through with the clinical, operations and finance leads, and then I wrote the organisation's AI Usage Policy, with zero-tolerance controls on patient-identifiable data and role-based access. My 28-day SLA compliance reporting covered 500+ client journeys and 30+ providers. Within a month, the weekly review that ran on it showed leadership a provider-level breach pattern they had not seen before.

    I took the clinic's AI use off consumer accounts and into ChatGPT Enterprise, then made the case for Microsoft Copilot and led the switch. Once I had trained the admin team and written the documentation, the team processed more reports, and patients and GPs asked for fewer changes.

  3. MSc Data Science and Analytics, University of Leeds, Merit

    2024

    Coursework in Python, SQL and R covered statistical learning and statistical theory and methods. Leeds' ARC4 HPC cluster ran my dissertation, which trained a ResNet-18 on CIFAR-10 with 50 clean epochs, then 50 FGSM epochs, lifting accuracy under a 30-step PGD attack from 0.57% to 35.66% while clean accuracy held at 88.75%.

  4. BTech Electronics and Communication Engineering, Techno India Saltlake

    2020, GPA 7.91/10

Contact

rajarshin264@gmail.com

AI Accountant's repository holds the plan for what comes next. I wrote its roadmap, phases 0 to 12, which runs through an HMRC-guidance RAG review layer, AI security and a quarter-review agent to an MCP server.

Email me for a 15-minute call, and on it I can take you through any of this code. Every repository named here is at github.com/rajo69, and my profile is on LinkedIn. CV on request.

Roles: AI Engineer, Applied AI Engineer, Product Engineer, Forward Deployed Engineer or Software Engineer, at a startup.