Install
$ agentstack add skill-onebrain-ai-onebrain-wrapup ✓ 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 No
- ✓ 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
Session Summary (TL;DR)
Generates a summary of this session and saves it to the logs folder for future recall.
Scope
/wrapup writes the session log only. It does NOT promote insights to memory/ — that is /recap's responsibility. Do not write to MEMORY.md or memory/ files.
Session Log Frontmatter
See skills/startup/references/session-formats.md → Session Log Format for frontmatter variants and body sections. Never add recapped: or topics: — those are populated by /recap later.
Step 0: Active Pause Thread Detection
Run this BEFORE Step 1.
- Read
[logs_folder]/pause/_active.md. If absent or empty → setwrapup_mode = "session"; skip to Step 1 (zero-overhead path for non-pause sessions). - If a slug is present: parse the file's single-line content as
slug. Glob[logs_folder]/pause/*-{slug}-pause-*.md→pause_count(file count) and derivefirst_date= earliestYYYY-MM-DDdate prefix among matched files (used in Step 3's question text). - Use
AskUserQuestion:
Question: "Active pause thread: {slug} ({pausecount} snapshots since {firstdate}). Wrap up this thread now?" Options:
- "Yes — consolidate into one session log" (sets
wrapup_mode = "thread") - "No — wrapup today's work only; keep pause thread active" (sets
wrapup_mode = "session")
- If
wrapup_mode = "session"AND active pause exists → fall through to Step 0b: Auto-Finalize Pause (below) BEFORE proceeding to Step 1. - If
wrapup_mode = "thread"→ proceed to Step 1 normally, then branch in Step 4 (see Step 4 modifications below).
Step 0b: Auto-Finalize Pause (Session-mode wrapup with active thread)
Runs only when wrapup_mode = "session" AND _active.md exists.
Apply the three skip conditions from skills/pause/SKILL.md → Auto-Finalize section:
- No-activity: if no checkpoint file exists for current
session_token, skip Auto-Finalize. - Already-captured-this-session: if latest pause file's frontmatter
session_tokenmatches current AND no checkpoint mtime > pause file mtime, skip. - No-pause-files-and-untouched: if no pause file exists for slug AND newest checkpoint mtime Note on cleanup: Checkpoints are deleted (not annotated) after the session log is successfully written. Any checkpoint file that still exists is unmerged by definition; no
merged:filter is needed.
Step 1b: Orphan Recovery Scan
After Step 1, scan for unmerged checkpoints belonging to other sessions (orphans).
Variable scope (used throughout this step): Initialize two lists at the top of Step 1b and keep them alive until Step 7 reads them at the end of /wrapup:
skipped_active = []—{path, age_minutes, reason}records, wherereason∈{"active", "age_unknown", "concurrent_during_recovery", "delete_failed", "already_recovered", "marker_write_failed"}. Both the Active-Session Guard and Auto-Recover Each Orphan Group append to this list. When adding a new value to this enum, also add a corresponding row to the{reason_summary}rendering table in Step 7 (search this file for{reason_summary}rendering); unmapped values render via the catch-all fallback row but the user-facing string is generic, so an explicit row is required for new values.orphaned_recovered_logs = []— paths of recovered session logs left on disk by an aborted recovery. Two abort sources feed this list: (1) concurrency abort in step (g) when the owning session writes a new checkpoint mid-recovery and the recovered-log delete itself also fails; (2) marker re-read failure in step (f) when the recovery marker is missing from the just-written log (LLM omission, partial write, encoding glitch). Both produce a recovered log without a deleted checkpoint group; the user must manually reconcile. Listed in its own Step 7 block (these are not checkpoint files, so they don't fit the checkpoint-file heading).
Scan Scope
Glob [logs_folder]/checkpoint/*-checkpoint-*.md (flat — post-v2.4.0 all checkpoints live in one directory regardless of date). No date filter: checkpoint/ is ephemeral (cleaned by /wrapup after each session), so any file surfacing here is either an active cross-harness session (caught by the Active-Session Guard below) or a real orphan that needs recovery.
Identify Orphans
From all found checkpoint files:
- Parse session_token from each filename: the alphanumeric segment between the date and the literal word "checkpoint" in pattern
YYYY-MM-DD-{session_token}-checkpoint-NN.md. If empty, apply Legacy token handling (see below) rather than skipping. - Exclude files where the parsed session_token exactly equals the current session token (those belong to the current session, already handled in Step 1). Do not use substring/contains matching — only exact equality.
- Group remaining files by their parsed session_token. Store the file list of each group as
group_files(the baseline used by step (g)'s concurrency re-glob below); never re-derive the group fresh later in this step.
Legacy token handling: If the parsed segment is a 6-character random string (pre-v1.10.4 format), still include the file in orphan recovery. Group these files under a synthetic key legacy-{segment} and process them the same way as regular groups. This ensures migration from v1.10.3 and earlier does not lose checkpoints. Note each legacy file in the Step 7 report as a warning.
If no orphan groups found: skip to Step 2.
Active-Session Guard (Time Window)
> Why this guard exists: A non-current token does NOT mean the session is dead. When two harnesses (e.g. Claude + Gemini) run in the same vault, each sees the other's in-flight checkpoints as "non-current token". Without this guard, the first /wrapup to run would auto-recover the other harness's active checkpoints into a fake session log and delete the originals — silently corrupting the live session. Token != mine ≠ session is dead.
For each orphan group from the Identify Orphans step above, decide between recover and skip-active by file age (the skipped_active list was initialized at the top of Step 1b):
- Resolve the threshold once (before scanning groups): read
onebrain.yml'scheckpoint.minutes(defaults to 30 when the key is absent) and computethreshold_minutes = max(60, 2 * checkpoint.minutes). Examples: default 30 → 60, raised 60 → 120, raised 90 → 180. Ifonebrain.ymlis missing, malformed, orcheckpoint.minutesis non-positive/non-numeric, fall back tothreshold_minutes = 60— the recovery flow is critical-path; never block on a config issue. - Compute
now_epochonce:now_epoch=$(date +%s). - For every checkpoint file in the group, get its mtime as epoch seconds:
- macOS / BSD:
stat -f '%m' - Linux / GNU:
stat -c '%Y' - Take the maximum across all files in the group as
group_newest_mtime.
- Compute
age_minutes = (now_epoch - group_newest_mtime) / 60(integer division is fine). - Fail-safe — destructive default is forbidden. If any of the following is true, mark the group as skip-active (do NOT recover):
- any stat call failed (file vanished mid-walk, EACCES, NFS error, etc.)
group_newest_mtimeis empty / unparseableage_minutesis negative (clock skew, future mtime)
When ambiguity is detected, append every file path in the group to skipped_active as {path, age_minutes: -1, reason: "age_unknown"} and continue with the next group. Never fall through to recover when age cannot be determined.
- If
age_minutes = threshold_minutes— the group looks dead: fall through to Auto-Recover Each Orphan Group below for this group only.
The threshold gives the owning session a buffer of two full checkpoint windows (the auto-checkpoint hook fires every checkpoint.messages messages or checkpoint.minutes minutes). A group whose newest checkpoint is older than that has missed at least two windows — a strong "session dead" signal. The max(60, 2 * checkpoint.minutes) policy preserves the PR #156 baseline (60 min) for default-config users while scaling proportionally for users who raised checkpoint.minutes. False-positives (idle but live sessions older than the threshold) are non-destructive: nothing was read, written, or deleted; the owning user's next /wrapup writes its own session log normally and consumes the still-on-disk checkpoints.
> Symmetry with onebrain checkpoint orphans: the CLI applies the identical max(60, 2 * checkpoint.minutes) rule (in onebrain-ai/onebrain-cli → crates/onebrain-fs/src/orphan/, is_group_active_or_ambiguous) so the startup banner and the recovery skill agree on what is and isn't an orphan. If you change this policy in one place, change it in the other.
Auto-Recover Each Orphan Group
Progress signal: if there are more than 3 orphan groups to recover, emit a one-line progress signal between groups so the user knows the skill is making progress: Recovering orphan group {n}/{N} ({date})…. Skip the signal when N ≤ 3 (recovery is fast enough that the signal would be noise).
For each orphan group (process in chronological order by date in filename):
a. Already-recovered short-circuit. Before reading checkpoint files, glob [logs_folder]/session/YYYY/MM/YYYY-MM-DD-session-*.md for the group's date (using the orphan date's YYYY/MM). For each match, search the file for the standardised recovery marker. The marker is ` where {token} is the orphan group's session token and {date}` is the group's date.
> Anchored match required (security): match the marker only when it appears at the start of a line — i.e., either the literal string \n or the file beginning with `. A bare substring match would false-positive on session logs whose body quotes the marker as documentation (e.g., a meta-note about how the recovery flow works). The destructive consequence of a false-positive is checkpoint deletion based on a documentation quote — not acceptable. Use rg -n -F with --multiline and a (?m)^ anchor, or grep the file line-by-line. **Strip trailing \r from each line before the startswith check** — Windows-edited logs use CRLF endings; without this the line literal \r won't match the bare prefix and a legitimate already-recovered marker is silently missed. After CRLF strip, check line.startswith(' body marker as the first body line. The marker must appear once per group recovered into this log; if a single recovery pass aggregates multiple groups (rare — date-grouping usually yields one group per date), emit one marker line per group on consecutive lines before the # Session Summary` heading. Apply the Preservation rule from Step 4 below: deduplication only, no summarization. Every unique decision, action item, open question, learning, and topic from every checkpoint must appear in the recovered session log.
f. Verify the session log exists and is non-empty before continuing. Marker re-read check (required): re-read the file from disk and confirm the ` marker line is present at the start of a line, before the # Session Summary : heading. If the marker is missing (LLM omission, partial write, encoding glitch), the next /wrapup's already-recovered short-circuit will fail to detect this log and could re-recover the same checkpoints into a duplicate session log. To prevent that destructive path, treat a missing-marker as **abort recovery for this group**: do NOT proceed to step (g) (no delete), append the session log path to orphanedrecoveredlogs, and for each file in groupfiles append {path, ageminutes, reason: "markerwritefailed"} to skipped_active`. The user sees both blocks in Step 7 and can investigate the recovered log + the still-present checkpoints together.
g. Delete checkpoint files for this group after confirming step f succeeded.
- Pre-delete re-stat (concurrency guard) — runs ONCE before any deletes: re-stat every file in
group_files(stored in Identify Orphans step 3) AND re-glob the group's filename pattern (YYYY-MM-DD-{token}-checkpoint-*.md) under[logs_folder]/checkpoint/(flat). The owning session became active during recovery if either of these holds: - any file's mtime has changed since the Active-Session Guard's stat above, OR
- the re-glob result contains a path NOT present in
group_files(set difference:re_glob_files \ group_filesis non-empty). - If concurrent activity is detected: abort the delete entirely for this group. Then attempt to delete the recovered session log written in step (e) so it does not leak duplicate content into the vault. For each file in
group_files, append{path, age_minutes, reason: "concurrent_during_recovery"}toskipped_active(use the originalage_minutesfrom the Active-Session Guard). If the recovered-log delete itself fails, append the recovered-log path toorphaned_recovered_logs(a separate list initialized at the top of Step 1b) so the user sees it under its own Step 7 block — these are session-log files, not checkpoint files, and conflate poorly with the checkpoint-file heading. Continue with the next group. - If no concurrent activity: delete each file in
group_files. Per-file failure rule: if an individualrmfails (EACCES, NFS hiccup, etc.), do NOT abort the whole group — append{path, age_minutes, reason: "delete_failed"}toskipped_active(reuse the originalage_minutesfrom the Active-Session Guard, never0) and continue with the next file. The recovered session log is already written; the next /wrapup's already-recovered short-circuit (step a) will detect that the orphaned checkpoint's content is already persisted and clean it up. - Stage discipline (do not conflate the two rules above): the concurrency check runs ONCE at the top of step (g). After it passes, individual
rmfailures are NEVER interpreted as concurrency — they recorddelete_failedper-file and the loop continues. Do not re-run the concurrency check between per-file deletes; do not promote a per-filedelete_failedtoconcurrent_during_recovery. The only group-level abort path is the pre-delete concurrency check. - Guard: only delete AFTER step f is confirmed AND the re-stat shows no concurrent activity. Never delete before.
h. Track recovered sessions: append {date} → session-NN.md ({C} checkpoints) to a recovered_sessions list for the final report, where {C} is the number of checkpoint files recovered for this group.
Step 2: Determine Session File Name
- Using the date from Step 1, extract
YYYY,MM(zero-padded month), andDD(zero-padded day). - List files in
[logs_folder]/session/YYYY/MM/matchingYYYY-MM-DD-session-*.md— use today's actual date as a literal prefix (e.g.2026-04-25-session-*.md), not as a wildcard. Only count sessions from today. - The next session number = count of matches + 1 (zero-padded to 2 digits: 01, 02, etc.)
- Verify
YYYY-MM-DD-session-NN.mddoes not already exist before writing; if it does, increment NN until a free slot is found. - File name:
[logs_folder]/session/YYYY/MM/YYYY-MM-DD-session-NN.md
Step 3: Review the Session
Reflect on the conversation that just occurred. Identify:
- Main topic(s) : What did we work on?
- Key decisions made : Any choices, directions, or conclusions reached
- Insights or learnings : New understanding, patterns noticed, things discovered
- What worked / didn't work : Approaches or tools that helped, and anything that slowed us down or failed (omit if nothing notable)
- Action items : Tasks to do, things to follow up on
- Open questions : Unresolved questions or things to investigate
Step 4: Write the Session Log
Branch on wrapup_mode (set in Step 0):
- If
wrapup_mode = "session"→ follow the existing flow below (no changes). - If
wrapup_mode = "thread"→ use the **Thread Wrapup Bra
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: onebrain-ai
- Source: onebrain-ai/onebrain
- License: Apache-2.0
- Homepage: https://onebrain.run
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.