Skip to content

feat: full /loop support — agent self-pacing via ScheduleWakeup interception #289

@nathanschram

Description

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

  1. Detect ScheduleWakeup in JSONL output — when Claude calls ScheduleWakeup during a run, it appears as a tool_use event in the stream-json output
  2. Extract parametersdelaySeconds (60-3600), reason, prompt
  3. After run completes — if a ScheduleWakeup was the last tool call, create a timer in Untether
  4. Timer fires — start a new Claude Code run with the captured prompt, same chat/project context
  5. Loop continues — new run may call ScheduleWakeup again, creating another timer
  6. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions