Skip to content

Releases: ScottRBK/agent-shell

v0.4.0

Choose a tag to compare

@ScottRBK ScottRBK released this 06 Sep 20:00
a23b692

AgentShell can now open the agents' native interactive UIs in tmux, alongside its existing
headless execution API. This release also adds persistent Pi package and local extension management.

Interactive tmux sessions

  • AgentShell.open_interactive() opens a native agent UI through TmuxExecutionHost for all
    seven supported agents. Native permission prompts remain available.
  • Sessions expose terminal controls and structured events where the harness supports them;
    session.capabilities reports the available features.
  • TmuxPlacement.split_pane(direction="right" | "down") adds pane placement alongside new
    sessions and windows. Existing session names are matched exactly.
  • Cleanup removes only the resources owned by the run, preserving neighbouring panes and sessions.

Packages and local extensions

  • Adds the shared PackageSpec, add_package, list_packages, and remove_package API.
    Pi is the first implementation; other adapters report unsupported operations clearly.
  • Supports exact npm versions, Git sources with explicit refs, local extension files, and package
    directories. Registrations persist for later AgentShell instances through Pi's existing settings.
  • Local files remain in place, including symbolic-link identities. Removing a local registration
    preserves the source files.
  • Source validation, persistence checks, timeouts, and cancellation handling surface installation
    failures, including cases where Pi exits successfully without saving its settings.

Compatibility

  • No intended breaking changes to existing headless APIs or execution defaults.
  • Interactive sessions remain experimental and opt-in. Feature support varies by harness;
    tmux is required, and this host currently supports NoIsolation only.
  • Package management uses the caller's existing Pi configuration. Callers own container isolation;
    per-run resource selection and individual resource toggles are outside this initial API.
  • No new Python runtime dependencies.

See usage examples and package implementation details.

Validation

  • Unit/integration CI and the tag build passed: 1,102 tests passed and 18 were skipped on the
    hosted runner. The wheel and source archive report version 0.4.0 and contain the runtime files.
  • Five real Pi package smoke tests passed without downloads or model requests.
  • Independent Astra x-high review completed; its symbolic-link finding was fixed and verified.

Full changelog: v0.3.2...v0.4.0

agent-shell-py 0.3.2

Choose a tag to compare

@ScottRBK ScottRBK released this 05 Sep 10:27

Adds three experimental ways to watch agent runs and an explicit PID isolation option for
restricted Linux containers.

New features

  • HerdrExecutionHost: run each command in an owned Herdr pane.
  • TmuxExecutionHost: run in a new session or a new window in an existing session, with
    explicit placement through TmuxPlacement.
  • TerminalWindowExecutionHost: mirror a headless run into a graphical terminal window.
  • LinuxPidNamespaceIsolation(mount_proc=False): retain the PID signal boundary, PID 1
    reaper, and descendant cleanup when a private /proc mount is unavailable. The selected
    mode is probed explicitly and never silently falls back.

Compatibility and limitations

  • Native execution and existing isolation defaults remain unchanged. The existing
    AGENTSHELL_ISOLATION_POLICY=linux-pid-namespace value still mounts a private /proc.
  • The three visible execution hosts are experimental, opt-in, and currently support
    NoIsolation only. Their APIs may change in a later minor release.
  • mount_proc=False inherits outer /proc visibility and does not create a private mount
    namespace. Process tools may report PIDs that differ from the child's namespace PIDs.
    This policy is not a filesystem, network, or credential sandbox.
  • No new Python runtime dependencies. Visible hosts require their external executables.
  • Added lifecycle, compatibility, public-export, and E2E tests, plus updated API documentation.
  • Stabilized the Herdr cleanup test by allowing subprocess startup time on shared CI runners;
    the simulated hung command remains bounded.

Validation

  • 979 unit and integration tests passed locally. CI and the tag build passed; the tag build
    ran 961 tests and skipped 18 namespace tests unavailable on the hosted runner.
  • Both live Codex PID isolation E2E cases passed: private and inherited /proc.
  • Downstream checks passed: 44 Pi extension tests and 128 relevant eval-harness tests.

Full changelog: v0.3.1...v0.3.2

agent-shell-py 0.3.1

Choose a tag to compare

@ScottRBK ScottRBK released this 28 Aug 16:52

Isolation policy environment configuration

AgentShell can now select its isolation policy through the process environment:

export AGENTSHELL_ISOLATION_POLICY=linux-pid-namespace

Accepted values are none and linux-pid-namespace. Resolution is deliberately predictable:

  1. An explicit isolation_policy= object
  2. AGENTSHELL_ISOLATION_POLICY
  3. NoIsolation()

Empty or unknown values raise ValueError instead of silently disabling isolation. When the
variable is unset, existing callers retain the NativeExecutionHost() plus NoIsolation()
default.

Verification

  • Added public-constructor coverage for both values, invalid configuration, the unchanged default,
    and explicit-policy precedence.
  • Added a real-process integration test proving the environment-selected CLI runs as PID 2 inside
    the Linux PID namespace.
  • Updated the README, architecture documentation, and invoking-cli-agents skill/API reference.
  • All 860 unit and integration tests passed locally and in GitHub Actions.
  • Independent Claude Code Opus review at high effort returned READY TO COMMIT with no actionable
    warnings.

Full changelog: v0.3.0...v0.3.1

v0.3.0

Choose a tag to compare

@ScottRBK ScottRBK released this 28 Aug 14:22

What’s new

Composable execution hosts and isolation policies

AgentShell now separates where a CLI process runs from how that process is isolated:

  • ExecutionHost owns process launch and returns a per-run RunHandle.
  • IsolationPolicy can independently prepare a launch.
  • NativeExecutionHost with NoIsolation remains the default, preserving existing callers.
  • All seven adapters use the new execution seam for execute(), stream(), and health_check().

This provides the foundation for future execution hosts such as tmux and Herder without requiring new agent adapters.

Opt-in Linux PID namespace isolation

LinuxPidNamespaceIsolation places the CLI and its descendants inside a rootless user/PID namespace. This prevents child-namespace processes from seeing or directly signalling AgentShell’s ancestor processes.

Isolation requests fail closed when the required Linux kernel features or unshare support are unavailable. There is no silent fallback to native execution.

This is a process/signal boundary, not a general sandbox: it does not restrict filesystem access, credentials, networking, tools, resources, or every possible host-side signalling path.

Process lifecycle improvements

  • Process execution and cancellation now flow through RunHandle across every adapter.
  • Non-zero exits expose normalized returncode and signal metadata in stream events and AgentExecutionError.
  • Process guardians remain attached to the stable run handle throughout normal completion, cancellation, abandoned streams, and interpreter shutdown.

Documentation and test reliability

  • Documented Cursor’s user-scope MCP configuration behavior.
  • Cursor E2E and health checks now explicitly select auto, avoiding mutable named-model defaults that free Cursor plans cannot execute.
  • Added real-kernel and integration coverage for execution-host wiring, PID isolation, cancellation, status propagation, and fail-closed behavior.

Compatibility

There are no intentional breaking defaults in this release. Existing AgentShell(agent_type=...) callers continue to use native execution without isolation unless they explicitly select a different host or policy.

Full Changelog: v0.2.5...v0.3.0

v0.2.5

Choose a tag to compare

@ScottRBK ScottRBK released this 08 Aug 23:42

Full Changelog: v0.2.4...v0.2.5

v0.2.4

Choose a tag to compare

@ScottRBK ScottRBK released this 08 Aug 20:59

What's new

Grok Build CLI adapter

  • New AgentType.GROK backed by the grok CLI
  • Headless via --output-format streaming-messages-json (full assistant blocks)
  • execute / stream / health_check / list_models
  • Session resume via --resume
  • Canonical tool denies (bashrun_terminal_cmd, verified live)
  • User-scoped MCP add/remove/list (~/.grok/config.toml)
  • Cost, duration, and raw output_tokens from the terminal result event

Docs

  • README, AGENTS.md, agent parameter comparison, and installable skills updated for seven agents

Install

uv add agent-shell-py==0.2.4
# or
pip install agent-shell-py==0.2.4

v0.2.3

Choose a tag to compare

@ScottSDWorx ScottSDWorx released this 07 Aug 09:09
0a9e1f5

Fixes

  • Normalise Copilot CLI reasoning-effort values case-insensitively.
  • Pass supported effort values to Copilot in the required lowercase form.
  • Reject unsupported effort values before starting the Copilot CLI process.
  • Update the Copilot CLI parameter documentation for the current effort choices and flags.

Tests

  • 735 unit and integration tests passed.
  • Added regression coverage for every supported effort value, case normalisation, and invalid-value rejection.

This release includes the unreleased changes merged in PR #16 and addresses issues #14 and #15.

Full changelog: v0.2.2...v0.2.3

v0.2.2

Choose a tag to compare

@ScottRBK ScottRBK released this 02 Aug 19:52

Closes #13.

Process cleanup safety

AgentShell no longer stores numeric process-group IDs and later tries to infer whether they still
belong to an AgentShell child. A reaped PID can be reused by Linux, so that design could send
SIGKILL to an unrelated process group.

Each agent execution now uses a dedicated process-group guardian:

  • AgentShell owns the guardian through a private pipe, an exact kernel object that cannot be
    confused with a recycled PID.
  • Cancellation, abandoned streams, model-discovery cleanup, and interpreter exit ask the guardian
    to kill its own group.
  • Normal stream completion releases the guardian without killing processes intentionally left by
    the CLI.
  • If the guardian has already died, cleanup fails safe and accepts a possible leak rather than
    signalling a numeric process-group ID.
  • Guardians close inherited file descriptors and redirect their own output to /dev/null.

All six adapters and every model-discovery path now use the same ownership-safe mechanism.

Tests and review

  • Added real-process lifecycle coverage for all six adapters through normal completion,
    cancellation, and stream abandonment.
  • Added kernel-level coverage for child/grandchild cleanup, dead-guardian failure, interpreter
    disappearance, already-reaped CLIs, model-discovery cleanup, and file-descriptor isolation.
  • Full local suite: 784 passed, 2 skipped.
  • Process-lifecycle suite passed 10 consecutive stress runs.
  • Wheel and source distribution builds verified.
  • Reviewed twice by Claude Code Opus at maximum effort with no blocking findings.

v0.2.1

Choose a tag to compare

@ScottRBK ScottRBK released this 02 Aug 17:19

Model discovery

AgentShell can now ask every supported CLI which models it currently advertises:

models = await shell.list_models(cwd="/path/to/project")
response = await shell.execute(
    cwd="/path/to/project",
    prompt="Review this project",
    model=models[0],
)

The returned strings are passed unchanged to execute(model=...) and stream(model=...).
Discovery is account/workspace-aware, sends no inference prompt, imports no harness SDK, and
uses no static fallback catalog.

Supported discovery paths:

  • Claude Code stream-JSON initialization
  • opencode models
  • Copilot CLI headless JSON-RPC
  • codex debug models
  • pi --no-approve --list-models
  • cursor-agent models

Reliability

  • Added timeout, cancellation, malformed-output, and UTF-8 error handling.
  • Discovery subprocesses use an isolated live process-group sentinel, preventing both leaked
    descendants and signalling through a reaped/reused CLI PID.
  • Pi selectors are provider-qualified so duplicate model IDs remain unambiguous.
  • Harness ordering and aliases such as auto and default are preserved.

Documentation and tests

  • Updated the README, AgentShell skill, architecture notes, and agent parameter comparison.
  • Added parser, integration, process-lifecycle, selector pass-through, and real-CLI E2E tests.
  • 726 unit/integration tests pass, all six model-discovery E2Es pass, and the full local E2E
    suite was verified before release.

v0.2.0

Choose a tag to compare

@ScottRBK ScottRBK released this 26 Jul 10:04

Closes #7, #10, #11.

Breaking changes

execute() now raises AgentExecutionError instead of returning on failure.
Previously a crashed, truncated or agent-level-failed run was indistinguishable from an
empty answer. Callers that relied on inspecting an empty response must now catch:

from agent_shell.models.agent import AgentExecutionError

try:
    result = await shell.execute(cwd=..., prompt=...)
except AgentExecutionError as e:
    print(f"failed: {e}")   # str(e) is the bare reason

AgentExecutionError carries whatever partial data the run produced (response, cost,
session_id, duration, output_tokens).

AgentType.GEMINI_CLI removed. Gemini is deprecated and never had an adapter, so
constructing it always raised ValueError. shell.py now has a module-level _ADAPTERS
registry, pinned to the enum by a test so a future AgentType cannot ship without one.

Fixes

  • #7 Process and stderr teardown was duplicated and subtly wrong across all six adapters.
    Now a shared release_process() called from a finally in every stream().
    kill_process_group() signals only while the pid still leads its own group — asyncio's
    ThreadedChildWatcher reaps the child and frees its pid before setting returncode, so
    returncode is not a sound liveness test and a recycled pid could be signalled.
  • #10 The Pi adapter reported success for failed runs. It now recognises failing stop
    reasons, prefers Pi's structured errorMessage, and judges only the last assistant message,
    since Pi emits multiple agent_end events when it auto-retries.
  • #11 A shared outcome.py holds one success predicate and reason precedence used by both
    execute() and health_check(), so the two cannot drift; response.py holds the shared
    aggregation.
  • cleanup_process_groups() bypassed the new pid-leader guard and called os.killpg directly.
  • Orphaned grandchildren leaked when the child was reaped while its process group still had
    live members. Reclaimed on the abandoned path.
  • A failing unit test could leave an invented pid in the module-global registry, and atexit
    would then SIGKILL whatever real process group held that number.

Documentation

  • Codex and Cursor cannot enforce disallowed_tools; the skill docs told readers to rely on it
    for read-only reviewers.
  • Stderr in error events is head+tail (500 characters each side), not the documented last 500.
  • Added a Pi section and documented Cursor as a supported agent.
  • Corrected process-cleanup docstrings that asserted measurably false claims.

Tests

Session-resumption e2e tests asserted that a model would recall a planted word, measuring model
compliance rather than library behaviour — one failed because the model declined to repeat the
token. All six adapters now assert session-id identity across a resume plus a distinct id for a
fresh session. Copilot e2e is pinned to the free auto model, with the two reasoning-effort
tests gated behind COPILOT_PAID_TIER.

682 unit and integration tests passing; 57 e2e passing, 2 skipped.