From 3d928b41db6c900276d1c81cc5bc0531e683b5c1 Mon Sep 17 00:00:00 2001 From: Parfii-bot Date: Wed, 22 Apr 2026 02:30:04 +0800 Subject: [PATCH 1/2] feat(skills): /sleep-on-it 6-phase wizard + kei-sleep-queue CRUD + incubation prompt Priority-scaled time budgets (quick/standard/deep/marathon/weekly), marathon-mode for hard derivations (skips Phase B REM for one task), checkpointing every N minutes via partial commits. --- _primitives/kei-sleep-queue.sh | 269 ++++++++++++++++++ .../templates/sleep-incubation-prompt.md | 211 ++++++++++++++ skills/sleep-on-it/SKILL.md | 117 ++++++++ skills/sleep-on-it/phase-1-intake.md | 58 ++++ skills/sleep-on-it/phase-2-type.md | 71 +++++ skills/sleep-on-it/phase-3-priority.md | 130 +++++++++ skills/sleep-on-it/phase-4-format.md | 63 ++++ skills/sleep-on-it/phase-5-submit.md | 121 ++++++++ skills/sleep-on-it/phase-6-ack.md | 74 +++++ 9 files changed, 1114 insertions(+) create mode 100755 _primitives/kei-sleep-queue.sh create mode 100644 _primitives/templates/sleep-incubation-prompt.md create mode 100644 skills/sleep-on-it/SKILL.md create mode 100644 skills/sleep-on-it/phase-1-intake.md create mode 100644 skills/sleep-on-it/phase-2-type.md create mode 100644 skills/sleep-on-it/phase-3-priority.md create mode 100644 skills/sleep-on-it/phase-4-format.md create mode 100644 skills/sleep-on-it/phase-5-submit.md create mode 100644 skills/sleep-on-it/phase-6-ack.md diff --git a/_primitives/kei-sleep-queue.sh b/_primitives/kei-sleep-queue.sh new file mode 100755 index 0000000..8a175ff --- /dev/null +++ b/_primitives/kei-sleep-queue.sh @@ -0,0 +1,269 @@ +#!/usr/bin/env bash +# kei-sleep-queue.sh — v0.12.0 "sleep on it" queue CRUD helper. +# Commands: add / list / show / done / fail / purge. +# Env: KEI_MEMORY_REPO_PATH (sourced from ~/.claude/secrets/.env). +# Bypass: KEI_SLEEP_GENESIS_BYPASS=1 skips genesis-scan gate on `add`. +set -u + +SECRETS_FILE="${HOME}/.claude/secrets/.env" +[ -f "$SECRETS_FILE" ] && [ -z "${KEI_MEMORY_REPO_PATH:-}" ] && \ + . "$SECRETS_FILE" 2>/dev/null || true + +REPO_PATH="${KEI_MEMORY_REPO_PATH:-}" +QUEUE_DIR="${REPO_PATH}/sleep-queue" +DONE_DIR="${REPO_PATH}/sleep-queue-done" +FAIL_DIR="${REPO_PATH}/sleep-queue-failed" +GENESIS_BIN="${HOME}/.claude/agents/_primitives/_rust/target/release/genesis-scan" +SYNC_SH="${HOME}/.claude/agents/_primitives/kei-sleep-sync.sh" + +err() { printf 'kei-sleep-queue: %s\n' "$*" >&2; } +die() { err "$*"; exit 1; } + +ensure_repo() { + [ -n "$REPO_PATH" ] || die "KEI_MEMORY_REPO_PATH not set (run /sleep-setup)" + [ -d "${REPO_PATH}/.git" ] || die "sync-repo not initialised at $REPO_PATH" + mkdir -p "$QUEUE_DIR" "$DONE_DIR" "$FAIL_DIR" 2>/dev/null || true +} + +gen_uuid() { + if command -v uuidgen >/dev/null 2>&1; then uuidgen | tr 'A-Z' 'a-z' + else printf '%s-%s' "$(date -u +%s)" "${RANDOM}${RANDOM}"; fi +} + +iso_utc() { date -u +%Y-%m-%dT%H:%M:%SZ; } +push_async() { [ -x "$SYNC_SH" ] && "$SYNC_SH" >/dev/null 2>&1 || true; } + +scan_prompt() { + [ "${KEI_SLEEP_GENESIS_BYPASS:-0}" = "1" ] && return 0 + [ -x "$GENESIS_BIN" ] || return 0 + "$GENESIS_BIN" --stdin --exit-on-hit --format text < "$1" >&2 && return 0 + err "genesis-scan flagged the prompt — see scanner output above" + err "bypass (false positives only): KEI_SLEEP_GENESIS_BYPASS=1 $0 add ..." + exit 2 +} + +# Find a queue file by uuid prefix in dir; echoes path or returns 1. +find_by_uuid() { + local uuid="$1" dir="$2" f + [ -d "$dir" ] || return 1 + for f in "$dir/${uuid}-"*.md "$dir/${uuid}.md"; do + [ -f "$f" ] && { printf '%s\n' "$f"; return 0; } + done + return 1 +} + +# Extract a frontmatter field value (first match) from a file. +fm_field() { awk -F': ' -v k="^$2:" '$0 ~ k {print $2; exit}' "$1"; } + +# Parse "m" → N (minutes), or die with context. +parse_minutes() { + local raw="$1" label="$2" stripped="${1%m}" + case "$stripped" in ''|*[!0-9]*) die "bad $label: $raw (expected m)" ;; esac + printf '%s\n' "$stripped" +} + +# Priority defaults: TIME_BUDGET_MINUTES, CHECKPOINT_EVERY_MINUTES, MARATHON. +priority_defaults() { + case "$1" in + quick) printf '15 0 false\n' ;; + standard) printf '60 20 false\n' ;; + deep) printf '240 30 false\n' ;; + marathon) printf '480 30 true\n' ;; + weekly) printf '60 20 false\n' ;; + *) die "bad --priority: $1 (expected quick|standard|deep|marathon|weekly)" ;; + esac +} + +# Validate add flags; sets ADD_* including time-budget / checkpoint / marathon. +parse_add_flags() { + ADD_TYPE=""; ADD_PRIORITY=""; ADD_FORMAT=""; ADD_PROMPT="" + ADD_TIME_BUDGET=""; ADD_CHECKPOINT=""; ADD_MARATHON=""; ADD_NO_TIMEOUT=0 + while [ $# -gt 0 ]; do + case "$1" in + --type) ADD_TYPE="$2"; shift 2 ;; + --priority) ADD_PRIORITY="$2"; shift 2 ;; + --format) ADD_FORMAT="$2"; shift 2 ;; + --prompt-file) ADD_PROMPT="$2"; shift 2 ;; + --time-budget) ADD_TIME_BUDGET="$(parse_minutes "$2" --time-budget)"; shift 2 ;; + --checkpoint-every) ADD_CHECKPOINT="$(parse_minutes "$2" --checkpoint-every)"; shift 2 ;; + --no-timeout) ADD_NO_TIMEOUT=1; shift ;; + --marathon) ADD_MARATHON="true"; shift ;; + *) die "unknown flag: $1" ;; + esac + done + case "$ADD_TYPE" in deep|pipeline|pattern|compare|custom) ;; *) die "bad --type: $ADD_TYPE" ;; esac + case "$ADD_FORMAT" in md|adr|checklist|table) ;; *) die "bad --format: $ADD_FORMAT" ;; esac + [ -n "$ADD_PROMPT" ] && [ -f "$ADD_PROMPT" ] || die "missing --prompt-file" + resolve_priority_fields +} + +# Apply priority defaults for any ADD_* fields that weren't overridden. +resolve_priority_fields() { + local defaults budget cp marathon + defaults="$(priority_defaults "$ADD_PRIORITY")" + budget="$(printf '%s' "$defaults" | awk '{print $1}')" + cp="$(printf '%s' "$defaults" | awk '{print $2}')" + marathon="$(printf '%s' "$defaults" | awk '{print $3}')" + [ -z "$ADD_TIME_BUDGET" ] && ADD_TIME_BUDGET="$budget" + [ -z "$ADD_CHECKPOINT" ] && ADD_CHECKPOINT="$cp" + [ -z "$ADD_MARATHON" ] && ADD_MARATHON="$marathon" + [ "$ADD_NO_TIMEOUT" = "1" ] && ADD_TIME_BUDGET="null" + if [ "$ADD_MARATHON" = "true" ] && [ "$ADD_PRIORITY" != "marathon" ]; then + err "warning: --marathon set but --priority=$ADD_PRIORITY (expected marathon)" + fi +} + +cmd_add() { + parse_add_flags "$@" + ensure_repo + scan_prompt "$ADD_PROMPT" + local uuid ts file + uuid="$(gen_uuid)" + ts="$(iso_utc)" + file="${QUEUE_DIR}/${uuid}-$(date -u +%s).md" + { + printf -- '---\n' + printf -- 'uuid: %s\n' "$uuid" + printf -- 'submitted_at: %s\n' "$ts" + printf -- 'type: %s\n' "$ADD_TYPE" + printf -- 'priority: %s\n' "$ADD_PRIORITY" + printf -- 'format: %s\n' "$ADD_FORMAT" + printf -- 'time_budget_minutes: %s\n' "$ADD_TIME_BUDGET" + printf -- 'checkpoint_every_minutes: %s\n' "$ADD_CHECKPOINT" + printf -- 'marathon: %s\n' "$ADD_MARATHON" + printf -- 'status: pending\n---\n\n' + cat "$ADD_PROMPT" + printf '\n' + } > "$file" || die "write failed: $file" + printf '%s\n%s\n' "$uuid" "$file" + push_async +} + +cmd_list() { + local filter="pending" dir + [ $# -gt 0 ] && case "$1" in + --pending) filter="pending" ;; + --done) filter="done" ;; + --failed) filter="failed" ;; + *) die "unknown filter: $1" ;; + esac + ensure_repo + case "$filter" in + pending) dir="$QUEUE_DIR" ;; done) dir="$DONE_DIR" ;; failed) dir="$FAIL_DIR" ;; + esac + printf '%-36s %-10s %-8s %-9s %s\n' UUID SUBMITTED TYPE PRIORITY FILE + local f u s t p + for f in "$dir"/*.md; do + [ -f "$f" ] || continue + u="$(fm_field "$f" uuid)" + s="$(fm_field "$f" submitted_at | cut -c1-10)" + t="$(fm_field "$f" type)" + p="$(fm_field "$f" priority)" + printf '%-36s %-10s %-8s %-9s %s\n' "${u:--}" "${s:--}" "${t:--}" "${p:--}" "$f" + done +} + +cmd_show() { + [ $# -ge 1 ] || die "usage: show " + ensure_repo + local uuid="$1" f dir + for dir in "$QUEUE_DIR" "$DONE_DIR" "$FAIL_DIR"; do + f="$(find_by_uuid "$uuid" "$dir" 2>/dev/null)" && { cat "$f"; return 0; } + done + die "uuid not found: $uuid" +} + +cmd_done() { + [ $# -ge 1 ] || die "usage: done " + ensure_repo + local src dest uuid="$1" + src="$(find_by_uuid "$uuid" "$QUEUE_DIR")" || die "pending uuid not found: $uuid" + dest="${DONE_DIR}/${uuid}.md" + sed 's/^status: pending$/status: done/' "$src" > "$dest" || die "write failed: $dest" + rm -f "$src" + printf 'moved: %s -> %s\n' "$src" "$dest" + push_async +} + +cmd_fail() { + local uuid="" reason="" + while [ $# -gt 0 ]; do + case "$1" in + --reason) reason="$2"; shift 2 ;; + *) [ -z "$uuid" ] && { uuid="$1"; shift; } || die "unknown arg: $1" ;; + esac + done + [ -n "$uuid" ] || die "usage: fail --reason " + ensure_repo + local src dest + src="$(find_by_uuid "$uuid" "$QUEUE_DIR")" || die "pending uuid not found: $uuid" + dest="${FAIL_DIR}/${uuid}.md" + { + sed 's/^status: pending$/status: failed/' "$src" + printf '\n---\n## Failure reason\n\n%s\n' "${reason:-(no reason given)}" + } > "$dest" || die "write failed: $dest" + rm -f "$src" + printf 'moved: %s -> %s\n' "$src" "$dest" + push_async +} + +cmd_purge() { + local days="" + while [ $# -gt 0 ]; do + case "$1" in + --older-than) days="${2%d}"; shift 2 ;; + *) die "unknown flag: $1" ;; + esac + done + case "$days" in ''|*[!0-9]*) die "--older-than d required (N integer)" ;; esac + ensure_repo + local removed=0 f dir + for dir in "$DONE_DIR" "$FAIL_DIR"; do + while IFS= read -r f; do + rm -f "$f" && removed=$((removed + 1)) + done < <(find "$dir" -maxdepth 1 -type f -name '*.md' -mtime "+$days" 2>/dev/null) + done + printf 'purged %d file(s) older than %sd\n' "$removed" "$days" + push_async +} + +usage() { + cat >&2 <<'EOF' +kei-sleep-queue.sh — v0.12 sleep-on-it queue helper + + add --type + --priority + --format + --prompt-file + [--time-budget m] override minutes from priority default + [--checkpoint-every m] override partial-result cadence + [--no-timeout] time_budget_minutes: null (run until done) + [--marathon] explicit marathon flag + list [--pending|--done|--failed] + show + done + fail --reason + purge --older-than d + +Env: KEI_MEMORY_REPO_PATH (required) + KEI_SLEEP_GENESIS_BYPASS=1 skip genesis-scan gate on add +EOF + exit 1 +} + +main() { + [ $# -ge 1 ] || usage + local sub="$1"; shift + case "$sub" in + add) cmd_add "$@" ;; + list) cmd_list "$@" ;; + show) cmd_show "$@" ;; + done) cmd_done "$@" ;; + fail) cmd_fail "$@" ;; + purge) cmd_purge "$@" ;; + -h|--help|help) usage ;; + *) die "unknown command: $sub" ;; + esac +} + +main "$@" diff --git a/_primitives/templates/sleep-incubation-prompt.md b/_primitives/templates/sleep-incubation-prompt.md new file mode 100644 index 0000000..7fef972 --- /dev/null +++ b/_primitives/templates/sleep-incubation-prompt.md @@ -0,0 +1,211 @@ +# Nightly incubation — Phase A (KeiSeiKit v0.12.0 "sleep on it") + + + +## Phase A — Incubation ("sleep on it") + +1. **Discover pending tasks.** List `sync-repo/sleep-queue/*.md` files + ordered by the `submitted_at` frontmatter field ascending (FIFO). +2. **Filter by day.** If today is NOT Sunday UTC, skip any file with + `priority: weekly`. On Sunday UTC, include weekly tasks alongside + `quick`, `standard`, `deep`, and `marathon` tasks in the same FIFO + order. +3. **Select tasks for this run (priority-aware).** + Priority resolution for the run: + 1. Count `marathon: true` tasks in queue. If ≥ 1 with a this-night + priority, select the OLDEST by `submitted_at` as the sole task + for tonight. **Phase B REM consolidation is SKIPPED this run.** + All other pending tasks are deferred to the next night. + 2. Else: pool this-night tasks (`priority ∈ {quick, standard, deep}`) + in FIFO order and **greedy-pack up to 480 minutes total** across + at most 5 tasks. Skip any task whose `time_budget_minutes` would + overflow the remaining budget; it stays pending for the next run. + 3. Weekly batch: only processed on Sunday UTC, counted toward the + 480-minute greedy-pack budget alongside `standard`/`deep` tasks. +4. **Budget time per task.** Read `time_budget_minutes` from the task's + frontmatter. Default 60 if absent or unparseable. Behavior: + - If `marathon: true`: this task gets the entire night (max 480 min); + other queue items skip this cycle; Phase B is skipped. + - If `checkpoint_every_minutes > 0`: every N minutes, write partial + result to `sleep-results/.partial.md` AND commit + push, so + if the run is cut short the user still has the partial. + - If the budget is exhausted and the task is not done: write the + partial with `[TIME-BOXED — min budget exhausted]` at the top + of the body, set `status: timed_out` in the queue-file frontmatter, + and move it to `sleep-queue-failed/.md`. + - If `time_budget_minutes: null` (no-timeout): run until done or + until the hard cloud-session cap is hit (still honor checkpointing + so no work is lost). +5. **Dispatch by type.** Read the `type` frontmatter and run the + corresponding tool chain: + - `deep` — ≥ 3 WebSearch queries + ≥ 2 WebFetch page reads + + synthesis section. If the web is unreachable, mark result + `[OFFLINE — web tools unavailable]` and fail the task (step 7). + - `pipeline` — emit 5–7 phases, each with a one-line + verify-criterion, followed by a tradeoffs matrix. Use the repo's + past reports (`sync-repo/reports/*.md`) as context if relevant. + - `pattern` — grep `sync-repo/reports/*.md` and `sync-repo/backlog.md` + for recurring tokens related to the task text; extract 3–5 trends; + propose one concrete action. + - `compare` — produce a markdown table with the options the user + listed as columns, weighted criteria as rows, and a weighted-score + recommendation in the final row. + - `custom` — follow the task text verbatim without any fixed + dispatch. Write whatever the task asks for in the chosen format. +6. **Write the result** to + `sync-repo/sleep-results/.md` in the chosen `format`: + - `md` — `# Title` + sections + sources. + - `adr` — `Context / Decision / Consequences`. + - `checklist` — `- [ ] item` bullets only (plus a one-line preamble). + - `table` — markdown table + short recommendation paragraph. + Every result MUST end with a `## Sources` section listing the + concrete URLs, files, or tool calls the agent used. +7. **Mark the task done.** Move the queue file: + `sync-repo/sleep-queue/-*.md` → `sync-repo/sleep-queue-done/.md` + Also update the `status:` frontmatter line from `pending` to `done`. +8. **On catastrophic failure** (tool error not fixable in the 15-min + budget, missing dependency, corrupted frontmatter): move the file to + `sync-repo/sleep-queue-failed/.md`, update `status:` to + `failed`, and append a `## Failure reason` block to the body. Continue + with the next task. +9. **Commit once after Phase A completes** (single commit regardless of + how many tasks were processed). Commit message: + `REM: incubation ( task(s))` +10. **Then run Phase B** (see `sleep-trigger-prompt.md`). Phase B gets + its own commit: `REM: consolidation `. + +### Phase A time cap + +Total wall-clock cap for Phase A is **dynamic**: +- **Marathon run:** up to 480 minutes for the single selected task. + Phase B is SKIPPED this cycle. +- **Regular run:** greedy-pack up to 480 minutes total across at most + 5 tasks, driven by each task's `time_budget_minutes`. + +If the cap is hit mid-task, commit partial progress (honoring the +task's `checkpoint_every_minutes` cadence) and move the in-flight +task to `sleep-queue-failed/` with reason `phase-a-time-cap`. The +partial result (if any) stays in `sleep-results/.partial.md`. + +### Checkpointing (intermediate commits) + +If a task's `checkpoint_every_minutes` is > 0, the agent commits +partial progress at that cadence: + +``` +git add sleep-results/.partial.md +git commit -m "sleep: checkpoint at min" +git push +``` + +A final "task done" commit rolls the partial into `.md` and +deletes the `.partial.md` file. If the run is cut short, the last +partial persists in the repo and the user can read it on morning pull. + +--- + +## Example queue file (input) + +``` +--- +uuid: 8d4f3c1e-7b2a-4f1d-9c8e-0a1b2c3d4e5f +submitted_at: 2026-04-22T14:03:17Z +type: compare +priority: standard +format: table +time_budget_minutes: 60 +checkpoint_every_minutes: 20 +marathon: false +status: pending +--- + +Compare SvelteKit, Astro, and Next.js App Router for the kit's landing +page. Criteria: bundle size, SSR ergonomics, build time, ecosystem +depth, hosting footprint. +``` + +## Example result file (output) + +``` +# Compare: SvelteKit / Astro / Next.js App Router + +| Criterion (weight) | SvelteKit | Astro | Next.js App Router | +|------------------------|-----------|--------|--------------------| +| Bundle size (0.3) | 9/10 | 10/10 | 6/10 | +| SSR ergonomics (0.2) | 8/10 | 7/10 | 9/10 | +| Build time (0.2) | 8/10 | 9/10 | 6/10 | +| Ecosystem depth (0.2) | 7/10 | 6/10 | 10/10 | +| Hosting footprint (0.1)| 8/10 | 9/10 | 5/10 | +| **Weighted score** | **8.1** | **8.2**| **7.3** | + +**Recommendation:** Astro narrowly wins for a content-first kit landing +page. Pick SvelteKit if the landing grows into an app; Next.js App +Router only if you already ship a Next.js product suite. + +## Sources +- https://svelte.dev/docs/kit +- https://docs.astro.build/en/concepts/why-astro/ +- https://nextjs.org/docs/app +- (tool: WebSearch) "SvelteKit vs Astro 2026 bundle size benchmark" +``` + +--- + +## Exit reasons (per-task status) + +Every task ends in exactly one of: + +- `done` — full result in `sleep-results/.md`, queue file moved + to `sleep-queue-done/`. +- `time_budget_exhausted` — partial in `sleep-results/.partial.md` + with `[TIME-BOXED — min budget exhausted]` marker, queue file + moved to `sleep-queue-failed/` with `status: timed_out`. +- `checkpoint_saved` — intermediate state; the task is still pending + but the latest `.partial.md` is committed and pushed. This is NOT a + terminal status; it upgrades to `done` or `time_budget_exhausted`. +- `failed` — tool error, missing dependency, genesis-scan hit, or + other non-recoverable failure. Queue file moved to + `sleep-queue-failed/` with a `## Failure reason` block. + +## Invariants (MUST NOT violate) + +- **Never modify or delete `traces/*.jsonl`.** Phase A only touches + `sleep-queue/`, `sleep-queue-done/`, `sleep-queue-failed/`, and + `sleep-results/`. Phase B touches `reports/` and `backlog.md`. Neither + touches `traces/`. +- **Checkpoint commits are mandatory** when `checkpoint_every_minutes + > 0`. Skipping them loses user work on cloud-session eviction. +- **Never delete files outside the queue trees.** Move within the + sync-repo is the only mutation Phase A performs; `rm` is banned + outside `sleep-queue*/` (and even there, only after a successful + move to done/failed). +- **Never paraphrase patent-sensitive terms into the result body.** The + user-side `genesis-scan` gate is line of defense 1; the agent is line + of defense 2. If the agent's best-effort `genesis-scan` run on the + prompt returns non-zero (the scanner's forbidden-pattern list is + embedded in the binary itself — use + `genesis-scan list-patterns` if you need to inspect it), mark the + task failed with reason `patent-term-detected` and skip it entirely + — no partial result, no paraphrasing the matched token. +- **No shell command writes outside `sync-repo/`.** Results land in the + repo, nothing else. +- **No session feedback loop (RULE 0.15).** Results are for the user to + read the next morning. Nothing Phase A writes is auto-consumed by + another Claude Code session. + +--- + +## Failure handling (same as Phase B) + +- Clone fails or repo is dirty → exit 1, let the next run retry. +- `sleep-queue/` missing → create it empty + commit, then exit clean + (first run on an older sync-repo). +- Any single task fails → move to `sleep-queue-failed/`, continue. +- Phase A overall fails (total time cap, unhandled tool error) → commit + whatever partial state exists, THEN run Phase B normally. Phase B + must not depend on Phase A succeeding. diff --git a/skills/sleep-on-it/SKILL.md b/skills/sleep-on-it/SKILL.md new file mode 100644 index 0000000..5cbf900 --- /dev/null +++ b/skills/sleep-on-it/SKILL.md @@ -0,0 +1,117 @@ +--- +name: sleep-on-it +description: Defer a hard question, research task, or design comparison to the nightly remote agent (KeiSeiKit v0.12.0 incubation layer). Runs on top of the v0.11 sleep-sync pipeline — user fills one free-text field plus three clicks, task lands in sync-repo/sleep-queue/ and is processed before REM consolidation. Up to 5 tasks per night, 15 minutes each. Pure-click wizard except the single task-description field. +argument-hint: (no arguments) +--- + +# Sleep On It — Incubation Wizard (index) + +Biological analog: the REM-sleep "sleep on it" effect — insight generation +during incubation (Wagner et al. 2004, *Nature*). During the day the user +submits open questions, research tasks, or design comparisons via this +wizard; the nightly cloud agent processes the queue before its existing +REM consolidation pass and writes results to `sync-repo/sleep-results/`. + +This `SKILL.md` is the INDEX. Each phase lives in its own file and is +executed in order. Never skip a phase. Never re-order phases. + +--- + +## Prerequisites (hard fail fast if missing) + +- v0.11 sleep-sync must be configured (`~/.claude/secrets/.env` contains + `KEI_MEMORY_REPO_PATH`, `KEI_MEMORY_SSH_KEY`, and the sync-repo exists + under that path with a `.git/` subdir). +- `_primitives/kei-sleep-queue.sh` exists at + `~/.claude/agents/_primitives/kei-sleep-queue.sh` and is executable. + +If either is missing, print the single line + +``` +v0.11 sleep-sync not configured — run `/sleep-setup` first, then retry. +``` + +and exit the wizard. Do not attempt to queue anything offline. + +--- + +## Pipeline overview (6 phases, 5+ AskUserQuestion) + +| Phase | File | Purpose | AskUserQuestion | +|---|---|---|---| +| 1 | [phase-1-intake.md](phase-1-intake.md) | One free-text field: the question / task | 0 (prompt, non-empty validate) | +| 2 | [phase-2-type.md](phase-2-type.md) | Task type: deep / pipeline / pattern / compare / custom | 1 (click) | +| 3 | [phase-3-priority.md](phase-3-priority.md) | Priority: tonight / FIFO / weekly | 1 (click) | +| 4 | [phase-4-format.md](phase-4-format.md) | Output format: markdown / ADR / checklist / table | 1 (click) | +| 5 | [phase-5-submit.md](phase-5-submit.md) | Preview frontmatter + body, submit / edit / abort | 1 (click) | +| 6 | [phase-6-ack.md](phase-6-ack.md) | Acknowledgment with UUID + queue path + run ETA | 1 (click) | + +**Minimum AskUserQuestion count: 5.** All clicks except the single +free-text task description in Phase 1. + +--- + +## Variables the pipeline produces + +| Name | Set in | Meaning | +|---|---|---| +| `TASK_TEXT` | Phase 1 | Free-text task description (non-empty) | +| `TASK_TYPE` | Phase 2 | `deep` / `pipeline` / `pattern` / `compare` / `custom` | +| `PRIORITY` | Phase 3 | `night` / `fifo` / `weekly` | +| `FORMAT` | Phase 4 | `md` / `adr` / `checklist` / `table` | +| `SUBMIT_ACTION` | Phase 5 | `submit` / `edit` / `abort` | +| `QUEUE_PATH` | Phase 5 | Path of the queue file written by `kei-sleep-queue.sh add` | +| `UUID` | Phase 5 | UUID assigned by the helper | + +--- + +## Final report (emit after Phase 6) + +``` +=== SLEEP-ON-IT REPORT === +UUID: +Queue file: +Task type: +Priority: +Output format: +Next run ETA: +Results land: sync-repo/sleep-results/.md +``` + +--- + +## Rules (apply throughout — enforced at every phase) + +- **Pure-click contract.** Only Phase 1 asks for free text; every other + decision is an `AskUserQuestion`. No `freeText` outside Phase 1. +- **Idempotent.** Re-running the wizard while a previous task is still + pending is fine — each submission gets its own UUID and its own queue + file. No "one pending at a time" constraint. +- **Genesis-scan on submit (RULE 0.1 second line of defense).** The + helper `kei-sleep-queue.sh add` pipes the task text through + `genesis-scan --stdin --exit-on-hit` when the binary exists. On hit + the submission is rejected with the scanner's stderr surfaced to chat. + Bypass only via `KEI_SLEEP_GENESIS_BYPASS=1` with a visible note. +- **NO DOWNGRADE (RULE -1).** If the helper rejects (genesis hit, invalid + flag, sync push fails), surface 2-3 constructive fix paths — never + "cannot submit". +- **NO HALLUCINATION (RULE 0.4).** Never fabricate a UUID, queue path, + or ETA — always echo the real helper output. +- **RULE 0.8 secrets.** Queue files never embed tokens; env refs live in + `~/.claude/secrets/.env` only. +- **Silent failure (RULE 0.15).** If the post-submit sync push fails, + the queue file still lives locally and will be pushed on the next + session-end dump. The wizard must NOT block on push failure. +- **Constructor Pattern (RULE ZERO).** Every phase file < 100 LOC. + +--- + +## References + +- `~/.claude/rules/sleep-layer.md` — RULE 0.15 full text (Phase A added v0.12.0) +- `_primitives/kei-sleep-queue.sh` — the queue CRUD helper +- `_primitives/kei-sleep-sync.sh` — the session-end-dump callback (also + invoked by `kei-sleep-queue.sh add` after write) +- `_primitives/templates/sleep-incubation-prompt.md` — cloud agent Phase A +- `_primitives/templates/sleep-trigger-prompt.md` — cloud agent Phase B +- `skills/sleep-setup/` — v0.11 one-time sync-repo wizard (prerequisite) diff --git a/skills/sleep-on-it/phase-1-intake.md b/skills/sleep-on-it/phase-1-intake.md new file mode 100644 index 0000000..c76d44b --- /dev/null +++ b/skills/sleep-on-it/phase-1-intake.md @@ -0,0 +1,58 @@ +# Phase 1 — Task intake (one free-text field) + +The single free-text field in the wizard. Everything else is a click. + +## 1a — Prerequisite check + +Before prompting, verify the v0.11 pipeline is live: + +```bash +# Resolve sync-repo path from env or secrets file. +# shellcheck disable=SC1091 +[ -f "${HOME}/.claude/secrets/.env" ] && . "${HOME}/.claude/secrets/.env" +REPO_PATH="${KEI_MEMORY_REPO_PATH:-}" +QUEUE_SH="${HOME}/.claude/agents/_primitives/kei-sleep-queue.sh" + +if [ -z "$REPO_PATH" ] || [ ! -d "$REPO_PATH/.git" ] || [ ! -x "$QUEUE_SH" ]; then + printf 'v0.11 sleep-sync not configured — run `/sleep-setup` first, then retry.\n' + exit 0 +fi +``` + +If either check fails, exit the wizard. Do not offer offline queue mode. + +## 1b — Free-text prompt + +Emit a plain chat message (NOT `AskUserQuestion` — a free-text message +is fine when it is the only typed field and has a trivial non-empty +validator): + +> What are you sleeping on? One or two sentences — the nightly agent +> will read this verbatim. Examples: +> +> - "Should I pick CfC or a small transformer as the memory re-ranker?" +> - "Compare SvelteKit, Astro, and Next.js App Router for the kit's landing page." +> - "What pattern in recent audit-backlog entries has the highest fix-value-per-effort?" + +Store the reply as `TASK_TEXT`. + +## 1c — Validate + +- Reject if `TASK_TEXT` is empty or only whitespace. +- Reject if `TASK_TEXT` > 4000 characters (keep queue files small; the + agent has 15 minutes wall-clock anyway — a novella does not help). + +On reject, print + +``` +Task description must be non-empty and <= 4000 chars. Try again? +``` + +and re-prompt. Up to 3 attempts; on the 3rd empty submission abort the +wizard with a short "try again with `/sleep-on-it`" message. + +## Verify-criterion + +- `TASK_TEXT` is non-empty and <= 4000 chars. +- The v0.11 sync pipeline is wired (REPO_PATH + QUEUE_SH exist). +- Exactly ZERO `AskUserQuestion` in this phase (free-text message only). diff --git a/skills/sleep-on-it/phase-2-type.md b/skills/sleep-on-it/phase-2-type.md new file mode 100644 index 0000000..db5ceeb --- /dev/null +++ b/skills/sleep-on-it/phase-2-type.md @@ -0,0 +1,71 @@ +# Phase 2 — Task type (click) + +Map the free-text task to one of five dispatch categories. The remote +agent's Phase A uses this to pick the right tool chain. + +## 2a — Click + +Emit ONE `AskUserQuestion`: + +```json +{ + "questions": [ + { + "question": "How should the nightly agent approach this task?", + "header": "Type", + "multiSelect": false, + "options": [ + { + "label": "Deep research", + "description": "WebSearch + WebFetch + synthesis — 3+ searches, 2+ page fetches, structured report" + }, + { + "label": "Pipeline design", + "description": "Architect + critic sequence — 5-7 phases with verify-criteria and tradeoffs" + }, + { + "label": "Pattern analysis", + "description": "Query kei-memory + past reports — extract trends across sessions, propose action" + }, + { + "label": "Comparative study", + "description": "Pros/cons matrix across N options the user lists — weighted recommendation" + }, + { + "label": "Custom", + "description": "Follow the task text verbatim — no dispatch tool, free-form response" + } + ] + } + ] +} +``` + +## 2b — Normalise + +Map the clicked label to a compact token the queue file stores: + +| Label | Token | +|---|---| +| Deep research | `deep` | +| Pipeline design | `pipeline` | +| Pattern analysis | `pattern` | +| Comparative study | `compare` | +| Custom | `custom` | + +Store as `TASK_TYPE`. + +## 2c — Soft nudge on mismatch + +If `TASK_TYPE == "custom"` AND `TASK_TEXT` contains any of +`should I | compare | trade[- ]off | which is better`, print a soft hint: + +> Your task text looks like a comparison — `compare` or `deep` usually +> produce a stronger result than `custom`. Proceeding anyway. + +Do NOT re-ask. One nudge, user keeps control. + +## Verify-criterion + +- `TASK_TYPE ∈ {deep, pipeline, pattern, compare, custom}`. +- Exactly ONE `AskUserQuestion` in this phase. diff --git a/skills/sleep-on-it/phase-3-priority.md b/skills/sleep-on-it/phase-3-priority.md new file mode 100644 index 0000000..3b1eead --- /dev/null +++ b/skills/sleep-on-it/phase-3-priority.md @@ -0,0 +1,130 @@ +# Phase 3 — Priority & time budget (click) + +Decide how much night-time the remote agent spends on this task. +Priority maps to a wall-clock budget; the pipeline reads the budget +from frontmatter, so a hard equation can own the whole night while a +quick lookup is boxed to 15 minutes. + +## 3a — Click + +Emit ONE `AskUserQuestion`: + +```json +{ + "questions": [ + { + "question": "How much night-time should this task get?", + "header": "Priority", + "multiSelect": false, + "options": [ + { + "label": "Quick", + "description": "15 min, this night — simple questions, fast lookups" + }, + { + "label": "Standard", + "description": "60 min, this night — default, medium research" + }, + { + "label": "Deep", + "description": "4 hour, this night — serious derivations, thorough prior-art" + }, + { + "label": "Marathon", + "description": "Full night, 1 task only — hard equations, full autonomy; Phase B REM skipped this night" + }, + { + "label": "Weekly batch", + "description": "60 min, processed next Sunday UTC — non-urgent research" + } + ] + } + ] +} +``` + +## 3b — Marathon confirmation + +If `LABEL == "Marathon"`, emit ONE more `AskUserQuestion` so the user +consciously accepts the cost: + +```json +{ + "questions": [ + { + "question": "Marathon = this task owns the whole night. Phase B REM consolidation is skipped. Other queue tasks deferred to next night. Confirm?", + "header": "Marathon", + "multiSelect": false, + "options": [ + {"label": "Yes, marathon", "description": "Take the full night; defer everything else"}, + {"label": "No, downgrade to Deep (4 hour)", "description": "Still a long run but Phase B and other tasks proceed"} + ] + } + ] +} +``` + +If the user picks "No, downgrade to Deep (4 hour)", treat the effective +label as `Deep` for the rest of the pipeline. + +## 3c — Normalise + +Map the final label (after any marathon downgrade) to four variables: + +| Label | `PRIORITY_LABEL` | `TIME_BUDGET_MINUTES` | `CHECKPOINT_EVERY_MINUTES` | `MARATHON` | +|---------------|------------------|-----------------------|----------------------------|------------| +| Quick | `quick` | 15 | 0 (off) | `false` | +| Standard | `standard` | 60 | 20 | `false` | +| Deep | `deep` | 240 | 30 | `false` | +| Marathon | `marathon` | 480 | 30 | `true` | +| Weekly batch | `weekly` | 60 | 20 | `false` | + +Store all four as phase-scoped variables. They flow to Phase 5, which +passes them to `kei-sleep-queue.sh add`. + +## 3d — Cap check (informational) + +If `PRIORITY_LABEL ∈ {quick, standard, deep, marathon}` (i.e. this +night), count current this-night pending tasks: + +```bash +~/.claude/agents/_primitives/kei-sleep-queue.sh list --pending \ + | awk '$4 ~ /^(quick|standard|deep|marathon)$/' \ + | wc -l +``` + +Informational messages: + +- **Marathon already queued this night:** + > A marathon task is already pending for tonight. Submitting a second + > marathon — or any this-night task — will be deferred to the next + > night, because the marathon owns the whole window. + +- **Greedy-pack near-full (≥ 480 min queued this-night):** + > Tonight's this-night budget is nearly full (≥ 8 hours queued). New + > this-night tasks will still be accepted but may be deferred to the + > next night by the greedy-packing scheduler. + +Do NOT re-prompt; the user may explicitly want overflow. + +## 3e — Advanced overrides (informational) + +After Phase 5 preview, explicit flags override the priority defaults: + +``` +kei-sleep-queue add --time-budget m # e.g. --time-budget 90m + --checkpoint-every m # e.g. --checkpoint-every 15m + --no-timeout # time_budget_minutes: null + --marathon # explicit marathon flag +``` + +The wizard does not emit these flags itself; they exist for power users +who call the helper directly. + +## Verify-criterion + +- `PRIORITY_LABEL ∈ {quick, standard, deep, marathon, weekly}`. +- `TIME_BUDGET_MINUTES ∈ {15, 60, 240, 480}` per the table. +- `CHECKPOINT_EVERY_MINUTES ∈ {0, 20, 30}` per the table. +- `MARATHON` is boolean and `true` iff `PRIORITY_LABEL == "marathon"`. +- At most TWO `AskUserQuestion` calls (second only on marathon path). diff --git a/skills/sleep-on-it/phase-4-format.md b/skills/sleep-on-it/phase-4-format.md new file mode 100644 index 0000000..376268f --- /dev/null +++ b/skills/sleep-on-it/phase-4-format.md @@ -0,0 +1,63 @@ +# Phase 4 — Output format (click) + +Tell the remote agent how to shape `sync-repo/sleep-results/.md`. + +## 4a — Click + +Emit ONE `AskUserQuestion`: + +```json +{ + "questions": [ + { + "question": "What format should the result use?", + "header": "Format", + "multiSelect": false, + "options": [ + { + "label": "Structured markdown report", + "description": "Sections + findings + sources — default, best for research / pattern analysis" + }, + { + "label": "ADR-style decision record", + "description": "Context / Decision / Consequences — best for pipeline-design output" + }, + { + "label": "Checklist / action items", + "description": "`- [ ] item` list — best when you want a morning TODO" + }, + { + "label": "Pros/cons table", + "description": "Markdown table with weighted criteria — best for comparative study" + } + ] + } + ] +} +``` + +## 4b — Normalise + +| Label | Token | +|---|---| +| Structured markdown report | `md` | +| ADR-style decision record | `adr` | +| Checklist / action items | `checklist` | +| Pros/cons table | `table` | + +Store as `FORMAT`. + +## 4c — Coherence hint + +Soft hint only (no re-ask), when type and format drift apart: + +- `TASK_TYPE == compare` and `FORMAT != table` → hint that `table` is the usual pick. +- `TASK_TYPE == pipeline` and `FORMAT != adr` → hint that `adr` is the usual pick. +- `TASK_TYPE == pattern` and `FORMAT != checklist` → hint that `checklist` often reads best. + +Format: single line, does not block. + +## Verify-criterion + +- `FORMAT ∈ {md, adr, checklist, table}`. +- Exactly ONE `AskUserQuestion` in this phase. diff --git a/skills/sleep-on-it/phase-5-submit.md b/skills/sleep-on-it/phase-5-submit.md new file mode 100644 index 0000000..989d6fc --- /dev/null +++ b/skills/sleep-on-it/phase-5-submit.md @@ -0,0 +1,121 @@ +# Phase 5 — Preview and submit (click) + +Show the user exactly what will be written, then submit via the helper. + +## 5a — Render preview + +Print a fenced block with the frontmatter + body preview: + +``` +--- +uuid: +submitted_at: +type: +priority: +format: +time_budget_minutes: +checkpoint_every_minutes: +marathon: +status: pending +--- + + +``` + +Then print a one-line wall-clock estimate: + +``` +estimated wall-clock: min +``` + +If `MARATHON == true`, append an explicit warning line beneath the +estimate: + +``` +marathon: Phase B REM consolidation will be SKIPPED the night this +task runs, and other queue items will be deferred to the next night. +``` + +Tell the user the `uuid` and `submitted_at` fields are assigned by the +helper on submit — the preview leaves them as placeholders. + +## 5b — Click + +Emit ONE `AskUserQuestion`: + +```json +{ + "questions": [ + { + "question": "Submit this to the nightly queue?", + "header": "Submit", + "multiSelect": false, + "options": [ + {"label": "Submit", "description": "Write queue file + push to memory-repo"}, + {"label": "Edit", "description": "Go back to Phase 1 and re-enter the task text"}, + {"label": "Abort", "description": "Drop the draft; nothing is written"} + ] + } + ] +} +``` + +Store the pick as `SUBMIT_ACTION`. + +## 5c — Dispatch + +- `SUBMIT_ACTION == "Edit"` → restart from Phase 1 (clears all variables). +- `SUBMIT_ACTION == "Abort"` → print `submission cancelled` and exit. +- `SUBMIT_ACTION == "Submit"` → call the helper (see 5d). + +## 5d — Invoke `kei-sleep-queue.sh add` + +Write the task text to a temp file, then: + +```bash +PROMPT_FILE="$(mktemp)" +printf '%s\n' "$TASK_TEXT" > "$PROMPT_FILE" +MARATHON_FLAG="" +[ "$MARATHON" = "true" ] && MARATHON_FLAG="--marathon" +OUTPUT="$( + ~/.claude/agents/_primitives/kei-sleep-queue.sh add \ + --type "$TASK_TYPE" \ + --priority "$PRIORITY_LABEL" \ + --format "$FORMAT" \ + --time-budget "${TIME_BUDGET_MINUTES}m" \ + --checkpoint-every "${CHECKPOINT_EVERY_MINUTES}m" \ + $MARATHON_FLAG \ + --prompt-file "$PROMPT_FILE" 2>&1 +)" +STATUS=$? +rm -f "$PROMPT_FILE" +``` + +The helper prints two lines on success: + +``` + + +``` + +Capture `UUID = first line`, `QUEUE_PATH = second line`. + +On non-zero exit, surface stderr verbatim. Common causes: + +- **genesis-scan hit** → task text contains a patent-sensitive term. + Constructive paths (RULE -1): + 1. Rewrite the task generically ("pick between " + becomes "pick between technology A and B"). + 2. Set `KEI_SLEEP_GENESIS_BYPASS=1` and re-run if the term is a + false positive (cite the specific word). + 3. Abort; keep the question local. +- **write failed** (disk / permissions) → print the error; exit. +- **sync push failed after local write succeeded** → not an error; the + queue file IS committed locally and will push on next session end. + +## Verify-criterion + +- `SUBMIT_ACTION ∈ {Submit, Edit, Abort}`. +- If `Submit`, `UUID` is a non-empty string and `QUEUE_PATH` ends in + `.md` under `sync-repo/sleep-queue/`. +- Exactly ONE `AskUserQuestion` in this phase. diff --git a/skills/sleep-on-it/phase-6-ack.md b/skills/sleep-on-it/phase-6-ack.md new file mode 100644 index 0000000..3bde0fa --- /dev/null +++ b/skills/sleep-on-it/phase-6-ack.md @@ -0,0 +1,74 @@ +# Phase 6 — Acknowledgment (click) + +Show the user what was written, how to inspect it, and when the agent +picks it up. + +## 6a — Resolve next-run ETA + +Read the cron expression the `/schedule` trigger uses. The helper keeps +the URL in `sync-repo/.keisei-sync.toml`; the cron target itself is in +the user's Claude Code `/schedule list`. We do not parse the scheduler +from this skill (no portable API) — instead, print the canonical line: + +```bash +grep -E '^schedule_utc_cron' "$REPO_PATH/.keisei-sync.toml" 2>/dev/null \ + || printf 'schedule_utc_cron = "unknown — run /schedule list to verify"\n' +``` + +If the key is absent (older sync-repo), print the fallback line +verbatim. Do not fabricate a time (RULE 0.4). + +## 6b — Print acknowledgment block + +Emit this block to chat: + +``` +Queued. + + UUID: + File: + Type: + Priority: + Format: + Next run: + Results at: /sleep-results/.md (after the next run) + +Inspect: `kei-sleep-queue show ` +List all: `kei-sleep-queue list --pending` +Cancel: delete the file at the path above before the next run +``` + +## 6c — Click (final) + +Emit ONE `AskUserQuestion`: + +```json +{ + "questions": [ + { + "question": "What now?", + "header": "Done", + "multiSelect": false, + "options": [ + {"label": "Show queue", "description": "Run `kei-sleep-queue list --pending`"}, + {"label": "Submit another", "description": "Restart the wizard"}, + {"label": "Done", "description": "Close the wizard"} + ] + } + ] +} +``` + +Handle each option: + +- `Show queue` → shell out to `kei-sleep-queue list --pending` and + print the table; then re-emit this click. +- `Submit another` → restart the wizard from Phase 1. +- `Done` → emit the final report from `SKILL.md` and exit. + +## Verify-criterion + +- The acknowledgment block in 6b was printed with real values (no `` + placeholders left). +- Exactly ONE `AskUserQuestion` in this phase (plus loops on "Show queue"). +- The final report block from `SKILL.md` was emitted on `Done`. From 3cead09520f908627cf2d901a0ce91405034ff6d Mon Sep 17 00:00:00 2001 From: Parfii-bot Date: Wed, 22 Apr 2026 02:30:04 +0800 Subject: [PATCH 2/2] feat(integration): Phase A incubation wired into trigger + install + README --- README.md | 24 +++++++++++++++++++ _primitives/templates/sleep-trigger-prompt.md | 22 ++++++++++++++++- install.sh | 9 +++---- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index dcf61cf..ccc1fa2 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,30 @@ After that, the sleep cycle runs every night automatically. The morning report i Opt in at install time with `./install.sh --with-sleep-sync` (TTY-only). Governed by RULE 0.15 in `~/.claude/rules/sleep-layer.md`. +### Sleep on it (incubation, v0.12.0) + +Defer a hard question or research task to the nightly remote agent: run `/sleep-on-it`, fill in one free-text field plus three clicks (type / priority / format), submit. The task lands in `sync-repo/sleep-queue/` and the nightly agent processes it before REM consolidation. + +Priority maps to a wall-clock budget. Pick the one that matches the task's difficulty: + +| Priority | Budget | When to pick | +|---|---|---| +| Quick | 15 min, this night | Simple questions, fast lookups | +| Standard | 60 min, this night | Default, medium research | +| Deep | 4 hours, this night | Serious derivations, thorough prior-art | +| Marathon | Full night (up to 8 h), **1 task only** | Hard equations, full autonomy; Phase B REM skipped that night | +| Weekly batch | 60 min, next Sunday UTC | Non-urgent research | + +Checkpointing: Standard / Deep / Marathon runs commit a `.partial.md` every 20–30 minutes, so if the cloud session is cut short you still get the partial on morning pull. + +Typical use: +- "Should I use CfC for memory re-ranker?" → deep-research → architectural recommendation by morning +- "Compare SvelteKit vs Astro vs Next.js App Router for the kit's landing" → comparative study +- "Derive closed form for the CfC attractor on Stiefel V(p,k=2)" → marathon mode, full night of autonomous derivation +- "What patterns in audit-backlog have highest impact?" → pattern analysis + +Results in `sync-repo/sleep-results/.md`, linked from the next morning's REM report. Biological analog: the REM-sleep "sleep on it" effect (Wagner et al. 2004, *Nature*). Queue mutations go through the `kei-sleep-queue` helper, which runs `genesis-scan` on submit as a second line of defense against patent-sensitive prompts leaking to the cloud agent. + ## Primitives (Rust) `_primitives/_rust/` is a Cargo workspace with 9 single-binary crates. `install.sh` builds `--release` and drops binaries at `~/.claude/agents/_primitives/_rust/target/release/`. diff --git a/_primitives/templates/sleep-trigger-prompt.md b/_primitives/templates/sleep-trigger-prompt.md index d8bf0e3..d13aab4 100644 --- a/_primitives/templates/sleep-trigger-prompt.md +++ b/_primitives/templates/sleep-trigger-prompt.md @@ -14,7 +14,27 @@ Clone: {REPO_URL} Branch: main Time: 03:00 local (UTC cron: {UTC_CRON}) -## Task +## Cycle order (v0.12.0+) + +1. **Phase A — Incubation ("sleep on it")** — process user-submitted + tasks in `sync-repo/sleep-queue/`. See + `sleep-incubation-prompt.md` (shipped in the same `templates/` dir) + for the full spec. Phase A writes results to + `sync-repo/sleep-results/.md` (plus optional intermediate + `.partial.md` checkpoints) and commits at least once. +2. **Phase B — REM consolidation** (this document). Phase B analyses + new traces and commits its own `REM: consolidation ` + commit. Normally two commits per night, one per phase. + +If `sync-repo/sleep-queue/` is empty or missing, Phase A is a silent +no-op. Phase B runs regardless of Phase A outcome **except when Phase +A selected a `marathon: true` task** — in that case Phase B is +SKIPPED for the night so the marathon task owns the full window. +Phase B resumes the next night; a single skipped night does not lose +traces (they stay in `traces/` and will be consolidated on the next +run). + +## Phase B — Task 1. Clone the memory repo shallow. 2. Identify NEW traces in `traces/` since the last consolidation by diff --git a/install.sh b/install.sh index 2086605..474fe3f 100755 --- a/install.sh +++ b/install.sh @@ -1005,10 +1005,11 @@ mkdir -p "$AGENTS_DIR/_primitives" cp -f "$KIT_DIR/_primitives/MANIFEST.toml" "$AGENTS_DIR/_primitives/MANIFEST.toml" 2>/dev/null || true cp -f "$KIT_DIR/_primitives/README.md" "$AGENTS_DIR/_primitives/" 2>/dev/null || true -# v0.11 sleep-sync scripts — NOT listed in MANIFEST because they're always -# available regardless of profile (zero binary deps; enabled only when the -# user opts in via /sleep-setup). Copy them every install. -for sleep_sh in kei-sleep-setup.sh kei-sleep-sync.sh; do +# v0.11 sleep-sync + v0.12 sleep-on-it queue scripts — NOT listed in MANIFEST +# because they're always available regardless of profile (zero binary deps; +# enabled only when the user opts in via /sleep-setup + /sleep-on-it). Copy +# them every install. +for sleep_sh in kei-sleep-setup.sh kei-sleep-sync.sh kei-sleep-queue.sh; do src="$KIT_DIR/_primitives/$sleep_sh" if [ -f "$src" ]; then cp -f "$src" "$AGENTS_DIR/_primitives/$sleep_sh"