🛎︎ Built for the Global AI Hackathon with Qwen Cloud

Innkeeper

The night audit finally sleeps.

Track 4 · Autopilot Agent — three ledgers in, evidence-cited verdicts out, a signed Merkle close every night.

Edy Cu · innkeeper.edycu.dev · github.com/edycutjong/innkeeper

02:00 · night audit
$ innkeeper run --night 2026-07-04 fetch → extract → match → adjudicate → gate → signed close

The hook

$6.67 tonight.
$2,300 by month-end.

The last time the inn let a "small" three-way discrepancy slide, that's what it grew into.

The problem · 12:40 AM

Three statements.
One exhausted innkeeper.

A husband-and-wife inn runs 14 rooms. Every night one of them stays up past midnight reconciling the PMS folios, the processor settlements, and the OTA's PDF statement — three systems that never quite agree.

  • PMS ledger — what the front desk thinks happened
  • Processor settlement — what the card terminal captured
  • OTA statement — an 8-pt PDF, commissions withheld at source

No controller, no audit team, no software budget. Just lost sleep — or lost money.

The solution

One command closes the night

innkeeper — real output, seeded night
$ innkeeper run --night 2026-07-04 2026-07-04: 39 txns · 10 matched · 12 mismatches → 11 auto-cleared, 1 queued close root d175694c4fd5427b… signed 689bcf7a1dbc… → QUEUE m-12 true_error/unposted_walkin $310.00 conf 0.60

Fetch → extract → match → adjudicate → expected-loss gatesigned Merkle close.

Confident mismatches clear themselves; only the material unknown reaches the owner's morning coffee.

Innkeeper hero panel — three ledgers reconciled into a signed night close

How it works

PDF in, signed close out

PMS foliosmcp/pms_server.py Processormcp/processor_server.py OTA statementreal rendered PDF · 8-pt tablemcp/ota_server.py VL extraction qwen3-vl-plus · two-pass t=0.0 / t=0.4 · bbox citations agree → confidence disagree → escalate (I5) 3-tier matcher ref_exact → fuzzy → amt+date deterministic · zero model calls clears ~77% of transactions Adjudicate residue qwen3.7-max + thinking typed Verdict · ≥2-system evidence · hypotheses · conf E[loss] gate amount × (1−conf) ≤ τ conf ≥ .85 ∧ ≤ $50 true_error → always queue queue → morning report Signed night-close Merkle root · Ed25519 chained to prev_root · replayable ChainI1–I4 ✓

The demo · two beats that matter

It clears $5.67 — and refuses $310

innkeeper run --night 2026-07-04 · real seeded output
m-07 AUTO-CLEAR fee/ota_commission conf 0.94 $189.00 gross − $183.33 payout = $5.67 = exactly 3% evidence: OTA statement line 7 bbox + sha256 · PMS folio-1042 m-12 QUEUE true_error/unposted_walkin $310.00 conf 0.60 h1 0.60 "room sold at the terminal, never posted" h2 0.40 "mis-keyed deposit or unlinked OTA capture" $ innkeeper replay --night 2026-07-04 replay 2026-07-04: IDENTICAL · root d175694c4fd5427b… signature reproduced
1bbox-cited to the PDF line
2true_error can never auto-clear
3byte-identical replay, zero keys

Key features

Invariants, tested — not promised

auto_clear conf ≥ 0.85 $50 true_error generalised: E[loss] = amount × (1−conf) ≤ τ τ-sweep 100¢ → 5000¢: false clears = 0, always

The risk knob τ trades automation against review load — without ever touching the safety floor.

  • I1 — zero false auto-clears on planted true errors, all 30 nights
  • I2 — every verdict cites ≥2 systems, sha256-resolvable
  • I3 — one-byte tamper anywhere fails verify-chain
  • I4 — replay reproduces verdicts, root, signature byte-for-byte
  • I5 — two-pass extraction disagreement escalates, never averages

Why Qwen Cloud — specifically

Remove Qwen, and this needs three vendors

  • qwen3-vl-plus — reads the 8-pt OTA table with bbox citations per figure; otherwise: a document-AI vendor bill, and no evidence highlight
  • Two-pass VL agreement — agreement = confidence, disagreement = escalation; otherwise: single-pass misreads corrupt money decisions silently
  • qwen3.7-max + thinking — ranks competing hypotheses over evidence; otherwise: the first plausible story wins
  • Structured output — the E[loss] gate computes over typed fields; free-text verdicts can't be gated, benched, or replayed
  • Function calling · 3× MCP — typed, logged tool calls are the replayable decision log

A 14-room inn will never pay for a document-AI vendor, a frontier LLM, and an orchestration framework — or get a single-vendor trail it can sign into the books.

Traction — shipped, verifiable

Built solo. Green everywhere.

277/281
auto-cleared · 30 nights
0
false clears — invariant
404
tests · 100% coverage
0.9964
classification accuracy
  • 5-stage CI: quality → security → build → offline proof → gate
  • CodeQL · Dependabot · pip-audit · TruffleHog — all green
  • MIT-licensed, including 3 reusable seedable MCP mock servers
  • Honest: PMS/processor/OTA are disclosed in-repo mocks
  • Honest: offline runs use deterministic FakeQwen; --live is key-gated
  • Honest: the 02:00 FC timer is configured (infra/fc/), not deployed

The ask

Run it. Five minutes,
zero keys.

$ git clone https://github.com/edycutjong/innkeeper $ pip install -e ".[dev]" && innkeeper seed --nights 30 $ innkeeper run --night 2026-07-04 # then replay · bench · pytest

Watch the $310 unknown refuse to auto-clear, then re-derive the whole night byte-for-byte. Judge the receipts, not the promises.

innkeeper.edycu.dev · github.com/edycutjong/innkeeper · Edy Cu — solo builder

Innkeeper — the night audit finally sleeps: brand panel with service bell and signed-ledger motif

The night auditor finally sleeps.

←/→ · SPACE · ESC grid · P notes · C contrast 01 / 10
Speaker notes