Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/plugins/onebrain/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "onebrain",
"version": "2.4.9",
"version": "2.4.10",
"description": "OneBrain — Where human and AI thinking become one. A powerful thinking partner powered by AI synergy.",
"author": {
"name": "OneBrain Contributors"
Expand Down
17 changes: 13 additions & 4 deletions .claude/plugins/onebrain/INSTRUCTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ If `[agent_folder]/MEMORY.md` has no `## Identity & Personality` section, onboar
07-logs/ Logs split by type:
session/YYYY/MM/ Session logs (YYYY-MM-DD-session-NN.md)
checkpoint/ Stop-hook scratch (flat; consumed by /wrapup)
pause/ Pause-thread snapshots (flat; _active.md pointer + YYYY-MM-DD-{slug}-pause-NN.md)
update/ Release history (flat, version-named)
log/YYYY/MM/ Skill log entries (recap, doctor, memory, ...)
attachments/ Copied files from /import --attach (pdf/, images/, video/)
Expand All @@ -73,6 +74,8 @@ TASKS.md Live task dashboard (created by /tasks, read-only query block
- Archive items: `[archive_folder]/YYYY/MM/filename.md` (organized by date archived)
- Session logs: `[logs_folder]/session/YYYY/MM/YYYY-MM-DD-session-NN.md`
- Checkpoints: `[logs_folder]/checkpoint/YYYY-MM-DD-{session_token}-checkpoint-NN.md` (flat, auto-generated by hooks, not manual)
- Pause snapshots: `[logs_folder]/pause/YYYY-MM-DD-{slug}-pause-NN.md` (flat, NN scoped to slug across all dates)
- Pause pointer: `[logs_folder]/pause/_active.md` (single line containing the active slug)
- Update logs: `[logs_folder]/update/YYYY-MM-DD-update-vX.Y.Z.md` (flat, written by /update)
- Skill logs: `[logs_folder]/log/YYYY/MM/YYYY-MM-DD-{skill}.md` (append per day; some have discriminator e.g. `distill-{slug}`, `qmd-{subcommand}`)
- Inbox items: `[inbox_folder]/YYYY-MM-DD-topic.md` (flat, no subfolders)
Expand Down Expand Up @@ -149,6 +152,8 @@ These workflows are documented in `.claude/plugins/onebrain/skills/`:
| `/tasks` | `tasks/SKILL.md` | Create or update live task dashboard (TASKS.md) and open in Obsidian | user asks to view the task dashboard, regenerate TASKS.md, or open it in Obsidian |
| `/moc` | `moc/SKILL.md` | Create or update vault portal (MOC.md) and open in Obsidian | user asks to update the vault map |
| `/wrapup` | `wrapup/SKILL.md` | Wrap up session → session log | explicit `/wrapup` command only — end-of-session signals are handled silently by Auto Session Summary |
| `/pause` | `pause/SKILL.md` | Save snapshot of long-running work to resume later | user signals pause of long task ("pause", "หยุดก่อน", "step away", "ทิ้งงานไว้") |
| `/resume` | `resume/SKILL.md` | Load active pause thread state | user signals resume of paused work ("resume", "กลับมาทำต่อ", "pick up", "ที่ค้างไว้") |
| `/learn` | `learn/SKILL.md` | Teach the agent : facts or behavioral preferences | user tells the agent to remember or learn something |
| `/memory-review` | `memory-review/SKILL.md` | Interactive memory pruning | (manual only) |
| `/clone` | `clone/SKILL.md` | Package agent context for vault transfer | (manual only) |
Expand Down Expand Up @@ -178,6 +183,8 @@ These agents live in `.claude/plugins/onebrain/agents/` and are dispatched autom

When a user message clearly maps to a skill, invoke it directly — no `/command` needed. If intent is ambiguous, use AskUserQuestion to confirm before invoking. When trigger conditions overlap, prefer the lighter-weight skill (e.g. `/capture` over `/braindump`, `/bookmark` over `/summarize`). Skills marked "manual only" require explicit `/command` always.

**/pause vs /capture vs /wrapup:** Use `/pause` only when work in progress will continue across multiple sessions. `/capture` is for a single idea unrelated to ongoing work. `/wrapup` is terminal — when the work is done. If unsure between `/pause` and `/capture`, prefer `/capture` (lighter weight). Routing keywords for `/pause`: "pause", "step away", "ทิ้งงานไว้", "ค่อยมาทำต่อ", "long task". Routing keywords for `/resume`: "resume", "continue", "pick up", "ทำต่อ", "ที่ค้างไว้".

## Search Strategy

If qmd MCP tools are available (`mcp__plugin_onebrain_qmd__query` in tool list):
Expand Down Expand Up @@ -240,18 +247,20 @@ On weekends: lighter, less task-focused tone. **No-repeat rule:** don't ask abou
- Glob `[inbox_folder]/*.md` → count files as `inbox_count`
- Run the Grep tool **twice** — once with `path: "[projects_folder]"` and once with `path: "[inbox_folder]"`, both with the pattern `- \[ \] .*📅 [0-9]{4}-[0-9]{2}-[0-9]{2}` and `output_mode: "content"`. Combine the two result sets. (Grep handles UTF-8 correctly on every platform; the previous Bash shell-out relied on `LC_ALL=en_US.UTF-8` and GNU grep BRE semantics, both Bash-only.) Keep only tasks where date ≤ today; group overdue first, then due today
- Run `onebrain orphan-scan "[logs_folder]" "[session_token]"` (from vault root) → parse JSON output; read `orphan_count` field. JSON shape: `{"orphan_count":N}`. If the command fails or is unavailable, fall back to a structure-aware glob: if `[logs_folder]/checkpoint/` exists, glob `[logs_folder]/checkpoint/*-checkpoint-*.md` (post-v2.4.0 flat layout); else glob `[logs_folder]/**/*-checkpoint-*.md` (pre-v2.4.0 nested layout — multi-vault user on an unmigrated vault). Then discard files whose date has a non-auto-saved session log (look in `[logs_folder]/session/YYYY/MM/` for post-v2.4.0, or `[logs_folder]/YYYY/MM/` for pre-v2.4.0), and count distinct session tokens among remaining files.
- Read `[logs_folder]/pause/_active.md` if present → parse single-line content as `active_pause_slug`. If absent, set `active_pause_slug = null`. Then if non-null: glob `[logs_folder]/pause/*-{active_pause_slug}-pause-*.md` and count them as `active_pause_count`; read the latest file's `date` frontmatter as `active_pause_last_date`.
- **Legacy structure detection (post-v2.4.0):** Check whether `[logs_folder]/session/` exists (any of the new top-level subfolders works as a sentinel; `session/` is the most representative). If it does NOT exist AND `[logs_folder]/YYYY/` does exist (legacy structure pre-v2.4.0), set `vault_structure_legacy = true`. If both `session/` and a legacy `YYYY/` exist (partial migration), still treat `vault_structure_legacy = false` — `/update` will resume cleanup on next run. If neither exists (fresh vault), `vault_structure_legacy = false`.

**Step 4 — Send startup status (after Step 3 completes):**

If inbox_count = 0 and orphan_count = 0 and qmd_unembedded = 0 and vault_structure_legacy = false and no tasks found: show nothing after the greeting.
If inbox_count = 0 and orphan_count = 0 and qmd_unembedded = 0 and active_pause_slug is null and vault_structure_legacy = false and no tasks found: show nothing after the greeting.

Otherwise, append after the greeting:

```
📥 inbox [N] ← omit if inbox_count = 0
📋 [N] orphan session(s) — /wrapup? ← omit if orphan_count = 0
⚠️ qmd: [N] doc(s) need embedding — /qmd embed ← omit if qmd_unembedded = 0
📂 active pause: {active_pause_slug} ({active_pause_count} snapshots, last {active_pause_last_date}) — /resume? ← omit if active_pause_slug is null
⚠️ vault structure outdated — run /update to migrate ← omit if vault_structure_legacy = false

Pending tasks:
Expand Down Expand Up @@ -335,12 +344,12 @@ Different commands have different verbosity expectations. Match output to the pr

| Profile | Commands | Behavior |
|---------|----------|----------|
| **Capture** | `/capture`, `/braindump`, `/bookmark`, `/learn` | Write the note, confirm done in 1 line. No elaboration. |
| **Capture** | `/capture`, `/braindump`, `/bookmark`, `/learn`, `/pause` | Write the note/snapshot, confirm done. /pause adds the active-thread line. No elaboration. |
| **Automated** | cron jobs, Auto Session Summary, `/wrapup` | Structured output only (bullets/sections). No commentary. Under 300 words. |
| **Interactive** | `/research`, `/connect`, `/consolidate`, `/reading-notes`, `/weekly`, `/distill`, `/recap` | Normal verbosity : depth matches task complexity. |
| **Interactive** | `/research`, `/connect`, `/consolidate`, `/reading-notes`, `/weekly`, `/distill`, `/recap`, `/resume` | Normal verbosity : depth matches task complexity. |
| **Diagnostic** | `/doctor` | Structured report output. No meta-commentary. Lead with findings. |
| **Config/Setup** | `/onboarding`, `/tasks`, `/moc`, `/qmd` | Confirm actions taken. No verbose explanation unless asked. |
> **Terminal rendering:** The Obsidian terminal plugin renders markdown natively (tables, bold, headers, code blocks). Interactive and Diagnostic profiles should use full markdown. Capture profile: 1-line plain-text confirm only. Automated profile: no headers — output is read async via Telegram where markdown rendering varies.
> **Terminal rendering:** The Obsidian terminal plugin renders markdown natively (tables, bold, headers, code blocks). Interactive and Diagnostic profiles should use full markdown. Capture profile: 1-line plain-text confirm only (exception: `/pause` emits a 2-line confirm + 2-line user instruction block per its SKILL.md Step 6). Automated profile: no headers — output is read async via Telegram where markdown rendering varies.


For cron/automated agents specifically: output is read by the user async (often via Telegram) : lead with the content, skip all meta-commentary about what you're doing.
Expand Down
46 changes: 46 additions & 0 deletions .claude/plugins/onebrain/skills/doctor/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,52 @@ Only run when vault.yml contains a `schedule:` block. Skip entirely otherwise.
- **Schedule drift** — Read `vault.yml` `schedule:` block. For each entry, check that the corresponding launchd plist exists at `~/Library/LaunchAgents/com.onebrain.<labelSafe>.plist` where `labelSafe` strips leading `/` from `entry.skill` and replaces non-`[a-zA-Z0-9-]` chars with `-`. If any entry's plist is missing → 🟡 drift — suggest `onebrain register-schedule`. If any installed plist no longer matches a vault.yml entry (stale orphan) → 🟡 stale plist — suggest `onebrain register-schedule --remove` then re-register.
- **One-shot reachability** — For each entry with `at:` (one-shot), verify the timestamp has not already passed. If passed and the plist still exists → 🟡 expired one-shot not cleaned up — suggest `onebrain register-schedule --remove` to clear the stale plist (the self-delete shell may have failed to run).

### Pause: Orphan Pointer

Check: `[logs_folder]/pause/_active.md` exists but no pause file matches its slug.

How to detect:
1. Read `_active.md`. If absent → skip.
2. Parse slug. Glob `[logs_folder]/pause/*-{slug}-pause-*.md`. If empty match → orphan pointer.

Report (if orphan):
```
⚠️ Pause pointer references `{slug}` but no snapshot files exist.
Fix: rm 07-logs/pause/_active.md (or create initial /pause)
```

### Pause: Missing Pointer

Check: pause files exist but `_active.md` is missing.

How to detect:
1. Glob `[logs_folder]/pause/*-pause-*.md`. If empty → skip.
2. If `_active.md` exists → skip.
3. Otherwise: missing pointer. Identify slug(s) from filenames.

Report (if missing):
```
⚠️ Pause files exist but no active pointer:
- {slug-1} (N snapshots, latest YYYY-MM-DD)
- {slug-2} (M snapshots, latest YYYY-MM-DD)
Fix: echo "{chosen-slug}" > 07-logs/pause/_active.md
```

### Pause: Idle Thread

Check: active pause thread has had no new activity (no new pause file, no `/resume`) for > 14 days.

How to detect:
1. Read `_active.md`. If absent → skip.
2. Glob pause files for the slug. Get max date prefix from filenames.
3. If `(today - max_date).days > 14` → idle.

Report (if idle):
```
⚠️ Pause thread `{slug}` idle for {N} days (last snapshot YYYY-MM-DD).
Fix: /wrapup to consolidate, or /pause to refresh, or /resume to continue
```

---

## Step 3: Report Findings
Expand Down
118 changes: 118 additions & 0 deletions .claude/plugins/onebrain/skills/pause/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
---
name: pause
description: "Save a snapshot of long-running work mid-flight to resume later in a future session. Use when user signals they need to pause a long task and continue another time — 'pause this work', 'หยุดก่อน', 'พักงานนี้ก่อน', 'พักไว้ก่อน', 'step away', 'ทิ้งงานไว้ก่อน', 'ค่อยมาทำต่อ'. Writes a snapshot to 07-logs/pause/ but does NOT end the session or clear context. Do NOT use for: ending a session (use /wrapup), capturing a single idea (use /capture), saving a memory (use /learn)."
schedulable: false
---

# /pause — Save Long-Task Snapshot (TL;DR)

Writes a per-thread snapshot of the current work to `[logs_folder]/pause/` so the next session can `/resume` and pick up seamlessly. Multiple pause files accumulate across days for the same task; `/wrapup` later consolidates them all into one session log.

**Mental model:** `/pause` = SAVE snapshot. It does NOT end the session and does NOT clear context. User runs `/clear` manually when ready to free context.

---

## Scope

- /pause writes pause snapshot files only. It does NOT touch checkpoints, session logs, MEMORY.md, or memory/ files.
- It DOES update the pointer file `[logs_folder]/pause/_active.md` to set/confirm the active thread slug.

---

## Step 1: Determine Active Thread Slug

1. Read `[logs_folder]/pause/_active.md` if present. The file is plain text — one line — containing a kebab-case slug.
2. If the file exists and is non-empty: use that slug as `active_slug`.
3. If absent / empty:
- Agent reviews session context → propose a kebab-case slug from the dominant topic (e.g. `cli-refactor`, `oracle-borrows`)
- Use `AskUserQuestion` to confirm. Question: "Active thread name? Suggested: `<proposed-slug>`" with options: (a) accept suggestion, (b) type a different slug
- On confirmation, set `active_slug = <chosen>` and continue
4. If `/pause --task=<slug>` was invoked with an explicit slug:
- If `_active.md` is empty or contains the same slug → set `active_slug = <slug>`, skip warning
- If `_active.md` contains a different slug → use `AskUserQuestion`: "⚠️ Active thread: `<existing>` (N unmerged snapshots). Switch to `<new>`? (y/N)". On `y` → set `active_slug = <new>`. On `n` → abort silently with message "Pause aborted — active thread unchanged."

---

## Step 2: Compute Next NN

1. Glob `[logs_folder]/pause/*-{active_slug}-pause-*.md` (no date filter — NN is scoped to slug across all dates).
2. Parse the `NN` segment (the two-digit number before `.md`) from each filename.
3. `next_nn` = `max(NN parsed) + 1`. If no files → `next_nn = 01`. Always zero-pad to 2 digits.

---

## Step 3: Generate Snapshot Content

Review the current conversation since the last pause file of `active_slug` (or since session start if none). Fill the body sections following `skills/startup/references/session-formats.md` → Pause File Format.

**Required sections (in order):**

- `## Where I Stopped` — 1–2 sentences: file being edited, decision pending, last test run, current focus
- `## Resume With` — one concrete next action: specific file path, command, decision point. Must be actionable as the FIRST thing on resume
- `## What We Worked On` — 2–3 sentences describing the pause-interval's focus
- `## Key Decisions` — bullet list (every unique decision since last pause, full detail)
- `## Insights & Learnings` — omit if none
- `## Action Items` — `- [ ] task 📅 YYYY-MM-DD` format
- `## Open Questions` — omit if none

**Word cap:** 350 words total. Preservation rule: every unique decision/action/question since last pause MUST appear — deduplication only, no summarization.

---

## Step 4: Write the Pause File

1. Today's date as `YYYY-MM-DD`.
2. Ensure directory exists: `mkdir -p [logs_folder]/pause/`
3. Get `session_token` from agent context (run `onebrain session-init` to recover if missing). **If `session-init` fails or returns no token:** abort the write. Do NOT proceed to Step 5. Output: `⚠️ Could not determine session token. Snapshot not saved — try again or run /doctor.`
4. Write to `[logs_folder]/pause/YYYY-MM-DD-{active_slug}-pause-{next_nn}.md`:

```yaml
---
tags: [pause, session-log]
date: YYYY-MM-DD
session_token: <token>
task_slug: <active_slug>
pause: <NN>
trigger: manual
---
```

Followed by the body sections from Step 3.

**If the file write fails** (disk full, permission denied, etc.): abort the skill. Do NOT proceed to Step 5 (do not update `_active.md` — that would create an instant orphan pointer). Output: `⚠️ Snapshot failed to save — check disk space or file permissions. Active thread unchanged.`

---

## Step 5: Update Active Pointer

Write `[logs_folder]/pause/_active.md` with a single line: the `active_slug` value (no trailing newline issues — overwrite is idempotent if slug already matches).

---

## Step 6: Confirm

Output exactly this format (Capture profile — 1 confirmation block, no elaboration):

```
💾 Snapshot saved: 07-logs/pause/YYYY-MM-DD-{slug}-pause-NN.md
📂 Active thread: {slug} (N snapshots)

คุยต่อได้เลย — ยังไม่ตัด context.
พิมพ์ /clear เมื่อพร้อมพักงาน (snapshot จะรอ session ถัดไป)
```

Where `N` = `next_nn` from Step 2 (the total snapshot count for this thread including the one just written).

---

## Auto-Finalize (Called by AUTO-SUMMARY and /wrapup "n" branch)

When AUTO-SUMMARY or `/wrapup` "n" branch needs to finalize an active thread before writing a daily session log, it calls into this skill's auto-finalize path. Three skip conditions — if ANY is true, skip:

1. **No-activity:** Glob `[logs_folder]/checkpoint/*-{current_session_token}-checkpoint-*.md` — if empty, the session produced no work; skip.
2. **Already-captured-this-session:** Find the latest pause file of `active_slug`. If its frontmatter `session_token` equals current session token AND no checkpoint file mtime > pause file mtime, the current session's work is already captured by an earlier `/pause`; skip.
3. **No-pause-files-and-untouched:** If no pause file exists yet for `active_slug` AND the newest checkpoint mtime is older than `_active.md` mtime, the slug was set but no thread activity occurred; skip.

If not skipped: run Steps 2–5 above, but in Step 4 frontmatter use `trigger: auto-finalize` instead of `manual`, and in Step 3's `## Where I Stopped` prepend "Auto-finalized at session end. " to the human-readable text.

No Step 6 confirm — auto-finalize is silent.
Loading
Loading