Skip to content

feat(cli): Add CLI with list and exec commands#60

Open
iiilisan wants to merge 4 commits intomainfrom
exian/cli-core
Open

feat(cli): Add CLI with list and exec commands#60
iiilisan wants to merge 4 commits intomainfrom
exian/cli-core

Conversation

@iiilisan
Copy link
Collaborator

@iiilisan iiilisan commented Feb 24, 2026

Summary

Introduces the cwsandbox CLI as an optional Click-based subpackage (pip install cwsandbox[cli]), with ls and exec commands for terminal-based sandbox management.

  • CLI scaffold — Click group at cwsandbox.cli, console script entry point, __main__.py with narrowed ImportError handling that re-raises unrelated import failures
  • cwsandbox ls — Query sandboxes with --status, --tag, --runway-id, --tower-id filters; table and JSON output
  • cwsandbox exec — Execute commands in a sandbox with real-time stdout/stderr streaming, --cwd and --timeout options, exit code passthrough
  • CLI quickstart guide — Installation, usage examples, JSON output for scripting

Design decisions

  • Click is an optional dependency behind the cli extra — import cwsandbox never loads Click or CLI modules
  • CLI commands mock cwsandbox.cli.<cmd>.Sandbox in tests (not the top-level cwsandbox.Sandbox) for proper isolation
  • Dev extra lists click>=8.0 directly instead of self-referencing cwsandbox[cli] to avoid resolver confusion

Test plan

  • test_cli_main.py — help, version, ImportError fallback, unrelated ImportError re-raise
  • test_cli_list.py — registration, output format, filters, empty state, API errors
  • test_cli_exec.py — stdout/stderr streaming, exit codes, --cwd, --timeout, not-found errors
  • Full unit suite passes

Stack: 1/3 — exian/cli-coreexian/logsexian/shell

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces an optional CLI for the aviato SDK, providing terminal-based commands for common sandbox operations. The CLI is implemented as a Click-based subpackage available via the [cli] extra dependency, ensuring that importing the main aviato package doesn't require Click.

Changes:

  • Adds aviato list and aviato exec commands for listing and executing commands in sandboxes
  • Implements proper ImportError handling with helpful install instructions when Click is missing
  • Includes comprehensive test coverage for CLI commands, entry points, and error handling

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pyproject.toml Adds CLI console script entry point, cli optional dependency group, and includes click in dev dependencies
uv.lock Updates lock file with Click dependency and new version 0.1.1
src/aviato/main.py Entry point for python -m aviato and aviato console script with ImportError fallback handling
src/aviato/init.py Updates version to 0.1.1
src/aviato/cli/init.py Click group definition with version option and command registration
src/aviato/cli/list.py List command with filtering by status, tags, runway IDs, and tower IDs
src/aviato/cli/exec.py Exec command with real-time stdout/stderr streaming, cwd and timeout options
tests/unit/aviato/test_cli_main.py Tests for CLI entry point, help, version, and ImportError handling
tests/unit/aviato/test_cli_list.py Tests for list command registration, output format, filters, and error handling
tests/unit/aviato/test_cli_exec.py Tests for exec command with stdout/stderr streaming, exit codes, options, and error scenarios
tests/unit/aviato/conftest.py Adds event loop management for testing concurrent stdout/stderr streaming
docs/guides/execution.md Documents CLI exec command with examples
DEVELOPMENT.md Adds CLI usage documentation for developers
AGENTS.md Documents CLI architecture and conventions
src/aviato/AGENTS.md Updates file structure to include CLI package
tests/AGENTS.md Adds CLI test files to test inventory

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 15 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 15 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Collaborator

@NavarrePratt NavarrePratt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[via Claude]

Branch Review: exian/cli-core

Overview

  • Branch: exian/cli-core -> exian/fixes
  • Commits: 3 commits
  • Files Changed: 18 files (+667/-39 lines)
  • Review Team: 4 Claude reviewers (Opus) + Codex validation
  • Reviewers: Security, Correctness, Architecture, Simplicity

Outcome: APPROVED

No confirmed Critical or High findings after Codex validation. Two Medium findings were identified; one was already fixed in the latest commits (ImportError name attribute). One Medium finding remains (CLI error handling).

Full review report

Critical & High Findings

None.

Medium Findings

1. ImportError name check (FIXED)

  • File: src/aviato/cli/init.py:19
  • Status: Fixed in latest commits - name="click" now set on re-raised ImportError
  • Found by: reviewer-architecture, reviewer-simplicity, reviewer-correctness

2. No CLI-level error handling for SDK exceptions

  • File: src/aviato/cli/exec.py:50, src/aviato/cli/list.py:37
  • Status: Still present - inline comment posted
  • Found by: reviewer-security, reviewer-architecture

Low Findings

3. stderr drain truncation (Skipped)

  • File: src/aviato/cli/exec.py:63,70
  • Status: Standard thread pattern with pragmatic timeout; skipped after industry comparison
  • Found by: reviewer-correctness

4. Test validates wrong failure path (FIXED)

  • File: tests/unit/aviato/test_cli_main.py:47-63
  • Status: Fixed - new test_main_import_error_missing_click test added
  • Found by: reviewer-simplicity (Codex)

Review Statistics

  • Total findings (pre-validation): 12
  • Post-validation: 4 confirmed, 5 disputed, 2 severity-adjusted, 1 new from Codex
  • By severity: Critical: 0, High: 0, Medium: 2, Low: 2
  • Cross-reviewer overlap: 3 findings caught by 2+ reviewers
  • Claude-Codex agreement rate: 75%

Reviewer Notes

Security: Overall security posture solid. Shell injection prevented with shlex.quote(). Auth flows through gRPC infrastructure. No secrets in code.

Correctness: No data corruption, crash, or silent wrong-result risks. Concurrency model sound.

Architecture: Clean module boundary. CLI subpackage design is architecturally sound.

Simplicity: Excellent simplicity. No over-engineering detected.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 15 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 15 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 15 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 15 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 15 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Collaborator

@NavarrePratt NavarrePratt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[via Claude] The existing examples/ and docs/guides/ are strong. I see the later stack PRs (logs, shell) add logging.md, interactive-shells.md, and a new example script. A CLI-specific quickstart guide (installing the extra, common workflows like list -> exec -> logs) would round this out nicely as a follow-up after the full stack merges. Not blocking for this PR.



cli.add_command(exec_command, "exec")
cli.add_command(list_sandboxes)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[via Claude] Consider adding command aliases for common shorthand. Click supports registering the same command under multiple names:

cli.add_command(list_sandboxes)
cli.add_command(list_sandboxes, "ls")

ls for list is the most natural one. Could also consider run as an alias for exec if that feels right for the UX.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add ls as an alias for list in this PR. Skipping run as an alias for exec for now.

In the SDK, Sandbox.run() creates a new sandbox (one-shot) while sandbox.exec() runs commands in an existing one (repeatable). Aliasing the CLI exec to run could create confusion between these two distinct operations, especially for users who use both the SDK and CLI.

click.echo("No sandboxes found.")
return

click.echo(f"{'SANDBOX ID':<40} {'STATUS':<14} {'TOWER':<20} {'RUNWAY':<20} {'STARTED AT'}")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[via Claude] The tabular output covers the basics but users will likely want more detail for individual sandboxes (tags, resources, network config, full status history). A few ideas for follow-up after this stack lands:

  • aviato describe <sandbox-id> for detailed single-sandbox view
  • --output json on list for machine-readable output
  • --output wide for additional columns (tags, returncode, etc.)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we able to surface the tags? I wonder if it requires an aviato change. WIll file a follow up!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a number of things we usually store within the client sandbox instances that we only get when we create it. You can see what we get and don't get in the sandbox instance creation flow from the list/from-existing flow.

Copy link
Collaborator Author

@iiilisan iiilisan Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

follow up: #65 needed for --wide and describe

NavarrePratt
NavarrePratt previously approved these changes Feb 26, 2026
Base automatically changed from exian/fixes to main February 26, 2026 15:52
@iiilisan iiilisan dismissed NavarrePratt’s stale review February 26, 2026 15:52

The base branch was changed.

Managing sandboxes currently requires writing Python scripts for
every operation. A CLI enables quick terminal workflows — listing,
executing, and inspecting sandboxes — without boilerplate.

Add the cwsandbox CLI framework as an optional dependency with a
Click group, __main__ entry point, and ImportError fallback when
Click is not installed.
Add `cwsandbox ls` with table and JSON output formats. Supports
filtering by --status, --tag, --runway-id, and --tower-id.
Add `cwsandbox exec <sandbox-id> <command>` for running commands in
sandboxes with real-time stdout/stderr streaming. Supports --cwd and
--timeout options.

Update conftest make_process helper to use real event loops for
thread-safe stream iteration in tests.
Cover installation, ls/exec usage, and JSON output for scripting.
@iiilisan iiilisan changed the title feat(cli): Add aviato CLI with list and exec commands feat(cli): Add CLI with list and exec commands Feb 27, 2026
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.

3 participants