Skip to content

fix: keep headless Claude and Codex stdout clean - #1007

Merged
david-siqi-liu merged 3 commits into
mainfrom
tt-le/ug-headless-stdout-only
Oct 6, 2026
Merged

david-siqi-liu merged 3 commits into
mainfrom
tt-le/ug-headless-stdout-only

Conversation

@tt-le

@tt-le tt-le commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Stack

  1. This PR: keep headless Claude/Codex stdout clean; targets main, merges independently.
  2. Follow-up: fix: reconcile headless managed settings without prompting #1008 — non-prompting managed-settings reconciliation.

Problem

isaac --claude -p --output-format json … > out.json produces invalid JSON because UG prints status lines to stdout before the agent's output. Reported with Isaac 2.0.0-20261005192727-d3c9edb / UG 0.1.0+0857d42 (Slack).

The thread also contains a second, separate failure: when the OS-managed settings differ on a UG-owned key (e.g. Isaac's jq … model-serving-token.json apiKeyHelper), headless launches stop with cannot be applied non-interactively. That is #1008, not this PR.

Changes

  • For Claude -p/--print and Codex exec/e/app-server, send UG status and bootstrap/install output to stderr. The agent's own stdout is untouched.
  • Detect headless mode by argument membership before the agent's -- (no Codex option parser). Matching an option value only moves UG diagnostics to stderr.
  • Unit/component regressions for streams, errors, forwarding, and bootstrap subprocesses; live headless journeys now parse raw JSON/JSONL.

Validation

  • Unit/component suites, Ruff, ty pass; CI green.
  • confirmed with local isaac build that --p --output-format json and exec --json produce valid jsons.
    | Case | main @ 4c1b866 | this PR @ 39f2d12 |
    |---|---|---|
    | ug claude -- -p --output-format json | ❌ | ✅ |
    | ug claude -- --print --output-format json | ❌ | ✅ |
    | ug claude -- -p --output-format stream-json --verbose | ❌ | ✅ |
    | ug claude -- -p (text) | ❌ | ✅ |
    | ug claude -- --output-format json --model sonnet -p | ❌ | ✅ |
    | ug claude -- -p … \| python3 -m json.tool | ❌ | ✅ |
    | ug codex exec --json | ❌ | ✅ |
    | ug codex e --json | ❌ | ✅ |
    | ug codex -c … exec --json | ❌ | ✅ |
    | ug codex exec (text) | ❌ | ✅ |
    | ug codex exec --output-schema … (stdout) | ❌ | ✅ |
    | ug codex exec --output-schema … -o file (file) | ✅ | ✅ |

Scope

No managed-settings, sudo, or Isaac changes (e.g. Isaac exit-code propagation, Isaac replacing apiKeyHelper).

This pull request and its description were written by Isaac.

@tt-le
tt-le requested a review from david-siqi-liu October 6, 2026 18:41
@david-siqi-liu
david-siqi-liu added this pull request to the merge queue Oct 6, 2026
Merged via the queue into main with commit 6a96894 Oct 6, 2026
27 checks passed
@david-siqi-liu
david-siqi-liu deleted the tt-le/ug-headless-stdout-only branch October 6, 2026 20:44
Pzharyuk pushed a commit to Pzharyuk/unity-gateway that referenced this pull request Oct 8, 2026
…s#1008)

## Summary

Headless Claude/Codex launches fail when an existing OS-managed file
overrides UG's gateway settings. Allow those conflicting files to be
repaired using one-shot `sudo -n` with stdin disconnected. Authorization
failures still block launch; there is no password-prompt fallback.

Reuse the existing backup, policy-preserving composition, atomic write,
and verification. Leave absent/compatible files unchanged. Headless
creation, revert, and managed MCP writes remain out of scope.

This PR targets `main`; the separate stdout/JSON fix (databricks#1007) is already
merged. Preventing Isaac from replacing UG's `apiKeyHelper` and
propagating harness exit codes remain separate Isaac work.

## Validation

- Reproduced end-to-end against a local Isaac build pinned to this
branch: opened Isaac Omni (interactive) to establish the
OS-managed-settings state, then ran headless Isaac with JSON output
(`isaac -p ... --output-format json`). The headless launch — which fails
on `main` — succeeded and returned JSON, confirming the fix.
- 610 managed-file, Claude, Codex, managed-model lifecycle, and
managed-resolve component tests passed.
- Ruff check/format, type checking, and `git diff --check` passed.
- The automated suite mocks the privileged write, so no live inference,
real sudo, or `/etc` writes run there; those paths were exercised by the
local Isaac repro above.

This pull request description was written with AI assistance.

---------

Co-authored-by: Isaac <no-reply@databricks.com>
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.

2 participants