@aitne-sh/aitne 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +464 -0
  3. package/agent-assets/agent-profiles/_safety.md +26 -0
  4. package/agent-assets/agent-profiles/conversational.md +33 -0
  5. package/agent-assets/agent-profiles/docs-qa.md +24 -0
  6. package/agent-assets/agent-profiles/observer.md +28 -0
  7. package/agent-assets/agent-profiles/profile-importer.md +63 -0
  8. package/agent-assets/agent-profiles/proxy.md +28 -0
  9. package/agent-assets/agent-profiles/routine.md +16 -0
  10. package/agent-assets/agent-profiles/task.md +18 -0
  11. package/agent-assets/docs/concepts/agent-day.md +88 -0
  12. package/agent-assets/docs/concepts/auth-health.md +75 -0
  13. package/agent-assets/docs/concepts/backends-and-tiers.md +126 -0
  14. package/agent-assets/docs/concepts/costs-and-quotas.md +103 -0
  15. package/agent-assets/docs/concepts/delegated-mode.md +223 -0
  16. package/agent-assets/docs/concepts/memory-model.md +118 -0
  17. package/agent-assets/docs/concepts/observations.md +80 -0
  18. package/agent-assets/docs/concepts/process-keys.md +89 -0
  19. package/agent-assets/docs/concepts/routines.md +108 -0
  20. package/agent-assets/docs/concepts/safety-and-execution.md +109 -0
  21. package/agent-assets/docs/concepts/safety-model.md +279 -0
  22. package/agent-assets/docs/concepts/skills.md +100 -0
  23. package/agent-assets/docs/features/integrations/calendar.md +92 -0
  24. package/agent-assets/docs/features/integrations/git.md +95 -0
  25. package/agent-assets/docs/features/integrations/github.md +170 -0
  26. package/agent-assets/docs/features/integrations/mail.md +106 -0
  27. package/agent-assets/docs/features/integrations/notion.md +69 -0
  28. package/agent-assets/docs/features/integrations/obsidian.md +71 -0
  29. package/agent-assets/docs/features/lifestyle/git.md +178 -0
  30. package/agent-assets/docs/features/lifestyle/reading.md +93 -0
  31. package/agent-assets/docs/features/lifestyle/receipts.md +71 -0
  32. package/agent-assets/docs/features/lifestyle/travel-bookings.md +44 -0
  33. package/agent-assets/docs/features/lifestyle/travel-time.md +52 -0
  34. package/agent-assets/docs/features/memory-files/agent-journal.md +105 -0
  35. package/agent-assets/docs/features/memory-files/projects.md +56 -0
  36. package/agent-assets/docs/features/memory-files/roadmap.md +61 -0
  37. package/agent-assets/docs/features/memory-files/schedule.md +112 -0
  38. package/agent-assets/docs/features/memory-files/today.md +73 -0
  39. package/agent-assets/docs/features/memory-files/user-profile.md +81 -0
  40. package/agent-assets/docs/features/messaging/dashboard-chat.md +93 -0
  41. package/agent-assets/docs/features/messaging/discord.md +50 -0
  42. package/agent-assets/docs/features/messaging/overview.md +111 -0
  43. package/agent-assets/docs/features/messaging/pairing-and-magic-phrase.md +69 -0
  44. package/agent-assets/docs/features/messaging/slack.md +51 -0
  45. package/agent-assets/docs/features/messaging/telegram.md +63 -0
  46. package/agent-assets/docs/features/messaging/whatsapp.md +48 -0
  47. package/agent-assets/docs/features/operations/activity-and-conversations.md +105 -0
  48. package/agent-assets/docs/features/operations/approvals.md +58 -0
  49. package/agent-assets/docs/features/operations/backend-routing.md +62 -0
  50. package/agent-assets/docs/features/operations/cost-tracking.md +59 -0
  51. package/agent-assets/docs/features/operations/notifications.md +69 -0
  52. package/agent-assets/docs/features/operations/quiet-hours.md +106 -0
  53. package/agent-assets/docs/features/operations/schedule-approaching.md +60 -0
  54. package/agent-assets/docs/features/routines/custom-routines.md +101 -0
  55. package/agent-assets/docs/features/routines/evening-review.md +81 -0
  56. package/agent-assets/docs/features/routines/hourly-check.md +85 -0
  57. package/agent-assets/docs/features/routines/monthly-review.md +65 -0
  58. package/agent-assets/docs/features/routines/morning-routine.md +123 -0
  59. package/agent-assets/docs/features/routines/weekly-review.md +70 -0
  60. package/agent-assets/docs/getting-started/01-what-is-this.md +192 -0
  61. package/agent-assets/docs/getting-started/02-first-steps.md +80 -0
  62. package/agent-assets/docs/getting-started/03-what-can-this-do.md +110 -0
  63. package/agent-assets/docs/getting-started/04-first-day.md +287 -0
  64. package/agent-assets/docs/glossary.md +116 -0
  65. package/agent-assets/docs/guides/add-a-custom-routine.md +71 -0
  66. package/agent-assets/docs/guides/backup-and-restore.md +54 -0
  67. package/agent-assets/docs/guides/change-which-model-handles-x.md +47 -0
  68. package/agent-assets/docs/guides/connect-a-new-mail-account.md +59 -0
  69. package/agent-assets/docs/guides/import-knowledge-file.md +275 -0
  70. package/agent-assets/docs/guides/install-and-run.md +72 -0
  71. package/agent-assets/docs/guides/migrate-machines.md +52 -0
  72. package/agent-assets/docs/guides/pause-the-agent.md +65 -0
  73. package/agent-assets/docs/guides/reinstall-cleanly.md +52 -0
  74. package/agent-assets/docs/guides/setup-wizard.md +107 -0
  75. package/agent-assets/docs/guides/switch-default-backend.md +60 -0
  76. package/agent-assets/docs/reference/api.md +51 -0
  77. package/agent-assets/docs/reference/cli-commands.md +121 -0
  78. package/agent-assets/docs/reference/config.md +74 -0
  79. package/agent-assets/docs/reference/disallowed-tools.md +76 -0
  80. package/agent-assets/docs/reference/keyboard-shortcuts.md +39 -0
  81. package/agent-assets/docs/reference/process-keys.md +59 -0
  82. package/agent-assets/docs/reference/skills.md +50 -0
  83. package/agent-assets/docs/troubleshooting/auth-failed.md +57 -0
  84. package/agent-assets/docs/troubleshooting/dashboard-shows-degraded.md +55 -0
  85. package/agent-assets/docs/troubleshooting/fallback-keeps-firing.md +54 -0
  86. package/agent-assets/docs/troubleshooting/messaging-not-pairing.md +53 -0
  87. package/agent-assets/docs/troubleshooting/morning-routine-didnt-run.md +75 -0
  88. package/agent-assets/docs/troubleshooting/observation-not-detected.md +57 -0
  89. package/agent-assets/docs/troubleshooting/quota-exhausted.md +57 -0
  90. package/agent-assets/optimizer-skills/drift-analysis/SKILL.md +75 -0
  91. package/agent-assets/optimizer-skills/knowledge-map/SKILL.md +71 -0
  92. package/agent-assets/optimizer-skills/skill-curation/SKILL.md +108 -0
  93. package/agent-assets/project-doc-templates/git-repo.md +21 -0
  94. package/agent-assets/project-doc-templates/project.md +38 -0
  95. package/agent-assets/skills/attach/SKILL.md +104 -0
  96. package/agent-assets/skills/context/SKILL.md +257 -0
  97. package/agent-assets/skills/context/curation.json +37 -0
  98. package/agent-assets/skills/context/seeds/file-responsibilities.seed.json +13 -0
  99. package/agent-assets/skills/context/seeds/frontmatter-requirements.seed.json +40 -0
  100. package/agent-assets/skills/docs-search/SKILL.md +176 -0
  101. package/agent-assets/skills/external-services/SKILL.delegated.claude.md +369 -0
  102. package/agent-assets/skills/external-services/SKILL.delegated.codex.md +349 -0
  103. package/agent-assets/skills/external-services/SKILL.delegated.gemini.md +347 -0
  104. package/agent-assets/skills/external-services/SKILL.md +371 -0
  105. package/agent-assets/skills/mail/SKILL.delegated.claude.md +284 -0
  106. package/agent-assets/skills/mail/SKILL.delegated.codex.md +261 -0
  107. package/agent-assets/skills/mail/SKILL.delegated.gemini.md +255 -0
  108. package/agent-assets/skills/mail/SKILL.md +313 -0
  109. package/agent-assets/skills/mail/references/errors.md +17 -0
  110. package/agent-assets/skills/mail/references/providers.md +40 -0
  111. package/agent-assets/skills/mail/references/query-grammar.md +24 -0
  112. package/agent-assets/skills/management-policy/SKILL.md +307 -0
  113. package/agent-assets/skills/management-policy/curation.json +13 -0
  114. package/agent-assets/skills/management-policy/seeds/policy-file-shape.seed.json +16 -0
  115. package/agent-assets/skills/management-task-modify/SKILL.md +202 -0
  116. package/agent-assets/skills/management-task-register/SKILL.md +330 -0
  117. package/agent-assets/skills/management-task-stop/SKILL.md +166 -0
  118. package/agent-assets/skills/notify/SKILL.md +196 -0
  119. package/agent-assets/skills/notion/SKILL.delegated.claude.md +254 -0
  120. package/agent-assets/skills/notion/SKILL.delegated.codex.md +195 -0
  121. package/agent-assets/skills/notion/SKILL.delegated.gemini.md +194 -0
  122. package/agent-assets/skills/notion/SKILL.md +86 -0
  123. package/agent-assets/skills/observations/SKILL.md +234 -0
  124. package/agent-assets/skills/observations/curation.json +13 -0
  125. package/agent-assets/skills/observations/seeds/source-namespacing.seed.json +20 -0
  126. package/agent-assets/skills/project-doc/SKILL.md +86 -0
  127. package/agent-assets/skills/project-doc/curation.json +21 -0
  128. package/agent-assets/skills/project-doc/seeds/project-shape.seed.json +25 -0
  129. package/agent-assets/skills/project-doc/seeds/slug-grammar.seed.json +20 -0
  130. package/agent-assets/skills/reading/SKILL.md +198 -0
  131. package/agent-assets/skills/reading/references/reading-taste.md +197 -0
  132. package/agent-assets/skills/receipts/SKILL.md +134 -0
  133. package/agent-assets/skills/roadmap/SKILL.md +276 -0
  134. package/agent-assets/skills/roadmap/curation.json +13 -0
  135. package/agent-assets/skills/roadmap/references/horizon-tags.md +40 -0
  136. package/agent-assets/skills/roadmap/references/preparation-timeline.md +47 -0
  137. package/agent-assets/skills/roadmap/seeds/entry-types.seed.json +16 -0
  138. package/agent-assets/skills/schedule/SKILL.md +228 -0
  139. package/agent-assets/skills/scheduled-managed-task/SKILL.md +392 -0
  140. package/agent-assets/skills/today/SKILL.md +198 -0
  141. package/agent-assets/skills/today/curation.json +21 -0
  142. package/agent-assets/skills/today/seeds/agent-notes-flavors.seed.json +17 -0
  143. package/agent-assets/skills/today/seeds/section-shape.seed.json +17 -0
  144. package/agent-assets/skills/travel/SKILL.md +132 -0
  145. package/agent-assets/skills/travel-time/SKILL.md +149 -0
  146. package/agent-assets/skills/user-interview/SKILL.md +323 -0
  147. package/agent-assets/skills/user-interview/references/sweep-and-fallback.md +94 -0
  148. package/agent-assets/skills/user-profile/SKILL.md +210 -0
  149. package/agent-assets/skills/user-profile/curation.json +29 -0
  150. package/agent-assets/skills/user-profile/seeds/learned-context-format.seed.json +14 -0
  151. package/agent-assets/skills/user-profile/seeds/routing-table.seed.json +53 -0
  152. package/agent-assets/skills/user-profile/seeds/topic-files.seed.json +27 -0
  153. package/agent-assets/task-flows/dashboard.docs_qa.md +43 -0
  154. package/agent-assets/task-flows/default.md +11 -0
  155. package/agent-assets/task-flows/git.branch.created.md +25 -0
  156. package/agent-assets/task-flows/git.lifecycle.poll.md +52 -0
  157. package/agent-assets/task-flows/git.local_ahead.stale.md +34 -0
  158. package/agent-assets/task-flows/git.merge_to_default.md +30 -0
  159. package/agent-assets/task-flows/git.project.refresh_architecture.md +100 -0
  160. package/agent-assets/task-flows/git.project.retemplate.md +73 -0
  161. package/agent-assets/task-flows/git.push.detected.md +32 -0
  162. package/agent-assets/task-flows/git.push.force_pushed.md +36 -0
  163. package/agent-assets/task-flows/git.tag.created.md +24 -0
  164. package/agent-assets/task-flows/github.assigned.md +43 -0
  165. package/agent-assets/task-flows/github.pull_request.review_requested.md +57 -0
  166. package/agent-assets/task-flows/github.security_alert.md +45 -0
  167. package/agent-assets/task-flows/github.workflow_run.failed.md +57 -0
  168. package/agent-assets/task-flows/knowledge.import.md +161 -0
  169. package/agent-assets/task-flows/message.received.dm.md +142 -0
  170. package/agent-assets/task-flows/message.received.dm_first.md +117 -0
  171. package/agent-assets/task-flows/message.received.md +14 -0
  172. package/agent-assets/task-flows/routine.custom.md +38 -0
  173. package/agent-assets/task-flows/routine.evening_review.md +323 -0
  174. package/agent-assets/task-flows/routine.hourly_check.delegated.claude.md +405 -0
  175. package/agent-assets/task-flows/routine.hourly_check.delegated.codex.md +400 -0
  176. package/agent-assets/task-flows/routine.hourly_check.delegated.gemini.md +404 -0
  177. package/agent-assets/task-flows/routine.hourly_check.md +184 -0
  178. package/agent-assets/task-flows/routine.hourly_check.triage.md +93 -0
  179. package/agent-assets/task-flows/routine.monthly_review.md +250 -0
  180. package/agent-assets/task-flows/routine.morning_routine.md +300 -0
  181. package/agent-assets/task-flows/routine.morning_routine_initial.md +184 -0
  182. package/agent-assets/task-flows/routine.roadmap_refresh.md +275 -0
  183. package/agent-assets/task-flows/routine.today_refresh.md +172 -0
  184. package/agent-assets/task-flows/routine.user_profile_sweep.md +242 -0
  185. package/agent-assets/task-flows/routine.weekly_review.md +247 -0
  186. package/agent-assets/task-flows/schedule.approaching.md +124 -0
  187. package/agent-assets/task-flows/scheduled.dm.md +391 -0
  188. package/agent-assets/task-flows/scheduled.task.md +141 -0
  189. package/agent-assets/task-flows/setup.initial.md +277 -0
  190. package/agent-assets/task-flows/setup.update.md +53 -0
  191. package/agent-assets/templates/README.md +85 -0
  192. package/agent-assets/templates/_index.md +39 -0
  193. package/agent-assets/templates/_manifest.json +103 -0
  194. package/agent-assets/templates/agent/journal.md +10 -0
  195. package/agent-assets/templates/agent/profile-questions.md +74 -0
  196. package/agent-assets/templates/context-index.md +42 -0
  197. package/agent-assets/templates/dossiers/_index.md +22 -0
  198. package/agent-assets/templates/dossiers/evening.md +23 -0
  199. package/agent-assets/templates/dossiers/hourly.md +23 -0
  200. package/agent-assets/templates/dossiers/monthly.md +23 -0
  201. package/agent-assets/templates/dossiers/morning.md +23 -0
  202. package/agent-assets/templates/dossiers/roadmap.md +23 -0
  203. package/agent-assets/templates/dossiers/weekly.md +23 -0
  204. package/agent-assets/templates/projects/_active.base +14 -0
  205. package/agent-assets/templates/projects/_index.md +29 -0
  206. package/agent-assets/templates/roadmap.md +15 -0
  207. package/agent-assets/templates/routines/_index.md +20 -0
  208. package/agent-assets/templates/routines/evening.md +22 -0
  209. package/agent-assets/templates/routines/hourly.md +30 -0
  210. package/agent-assets/templates/routines/monthly.md +25 -0
  211. package/agent-assets/templates/routines/morning.md +26 -0
  212. package/agent-assets/templates/routines/weekly.md +23 -0
  213. package/agent-assets/templates/rules/_index.md +19 -0
  214. package/agent-assets/templates/rules/journal-export.md +41 -0
  215. package/agent-assets/templates/rules/journal-format.md +61 -0
  216. package/agent-assets/templates/rules/management.md +48 -0
  217. package/agent-assets/templates/rules/mcp.md +40 -0
  218. package/agent-assets/templates/rules/policies/_index.md +22 -0
  219. package/agent-assets/templates/rules/redaction.md +30 -0
  220. package/agent-assets/templates/today.md +13 -0
  221. package/agent-assets/templates/user/_index.md +16 -0
  222. package/agent-assets/templates/user/expertise.md +7 -0
  223. package/agent-assets/templates/user/goals.md +7 -0
  224. package/agent-assets/templates/user/people.md +7 -0
  225. package/agent-assets/templates/user/personal.md +7 -0
  226. package/agent-assets/templates/user/profile.md +28 -0
  227. package/agent-assets/templates/user/work.md +7 -0
  228. package/bin/aitne.mjs +1096 -0
  229. package/package.json +78 -0
  230. package/personal-agent.mjs +39 -0
  231. package/scripts/browser.mjs +99 -0
  232. package/scripts/check-redaction-coverage.mjs +109 -0
  233. package/scripts/commands/audit.mjs +309 -0
  234. package/scripts/commands/doctor.mjs +437 -0
  235. package/scripts/commands/open.mjs +40 -0
  236. package/scripts/commands/setup.mjs +21 -0
  237. package/scripts/commands/uninstall.mjs +114 -0
  238. package/scripts/commands/update.mjs +96 -0
  239. package/scripts/commands/version.mjs +62 -0
  240. package/scripts/commands.md +0 -0
  241. package/scripts/lib/sqlite-loader.mjs +49 -0
  242. package/scripts/message-discipline-digest.mjs +535 -0
  243. package/scripts/poc/google-connector-inheritance/REPORT.md +197 -0
  244. package/scripts/poc/google-connector-inheritance/claude-sdk-probe.mjs +79 -0
  245. package/scripts/remint-roadmap-ids.mjs +257 -0
  246. package/scripts/rm-paths.mjs +22 -0
  247. package/scripts/run-node.mjs +223 -0
  248. package/scripts/smoke-obsidian-api.mjs +166 -0
  249. package/scripts/start.mjs +160 -0
@@ -0,0 +1,371 @@
1
+ ---
2
+ name: external-services
3
+ description: Load for calendar work (Google Calendar, Outlook Calendar, OR Apple Calendar / iCloud), the user's external Obsidian vault, GitHub, or user-authored Skills management. Mail lives in `mail`; Notion in `notion`; one-shot and recurring scheduling in `schedule`.
4
+ allowed-tools:
5
+ - Bash(curl *)
6
+ - Bash(jq *)
7
+ - Read
8
+ ---
9
+
10
+ # External Services API Reference
11
+
12
+ Base URL: `http://localhost:8321`. All calls via `curl -s` with `Content-Type: application/json` on POST/PATCH/PUT. URL-encode spaces in paths.
13
+
14
+ ## Source of Truth (READ THIS FIRST)
15
+
16
+ Two adjacent files declare where the user's data lives — read both before
17
+ routing any external-service call.
18
+
19
+ 1. **`rules/management.md` → `## Source of Truth`** carries durable
20
+ user-authored answers ("Schedule = Google Calendar", "Tasks = Notion",
21
+ etc.). This is the authoritative routing table.
22
+ 2. **`~/.personal-agent/integrations.md` → `## Note Sources`** is the
23
+ daemon-rendered snapshot of where notes are kept (the user's external
24
+ Obsidian vault, plus Notion's mode). When the user asks "check
25
+ obsidian", this section names the path under
26
+ `Obsidian vault (personal): <path>` — use that path with the Obsidian
27
+ skill below. Hand-edits to this section are overwritten on the next
28
+ render; the canonical edit surface is the Note step in setup or
29
+ Settings → Note.
30
+
31
+ The Note Sources block is **read-only** — it advertises configuration
32
+ that lives in `runtime_settings.externalObsidianVaultPath` plus the
33
+ integrations DB. Treat it as a routing hint, not a knob.
34
+
35
+ ### Calendar provider routing
36
+
37
+ The user's calendar provider lives in `rules/management.md` → `## Source of Truth` → Schedule row. Read it before every calendar call.
38
+
39
+ | Schedule value in management rules | Use this base path | Backed by |
40
+ |---|---|---|
41
+ | `Google Calendar` | `/api/calendar/*` | Google Calendar API |
42
+ | `Outlook Calendar` | `/api/calendar/outlook/*` | Microsoft Graph |
43
+ | `Apple Calendar` (or `iCloud`) | `/api/apple-calendar/*` | iCloud CalDAV |
44
+
45
+ **Hard rule**: NEVER cross-call. Calling `/api/calendar/*` while Schedule = Apple Calendar does NOT return empty — it queries the user's separate Google account if one exists, returning the wrong day. Calling `/api/apple-calendar/*` while Schedule = Google Calendar returns 503. Both failure modes are silent at the agent level — only the user notices, in the form of wrong answers.
46
+
47
+ If `rules/management.md` is missing, ambiguous, or names a provider not listed here, **stop and ask the user** rather than guessing. Do not default to Google.
48
+
49
+ The endpoint sets are intentionally near-identical in shape (same JSON for events, same query parameters for listing) so the rest of this skill body documents both at once. Provider-specific differences are flagged inline with **[Apple only]** or **[Google only]**.
50
+
51
+ ## Delegation-aware routing for Google Calendar (read before any `/api/calendar/*` call)
52
+
53
+ This body is materialized only in direct mode and same-backend Calendar
54
+ delegation. (Cross-backend Calendar delegation pulls
55
+ `SKILL.delegated.<backend>.md` instead — that variant has its own
56
+ routing prose.) Only **Google Calendar** in this skill is
57
+ integration-gated; Obsidian, GitHub, recurring-schedule CRUD, one-shot
58
+ scheduling, and Skills CRUD remain direct-mode routes regardless of
59
+ Calendar's mode.
60
+
61
+ Read the `<integration_modes>` block injected above. If
62
+ `google_calendar="delegated"` (same-backend), the entire
63
+ `/api/calendar/*` prefix returns `410 {"error": "integration_delegated"}`
64
+ (route-prefix gate). Use the connector tools your session already holds
65
+ natively — `mcp__claude_ai_Google_Calendar__*` (Claude session) or
66
+ `mcp__codex_apps__google_calendar._*` (Codex session).
67
+
68
+ The Calendar section below documents the direct-mode route shapes;
69
+ consult it for tool argument shapes (native MCP tools mirror the route
70
+ JSON), then dispatch through the native connector when delegated or the
71
+ direct route when not.
72
+
73
+ ## Shell rules (read before writing curl pipelines)
74
+
75
+ - **JSON post-processing: use `jq`, never `python3`.** `python3` is not in the daemon's allowlist, so `curl ... | python3 -c ...` is denied under `permissionMode: "dontAsk"` and the call silently fails. Use `jq` for all field extraction, filtering, and pretty-printing.
76
+ - **`jq` is restricted**: `--slurpfile`, `--rawfile`, `-L`, and the `env` filter are blocked by the security hook (arbitrary file read / process environment exfiltration). Use only the filter language itself: `.field`, `.array[]`, `select()`, `map()`, `{a, b}`, etc.
77
+ - **`curl` is restricted to `http://localhost:8321`**: connection-override flags (`--connect-to`, `--resolve`, `--config`, `--proxy`) and non-localhost hosts are blocked by the security hook.
78
+ - **For a bare pretty-print**: `curl -s http://localhost:8321/api/health | jq .`
79
+
80
+ ---
81
+
82
+ <!-- service:calendar -->
83
+ ## Calendar
84
+
85
+ Google Calendar proxy. Operates on the user's primary calendar (configurable via `calendarId` param).
86
+
87
+ **Timezone rule**: Always include a TZ offset in `start`/`end` dateTime values (e.g. `-04:00`). All-day events use `YYYY-MM-DD` (no TZ needed).
88
+
89
+ **Event status**: GET returns deleted events with `status: "cancelled"` (200, not 404). Always check `status` before acting. The list endpoint automatically excludes cancelled events.
90
+
91
+ ### List events
92
+ ```bash
93
+ curl -s "http://localhost:8321/api/calendar/events?date=today&days=3"
94
+ ```
95
+
96
+ ### Get event detail
97
+ ```bash
98
+ curl -s "http://localhost:8321/api/calendar/events/abc123eventid"
99
+ ```
100
+ **Always GET before PATCH** to see current state and attendees.
101
+
102
+ ### Create event (write — Autonomous)
103
+ ```bash
104
+ curl -s -X POST "http://localhost:8321/api/calendar/events" \
105
+ -H 'Content-Type: application/json' \
106
+ -d '{"summary": "Team meeting", "start": "2026-04-02T14:00:00-04:00", "end": "2026-04-02T15:00:00-04:00"}'
107
+ ```
108
+ Optional: `description`, `location`, `reminders`, `recurrence`, `attendees`, `visibility`. All-day: `YYYY-MM-DD`. Attendees: add `?sendUpdates=all` to notify. RRULE: `RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR`.
109
+
110
+ ### Update event (write — Autonomous; commonly on the starter denylist)
111
+ ```bash
112
+ curl -s -X PATCH "http://localhost:8321/api/calendar/events/abc123" \
113
+ -H 'Content-Type: application/json' \
114
+ -d '{"start": "2026-04-02T15:00:00-04:00", "end": "2026-04-02T16:00:00-04:00"}'
115
+ ```
116
+ For recurring events, use the instance ID to update a single occurrence — never PATCH the master.
117
+
118
+ **ATTENDEES WARNING**: PATCH with `attendees` **replaces the entire list** — it does NOT append. To add one attendee: (1) GET, (2) copy existing, (3) add new, (4) PATCH full list.
119
+
120
+ ### Delete event (write — Autonomous; default starter denylist denies it)
121
+ ```bash
122
+ curl -s -X DELETE "http://localhost:8321/api/calendar/events/abc123"
123
+ ```
124
+ Add `?sendUpdates=all` to notify attendees. Do NOT PATCH a cancelled event.
125
+
126
+ ### List calendars
127
+ ```bash
128
+ curl -s http://localhost:8321/api/calendar/calendars
129
+ ```
130
+
131
+ ### Free/busy query
132
+ ```bash
133
+ curl -s -X POST http://localhost:8321/api/calendar/freebusy \
134
+ -H 'Content-Type: application/json' \
135
+ -d '{"timeMin": "2026-04-11T09:00:00-04:00", "timeMax": "2026-04-11T18:00:00-04:00"}'
136
+ ```
137
+
138
+ ### Calendar error envelope (direct mode)
139
+
140
+ | HTTP | `error` | What it means / what to do |
141
+ |---|---|---|
142
+ | 400 | `validation_error` | Bad request shape (e.g. missing `start`/`end`, malformed RRULE). Fix and retry. |
143
+ | 404 | `not_found` | Event id unknown or already deleted. Re-list before retrying. |
144
+ | 410 | `integration_delegated` | Calendar flipped to delegated mode mid-session. This skill body is direct-only — re-read `integrations.md` and use `POST /api/integrations/google_calendar/exec` (cross-backend task mode) or your session backend's native Calendar MCP (the same-backend variant) instead. |
145
+ | 502 | `calendar_error` | Upstream Google API error — `message` carries the API's text. Surface verbatim; do not retry unless clearly transient. |
146
+ | 503 | `calendar_not_configured` | Direct OAuth credentials are missing or the user has disabled Calendar in settings. Tell the user and stop. |
147
+ <!-- /service:calendar -->
148
+
149
+ ---
150
+
151
+ <!-- service:outlook-calendar -->
152
+ ## Outlook Calendar (Microsoft Graph)
153
+
154
+ Use this section **only when `rules/management.md` Schedule = Outlook Calendar**. The provider-routing table at the top of this skill is non-negotiable.
155
+
156
+ v1 is **read-only and on-demand** — there is no Outlook calendar poller, so `schedule.approaching` events do not fire for Outlook calendars (the user's own Outlook clients fill that gap). Write surfaces (create / update / delete) are deferred. If the user asks the agent to schedule or change an Outlook event, tell them you can read the calendar but must defer the write to them.
157
+
158
+ OAuth is **shared with Outlook Mail** via the same MSAL cache row (`mail:outlook:<accountId>`) — if Outlook Mail is configured `direct` and authenticated, calendar reads succeed with no second consent.
159
+
160
+ ### List events
161
+ ```bash
162
+ curl -s "http://localhost:8321/api/calendar/outlook/events?date=today&days=3"
163
+ ```
164
+ Same query params as Google (`date`: `YYYY-MM-DD` or `today`; `days`: 1–90; optional `calendarId`). Returns `{ events: [...], accountId }`.
165
+
166
+ ### List calendars
167
+ ```bash
168
+ curl -s http://localhost:8321/api/calendar/outlook/calendars
169
+ ```
170
+ Returns `{ calendars: [...], accountId }`. The user's primary calendar is marked `primary: true`.
171
+
172
+ ### Outlook Calendar error envelope
173
+
174
+ | HTTP | `error` | What it means / what to do |
175
+ |---|---|---|
176
+ | 400 | bad query | Malformed `date` or `days` value. |
177
+ | 502 | `calendar_error` | Upstream Microsoft Graph error — `message` carries wire text. |
178
+ | 503 | `outlook_not_configured` | No authenticated Outlook account. Direct OAuth credentials missing. |
179
+ | 503 | `outlook_calendar_disabled` | The user toggled Outlook Calendar off in Settings → Calendar. Tell the user and stop. |
180
+ <!-- /service:outlook-calendar -->
181
+
182
+ ---
183
+
184
+ <!-- service:apple-calendar -->
185
+ ## Apple Calendar (iCloud CalDAV)
186
+
187
+ Use this section **only when `rules/management.md` Schedule = Apple Calendar**. The provider-routing table at the top of this skill is non-negotiable.
188
+
189
+ The route shape mirrors `/api/calendar/*` so prose patterns transfer: list → get → patch / create / delete. Differences are flagged below.
190
+
191
+ ### Probe configuration before first use
192
+ ```bash
193
+ curl -s http://localhost:8321/api/apple-calendar/status
194
+ # → { "configured": bool, "available": bool }
195
+ ```
196
+ - `configured: false` → user has not entered Apple ID + app-specific password yet. Tell the user to open the dashboard's Apple Calendar card (Connections page) and paste a password from `appleid.apple.com` → Sign-In and Security → App-Specific Passwords. **Do not try to read or write events** until `available: true`.
197
+ - `configured: true, available: false` → credentials are stored but iCloud rejected the last connection. Surface verbatim; common cause is the user revoked the app-specific password.
198
+
199
+ ### List events
200
+ ```bash
201
+ curl -s "http://localhost:8321/api/apple-calendar/events?date=today&days=3"
202
+ ```
203
+ Same query params as Google: `date` (`YYYY-MM-DD` or `today`), `days` (max 90). Returns `{ events: [...] }` with the same JSON shape used by the Google route — `id`, `summary`, `start`, `end`, `location`, `description`, `allDay`, `status`, plus two Apple-specific fields:
204
+ - `recurring` (bool) — true for any event in a recurring series.
205
+ - `recurrenceId` (string|null) — populated for an expanded instance of a series.
206
+
207
+ For a recurring instance the `id` is `<UID>__<RECURRENCE-ID>` so you can address a specific occurrence.
208
+
209
+ **Timezones**: dateTime values are emitted in UTC (`Z` suffix). Convert to the user's local timezone before showing them.
210
+
211
+ ### Get event detail
212
+ ```bash
213
+ curl -s "http://localhost:8321/api/apple-calendar/events/<id>"
214
+ ```
215
+ Always GET before PATCH so you see the current summary/start/end.
216
+
217
+ ### Create event (write — Autonomous)
218
+ ```bash
219
+ curl -s -X POST http://localhost:8321/api/apple-calendar/events \
220
+ -H 'Content-Type: application/json' \
221
+ -d '{"summary": "Team meeting", "start": "2026-04-26T14:00:00+09:00", "end": "2026-04-26T15:00:00+09:00"}'
222
+ ```
223
+ Optional: `description`, `location`. **[Apple only]** `attendees`, `reminders`, `recurrence`, `visibility` from the Google shape are accepted by the Zod schema but are silently dropped — iCloud invitations and reminder defaults belong to the user's Apple ID and the agent should not author them. If a user asks for those, tell them and stop.
224
+
225
+ ### Update event (write — Autonomous)
226
+ ```bash
227
+ curl -s -X PATCH http://localhost:8321/api/apple-calendar/events/<id> \
228
+ -H 'Content-Type: application/json' \
229
+ -d '{"start": "2026-04-26T15:00:00+09:00", "end": "2026-04-26T16:00:00+09:00"}'
230
+ ```
231
+
232
+ **[Apple only] Recurring-event editing semantics — read before writing**
233
+ - A composite id (one whose suffix matches `__YYYY-MM-DD…`) addresses **one occurrence** of a series. PATCH/DELETE on it returns `501 recurring_instance_unsupported`. To move a single occurrence the user must edit it from Calendar.app.
234
+ - A bare id whose GET returned `recurring: true` is the **series master**. PATCH on the master shifts the **entire series** (every future occurrence moves), and DELETE removes the entire series. Confirm with the user that they intend a series-level edit before issuing the call — agents have historically read "PATCH this event's start" as a single-instance reschedule, which is wrong here.
235
+ - A bare id with `recurring: false` is a normal one-off event — PATCH/DELETE behave as usual.
236
+ - `summary`, `start`, and `end` may be updated independently. Toggling all-day-ness (`YYYY-MM-DD` ↔ `…T…Z`) requires providing **both** `start` and `end` in the same PATCH; the codec rejects partial all-day toggles with `400 validation_error`.
237
+ - Time strings must include a TZ offset (`Z` or `±HH:MM`); naked ISO without offset returns `400 validation_error` — do not interpret a user-stated time as local without an explicit offset.
238
+
239
+ ### Delete event (write — Autonomous)
240
+ ```bash
241
+ curl -s -X DELETE http://localhost:8321/api/apple-calendar/events/<id>
242
+ ```
243
+ Same recurring semantics as PATCH (see the rules block above).
244
+
245
+ ### List calendars
246
+ ```bash
247
+ curl -s http://localhost:8321/api/apple-calendar/calendars
248
+ # → { "calendars": [{ id, summary, description, primary }, ...] }
249
+ ```
250
+ The `id` is an opaque CalDAV URL. The user's primary calendar is marked `primary: true`. To change which calendar create/list reads, see the dashboard Apple Calendar card.
251
+
252
+ ### Free/busy query
253
+ ```bash
254
+ curl -s -X POST http://localhost:8321/api/apple-calendar/freebusy \
255
+ -H 'Content-Type: application/json' \
256
+ -d '{"timeMin": "2026-04-26T09:00:00Z", "timeMax": "2026-04-26T18:00:00Z"}'
257
+ ```
258
+ **[Apple only]** Free-busy is derived from `listEvents` — events with `status: "cancelled"` are excluded. `calendarIds` is ignored (the primary calendar is the only target).
259
+
260
+ ### Apple Calendar error envelope
261
+
262
+ | HTTP | `error` | What it means / what to do |
263
+ |---|---|---|
264
+ | 400 | `validation_error` | Bad request shape. Fix and retry. |
265
+ | 401 | `auth_failed` | iCloud rejected the credentials. Tell the user to refresh the app-specific password in the dashboard. |
266
+ | 404 | `not_found` | Event id unknown or already deleted. Re-list before retrying. |
267
+ | 501 | `recurring_instance_unsupported` | The id targets a single occurrence of a recurring series — see the PATCH/DELETE notes above. |
268
+ | 502 | `apple_calendar_error` | Upstream iCloud / CalDAV error. `message` carries the wire text. |
269
+ | 503 | `apple_calendar_not_configured` | Credentials missing or last connection failed. Run the status probe above. |
270
+
271
+ ### Known gap: no proactive notifications
272
+
273
+ The hourly polling pivot (`schedule.approaching` events, observation deltas) only fires for Google Calendar today. With Apple Calendar selected, on-demand DM queries work but the agent will not proactively warn about an imminent event — the user's own iOS / macOS Calendar.app notifications fill that gap.
274
+ <!-- /service:apple-calendar -->
275
+
276
+ ---
277
+
278
+ <!-- service:obsidian -->
279
+ ## Obsidian (external vault)
280
+
281
+ **Scope**: this skill targets a **separate** Obsidian vault the user maintains
282
+ alongside this app — e.g. a personal knowledge base. It is **not** the agent's
283
+ own primary management store. The agent's primary files (`today.md`,
284
+ `roadmap.md`, `projects/`, `rules/`, `routines/`, `user/`, `agent/`, …) live
285
+ in the primary vault and are reached via `/api/context/*` (see the `context`
286
+ skill). **Never** use this skill to read or write the primary vault.
287
+
288
+ Use this skill when the user asks the agent to look up, append to, or create
289
+ notes inside their external knowledge vault — never for the agent's own
290
+ working state.
291
+
292
+ Full CRUD over the external vault. Requires the Obsidian app running (the
293
+ CLI proxies through it). Omit `.md` extension from paths. All writes are
294
+ Autonomous; the daemon does not DM the owner before/after the call. Call
295
+ `POST /api/notify` yourself when the user would want to know.
296
+
297
+ ```bash
298
+ curl -s http://localhost:8321/api/obsidian/status # external vault availability
299
+ curl -s "http://localhost:8321/api/obsidian/search?q=meeting+notes&limit=10" # search external vault
300
+ curl -s http://localhost:8321/api/obsidian/notes/Daily%20Notes/2026-04-06 # read external note
301
+ curl -s -X POST http://localhost:8321/api/obsidian/notes \
302
+ -H 'Content-Type: application/json' \
303
+ -d '{"name": "Meeting Notes 2026-04-02", "content": "# Meeting\n..."}' # create external note (fails if exists)
304
+ curl -s -X PUT http://localhost:8321/api/obsidian/notes/Projects/ProjectA \
305
+ -H 'Content-Type: application/json' -d '{"content": "# Full body"}' # create-or-overwrite external note
306
+ curl -s -X PATCH http://localhost:8321/api/obsidian/notes \
307
+ -H 'Content-Type: application/json' \
308
+ -d '{"file": "Meeting Notes 2026-04-02", "content": "\n- Action item"}' # append to external note
309
+ curl -s -X PATCH http://localhost:8321/api/obsidian/daily \
310
+ -H 'Content-Type: application/json' -d '{"content": "- [ ] Follow up"}' # append to external daily note
311
+ curl -s -X DELETE http://localhost:8321/api/obsidian/notes/Projects/Old # delete from external vault (moves to trash)
312
+ ```
313
+ **Endpoint choice**: Read → GET, Create-only → POST, Edit → PUT, Append → PATCH.
314
+
315
+ If the user's request is really about the agent's own state (today, roadmap,
316
+ projects, journal, rules, routines, user profile), switch to the `context`
317
+ skill and the `/api/context/*` endpoints instead.
318
+ <!-- /service:obsidian -->
319
+
320
+ ---
321
+
322
+ <!-- service:github -->
323
+ ## GitHub
324
+
325
+ ```bash
326
+ curl -s http://localhost:8321/api/github/repos # list watched repos
327
+ curl -s "http://localhost:8321/api/github/pulls?owner=user&repo=repo&state=open" # list PRs
328
+ curl -s -X POST http://localhost:8321/api/github/pulls/comment \
329
+ -H 'Content-Type: application/json' \
330
+ -d '{"owner": "user", "repo": "repo", "pull_number": 42, "comment": "LGTM"}' # comment — Autonomous
331
+ ```
332
+ <!-- /service:github -->
333
+
334
+ ---
335
+
336
+ <!-- service:notion -->
337
+ ## Notion
338
+
339
+ Notion operations live in the dedicated `notion` skill — load that when
340
+ the user asks anything Notion-shaped (search, query, read, create,
341
+ update, archive).
342
+ <!-- /service:notion -->
343
+
344
+ ---
345
+
346
+ ## Scheduling
347
+
348
+ One-shot wake-ups, pre-composed DMs, and recurring agent tasks live in
349
+ the `schedule` skill — load it for `/api/schedule`, `/api/schedule/dm`,
350
+ and `/api/recurring-schedules`. This skill no longer mirrors those
351
+ endpoints; keeping a single source of truth avoids drift across the
352
+ two skills loaded together by morning, hourly, DM, and scheduled
353
+ flows.
354
+
355
+ ---
356
+
357
+ ## Skills Management
358
+
359
+ User-authored skills: `~/.personal-agent/skills/{slug}/SKILL.md`. Built-in skills are read-only (403). Slug: lowercase kebab-case `[a-z0-9][a-z0-9-]*`, 1–64 chars.
360
+
361
+ ```bash
362
+ curl -s http://localhost:8321/api/skills # list all
363
+ curl -s http://localhost:8321/api/skills/todo-digest # read one
364
+ curl -s -X POST http://localhost:8321/api/skills \
365
+ -H 'Content-Type: application/json' \
366
+ -d '{"name": "todo-digest", "description": "Summarize today.md", "content": "# TODO Digest\n...", "allowedTools": ["Bash(curl *)", "Read"]}'
367
+ curl -s -X PUT http://localhost:8321/api/skills/todo-digest \
368
+ -H 'Content-Type: application/json' -d '{"description": "New description"}' # update
369
+ curl -s -X DELETE http://localhost:8321/api/skills/todo-digest # delete
370
+ ```
371
+ Always `GET /api/skills` before creating (check name collisions). **Omit frontmatter** from `content` — the API injects it.
@@ -0,0 +1,284 @@
1
+ ---
2
+ name: mail
3
+ description: Load when the task touches Gmail and Gmail is in cross-backend delegated mode (DM session is Claude Code; `delegatedBackend` is non-Claude). Gmail accounts route through `POST /api/integrations/gmail/exec`; non-Gmail accounts (IMAP/Outlook/iCloud/Yahoo) keep the direct-mode `/api/mail/*` surface.
4
+ allowed-tools:
5
+ - Bash(curl *)
6
+ - Read
7
+ ---
8
+
9
+ # Mail (delegated, cross-backend)
10
+
11
+ Gmail is delegated to a different backend (Codex or Gemini). The daemon
12
+ spawns that backend on demand, lets it pick the right MCP tool, and
13
+ returns a schema-validated JSON result. **You describe intent in
14
+ natural language; the daemon picks the tool.** Tool name divergence
15
+ between Codex (`search_emails`), Gemini (`search`) and any custom MCP
16
+ server the user installs is invisible to you.
17
+
18
+ To confirm Gmail's current delegate, read
19
+ `~/.personal-agent/integrations.md` and consult its `delegatedBackend`
20
+ field. The same prose body below works for every delegate.
21
+
22
+ ## Non-Gmail accounts keep the direct-mode surface
23
+
24
+ Per-account gating: the `/api/mail/*` 410 only fires when the resolved
25
+ `accountId` is `kind=gmail`. IMAP / Outlook / iCloud / Yahoo accounts
26
+ remain fully reachable through the direct-mode endpoints documented in
27
+ the base `mail` skill body — `GET /api/mail/:acct/messages`,
28
+ `POST /mail/:acct/drafts`, `GET /api/mail/:acct/threads/:threadId`, etc.
29
+ Use `accounts.md` (still materialized for this session) to resolve the
30
+ account and pick the path:
31
+
32
+ | Selected account `kind` | Path |
33
+ |---|---|
34
+ | `gmail` | task: `POST /api/integrations/gmail/exec {task, outputSchema, …}` (this file) |
35
+ | `outlook` / `icloud` / `yahoo` / `imap` | direct: `/api/mail/:acct/*` (base body) |
36
+
37
+ Only the Gmail branch leaves the direct-mode surface. Account
38
+ resolution (§1 of the base body), draft-vs-send rules, and reply-thread
39
+ chaining are unchanged for non-Gmail accounts.
40
+
41
+ ## Call shape
42
+
43
+ The single endpoint is `POST /api/integrations/gmail/exec`. The body
44
+ takes a natural-language `task` plus an `outputSchema` (Draft-07 JSON
45
+ Schema) the daemon validates the result against. Optional fields
46
+ default safely; raise them only when the task genuinely needs more
47
+ budget.
48
+
49
+ ```bash
50
+ curl -s -X POST http://localhost:8321/api/integrations/gmail/exec \
51
+ -H 'Content-Type: application/json' \
52
+ -d '{
53
+ "task": "Search Gmail for unread messages from alice@example.com in the last 7 days. Return up to 10 with sender, subject, snippet, timestamp.",
54
+ "outputSchema": {
55
+ "type": "object",
56
+ "required": ["messages"],
57
+ "properties": {
58
+ "messages": {
59
+ "type": "array",
60
+ "items": {
61
+ "type": "object",
62
+ "required": ["from", "subject", "snippet", "ts"],
63
+ "properties": {
64
+ "from": {"type": "string"},
65
+ "subject": {"type": "string"},
66
+ "snippet": {"type": "string"},
67
+ "ts": {"type": "string", "format": "date-time"}
68
+ }
69
+ }
70
+ }
71
+ }
72
+ },
73
+ "maxToolCalls": 5,
74
+ "cacheable": true
75
+ }'
76
+ ```
77
+
78
+ Response shape on success:
79
+
80
+ ```jsonc
81
+ {
82
+ "result": { "messages": [ ... ] }, // schema-validated parse
83
+ "needsConfirmation": false,
84
+ "confirmationPlan": null,
85
+ "trace": [ /* per-tool-call breakdown — informational */ ],
86
+ "cost": { "tokensInput": ..., "costUsd": ..., "durationMs": ... }
87
+ }
88
+ ```
89
+
90
+ `outputSchema` is **required** — the subprocess emits exactly one JSON
91
+ object as its final message and the daemon validates it. Schemas
92
+ larger than 4 KB are rejected (`schema_too_large`). Caps default to
93
+ `maxToolCalls=7`, `maxBudgetUsd=0.05`, `timeoutMs=60000` — bump them via
94
+ the request body up to the hard caps (15 / 0.50 / 300000) when a task
95
+ genuinely needs more.
96
+
97
+ ## Idempotent reads — `cacheable: true`
98
+
99
+ Pure-read tasks (thread fetches, search summarisations, label lookups)
100
+ should set `cacheable: true` so a repeat invocation within 60s returns
101
+ ~5ms from the in-memory LRU. The cache key includes the integration
102
+ state version, so flipping `deniedTools` or `delegatedBackend` purges
103
+ entries automatically. Cache hits still write a `delegated_task.exec`
104
+ audit row with `cost_usd=0` and `detail.cacheHit=true` — accounting
105
+ stays correct.
106
+
107
+ Never set `cacheable: true` on:
108
+ - destructive-confirm second calls (`allowDestructive: true`),
109
+ - tasks that depend on minute-level freshness,
110
+ - any write.
111
+
112
+ ## Destructive-confirm dance — `allowDestructive`
113
+
114
+ Default is `false`. The subprocess will not call destructive tools
115
+ (send / delete / batch label mutate / etc.) — instead it returns:
116
+
117
+ ```jsonc
118
+ {
119
+ "needsConfirmation": true,
120
+ "confirmationPlan": "I will send a reply to alice@example.com with subject \"Re: Proposal\" and body …"
121
+ }
122
+ ```
123
+
124
+ Surface `confirmationPlan` to the user verbatim. On their explicit OK,
125
+ re-issue the **same `task` verbatim** with `allowDestructive: true`. Do
126
+ NOT set `cacheable: true` on the second call — the confirmation does
127
+ not extend across cache lifetimes.
128
+
129
+ ## Worked examples
130
+
131
+ ### Read a whole thread (composition handled by the subprocess)
132
+
133
+ When the active connector lacks a thread-fetch primitive (Gemini), the
134
+ subprocess composes search + per-message get — you don't have to
135
+ think about it.
136
+
137
+ ```bash
138
+ curl -s -X POST http://localhost:8321/api/integrations/gmail/exec \
139
+ -H 'Content-Type: application/json' \
140
+ -d '{
141
+ "task": "Fetch every message in Gmail thread <THREAD_ID>. For each message, return from / subject / body / timestamp. Sort by timestamp ascending.",
142
+ "outputSchema": {
143
+ "type": "object",
144
+ "required": ["messages"],
145
+ "properties": {
146
+ "messages": {
147
+ "type": "array",
148
+ "items": {
149
+ "type": "object",
150
+ "required": ["from", "subject", "body", "ts"],
151
+ "properties": {
152
+ "from": {"type": "string"},
153
+ "subject": {"type": "string"},
154
+ "body": {"type": "string"},
155
+ "ts": {"type": "string", "format": "date-time"}
156
+ }
157
+ }
158
+ }
159
+ }
160
+ },
161
+ "maxToolCalls": 7,
162
+ "cacheable": true
163
+ }'
164
+ ```
165
+
166
+ ### Compose a draft (default-safe, no destructive flag needed)
167
+
168
+ Drafts are inert — the user can review and send from the Gmail web UI.
169
+ Prefer drafts over send.
170
+
171
+ ```bash
172
+ curl -s -X POST http://localhost:8321/api/integrations/gmail/exec \
173
+ -H 'Content-Type: application/json' \
174
+ -d '{
175
+ "task": "Compose a Gmail draft replying to message <MESSAGE_ID>. Subject: \"Re: <ORIGINAL_SUBJECT>\". Body: <BODY>. Preserve the RFC-2822 thread (Message-Id + References).",
176
+ "outputSchema": {
177
+ "type": "object",
178
+ "required": ["draftId"],
179
+ "properties": { "draftId": { "type": "string" } }
180
+ },
181
+ "maxToolCalls": 4
182
+ }'
183
+ ```
184
+
185
+ ### Send a previously-vetted draft (destructive — confirmation required)
186
+
187
+ Two-step ceremony: first call without `allowDestructive` returns the
188
+ confirmation envelope; on user OK, re-issue with the flag.
189
+
190
+ ```bash
191
+ curl -s -X POST http://localhost:8321/api/integrations/gmail/exec \
192
+ -H 'Content-Type: application/json' \
193
+ -d '{
194
+ "task": "Send Gmail draft <DRAFT_ID> as-is. Do not edit the body.",
195
+ "outputSchema": {
196
+ "type": "object",
197
+ "required": ["messageId"],
198
+ "properties": { "messageId": { "type": "string" } }
199
+ },
200
+ "maxToolCalls": 2,
201
+ "allowDestructive": true
202
+ }'
203
+ ```
204
+
205
+ ## Default deny floor
206
+
207
+ The setup wizard pre-populates `gmail.deniedTools` with the connector's
208
+ destructive defaults (send / batch label mutate / etc.). `/exec`
209
+ honors the deny list: a task that requires a denied tool surfaces as
210
+ `tool_unavailable` (not 403) — the subprocess reports the gap and the
211
+ daemon returns 502. Surface that to the user and ask whether to lift
212
+ the deny before retrying.
213
+
214
+ ## Decision rules
215
+
216
+ - **Prefer drafts over send.** Drafts are reversible, send is not. The
217
+ destructive-confirm dance applies to send anyway.
218
+ - **Replies preserve the RFC-2822 chain.** Pin `Message-Id` /
219
+ `References` headers on the draft. The subprocess fetches them from
220
+ the original message regardless of which connector underlies the
221
+ delegate.
222
+ - **The reply account is implicit.** The connector picks the account
223
+ based on its own auth — do not pass an `accountId`.
224
+ - **No `bcc` unless the user explicitly asks for it.**
225
+ - **Bulk operations: ask first.** Mass-mutation intents touch many
226
+ messages in one call. Summarise what you would do (count + criteria)
227
+ and confirm before invoking, even on the destructive-confirm path.
228
+
229
+ ## Error envelope
230
+
231
+ `/exec` extends the direct-mode envelope with delegated-mode fields.
232
+ Discriminator: `body.mode === "delegated"`.
233
+
234
+ | HTTP | `error` | retry? | What to do |
235
+ |---|---|---|---|
236
+ | 400 | `validation_error` / `schema_too_large` | no | Fix the request body. |
237
+ | 409 | `mode_mismatch` | no | Gmail isn't delegated, OR your DM backend matches `delegatedBackend`. Re-read `integrations.md` and stop. |
238
+ | 409 | `precondition` | no | Mode/backend was flipped while the call queued. Re-read `integrations.md` and re-plan. |
239
+ | 429 | `task_quota_exhausted` | no | Daily cap reached; wait or surface. |
240
+ | 502 | `parse_error` / `schema_violation` | no (daemon already retried once) | Consider a simpler schema. |
241
+ | 502 | `tool_unavailable` | no | No connector tool fits the intent. Surface the gap to the user. |
242
+ | 502 | `tool_failed` | maybe | Connector tool returned an error. Surface `body.message` verbatim; retry only if clearly transient. |
243
+ | 502 | `auth_error` | no | Connector signed out. Tell the user to re-authenticate. |
244
+ | 502 | `policy_violation` | no | Subprocess attempted a tool outside the per-task allowlist (anti-injection). Surface as anomaly. |
245
+ | 502 | `loop_aborted` | no | `maxToolCalls` exceeded. Likely planning gap; bump the cap or simplify the task. |
246
+ | 502 | `budget_exhausted` | no | `maxBudgetUsd` exceeded. Caller can raise the cap. |
247
+ | 502 | `post_write_format_failure` | no | Write succeeded; formatting failed. The side effect is real — surface to user with the partial trace. |
248
+ | 503 | `delegated_proxy_busy` | yes | Queue saturated. Backoff 3-5s and retry once. |
249
+ | 503 | `task_mode_disabled` | no | Operator turned the kill switch off. Stop. |
250
+ | 504 | `timeout` | yes (1×) | Wall-clock fired. Retry once for simple intents; otherwise surface. |
251
+ | 500 | `subprocess_crashed` | no | Daemon-side defect. Surface and stop. |
252
+
253
+ ## Owner notification (opt-in)
254
+
255
+ The daemon does not auto-DM the owner. When you take an action the
256
+ user would want to know about *immediately* — sending an external
257
+ email, archiving a stack, applying a sensitive label — call:
258
+
259
+ ```bash
260
+ curl -s -X POST http://localhost:8321/api/notify \
261
+ -H 'Content-Type: application/json' \
262
+ -d '{"message": "Sent reply to alice@example.com (Re: Proposal)"}'
263
+ ```
264
+
265
+ Do not call `/api/notify` for routine reads / drafts / searches. The
266
+ default posture is autonomous; the user's `deniedTools` is the
267
+ hard-stop, on-demand retrospective covers awareness, and `/api/notify`
268
+ is the small hammer for "speak up if I'm about to do something
269
+ unusual."
270
+
271
+ ## Cost / retrospective
272
+
273
+ Every `/exec` writes one row to `agent_actions` with
274
+ `action_type='delegated_task.exec'` (token + USD breakdown, parent
275
+ `event_id` / `processKey` attached automatically via session env
276
+ vars). When the user asks what you did:
277
+
278
+ ```bash
279
+ curl -s "http://localhost:8321/api/agent/actions?kind=delegated_task.exec&since=2026-04-25T00:00:00Z&limit=50"
280
+ ```
281
+
282
+ Summarise from the returned `actions` array — each row carries
283
+ `detail.task` (the natural-language intent), cost, cache hit flag, and
284
+ timestamp.