{"record":{"id":"922e608cf478d677","repo":"Hmbown/CodeWhale","slug":"codewhale-tui-cannot-start-from-a-background-or-suspended","errorCode":null,"errorMessage":"Codewhale TUI cannot start from a background or suspended terminal job (terminal foreground process group {terminal_pgid}, Codewhale process group {process_pgid}).\nRun `fg` to foreground the job or launch `codew` in a new terminal. For automated prompts use `codewhale exec \"…\"` instead.","messagePattern":"Codewhale TUI cannot start from a background or suspended terminal job \\(terminal foreground process group (.+?), Codewhale process group (.+?)\\)\\.\nRun `fg` to foreground the job or launch `codew` in a new terminal\\. For automated prompts use `codewhale exec \"…\"` instead\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/ui/terminal.rs","lineNumber":149,"sourceCode":"        ));\n    }\n    validate_foreground_process_group(terminal_pgid, process_pgid)\n}\n\n#[cfg(not(unix))]\npub(crate) fn require_foreground_terminal_owner() -> Result<()> {\n    Ok(())\n}\n\n#[cfg(unix)]\npub(crate) fn validate_foreground_process_group(\n    terminal_pgid: libc::pid_t,\n    process_pgid: libc::pid_t,\n) -> Result<()> {\n    if terminal_pgid == process_pgid {\n        return Ok(());\n    }\n    Err(anyhow::anyhow!(\n        \"Codewhale TUI cannot start from a background or suspended terminal job \\\n         (terminal foreground process group {terminal_pgid}, Codewhale process group {process_pgid}).\\n\\\n         Run `fg` to foreground the job or launch `codew` in a new terminal. \\\n         For automated prompts use `codewhale exec \\\"…\\\"` instead.\"\n    ))\n}\n\npub(crate) fn subagent_terminal_projection_from_mailbox(\n    message: &MailboxMessage,\n) -> Option<(&str, SubAgentStatus, Option<String>)> {\n    match message {\n        MailboxMessage::Completed { agent_id, summary } => Some((\n            agent_id.as_str(),\n            SubAgentStatus::Completed,\n            Some(summary.clone()),\n        )),\n        MailboxMessage::Failed { agent_id, error } => Some((\n            agent_id.as_str(),","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tui/ui/terminal.rs#L131-L167","documentation":"validate_foreground_process_group rejects TUI startup when the terminal's foreground process group (from tcgetpgrp) differs from the Codewhale process group. A background/suspended job must not put the terminal into raw mode or fight the shell for input, so startup is blocked with guidance to foreground the job.","triggerScenarios":"Launching `codew` while the process is a background job of the shell (e.g. `codew &` then ignoring job control), resuming a suspended session (`Ctrl-Z` then running without `fg`), or starting the TUI from a scripted context where another process group holds the terminal foreground.","commonSituations":"Developer starts codew, hits Ctrl-Z, then launches it again from a script; or an alias/wrapper backgrounds the process; or a test harness spawns codew without granting it the foreground pgroup via tcsetpgrp.","solutions":["Bring the job to the foreground: run `fg` in the shell before interacting.","Launch `codew` in a fresh terminal window/tab.","Use `codewhale exec \"…\"` for automated/non-interactive prompts.","If spawning programmatically, call tcsetpgrp to make the child the terminal's foreground process group, or run the child with its own pty."],"exampleFix":"// before\n$ codew &   # blocked: background job\n// after\n$ fg %1     # or launch codew directly in the foreground","handlingStrategy":"validation","validationCode":"let fg = unsafe { libc::tcgetpgrp(libc::STDIN_FILENO) };\nlet mine = unsafe { libc::getpgrp() };\nif fg >= 0 && fg != mine {\n    eprintln!(\"background job: run `fg` first or use codewhale exec\");\n}","typeGuard":"fn is_foreground_job() -> bool {\n    let fg = unsafe { libc::tcgetpgrp(libc::STDIN_FILENO) };\n    fg >= 0 && fg == unsafe { libc::getpgrp() }\n}","tryCatchPattern":null,"preventionTips":["Do not launch the TUI with `&`; wait for the foreground job.","After Ctrl-Z, run `fg` before issuing further commands that relaunch the TUI.","Use codewhale exec for any non-interactive invocation.","When spawning the TUI programmatically, give the child the terminal foreground pgroup (tcsetpgrp) or its own pty."],"tags":["terminal","process-group","job-control","tui"],"backgroundTag":"invalid-state-transition","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}