Skip to content

About

Approval-gated automation for Taiwanese temple affairs, volunteer scheduling, and financial review.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

temple-operator

English · 繁體中文

Approval-gated automation for temple (宮廟) affairs. Registrations flow in, an AI collates them into offering/lamp lists and drafts the purchase orders and notices — but nothing money-facing or member-facing ships until a real person approves it. Every step is recorded in an immutable audit trail.

Runs on the Node.js 24 standard library with zero runtime dependencies — no native builds, no external services. git clone → pnpm dashboard.

Inspired by Morning Operator's human-in-the-loop model (approval gates · SQLite job queue · provider-neutral adapters · industry packs). This project applies that model to verticals Morning Operator doesn't cover — starting with Taiwanese temple ceremony operations — as a focused, runnable reference implementation.

It ships two packs on one engine (temple-affairs and volunteer-shifts) to demonstrate the point of the architecture: the domain lives in the packs, and the queue / gates / audit / adapters are generic.


Why this exists

Temple ceremonies (法會) generate a mountain of low-stakes-but-error-sensitive paperwork: totalling everyone's lamps and offerings, drafting purchase orders, sending payment notices. It's automatable — but you cannot let it run fully autonomous, because a wrong total or a notice sent to someone who never consented is a real-world trust failure.

So the design rule is: automation prepares, a human authorizes. The interesting engineering is everything that makes that safe and reliable — the gates, the queue, the audit trail, the escalation rules.

The flow

registrations
     │  collate  (AI adapter)
     ▼
 ┌─────────────────── GATE ① review-collation ───────────────────┐
 │  reviewer sees item totals, per-registrant breakdown, anomalies │
 └────────────────────────────┬──────────────────────────────────┘
        approved              │  fulfill
                              ▼
 ┌─────────────────── GATE ② approve-delivery ───────────────────┐
 │  purchase order + notice preview + recipient count             │
 │  ⚠ auto-escalated if a restricted-action rule fires            │
 └────────────────────────────┬──────────────────────────────────┘
        approved              │  deliver  (notify adapter)
                              ▼
                     notices sent · event done

Quickstart

pnpm install          # only dev deps (typescript); runtime is dependency-free
cp .env.example .env  # optional — sensible defaults built in
pnpm dashboard        # open http://127.0.0.1:4173

The dashboard is the interactive showcase: click 重新載入示範 to create one event from each pack, inspect what the automation prepared, then approve or reject each gate as a named reviewer. An approval resumes the queue automatically and stops again at the next human gate. Dedicated volunteer-roster and financial-control views preserve the operational details after approval; queue health, event progress, and the immutable audit trail update on the same screen.

For a terminal-only walkthrough, run pnpm demo. It drives both packs through the same approval flow using a scripted reviewer.

pnpm demo runs two different packs through the same engine: a 中元普渡法會 (temple-affairs) and a 志工排班 (volunteer-shifts). For each it drives the worker through both approval gates (auto-approving as a scripted reviewer) and sends notices via the console adapter. In between it enqueues a deliberately failing job to show retry-with-backoff → dead-letter, and finally prints each event's audit trail.

Other scripts:

command what it does
pnpm dashboard start the interactive human-review dashboard on port 4173
pnpm seed reset the DB and queue one ceremony's first job
pnpm worker run the long-lived worker loop (Ctrl-C to stop)
pnpm test run the queue/gate unit tests
pnpm typecheck tsc --noEmit

Architecture

Piece File Role
Job queue src/queue.ts enqueue / lease / complete / fail, with attempt leases (crash recovery), exponential backoff, and a dead-letter state
Approval gates src/approvals.ts open a gate → pipeline pauses → decide() resumes it
Audit log src/audit.ts append-only record of every state change, replayable per event
Web dashboard src/dashboard.ts + web/* local review queue, decisions, event progress, and audit activity
Engine (generic) src/engine.ts routes a job to the owning pack's handler; knows nothing about any domain
Pack registry src/registry.ts maps pack_id → handlers + advance logic
Pack — data packs/*.json the domain as reviewable data: gates, metrics, restricted & prohibited actions
Pack — code src/packs/*.ts that pack's job handlers and post-approval steps
Adapters src/adapters/* provider-neutral notify and ai — swap console→LINE or mock→Claude without touching business logic

Everything persists to a single SQLite file via Node 24's built-in node:sqlite.

Industry packs

A pack has two halves. The declarative half (packs/<id>.json) is static, reviewable data — a non-engineer can read it and see exactly what the system will and won't do:

  • gates — where a human must approve, and what they get to see
  • restricted_actions — tiny rules (purchase_order.total > 30000) that force an extra escalation instead of running automatically
  • prohibited_actions — things the system must never do (e.g. store full national ID numbers, send to non-consenting registrants)

The runtime half (src/packs/<id>.ts) registers that pack's job handlers.

Two packs ship as reference implementations:

pack domain pipeline
temple-affairs temple ceremony paperwork registrations → collate → gate → fulfill → gate → deliver
volunteer-shifts volunteer scheduling availability → roster → gate → dispatch → gate → notify

Adding a third vertical = write packs/<id>.json + src/packs/<id>.ts (calling registerPack) + one line in src/packs/index.ts. The engine, queue, gates, audit and adapters are untouched.

Production notes

The showcase is complete but intentionally offline: the console notify adapter prints instead of sending, and the mock AI adapter is deterministic with no network calls. Wiring NOTIFY_ADAPTER=line / AI_ADAPTER=anthropic (Claude claude-opus-4-8) behind the same interfaces is where real deployment begins.

License

Apache-2.0 — same as the project that inspired it.

About

Approval-gated automation for Taiwanese temple affairs, volunteer scheduling, and financial review.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages