aaif-goose / aaif-goose/goose

feat(tasks): unified task registry + tasks platform extension (background processes, timers, wait_for wake-ups)

Open
#11,740 2 comments 0 reactions 1 assignee Claimed by @jamadeo View on GitHub
Dominant language
Rust
Stars
54.2k
Forks
6.2k
Avg merge
3d 2h
Merged PRs (30d)
262

Description

## What problem would this solve?

Long-running work is a first-class citizen in agent-driven development — builds, test suites, dev servers, watchers, interactive programs (debuggers, REPLs), and scheduled follow-ups. Today goose has no first-class way to run that work in the background while the conversation continues:

- **Blocking work blocks the whole turn.** `developer`'s shell tool is synchronous: a 20-minute build freezes the conversation, and the user cannot interact until it finishes.
- **Every async mechanism is siloed.** Async behavior exists only inside `summon` (async `delegate` subagents, with peek mode / structured metadata / stale eviction), the recipe scheduler, and the desktop notification for finished tasks. There is no shared substrate — processes, timers, resource subscriptions, and agent scheduling each track their own lifecycle, if they track one at all.
- **Results are invisible between turns.** Nothing wakes the agent when background finishes. On the CLI, output of still-running work is invisible until something polls it; pattern-matching on "the server is up" or "the build finished" cannot trigger progress.
- **No interactivity with running work.** There is no way to send input to an already-spawned interactive program (a REPL under test, `ssh`, `gdb`), no cancel-with-partial-output, no structured lifecycle — every ad-hoc `&`-backgrounded shell call is fire-and-forget text.

This is table stakes elsewhere in the ecosystem. Agent harnesses are converging on managed task frameworks precisely so the LLM can keep interacting with the user while long work runs in the background: Claude Code's background `bash` commands with output polling and completion notifications, OpenAI Codex's long-horizon/cloud tasks, Cursor's background agents (async cloud coding sessions while the user keeps working), Kiro's hooks/steering for long-running flows. Meanwhile MCP itself just standardized the pattern — the MCP Tasks extension (`io.modelcontextprotocol/tasks`, spec: modelcontextprotocol.io/extensions/tasks/overview, from SEP-1686 *Tasks* / SEP-2663, now shipping in the 2026-07-28 spec). Goose's CLI currently offers no equivalent surface beyond subagent delegation.

## What would a good outcome look like?

A unified **task registry** in the agent runtime, with a small platform extension exposing it to the model:

- `start_task` — process tasks (shell command, optionally PTY), timer tasks (scheduled reminders); the registry is the substrate, subagent scheduling remains `summon`'s `delegate` (see approaches)
- `read_output` / `send_input` — inspect output (truncated with line/byte limits and the on-disk log path), feed stdin / signals to running processes (interactive programs, PTY)
- `wait_for` / pattern notifications — a pattern match (stdout or stderr, including prompts without trailing newlines) wakes the model: e.g. "start the dev server with `wait_for: 'listening on'`, then keep answering me"
- `cancel_task` / `get_task` / `list_tasks` — lifecycle management with consistent states (Working → Complete/Failed/Cancelled, plus InputRequired)
- **Completion notifications between turns** with a configurable per-task interrupt policy — a finished task becomes a system notification the model can act on

The end state: an agent can kick off a long build, keep helping the user, get woken when it finishes (or when a pattern appears in its output), read the tail, decide what to do next — across processes, timers, and (later) MCP task-bearing servers and subagents, all under one registry.

## Possible approaches

**Scope: registry + processes/timers first.** The `TaskSource` enum should reserve the full space (`Subagent`, `Process`, `McpResource`, `McpTool`, `SwarmAgent`, `Timer`) but the initial surface should be only what is validated end-to-end: process, timer, and the subagent correlation seam.

**Relationship to summon.** Async `delegate` already exists with peek mode, structured metadata, and stale eviction; #11539 is redesigning subagent scheduling around session-correlated children. The registry should be the shared substrate summon reports through (TaskSource::Subagent has to track #11539), not a competing scheduler.

**Relationship to MCP Tasks (the `io.modelcontextprotocol/tasks` extension).** The proposed lifecycle and tool surface deliberately mirror the MCP Tasks extension (SEP-1686 → SEP-2663; current spec at modelcontextprotocol.io/extensions/tasks/overview): created → Working → terminal state (`working`/`input_required`/`completed`/`failed`/`cancelled` — matching our TaskState one-to-one), `tasks/get`/`tasks/cancel`/list-equivalents, results fetched by task id, the call-now/fetch-later contract, and even mid-flight `input_required` matching our InputRequired. `TaskSource::McpTool` / `McpResource` are already reserved so MCP servers implementing the Tasks extension can surface through the same registry and tool surface as native process/timer tasks, rather than each MCP server reinventing backgrounding against the model — and this complements #11208 (goose as a Tasks-consuming *client*): client-side support handles MCP-server tasks, the registry gives both native and MCP-task sources one shared substrate and tool surface.

**Notification delivery — the open design question.**
- Within a running turn / between turns, the state machine can drain finished tasks and emit system-notification messages (`TaskNotificationOperation`), and background task events can steer a run that is already active. A prototype on branch `feat/tasks` implements and tests this (between-turns operation in both agent-loop paths).
- **The CLI input loop is currently blocking**: there is no mechanism today for a background event to *interrupt* an idle prompt. The prototype's interim answer is pragmatic: when the user submits their next message, pending completion notifications are drained and prepended as inline system notifications on that user message (validated working; see prototype). This is lossy on latency, not correctness — the model sees everything, just batched at the next turn.
- A more capable TUI (async input loop) could accept user input and steers *and* wake on task events concurrently. That is a nontrivial input-model change (rustyline blocking read; compare Zed's approach) and we should discuss whether forced-turn/steer semantics apply to the CLI, ACP hosts (#11320 currently drops out-of-prompt updates over ACP), and what an idle-wake UX looks like.

**Permissions.** `start_task` spawns arbitrary processes; it rides the standard permission flow (needs-approval default + read-only judge), nothing auto-allows it. Worth confirming in review that background spawns are comfortable with that default, since a denied spawn is cheap but a backgrounded one is less observable than a foreground call.

**Integration as the concept matures.** If this becomes the core async substrate, natural follow-ons: `developer`/shell spawning through the registry (backgrounded shell + `wait_for` in one place), `summon` async delegates surfacing completion through the registry, scheduler jobs appearing as timer/task entries, and ACP hosts subscribing to task completion events instead of polling.

## Additional context

**History and scope of this proposal.** I have been developing and maintaining this capability locally for some time — a working registry and task extension with process/timer/steering semantics — and have discussed it informally on the goose Discord in the past. I am now formalizing it as this scoped feature request rather than landing a broad branch cold, deliberately narrowing the surface to processes + timers and explicitly tracking the agent-loop unwinding work underway (#11539 and related) so the Subagent source and notification semantics align with that effort rather than competing with it. The prototype is feature-frozen until this reaches Ready; I'd rather converge the design first.

**Prototype exists.** A working implementation is on my fork under the branch `feat/tasks` (single commit, rebased on current `main`): unified registry (`crates/goose/src/tasks.rs`), platform extension with the six tools above (`agents/platform_extensions/tasks/`), process hardening (stdout+stderr `wait_for`, partial-line/prompt matching, PTY, truncation with log path), `TaskNotificationOperation` wired in both agent-loop paths, per-session temp log dirs, GC with cancellation, and 6 integration tests (lifecycle, output truncation, stdin, wait_for on stderr, partial-line matching). `cargo check`/clippy/tests green on current main. Happy to open the PR once this reaches Ready — the issue above describes the outcome, the PR carries the implementation.

**Prior art inside goose:** summon async delegates + peek (#9519, #9518, #9521, #9514), scheduler recipes, GOOSE_MAX_BACKGROUND_TASKS, desktop finish notification (#8647), goose-steer (CLI #steer / state machine steer ops).

**Related ecosystem:** Claude Code background bash (Ctrl+B) + background agents; Codex long-horizon/cloud tasks; Cursor background agents; Kiro steering/hooks; MCP Tasks extension (call-now, fetch-later, modelcontextprotocol.io/extensions/tasks/overview). All are moving toward "the LLM manages long-running work while the human keeps talking to the harness"; goose's interactive CLI currently cannot do this cleanly.

**Related goose issues:** #11208 (Support MCP Tasks — goose client-side support for the Tasks extension, modelcontextprotocol.io/extensions/tasks/overview; this registry is where MCP server tasks would surface, with TaskSource::McpTool/McpResource reserved for exactly that), #11020 (closed: Tasks-extension client reachability — protocol pinning fixed; that reporter's own goal was "notifications land in goose when long-running async tasks complete," confirming demand), #11194 (MRTR input_required — complements InputRequired task state), #11320 (out-of-prompt ACP updates dropped — affects notification delivery to ACP hosts), #11539 (subagents in the unrolled agent loop — alignment target for the Subagent source), #11399 and #11122 (shell permission/output concerns adjacent to process tasks), summon task features listed above.

**Prior requests for this exact capability:** #1748 "Background tasks" (closed as completed by scheduler + subagents — neither actually backgrounds foreground work; the multi-tab workaround remains for processes), #6871 "developer 'launch' for background tasks" (closed as duplicate of #1748; its four-function ask — launch/enumerate/read-logs/kill — is a subset of this proposal's start/list/read_output/cancel), #8607 (completed; desktop notification only).

- [x] I have verified this does not duplicate an existing feature request (searched open+closed for: background/async task, task registry/manager/platform, long-running, timer, wait_for/steer, MCP Tasks/SEP-1686; closest historical are #1748/#6871 — see Prior requests above — both predate the unified-registry/steerable-notification design and neither is equivalent)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.