Skip to content

[FEATURE]: add wait built-in tool with countdown in footer #50041

Open

Description

@lowern1ght

[FEATURE]: add wait built-in tool with countdown in footer

Summary

Add a Core built-in wait tool that blocks for N seconds while publishing
Tool.Progress updates, and render a countdown in the TUI footer instead of
the generic spinner.

Why

Claude Code has a WAIT tool that blocks (in tool-call queue, async to the
agent loop) and shows countdown in footer — useful for:

  • CI / deployment wait loops (wait N seconds then check status)
  • Avoiding busy-poll bash: sleep 1; check
  • First real consumer of the Tool.Progress event (currently defined but unused)

We already have all the infrastructure:

  • Tool.Progress event schema (packages/schema/src/session-event.ts:331-340)
  • TUI footer spinner (packages/tui/src/component/prompt/index.tsx:1515-1594)
  • App reducer already handles session.tool.progress (packages/app/src/context/server-session-v2-reducer.ts:276)
  • Tool.make + permission.assert pattern (see webfetch.ts)
  • Effect.gen for time-based orchestration
  • Async tool execution via FiberSet.run (packages/core/src/session/runner/llm.ts:278) — wait runs in parallel with sibling tool calls in the same turn, like all other tools

Proposed contract

Input:  { seconds: 1..600, reason?: string }
Output: { waited: number, reason?: string }

Hard cap 600s to discourage wait(seconds=86400) (Claude Code removed wait
after abuse — same model here).

Implementation sketch

  1. packages/core/src/tool/wait.ts — new built-in
    • Effect.gen with 1Hz ticker publishing Tool.Progress with { remainingSeconds, totalSeconds, reason } in structured/metadata
    • permission.assert({ action: "wait", resources: [] }) — every call requires approval unless allowlisted (same as webfetch)
    • Built-in registered in packages/core/src/tool/builtins.ts + new location node
  2. packages/tui/src/component/prompt/index.tsx — match progress.structured.type === "wait" → ⠋ 12s remaining (reason); fallback to generic spinner for non-wait tools
  3. packages/app/src/... — RunningToolPart (or wherever running tool is rendered) reads metadata; if structured.type === "wait" show 12s remaining. App reducer already passes metadata through (packages/app/src/context/server-session-v2-reducer.ts:282).
  4. Tests: extend packages/core/test/session-tool-progress.test.ts with wait-specific cases (cap enforcement, permission gating, progress event cadence)

Out of scope (future)

  • Stage 3: URL polling source (wait({ url, expect: 2xx }))
  • Stage 4: pluggable sources via opencode.tools.register

Open questions (to resolve during impl)

  1. How exactly to publish Tool.Progress from inside Tool.make execute — the publisher lives in runner/publish-llm-event.ts; need to verify the channel exposed to tool leaves. May need a new lightweight ctx.progress.emit(structured) accessor.
  2. Permission resource for wait (webfetch uses URL; wait has no resource — []?).
  3. Footer vs timeline rendering trade-off (TUI has both — pick one or both).

Activity

  1. opencodejr commented on Oct 28, 2026

    @opencodejr
    Contributor

    Thanks for the detailed proposal! You're asking for a built-in wait tool that blocks for a set number of seconds (capped at 600), reports its progress, and shows a countdown like 12s remaining (reason) in the TUI footer and the app instead of the generic spinner. That would replace bash sleep polling in CI and deploy loops.

    One small correction: tool progress is already used. The subagent tool reports progress, and plugin tools get ctx.progress(...). So a plugin could already provide a wait tool. What it can't do is show the countdown in the footer, because the footer only shows a generic spinner for running tools.

    Related issues:

    Maintainers will look at this and decide whether to add it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions