diff --git a/src/features/team-mode/team-layout-tmux/live-tmux-smoke.test.ts b/src/features/team-mode/team-layout-tmux/live-tmux-smoke.test.ts
new file mode 100644
index 000000000..349e1dd84
--- /dev/null
+++ b/src/features/team-mode/team-layout-tmux/live-tmux-smoke.test.ts
@@ -0,0 +1,320 @@
+///
+
+import { randomUUID } from "node:crypto"
+import { mkdir, rm } from "node:fs/promises"
+import path from "node:path"
+
+import { afterEach, beforeEach, describe, expect, test } from "bun:test"
+import { spawn } from "bun"
+
+const LIVE = process.env.OMO_LIVE_TMUX === "1"
+const HOSTNAME = "127.0.0.1"
+const layoutSpecifier = import.meta.resolve("./layout")
+
+type TeamLayoutMemberLike = {
+ name: string
+ sessionId: string
+ worktreePath?: string
+}
+
+type TmuxManagerLike = {
+ getServerUrl: () => string
+}
+
+type TeamLayoutResultLike = {
+ focusWindowId: string
+ gridWindowId: string
+ focusPanesByMember: Record
+ gridPanesByMember: Record
+ targetSessionId: string
+ ownedSession: boolean
+}
+
+type LoadedLayoutModule = {
+ createTeamLayout?: unknown
+ removeTeamLayout?: unknown
+}
+
+type TmuxCommandResult = {
+ success: boolean
+ stdout: string
+ stderr: string
+ exitCode: number
+}
+
+type TmuxWindow = {
+ id: string
+ name: string
+}
+
+type LiveTestState = {
+ callerPaneId: string
+ callerSessionId: string
+ callerSessionName: string
+ healthServer: ReturnType
+ originalTmux: string | undefined
+ originalTmuxPane: string | undefined
+ socketPath: string
+ tempRoot: string
+ tmuxManager: TmuxManagerLike
+}
+
+let liveTestState: LiveTestState | null = null
+
+function requireLiveTestState(): LiveTestState {
+ if (liveTestState === null) {
+ throw new Error("live tmux smoke test state was not initialized")
+ }
+
+ return liveTestState
+}
+
+function isRecord(value: unknown): value is Record {
+ return value !== null && typeof value === "object"
+}
+
+function isTeamLayoutResultLike(value: unknown): value is TeamLayoutResultLike {
+ if (!isRecord(value)) {
+ return false
+ }
+
+ return typeof value.focusWindowId === "string"
+ && typeof value.gridWindowId === "string"
+ && isRecord(value.focusPanesByMember)
+ && isRecord(value.gridPanesByMember)
+ && typeof value.targetSessionId === "string"
+ && typeof value.ownedSession === "boolean"
+}
+
+async function runTmuxCommand(args: string[]): Promise {
+ const subprocess = spawn(["tmux", ...args], {
+ stdout: "pipe",
+ stderr: "pipe",
+ })
+
+ const [stdout, stderr, exitCode] = await Promise.all([
+ new Response(subprocess.stdout).text(),
+ new Response(subprocess.stderr).text(),
+ subprocess.exited,
+ ])
+
+ return {
+ success: exitCode === 0,
+ stdout: stdout.trim(),
+ stderr: stderr.trim(),
+ exitCode,
+ }
+}
+
+async function createCallerSession(sessionName: string): Promise<{ callerSessionId: string; callerPaneId: string; socketPath: string }> {
+ const createdSession = await runTmuxCommand([
+ "new-session",
+ "-d",
+ "-s",
+ sessionName,
+ "-P",
+ "-F",
+ "#{session_id} #{pane_id}",
+ ])
+
+ if (!createdSession.success) {
+ throw new Error(`failed to create caller tmux session: ${createdSession.stderr || createdSession.stdout}`)
+ }
+
+ const [callerSessionId, callerPaneId] = createdSession.stdout.split(" ", 2)
+ if (!callerSessionId || !callerPaneId) {
+ throw new Error(`failed to parse caller session identifiers: ${createdSession.stdout}`)
+ }
+
+ const socketPathResult = await runTmuxCommand(["display-message", "-p", "-t", callerPaneId, "#{socket_path}"])
+ if (!socketPathResult.success || socketPathResult.stdout.length === 0) {
+ throw new Error(`failed to resolve tmux socket path: ${socketPathResult.stderr || socketPathResult.stdout}`)
+ }
+
+ return { callerSessionId, callerPaneId, socketPath: socketPathResult.stdout }
+}
+
+async function listWindows(sessionId: string): Promise {
+ const listedWindows = await runTmuxCommand(["list-windows", "-t", sessionId, "-F", "#{window_id}\t#{window_name}"])
+ if (!listedWindows.success) {
+ throw new Error(`failed to list tmux windows: ${listedWindows.stderr || listedWindows.stdout}`)
+ }
+
+ return listedWindows.stdout
+ .split("\n")
+ .map((line) => line.trim())
+ .filter((line) => line.length > 0)
+ .map((line) => {
+ const [id, name] = line.split("\t", 2)
+ if (!id || !name) {
+ throw new Error(`failed to parse tmux window line: ${line}`)
+ }
+
+ return { id, name }
+ })
+}
+
+async function waitForCondition(predicate: () => Promise): Promise {
+ for (let attempt = 0; attempt < 30; attempt += 1) {
+ if (await predicate()) {
+ return true
+ }
+
+ await new Promise((resolve) => {
+ setTimeout(resolve, 100)
+ })
+ }
+
+ return false
+}
+
+async function loadLayoutModule(): Promise {
+ return import(`${layoutSpecifier}?live=${Date.now()}-${Math.random()}`)
+}
+
+async function invokeCreateTeamLayout(
+ layoutModule: LoadedLayoutModule,
+ teamRunId: string,
+ members: TeamLayoutMemberLike[],
+ tmuxManager: TmuxManagerLike,
+): Promise {
+ const createTeamLayout = layoutModule.createTeamLayout
+ if (!(createTeamLayout instanceof Function)) {
+ throw new Error("createTeamLayout export missing")
+ }
+
+ const result = await Promise.resolve(Reflect.apply(createTeamLayout, undefined, [teamRunId, members, tmuxManager]))
+ if (!isTeamLayoutResultLike(result)) {
+ throw new Error("createTeamLayout returned an unexpected result")
+ }
+
+ return result
+}
+
+async function invokeRemoveTeamLayout(
+ layoutModule: LoadedLayoutModule,
+ teamRunId: string,
+ tmuxManager: TmuxManagerLike,
+ layoutResult: TeamLayoutResultLike,
+ targetSessionId: string,
+): Promise {
+ const removeTeamLayout = layoutModule.removeTeamLayout
+ if (!(removeTeamLayout instanceof Function)) {
+ throw new Error("removeTeamLayout export missing")
+ }
+
+ await Promise.resolve(Reflect.apply(removeTeamLayout, undefined, [
+ teamRunId,
+ {
+ ownedSession: false,
+ targetSessionId,
+ focusWindowId: layoutResult.focusWindowId,
+ gridWindowId: layoutResult.gridWindowId,
+ },
+ tmuxManager,
+ ]))
+}
+
+describe("team-mode live tmux smoke", () => {
+ beforeEach(async () => {
+ if (!LIVE) {
+ return
+ }
+
+ const callerSessionName = `omo-smoke-${Date.now()}`
+ const { callerSessionId, callerPaneId, socketPath } = await createCallerSession(callerSessionName)
+ const tempRoot = path.join("/tmp", `omo-live-tmux-${randomUUID()}`)
+ await mkdir(path.join(tempRoot, "lead"), { recursive: true })
+ await mkdir(path.join(tempRoot, "member-two"), { recursive: true })
+
+ const healthServer = Bun.serve({
+ port: 0,
+ hostname: HOSTNAME,
+ fetch(request) {
+ const requestUrl = new URL(request.url)
+ if (requestUrl.pathname === "/global/health") {
+ return new Response("ok")
+ }
+
+ return new Response("not found", { status: 404 })
+ },
+ })
+
+ liveTestState = {
+ callerPaneId,
+ callerSessionId,
+ callerSessionName,
+ healthServer,
+ originalTmux: process.env.TMUX,
+ originalTmuxPane: process.env.TMUX_PANE,
+ socketPath,
+ tempRoot,
+ tmuxManager: {
+ getServerUrl: () => `http://${HOSTNAME}:${healthServer.port}`,
+ },
+ }
+
+ process.env.TMUX = `${socketPath},0,0`
+ process.env.TMUX_PANE = callerPaneId
+ })
+
+ afterEach(async () => {
+ const state = liveTestState
+ liveTestState = null
+ if (state === null) {
+ return
+ }
+
+ state.healthServer.stop(true)
+ process.env.TMUX = state.originalTmux
+ process.env.TMUX_PANE = state.originalTmuxPane
+ await runTmuxCommand(["kill-session", "-t", state.callerSessionName])
+ await rm(state.tempRoot, { recursive: true, force: true })
+ })
+
+ test.skipIf(!LIVE)("#given a real caller tmux session and two mock members #when createTeamLayout runs #then two new windows appear in the caller session AND removeTeamLayout deletes exactly those two windows leaving the caller session intact", async () => {
+ // given
+ const state = requireLiveTestState()
+ const layoutModule = await loadLayoutModule()
+ const teamRunId = randomUUID()
+ const shortTeamRunId = teamRunId.slice(0, 8)
+ const expectedWindowNames = [`focus-${shortTeamRunId}`, `grid-${shortTeamRunId}`]
+ const initialWindows = await listWindows(state.callerSessionId)
+ const members: TeamLayoutMemberLike[] = [
+ {
+ name: "lead",
+ sessionId: `${teamRunId}-lead`,
+ worktreePath: path.join(state.tempRoot, "lead"),
+ },
+ {
+ name: "member-two",
+ sessionId: `${teamRunId}-member-two`,
+ worktreePath: path.join(state.tempRoot, "member-two"),
+ },
+ ]
+
+ // when
+ const layoutResult = await invokeCreateTeamLayout(layoutModule, teamRunId, members, state.tmuxManager)
+ const windowsAppeared = await waitForCondition(async () => {
+ const windows = await listWindows(state.callerSessionId)
+ return expectedWindowNames.every((windowName) => windows.some((window) => window.name === windowName))
+ })
+
+ await invokeRemoveTeamLayout(layoutModule, teamRunId, state.tmuxManager, layoutResult, state.callerSessionId)
+ const windowsRemoved = await waitForCondition(async () => {
+ const windows = await listWindows(state.callerSessionId)
+ const noExpectedWindowsRemain = expectedWindowNames.every((windowName) => windows.every((window) => window.name !== windowName))
+ const sameWindowIds = windows.map((window) => window.id).join(",") === initialWindows.map((window) => window.id).join(",")
+ return noExpectedWindowsRemain && sameWindowIds
+ })
+ const callerSessionStillAlive = await runTmuxCommand(["has-session", "-t", state.callerSessionId])
+
+ // then
+ expect(layoutResult.focusWindowId.length).toBeGreaterThan(0)
+ expect(layoutResult.gridWindowId.length).toBeGreaterThan(0)
+ expect(windowsAppeared).toBe(true)
+ expect(windowsRemoved).toBe(true)
+ expect(callerSessionStillAlive.success).toBe(true)
+ expect(process.env.TMUX_PANE).toBe(state.callerPaneId)
+ })
+})