Repository navigation
feat(computer): each computer app runs its own server, which launches it and says when it's ready - #385
Merged
earakely-scale merged 7 commits intoOct 29, 2026
Conversation
Base automatically changed from
edgararakelyan/fd-4366-m09-load_artifact-and-run_code-inside-the-computer
to
main
October 29, 2026 15:04
A computer app's launch and readiness, which M1.1 declares, now act. The composer writes each app's .agentenv/app.json and, with a launch, a launch script, a launcher and, for a boot app, an XDG autostart entry. The SDK runtime counts each app that starts with the computer in computer-ready: by a window matching launch.window (a new list_windows operation, with a Linux default over xprop and the reference driver's over python-xlib), a port, a command, or its @ready_check methods, run in the app's venv by _ready. A deploy, a reset and the probe wait up to the slowest boot app's own timeout. Declarations whose readiness can't be checked are refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
earakely-scale
force-pushed
the
edgararakelyan/fd-4368-m15-app-launch-and-readiness
branch
from
October 29, 2026 15:25
1f3e1aa to
8b2a455
Compare
An app's ComputerAppEnvironment class now runs on the computer as the app's own server (serve_app), in the app's venv, on .agentenv/server.sock in its folder. It serves the app's card with computer-app/v1: the app's launch as params, launch, and ready, which checks the app's window, port, command and @ready_check methods in-process, each within 10 s. Once the desktop session is up it adds the app's launcher to the session user's menu, which launches through the server, and launches a boot app once per boot. What it does in the session is the SDK's per-OS session module. The driver finds apps by their sockets: computer-ready needs every app's server to answer, each boot app and each app with no launch to be ready, and a demand app once launched. list_windows leaves the driver contract, and app.json, the launch script, the XDG entries and _ready go. The composer gives every app a venv with the protocol's new app extra (mcp, uvicorn) and its server as a supervisord program, and put refuses an app whose install leaves out its class's file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
earakely-scale
marked this pull request as ready for review
October 29, 2026 16:48
…start An app's server ran its checks one after another and the driver asked each app in turn, while a deploy gave the whole computer-ready status 10 s, so one slow check timed the status out and the deploy's error stopped naming the app. Checks now run at once in the server, each still within 10 s, the driver asks every app at once and counts a server as not answering after 15 s (ANSWER_TIMEOUT_S), and the deploy's status call allows 30 s. A server that can't start writes why to .agentenv/server.failure in the app's folder, cleared at each start, and the driver reports it instead of "its server isn't answering yet". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and xprop's titles A restarted app server now finds a demand app it launched as well as a boot one: every launch marks /run/agentenv/apps/, so the driver keeps counting the open app. A sync @ready_check past its bound keeps running in its thread, which can't be stopped, so a later poll waits on that call instead of starting another, and polls can't fill the worker threads. The session reads window titles and classes without xprop's escapes, so a title with quotes matches, and kills xprop when a window check is cut short. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…readiness What an app's server does moves out of app.py into app_runtime.py, as a driver's does into runtime.py: AppRuntime holds its state, launches the app and runs its checks, and the class keeps thin launch and ready methods and the declaration. A subclass whose __init__ skips super().__init__() now fails at start, saying so in .agentenv/server.failure. The ready answer is an AppReadiness the server dumps and the driver validates. Whether the app was launched comes from its boot mark alone, and its clock from the mark's time, so a restarted server no longer restarts the app's clock. The driver and the launcher take the computer-app/v1 endpoints from the app's card instead of building them, and checks run as coroutines rather than lambdas. The serve_app startup tests join the serve tests, sharing one import-isolation fixture. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s match The app server's start in the desktop session ran as a background task whose error nobody read, so a launcher it couldn't add left readiness at "not launched yet" until the deploy timed out. A start that fails now stops the server, which writes the error to .agentenv/server.failure and exits, and the driver reports it as for any server that can't start, a demand app's too. A failed launch is still reported by readiness. The session reads a window's title from WM_NAME when it sets no _NET_WM_NAME, as older X11 apps do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
earakely-scale
deleted the
edgararakelyan/fd-4368-m15-app-launch-and-readiness
branch
October 29, 2026 19:50
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
M1.5 of the CUA env epic (FD-4345): a computer app starts and says when it's ready, FD-4368. It follows the design doc CUA Env M1.5: App Launch and Readiness, with all seven choices decided, and the full example of an app in this design, M1.5 example app.
Each computer app is its own server. The app's
ComputerAppEnvironmentclass runs on the computer as a server that serves the app's card. It launches the app into the desktop session and says whether the app is ready. The driver finds each app by its server's socket and asks it. Nothing here is specific to XFCE, so another base image or OS brings only its own session module.What's in it
The protocol (
agentenv_protocol.computer):An app's own server (
serve_app.py, its work inapp_runtime.py'sAppRuntime, as a driver's is inruntime.py). The computer's init runspython -m agentenv_protocol.computer.serve_app <file>:<Class>from the app's folder, in the app's venv. The server serves the class's card and tools on the Unix socket.agentenv/server.sockin that folder, with a new extension,computer-app/v1:launch;launch(POST): starts the app in the desktop session;ready(GET): returns anAppReadiness:ready,problems,launched,waited_sandtimeout_s. It runs the app's checks at once when asked: a window matchinglaunch.window, a port answering on loopback, a command exiting 0, and each@ready_check. Each check is in-process with a 10 s limit; a sync check runs in a thread, one call at a time even past its limit, and an exception becomes a problem.Once the desktop session is up, the server:
~/.local/share/applications). The launcher runspython -m agentenv_protocol.computer.launch <folder>, which asks the server to launch the app, so the server starts every copy of it;bootapp, once per boot. Every launch, at boot or on demand, is marked in/run/agentenv/apps/. The mark is the one record of the launch, and the app's clock runs from its time, so a server that restarts takes the app as launched, keeps its clock and leaves it alone.A server that can't start says why: it writes the error to
.agentenv/server.failurein the app's folder, cleared at each start, and the driver reports it in place of "its server isn't answering yet". A start in the session that fails (adding the launcher, say) stops the server the same way, so supervisord retries it.The session (
session.py) holds what the server does in the desktop session, the Linux way: wait for it, launch into it in a session of its own, add a launcher, and list windows withxprop, titled by_NET_WM_NAMEorWM_NAME. Another OS type brings its own.computer-readyasks every app's server at once (apps.py), on the socket in each folder under/opt/agentenv/apps, at the endpoints its card advertises, and counts one as not answering after 15 s:bootapp, and each app with no launch, must say it's ready;demandapp counts once something launches it.A failing check says what it still waits on: "not ready yet, N s in", or once past the app's
timeout_s, "not ready after N s". The app's clock starts from its launch.A new
appextra:agentenv-framework-protocol[app], with mcp and uvicorn.Refused declarations:
Readythat waits on nothing;launch.windowto match;launch.windowthat matches by anything but class, instance or title._declarereports a pydantic error on one line, sinceputshows its last line.agent-env:
appextra, plus the app's own requirements if it names any;app-<name>, beside its services,app-<name>-<service>;.agentenvfolder owned by the session user.bootapp'stimeout_splus 30 s (boot.ready_timeout). Eachcomputer-readystatus call may take 30 s, the driver's own checks and then the apps' servers.Testing
tst/unit), and 887 passed in the protocol's tests.test_computer_app_server.py, with real uvicorn servers on Unix sockets):@ready_check;bootapp launched once per boot across a server restart, and ademandapp's launch kept across one;bootapp not yet ready, then "not ready after", and ademandapp that counts once it's launched through the launcher.xpropparse without its escapes, and anxpropcut short being killed.appextra, from a release or from this checkout;ready_timeout;tst/integration/computer, laptop arm64, real Docker): 21 passed and 1 skipped (the agent task, which needs a model endpoint). The fixture app has no requirements of its own. Its server launches a Tk window of classNotesatboot, and a@ready_checkwaits for its service's file. Deployed alone,computer-readyreports "app notes" ready, the launcher is in the session user's menu, and the app is marked launched.computer-readyreports "app notes" not ready, with "no window with class 'Notes'".modal_vm.🤖 Generated with Claude Code


Confidence Score: 5/5
The PR appears safe to merge; both numbered findings are addressed and no new actionable issue was found.Summary
Each computer app now runs its own server to launch the app and report readiness.
No new actionable issues were found. Tests were read but not run.
Diagram
sequenceDiagram participant Init as Computer init participant App as App server participant Session as Desktop session participant Driver as Computer driver Init->>App: Start server App->>Session: Wait for session and add launcher App->>Session: Launch boot app unless already marked Driver->>App: Read card and request readiness App->>Session: Check window, port, command, and custom checks App-->>Driver: Readiness and launch state Note over App,Driver: Startup errors are written to server.failureReviews (6) · Last reviewed commit: "fix(computer): a failed app start stops ..." · Reviewed by Greptile