@aitne-sh/aitne 0.1.4 → 0.1.6

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 (87) hide show
  1. package/README.md +16 -0
  2. package/agent-assets/agent-profiles/_safety.md +29 -0
  3. package/agent-assets/agent-profiles/routine-fetch-window.md +75 -40
  4. package/agent-assets/agent-profiles/wiki-agent.md +19 -0
  5. package/agent-assets/docs/features/messaging/bang-commands.md +161 -0
  6. package/agent-assets/docs/features/messaging/overview.md +3 -0
  7. package/agent-assets/docs/features/wiki/commands.md +222 -0
  8. package/agent-assets/docs/features/wiki/overview.md +145 -0
  9. package/agent-assets/docs/getting-started/03-what-can-this-do.md +18 -0
  10. package/agent-assets/docs/glossary.md +34 -0
  11. package/agent-assets/docs/guides/budget-and-cost-for-wiki.md +123 -0
  12. package/agent-assets/docs/guides/build-your-wiki.md +99 -0
  13. package/agent-assets/docs/guides/explore-with-trace-and-connect.md +169 -0
  14. package/agent-assets/docs/guides/maintain-wiki-health.md +168 -0
  15. package/agent-assets/docs/guides/multiple-wikis-for-multiple-domains.md +192 -0
  16. package/agent-assets/docs/guides/pause-the-agent.md +10 -3
  17. package/agent-assets/docs/guides/use-an-existing-obsidian-vault.md +156 -0
  18. package/agent-assets/docs/reference/cli-commands.md +24 -1
  19. package/agent-assets/docs/troubleshooting/wiki-ingest-full-blocked.md +96 -0
  20. package/agent-assets/docs/troubleshooting/wiki-write-failed.md +82 -0
  21. package/agent-assets/skills/context/SKILL.md +288 -17
  22. package/agent-assets/skills/external-services/SKILL.delegated.claude.md +2 -2
  23. package/agent-assets/skills/external-services/SKILL.delegated.codex.md +3 -3
  24. package/agent-assets/skills/external-services/SKILL.delegated.gemini.md +6 -6
  25. package/agent-assets/skills/external-services/SKILL.md +5 -3
  26. package/agent-assets/skills/external-services/SKILL.native.claude.md +49 -58
  27. package/agent-assets/skills/external-services/SKILL.native.codex.md +50 -58
  28. package/agent-assets/skills/external-services/SKILL.native.gemini.md +53 -56
  29. package/agent-assets/skills/mail/SKILL.md +5 -5
  30. package/agent-assets/skills/mail/SKILL.native.claude.md +57 -65
  31. package/agent-assets/skills/mail/SKILL.native.codex.md +73 -75
  32. package/agent-assets/skills/mail/SKILL.native.gemini.md +80 -75
  33. package/agent-assets/skills/management-task-register/SKILL.md +3 -3
  34. package/agent-assets/skills/notion/SKILL.native.claude.md +78 -82
  35. package/agent-assets/skills/notion/SKILL.native.codex.md +78 -80
  36. package/agent-assets/skills/notion/SKILL.native.gemini.md +91 -90
  37. package/agent-assets/skills/observations/SKILL.md +123 -15
  38. package/agent-assets/skills/roadmap/SKILL.md +31 -4
  39. package/agent-assets/skills/schedule/SKILL.md +44 -3
  40. package/agent-assets/skills/today/SKILL.md +50 -11
  41. package/agent-assets/skills/travel-time/SKILL.md +9 -0
  42. package/agent-assets/skills/wiki/wiki-ask/SKILL.md +32 -0
  43. package/agent-assets/skills/wiki/wiki-compile/SKILL.md +126 -0
  44. package/agent-assets/skills/wiki/wiki-connect/SKILL.md +75 -0
  45. package/agent-assets/skills/wiki/wiki-graduate/SKILL.md +45 -0
  46. package/agent-assets/skills/wiki/wiki-ingest/SKILL.md +182 -0
  47. package/agent-assets/skills/wiki/wiki-lint/SKILL.md +90 -0
  48. package/agent-assets/skills/wiki/wiki-trace/SKILL.md +72 -0
  49. package/agent-assets/skills/wiki/wiki-vault-rules/SKILL.md +145 -0
  50. package/agent-assets/task-flows/_partials/calendar-acquire.google_calendar.md +28 -9
  51. package/agent-assets/task-flows/_partials/calendar-acquire.outlook_calendar.md +26 -9
  52. package/agent-assets/task-flows/_partials/mail-acquire.gmail.md +51 -24
  53. package/agent-assets/task-flows/_partials/mail-acquire.outlook_mail.md +46 -16
  54. package/agent-assets/task-flows/_partials/notion-acquire.notion.md +29 -9
  55. package/agent-assets/task-flows/message.received.dm.md +35 -2
  56. package/agent-assets/task-flows/message.received.dm.native.claude.md +25 -26
  57. package/agent-assets/task-flows/message.received.dm.native.codex.md +30 -24
  58. package/agent-assets/task-flows/message.received.dm.native.gemini.md +36 -36
  59. package/agent-assets/task-flows/message.received.dm_first.md +43 -4
  60. package/agent-assets/task-flows/message.received.dm_first.native.claude.md +20 -20
  61. package/agent-assets/task-flows/message.received.dm_first.native.codex.md +22 -19
  62. package/agent-assets/task-flows/message.received.dm_first.native.gemini.md +28 -24
  63. package/agent-assets/task-flows/routine.fetch_window.md +51 -36
  64. package/agent-assets/task-flows/routine.morning_routine.md +12 -3
  65. package/agent-assets/task-flows/routine.morning_routine_initial.md +22 -1
  66. package/agent-assets/task-flows/routine.roadmap_refresh.md +7 -3
  67. package/agent-assets/task-flows/scheduled.dm.md +477 -0
  68. package/agent-assets/task-flows/setup.initial.md +50 -23
  69. package/agent-assets/task-flows/wiki.ask.md +11 -0
  70. package/agent-assets/task-flows/wiki.compile.md +28 -0
  71. package/agent-assets/task-flows/wiki.connect.md +12 -0
  72. package/agent-assets/task-flows/wiki.ingest_url.md +35 -0
  73. package/agent-assets/task-flows/wiki.lint.md +13 -0
  74. package/agent-assets/task-flows/wiki.trace.md +13 -0
  75. package/agent-assets/wiki-seeds/schemas/output.md +12 -0
  76. package/agent-assets/wiki-seeds/schemas/raw.md +13 -0
  77. package/agent-assets/wiki-seeds/schemas/wiki.md +12 -0
  78. package/agent-assets/wiki-seeds/taxonomy.md +13 -0
  79. package/package.json +10 -6
  80. package/scripts/check-redaction-coverage.mjs +0 -109
  81. package/scripts/commands.md +0 -0
  82. package/scripts/message-discipline-digest.mjs +0 -535
  83. package/scripts/poc/google-connector-inheritance/REPORT.md +0 -197
  84. package/scripts/poc/google-connector-inheritance/claude-sdk-probe.mjs +0 -79
  85. package/scripts/regen-skill-fixtures.mjs +0 -39
  86. package/scripts/remint-roadmap-ids.mjs +0 -257
  87. package/scripts/smoke-obsidian-api.mjs +0 -166
@@ -1,13 +1,13 @@
1
1
  ---
2
2
  name: notion
3
- description: Load when the task touches Notion and Notion is in native mode bound to Gemini (`nativeBackend === "gemini"`). Use the user-installed Notion MCP server on Gemini CLI directly; the daemon does not proxy Notion. `/api/notion/databases` (label → UUID config dump) is the only daemon route still reachable.
3
+ description: Load when the task touches Notion and Notion is in native mode bound to Gemini (`nativeBackend === "gemini"`). Use the in-session Notion connector your Gemini harness exposes directly; the daemon does not proxy Notion. `/api/notion/databases` (label → UUID config dump) is the only daemon route still reachable.
4
4
  allowed-tools:
5
5
  - Bash(curl *)
6
6
  - Bash(jq *)
7
7
  - Read
8
8
  ---
9
9
 
10
- # Notion (native — Gemini, user-installed Notion MCP)
10
+ # Notion (native — in-session Notion connector)
11
11
 
12
12
  > **Refusal directive — read first.** Notion is in `native` mode bound
13
13
  > to Gemini. Do **NOT** call any of:
@@ -18,22 +18,22 @@ allowed-tools:
18
18
  > - `/api/notion/query`, `/api/notion/search`, `/api/notion/pages`,
19
19
  > `/api/notion/pages/<id>/content` (each route-prefix 410)
20
20
  >
21
- > Reach Notion through the `mcp_notion_*` MCP tools your Gemini session
22
- > already holds via the user-installed Notion MCP server.
21
+ > Reach Notion through the in-session Notion connector your harness
22
+ > exposes (typically a user-installed Notion MCP server registered
23
+ > against the Gemini CLI). Your tool menu lists every available tool at
24
+ > session start — pick the Notion one.
23
25
  >
24
26
  > Exception: **`GET /api/notion/databases`** remains reachable in every
25
27
  > mode (config dump, no Notion API side-effect).
26
28
 
27
- ## Server-name assumption
29
+ ## Connector presence assumption
28
30
 
29
- The registry assumes the user registered Notion's official MCP server
30
- under the literal name `notion` (`gemini mcp add notion <url>` or via
31
- the dashboard's MCP page). Gemini surfaces tools as
32
- `mcp_<server>_<tool>`, so the namespace `mcp_notion_` only resolves if
33
- the server is named `notion` exactly. If the user picked a different
34
- name, the §9.3 probe at flip time will report every required capability
35
- missing and the dashboard surfaces an actionable "wrong server name"
36
- hint. This skill body assumes the probe passed.
31
+ Native:gemini mode assumes a Notion MCP server is registered against
32
+ the user's Gemini CLI. The §9.3 probe at flip time verifies every
33
+ required capability is reachable from the in-session tool menu; if the
34
+ probe fails (wrong server name, server not registered, or capabilities
35
+ missing), the dashboard surfaces an actionable hint and the mode does
36
+ not flip. This skill body assumes the probe passed.
37
37
 
38
38
  Confirm the binding via `<integration_modes>` (`notion="native"`) and
39
39
  the `<integration-routing-table>` block in the session preamble.
@@ -47,106 +47,107 @@ curl -s http://localhost:8321/api/notion/databases
47
47
 
48
48
  Resolve label → UUID before any Notion call.
49
49
 
50
- ## 2. Notion — user-installed Notion MCP (native)
50
+ ## 2. Notion — in-session connector
51
+
52
+ The exact tool names depend on which Notion MCP server the user has
53
+ registered against their Gemini CLI. Inspect your tool menu at session
54
+ start and pick the matching capability. Notion's official MCP server
55
+ exposes hyphenated identifiers (search / fetch / get-comments / …);
56
+ under Gemini's namespace convention they surface with a server prefix.
57
+ The capability classes below are stable across connectors; the exact
58
+ tool names depend on the server you have loaded.
59
+
60
+ ### Read-class capabilities
61
+
62
+ | Capability | What to do |
63
+ |---|---|
64
+ | `search` | Workspace search (text + Notion query parameters), optionally filtered to a specific data source. |
65
+ | `read` | Retrieve a single page / database / block by URL or UUID; returns block tree. |
66
+ | `comments` | Read page comments. |
67
+ | `users` | Enumerate workspace users. |
68
+ | `teams` | Enumerate teams / teamspaces. |
69
+
70
+ Canonical search flow: invoke your connector's search function with
71
+ the user's text query and the data-source URL constructed from the
72
+ resolved UUID (e.g.
73
+ `https://www.notion.so/<workspace>/<database-uuid>`).
74
+
75
+ Canonical page read: invoke your connector's fetch / read-page
76
+ function with the page's URL or UUID.
77
+
78
+ ### Destructive capabilities (require explicit user confirmation)
79
+
80
+ Per the registry's `notion.backendConnectors.gemini.destructiveTools`,
81
+ the following capability classes are destructive in native:gemini mode:
82
+
83
+ - **Page creation** — adds new pages (batch-aware on most connectors).
84
+ - **Page update** — mutates properties / content; **also** the archive
85
+ workaround (Status="Archived") — §3 below.
86
+ - **Page duplicate** — clones a page.
87
+ - **Page move** — relocates pages between databases / parents.
88
+ - **Comment create** — posts a comment (user-visible).
89
+ - **Database create** — schema admin (creates new DB).
90
+ - **Data-source update** — schema admin (mutates DB columns).
91
+ - **View create / update** — schema admin (new view / mutates view
92
+ config).
93
+
94
+ Apply the destructive-confirm contract every time. Schema-admin
95
+ capability classes warrant an explicit "schema admin" label on the
96
+ surfaced plan. The starter `deniedTools` list is enforced before the
97
+ call lands.
51
98
 
52
- Tool namespace: `mcp_notion_`
53
-
54
- The Notion MCP server exposes the same tool names as Anthropic's hosted
55
- Notion connector (hyphenated identifiers, e.g. `notion-search`); under
56
- Gemini's namespace convention they surface as `mcp_notion_<tool>`.
57
-
58
- ### Read-class tools
59
-
60
- | Capability | Tool | Use |
61
- |---|---|---|
62
- | `search` | `mcp_notion_notion-search` | Workspace search. |
63
- | `read` | `mcp_notion_notion-fetch` | Single page / database / block by URL or UUID. |
64
- | `comments` | `mcp_notion_notion-get-comments` | Read page comments. |
65
- | `users` | `mcp_notion_notion-get-users` | Enumerate workspace users. |
66
- | `teams` | `mcp_notion_notion-get-teams` | Enumerate teams. |
67
-
68
- Canonical search call:
69
-
70
- ```
71
- mcp_notion_notion-search(
72
- query="acme proposal",
73
- data_source_url="https://www.notion.so/<workspace>/<database-uuid>"
74
- )
75
- ```
76
-
77
- Canonical page read:
78
-
79
- ```
80
- mcp_notion_notion-fetch(id="<page-url-or-uuid>")
81
- ```
82
-
83
- ### Destructive tools (require explicit user confirmation)
84
-
85
- Per the registry's `notion.backendConnectors.gemini.destructiveTools`:
86
-
87
- - `mcp_notion_notion-create-pages`
88
- - `mcp_notion_notion-update-page` — properties / content / archive
89
- workaround.
90
- - `mcp_notion_notion-duplicate-page`
91
- - `mcp_notion_notion-move-pages`
92
- - `mcp_notion_notion-create-comment`
93
- - `mcp_notion_notion-create-database` — schema admin.
94
- - `mcp_notion_notion-update-data-source` — schema admin.
95
- - `mcp_notion_notion-create-view` — schema admin.
96
- - `mcp_notion_notion-update-view` — schema admin.
99
+ ## 3. Page archive — workaround only
97
100
 
98
- Apply the destructive-confirm contract every time. Schema-admin tools
99
- warrant an explicit "schema admin" label on the surfaced plan. The
100
- starter `deniedTools` list is enforced before the call lands.
101
+ Same gap as Claude / Codex hosted connectors — typically no dedicated
102
+ archive tool. To "archive":
101
103
 
102
- ## 3. Page archive workaround only
104
+ 1. **Property workaround** (preferred): update the page's Status
105
+ property to "Archived" via the page-update capability.
106
+ 2. **Move to a "Trash" page**: relocate the page under a top-level
107
+ "Trash" page via the page-move capability.
103
108
 
104
- Same gap as Claude / Codex hosted connectors — no dedicated archive
105
- tool. Use the property-update workaround (Status="Archived") via
106
- `mcp_notion_notion-update-page`, or move the page under a top-level
107
- Trash page via `mcp_notion_notion-move-pages`. Surface the choice.
109
+ Surface the choice to the user.
108
110
 
109
111
  ## 4. Decision rules
110
112
 
111
113
  - **Hourly check is read-only** — inherits the constraint from
112
114
  `routine.hourly_check.native.gemini.md`.
113
- - **Mass-update — ask first.** `mcp_notion_notion-create-pages` can
114
- take up to 100 pages; batches >~10 pages warrant explicit
115
- confirmation.
115
+ - **Mass-update — ask first.** Batch page-creation can take up to 100
116
+ pages; batches >~10 pages warrant explicit confirmation.
116
117
  - **Schema admin — Approve-tier.** Database / view / data-source
117
118
  mutations alter workspace structure.
118
- - **Comments are user-visible.** `mcp_notion_notion-create-comment`
119
- posts to a page comment thread — treat like a send.
120
- - **No `_notion_query_data_sources` equivalent** on this connector.
121
- For "what tasks are in status X" intents, use
122
- `mcp_notion_notion-search` with the data-source filter scoping the
123
- workspace and process the result client-side; Codex's SQL-style
124
- query is a Codex-only feature.
119
+ - **Comments are user-visible.** Posting a page comment is treated
120
+ like a send: confirm before issuing.
121
+ - **No SQL-style structured query on this surface.** Notion's official
122
+ MCP server (the typical native:gemini connector) does not expose a
123
+ structured-filter primitive equivalent to Codex's
124
+ `query_data_sources`. For "what tasks are in status X" intents, use
125
+ the workspace search capability with a data-source filter scoping
126
+ the request and process the result client-side.
125
127
 
126
128
  ## 5. Persisting observations from native fetches
127
129
 
130
+ **Batch when you have more than one page.** Use
131
+ `POST /api/observations/batch` with up to 200 items in one
132
+ `observations[]` array (see the `observations` skill for the envelope).
133
+ The single-item form below is for the rare "one page changed" case.
134
+
128
135
  ```bash
129
136
  curl -s -X POST http://localhost:8321/api/observations \
130
137
  -H 'Content-Type: application/json' \
131
138
  -d '{
132
- "source": "notion",
133
- "type": "notion:lifecycle",
139
+ "source": "notion:<workspaceId>",
134
140
  "ref": "<pageId>",
135
- "actor": "user",
136
- "receivedAt": "<ISO-8601 UTC>",
137
- "summary_text": "<title last edited HH:MM>",
138
- "refs": {
139
- "pageId": "<id>",
140
- "parentDatabase": "<db-uuid-or-null>",
141
- "title": "<title>"
142
- },
143
- "payload": <verbatim MCP page object>
141
+ "changeType": "created",
142
+ "actor": "agent",
143
+ "payload": <verbatim connector page object>
144
144
  }'
145
145
  ```
146
146
 
147
147
  The daemon computes `contentHash` server-side. Pass `payload`
148
- verbatim. HTTP 409 mode-flip race window (§11.3.1); stop and re-read
149
- `<integration_modes>`.
148
+ verbatim. `actor` MUST be `"agent"` or `"system"` the server
149
+ rejects `"user"`. HTTP 409 → mode-flip race window (§11.3.1); stop
150
+ and re-read `<integration_modes>`.
150
151
 
151
152
  ## 6. Owner notification (opt-in)
152
153
 
@@ -26,8 +26,10 @@ the update.
26
26
  - Update `roadmap.md` or `projects/*.md` only for material project-state changes
27
27
  - Schedule a wake-up if the observation implies a future reminder
28
28
  5. Apply the smallest meaningful set of context updates.
29
- 6. Mark processed observations consumed:
30
- `curl -s -X POST http://localhost:8321/api/observations/consume -H 'Content-Type: application/json' -d '{"ids":[1,2],"correlationId":"<event-correlation-id>"}'`
29
+ 6. Mark processed observations consumed via the bulk endpoint
30
+ (`POST /api/observations/consume`) see "POST /api/observations/consume"
31
+ in the API Reference below for the exact body shape and the
32
+ `correlationId` rule. There is no per-id variant.
31
33
 
32
34
  ## Skip Criteria
33
35
 
@@ -131,15 +133,105 @@ creating a duplicate. Subkind suffixes after the colon are by
131
133
  convention (`roadmap_candidate:calendar`, `roadmap_candidate:vault`,
132
134
  etc.) and are picked up by the prefix match on the GET route.
133
135
 
136
+ ### POST /api/observations/batch
137
+
138
+ Bulk-insert up to 200 observations in a single transaction. Use this
139
+ whenever a single fetch surface (a mail window, a calendar query, a
140
+ Notion page list) yields more than one observation — calling
141
+ `POST /api/observations` once per item collides with the Bash hook
142
+ that caps each curl invocation at one HTTP request and strips heredoc
143
+ bodies before URL validation. The batch endpoint resolves the
144
+ cardinality mismatch without weakening either hook.
145
+
146
+ ```bash
147
+ curl -s -X POST http://localhost:8321/api/observations/batch \
148
+ -H 'Content-Type: application/json' \
149
+ -d @- <<'JSON'
150
+ {
151
+ "observations": [
152
+ {"source":"gmail:acct-1","ref":"msg-123","changeType":"created","actor":"agent",
153
+ "payload":{"kind":"mail","providerId":"acct-1","raw":{"subject":"…","from":"…","snippet":"…","date":"…"}}},
154
+ {"source":"gmail:acct-1","ref":"msg-124","changeType":"created","actor":"agent",
155
+ "payload":{"kind":"mail","providerId":"acct-1","raw":{"subject":"…","from":"…","snippet":"…","date":"…"}}}
156
+ ]
157
+ }
158
+ JSON
159
+ ```
160
+
161
+ Per-element shape mirrors `POST /api/observations` exactly. Same
162
+ forgery guard (`actor` must be `"agent"` or `"system"`), same
163
+ server-side `(source, payload)` content-hash dedup.
164
+
165
+ Response is always `200` with envelope:
166
+
167
+ ```json
168
+ {
169
+ "results": [
170
+ {"index":0,"status":"created","source":"gmail:acct-1","ref":"msg-123","contentHash":"…","id":42},
171
+ {"index":1,"status":"duplicate","source":"gmail:acct-1","ref":"msg-124","contentHash":"…","id":17}
172
+ ],
173
+ "fetched": 2,
174
+ "posted": 1,
175
+ "duplicates": 1,
176
+ "errors": 0
177
+ }
178
+ ```
179
+
180
+ `results[*].status` is one of `"created"`, `"modified"`, `"duplicate"`,
181
+ `"flip_locked"` (integration mode-flip in progress — retry on the next
182
+ tick), `"validation_error"` (malformed item; `error` field names the
183
+ issue). The envelope's `posted` / `duplicates` / `errors` counters are
184
+ pre-aggregated; the per-item array is for correlating a failure back
185
+ to a specific input.
186
+
187
+ Hard limits:
188
+
189
+ - Max 200 items per call. Larger batches return 400 `batch_too_large` —
190
+ split into chunks.
191
+ - 1 MiB body cap (shared with the single-item route).
192
+ - Envelope JSON must have an `observations` array; missing or
193
+ non-array returns 400 `validation_error` with a hint.
194
+
134
195
  ### POST /api/observations/consume
135
196
 
197
+ Marks one or more observations consumed. **Bulk-only** — there is no
198
+ per-id endpoint (`POST /api/observations/<id>/consume` returns 404).
199
+ Always use this shape, even for a single id.
200
+
201
+ Copy the `correlationId` value verbatim from the
202
+ `<event_correlation_id>…</event_correlation_id>` tag in your turn
203
+ context — do not paste the angle-bracket placeholder.
204
+
136
205
  ```bash
206
+ # Example: <event_correlation_id>hourly-2026-04-23T15:00:00Z-7af3</event_correlation_id>
207
+ # arrived in context, and observations 14 and 17 were processed.
137
208
  curl -s -X POST http://localhost:8321/api/observations/consume \
138
209
  -H 'Content-Type: application/json' \
139
- -d '{"ids": [1, 2, 3], "correlationId": "<event_correlation_id>"}'
210
+ -d '{"ids":[14,17],"correlationId":"hourly-2026-04-23T15:00:00Z-7af3"}'
140
211
  ```
141
212
 
142
- Response: `{ "consumed": 3 }`
213
+ | Field | Type | Required | Notes |
214
+ |---|---|---|---|
215
+ | `ids` | `number[]` | yes | Integers, not strings. `["14"]` is rejected. |
216
+ | `correlationId` | `string` | yes | camelCase, verbatim from the `<event_correlation_id>` context tag. Non-string, missing, snake_case `correlation_id`, or the literal placeholder `<...>` → 400. |
217
+
218
+ Response: `{ "consumed": <count>, "notFound": [<id>...] }`. Validation
219
+ failures return 400 with `{ "error": "validation_error", "issues": [...], "expectedShape": "...", "example": "..." }`. **Read the
220
+ `issues` array — each entry names the offending field and a one-line
221
+ fix. Do NOT retry with a different shape unless the issue list tells
222
+ you to.**
223
+
224
+ #### Common mistakes — do not retry these, they will keep failing
225
+
226
+ | Wrong call | Why it fails | Correct shape |
227
+ |---|---|---|
228
+ | `POST /api/observations -d 'limit=30'` | Body is a query string. POST records, GET fetches. | `GET /api/observations?limit=30&pending=true` |
229
+ | `POST /api/observations/14/consume` | Per-id path returns 405 `use_bulk_endpoint`. | `POST /api/observations/consume -d '{"ids":[14],"correlationId":"..."}'` |
230
+ | `GET /api/observations/consume` | Consume is POST-only; GET returns 405. | `POST /api/observations/consume -d '{"ids":[...],"correlationId":"..."}'` |
231
+ | `PATCH /api/observations` | No PATCH route — auth middleware returns 401. | `POST /api/observations/consume` (or `POST /api/observations` for new rows). |
232
+ | `-d '{"ids":[14],"correlation_id":"..."}'` | snake_case. Field must be camelCase. | `-d '{"ids":[14],"correlationId":"..."}'` |
233
+ | `-d '{"ids":["14"],"correlationId":"..."}'` | Stringified ids. Use integers. | `-d '{"ids":[14],"correlationId":"..."}'` |
234
+ | `-d '{"ids":[14],"correlationId":"<event_correlation_id>"}'` | Pasted the angle-bracket placeholder. | Paste the actual id, e.g. `"hourly-2026-04-23T15:00:00Z-7af3"`. |
143
235
 
144
236
  ### GET /api/observations/stats
145
237
 
@@ -192,17 +284,20 @@ involved. Resolve `<databaseId>` first by reading the un-gated
192
284
  (`curl -s http://localhost:8321/api/notion/databases`) and then pass
193
285
  the UUID to the connector's data-source / search tool:
194
286
 
195
- | session backend | structured filter (data-source query) | listing fallback (no filter support) | workspace search |
196
- |-----------------|----------------------------------------------------|----------------------------------------------|-------------------------|
197
- | claude | n/a — connector has no filtered query | `mcp__claude_ai_Notion__notion-fetch` | `mcp__claude_ai_Notion__notion-search` |
198
- | codex | `mcp__codex_apps__notion._notion_query_data_sources` | `mcp__codex_apps__notion._fetch` | `mcp__codex_apps__notion._search` |
199
- | gemini | n/a — connector has no filtered query | `mcp_notion_notion-fetch` | `mcp_notion_notion-search` |
200
-
201
- For Claude / Gemini sessions: call the listing tool against the data
202
- source and post-filter in this skill (the structured-filter capability
203
- is Codex-only). For Codex sessions: pass the SQLite-style `WHERE`
204
- clause directly to `_notion_query_data_sources`. See the `notion`
205
- skill body for full property-naming and write-tier conventions.
287
+ | session backend | structured filter (data-source query) | listing fallback (no filter support) | workspace search |
288
+ |-----------------|---------------------------------------|--------------------------------------|------------------|
289
+ | claude | n/a — hosted connector has no filtered query | in-session Notion page-fetch capability | in-session Notion search capability |
290
+ | codex | in-session Notion data-source-query capability | in-session Notion fetch capability | in-session Notion search capability |
291
+ | gemini | n/a — hosted connector has no filtered query | in-session Notion page-fetch capability | in-session Notion search capability |
292
+
293
+ The exact tool names depend on which Notion connector your harness has
294
+ loaded pick them from your tool menu at session start by capability.
295
+ For Claude / Gemini sessions: call the listing capability against the
296
+ data source and post-filter in this skill (the structured-filter
297
+ capability is typically Codex-only). For Codex sessions: pass the
298
+ SQLite-style `WHERE` clause directly to the data-source-query
299
+ capability. See the `notion` skill body for full property-naming and
300
+ write-tier conventions.
206
301
  <!-- /mode:delegated-same:notion -->
207
302
  <!-- mode:delegated-cross:notion -->
208
303
  The `/api/notion/query|search|pages` routes return 410 in delegated
@@ -231,6 +326,19 @@ Do NOT call `/api/notion/{query,search,pages}` directly (returns
231
326
  tools — that connector reads a different workspace than the user's
232
327
  delegated one.
233
328
  <!-- /mode:delegated-cross:notion -->
329
+ <!-- mode:native:notion -->
330
+ Notion is in native mode — the `/api/notion/{query,search,pages}`
331
+ routes return 410 `{"error":"integration_native"}` and the daemon
332
+ does not host an `/exec` proxy. Use your session backend's native
333
+ Notion MCP tools directly; the materialized `notion` skill body
334
+ (`SKILL.native.<session-backend>.md`) lists the per-backend tool
335
+ names and the canonical search / fetch call shapes. Resolve
336
+ `<databaseId>` first via the un-gated config dump
337
+ (`curl -s http://localhost:8321/api/notion/databases`) and pass the
338
+ UUID to the connector's data-source / search tool. Do NOT call
339
+ `/api/notion/*` (410) or `/api/integrations/notion/exec` (also 410
340
+ in native mode).
341
+ <!-- /mode:native:notion -->
234
342
  <!-- mode:disabled:notion -->
235
343
  Notion is disabled — there is no live source. Treat the observation
236
344
  as preview-only and proceed without a Notion fetch.
@@ -233,6 +233,25 @@ recipe — they always emit the full section schema.
233
233
  Roadmap writes serialize via an optional exclusive lock so a
234
234
  mid-session refresh is not interleaved with a DM handler PATCH.
235
235
 
236
+ **Lock endpoint paths — get the order right:**
237
+
238
+ | Operation | Method | Path |
239
+ |---|---|---|
240
+ | Acquire | `POST` | `/api/context/lock/roadmap` |
241
+ | Release | `DELETE` | `/api/context/lock/roadmap` |
242
+
243
+ **Common mistakes (NOT registered):**
244
+
245
+ - `POST /api/context/roadmap/lock` — order reversed
246
+ - `POST /api/context/roadmap/write-lock` — order reversed and wrong noun
247
+ - `POST /api/context/lock/roadmap-write` — wrong noun
248
+
249
+ Any of these return `404 {"error":"unknown_route", ...}` with a hint
250
+ pointing at the correct path — re-read the table above and resend. The
251
+ correct lock endpoints are Autonomous-tier, so no bearer token is
252
+ required; if you see `401 {"error":"unauthorized"}` from a path you
253
+ believe is correct, the path is still wrong.
254
+
236
255
  - If `<roadmap_write_lock_id>` is in your context, include
237
256
  `X-Lock-Id: <roadmap_write_lock_id>` on every PUT / PATCH to
238
257
  `/api/context/roadmap`.
@@ -246,6 +265,12 @@ mid-session refresh is not interleaved with a DM handler PATCH.
246
265
 
247
266
  ## roadmap.md API
248
267
 
268
+ Body submission follows `_safety.md` "Daemon-API body submission":
269
+ small POST / PATCH bodies use inline `-d '{...}'`; the full-file PUT
270
+ runs multi-KB and uses the stdin heredoc `-d @- <<'JSON'` shape.
271
+ Include `X-Lock-Id: <roadmap_write_lock_id>` on every PUT / PATCH
272
+ when that tag is in your context.
273
+
249
274
  ```bash
250
275
  # Read
251
276
  curl -s http://localhost:8321/api/context/roadmap
@@ -254,19 +279,21 @@ curl -s http://localhost:8321/api/context/roadmap
254
279
  curl -s -X POST http://localhost:8321/api/context/roadmap/id \
255
280
  -H 'Content-Type: application/json' \
256
281
  -H 'X-Lock-Id: <roadmap_write_lock_id>' \
257
- -d '{"creationDate": "YYYY-MM-DD"}'
282
+ -d '{"creationDate":"YYYY-MM-DD"}'
258
283
 
259
- # Full replace (roadmap refresh — include X-Lock-Id if context provides one)
284
+ # Full replace (roadmap refresh)multi-KB body, use heredoc.
260
285
  curl -s -X PUT http://localhost:8321/api/context/roadmap \
261
286
  -H 'Content-Type: application/json' \
262
287
  -H 'X-Lock-Id: <roadmap_write_lock_id>' \
263
- -d '{"content": "# Roadmap\n..."}'
288
+ -d @- <<'JSON'
289
+ {"content":"# Roadmap\n> Last synced: 2026-04-23\n\n## Annual Goals\n- ...\n\n## Quarterly Focus\n- ...\n\n## Long-term Plans\n- [2026-Q3] ... <!-- id: rm-20260419-b8e7d4 -->\n\n## Agent Action Plan\n\n## Recurring\n- Every Friday: weekly review\n"}
290
+ JSON
264
291
 
265
292
  # Section PATCH
266
293
  curl -s -X PATCH http://localhost:8321/api/context/roadmap \
267
294
  -H 'Content-Type: application/json' \
268
295
  -H 'X-Lock-Id: <roadmap_write_lock_id>' \
269
- -d '{"section": "long_term_plans", "mode": "append", "content": "- [2026-Q3] ...\n"}'
296
+ -d '{"section":"long_term_plans","mode":"append","content":"- [2026-Q3] ...\n"}'
270
297
  ```
271
298
 
272
299
  Snapshotting, mtime updates, and path validation are handled by the
@@ -35,11 +35,52 @@ user but compound into duplicate DMs/notifications at fire time.
35
35
  confirm no recurring rule already covers this cadence (e.g. a daily
36
36
  09:00 inbox triage). If covered, skip — the recurring instance will
37
37
  regenerate on its own.
38
+ 4. **`confirm_dedup_key` check (mandatory for `confirm:` sub-flow rows
39
+ only).** When scheduling a `dm_session` row with
40
+ `taskContext.sub_flow="confirm"`, additionally filter
41
+ `GET /api/schedule?status=pending,running` by
42
+ `taskContext.confirm_dedup_key`. Skip if any match exists —
43
+ regardless of `scheduledFor` distance or description match. The
44
+ confirm sub-flow's chained-fire model (see `scheduled.dm.md`
45
+ §"Confirmation follow-up" Step 3) and a hot-thread defer (Step 1
46
+ check 1) both inherit the same dedup_key, so a successor or defer
47
+ row legitimately occupies the queue with the same key — a second
48
+ gate firing for the same topic MUST yield to it rather than
49
+ double-asking.
50
+
51
+ ```bash
52
+ curl -s "http://localhost:8321/api/schedule?status=pending,running" \
53
+ | jq --arg k "<gate>:<stable-topic>" \
54
+ '[.items[] | select(.taskContext.confirm_dedup_key == $k)] | length'
55
+ ```
56
+
57
+ If the count is `≥ 1`, log to `## Agent Log` and proceed without
58
+ scheduling:
59
+ ```
60
+ - HH:MM [confirm] skipped <dedup_key>: row already pending
61
+ ```
62
+
63
+ **`confirm_dedup_key` shape contract.** The key is
64
+ `<gate>:<stable-topic>` — for example
65
+ `create_project:la-pm-masters`,
66
+ `roadmap_ambiguous:tokyo-trip-date`,
67
+ `managed_task_dedup:<existing-task-id>`. The gate scope ensures
68
+ two unrelated gates can't collide on the same topic name; the
69
+ topic component MUST be deterministic from the topic itself
70
+ (no timestamps, no message IDs, no random nonces) so re-fires of
71
+ the same gate produce the same key and this pre-flight catches
72
+ them.
73
+
74
+ This rule layers on top of bullets 1-3, which catch the common
75
+ recurring / Agent-Plan duplicates. Bullet 4 catches the case
76
+ where two confirms target the same topic at different scheduled
77
+ times (e.g. one queued for the morning briefing, another the
78
+ gate would queue for `+4h`).
38
79
 
39
80
  Log the skip to `## Agent Log`:
40
81
  `- HH:MM [schedule] skipped <subject>: duplicate of <planId|row>`.
41
82
 
42
- Only after all three clear do you create the new schedule.
83
+ Only after all four clear do you create the new schedule.
43
84
 
44
85
  ## When the user wants a durable rule, not a wake-up
45
86
 
@@ -151,7 +192,7 @@ curl -s -X POST http://localhost:8321/api/schedule \
151
192
  | `model` | No | `sonnet` (default) or `opus` |
152
193
  | `taskContext` | No | Structured metadata object |
153
194
 
154
- Rejects times in the past (> 1 min ago), same as `/api/schedule/dm`.
195
+ Response: `{ "status":"scheduled", "scheduleId":"123", "scheduledFor":"YYYY-MM-DD HH:MM:SS" }`. `scheduledFor` is the normalized UTC SQLite timestamp the daemon actually stored — log this verbatim instead of re-formatting the input `time`. Rejects times in the past (> 1 min ago), same as `/api/schedule/dm`.
155
196
 
156
197
  ### PATCH /api/schedule/:id — Edit a pending item
157
198
  ```bash
@@ -170,7 +211,7 @@ Param `status` (default `pending,running`): comma-separated `pending`, `running`
170
211
  Param `roadmapEligible=true`: return only rows that may become
171
212
  roadmap `Scheduled:` entries (`transient` / `low` excluded, `normal`
172
213
  only beyond 7 days, `strategic` included).
173
- Response: `{ "items":[{ "id","scheduledFor","taskType","description","prompt","status","createdAt" }] }` — `prompt` is `null` when no override is set.
214
+ Response: `{ "items":[{ "id","scheduledFor","taskType","description","prompt","status","model","taskContext","createdAt" }] }` — `prompt` is `null` when no override is set. `taskContext` is the parsed JSON object (or `null` when none was stored); use it for sub-flow-aware filtering, e.g. `jq '.items[] | select(.taskContext.confirm_dedup_key == "create_project:la-pm-masters")'`.
174
215
 
175
216
  ### DELETE /api/schedule/:id — Cancel a pending item
176
217
  ```bash
@@ -9,11 +9,31 @@ allowed-tools:
9
9
  # today.md Guide
10
10
 
11
11
  Output language: follow `<output_language_policy>`. today.md is
12
- Policy B — the six required H2 headers (`## User Schedule`,
13
- `## User Tasks`, `## Agent Plan`, `## Agent Notes`, `## Agent Log`,
14
- `## Handoff`) are skeleton and stay English; bullets, narrative, and
15
- free-text fields under them are written in `<settings primary_language>`.
16
- Preserve user-customized headers verbatim.
12
+ Policy B — the **skeleton lines listed below stay English verbatim**;
13
+ bullets, narrative, and free-text fields under each H2 are written in
14
+ `<settings primary_language>`. Preserve user-customized headers verbatim.
15
+
16
+ **Skeleton (do NOT translate — exact-regex-validated on PUT):**
17
+
18
+ 1. **Line 1** — `# YYYY-MM-DD (day-of-week)` H1 date line. The weekday
19
+ inside `(...)` is free-form and may be localized; the rest is fixed.
20
+ 2. **Line 2** — `> Day type: …` blockquote (full pattern below). Field
21
+ labels (`Day type`, `Work focus`, `Study focus`, `Personal focus`),
22
+ values (`Weekday`/`Weekend`, `on`/`off`), pipe separators (` | `),
23
+ and the leading `> ` are **all English ASCII, fixed casing, fixed
24
+ spacing**. This is parsed by every downstream event handler.
25
+ 3. **The six H2 headers** — `## User Schedule`, `## User Tasks`,
26
+ `## Agent Plan`, `## Agent Notes`, `## Agent Log`, `## Handoff` —
27
+ in this order.
28
+
29
+ A `PUT /api/context/today` whose line 1 or line 2 fails the exact regex
30
+ is rejected with 400 and the daemon does NOT write the file. Translating
31
+ any keyword on line 2 (the field labels, the `Weekday`/`Weekend` value,
32
+ or `on`/`off`) into the user's primary language is the most common
33
+ failure mode — keep it English even when the rest of today.md is being
34
+ written in another language. The `<output_language_policy>` skeleton
35
+ precedence rule already covers this; this paragraph just makes the
36
+ consequence explicit.
17
37
 
18
38
  today.md has a **day-type header line** (second line) and **six required sections**.
19
39
 
@@ -186,15 +206,34 @@ PUT today.md must contain the H1 date line, day-type header quote, and all six s
186
206
 
187
207
  ## today.md API (subset of context API)
188
208
 
209
+ Body submission follows the rule in `_safety.md` "Daemon-API body
210
+ submission": small section PATCHes use inline `-d '{...}'`; full-file
211
+ PUT uses the stdin heredoc `-d @- <<'JSON'` shape because the body
212
+ runs multi-KB. Add `X-Lock-Id: <today_write_lock_id>` on every
213
+ PUT / PATCH when that tag is in your context.
214
+
189
215
  ```bash
190
- curl -s http://localhost:8321/api/context/today # Read
191
- curl -s -X PUT http://localhost:8321/api/context/today \ # Full replace (Morning only)
192
- -H 'Content-Type: application/json' -d '{"content": "# 2026-04-02 (Thu)\n..."}'
193
- curl -s -X PATCH http://localhost:8321/api/context/today \ # Section operation
194
- -H 'Content-Type: application/json' -d '{"section": "agent_log", "mode": "append", "content": "- 09:35 ..."}'
216
+ # Read
217
+ curl -s http://localhost:8321/api/context/today
218
+
219
+ # Full replace Morning Routine only. Multi-KB body → heredoc.
220
+ curl -s -X PUT http://localhost:8321/api/context/today \
221
+ -H 'Content-Type: application/json' \
222
+ -H 'X-Lock-Id: <today_write_lock_id>' \
223
+ -d @- <<'JSON'
224
+ {"content":"# 2026-04-02 (Thursday)\n> Day type: Weekday | Work focus: on | Study focus: on | Personal focus: on\n\n## User Schedule\n- 14:00–15:00 Design review [work]\n\n## User Tasks\n- [ ] 11:00 Finalize Q2 draft [work]\n\n## Agent Plan\n- [ ] 08:55 DM reminder: standup [work] →DM\n\n## Agent Notes\n\n## Agent Log\n- 04:00 Morning Routine completed (day-type: Weekday)\n\n## Handoff\n- (none)\n"}
225
+ JSON
226
+
227
+ # Section operation — small body, inline `-d` is fine.
228
+ curl -s -X PATCH http://localhost:8321/api/context/today \
229
+ -H 'Content-Type: application/json' \
230
+ -H 'X-Lock-Id: <today_write_lock_id>' \
231
+ -d '{"section":"agent_log","mode":"append","content":"- 09:35 ..."}'
195
232
  ```
196
233
 
197
- Add `X-Lock-Id` header if `<today_write_lock_id>` is in context. See context skill for full API reference.
234
+ The H1 date and the `> Day type:` quote line are validated by exact
235
+ regex on PUT — keep both English-shaped exactly as the template. See
236
+ context skill for the full endpoint reference.
198
237
 
199
238
  ## Knowledge map — section shape (auto-curated)
200
239
 
@@ -43,6 +43,15 @@ enabled.
43
43
  `external-services` skill — cross-backend variant for worked
44
44
  examples).
45
45
  <!-- /mode:delegated-cross:google_calendar -->
46
+ <!-- mode:native:google_calendar -->
47
+ Native mode → use this session backend's native Calendar
48
+ list-events MCP tool (same call shape as `delegated-same`). The
49
+ materialized `external-services` skill body
50
+ (`SKILL.native.<session-backend>.md`) lists the per-backend tool
51
+ names. The daemon does not proxy in native mode;
52
+ `/api/calendar/events` returns 410 and
53
+ `/api/integrations/google_calendar/exec` returns 410 too.
54
+ <!-- /mode:native:google_calendar -->
46
55
  <!-- mode:disabled:google_calendar -->
47
56
  Disabled → skip this skill; there is no calendar to source events from.
48
57
  <!-- /mode:disabled:google_calendar -->