Mental Model
Mental Model: How Requests Flow Through OnceOnly
Section titled “Mental Model: How Requests Flow Through OnceOnly”This page explains the mental model of how every request is processed by OnceOnly, from the agent’s perspective to the API gateway’s decision-making.
Simple Request: Check Lock (Idempotency)
Section titled “Simple Request: Check Lock (Idempotency)”An agent wants to execute an action and check if it’s a duplicate.
┌─────────────────────────────────────────┐│ Agent (Claude/GPT-4) ││ POST /v1/check-lock ││ key="payment_invoice_123" ││ ttl=3600 ││ metadata={...} │└────────────────────┬────────────────────┘ │ ┌──────────▼──────────┐ │ OnceOnly API │ │ Validation Layer │ └────────┬────────────┘ │ ┌──────────┴──────────┬──────────┐ ▼ ▼ ▼ ┌─────────┐ ┌──────────┐ ┌──────────┐ │Validate │ │Validate │ │Rate Limit│ │Request │ │API key │ │Check │ │Schema │ │(Bearer) │ │ │ └────┬────┘ └────┬─────┘ └────┬─────┘ │ │ │ └───────────┬───────┴─────────────┘ │ ┌──────────▼──────────────────────┐ │ Check Redis for existing lock │ │ key="lock:payment_invoice_123" │ └────────┬─────────────┬──────────┘ │ │ ┌─────────▼──┐ ┌────▼──────────┐ │Lock EXISTS │ │Lock DOESN'T │ │(duplicate) │ │EXIST (new) │ └──────┬─────┘ └────┬──────────┘ │ │ │ ▼ │ Create Redis lock │ key="lock:payment_invoice_123" │ TTL = 3600 seconds │ (expires after 1 hour) │ │ │ ┌────────▼────────┐ │ │Track usage │ │ │and metrics │ │ └────────┬────────┘ │ │ └────────┬───────┘ │ ┌────▼────────────────┐ │Return Response │ │status: "duplicate" or│ │status: "locked" │ └─────────────────────┘Response: First Call (New Action)
Section titled “Response: First Call (New Action)”{ "success": true, "status": "locked", "key": "payment_invoice_123", "ttl": 3600, "first_seen_at": null}→ Means: This is a new action. Safe to execute the payment.
Response: Second Call (Duplicate)
Section titled “Response: Second Call (Duplicate)”If you repeat the same request within 1 hour:
{ "success": false, "status": "duplicate", "key": "payment_invoice_123", "ttl": 3600, "first_seen_at": "2025-01-15T10:30:00Z"}→ Means: This action was already attempted. Don’t charge the customer again. Skip the side effect and return your own saved result if you have one.
Complex Request: AI Lease (Long-running Tasks)
Section titled “Complex Request: AI Lease (Long-running Tasks)”An agent starts a long task (e.g., customer support chat) and needs a “lease” to hold exclusive execution.
┌──────────────────────────────────────┐│ Agent ││ POST /v1/ai/lease ││ key="support_chat_001" ││ ttl=1800 (30 minutes) │└──────────────┬───────────────────────┘ │ ┌──────────▼─────────────┐ │OnceOnly AI Lease API │ │/v1/ai/lease │ └──────┬────────────────┘ │ ┌──────┴────────────┬──────────┐ ▼ ▼ ▼┌────────┐ ┌────────────┐ ┌──────────┐│Validate│ │Validate TTL│ │Rate Limit││API Key │ │and payload │ │Check ││ │ │ │ │ │└───┬────┘ └──────┬─────┘ └────┬─────┘ │ │ │ └──────────┬─────────┴─────────────┘ │ ┌──────▼──────────────────────┐ │Check Redis for existing │ │lease on key │ └──────┬──────────┬────────────┘ │ │ ┌──────▼──┐ ┌───▼──────────┐ │Lease/key│ │No lease yet │ │already │ │(new) │ │exists │ └───┬──────────┘ │ │ │ └───┬────┘ │ │ ▼ │ Create new lease: │ • Generate lease_id │ • Store in Redis │ • TTL = 1800 sec │ • Status = "in_progress" │ │ │ ┌────────┴────────┐ │ ▼ ▼ │ Read lease Return lease │ state info │ │ └───┴─────────────────┐ │ ┌─────────▼──────┐ │Return lease │ │info to agent │ └────────────────┘Response: Acquired (This Agent Owns the Lease)
Section titled “Response: Acquired (This Agent Owns the Lease)”{ "ok": true, "status": "acquired", "key": "support_chat_001", "lease_id": "lease_abc123xyz", "ttl": 1800, "first_seen_at": "2025-01-15T10:30:00Z"}→ Means: This agent has exclusive permission to run this task for the next 30 minutes.
Response: Polling (Another Agent Owns It)
Section titled “Response: Polling (Another Agent Owns It)”If another agent already acquired the lease:
{ "ok": true, "status": "polling", "key": "support_chat_001", "lease_id": "lease_abc123xyz", "ttl_left": 1750}→ Means: Another agent is already running this task. Don’t start it again. Wait for the other agent to finish.
If the same key already finished earlier, /v1/ai/lease can also return completed or failed instead of creating a new lease.
Status Checking During Execution
Section titled “Status Checking During Execution”Another process (or monitoring dashboard) wants to check progress:
┌──────────────────────────────────┐│ Monitor / Other Agent ││ GET /v1/ai/status?key=support... │└──────────────┬───────────────────┘ │ ┌──────────▼────────────┐ │Fetch from Redis │ │lease:support_chat_001 │ └──────┬────────────────┘ │ ┌────┴───────────────┐ │ │ ▼ ▼ ┌──────────────┐ ┌──────────────┐ │Lease found │ │Lease not │ │Status check │ │found │ │ │ │→ "not_found" │ └──┬──┬────────┘ └──────────────┘ │ │ │ └──────────────────────┐ ▼ ▼┌──────────┐ ┌──────────┐ ┌─────────┐│in_progress │completed │failed ││(ttl_left:500)│(done_at, │(error_ ││ │result_hash) │code) │└──────────────┴──────────────┴─────────┘Response (In Progress):
{ "ok": true, "status": "in_progress", "key": "support_chat_001", "lease_id": "lease_abc123xyz", "ttl_left": 1500}→ Means: The chat is still running. 25 minutes remaining.
Completing the Lease
Section titled “Completing the Lease”When the agent finishes the task:
┌──────────────────────────────┐│ Agent ││ POST /v1/ai/complete ││ key="support_chat_001" ││ lease_id="lease_abc123xyz" ││ result={...} │└──────────────┬───────────────┘ │ ┌──────────▼──────────────┐ │OnceOnly Complete API │ │/v1/ai/complete │ └──────┬───────────────────┘ │ ┌──────┴──────────┐ │ │ ▼ ▼┌──────────────┐ ┌────────────────┐│Verify owner │ │Verify lease ││(lease_id │ │exists & ││matches) │ │in_progress │└───┬──────────┘ └────────┬───────┘ │ │ └──────┬───────────────┘ │ ┌──────▼──────────────────┐ │Update lease state in │ │Redis: │ │• status = "completed" │ │• result_hash = "..." │ │• done_at = now │ │• TTL = 7 days │ └──────┬───────────────────┘ │ ┌──────▼──────────────────┐ │If `result` is provided, │ │store it separately for │ │`/v1/ai/result` │ └──────┬──────────────────┘ │ ▼ ┌──────────────────┐ │Return "completed"│ └──────────────────┘Response:
{ "ok": true, "status": "completed", "key": "support_chat_001", "version": 2}Now future requests to /v1/ai/status will return the completed state, and /v1/ai/result will return the stored payload only if one was provided during completion.
Failure Handling
Section titled “Failure Handling”If something goes wrong:
┌──────────────────────────┐│ Agent ││ POST /v1/ai/fail ││ key="support_chat_001" ││ lease_id="lease_abc123" ││ error_code="timeout" │└──────────────┬───────────┘ │ ┌──────────▼──────────────┐ │OnceOnly Fail API │ │/v1/ai/fail │ └──────┬──────────────────┘ │ ┌──────┴──────────┐ │ │ ▼ ▼┌──────────────┐ ┌────────────────┐│Verify owner │ │Verify lease ││(lease_id │ │exists & ││matches) │ │in_progress │└───┬──────────┘ └────────┬───────┘ │ │ └──────┬───────────────┘ │ ┌─────▼───────────────┐ │Store failed state: │ │• status = "failed" │ │• error_code │ │• done_at │ │• TTL = 7 days │ └──────┬──────────────┘ │ ▼ ┌──────────────┐ │Return failed │ └──────────────┘Response:
{ "ok": true, "status": "failed", "key": "support_chat_001", "version": 2}Policy Enforcement
Section titled “Policy Enforcement”When an agent tries to run an action, policies are checked:
┌──────────────────────────────────┐│ Agent ││ POST /v1/ai/run ││ agent_id="support_bot" ││ tool="send_email" ││ args={...} │└──────────────┬───────────────────┘ │ ┌──────────▼──────────────────┐ │OnceOnly Governed Tool │ │Execution Check │ └──────┬───────────────────────┘ │ ┌──────┴──────────────────────┐ │ │ ▼ ▼┌─────────────────────┐ ┌───────────────────┐│Check allowed_tools │ │Check blocked_tools││for "send_email" │ │for "send_email" ││Result: FOUND ✓ │ │Result: NOT FOUND ✓│└──────┬──────────────┘ └────────┬──────────┘ │ │ └──────────┬───────────────┘ │ ┌────────▼─────────────┐ │Check rate limit: │ │max=100/hour │ │used this hour: 95 │ │95 < 100 → Allow ✓ │ └────────┬─────────────┘ │ ┌────────▼──────────────┐ │Check budget: │ │remaining: $450 │ │estimated cost: $10 │ │$450 > $10 → Allow ✓ │ └────────┬──────────────┘ │ ┌────────▼───────────────┐ │Log decision: │ │decision="executed" │ │policy_reason="ok" │ └────────┬───────────────┘ │ ▼ ┌──────────────────────┐ │Execute tool and │ │return result │ └──────────────────────┘Response (Allowed):
{ "ok": true, "allowed": true, "decision": "executed", "policy_reason": "ok", "risk_level": "low", "result": {"status": "sent"}}Response (Blocked):
{ "ok": true, "allowed": false, "decision": "blocked", "policy_reason": "tool_not_in_allowed_list", "risk_level": "medium"}Audit Logging
Section titled “Audit Logging”Every action is logged for later review:
{ "ts": 1705324205, "agent_id": "support_bot", "tool": "send_email", "decision": "executed", "policy_reason": "ok", "risk_level": "low", "spend_usd": 0.05}Admin can query:
GET /v1/agents/support_bot/logs?limit=100→ [list of recent decisions for that agent]Request Flow Summary
Section titled “Request Flow Summary”1. Agent wants to do action ↓2. Call `/check-lock`, `/ai/lease`, or `/ai/run` ↓3. OnceOnly validates API key ↓4. Check duplicate/lease state or policy/tool permissions ↓5. Track the outcome ↓6. Return `locked`, `duplicate`, `acquired`, `polling`, `completed`, `failed`, `executed`, or `blocked` ↓7. Agent executes action (or skips if blocked) ↓8. If lease-based, agent later calls `/ai/complete` or `/ai/fail` ↓9. OnceOnly stores status/result ↓10. Other agents can call `/ai/status` or `/ai/result`Key Concepts Recap
Section titled “Key Concepts Recap”| Concept | Meaning |
|---|---|
| Lock | Redis-backed idempotency window with a request TTL |
| Lease | Redis-backed ownership for long tasks with extendable TTL |
| TTL | Time to live = how long the lock/lease blocks |
| Policy | Rules: which tools allowed, rate limits, budget |
| Audit | Log of all decisions with timestamps |
| Rate Limit | Max actions per agent per time period |
| Budget | Max USD spend per agent per time period |
Next, read Quickstart to integrate OnceOnly into your application.