Build an AI agent on mykal
mykal's differentiator is that humans and AI agents collaborate on the same schedule. A reminder fires, your agent takes the action, and the task reaches "done" — all under the same audit trail a human would leave.
Architecture
Four moving parts: (1) mykal emits reminder.fired;
(2) your edge verifies the signature and enqueues; (3) a
worker runs the LLM prompt; (4) the agent calls back into
mykal with its result.
Register your agent endpoint
Your agent is a webhook receiver. Register it the same way a
human integrator would — see
Webhooks > Signing
for the full spec. The only twist is the task payload you'll
match on: set reminder_channels to include
"webhook" so the outbound signal is fired.
Authentication from your agent back to mykal
Your agent needs its own credentials to call mykal's API (mark tasks done, post sub-reminders, etc.). Two models:
- Agent-scoped API key (recommended): a long-lived bearer token tied to a service user with a narrow permission set — typically
MYKAL_TASK_READ,MYKAL_TASK_UPDATE,MYKAL_REMINDER_MANAGE. Currently request via support; the first-class UI for issuing keys is under construction. - Per-user impersonation: the same bearer flow a human uses. Fine for single-tenant prototypes. Subject to the user's quota.
Three patterns
Pattern A — Synchronous agent
Simplest. Receiver verifies signature → runs LLM inline → acts → returns 200. Works when the task fits a sub-10-second LLM call. Blocks the mykal retry loop if it doesn't — do not use for long-running workflows.
Pattern B — Queued agent
Receiver verifies → enqueues on Redis/SQS/Kafka → returns 200
immediately → worker pool drains and calls back. This is the
default production pattern. Use the delivery_id
as the queue's idempotency key so mykal retries don't
double-process.
Pattern C — Multi-step with human-in-the-loop
Same as Pattern B, plus the worker can escalate: instead of
completing the task itself, the agent creates a reminder on
the human user (POST tasks with
reminder_channels=["inapp","email"] and a short
deadline) asking for approval. If the human approves in-app,
your agent sees the approval via a task update poll or a
follow-on webhook you also subscribed to.
Acting back on tasks
| intent | endpoint |
|---|---|
| Mark task done after action | POST calendar/events/{id}/done |
| Skip this occurrence | POST calendar/events/{id}/skip |
| Unschedule + return to pending | DELETE calendar/events/{id} |
| Adjust task fields (priority, duration, deadline) | PATCH tasks/{id} |
| Ask for a re-schedule | POST schedule (task_ids, optional provider) |
| Manually override the slot | POST schedule/decisions/{id}/override |
| Create a follow-up reminder for the human | POST tasks with channels = inapp/email |
Errors & retries
- Receiver fails: return 5xx or take >10s. mykal retries per the DLQ schedule. Your agent must be idempotent on
delivery_id. - LLM call fails: don't bubble 5xx to mykal if you've already accepted — catch, enqueue a private retry, return 200.
- Quota breach: mykal responds 429 on
POST schedulewithX-Mykal-Quota-Resetheader pointing to next UTC midnight. Back off until then; send the human an inapp reminder so the user knows their schedule didn't regenerate. - Auth breaks mid-run: 401 from mykal → refresh the agent key and retry once; on second 401, DLQ + alert.
Cost considerations
- Your LLM bill is yours. If your receiver calls Anthropic/OpenAI directly, those tokens bill to your account, not mykal's.
- mykal's LLM quota is separate and only applies when you call mykal's built-in scheduler (
POST schedule). Caps default to $5 soft / $20 hard per user per day (see RATE_LIMITS.md). - Prompt-cache your prompts — most reminder payloads share a common system prompt; the Anthropic
cache_controlfield reduces cost ~90% on the cached prefix. - Batch the small stuff — if your agent gets a burst of reminders, coalesce them into one LLM call with a single system prompt and a list of tasks, then fan the results back out.
Full working example
A ~200-line Python agent that verifies a signed
reminder.fired webhook, decides what to do with
Anthropic Claude, and marks the task done — lives at
/mykal/developer-examples/python-agent/. It ships
with requirements.txt, .env.example,
and a README.
Run locally, expose via ngrok, register the tunnel as a webhook endpoint (see the quickstart), and fire a test ping. First real reminder triggers the Claude call.