Programs running in Solo can report what they're doing with OSC 7501, the program status protocol: working, blocked on you, done, failed, or idle. Solo uses those reports to drive agent activity indicators and attention alerts, and to hold automated messages while a program waits for you.
This is useful when you build a CLI agent, a long-running script, or a TUI and want Solo to know its real state instead of guessing from output.
Send a report
A report is an OSC sequence with key=value pairs separated by colons:
ESC ] 7501 ; key=value:key=value BEL
You can end the sequence with BEL (\007) or ESC \. The whole sequence, from ESC ] to the terminator, can be at most 4,096 bytes.
For example, report that a build finished:
printf '\033]7501;state=done:msg=%s\007' "$(printf 'Build finished' | base64)"
Report that the program is working, then that it's waiting for permission:
printf '\033]7501;state=working:progress=40\007'printf '\033]7501;state=blocked:kind=permission:msg=%s\007' "$(printf 'Allow deploy?' | base64)"
Keys
| Key | Value |
|---|---|
state |
Required. idle, working, blocked, done, error, or clear. |
kind |
Only with blocked: permission, question, or auth. |
progress |
Only with working or blocked: a whole number from 0 to 100. |
id |
Optional record ID, such as build or build/tests. Up to 8 /-separated segments of letters, digits, _, ., +, or -; at most 32 bytes per segment and 128 bytes in total. |
app |
Optional program name, up to 32 bytes. |
title |
Optional notification title, base64-encoded UTF-8, up to 192 bytes once decoded. |
msg |
Optional notification message, base64-encoded UTF-8, up to 2,048 bytes once decoded. |
Keys are lowercase. Base64 padding is optional. Solo rejects a report that is missing state, uses an unknown state, or breaks a length limit; it ignores keys it doesn't recognize.
Failure is reported as state=error.
Records and clearing
Each report replaces the record for its id. A report without id sets the program's root record, so a simple program never needs one. Programs that track several tasks can give each its own ID.
state=clear removes records instead of setting one:
- With an
id, it clears that record and everything under it.state=clear:id=buildclearsbuildandbuild/tests, but notbuilder. - Without an
id, it clears every record for the terminal.
Check for support
To find out whether the terminal supports the protocol, send the feature query:
ESC ] 7501 ; ? BEL
Solo answers with the same sequence, using the terminator your query used. This reply is the only data the protocol ever writes back to the program.
How Solo uses reports
Activity
For agents and terminals, working and blocked reports take precedence over Solo's own activity heuristics. A program that reports working stays busy through quiet periods, and a blocked program isn't shown as working even while it redraws the screen. When no working or blocked record remains, Solo goes back to its usual detection.
Attention
A record that newly becomes blocked, done, or error, or whose blocked kind changes, marks the process as needing attention and can send a notification. Repeating the same report or updating progress doesn't alert you again.
The notification title is the record's title, or app when there's no title. The message is msg, or a default based on the state:
| State | Default message |
|---|---|
blocked with kind=permission |
Waiting for permission |
blocked with kind=question |
Waiting for an answer |
blocked with kind=auth |
Waiting for sign-in |
blocked without kind |
Waiting for input |
error |
Failed |
done |
Finished |
When the record leaves that state, for example the program reports working again, Solo removes the attention it raised. Other unread notifications for the process stay.
Program status alerts follow the same rule as BEL and other OSC alerts: they only appear when the effective notification level for the project and process is All.
Automated messages
While a program reports blocked, Solo holds timer and MCP messages for that process and delivers them after it continues. For idle-triggered timers, a blocked process counts as idle, because it's waiting on you.
When records expire
working,blocked, andidlerecords end when the program's process exits, when a new shell prompt starts, and when the terminal is reset.doneanderrorrecords survive the process exiting, so a finished or failed result stays visible.- Starting a new run of the process starts with no records.