@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.
- package/README.md +16 -0
- package/agent-assets/agent-profiles/_safety.md +29 -0
- 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 +123 -15
- package/agent-assets/skills/roadmap/SKILL.md +31 -4
- package/agent-assets/skills/schedule/SKILL.md +44 -3
- package/agent-assets/skills/today/SKILL.md +50 -11
- 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/routine.roadmap_refresh.md +7 -3
- package/agent-assets/task-flows/scheduled.dm.md +477 -0
- package/agent-assets/task-flows/setup.initial.md +50 -23
- 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 +10 -6
- 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/regen-skill-fixtures.mjs +0 -39
- package/scripts/remint-roadmap-ids.mjs +0 -257
- package/scripts/smoke-obsidian-api.mjs +0 -166
|
@@ -78,6 +78,7 @@ content rules.
|
|
|
78
78
|
|
|
79
79
|
- starts with `morning briefing` → see `## Morning briefing` below
|
|
80
80
|
- starts with `profile_interview:` → see `## Profile interview` below
|
|
81
|
+
- starts with `confirm:` → see `## Confirmation follow-up` below
|
|
81
82
|
- (future sub-flows added here)
|
|
82
83
|
|
|
83
84
|
If no sub-flow matches:
|
|
@@ -148,6 +149,16 @@ the daily greeting.
|
|
|
148
149
|
to your own backend's native Gmail MCP tools — that connector
|
|
149
150
|
reads a different account than the user's delegated one.
|
|
150
151
|
<!-- /mode:delegated-cross:gmail -->
|
|
152
|
+
<!-- mode:native:gmail -->
|
|
153
|
+
Non-Gmail accounts: use the `mail` skill as in direct mode.
|
|
154
|
+
Gmail accounts: the `/api/mail/*` per-account gate returns 410
|
|
155
|
+
`{"error":"integration_native"}` — use your session backend's
|
|
156
|
+
native Gmail MCP tool with a "10 most recent inbox" query
|
|
157
|
+
(`q=in:inbox`, limit/maxResults `10`). The materialized `mail`
|
|
158
|
+
skill body (`SKILL.native.<session-backend>.md`) lists the
|
|
159
|
+
per-backend tool names. The daemon does not proxy in native mode;
|
|
160
|
+
do NOT call `/api/integrations/gmail/exec` (also returns 410).
|
|
161
|
+
<!-- /mode:native:gmail -->
|
|
151
162
|
<!-- mode:disabled:gmail -->
|
|
152
163
|
Gmail is disabled — skip Gmail accounts entirely. Continue with
|
|
153
164
|
the remaining accounts (iCloud / Outlook / Yahoo / IMAP) via the
|
|
@@ -391,3 +402,469 @@ preserve any other entries byte-for-byte, PATCH `mode=replace`. Without
|
|
|
391
402
|
this transition, the DM-handler queue-flip (Operation 4) will see
|
|
392
403
|
`state=scheduled` and treat the user's reply as unrelated, leaving the
|
|
393
404
|
row open.
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## Confirmation follow-up
|
|
409
|
+
|
|
410
|
+
Triggered by `{event_data[task]}` starting with `confirm:`. The DM
|
|
411
|
+
handler scheduled this row because a gate (e.g. project-creation, a
|
|
412
|
+
managed-task duplicate, a long-horizon ambiguity) was triggered during
|
|
413
|
+
an earlier DM but could not be asked then — either the conversation
|
|
414
|
+
topic was incompatible, or the user's reply was already long, or the
|
|
415
|
+
universal "no topic-pivoting trailing question" rule in
|
|
416
|
+
`message.received.dm{,_first}.md` suppressed the inline ask.
|
|
417
|
+
|
|
418
|
+
The full `taskContext` schema is documented in
|
|
419
|
+
`docs/design/appendices/dm-conversational-flow.md` §B1. The fields
|
|
420
|
+
this sub-flow reads at fire time are:
|
|
421
|
+
|
|
422
|
+
- `confirm_id` — opaque per-row identifier; logged on abort / fire
|
|
423
|
+
- `confirm_dedup_key` (required) — stable topic key (`<gate>:<topic>`)
|
|
424
|
+
- `confirm_hint` — agent-internal English brief of what to ask
|
|
425
|
+
- `confirm_recent_window_hours` (default 24) — DM-history scan horizon
|
|
426
|
+
- `confirm_attempt` (default 1) / `confirm_max_attempts` (default 2)
|
|
427
|
+
— retry accounting (see Step 3)
|
|
428
|
+
- `confirm_defer_count` (default 0) / `confirm_max_defers` (default 3)
|
|
429
|
+
— active-conversation-interlock deferrals (see Step 1 check 1)
|
|
430
|
+
- `confirm_decline_marker` (optional, `{path, section, match}`) —
|
|
431
|
+
file + section + match string that, when present in the named
|
|
432
|
+
context file, signals the user already declined
|
|
433
|
+
- `confirm_slot` (optional, `{path, section?, anchor?}`) — file slot
|
|
434
|
+
that, when filled, means the answer already landed via a different
|
|
435
|
+
path
|
|
436
|
+
|
|
437
|
+
### Step 1 — Fire-time abort or defer
|
|
438
|
+
|
|
439
|
+
Four checks, run in order. **The first positive result terminates
|
|
440
|
+
Step 1** — either abort silent or self-defer; checks after a positive
|
|
441
|
+
are skipped.
|
|
442
|
+
|
|
443
|
+
#### Check 1 — Active-conversation interlock
|
|
444
|
+
|
|
445
|
+
Inspect `<recent_dm_messages window="60min">`:
|
|
446
|
+
|
|
447
|
+
- **state=very-recent** (inbound user DM in the last 5 min):
|
|
448
|
+
**self-defer.** The user is mid-thread. Firing now violates Goal 1
|
|
449
|
+
("don't break the conversation thread") even with a Variant-B
|
|
450
|
+
bridge. POST a replacement schedule row at
|
|
451
|
+
`<current_time> + 15 min` with the SAME `confirm_dedup_key`,
|
|
452
|
+
`confirm_attempt` unchanged, `confirm_defer_count += 1`, and all
|
|
453
|
+
other `taskContext` fields inherited:
|
|
454
|
+
|
|
455
|
+
```bash
|
|
456
|
+
curl -s -X POST http://localhost:8321/api/schedule \
|
|
457
|
+
-H 'Content-Type: application/json' \
|
|
458
|
+
-d @- <<JSON
|
|
459
|
+
{
|
|
460
|
+
"time": "<current_time + 15min, ISO 8601 with offset>",
|
|
461
|
+
"taskType": "dm_session",
|
|
462
|
+
"description": "confirm:<topic> — <hint>",
|
|
463
|
+
"model": "sonnet",
|
|
464
|
+
"taskContext": {
|
|
465
|
+
"scheduledBy": "scheduled_dm.confirm_followup.self_defer",
|
|
466
|
+
"sub_flow": "confirm",
|
|
467
|
+
"confirm_id": "<new short id>",
|
|
468
|
+
"confirm_dedup_key": "<inherited>",
|
|
469
|
+
"confirm_hint": "<inherited>",
|
|
470
|
+
"confirm_recent_window_hours": <inherited>,
|
|
471
|
+
"confirm_attempt": <inherited unchanged>,
|
|
472
|
+
"confirm_max_attempts": <inherited>,
|
|
473
|
+
"confirm_defer_count": <prior + 1>,
|
|
474
|
+
"confirm_max_defers": <inherited>,
|
|
475
|
+
"confirm_decline_marker": <inherited>,
|
|
476
|
+
"confirm_slot": <inherited>,
|
|
477
|
+
"importance": "low"
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
JSON
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
If `confirm_defer_count` after increment would **exceed**
|
|
484
|
+
`confirm_max_defers` (default 3, max total ~45 min delay), do NOT
|
|
485
|
+
re-schedule. Instead fall through to checks 2-4 below and let one
|
|
486
|
+
of them decide whether to fire or abort. The conversation has been
|
|
487
|
+
continuously hot for ~45 min; further deferral is unlikely to find
|
|
488
|
+
a better moment, and at this point the universal Goal-1-outranks-
|
|
489
|
+
Goal-3 rule means we accept Variant-B framing rather than letting
|
|
490
|
+
the confirm starve forever.
|
|
491
|
+
|
|
492
|
+
Log:
|
|
493
|
+
```
|
|
494
|
+
- HH:MM [dm_session] confirm:<topic> deferred (defer=N): user mid-thread
|
|
495
|
+
```
|
|
496
|
+
Then end the turn with NO assistant text.
|
|
497
|
+
|
|
498
|
+
- **state=active** (last 30 min, not last 5 min): **proceed** to
|
|
499
|
+
check 2. The conversational weave (Variant B) framing in this
|
|
500
|
+
task flow handles the on-the-fly bridge.
|
|
501
|
+
|
|
502
|
+
- **state=asleep**: **proceed** to check 2. Variant A applies.
|
|
503
|
+
|
|
504
|
+
#### Check 2 — Decline-marker probe (when `confirm_decline_marker` is set)
|
|
505
|
+
|
|
506
|
+
If `taskContext.confirm_decline_marker` is set, the user may have
|
|
507
|
+
previously said "no" to this exact intent. Read the file and grep the
|
|
508
|
+
named section for the `match` string:
|
|
509
|
+
|
|
510
|
+
```bash
|
|
511
|
+
curl -sS -w '\n%{http_code}' "http://localhost:8321/api/context/<confirm_decline_marker.path>"
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
A `404` status means the file has not yet been created → no marker
|
|
515
|
+
can exist → continue to Check 3. On `200`, parse the body and look
|
|
516
|
+
under the `<confirm_decline_marker.section>` heading: if any line in
|
|
517
|
+
that section contains `<confirm_decline_marker.match>` as a
|
|
518
|
+
substring, the marker is present → **abort silent** with reason
|
|
519
|
+
`decline-marker`.
|
|
520
|
+
|
|
521
|
+
#### Check 3 — Slot-filled probe (when `confirm_slot` is set)
|
|
522
|
+
|
|
523
|
+
If `taskContext.confirm_slot` is set, the gate's durable state may
|
|
524
|
+
have been written via a different path since this confirm was
|
|
525
|
+
scheduled. Probe:
|
|
526
|
+
|
|
527
|
+
```bash
|
|
528
|
+
curl -s "http://localhost:8321/api/profile-questions/slot-filled?path=<confirm_slot.path>§ion=<confirm_slot.section?>&anchor=<confirm_slot.anchor?>"
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
(The endpoint is profile-questions-named but generic — see
|
|
532
|
+
`packages/daemon/src/core/profile-questions/slot-filled.ts`.)
|
|
533
|
+
|
|
534
|
+
**Abort silent** with reason `slot-filled` when EITHER:
|
|
535
|
+
|
|
536
|
+
- `filled: true` — the named section / anchor has a substantive
|
|
537
|
+
bullet. This is the standard case (e.g. user-profile slot already
|
|
538
|
+
landed via a separate write), OR
|
|
539
|
+
- `fileExists: true` AND `confirm_slot.section` is null/omitted
|
|
540
|
+
AND `confirm_slot.anchor` is null/omitted — i.e. the gate
|
|
541
|
+
encoded "the file's mere existence is the answer". This covers
|
|
542
|
+
project-creation, where the durable state is "a
|
|
543
|
+
`projects/<slug>.md` file with frontmatter + H1 exists" rather
|
|
544
|
+
than "a specific section is populated". The endpoint reports
|
|
545
|
+
`filled: false` for a fresh frontmatter+H1 file (zero substantive
|
|
546
|
+
bullets), so a `filled`-only check would let the confirm fire
|
|
547
|
+
even though the project was already created — `fileExists` is
|
|
548
|
+
the correct signal in the no-section/no-anchor case.
|
|
549
|
+
|
|
550
|
+
Otherwise (file does not exist, or filled=false with a section
|
|
551
|
+
or anchor specified) continue to Check 4.
|
|
552
|
+
|
|
553
|
+
#### Check 4 — DM-history scan
|
|
554
|
+
|
|
555
|
+
Read `<recent_dm_conversation>` (last 20 turns) AND
|
|
556
|
+
`<recent_dm_messages window="60min">`. Judge whether the user
|
|
557
|
+
already answered the question described in
|
|
558
|
+
`taskContext.confirm_hint`. Three answer shapes count as "answered":
|
|
559
|
+
|
|
560
|
+
- **Affirmative resolution** — user wrote a sentence that lets the
|
|
561
|
+
gate complete its write. Examples: *"yeah, track it as
|
|
562
|
+
la-pm-masters"*, *"sounds good"*, *"go ahead"*, *"please do"*.
|
|
563
|
+
Abort silent with reason `already answered (yes) in DM`.
|
|
564
|
+
- **Negative resolution** — user wrote a clear decline. Examples:
|
|
565
|
+
*"no"*, *"don't bother"*, *"later"*, *"skip it"*, *"drop it"*.
|
|
566
|
+
Abort silent with reason `already answered (no) in DM`. AND if
|
|
567
|
+
`taskContext.confirm_decline_marker` is set, write the marker now
|
|
568
|
+
(see §"Decline-marker write" below) so subsequent re-fires of the
|
|
569
|
+
same gate see the declined state.
|
|
570
|
+
- **Volunteered answer** — user wrote the underlying fact without
|
|
571
|
+
prompting (e.g. *"I changed my mind about LA — heading back to
|
|
572
|
+
Tokyo"*, or supplied the value the gate would have asked for).
|
|
573
|
+
The gate's write-side picks this up. Abort silent with reason
|
|
574
|
+
`already answered (volunteered) in DM`.
|
|
575
|
+
|
|
576
|
+
Does NOT count as "answered" (fire the DM):
|
|
577
|
+
- bare re-mention without action: *"still thinking about LA PM"*
|
|
578
|
+
- status updates on the topic without consent/decline: *"LA
|
|
579
|
+
classes started"*, *"midterm was hard"*
|
|
580
|
+
- non-answer continuations: *"hmm"*, *"not sure"*
|
|
581
|
+
|
|
582
|
+
The examples above are English for prompt clarity only; recognise
|
|
583
|
+
the same shapes in any language the user writes in.
|
|
584
|
+
|
|
585
|
+
**Bias conservative on ambiguous shapes, strict on explicit "yes" /
|
|
586
|
+
"no".** A redundant ask is recoverable; a missed confirmation can
|
|
587
|
+
leave a project / roadmap entry unwritten. When the DM-history
|
|
588
|
+
evidence is genuinely ambiguous, fire the DM (fall through to
|
|
589
|
+
Step 2).
|
|
590
|
+
|
|
591
|
+
#### On abort
|
|
592
|
+
|
|
593
|
+
1. Append one line to today.md `## Agent Log` via the `today` skill
|
|
594
|
+
(PATCH `mode: "append"`, `section: "agent_log"`):
|
|
595
|
+
```
|
|
596
|
+
- HH:MM [dm_session] confirm:<topic> aborted: <reason>
|
|
597
|
+
```
|
|
598
|
+
Where `<reason>` is one of `interlock-skip`, `decline-marker`,
|
|
599
|
+
`slot-filled`, `already answered (yes|no|volunteered) in DM`.
|
|
600
|
+
2. End the turn with **NO assistant text**. `shouldNotify` is
|
|
601
|
+
unconditional for `scheduled.dm` — an empty turn means no DM is
|
|
602
|
+
sent. Do NOT emit a placeholder string.
|
|
603
|
+
3. Step 2 and Step 3 are skipped.
|
|
604
|
+
|
|
605
|
+
#### On self-defer (Check 1 only)
|
|
606
|
+
|
|
607
|
+
Same as abort (no DM, no Step 2 / Step 3 execution) — the replacement
|
|
608
|
+
schedule row is the recovery path.
|
|
609
|
+
|
|
610
|
+
#### Decline-marker write (helper for Check 4 "no" branch and evaluator)
|
|
611
|
+
|
|
612
|
+
When Check 4 detects a "no" (or the evaluator branch in Step 2 fires
|
|
613
|
+
on silence) and `taskContext.confirm_decline_marker` is set, write
|
|
614
|
+
the marker before ending the turn. Three cases — file missing
|
|
615
|
+
entirely, file present but section missing, both present — are
|
|
616
|
+
handled in one read-then-branch sequence:
|
|
617
|
+
|
|
618
|
+
1. GET the file, capturing the status code:
|
|
619
|
+
```bash
|
|
620
|
+
resp=$(curl -sS -w '\n%{http_code}' "http://localhost:8321/api/context/<confirm_decline_marker.path>")
|
|
621
|
+
status=$(printf '%s\n' "$resp" | tail -n1)
|
|
622
|
+
body=$(printf '%s\n' "$resp" | sed '$d')
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
`<confirm_decline_marker.path>` is the value from `taskContext`
|
|
626
|
+
(e.g. `agent/journal.md`). The endpoint accepts the path with or
|
|
627
|
+
without the `.md` suffix.
|
|
628
|
+
|
|
629
|
+
2. Branch on status + section presence:
|
|
630
|
+
- **status=404 (file missing).** Some marker paths
|
|
631
|
+
(`agent/journal`) support `PUT` for first-write creation via the
|
|
632
|
+
daemon's CREATE_ONLY_PUT allowlist. PUT a minimal file
|
|
633
|
+
containing an H1, the section header, and the new marker line:
|
|
634
|
+
```bash
|
|
635
|
+
curl -s -X PUT "http://localhost:8321/api/context/<confirm_decline_marker.path>" \
|
|
636
|
+
-H 'Content-Type: application/json' \
|
|
637
|
+
-d "$(jq -n --arg m '- <YYYY-MM-DD> [<confirm_dedup_key>] user declined (DM fire-time scan)' \
|
|
638
|
+
--arg s '<confirm_decline_marker.section as Title Case heading>' \
|
|
639
|
+
'{content: "# Agent Journal\n\n## \($s)\n\($m)\n"}')"
|
|
640
|
+
```
|
|
641
|
+
If the PUT returns 403 (`forbidden`), the path is not on the
|
|
642
|
+
create-only allowlist — fall through to an `append_to_file`
|
|
643
|
+
PATCH (which will fail with 404, surfacing the design gap so
|
|
644
|
+
the operator can fix it).
|
|
645
|
+
- **status=200 AND `body` contains `## <section title>`.**
|
|
646
|
+
Append a bullet to the existing section:
|
|
647
|
+
```bash
|
|
648
|
+
curl -s -X PATCH "http://localhost:8321/api/context/<confirm_decline_marker.path>" \
|
|
649
|
+
-H 'Content-Type: application/json' \
|
|
650
|
+
-d '{"section":"<section snake_case>","mode":"append","content":"- <YYYY-MM-DD> [<confirm_dedup_key>] user declined (DM fire-time scan)"}'
|
|
651
|
+
```
|
|
652
|
+
- **status=200 AND section heading missing.** Use
|
|
653
|
+
`mode: "append_to_file"` and include the header in the content:
|
|
654
|
+
```bash
|
|
655
|
+
curl -s -X PATCH "http://localhost:8321/api/context/<confirm_decline_marker.path>" \
|
|
656
|
+
-H 'Content-Type: application/json' \
|
|
657
|
+
-d '{"mode":"append_to_file","content":"\n## <Section Title>\n- <YYYY-MM-DD> [<confirm_dedup_key>] user declined (DM fire-time scan)\n"}'
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
The marker is one short line; do not paraphrase the user's words.
|
|
661
|
+
Lifetime: append-only, no rotation — the gate that opted in can
|
|
662
|
+
remove the line later if the user explicitly revisits ("OK now let's
|
|
663
|
+
start that LA project after all"), but the confirm sub-flow itself
|
|
664
|
+
never deletes markers.
|
|
665
|
+
|
|
666
|
+
**Duplicate-line tolerance.** Both this helper and the gate's
|
|
667
|
+
reply-branch Decline path (e.g. `context` skill §"Reply branches")
|
|
668
|
+
can in principle write the same `[<confirm_dedup_key>]` line if a
|
|
669
|
+
narrow race slips past `runWithSessionGates`. Do NOT add a defensive
|
|
670
|
+
"check before write" guard. The pre-check readers (e.g. Step 1
|
|
671
|
+
Check 2 here; the gate's Step 1 decline-marker pre-check) all match
|
|
672
|
+
on the `[<confirm_dedup_key>]` substring, so duplicate lines do not
|
|
673
|
+
break the dedup contract — they are cosmetic only.
|
|
674
|
+
|
|
675
|
+
### Step 2 — Compose the confirmation (or close the chain silently)
|
|
676
|
+
|
|
677
|
+
#### Evaluator branch — chain-close on silence
|
|
678
|
+
|
|
679
|
+
If `taskContext.confirm_attempt > taskContext.confirm_max_attempts`,
|
|
680
|
+
this row is a **decline-on-silence evaluator** (see Step 3). Step 1's
|
|
681
|
+
four checks already established that the user has not replied. Do
|
|
682
|
+
NOT compose a DM. Instead:
|
|
683
|
+
|
|
684
|
+
1. Write the decline marker described in §"Decline-marker write"
|
|
685
|
+
above, with marker text:
|
|
686
|
+
```
|
|
687
|
+
- <YYYY-MM-DD> [<confirm_dedup_key>] silence-after-<confirm_max_attempts>-asks
|
|
688
|
+
```
|
|
689
|
+
2. Append one line to today.md `## Agent Log`:
|
|
690
|
+
```
|
|
691
|
+
- HH:MM [dm_session] confirm:<topic> chain closed: silent decline
|
|
692
|
+
```
|
|
693
|
+
3. End the turn with **NO assistant text**. The chain is now closed;
|
|
694
|
+
Step 3 below is skipped for the evaluator branch.
|
|
695
|
+
|
|
696
|
+
#### Compose branch — emit a single short DM
|
|
697
|
+
|
|
698
|
+
`taskContext.confirm_attempt <= taskContext.confirm_max_attempts`.
|
|
699
|
+
Compose a single short DM in persona voice that asks the question
|
|
700
|
+
from `taskContext.confirm_hint`. The hint is agent-internal English
|
|
701
|
+
(Policy A); the rendered DM follows `<output_language_policy>` and
|
|
702
|
+
the persona / Character voice rules at the top of this file.
|
|
703
|
+
|
|
704
|
+
Hard rules:
|
|
705
|
+
|
|
706
|
+
- **One question, one sentence** unless the topic genuinely needs
|
|
707
|
+
more context. End with the question; do NOT layer a second topic.
|
|
708
|
+
- **Do NOT mention** the schedule, the queue, the gate that fired
|
|
709
|
+
it, the word "confirm" / "confirmation", `taskContext`, IDs, or
|
|
710
|
+
any internal mechanism. The user sees a natural DM, not a queue
|
|
711
|
+
entry.
|
|
712
|
+
- **Conversation-state framing applies.** If state=active or
|
|
713
|
+
very-recent (Check 1 returned "proceed"), use Variant B — no
|
|
714
|
+
greeting, acknowledge the interruption briefly, hand the floor
|
|
715
|
+
back at the end. If state=asleep, use Variant A — persona
|
|
716
|
+
greeting opener is fine.
|
|
717
|
+
- **Softened re-check on retries.** If `confirm_attempt > 1`, this
|
|
718
|
+
is a re-check after silence, NOT a re-issue of the same question.
|
|
719
|
+
Phrase it as a check-in with a soft exit ("...or skip?", "...or
|
|
720
|
+
did this change?", "...or want me to leave it open?"). The user
|
|
721
|
+
must feel acknowledged, not pestered.
|
|
722
|
+
|
|
723
|
+
Examples (English source; render per `<output_language_policy>` and
|
|
724
|
+
persona — these phrasings are STRUCTURAL):
|
|
725
|
+
|
|
726
|
+
- Initial (`confirm_attempt=1`):
|
|
727
|
+
- hint: `create project "la-pm-masters"? (origin: DM said they moved to LA and started a PM master's)` →
|
|
728
|
+
*"Should I track 'LA PM master's' as a project so I can keep the syllabus / deadlines in one place?"*
|
|
729
|
+
- hint: `ambiguous: trip to Tokyo "next month" — date 5/15?` →
|
|
730
|
+
*"Was the Tokyo trip 5/15, or are you still picking the date?"*
|
|
731
|
+
- Softened re-check (`confirm_attempt=2`):
|
|
732
|
+
- same first hint →
|
|
733
|
+
*"Still on for tracking the LA PM master's as its own project, or skip for now?"*
|
|
734
|
+
- same second hint →
|
|
735
|
+
*"Did the Tokyo date settle, or want me to leave it open?"*
|
|
736
|
+
|
|
737
|
+
### Step 3 — Schedule the chain successor
|
|
738
|
+
|
|
739
|
+
This step runs only on the **compose branch** of Step 2 (a DM was
|
|
740
|
+
emitted). The evaluator branch already closed the chain in Step 2;
|
|
741
|
+
Step 3 is skipped in that case.
|
|
742
|
+
|
|
743
|
+
After Step 2 emits the DM text (which the daemon will dispatch as
|
|
744
|
+
this turn's final assistant text), schedule a successor row based on
|
|
745
|
+
the current attempt counter. Inherit all unchanged `taskContext`
|
|
746
|
+
fields from this row.
|
|
747
|
+
|
|
748
|
+
**Quiet-hours discipline.** The literal `<current_time> + 24h` may
|
|
749
|
+
land inside the user's quiet hours (default 22:00-08:00, configurable
|
|
750
|
+
via `runtime_settings.quietHoursStart/End`). The schedule skill's
|
|
751
|
+
"Time discipline" section forbids non-`critical` rows in quiet hours,
|
|
752
|
+
and the scheduler rejects them. Pick a target time that:
|
|
753
|
+
|
|
754
|
+
1. Is at least 24h after `<current_time>` (the §B6 minimum-interval
|
|
755
|
+
contract), and
|
|
756
|
+
2. Falls outside the user's quiet hours.
|
|
757
|
+
|
|
758
|
+
The simplest pattern: take `<current_time> + 24h` and, if that
|
|
759
|
+
clock-time is inside quiet hours, roll forward to quiet-hours-end
|
|
760
|
+
on that day. For a 23:30 initial fire with quiet hours starting at
|
|
761
|
+
22:00, this yields a 08:00 successor 24h+8.5h later — slightly more
|
|
762
|
+
than 24h, still within the spirit of "next agent-day". Do not roll
|
|
763
|
+
*backward* to fit before quiet hours; that violates the 24h
|
|
764
|
+
minimum.
|
|
765
|
+
|
|
766
|
+
#### Case A — `confirm_attempt < confirm_max_attempts`
|
|
767
|
+
|
|
768
|
+
Schedule a **softened retry** at `<current_time> + 24h`:
|
|
769
|
+
|
|
770
|
+
```bash
|
|
771
|
+
curl -s -X POST http://localhost:8321/api/schedule \
|
|
772
|
+
-H 'Content-Type: application/json' \
|
|
773
|
+
-d @- <<JSON
|
|
774
|
+
{
|
|
775
|
+
"time": "<current_time + 24h, ISO 8601 with offset>",
|
|
776
|
+
"taskType": "dm_session",
|
|
777
|
+
"description": "confirm:<topic> — <hint, softened paraphrase>",
|
|
778
|
+
"model": "sonnet",
|
|
779
|
+
"taskContext": {
|
|
780
|
+
"scheduledBy": "scheduled_dm.confirm_followup.retry",
|
|
781
|
+
"sub_flow": "confirm",
|
|
782
|
+
"confirm_id": "<new short id>",
|
|
783
|
+
"confirm_dedup_key": "<inherited unchanged>",
|
|
784
|
+
"confirm_hint": "<softened English brief — e.g. 'still on for tracking LA PM master's, or skip?'>",
|
|
785
|
+
"confirm_recent_window_hours": <inherited>,
|
|
786
|
+
"confirm_attempt": <prior + 1>,
|
|
787
|
+
"confirm_max_attempts": <inherited>,
|
|
788
|
+
"confirm_defer_count": 0,
|
|
789
|
+
"confirm_max_defers": <inherited>,
|
|
790
|
+
"confirm_decline_marker": <inherited>,
|
|
791
|
+
"confirm_slot": <inherited>,
|
|
792
|
+
"importance": "low"
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
JSON
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
The successor's `confirm_hint` SHOULD be softened by the composing
|
|
799
|
+
session — the next fire's Step 2 reads the hint as written, so a
|
|
800
|
+
gentler hint produces a gentler DM. Reset `confirm_defer_count` to 0
|
|
801
|
+
on a retry (defers are per-fire, not per-chain).
|
|
802
|
+
|
|
803
|
+
#### Case B — `confirm_attempt == confirm_max_attempts`
|
|
804
|
+
|
|
805
|
+
Schedule a single **decline-on-silence evaluator** at
|
|
806
|
+
`<current_time> + 24h` with `confirm_attempt = confirm_max_attempts + 1`
|
|
807
|
+
(sentinel). At the evaluator's fire time, Step 1 runs as usual; if
|
|
808
|
+
all four checks pass (user still has not replied), Step 2's
|
|
809
|
+
evaluator branch silently writes the decline marker and ends —
|
|
810
|
+
no DM, no further successor.
|
|
811
|
+
|
|
812
|
+
```bash
|
|
813
|
+
curl -s -X POST http://localhost:8321/api/schedule \
|
|
814
|
+
-H 'Content-Type: application/json' \
|
|
815
|
+
-d @- <<JSON
|
|
816
|
+
{
|
|
817
|
+
"time": "<current_time + 24h, ISO 8601 with offset>",
|
|
818
|
+
"taskType": "dm_session",
|
|
819
|
+
"description": "confirm:<topic> — silence-evaluator",
|
|
820
|
+
"model": "sonnet",
|
|
821
|
+
"taskContext": {
|
|
822
|
+
"scheduledBy": "scheduled_dm.confirm_followup.evaluator",
|
|
823
|
+
"sub_flow": "confirm",
|
|
824
|
+
"confirm_id": "<new short id>",
|
|
825
|
+
"confirm_dedup_key": "<inherited unchanged>",
|
|
826
|
+
"confirm_hint": "<inherited>",
|
|
827
|
+
"confirm_recent_window_hours": <inherited>,
|
|
828
|
+
"confirm_attempt": <confirm_max_attempts + 1>,
|
|
829
|
+
"confirm_max_attempts": <inherited>,
|
|
830
|
+
"confirm_defer_count": 0,
|
|
831
|
+
"confirm_max_defers": <inherited>,
|
|
832
|
+
"confirm_decline_marker": <inherited>,
|
|
833
|
+
"confirm_slot": <inherited>,
|
|
834
|
+
"importance": "low"
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
JSON
|
|
838
|
+
```
|
|
839
|
+
|
|
840
|
+
#### Bookkeeping (silent — never visible to the user)
|
|
841
|
+
|
|
842
|
+
After scheduling the successor (Case A or B), append one line to
|
|
843
|
+
today.md `## Agent Log`:
|
|
844
|
+
|
|
845
|
+
```
|
|
846
|
+
- HH:MM [dm_session] confirm:<topic> sent (attempt=N/max=M); successor scheduled <case>
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
(Use `case=retry` for Case A and `case=evaluator` for Case B.)
|
|
850
|
+
|
|
851
|
+
### Notes — invariants this sub-flow upholds
|
|
852
|
+
|
|
853
|
+
- **Goal 1 (thread preservation).** Check 1's self-defer keeps a
|
|
854
|
+
hot thread intact even though the confirm has been waiting.
|
|
855
|
+
When defers exhaust, Goal 1 still wins: Variant-B framing softens
|
|
856
|
+
the entry rather than firing a cold opener.
|
|
857
|
+
- **Goal 2 (confirmations happen naturally).** Step 2's persona
|
|
858
|
+
voice + state-aware framing means the user experiences the DM as
|
|
859
|
+
a check-in, not a queue ping.
|
|
860
|
+
- **Goal 3 (never ask twice).** Checks 2-4 dedup against all
|
|
861
|
+
observable answer surfaces (declined, slot-filled, replied in
|
|
862
|
+
DM). Step 3's chained-fire model caps the chain at
|
|
863
|
+
`confirm_max_attempts + 1` fires (default 3), of which only
|
|
864
|
+
`confirm_max_attempts` (default 2) send DMs. The minimum
|
|
865
|
+
inter-fire interval is 24h — no same-day re-asks.
|
|
866
|
+
- **Schedule row IS the queue.** No new table, no
|
|
867
|
+
`pending-confirmations.md`. All chain state lives in
|
|
868
|
+
`taskContext`; cross-path cancellation is the gate's
|
|
869
|
+
responsibility (see the gate's reply-branch contract, e.g. the
|
|
870
|
+
`context` skill's Project DM-intent detection §"Reply branches").
|
|
@@ -7,8 +7,9 @@ Vault step already captured `settings.primary_language` (BCP-47 tag, e.g.
|
|
|
7
7
|
`en` or `es`) and `settings.vault_mode` (`plain` or `obsidian`) — the
|
|
8
8
|
latter controls how the **primary management vault** is laid out, not the
|
|
9
9
|
separate external Obsidian integration. Do NOT re-ask those questions.
|
|
10
|
-
Output language for
|
|
11
|
-
follow
|
|
10
|
+
Output language for everything written to disk in this flow
|
|
11
|
+
(`user/profile.md`, `user/*.md`, `rules/management.md` body): follow
|
|
12
|
+
`<output_language_policy>`.
|
|
12
13
|
|
|
13
14
|
SETUP-FLOW-REDESIGN-PLAN §5.8 — the legacy "tool selections" form was
|
|
14
15
|
removed. Steps 4–6 of the wizard (Mail, Calendar, Note) already
|
|
@@ -68,6 +69,15 @@ about all four rows rather than fabricating defaults. Do not retry
|
|
|
68
69
|
with a curl.
|
|
69
70
|
|
|
70
71
|
### Instructions
|
|
72
|
+
|
|
73
|
+
Steps 3–8 all happen in the same agent turn. They are ordered to match
|
|
74
|
+
the actual emission sequence: the two staged code blocks (rules then
|
|
75
|
+
character) land in the stream first; the silent curl writes follow. The
|
|
76
|
+
dashboard reveals the preview as soon as the rules block lands but
|
|
77
|
+
keeps "Save & Finish" disabled until the whole turn ends, so emitting
|
|
78
|
+
blocks before curls minimizes how long the user waits on a disabled
|
|
79
|
+
button.
|
|
80
|
+
|
|
71
81
|
1. Run Step 0 silently. Greet the user in one line, introducing
|
|
72
82
|
yourself by the name in `<agent_identity>` display_name. Then
|
|
73
83
|
present the derived Source-of-Truth table and ask any remaining
|
|
@@ -78,28 +88,30 @@ with a curl.
|
|
|
78
88
|
- Project-management method preferences (anything you want the agent
|
|
79
89
|
to follow when handling your projects?)
|
|
80
90
|
Either answer may be "no preference" / "skip" — accept that cleanly.
|
|
81
|
-
3.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
91
|
+
3. Generate rules/management.md inside a ```management-rules code
|
|
92
|
+
block. This is the FIRST thing emitted in the turn — the dashboard
|
|
93
|
+
reveals the preview as soon as it lands.
|
|
94
|
+
4. If the user requests changes, revise (return to step 3). Complete
|
|
95
|
+
within **at most 2 revision rounds**.
|
|
85
96
|
5. **Do NOT put communication style inside rules/management.md, and do NOT
|
|
86
97
|
put it inside `user/profile.md` either.** Tone / style / voice / emoji
|
|
87
98
|
/ language preferences live in the `character` runtime-config field
|
|
88
|
-
only — emitted as a ```character``` code block (see step 6
|
|
99
|
+
only — emitted as a ```character``` code block (see step 6). See
|
|
89
100
|
`docs/design/15-character.md` for the split rule.
|
|
90
|
-
6.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
6. If the user stated a communication-style preference in step 2, emit
|
|
102
|
+
a ```character``` code block immediately after the rules block (see
|
|
103
|
+
"Character code block format" below). If the user skipped, omit the
|
|
104
|
+
block.
|
|
105
|
+
7. After the staged blocks, silently call PUT /api/context/user/profile
|
|
106
|
+
using the template in "user/profile.md Format" below. Working hours
|
|
107
|
+
and quiet hours are pre-populated with defaults (Weekdays 09:00–18:00,
|
|
108
|
+
Quiet hours 22:00–08:00) — do not ask about them. Fill Platforms
|
|
109
|
+
from the **derived Source-of-Truth table** (Step 0) — the row values
|
|
110
|
+
you confirmed with the user. Leave Identity blank — setup does not
|
|
111
|
+
collect name or timezone.
|
|
112
|
+
8. If the conversation surfaced detail-heavy facts that belong in the
|
|
113
|
+
detailed profile layer, also PATCH the matching user/*.md file (still
|
|
114
|
+
the same turn, after step 7). Typical Q&A → file mappings:
|
|
103
115
|
- Named colleagues, family, friends → user/people.md
|
|
104
116
|
- Current company, role specifics, ongoing projects → user/work.md
|
|
105
117
|
- Specific frameworks, years of experience → user/expertise.md
|
|
@@ -109,7 +121,7 @@ with a curl.
|
|
|
109
121
|
Only seed what the user actually stated — do not invent or infer. If
|
|
110
122
|
nothing came up for a given file, do not touch it. See the user-profile
|
|
111
123
|
skill for the read-before-write PATCH recipe.
|
|
112
|
-
|
|
124
|
+
9. Keep steps 7–8 silent — the dashboard handles saving
|
|
113
125
|
rules/management.md separately when the user approves the preview. Do
|
|
114
126
|
not create or modify any other context files; the daemon seeds the
|
|
115
127
|
rest of the primary-vault scaffold automatically.
|
|
@@ -218,6 +230,18 @@ write tone/style preferences into user/profile.md.
|
|
|
218
230
|
|
|
219
231
|
### rules/management.md Format
|
|
220
232
|
|
|
233
|
+
Output language: follow `<output_language_policy>`. rules/management.md
|
|
234
|
+
is Policy B — the section headers (`## Agent Identity`, `## Source of
|
|
235
|
+
Truth`, `## Autonomy Levels`, `## Notification Rules`, `## Schedule`,
|
|
236
|
+
`## Project Management`) are skeleton and stay English; the descriptive
|
|
237
|
+
bullets under `## Autonomy Levels`, `## Notification Rules`, `## Schedule`,
|
|
238
|
+
and `## Project Management` are written in `<settings primary_language>`.
|
|
239
|
+
File-specific carve-outs that also stay English: the `## Agent Identity`
|
|
240
|
+
field labels (`- AI name:`, `- WhatsApp label:`) — the daemon parses and
|
|
241
|
+
rewrites this section; the Source of Truth table column headers and
|
|
242
|
+
Domain-column row labels; and product/brand cells (`Google Calendar`,
|
|
243
|
+
`Obsidian`, `Notion`, `today.md`, `projects/*.md`).
|
|
244
|
+
|
|
221
245
|
Fill the Source of Truth table from the **derived rows you confirmed
|
|
222
246
|
with the user in Step 0** (Schedule / Tasks / Notes / Projects).
|
|
223
247
|
Generate using this format:
|
|
@@ -274,5 +298,8 @@ heading onto the end of the previous list item (e.g. `- Label:
|
|
|
274
298
|
<value>## Next Section` on one line). Copy user-provided values as-is,
|
|
275
299
|
then newline, blank line, then the next heading.
|
|
276
300
|
|
|
277
|
-
**Important**:
|
|
278
|
-
The dashboard
|
|
301
|
+
**Important**: Do NOT curl-write rules/management.md to disk yourself.
|
|
302
|
+
The dashboard persists it via `POST /setup/save-rules` when the user
|
|
303
|
+
clicks Save & Finish. (The silent curl PUT to /api/context/user/profile
|
|
304
|
+
in step 7 and the user/*.md PATCHes in step 8 ARE required — only the
|
|
305
|
+
rules file is saved by the dashboard.)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{context}
|
|
2
|
+
|
|
3
|
+
## Task: Answer from the wiki
|
|
4
|
+
|
|
5
|
+
Read `<wiki_command>` for the question. Follow the `wiki-ask` skill:
|
|
6
|
+
|
|
7
|
+
1. Search `20_wiki/` for relevant notes.
|
|
8
|
+
2. Verify against source links or `10_raw/` only when needed.
|
|
9
|
+
3. Write one `30_outputs/<YYYY-MM-DD>-<slug>.md` answer through the Wiki API with `x-process-key: wiki.ask`.
|
|
10
|
+
4. Keep the final assistant response concise; the durable answer belongs in `30_outputs/`.
|
|
11
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{context}
|
|
2
|
+
|
|
3
|
+
## Task: Compile wiki notes
|
|
4
|
+
|
|
5
|
+
A `!compile` (or approved `!compile full`) landed here. Read `<wiki_command>` for `data.mode` — `"incremental"` (compile only `10_raw/` notes touched since the last compile) or `"full"` (compile every raw). Read `<wiki_workspace>` for the destination workspace.
|
|
6
|
+
|
|
7
|
+
You succeed if and only if every wiki note you claim to have created came back from the daemon's Wiki API as `{"ok":true,"path":"20_wiki/<slug>.md"}`. The vault is on disk and there is no other path to write it.
|
|
8
|
+
|
|
9
|
+
### Critical: the only write surface is the Wiki API via `curl`
|
|
10
|
+
|
|
11
|
+
- `Write` and `Edit` tools are **stripped from this session's allow-list**. The SDK denies them silently under `dontAsk` ("Permission to use Write has been denied …"). They cannot be made to work via path rewriting; do not try.
|
|
12
|
+
- `Bash(find ...)`, `Bash(ls ...)`, `Bash(cat ...)`, `Bash(grep ...)`, `Bash(wc ...)` and every other shell utility are also silently denied. Only `Bash(curl *)` and `Bash(jq *)` are on the allow-list. Enumerate raw notes via `GET /api/wiki/<workspace>/index`, NOT by walking `{{vault_path}}` from disk.
|
|
13
|
+
- The `Bash(curl *)` allow-rule is prefix-matched against the full command. Wrappers — `echo '{...}' | curl …`, `cat <<JSON | curl …`, `bash -c "curl …"`, `( curl … )`, `var=… curl …`, chained `curl … ; curl …` — are silently denied (no output, no `PA_API_ERROR`). The reverse, `curl … -d @- <<'JSON' … JSON` on the same line, IS allowed because the command still starts with `curl`; the shim reads stdin via `-d @-`.
|
|
14
|
+
|
|
15
|
+
### Procedure
|
|
16
|
+
|
|
17
|
+
1. **Baseline (incremental only).** Read `20_wiki/_index.md` (or the most recent `wiki.compile` entry in `log.md`) to recover the prior `compiled_at` ISO timestamp. If the workspace has never been compiled, compile every raw.
|
|
18
|
+
2. **Enumerate raw notes** via `GET /api/wiki/<workspace>/index`, then filter with `jq` for `path` under `10_raw/` and (incremental) `mtime > <baseline>`.
|
|
19
|
+
3. **Read existing wiki + taxonomy** so synthesis can de-duplicate and use canonical slugs.
|
|
20
|
+
4. **For each topic**, synthesize a root-level `20_wiki/<slug>.md` note (one note per coherent topic — merge multiple raws when they cover the same thing). `POST` for a new slug, `PATCH mode: "replace"` for an existing one (read-before-write).
|
|
21
|
+
5. **Append `20_wiki/_index.md`** (`PATCH mode: "append"`) with one bullet per added or updated note.
|
|
22
|
+
6. **Append `log.md`** (`PATCH mode: "append"`) with one summary line: `[<ISO>] wiki.compile (<mode>): compiled <N> notes from <M> raws — added <A>, updated <B>, unchanged <C>`.
|
|
23
|
+
|
|
24
|
+
The `wiki-compile` skill carries the canonical curl shapes (including the multi-KB heredoc body shape), the per-error recovery table, and the slug rules. The `wiki-vault-rules` skill carries the body-quoting cheat-sheet and the full layer/endpoint reference.
|
|
25
|
+
|
|
26
|
+
Do NOT modify `00_inbox/` or existing `10_raw/` notes. Do NOT call `/api/send-message`, `/api/whatsapp/send`, `/api/notify-user`, or any other "send" endpoint — those routes do not exist. Your final assistant text IS the delivery channel; the daemon forwards it to the bang's reply target automatically.
|
|
27
|
+
|
|
28
|
+
End with the single-line completion DM from the skill (Success / Partial / Failure).
|