Multi-Agent Coordination
Multiple Claude Code agents share a single Firefox window with a 12-tab pool. Claudezilla enforces ownership rules and provides coordination mechanisms to prevent conflicts. ## Tab Ownership Every tab tracks the agent that created it. Only the creator can close or navigate their tabs. ```js // Agent A creates a tab const tab = firefox_create_window({ url: "https://example.com" }) // tab.ownerId = "agent_a1b2c3..." // Agent B tries to close it firefox_close_tab({ tabId: tab.tabId }) // Error: OWNERSHIP: Cannot close tab 42 (owned by agent_a1b2...) ``` All content commands (getContent, click, type, screenshot, etc.) also verify ownership. Use `firefox_get_tabs` to see which agent owns each tab: ```js firefox_get_tabs() // { // tabCount: 3, // maxTabs: 12, // tabs: [ // { tabId: 42, url: "...", title: "...", ownerId: "agent_a1b2..." }, // { tabId: 43, url: "...", title: "...", ownerId: "agent_d4e5..." } // ] // } ``` ## Pool Limits The tab pool is capped at 12 tabs. When an agent tries to open a 13th tab, it gets a `POOL_FULL` error instead of silently evicting another agent's tab. ``` POOL_FULL: Tab pool is full (12/12). Your tabs: 4 Other agents: 8 Hint: Close one of your tabs, or use firefox_request_tab_space. ``` Agents can only auto-evict their **own** oldest tab. If all 12 tabs belong to other agents, the mercy system is required. ## Mercy System The mercy system lets blocked agents request tab space from other agents through slot reservations. ### Step 1: Request Space When blocked by `POOL_FULL`, queue a request: ```js firefox_request_tab_space() // { queued: true, position: 1 } ``` ### Step 2: Another Agent Grants Space When an agent sees pending requests (or closes a tab), a 30-second slot reservation is created for the waiting agent: ```js // The granting agent calls: firefox_grant_tab_space() // Closes their oldest tab, creates reservation for waiting agent ``` ### Step 3: Check and Claim The waiting agent polls for its reservation: ```js firefox_get_slot_requests() // { // pendingRequests: [], // youHaveReservation: true, // reservationExpiresInMs: 28000 // } // Reservation found — claim it immediately firefox_create_window({ url: "https://example.com" }) // Bypasses POOL_FULL check during reservation window ``` Reservations expire after 30 seconds. If unclaimed, the slot becomes available to any agent. ## Session Cleanup When a Claude session ends normally (Ctrl+C, task completion), the MCP server sends a `goodbye` command that immediately closes all tabs owned by that agent. ``` [claudezilla] Agent agent_a1b2... disconnecting, cleaning up 3 tab(s) ``` This also removes the agent's pending slot requests and active reservations. ## Orphaned Tab Cleanup If an agent crashes hard (SIGKILL, OOM) without sending `goodbye`, tabs become orphaned. Claudezilla handles this with heartbeat tracking: - **Heartbeat**: Every command updates the agent's last-seen timestamp - **Timeout**: Agent is considered dead after 10 minutes of inactivity - **Cleanup**: Every 60 seconds, the MCP server checks for orphaned agents and closes their tabs This prevents "ghost tabs" from permanently consuming pool slots after crashes. ## Screenshot Mutex Screenshots are serialized across all agents to prevent tab-switching races. If the mutex is held for more than 3 seconds, you get `MUTEX_BUSY`: ``` MUTEX_BUSY: Screenshot mutex held by another agent. Hint: Use getPageState (no mutex) or retry after delay. ``` `firefox_get_page_state` is a good alternative when you need page structure without a visual capture.Multiple Claude Code agents share a single Firefox window with a 12-tab pool. Claudezilla enforces ownership rules and provides coordination mechanisms to prevent conflicts.
Tab Ownership
Section titled “Tab Ownership”Every tab tracks the agent that created it. Only the creator can close or navigate their tabs.
// Agent A creates a tabconst tab = firefox_create_window({ url: "https://example.com" })// tab.ownerId = "agent_a1b2c3..."
// Agent B tries to close itfirefox_close_tab({ tabId: tab.tabId })// Error: OWNERSHIP: Cannot close tab 42 (owned by agent_a1b2...)All content commands (getContent, click, type, screenshot, etc.) also verify ownership. Use firefox_get_tabs to see which agent owns each tab:
firefox_get_tabs()// {// tabCount: 3,// maxTabs: 12,// tabs: [// { tabId: 42, url: "...", title: "...", ownerId: "agent_a1b2..." },// { tabId: 43, url: "...", title: "...", ownerId: "agent_d4e5..." }// ]// }Pool Limits
Section titled “Pool Limits”The tab pool is capped at 12 tabs. When an agent tries to open a 13th tab, it gets a POOL_FULL error instead of silently evicting another agent’s tab.
POOL_FULL: Tab pool is full (12/12). Your tabs: 4 Other agents: 8 Hint: Close one of your tabs, or use firefox_request_tab_space.Agents can only auto-evict their own oldest tab. If all 12 tabs belong to other agents, the mercy system is required.
Mercy System
Section titled “Mercy System”The mercy system lets blocked agents request tab space from other agents through slot reservations.
Step 1: Request Space
Section titled “Step 1: Request Space”When blocked by POOL_FULL, queue a request:
firefox_request_tab_space()// { queued: true, position: 1 }Step 2: Another Agent Grants Space
Section titled “Step 2: Another Agent Grants Space”When an agent sees pending requests (or closes a tab), a 30-second slot reservation is created for the waiting agent:
// The granting agent calls:firefox_grant_tab_space()// Closes their oldest tab, creates reservation for waiting agentStep 3: Check and Claim
Section titled “Step 3: Check and Claim”The waiting agent polls for its reservation:
firefox_get_slot_requests()// {// pendingRequests: [],// youHaveReservation: true,// reservationExpiresInMs: 28000// }
// Reservation found — claim it immediatelyfirefox_create_window({ url: "https://example.com" })// Bypasses POOL_FULL check during reservation windowReservations expire after 30 seconds. If unclaimed, the slot becomes available to any agent.
Session Cleanup
Section titled “Session Cleanup”When a Claude session ends normally (Ctrl+C, task completion), the MCP server sends a goodbye command that immediately closes all tabs owned by that agent.
[claudezilla] Agent agent_a1b2... disconnecting, cleaning up 3 tab(s)This also removes the agent’s pending slot requests and active reservations.
Orphaned Tab Cleanup
Section titled “Orphaned Tab Cleanup”If an agent crashes hard (SIGKILL, OOM) without sending goodbye, tabs become orphaned. Claudezilla handles this with heartbeat tracking:
- Heartbeat: Every command updates the agent’s last-seen timestamp
- Timeout: Agent is considered dead after 10 minutes of inactivity
- Cleanup: Every 60 seconds, the MCP server checks for orphaned agents and closes their tabs
This prevents “ghost tabs” from permanently consuming pool slots after crashes.
Screenshot Mutex
Section titled “Screenshot Mutex”Screenshots are serialized across all agents to prevent tab-switching races. If the mutex is held for more than 3 seconds, you get MUTEX_BUSY:
MUTEX_BUSY: Screenshot mutex held by another agent. Hint: Use getPageState (no mutex) or retry after delay.firefox_get_page_state is a good alternative when you need page structure without a visual capture.