Why this issue exists
This came from the local:session-concurrency eval. The eval is trying to prove two separate things:
- Two different sessions can run browser work in parallel.
- Two overlapping CLI invocations against the same session produce structured
SESSION_BUSY, followed by a safe retry.
Source reports:
/Users/ankitranjan/Work/agentrhq/evals/results/run-20260820T085734Z/report.md
/Users/ankitranjan/Work/agentrhq/evals/results/run-20260820T103952Z/report.md
Current Webcmd state
As of origin/main 22974697bb3fe784bad5ef5a208f2d6ee5a272a8 (webcmd-v0.7.4-2-g2297469):
SESSION_BUSY exists as a structured CLI error.
- The error message says the session is busy because another holder is already driving it.
- The hint says: wait, then run the same command again.
- If the holder pid is live, the hint says not to force-close; if the holder is not live,
webcmd session close --force <session-id> is presented as a last resort.
- The local runtime queues browser work by profile/session/site before execution, so session occupancy is a Webcmd runtime concern.
- Current skill/help text names
SESSION_BUSY, but it does not make the two-CLI-invocation shape impossible to miss.
Observed agent behavior
The successful run eventually did the right thing:
- Created two explicit sessions.
- Backgrounded two
webcmd --session <id> browser run commands and proved the 3s waits overlapped.
- Started one long command on the Alpha session.
- Issued a second
webcmd --session <same-alpha-id> browser run while the first was still holding the session.
- Received
SESSION_BUSY naming the holder pid.
- Waited, retried the same second command without
--force, and verified final count 2.
The failed run shows the agent confusion:
- It created sessions, but did not create CLI-level contention.
- It tried to overlap work inside one
browser run with two page.evaluate(applyUpdate) calls.
- Both in-page calls completed, so no
SESSION_BUSY envelope appeared.
- The agent concluded the structured busy response did not exist in page code.
- The final count became
3, because the retry happened after in-page writes rather than after a CLI busy/retry sequence.
What went wrong
The agent modeled session occupancy as a page-level lock. It looked for busy state inside the browser page instead of in the Webcmd session runtime.
SESSION_BUSY is not produced by two promises inside one browser run. It is produced when a second Webcmd CLI invocation tries to drive the same session while another invocation still owns it.
The recurring failure pattern is:
- The agent sees a concurrency task.
- It creates two sessions correctly.
- For same-session contention, it stays inside one browser program.
- It invents an in-page lock or in-page overlap.
- It never asks the CLI to arbitrate the session.
Why this matters
This is a product affordance issue more than an eval-specific skill issue. Agents should not need deep skill text to understand where the lock lives. The CLI/runtime should make it hard to miss that session contention is between Webcmd invocations, not page scripts.
Related product concern: SESSION_BUSY must be returned before browser work starts when a session is already held.
Solution directions
The preferred solution should put the durable behavior in the CLI/runtime first.
Possible directions:
- Product/runtime: ensure every mutating browser command checks session ownership before doing browser work and returns structured
SESSION_BUSY with holder details.
- CLI help/error text: make the error say that the caller should wait for the listed holder, then retry the same command.
--force is only for a dead holder.
session list: make active holders visible enough that an agent can inspect the session state without inventing page locks.
- Minimal skill text, if needed: one troubleshooting line saying
SESSION_BUSY comes from a second webcmd --session <id> ... process, not from page.evaluate.
Open questions for senior review
- Is the runtime/error surface already strong enough after the product fix, making the skill PR unnecessary?
- Should there be a CLI-visible way to show the current holder command/pid in
session list?
- Should the docs include a two-terminal recipe, or is that too much eval-specific instruction?
Acceptance criteria
- A second CLI invocation on a held session returns structured
SESSION_BUSY before browser work starts.
- The error tells the agent to wait for the holder and retry the same command.
- The agent does not implement an in-page mutex or use
page.evaluate as the safety signal.
- The safe retry path completes without
--force and without an extra write.
Non-goals
- No fixture-specific wording.
- No
data: localStorage policy changes here.
- No encouragement to force-close a live holder.
Why this issue exists
This came from the
local:session-concurrencyeval. The eval is trying to prove two separate things:SESSION_BUSY, followed by a safe retry.Source reports:
/Users/ankitranjan/Work/agentrhq/evals/results/run-20260820T085734Z/report.md/Users/ankitranjan/Work/agentrhq/evals/results/run-20260820T103952Z/report.mdCurrent Webcmd state
As of
origin/main22974697bb3fe784bad5ef5a208f2d6ee5a272a8(webcmd-v0.7.4-2-g2297469):SESSION_BUSYexists as a structured CLI error.webcmd session close --force <session-id>is presented as a last resort.SESSION_BUSY, but it does not make the two-CLI-invocation shape impossible to miss.Observed agent behavior
The successful run eventually did the right thing:
webcmd --session <id> browser runcommands and proved the 3s waits overlapped.webcmd --session <same-alpha-id> browser runwhile the first was still holding the session.SESSION_BUSYnaming the holder pid.--force, and verified final count2.The failed run shows the agent confusion:
browser runwith twopage.evaluate(applyUpdate)calls.SESSION_BUSYenvelope appeared.3, because the retry happened after in-page writes rather than after a CLI busy/retry sequence.What went wrong
The agent modeled session occupancy as a page-level lock. It looked for busy state inside the browser page instead of in the Webcmd session runtime.
SESSION_BUSYis not produced by two promises inside onebrowser run. It is produced when a second Webcmd CLI invocation tries to drive the same session while another invocation still owns it.The recurring failure pattern is:
Why this matters
This is a product affordance issue more than an eval-specific skill issue. Agents should not need deep skill text to understand where the lock lives. The CLI/runtime should make it hard to miss that session contention is between Webcmd invocations, not page scripts.
Related product concern:
SESSION_BUSYmust be returned before browser work starts when a session is already held.Solution directions
The preferred solution should put the durable behavior in the CLI/runtime first.
Possible directions:
SESSION_BUSYwith holder details.--forceis only for a dead holder.session list: make active holders visible enough that an agent can inspect the session state without inventing page locks.SESSION_BUSYcomes from a secondwebcmd --session <id> ...process, not frompage.evaluate.Open questions for senior review
session list?Acceptance criteria
SESSION_BUSYbefore browser work starts.page.evaluateas the safety signal.--forceand without an extra write.Non-goals
data:localStorage policy changes here.