feat(skills): /sleep-setup 5-phase wizard (click + 1 free-text URL)
This commit is contained in:
parent
7db2328b68
commit
8e9c05272f
6 changed files with 489 additions and 0 deletions
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