Skip to content

notifications: command-completion for non-Claude long-running tasks #552

@Axelj00

Description

@Axelj00

Question to resolve

Should Clawterm notify on a long-running shell command finishing in a background tab, even when the command isn't an AI agent emitting OSC 9;2?

Concrete example: I run npm test in tab B, switch to tab A. 5 minutes later the tests finish. Today: nothing. Pre-#547 also nothing — the old notifyCommandComplete was actually only wired to OSC 9;2 despite its name.

Why this is a real gap

Background long-running tasks are exactly when you want a notification. AI agents have OSC 9;2; other tools don't. Cargo builds, test runs, deploys — none of them speak OSC. If "Claude is done" gets a banner but "5-minute test suite finished" doesn't, the app feels inconsistent.

Why this is hard to do well

Detecting "command finished" reliably is the terminal-emulator problem. Options ranked by reliability:

A. PID-based idle transition

Watch the foreground process group via tcgetpgrp. When it transitions from "child of shell" → "shell itself", a command just finished. Already half-implemented (tab.ts central poll loop).

Caveats:

  • REPLs (node, python) stay as foreground children but are "idle" between prompts — hard to distinguish from a still-working compile
  • Multi-stage commands (make && ./out) flap rapidly
  • Shells with custom prompts may not register the transition cleanly

B. Output-quiescence

"No PTY output for N seconds while foreground PID is the shell." More reliable than pure PID, less reliable than direct shell integration. Some output during shell prompt rendering can confuse it.

C. Shell integration (OSC 133)

The right answer. OSC 133;A/B/C/D are the shell-integration prompt sequences (zsh/bash/fish all support via plugins). 133;D is "command finished" with optional exit code. We'd:

  1. Detect (or install) shell integration
  2. Listen for OSC 133;D on each pane
  3. Use exit code to differentiate "command finished cleanly" vs "command failed"

Cost: users need to enable shell integration (or we install it). Most terminal emulators (iTerm2, Wezterm, Ghostty, Warp) document this and either auto-install or guide the user.

Proposal

Two-phase:

Phase 1 — opt-in PID-based completion notification

Add notifications.commandCompletion: boolean config field, default false. When enabled, fire a banner when:

  • Tab is hidden (background)
  • Foreground PID transitions back to the shell
  • The previous foreground command ran for >30s (configurable threshold)

Banner reads: Command finished: <last-foreground-process-name> (5m 12s).

Threshold + opt-in keeps the noise floor low. Users who want it turn it on; users who don't aren't surprised.

Phase 2 — OSC 133 shell integration

Detect OSC 133;D, prefer it over the PID heuristic when available. Document shell setup in README. Possibly add a "Set up shell integration" command in the palette that writes the relevant lines to .zshrc / .bashrc / config.fish.

Decision needed

  • Do we want command-completion notifications at all? (Some users hate them; some want them badly.)
  • If yes, opt-in or opt-out default?
  • Phase 2 in scope, or separate?

My recommendation: opt-in, Phase 1 only for v1. Ship Phase 2 if users ask for it. The PID heuristic is good enough for the common "I ran a build, want to know when it's done" case.

Files (if we proceed with Phase 1)

File Change
src/config-types.ts / src/config.ts Add notifications.commandCompletion, notifications.commandCompletionThresholdMs
src/tab.ts Track command start time on foreground PID change; on idle transition, compute duration
src/notifications.ts Add notifyCommandComplete(name, durationMs, tabTitle, tabId) — different from the one we just removed, this one is opt-in and carries real info
src/terminal-manager.ts Wire tab → notifications, with mute + active-tab + pane-focus checks (same gates as OSC)

Files (Phase 2)

File Change
src/osc-handler.ts Add OSC 133 handlers
docs/shell-integration.md New — how to enable
src/command-palette.ts Add "Install shell integration" command

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestuxUser experience and interaction quality

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions