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 passapply=Trueexplicitly. 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
mainpublishes to PyPI. Seedocs/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 semantics —
webglass-cliowns 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-cliowns them - PR policy, acceptance judgment, or handoff decisions
- claiming containers are perfect isolation, or that worktrees contain anything
Repo furniture
- Mesh identity —
culture.yaml(suffix+backend) and the matching resident prompt file (AGENTS.colleague.md, since this agent runsbackend: colleague).CLAUDE.mdis 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.
Metadata
Release files for shell-cli 0.14.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| shell_cli-0.14.0.tar.gz | 590.1 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| shell_cli-0.14.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 737.6 kB
Release files / shell_cli-0.14.0.tar.gz
| Download URL | shell_cli-0.14.0.tar.gz |
|---|---|
| Size | 590.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1017a0ac175767da95cb0fe8c2fbaee8a441e0b51b5ea8b1681c7e3ed6b8fc01
|
|
BLAKE2b-256 checksum How to use checksums |
42f95061fc8d021aa0e9da6be8b66e435afcfabde7fb3748303939fb7d592c88
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|
Release files / shell_cli-0.14.0-py3-none-any.whl
| Download URL | shell_cli-0.14.0-py3-none-any.whl |
|---|---|
| Size | 147.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1421c4de9729189416a09907ba0bdd15a6bbd491bbbee78bd6ee7017accd117a
|
|
BLAKE2b-256 checksum How to use checksums |
3f3aac37507b8c37e07b2d719b4b5c313c566a835ddfa4cf0f78ab1f295f4e66
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|
Security for shell-cli 0.14.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.