Project · tax-notice automation

A desktop tool that handles the notice backlog before the deadline.

Chronos Notice is one of our own builds — a desktop tool for CA firms and tax practices drowning in GST, IT, and TDS notices. It watches the scanner folder, extracts each notice with OCR plus Claude, routes it to the right partner, writes into the firm’s existing sheet, and chases the deadline. Local-first, so notice contents never leave the machine. This is how it’s built.

Type
Tax-notice automation
Engagement shape
14-day Custom MVP
Built on
Chronos Notice · our own product
Surface
Windows desktop app
Posture
Local-first · notices stay on the machine
Hero visual · pipeline overview

scanner inbox → OCR → Claude extraction → partner routing → Google Sheet

A horizontal flow showing how a paper notice enters the scanner, hits Tesseract for layout-aware OCR, gets handed to Claude vision for structured-output extraction, routes to the assigned partner via a confidence-weighted classifier, then writes into the partner-level master Google Sheet with the response template attached.

scanner in tesseract claude extract route partner sheet write template

The problem

Saturdays disappear. Then a deadline gets missed.

This is the failure shape Chronos Notice is built against. A firm handling compliance for a few hundred businesses — GST registrations, returns, scrutiny notices, the full stack. A backlog of notices piling up as unprocessed PDFs in a shared inbox, and partners spending most of every Saturday triaging them.

The manual workflow looks like this:

  • A junior opens each notice PDF, reads it, types the client GSTIN, the notice type (DRC-01, ASMT-10, REG-17, etc.), the demand amount and the response-by date into a master Excel sheet on Google Drive.
  • They look up which partner is assigned to that client from a separate “client-partner mapping” sheet.
  • They copy the relevant block into that partner’s personal tab, paste a response-template link, and DM the partner on WhatsApp with the due date.
  • The partner replies, the junior marks it done. Or the partner forgets, the deadline passes, and someone notices on Monday.

The Saturday work is painful but tolerable. What breaks a firm is the first time a notice slips past the response deadline — the client gets hit with a penalty and the relationship turns awkward fast. You’re losing trust because you’re losing PDFs in a spreadsheet.

The constraints are tight, and they shaped the product. No cloud upload of notice contents. No subscription with per-notice metering — a one-time install. No new login for the juniors — it has to slot into the existing scanner-and-Sheets workflow. And it has to be ready before the next quarter’s notice wave lands.


What we built

A desktop tool that watches the scanner folder. Everything else follows.

Chronos Notice is the desktop product behind this. The shape of it: a small Electron front-end a junior actually clicks on, a Python backend that does the heavy lifting, and a strict local-first posture on the notice contents themselves. The architecture below is the build.

Stack

Front-end
Electron desktop app
Back-end
Python · SQLite (WAL)
OCR
Tesseract local + Claude vision
Extraction
Claude structured output (JSON schema)
Sync
Google Sheets API (partner-level tabs)
Reminders
Telegram bot (firm’s own token)
Install
Per-machine MSI · no admin rights
Storage posture
Notice PDFs stay local

Architecture, in five hops

  1. Scanner inbox watcher. A Python watchdog Observer pointed at the firm’s shared scanner output folder. Debounced (3 second window so a double-scan doesn’t double-index). One worker thread drains the queue, runs one notice at a time.
  2. OCR extraction. Tesseract first — it’s fast, local, and handles 80% of cleanly-scanned notices on its own. If the OCR confidence is below threshold or page layout looks unusual, we promote to Claude vision for the same page. The page bytes leave the machine only on the promote path, and only with the user’s OCR-provider choice in config.
  3. Claude structured-output extraction. The text payload is handed to Claude with a strict JSON schema for the extracted record — notice_type, gstin, client_name, demand_amount, response_by, hearing_on, issuing_authority, din, plus a per-field confidence score. No prose, no narrative — JSON or it doesn’t commit.
  4. Routing to assigned partner. Look up the GSTIN in the client-partner mapping table (we imported their existing sheet on day 9). Attach the partner ID to the notice record. On ambiguous matches (a multi-entity client, say), surface the candidates to the junior for one click.
  5. Response template + sheet write + Telegram ping. The notice lands in SQLite. A row appends to the partner’s tab in the master Google Sheet (same sheet they were using before — we did not replace it, we wrote into it). A Telegram message goes to the assigned partner: “GST ASMT-10 for ABC Traders · due 14 Aug · ₹2,84,500 · response template attached.” Three reminders fire after that: 1 week, 1 day, 1 hour before deadline. State machine tracks reply / extension / closed.
extracted record · GST ASMT-10 · client: ABC Traders Pvt Ltd
notice_typeGST_ASMT_1099%
gstin27AABCT1234C1Z598%
demand_amount₹2,84,50082%
response_by14 Aug 202697%
routed_toPartner 3 · Mehta100%
template_attachedgst_asmt10_reply.docx
Junior’s review screen. Edit-then-accept on any amber (<90%) field. Green chips can pass through silently.

The 14-day shape

How a build like this runs, in order.

  • Days 1–3 · samples & shape
    Start from real notice samples, not assumptions.

    Gather representative PDFs across every notice type a firm actually sees (GST DRC-01, ASMT-10, REG-17, IT scrutiny, TDS default, MCA). Don’t start coding. Sit with the juniors, watch them process a real notice each, and write down every field they type into the sheet. The schema comes from that exercise.

  • Days 4–7 · the extraction pipeline
    Tesseract first, Claude vision second, JSON-schema strict.

    Build the watcher, the OCR dispatch, and the Claude structured-output extractor. The interesting decision is the OCR fallback ladder: Tesseract local first for minimal cloud exposure, Claude vision as the promote path only when local confidence drops. The hard cases are predictable — a faxed-and-rescanned notice that’s genuinely unreadable, or a GSTIN rotated 90 degrees on weird letterhead.

  • Days 8–10 · partner routing + sheet write-back
    Import the client-partner mapping. Write into the existing sheet.

    This is where it’s tempting to over-build. A confidence-weighted classifier can look at GSTIN, entity-name fuzz, and historical routing to pick the assigned partner. Then the write-back wires into the firm’s existing master Google Sheet — same tabs, same column order, so the juniors don’t learn a new layout. Writing into the sheet they already use saves days of change-management friction.

  • Days 11–14 · testing on the backlog & deploy
    Run the tool against the full backlog. Ship on day 14.

    Point the tool at the backlog and watch the queue drain — a small fraction need a junior intervention on a low-confidence field, the rest go through clean. Then Telegram-reminder testing on a separate test bot, and hardening: corrupted PDFs out of the scanner, Google Sheets API rate-limits, a missing GSTIN field entirely. Day 14 is install on the partner machines and junior workstations plus a walkthrough.


What the build delivers

What the tool is built to change.

We don’t have paying customers yet, so there are no client numbers to post here — we won’t invent them. What we can describe is what the tool does on a clean notice, and the design choices that make it hold up.

Wall-clock from PDF-in-folder to partner-Telegram-ping for a clean GST notice is seconds, not the 20+ minutes a manual pass takes. Tesseract handles the OCR in roughly 4 seconds; Claude extraction takes 6–9 seconds depending on document length; the rest is routing, sheet write, and the reminder schedule. For low-confidence notices that need junior review the wall-clock stretches — but the work surfaces the moment it’s reviewed, not the next Saturday.

The deadline discipline is the part we care about most. The Telegram reminder ladder (1 week / 1 day / 1 hour) is unremarkable engineering — what makes it work is that the message contains the response-template URL and the GSTIN in one line, so a partner can act from the lock screen without opening a sheet first. Friction matters more than cleverness.

And the Saturday triage doesn’t have to exist. The watcher fires extraction the moment a scan lands, the partner gets the ping, and the response template is open by the time they decide to look — so the queue gets handled in short bursts during the work week instead of one painful block.


What we’d do differently

Honest build lessons, written down before we forget them.

The routing classifier is easy to over-engineer.

A confidence-weighted classifier looking at GSTIN match, entity-name fuzz, and historical routing patterns is elegant — and usually unnecessary. The real need is “this notice belongs to Partner X” from the GSTIN-to-partner mapping a firm already maintains in a sheet. Ship the dumb lookup first, let real usage tell you whether the smart version earns its keep. The classifier tends to buy about half a percentage point on routing accuracy for a day and a half of work.

The corrupted-PDF path deserves v1 attention.

Roughly 1 in 60 scans comes out of a scanner with a corrupted PDF header. Surfacing the error to the junior and stopping works — but what it should do is queue the PDF for a re-scan prompt and quietly retry the watcher pickup, so nobody has to think about it. Small failure modes erode trust faster than big ones — a stalled queue gets noticed every time, even when it’s “just” a scanner artifact. Build it into v1.

The reminder cadence wants firm-specific tuning.

The default ladder — 1 week, 1 day, 1 hour — is right for most firms. But a firm that triages on a fortnight cadence finds the 1-week ping noisy and wants something like 10 days / 2 days / 4 hours. Ask about triage rhythm up front, don’t infer it.

Pre-build the partner-handover view.

When a partner is travelling or unwell, notices need to route to someone else temporarily. Without a clean UI for that, it falls back to editing the client-partner mapping sheet directly — which works, but it’s the kind of thing a partner shouldn’t have to think about. Worth building in from the start.


Talk to us

Want this for your firm?

We do diagnose calls Monday to Friday. Bring a real backlog and a representative notice or three. We’ll tell you what we’d build, what we’d refuse to build, and roughly what it costs — we share pricing in conversation, not on a marketing page.

Talk to us on WhatsApp See the Chronos Notice product page