feat: emit OSC 9 progress for reliable agent status detection (herdr integration)
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 19.9k
- Forks
- 2.3k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 30
Description
Problem
Herdr currently detects jcode's agent state using only screen-scraping (TOML manifest regex/contains rules). This is fragile because:
- Spinner frames change —
⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏are matched per-frame, but any visual change breaks detection - Status text is version-dependent —
"sending…","thinking…","running tool"labels change between jcode releases - False positives — generic words like
"permission","allow","deny"appear in conversation text - No transcript viewer rule — scrollback text can confuse state detection
- Stale text handling — requires complex
bottom_non_empty_lines(N)+notgate tuning
How reliable agents do it
Every well-detected agent (codex, claude, opencode, kilo) uses OSC sequences as the primary detection path, with screen-scrape as a lower-priority fallback. jcode currently emits none.
Herdr captures two OSC channels from the terminal stream:
- OSC 0/2 (terminal title) →
osc_titleregion in manifests - OSC 9 (progress) →
osc_progressregion in manifests
Proposed solution
Emit structured OSC 9 progress sequences with a stable, version-independent payload when the TUI's ProcessingStatus changes:
Working: ESC ] 9 ;jcode:working BEL
Idle: ESC ] 9 ;jcode:idle BEL
Blocked: ESC ] 9 ;jcode:blocked BEL
Implementation
tui_lifecycle_runtime.rs—emit_agent_status_osc()method that writes the OSC 9 escape sequence to stdout, with dedup so it only emits on state transitions (safe to call on every redraw)run_shell.rs— callemit_agent_status_osc()on every completed spinner framelocal.rs— call it when a turn finishes (→ idle)jcode-tui-permissions/src/lib.rs— emitjcode:blockedwhen the permissions viewer opens andjcode:idlewhen it closes (the main TUI is paused during permission prompts)app.rs/tui_lifecycle.rs—last_osc_statefield for dedup tracking
Test coverage
Unit tests verify:
- Idle state when not processing
- Working state when processing
- Dedup skips repeated same-state calls
- State transitions emit correctly (working → idle → working)
- Suppressed in replay mode
- Suppressed when terminal title updates are off
Benefits
- Version-stable —
jcode:workingstring never changes even if UI text changes - No false positives — structured payload can't appear in conversation text
- No stale text issues — OSC is a live signal, not screen-scraped
- Cheap — one escape sequence per status change, negligible overhead
- Backward compatible — screen-scrape rules remain as fallback
- Consistent with ecosystem — matches codex/claude OSC-first approach
Reference branch
Changes available at: https://github.com/alecuba16/jcode/tree/herdr_detectable
Commit: acb185a3 — feat: emit OSC 9 progress for herdr agent status detection
Files changed (6 files, +172 lines)
crates/jcode-tui-permissions/src/lib.rs | 21 +++
crates/jcode-tui/src/tui/app.rs | 2 +
crates/jcode-tui/src/tui/app/local.rs | 1 +
crates/jcode-tui/src/tui/app/run_shell.rs | 5 +
crates/jcode-tui/src/tui/app/tui_lifecycle.rs | 2 +
crates/jcode-tui/src/tui/app/tui_lifecycle_runtime.rs | 141 +++++++++++
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with crates/jcode-tui/src/tui/app/tui_lifecycle_runtime.rs and inspect the related changes in app.rs, tui_lifecycle.rs, run_shell.rs, local.rs, and jcode-tui-permissions/src/lib.rs. Run the relevant unit tests for status emission and confirm that OSC 9 transitions, deduplication, replay suppression, and terminal-title settings behave as described.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- cli
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100