Skip to main content

shell-cli

The guarded local operations plane for AI agents.

An agent harness has to touch the local machine constantly — read a file, write one, run a command, run the tests, run a linter, fire a hook, drive git, invoke a trusted CLI. Every harness reimplements that surface, and reimplements its safety model with it, usually worse each time.

shell-cli provides one place to plan, authorize, execute, observe, and record a local operation. It does not decide why, when, or which — that is the calling harness's job. It is not another agent: it contains no model, planner, memory, web browser, or domain workflow. It is the execution substrate beneath them.

colleague is the first consumer, not the owner. colleague imports shell-cli; shell-cli imports nothing from colleague.

Repo token shell-cli, console command shell, import package shell, PyPI distribution shell-cli.

⚠️ A guard, not a sandbox

Read this before you rely on anything here.

The execution gate is best-effort. It inspects the command string it is handed, so it is bypassable by sh -c, pipelines, shell expansion, here-docs, and any interpreter that takes code as an argument. There is no namespace, container, or seccomp isolation.

It protects against accidental and careless model behaviour. It does not protect against an adversarial one, and it is not a security boundary to put untrusted input behind.

A container runner is planned, and when it lands it will be described separately: a declared boundary with a documented profile, recorded per operation. It will not retroactively change what the host path above provides. The two claims stay textually separate on purpose.

Full detail — assets, actors, known bypasses, and what real isolation would require — in docs/threat-model.md. The same posture is readable in-band via shell explain safety, and tests/test_honesty.py fails the build if any shipped surface drops the disclaimer or claims isolation.

Status

The operation core is built, and the CLI has started catching up to it. The library has Operation, OperationResult, Environment, the ported policy evaluator, the evidence contract, and a HostRunner with real execution — fs.read, fs.list, fs.stat, fs.write, fs.edit, fs.media, process.exec, and process.shell are all built and green.

The CLI exposes the introspection verbs (whoami, learn, explain, overview, doctor, cli), two operation-aware nouns — policy check/policy explain evaluate the same gate execute() uses, and operation show retrieves persisted evidence — and two groups whose verbs execute operations: shell fs read|list|stat|write|edit|media and shell process exec|shell. They front operations.execute() rather than reimplementing anything, so the CLI and the library share one engine. Mutation and execution verbs preview by default and require --apply, and the flag is derived from each kind's registered intent rather than hand-maintained. process shell accepts the project profile only — a raw string is re-interpreted by a shell after the gate read it, so it cannot honestly carry control-plane trust.

shell env describe renders the selected environment's two axes and the runner's posture. env create/env destroy are deliberately absent until the lifecycle engine exists, rather than shipped as a facade.

Still library-only: the git noun group does not exist yet, and neither does a container runner or colleague delegation. Publishing is gated on the full quality suite plus a built-wheel smoke test.

Issue #1 is the source of truth for scope; the converged spec and the buildable plan live in docs/specs/ and docs/plans/.

The model

An operation is any local observation, mutation, process invocation, or environment lifecycle action. The boundary is work-affecting I/O — not every internal byte a runtime writes. Every operation follows one lifecycle:

intent -> Operation -> policy + preview -> environment backend
       -> result + evidence -> caller

Environments have two independent axes

"Host", "worktree" and "container" are not one overloaded mode. A workspace axis selects what may be observed and changed; a runner axis selects what executes it.

The Container rows are a design target, not a description of shipped behaviour. HostRunner is built and is what every shipped operation runs through today; ContainerRunner does not exist yet. The Intended guarantee column says what each combination provides for the Host rows now, and what the Container rows are meant to provide once built — read the Container rows as a specification and do not rely on them as a present-tense security property.

Workspace Runner Intended guarantee Built?
Checkout Host Guarded host execution; no isolation Yes
Worktree Host Reviewable/recoverable changes; no process isolation Yes
Checkout Container Execution isolation against the selected checkout No
Worktree Container Preferred autonomous mode No

When the container rows are built, their actual profile gets measured and recorded per operation, and documented separately from the host claim above. Until then the honest summary of what shell-cli isolates is: nothing.

Three operation profiles

Every subprocess declares why it is running, because not all of them deserve equal trust.

  • project — executes repository-controlled code: model-issued commands, tests, linters, repo hooks.
  • control — executes trusted control-plane programs: git mechanics, neighbouring AgentCulture CLIs, the container engine itself. Argv vectors only; raw shell strings are not appropriate here.
  • observe — structured reads confined to the selected root.

Evidence is a product surface

Every operation produces a structured record suitable for the model, the operator, telemetry, and an external validator: what was requested and how it normalized, the policy verdict, the environment and runner, timing and exit status, separately captured stdout/stderr with truncation markers, and the known filesystem/git effects — plus an honest marker for whether that effect list is complete. Secrets are never recorded, and a failure to capture evidence never turns an executed action into an unrecorded success.

Constraints that hold it together

  • Pure-stdlib core, zero base dependencies. dependencies = [], guarded by a test. colleague allow-lists exactly its sanctioned base deps; a third-party dependency here means colleague cannot import this package at all. Optional integrations go behind extras.
  • A guard, not a sandbox — see above.
  • Mutation and execution preview by default. The CLI requires --apply; imported callers must pass apply=True explicitly. A preview is never reported as success — it gets its own status.
  • Library first, CLI second. The CLI is a front end over the same operation engine, never a second implementation.
  • Every PR bumps the version — every push to main publishes to PyPI. See docs/release-runbook.md.

Quickstart

uv sync
uv run pytest -n auto                 # run the test suite
uv run shell whoami                   # identity from culture.yaml
uv run shell learn                    # self-teaching prompt (add --json)
uv run shell explain safety           # the safety posture, in-band
uv run teken cli doctor . --strict    # the agent-first rubric gate CI runs

CLI

Verb What it does
whoami Report this agent's nick, version, backend, and model from culture.yaml.
learn Print a structured self-teaching prompt.
explain <path> Markdown docs for any noun/verb path (explain safety for the threat model).
overview Read-only descriptive snapshot of the agent.
doctor Check the agent-identity invariants (prompt-file-present, backend-consistency).
cli overview Describe the CLI surface itself.

Every command supports --json. Results go to stdout, errors/diagnostics to stderr (never mixed). Exit codes: 0 success, 1 user error, 2 environment error, 3+ reserved.

Non-goals

shell-cli is deliberately not a general agent layer. It owns local operation mechanics and nothing else:

  • reasoning, planning, roles, or agent orchestration — colleague's job
  • model APIs or prompt construction
  • web search and navigation semanticswebglass-cli owns them, as a separate repository and a separate colleague capability seam. shell-cli does not embed a browser and does not model web actions as local operations. Only provider-neutral artifact transfer crosses between the two: a file webglass produces is just a file shell-cli can be asked to read.
  • memory semantics — eidetic-cli owns them
  • PR policy, acceptance judgment, or handoff decisions
  • claiming containers are perfect isolation, or that worktrees contain anything

Repo furniture

  • Mesh identityculture.yaml (suffix + backend) and the matching resident prompt file (AGENTS.colleague.md, since this agent runs backend: colleague). CLAUDE.md is the Claude Code prompt and the contributor guide.
  • The canonical guildmaster skill kit under .claude/skills/, vendored cite-don't-import. Provenance and the re-sync procedure: docs/skill-sources.md.
  • Build + deploy baseline — pytest, lint, the agent-first rubric gate, and PyPI Trusted Publishing wired into GitHub Actions.

License

Apache 2.0 — see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

shell_cli-0.14.0.tar.gz (590.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

shell_cli-0.14.0-py3-none-any.whl (147.5 kB view details)

Uploaded Python 3

File details

Details for the file shell_cli-0.14.0.tar.gz.

File metadata

  • Download URL: shell_cli-0.14.0.tar.gz
  • Upload date:
  • Size: 590.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.0 {"installer":{"name":"uv","version":"0.12.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for shell_cli-0.14.0.tar.gz
Algorithm Hash digest
SHA256 1017a0ac175767da95cb0fe8c2fbaee8a441e0b51b5ea8b1681c7e3ed6b8fc01
MD5 bf3584343a95e42cd7c11fc0787f2b71
BLAKE2b-256 42f95061fc8d021aa0e9da6be8b66e435afcfabde7fb3748303939fb7d592c88

See more details on using hashes here.

File details

Details for the file shell_cli-0.14.0-py3-none-any.whl.

File metadata

  • Download URL: shell_cli-0.14.0-py3-none-any.whl
  • Upload date:
  • Size: 147.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.0 {"installer":{"name":"uv","version":"0.12.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for shell_cli-0.14.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1421c4de9729189416a09907ba0bdd15a6bbd491bbbee78bd6ee7017accd117a
MD5 02ff2a25c9b68bd61a2293781ade40ce
BLAKE2b-256 3f3aac37507b8c37e07b2d719b4b5c313c566a835ddfa4cf0f78ab1f295f4e66

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.14.0 This release

2 files

0.13.1

2 files

0.8.7

2 files

0.8.2

2 files

0.8.0

2 files

0.7.2

2 files

0.6.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page