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
30 changes: 30 additions & 0 deletions .github/release-notes/v0.4.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# WAKE v0.4.0

WAKE now resumes long-running work by persisting the **task**, not by reopening the old Codex chat.

## Highlights

- Replaces automatic `codex exec resume <thread-id>` with checkpoint-first job continuation.
- Stores durable jobs under `~/.codex/wake/jobs/<job-id>`.
- Starts a fresh lightweight Codex thread after quota recovery and reads `checkpoint.md` first.
- Keeps `ordinaryUsageAllowed` as the authoritative recovery signal; reset timestamps remain hints only.
- Adds bounded retry handling for temporary model-capacity and network failures.
- Adds explicit job states for `retry_waiting`, `stopped`, and `needs_attention`.
- Supports optional per-job model and reasoning-effort overrides.
- Preserves job/checkpoint history across Skill reinstall.

## Validation

Validated on Windows with:

- Python syntax checks.
- Unit tests for checkpoint lifecycle, quota transitions, retry behavior, and handoff launch.
- Installer/start/stop/status lifecycle tests.
- A real Codex handoff through the recovered-quota path that created a new thread, read the checkpoint, produced and byte-verified the requested artifact, updated the checkpoint, and marked the job `completed`.

The real handoff also exercised transient timeout/capacity retries before succeeding.

## Compatibility note

v0.3.2 exact-thread resume could hit a Desktop active-writer conflict. v0.4.0 deliberately avoids taking ownership of the original Desktop thread.

61 changes: 31 additions & 30 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- name: Check out repository
uses: actions/checkout@v4

- name: Validate WAKE metadata
- name: Validate metadata and checkpoint-first contract
shell: python
run: |
from pathlib import Path
Expand All @@ -23,40 +23,41 @@ jobs:
skill = Path("SKILL.md")
agent = Path("agents/openai.yaml")
watcher = Path("watcher/wake_watcher.py")
docs = Path("docs/quota-watcher.md")

assert skill.is_file()
assert agent.is_file()
assert watcher.is_file()
for path in (skill, agent, watcher, docs):
assert path.is_file(), f"Missing {path}"

text = skill.read_text(encoding="utf-8")
assert text.startswith("---\n")
assert re.search(r"(?m)^name:\s*wake\s*$", text)

required = [
"$wake",
"$wake start",
"$wake stop",
"$wake status",
"CODEX_THREAD_ID",
"ordinaryUsageAllowed",
"QUOTA_BLOCKED",
"WAITING_USER",
"BYMINUTE=0,15,30,45",
]
for item in required:
assert item in text, f"Missing required content: {item}"

version = Path("VERSION").read_text(encoding="utf-8").strip()
assert version in {"0.2.0", "0.3.2"}

agent_text = agent.read_text(encoding="utf-8")
watcher_text = watcher.read_text(encoding="utf-8")
assert 'VERSION = "0.3.2"' in watcher_text

- name: Compile watcher
run: python -m py_compile watcher/wake_watcher.py
assert text.startswith("---\n")
assert re.search(r"(?m)^name:\s*wake\s*$", text)
for required in (
"$wake", "$wake start", "$wake stop", "$wake status",
"checkpoint", "quota_waiting", "needs_attention",
"ordinaryUsageAllowed", "job-create-current", "job-complete",
):
assert required in text, f"Missing SKILL contract: {required}"

assert "codex exec resume" not in watcher_text
assert '"exec"' in watcher_text
assert "checkpoint.md" in watcher_text
assert re.search(
r"(?m)^\s*allow_implicit_invocation:\s*true\s*$",
agent_text,
)

- name: Run Python tests
run: |
python -m py_compile watcher/wake_watcher.py
python -m unittest discover -s tests -v

- name: Check shell scripts
run: |
for file in scripts/*.sh; do
bash -n "$file"
done
bash -n scripts/install.sh
bash -n scripts/uninstall.sh
bash -n scripts/start-watcher.sh
bash -n scripts/status-watcher.sh
bash -n scripts/stop-watcher.sh
10 changes: 4 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
# Runtime state
.state/
*.log
__pycache__/
*.py[cod]

# OS
.DS_Store
Thumbs.db
Expand All @@ -14,6 +8,10 @@ Thumbs.db
*.swp
*.swo

# Python
__pycache__/
*.py[cod]

# Temporary files
*.tmp
*.bak
44 changes: 36 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
# Changelog

All notable changes to this project will be documented here.

## [0.4.0] - 2026-09-26

### Changed

- Replaced thread-resume recovery with checkpoint-first job continuation.
- WAKE now persists durable jobs under `~/.codex/wake/jobs/<job-id>`.
- Quota recovery launches a new lightweight `codex exec` thread instead of reopening the old chat.
- The watcher uses one hidden persistent `codex app-server` for quota reads.
- Skill reinstall no longer owns or deletes durable job history.

### Added

- Compact `checkpoint.md` handoff contract.
- Job states: draft, monitoring, quota_waiting, running, retry_waiting, waiting_user, needs_attention, stopped, completed.
- Commands: `job-create-current`, `job-arm`, `job-status`, `job-list`, `job-pause`, `job-rearm`, `job-stop`, `job-complete`.
- Optional per-job model and reasoning-effort overrides.
- Bounded retries for temporary capacity/network failures.
- Unit tests for checkpoint lifecycle, quota transitions, handoff launch, and transient retries.

### Removed

- Automatic `codex exec resume <thread-id>`.
- Dependency on Desktop Goal owner/control-socket recovery for the primary path.

## [0.3.2] - 2026-09-24

### Added
Expand All @@ -26,8 +52,7 @@

### Known limitation

- Exact quota recovery currently resumes through detached `codex exec resume <thread-id>`;
Codex Desktop UI synchronization may vary by version.
- Exact quota recovery used detached `codex exec resume <thread-id>`; v0.4.0 replaces that path with checkpoint-first job continuation.

## [0.2.0] - 2026-09-19

Expand All @@ -38,11 +63,14 @@
- Automatic pause when progress requires user input, approval, credentials,
confirmation, restart, or another manual action.
- Re-arm flow after the user resolves a WAITING_USER blocker.
- State-machine documentation.
- Optional implicit invocation for re-arming an already-paused WAKE conversation.
- State-machine documentation and central-supervisor design notes.

### Fixed
### Changed

- Prevent repeated quarter-hour wakeups while Codex is waiting for the user.
- WAKE no longer treats every unfinished conversation as immediately runnable.
- Scheduled runs classify state before doing project work.
- `$wake status` now reports paused state and pause reason when available.

## [0.1.0] - 2026-09-18

Expand All @@ -51,6 +79,6 @@
- Initial public WAKE skill.
- `$wake`, `$wake start`, `$wake stop`, and `$wake status`.
- Shared quarter-hour synchronization at `:00 / :15 / :30 / :45`.
- Windows/macOS/Linux install scripts.
- English and Simplified Chinese documentation.
- GitHub Actions validation.
- Duplicate-schedule prevention guidance.
- Windows PowerShell install/uninstall scripts.
- macOS/Linux install/uninstall scripts.
131 changes: 60 additions & 71 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,39 @@
# wake

[![Validate skill](https://github.com/Gordon-Jang/codex-wake/actions/workflows/validate.yml/badge.svg)](https://github.com/Gordon-Jang/codex-wake/actions/workflows/validate.yml)
[![GitHub release](https://img.shields.io/github/v/release/Gordon-Jang/codex-wake)](https://github.com/Gordon-Jang/codex-wake/releases)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
**wake** is a Codex Skill for long-running tasks that may span multiple quota windows.

[English](README.md) · [简体中文](README.zh-CN.md)
## v0.4.0: persist the task, not the chat

**wake** is a state-aware Codex Skill for long-running work. v0.3.2 adds a local
quota watcher so quota recovery no longer depends on blind 15-minute model retries.
Earlier WAKE versions tried to resume the original Codex thread. On Codex Desktop that
can conflict with the active writer already owned by Desktop. v0.4 changes the recovery
unit from a thread to a durable **job**.

## What v0.3.2 does
A job stores a compact checkpoint under:

- registers the exact current Codex thread from `CODEX_THREAD_ID`
- reads quota locally through `codex app-server`
- treats `ordinaryUsageAllowed` as the recovery authority
- uses `resetsAt` only to decide when to check again
- tracks `monitoring -> quota_waiting -> monitoring`
- never wakes `waiting_user` threads
- never uses `--last` or guesses a thread id
- keeps synchronized Scheduled Tasks as a conservative fallback
`~/.codex/wake/jobs/<job-id>/checkpoint.md`

> [!IMPORTANT]
> WAKE does not bypass OpenAI usage limits, quotas, rate limits, credits, or safety controls.
When included usage is unavailable, WAKE waits locally without making model turns. When
`ordinaryUsageAllowed` becomes true again, WAKE starts a **new** lightweight
`codex exec` thread that reads the checkpoint first and continues only unfinished work.

## Why this design

- avoids `thread already has an active writer` conflicts;
- does not depend on Codex Desktop Goal UI automation;
- does not require the experimental Windows app-server daemon;
- avoids blindly resuming a huge old chat;
- keeps quota checks local through one hidden persistent `codex app-server`;
- never infers recovery from reset time alone.

WAKE does not bypass OpenAI usage limits, credits, rate limits, or safety controls.

## Requirements

- Codex CLI available as `codex`
- Python 3
- Codex authentication already configured
- a Codex host that exposes `CODEX_THREAD_ID` to shell/tool execution for exact-thread registration
- existing Codex authentication
- a Codex host that exposes `CODEX_THREAD_ID` to shell/tool execution when `$wake`
creates the initial job

## Install

Expand All @@ -37,81 +42,65 @@ Windows:
```powershell
git clone https://github.com/Gordon-Jang/codex-wake.git
cd codex-wake
.scriptsinstall.cmd
.\scripts\install.cmd
```

Default install path:

```text
%USERPROFILE%.codexskillswake
```
`%USERPROFILE%\.codex\skills\wake`

macOS/Linux:
Durable job/checkpoint data lives separately under:

```bash
git clone https://github.com/Gordon-Jang/codex-wake.git
cd codex-wake
./scripts/install.sh
```
`%USERPROFILE%\.codex\wake`

## Verify quota integration
Reinstalling the Skill does not erase that job history.

```powershell
cd $HOME.codexskillswake
python .watcherwake_watcher.py doctor
```
## Use

Working integration reports:
In the Codex conversation that owns the task:

```text
"quotaReadOk": true
$wake
```

## Start watcher
The Skill creates a job, writes a compact checkpoint from the current task context, arms
the job, starts the local watcher, and continues working.

Windows:
Useful diagnostics:

```powershell
.scriptsstart-watcher.cmd
.scriptsstatus-watcher.cmd
python "$HOME\.codex\skills\wake\watcher\wake_watcher.py" doctor
python "$HOME\.codex\skills\wake\watcher\wake_watcher.py" status
python "$HOME\.codex\skills\wake\watcher\wake_watcher.py" job-list
```

Then, in the Codex conversation to manage:
For advanced use, `job-create` / `job-create-current` also accept `--model` and `--reasoning-effort`; if omitted, Codex uses the normal configuration.

```text
$wake
```
## Job states

The Skill should register the exact thread from inside that conversation. A normal
external terminal does not have `CODEX_THREAD_ID`, so `register-current` is
intentionally rejected there.
- `draft` — checkpoint exists but is not armed;
- `monitoring` — current work is active and quota is watched;
- `quota_waiting` — ordinary included usage is unavailable;
- `running` — a checkpoint handoff thread is executing;
- `retry_waiting` — transient capacity/network failure; retries with bounded backoff;
- `waiting_user` — explicit user/manual dependency; never auto-launched;
- `needs_attention` — continuation exited unexpectedly; never loops blindly;
- `stopped` — user disabled automatic continuation but kept the checkpoint;
- `completed` — verified done; ignored by watcher.

Check registrations:
## Recovery contract

```powershell
python $HOME.codexskillswakewatcherwake_watcher.py list
```
A handoff thread reads the checkpoint first, then normally checks only
`git status --short` and `git diff --stat`. It is explicitly told not to reconstruct,
resume, or reread the previous chat.

## State behavior
See [docs/quota-watcher.md](docs/quota-watcher.md) for the state machine.

| State | Behavior |
|---|---|
| ACTIVE | Do not duplicate work |
| WAITING_USER | Pause; quota refresh must not wake it |
| QUOTA_BLOCKED | Watch locally until ordinary usage is actually allowed |
| RETRYABLE_BLOCKED | Use conservative Scheduled Task fallback |
| RUNNABLE | Continue unfinished work |
| DONE | Unregister and stop |
| UNKNOWN | Ask once, then pause |
## Development

See [docs/quota-watcher.md](docs/quota-watcher.md).

## Known limitation

Quota recovery currently launches exact `codex exec resume <thread-id>`. It is
safer than `--last`, but a detached CLI continuation may not always render in
Codex Desktop exactly like a native Desktop turn.

## License
```powershell
python -m py_compile .\watcher\wake_watcher.py
python -m unittest discover -s tests -v
```

MIT.
v0.4.0 has been validated with unit tests plus a real Windows handoff through the recovered-quota path: a fresh Codex thread read the checkpoint, produced and byte-verified the requested artifact, updated the checkpoint, and marked the job completed.
Loading
Loading