Context
Claude Code has a /loop feature that lets the agent run repeatedly with self-paced delays. The agent calls the ScheduleWakeup tool to say "wake me up in N seconds with this prompt," and the Claude Code runtime creates a timer that fires a new session when it expires.
Through Untether, /loop doesn't work — each Untether run is a single CLI invocation that exits when done. There's no mechanism to detect the agent's wakeup request and schedule the next run.
Proposal
Intercept ScheduleWakeup tool calls in the Claude Code JSONL stream and implement the timer loop within Untether.
How it would work
- Detect ScheduleWakeup in JSONL output — when Claude calls ScheduleWakeup during a run, it appears as a tool_use event in the stream-json output
- Extract parameters —
delaySeconds (60-3600), reason, prompt
- After run completes — if a ScheduleWakeup was the last tool call, create a timer in Untether
- Timer fires — start a new Claude Code run with the captured prompt, same chat/project context
- Loop continues — new run may call ScheduleWakeup again, creating another timer
- Loop ends — when a run completes without calling ScheduleWakeup, the loop stops
User experience
User: /loop Check if the build passed
Claude: [checks build, still running]
ScheduleWakeup(delay=270, reason="build still running, check in 4.5 min")
→ Untether shows: "⏳ Next check in 4m 30s"
[4.5 minutes later]
Claude: [checks build, it passed!]
→ No ScheduleWakeup → loop ends
→ "Build passed! ✅"
Controls
/loop stop or /cancel to abort a running loop
- Max iterations cap (configurable, default 20) to prevent runaway loops
- Max total duration cap (configurable, default 4 hours)
- Cost tracking across all iterations
- Show loop iteration count in progress: "Loop iteration 3/20"
Implementation areas
| Area |
Work |
| Claude JSONL parsing — detect ScheduleWakeup tool_use |
runners/claude.py |
| Timer management — schedule next run after delay |
telegram/loop.py or new loop_manager.py |
| Loop state tracking — iteration count, total cost, stop signal |
New state object |
/loop command — parse arguments, start first run |
commands/ |
/loop stop — cancel pending timer and running task |
commands/ |
| Progress display — show timer countdown, iteration count |
markdown.py |
| Tests |
Substantial — JSONL parsing, timer logic, cancellation |
Effort estimate
~8-12 hours for a basic implementation (Claude engine only). Extending to other engines that support similar loop mechanisms would be additional work.
Engine support
- Claude Code — primary target, has ScheduleWakeup
- Other engines — would need their own loop detection or a generic "re-run after delay" mechanism
Related
Context
Claude Code has a
/loopfeature that lets the agent run repeatedly with self-paced delays. The agent calls theScheduleWakeuptool to say "wake me up in N seconds with this prompt," and the Claude Code runtime creates a timer that fires a new session when it expires.Through Untether,
/loopdoesn't work — each Untether run is a single CLI invocation that exits when done. There's no mechanism to detect the agent's wakeup request and schedule the next run.Proposal
Intercept
ScheduleWakeuptool calls in the Claude Code JSONL stream and implement the timer loop within Untether.How it would work
delaySeconds(60-3600),reason,promptUser experience
Controls
/loop stopor/cancelto abort a running loopImplementation areas
runners/claude.pytelegram/loop.pyor newloop_manager.py/loopcommand — parse arguments, start first runcommands//loop stop— cancel pending timer and running taskcommands/markdown.pyEffort estimate
~8-12 hours for a basic implementation (Claude engine only). Extending to other engines that support similar loop mechanisms would be additional work.
Engine support
Related
/atcommand,run_onceflag) — simpler v0.35.1 building blockScheduleWakeuptool — the upstream feature this intercepts