@aitne-sh/aitne 0.1.3 → 0.1.5
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.
- package/README.md +151 -147
- package/agent-assets/agent-profiles/_safety.md +14 -0
- package/agent-assets/agent-profiles/conversational.md +23 -1
- package/agent-assets/agent-profiles/observer.md +15 -0
- package/agent-assets/agent-profiles/routine-fetch-window.md +128 -0
- package/agent-assets/agent-profiles/routine.md +16 -0
- package/agent-assets/agent-profiles/task.md +15 -0
- package/agent-assets/docs/concepts/auth-health.md +25 -9
- package/agent-assets/docs/concepts/backends-and-tiers.md +40 -4
- package/agent-assets/docs/concepts/costs-and-quotas.md +87 -25
- package/agent-assets/docs/concepts/delegated-mode.md +7 -13
- package/agent-assets/docs/concepts/memory-model.md +14 -1
- package/agent-assets/docs/concepts/observations.md +19 -1
- package/agent-assets/docs/concepts/process-keys.md +5 -0
- package/agent-assets/docs/concepts/routines.md +22 -10
- package/agent-assets/docs/concepts/safety-model.md +3 -8
- package/agent-assets/docs/concepts/skills.md +36 -1
- package/agent-assets/docs/features/integrations/calendar.md +74 -3
- package/agent-assets/docs/features/integrations/git.md +4 -4
- package/agent-assets/docs/features/integrations/github.md +75 -107
- package/agent-assets/docs/features/lifestyle/git.md +169 -22
- package/agent-assets/docs/features/messaging/overview.md +10 -1
- package/agent-assets/docs/features/routines/morning-routine.md +1 -1
- package/agent-assets/docs/getting-started/01-what-is-this.md +30 -12
- package/agent-assets/docs/getting-started/02-first-steps.md +15 -4
- package/agent-assets/docs/getting-started/03-what-can-this-do.md +17 -2
- package/agent-assets/docs/guides/install-and-run.md +10 -1
- package/agent-assets/docs/guides/setup-wizard.md +43 -6
- package/agent-assets/docs/guides/switch-default-backend.md +7 -3
- package/agent-assets/docs/reference/skills.md +10 -1
- package/agent-assets/docs/troubleshooting/auth-failed.md +27 -8
- package/agent-assets/docs/troubleshooting/quota-exhausted.md +35 -12
- package/agent-assets/skills/context/SKILL.md +6 -0
- package/agent-assets/skills/external-services/SKILL.md +4 -0
- package/agent-assets/skills/external-services/SKILL.native.claude.md +320 -0
- package/agent-assets/skills/external-services/SKILL.native.codex.md +243 -0
- package/agent-assets/skills/external-services/SKILL.native.gemini.md +237 -0
- package/agent-assets/skills/mail/SKILL.md +42 -14
- package/agent-assets/skills/mail/SKILL.native.claude.md +175 -0
- package/agent-assets/skills/mail/SKILL.native.codex.md +165 -0
- package/agent-assets/skills/mail/SKILL.native.gemini.md +169 -0
- package/agent-assets/skills/management-task-modify/SKILL.md +2 -1
- package/agent-assets/skills/management-task-stop/SKILL.md +2 -2
- package/agent-assets/skills/notify/SKILL.md +4 -4
- package/agent-assets/skills/notion/SKILL.md +6 -0
- package/agent-assets/skills/notion/SKILL.native.claude.md +202 -0
- package/agent-assets/skills/notion/SKILL.native.codex.md +166 -0
- package/agent-assets/skills/notion/SKILL.native.gemini.md +167 -0
- package/agent-assets/skills/observations/SKILL.md +29 -4
- package/agent-assets/skills/project-doc/SKILL.md +6 -0
- package/agent-assets/skills/reading/SKILL.md +2 -0
- package/agent-assets/skills/roadmap/SKILL.md +19 -4
- package/agent-assets/skills/today/SKILL.md +32 -6
- package/agent-assets/skills/user-interview/SKILL.md +1 -1
- package/agent-assets/skills/user-profile/SKILL.md +7 -0
- package/agent-assets/task-flows/_partials/calendar-acquire.google_calendar.md +119 -0
- package/agent-assets/task-flows/_partials/calendar-acquire.outlook_calendar.md +101 -0
- package/agent-assets/task-flows/_partials/mail-acquire.gmail.md +113 -0
- package/agent-assets/task-flows/_partials/mail-acquire.outlook_mail.md +97 -0
- package/agent-assets/task-flows/_partials/notion-acquire.notion.md +104 -0
- package/agent-assets/task-flows/git.project.refresh_architecture.md +24 -1
- package/agent-assets/task-flows/message.received.dm.md +3 -0
- package/agent-assets/task-flows/message.received.dm.native.claude.md +76 -0
- package/agent-assets/task-flows/message.received.dm.native.codex.md +57 -0
- package/agent-assets/task-flows/message.received.dm.native.gemini.md +70 -0
- package/agent-assets/task-flows/message.received.dm_first.md +3 -0
- package/agent-assets/task-flows/message.received.dm_first.native.claude.md +56 -0
- package/agent-assets/task-flows/message.received.dm_first.native.codex.md +48 -0
- package/agent-assets/task-flows/message.received.dm_first.native.gemini.md +54 -0
- package/agent-assets/task-flows/routine.evening_review.md +28 -1
- package/agent-assets/task-flows/routine.fetch_window.md +93 -0
- package/agent-assets/task-flows/routine.hourly_check.md +44 -5
- package/agent-assets/task-flows/routine.monthly_review.md +13 -2
- package/agent-assets/task-flows/routine.morning_routine.md +55 -42
- package/agent-assets/task-flows/routine.morning_routine_initial.md +37 -38
- package/agent-assets/task-flows/routine.roadmap_refresh.md +45 -49
- package/agent-assets/task-flows/routine.today_refresh.md +53 -96
- package/agent-assets/task-flows/routine.weekly_review.md +40 -17
- package/agent-assets/task-flows/scheduled.dm.md +13 -11
- package/agent-assets/task-flows/scheduled.task.md +2 -2
- package/agent-assets/task-flows/setup.initial.md +53 -25
- package/agent-assets/task-flows/setup.update.md +1 -1
- package/agent-assets/templates/README.md +13 -6
- package/package.json +47 -23
- package/agent-assets/task-flows/routine.hourly_check.delegated.claude.md +0 -405
- package/agent-assets/task-flows/routine.hourly_check.delegated.codex.md +0 -400
- package/agent-assets/task-flows/routine.hourly_check.delegated.gemini.md +0 -404
- package/scripts/check-redaction-coverage.mjs +0 -109
- package/scripts/commands.md +0 -0
- package/scripts/message-discipline-digest.mjs +0 -535
- package/scripts/poc/google-connector-inheritance/REPORT.md +0 -197
- package/scripts/poc/google-connector-inheritance/claude-sdk-probe.mjs +0 -79
- package/scripts/remint-roadmap-ids.mjs +0 -257
- package/scripts/smoke-obsidian-api.mjs +0 -166
|
@@ -8,6 +8,13 @@ allowed-tools:
|
|
|
8
8
|
|
|
9
9
|
# today.md Guide
|
|
10
10
|
|
|
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.
|
|
17
|
+
|
|
11
18
|
today.md has a **day-type header line** (second line) and **six required sections**.
|
|
12
19
|
|
|
13
20
|
```
|
|
@@ -179,15 +186,34 @@ PUT today.md must contain the H1 date line, day-type header quote, and all six s
|
|
|
179
186
|
|
|
180
187
|
## today.md API (subset of context API)
|
|
181
188
|
|
|
189
|
+
Body submission follows the rule in `_safety.md` "Daemon-API body
|
|
190
|
+
submission": small section PATCHes use inline `-d '{...}'`; full-file
|
|
191
|
+
PUT uses the stdin heredoc `-d @- <<'JSON'` shape because the body
|
|
192
|
+
runs multi-KB. Add `X-Lock-Id: <today_write_lock_id>` on every
|
|
193
|
+
PUT / PATCH when that tag is in your context.
|
|
194
|
+
|
|
182
195
|
```bash
|
|
183
|
-
|
|
184
|
-
curl -s
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
196
|
+
# Read
|
|
197
|
+
curl -s http://localhost:8321/api/context/today
|
|
198
|
+
|
|
199
|
+
# Full replace — Morning Routine only. Multi-KB body → heredoc.
|
|
200
|
+
curl -s -X PUT http://localhost:8321/api/context/today \
|
|
201
|
+
-H 'Content-Type: application/json' \
|
|
202
|
+
-H 'X-Lock-Id: <today_write_lock_id>' \
|
|
203
|
+
-d @- <<'JSON'
|
|
204
|
+
{"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"}
|
|
205
|
+
JSON
|
|
206
|
+
|
|
207
|
+
# Section operation — small body, inline `-d` is fine.
|
|
208
|
+
curl -s -X PATCH http://localhost:8321/api/context/today \
|
|
209
|
+
-H 'Content-Type: application/json' \
|
|
210
|
+
-H 'X-Lock-Id: <today_write_lock_id>' \
|
|
211
|
+
-d '{"section":"agent_log","mode":"append","content":"- 09:35 ..."}'
|
|
188
212
|
```
|
|
189
213
|
|
|
190
|
-
|
|
214
|
+
The H1 date and the `> Day type:` quote line are validated by exact
|
|
215
|
+
regex on PUT — keep both English-shaped exactly as the template. See
|
|
216
|
+
context skill for the full endpoint reference.
|
|
191
217
|
|
|
192
218
|
## Knowledge map — section shape (auto-curated)
|
|
193
219
|
|
|
@@ -37,7 +37,7 @@ curl -s http://localhost:8321/api/context/agent/profile-questions
|
|
|
37
37
|
| `target_path` | which user file the answer should land in, e.g. `user/profile.md` |
|
|
38
38
|
| `## Section` | optional — narrows to a section within the target file |
|
|
39
39
|
| `match=<anchor>` | optional — bullet key (English, like `Name`, `Timezone`, `Sleep`, `Working hours`). Required when multiple rows share a section, or when setup pre-seeds the section with an unrelated bullet |
|
|
40
|
-
| `ask-hint` | English brief of WHAT to ask. Render the actual DM
|
|
40
|
+
| `ask-hint` | English brief of WHAT to ask (agent-internal, Policy A). Render the actual DM per `<output_language_policy>` — this skill intentionally splits the two surfaces |
|
|
41
41
|
| `last_attempted=...` | optional inline HTML comment maintained by the evening sweep — selector deprioritises rows whose comment is < 7 days old |
|
|
42
42
|
|
|
43
43
|
### In Progress entry format
|
|
@@ -8,6 +8,13 @@ allowed-tools:
|
|
|
8
8
|
|
|
9
9
|
# User Profile Update Guide
|
|
10
10
|
|
|
11
|
+
Output language: follow `<output_language_policy>`. `user/profile.md`
|
|
12
|
+
and `user/*.md` are Policy B — template H2 headers (`## Identity`,
|
|
13
|
+
`## Work Pattern`, `## Platforms`, `## Expertise`, `## Notification
|
|
14
|
+
Preferences`, `## Learned Context`, `## Raw Signals`) are skeleton and
|
|
15
|
+
stay English; the facts you write under them are in
|
|
16
|
+
`<settings primary_language>`. Preserve user-customized headers verbatim.
|
|
17
|
+
|
|
11
18
|
`user/profile.md` stores the user's identity, preferences, and learned behavioral patterns. It is injected into every agent session via `<user>` tags — keep it concise (target: under ~600 tokens total).
|
|
12
19
|
|
|
13
20
|
Detailed, dictionary-like background belongs under `user/*.md`. Read `user/_index.md` first, then fetch only the topic file you need.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: calendar-acquire.google_calendar
|
|
3
|
+
description: Acquire a Google Calendar event window per <acquisition-plan> row.
|
|
4
|
+
spec: ROUTINE_DATA_ACQUISITION_DESIGN.md §6.8 / §8.3
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Google Calendar acquisition
|
|
8
|
+
|
|
9
|
+
For every `<fetch integration="google_calendar" ...>` row in
|
|
10
|
+
`<acquisition-plan>`, take the branch below that matches the row's `mode`
|
|
11
|
+
attribute. Calendar rows do not fan out per account today — the dispatcher
|
|
12
|
+
emits one row per active provider, scoped to the bound primary calendar.
|
|
13
|
+
|
|
14
|
+
Note on coverage: routines whose calendar window is already covered by
|
|
15
|
+
`ContextBuilder.buildCalendarBlock` (the `<calendar_events_*>` blocks) do
|
|
16
|
+
**not** appear in the pre-pass plan for the same window — that would
|
|
17
|
+
double-fetch. The catalog only emits drift / retrospective / imminent
|
|
18
|
+
windows for the pre-pass.
|
|
19
|
+
|
|
20
|
+
POST every returned event to `http://localhost:8321/api/observations`:
|
|
21
|
+
|
|
22
|
+
- `source` = `"google_calendar:<calendarId>"` (use `"primary"` when the
|
|
23
|
+
provider returns no explicit id)
|
|
24
|
+
- `ref` = provider-side stable event id
|
|
25
|
+
- `changeType` = `"created"` for fresh events; `"modified"` when the
|
|
26
|
+
payload updates an existing `(source, ref)`; `"deleted"` for cancelled
|
|
27
|
+
events (payload = `{ "kind": "calendar", "providerId": "<calendarId>",
|
|
28
|
+
"raw": { "deletedAt": "<iso>" } }`)
|
|
29
|
+
- `actor` = `"agent"`
|
|
30
|
+
- `payload` = `{ "kind": "calendar", "providerId": "<calendarId>",
|
|
31
|
+
"raw": { "title": ..., "start": ..., "end": ...,
|
|
32
|
+
"attendees": [...], "status": ... } }`
|
|
33
|
+
|
|
34
|
+
Server computes the dedup hash from `(source, payload)`. Response shape:
|
|
35
|
+
|
|
36
|
+
- `200 {action: "created"|"modified"}` — fresh / updated row; count in `posted`.
|
|
37
|
+
- `409 {error: "duplicate"}` — identical payload already pending; count in `duplicates`.
|
|
38
|
+
- `409 {error: "integration_flip_in_progress"}` — append
|
|
39
|
+
`{type:"flip-locked","integration":"google_calendar"}` to `errors`
|
|
40
|
+
and move on.
|
|
41
|
+
|
|
42
|
+
<!-- mode:direct:google_calendar -->
|
|
43
|
+
GET `http://localhost:8321/api/calendar/events<query>` where `<query>` is
|
|
44
|
+
the literal `query` attribute of the `<fetch>` row (e.g.
|
|
45
|
+
`?date=2026-05-11&days=1` or `?date=2026-05-04&days=7`). The route
|
|
46
|
+
accepts `date=YYYY-MM-DD` (or `today`) plus `days=N` (≤90); `timeMin`
|
|
47
|
+
/ `timeMax` are NOT recognised. The daemon returns `{ "events": [...] }`;
|
|
48
|
+
map each event into one observation POST as specified above.
|
|
49
|
+
<!-- /mode:direct:google_calendar -->
|
|
50
|
+
|
|
51
|
+
<!-- mode:delegated-same:google_calendar -->
|
|
52
|
+
The connector is bound to your own session backend. Use the in-session
|
|
53
|
+
connector surface your skills document; the `<fetch>` row's `query`
|
|
54
|
+
attribute carries the catalog's `delegated` form (e.g.
|
|
55
|
+
`timeMin="..." timeMax="..." maxResults=50`). Translate it into the args
|
|
56
|
+
your bound surface accepts. POST every returned event as specified above.
|
|
57
|
+
<!-- /mode:delegated-same:google_calendar -->
|
|
58
|
+
|
|
59
|
+
<!-- mode:delegated-cross:google_calendar -->
|
|
60
|
+
The connector is bound to a different backend than this session — reach
|
|
61
|
+
it through the daemon's delegation proxy. POST to
|
|
62
|
+
`http://localhost:8321/api/integrations/google_calendar/exec` with the
|
|
63
|
+
following body (substitute the row's `query` into `task`):
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"task": "List Google Calendar events for the window <query>. Return id, title, start, end, attendees (email + responseStatus), and status. Up to 100 events.",
|
|
68
|
+
"outputSchema": {
|
|
69
|
+
"type": "object",
|
|
70
|
+
"required": ["events"],
|
|
71
|
+
"properties": {
|
|
72
|
+
"events": {
|
|
73
|
+
"type": "array",
|
|
74
|
+
"items": {
|
|
75
|
+
"type": "object",
|
|
76
|
+
"required": ["id"],
|
|
77
|
+
"properties": {
|
|
78
|
+
"id": { "type": "string" },
|
|
79
|
+
"title": { "type": "string" },
|
|
80
|
+
"start": { "type": "string" },
|
|
81
|
+
"end": { "type": "string" },
|
|
82
|
+
"status": { "type": "string" },
|
|
83
|
+
"attendees": {
|
|
84
|
+
"type": "array",
|
|
85
|
+
"items": {
|
|
86
|
+
"type": "object",
|
|
87
|
+
"properties": {
|
|
88
|
+
"email": { "type": "string" },
|
|
89
|
+
"responseStatus": { "type": "string" }
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"maxToolCalls": 3,
|
|
99
|
+
"cacheable": true
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Map each item in `result.events[]` to one observation POST.
|
|
104
|
+
<!-- /mode:delegated-cross:google_calendar -->
|
|
105
|
+
|
|
106
|
+
<!-- mode:native:google_calendar -->
|
|
107
|
+
The connector is bound natively to your own session backend. Use the
|
|
108
|
+
in-session connector surface your skills document — same call shape as
|
|
109
|
+
`delegated-same`. The daemon does not proxy. POST every returned event as
|
|
110
|
+
specified above.
|
|
111
|
+
<!-- /mode:native:google_calendar -->
|
|
112
|
+
|
|
113
|
+
<!-- mode:disabled:google_calendar -->
|
|
114
|
+
Defensive no-op. The dispatcher filters disabled integrations out of
|
|
115
|
+
`<acquisition-plan>`. If a `<fetch integration="google_calendar">` row
|
|
116
|
+
still reaches this branch, skip it and append
|
|
117
|
+
`{"type":"unexpected-row","integration":"google_calendar","reason":"disabled-row-emitted"}`
|
|
118
|
+
to your `errors` array.
|
|
119
|
+
<!-- /mode:disabled:google_calendar -->
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: calendar-acquire.outlook_calendar
|
|
3
|
+
description: Acquire an Outlook Calendar event window per <acquisition-plan> row.
|
|
4
|
+
spec: ROUTINE_DATA_ACQUISITION_DESIGN.md §6.8 / §8.4
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Outlook Calendar acquisition
|
|
8
|
+
|
|
9
|
+
For every `<fetch integration="outlook_calendar" ...>` row in
|
|
10
|
+
`<acquisition-plan>`, take the branch below that matches the row's `mode`
|
|
11
|
+
attribute. Calendar rows do not fan out per account today — the dispatcher
|
|
12
|
+
emits one row per active provider, scoped to the bound primary calendar.
|
|
13
|
+
|
|
14
|
+
Outlook Calendar is a **user-managed** integration: the daemon has no
|
|
15
|
+
delegation proxy (no `/api/integrations/outlook_calendar/exec` exists).
|
|
16
|
+
The four non-disabled branches therefore split into two real flows:
|
|
17
|
+
|
|
18
|
+
- `direct` → the daemon's Outlook calendar route
|
|
19
|
+
(`/api/calendar/outlook/events`).
|
|
20
|
+
- `delegated-same`, `delegated-cross`, `native` → use the in-session
|
|
21
|
+
connector surface your skills document. The user picks the binding (an
|
|
22
|
+
in-session connector, a local CLI invoked via a skill, a custom
|
|
23
|
+
script); the partial states the intent, not specific tool names. If no
|
|
24
|
+
surface is bound, record an error and continue.
|
|
25
|
+
|
|
26
|
+
Note on coverage: when `ContextBuilder.buildCalendarBlock` already covers
|
|
27
|
+
the window via `<calendar_events_*>` (multi-provider after §6.6), the
|
|
28
|
+
catalog skips the pre-pass row to avoid double-fetching. The pre-pass
|
|
29
|
+
only ships drift / retrospective / imminent windows.
|
|
30
|
+
|
|
31
|
+
POST every returned event to `http://localhost:8321/api/observations`:
|
|
32
|
+
|
|
33
|
+
- `source` = `"outlook_calendar:<calendarId>"` (use `"primary"` when
|
|
34
|
+
the provider returns no explicit id)
|
|
35
|
+
- `ref` = provider-side stable event id
|
|
36
|
+
- `changeType` = `"created"` for fresh events; `"modified"` when the
|
|
37
|
+
payload updates an existing `(source, ref)`; `"deleted"` for cancelled
|
|
38
|
+
events
|
|
39
|
+
- `actor` = `"agent"`
|
|
40
|
+
- `payload` = `{ "kind": "calendar", "providerId": "<calendarId>",
|
|
41
|
+
"raw": { "title": ..., "start": ..., "end": ...,
|
|
42
|
+
"attendees": [...], "status": ... } }`
|
|
43
|
+
|
|
44
|
+
Server computes the dedup hash from `(source, payload)`. Response shape:
|
|
45
|
+
|
|
46
|
+
- `200 {action: "created"|"modified"}` — fresh / updated row; count in `posted`.
|
|
47
|
+
- `409 {error: "duplicate"}` — identical payload already pending; count in `duplicates`.
|
|
48
|
+
- `409 {error: "integration_flip_in_progress"}` — append
|
|
49
|
+
`{type:"flip-locked","integration":"outlook_calendar"}` to `errors`
|
|
50
|
+
and move on.
|
|
51
|
+
|
|
52
|
+
<!-- mode:direct:outlook_calendar -->
|
|
53
|
+
GET `http://localhost:8321/api/calendar/outlook/events<query>` where
|
|
54
|
+
`<query>` is the literal `query` attribute of the `<fetch>` row (e.g.
|
|
55
|
+
`?date=2026-05-11&days=1` or `?date=2026-05-04&days=7`). The route
|
|
56
|
+
accepts `date=YYYY-MM-DD` (or `today`) plus `days=N` (≤90); `timeMin`
|
|
57
|
+
/ `timeMax` are NOT recognised. The daemon returns
|
|
58
|
+
`{ "events": [...] }`; map each event into one observation POST as
|
|
59
|
+
specified above.
|
|
60
|
+
<!-- /mode:direct:outlook_calendar -->
|
|
61
|
+
|
|
62
|
+
<!-- mode:delegated-same:outlook_calendar -->
|
|
63
|
+
The integration is bound to your own session backend. Use the in-session
|
|
64
|
+
connector surface your skills document for Outlook Calendar; the
|
|
65
|
+
`<fetch>` row's `query` attribute carries the catalog's `delegated` form
|
|
66
|
+
(e.g. `startDateTime=... endDateTime=...`). Translate it into the args
|
|
67
|
+
your bound surface accepts. POST every returned event as specified above.
|
|
68
|
+
|
|
69
|
+
If no Outlook Calendar surface is bound, append
|
|
70
|
+
`{"type":"no-surface","integration":"outlook_calendar"}` to your `errors`
|
|
71
|
+
array and continue with the next row. Do NOT halt the pre-pass.
|
|
72
|
+
<!-- /mode:delegated-same:outlook_calendar -->
|
|
73
|
+
|
|
74
|
+
<!-- mode:delegated-cross:outlook_calendar -->
|
|
75
|
+
Outlook Calendar is user-managed, so the daemon does not host a
|
|
76
|
+
delegation proxy. The dispatcher should not have emitted a
|
|
77
|
+
`delegated-cross` row for this integration — if you see one, treat it
|
|
78
|
+
exactly like `delegated-same`: use whichever in-session connector
|
|
79
|
+
surface your skills document for Outlook Calendar. If nothing is bound,
|
|
80
|
+
append `{"type":"no-surface","integration":"outlook_calendar"}` to
|
|
81
|
+
`errors` and continue.
|
|
82
|
+
<!-- /mode:delegated-cross:outlook_calendar -->
|
|
83
|
+
|
|
84
|
+
<!-- mode:native:outlook_calendar -->
|
|
85
|
+
The integration is bound natively to your own session backend. Use the
|
|
86
|
+
in-session connector surface your skills document — same call shape as
|
|
87
|
+
`delegated-same`. The daemon does not proxy. POST every returned event as
|
|
88
|
+
specified above.
|
|
89
|
+
|
|
90
|
+
If no Outlook Calendar surface is bound, append
|
|
91
|
+
`{"type":"no-surface","integration":"outlook_calendar"}` to `errors` and
|
|
92
|
+
continue.
|
|
93
|
+
<!-- /mode:native:outlook_calendar -->
|
|
94
|
+
|
|
95
|
+
<!-- mode:disabled:outlook_calendar -->
|
|
96
|
+
Defensive no-op. The dispatcher filters disabled integrations out of
|
|
97
|
+
`<acquisition-plan>`. If a `<fetch integration="outlook_calendar">` row
|
|
98
|
+
still reaches this branch, skip it and append
|
|
99
|
+
`{"type":"unexpected-row","integration":"outlook_calendar","reason":"disabled-row-emitted"}`
|
|
100
|
+
to your `errors` array.
|
|
101
|
+
<!-- /mode:disabled:outlook_calendar -->
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mail-acquire.gmail
|
|
3
|
+
description: Acquire a Gmail message window per <acquisition-plan> row.
|
|
4
|
+
spec: ROUTINE_DATA_ACQUISITION_DESIGN.md §6.8 / §8.1
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Gmail acquisition
|
|
8
|
+
|
|
9
|
+
For every `<fetch integration="gmail" ...>` row in `<acquisition-plan>`, take
|
|
10
|
+
the branch below that matches the row's `mode` attribute and acquire the
|
|
11
|
+
window described by `query`. Each row carries `account="<accountId>"` — apply
|
|
12
|
+
the query against that account only, do not pool across accounts.
|
|
13
|
+
|
|
14
|
+
POST every returned message to `http://localhost:8321/api/observations` per
|
|
15
|
+
the contract in your agent profile (the response from the upstream call IS
|
|
16
|
+
the payload; do not summarise or rank). Use:
|
|
17
|
+
|
|
18
|
+
- `source` = `"gmail:<accountId>"`
|
|
19
|
+
- `ref` = provider-side stable message id
|
|
20
|
+
- `changeType` = `"created"` for fresh items; `"modified"` when the row updates
|
|
21
|
+
a payload the server already has under the same `(source, ref)`
|
|
22
|
+
- `actor` = `"agent"`
|
|
23
|
+
- `payload` = `{ "kind": "mail", "providerId": "<accountId>", "raw": {
|
|
24
|
+
"subject": ..., "from": ..., "snippet": ...,
|
|
25
|
+
"date": ... } }`
|
|
26
|
+
|
|
27
|
+
Do NOT compute the dedup hash — the server derives it from `(source, payload)`.
|
|
28
|
+
The response body shape distinguishes three outcomes:
|
|
29
|
+
|
|
30
|
+
- `200 {action: "created"}` — fresh row inserted; count it in `posted`.
|
|
31
|
+
- `200 {action: "modified"}` — same `(source, ref)` pending row existed
|
|
32
|
+
with a different payload; the row was updated and re-summarized.
|
|
33
|
+
Count it in `posted`.
|
|
34
|
+
- `409 {error: "duplicate"}` — same `(source, ref)` pending row already
|
|
35
|
+
stores an identical payload. Nothing was written; count it in
|
|
36
|
+
`duplicates` and move on.
|
|
37
|
+
- `409 {error: "integration_flip_in_progress"}` — a mode flip is
|
|
38
|
+
draining for this integration. Record
|
|
39
|
+
`{type:"flip-locked","integration":"gmail","account":"<accountId>"}`
|
|
40
|
+
in `errors` and continue with the next row (the parent routine will
|
|
41
|
+
retry on the next tick).
|
|
42
|
+
|
|
43
|
+
<!-- mode:direct:gmail -->
|
|
44
|
+
GET `http://localhost:8321/api/mail/<accountId>/messages<query>` where
|
|
45
|
+
`<query>` is the literal `query` attribute of the `<fetch>` row (e.g.
|
|
46
|
+
`?since=2026-05-11T00:00:00.000Z&limit=20` or
|
|
47
|
+
`?since=2026-05-11T10:00:00.000Z&unreadOnly=true&limit=10` or
|
|
48
|
+
`?folder=sent&since=2026-05-11T00:00:00.000Z&limit=30`). The route
|
|
49
|
+
accepts `since` (ISO 8601 datetime), `limit`, `folder`, `q`,
|
|
50
|
+
`unreadOnly` — `days=…` is NOT recognised. The daemon returns
|
|
51
|
+
`{ "messages": [...] }`; map each item to one POST as specified above.
|
|
52
|
+
<!-- /mode:direct:gmail -->
|
|
53
|
+
|
|
54
|
+
<!-- mode:delegated-same:gmail -->
|
|
55
|
+
The Gmail connector is bound to your own session backend. Use the in-session
|
|
56
|
+
connector surface your skills document for this integration; the `<fetch>`
|
|
57
|
+
row's `query` attribute carries the catalog's `delegated` form (e.g.
|
|
58
|
+
`q="newer_than:1d" maxResults=20`) — translate it into the args your bound
|
|
59
|
+
surface accepts. POST every returned message as specified above. The daemon
|
|
60
|
+
does not proxy in this branch.
|
|
61
|
+
<!-- /mode:delegated-same:gmail -->
|
|
62
|
+
|
|
63
|
+
<!-- mode:delegated-cross:gmail -->
|
|
64
|
+
The connector is bound to a different backend than this session, so reach it
|
|
65
|
+
through the daemon's delegation proxy. POST to
|
|
66
|
+
`http://localhost:8321/api/integrations/gmail/exec` with the following body
|
|
67
|
+
(substitute the row's `query` and `accountId` into `task`):
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"task": "On account <accountId>, search Gmail with the query expression <query> and return id, subject, from, snippet, date for each message. Up to 30 messages.",
|
|
72
|
+
"outputSchema": {
|
|
73
|
+
"type": "object",
|
|
74
|
+
"required": ["messages"],
|
|
75
|
+
"properties": {
|
|
76
|
+
"messages": {
|
|
77
|
+
"type": "array",
|
|
78
|
+
"items": {
|
|
79
|
+
"type": "object",
|
|
80
|
+
"required": ["id"],
|
|
81
|
+
"properties": {
|
|
82
|
+
"id": { "type": "string" },
|
|
83
|
+
"subject": { "type": "string" },
|
|
84
|
+
"from": { "type": "string" },
|
|
85
|
+
"snippet": { "type": "string" },
|
|
86
|
+
"date": { "type": "string" }
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"maxToolCalls": 3,
|
|
93
|
+
"cacheable": true
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Map each item in `result.messages[]` to one observation POST.
|
|
98
|
+
<!-- /mode:delegated-cross:gmail -->
|
|
99
|
+
|
|
100
|
+
<!-- mode:native:gmail -->
|
|
101
|
+
The connector is bound natively to your own session backend. Use the
|
|
102
|
+
in-session connector surface your skills document — same call shape as
|
|
103
|
+
`delegated-same`. The daemon does not proxy. POST every returned message as
|
|
104
|
+
specified above.
|
|
105
|
+
<!-- /mode:native:gmail -->
|
|
106
|
+
|
|
107
|
+
<!-- mode:disabled:gmail -->
|
|
108
|
+
Defensive no-op. The dispatcher filters disabled integrations out of
|
|
109
|
+
`<acquisition-plan>`, so no `<fetch integration="gmail">` row should ever
|
|
110
|
+
land in this branch. If one does, skip it and append
|
|
111
|
+
`{"type":"unexpected-row","integration":"gmail","reason":"disabled-row-emitted"}`
|
|
112
|
+
to your `errors` array.
|
|
113
|
+
<!-- /mode:disabled:gmail -->
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mail-acquire.outlook_mail
|
|
3
|
+
description: Acquire an Outlook Mail message window per <acquisition-plan> row.
|
|
4
|
+
spec: ROUTINE_DATA_ACQUISITION_DESIGN.md §6.8 / §8.2
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Outlook Mail acquisition
|
|
8
|
+
|
|
9
|
+
For every `<fetch integration="outlook_mail" ...>` row in `<acquisition-plan>`,
|
|
10
|
+
take the branch below that matches the row's `mode` attribute. Each row
|
|
11
|
+
carries `account="<accountId>"` — apply the query to that account only.
|
|
12
|
+
|
|
13
|
+
Outlook Mail is a **user-managed** integration: the daemon has no
|
|
14
|
+
delegation proxy for it (no `/api/integrations/outlook_mail/exec` exists).
|
|
15
|
+
The four non-disabled branches therefore split into two real flows:
|
|
16
|
+
|
|
17
|
+
- `direct` → the unified daemon mail route (transparently handles Outlook
|
|
18
|
+
accounts).
|
|
19
|
+
- `delegated-same`, `delegated-cross`, `native` → use the in-session
|
|
20
|
+
connector surface your skills document. The user picks the binding (an
|
|
21
|
+
in-session connector, a local CLI invoked via a skill, a custom script);
|
|
22
|
+
this partial states the intent, not specific tool names. If no surface
|
|
23
|
+
is bound, record an error and continue.
|
|
24
|
+
|
|
25
|
+
POST every returned message to `http://localhost:8321/api/observations`:
|
|
26
|
+
|
|
27
|
+
- `source` = `"outlook_mail:<accountId>"`
|
|
28
|
+
- `ref` = provider-side stable message id
|
|
29
|
+
- `changeType` = `"created"` for fresh items; `"modified"` when the row
|
|
30
|
+
updates a payload already known under `(source, ref)`
|
|
31
|
+
- `actor` = `"agent"`
|
|
32
|
+
- `payload` = `{ "kind": "mail", "providerId": "<accountId>", "raw": {
|
|
33
|
+
"subject": ..., "from": ..., "snippet": ...,
|
|
34
|
+
"date": ... } }`
|
|
35
|
+
|
|
36
|
+
The server computes the dedup hash from `(source, payload)`. Response
|
|
37
|
+
shape:
|
|
38
|
+
|
|
39
|
+
- `200 {action: "created"|"modified"}` — fresh / updated row; count in `posted`.
|
|
40
|
+
- `409 {error: "duplicate"}` — identical payload already pending; count in `duplicates`.
|
|
41
|
+
- `409 {error: "integration_flip_in_progress"}` — append
|
|
42
|
+
`{type:"flip-locked","integration":"outlook_mail","account":"<accountId>"}`
|
|
43
|
+
to `errors` and move on; do not retry inline.
|
|
44
|
+
|
|
45
|
+
<!-- mode:direct:outlook_mail -->
|
|
46
|
+
GET `http://localhost:8321/api/mail/<accountId>/messages<query>` where
|
|
47
|
+
`<query>` is the literal `query` attribute of the `<fetch>` row (e.g.
|
|
48
|
+
`?since=2026-05-11T00:00:00.000Z&limit=20` or
|
|
49
|
+
`?folder=sent&since=2026-05-11T00:00:00.000Z&limit=30`). The route
|
|
50
|
+
accepts `since` (ISO 8601), `limit`, `folder`, `q`, `unreadOnly` — it
|
|
51
|
+
does NOT accept `days=…`. The daemon returns `{ "messages": [...] }`
|
|
52
|
+
regardless of the underlying provider; map each item into one
|
|
53
|
+
observation POST as specified above.
|
|
54
|
+
<!-- /mode:direct:outlook_mail -->
|
|
55
|
+
|
|
56
|
+
<!-- mode:delegated-same:outlook_mail -->
|
|
57
|
+
The integration is bound to your own session backend. Use the in-session
|
|
58
|
+
connector surface your skills document for Outlook Mail. The `<fetch>`
|
|
59
|
+
row's `query` attribute carries the catalog's `delegated` form (e.g.
|
|
60
|
+
`filter=receivedDateTime ge 2026-05-11T00:00:00Z`) — translate it into the
|
|
61
|
+
args your bound surface accepts. POST every returned message as specified
|
|
62
|
+
above.
|
|
63
|
+
|
|
64
|
+
If no Outlook Mail surface is bound on this backend, append
|
|
65
|
+
`{"type":"no-surface","integration":"outlook_mail","account":"<accountId>"}`
|
|
66
|
+
to your `errors` array and continue with the next row. Do NOT halt the
|
|
67
|
+
pre-pass; the parent routine continues with whatever observations the rest
|
|
68
|
+
of the plan produced.
|
|
69
|
+
<!-- /mode:delegated-same:outlook_mail -->
|
|
70
|
+
|
|
71
|
+
<!-- mode:delegated-cross:outlook_mail -->
|
|
72
|
+
Outlook Mail is user-managed, so the daemon does not host a delegation
|
|
73
|
+
proxy. The dispatcher should not have emitted a `delegated-cross` row for
|
|
74
|
+
this integration — if you see one, treat it exactly like
|
|
75
|
+
`delegated-same`: use whichever in-session surface your skills document
|
|
76
|
+
for Outlook Mail. If nothing is bound, append
|
|
77
|
+
`{"type":"no-surface","integration":"outlook_mail","account":"<accountId>"}`
|
|
78
|
+
to `errors` and continue.
|
|
79
|
+
<!-- /mode:delegated-cross:outlook_mail -->
|
|
80
|
+
|
|
81
|
+
<!-- mode:native:outlook_mail -->
|
|
82
|
+
The integration is bound natively to your own session backend. Use the
|
|
83
|
+
in-session connector surface your skills document for Outlook Mail —
|
|
84
|
+
same call shape as `delegated-same`. The daemon does not proxy.
|
|
85
|
+
|
|
86
|
+
If no Outlook Mail surface is bound, append
|
|
87
|
+
`{"type":"no-surface","integration":"outlook_mail","account":"<accountId>"}`
|
|
88
|
+
to `errors` and continue.
|
|
89
|
+
<!-- /mode:native:outlook_mail -->
|
|
90
|
+
|
|
91
|
+
<!-- mode:disabled:outlook_mail -->
|
|
92
|
+
Defensive no-op. The dispatcher filters disabled integrations out of
|
|
93
|
+
`<acquisition-plan>`. If a `<fetch integration="outlook_mail">` row still
|
|
94
|
+
reaches this branch, skip it and append
|
|
95
|
+
`{"type":"unexpected-row","integration":"outlook_mail","reason":"disabled-row-emitted"}`
|
|
96
|
+
to your `errors` array.
|
|
97
|
+
<!-- /mode:disabled:outlook_mail -->
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: notion-acquire.notion
|
|
3
|
+
description: Acquire recently-updated Notion pages per <acquisition-plan> row.
|
|
4
|
+
spec: ROUTINE_DATA_ACQUISITION_DESIGN.md §6.8 / §8.5
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Notion acquisition
|
|
8
|
+
|
|
9
|
+
For every `<fetch integration="notion" ...>` row in `<acquisition-plan>`,
|
|
10
|
+
take the branch below that matches the row's `mode` attribute. Notion rows
|
|
11
|
+
do not fan out per account — the dispatcher emits one row per workspace.
|
|
12
|
+
|
|
13
|
+
POST every returned page to `http://localhost:8321/api/observations`:
|
|
14
|
+
|
|
15
|
+
- `source` = `"notion:<workspaceId>"` (use `"default"` when the daemon
|
|
16
|
+
reports no explicit workspace id)
|
|
17
|
+
- `ref` = Notion page id (stable UUID)
|
|
18
|
+
- `changeType` = `"created"` for fresh pages; `"modified"` when the
|
|
19
|
+
payload updates an existing `(source, ref)`
|
|
20
|
+
- `actor` = `"agent"`
|
|
21
|
+
- `payload` = `{ "kind": "notion", "providerId": "<workspaceId>",
|
|
22
|
+
"raw": { "title": ..., "last_edited": ...,
|
|
23
|
+
"parent": ..., "url": ... } }`
|
|
24
|
+
|
|
25
|
+
The server computes the dedup hash from `(source, payload)`. Response shape:
|
|
26
|
+
|
|
27
|
+
- `200 {action: "created"|"modified"}` — fresh / updated row; count in `posted`.
|
|
28
|
+
- `409 {error: "duplicate"}` — identical payload already pending; count in `duplicates`.
|
|
29
|
+
- `409 {error: "integration_flip_in_progress"}` — append
|
|
30
|
+
`{type:"flip-locked","integration":"notion"}` to `errors` and move on.
|
|
31
|
+
|
|
32
|
+
<!-- mode:direct:notion -->
|
|
33
|
+
GET `http://localhost:8321/api/notion/search<query>` where `<query>` is
|
|
34
|
+
the literal `query` attribute of the `<fetch>` row (e.g.
|
|
35
|
+
`?page_size=50&sort=descending` or `?page_size=20&sort=descending`).
|
|
36
|
+
The route accepts `q`, `type`, `sort` (`ascending` / `descending`),
|
|
37
|
+
`page_size` (≤100), `start_cursor` — it has NO time filter, so do the
|
|
38
|
+
window cutoff client-side. The daemon returns `{ "results": [...] }`
|
|
39
|
+
sorted by `last_edited_time` descending; filter to entries whose
|
|
40
|
+
`last_edited_time` is at or after the window the `<fetch>` row's
|
|
41
|
+
window symbol implies (`updated_24h` → today's agent-day start,
|
|
42
|
+
`updated_1h` → the current hour boundary), then map each surviving
|
|
43
|
+
page into one observation POST as specified above.
|
|
44
|
+
<!-- /mode:direct:notion -->
|
|
45
|
+
|
|
46
|
+
<!-- mode:delegated-same:notion -->
|
|
47
|
+
The connector is bound to your own session backend. Use the in-session
|
|
48
|
+
connector surface your skills document for Notion; the `<fetch>` row's
|
|
49
|
+
`query` attribute carries the catalog's `delegated` form
|
|
50
|
+
(e.g. `last_edited_time>=<iso>`). Translate it into the args your bound
|
|
51
|
+
surface accepts. POST every returned page as specified above.
|
|
52
|
+
<!-- /mode:delegated-same:notion -->
|
|
53
|
+
|
|
54
|
+
<!-- mode:delegated-cross:notion -->
|
|
55
|
+
The connector is bound to a different backend than this session — reach
|
|
56
|
+
it through the daemon's delegation proxy. POST to
|
|
57
|
+
`http://localhost:8321/api/integrations/notion/exec` with the following
|
|
58
|
+
body (substitute the row's `query` into `task`):
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"task": "Search Notion for pages with last_edited_time matching <query>. Return id, title, last_edited, parent, url for each page. Up to 50 pages.",
|
|
63
|
+
"outputSchema": {
|
|
64
|
+
"type": "object",
|
|
65
|
+
"required": ["pages"],
|
|
66
|
+
"properties": {
|
|
67
|
+
"pages": {
|
|
68
|
+
"type": "array",
|
|
69
|
+
"items": {
|
|
70
|
+
"type": "object",
|
|
71
|
+
"required": ["id"],
|
|
72
|
+
"properties": {
|
|
73
|
+
"id": { "type": "string" },
|
|
74
|
+
"title": { "type": "string" },
|
|
75
|
+
"last_edited": { "type": "string" },
|
|
76
|
+
"parent": { "type": "string" },
|
|
77
|
+
"url": { "type": "string" }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"maxToolCalls": 3,
|
|
84
|
+
"cacheable": true
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Map each item in `result.pages[]` to one observation POST.
|
|
89
|
+
<!-- /mode:delegated-cross:notion -->
|
|
90
|
+
|
|
91
|
+
<!-- mode:native:notion -->
|
|
92
|
+
The connector is bound natively to your own session backend. Use the
|
|
93
|
+
in-session connector surface your skills document — same call shape as
|
|
94
|
+
`delegated-same`. The daemon does not proxy. POST every returned page as
|
|
95
|
+
specified above.
|
|
96
|
+
<!-- /mode:native:notion -->
|
|
97
|
+
|
|
98
|
+
<!-- mode:disabled:notion -->
|
|
99
|
+
Defensive no-op. The dispatcher filters disabled integrations out of
|
|
100
|
+
`<acquisition-plan>`. If a `<fetch integration="notion">` row still
|
|
101
|
+
reaches this branch, skip it and append
|
|
102
|
+
`{"type":"unexpected-row","integration":"notion","reason":"disabled-row-emitted"}`
|
|
103
|
+
to your `errors` array.
|
|
104
|
+
<!-- /mode:disabled:notion -->
|
|
@@ -10,6 +10,28 @@ surgical merge — you submit only the new section body and it replaces the
|
|
|
10
10
|
marker-bracketed Architecture block in place. Other sections (Summary,
|
|
11
11
|
Notable Changes, Daily Activity Log) are preserved automatically.
|
|
12
12
|
|
|
13
|
+
## Tools available to you
|
|
14
|
+
|
|
15
|
+
This session runs under a **read-only clamp**. Your only write surface is the
|
|
16
|
+
single daemon-API call in Step 6. The runtime denies every other writer.
|
|
17
|
+
|
|
18
|
+
Available:
|
|
19
|
+
|
|
20
|
+
- `Read` / `Glob` / `Grep` — inspect the repository at `<localPath>` and any
|
|
21
|
+
documentation under it. Pass absolute paths; you do **not** need to `cd`.
|
|
22
|
+
- `Bash(curl *)` — pinned to `localhost:<apiPort>` by the security hook; used
|
|
23
|
+
exclusively for the Step 6 `PUT`.
|
|
24
|
+
- `Bash(jq *)` — JSON post-processing for the curl response.
|
|
25
|
+
|
|
26
|
+
Denied (these tools will fail at the SDK layer — do not attempt them):
|
|
27
|
+
|
|
28
|
+
- `Write`, `Edit` — no agent-side write to the worktree. The daemon owns
|
|
29
|
+
every byte under `git/<slug>/`.
|
|
30
|
+
- `Bash(git ...)`, `Bash(ls ...)`, `Bash(cat ...)` and any other shell verbs —
|
|
31
|
+
use `Glob` to enumerate directories and `Read` to inspect files. You are
|
|
32
|
+
analysing *current code structure*, not git history, so the git CLI is not
|
|
33
|
+
needed here. The daily-journal cron is the path that consumes git history.
|
|
34
|
+
|
|
13
35
|
## Inputs
|
|
14
36
|
|
|
15
37
|
Read `<task_context>` first. It contains:
|
|
@@ -52,7 +74,8 @@ synthesize.
|
|
|
52
74
|
1. **Read the README** at `<localPath>/README.md` (or `README.*`). Use
|
|
53
75
|
it as the author's stated framing of the project, but verify against
|
|
54
76
|
the code; the README can drift.
|
|
55
|
-
2. **Survey top-level structure.** `
|
|
77
|
+
2. **Survey top-level structure.** `Glob` `<localPath>/*` (and
|
|
78
|
+
`<localPath>/.*` for dotfiles you care about) + targeted `Read`s of
|
|
56
79
|
`package.json` / `pyproject.toml` / `Cargo.toml` / `go.mod` / etc. to
|
|
57
80
|
identify the language, build system, and entry points.
|
|
58
81
|
3. **Walk the meaningful directories.** Read enough source to confirm
|