A Claude Code plugin that dispatches queued follow-up tasks as parallel background agents. Tasks accumulate in .claude/LATER.md during a session. Near the end of each usage window, cc-later spawns one claude -p agent per ## Section — each in its own git worktree to prevent conflicts. Failed tasks auto-resume in the next fresh window. Stuck agents are detected and restarted.
Python 3.10+ with uv for dependency management. Deps are resolved automatically on first hook run.
- Install
- Quick start
- What it does
- LATER.md format
- Capture shortcut
- Dispatch modes
- Parallel agents and worktrees
- Auto-resume
- Nudge (stuck agent detection)
- Context recovery (compact)
- Token analytics (stats)
- Configuration reference
- Status command
- File layout
- Development and testing
- uv (dependency manager —
curl -LsSf https://astral.sh/uv/install.sh | sh)
claude plugin marketplace add vaddisrinivas/cc-later
claude plugin install cc-laterOn first run, ~/.cc-later/config.env is created from the bundled template. Dependencies (pydantic, filelock, pendulum) are resolved automatically by uv on the first hook invocation — no manual pip install needed.
cc-retrospect — real-time cost monitoring, waste interception, and token analytics for Claude Code. Complements cc-later: retrospect monitors what work costs now, later handles what work to do later.
- Install the plugin (above).
- Set your plan in
~/.cc-later/config.env:PLAN=max - During any session, add tasks to
.claude/LATER.md:# LATER ## Auth - [ ] (P0) fix token refresh in src/auth/service.py - [ ] (P1) add rate limiting to POST /api/refresh ## Tests - [ ] (P1) add integration test for retry path
- Or use the capture shortcut in your prompt:
later: add integration test for the retry path - Near window end, cc-later dispatches one agent per section in parallel.
- Check status anytime:
/cc-later:status - View token analytics:
uv run scripts/stats.py
| Capability | How it works |
|---|---|
| Parallel dispatch | Each ## Section in LATER.md gets its own claude -p agent. All sections run simultaneously. |
| Worktree isolation | When DISPATCH_ALLOW_FILE_WRITES=true, each agent gets its own git worktree + branch. Merged back on completion. |
| Window awareness | Self-calibrating detection of the 5-hour usage window. Dispatches near window end to use otherwise-idle capacity. |
| Auto-resume | Tasks that fail due to rate limits are re-queued and dispatched in the next fresh window. |
| Nudge | Detects stuck agents (no output for N minutes) and restarts them. Detects crashed agents and re-queues. |
| Budget gate | Rolling 7-day token budget with configurable backoff threshold. |
| Context recovery | After /compact, re-injects LATER.md queue + window state into Claude's context. |
| Capture | later: fix the auth bug in any prompt auto-appends to LATER.md. |
| Stats | Per-model token analytics with API-equivalent cost breakdown. |
| Type | Count | Details |
|---|---|---|
| Skills | 1 | cc-later — guides Claude on writing LATER.md entries (format, sections, priorities) |
| Commands | 1 | /cc-later:status — window, gates, queue, recent runs dashboard |
| Hooks | 3 | Stop (dispatch), UserPromptSubmit (capture), SessionStart (compact inject) |
| Scripts | 5 | handler, capture, compact, status, stats |
| Config options | 23 | Plan, paths, dispatch, window, limits, auto-resume, compact, nudge |
LATER.md lives at .claude/LATER.md in your repo root (configurable via LATER_PATH). It is a plain Markdown file:
# LATER
## Auth
- [ ] (P1) fix token refresh in src/auth/service.py
- [ ] (P0) handle expired sessions in middleware
## Payments
- [ ] (P1) add retry logic to webhook handler
- [ ] (P2) clean up stripe client initialization
- [x] (P1) migrate database schema <-- completed, marked by cc-laterEach ## heading defines a group of related tasks. When dispatch fires, one background agent is spawned per section, all running in parallel. The Auth agent and Payments agent above start simultaneously, each in its own git worktree and branch, so they cannot conflict.
Tasks that appear before the first ## header are collected into a single unnamed agent.
- [ ] (P0) <description> <-- urgent: dispatched first within the section
- [ ] (P1) <description> <-- normal priority (default)
- [ ] (P2) <description> <-- nice-to-have
- [!] <description> <-- shorthand for P0
- [x] <description> <-- completed (written by cc-later, not by you)
Priority controls ordering within a section. P0 before P1, P1 before P2. Within the same priority, tasks run in file order. LATER_MAX_ENTRIES_PER_DISPATCH caps how many tasks from each section are selected per cycle.
Add tasks to LATER.md directly from your prompt. The UserPromptSubmit hook watches for these patterns:
| Prompt pattern | Result |
|---|---|
later: fix the auth bug |
Appends as (P1) task |
add to later: update readme |
Appends as (P1) task |
note for later: clean up tests |
Appends as (P1) task |
queue for later: refactor parser |
Appends as (P1) task |
for later: add pagination |
Appends as (P1) task |
later[!]: SQL injection in filter |
Appends as (P0) urgent task |
Multiple captures in one prompt are all appended. Duplicates (case-insensitive substring match) are suppressed.
Captured tasks are appended without a section header. To place them in a specific section, write LATER.md directly.
WINDOW_DISPATCH_MODE controls when the dispatch gate opens.
| Mode | Behavior | Best for |
|---|---|---|
window_aware |
Fires when the current usage window has <= WINDOW_TRIGGER_AT_MINUTES_REMAINING minutes remaining. Requires active JSONL session data. |
Most users -- tasks run near window end, using otherwise-idle capacity |
time_based |
Fires only inside the time ranges in WINDOW_FALLBACK_DISPATCH_HOURS (local time). No window data required. |
Teams with predictable off-hours or deterministic scheduling |
always |
Fires whenever the idle grace period passes. | Development, testing, or continuous dispatch |
All gates fire in order. The first failure skips the cycle.
DISPATCH_ENABLED-- master on/off switch- Idle grace -- at least
WINDOW_IDLE_GRACE_PERIOD_MINUTESsince the last hook run (prevents thrashing) - Weekly budget -- stop if
LIMITS_BACKOFF_AT_PCT% ofLIMITS_WEEKLY_BUDGET_TOKENSis consumed - Mode gate -- fires as described above
The auto-resume gate is evaluated separately and can trigger even when the mode gate is closed.
When DISPATCH_ALLOW_FILE_WRITES=true, cc-later creates an isolated git worktree for each section agent before spawning it. This prevents agents from conflicting on the same files.
dispatch:
timestamp = YYYYMMDD-HHMMSS (same for all sections in one cycle)
for each section:
git worktree add ~/.cc-later/worktrees/{repo}-{slug}-{ts}
-b cc-later/{slug}-{ts}
spawn agent with cwd = worktree path
reconcile (agent finishes):
if branch has no new commits -> skip merge, clean up
git -C {repo} merge --no-ff cc-later/{slug}-{ts}
-m "cc-later: {section} tasks"
if merge OK -> git worktree remove + git branch -d
if conflict -> git merge --abort
preserve worktree, mark tasks NEEDS_HUMAN
log merge_conflict event with conflicting files
When DISPATCH_ALLOW_FILE_WRITES=false (default), no worktrees are created -- agents run in the repo directory and are instructed not to modify files.
cc-later/{section-slug}-{YYYYMMDD-HHMMSS}
Section names are slugified: non-alphanumeric characters replaced with _.
If a merge conflict occurs during reconcile:
- The failed merge is aborted immediately -- the repo is left in a clean state
- The worktree is preserved at
~/.cc-later/worktrees/for inspection - All tasks from that agent are marked
NEEDS_HUMAN - A
merge_conflictevent is logged with branch name and conflicting file list
To resolve manually:
cd ~/.cc-later/worktrees/{repo}-{slug}-{ts}
git diff HEAD~1
cd /path/to/repo
git merge --no-ff cc-later/{slug}-{ts}
# resolve conflicts, then commit
git worktree remove ~/.cc-later/worktrees/{repo}-{slug}-{ts}
git branch -d cc-later/{slug}-{ts}cc-later tracks usage window boundaries without relying on external APIs:
- On each Stop hook: if
remaining <= 0, recordwindow_limit_tsin state. - Next activity after the limit (idle grace has passed): detect the window has reset, set
window_start_tsto now. Clearwindow_limit_ts. - Auto-resume dispatch also sets
window_start_ts(fresh window confirmed by successful dispatch). - First window uses clamp (
now - duration) as a conservative estimate. Subsequent windows use the calibratedwindow_start_tsfor accurate timing.
This means dispatch timing improves automatically after the first window cycle.
When a background agent's output contains rate or usage limit signals ("rate limit", "usage limit", "quota", "429", "5-hour window", "window exhausted", "try again later"), its failed tasks are saved to resume_entries in state.json.
On the next handler run, if AUTO_RESUME_ENABLED=true and (in window_aware mode) at least AUTO_RESUME_MIN_REMAINING_MINUTES remain, those tasks are re-dispatched as a single agent.
Resume dispatch happens before normal section dispatch. The auto-resume agent runs in its own worktree if file writes are enabled.
When NUDGE_ENABLED=true, cc-later monitors dispatched agents for signs of being stuck:
- Stale agents: If a live agent's result file (or dispatch timestamp if no file yet) hasn't been modified for
NUDGE_STALE_MINUTES, the agent is killed (SIGTERM) and re-dispatched with an incremented retry counter. - Dead agents: If an agent's process has exited but produced no output file, it is re-queued for dispatch.
- Max retries: After
NUDGE_MAX_RETRIESattempts, the agent is abandoned and logged asagent_abandoned.
Nudged agents get fresh worktrees (old ones are cleaned up) and the retry count is tracked per agent.
When COMPACT_ENABLED=true, the SessionStart hook (with compact matcher) fires after /compact or auto-compaction. It injects into Claude's context:
- Current window state (remaining minutes, mode, elapsed time)
- All pending LATER.md tasks grouped by section
- In-flight dispatch status
- Auto-resume queue status
This ensures Claude retains awareness of the task queue after context compaction.
uv run scripts/stats.py # default: 7d and 30d
uv run scripts/stats.py 60 # custom single range
uv run scripts/stats.py 7 30 90 # multiple rangesOutput includes per-model breakdowns (input, cache creation, cache read, output tokens), API-equivalent cost at current pricing, session count, and a comparison against Max plan subscription cost.
Supported models: claude-opus-4-6, claude-opus-4-5, claude-sonnet-4-6, claude-sonnet-4-5, claude-haiku-4-5.
Config lives at ~/.cc-later/config.env as plain KEY=VALUE. Comment lines start with #. Created automatically on first run from the bundled template.
| Key | Type | Default | Description |
|---|---|---|---|
PLAN |
string | max |
Your Claude plan. Sets window duration defaults. One of: free, pro, max, team, enterprise. |
| Key | Type | Default | Description |
|---|---|---|---|
PATHS_WATCH |
comma-separated paths | (empty) | Repos to watch. Empty = auto-detect from hook cwd. |
| Key | Type | Default | Description |
|---|---|---|---|
LATER_PATH |
string | .claude/LATER.md |
Path to LATER.md relative to repo root. |
LATER_MAX_ENTRIES_PER_DISPATCH |
integer | 3 |
Max tasks selected per section per dispatch cycle. |
LATER_AUTO_GITIGNORE |
bool | true |
Auto-add LATER_PATH to .gitignore. |
| Key | Type | Default | Description |
|---|---|---|---|
DISPATCH_ENABLED |
bool | true |
Master on/off switch. |
DISPATCH_MODEL |
string | sonnet |
Model for background agents. One of: sonnet, opus, haiku. |
DISPATCH_ALLOW_FILE_WRITES |
bool | false |
When true, agents may edit files directly (each in its own git worktree). When false, agents report findings only. |
DISPATCH_OUTPUT_PATH |
string | ~/.cc-later/results/{repo}-{date}.json |
Path template for agent result files. |
| Key | Type | Default | Description |
|---|---|---|---|
WINDOW_DISPATCH_MODE |
string | window_aware |
One of: window_aware, time_based, always. |
WINDOW_DURATION_MINUTES |
integer | (plan default) | Override window duration in minutes. Leave blank to use plan default (all plans: 300m). |
WINDOW_TRIGGER_AT_MINUTES_REMAINING |
integer | 30 |
(window_aware) Dispatch when <= this many minutes remain. |
WINDOW_IDLE_GRACE_PERIOD_MINUTES |
integer | 10 |
Minimum minutes between dispatch attempts. |
WINDOW_FALLBACK_DISPATCH_HOURS |
comma-separated ranges | (empty) | (time_based) Local-time ranges as HH:MM-HH:MM. Overnight ranges supported. |
WINDOW_JSONL_PATHS |
comma-separated paths | (empty) | Override JSONL paths for window/budget detection. |
| Key | Type | Default | Description |
|---|---|---|---|
LIMITS_WEEKLY_BUDGET_TOKENS |
integer | 10000000 |
Rolling 7-day token budget across all repos. |
LIMITS_BACKOFF_AT_PCT |
integer | 80 |
Pause dispatch at this % of weekly budget consumed. |
| Key | Type | Default | Description |
|---|---|---|---|
AUTO_RESUME_ENABLED |
bool | true |
Re-dispatch limit-failed tasks in the next fresh window. |
AUTO_RESUME_MIN_REMAINING_MINUTES |
integer | 240 |
(window_aware) Only auto-resume when >= this many minutes remain. |
| Key | Type | Default | Description |
|---|---|---|---|
COMPACT_ENABLED |
bool | true |
Inject LATER.md queue into Claude's context after /compact or auto-compaction. |
| Key | Type | Default | Description |
|---|---|---|---|
NUDGE_ENABLED |
bool | true |
Detect and restart stuck/dead dispatched agents. |
NUDGE_STALE_MINUTES |
integer | 10 |
Minutes of no output before an agent is considered stuck. |
NUDGE_MAX_RETRIES |
integer | 2 |
Maximum re-dispatch attempts per agent before abandoning. |
/cc-later:statusExample output:
## cc-later Status
### Window
Mode: window_aware
Elapsed/Remaining: 142m / 158m
Tokens: 84,201 in / 12,450 out
Window ends: 2026-04-06 14:22 PDT
Next window: starts on first Claude request after 14:22 PDT
Weekly budget: 1,240,000 / 10,000,000 (12.4%)
Backoff at: 80% (8,000,000 tokens)
### Queue
myrepo/ [in-flight]
pending: 4
agent [Auth]: pid=84312 branch=cc-later/Auth-20260406-100000
agent [Payments]: pid=84313 branch=cc-later/Payments-20260406-100000
### Gates
dispatch.enabled: pass
mode gate: FAIL
auto-resume gate: closed
budget gate: pass
### Recent Runs
04-06 10:18 dispatch
04-06 09:55 skip idle_grace_active
04-06 09:32 dispatch
04-05 23:41 skip mode_gate_closed
~/.cc-later/
config.env <-- your configuration
state.json <-- in-flight agent and resume queue tracking
run_log.jsonl <-- append-only event log
results/
myrepo-Auth-20260406-100000.json <-- per-agent structured output
myrepo-Payments-20260406-100000.json
worktrees/ <-- only when DISPATCH_ALLOW_FILE_WRITES=true
myrepo-Auth-20260406-100000/ <-- isolated worktree, removed on clean merge
myrepo-Payments-20260406-100000/ <-- preserved on conflict for manual resolution
<repo-root>/
.claude/
LATER.md <-- task queue (auto-added to .gitignore)
Plugin source:
cc_later/
__init__.py
core.py <-- all logic (pydantic models, filelock, pendulum)
scripts/
handler.py <-- Stop hook -> core.run_handler()
capture.py <-- UserPromptSubmit hook -> core.capture_from_payload()
compact.py <-- SessionStart/compact hook -> core.run_compact_inject()
status.py <-- /cc-later:status -> core.run_status()
stats.py <-- Token analytics -> core.run_stats()
default_config.env <-- config template (copied on first run)
hooks/hooks.json <-- Hook definitions (all use uv run --project)
commands/status.md
skills/cc-later/SKILL.md
.claude-plugin/plugin.json
.claude-plugin/marketplace.json
pyproject.toml <-- uv project config + dependencies
uv.lock <-- lockfile
Requires uv.
# Install deps (including test group)
uv sync --group test
# Run all 513 tests
uv run pytest tests/ -v
# Smoke-test the handler without spawning real agents
echo '{}' | uv run scripts/handler.py
# Check status
uv run scripts/status.py
# Token analytics (7d and 30d)
uv run scripts/stats.py| Package | Purpose |
|---|---|
| pydantic | Config models with declarative validation (Literal, Field(gt=0)) |
| pydantic-settings | Env file loading support |
| filelock | Cross-platform file locking (macOS, Linux, Windows, NFS) |
| pendulum | Timezone-aware datetime parsing and arithmetic |
513 tests across 10 modules:
| File | What it tests |
|---|---|
test_config_and_format.py |
Config loading, task/section parsing, priority ordering, mark-done |
test_handler_status_capture.py |
Full capture -> dispatch -> reconcile -> status flow |
test_handler_worktree_state.py |
Worktree creation, merge, cleanup, state management |
test_reconcile_resume.py |
Limit-fail detection, resume scheduling, done-marking |
test_reconcile_nudge.py |
Stale agent detection, dead agent re-queue, retry limits |
test_window_budget.py |
JSONL window calculation, stale row filtering, weekly budget |
test_window_gates_budget.py |
Window gate logic, budget gate, dispatch mode gates |
test_stats_compact_tasks.py |
Stats output, compact injection, task parsing edge cases |
test_utils_and_config.py |
Pydantic validation, utility functions, plan defaults |
test_plugin_layout.py |
Plugin manifest validity, hook config, command presence |