Metadata-Version: 2.4
Name: bosn
Version: 0.1.13
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
License-File: LICENSE
Summary: Let your agents use Docker all day without filling the disk
Author: Zach Vorhies
License: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Homepage, https://github.com/zackees/bosn

# Bosn

Bosn is a Rust daemon for safely managing Docker development applications.
It keeps ownership, generation, volume, lease, execution-session, and event
state in a durable SQLite registry. The daemon is the only component that
mutates Docker or that writes that registry.

The distribution includes three intentionally thin front ends:

- `bosn`, a bundled native CLI;
- `import bosn`, a PyO3 client binding; and
- `bosn mcp`, a stdio MCP server for Hermes and other MCP clients.

The former Python daemon, Docker front doors, manifest parser, and SQLite
registry are deliberately not packaged. Python callers use `bosn.Client`; they
cannot import or invoke a second lifecycle implementation.

## Install

```bash
pip install bosn
bosn --version
```

Platform wheels contain the native `bosn` CLI and the `bosn._native` Python
extension. Installing the wheel puts the `bosn` binary itself into the
environment's scripts directory, so the `bosn` on `PATH` is the native CLI,
with no Python wrapper in between.
The extension uses PyO3's `abi3-py310` ABI, so Bosn supports CPython 3.10 and
newer with one platform wheel rather than publishing cp311-only artifacts.

## One-file setup

Bosn accepts a local file or HTTPS URL for a versioned setup document. The
document declares a digest-pinned image or inline Dockerfile, optional inline
files, environment, bind mounts, named volumes, tmpfs mounts, and named tasks.
Planning is inert; ensure and task submission are daemon-owned jobs.

```toml
version = 1

[app]
image = "registry.example/team/app@sha256:REPLACE_WITH_64_LOWERCASE_HEX_DIGEST"
command = "exec sleep 120"

[task.check]
command = "cargo check"
```

```bash
bosn setup plan --state-dir "$HOME/.local/state/bosn" \
  --workspace "$PWD" --config https://example.invalid/bosn-setup.toml \
  --refresh
bosn setup ensure --state-dir "$HOME/.local/state/bosn" \
  --workspace "$PWD" --config https://example.invalid/bosn-setup.toml \
  --refresh --deadline-ms 300000 --output-limit 8388608
```

`online_refresh` is explicit; `offline_cache_only` uses only a previously
validated local cache record. URLs with credentials, unsupported schemes,
path traversal, unpinned images, and oversized documents are refused.

## Python

```python
from pathlib import Path
import bosn

client = bosn.Client(Path.home() / ".local/state/bosn")
plan = client.plan_setup(
    Path.cwd(), "https://example.invalid/bosn-setup.toml", policy="online_refresh"
)
job_id = client.submit_setup_ensure(
    Path.cwd(),
    "https://example.invalid/bosn-setup.toml",
    policy="online_refresh",
    deadline_ms=300_000,
    output_limit=8 * 1024 * 1024,
)
```

The binding exposes typed request and observation operations only. It does not
accept Docker command arguments, container identifiers, mounts, or arbitrary
commands from callers.

## Concurrent runs

The daemon runs task jobs (`bosn run --task ...`) from different checkouts in
parallel, `max(1, ncpu * 2)` runner slots by default, each limited to 4 CPUs.
Stack ensures run in their own lane, so they never wait behind long tasks.
`bosn jobs` (or the `bosn_jobs` MCP tool) shows what is running, in which slot,
with which containers and caches. A task that goes silent is torn down, and a
daemon restart reaps what its predecessor left running. For stacks that drive
the host Docker engine (act), a per-job proxy labels, limits, isolates and
removes the job's containers, and maps cache volumes into act's job
containers. See [docs/runners.md](docs/runners.md).

```bash
bosn jobs                                  # what is running now
bosn daemon serve --state-dir "$HOME/.local/state/bosn" --runner-slots 8 --runner-cpus 4
```

## MCP / Hermes

Run `bosn mcp` over stdio. A typical Hermes registration is:

```yaml
mcp_servers:
  bosn:
    command: bosn
    args: [mcp]
```

Set `BOSN_STATE_DIR` if the default state directory is not appropriate. MCP
tools use the same typed daemon operations as the CLI and Python client; long
operations return durable job IDs.

## Development

```bash
./install
./lint
./test
```

`./install` prepares Soldr and the Rust toolchain pinned by
`rust-toolchain.toml` before installing the native package. Source builds use
Soldr for both the CLI and Maturin's compiler calls. The declared Docker test
and lint tasks build a wheel against a read-only checkout, with writable
target, toolchain and environment volumes.

The Rust migration status, native manifest lifecycle boundary, and registry
details are documented in [docs/migration-rust.md](docs/migration-rust.md),
[docs/rust-manifest-runtime.md](docs/rust-manifest-runtime.md), and
[docs/rust-registry.md](docs/rust-registry.md). Daemon-owned task secrets
(an opt-in `GITHUB_TOKEN` for act runs) are in
[docs/task-secrets.md](docs/task-secrets.md); the read-only GitHub API proxy
that keeps the token out of containers is in
[docs/github-api-proxy.md](docs/github-api-proxy.md).
Local CI on an isolated, daemon-owned engine (`bosn ci run --wait`, with
reports and stable exit codes for agents) is in [docs/ci.md](docs/ci.md).

Before pushing this repository, run its gate from a clean, committed checkout:

```bash
uvx --from git+https://github.com/zackees/ci.yml@86b63937960d00655f7ef3752ef6f15b6b06f35b ci-lint local-gate run
```

The heavy lanes require Bosn 0.1.12 or later and replay the Rust checks and
Linux test tier through act2 on isolated engines. The gate checks the executed
source and required successful steps before stamping the commit. Unchanged
lane inputs can reuse a recorded pass; compiler units are cached across runs.

PR verification refuses missing or stale proof. A trusted, attested PR can
skip the mapped policy and Rust jobs, with audit sampling retained. Explicit
`ci-test`/`ci-full` requests keep their Linux test-tier coverage; main pushes
and release validation retain their remote checks.

If the gate rejects an old Bosn before submitting a run, check `bosn --version`
and the executable selected by `command -v bosn`. The gate requires at least
0.1.12. Its `uv run --no-project --isolated` launchers avoid selecting a virtual
environment in an ancestor directory: `--no-project` alone does not isolate
the tooling environment. Make the supported executable available on PATH and
rerun the gate; the rejected preflight produces no attestation.

