@aitne-sh/aitne 0.1.5 → 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.
- package/README.md +16 -0
- package/agent-assets/agent-profiles/_safety.md +17 -2
- package/agent-assets/agent-profiles/routine-fetch-window.md +75 -40
- package/agent-assets/agent-profiles/wiki-agent.md +19 -0
- package/agent-assets/docs/features/messaging/bang-commands.md +161 -0
- package/agent-assets/docs/features/messaging/overview.md +3 -0
- package/agent-assets/docs/features/wiki/commands.md +222 -0
- package/agent-assets/docs/features/wiki/overview.md +145 -0
- package/agent-assets/docs/getting-started/03-what-can-this-do.md +18 -0
- package/agent-assets/docs/glossary.md +34 -0
- package/agent-assets/docs/guides/budget-and-cost-for-wiki.md +123 -0
- package/agent-assets/docs/guides/build-your-wiki.md +99 -0
- package/agent-assets/docs/guides/explore-with-trace-and-connect.md +169 -0
- package/agent-assets/docs/guides/maintain-wiki-health.md +168 -0
- package/agent-assets/docs/guides/multiple-wikis-for-multiple-domains.md +192 -0
- package/agent-assets/docs/guides/pause-the-agent.md +10 -3
- package/agent-assets/docs/guides/use-an-existing-obsidian-vault.md +156 -0
- package/agent-assets/docs/reference/cli-commands.md +24 -1
- package/agent-assets/docs/troubleshooting/wiki-ingest-full-blocked.md +96 -0
- package/agent-assets/docs/troubleshooting/wiki-write-failed.md +82 -0
- package/agent-assets/skills/context/SKILL.md +288 -17
- package/agent-assets/skills/external-services/SKILL.delegated.claude.md +2 -2
- package/agent-assets/skills/external-services/SKILL.delegated.codex.md +3 -3
- package/agent-assets/skills/external-services/SKILL.delegated.gemini.md +6 -6
- package/agent-assets/skills/external-services/SKILL.md +5 -3
- package/agent-assets/skills/external-services/SKILL.native.claude.md +49 -58
- package/agent-assets/skills/external-services/SKILL.native.codex.md +50 -58
- package/agent-assets/skills/external-services/SKILL.native.gemini.md +53 -56
- package/agent-assets/skills/mail/SKILL.md +5 -5
- package/agent-assets/skills/mail/SKILL.native.claude.md +57 -65
- package/agent-assets/skills/mail/SKILL.native.codex.md +73 -75
- package/agent-assets/skills/mail/SKILL.native.gemini.md +80 -75
- package/agent-assets/skills/management-task-register/SKILL.md +3 -3
- package/agent-assets/skills/notion/SKILL.native.claude.md +78 -82
- package/agent-assets/skills/notion/SKILL.native.codex.md +78 -80
- package/agent-assets/skills/notion/SKILL.native.gemini.md +91 -90
- package/agent-assets/skills/observations/SKILL.md +104 -14
- package/agent-assets/skills/roadmap/SKILL.md +19 -0
- package/agent-assets/skills/schedule/SKILL.md +44 -3
- package/agent-assets/skills/today/SKILL.md +25 -5
- package/agent-assets/skills/travel-time/SKILL.md +9 -0
- package/agent-assets/skills/wiki/wiki-ask/SKILL.md +32 -0
- package/agent-assets/skills/wiki/wiki-compile/SKILL.md +126 -0
- package/agent-assets/skills/wiki/wiki-connect/SKILL.md +75 -0
- package/agent-assets/skills/wiki/wiki-graduate/SKILL.md +45 -0
- package/agent-assets/skills/wiki/wiki-ingest/SKILL.md +182 -0
- package/agent-assets/skills/wiki/wiki-lint/SKILL.md +90 -0
- package/agent-assets/skills/wiki/wiki-trace/SKILL.md +72 -0
- package/agent-assets/skills/wiki/wiki-vault-rules/SKILL.md +145 -0
- package/agent-assets/task-flows/_partials/calendar-acquire.google_calendar.md +28 -9
- package/agent-assets/task-flows/_partials/calendar-acquire.outlook_calendar.md +26 -9
- package/agent-assets/task-flows/_partials/mail-acquire.gmail.md +51 -24
- package/agent-assets/task-flows/_partials/mail-acquire.outlook_mail.md +46 -16
- package/agent-assets/task-flows/_partials/notion-acquire.notion.md +29 -9
- package/agent-assets/task-flows/message.received.dm.md +35 -2
- package/agent-assets/task-flows/message.received.dm.native.claude.md +25 -26
- package/agent-assets/task-flows/message.received.dm.native.codex.md +30 -24
- package/agent-assets/task-flows/message.received.dm.native.gemini.md +36 -36
- package/agent-assets/task-flows/message.received.dm_first.md +43 -4
- package/agent-assets/task-flows/message.received.dm_first.native.claude.md +20 -20
- package/agent-assets/task-flows/message.received.dm_first.native.codex.md +22 -19
- package/agent-assets/task-flows/message.received.dm_first.native.gemini.md +28 -24
- package/agent-assets/task-flows/routine.fetch_window.md +51 -36
- package/agent-assets/task-flows/routine.morning_routine.md +12 -3
- package/agent-assets/task-flows/routine.morning_routine_initial.md +22 -1
- package/agent-assets/task-flows/scheduled.dm.md +477 -0
- package/agent-assets/task-flows/wiki.ask.md +11 -0
- package/agent-assets/task-flows/wiki.compile.md +28 -0
- package/agent-assets/task-flows/wiki.connect.md +12 -0
- package/agent-assets/task-flows/wiki.ingest_url.md +35 -0
- package/agent-assets/task-flows/wiki.lint.md +13 -0
- package/agent-assets/task-flows/wiki.trace.md +13 -0
- package/agent-assets/wiki-seeds/schemas/output.md +12 -0
- package/agent-assets/wiki-seeds/schemas/raw.md +13 -0
- package/agent-assets/wiki-seeds/schemas/wiki.md +12 -0
- package/agent-assets/wiki-seeds/taxonomy.md +13 -0
- package/package.json +21 -41
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 1
|
|
3
|
+
slug: troubleshooting/wiki-ingest-full-blocked
|
|
4
|
+
title: "`!compile full` Is Blocked"
|
|
5
|
+
id: wiki-ingest-full-blocked
|
|
6
|
+
aliases:
|
|
7
|
+
- ingest full refused
|
|
8
|
+
- wiki approval pending
|
|
9
|
+
- wiki dirty tree refused
|
|
10
|
+
category: troubleshooting
|
|
11
|
+
summary: |
|
|
12
|
+
`!compile full` either refused with "uncommitted changes" (git
|
|
13
|
+
pre-compile gate) or returned "Sent for approval" (cost gate).
|
|
14
|
+
This entry tells you how to clear each branch.
|
|
15
|
+
section: wiki-ingest-full-blocked
|
|
16
|
+
tags:
|
|
17
|
+
- troubleshooting
|
|
18
|
+
- wiki
|
|
19
|
+
- cost
|
|
20
|
+
- git
|
|
21
|
+
status: stable
|
|
22
|
+
ask_examples:
|
|
23
|
+
- Why did !compile full refuse to run?
|
|
24
|
+
- Where do I approve a pending wiki compile?
|
|
25
|
+
- Why does !compile full want a clean git tree?
|
|
26
|
+
locale: en-US
|
|
27
|
+
created: 2026-05-12
|
|
28
|
+
updated: 2026-05-12
|
|
29
|
+
related:
|
|
30
|
+
- features/wiki/commands
|
|
31
|
+
- guides/budget-and-cost-for-wiki
|
|
32
|
+
- features/wiki/overview
|
|
33
|
+
ui_anchors:
|
|
34
|
+
- /settings/wiki
|
|
35
|
+
- /approvals
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
# `!compile full` Is Blocked
|
|
39
|
+
|
|
40
|
+
## What You See
|
|
41
|
+
|
|
42
|
+
You ran `!compile full` and the bang reply says either:
|
|
43
|
+
|
|
44
|
+
- "Cannot run `!compile full` — the external vault has uncommitted
|
|
45
|
+
changes."
|
|
46
|
+
- "Sent for approval. Open `/settings/wiki` → Approvals to confirm
|
|
47
|
+
and the compile will start."
|
|
48
|
+
|
|
49
|
+
## "Uncommitted Changes"
|
|
50
|
+
|
|
51
|
+
This is the **git pre-compile gate** firing. Aitne refuses to start
|
|
52
|
+
`!compile full` on an external git-tracked vault with a dirty working
|
|
53
|
+
tree because the pre-compile snapshot it would create can no longer
|
|
54
|
+
be a clean baseline.
|
|
55
|
+
|
|
56
|
+
To proceed:
|
|
57
|
+
|
|
58
|
+
1. `git -C <vault> status` — review the dirty paths Aitne listed.
|
|
59
|
+
2. Commit or stash them: `git add -A && git commit -m "wip"` or
|
|
60
|
+
`git stash -u`.
|
|
61
|
+
3. Re-run `!compile full`. On a clean tree Aitne runs
|
|
62
|
+
`git add -A && git commit -m "aitne wiki: pre-compile snapshot <ts>"`
|
|
63
|
+
automatically.
|
|
64
|
+
|
|
65
|
+
If you don't want the auto-commit, disable **Auto-commit before
|
|
66
|
+
`!compile full`** in **Settings → Wiki** (only visible for
|
|
67
|
+
git-tracked external vaults). Aitne will then run without taking a
|
|
68
|
+
snapshot — and the approval-gate DM will explicitly say "no git
|
|
69
|
+
backup taken".
|
|
70
|
+
|
|
71
|
+
## "Sent for Approval"
|
|
72
|
+
|
|
73
|
+
The cost estimator's pessimistic bound (`2× expected`) exceeded the
|
|
74
|
+
per-workspace approval threshold (default $2.00). To approve:
|
|
75
|
+
|
|
76
|
+
1. Open the dashboard.
|
|
77
|
+
2. Go to **Settings → Wiki → Approvals** (or hit the **Approvals**
|
|
78
|
+
notification card directly).
|
|
79
|
+
3. Review the estimate. Click **Approve** to run, **Deny** to skip.
|
|
80
|
+
|
|
81
|
+
If the estimate looks wrong, you have three levers:
|
|
82
|
+
|
|
83
|
+
- **Lower the avg input tokens** — the default 1500 is conservative
|
|
84
|
+
for short raw notes; check whether your typical raw note is
|
|
85
|
+
smaller.
|
|
86
|
+
- **Switch the `wiki.compile` model** to a lite tier in the
|
|
87
|
+
per-command selector. Sonnet's per-token cost is the dominant
|
|
88
|
+
variable.
|
|
89
|
+
- **Raise the threshold** in **Settings → Wiki** so routine
|
|
90
|
+
recompiles don't queue an approval.
|
|
91
|
+
|
|
92
|
+
## "Not Enabled"
|
|
93
|
+
|
|
94
|
+
If `!compile full` replies "Wiki is not enabled", you have no active
|
|
95
|
+
workspace row. Run **Enable Internal Workspace** (or **Probe &
|
|
96
|
+
Create External**) on `/settings/wiki` first.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 1
|
|
3
|
+
slug: troubleshooting/wiki-write-failed
|
|
4
|
+
title: Wiki Write Failed
|
|
5
|
+
id: wiki-write-failed
|
|
6
|
+
aliases:
|
|
7
|
+
- wiki EPERM
|
|
8
|
+
- obsidian cli not detected
|
|
9
|
+
- wiki write strategy stuck on cli
|
|
10
|
+
category: troubleshooting
|
|
11
|
+
summary: |
|
|
12
|
+
A wiki bang command failed to write, or the dashboard health card
|
|
13
|
+
shows a non-`fs` strategy with `cliAvailable: false`. Triage the
|
|
14
|
+
filesystem permission vs. the Obsidian CLI fallback path.
|
|
15
|
+
section: wiki-write-failed
|
|
16
|
+
tags:
|
|
17
|
+
- troubleshooting
|
|
18
|
+
- wiki
|
|
19
|
+
- obsidian
|
|
20
|
+
status: stable
|
|
21
|
+
ask_examples:
|
|
22
|
+
- Why can't the wiki write to my Obsidian vault?
|
|
23
|
+
- Why does the wiki health card say cliAvailable false?
|
|
24
|
+
- How do I retry the write-strategy probe?
|
|
25
|
+
locale: en-US
|
|
26
|
+
created: 2026-05-12
|
|
27
|
+
updated: 2026-05-12
|
|
28
|
+
related:
|
|
29
|
+
- features/wiki/overview
|
|
30
|
+
- guides/use-an-existing-obsidian-vault
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
# Wiki Write Failed
|
|
34
|
+
|
|
35
|
+
## What You See
|
|
36
|
+
|
|
37
|
+
A wiki bang command (`!ingest`, `!compile`) reports a write failure in
|
|
38
|
+
the daemon log, or the dashboard `/api/wiki/:ws/health` endpoint
|
|
39
|
+
surfaces a non-`fs` strategy with `cliAvailable: false`.
|
|
40
|
+
|
|
41
|
+
## Quick Checklist
|
|
42
|
+
|
|
43
|
+
1. **Internal mode?** Internal workspaces always write via the local
|
|
44
|
+
filesystem. If you see EPERM there, the underlying issue is
|
|
45
|
+
`dataDir` permissions — fix those rather than thinking the wiki
|
|
46
|
+
is the problem.
|
|
47
|
+
2. **External mode + `write_strategy=fs`?** The filesystem rejected
|
|
48
|
+
the write. Common causes:
|
|
49
|
+
- iCloud sandbox (most frequent on macOS).
|
|
50
|
+
- Read-only volume / snapshot mount.
|
|
51
|
+
- Filesystem ACL on the parent directory.
|
|
52
|
+
3. **External mode + `write_strategy=cli`?** The probe already fell
|
|
53
|
+
back to the Obsidian CLI but the CLI is unavailable. See the CLI
|
|
54
|
+
checklist below.
|
|
55
|
+
|
|
56
|
+
## The CLI Fallback Path
|
|
57
|
+
|
|
58
|
+
When direct fs writes fail with `EPERM` / `EACCES` / `EROFS` /
|
|
59
|
+
`EBUSY`, Aitne falls back to the official Obsidian CLI (1.12+).
|
|
60
|
+
Requirements:
|
|
61
|
+
|
|
62
|
+
- Obsidian installed (1.12 or later).
|
|
63
|
+
- **Settings → General → Command line interface** enabled inside
|
|
64
|
+
Obsidian.
|
|
65
|
+
- The Obsidian app is running (the CLI is a thin client to the live
|
|
66
|
+
process).
|
|
67
|
+
- The `obsidian` binary is on `PATH` (`~/.zprofile` is auto-updated
|
|
68
|
+
when CLI is enabled).
|
|
69
|
+
|
|
70
|
+
If any of these is missing, the daemon surfaces a structured error:
|
|
71
|
+
|
|
72
|
+
| Error code | Meaning |
|
|
73
|
+
|---|---|
|
|
74
|
+
| `EWIKI_CLI_UNAVAILABLE` | Aitne's `ObsidianService` is not configured. Open `Settings → Integrations → Obsidian` and complete the pairing. |
|
|
75
|
+
| `EWIKI_CLI_NOT_RUNNING` | Obsidian is not running. Launch the app and retry. |
|
|
76
|
+
|
|
77
|
+
## Force a Re-Probe
|
|
78
|
+
|
|
79
|
+
If you've fixed the underlying issue (granted iCloud permission,
|
|
80
|
+
mounted the disk read-write) but the cached strategy is still `cli`,
|
|
81
|
+
flip the dropdown in **Settings → Wiki → Write strategy** back to
|
|
82
|
+
`auto`. The next write probes again and persists the fresh outcome.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: context
|
|
3
|
-
description: Load when reading or writing project notes, weekly/monthly summaries, or agent
|
|
3
|
+
description: Load when reading or writing project notes, weekly/monthly summaries, or agent/journal.md. Owns GET/PATCH for context files except today.md and roadmap.md, which use their dedicated skills.
|
|
4
4
|
allowed-tools:
|
|
5
5
|
- Bash(curl *)
|
|
6
6
|
- Read
|
|
@@ -95,12 +95,58 @@ can copy the same pattern into their own skills.
|
|
|
95
95
|
|
|
96
96
|
**Decision tree:**
|
|
97
97
|
|
|
98
|
-
1. **Existing or new
|
|
99
|
-
the user's wording
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
1. **Existing or new? (Plus decline-marker pre-check.)**
|
|
99
|
+
- `GET /api/context/list/projects` and match the user's wording
|
|
100
|
+
against returned filenames (slug stem) and, if needed, against
|
|
101
|
+
the H1 / title of each candidate via
|
|
102
|
+
`GET /api/context/projects/<slug>`. If multiple candidates
|
|
103
|
+
match, prefer the one with the closest slug stem; if still
|
|
104
|
+
ambiguous, ask *"is this for `<slug-A>` or `<slug-B>`?"* before
|
|
105
|
+
writing.
|
|
106
|
+
- **Decline-marker pre-check (Goal 3 — never ask twice).** Before
|
|
107
|
+
classifying a no-match as new, compute the candidate slug and
|
|
108
|
+
read `agent/journal.md ## Declined Intents`:
|
|
109
|
+
```bash
|
|
110
|
+
curl -s "http://localhost:8321/api/context/agent/journal" \
|
|
111
|
+
| jq -r '.content // ""' \
|
|
112
|
+
| awk '/^## Declined Intents/{f=1;next} f && /^## /{exit} f'
|
|
113
|
+
```
|
|
114
|
+
(404 from the GET means the journal file does not yet exist →
|
|
115
|
+
no marker can exist → treat as "no marker present" and continue
|
|
116
|
+
to the no-match path.) If any line under that section contains
|
|
117
|
+
`create_project:<slug>` (the dedup_key shape — see §"Reply
|
|
118
|
+
branches" below), the user previously declined this exact
|
|
119
|
+
intent. The default behaviour is **skip silently** — do NOT
|
|
120
|
+
re-ask, do NOT schedule a confirm, do NOT write.
|
|
121
|
+
|
|
122
|
+
**Reversal-signal carve-out (rare).** If the user's current DM
|
|
123
|
+
contains an unambiguous reversal phrase for this exact intent,
|
|
124
|
+
treat the DM as a fresh affirmative. Run the
|
|
125
|
+
§"Decline-marker reversal" recipe below (remove the matching
|
|
126
|
+
marker line, then PUT the project file per Step 4). Pattern
|
|
127
|
+
shape: explicit verb of resumption + the topic + action
|
|
128
|
+
consent. Match on intent, not surface vocabulary — any
|
|
129
|
+
language qualifies.
|
|
130
|
+
|
|
131
|
+
Counts as reversal (do the recipe):
|
|
132
|
+
- *"actually let's start that LA project after all"*
|
|
133
|
+
- *"go ahead and track LA PM"*
|
|
134
|
+
- *"changed my mind, let's do it"*
|
|
135
|
+
|
|
136
|
+
Does NOT count as reversal (skip silently, marker stays):
|
|
137
|
+
- bare re-mention without an action verb: *"still thinking
|
|
138
|
+
about LA PM"*, *"made a bit of progress on LA"*
|
|
139
|
+
- status update on the topic without consent: *"LA classes
|
|
140
|
+
started"*, *"midterm was hard"*
|
|
141
|
+
- ambiguous "maybe" / non-commitment: *"maybe I'll track it
|
|
142
|
+
eventually"*, *"might revisit this later"*
|
|
143
|
+
|
|
144
|
+
The examples are English for prompt clarity only; recognise the
|
|
145
|
+
same shapes in any language the user writes in. Bias
|
|
146
|
+
conservative — when in doubt, skip silently and wait for a
|
|
147
|
+
clearer signal. A missed reversal costs nothing (user can
|
|
148
|
+
re-state explicitly); a false reversal silently overwrites a
|
|
149
|
+
deliberate "no".
|
|
104
150
|
|
|
105
151
|
2. **Existing match → append a dated bullet.** Default section is
|
|
106
152
|
`## Log` (or whatever section the file already uses for time-ordered
|
|
@@ -128,13 +174,84 @@ can copy the same pattern into their own skills.
|
|
|
128
174
|
frontmatter parser is line-scalar so per-key PATCH is not available.
|
|
129
175
|
Bump `updated` to today on the same write.
|
|
130
176
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
177
|
+
**Cross-path cancellation.** If this existing-match write resolves
|
|
178
|
+
what was previously a "no match" → confirm path (i.e. a confirm row
|
|
179
|
+
was scheduled and the user has since clarified the project is the
|
|
180
|
+
same as an existing one), delete the pending confirm rows before
|
|
181
|
+
completing the write. See §"Reply branches" below.
|
|
182
|
+
|
|
183
|
+
3. **No match — schedule a confirm DM (do NOT ask inline).**
|
|
184
|
+
The universal "no topic-pivoting trailing question" rule in
|
|
185
|
+
`message.received.dm{,_first}.md` Step 3 forbids appending a
|
|
186
|
+
project-creation ask to a content-rich reply. Instead of inline
|
|
187
|
+
"Create project `<slug>`? (yes/no)" and waiting on the same DM
|
|
188
|
+
turn, schedule a `confirm:` sub-flow row for a natural follow-up
|
|
189
|
+
moment (default: next morning briefing slot, or `<current_time>
|
|
190
|
+
+ 4h` if the DM landed well before quiet hours):
|
|
191
|
+
|
|
192
|
+
**a. Pre-flight idempotency check.** Compute the dedup_key
|
|
193
|
+
`create_project:<slug>` and ensure no row is already pending
|
|
194
|
+
(Goal 3):
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
curl -s "http://localhost:8321/api/schedule?status=pending,running" \
|
|
198
|
+
| jq --arg k "create_project:<slug>" \
|
|
199
|
+
'[.items[] | select(.taskContext.confirm_dedup_key == $k)] | length'
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
If the count is `≥ 1`, a confirm is already queued — do NOT
|
|
203
|
+
schedule a duplicate. Log to today.md `## Agent Log` and proceed:
|
|
204
|
+
```
|
|
205
|
+
- HH:MM [confirm] skipped create_project:<slug>: row already pending
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**b. Schedule the confirm.** Use the shape documented in
|
|
209
|
+
`scheduled.dm.md` §"Confirmation follow-up":
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
curl -s -X POST http://localhost:8321/api/schedule \
|
|
213
|
+
-H 'Content-Type: application/json' \
|
|
214
|
+
-d @- <<JSON
|
|
215
|
+
{
|
|
216
|
+
"time": "<next morning-briefing slot, or current_time + 4h — ISO 8601 with offset>",
|
|
217
|
+
"taskType": "dm_session",
|
|
218
|
+
"description": "confirm:create_project:<slug> — track <paraphrase> as a project?",
|
|
219
|
+
"model": "sonnet",
|
|
220
|
+
"taskContext": {
|
|
221
|
+
"scheduledBy": "dm_handler.project_creation_gate",
|
|
222
|
+
"sub_flow": "confirm",
|
|
223
|
+
"confirm_id": "<short uuid v4 first 8 chars>",
|
|
224
|
+
"confirm_dedup_key": "create_project:<slug>",
|
|
225
|
+
"confirm_hint": "create project \"<slug>\"? (origin: <one-line paraphrase of user's DM>)",
|
|
226
|
+
"confirm_recent_window_hours": 24,
|
|
227
|
+
"confirm_attempt": 1,
|
|
228
|
+
"confirm_max_attempts": 2,
|
|
229
|
+
"confirm_defer_count": 0,
|
|
230
|
+
"confirm_max_defers": 3,
|
|
231
|
+
"confirm_decline_marker": {
|
|
232
|
+
"path": "agent/journal.md",
|
|
233
|
+
"section": "declined_intents",
|
|
234
|
+
"match": "create_project:<slug>"
|
|
235
|
+
},
|
|
236
|
+
"confirm_slot": {
|
|
237
|
+
"path": "projects/<slug>.md"
|
|
238
|
+
},
|
|
239
|
+
"importance": "low"
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
JSON
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
The `confirm_slot.path` (just the file path, no section / anchor)
|
|
246
|
+
makes the fire-time slot-filled probe abort if the project file
|
|
247
|
+
already exists by the time the confirm fires — covering the case
|
|
248
|
+
where the user volunteers an affirmative shape between scheduling
|
|
249
|
+
and fire.
|
|
250
|
+
|
|
251
|
+
**c. Do NOT inline-ask.** The DM reply must remain in the user's
|
|
252
|
+
thread per the universal rule. The confirm sub-flow will surface
|
|
253
|
+
the question at the next natural moment. Silently inferring a
|
|
254
|
+
slug and writing without confirmation remains forbidden.
|
|
138
255
|
|
|
139
256
|
4. **On confirmed creation → PUT the file.** Required + conventional
|
|
140
257
|
frontmatter and an H1:
|
|
@@ -150,6 +267,152 @@ can copy the same pattern into their own skills.
|
|
|
150
267
|
Add `due`, `stakeholders`, `next_milestone`, `tags` only when the
|
|
151
268
|
user supplied them. Do not invent values.
|
|
152
269
|
|
|
270
|
+
5. **Reply branches — how the user's response to a scheduled confirm
|
|
271
|
+
is handled.** When the confirm sub-flow fires (`scheduled.dm.md`
|
|
272
|
+
## Confirmation follow-up) and the user replies, the reply routes
|
|
273
|
+
through `message.received.dm.md` as usual; the dispatcher injects
|
|
274
|
+
`<conversation_history>` so the agent sees both the confirm DM and
|
|
275
|
+
the user's reply in the same turn. This gate is the writer for all
|
|
276
|
+
three branches; every branch is REQUIRED.
|
|
277
|
+
|
|
278
|
+
- **Affirmative** — user gave a clear positive answer to the
|
|
279
|
+
confirm question. Examples: *"yes"*, *"go ahead"*,
|
|
280
|
+
*"track it as X"*, *"sounds good"*, *"please do"*. Match on
|
|
281
|
+
intent, not surface vocabulary — recognise the same shape in
|
|
282
|
+
any language the user writes in. Execute the "On confirmed
|
|
283
|
+
creation → PUT the file" path in Step 4. Then run
|
|
284
|
+
§"Cross-path cancellation" below (delete any sibling confirm
|
|
285
|
+
rows with matching `confirm_dedup_key` so a parallel queued
|
|
286
|
+
row does not re-fire).
|
|
287
|
+
|
|
288
|
+
- **Counter-proposal** — user supplied new info ("call it
|
|
289
|
+
`la-pm` instead", "actually make it the syllabus dossier",
|
|
290
|
+
"rename it to `la-pm`").
|
|
291
|
+
Use the user's wording, not your original paraphrase:
|
|
292
|
+
re-compute the slug from the corrected wording, PUT the file,
|
|
293
|
+
then cancel pending confirm rows whose `confirm_dedup_key`
|
|
294
|
+
matches **either** the original or the new slug:
|
|
295
|
+
- `create_project:<original-slug>` — the chained-fire successor
|
|
296
|
+
inherits the original key, so this is the primary sweep.
|
|
297
|
+
- `create_project:<new-slug>` — a separate gate fire from an
|
|
298
|
+
earlier DM may have queued a confirm with the new slug (e.g.
|
|
299
|
+
the user previously paraphrased the same project differently
|
|
300
|
+
and that fire's confirm has not yet aborted). The fire-time
|
|
301
|
+
`slot-filled` probe would catch this (the project file now
|
|
302
|
+
exists), but a symmetric sweep here saves a wasted session.
|
|
303
|
+
|
|
304
|
+
Run the §"Cross-path cancellation" loop twice — once with each
|
|
305
|
+
key — or merge the two `select`s in jq.
|
|
306
|
+
|
|
307
|
+
- **Decline** — user wrote a clear negative answer to the
|
|
308
|
+
confirm question.
|
|
309
|
+
|
|
310
|
+
Counts as decline: *"no"*, *"don't bother"*, *"not now"*,
|
|
311
|
+
*"later"*, *"skip it"*, *"forget it"*, *"drop it"*.
|
|
312
|
+
|
|
313
|
+
Does NOT count as decline (treat as ambiguous → no DM action
|
|
314
|
+
this turn, marker NOT written, sweep NOT run; the chain's
|
|
315
|
+
softened re-check will handle it):
|
|
316
|
+
- non-answer continuations: *"hmm"*, *"not sure"*, *"I don't
|
|
317
|
+
know"*
|
|
318
|
+
- questions back to the agent: *"why are you asking?"*,
|
|
319
|
+
*"what would that involve?"* — these are clarification
|
|
320
|
+
requests, not declines
|
|
321
|
+
|
|
322
|
+
The examples are English for prompt clarity only; recognise
|
|
323
|
+
the same shapes in any language the user writes in. On a true
|
|
324
|
+
decline, do NOT write the project file. Two mandatory writes:
|
|
325
|
+
|
|
326
|
+
a. **Write the decline marker** to
|
|
327
|
+
`agent/journal.md ## Declined Intents`. Three cases — file
|
|
328
|
+
missing entirely, file present but section missing, file +
|
|
329
|
+
section both present — are handled in one read-then-branch
|
|
330
|
+
sequence:
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
# 1. GET. HTTP 404 means the journal file does not yet exist.
|
|
334
|
+
body=$(curl -sS -w '\n%{http_code}' "http://localhost:8321/api/context/agent/journal")
|
|
335
|
+
status=$(printf '%s\n' "$body" | tail -n1)
|
|
336
|
+
content=$(printf '%s\n' "$body" | sed '$d' | jq -r '.content // ""' 2>/dev/null)
|
|
337
|
+
|
|
338
|
+
marker_line='- 2026-05-12 [create_project:<slug>] user declined inline (DM)'
|
|
339
|
+
|
|
340
|
+
if [ "$status" = "404" ]; then
|
|
341
|
+
# Case A — file missing. CREATE_ONLY_PUT is enabled for
|
|
342
|
+
# agent/journal, so PUT creates the file in a single call.
|
|
343
|
+
# Include both the H1 and the Declined Intents section.
|
|
344
|
+
curl -s -X PUT "http://localhost:8321/api/context/agent/journal" \
|
|
345
|
+
-H 'Content-Type: application/json' \
|
|
346
|
+
-d "$(jq -n --arg m "$marker_line" '{content: "# Agent Journal\n\n## Declined Intents\n\($m)\n"}')"
|
|
347
|
+
elif printf '%s' "$content" | grep -q '^## Declined Intents'; then
|
|
348
|
+
# Case B — file + section present. Append a bullet to the
|
|
349
|
+
# existing section.
|
|
350
|
+
curl -s -X PATCH "http://localhost:8321/api/context/agent/journal" \
|
|
351
|
+
-H 'Content-Type: application/json' \
|
|
352
|
+
-d "$(jq -n --arg m "$marker_line" '{section:"declined_intents",mode:"append",content:$m}')"
|
|
353
|
+
else
|
|
354
|
+
# Case C — file present but section missing. append_to_file
|
|
355
|
+
# adds the section header + bullet to the end of the file.
|
|
356
|
+
curl -s -X PATCH "http://localhost:8321/api/context/agent/journal" \
|
|
357
|
+
-H 'Content-Type: application/json' \
|
|
358
|
+
-d "$(jq -n --arg m "$marker_line" '{mode:"append_to_file",content:"\n## Declined Intents\n\($m)\n"}')"
|
|
359
|
+
fi
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Use today's date (resolve via `<current_time>`) for the
|
|
363
|
+
marker line.
|
|
364
|
+
|
|
365
|
+
b. **Cancellation** — see §"Cross-path cancellation" below.
|
|
366
|
+
The decline must also delete any pending confirm rows with
|
|
367
|
+
the matching `confirm_dedup_key`, otherwise the chained-fire
|
|
368
|
+
successor will re-ask 24h later despite the explicit "no".
|
|
369
|
+
|
|
370
|
+
The decline marker is what the next DM-intent detection (Step 1
|
|
371
|
+
above) consults — without it, the next time the user mentions LA
|
|
372
|
+
PM master's, this gate would compute the same slug, see no
|
|
373
|
+
existing project, and schedule another confirm. The marker is
|
|
374
|
+
how Goal 3 ("never ask the same question twice") survives across
|
|
375
|
+
sessions.
|
|
376
|
+
|
|
377
|
+
**Decline-marker reversal.** When the user later volunteers an
|
|
378
|
+
unambiguously affirmative shape ("OK now let's start that LA
|
|
379
|
+
project after all", "actually go ahead and track LA PM") — either
|
|
380
|
+
inline in a fresh DM (the carve-out in Step 1) or as a reply to a
|
|
381
|
+
confirm DM — run this recipe instead of skipping:
|
|
382
|
+
|
|
383
|
+
1. GET `agent/journal.md`, parse the `## Declined Intents`
|
|
384
|
+
section, drop the line whose bracketed dedup_key matches
|
|
385
|
+
`create_project:<slug>`, and PATCH the section with
|
|
386
|
+
`mode: "replace"` carrying the rebuilt body (the other lines
|
|
387
|
+
preserved byte-for-byte). If the rebuilt section is empty,
|
|
388
|
+
replace with the empty string — `mode: "replace"` accepts an
|
|
389
|
+
empty `content` and leaves the heading in place.
|
|
390
|
+
2. Proceed with Step 4 (PUT the project file).
|
|
391
|
+
|
|
392
|
+
Without the reversal, a previously-declined project would stay
|
|
393
|
+
dormant forever.
|
|
394
|
+
|
|
395
|
+
**Cross-path cancellation (required for affirmative,
|
|
396
|
+
counter-proposal, and decline branches).** When this gate
|
|
397
|
+
commits durable state via ANY of the three branches above, sweep
|
|
398
|
+
pending confirm rows with the same dedup_key so a queued
|
|
399
|
+
successor does not re-fire:
|
|
400
|
+
|
|
401
|
+
```bash
|
|
402
|
+
curl -s "http://localhost:8321/api/schedule?status=pending,running" \
|
|
403
|
+
| jq -r --arg k "create_project:<slug>" \
|
|
404
|
+
'.items[] | select(.taskContext.confirm_dedup_key == $k) | .id' \
|
|
405
|
+
| while read -r id; do
|
|
406
|
+
curl -s -X DELETE "http://localhost:8321/api/schedule/$id" >/dev/null
|
|
407
|
+
done
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
Apply this after the affirmative write, after the counter-proposal
|
|
411
|
+
write (with the ORIGINAL slug, not the corrected one), and after
|
|
412
|
+
the decline marker write. The cost is one GET plus zero-to-one
|
|
413
|
+
DELETE per write — bounded by "gate wrote something", which is
|
|
414
|
+
rare relative to inbound DM volume.
|
|
415
|
+
|
|
153
416
|
**Slug grammar (convention only — no API-level validation today):**
|
|
154
417
|
- match `^[a-z0-9][a-z0-9-]*[a-z0-9]$` (or a single `[a-z0-9]`)
|
|
155
418
|
- ≤ 64 chars
|
|
@@ -235,11 +498,19 @@ curl -s -X PATCH http://localhost:8321/api/context/today \
|
|
|
235
498
|
|
|
236
499
|
| Field | Type | Description |
|
|
237
500
|
|---|---|---|
|
|
238
|
-
| `section` | string | snake_case of heading. **Omit for `append_to_file
|
|
239
|
-
| `mode` | `append` \| `replace` \| `clear` \| `append_to_file` | Default `append` |
|
|
240
|
-
| `content` | string | Ignored for `clear` |
|
|
501
|
+
| `section` | string | snake_case of heading. **Omit for `append_to_file`**; required for every other mode. |
|
|
502
|
+
| `mode` | `append` \| `replace` \| `clear` \| `clear_before` \| `append_to_file` | Default `append` |
|
|
503
|
+
| `content` | string | Ignored for `clear` / `clear_before` |
|
|
504
|
+
| `cutoff` | string | **Required when `mode: "clear_before"`.** Format `YYYY-MM-DD HH:MM:SS` (zero-padded). Removes bullet rows whose `- [YYYY-MM-DD HH:MM:SS]` timestamp is ≤ cutoff. |
|
|
505
|
+
| `maxEntries` | number | Optional for `mode: "append"`. After appending, trim oldest bullet entries from the top of the section body so at most `maxEntries` bullets remain. Non-bullet lines are preserved. |
|
|
241
506
|
|
|
242
507
|
`append_to_file`: appends to end of file (no `section`). Use for agent/journal.md.
|
|
508
|
+
`clear_before`: rolling-log trim — pass a SQLite-format `cutoff` to drop bullets older than it. Non-bullet lines are preserved.
|
|
509
|
+
|
|
510
|
+
**Error responses worth knowing:**
|
|
511
|
+
- `400 {error:"section_not_found", section, availableSections:[...]}` — the section name didn't match. The `availableSections` array lists every section heading the file actually has (snake_cased); pick the closest match from that list before retrying. Do NOT retry the same `section` value.
|
|
512
|
+
- `400 {error:"validation_error", message, path}` — content failed the file-specific validator (e.g. today.md day-type line, roadmap.md preparation-timeline row). The `message` field names the offending line and (where applicable) the expected shape.
|
|
513
|
+
- `400 {error:"cutoff_required", message}` — `clear_before` was called without a valid `cutoff`.
|
|
243
514
|
|
|
244
515
|
### GET /api/context/list/:dir — List files
|
|
245
516
|
`curl -s http://localhost:8321/api/context/list/projects` → `{ "files": [{ "name", "lastModified" }] }`
|
|
@@ -16,8 +16,8 @@ Your DM session runs on Claude Code. **Google Calendar** access has been
|
|
|
16
16
|
delegated to a different backend whose Calendar connector is signed in.
|
|
17
17
|
You describe Calendar intent in natural language; the daemon spawns the
|
|
18
18
|
delegated backend, lets it pick the right MCP tool, and returns a
|
|
19
|
-
schema-validated JSON result. The
|
|
20
|
-
tools are not on
|
|
19
|
+
schema-validated JSON result. The hosted Google Calendar connector
|
|
20
|
+
tools are not on this session's tool menu (Calendar is not delegated to
|
|
21
21
|
Claude in this session).
|
|
22
22
|
|
|
23
23
|
The rest of this skill — Obsidian, GitHub, recurring schedules, one-shot
|
|
@@ -16,9 +16,9 @@ Your DM session runs on Codex CLI. **Google Calendar** access has been
|
|
|
16
16
|
delegated to a different backend whose Calendar connector is signed
|
|
17
17
|
in. You describe Calendar intent in natural language; the daemon
|
|
18
18
|
spawns the delegated backend, lets it pick the right MCP tool, and
|
|
19
|
-
returns a schema-validated JSON result. The
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
returns a schema-validated JSON result. The in-session Google Calendar
|
|
20
|
+
connector your Codex harness might expose is not on the inventory for
|
|
21
|
+
these calls (Calendar is not delegated to Codex here).
|
|
22
22
|
|
|
23
23
|
The rest of this skill — Obsidian, GitHub, recurring schedules, one-shot
|
|
24
24
|
scheduling, skills CRUD — works identically to the direct-mode body.
|
|
@@ -15,12 +15,12 @@ Base URL: `http://localhost:8321`. All calls via `curl -s` with
|
|
|
15
15
|
Your DM session runs on Gemini CLI. **Google Calendar** access has been
|
|
16
16
|
delegated to a *different* backend (Claude or Codex) whose Calendar
|
|
17
17
|
connector is signed in. Same-backend setups (DM on Gemini, Calendar
|
|
18
|
-
also delegated to Gemini via the
|
|
19
|
-
load this skill — the resolver returns
|
|
20
|
-
|
|
21
|
-
skill body is the cross-backend variant only: every Calendar
|
|
22
|
-
goes through the daemon proxy because the connector lives on
|
|
23
|
-
different backend than the one running the DM.
|
|
18
|
+
also delegated to Gemini via the in-session Calendar connector your
|
|
19
|
+
Gemini harness exposes) never load this skill — the resolver returns
|
|
20
|
+
no body and the agent uses its in-session Calendar connector directly.
|
|
21
|
+
This skill body is the cross-backend variant only: every Calendar
|
|
22
|
+
operation goes through the daemon proxy because the connector lives on
|
|
23
|
+
a different backend than the one running the DM.
|
|
24
24
|
|
|
25
25
|
The rest of this skill — Obsidian, GitHub, recurring schedules, one-shot
|
|
26
26
|
scheduling, skills CRUD — works identically to the direct-mode body.
|
|
@@ -61,9 +61,11 @@ Calendar's mode.
|
|
|
61
61
|
Read the `<integration_modes>` block injected above. If
|
|
62
62
|
`google_calendar="delegated"` (same-backend), the entire
|
|
63
63
|
`/api/calendar/*` prefix returns `410 {"error": "integration_delegated"}`
|
|
64
|
-
(route-prefix gate). Use the
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
(route-prefix gate). Use the in-session Google Calendar connector your
|
|
65
|
+
harness exposes — your tool menu lists every available tool at session
|
|
66
|
+
start. The exact tool namespace depends on which connector your
|
|
67
|
+
harness has loaded (Claude / Codex sessions each surface Calendar under
|
|
68
|
+
their own connector's namespace).
|
|
67
69
|
|
|
68
70
|
The Calendar section below documents the direct-mode route shapes;
|
|
69
71
|
consult it for tool argument shapes (native MCP tools mirror the route
|