Skip to content

Build brief: shell-cli — the guarded local operations plane for AI agents #1

Description

@OriNachum

Build brief: shell-cli — the guarded local operations plane for AI agents

This issue is the architectural source of truth for shell-cli. It supersedes
the original narrow “extract six tools from Colleague” framing while preserving
that extraction as the first compatibility slice.

The identity is settled:

  • repository and PyPI distribution: shell-cli
  • console command: shell
  • import package: shell
  • first consumer: agentculture/colleague

The repository is currently a green scaffold. Development has not started, so
we will establish the complete boundary before copying implementation.

1. Vision

shell-cli is the guarded local operations plane for AI agents.

Colleague should decide why, when, and which action to take.
shell-cli should provide one place to plan, authorize, execute, observe, and
record the local operation.

That includes more than the six model-facing tools. Files, arbitrary commands,
curated tests, lint, hooks, Git/worktree mechanics, and trusted external CLIs
all eventually need the same operation lifecycle even when their higher-level
semantics stay elsewhere.

The separation is:

Colleague                 shell-cli                    capability CLIs
-----------------------   --------------------------   ----------------------
reason and plan           materialize environment      devague semantics
choose capabilities       normalize operation          eidetic semantics
apply roles               evaluate operation policy    culture semantics
orchestrate agents        execute locally              coherence semantics
interpret results         capture effects/evidence     webglass web semantics
validate completion       report structured outcome

shell-cli is not another agent. It contains no model, planner, memory, web
browser, or domain workflow. It is the execution substrate beneath them.

2. The operation is the core abstraction

An operation is any local observation, mutation, process invocation, or
environment lifecycle action.

The boundary is work-affecting I/O, not every internal byte Colleague ever
writes. Runtime-private bookkeeping such as artifacts, trace/flight feeds,
telemetry buffers, caches, and lock files remains with its owning runtime unless
it executes code or touches the target workspace. This prevents shell-cli from
becoming a god-layer around ordinary application internals.

Every operation follows one lifecycle:

flowchart LR
    C["Colleague intent"] --> O["Operation"]
    O --> P["Policy + preview"]
    P --> B["Environment backend"]
    B --> E["Result + evidence"]
    E --> C
Loading

The pure library contract should be provider-neutral and JSON-serializable:

operation = Operation(
    kind="process.exec",
    arguments={"argv": ["python", "-m", "pytest"]},
    profile="project",
    apply=True,
    caller={"agent": "colleague", "task_id": "...", "tool": "run_tests"},
)

result = operations.execute(operation, environment)

The concrete names may improve during design, but the semantics are fixed:

Operation

  • stable operation id
  • kind and normalized arguments
  • intent: observe, mutate, execute, or lifecycle
  • execution profile
  • caller/provenance metadata
  • explicit preview/apply intent
  • timeout and resource request

OperationResult

  • status: previewed, denied, succeeded, failed, or timed_out
  • structured output and a bounded human/model rendering
  • policy verdict and reason
  • known effects: changed paths, bytes written, Git refs/diff, created resources
  • evidence: backend, root, cwd, mounts, network, timing, exit code, truncation
  • honest completeness marker for effects that cannot be fully observed
  • neutral media observation when applicable

A preview is never reported as success. A shell command preview describes what
would run; it does not pretend to predict the command's effects.

3. Environments have two independent axes

Do not encode “host,” “worktree,” and “Docker” as one overloaded mode.

Workspace/root axis

  • operator checkout
  • existing caller-provided worktree
  • shell-managed generic worktree, when that capability is migrated

Runner axis

  • HostRunner
  • ContainerRunner using Docker or Podman
  • a future VM/remote runner behind the same contract

The useful matrix is:

Workspace Runner Guarantee
Checkout Host Guarded host execution; no isolation
Worktree Host Reviewable/recoverable changes; no process isolation
Checkout Container Execution isolation against the selected checkout
Worktree Container Preferred autonomous mode: isolated execution + reviewable changes

Colleague already uses worktree + host for work/drive and parallel
children. Interactive sessions run checkout + host, and failed worktree
creation may degrade to in-place execution. shell-cli must preserve those
behaviours during migration rather than rebuilding a simpler competing
worktree system.

An environment therefore distinguishes at least:

  • source_root: trusted repository/control context
  • work_root: the tree operations may observe/change
  • runner: host/container implementation
  • read-only paths
  • mount policy
  • network policy
  • environment-variable and secret policy
  • user identity, resource limits, and timeout defaults

Policy is snapshotted from trusted control context before model mutations; an
agent must not be able to edit its own active authorization by changing a file
inside the work root.

4. Three operation profiles

Every subprocess must declare why it is running. Avoid treating all
subprocess.run calls as equally trusted.

project

Executes repository-controlled code:

  • model-issued shell commands
  • tests
  • lint/format tools
  • affected-test runners
  • repository hooks when configured as project code

Target: containerized by default, network disabled unless explicitly granted.

control

Executes trusted agent/control-plane programs:

  • git worktree/handoff mechanics
  • devague, eidetic, culture, and coherence CLIs
  • neighbour clone management
  • Docker/Podman itself when materializing a container runner

Host execution is expected, but it should use argv vectors, executable
allow-lists, minimal environment inheritance, explicit cwd, bounded output, and
evidence. Raw shell strings are not appropriate for control operations.

observe

Structured reads such as file listing, text/media loading, status, and diff.
These are confined to the selected root and never imply process isolation.

5. Where every Colleague operation goes

“All operations have a place” does not mean all semantics move into shell-cli.
The mechanism moves; domain intent stays with its owner.

Current Colleague action Target operation level Semantic owner
read_file, list_dir fs.read, fs.list shell-cli
write_file, edit_file fs.write, fs.edit shell-cli
view_media confined neutral fs.media observation shell-cli; Colleague adapts model payload
run_command process.shell, profile project shell-cli
run_tests curated process.exec, profile project Colleague chooses argv; shell-cli executes
lint / affected tests process.exec, profile project Colleague chooses gate; shell-cli executes
hooks process.exec with declared profile Colleague owns hook lifecycle; shell-cli executes
worktree add/remove/prune generic Git/worktree operations Colleague owns task/branch lifecycle; shell-cli owns mechanism
commit/diff/merge/handoff Git calls generic Git operations Colleague owns handoff semantics; shell-cli executes
neighbour cloning Git control operation Colleague selects neighbours; shell-cli executes
Devague / Culture / Eidetic / Coherence trusted CLI control operation each CLI owns semantics; shell-cli invokes
subagent launch child environment request Colleague owns orchestration; shell-cli materializes local environment
finish, deepthink, model completion not a local shell operation Colleague
web search/navigation not shell semantics webglass-cli provider
artifacts, flight feeds, telemetry buffers, caches, locks runtime-private bookkeeping owning runtime; direct stdlib I/O

The end state should make direct process creation in Colleague exceptional and
mechanically guarded. Project-code execution must not bypass the selected
shell environment merely because it came from run_tests, lint, or a hook
instead of run_command.

6. Library first, CLI second

The importable API is primary. The CLI is a front end over exactly the same
operation engine.

Canonical CLI groups:

shell env describe|create|destroy
shell fs read|list|stat|write|edit|media
shell process exec|shell
shell git status|diff|worktree|commit|merge
shell policy check|explain
shell operation show
shell whoami|learn|explain|doctor

Compatibility aliases such as shell read, shell edit, and shell run may
exist, but they must not distort the library model.

Every command supports structured JSON. Results go to stdout; diagnostics go
to stderr. Long-running operations support streaming events and cancellation.

Mutation and execution verbs preview by default in the human/agent CLI and
require --apply. Reads execute immediately. Imported callers must also state
apply=True explicitly. The Colleague compatibility adapter passes it for
today's immediately-applied write_file, edit_file, and run_command
semantics.

7. Layered safety model

Safety has four distinct layers. Do not merge their claims.

  1. Capability authorization — Colleague. Roles decide which semantic tools
    may be offered and invoked.
  2. Operation policy — shell-cli. The normalized operation is allowed,
    denied, or previewed under an operator-supplied policy snapshot.
  3. Execution isolation — runner. Host mode is a guard; container mode is a
    declared isolation boundary with a documented profile.
  4. Outcome validation — Colleague. Tests, lint, integrity, acceptance, and
    handoff gates decide whether the work is acceptable.

For Colleague, the ordering must remain:

role gate → pre-tool hook/rewrite → operation policy → execution
          → evidence/result → post-tool hook → validation/handoff gates

Host honesty

HostRunner is a guard, not a sandbox. Structured filesystem primitives
are path-confined; a raw host shell command can escape the repository through
shell expansion, interpreters, absolute paths, network calls, or child
processes. Documentation and result metadata must say this plainly.

Container baseline

The default project container profile should include:

  • non-root user mapped to appropriate host UID/GID
  • no privileged mode and no Docker socket
  • all capabilities dropped unless explicitly restored
  • network disabled by default
  • read-only container root filesystem
  • only the selected work root mounted writable
  • explicit dependency/cache volumes
  • bounded CPU, memory, pids, output, and wall time
  • explicit, redacted secret injection

Dependency preparation may be a separate network-enabled operation that
populates a cache/volume. It must not quietly enable network during the sealed
test or execution phase.

A linked Git worktree contains a .git pointer into the source repository's
common Git directory. Mounting only the worktree into a container therefore
does not preserve today's in-worktree Git behaviour. The container milestone
must explicitly choose between:

  • project containers do not receive Git metadata; structured Git operations run
    through the trusted control plane; or
  • the environment receives isolated Git metadata that cannot mutate unrelated
    host refs.

Do not solve this by broadly mounting the host repository's common .git
directory writable. That would give project code a path back into operator refs
and weaken the isolation claim.

Policy compatibility

The evaluator and policy data structures move to shell-cli. Location resolution
does not:

  • shell core accepts explicit policy data/files and has no .colleague import
  • the Colleague adapter preserves existing repo/user/model overlays and file
    format during migration
  • shell-native policy can be versioned independently
  • absent policy and malformed configured policy are distinct states; native
    policy should not silently turn a malformed declared gate into allow-all

8. Evidence is a product surface

Every operation produces a structured evidence record suitable for the model,
the operator, telemetry, and a validator such as Heimdall.

Minimum evidence:

  • operation id, caller, task and tool
  • requested and normalized operation
  • preview/applied state
  • policy verdict and matched rule
  • environment id, workspace kind, runner, root and cwd
  • mounts, network and resource profile
  • start/end/duration
  • exit code or structured error
  • separately captured stdout/stderr with bounded rendering
  • truncation markers plus hashes/byte counts of full captured output when known
  • known filesystem/Git effects and whether that effect list is complete

Secrets are never recorded. Evidence failure must not turn an executed action
into an unrecorded success; the result must honestly mark degraded evidence.

Colleague maps neutral results into its existing ToolOutcome, Step, media
message, progress, statistics, and artifact shapes. shell-cli must not import
Colleague contracts.

9. Pure-stdlib core

The base package has zero third-party runtime dependencies.

  • filesystem, policy, subprocess, JSON, hashes, dataclasses, and streaming use
    the Python standard library
  • Git, Docker, and Podman are optional external executables discovered on PATH,
    not Python SDK dependencies
  • optional protocol/rendering integrations live behind extras
  • a zero-dependency/import-leak guard is required from the first implementation PR

The dependency direction is one-way:

Colleague → shell-cli
shell-cli ↛ Colleague

10. Compatibility invariants

The first consumer migration is successful only if Colleague loses no behaviour.

  • The six existing OpenAI tool schemas remain byte-equivalent, including order
    and descriptions, until an intentional separately-reviewed schema change.
  • Role curation and runtime refusal remain intact.
  • Hook rewrite precedes command policy.
  • Policy denial remains a non-success step with the same model-visible reason
    and telemetry meaning.
  • write_file / edit_file still apply immediately through the adapter.
  • run_command remains a fresh shell, rooted cwd, bounded timeout, and current
    output rendering during the parity milestone.
  • line numbering, truncation, media size/type limits, and error messages remain
    compatible.
  • changed-file aggregation, subagent changes, and bytes_written ROI accounting
    remain intact.
  • Colleague's worktree/self-commit/continuation/merge/handoff behaviour remains intact.
  • malformed arguments remain recoverable model-visible tool errors, never run aborts.

Characterization tests must compare the legacy and new execution paths against
the same fixtures before the legacy implementation is removed.

11. Target package shape

Illustrative, not a mandate on filenames:

shell/
├── operations.py       # Operation and dispatch
├── results.py          # neutral results/effects
├── environment.py      # source/work roots + profiles
├── policy.py           # evaluator and versioned policy data
├── evidence.py         # events, redaction, rendering
├── fs/                 # confined file/media operations
├── process/            # argv and raw-shell operations
├── git/                # generic Git/worktree primitives
├── runners/
│   ├── host.py
│   └── container.py
└── cli/

Avoid a giant Shell god object. Operation handlers should be small and
composable behind one lifecycle pipeline.

12. Delivery plan

This issue is the umbrella contract. Implement it in independently reviewable
vertical slices; do not ship one giant rewrite.

Milestone 0 — inventory and characterization

  • inventory every process/workspace mutation path in Colleague and explicitly
    classify runtime-private bookkeeping as exempt or mediated
  • classify it as project, control, observe, or not a shell operation
  • snapshot the six tool schemas and observable behaviour
  • establish cross-repo compatibility fixtures

Milestone 1 — operation core + parity provider

  • implement Operation, OperationResult, Environment, policy, evidence,
    confined filesystem operations, and HostRunner
  • expose the six compatibility schemas/provider
  • keep pure-stdlib and CLI dry-run guarantees
  • do not remove Colleague's implementation yet

Milestone 2 — Colleague delegates the six tools

  • compose shell-cli into Colleague's existing router; do not subclass it
  • preserve roles, hooks, policy ordering, result mapping and accounting
  • run old/new characterization in parallel tests
  • publish shell-cli, pin a tested floor in Colleague, then remove duplication

Milestone 3 — route all Colleague local operations

  • project execution: run_tests, lint, affected tests, configured project hooks
  • control execution: Git/worktrees/handoff, neighbour cloning, AgentCulture CLIs
  • add a boundary test preventing new unclassified direct subprocess paths
  • preserve Colleague's domain orchestration and worktree semantics

Milestone 4 — container runner

  • Docker/Podman backend with the declared isolation profile
  • project profile uses container execution when selected
  • Colleague's existing worktree becomes the mounted work root
  • dependency preparation and sealed execution are distinct operations
  • host fallback is explicit and visible, never silent

Milestone 5 — ecosystem providers

  • publish the stable capability/evidence contract for other harnesses
  • integrate webglass-cli as a separate semantic provider
  • let other AgentCulture CLIs reuse the control-operation invocation path

13. Test ownership

Tests move according to responsibility, not by filename.

shell-cli owns

  • operation lifecycle and result states
  • filesystem confinement and symlink escapes
  • read/write/edit/list/media behaviour
  • HostRunner and ContainerRunner
  • policy parsing/evaluation
  • preview/apply semantics
  • evidence/redaction/truncation
  • generic Git/worktree primitives
  • zero-dependency/import cleanliness

Colleague retains

  • role schema curation and runtime refusal
  • hook ordering/rewrite/deny behaviour
  • all-engine policy parity
  • ToolOutcome and media-message adaptation
  • changed/subagent/ROI aggregation
  • worktree branch naming, continuation and handoff semantics
  • loop recovery, telemetry, validation gates and artifact parity

14. Definition of done

  • Every Colleague work-affecting local operation is inventoried and classified;
    runtime-private bookkeeping is explicitly accounted for.
  • Every project-code execution path uses the selected shell environment.
  • Every trusted control subprocess uses an explicit control profile.
  • Colleague has no unclassified direct subprocess path.
  • The six original tools migrate with observable parity.
  • Existing worktree and handoff guarantees remain green.
  • Host mode is documented as a guard, never a sandbox.
  • Container mode's actual isolation profile is tested and recorded per operation.
  • Structured evidence is available to Colleague, humans, telemetry, and validators.
  • Base shell-cli remains pure-stdlib.
  • The CLI and library use the same operation engine.
  • Colleague imports shell-cli; shell-cli never imports Colleague.

15. Non-goals

  • reasoning, planning, roles, or agent orchestration
  • model APIs or prompt construction
  • web search/navigation semantics (webglass-cli owns them)
  • memory semantics (eidetic-cli owns them)
  • Devague/Culture/Coherence domain logic
  • PR policy, acceptance judgment, or handoff decisions
  • claiming containers are perfect isolation or worktrees are sandboxes
  • adding abstractions with no current Colleague or CLI consumer

16. Infographic corrections

The current first-draft infographic is visually useful, but the next version
should reflect this issue:

  • title: “The Guarded Local Operations Plane for AI Agents”
  • show workspace and runner as a 2×2 matrix, including worktree + host
  • do not label checkout + host as Colleague's universal default
  • say structured file operations are path-confined; raw host shell is not
  • distinguish project execution from trusted control operations
  • show policy → backend → evidence as the central lifecycle
  • label the media result provider-neutral
  • show Preview and Apply as distinct states, not an ambiguous toggle
  • include evidence/effects as a first-class output

17. First implementation decision

Before large-scale work, reply with a concrete Milestone 0/1 plan that names:

  1. the proposed operation/result/environment types;
  2. the exact Colleague characterization tests;
  3. how policy ordering and role refusal remain unchanged;
  4. how state/accounting is mapped without importing Colleague;
  5. which direct subprocess paths are parked for Milestone 3;
  6. the smallest first PR that proves the seam without duplicating a framework.

Use Devague to challenge the plan for boundary leaks, false safety claims,
version skew, and operations that would bypass the selected environment.

  • AgentCulture

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions