Skip to content

fix: clean up tabs owned by each CLI invocation - #526

Open
kesava500 wants to merge 2 commits into
browser-use:mainfrom
kesava500:fix/owned-tab-cleanup
Open

fix: clean up tabs owned by each CLI invocation#526
kesava500 wants to merge 2 commits into
browser-use:mainfrom
kesava500:fix/owned-tab-cleanup

Conversation

@kesava500

@kesava500 kesava500 commented Jul 14, 2026

Copy link
Copy Markdown

Summary

Automatically clean up tabs owned by each browser-harness CLI invocation without touching pre-existing tabs or targets opened by another process.

This rebases and extends the approach proposed by @hamanori in #354, which is now conflicting with main.

What changed

  • Track only targets created by this process through new_tab().
  • Close owned targets in a finally block, including when the browser task raises an error.
  • Restore a pre-existing blank tab when new_tab() reuses it instead of closing that target.
  • Move the daemon onto a fresh blank keeper before closing its currently attached owned target.
  • Leave the current target open if a safe session handoff fails, rather than leaving the daemon attached to a dead session.
  • Support explicit persistence through keep_opened_tabs() or BH_KEEP_TABS=1.
  • Document the lifecycle behavior in SKILL.md.

Why

The browser daemon intentionally survives between CLI invocations, so tabs also survive unless an agent remembers to close them. Long-running agents and scheduled research tasks therefore accumulate abandoned tabs and eventually consume substantial browser resources.

The original #354 ownership model avoids closing unrelated tabs. This version also accounts for current main reusing an existing blank tab and for the dangling-session failure described in #379 when the attached target closes.

The same lifecycle applies when the CLI is connected to a remote or cloud browser. Cleanup remains limited to targets owned by that invocation.

Verification

  • uv run --with pytest python -m pytest -q (137 passed)
  • uv run --with ruff ruff check tests/unit/test_tab_cleanup.py
  • uv run python -m compileall -q src tests
  • git diff --check
  • Live Chromium check: two navigated task pages were cleaned up, the reused keeper returned to about:blank, and the next CLI invocation remained attached and usable.
  • Concurrency check: an untracked target created alongside owned tabs survived cleanup.

Related work


Summary by cubic

Automatically cleans up tabs owned by each browser-harness CLI run and keeps the daemon attached to a live page. Cleanup runs after success or error and never touches unrelated tabs.

  • Bug Fixes

    • Close only tabs created via new_tab() and do it in a finally block; print a warning if cleanup fails and never mask task errors.
    • Restore reused blank tabs to about:blank when not keeping; keep mode now protects reused-blank tabs too. force=True still restores/closes.
    • Move the daemon to a fresh keeper before closing an owned tab; keep the current tab if the handoff fails and retain failures for retry.
    • Never close pre-existing tabs, tabs from other processes, or indirect popups (window.open, target=_blank).
    • Added opened_tabs(), keep_opened_tabs(), and close_opened_tabs(force=False); the keep flag is scoped to one invocation. Documented lifecycle in SKILL.md and added targeted tests.
  • Migration

    • To keep new tabs or reused blank tabs for a later run, call keep_opened_tabs() or set BH_KEEP_TABS=1 (case-insensitive). In keep mode, owned and reused-blank tabs are left as-is; use close_opened_tabs(force=True) to restore or close them.

Written for commit d57c921. Summary will update on new commits.

Review in cubic

@browser-harness-review

Copy link
Copy Markdown

✅ Skill review passed

Reviewed 1 file(s) — no findings.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 5 files

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

Comment thread src/browser_harness/helpers.py Outdated
Comment thread src/browser_harness/run.py
Comment thread src/browser_harness/run.py Outdated
Comment thread src/browser_harness/helpers.py
Comment thread src/browser_harness/helpers.py Outdated
Comment thread src/browser_harness/helpers.py Outdated
Comment thread src/browser_harness/helpers.py
Comment thread src/browser_harness/helpers.py
@kesava500
kesava500 force-pushed the fix/owned-tab-cleanup branch from 9d80b4b to 6f38468 Compare July 14, 2026 17:46
new_tab() usually reuses the current blank tab instead of creating a
new one via Target.createTarget, since the daemon is commonly parked
on a blank keeper tab between invocations. close_opened_tabs() only
ever checked _KEEP_OPENED_TABS after unconditionally restoring
reused-blank tabs, so keep_opened_tabs() silently failed to protect
exactly the common single-tab case callers rely on it for.

Move the keep-mode early return above _restore_reused_blank_tabs()
so both owned and reused-blank tabs are left untouched when keeping,
matching the actual promise of the API. force=True still restores as
before.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant