Public
AI mailroom propose/commit action-gate agent
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
A single public HTTPS endpoint implementing the propose → commit action-gate protocol for an AI mailroom triage agent.
POST / (this val's main.ts)
Both operations go to the same URL, selected by the JSON body's operation field.
Rendering mermaid diagram...
- main.ts — HTTP entrypoint. Parses the envelope, dispatches
propose/commit, enforces response size/content-type rules, and owns the idempotency/replay/conflict state machine. - lib/validate.ts — structural request validation (before any AI/tool work) plus per-action frozen target/payload shape validation and evidence-lineId checking for model output.
- lib/db.ts — SQLite persistence: one row per
evaluationId(propose state, stored response, commit state, stored response) and adossier_cachetable keyed by canonical dossier content hash so repeat Checks/Saves over the same 64 stable dossiers cost no model call. - lib/ai.ts — the only layer that calls a model. Uses Val Town's free
std/openaiproxy by default (gpt-5.4-nano), or your ownOPENAI_API_KEYif set. Batches every uncached dossier from oneproposecall into a single chat completion. - lib/verify.ts — Ed25519 signature verification (
@noble/ed25519) over the exact canonical receipt-verification message shape from the spec. - lib/canonical.ts — recursively key-sorted, compact JSON canonicalization and SHA-256 hex
hashing, shared by
inputDigest,proposalDigest, and cache keys.
- Idempotency: keyed by
evaluationId. An exact replay (same canonicaldossiers→ sameinputDigest) returns the stored response byte-for-byte with no model call. A reusedevaluationIdwith different content returns409 IDEMPOTENCY_CONFLICT. - Caching: each dossier's decision is cached by
sha256(canonical(dossier)), independent ofevaluationId/batch. A cache hit reuses the samecallId(derived ascall-<contentHash>), so stable dossiers produce byte-identical proposals across evaluations and later Checks. - Commit validation: every receipt must reference a
callIdthat exists in the stored proposal set, with matchingdossierId,action, andproposalDigest; every signature is verified against thereceiptVerifierstored from the matchingproposecall. The whole commit is rejected (no partial effects) if any receipt fails these checks — checked before any outcome is recorded. - Terminal state: once
completed, the evaluation is immutable. A byte-identical commit replay returns the same stored response; a commit with different receipts returns409 ALREADY_COMPLETED. - Safety: the system prompt treats all dossier content as untrusted data, instructs the model
to
quarantine_itemon prompt-injection / tool-control / exfiltration attempts, and every proposal is independently re-validated in code against the frozen per-action target/payload shapes and evidence-lineId rules — a decision that doesn't parse or match the schema falls back to a saferequest_confirmation, never an outbound or record-changing action.
By default this val uses Val Town's free hosted OpenAI proxy (no key required). To use your own OpenAI account instead (e.g. to raise rate limits), set:
OPENAI_API_KEY— your OpenAI API key.OPENAI_MODEL— override the model (defaults togpt-5.4-nano).
👉 Add OPENAI_API_KEY here: https://www.val.town/x/kumar49/mailroom-action-gate/environment-variables?key=OPENAI_API_KEY