Inspiration

Month-end close still runs in Excel. Fund accountants and controllers burn hours on mechanical tie-out — matching bank narratives to vendor masters, pulling GL balances into entity registers, cleaning invoice exports — work that scales with headcount, not process.

We targeted one high-friction moment in that close: bank counterparty matching before journal entry. Banks truncate and mangle payee names; the vendor master holds clean legal names. Accountants either guess (audit risk) or manually research every unmatched row. Real anonymised fund-admin data preserves dozens of deliberate non-matches — that isn't bad data, that's the job.

Our wedge is verification-first automation: the agent fills what it can prove; everything else goes to a human with source-row evidence. Every populated cell ties back to its source.

────────────────────────────────────────

What it does

tieout takes a workbook and a plain-English mandate, then:

  1. Classifies the workflow (lookup, aggregation, sheet transform, consolidation)
  2. Executes via values-first inference or sandboxed Python/openpyxl codegen
  3. Verifies every answer cell — fatal formula errors and unresolved lookups block, never silently overwrite
  4. Retries with attribution-guided repair, up to 3 attempts
  5. Routes exceptions to a human-review queue with evidence rows from the source sheet
  6. Archives a complete audit trail (traces/<task>.jsonl, exceptions.json)

Hero demo — close-tieout-bank-cp: match truncated counterparty names from a bank staging sheet to a vendor master. Where there's no provable match, column K stays blank and the row enters the exception queue.

Our fixture has two unmatched rows, preserved from real client data shapes — not model failures.

The accountant reviews each exception and approves (keep flagged/blank) or rejects (revert). Source data stays read-only; only approved outcomes reach the final workbook.

python3 demo/build_fixtures.py
./demo/simulate_demo.sh close-tieout-bank-cp
cd research && uv run python ../harness/exceptions.py review

/tmp/syndicate-demo/exceptions.json

Repo: https://github.com/udirobert/tieout

────────────────────────────────────────

How we built it

Product agent (inference):

  • harness/pipeline.py — classify → execute → verify → retry → exception queue
  • harness/exceptions.py — post-run queue plus interactive approve/reject CLI with evidence
  • harness/skills.py — domain skill fragments injected from instruction text (lookup, reconciliation, consolidation)
  • Tinker running Qwen3.8-27B for live runs; offline demo via ./demo/simulate_demo.sh, no API key required

CFO demo data: fixtures extracted from Ylookup anonymised fund-admin datasets (demo/close-tieout/) — bank counterparty, entity mapping, movements reconciliation.

Engineering (Agent Orchestrator): we used AO (aoagents.dev) as the development control plane. One orchestrator session planned the work; four worker sessions implemented the exception queue, demo fixtures, submission docs, and demo script in isolated git worktrees. AO's Kanban tracked each session from task → implementation → merge. 5 total sessions — see the demo video for the dashboard.

The spreadsheet agent runs at inference time via Tinker; AO orchestrated the engineering work for Track 2.

Stack: AO · Python · openpyxl · Tinker · audit traces (Neatlogs-friendly JSONL)

────────────────────────────────────────

Challenges we ran into

Don't guess on unmatched counterparties. Our first instinct was to force a "best effort" vendor name. Fund-admin data taught us the opposite: a blank K means "no match — human must decide." We encoded that rule in the mandate, the verifier, and the exception policy.

Human review has to carry evidence. An exception queue that only says "cell K5 failed" isn't usable during close. We attach source-row keys from the staging sheet so the accountant can see exactly what the agent evaluated and why it stopped.

Agentic ≠ one-shot API. Spreadsheet work needs a classify → execute → verify → retry loop, plus sheet-level codegen in a sandbox. Getting verification right — never-blank reliability without silent bad commits — took iteration on the harness.

Scope for a hackathon. A full close spans bank feeds, JEs, GL, and sign-off. We scoped to one high-pain step — counterparty matching — and made it demoable end-to-end with realistic data shapes.

────────────────────────────────────────

Accomplishments that we're proud of

  • End-to-end CFO demo on real anonymised fund-admin data — bank counterparty matching with 2 preserved exceptions and a human approve/reject flow
  • Exception queue with evidence — not a black-box "something failed"; every flag cites source rows
  • Verification-first architecture — agent proposes, accountant disposes; source data read-only, writes approval-gated
  • Skill loop without retraining — domain fragments in harness/skills.py; ./demo/run_skill_demo.sh shows inject-and-rerun on lookup patterns
  • Built with AO — orchestrator + 4 workers, 5 sessions, full Syndicate pivot documented on the dashboard
  • Never-blank contract — every run emits a workbook and a trace; an exceptions file emits when applicable

────────────────────────────────────────

What we learned

Track 2 is domain-first. A strong spreadsheet agent isn't enough — judges need to recognize the underlying accounting problem and trust the review step. Grounding the workflow in bank staging → vendor master → exception queue made the automation believable.

Unmatched rows are a feature. In production fund-admin data, a meaningful fraction of bank lines don't map cleanly. The product wins by knowing when not to overwrite them.

Separate build orchestration from runtime. AO coordinated engineering; Tinker runs the agent at demo time — a split that mirrors how teams actually build and ship agentic products.

Tools for agents need finance-shaped outputs. JSON traces, exception schemas, and evidence rows matter as much as model accuracy. Accountants need auditability, not just filled cells.

────────────────────────────────────────

What's next for tieout

Near term

  • Review UI for controllers (beyond CLI) — an exception inbox tied to the close checklist
  • Expand fixtures: sub-ledger tie-out, movements reconciliation, entity mapping (already extracted, not yet the hero demo)
  • Live Tinker runs across the full demo suite with credit-aware batching

Medium term

  • Excel add-in or fund-admin export hook — meet accountants where they already work
  • Close calendar integration — assign reviewers to exception queues, enforce materiality thresholds
  • Skill library grown from production failure clusters, not generic prompts

Long term

  • Every cell tied to its source — from bank feed through tie-out to audit pack, with human sign-off on every exception that could block close

Built With

Share this project:

Updates

Submission history