You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Expose live visibility (matching console UI) for apply-pipeline agents (Tailor/Runner) over MCP #971
Problem:
The application pipeline (Application Tailor and Application Runner / Job Application Assistant) has no MCP-level visibility into what's actually happening during a tailoring or filling run. list_applications / get_application only expose a static status field (e.g. "tailoring", "filling", "blocked"), with no equivalent of coding_session_capture / coding_timeline that coding agents get.
However, the console UI already shows live progress for these browser-driving apply agents while a run is in progress. That same data is not exposed through MCP.
Request:
Add an MCP tool (or extend get_application) for Tailor and Runner instances that surfaces the same live run detail already rendered in the console UI — what the agent is currently doing/seeing in its browser or tailoring session — in real time, analogous to coding_session_capture/coding_timeline for coding agents.
Context: this was raised after two application tailoring runs were blocked with runner_rejected ("already tailoring 1 application(s) for this agent, limit 1") with no way to inspect what the active run was doing, or how close it was to finishing, short of polling get_application's status field.
Filed from owner feedback on instances 19b2e410-394a-4485-b832-6005356e7766 (Application Tailor) and 2e85124f-4946-49d2-b922-8636ba92ca6a (Application Runner).
Concrete real example of this gap, from application 435d31c8-01a4-48d7-87f2-08584fa6d02e (Head of Engineering @ Business AI Group):
Tailoring (Application Tailor, instance 19b2e410-394a-4485-b832-6005356e7766) completed cleanly — résumé + cover letter written, 36/36 claims matched, run.ended status completed.
The application then handed off to the Application Runner (instance 2e85124f-4946-49d2-b922-8636ba92ca6a) to fill the SEEK application form. application_trace for this run shows only: run.requested → policy.submit_gate → runner.dispatched → source.read → engine.started → engine.ended (exitCode 0) → run.ended (status: blocked, reason: incomplete).
That is the ENTIRE record of a 51-second browser session. There is no indication of: which page(s) it navigated to, which form fields it filled or attempted to fill, where in the form it stopped, or why it considered the submission incomplete.
Critically: the console UI for this same run DOES show screenshots and what looks like a transcript of the browser session while/after it ran. That data exists and is being captured — it is simply not exposed through any MCP tool. application_trace and get_application only ever surface the coarse lifecycle/engine events above, never the page-by-page or field-by-field browser actions the UI renders.
This is the exact case the Runner should expose via MCP: when a fill run ends blocked/incomplete with no code-level error, the owner currently has no way via API/MCP to find out what the agent actually did on the site before stopping — they'd have to go look at the console UI screenshots/transcript by hand. Whatever backs that UI view (screenshots, page transcript, step log) should be readable through MCP, the same way coding_session_capture/coding_timeline expose a coding agent's terminal.
Implemented in 2b9a2fd — four read-only MCP tools, live where the route is live.
Tool
Answers
Live?
application_runs
a Runner's fill runs, newest first — which run holds the concurrency slot
—
application_run
ONE fill run as it stands now (the coding_session_capture counterpart)
yes
application_run_supervision
each checkpoint's facts + the one directive recorded for it
yes
tailoring_run
a Tailor's run: policy, result, trace
yes, while running
application_run returns the run's status, pause (what it waits for and the questions it asked), policy with mode/limits/allowed domains and every submit-gate check with its verdict, result (outcome, fields filled, uploads, whether a submit was attempted), engineAuth, runnerNode, errors, timings, and the runner event trace — browser.navigated, field.filled, artifact.uploaded, policy.decision, browser.blocked, submit.*, supervisor.* — each with its runnerSeq, plus the application and its lifecycle audit. tailoring_run carries artifact handles, never résumé or cover-letter text.
The three live reads pull the owner's machine before answering, so a just-emitted event is already in the reply. All four are reads: scope read, GET only (asserted in the test) — a live view starts, resumes and dispatches nothing.
The gap was real, and it was exactly this: not one MCP tool reached /application-runs/* or the Tailor's /applications/:id. Everything above was HTTP-reachable and reachable nowhere else.
Two claims in this issue don't match the code, and they change what this can promise. Both verified:
The console does not show screenshots or a transcript for these runs.ApplicationsTab.tsx's only per-application read is /application-queue/:id/trace (line 159) — exactly what application_trace already returned; it never calls /application-runs/*. The screenshot-replay page is pages/RunDetail.tsx, which its own header scopes to "any browser-runtime task" (RuntimeTask/RuntimeEvent + lib/run-shots.ts) — the legacy JOB_APPLY path, retired for new starts in 651bdd1. Nothing under lib/local-apply/ or browser-runner/src/local-apply/ captures a screenshot at all. What you saw was almost certainly an older Job Application Assistant run's replay, not this Runner's.
application_trace was hiding nothing.lib/applications/control.ts folds in every event from local_apply_runs.traceunfiltered. Had browser.navigated/field.filled been recorded for application 435d31c8, they would already have appeared there.
So for that specific 51-second run, the page-by-page detail does not exist server-side. The bridge does emit those events (bridge.ts — navigated, field.filled, artifact.uploaded, review.ready), but only when the CLI calls a bridge tool. That engine started and exited 0 having called none — which is itself why the run ended blocked/incomplete. A trace holding only engine.started/engine.ended is therefore a finding, not a hole in this tool, and application_run's description says exactly that so a reader stops hunting for a record that was never written.
What would close that last gap, and why I did not do it here: the CLI's own stdout is kept on the machine (local-apply/runtime.ts) and deliberately never crosses the runner contract — LocalApplyStatusResponse carries state/pause/events/lastSeq/result, and result.summary is the only part derived from that output which reaches the cloud. Shipping a bounded engine-output tail would answer "what did the CLI do when it called nothing", but it needs a runner-contract change, a CLI release, and a privacy decision: CLI prose can contain profile values, which is why the contract excludes it today. Worth its own issue if you want it.
MCP 0.1.94: 275 registrations → 279 (always-on 249 → 253, gated unchanged), lock entry appended, with the manifest, docs, README, operator skills and about page following.
Verification: full suite 855 files / 14,381 tests green; biome, all three tsconfig.test.json typechecks, MCP parity, docs:drift, file-size, surface-lock --require-history and OpenAPI 406/406 all clean. CI for 2b9a2fd was still queued when this was written.
Activity
proagentstore commentedon Oct 8, 2026
Concrete real example of this gap, from application 435d31c8-01a4-48d7-87f2-08584fa6d02e (Head of Engineering @ Business AI Group):
Tailoring (Application Tailor, instance 19b2e410-394a-4485-b832-6005356e7766) completed cleanly — résumé + cover letter written, 36/36 claims matched, run.ended status completed.
The application then handed off to the Application Runner (instance 2e85124f-4946-49d2-b922-8636ba92ca6a) to fill the SEEK application form. application_trace for this run shows only: run.requested → policy.submit_gate → runner.dispatched → source.read → engine.started → engine.ended (exitCode 0) → run.ended (status: blocked, reason: incomplete).
That is the ENTIRE record of a 51-second browser session. There is no indication of: which page(s) it navigated to, which form fields it filled or attempted to fill, where in the form it stopped, or why it considered the submission incomplete.
Critically: the console UI for this same run DOES show screenshots and what looks like a transcript of the browser session while/after it ran. That data exists and is being captured — it is simply not exposed through any MCP tool. application_trace and get_application only ever surface the coarse lifecycle/engine events above, never the page-by-page or field-by-field browser actions the UI renders.
This is the exact case the Runner should expose via MCP: when a fill run ends blocked/incomplete with no code-level error, the owner currently has no way via API/MCP to find out what the agent actually did on the site before stopping — they'd have to go look at the console UI screenshots/transcript by hand. Whatever backs that UI view (screenshots, page transcript, step log) should be readable through MCP, the same way coding_session_capture/coding_timeline expose a coding agent's terminal.
serge-ivo commentedon Oct 8, 2026
Implemented in 2b9a2fd — four read-only MCP tools, live where the route is live.
application_runsapplication_runcoding_session_capturecounterpart)application_run_supervisiontailoring_runapplication_runreturns the run'sstatus,pause(what it waits for and the questions it asked),policywith mode/limits/allowed domains and every submit-gate check with its verdict,result(outcome, fields filled, uploads, whether a submit was attempted),engineAuth,runnerNode, errors, timings, and the runner event trace —browser.navigated,field.filled,artifact.uploaded,policy.decision,browser.blocked,submit.*,supervisor.*— each with itsrunnerSeq, plus the application and its lifecycle audit.tailoring_runcarries artifact handles, never résumé or cover-letter text.The three live reads pull the owner's machine before answering, so a just-emitted event is already in the reply. All four are reads: scope
read, GET only (asserted in the test) — a live view starts, resumes and dispatches nothing.The gap was real, and it was exactly this: not one MCP tool reached
/application-runs/*or the Tailor's/applications/:id. Everything above was HTTP-reachable and reachable nowhere else.Two claims in this issue don't match the code, and they change what this can promise. Both verified:
The console does not show screenshots or a transcript for these runs.
ApplicationsTab.tsx's only per-application read is/application-queue/:id/trace(line 159) — exactly whatapplication_tracealready returned; it never calls/application-runs/*. The screenshot-replay page ispages/RunDetail.tsx, which its own header scopes to "any browser-runtime task" (RuntimeTask/RuntimeEvent+lib/run-shots.ts) — the legacy JOB_APPLY path, retired for new starts in 651bdd1. Nothing underlib/local-apply/orbrowser-runner/src/local-apply/captures a screenshot at all. What you saw was almost certainly an older Job Application Assistant run's replay, not this Runner's.application_tracewas hiding nothing.lib/applications/control.tsfolds in every event fromlocal_apply_runs.traceunfiltered. Hadbrowser.navigated/field.filledbeen recorded for application 435d31c8, they would already have appeared there.So for that specific 51-second run, the page-by-page detail does not exist server-side. The bridge does emit those events (
bridge.ts— navigated, field.filled, artifact.uploaded, review.ready), but only when the CLI calls a bridge tool. That engine started and exited 0 having called none — which is itself why the run endedblocked/incomplete. A trace holding onlyengine.started/engine.endedis therefore a finding, not a hole in this tool, andapplication_run's description says exactly that so a reader stops hunting for a record that was never written.What would close that last gap, and why I did not do it here: the CLI's own stdout is kept on the machine (
local-apply/runtime.ts) and deliberately never crosses the runner contract —LocalApplyStatusResponsecarriesstate/pause/events/lastSeq/result, andresult.summaryis the only part derived from that output which reaches the cloud. Shipping a bounded engine-output tail would answer "what did the CLI do when it called nothing", but it needs a runner-contract change, a CLI release, and a privacy decision: CLI prose can contain profile values, which is why the contract excludes it today. Worth its own issue if you want it.MCP 0.1.94: 275 registrations → 279 (always-on 249 → 253, gated unchanged), lock entry appended, with the manifest, docs, README, operator skills and about page following.
Verification: full suite 855 files / 14,381 tests green; biome, all three
tsconfig.test.jsontypechecks, MCP parity,docs:drift, file-size, surface-lock--require-historyand OpenAPI 406/406 all clean. CI for 2b9a2fd was still queued when this was written.feat: application-runner reliability (#975) — zero-bridge reason, red…
fix(#977): a machine below the application contract is refused, inste…