Metadata-Version: 2.4
Name: pybun-cli
Version: 0.2.5
Summary: PyBun shim bootstrapper for signed releases
Author: PyBun Authors
License-Expression: MIT
Project-URL: Homepage, https://github.com/VOID-TECHNOLOGY-INC/PyBun
Project-URL: Repository, https://github.com/VOID-TECHNOLOGY-INC/PyBun
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# PyBun (Python Bundle)

## v0.2 backend transition

PyBun 0.2 delegates normal project dependency operations and project/PEP 723
execution to uv. You need `uv >=0.12.0,<0.13.0` on `PATH` (or point `PYBUN_UV`
at a supported executable). Missing, unsupported, or failed uv produces a
structured error; PyBun does not silently fall back to its native resolver.

| Operation | Default path (requires uv) |
| --- | --- |
| `pybun install` | `uv sync` |
| `pybun add` / `pybun remove` | `uv add` / `uv remove` |
| `pybun lock` | `uv lock`; `--script` selects a PEP 723 script |
| `pybun upgrade` | `uv lock --upgrade` / `--upgrade-package`; run `pybun install` to sync |
| Project `run`, PEP 723 `run` | uv environment preparation, then Python under PyBun's sandbox/profile settings |

The legacy native dependency commands and binary locks remain available only
with `PYBUN_BACKEND=native`. See [backend semantics and migration](docs/UV_BACKEND.md)
for lock ownership, JSON v2, MCP parity, receipts, and native compatibility limits.

<p align="center">
  <strong>🐍 The Agent-Native Python Control Plane 🤖</strong>
</p>

<p align="center">
  <em>Safe, structured, deterministic Python execution for AI coding agents —<br>
  orchestrating Python, pytest, and command-specific uv backends with JSON-first output and a built-in MCP server.</em>
</p>

<p align="center">
  <a href="#video-demo">Video Demo</a> •
  <a href="#quick-start">Quick Start</a> •
  <a href="#why-pybun">Why PyBun?</a> •
  <a href="#mcp-server">MCP Server</a> •
  <a href="#command-reference">Commands</a> •
  <a href="#execution-history-environment-diff-and-dependency-provenance">Evidence</a> •
  <a href="#benchmarks">Benchmarks</a> •
  <a href="#roadmap">Roadmap</a>
</p>

<p align="center">
  <img src="https://img.shields.io/badge/Platform-macOS%20%7C%20Linux%20%7C%20Windows-blue" alt="Platform">
  <img src="https://img.shields.io/badge/Language-Rust-orange" alt="Rust">
  <img src="https://img.shields.io/badge/License-MIT-green" alt="License">
</p>

---

## Video Demo

<p align="center">
  <a href="https://www.youtube.com/watch?v=335xndnBOmE">
    <img src="https://img.youtube.com/vi/335xndnBOmE/0.jpg" alt="PyBun Video Demo" width="600">
  </a>
</p>

---

## Quick Start

[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/VOID-TECHNOLOGY-INC/PyBun/blob/main/examples/PyBun_Quick_Start.ipynb)

**Requirements:** `uv >=0.12.0,<0.13.0` on `PATH` (see uv's
[installation guide](https://docs.astral.sh/uv/getting-started/installation/))
and a supported CPython interpreter (3.9–3.12; see the
[supported versions](docs/SPECS.md)). uv may provide the interpreter for
project/PEP 723 runs, but standalone script execution still needs one on the
machine. The exact range and error behavior are in
[UV_BACKEND.md](docs/UV_BACKEND.md).

**macOS / Linux:**
```bash
curl -LsSf https://raw.githubusercontent.com/VOID-TECHNOLOGY-INC/PyBun/main/scripts/install.sh | sh
```

**Windows (PowerShell):**
```powershell
irm https://raw.githubusercontent.com/VOID-TECHNOLOGY-INC/PyBun/main/scripts/install.ps1 | iex
```

**Or via pip/pipx ([PyPI](https://pypi.org/project/pybun-cli/)):**
```bash
pipx install pybun-cli
# or
pip install pybun-cli
```

**Then run:**
```bash
pybun init --yes
pybun add requests
pybun run -c "import requests; print('Hello, PyBun!')"
```

`pybun init --yes` accepts defaults non-interactively and creates a `pyproject.toml`. `pybun add` then delegates to
`uv add`, which updates project metadata, `uv.lock`, and the environment.

---

## Why PyBun?

Existing Python tools are built for **humans**. PyBun is designed for **AI agents** — and humans who work alongside them.

**PyBun is not a speed competitor to uv.** Tools like uv and pip are excellent at dependency resolution and installation. PyBun adds an **agent-facing control layer**: structured output, MCP integration, sandboxed execution, and audit/provenance that AI systems can rely on without fragile text scraping or unverifiable side effects. In v0.2, `pybun install`, `pybun add`, `pybun remove`, `pybun lock`, and `pybun upgrade` delegate to uv by default, as do project and PEP 723 runs. PyBun keeps the agent-facing contract around that backend instead of reimplementing dependency resolution.

The value PyBun adds isn't "faster pip." It's removing the ambiguity, non-determinism, and risk an agent faces when it operates a Python environment on its own.

**Hypothesis about who benefits:** PyBun is aimed at people building automated Python agents and the reviewers who supervise them. If that describes you, the intended shortcuts are concrete: locating a usable interpreter, reproducing the environment behind a failure, explaining why a package is locked, comparing two captured environments, and attaching a receipt that says which backend and lock produced a result. These are design targets, not validated adoption claims; real usage is being studied in [Issue #242](https://github.com/VOID-TECHNOLOGY-INC/PyBun/issues/242).

### Design Philosophy

```text
           AI Agent
              │  MCP / JSON
              ▼
        ┌───────────────┐
        │     PyBun      │   Policy · Sandbox · Schema
        │ Control Plane  │   Diagnostics · Audit · Provenance
        └───────┬────────┘
                │  delegates execution
      ┌─────────┼─────────┐
      ▼         ▼         ▼
     uv       pytest    Python
```

PyBun is a thin, structured control layer on top of proven execution backends rather than a reimplementation of the Python packaging/import ecosystem. Since v0.2, project dependency operations and project/PEP 723 execution delegate to uv; the native path is an explicit compatibility mode. See [`docs/SPECS.md`](docs/SPECS.md#03-外部レビューによる方向性提言-2026-08-29) for the reasoning behind this scope decision.

### ✨ What PyBun adds that other tools don't

- 🤖 **JSON-first output:** Every command supports `--format=json` as a first-class citizen. LLMs can parse outputs reliably — no regex, no brittle string matching.
- 🔌 **Built-in MCP Server:** [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) lets AI tools like Cursor and Claude Desktop operate your Python environment directly via stdio — no extra glue code required.
- 📋 **Structured diagnostics:** Errors come with machine-readable `code`, `level`, and `message` fields. Agents can act on failures without guessing what went wrong.
- 🛡️ **Sandbox Mode:** Run untrusted AI-generated code safely with `--sandbox`. File and network access are restricted when the flag is set.
- 📦 **Single executable:** The PyBun binary itself has no bundled runtime. Project dependency operations additionally require a supported `uv` on `PATH`; commands that execute Python (`run`, `test`, `build`, `x`, and others) also need an interpreter.

### 💡 Example: AI Agent Workflow

```bash
# AI agent asks: "Install pandas and show the version" (inside a pybun project)
$ pybun --format=json add pandas
{"version": "2", "status": "ok", "detail": {"contract_version": "2", ...}}

$ pybun --format=json run -c "import pandas; print(pandas.__version__)"
{"version": "2", "status": "ok", "detail": {"contract_version": "2", "stdout": "2.2.0\n", ...}}
```

The AI receives structured JSON — no parsing required, no ambiguity. Delegated
commands additionally report the backend, lock digest, policy, and receipt ID;
see [JSON contracts](#json-output-examples).

---

## Status

Maturity is assigned per execution path rather than to an entire milestone.
Labels follow the definitions in [docs/SPECS.md](docs/SPECS.md); uv-path labels
assume a supported uv 0.12.x.

| Surface | Maturity | Current execution path |
| --- | --- | --- |
| `pybun install` | **Stable for common cases** | `uv sync`: exact synchronization of the project environment. Requires a supported uv. |
| `pybun add` / `pybun remove` | **Stable for common cases** | `uv add` / `uv remove`: mutate project metadata, `uv.lock`, and the environment. Requires a supported uv. |
| `pybun lock` | **Stable for common cases** | `uv lock`; `--script` selects a PEP 723 script. Requires a supported uv. |
| `pybun upgrade` | **Stable for common cases** | `uv lock --upgrade` / `--upgrade-package`: update the lock without syncing. Run `pybun install` afterward. Requires a supported uv. |
| `pybun outdated` | **Preview** | Native reader of `pybun.lockb`; it is not part of the uv delegation path. |
| `pybun x` | **Stable for common cases** | Creates a temporary environment with Python and uses `uv pip install` when uv is available; otherwise it falls back to pip. |
| `pybun run` | **Stable for common cases** | Project and PEP 723 runs prepare the environment with uv. Standalone scripts without project or PEP 723 metadata use PyBun's existing interpreter path. |
| `pybun test` | **Stable for common cases** | The default backend wraps pytest/unittest. `--backend=pybun` is **Preview** and reports `W_TEST_BACKEND_COMPAT_*` diagnostics for known plugin/fixture gaps. |
| `pybun watch` | **Preview** | Native monitoring on macOS/Linux, with polling fallback on standard builds. |
| `pybun module-find` | **Experimental** | Standalone Rust Module Finder; it is not wired into CPython's runtime import path ([Issue #403](https://github.com/VOID-TECHNOLOGY-INC/PyBun/issues/403)). |
| Windows support | **Preview** | CI compile coverage and selected cross-platform behavior; continue to validate command-specific behavior. |

Delegated commands require `uv >=0.12.0,<0.13.0` and do not fall back automatically. `PYBUN_BACKEND=native` is an explicit compatibility opt-in for schema v1 native dependency commands and binary locks; treat it as a migration or fixture path, not the default.

`pybun outdated` remains on the native path and reads `pybun.lockb` even when other commands use uv. For uv projects, inspect `uv.lock` with uv's own tools until `outdated` is migrated.

PyBun-managed PEP 723 environments may still use `uv pip install` for dependency installation when uv is available, including sandboxed, no-cache, and PyBun-lockfile paths. Without uv, those paths fall back to native resolution/installation or pip depending on the environment mode. This is separate from the v0.2 project/PEP 723 uv preparation path.

In native compatibility mode, the installer's `.data/{purelib,platlib,scripts,headers,data}` routing is implemented and tested by the work that closed [Issue #402](https://github.com/VOID-TECHNOLOGY-INC/PyBun/issues/402). That tested subset includes relocation, script permissions/shebang handling, and headers placement; it does not promise complete wheel compatibility such as console-entry-point generation, every platform scheme, source distributions, or arbitrary install hooks.

- **Platforms:** macOS/Linux (arm64/amd64), Windows (preview)

> PyBun's priority is the agent-facing control layer (JSON/MCP/diagnostics/sandbox/audit/drift), not re-implementing Python packaging/import internals. See [`docs/SPECS.md`](docs/SPECS.md#03-外部レビューによる方向性提言-2026-08-29) for feature maturity, phased rollout policy, and the current scope decisions.

---

## Installation

The easiest way to install PyBun:

```bash
pip install pybun-cli
```

> **Prerequisite: `minisign`.** The pip/uvx shim and `install.sh` verify the
> downloaded binary's signature and fail closed when `minisign` is not on
> `PATH` (the MCP server would otherwise fail to start with no visible reason).
> Install it before the first `pybun` invocation:
>
> | Platform | Command |
> | --- | --- |
> | macOS | `brew install minisign` |
> | Debian/Ubuntu | `apt-get install minisign` |
> | Alpine | `apk add minisign` |
> | Windows | `scoop install minisign` |
>
> `PYBUN_PYPI_NO_VERIFY=1` skips signature verification, but it is **insecure**
> and intended only for offline testing.

<details>
<summary><strong>Other installation methods</strong></summary>

**macOS / Linux (shell script):**
```bash
curl -LsSf https://raw.githubusercontent.com/VOID-TECHNOLOGY-INC/PyBun/main/scripts/install.sh | sh
```

**Windows (PowerShell):**
```powershell
irm https://raw.githubusercontent.com/VOID-TECHNOLOGY-INC/PyBun/main/scripts/install.ps1 | iex
```

**From source:**
```bash
cargo install --path .
```

</details>

> **Note:** If your PATH resolves `pybun` to [Bun](https://bun.sh), use `pybun-cli` instead.

## Command Reference

### Package Management

```bash
# Initialize a new project (pyproject.toml)
pybun init
pybun init --yes
pybun init --name my-project --python ">=3.11" --template package

# Synchronize the project environment from pyproject.toml/uv.lock (requires uv)
pybun install

# Add a package: updates pyproject.toml, uv.lock, and the environment (requires uv)
pybun add requests

# Remove a package (requires uv)
pybun remove requests

# Lock dependencies for a PEP 723 script (requires uv)
pybun lock --script script.py

# Check outdated dependencies: requires a native pybun.lockb (see note below)
pybun outdated

# Upgrade the lock without syncing (requires uv); run `pybun install` afterward
pybun upgrade
pybun upgrade requests
```

The default project path passes `--index` values to uv as HTTP(S) URLs or
`NAME=URL`; authenticated private indexes are covered in
[PRIVATE_INDEXES.md](docs/PRIVATE_INDEXES.md). For `install`, `lock`, and
`upgrade`, JSON fixture indexes and legacy selectors belong to native
compatibility mode; `add`/`remove --index` require uv:

`pybun outdated` reads only `pybun.lockb`, which default uv-mode `pybun install`
does not create. For a uv-only project, inspect `uv.lock` with uv's own tools or
opt into native compatibility and build a `pybun.lockb` first.

```bash
# Explicit native compatibility mode (schema v1, binary pybun.lockb)
PYBUN_BACKEND=native pybun install --require requests==2.31.0
PYBUN_BACKEND=native pybun upgrade --dry-run
```

### Script Execution

```bash
# Run a Python script
pybun run script.py

# Run with arguments
pybun run script.py -- arg1 arg2

# Run inline code
pybun run -c "import sys; print(sys.version)"

# Run with profile
pybun run --profile=prod script.py
```

PEP 723 inline metadata is also supported:
```python
# /// script
# requires-python = ">=3.11"
# dependencies = ["requests>=2.28"]
# ///
import requests
```
※ Metadata parsing and isolated-environment execution are supported. Eligible PEP 723 scripts go through the uv project path. With `PYBUN_BACKEND=native`, `PYBUN_PEP723_BACKEND` selects the PyBun-native or uv path; PyBun-managed fallback paths inherit the native installer's Preview limitations. Environments are cached per script/dependency/Python-version key; see `docs/PLAN.md` for details.

### Ad-hoc Execution (`pybun x`)

Install a package in a temporary environment and execute it (Python version of `npx`).
The environment is created with `python -m venv`. If `uv` is available, PyBun uses `uv pip install` for package installation; otherwise it uses pip.

```bash
# Temporarily install and run cowsay
# (Use -t flag for Python cowsay package)
pybun x cowsay -- -t "Hello"

# Specify version
pybun x cowsay==6.1

# With arguments
pybun x black -- --check .
```

### Affected Tests

```bash
pybun test --affected
pybun test --affected --since main --format=json
pybun test --affected --discover --format=json
```

`--changed` is an alias for `--affected`. Selection is repository-wide and cannot be combined with explicit paths or `--member`. MCP `pybun_test` uses the same service with `{"changed": true, "since": "main"}`.

JSON includes `selection` with `direct`, `transitive`, or `conservative` reasons and import chains. The target Python's standard AST parser reads project source without executing it. Imports and ancestor `conftest.py` dependencies are modeled; uncertain parsing, known dynamic imports, or non-Python/configuration changes conservatively select all tests. Import-root ambiguity may select extra tests. Arbitrary runtime file dependencies are not inferred. Unavailable git/runtime evidence returns an error rather than a verified empty selection.

### Python Version Management

```bash
# Show installed versions
pybun python list

# Show all available versions
pybun python list --all

# Install Python
pybun python install 3.12

# Remove Python
pybun python remove 3.12

# Show Python path
pybun python which
pybun python which 3.11
```

### Runtime Optimization

> These commands (Module Finder, Lazy Import, Watch) are opportunistic performance optimizations, evaluated independently for ROI — they are not required for PyBun's core agent-control-plane value (JSON/MCP/diagnostics/sandbox). Module Finder in particular is not yet connected to CPython's runtime import resolution (Issue #403).

#### Module Finder

Rust-based high-speed module search:

```bash
# Find a module
pybun module-find os.path

# Scan a directory for all modules
pybun module-find --scan -p ./src

# With benchmark
pybun module-find --benchmark os.path
```

#### Lazy Import

```bash
# Show configuration
pybun lazy-import --show-config

# Check module decision
pybun lazy-import --check numpy

# Generate Python code
pybun lazy-import --generate -o lazy_setup.py

# Specify allow/deny lists
pybun lazy-import --allow mymodule --deny debug_tools --generate
```

#### File Watch (Development Mode)

```bash
# Watch for file changes and re-run (currently preview)
# Native watching (macOS/Linux, `native-watch` feature) or a polling fallback
# (standard builds) is used automatically. --shell-command remains available
# for an external watcher.
pybun watch main.py

# Watch a specific directory
pybun watch main.py -p src

# Show configuration
pybun watch --show-config

# Generate shell command for external watcher
pybun watch --shell-command main.py
```

#### Dependency Drift

Detect undeclared imports and unused declared dependencies:

```bash
pybun drift
pybun drift --path ./src
```

#### Vulnerability Scanning

Scan installed packages against the [OSV](https://osv.dev) database (same scan logic as the MCP `pybun_audit` tool):

```bash
pybun audit

# Only report medium severity and above
pybun audit --severity-threshold=medium

# Exit non-zero when high/critical vulnerabilities are found (CI gating)
pybun audit --fail-on=high
```

The scanner follows OSV batch pagination and fetches advisory details before filtering or suggesting fixes. Missing severity is reported as `unknown`, remains visible at every threshold, and fails any `--fail-on` gate. Failed advisory lookups fail the scan. `PYBUN_OSV_URL` can point to a mirror's batch endpoint; its sibling `vulns/<id>` endpoint must serve full advisories.

### Profile Management

```bash
# Show available profiles
pybun profile --list

# Show profile settings
pybun profile dev --show

# Compare profiles
pybun profile dev --compare prod

# Export profile
pybun profile prod -o prod-config.toml
```

Profiles:
- `dev`: Hot reload enabled, verbose logging
- `prod`: Lazy imports enabled, optimizations
- `benchmark`: Tracing and timing measurement

### MCP Server

MCP server for AI agents:

```bash
# Start in stdio mode
pybun mcp serve --stdio
```

Dependency/project tools: `pybun_install`, `pybun_add`, `pybun_remove`,
`pybun_lock`, `pybun_upgrade`, `pybun_resolve`.
Execution/diagnostics tools: `pybun_run`, `pybun_test`, `pybun_gc`,
`pybun_doctor`, `pybun_lint`, `pybun_type_check`, `pybun_profile`, `pybun_fix`,
`pybun_context`, `pybun_drift`, `pybun_audit`.
Evidence tools: `pybun_why`, `pybun_environment_diff`.
Resources: `pybun://cache/info`, `pybun://env/info`, `pybun://audit/recent`,
`pybun://project/snapshot`.

`pybun_install` and `pybun_upgrade` keep native branches and return schema v1
when the server runs with `PYBUN_BACKEND=native`; otherwise they use uv and
return contract v2. `pybun_add`, `pybun_remove`, and `pybun_lock` require the uv
backend and return an actionable error in native mode. `pybun_resolve` requires
native mode; use `pybun_lock` or `pybun_install` for uv project semantics. HTTP
mode is not yet implemented.

`pybun_run` is sandboxed by default for MCP-originated calls. To preview code without executing it, pass `dry_run: true`; to disable the sandbox, pass `unsafe_no_sandbox: true` and treat the warning in the response as an approval checkpoint.

### Build

```bash
# Build sdist/wheel artifacts (wraps `python -m build`)
pybun build

# Build and emit a CycloneDX SBOM alongside artifacts
pybun build --sbom
```

### Diagnostics & Maintenance

```bash
# Environment diagnostics
pybun doctor
pybun doctor --verbose

# Compute a remediation plan for detected issues (preview)
pybun doctor --fix

# Apply safe, auto-applicable fixes from the remediation plan
pybun doctor --fix --apply

# Cache garbage collection
pybun gc
pybun gc --max-size 1G
pybun gc --dry-run

# Self-update check
pybun self update --dry-run
pybun self update --channel nightly
```

MCP exposes the same doctor remediation plan: call `pybun_doctor` with `{"fix": true}` to preview, or `{"fix": true, "apply": true}` to apply low-risk, auto-applicable fixes. `applied_fixes` includes before/after cache counts; `skipped_fixes` explains candidates requiring manual action. The existing `pybun_fix` tool continues to fix lint violations with Ruff.

## Sandbox usage

Use the sandbox for untrusted scripts or PEP 723 snippets:
```bash
pybun --format=json run --sandbox examples/hello.py
pybun --format=json run --sandbox --allow-network -c "print('net ok')"
```
Use repeatable `--allow-net=host[:port]` to permit selected network destinations
and `--allow-run=executable-name-or-path` to permit trusted executables. For example:

```bash
pybun --format=json run --sandbox --allow-net=pypi.org:443 script.py
pybun --format=json run --sandbox --allow-run=/usr/bin/git script.py
```

`--allow-network` retains unrestricted network access. Hostnames are resolved
once at startup; permission includes those IP addresses (and hosts sharing them).
Ports are exact when provided; omit the port to allow all ports for that host.
Use brackets for IPv6, for example `[::1]:8080`. TCP and UDP sends, direct
connects, and DNS lookups are checked. Denials identify the target with
`E_SANDBOX_NET_DENIED` or `E_SANDBOX_RUN_DENIED` and a permission hint.
MCP `sandbox_policy` supports matching `allow_net` and `allow_run` arrays.

Executable names are resolved from the initial PATH and pinned to their real
paths. Subprocess PATH/cwd overrides cannot authorize a different executable.
Use explicit paths for direct exec/posix_spawn calls; raw fork and shell-command
APIs remain denied. An allowed executable is trusted: it can launch children and
access the host independently of Python guards. When `allow_run` is nonempty,
the blanket zero-child OS process limit is not applied; `resource_limits.unsupported`
reports `process`. Existing parent OS limits still apply.

These are Python runtime guards plus supported resource limits, not a kernel
containment boundary. Native extensions and trusted external programs require
an OS/container sandbox when hostile code containment is needed. Combine with
`--profile=prod` for production-like runs.

## Profiles

Profiles tune defaults for performance vs. development ergonomics:
- `dev` (default): hot reload enabled, verbose logging.
- `prod`: lazy imports and optimizations enabled, quieter output.
- `benchmark`: stable timing/logging for reproducible benchmarks.

Examples:
```bash
pybun profile --list
pybun run --profile=prod app.py
pybun test --profile=benchmark --format=json
```

## MCP server (stdio)

Operate PyBun as an MCP server for agents/IDEs:
```bash
pybun mcp serve --stdio
pybun --format=json mcp serve --stdio  # JSON envelope for tooling
```
Tools: `pybun_install`, `pybun_add`, `pybun_remove`, `pybun_lock`,
`pybun_upgrade`, `pybun_resolve`, `pybun_run`, `pybun_test`, `pybun_gc`,
`pybun_doctor`, `pybun_lint`, `pybun_type_check`, `pybun_profile`, `pybun_fix`,
`pybun_context`, `pybun_drift`, `pybun_audit`, `pybun_why`,
`pybun_environment_diff`. Resources: `pybun://cache/info`,
`pybun://env/info`, `pybun://audit/recent`, `pybun://project/snapshot`.

MCP `pybun_run` applies the sandbox by default, including process/file-size limits and secret-like environment variable filtering. Use `sandbox_policy` to allow network/path/env exceptions, `dry_run: true` for a non-executing plan, or `unsafe_no_sandbox: true` only in controlled environments.

### Configuration (Claude Desktop)

Add to your `claude_desktop_config.json`:

#### Option 1: Using `uvx` (No install required)

`uvx` runs the same shim, so `minisign` must be on `PATH` (see
[Installation](#installation)) before the MCP server can start.
```json
{
  "mcpServers": {
    "pybun": {
      "command": "uvx",
      "args": [
        "--from",
        "pybun-cli",
        "pybun",
        "mcp",
        "serve",
        "--stdio"
      ]
    }
  }
}
```

#### Option 2: Using pip install
Requires `pip install pybun-cli`.
```json
{
  "mcpServers": {
    "pybun": {
      "command": "pybun",
      "args": [
        "mcp",
        "serve",
        "--stdio"
      ]
    }
  }
}
```
*Note: If `pybun` is not in the PATH, provide the absolute path (e.g., `/Users/username/bin/pybun`).*

### Server policy

MCP execution requires an operator-owned security policy. Configure it before
starting the server; requests cannot reload or override it. The server freezes
one configuration at startup, with this precedence: `PYBUN_MCP_POLICY` file,
then `.pybun/config.toml`, then `pyproject.toml`. A selected file with a missing
or malformed policy fails closed; it does not fall back to another file.
`pyproject.toml` and explicit files use `[tool.pybun.mcp.policy]`;
`.pybun/config.toml` also accepts `[mcp.policy]`.

For a restricted native execution server:

```toml
[tool.pybun.mcp.policy]
default_sandbox = true
require_sandbox = true
allow_network = false
max_execution_time_s = 30
max_memory_mb = 0                 # Linux supports a nonzero memory cap
max_cpu_time_s = 0
allowed_working_directories = ["."]
allowed_backends = ["native"]
denied_tools = ["pybun_gc"]
```

Start it with `PYBUN_BACKEND=native pybun mcp serve --stdio`. Relative boundaries
are resolved against the startup directory; start at the workspace root or
explicitly authorize its ancestor workspace. Keep policy files under operator
control, outside agent-writable paths for deployments. Audit logs must also be
outside the effective writable project roots.

Every tool and its resource aliases pass through authorization before audit
setup, filesystem snapshots or execution. Responses expose `policy_applied` and
stable `E_MCP_POLICY_*` denial codes. Requested limits may be stricter; zero
(unlimited) cannot relax an operator cap. Required sandboxing and active caps
prevent `unsafe_no_sandbox` from bypassing enforcement. Disallowed network
permission also removes granular network and executable grants. Sandbox reads
and writes default to the startup project boundary; explicit paths, symlinks,
backend-derived workspaces and environment/lock outputs are checked against the
operator's authorized directories. System-environment installation is denied.
Write snapshots skip symlinks and generated trees (`target`, `.git`, `.venv`,
`venv`, `__pycache__`, `node_modules`), and are bounded to 2,000 entries, depth
32, 4 MiB per file and 16 MiB read per snapshot. Audit records expose
`file_snapshot_complete=false` whenever evidence is skipped or bounded; their
`file_writes` then describes only observed changes, not a complete write trace.
Pure in-memory environment comparisons remain available without execution policy.

Enforcement support is explicit: native inline code and ordinary scripts support
these execution limits. Bounded uv preparation and native PEP 723 preparation
cannot currently propagate all server limits, so incompatible calls return
`E_MCP_POLICY_UNSUPPORTED` before preparation. Other tool handlers that cannot
enforce a requested sandbox/network/resource restriction also return that code.
Memory caps are unavailable on macOS/Windows; CPU caps require Unix. A dry run
can preview a bounded uv call without starting the backend.

Operators who authorize trusted uv project operations can set
`require_sandbox=false`, `allow_network=true`, `max_execution_time_s=0`,
`max_memory_mb=0`, and `max_cpu_time_s=0`; execution-time restrictions that a tool
cannot enforce must be disabled explicitly. Its existing backend deadlines still
apply. This does not grant requests permission to escape working-directory or
backend boundaries. The Python guard's documented containment limits still apply.

### Previewing execution

Call `pybun_run` with `dry_run: true` to return `would_execute`,
`estimated_risk` (`low`, `medium`, or `high`), `risk_reasons`, and
`sandbox_policy_that_would_apply` without executing code or preparing a backend.
The existing `risk_level` and `sandbox_policy` fields remain equivalent aliases.
The response also includes server policy and admission limits; previews consume
normal tool quota. Previewing an unsupported bounded backend reports
`policy_applied.execution_supported=false` and its denial code.

Risk is a substring heuristic over inline code or at most 2 MiB of regular UTF-8
script source. Missing script targets are rejected. Non-text, oversized or unreadable source reports
uncertainty as `medium`; filenames are not treated as source. If both are supplied,
inline code takes precedence, matching execution. `low` is not proof of safety:
dynamic imports, called code and later file changes can alter behavior. A preview
does not grant execution permission; the actual call is authorized independently.

### Tool rate limits

The same frozen configuration accepts `[tool.pybun.mcp.rate_limit]` (or
`[mcp.rate_limit]` in `.pybun/config.toml`):

```toml
[tool.pybun.mcp.rate_limit]
calls_per_minute = 60             # all calls in one stdio session
global_calls_per_minute = 600     # all sessions in this process/configuration
pybun_run_per_minute = 10
pybun_install_per_hour = 20

[tool.pybun.mcp.rate_limit.per_tool.pybun_lock]
calls = 5
window_secs = 60
```

These are token buckets: each starts with a full window's burst and refills
continuously using monotonic time. All applicable buckets are checked and debited
atomically after policy authorization, before filesystem snapshots, backend work
or subprocesses. Resource aliases share the corresponding tool's bucket. A denied
call debits no bucket; cancelling an admitted call retains its debit. Rejections
return `mcp.rate_limit_exceeded`, positive `retry_after_ms`, scope and applicable
limits in `rate_limit_applied`, and write a security audit event without invoking
the tool or producing its success receipt. Admitted responses expose their limits.

One stdio server owns one generated session UUID for its lifetime; client IDs and
arguments cannot change it. Global/per-tool quotas are shared by server instances
in the same process with the same canonical startup directory and frozen rate
configuration. Separate processes and restarts do not share quota state. State
is bounded to 64 configurations and 512 sessions per configuration; live entries
are never evicted to reset a quota. Idle sessions expire after two minutes and
configurations after twice their longest tool window (at least two hours).
Capacity exhaustion returns a retry hint. Configuration rejects unknown tool names
and fields, zero or more than 1,000,000 calls, and windows outside 1–86,400 seconds.

## JSON output examples

All commands support `--format=json`. Two contracts are in use:

| Command family | Envelope | Contract |
| --- | --- | --- |
| Non-delegated commands (`test`, `doctor`, `watch`, standalone `run`, …) | schema v1 | Default and frozen; `pybun schema print` |
| Delegated project commands (`install`, `add`, `remove`, `lock`, `upgrade`, project/PEP 723 `run`) | schema v2 | `version: "2"` and `detail.contract_version: "2"`; `pybun schema print --schema-version 2` |
| Native compatibility mode (`PYBUN_BACKEND=native`) | schema v1 | Legacy dependency results and binary locks |

Schema v2 details add backend name/version/operation, environment fingerprint,
lock source and SHA-256, effective policy, duration, diagnostics, and a persisted
receipt identifier under `.pybun/receipts/<id>.json`. Receipts omit execution
stdout/stderr. MCP project tools return the same v2 detail payload. Backend
stdout/stderr stays private; fixed diagnostics avoid leaking credentials from
netrc, keyring, or backend errors. See
[UV_BACKEND.md](docs/UV_BACKEND.md#json-and-mcp-contracts).

Schema v1 examples (shown outside a project; inside a uv project, `run` uses
the v2 contract):

```bash
pybun --format=json run -c "print('hello')"
```

Abridged success output:
```json
{
  "version": "1",
  "command": "pybun run",
  "status": "ok",
  "detail": {
    "cache_hit": false,
    "exit_code": 0,
    "pep723_backend": "system",
    "stdout": "hello\n",
    "stderr": null,
    "profile": { "name": "dev", "...": "..." },
    "...": "..."
  },
  "events": [{ "type": "command_start", "...": "..." }],
  "diagnostics": []
}
```

Failure example:
```bash
pybun --format=json run missing.py
```

```json
{
  "version": "1",
  "command": "pybun run",
  "status": "error",
  "detail": { "error": "script not found: missing.py", "...": "..." },
  "diagnostics": [
    {
      "code": "E_RUN_FAILED",
      "level": "error",
      "message": "script not found: missing.py",
      "suggestion": "Check the script path and any PEP 723 inline metadata, then re-run `pybun run <script>`."
    }
  ]
}
```

Tests/builds emit structured summaries (pass/fail counts, shard info) while keeping the same envelope:
```bash
pybun --format=json test --fail-fast
pybun --format=json build
```

Enable trace IDs for debugging:
```bash
PYBUN_TRACE=1 pybun --format=json run script.py
```

Print or validate the JSON schema itself:
```bash
pybun schema print                    # schema v1 (frozen)
pybun schema check
pybun schema print --schema-version 2 # delegated contract
```

## Environment Variables

| Variable | Description |
|----------|-------------|
| `PYBUN_ENV` | Path to venv to use |
| `PYBUN_PYTHON` | Path to Python binary |
| `PYBUN_BACKEND` | `uv` (default) or `native` for explicit legacy compatibility |
| `PYBUN_UV` | Path to the uv executable (defaults to `uv` on `PATH`) |
| `PYBUN_PEP723_BACKEND` | PyBun-managed PEP 723 backend: `auto`, `pybun`, or `uv` |
| `PYBUN_PROFILE` | Default profile (dev/prod/benchmark) |
| `PYBUN_TRACE` | Set to `1` to enable trace ID |
| `PYBUN_HOME` | Override cache root directory |
| `PYBUN_TELEMETRY` | Override telemetry setting (0/1) |
| `PYBUN_PROGRESS` | Override `--progress` (auto/always/never) |
| `PYBUN_PYPI_BASE_URL` | Override the PyPI index base URL |
| `PYBUN_PYPI_CACHE_DIR` | Override the PyPI metadata cache directory. By default this uses the platform cache directory plus `pybun/pypi` (for example `~/Library/Caches/pybun/pypi` on macOS). Current binary cache entries use `.bin`; legacy `.json` entries are only read from the same directory as a fallback. |
| `PYBUN_AUDIT_LOG` | Override the MCP audit log path (`/dev/null` disables it) |
| `PYBUN_SANDBOX_ALLOW_NETWORK` | Allow network access under `--sandbox` |
| `PYBUN_HISTORY` | Set to `0`, `false`, or `off` to disable local execution-history recording |
| `PYBUN_OSV_URL` | Override the OSV batch endpoint used by `pybun audit` |

See `CLAUDE.md`'s Environment Variables section for the full list, including testing/dry-run-only variables.

## Release note automation

- Generate GA release notes from tags:  
  `python scripts/release/generate_release_notes.py --repo . --previous-tag v0.1.0 --tag v0.2.0 --notes-output release/RELEASE_NOTES.md --changelog CHANGELOG.md`
- Attach the notes to the release manifest (served by installers/self-update via `release_notes` in JSON):  
  `python scripts/release/generate_manifest.py --assets-dir release --version 0.2.0 --channel stable --base-url https://github.com/VOID-TECHNOLOGY-INC/PyBun/releases/download/v0.2.0 --output pybun-release.json --release-notes release/RELEASE_NOTES.md`
- CI-friendly JSON summary: `python scripts/release/generate_release_notes.py --repo . --previous-tag v0.1.0 --tag v0.2.0 --format json`

## Upgrade guide

See `docs/UPGRADE.md` for pre-GA → GA migration notes, breaking changes, and the recommended CI checks (doc lint/link + release note automation).

## Development

### Requirements

- Rust stable (`rustup`, `cargo`)

### Basic Commands

```bash
# Format
cargo fmt

# Lint
cargo clippy --all-targets --all-features -- -D warnings

# Test
cargo test

# Development scripts
./scripts/dev fmt
./scripts/dev lint
./scripts/dev test
```

### Testing

```bash
# All tests
cargo test

# Specific tests
cargo test cli_smoke
cargo test json_schema
cargo test mcp
```

## Benchmarks

PyBun is not a speed competitor to uv — it is an interface layer. Since v0.2, project dependency operations and project/PEP 723 execution delegate to uv, so dependency timings mostly measure uv plus PyBun's orchestration overhead rather than a competing resolver. Native resolver timings describe the explicit `PYBUN_BACKEND=native` compatibility path.

The areas where PyBun intentionally differs from uv (JSON output, MCP, sandbox, receipts) are evaluated for structured correctness and safety first. Native resolver performance work and measurements are tracked in [Issue #239](https://github.com/VOID-TECHNOLOGY-INC/PyBun/issues/239); they should not be read as a product goal to out-run uv.

The linked report is a historical pre-v0.2 snapshot (PyBun 0.1.21 / uv 0.11.21)
that measured the native resolver, not the current delegated path. Re-run
`scripts/benchmark` against a v0.2 build before quoting dependency numbers.
[Historical numbers](docs/BENCHMARK_UV_COMPARISON.md)

---

## Roadmap

- [x] M0: Repository & CI scaffold
- [x] M1: Installer foundation (lockfile, native resolver, PEP 723); v0.2 delegates project dependency operations and project/PEP 723 execution to uv, with native retained as an explicit compatibility mode
- [x] M2: Runtime optimization (module finder, lazy import, hot reload) — *opportunistic, ROI under evaluation; see [Issue #403](https://github.com/VOID-TECHNOLOGY-INC/PyBun/issues/403)*
- [x] M3: Test runner (discovery, parallel execution, snapshots)
- [x] M4: JSON/MCP & diagnostics
- [ ] M5: Agent control plane hardening (extended `doctor`/`drift`, audit/provenance depth) — reprioritized over a full native wheel installer; see [`docs/SPECS.md` §0.3](docs/SPECS.md#03-外部レビューによる方向性提言-2026-08-29)
- [ ] M6: Release hardening (remote cache, workspaces, telemetry)

See `docs/PLAN.md` for details.

## Privacy & Telemetry

PyBun does **not** collect telemetry by default (opt-in model).

```bash
# Check telemetry status
pybun telemetry status

# Enable telemetry
pybun telemetry enable

# Disable telemetry
pybun telemetry disable
```

**Collected data (when enabled):**
- Command usage (anonymized)
- Error diagnostics
- Performance metrics

**Never collected:** API keys, tokens, credentials, passwords, or file contents.

Environment override: `PYBUN_TELEMETRY=0|1`

## Execution history, environment diff, and dependency provenance

These read-only surfaces answer the evidence questions an agent or reviewer
usually asks after a command: what ran, what changed, and why is this package
here.

- `pybun history` lists local CLI receipts for `run`, `test`, `install`, `add`,
  and `remove`, including failures.
- `pybun environment diff` compares two captures or receipts without execution.
- `pybun why` explains every known declaration path to a locked package.

MCP exposes the same services as `pybun_environment_diff` and `pybun_why`;
`pybun_context` provides the current project snapshot. See
[UV_BACKEND.md](docs/UV_BACKEND.md) for backend-specific lock evidence.

### Local execution history

`pybun history --since 20m --format=json` queries CLI receipts for `run`, `test`,
`install`, `add`, and `remove`, including failed invocations. Receipts are appended
under `PYBUN_HOME/history.jsonl` (default `~/.cache/pybun/history.jsonl`), with a
private file mode on Unix and a file lock for concurrent writers. Existing files
with group/other permissions are rejected for appends; restrict them to mode 600. Set
`PYBUN_HISTORY=0` to disable recording. History queries never record themselves;
recording failures warn without changing the command's exit code.

Records contain timestamps, duration, exit code, lock digest when available,
backend identity, Python version/ABI, and known cache/policy/profile evidence.
Python observations identify whether they describe the execution interpreter or
the selected environment observed after the command; unavailable evidence is
`null`. Recording does not launch an extra interpreter: the version is read from
`pyvenv.cfg` (or the interpreter layout) and the inventory from
`*.dist-info/METADATA` and `*.egg-info/PKG-INFO` under `site-packages`. Daemon use is false for the current direct execution paths. Inline code
and credential option values are removed, and the existing output redaction rules
apply before persistence and on reads. Program output and environment variables
are never stored. Arbitrary positional secrets cannot be inferred; disable
history when arguments contain such values. Queries accept positive `s`, `m`,
`h`, or `d` durations, report corrupt/partial lines without echoing them, and
reject files over 32 MiB; archive the local log when needed.

### Comparing captured environments

`pybun why <package> --format=json` explains every known declaration path to a
locked distribution. MCP `pybun_why` takes a `package` string and uses the same
service. The uv backend reads frozen, offline `uv workspace metadata`; it does
not resolve, install, or synchronize an environment. Paths retain markers and
classify direct, transitive, extra, dependency-group, and workspace provenance.
They describe lock alternatives rather than the currently active environment.
Results include backend/version, lock digest, `complete`, and diagnostics. An
unreachable or unavailable locked variant is explicitly `unknown`. Native
provenance uses current declarations with its lock and always reports partial
evidence. Traversal is bounded (10,000 nodes, 100,000 expansions, depth 256,
1,000 paths); reaching a bound also reports partial evidence.

`pybun environment diff before.json after.json --format=json` compares two JSON
captures, raw execution receipts, or JSON command envelopes. The MCP equivalent is
`pybun_environment_diff` with `before` and `after` objects; both use the same
read-only service. To compare CLI history entries, save the chosen `records[]`
objects from `pybun history --format=json` as the input files. Each input file is
limited to 4 MiB.

The response reports deterministic `changes` with reason codes for Python,
backend, lock, package, policy, profile and project evidence. `installed_packages`
describes interpreter-site inventory; `packages` separately describes a backend's
resolved lock inventory, which does not prove installation. History captures
standard isolated-venv site packages by reading distribution metadata without
importing project packages or running site hooks. System Python and venvs that
include system/user sites leave the installed inventory unavailable. Executable
digests are captured when readable; wheel artifact hashes remain unavailable
unless supplied by a capture.

Missing, masked and explicitly unknown values appear in `unavailable` and warning
diagnostics. They do not establish equality or a runtime state change. An identical
partial capture has an empty `changes` array while still reporting missing evidence.
Array ordering and normalized package spelling do not create differences. Only
typed, allowlisted metadata is compared; unrestricted environment variables and
unknown configuration keys are excluded, and existing redaction applies before
comparison. `causality: "not_inferred"` means the result describes recorded state
changes and never claims that they caused a program's output to change.

## License

MIT
