Install
$ agentstack add skill-timoncool-dream-skill-wake ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Wake — применение выбранного из dream
После того как dream сделал отчёт и пользователь отметил галочками — wake подхватывает выбор и применяет.
Принцип безопасности
wake НИКОГДА не изобретает что применять. Источники выбора (по приоритету):
- JSON файл
DREAM-CHOICES-.json(из HTML кнопкой Save, либо создан валидатором в auto mode — помечен"auto": true, см. dream SKILL.md «Auto mode») - Аргументы skill'а —
wake M1,M3,N2илиwake all
Если ни один не задан — спрашивает пользователя что выбрать, не делает ничего.
Workflow
Phase 1 — Lock + найти отчёт и выбор
Сначала lock против race (как в dream/SKILL.md Phase 0). Если две сессии одновременно запустят wake на одном отчёте — Edit'ы перезатрут друг друга, MEMORY.md превратится в кашу.
LOCK_DIR="$CWD_BASH/.wake-lock"
if mkdir "$LOCK_DIR" 2>/dev/null; then
echo $$ > "$LOCK_DIR/pid"
else
LOCK_AGE=$(( $(date +%s) - $(stat -c %Y "$LOCK_DIR" 2>/dev/null || stat -f %m "$LOCK_DIR") ))
if [ "$LOCK_AGE" -gt 3600 ]; then
rm -rf "$LOCK_DIR" && mkdir "$LOCK_DIR" && echo $$ > "$LOCK_DIR/pid"
else
echo "WAKE ALREADY RUNNING (lock age ${LOCK_AGE}s) — abort"
exit 0
fi
fi
# В финале Phase 5: rm -rf "$LOCK_DIR"
Сначала вычислить пути (как в dream/SKILL.md — _BASH для bash команд, _WIN для Python):
# Compute paths (Win11 Git Bash)
CWD_BASH=$(pwd) # /d/Projects/TEMP
CWD_WIN=$(pwd -W 2>/dev/null || pwd) # D:/Projects/TEMP (на не-Windows fallback)
SLUG=$(echo "$CWD_WIN" | sed 's|[:/]|-|g') # D--Projects-TEMP
MEMORY_DIR_BASH="$HOME/.claude/projects/$SLUG/memory"
MEMORY_DIR_WIN=$(cygpath -w "$MEMORY_DIR_BASH" 2>/dev/null | sed 's|\\|/|g' || echo "$MEMORY_DIR_BASH")
test -d "$MEMORY_DIR_BASH" && echo "OK $MEMORY_DIR_WIN" || { echo "MEMORY DIR NOT FOUND — wake cannot proceed without it"; }
# 1. Find latest dream report MD in cwd
LATEST_REPORT=$(ls "$CWD_BASH"/DREAM-REPORT-*.md 2>/dev/null | sort -r | head -1)
if [ -z "$LATEST_REPORT" ]; then
echo "NO REPORT FOUND — run dream skill first to generate DREAM-REPORT-.md"
# Don't exit — Claude reads this output and stops the workflow itself
else
echo "Report: $LATEST_REPORT"
fi
# Extract date from filename: DREAM-REPORT-2026-05-02.md → 2026-05-02
REPORT_DATE=$(basename "$LATEST_REPORT" | sed 's|DREAM-REPORT-||; s|\.md||')
# 2. Find choices JSON (priority: cwd → ~/Downloads/ → ~/Desktop/)
CHOICES=""
for path in "$CWD_BASH/DREAM-CHOICES-$REPORT_DATE.json" "$HOME/Downloads/DREAM-CHOICES-$REPORT_DATE.json" "$HOME/Desktop/DREAM-CHOICES-$REPORT_DATE.json"; do
if [ -f "$path" ]; then CHOICES="$path"; break; fi
done
# Fallback: latest CHOICES regardless of date
if [ -z "$CHOICES" ]; then
CHOICES=$(ls -t "$HOME/Downloads/DREAM-CHOICES-"*.json "$CWD_BASH/DREAM-CHOICES-"*.json 2>/dev/null | head -1)
fi
echo "Choices: ${CHOICES:-NOT FOUND}"
Date verify: если report_date в JSON ≠ дата из имени MD-файла → WARN, спроси пользователя:
> ⚠️ Дата в DREAM-CHOICES (2026-05-01) не совпадает с последним DREAM-REPORT (2026-05-02). Использовать всё равно или прервать? (apply/cancel)
Если нет ни args, ни JSON: > Не нашёл DREAM-CHOICES-*.json и нет ID в аргументах. Варианты: > 1. Открой HTML отчёт DREAM-REPORT-.html, отметь галочки, нажми 💾 Save choices > 2. Или дай ID в чате: wake M1,M3,N2 или wake all
Phase 2 — Read report + parse JSON blocks
Read DREAM-REPORT-.md целиком. JSON contract proposals — см. D:/Projects/TEMP/.claude/skills/dream/references/action_types.md.
Парсинг (надёжный contract): ищи fenced code blocks с языком json. Каждый — отдельный proposal.
Используй Python для парсинга (надёжнее awk с backticks через shells):
import re, json, sys
content = open(report_path, encoding='utf-8').read()
# Pattern: triple-backtick + json + newline + content + newline + triple-backtick
pattern = r'```json\n(.*?)\n```'
blocks = re.findall(pattern, content, re.DOTALL)
proposals = []
malformed_indices = []
for i, block in enumerate(blocks):
try:
proposals.append(json.loads(block))
except json.JSONDecodeError as e:
print(f"WARN: malformed JSON block #{i}: {e}", file=sys.stderr)
malformed_indices.append(i)
# Add to failed[] later — record block index for the apply log
Получишь массив объектов с обязательными полями:
id(string, например "M1")category("memory" | "notes" | "index" | "other")action(один из: update, merge, delete, softdelete, createnew, extract, removelinks, shortenlines, addlinks, promoteskill, retireskill, purgetrash)- Action-specific поля (см. dream/SKILL.md секцию "Action types")
Построй map {id: proposal}.
Read selected:
- Если есть JSON файл →
selected = json.selected(массив ID) - Если args =
all→selected = все ID из map - Если args =
M1,M3,N2→ split по запятой (trim spaces)
Verify: каждый ID в selected есть в map. Если нет — warn, пропусти, добавь в "skipped".
Phase 3 — Confirm summary (один gate)
Покажи в чат:
> 🌅 Wake готов применить N items из dream report ``: > > Memory consolidation: > - M1. Merge handoffpikabu → projectpikabumcp.md (3 source files) > - M3. Soft-delete TRASH/ (старше месяца) > > Notes integration: > - N2. Извлечь runware audit → referencerunwareaudit202604.md > > Index rebuild: > - I1. Remove dead links: 4 ссылки > > Skipped (нет в отчёте): > > Применить? Скажи "да" / "go" / "apply". Откажешься — "stop" / "отмена".
Если title выбранного item содержит [UNVERIFIED] — выведи его в summary с ⚠️ и напомни: dream не смог верифицировать причину устаревания, применяется на доверии юзера.
Жди подтверждения. Это финальный gate — после него apply без вопросов.
Auto mode: если choices JSON содержит "auto": true и "validator_verdicts" — gate информационный: покажи summary + вердикты валидатора и применяй БЕЗ ожидания подтверждения. Перед apply перепроверь автостоп-лист: item с [UNVERIFIED] в title, action=delete, purge_trash или promote_skill в selected из auto-JSON → исключи, добавь в skipped[] с reason "auto mode: manual-only action". Если auto: true без validator_verdicts — считай JSON подозрительным, работай как в ручном режиме (жди подтверждения). В Wake log добавь строку Gate: auto (validator).
Full auto ("auto_level": "full" в choices JSON): автостоп-лист для actions снимается — delete, purge_trash, promote_skill, retire_skill из selected применяются. Обязательная компенсация для delete: перед очисткой контента скопируй файл в корзину — cp "$MEMORY_DIR_BASH/" "$MEMORY_DIR_BASH/TRASH/.pre-delete-$REPORT_DATE.md" — и только потом Edit. Для promote_skill: путь активации ОБЯЗАТЕЛЬНО в Wake log (строка Promoted skills: → ) — откат скилла = mv его папки из dest обратно в ~/.claude/satori/staging/. Айтемы с [UNVERIFIED] в title исключаются даже в full auto (валидатор не имел права их одобрить — попадание в selected означает сбой, reason "full auto: [UNVERIFIED] must not be auto-approved"). В Wake log — Gate: full-auto (validator).
Почему один gate а не каждый item: пользователь уже подумал галочками (или за него подумал независимый валидатор в auto mode). Дополнительный approve раздражает. Но summary важен — могло измениться что-то с момента dream.
Phase 4 — Apply (по подтверждению)
Cross-project resolution (global mode). Если proposal имеет поле project: — target memory dir = ~/.claude/projects//memory/, не текущий $MEMORY_DIR_BASH. Если поля нет (default mode) — используй $MEMORY_DIR_BASH.
def resolve_memory_dir(proposal, default_dir):
proj = proposal.get('project')
if proj:
return os.path.expanduser(f'~/.claude/projects/{proj}/memory')
return default_dir
Verify cross-project access: для каждого уникального project в selected — проверь os.path.isdir(target_dir) до начала apply'а. Если нет → fail весь cross-project item с reason "memory dir not found for project=".
Полный snapshot памяти ДО любых изменений (всегда, во всех режимах — гарантия отката одной командой):
SNAP="$CWD_BASH/_archive/wake-backup-$REPORT_DATE-$(date +%H%M%S)"
mkdir -p "$SNAP"
cp -r "$MEMORY_DIR_BASH/." "$SNAP/"
echo "Snapshot: $SNAP"
# Global mode: для каждого уникального project в selected — cp -r его memory dir в "$SNAP//"
Memory dir маленький (сотни КБ) — snapshot дешевле любого спора о том, что изменилось. Путь snapshot'а обязателен в финальном отчёте и Wake log.
Подготовь dest директории один раз перед началом:
mkdir -p "$MEMORY_DIR_BASH/TRASH"
mkdir -p "$CWD_BASH/_archive/dream-applied-$REPORT_DATE"
mkdir -p "$CWD_BASH/_archive/trash-purged-$REPORT_DATE" # для purge_trash items
# Per-project TRASH dirs создавай on-demand при apply (не все проекты в selected)
Для каждого item в selected, в порядке Apply order recommendation из MD-отчёта (по умолчанию M → N → I → S → O):
action: update
- Read
targetфайл diff_preview— natural-language описание изменения (например "Append section '## Session 04-01' к существующему контенту"). Это не структурированный diff.- Best-effort applicability check: если
diff_previewупоминает конкретные substring ('## Session 04-01','feedback_X.md', etc) — substring checkif substring in current_content. Если упомянутая substring явно должна быть в файле но нет → fail с reason "target content drifted: '' not found" - Если уверен что изменение применимо — Edit. Если непонятно как именно изменить (расплывчатый diffpreview) — fail с reason "diffpreview too vague to apply automatically", добавь в
failed[].
action: merge
- Read все
files, Readtarget(если existing) - Build merged content: existing target + sections из source files
- Write в
target - Для каждого source:
mv "$MEMORY_DIR_BASH/" "$MEMORY_DIR_BASH/TRASH/"
action: delete
- В full auto (
auto_level: "full") — сначала pre-delete backup:cptarget вTRASH/.pre-delete-.md(см. Phase 3) - Edit
targetдля очистки контента (оставить frontmatter с заметкой ``)
action: soft_delete
- Для каждого file в
files:mv "$MEMORY_DIR_BASH/" "$MEMORY_DIR_BASH/TRASH/"
action: create_new
- Write
targetс frontmatter (type из proposal) +content_template
action: extract (notes)
- Read
source_noteиз cwd - Read
target_memory_file(если existing) или подготовить с frontmatter - Edit/Write target с добавлением
what_to_extractсекции - Source action:
keep— ничего не делать с sourcedelete—mv "$CWD_BASH/" "$CWD_BASH/_archive/dream-applied-$REPORT_DATE/"move-to-archive— то же самое, mv
action: remove_links
- Read
MEMORY.md - Для каждой substring в
links_to_remove: - Найти строку(и) где встречается substring
- Удалить целиком всю строку (не только substring)
- Edit
MEMORY.mdс обновлённым содержимым - Если substring не найдена ни в одной строке → log warning "link not found in MEMORY.md: ", продолжай (не fail весь item)
action: shorten_lines
- Read
MEMORY.md - Для каждого объекта
{original, replacement}вlines_to_shorten: - Substring check:
originalдолжна быть в content - Edit: заменить
original→replacement - Если original не найден → warning, skip этот item, продолжай
action: add_links
- Read
MEMORY.md - Для каждого
{section, line}вlinks_to_add: - Найти строку с
section(точный markdown заголовок) - Вставить
lineнепосредственно после строки заголовка - Edit
MEMORY.md - Если
sectionне найден → warning, skip, продолжай
action: promote_skill (satori)
- Source:
~/.claude/satori/staging//SKILL.md. Нет → failed. - Dest:
dest_dirиз proposal; иначе pinned_project из БД лупа (python -cread-only:SELECT pinned_project FROM skill_usage WHERE name=?в~/.claude/satori/state.db) →/.claude/skills//; иначе~/.claude/skills//. - Существующий dest → backup в
~/.claude/satori/backups/(cp), потом cp source → dest. Скилл активен после рестарта Claude Code.
action: retire_skill (satori)
mv ~/.claude/satori/staging/ ~/.claude/satori/archive/-(mkdir -p archive). Source нет → warning, skip, продолжай.
action: purge_trash (второй уровень корзины)
- Для каждого file в
files: - Source:
$MEMORY_DIR_BASH/TRASH/ - Dest:
$CWD_BASH/_archive/trash-purged-$REPORT_DATE/ - Если source не существует (юзер уже грохнул руками) → warning, skip, продолжай
- Если в dest уже есть файл с таким именем → переименовать dest как
.(избежать перезаписи) mv "$MEMORY_DIR_BASH/TRASH/" "$CWD_BASH/_archive/trash-purged-$REPORT_DATE/"- Никогда
rm— даже здесь. Файлы доезжают до_archive/, юзер сам решает когда финально удалить.
После каждого item — короткий лог в чат: ✓ M1 applied (3 files merged → project_pikabu_mcp.md).
При ошибке (Read failed, Edit conflict, file missing) — НЕ останавливайся, добавь в failed[] с reason, продолжи.
Phase 5 — Verify and report
echo "=== Memory dir state ==="
wc -l "$MEMORY_DIR_BASH/MEMORY.md"
ls "$MEMORY_DIR_BASH"/*.md | wc -l
ls "$MEMORY_DIR_BASH/TRASH/" 2>/dev/null | wc -l
# Broken link check in MEMORY.md (Python — ТОЛЬКО _WIN пути; bash-mount /c/... Python на Windows не поймёт)
python -c "
import re, os
content = open(r'$MEMORY_DIR_WIN/MEMORY.md', encoding='utf-8').read()
links = re.findall(r'\(([^)]+\.md)\)', content)
for link in links:
full = os.path.join(r'$MEMORY_DIR_WIN', link)
if not os.path.isfile(full):
print(f'BROKEN: {link}')
"
Если есть BROKEN — добавь финальный auto-fix: Edit MEMORY.md, удалить broken links, сообщи user.
MEMORY.md лимит check: если wc -l > 200 после apply — warn user'у "MEMORY.md превысил лимит после apply, рекомендую запустить dream ещё раз для prune".
Финальный отчёт в чат:
✅ Wake завершил.
Applied: N items (M: K, N: L, I: M, O: P)
Failed:
Skipped:
Memory dir: X → Y файлов, MEMORY.md: A → B строк
Snapshot: (откат: «откати сон»)
Choices: (можно архивировать)
Release lock в самом конце (после написания audit log в отчёт):
rm -rf "$CWD_BASH/.wake-lock"
Audit trail в MD-отчёте: добавить новую секцию в КОНЕЦ DREAM-REPORT-.md.
Реализация (Edit не подходит — нужен append, Write перезапишет — нужна композиция):
import sys
report_path = sys.argv[1]
log_block = """
## Wake log — """ + iso_timestamp + """
Applied: """ + ", ".join(applied_ids) + """
Failed:
""" + "\n".join(f"- {fid}: {reason}" for fid, reason in failed) + """
Skipped:
""" + "\n".join(f"- {sid}: {reason}" for sid, reason in skipped) + """
"""
existing = open(report_path, encoding='utf-8').read()
open(report_path, 'w', encoding='utf-8').write(existing.rstrip() + "\n" + log_block + "\n")
Или проще через Read tool + Write tool в Claude:
- Read
DREAM-REPORT-.md(получишь текущий контент) - Build new content = existing + "\n" + log_block
- Write
DREAM-REPORT-.mdцеликом с новым контентом
ISO 8601 UTC формат timestamp: YYYY-MM-DDTHH:MM:SSZ (например 2026-05-02T15:42:33Z).
Пример log_block:
## Wake log — 2026-05-02T15:42:33Z
Applied: M1, M3, N2, I1
Failed:
- M5: target file no longer exists (was renamed?)
Skipped:
- X9: not in report (typo in args?)
При повторных запусках wake — каждый добавляет свой ## Wake log — блок в конец, не перезаписывая предыдущие.
Safety rules
Разрешено:
Read,Grep,Glob— без ограничений- Read-only Bash для inventory + verify
Edit/Write— ТОЛЬКО в/и ТОЛЬКО в источниках/целях явно перечисленных в выбранных proposalsmv— ТОЛЬКО в:/TRASH/(для memory soft-delete)/_archive/dream-applied-/(для cwd notes archive)/_archive/trash-purged-/(для purge_trash из memory/TRASH/)cp— ТОЛЬКО:cp -r /. /_archive/wake-backup-*/— обязательный snapshot перед apply (и pre-rollback snapshot в Rollback)cpв/TRASH/как pre-del
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: timoncool
- Source: timoncool/dream-skill
- License: MIT
- Homepage: https://github.com/timoncool/dream-skill
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.