# agentic-bees
An AI agent can use `agentic-bees` to inspect Btrfs storage, choose bounded scans, review matches, and apply deduplication within an authorized scope. The Rust CLI finds matching filesystem-sector anchors and produces reviewable JSON plans; the kernel verifies deduplication. No background service, resident hash database, or external model API is required for this workflow.
> [!WARNING]
> This project does **not** yet have full feature parity with upstream [bees](https://github.com/Zygo/bees): residual-reference rewriting and cost-based allocation transformations remain unfinished. The historical [upstream README](docs/upstream-bees-README.md) describes a different implementation; upstream C++ source is not included.
## Build
Current supported target: Linux x86_64 with Btrfs and kernel `openat2` support (Linux 5.6 or newer). Build with Rust 1.88 or newer:
```sh
cargo build --locked --release
./target/release/agentic-bees --help
```
The binary uses the kernel deduplication ioctl; it does not require the upstream bees executable. Start with ordinary user permissions. Reading source files and writing destination files must be permitted; a permission failure is a reason to review access, not to automatically rerun as root.
## Agent-directed operation
Install or load the [agent skill](skills/agentic-bees/SKILL.md) in your assistant, then ask it to inspect and deduplicate a specific Btrfs directory. The assistant chooses budgets, interprets each batch, and decides whether to continue; the binary itself does not run an AI model. Each scan process exits. A private saved plan retains a bounded index and cursor between invocations; an optional SQLite index stores additional hints on disk. Clean up temporary state after the task. Explicitly authorize mutation, not just discovery.
## Inspect, scan, review, apply
Replace `/srv/dedupe-data` with an existing Btrfs directory you are authorized to operate on. Keep all plans, state, lock files, and command output **outside the scanned tree**, including when that tree contains your home directory. The CLI rejects `--output`, `--resume`, and run state/lock paths inside the scanned tree and rejects symlink paths for those files. You must also keep shell-redirection output outside it.
```sh
# This example assumes /srv/dedupe-data does not contain this state directory.
state_dir="${XDG_STATE_HOME:-$HOME/.local/state}/agentic-bees"
mkdir -p "$state_dir"
agentic-bees inspect /srv/dedupe-data
agentic-bees scan /srv/dedupe-data \
--max-files 1000 --max-bytes 67108864 --max-seconds 10 \
--block-size 131072 --output "$state_dir/plan.json"
```
`scan` reads file data and prints the full plan as JSON even when `--output` saves it. Check `warnings`, `complete`, `stop_reason`, and the source/destination ranges in `candidates`. An incomplete plan can contain usable candidates. Preserve that plan before continuing if you want to apply its candidates: resumed scans retain a bounded hash index and cursor, but return a new batch of candidates rather than accumulating old batches.
```sh
agentic-bees scan /srv/dedupe-data \
--max-files 1000 --max-bytes 67108864 --max-seconds 10 \
--block-size 131072 --resume "$state_dir/plan.json" \
--output "$state_dir/next-plan.json"
# Run only after explicit authorization to apply this reviewed plan.
agentic-bees apply "$state_dir/plan.json"
```
Apply rechecks file identity and content before asking the kernel to deduplicate. It can partially succeed; inspect every result and the `errors` count. Reported `bytes_deduped` are **kernel-processed logical bytes**, not measured physical disk savings.
## Finite repeated scans
`run` is an explicit finite loop, with a default of one cycle. It resumes through `--state`, uses a neighboring `.lock` file, and saves state after each scan. It never calls Jev.
```sh
agentic-bees run /srv/dedupe-data --state "$state_dir/run.json" \
--cycles 3 --interval 60 \
--max-files 1000 --max-bytes 67108864 --max-seconds 10
```
This command only discovers. Adding `--apply` explicitly authorizes application of each newly generated plan during those cycles; review the scope before using it. Do not combine `run` with `--resume` or `--after`.
## Resumable service and allocation discovery
Choose an existing parent outside the scan root. The service creates a private 0700 state directory. It records a pending plan before applying and retains failed work rather than skipping it. A failure requires inspection and a fresh state directory for a rescan; restart after a crash may replay already processed ranges.
```sh
agentic-bees service start /srv/dedupe-data \
--state-dir /var/tmp/agentic-bees-state --max-passes 1 \
--max-bytes 67108864 --max-seconds 10
agentic-bees service status /var/tmp/agentic-bees-state
agentic-bees service pause /var/tmp/agentic-bees-state
agentic-bees service resume /var/tmp/agentic-bees-state
agentic-bees service stop /var/tmp/agentic-bees-state
agentic-bees service plan /var/tmp/agentic-bees-state
```
`start` runs until its explicit limits are reached. Add `--apply` only for authorized application; `--continuous` explicitly removes finite invocation limits. Controls are durable requests whose IDs appear in status after acknowledgement. Pause/stop waits for the current batch. `--bytes-per-second` paces average scan bytes between batches; apply I/O and blocked syscalls are not bounded by that rate. `--max-load-average` gates batches using the system's one-minute load.
For an authorized complete subvolume and appropriately provisioned permissions, add `--extent-scan` to `scan` or `service start`. No implicit privilege escalation occurs. `allocations PATH [--references]` and `extents FILE` expose bounded read-only discovery; their returned `next_cursor` can be saved separately and passed with `--cursor`. A cursor binds filesystem, scope and transaction window. Live tree observations are rechecked and do not provide snapshot isolation.
## Optional advice and MCP
`agentic-bees decide PLAN.json` asks Jev for a next-step recommendation. Set `JEV_API_KEY` in the process environment; `JEV_MODEL` defaults to `jev-latest` and `JEV_BASE_URL` to `https://api.typesafe.ai/v1`. Only allowlisted counters and a completion flag leave the machine: paths, hashes, warning text, and file contents are excluded. This is an external API request and may incur provider charges. The result is always `advisory_only: true` and cannot authorize execution.
To use an existing local Magpie gateway with its `typesafe` provider and `jev-latest` model:
```sh
export JEV_BASE_URL='http://127.0.0.1:3425/v1'
export JEV_MODEL='typesafe/jev-latest'
export JEV_API_KEY='magpie'
```
`magpie` is a nonsecret placeholder accepted by the direct loopback gateway; Magpie manages the real provider credentials. `decide` uses the native `/v1/systemone` route and can still incur provider charges through the gateway. These variables alone send no requests; `inspect`, `scan`, `apply`, `run`, and MCP do not call Jev. See [the guide](docs/agentic-bees.md#using-a-local-magpie-gateway) for persistent shell configuration.
The stdio MCP server exposes `inspect`, `scan`, `apply`, `allocations`, and `extents`. Filesystem-wide allocation inventory and `scan` with `extent_scan: true` require the separate host `--enable-inventory` switch; apply still requires `--enable-apply`:
```sh
agentic-bees mcp --root /srv/dedupe-data
```
The host must supply one or more existing absolute `--root` directories. Apply is disabled unless the host explicitly adds `--enable-apply`. Client roots and tool arguments cannot expand that scope or enable mutation. See [examples/mcp.json](examples/mcp.json) for a read-only host configuration and [the command and MCP guide](docs/agentic-bees.md) for exact tool arguments, limits, and resume behavior.
## Scope and limitations
- Discovery matches sector-aligned BLAKE3 anchors and compares source bytes. Contiguous matches coalesce up to `--block-size`; a 4 KiB shift on a 4 KiB-sector filesystem is detected. Same-inode nonoverlapping ranges are supported. Symlinks are not traversed and pathname scanning skips other devices.
- Candidate batches and the in-plan index are bounded to 65,536 entries each. `scan --index PATH` and the service's private `anchors.sqlite` keep additional hints on disk. Every hit is revalidated. Completing a pass does not prove all duplicates were discovered.
- Time and byte budgets bound cooperative discovery work, not kernel or filesystem latency. Very wide directories can fail the bounded scan and require a narrower root.
- Plans contain sensitive local paths, hashes, and metadata. Protect them locally even though optional Jev advice strips those fields.
- `service start` runs in the foreground with durable pending plans, an exclusive lock, status/pause/resume/stop controls, optional average scan throughput pacing and a load gate. Continuous operation needs `--continuous`; default operation stops after one batch. No startup unit, timer or automatic model execution is installed.
- `scan --extent-scan` uses `TREE_SEARCH_V2`, `LOGICAL_INO_V2` and inode paths, requiring kernel privilege and a full subvolume root (inode 256). It processes references only in that authorized subvolume, reports skipped outside/unsupported references, and never expands authority to snapshots. Inline, preallocated, hole and unaligned EOF ranges are excluded. Compressed file data is read through normal file offsets; allocation addresses are filesystem-logical addresses.
- Allocation-aware residual rewriting, full all-reference reclamation, cost optimization and upstream-equivalent operational coverage are unfinished. This development tree must not be published as a completed bees replacement.
[Companion agent skill](skills/agentic-bees/SKILL.md) · [Local Arch packaging](docs/agentic-bees.md#local-arch-package) · [License](COPYING) (GPL-3.0-or-later)