Agents serve the app through one Braid tool that starts it on the run's port, waits until it answers, shows its log and stops it #110

Closed
opened 2026-09-29 02:36:21 -04:00 by cmoriarty · 1 comment
Owner

What happens

An agent that needs the app running starts it itself. That covers trying an endpoint, and agent.test.browser, whose browser subagent can't start anything (#17). The agent runs nohup … &, loops on sleep and curl until the app answers, then kills or pkills it.

  • In the 8 runs whose logs are still on production (runs 17 to 29), about 156 of 1,474 bash calls (11%) went on this: run 17 55 times, run 22 33, run 23 27, run 25 19 and run 26 18.
  • The app was started with nohup 24 times across those five runs.
  • Twice the port was already taken (runs 17 and 25).
  • Run 17's curls got "connection refused" 12 times while it waited.

Expected

  • Implementation steps have one tool for the app under test. It starts the app on the run's PREVIEW_PORT in the background, waits until it answers HTTP, and returns the URL. If the app exits first, the tool returns the exit code and the end of its log.
  • The same tool reports status, shows the recent log and stops the app. Anything still running when the step ends is stopped.
  • The command comes from the repository: a setting or a pipeline value, like #104's choice of test suite, falling back to the preview or dev script in package.json, and so on.
  • agent.test.browser uses it. A UI check then makes no nohup, sleep or curl calls, and the browser subagent gets a URL that is already answering.

How

  • An opencode custom tool rather than another MCP server. opencode 1.18.21 loads tool/*.{js,ts} from the config folder, and each run's config folder already has the run plugin and @opencode-ai/plugin installed (#67). So the tool needs no extra process and no extra install, and costs one small schema.
  • Lean steps don't get it.

Done when a run with a UI change serves its app through the tool and the browser subagent checks the page. No production run has done that yet: all 6 Playwright calls so far were in run 22 and all failed, before the --browser chromium fix.

Related: #17, #46, #104, and #109, since the app can't be served before its dependencies are installed.

**What happens** An agent that needs the app running starts it itself. That covers trying an endpoint, and `agent.test.browser`, whose `browser` subagent can't start anything (#17). The agent runs `nohup … &`, loops on `sleep` and `curl` until the app answers, then `kill`s or `pkill`s it. - In the 8 runs whose logs are still on production (runs 17 to 29), about 156 of 1,474 bash calls (11%) went on this: run 17 55 times, run 22 33, run 23 27, run 25 19 and run 26 18. - The app was started with `nohup` 24 times across those five runs. - Twice the port was already taken (runs 17 and 25). - Run 17's `curl`s got "connection refused" 12 times while it waited. **Expected** - Implementation steps have one tool for the app under test. It starts the app on the run's `PREVIEW_PORT` in the background, waits until it answers HTTP, and returns the URL. If the app exits first, the tool returns the exit code and the end of its log. - The same tool reports status, shows the recent log and stops the app. Anything still running when the step ends is stopped. - The command comes from the repository: a setting or a pipeline value, like #104's choice of test suite, falling back to the `preview` or `dev` script in `package.json`, and so on. - `agent.test.browser` uses it. A UI check then makes no `nohup`, `sleep` or `curl` calls, and the `browser` subagent gets a URL that is already answering. **How** - An opencode custom tool rather than another MCP server. opencode 1.18.21 loads `tool/*.{js,ts}` from the config folder, and each run's config folder already has the run plugin and `@opencode-ai/plugin` installed (#67). So the tool needs no extra process and no extra install, and costs one small schema. - Lean steps don't get it. **Done when** a run with a UI change serves its app through the tool and the `browser` subagent checks the page. No production run has done that yet: all 6 Playwright calls so far were in run 22 and all failed, before the `--browser chromium` fix. Related: #17, #46, #104, and #109, since the app can't be served before its dependencies are installed.
cmoriarty referenced this issue from a commit 2026-09-29 04:10:17 -04:00
Author
Owner

Shipped in a2131ea, as the OpenSpec change app-tool. It is now archived (9d27890). Its requirements are the new app-tool spec, and browser-check and agent-delegation are updated.

One tool, app. osfd writes it into each run's opencode config folder as tool/app.js. Its arguments are plain JSON Schema, which opencode 1.18.21 accepts, so it needs no install.

  • start runs the command with sh -c in its own process group, with PORT set to $PREVIEW_PORT. It waits up to two minutes for http://127.0.0.1:$PREVIEW_PORT/ to answer, and returns the URL, or the exit code and the end of the log. It refuses a port that something else holds, and restarts an app it started itself.
  • status and logs report on the app, and stop stops its whole process group.
  • An empty command uses the run's App command (#104), or else a dev script at the root or one directory down.

Only where it belongs, and never left running.

  • Only an implementation step's primary gets it; lean steps, the handoff turn and every subagent do not. It adds 1,116 characters to the implementation floor.
  • osfd stops the app when the attempt that started it ends, and when the run's server stops.
  • The browser check, the browser delegation guidance and AGENTS.md say to use it, and never nohup … &.

Scratch's browser check runs. A project now also counts as servable when it has a package manifest one directory down, or the run has an App command. Every scratch run before this skipped the check as "the project cannot be served".

Verified on production with run 33's agent.test.browser:

  • The agent served the app with app in three start and stop pairs, one of them frontend-only to see the page with the backend down. Each start answered in under 2 s, and each stop reported the port free.
  • All 18 of the browser subagent's Playwright calls completed, the first ever to succeed on production, and its three checks passed with screenshots.
  • Afterwards no state file was left, and ports 5201 and 8000 were free.
  • No step of the run started a server by hand.
Shipped in a2131ea, as the OpenSpec change `app-tool`. It is now archived (9d27890). Its requirements are the new `app-tool` spec, and `browser-check` and `agent-delegation` are updated. **One tool, `app`.** osfd writes it into each run's opencode config folder as `tool/app.js`. Its arguments are plain JSON Schema, which opencode 1.18.21 accepts, so it needs no install. - `start` runs the command with `sh -c` in its own process group, with `PORT` set to `$PREVIEW_PORT`. It waits up to two minutes for `http://127.0.0.1:$PREVIEW_PORT/` to answer, and returns the URL, or the exit code and the end of the log. It refuses a port that something else holds, and restarts an app it started itself. - `status` and `logs` report on the app, and `stop` stops its whole process group. - An empty command uses the run's App command (#104), or else a `dev` script at the root or one directory down. **Only where it belongs, and never left running.** - Only an implementation step's primary gets it; lean steps, the handoff turn and every subagent do not. It adds 1,116 characters to the implementation floor. - osfd stops the app when the attempt that started it ends, and when the run's server stops. - The browser check, the `browser` delegation guidance and `AGENTS.md` say to use it, and never `nohup … &`. **Scratch's browser check runs.** A project now also counts as servable when it has a package manifest one directory down, or the run has an App command. Every scratch run before this skipped the check as "the project cannot be served". **Verified on production** with run 33's `agent.test.browser`: - The agent served the app with `app` in three start and stop pairs, one of them frontend-only to see the page with the backend down. Each start answered in under 2 s, and each stop reported the port free. - All 18 of the `browser` subagent's Playwright calls completed, the first ever to succeed on production, and its three checks passed with screenshots. - Afterwards no state file was left, and ports 5201 and 8000 were free. - No step of the run started a server by hand.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cmoriarty/braid#110
No description provided.