Skip to content
This repository was archived by the owner on Apr 21, 2026. It is now read-only.

fix: Switch code() to interactive stream-json mode and run CLI as non-root#4

Merged
DorianZheng merged 1 commit into
mainfrom
fix/code-interactive-mode-nonroot
Feb 5, 2026
Merged

fix: Switch code() to interactive stream-json mode and run CLI as non-root#4
DorianZheng merged 1 commit into
mainfrom
fix/code-interactive-mode-nonroot

Conversation

@DorianZheng

Copy link
Copy Markdown
Member

Summary

  • Switch code() from broken one-shot mode to interactive stream-json mode — one-shot (-p prompt) does not stream stdout through BoxLite's pipe-based exec; interactive mode sends prompt via stdin as NDJSON and streams responses correctly
  • Create non-root user in VM — Claude CLI v2.0.76 rejects --dangerously-skip-permissions when running as root (the default in BoxLite VMs); now creates a claude user and wraps all CLI calls with su -c
  • Add debug logging and fix test mocks — diagnostic logging throughout code(), proper NDJSON mock output, and AsyncMock for runtime.create()

Root Cause

Diagnosed via test_oneshot_vs_interactive.py running inside a real BoxLite VM:

Mode As Root As Non-Root
One-shot (-p prompt) Rejected 0 stdout chunks (hangs)
Interactive (stream-json) Rejected Works (3 chunks streamed)

Changes

File Change
src/claudebox/box.py Rewrite code() to interactive mode; add _setup_claude_user(), _build_claude_cmd(); update _start_claude()
tests/conftest.py Add stdin mock, fix stdout NDJSON format, AsyncMock for runtime.create
examples/*.py Add logging.basicConfig() for visible debug output

Test plan

  • All 99 unit/integration tests pass (pytest tests/ -v)
  • Ruff lint + format clean on changed files
  • Run python examples/01_basic_usage.py with CLAUDE_CODE_OAUTH_TOKEN set — verify log output and successful code() completion

@DorianZheng DorianZheng force-pushed the fix/code-interactive-mode-nonroot branch from 864b71f to 9130c22 Compare February 5, 2026 15:16
…-root

Two independent issues prevented code() from working:

1. One-shot mode (-p prompt) does not stream stdout through BoxLite's
   pipe-based exec. Interactive mode (--input-format stream-json) works
   correctly, streaming NDJSON responses in real-time.

2. Claude CLI v2.0.76 rejects --dangerously-skip-permissions when running
   as root, which is the default user in BoxLite VMs.

Changes:
- Rewrite code() to use interactive stdin/stdout protocol instead of
  one-shot -p flag. Sends prompt as NDJSON on stdin, reads streamed
  responses from stdout.
- Add _setup_claude_user() to create non-root 'claude' user in VM
  during __aenter__(), with workspace permissions.
- Add _build_claude_cmd() to wrap all CLI invocations with
  su -c "ENV=val claude --flags" claude.
- Update _start_claude() (used by stream()) with same su -c wrapping.
- Add debug logging throughout code() for diagnostics.
- Add logging.basicConfig to all example files.
- Fix test mocks: add stdin mock, proper NDJSON output, AsyncMock for
  runtime.create().
- Update templates, docs, and CI configuration.
@DorianZheng DorianZheng force-pushed the fix/code-interactive-mode-nonroot branch from 9130c22 to 87d1642 Compare February 5, 2026 15:22
@DorianZheng DorianZheng merged commit 12fdba4 into main Feb 5, 2026
5 checks passed
@DorianZheng DorianZheng deleted the fix/code-interactive-mode-nonroot branch February 5, 2026 15:24
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant