---
slug: "llblab-pi-wakeup"
source_type: "readme"
source_url: "https://cdn.jsdelivr.net/gh/llblab/pi-wakeup@main/README.md"
repo: "https://github.com/llblab/pi-wakeup"
source_file: "README.md"
branch: "main"
---
# pi-wakeup

**Durable wake-up rhythm for Pi.**

`pi-wakeup` lets one live Pi session deliver scheduled follow-up prompts from a human-editable Markdown plan. It is a small local scheduler for agent rhythm: write the future task once, keep it visible in `WAKEUP.md`, and let the active owner session bring it back at the right time.

It is not cron, a daemon, or a background task runner. The product boundary is deliberate: wake-ups are Pi prompts, delivery is singleton-owned, schedule state is plain Markdown, and every future action remains readable before it fires.

## Why it exists

Agents often need to pause and return later: check a build in ten minutes, resume a review tomorrow, close a fired reminder, or keep a spaced work cadence without external infrastructure. `pi-wakeup` gives that rhythm a durable local surface instead of hiding it in timers, shell jobs, or chat memory.

```text
future intent
→ WAKEUP.md entry
→ singleton delivery owner
→ local timer
→ ⏰ Wakeup! prompt
→ wakeup done
```

## Core promise

- **Readable schedule state.** `~/.pi/agent/WAKEUP.md` is the source of truth and stays safe to inspect or edit.
- **Automatic uncontested ownership.** The first live Pi instance acquires delivery when no live owner exists; later instances stay passive while that owner is alive and automatically take over after it exits.
- **Agent-callable scheduling.** The `wakeup` tool can check, schedule, and close tasks from inside normal Pi work.
- **No immediate execution confusion.** Scheduling means schedule only; the action runs later when the wake-up prompt fires.
- **Ownership-visible status rhythm.** The footer stays hidden for non-owner/inactive sessions, shows `wakeup on` when this Pi instance owns delivery, and adds `[hh:mm:ss]` during an active future countdown.
- **Sequential prompts.** Fired tasks become `[~]`; overdue pending tasks wait until the active fired task is closed.

## Install

From npm:

```bash
pi install npm:@llblab/pi-wakeup
```

From git:

```bash
pi install git:github.com/llblab/pi-wakeup
```

## First run

Schedule a future prompt. If no live owner exists, this Pi session activates delivery automatically:

```text
wakeup schedule "in 10m | Review WAKEUP.md"
```

Inspect the schedule:

```text
wakeup check
```

When a task fires, Pi receives a prompt starting with:

```text
⏰ Wakeup!
```

Close fired work after handling it:

```text
wakeup done
```

Manual ownership commands remain available for advanced recovery: `/wakeup-start` explicitly moves delivery here, and `/wakeup-stop` releases the current owner.

## Product model

| Lens | What `pi-wakeup` owns |
| --- | --- |
| Rhythm keeper | Future prompts that should return to the active Pi workflow at a chosen time |
| Markdown schedule | `WAKEUP.md` as durable, readable, user-editable state |
| Singleton delivery | One live Pi process owns timers and sends fired prompts; ownership is automatic only when uncontested |
| Agent tool | `wakeup check`, `wakeup schedule`, and `wakeup done` as compact LLM-facing controls |
| Status surface | Owner presence as `wakeup on`, upgraded to `wakeup on [hh:mm:ss]` while a future wake-up is actively ticking |
| Safety boundary | Scheduling is not execution; ownership blocks silent live-session takeover |

## Feature showcase

| Surface | What you can do | Why it matters |
| --- | --- | --- |
| Automatic ownership | Acquire delivery on session start or scheduling when no live owner exists, release it on clean shutdown, and let passive sessions recover stale ownership. | Users do not need to remember a start command when sessions open, close, or fail. |
| Manual ownership | Use `/wakeup-start` and `/wakeup-stop` as advanced takeover/release controls. | Operators still have an escape hatch for recovery or deliberate owner moves. |
| `wakeup schedule` | Add a future prompt using relative or absolute time, even from passive instances. | Agents can create their own return points without cron, shell timers, or lock ping-pong. |
| `wakeup check` | Read the current schedule and ownership state. | The agent can verify timing before acting or editing. |
| `wakeup done` | Close current fired tasks by all current `[~]` tasks or a specific index. | Fired prompts become deliberate workflow checkpoints, not endless reminders. |
| Direct `WAKEUP.md` edits | Reschedule, remove, or adjust tasks by editing Markdown. | Operators keep full readable control over the plan. |
| File watcher | Reload valid schedule edits in the active owner and acquire delivery only when ownerless. | Manual edits and tool scheduling stay synchronized without stealing from live owners. |
| Dynamic status | Show owner presence as `wakeup on`, then active countdowns as `wakeup on [hh:mm:ss]`. | The footer shows which terminal owns singleton delivery while keeping countdown urgency visible. |
| Sequential firing | Keep one `[~]` active and fire overdue tasks after it is done. | Multiple overdue reminders do not stack into concurrent prompt noise. |
| Completed-entry retention | Keep completed tasks while work remains, then reset to the empty template. | History stays useful during an active batch and disappears when the plan is clean. |

## Scheduling

Prefer relative time for user-facing delays:

```text
wakeup schedule "in 10m | Review WAKEUP.md"
wakeup schedule "1h30m | Deep work checkpoint"
wakeup schedule "2026-04-28T15:00:00Z | Absolute UTC task"
```

Supported duration units: `s`, `m`, `h`, `d`.

A scheduling request creates a future wake-up. It should not execute the scheduled task immediately in the current turn; execution happens only when the wake-up fires as a future prompt.

## WAKEUP.md format

Entries are stored as UTC ISO 8601 timestamps:

```markdown
# Wakeup Plan

> Flat list of scheduled agent awakenings
> Format: `N. [status] YYYY-MM-DDTHH:MM:SSZ | action`
> N: task index, starts from 3
> Status: ` ` pending, `x` done, `~` in progress
> Timestamps are stored as UTC ISO 8601

---

0. [x] 2026-04-28T10:00:00Z | Finished task
1. [~] 2026-04-28T11:00:00Z | Current fired task
2. [ ] 2026-04-28T12:00:00Z | Future task

---
```

`WAKEUP.md` keeps human-edited order. The `> N: task index, starts from ...` header stores the next task index. Use direct file edits for rescheduling or removing tasks when that is clearer than asking the agent to schedule a new entry.

## Runtime and ownership

- `WAKEUP.md` is editable schedule state under `~/.pi/agent/WAKEUP.md`.
- `tmp/wakeup/owner.json` stores one private `{ "pid": ..., "cwd": ... }` delivery owner; mutations serialize through `owner.json.transaction` and publish atomically with mode `0600` on POSIX filesystems.
- Version `0.9.0` ignores legacy `locks.json` ownership, leaves that registry untouched, and elects or acquires a fresh owner after upgrade.
- Timers are rebuilt from `WAKEUP.md` on startup, owner tool edits, and manual file changes.
- Only the owning Pi process sends `⏰ Wakeup!`.
- Session start acquires delivery automatically when no live owner exists or the stored owner is stale.
- New sessions stay passive when another live owner exists and check ownership every five seconds.
- The owning session releases exact ownership on clean shutdown; if it disappears without cleanup, a passive session detects the dead PID and takes over automatically.
- The `wakeup` tool remains available to the agent, while delivery stays singleton-locked.
- `wakeup schedule` writes the shared `WAKEUP.md`; it activates local delivery only when no live owner exists and never steals from a live owner.
- Direct `WAKEUP.md` edits can also acquire local delivery only when no live external owner blocks them.
- `/wakeup-start` can manually move singleton ownership here when another live Pi instance owns delivery.
- `/new` and process restarts resume or reacquire ownership when `pid`/`cwd` semantics allow it.
- The footer countdown is updated from cached schedule state, not by rereading `WAKEUP.md` every second.
- The footer status is hidden when wake-up is off or this process is not the owner.
- The footer shows accent `wakeup` plus muted `on` while this process owns delivery and `wakeup on [hh:mm:ss]` when a future pending task is counting down.
- No cron, daemon, or external service is introduced.

## Safety boundary

`pi-wakeup` schedules prompts; it does not perform the scheduled work at scheduling time.

A future task is intentionally two-step:

1. Schedule the wake-up.
2. Let the fired `⏰ Wakeup!` prompt ask the agent to do the work later.

This keeps delayed execution visible and interruptible. A live external owner blocks delivery takeover, not shared schedule mutation: passive instances may write `WAKEUP.md`, while the sticky owner remains responsible for reloading and delivering the schedule.

## Documentation

- [Project context](https://github.com/llblab/pi-wakeup/blob/HEAD/AGENTS.md)
- [Open backlog](https://github.com/llblab/pi-wakeup/blob/HEAD/BACKLOG.md)
- [Changelog](https://github.com/llblab/pi-wakeup/blob/HEAD/CHANGELOG.md)
- [Documentation index](https://github.com/llblab/pi-wakeup/blob/HEAD/docs/README.md)
- [Architecture and ownership](https://github.com/llblab/pi-wakeup/blob/HEAD/docs/architecture.md)

## Development

```bash
npm run check
npm test
npm run pack:dry
```

CI runs these gates on Linux, macOS, and native Windows. The transaction guard uses the same directory/rename primitives on Android/Termux and avoids hard links and platform-specific advisory locks.
