gyeoljae
v0.2.0-rc.1
Published
Human-in-the-loop approval bridge between your ops ledger and your messenger
Maintainers
Readme
gyeoljae (결재)
Human-in-the-loop approval bridge between your ops ledger and your messenger.
Gyeoljae is the Korean ritual of getting the boss's stamp before work proceeds. This service does exactly that for agent-driven operations: agents file their work in a ledger, humans approve from chat, and nothing high-risk moves without a recorded sign-off.
Status: early. Extracted from a private operating system where a Ruby shadow implementation has been running in production since day one. The Ruby test suite serves as the golden spec for this TypeScript port.
Release candidate:
v0.2.0-rc.1packages the library andpoll/listen/watchCLIs. Public envelopes strip both source text andredacted_textafter PR #13.
Why
If you run autonomous agents against real infrastructure, you learn two things quickly:
- Every intake must land in the ledger before anything acts on it. An agent that crashes after reading a message loses the message; a bridge that records first degrades to "recorded but unprocessed."
- Approvals belong in chat, but authority belongs in the ledger. Humans live in Slack; the source of truth cannot.
gyeoljae is the thin, deterministic piece between the two. It is deliberately not an agent: it never interprets content, credentials are isolated from agents and read only by the bridge process, and anything ambiguous degrades to needs-human — never to silent progress.
Architecture
chat (Slack, ...) ──inbound──▶ sanitized envelope ──▶ ledger (record first)
│
router: routine │ agent-required │ needs-human
│
ledger events (approval needed, done) ──outbound──▶ chat notification
human reply ("approve") ──inbound──▶ validated ──▶ ledger record ──▶ agent resumesCore rules, enforced in code:
text_excerptis always null in shadow mode; file refs are metadata-only (id, name, mime, size, hash). Contents are never read.- Every envelope has an idempotent
dedup_key; replays and retries create no duplicates. - Notification delivery is deduplicated at-least-once by default (a crash after a remote send but before the checkpoint can repeat). Back the notifier with an
Outboxfor explicit pending → sending → sent state (events enqueued durably before the ledger transition), stored receipts, reconciliation of the post crash window, and a drain that retries sends whose items have already left the open set. - Outage recovery is replay from chat history after the last acknowledged timestamp — no durable queue to babysit.
- Message edits keep their identity: same
dedup_key, recordededited_ts, incrementedversion. - Notifications carry ledger refs and statuses, never content.
Adapters
| Kind | Built-in | Bring your own |
| --- | --- | --- |
| Chat | Slack polling + Socket Mode listener (shipped; live writes deployment-gated) | ChatAdapter interface; multi-channel fan-out via Apprise planned |
| Ledger | GitHub Issues (shipped) | LedgerAdapter interface |
The original deployment uses a private ledger (Paperclip) through the same adapter interface.
Development
npm install
npm test
npm run check:sanitize
npm run smoke:packageThe package is ESM-only. Use import; CommonJS require() is not part of the v0.2.0-rc.1 package contract.
Docs
- Getting started — mental model, library usage, invariants
- Cookbook — wiring AI agents into the approval loop, end-to-end deployment recipes
- Token-file hardening — ownership, permissions, symlink checks, and rotation
- Local JSON state — required single-writer deployment contract
- Release notes — Developer Preview limitations and upgrade notes
Roadmap
- [x] Core: envelope builder, classifier (ported, golden-spec tested)
- [x] Shadow store + replay planner port
- [x] Slack inbound poller (one-shot, cron/launchd friendly)
- [x] Redaction pipeline port (redaction_status/manifest envelope fields)
- [x] Outbound notifier (ledger → chat) with nudge endpoint for low-latency approval requests
- [x] Slack Socket Mode listener for real-time approval replies (live shadow rollout gated per deployment)
- [x] GitHub Issues ledger adapter
- [x] Docker packaging
License
MIT
