Merge branch 'feat/v0.11-sleep-sync' — v0.11.0 cloud REM sync for public users
This commit is contained in:
commit
c6c572dcf4
12 changed files with 921 additions and 5 deletions
27
README.md
27
README.md
|
|
@ -1,6 +1,6 @@
|
|||
# KeiSeiKit — Constructor-Pattern Agent Kit for Claude Code
|
||||
|
||||
KeiSeiKit is a comprehensive drop-in toolkit for [Claude Code](https://claude.com/claude-code). It ships a curated set of composable behavioral blocks, a Rust assembler that builds agent `.md` files from TOML manifests deterministically, nine pre-wired hooks (three of them dedicated to RULE 0.14 session self-audit), 35 portable skills (including an interactive `/new-agent` wizard, 10 hub-and-spoke pipelines, and the `/self-audit` retrospective skill), **10 Rust primitive crates** (including `genesis-scan` patent-IP leak detector), 13 shell primitives, and 11 cross-tool bridge templates. Everything follows a Constructor Pattern: one file per concern, manifests as single source of truth, and the generated agent files are regenerated on every relevant edit.
|
||||
KeiSeiKit is a comprehensive drop-in toolkit for [Claude Code](https://claude.com/claude-code). It ships a curated set of composable behavioral blocks, a Rust assembler that builds agent `.md` files from TOML manifests deterministically, nine pre-wired hooks (three of them dedicated to RULE 0.14 session self-audit), 35 portable skills (including an interactive `/new-agent` wizard, 10 hub-and-spoke pipelines, and the `/self-audit` retrospective skill), **9 Rust primitive crates**, 13 shell primitives, and 11 cross-tool bridge templates. Everything follows a Constructor Pattern: one file per concern, manifests as single source of truth, and the generated agent files are regenerated on every relevant edit.
|
||||
|
||||
The kit is MIT-licensed and fully generic — install it on a fresh machine and you get a sane 12-agent fleet (implementers, critics, researchers, cost-guardians, and more — all namespaced under `kei-*` so they won't collide with your own same-named agents), a wizard for spinning up new project specialists, 10 pipeline skills that combine primitives end-to-end (`/compose-solution`, `/site-create`, `/schema-design`, `/observability-setup`, `/auth-setup`, `/api-design`, `/ci-scaffold`, `/test-matrix`, `/docs-scaffold`, `/new-project`, `/vm-provision`), and a build pipeline that keeps every agent derivable from its manifest.
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ By default `./install.sh` is **minimal** — agents + hooks + skills + bridges,
|
|||
| Profile | Primitives added | Install time | Disk (approx) |
|
||||
|---|---|---|---|
|
||||
| `minimal` (default) | none | ~5s | ~2 MB |
|
||||
| `core` | `tomd`, `genesis-scan` | ~10s | ~5 MB |
|
||||
| `core` | `tomd` | ~5s | ~3 MB |
|
||||
| `frontend` | 8 site tools: `mock-render`, `visual-diff`, `tokens-sync`, `design-scrape`, `live-preview`, `figma-tokens`, `frontend-inspect`, `screenshot-decode` | ~60s | ~80 MB |
|
||||
| `ops` | 8 infra tools: `kei-ledger`, `ssh-check`, `firewall-diff`, `provision-hetzner`, `provision-vultr`, `harden-base`, `metrics-scrape`, `log-ship` | ~90s | ~50 MB |
|
||||
| `dev` | 4 dev tools: `kei-migrate`, `kei-changelog`, `kei-ci-lint`, `kei-docs-scaffold` | ~60s | ~40 MB |
|
||||
|
|
@ -152,6 +152,28 @@ Manual trigger: `/self-audit` skill (same flow, invoked on demand).
|
|||
|
||||
Requires the `kei-memory` primitive. Included in the `dev` and `full` profiles; otherwise add via `./install.sh --add=kei-memory`.
|
||||
|
||||
## Cloud REM sync (sleep layer, v0.11.0)
|
||||
|
||||
Run a nightly "sleep" cycle on Anthropic's cloud — no laptop, no infra, no DevOps.
|
||||
|
||||
**How it works:**
|
||||
- Each session: your Mac pushes trace JSONL to a private git repo you control
|
||||
- 03:00 local time: a remote Claude Code agent clones the repo, analyzes the last 24h of traces, writes `reports/sleep-YYYY-MM-DD.md`, and commits back
|
||||
- Next morning: `git pull` and read the consolidated findings
|
||||
|
||||
**Setup (one-time, ~5 min):**
|
||||
|
||||
1. Create an empty private repo on GitHub / GitLab / Bitbucket / self-hosted Forgejo
|
||||
2. In Claude Code run `/sleep-setup`
|
||||
3. The wizard generates an SSH deploy key → you paste it into the repo's deploy-key settings with WRITE access
|
||||
4. The wizard emits a ready-to-paste `/schedule create` command, converted to your local 03:00 in UTC
|
||||
|
||||
After that, the sleep cycle runs every night automatically. The morning report is yours to read — nothing is auto-injected back into any session.
|
||||
|
||||
**Requires** the `kei-memory` primitive (shipped in the `dev` and `full` profiles; add via `./install.sh --add=kei-memory` otherwise). Sleep-sync scripts themselves are installed unconditionally and stay dormant until you opt in via `/sleep-setup`.
|
||||
|
||||
Opt in at install time with `./install.sh --with-sleep-sync` (TTY-only). Governed by RULE 0.15 in `~/.claude/rules/sleep-layer.md`.
|
||||
|
||||
## 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/<name>`.
|
||||
|
|
@ -167,7 +189,6 @@ Requires the `kei-memory` primitive. Included in the `dev` and `full` profiles;
|
|||
| `visual-diff` | Pixel diff with tolerance — used in `/site-create` screenshot-regression loop |
|
||||
| `tokens-sync` | Design tokens JSON → Tailwind config extend + CSS variables under `:root` |
|
||||
| `kei-memory` | Session retrospective + recurring pattern detector; offline-first analyzer powering RULE 0.14 self-audit |
|
||||
| `genesis-scan` | Patent-IP leak scanner — runs as a git pre-commit or CI gate (complements the `genesis-leak-guard` runtime hook) |
|
||||
|
||||
## Primitives (shell)
|
||||
|
||||
|
|
|
|||
192
_primitives/kei-sleep-setup.sh
Executable file
192
_primitives/kei-sleep-setup.sh
Executable file
|
|
@ -0,0 +1,192 @@
|
|||
#!/usr/bin/env bash
|
||||
# kei-sleep-setup.sh — KeiSeiKit v0.11 sleep-sync first-time wizard.
|
||||
# Generates deploy key, scaffolds sync-repo, writes env refs (RULE 0.8).
|
||||
# Idempotent. Invoked by `/sleep-setup` skill or `install.sh --with-sleep-sync`.
|
||||
set -eu
|
||||
|
||||
KEI_HOME="${HOME}/.claude"
|
||||
SECRETS_FILE="${KEI_HOME}/secrets/.env"
|
||||
SSH_KEY="${HOME}/.ssh/keisei-memory-sync"
|
||||
REPO_PATH="${KEI_HOME}/memory/sync-repo"
|
||||
|
||||
say() { printf '[sleep-setup] %s\n' "$*"; }
|
||||
warn() { printf '[sleep-setup] warn: %s\n' "$*" >&2; }
|
||||
err() { printf '[sleep-setup] error: %s\n' "$*" >&2; }
|
||||
|
||||
validate_ssh_url() {
|
||||
printf '%s' "$1" | grep -Eq '^git@[A-Za-z0-9._-]+:[A-Za-z0-9._/-]+\.git$'
|
||||
}
|
||||
|
||||
url_host() {
|
||||
printf '%s' "$1" | sed -E 's/^git@([^:]+):.*/\1/'
|
||||
}
|
||||
|
||||
prompt_repo_url() {
|
||||
local url="${KEI_MEMORY_REPO_URL:-}"
|
||||
if [ -n "$url" ]; then
|
||||
say "using KEI_MEMORY_REPO_URL from environment"
|
||||
elif [ -t 0 ]; then
|
||||
printf '\nMemory repo SSH URL (e.g. git@github.com:you/kei-memory.git):\n > '
|
||||
read -r url
|
||||
else
|
||||
err "no repo URL provided and no TTY to prompt; set KEI_MEMORY_REPO_URL"
|
||||
exit 1
|
||||
fi
|
||||
if ! validate_ssh_url "$url"; then
|
||||
err "invalid SSH URL format: $url"
|
||||
err "expected: git@<host>:<org>/<repo>.git"
|
||||
exit 1
|
||||
fi
|
||||
printf '%s' "$url"
|
||||
}
|
||||
|
||||
ensure_ssh_key() {
|
||||
mkdir -p "$(dirname "$SSH_KEY")"
|
||||
chmod 700 "$(dirname "$SSH_KEY")" 2>/dev/null || true
|
||||
if [ -f "$SSH_KEY" ] && [ -f "${SSH_KEY}.pub" ]; then
|
||||
say "deploy key already exists at $SSH_KEY (skipping)"
|
||||
return 0
|
||||
fi
|
||||
say "generating ed25519 deploy key at $SSH_KEY"
|
||||
ssh-keygen -t ed25519 -f "$SSH_KEY" -N '' -C 'keisei-memory-sync' >/dev/null
|
||||
chmod 600 "$SSH_KEY"
|
||||
}
|
||||
|
||||
show_deploy_key_instructions() {
|
||||
local url="$1"
|
||||
printf '\n==============================================================\n'
|
||||
printf ' ADD THIS AS A DEPLOY KEY (WRITE ACCESS) TO: %s\n' "$url"
|
||||
printf '==============================================================\n\n'
|
||||
cat "${SSH_KEY}.pub"
|
||||
printf '\nFingerprint: '
|
||||
ssh-keygen -lf "${SSH_KEY}.pub" 2>/dev/null || true
|
||||
printf '\nGitHub: Settings -> Deploy keys -> Add ("Allow write access")\n'
|
||||
printf 'GitLab: Settings -> Repository -> Deploy keys -> Enable write\n'
|
||||
printf 'Bitbucket: Repository settings -> Access keys -> Add (write)\n'
|
||||
printf 'Forgejo: Settings -> Deploy Keys -> Add (allow write)\n'
|
||||
printf '==============================================================\n\n'
|
||||
}
|
||||
|
||||
init_sync_repo() {
|
||||
local url="$1"
|
||||
mkdir -p "$REPO_PATH"
|
||||
if [ -d "${REPO_PATH}/.git" ]; then
|
||||
say "sync-repo already initialized at $REPO_PATH"
|
||||
return 0
|
||||
fi
|
||||
say "cloning $url → $REPO_PATH (shallow, may fail if repo empty — will init instead)"
|
||||
if GIT_SSH_COMMAND="ssh -i $SSH_KEY -o StrictHostKeyChecking=accept-new" \
|
||||
git clone --depth 1 "$url" "$REPO_PATH" 2>/dev/null; then
|
||||
say "cloned existing repo"
|
||||
else
|
||||
say "clone failed (empty repo?) — initializing local and setting remote"
|
||||
rm -rf "$REPO_PATH"
|
||||
mkdir -p "$REPO_PATH"
|
||||
( cd "$REPO_PATH" && git init -q -b main && git remote add origin "$url" )
|
||||
fi
|
||||
}
|
||||
|
||||
scaffold_repo_structure() {
|
||||
local url="$1"
|
||||
cd "$REPO_PATH"
|
||||
mkdir -p traces reports
|
||||
[ -f README.md ] || write_readme
|
||||
[ -f .gitignore ] || printf 'target/\nnode_modules/\n.DS_Store\n*.swp\n*.swo\n' > .gitignore
|
||||
[ -f backlog.md ] || write_backlog
|
||||
[ -f .keisei-sync.toml ] || write_sync_config "$url"
|
||||
}
|
||||
|
||||
write_readme() {
|
||||
cat > README.md <<'EOF'
|
||||
# KeiSeiKit memory store
|
||||
|
||||
Append-only store for KeiSeiKit session traces + nightly REM reports.
|
||||
Managed by kei-sleep-sync; do not hand-edit.
|
||||
|
||||
- traces/ — session JSONL pushed after each Claude Code session
|
||||
- reports/ — nightly reports written by a cloud agent on /schedule
|
||||
- backlog.md — recurring patterns flagged for your review
|
||||
EOF
|
||||
}
|
||||
|
||||
write_backlog() {
|
||||
cat > backlog.md <<'EOF'
|
||||
# REM backlog — recurring patterns
|
||||
|
||||
Nightly consolidation prepends dated blocks when >=3 patterns recur.
|
||||
Pop entries manually after review.
|
||||
|
||||
<!-- populated by the cloud agent -->
|
||||
EOF
|
||||
}
|
||||
|
||||
write_sync_config() {
|
||||
cat > .keisei-sync.toml <<EOF
|
||||
# KeiSeiKit sleep-sync config (per-repo)
|
||||
repo_url = "$1"
|
||||
push_on_session_end = true
|
||||
branch = "main"
|
||||
commit_prefix = "memory"
|
||||
EOF
|
||||
}
|
||||
|
||||
write_env_refs() {
|
||||
local url="$1"
|
||||
mkdir -p "$(dirname "$SECRETS_FILE")"
|
||||
chmod 700 "$(dirname "$SECRETS_FILE")" 2>/dev/null || true
|
||||
touch "$SECRETS_FILE"
|
||||
chmod 600 "$SECRETS_FILE"
|
||||
# Remove any prior KEI_MEMORY_* lines (idempotent update).
|
||||
local tmp
|
||||
tmp="$(mktemp)"
|
||||
grep -vE '^(KEI_MEMORY_REPO_URL|KEI_MEMORY_REPO_PATH|KEI_MEMORY_SSH_KEY)=' \
|
||||
"$SECRETS_FILE" > "$tmp" 2>/dev/null || true
|
||||
cat >> "$tmp" <<EOF
|
||||
KEI_MEMORY_REPO_URL=$url
|
||||
KEI_MEMORY_REPO_PATH=$REPO_PATH
|
||||
KEI_MEMORY_SSH_KEY=$SSH_KEY
|
||||
EOF
|
||||
mv "$tmp" "$SECRETS_FILE"
|
||||
chmod 600 "$SECRETS_FILE"
|
||||
say "wrote env refs to $SECRETS_FILE"
|
||||
}
|
||||
|
||||
test_ssh_auth() {
|
||||
local url="$1"
|
||||
local host
|
||||
host="$(url_host "$url")"
|
||||
say "testing SSH auth to $host"
|
||||
# ssh -T on git hosts returns non-zero even on success; grep the banner.
|
||||
local out
|
||||
out="$(ssh -i "$SSH_KEY" -o StrictHostKeyChecking=accept-new \
|
||||
-o BatchMode=yes -T "git@$host" 2>&1 || true)"
|
||||
if printf '%s' "$out" | grep -Eiq '(successfully authenticated|welcome|you.?ve|does not provide shell access)'; then
|
||||
say "SSH auth OK ($host)"
|
||||
return 0
|
||||
fi
|
||||
warn "SSH auth to $host did not return a known success banner"
|
||||
warn "server said: $(printf '%s' "$out" | head -n1)"
|
||||
warn "if the deploy key was just added it may need 30-60s to propagate"
|
||||
return 1
|
||||
}
|
||||
|
||||
main() {
|
||||
say "KeiSeiKit v0.11 sleep-sync setup"
|
||||
local url
|
||||
url="$(prompt_repo_url)"
|
||||
ensure_ssh_key
|
||||
show_deploy_key_instructions "$url"
|
||||
if [ -t 0 ]; then
|
||||
printf 'Deploy key added to the repo? Press ENTER to continue, Ctrl-C to abort.\n'
|
||||
read -r _ || true
|
||||
fi
|
||||
init_sync_repo "$url"
|
||||
scaffold_repo_structure "$url"
|
||||
write_env_refs "$url"
|
||||
test_ssh_auth "$url" || warn "continuing despite auth test warning"
|
||||
echo
|
||||
say "setup complete"
|
||||
say "next: run /sleep-setup in Claude Code to register a nightly /schedule trigger"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
77
_primitives/kei-sleep-sync.sh
Executable file
77
_primitives/kei-sleep-sync.sh
Executable file
|
|
@ -0,0 +1,77 @@
|
|||
#!/bin/sh
|
||||
# kei-sleep-sync.sh — POSIX-sh helper called at session end.
|
||||
#
|
||||
# Stages any new session traces + backlog in the user's memory-repo and
|
||||
# pushes via a dedicated deploy key. NEVER blocks the session: every
|
||||
# failure path logs to ~/.claude/memory/sync-errors.log and exits 0.
|
||||
#
|
||||
# Config resolution order:
|
||||
# 1. env var KEI_MEMORY_REPO_PATH / KEI_MEMORY_SSH_KEY
|
||||
# 2. ~/.claude/secrets/.env (sourced if present)
|
||||
# 3. sync-repo's .keisei-sync.toml (informational only)
|
||||
#
|
||||
# Emergency bypass: `KEI_SLEEP_SYNC_BYPASS=1 ...` — silent exit 0.
|
||||
|
||||
set -u
|
||||
|
||||
ERR_LOG="${HOME}/.claude/memory/sync-errors.log"
|
||||
|
||||
log_err() {
|
||||
mkdir -p "$(dirname "$ERR_LOG")" 2>/dev/null || return 0
|
||||
printf '[%s] %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$*" >> "$ERR_LOG" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# ---- bypass + env -----------------------------------------------------------
|
||||
|
||||
[ "${KEI_SLEEP_SYNC_BYPASS:-0}" = "1" ] && exit 0
|
||||
|
||||
SECRETS_FILE="${HOME}/.claude/secrets/.env"
|
||||
if [ -f "$SECRETS_FILE" ] && [ -z "${KEI_MEMORY_REPO_PATH:-}" ]; then
|
||||
# shellcheck disable=SC1090
|
||||
. "$SECRETS_FILE" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
REPO_PATH="${KEI_MEMORY_REPO_PATH:-}"
|
||||
SSH_KEY="${KEI_MEMORY_SSH_KEY:-}"
|
||||
|
||||
# Silent no-op when sync isn't configured yet (most users).
|
||||
[ -z "$REPO_PATH" ] && exit 0
|
||||
[ -d "${REPO_PATH}/.git" ] || exit 0
|
||||
|
||||
# ---- stage, commit, push ---------------------------------------------------
|
||||
|
||||
# cd may fail (permissions / path vanished) — silent exit.
|
||||
cd "$REPO_PATH" 2>/dev/null || exit 0
|
||||
|
||||
# Mirror traces from the canonical local dump dir into the repo.
|
||||
TRACES_SRC="${HOME}/.claude/memory/traces"
|
||||
if [ -d "$TRACES_SRC" ]; then
|
||||
mkdir -p traces 2>/dev/null || true
|
||||
# -n = never overwrite; append-only semantics.
|
||||
cp -n "$TRACES_SRC"/*.jsonl traces/ 2>/dev/null || true
|
||||
fi
|
||||
|
||||
git add traces/ backlog.md 2>/dev/null || { log_err "git add failed"; exit 0; }
|
||||
|
||||
# Nothing staged — silent exit.
|
||||
if git diff --cached --quiet 2>/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
COMMIT_MSG="memory: session traces $(date +%Y-%m-%dT%H:%M:%S%z)"
|
||||
if ! git commit -q -m "$COMMIT_MSG" 2>/dev/null; then
|
||||
log_err "git commit failed"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Push via the dedicated deploy key so we don't clobber the user's default SSH.
|
||||
if [ -n "$SSH_KEY" ] && [ -f "$SSH_KEY" ]; then
|
||||
GIT_SSH_COMMAND="ssh -i $SSH_KEY -o StrictHostKeyChecking=accept-new" \
|
||||
git push -q origin HEAD 2>/dev/null \
|
||||
|| { log_err "git push failed via $SSH_KEY"; exit 0; }
|
||||
else
|
||||
git push -q origin HEAD 2>/dev/null \
|
||||
|| { log_err "git push failed (no SSH_KEY set)"; exit 0; }
|
||||
fi
|
||||
|
||||
exit 0
|
||||
94
_primitives/templates/sleep-trigger-prompt.md
Normal file
94
_primitives/templates/sleep-trigger-prompt.md
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
# Nightly REM consolidation (KeiSeiKit v0.11 sleep-sync)
|
||||
|
||||
<!--
|
||||
Template prompt. Render placeholders before pasting into Claude Code
|
||||
`/schedule create`. The sleep-setup skill does this for you; this file
|
||||
exists so power-users can customise the prompt before scheduling.
|
||||
|
||||
Placeholders:
|
||||
{REPO_URL} — your memory-repo SSH URL (git@host:org/repo.git)
|
||||
{UTC_CRON} — cron expression in UTC (sleep-setup converts local 03:00)
|
||||
-->
|
||||
|
||||
Clone: {REPO_URL}
|
||||
Branch: main
|
||||
Time: 03:00 local (UTC cron: {UTC_CRON})
|
||||
|
||||
## Task
|
||||
|
||||
1. Clone the memory repo shallow.
|
||||
2. Identify NEW traces in `traces/` since the last consolidation by
|
||||
comparing filenames against `reports/last-run.txt` (if the file is
|
||||
missing, treat ALL traces as new on the first run).
|
||||
3. For each new trace (JSONL, one event per line), extract:
|
||||
- user prompts (role = "user", type = "message")
|
||||
- tool calls (type = "tool_use", name + input summary)
|
||||
- tool errors (is_error = true)
|
||||
- session duration (first vs last timestamp)
|
||||
4. Group events into topics via simple keyword matching on user prompts
|
||||
(no ML, no embeddings — keyword co-occurrence ≥ 2 is enough).
|
||||
5. Count recurring patterns: any tool-call sequence OR error class that
|
||||
appears in ≥ 2 distinct sessions is a "cross-session pattern".
|
||||
6. Write `reports/sleep-YYYY-MM-DD.md` with this structure:
|
||||
|
||||
```
|
||||
# REM report — YYYY-MM-DD
|
||||
|
||||
Sessions analyzed: <count>
|
||||
Total duration: <hh:mm>
|
||||
|
||||
## Top tool-call sequences (cross-session)
|
||||
1. <seq> ×<count>
|
||||
...
|
||||
|
||||
## Top error classes
|
||||
1. <class> ×<count>
|
||||
...
|
||||
|
||||
## Suggested rule/hook candidates (dry-run only)
|
||||
- [ ] <name> — why (<E-grade>)
|
||||
...
|
||||
```
|
||||
|
||||
7. If there are ≥ 3 cross-session patterns, prepend a timestamped block
|
||||
to `backlog.md`:
|
||||
|
||||
```
|
||||
## YYYY-MM-DD — REM consolidation
|
||||
- <pattern 1>
|
||||
- <pattern 2>
|
||||
- <pattern 3>
|
||||
```
|
||||
|
||||
8. Write a single line to `reports/last-run.txt` with this run's
|
||||
ISO-8601 UTC timestamp (overwrite, no append).
|
||||
9. Stage, commit, push:
|
||||
|
||||
```
|
||||
git add reports/ backlog.md
|
||||
git commit -m "REM: consolidation $(date -I)"
|
||||
git push
|
||||
```
|
||||
|
||||
## Invariants
|
||||
|
||||
- Traces are append-only. Never delete or modify `traces/*.jsonl`.
|
||||
- If nothing recurred this cycle, the report MUST still be written —
|
||||
with body "no patterns this cycle" — so you can tell "ran and found
|
||||
nothing" apart from "did not run".
|
||||
- Never fabricate findings. If the analyzer outputs an empty list,
|
||||
emit an empty report.
|
||||
- Never paraphrase patent-sensitive content from the traces into the
|
||||
report body. Install a project-local pre-commit gate on the
|
||||
memory-repo if you want hard enforcement of that boundary.
|
||||
- Success signal = commit pushed cleanly. Anything else is a failure
|
||||
that surfaces to the user on the next `git pull`.
|
||||
|
||||
## Failure handling
|
||||
|
||||
- Clone fails → post an issue to the repo if possible; otherwise exit 1.
|
||||
- Commit hook blocks → do NOT force-push. Write the failure reason to
|
||||
`reports/sleep-YYYY-MM-DD.md` body and attempt a commit excluding the
|
||||
offending file.
|
||||
- Push fails → retry once with exponential backoff; on second failure,
|
||||
leave local commit in place and exit 1 (next run will push).
|
||||
|
|
@ -41,4 +41,12 @@ if command -v kei-memory >/dev/null 2>&1 && [ -f "$dest" ]; then
|
|||
>/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
# v0.11 sleep-sync (RULE 0.15) — push traces to the user's memory-repo so a
|
||||
# cloud agent can consolidate them overnight. Silent no-op when the primitive
|
||||
# is absent or the user hasn't opted in via /sleep-setup.
|
||||
sleep_sync="${HOME}/.claude/agents/_primitives/kei-sleep-sync.sh"
|
||||
if [ -x "$sleep_sync" ]; then
|
||||
"$sleep_sync" >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
|
|
|||
39
install.sh
39
install.sh
|
|
@ -26,6 +26,7 @@ INSTALLED_FILE="$AGENTS_DIR/_primitives/.installed"
|
|||
# --- flag parsing ----------------------------------------------------------
|
||||
ACTIVATE_HOOKS=0
|
||||
WITH_BRIDGES=0
|
||||
WITH_SLEEP_SYNC=0
|
||||
PROFILE=""
|
||||
ADD_LIST=""
|
||||
REMOVE_NAME=""
|
||||
|
|
@ -37,6 +38,7 @@ for arg in "$@"; do
|
|||
case "$arg" in
|
||||
--activate-hooks) ACTIVATE_HOOKS=1 ;;
|
||||
--with-bridges) WITH_BRIDGES=1 ;;
|
||||
--with-sleep-sync) WITH_SLEEP_SYNC=1 ;;
|
||||
--profile=*) PROFILE="${arg#--profile=}" ;;
|
||||
--add=*) ADD_LIST="${arg#--add=}" ;;
|
||||
--remove=*) REMOVE_NAME="${arg#--remove=}" ;;
|
||||
|
|
@ -71,6 +73,11 @@ Usage: ./install.sh [flags]
|
|||
Aider / Replit / Antigravity / Warp / Zed).
|
||||
Skipped if invoked inside the KeiSeiKit repo itself.
|
||||
|
||||
--with-sleep-sync after core install, run the v0.11 sleep-layer
|
||||
setup helper (kei-sleep-setup.sh). TTY-only — no-op
|
||||
on CI / non-interactive invocations. Print a
|
||||
reminder to finish via /sleep-setup either way.
|
||||
|
||||
--activate-hooks jq-merge settings-snippet.json into ~/.claude/settings.json
|
||||
non-interactively. Without this flag, a TTY prompt asks
|
||||
at the end; non-TTY runs print manual instructions.
|
||||
|
|
@ -289,7 +296,6 @@ primitive_time_secs() {
|
|||
case "$name" in
|
||||
mock-render|kei-migrate|kei-ledger) echo 20 ;;
|
||||
kei-changelog|firewall-diff) echo 15 ;;
|
||||
genesis-scan) echo 10 ;;
|
||||
visual-diff|tokens-sync|ssh-check) echo 5 ;;
|
||||
*) echo 10 ;;
|
||||
esac
|
||||
|
|
@ -307,7 +313,6 @@ primitive_disk_kb() {
|
|||
case "$name" in
|
||||
mock-render|kei-migrate|kei-ledger) echo 30000 ;;
|
||||
kei-changelog|firewall-diff) echo 10000 ;;
|
||||
genesis-scan) echo 6000 ;;
|
||||
visual-diff|tokens-sync|ssh-check) echo 5000 ;;
|
||||
*) echo 8000 ;;
|
||||
esac
|
||||
|
|
@ -1000,6 +1005,21 @@ 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
|
||||
src="$KIT_DIR/_primitives/$sleep_sh"
|
||||
if [ -f "$src" ]; then
|
||||
cp -f "$src" "$AGENTS_DIR/_primitives/$sleep_sh"
|
||||
chmod +x "$AGENTS_DIR/_primitives/$sleep_sh"
|
||||
fi
|
||||
done
|
||||
if [ -d "$KIT_DIR/_primitives/templates" ]; then
|
||||
mkdir -p "$AGENTS_DIR/_primitives/templates"
|
||||
cp -f "$KIT_DIR/_primitives/templates/"*.md "$AGENTS_DIR/_primitives/templates/" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
say "resolving primitives for profile=$PROFILE"
|
||||
# Clean slate: drop every shell .sh + rust crate dir from the installed set
|
||||
# FAST (no per-rust rebuild). A single regenerate_rust_workspace at the end
|
||||
|
|
@ -1148,6 +1168,21 @@ if [[ "$WITH_BRIDGES" == "1" ]]; then
|
|||
fi
|
||||
fi
|
||||
|
||||
# --- optional: run sleep-sync setup helper (v0.11) -----------------------
|
||||
# The helper has its own TTY prompts + validation. We only kick it off when
|
||||
# stdin+stdout are TTY; otherwise print the reminder so the user can finish
|
||||
# later via /sleep-setup inside a Claude Code session.
|
||||
if [[ "$WITH_SLEEP_SYNC" == "1" ]]; then
|
||||
SLEEP_HELPER="$AGENTS_DIR/_primitives/kei-sleep-setup.sh"
|
||||
if [[ -x "$SLEEP_HELPER" ]] && [ -t 0 ] && [ -t 1 ]; then
|
||||
say "running sleep-sync setup helper"
|
||||
"$SLEEP_HELPER" || warn "sleep-sync setup did not complete — re-run via /sleep-setup"
|
||||
else
|
||||
say "sleep-sync setup deferred (non-TTY or helper missing)"
|
||||
say " run /sleep-setup inside Claude Code to finish configuration"
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- done ----------------------------------------------------------------
|
||||
echo
|
||||
say "install complete (profile=$PROFILE)"
|
||||
|
|
|
|||
102
skills/sleep-setup/SKILL.md
Normal file
102
skills/sleep-setup/SKILL.md
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
---
|
||||
name: sleep-setup
|
||||
description: One-time wizard (RULE 0.15) that configures KeiSeiKit v0.11 cloud REM sync. Generates an SSH deploy key, initializes the user's memory-repo, writes env refs (RULE 0.8), and emits a ready-to-paste `/schedule create` command for nightly consolidation. Pure-click except the 1 free-text field for repo URL.
|
||||
argument-hint: (no arguments)
|
||||
---
|
||||
|
||||
# Sleep Setup — Cloud REM Sync Wizard (index)
|
||||
|
||||
You are running the one-time configuration wizard for the KeiSeiKit v0.11
|
||||
sleep layer. Each session-end dump pushes to a private git repo; a cloud
|
||||
Claude Code agent on `/schedule` clones the repo nightly, analyzes traces,
|
||||
and commits a consolidation report back. In the morning the user runs
|
||||
`git pull` and reads the report. Nothing in this pipeline blocks session
|
||||
close, and report content is for the user to READ — never auto-injected.
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
## Pipeline overview (5 phases, 5+ AskUserQuestion)
|
||||
|
||||
| Phase | File | Purpose | AskUserQuestion |
|
||||
|---|---|---|---|
|
||||
| 1 | [phase-1-repo-pick.md](phase-1-repo-pick.md) | Pick repo provider + visibility | 2 (click-only) |
|
||||
| 2 | [phase-2-repo-url.md](phase-2-repo-url.md) | Collect SSH URL (1 free-text field) | 1 (AskUserQuestion `freeText`) |
|
||||
| 3 | [phase-3-deploy-key.md](phase-3-deploy-key.md) | Run `kei-sleep-setup.sh`, show pubkey, confirm deploy-key added | 1 (click) |
|
||||
| 4 | [phase-4-test-push.md](phase-4-test-push.md) | Dry-run a test commit via `kei-sleep-sync.sh` | 1 (click) |
|
||||
| 5 | [phase-5-trigger.md](phase-5-trigger.md) | Render `/schedule create` command, offer to run now | 1 (click) |
|
||||
|
||||
**Minimum AskUserQuestion count: 6.** All clicks except the single repo-URL
|
||||
free-text in Phase 2.
|
||||
|
||||
---
|
||||
|
||||
## Variables the pipeline produces
|
||||
|
||||
| Name | Set in | Meaning |
|
||||
|---|---|---|
|
||||
| `PROVIDER` | Phase 1 | `github` / `gitlab` / `bitbucket` / `self-hosted` |
|
||||
| `VISIBILITY` | Phase 1 | `private` (recommended) / `public` (explicit user choice) |
|
||||
| `REPO_URL` | Phase 2 | Validated SSH URL (`git@host:org/repo.git`) |
|
||||
| `KEY_ADDED` | Phase 3 | boolean; was deploy key confirmed added? |
|
||||
| `TEST_VERIFIED` | Phase 4 | boolean; did the user see the test commit in the remote? |
|
||||
| `SCHEDULE_ACTION` | Phase 5 | `run-now` / `copy-later` / `skip` |
|
||||
|
||||
---
|
||||
|
||||
## Final report (emit after Phase 5)
|
||||
|
||||
```
|
||||
=== SLEEP-SETUP REPORT ===
|
||||
Provider: <PROVIDER> (visibility: <VISIBILITY>)
|
||||
Repo URL: <REPO_URL>
|
||||
Deploy key: ~/.ssh/keisei-memory-sync(.pub)
|
||||
Sync repo path: ~/.claude/memory/sync-repo/
|
||||
Env refs: ~/.claude/secrets/.env (KEI_MEMORY_REPO_URL, _PATH, _SSH_KEY)
|
||||
Test push: <PASS/FAIL> (Phase 4)
|
||||
Schedule: <SCHEDULE_ACTION>
|
||||
```
|
||||
|
||||
If `SCHEDULE_ACTION == skip`, add:
|
||||
```
|
||||
Local-only mode. Traces will be pushed to the repo on every session end.
|
||||
To enable nightly consolidation later: paste the prompt from Phase 5 into
|
||||
`/schedule create` any time.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rules (apply throughout — enforced at every phase)
|
||||
|
||||
- **Pure-click contract.** Only Phase 2 asks for free text; every
|
||||
decision is an `AskUserQuestion`. No `freeText` outside Phase 2.
|
||||
- **Idempotent.** Re-running the wizard must NOT clobber existing
|
||||
`~/.ssh/keisei-memory-sync` or `~/.claude/memory/sync-repo/`; the
|
||||
helper script handles re-use.
|
||||
- **NO DOWNGRADE (RULE -1).** If SSH auth fails, return 2-3 constructive
|
||||
paths (re-check deploy key, check `sshd` host, fall back to HTTPS with
|
||||
PAT — with warning) — never "cannot set up".
|
||||
- **NO HALLUCINATION (RULE 0.4).** Never fabricate repo URLs, key
|
||||
fingerprints, or commit hashes. Show the real output of the script.
|
||||
- **RULE 0.8 secrets.** The wizard writes env-var REFERENCES to
|
||||
`~/.claude/secrets/.env`, never inline tokens in any generated file.
|
||||
- **RULE 0.1 private remotes.** Recommend private visibility in Phase 1.
|
||||
If the user explicitly picks `public`, warn once: "a public memory
|
||||
repo leaks your session prompts and tool usage — confirm?".
|
||||
- **Silent failure (RULE 0.15).** Nothing in the session-end path may
|
||||
block the session from closing. The wizard itself may fail loudly.
|
||||
- **Constructor Pattern (RULE ZERO).** Every phase file < 100 LOC
|
||||
(well under the 200-LOC file limit).
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- `~/.claude/rules/sleep-layer.md` — RULE 0.15 full text
|
||||
- `~/.claude/rules/secrets-single-source.md` — RULE 0.8 enforcement
|
||||
- `_primitives/kei-sleep-setup.sh` — the imperative setup helper
|
||||
- `_primitives/kei-sleep-sync.sh` — the session-end-dump callback
|
||||
- `_primitives/templates/sleep-trigger-prompt.md` — cloud agent prompt
|
||||
- `hooks/session-end-dump.sh` — where `kei-sleep-sync.sh` is invoked
|
||||
71
skills/sleep-setup/phase-1-repo-pick.md
Normal file
71
skills/sleep-setup/phase-1-repo-pick.md
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# Phase 1 — Repo provider + visibility
|
||||
|
||||
Ask the user to pick where the memory-repo lives. Purely click-based —
|
||||
two `AskUserQuestion` batches, zero free text.
|
||||
|
||||
## 1a — Provider click
|
||||
|
||||
Emit ONE `AskUserQuestion`:
|
||||
|
||||
```json
|
||||
{
|
||||
"questions": [
|
||||
{
|
||||
"question": "Where does your memory-repo live?",
|
||||
"header": "Provider",
|
||||
"multiSelect": false,
|
||||
"options": [
|
||||
{"label": "GitHub", "description": "github.com — easiest; private repo recommended"},
|
||||
{"label": "GitLab", "description": "gitlab.com or self-managed GitLab"},
|
||||
{"label": "Bitbucket", "description": "bitbucket.org (Atlassian)"},
|
||||
{"label": "Self-hosted", "description": "Forgejo / Gitea / custom; requires SSH access"}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Store the pick as `PROVIDER`.
|
||||
|
||||
## 1b — Visibility click
|
||||
|
||||
Emit ONE `AskUserQuestion`:
|
||||
|
||||
```json
|
||||
{
|
||||
"questions": [
|
||||
{
|
||||
"question": "Repo visibility — private is strongly recommended. Your traces contain prompts and tool calls.",
|
||||
"header": "Visibility",
|
||||
"multiSelect": false,
|
||||
"options": [
|
||||
{"label": "Private (recommended)", "description": "Only you + the deploy key can read"},
|
||||
{"label": "Public (I accept the risk)", "description": "Traces visible to anyone — confirm below"}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Store the pick as `VISIBILITY`.
|
||||
|
||||
## 1c — Public-visibility warning
|
||||
|
||||
If `VISIBILITY == "Public (I accept the risk)"`, print the warning block
|
||||
below to stdout BEFORE proceeding to Phase 2:
|
||||
|
||||
```
|
||||
WARNING: a public memory repo leaks your session prompts, tool usage, and
|
||||
file paths to anyone who finds the repo. This is rarely what you want.
|
||||
If you proceed, the rest of the wizard will continue unchanged — there is
|
||||
no second confirmation.
|
||||
```
|
||||
|
||||
Do NOT emit a third AskUserQuestion for re-confirm — the user already
|
||||
picked "I accept the risk".
|
||||
|
||||
## Verify-criterion
|
||||
|
||||
- `PROVIDER ∈ {GitHub, GitLab, Bitbucket, Self-hosted}`.
|
||||
- `VISIBILITY ∈ {Private, Public}`.
|
||||
- Exactly TWO `AskUserQuestion` calls were emitted in this phase.
|
||||
62
skills/sleep-setup/phase-2-repo-url.md
Normal file
62
skills/sleep-setup/phase-2-repo-url.md
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# Phase 2 — Collect SSH repo URL
|
||||
|
||||
The one and only free-text field in the wizard. Everything else is a
|
||||
click.
|
||||
|
||||
## 2a — Free-text prompt
|
||||
|
||||
Emit ONE `AskUserQuestion` with a `freeText` field:
|
||||
|
||||
```json
|
||||
{
|
||||
"questions": [
|
||||
{
|
||||
"question": "Paste the SSH URL of the memory repo you created.",
|
||||
"header": "Repo URL",
|
||||
"multiSelect": false,
|
||||
"freeText": true,
|
||||
"placeholder": "git@github.com:you/kei-memory.git"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 2b — Validate
|
||||
|
||||
Regex: `^git@[A-Za-z0-9._-]+:[A-Za-z0-9._/-]+\.git$`
|
||||
|
||||
If the user's input does NOT match, print:
|
||||
|
||||
```
|
||||
Invalid SSH URL. Expected shape: git@<host>:<org>/<repo>.git
|
||||
Examples:
|
||||
git@github.com:alice/kei-memory.git
|
||||
git@gitlab.com:alice/devops/kei-memory.git
|
||||
git@forgejo.keisei.app:alice/kei-memory.git
|
||||
```
|
||||
|
||||
Re-emit the same `AskUserQuestion`. Up to 3 attempts; on the 3rd failure
|
||||
abort the wizard with a short "try again later with `/sleep-setup`"
|
||||
message. Do not loop silently.
|
||||
|
||||
## 2c — Cross-check against Phase 1
|
||||
|
||||
Extract the host from the URL:
|
||||
|
||||
```
|
||||
host = url.match(/^git@([^:]+):/)[1]
|
||||
```
|
||||
|
||||
If `PROVIDER == "GitHub"` and `host != "github.com"`, print a soft
|
||||
warning: "host <host> doesn't look like github.com — continuing anyway".
|
||||
Same for GitLab → `gitlab.com`, Bitbucket → `bitbucket.org`. For
|
||||
`Self-hosted`, skip this check.
|
||||
|
||||
Store the URL as `REPO_URL`.
|
||||
|
||||
## Verify-criterion
|
||||
|
||||
- `REPO_URL` matches the validation regex.
|
||||
- Exactly ONE `AskUserQuestion` (or up to 3 if the user mistyped).
|
||||
- No secret-like token accidentally pasted into the URL
|
||||
(regex rejects `@` outside the leading `git@`).
|
||||
70
skills/sleep-setup/phase-3-deploy-key.md
Normal file
70
skills/sleep-setup/phase-3-deploy-key.md
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# Phase 3 — Run setup script, hand off deploy key
|
||||
|
||||
Run the imperative helper and hand the public-key material to the user.
|
||||
|
||||
## 3a — Invoke `kei-sleep-setup.sh`
|
||||
|
||||
Run the primitive non-interactively with `REPO_URL` pre-supplied:
|
||||
|
||||
```bash
|
||||
KEI_MEMORY_REPO_URL="<REPO_URL>" \
|
||||
~/.claude/agents/_primitives/kei-sleep-setup.sh
|
||||
```
|
||||
|
||||
Capture stdout + stderr. The script:
|
||||
1. Generates `~/.ssh/keisei-memory-sync` if missing.
|
||||
2. Prints the `.pub` contents and fingerprint.
|
||||
3. Scaffolds `~/.claude/memory/sync-repo/` and writes config + env refs.
|
||||
4. Tests SSH auth against the host (advisory).
|
||||
|
||||
If the script exits non-zero, surface its stderr directly to chat and
|
||||
abort the wizard. Do NOT retry silently.
|
||||
|
||||
## 3b — Render deploy-key block to chat
|
||||
|
||||
The script already printed the key + fingerprint to its stdout. Echo
|
||||
that block back to the user verbatim, prefaced with:
|
||||
|
||||
```
|
||||
Add this key as a DEPLOY KEY with WRITE access to <REPO_URL>.
|
||||
GitHub: Settings → Deploy keys → Add deploy key ("Allow write access")
|
||||
GitLab: Settings → Repository → Deploy keys → Enable with write access
|
||||
Bitbucket: Repository settings → Access keys → Add key (write)
|
||||
Self-host: check your provider's "deploy key" or "access key" feature
|
||||
```
|
||||
|
||||
NEVER show the private key. The `.pub` file is safe to display.
|
||||
|
||||
## 3c — Confirm click
|
||||
|
||||
Emit ONE `AskUserQuestion`:
|
||||
|
||||
```json
|
||||
{
|
||||
"questions": [
|
||||
{
|
||||
"question": "Have you added the deploy key to the repo with WRITE access?",
|
||||
"header": "Deploy key",
|
||||
"multiSelect": false,
|
||||
"options": [
|
||||
{"label": "Yes, it's added", "description": "Proceed to a test push"},
|
||||
{"label": "Show me the key again", "description": "Re-print the public key + fingerprint"},
|
||||
{"label": "Abort", "description": "Cancel — re-run /sleep-setup later"}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Handle each option:
|
||||
- `Yes` → set `KEY_ADDED = true`, proceed to Phase 4.
|
||||
- `Show again` → re-print the block from 3b, re-emit this click.
|
||||
- `Abort` → print "aborted — re-run /sleep-setup later"; exit.
|
||||
|
||||
## Verify-criterion
|
||||
|
||||
- `~/.ssh/keisei-memory-sync(.pub)` exist.
|
||||
- `~/.claude/memory/sync-repo/.git/` exists.
|
||||
- `~/.claude/secrets/.env` contains all three `KEI_MEMORY_*` refs.
|
||||
- `KEY_ADDED == true`.
|
||||
- Exactly ONE `AskUserQuestion` (plus loops on "Show me again").
|
||||
89
skills/sleep-setup/phase-4-test-push.md
Normal file
89
skills/sleep-setup/phase-4-test-push.md
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# Phase 4 — Test push (verify write access)
|
||||
|
||||
Write a tiny marker file, call `kei-sleep-sync.sh`, let the user confirm
|
||||
the commit landed in the remote.
|
||||
|
||||
## 4a — Write a test marker
|
||||
|
||||
```bash
|
||||
touch ~/.claude/memory/sync-repo/traces/.sleep-setup-test
|
||||
```
|
||||
|
||||
The marker file is tracked the same way real traces are (so it tests the
|
||||
real `git add traces/` path used at session end).
|
||||
|
||||
## 4b — Invoke the sync helper
|
||||
|
||||
```bash
|
||||
~/.claude/agents/_primitives/kei-sleep-sync.sh
|
||||
```
|
||||
|
||||
Capture exit code. The helper is designed to be silent on success; capture
|
||||
`~/.claude/memory/sync-errors.log` as well — if it gained a new line in
|
||||
the last 60s, surface that line to chat.
|
||||
|
||||
## 4c — Show expected commit to user
|
||||
|
||||
Read `HEAD`'s commit message from the local mirror:
|
||||
|
||||
```bash
|
||||
( cd ~/.claude/memory/sync-repo && git log -1 --pretty=format:'%h %s' )
|
||||
```
|
||||
|
||||
Print this commit to chat as "expected to appear on your remote:".
|
||||
|
||||
## 4d — Confirm click
|
||||
|
||||
Emit ONE `AskUserQuestion`:
|
||||
|
||||
```json
|
||||
{
|
||||
"questions": [
|
||||
{
|
||||
"question": "Do you see this commit on the remote (refresh the repo page)?",
|
||||
"header": "Test push",
|
||||
"multiSelect": false,
|
||||
"options": [
|
||||
{"label": "Yes, commit is there", "description": "Proceed to schedule"},
|
||||
{"label": "No, not showing up", "description": "Show diagnostics + 2-3 fix paths"},
|
||||
{"label": "Skip — I'll check later", "description": "Mark as UNVERIFIED, continue"}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Handle each option:
|
||||
- `Yes` → set `TEST_VERIFIED = true`, clean up marker, proceed to Phase 5.
|
||||
- `No` → print the diagnostic block below; re-emit the click.
|
||||
- `Skip` → set `TEST_VERIFIED = false`, proceed to Phase 5.
|
||||
|
||||
## 4e — Diagnostic block (when user says "not showing up")
|
||||
|
||||
Render constructively per RULE -1:
|
||||
|
||||
```
|
||||
Three things to check:
|
||||
1. Deploy key write-access — GitHub/GitLab/Bitbucket default to READ,
|
||||
you must tick the write box explicitly.
|
||||
2. Default branch — your repo must have a 'main' branch; if it has
|
||||
'master' or nothing at all the push target is missing.
|
||||
3. SSH reachability — run:
|
||||
ssh -i ~/.ssh/keisei-memory-sync -T git@<host>
|
||||
and confirm the auth banner shows your repo account.
|
||||
If all three look correct, check ~/.claude/memory/sync-errors.log.
|
||||
```
|
||||
|
||||
## 4f — Cleanup marker
|
||||
|
||||
Regardless of branch:
|
||||
|
||||
```bash
|
||||
rm -f ~/.claude/memory/sync-repo/traces/.sleep-setup-test
|
||||
```
|
||||
|
||||
## Verify-criterion
|
||||
|
||||
- Exactly ONE `AskUserQuestion` (plus loops on the "No" branch).
|
||||
- `TEST_VERIFIED` is either `true` or `false` (both acceptable; only
|
||||
"Abort" terminates the wizard, and that option doesn't exist here).
|
||||
95
skills/sleep-setup/phase-5-trigger.md
Normal file
95
skills/sleep-setup/phase-5-trigger.md
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# Phase 5 — Emit `/schedule create` command
|
||||
|
||||
Render the ready-to-paste nightly trigger and ask whether to run it now,
|
||||
copy and do later, or skip to local-only mode.
|
||||
|
||||
## 5a — Load template
|
||||
|
||||
Read `_primitives/templates/sleep-trigger-prompt.md` from the kit install
|
||||
path:
|
||||
|
||||
```
|
||||
~/.claude/agents/_primitives/templates/sleep-trigger-prompt.md
|
||||
```
|
||||
|
||||
If the file is missing (older kit version), fall back to the inline
|
||||
template in this phase file (see 5e).
|
||||
|
||||
## 5b — Compute UTC cron
|
||||
|
||||
Local target: `03:00` user-local time, every day.
|
||||
|
||||
```bash
|
||||
# macOS / GNU date — detect local TZ offset in minutes
|
||||
offset_min=$(date +%z | awk '{ s=substr($0,1,1); h=substr($0,2,2); m=substr($0,4,2); print (s=="-" ? 1 : -1) * (h*60+m) }')
|
||||
# local 03:00 = 180 minutes past midnight local
|
||||
local_minutes=180
|
||||
utc_minutes=$(( (local_minutes + offset_min + 1440) % 1440 ))
|
||||
utc_hour=$(( utc_minutes / 60 ))
|
||||
utc_min=$(( utc_minutes % 60 ))
|
||||
utc_cron=$(printf '%d %d * * *' "$utc_min" "$utc_hour")
|
||||
```
|
||||
|
||||
Keep arithmetic in the skill prompt if Claude Code executes shell;
|
||||
otherwise have Claude compute the offset directly.
|
||||
|
||||
## 5c — Render placeholders
|
||||
|
||||
Replace `{REPO_URL}` with `REPO_URL` and `{UTC_CRON}` with `utc_cron` in
|
||||
the template. Print the rendered prompt to chat inside a fenced code
|
||||
block so the user can one-click-copy.
|
||||
|
||||
## 5d — Click
|
||||
|
||||
Emit ONE `AskUserQuestion`:
|
||||
|
||||
```json
|
||||
{
|
||||
"questions": [
|
||||
{
|
||||
"question": "How should we register the nightly REM trigger?",
|
||||
"header": "Schedule",
|
||||
"multiSelect": false,
|
||||
"options": [
|
||||
{"label": "Run /schedule now", "description": "Invoke /schedule create with the rendered prompt"},
|
||||
{"label": "Copy, run later", "description": "Leave it to me — I'll paste into /schedule create myself"},
|
||||
{"label": "Skip (local-only)", "description": "Just push traces; no nightly consolidation"}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Handle:
|
||||
- `Run now` → set `SCHEDULE_ACTION = run-now`; invoke
|
||||
`/schedule create` with the rendered body.
|
||||
- `Copy later` → set `SCHEDULE_ACTION = copy-later`; print the body
|
||||
again and a one-line reminder.
|
||||
- `Skip` → set `SCHEDULE_ACTION = skip`; print the local-only
|
||||
footer from SKILL.md's "Final report".
|
||||
|
||||
## 5e — Fallback inline template (if kit missing the file)
|
||||
|
||||
If `~/.claude/agents/_primitives/templates/sleep-trigger-prompt.md` is
|
||||
absent, use this minimal inline prompt:
|
||||
|
||||
```
|
||||
Clone: <REPO_URL>
|
||||
At UTC <utc_cron>:
|
||||
1. Clone shallow, read traces/ since reports/last-run.txt
|
||||
2. Write reports/sleep-<date>.md with session + tool + error summary
|
||||
3. If >=3 cross-session patterns, prepend to backlog.md
|
||||
4. Commit + push to main
|
||||
Invariants: append-only traces; no fabricated findings; never
|
||||
paraphrase patent-sensitive content into report bodies.
|
||||
```
|
||||
|
||||
Note the fallback is strictly less capable — loudly log "template file
|
||||
missing from kit install; using fallback" so the user can re-install.
|
||||
|
||||
## Verify-criterion
|
||||
|
||||
- Exactly ONE `AskUserQuestion`.
|
||||
- Rendered prompt contains no placeholder (`{REPO_URL}` / `{UTC_CRON}`).
|
||||
- `SCHEDULE_ACTION` is one of `run-now` / `copy-later` / `skip`.
|
||||
- The final report block from SKILL.md is emitted with real values.
|
||||
Loading…
Reference in a new issue