diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index d1d0a52ee..5a3e918ab 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -7,20 +7,12 @@ on:
permissions:
contents: read
-env:
- FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
-
jobs:
# ---------------------------------------------------------------------------
- # Linux: compile KVM hypervisor backend (cfg(target_os = "linux"))
+ # Linux: compile + test KVM hypervisor backend (cfg(target_os = "linux"))
# ---------------------------------------------------------------------------
test-linux:
runs-on: ubuntu-24.04-arm
- env:
- # Hosted ARM runners can expose /dev/kvm but hang in nested/restricted
- # KVM ioctls. PR CI compiles the Linux KVM backend and test binaries.
- # The release pipeline owns real-KVM coverage.
- CAPSEM_SKIP_KVM_TESTS: "1"
steps:
- uses: actions/checkout@v5
@@ -28,48 +20,50 @@ jobs:
with:
components: llvm-tools
- - name: Normalize cargo proxy
- run: bash scripts/ci/normalize-cargo.sh
-
- uses: Swatinem/rust-cache@v2
- # Collect KVM diagnostics only. GitHub-hosted runners don't always expose
- # nested virt -- and when they do, restricted ioctls can hang. PR CI
- # compiles the KVM backend with CAPSEM_SKIP_KVM_TESTS=1; the release
- # pipeline owns real-KVM coverage.
- - name: Collect KVM diagnostics
+ # Try to enable KVM for integration tests. GitHub-hosted runners don't
+ # always expose nested virt -- when /dev/kvm is absent the udev trigger
+ # fails with "Failed to open the device 'kvm': Invalid argument". We
+ # let that pass and fall through to a compile-only/no-KVM run; the
+ # release pipeline owns real-KVM coverage. See sprints/done/ci-green.
+ - name: Enable KVM (best-effort)
+ continue-on-error: true
run: |
- if echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules >/dev/null; then
- sudo udevadm control --reload-rules || echo "::notice::udev reload failed; keeping KVM diagnostics non-blocking"
- sudo udevadm trigger --name-match=kvm || echo "::notice::udev trigger failed; keeping KVM diagnostics non-blocking"
- else
- echo "::notice::could not write KVM udev rule; keeping KVM diagnostics non-blocking"
- fi
- if [ -e /dev/kvm ]; then
- ls -l /dev/kvm
- else
- echo "::notice::/dev/kvm is not present on this runner"
- fi
+ echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
+ sudo udevadm control --reload-rules
+ sudo udevadm trigger --name-match=kvm
- # Compile Linux library + service crate tests without executing them. The
- # macOS job owns runtime unit coverage for portable code; this job proves
- # the Linux-only/KVM cfg surface and test binaries compile on aarch64.
+ - name: Install tools
+ run: |
+ cargo install cargo-nextest --locked
+ cargo install cargo-llvm-cov --locked
+
+ # Library + service crate tests with coverage (capsem-core includes KVM backend on Linux).
# capsem-app (Tauri shell) and capsem-tray (macOS muda menu-bar) are macOS-only; every
- # other host crate is portable and compiles here for Linux-specific regression coverage.
- - name: Compile tests (KVM backend, no live KVM)
- timeout-minutes: 15
+ # other host crate is portable and runs here so it gets Linux-specific regression coverage.
+ - name: Unit tests (KVM backend) with coverage
run: |
- cargo test --no-run --all-targets -p capsem-core -p capsem-agent -p capsem-logger -p capsem-proto -p capsem-guard -p capsem-gateway -p capsem-service -p capsem -p capsem-mcp -p capsem-mcp-aggregator -p capsem-mcp-builtin -p capsem-process
+ cargo llvm-cov nextest --no-cfg-coverage --profile ci --codecov --output-path codecov-linux.json -p capsem-core -p capsem-admin -p capsem-agent -p capsem-logger -p capsem-proto -p capsem-guard -p capsem-gateway -p capsem-service -p capsem -p capsem-tui -p capsem-mcp -p capsem-mcp-aggregator -p capsem-mcp-builtin -p capsem-process
+ cargo llvm-cov report --summary-only -p capsem-core -p capsem-admin -p capsem-agent -p capsem-logger -p capsem-proto -p capsem-guard -p capsem-gateway -p capsem-service -p capsem -p capsem-tui -p capsem-mcp -p capsem-mcp-aggregator -p capsem-mcp-builtin -p capsem-process 2>&1 | tee coverage-summary-linux.txt
+
+ - name: Upload Linux coverage
+ if: ${{ !cancelled() }}
+ uses: codecov/codecov-action@v5
+ with:
+ files: codecov-linux.json
+ flags: linux-unit
+ token: ${{ secrets.CODECOV_TOKEN }}
+ fail_ci_if_error: false
- # Note KVM exercise status. Hosted ARM runners may lack /dev/kvm or
- # expose restricted nested KVM; PR CI keeps this compile/no-run and
- # release CI owns live-KVM coverage. Surfacing as a warning keeps CI
- # honest without false-failing or hanging on a runner-fleet limitation.
+ # Note KVM exercise status. Hosted ARM runners may lack /dev/kvm; the
+ # compile-only path still catches Linux build/lint regressions, and
+ # real-KVM coverage runs in the release pipeline. Surfacing as a
+ # warning (not an error) keeps CI honest about what was actually
+ # exercised without false-failing on a runner-fleet limitation.
- name: Note KVM exercise status
run: |
- if [ "${CAPSEM_SKIP_KVM_TESTS:-}" = "1" ]; then
- echo "::warning::CAPSEM_SKIP_KVM_TESTS=1 -- PR CI compiled the KVM backend but did not exercise live KVM. Real-KVM coverage runs in release pipeline."
- elif [ -e /dev/kvm ]; then
+ if [ -e /dev/kvm ]; then
echo "KVM is available at /dev/kvm -- KVM-backed tests exercised."
else
echo "::warning::/dev/kvm not available on this runner -- compile + non-KVM tests only. Real-KVM coverage runs in release pipeline."
@@ -79,11 +73,9 @@ jobs:
if: always()
run: |
KVM_STATUS="available"
- if [ "${CAPSEM_SKIP_KVM_TESTS:-}" = "1" ]; then
- KVM_STATUS="skipped in PR CI"
- elif [ ! -e /dev/kvm ]; then
- KVM_STATUS="not available"
- fi
+ [ -e /dev/kvm ] || KVM_STATUS="not available"
+ COV=$(grep 'TOTAL' coverage-summary-linux.txt 2>/dev/null | awk '{print $(NF)}' || echo "?")
+
cat >> "$GITHUB_STEP_SUMMARY" << EOF
## Linux Test Results
@@ -91,8 +83,8 @@ jobs:
|--------|--------|
| Runner | ubuntu-24.04-arm (aarch64) |
| /dev/kvm | $KVM_STATUS |
- | Test execution | no-run in PR CI |
- | KVM backend | compiled with test binaries (real-KVM tests run in release pipeline) |
+ | Line coverage | $COV |
+ | KVM backend | compiled (real-KVM tests run only when /dev/kvm is present) |
EOF
# T5: preserve test artifacts on failure (Linux job).
@@ -104,7 +96,6 @@ jobs:
path: |
test-artifacts/
frontend/test-artifacts/
- target/build.log
retention-days: 7
if-no-files-found: ignore
@@ -121,9 +112,6 @@ jobs:
targets: aarch64-unknown-linux-musl,x86_64-unknown-linux-musl
components: llvm-tools
- - name: Normalize cargo proxy
- run: bash scripts/ci/normalize-cargo.sh
-
- uses: Swatinem/rust-cache@v2
- uses: pnpm/action-setup@v5
@@ -134,13 +122,11 @@ jobs:
node-version: 24
cache: pnpm
cache-dependency-path: frontend/pnpm-lock.yaml
- - run: cd frontend && pnpm install --frozen-lockfile
-
- uses: astral-sh/setup-uv@v5
- run: uv sync
-
- - name: Normalize cargo proxy after Python setup
- run: bash scripts/ci/normalize-cargo.sh
+ - run: bash scripts/generate-settings.sh
+ - run: cd frontend && pnpm install --frozen-lockfile
+ - run: cd frontend && pnpm run build
- name: Dependency audit
run: |
@@ -153,24 +139,18 @@ jobs:
cargo install cargo-llvm-cov --locked
cargo install cargo-nextest --locked
- - name: Create frontend dist for Tauri test build
- run: |
- mkdir -p frontend/dist
- printf '
\n' > frontend/dist/index.html
-
# Unit tests: all crates with coverage + JUnit XML for test analytics.
# capsem-app (Tauri bin) is macOS-only; capsem-mcp-aggregator and
# capsem-mcp-builtin are thin binaries that pull capsem-core logic.
- name: Unit tests with coverage
run: |
- set -o pipefail
- cargo llvm-cov nextest --no-cfg-coverage --profile ci --codecov --output-path codecov-unit.json --fail-under-lines 65 -p capsem-core -p capsem-agent -p capsem-logger -p capsem-proto -p capsem-guard -p capsem-gateway -p capsem-service -p capsem -p capsem-mcp -p capsem-mcp-aggregator -p capsem-mcp-builtin -p capsem-tray -p capsem-app -p capsem-process
- cargo llvm-cov report --summary-only -p capsem-core -p capsem-agent -p capsem-logger -p capsem-proto -p capsem-guard -p capsem-gateway -p capsem-service -p capsem -p capsem-mcp -p capsem-mcp-aggregator -p capsem-mcp-builtin -p capsem-tray -p capsem-app -p capsem-process 2>&1 | tee coverage-summary.txt
+ cargo llvm-cov nextest --no-cfg-coverage --profile ci --codecov --output-path codecov-unit.json -p capsem-core -p capsem-admin -p capsem-agent -p capsem-logger -p capsem-proto -p capsem-guard -p capsem-gateway -p capsem-service -p capsem -p capsem-tui -p capsem-mcp -p capsem-mcp-aggregator -p capsem-mcp-builtin -p capsem-tray -p capsem-app -p capsem-process
+ cargo llvm-cov report --summary-only -p capsem-core -p capsem-admin -p capsem-agent -p capsem-logger -p capsem-proto -p capsem-guard -p capsem-gateway -p capsem-service -p capsem -p capsem-tui -p capsem-mcp -p capsem-mcp-aggregator -p capsem-mcp-builtin -p capsem-tray -p capsem-app -p capsem-process 2>&1 | tee coverage-summary.txt
# Integration tests (tests/ directory, cross-crate)
- name: Integration tests with coverage
run: |
- cargo llvm-cov nextest --no-cfg-coverage --profile ci --codecov --output-path codecov-integration.json -p capsem-core --test '*'
+ cargo llvm-cov nextest --no-cfg-coverage --profile ci --codecov --output-path codecov-integration.json -p capsem-core --test '*' || true
# Frontend tests with coverage + JUnit output
- name: Frontend type-check, test, and build
@@ -181,16 +161,48 @@ jobs:
pnpm run build
# Python schema tests with coverage
- - name: Python schema tests with coverage
- run: uv run python -m pytest tests/test_*.py --cov=src/capsem --cov-report=xml:codecov-python.xml --cov-fail-under=89 --junitxml=python-junit.xml
+ - name: Python lint and type check
+ run: |
+ uv run ruff check .
+ uv run ty check src/capsem
+ uv run capsem-builder validate-skills skills
- # Python integration tests that need no VM and no generated assets.
- # Bootstrap/codesign suites are artifact-dependent: full `just test`
- # runs them after assets and signed host binaries exist, while this PR
- # lane import-collects them below to catch syntax/fixture drift.
+ - name: Python schema tests with coverage
+ run: |
+ uv run python -m pytest \
+ tests/test_audit.py \
+ tests/test_build_pkg.py \
+ tests/test_capsem_bench_mock_server_protocol.py \
+ tests/test_capsem_bench_storage.py \
+ tests/test_cli.py \
+ tests/test_config.py \
+ tests/test_docker.py \
+ tests/test_doctor.py \
+ tests/test_manifest.py \
+ tests/test_mcp.py \
+ tests/test_mock_server_launcher.py \
+ tests/test_models.py \
+ tests/test_protocol_fixture_recorder.py \
+ tests/test_repack_deb.py \
+ tests/test_settings_spec.py \
+ tests/test_skills.py \
+ tests/test_validate.py \
+ tests/capsem-cleanup-script/test_clean_stale.py \
+ tests/capsem-rootfs-artifacts/test_rootfs_artifacts.py \
+ --cov=src/capsem \
+ --cov-report=xml:codecov-python.xml \
+ --cov-fail-under=90 \
+ --junitxml=python-junit.xml
+
+ # Python integration tests that need no VM
- name: Python integration tests (non-VM suites)
run: |
- uv run python -m pytest tests/capsem-rootfs-artifacts/ -v --tb=short
+ bash scripts/prepare-install-test-assets.sh
+ cargo build -p capsem-process -p capsem-service -p capsem -p capsem-mcp
+ for bin in target/debug/capsem-process target/debug/capsem-service target/debug/capsem target/debug/capsem-mcp; do
+ codesign --sign - --entitlements entitlements.plist --force "$bin"
+ done
+ uv run python -m pytest tests/capsem-bootstrap/ tests/capsem-codesign/ tests/capsem-rootfs-artifacts/ -v --tb=short
# Verify all integration test suites import cleanly (catches broken imports/syntax)
- name: Verify all integration test imports
@@ -201,7 +213,9 @@ jobs:
- name: Schema drift check
run: |
uv run python scripts/generate_schema.py
- git diff --exit-code config/settings-schema.json
+ git diff --exit-code config/settings/schema.generated.json \
+ config/settings/ui-metadata.generated.json \
+ frontend/src/lib/mock-settings.generated.ts
# Upload coverage with flags
- name: Upload Rust unit test coverage
@@ -226,7 +240,7 @@ jobs:
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v5
with:
- files: coverage/frontend/coverage-final.json
+ files: frontend/coverage/coverage-final.json
flags: unit
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
@@ -243,11 +257,10 @@ jobs:
# Upload test results for test analytics
- name: Upload test results to Codecov
if: ${{ !cancelled() }}
- uses: codecov/codecov-action@v5
+ uses: codecov/test-results-action@v1
with:
files: target/nextest/ci/junit.xml,frontend-junit.xml,python-junit.xml
token: ${{ secrets.CODECOV_TOKEN }}
- report_type: test_results
# T5: preserve every test artifact (service.log / process.log /
# session.db etc.) on failure so PR reviewers can debug without
@@ -262,15 +275,11 @@ jobs:
path: |
test-artifacts/
frontend/test-artifacts/
- target/build.log
retention-days: 7
if-no-files-found: ignore
# Check-only (no link) -- actual cross-compile runs on Linux in release workflow
- name: Cross-compile check (guest binaries)
- # Keep release-profile checks on PR validation, but skip them on
- # post-merge pushes to main.
- if: ${{ github.event_name == 'pull_request' }}
run: |
cargo check --release --target aarch64-unknown-linux-musl -p capsem-agent
cargo check --release --target x86_64-unknown-linux-musl -p capsem-agent
@@ -302,34 +311,8 @@ jobs:
steps:
- uses: actions/checkout@v5
- - uses: dtolnay/rust-toolchain@stable
- with:
- targets: aarch64-unknown-linux-musl
- components: llvm-tools
-
- - name: Normalize cargo proxy
- run: bash scripts/ci/normalize-cargo.sh
-
- uses: extractions/setup-just@v3
- - uses: pnpm/action-setup@v5
- with:
- version: 10
- - uses: actions/setup-node@v5
- with:
- node-version: 24
-
- - uses: astral-sh/setup-uv@v5
- - run: uv sync
-
- - name: Install install-test host tools
- run: |
- sudo apt-get update
- sudo apt-get install -y --no-install-recommends b3sum minisign
-
- - name: Build install VM assets
- run: bash scripts/build-assets.sh --profile config/profiles/base/coding.profile.toml --assets-dir assets --arch arm64
-
- name: Build host builder Docker image
run: just build-host-image
diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml
index f60e61657..ec27ce2c2 100644
--- a/.github/workflows/docs.yaml
+++ b/.github/workflows/docs.yaml
@@ -14,7 +14,6 @@ jobs:
deployments: write
env:
- FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
steps:
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 58715ec4e..671d81071 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -8,9 +8,6 @@ permissions:
attestations: write
id-token: write
-env:
- FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
-
jobs:
preflight:
runs-on: macos-14
@@ -24,19 +21,7 @@ jobs:
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
- APPLE_INSTALLER_SIGNING_IDENTITY: ${{ secrets.APPLE_INSTALLER_SIGNING_IDENTITY }}
run: |
- if [ -z "$APPLE_INSTALLER_SIGNING_IDENTITY" ]; then
- echo "::error::APPLE_INSTALLER_SIGNING_IDENTITY secret is not set"
- exit 1
- fi
- case "$APPLE_INSTALLER_SIGNING_IDENTITY" in
- "Developer ID Installer:"*) ;;
- *)
- echo "::error::APPLE_INSTALLER_SIGNING_IDENTITY must name a Developer ID Installer identity"
- exit 1
- ;;
- esac
echo "$APPLE_CERTIFICATE" | base64 --decode > cert.p12
KEYCHAIN="preflight-$$.keychain"
security create-keychain -p "" "$KEYCHAIN"
@@ -111,21 +96,25 @@ jobs:
- uses: astral-sh/setup-uv@v5
- run: uv sync
- uses: extractions/setup-just@v3
+ - uses: actions/setup-node@v5
+ with:
+ node-version: 24
+
+ - name: Install OBOM generator
+ run: |
+ npm install -g @cyclonedx/cdxgen@latest
+ cdxgen --version
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.rust-target }}
- - name: Normalize cargo proxy
- run: bash scripts/ci/normalize-cargo.sh
-
- name: Build VM assets (kernel + rootfs)
+ env:
+ CAPSEM_CDXGEN_CMD: cdxgen
run: |
- just build-kernel ${{ matrix.arch }}
- just build-rootfs ${{ matrix.arch }}
-
- - name: Validate rootfs contains all required artifacts
- run: scripts/validate-rootfs.sh assets/${{ matrix.arch }}/rootfs.squashfs
+ just build-kernel ${{ matrix.arch }} code
+ just build-rootfs ${{ matrix.arch }} code
- uses: actions/upload-artifact@v7
with:
@@ -142,9 +131,6 @@ jobs:
with:
components: llvm-tools
- - name: Normalize cargo proxy
- run: bash scripts/ci/normalize-cargo.sh
-
- uses: Swatinem/rust-cache@v2
with:
key: test
@@ -213,16 +199,11 @@ jobs:
EOF
test-install:
- needs: [preflight, build-assets]
+ needs: preflight
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v5
- - uses: actions/download-artifact@v8
- with:
- name: vm-assets-arm64
- path: assets/arm64/
-
- uses: extractions/setup-just@v3
- name: Install Linux host-build deps
@@ -236,9 +217,7 @@ jobs:
librsvg2-dev \
libxdo-dev \
pkg-config \
- build-essential \
- b3sum \
- minisign
+ build-essential
- name: Build host builder Docker image
run: just build-host-image
@@ -259,12 +238,8 @@ jobs:
with:
name: vm-assets-arm64
path: assets/arm64/
- - uses: actions/download-artifact@v8
- with:
- name: vm-assets-x86_64
- path: assets/x86_64/
- # Regenerate unified manifest for both arch dirs.
+ # Regenerate manifest for this arch (creates assets/current symlink).
- uses: astral-sh/setup-uv@v5
- run: uv sync
- name: Generate manifest
@@ -276,16 +251,6 @@ jobs:
generate_checksums(Path('assets'), '$VERSION')
"
- - name: Sign package payload manifest
- run: |
- brew install minisign
- echo "$MINISIGN_SECRET_KEY" > /tmp/manifest-sign.key
- minisign -S -s /tmp/manifest-sign.key -m assets/manifest.json
- rm /tmp/manifest-sign.key
- minisign -Vm assets/manifest.json -x assets/manifest.json.minisig -p config/manifest-sign.pub
- env:
- MINISIGN_SECRET_KEY: ${{ secrets.MINISIGN_SECRET_KEY }}
-
# Replace symlink with real copy -- GitHub Actions strips symlinks
# and Tauri build.rs needs assets/current/ to exist as a real dir.
- name: Copy assets/current
@@ -294,14 +259,21 @@ jobs:
cp -r assets/arm64 assets/current
- uses: dtolnay/rust-toolchain@stable
-
- - name: Normalize cargo proxy
- run: bash scripts/ci/normalize-cargo.sh
-
- uses: Swatinem/rust-cache@v2
with:
key: build-app-macos
+ - name: Materialize runtime config
+ run: |
+ cargo run -p capsem-admin -- profile materialize \
+ --profile config/profiles/code/profile.toml \
+ --config-root config \
+ --manifest assets/manifest.json \
+ --assets-dir assets \
+ --output-root target/config \
+ --arch arm64 \
+ --clean
+
- uses: pnpm/action-setup@v5
with:
version: 10
@@ -380,20 +352,19 @@ jobs:
-p capsem \
-p capsem-service \
-p capsem-process \
+ -p capsem-tui \
-p capsem-mcp \
-p capsem-mcp-aggregator \
-p capsem-mcp-builtin \
-p capsem-gateway \
- -p capsem-tray
-
- - name: Prepare capsem-admin package payload
- run: bash scripts/prepare-admin-cli.sh target/release
+ -p capsem-tray \
+ -p capsem-admin
- name: Codesign companion binaries
env:
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
run: |
- for bin in capsem capsem-service capsem-process capsem-mcp capsem-mcp-aggregator capsem-mcp-builtin capsem-gateway capsem-tray; do
+ for bin in capsem capsem-service capsem-process capsem-tui capsem-mcp capsem-mcp-aggregator capsem-mcp-builtin capsem-gateway capsem-tray capsem-admin; do
codesign --sign "$APPLE_SIGNING_IDENTITY" \
--options runtime \
--timestamp \
@@ -403,40 +374,16 @@ jobs:
done
- name: Build .pkg installer
- env:
- APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
- APPLE_INSTALLER_SIGNING_IDENTITY: ${{ secrets.APPLE_INSTALLER_SIGNING_IDENTITY }}
run: |
VERSION="${GITHUB_REF_NAME#v}"
- export CAPSEM_INSTALL_PROFILE_ASSET_ROOT="https://github.com/google/capsem/releases/download/v${VERSION}/{arch}-{name}"
bash scripts/build-pkg.sh \
+ --manifest assets/manifest.json \
"target/release/bundle/macos/Capsem.app" \
"target/release" \
"assets" \
+ "target/config" \
"$VERSION" \
- "$APPLE_INSTALLER_SIGNING_IDENTITY"
-
- - name: Verify .pkg payload manifest
- run: |
- VERSION="${GITHUB_REF_NAME#v}"
- EXPANDED="$RUNNER_TEMP/capsem-pkg-expanded"
- rm -rf "$EXPANDED"
- pkgutil --expand-full "packages/Capsem-$VERSION.pkg" "$EXPANDED"
- MANIFEST=$(find "$EXPANDED" -path '*/usr/local/share/capsem/assets/manifest.json' -print -quit)
- SIG=$(find "$EXPANDED" -path '*/usr/local/share/capsem/assets/manifest.json.minisig' -print -quit)
- if [ -z "$MANIFEST" ] || [ -z "$SIG" ]; then
- echo "::error::.pkg payload missing manifest.json or manifest.json.minisig"
- exit 1
- fi
- minisign -Vm "$MANIFEST" -x "$SIG" -p config/manifest-sign.pub
- python3 - "$MANIFEST" <<'PY'
- import json, sys
- data = json.load(open(sys.argv[1]))
- arches = data["assets"]["releases"][data["assets"]["current"]]["arches"]
- missing = {"arm64", "x86_64"} - set(arches)
- if missing:
- raise SystemExit(f"manifest missing arch maps: {sorted(missing)}")
- PY
+ "${{ secrets.APPLE_INSTALLER_SIGNING_IDENTITY }}"
- name: Notarize and staple .pkg
env:
@@ -453,12 +400,6 @@ jobs:
xcrun stapler staple "packages/Capsem-$VERSION.pkg"
xcrun stapler validate "packages/Capsem-$VERSION.pkg"
- - name: Verify .pkg signature and Gatekeeper acceptance
- run: |
- VERSION="${GITHUB_REF_NAME#v}"
- pkgutil --check-signature "packages/Capsem-$VERSION.pkg"
- spctl -a -vv -t install "packages/Capsem-$VERSION.pkg"
-
- name: Generate SBOM
run: cargo sbom --output-format spdx_json_2_3 > capsem-sbom.spdx.json
@@ -481,6 +422,9 @@ jobs:
build-app-linux:
needs: [preflight, build-assets, test, test-install]
+ # Linux release is best-effort for now. See sprints/linux/tracker.md --
+ # macOS .pkg is the shipping artifact until Linux is verified end-to-end.
+ continue-on-error: true
strategy:
fail-fast: false
matrix:
@@ -511,17 +455,6 @@ jobs:
generate_checksums(Path('assets'), '$VERSION')
"
- - name: Sign package payload manifest
- run: |
- sudo apt-get update
- sudo apt-get install -y --no-install-recommends minisign zstd
- echo "$MINISIGN_SECRET_KEY" > /tmp/manifest-sign.key
- minisign -S -s /tmp/manifest-sign.key -m assets/manifest.json
- rm /tmp/manifest-sign.key
- minisign -Vm assets/manifest.json -x assets/manifest.json.minisig -p config/manifest-sign.pub
- env:
- MINISIGN_SECRET_KEY: ${{ secrets.MINISIGN_SECRET_KEY }}
-
# Replace symlink with real copy -- GitHub Actions strips symlinks
# and Tauri build.rs needs assets/current/ to exist as a real dir.
- name: Copy assets/current
@@ -530,14 +463,21 @@ jobs:
cp -r assets/${{ matrix.arch }} assets/current
- uses: dtolnay/rust-toolchain@stable
-
- - name: Normalize cargo proxy
- run: bash scripts/ci/normalize-cargo.sh
-
- uses: Swatinem/rust-cache@v2
with:
key: build-app-linux-${{ matrix.arch }}
+ - name: Materialize runtime config
+ run: |
+ cargo run -p capsem-admin -- profile materialize \
+ --profile config/profiles/code/profile.toml \
+ --config-root config \
+ --manifest assets/manifest.json \
+ --assets-dir assets \
+ --output-root target/config \
+ --arch ${{ matrix.arch }} \
+ --clean
+
- name: Install Tauri system deps
run: |
sudo apt-get update
@@ -579,7 +519,27 @@ jobs:
cat assets/manifest.json | head -5
- name: Validate rootfs contains all required artifacts
- run: scripts/validate-rootfs.sh assets/${{ matrix.arch }}/rootfs.squashfs
+ run: |
+ ROOTFS="assets/${{ matrix.arch }}/rootfs.erofs"
+ if [ ! -f "$ROOTFS" ]; then
+ echo "::error::rootfs.erofs not found at $ROOTFS"
+ exit 1
+ fi
+ MOUNT=$(mktemp -d)
+ sudo mount -t erofs -o loop,ro "$ROOTFS" "$MOUNT"
+ MISSING=""
+ for bin in capsem-pty-agent capsem-net-proxy capsem-mcp-server capsem-doctor capsem-bench snapshots; do
+ if [ ! -f "$MOUNT/usr/local/bin/$bin" ]; then
+ MISSING="$MISSING $bin"
+ fi
+ done
+ sudo umount "$MOUNT"
+ rmdir "$MOUNT"
+ if [ -n "$MISSING" ]; then
+ echo "::error::rootfs is missing required binaries:$MISSING"
+ exit 1
+ fi
+ echo "All required binaries present in rootfs"
- name: Build app
env:
@@ -591,34 +551,19 @@ jobs:
- name: Build companion binaries
run: |
- cargo build --release -p capsem -p capsem-service -p capsem-process -p capsem-mcp -p capsem-mcp-aggregator -p capsem-mcp-builtin -p capsem-gateway -p capsem-tray
-
- - name: Prepare capsem-admin package payload
- run: bash scripts/prepare-admin-cli.sh target/release
+ cargo build --release -p capsem -p capsem-service -p capsem-process -p capsem-tui -p capsem-mcp -p capsem-mcp-aggregator -p capsem-mcp-builtin -p capsem-gateway -p capsem-tray -p capsem-admin
- name: Repack .deb with companion binaries
run: |
- VERSION="${GITHUB_REF_NAME#v}"
- export CAPSEM_INSTALL_PROFILE_ASSET_ROOT="https://github.com/google/capsem/releases/download/v${VERSION}/{arch}-{name}"
DEB_FILE=$(ls target/release/bundle/deb/*.deb)
- bash scripts/repack-deb.sh "$DEB_FILE" "target/release" "assets"
+ bash scripts/repack-deb.sh --manifest assets/manifest.json "$DEB_FILE" "target/release" "target/config" "assets"
- name: Validate artifacts
run: |
echo "=== Validate deb ==="
dpkg-deb --info target/release/bundle/deb/*.deb
- echo "=== Verify companion binaries and signed manifest in deb ==="
- VERSION="${GITHUB_REF_NAME#v}"
- case "${{ matrix.arch }}" in
- arm64) deb_arch=arm64 ;;
- x86_64) deb_arch=amd64 ;;
- *) echo "::error::unknown release arch ${{ matrix.arch }}" >&2; exit 1 ;;
- esac
- python3 scripts/verify_deb_payload.py \
- target/release/bundle/deb/*.deb \
- --version "$VERSION" \
- --architecture "$deb_arch" \
- --minisign-pubkey config/manifest-sign.pub
+ echo "=== Verify companion binaries in deb ==="
+ dpkg-deb --contents target/release/bundle/deb/*.deb | grep -E "capsem-service|capsem-tui|capsem-mcp-aggregator|capsem-mcp-builtin|capsem-gateway|capsem-tray|capsem-admin"
- name: Boot test (x86_64)
if: matrix.arch == 'x86_64'
@@ -662,13 +607,12 @@ jobs:
path: release-artifacts/
create-release:
- needs: [test, test-install, build-assets, build-app-macos, build-app-linux]
+ needs: [test, test-install, build-app-macos, build-app-linux]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- # Download all platform artifacts. Expected package artifacts are
- # release-blocking: missing Linux artifacts must fail before publish.
+ # Download all platform artifacts. macOS is required; Linux is best-effort.
- uses: actions/download-artifact@v8
with:
name: release-macos
@@ -677,10 +621,12 @@ jobs:
with:
name: release-linux-arm64
path: release-artifacts/
+ continue-on-error: true
- uses: actions/download-artifact@v8
with:
name: release-linux-x86_64
path: release-artifacts/
+ continue-on-error: true
# Download per-arch VM assets for the release.
- uses: actions/download-artifact@v8
@@ -701,10 +647,6 @@ jobs:
mkdir -p unified-assets/arm64 unified-assets/x86_64
cp release-artifacts/arm64/* unified-assets/arm64/
cp release-artifacts/x86_64/* unified-assets/x86_64/
- gh release download --pattern manifest.json -D /tmp/prev-manifest 2>/dev/null || true
- if [ -f /tmp/prev-manifest/manifest.json ]; then
- cp /tmp/prev-manifest/manifest.json unified-assets/manifest.json
- fi
VERSION="${GITHUB_REF_NAME#v}"
uv run python3 -c "
from pathlib import Path
@@ -712,8 +654,6 @@ jobs:
generate_checksums(Path('unified-assets'), '$VERSION')
"
cp unified-assets/manifest.json release-artifacts/manifest.json
- env:
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Populate v2 manifest binaries.releases[VERSION] with pkg + deb entries
# and merge previous release's assets/binaries so clients can still
@@ -747,24 +687,19 @@ jobs:
return h.hexdigest()
binary_files = []
+ # .pkg is required -- .deb may be absent if Linux best-effort build failed.
for pattern in ('*.pkg', '*.deb'):
binary_files.extend(sorted(artifacts.glob(pattern)))
if not any(f.suffix == '.pkg' for f in binary_files):
raise SystemExit('No .pkg found in release-artifacts/ -- macOS build must have failed')
- debs = [f for f in binary_files if f.suffix == '.deb']
- if len(debs) < 2:
- raise SystemExit(f'Expected Linux .deb artifacts for both arches, found {len(debs)}')
-
- # Preserve generated metadata (`date`, `deprecated`, `min_assets`)
- # while adding package file hashes for the published release.
- entry = new['binaries']['releases'].get(version, {})
- entry.update({
+
+ entry = {
'version': version,
'files': [
{'name': f.name, 'size': f.stat().st_size, 'sha256': sha256(f)}
for f in binary_files
],
- })
+ }
new['binaries']['releases'][version] = entry
print(f'Populated binaries.releases[{version}] with {len(entry["files"])} file(s):')
for fd in entry['files']:
@@ -792,36 +727,20 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- - name: Sign manifest
- run: |
- sudo apt-get update && sudo apt-get install -y minisign
- echo "$MINISIGN_SECRET_KEY" > /tmp/manifest-sign.key
- minisign -S -s /tmp/manifest-sign.key -m release-artifacts/manifest.json
- rm /tmp/manifest-sign.key
- env:
- MINISIGN_SECRET_KEY: ${{ secrets.MINISIGN_SECRET_KEY }}
-
- - name: Attest build provenance (packages, signed manifest, boot assets)
+ - name: Attest build provenance (pkg + deb + rootfs per arch)
uses: actions/attest-build-provenance@v4
with:
subject-path: |
release-artifacts/*.pkg
release-artifacts/*.deb
- release-artifacts/manifest.json
- release-artifacts/manifest.json.minisig
- release-artifacts/arm64/vmlinuz
- release-artifacts/arm64/initrd.img
- release-artifacts/arm64/rootfs.squashfs
- release-artifacts/x86_64/vmlinuz
- release-artifacts/x86_64/initrd.img
- release-artifacts/x86_64/rootfs.squashfs
+ release-artifacts/arm64/rootfs.erofs
+ release-artifacts/x86_64/rootfs.erofs
- name: Attest SBOM
uses: actions/attest@v4
with:
subject-path: |
release-artifacts/*.pkg
- release-artifacts/*.deb
predicate-type: https://spdx.dev/Document/v2.3
predicate-path: release-artifacts/capsem-sbom.spdx.json
@@ -831,11 +750,15 @@ jobs:
PKG=$(ls -1 release-artifacts/*.pkg 2>/dev/null | head -1)
PKG_NAME=$(basename "$PKG" 2>/dev/null || echo "N/A")
PKG_SIZE=$(du -h "$PKG" 2>/dev/null | cut -f1 || echo "N/A")
- ARM64_ROOTFS=$(du -h release-artifacts/arm64/rootfs.squashfs 2>/dev/null | cut -f1 || echo "N/A")
- X86_ROOTFS=$(du -h release-artifacts/x86_64/rootfs.squashfs 2>/dev/null | cut -f1 || echo "N/A")
+ ARM64_ROOTFS=$(du -h release-artifacts/arm64/rootfs.erofs 2>/dev/null | cut -f1 || echo "N/A")
+ X86_ROOTFS=$(du -h release-artifacts/x86_64/rootfs.erofs 2>/dev/null | cut -f1 || echo "N/A")
SBOM_PKGS=$(python3 -c "import json; d=json.load(open('release-artifacts/capsem-sbom.spdx.json')); print(len(d.get('packages',[])))" 2>/dev/null || echo "?")
+ ARM64_OBOM=$(du -h release-artifacts/arm64/obom.cdx.json 2>/dev/null | cut -f1 || echo "N/A")
+ X86_OBOM=$(du -h release-artifacts/x86_64/obom.cdx.json 2>/dev/null | cut -f1 || echo "N/A")
+ ARM64_OBOM_COMPONENTS=$(python3 -c "import json; d=json.load(open('release-artifacts/arm64/obom.cdx.json')); print(len(d.get('components',[])))" 2>/dev/null || echo "?")
+ X86_OBOM_COMPONENTS=$(python3 -c "import json; d=json.load(open('release-artifacts/x86_64/obom.cdx.json')); print(len(d.get('components',[])))" 2>/dev/null || echo "?")
- # Build artifact table rows for required Linux debs.
+ # Build artifact table rows for all debs (may be absent if Linux best-effort failed)
LINUX_ROWS=""
for f in release-artifacts/*.deb; do
[ -f "$f" ] || continue
@@ -844,10 +767,8 @@ jobs:
LINUX_ROWS="${LINUX_ROWS}| ${NAME} | ${SIZE} |
"
done
- if [ -z "$LINUX_ROWS" ]; then
- echo "::error::No .deb artifacts found"
- exit 1
- fi
+ [ -z "$LINUX_ROWS" ] && LINUX_ROWS="| (no .deb produced -- Linux best-effort) | -- |
+ "
cat >> "$GITHUB_STEP_SUMMARY" << EOF
## Release $VERSION
@@ -857,17 +778,19 @@ jobs:
| File | Size |
|------|------|
| $PKG_NAME | $PKG_SIZE |
- ${LINUX_ROWS}| rootfs.squashfs (arm64) | $ARM64_ROOTFS |
- | rootfs.squashfs (x86_64) | $X86_ROOTFS |
- | manifest.json | signed (minisign) |
+ ${LINUX_ROWS}| rootfs.erofs (arm64) | $ARM64_ROOTFS |
+ | rootfs.erofs (x86_64) | $X86_ROOTFS |
+ | manifest.json | BLAKE3 asset metadata |
| capsem-sbom.spdx.json | $SBOM_PKGS packages |
+ | obom.cdx.json (arm64) | $ARM64_OBOM, $ARM64_OBOM_COMPONENTS components |
+ | obom.cdx.json (x86_64) | $X86_OBOM, $X86_OBOM_COMPONENTS components |
### Security
- Apple codesigned (Developer ID), notarized + stapled (.pkg)
- SLSA build provenance attested (pkg + deb + rootfs)
- SBOM attested (SPDX 2.3, pkg)
- - Manifest signed (minisign)
+ - VM base-image OBOM published (CycloneDX, cdxgen, per arch)
EOF
- name: Create GitHub release
@@ -891,11 +814,11 @@ jobs:
done < release-artifacts/arm64/tool-versions.txt
fi
- # Create release with the .pkg + manifest, then upload the required
- # Linux .deb files.
+ # Create release with the .pkg + manifest, then upload optional .deb
+ # files if Linux build succeeded (best-effort until sprints/linux lands).
gh release create ${{ github.ref_name }} \
release-artifacts/*.pkg \
- release-artifacts/manifest.json release-artifacts/manifest.json.minisig \
+ release-artifacts/manifest.json \
release-artifacts/capsem-sbom.spdx.json \
--title "Capsem ${{ github.ref_name }}" \
--notes "$NOTES"
@@ -911,6 +834,12 @@ jobs:
for f in release-artifacts/$arch/*; do
[ -f "$f" ] || continue
base=$(basename "$f")
+ case "$base" in
+ build-ledger.log|tool-versions.txt|B3SUMS)
+ echo "Skipping debug-only $arch/$base from release upload"
+ continue
+ ;;
+ esac
mv "$f" "release-artifacts/$arch/${arch}-${base}"
gh release upload ${{ github.ref_name }} "release-artifacts/$arch/${arch}-${base}"
done
@@ -930,11 +859,6 @@ jobs:
steps:
- uses: actions/checkout@v5
- - name: Install verification tools
- run: |
- sudo apt-get update
- sudo apt-get install -y minisign zstd
-
- name: Wait for release assets to be queryable
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -953,10 +877,6 @@ jobs:
set -euo pipefail
mkdir -p /tmp/verify
gh release download "${{ github.ref_name }}" --pattern manifest.json -D /tmp/verify
- gh release download "${{ github.ref_name }}" --pattern manifest.json.minisig -D /tmp/verify
- minisign -Vm /tmp/verify/manifest.json \
- -x /tmp/verify/manifest.json.minisig \
- -p config/manifest-sign.pub
# The URL contract: /v/-
# where binary_version is the release tag (without leading 'v').
# This MUST match crates/capsem-core/src/asset_manager.rs::asset_download_url.
@@ -992,14 +912,12 @@ jobs:
arch=$(uname -m)
[ "$arch" = "aarch64" ] && deb_arch=arm64 || deb_arch=amd64
mkdir -p /tmp/deb
- gh release download "${{ github.ref_name }}" \
- --pattern "Capsem_*_${deb_arch}.deb" -D /tmp/deb
+ if ! gh release download "${{ github.ref_name }}" \
+ --pattern "Capsem_*_${deb_arch}.deb" -D /tmp/deb; then
+ echo "::warning::no .deb for ${deb_arch} on this release -- skipping binary e2e"
+ exit 0
+ fi
deb=$(ls /tmp/deb/Capsem_*_${deb_arch}.deb | head -1)
- version="${GITHUB_REF_NAME#v}"
- python3 scripts/verify_deb_payload.py "$deb" \
- --version "$version" \
- --architecture "$deb_arch" \
- --minisign-pubkey config/manifest-sign.pub
# Extract the bundled capsem binary; we don't need to dpkg -i for this.
mkdir -p /tmp/extract && cd /tmp/extract
ar x "$deb"
@@ -1010,35 +928,20 @@ jobs:
# bundled separately under /usr/share/capsem/bin or similar. Find it.
CAPSEM_BIN=$(find . -type f -name capsem -perm -u+x | head -1)
if [ -z "$CAPSEM_BIN" ]; then
- echo "::error::no 'capsem' CLI inside .deb"
- exit 1
+ echo "::warning::no 'capsem' CLI inside .deb -- skipping binary e2e"
+ exit 0
fi
echo "Using $CAPSEM_BIN ($("$CAPSEM_BIN" --version 2>&1 | head -1))"
- PKG_MANIFEST=$(find . -path '*/usr/share/capsem/assets/manifest.json' -print -quit)
- PKG_SIG=$(find . -path '*/usr/share/capsem/assets/manifest.json.minisig' -print -quit)
- if [ -z "$PKG_MANIFEST" ] || [ -z "$PKG_SIG" ]; then
- echo "::error::.deb payload missing manifest.json or manifest.json.minisig"
- exit 1
- fi
- minisign -Vm "$PKG_MANIFEST" -x "$PKG_SIG" -p "$GITHUB_WORKSPACE/config/manifest-sign.pub"
-
- # Stand up a clean CAPSEM_HOME using the package payload manifest.
+ # Stand up a clean CAPSEM_HOME with only the published manifest.
export CAPSEM_HOME=/tmp/capsem-home
- mkdir -p "$CAPSEM_HOME/assets" "$CAPSEM_HOME/profiles/base"
- cp "$PKG_MANIFEST" "$CAPSEM_HOME/assets/manifest.json"
- cp "$PKG_SIG" "$CAPSEM_HOME/assets/manifest.json.minisig"
- PKG_PROFILES=$(find . -path '*/usr/share/capsem/profiles/base' -type d -print -quit)
- if [ -z "$PKG_PROFILES" ]; then
- echo "::error::.deb payload missing base profiles"
- exit 1
- fi
- cp "$PKG_PROFILES/"*.profile.toml "$CAPSEM_HOME/profiles/base/"
+ mkdir -p "$CAPSEM_HOME/assets"
+ cp /tmp/verify/manifest.json "$CAPSEM_HOME/assets/manifest.json"
# No CAPSEM_RELEASE_URL override -- the binary must hit real GitHub.
"$CAPSEM_BIN" update --assets
# Sanity: at least the host arch's three canonical files must now exist.
host_arch=$( [ "$arch" = "aarch64" ] && echo arm64 || echo x86_64 )
- for f in vmlinuz initrd.img rootfs.squashfs; do
+ for f in vmlinuz initrd.img rootfs.erofs; do
count=$(find "$CAPSEM_HOME/assets/$host_arch" -name "${f%.*}-*" 2>/dev/null | wc -l)
[ "$count" -ge 1 ] || { echo "::error::no downloaded file for $f"; exit 1; }
done
diff --git a/.github/workflows/site.yaml b/.github/workflows/site.yaml
index 256b04ca9..add244c0c 100644
--- a/.github/workflows/site.yaml
+++ b/.github/workflows/site.yaml
@@ -14,7 +14,6 @@ jobs:
deployments: write
env:
- FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
steps:
diff --git a/.gitignore b/.gitignore
index 7608778d7..498a5625a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -57,16 +57,11 @@ Cargo.lock
# Git worktrees
worktrees/
-# VM assets (built by capsem-builder or linked to the local asset cache)
-/assets
-.capsem-assets/
-# Accidental literal-home artifacts from misresolved profile paths
-/~/
+# VM assets (built by capsem-builder)
+assets/*
# Built packages (.pkg, .deb)
packages/
-!guest/config/packages/
-!guest/config/packages/*.toml
# Tauri
crates/capsem-app/gen/
@@ -76,8 +71,9 @@ crates/capsem-app/gen/
frontend/.astro/
frontend/dist/
frontend/node_modules/
-# Generator output imported by the frontend mock/settings runtime. Keep tracked
-# and regenerate with `just _generate-settings` when config/defaults.json changes.
+# Generator output -- no runtime code imports it; kept out of the tree to avoid
+# churn on every `just _generate-settings` run. See commit 97ab1b5.
+frontend/src/lib/mock-settings.generated.ts
# Site
site/dist/
diff --git a/B3SUMS b/B3SUMS
deleted file mode 100644
index bb8b67237..000000000
--- a/B3SUMS
+++ /dev/null
@@ -1,3 +0,0 @@
-f347ba4e17e8d5877980f987afc929507677114c94250bd3d1ebb3e0d9f421c5 assets/arm64/vmlinuz
-ec02a9a2604dabbb80bff01ec6717cff9139e4a3d5d5ae97d7d69d8302f9a687 assets/arm64/initrd.img
-c58d43c7edfb0438032d2484884b7dddc8e424c3f1c2a729d419bfceb2716f25 assets/arm64/rootfs.squashfs
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ab3111d8e..d320196cf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,1759 +8,1441 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
-- Recorded a fresh Linux x86_64 canonical `just benchmark` run from clean
- source commit `b6f9b6e2`, including refreshed active artifacts and a
- pre-rerun archive of the prior Linux artifacts for provenance.
-- Added canonical `just benchmark` retention so same-architecture active
- artifacts are copied to `benchmarks/archive/` before reruns, superseded
- generated benchmark artifacts are zipped afterward, and active benchmark
- directories keep only the latest artifact for each category, architecture,
- and benchmark lane.
-- Added the Hypervisor Improvement meta sprint to turn the Firecracker source
- audit into structured sub-sprints for KVM safety, event delivery,
- observability/status/OTel, CPU/SMP lifecycle, storage/rootfs experiments, and
- benchmark proof.
-- Added a Linux KVM virtio-blk io_uring backend that submits read/write
- requests from the existing ioeventfd worker, reaps completions through a
- completion eventfd, preserves synchronous fallback, and records async
- submission/completion/in-flight metrics.
-- Added OTel-ready KVM virtio-blk queue/backend metrics for notifications,
- drains, descriptor/used-ring volume, request bytes/duration, interrupt
- decisions, and quiesce drain timing.
-- Added the Virtio Block Firecracker Path sprint to track KVM block
- notification suppression, async I/O depth, shared rootfs/benchmark work, and
- macOS comparison reruns as one measured performance stack.
-- Recorded macOS arm64 benchmark data for `1.2.1779673506`, including
- in-VM, lifecycle, fork, and security-engine benchmark results.
-- Recorded fresh macOS arm64 canonical `just benchmark` data for
- `1.2.1780103109` after merging the Linux support branch, including in-VM,
- endpoint-latency, host-native, lifecycle, fork, parallel, Criterion, and
- VM-originated security-engine benchmark artifacts.
-- Added `just benchmark-compare` and `scripts/compare_benchmark_artifacts.py`
- to turn committed Linux/macOS benchmark artifacts into ratio and percentage
- comparisons while making missing lanes explicit.
-- Added benchmark contract tests proving the canonical `just benchmark` path
- includes Criterion archiving plus the required serial artifact lanes,
- including host-native, lifecycle, fork, and VM-originated security benchmarks.
-- Included `capsem-bench storage` in the default `capsem-bench all` path so
- canonical Linux and macOS benchmark artifacts both record storage attribution
- for rootfs, workspace, tmpfs, overlay, and queue/FUSE metadata.
-- Added scatter/gather virtio-blk tests proving KVM block requests preserve
- multi-descriptor guest payload order.
-- Added the initial `capsem-tui` crate with a fixture-backed standalone
- terminal control screen, global service light-bar state, per-session desktop
- indicators, and deterministic snapshot rendering for early UI proof.
-- Added a `just dev-tui` standalone TUI shell with two fixture sessions,
- SVG snapshot export, and keyboard session switching that does not capture
- plain `q`.
-- Added live `capsem-tui` gateway wiring against the installed Capsem HTTP
- gateway with token auth, periodic refresh, typed session mapping, fixture
- fallback, and HTTP provider tests.
-- Added active-session terminal WebSocket wiring for `capsem-tui`, including
- gateway token reuse, terminal input forwarding, output buffering, resize
- messages, and basic ANSI cleanup for the Ratatui surface.
-- Added hidden `capsem-tui` overlays for help, active-session statistics, and
- the session list so the normal terminal surface stays minimal.
-- Added confirmed `capsem-tui` service actions for resuming, suspending,
- stopping, and deleting sessions through the installed HTTP gateway without
- blocking the terminal UI.
-- Added `Alt+p` purge in `capsem-tui`, routed through the installed gateway's
- authenticated `/purge` endpoint for temporary and broken VM cleanup.
-- Added a profile-aware `capsem-tui` new-session dialog with an editable
- prefilled `tmp-*` session name and live profile selection before
- provisioning.
-- Added a `capsem-tui` fork dialog on `Alt+f` that asks for a fork name and
- sends the request through the installed gateway.
-- Added `Alt+c` checkpoint/save as an explicit `capsem-tui` action, leaving
- `Alt+s` to mean suspend.
-- Added `capsem-tui` to local install/package payloads so the TUI is available
- from `~/.capsem/bin/capsem-tui` after installation.
-- Added `capsem_terminal_snapshot` to the Capsem MCP server so agents can
- inspect a session terminal/log surface through MCP with ANSI cleanup, grep,
- source selection, and tailing.
-- Added an 8-live-VM host endpoint latency benchmark under
- `tests/capsem-serial/test_endpoint_latency_benchmark.py`, covering global
- service reads, per-VM detail/history/file/policy-context reads, and gateway
- health/token/status reads with committed `benchmarks/endpoint-latency/`
- results.
-
-### Changed
-- Disabled in-VM shutdown commands. `capsem-sysutil` now only supports guest
- suspend, `capsem-init` removes `/sbin/shutdown`, `/sbin/halt`,
- `/sbin/poweroff`, and `/sbin/reboot` from the VM overlay, and the host
- ignores deprecated shutdown lifecycle frames for compatibility.
-- Gated the Linux KVM virtio-blk io_uring backend to writable block devices
- after the first benchmark showed scratch sequential-read gains but rootfs and
- AI CLI startup regressions when io_uring was used unconditionally.
-- Made the Linux KVM virtio-blk io_uring backend opt-in while measured default
- gates continue to show disk or rootfs regressions.
-- Added KVM virtio-blk event-index negotiation and shared virtqueue
- notification-suppression helpers, with canonical Linux benchmark artifacts
- recording the mixed performance result for the Firecracker-path sprint.
-- Split Google into its own `sprints/google/` meta sprint covering Gmail,
- Drive, gcloud, Firebase, Firebase Realtime DB remote comms, Jet Ski, Gemini,
- and Google AI.
-- Routed x86_64 KVM virtio-blk queue notifications through `KVM_IOEVENTFD`
- with a dedicated block worker, so guest queue kicks no longer require vCPU
- MMIO exits while preserving synchronous fallback tests.
-- Switched the KVM virtio-blk read/write data path from seek plus per-descriptor
- host I/O to `preadv`/`pwritev` over GPA-translated guest memory iovecs.
-- Batched KVM virtio-blk used-ring publication so one queue notification writes
- `used.idx` once after draining all completed block descriptors.
-- Added the Profile Foundation meta sprint with F00-F12 sub-sprints, a
- code-reality check, and a crosswalk from the old Profile V2 S-numbered
- boards.
-- Made security plugins, dashboard improvements, Google/Gemini integration,
- OpenTelemetry, remote decisions, and remote alert logging explicit Profile
- Foundation scope.
-- Renamed Foundation F07 around graph, dashboard, and observability so product
- relationships are a first-class contract instead of dashboard-only logic.
-- Expanded Foundation Google scope to name Gmail, Drive, gcloud, Firebase, Jet
- Ski, Gemini, and Google AI credential/integration proof explicitly.
-- Reframed S24 as the active post-ship Profile V2 meta sprint so every open
- Profile V2 item is tracked as in-scope child sprint work.
-- Created S24 as the single post-ship Profile V2 sprint and migrated remaining
- release-hit-list proof, polish, and board cleanup work into it.
-- Added a current Profile V2 sprint snapshot and reconciled the active board so
- S18 is the explicit release gate while S09, S11, S16, and S19 are marked
- closed for the bedrock release.
-- Made `just benchmark` archive Rust Criterion microbenchmarks into
- `benchmarks/security-engine/` JSON artifacts, removed superseded historical
- benchmark JSONs, and refreshed benchmark docs so the repo only points at the
- current canonical artifact path.
-- Extended benchmark artifacts with UTC timestamps plus richer host hardware and
- OS metadata, and added a host-native benchmark artifact to the canonical
- `just benchmark` path so VM performance is recorded beside the machine's
- local disk, startup, small-file read, and metadata-stat baselines.
-- Split benchmark artifact git metadata into overall dirty state and
- `source_dirty`, so artifacts generated earlier in the same run do not hide
- whether the measured source tree itself was clean.
-- Standardized benchmark execution around `just benchmark`, with `just bench`
- as an alias and no Linux-only benchmark recipe, so performance artifacts use
- one cross-platform recording path.
-- Changed the guest rootfs build default to a configurable 128K squashfs block
- size, improving measured CLI startup and sequential rootfs reads while
- recording the chunk-size choice in `guest/config/build.toml`.
-- Changed `capsem-tui` gateway refreshes to reuse the HTTP client and cached
- gateway token, so status polling measures the local status request instead of
- redoing auth bootstrap on every tick.
-- Changed `capsem-process` live metrics snapshots to stay on in-memory
- counters instead of recursively scanning VM session directories on the
- service `/list` hot path.
-- Changed service read hot paths so `/list` no longer calls per-VM live metrics,
- `/stats` uses an empty/read-only fast path, raw session DB queries use
- SQLite progress handlers instead of a 100ms watchdog-thread floor, and
- policy-context exports no longer duplicate one security event across multiple
- joined detail rows.
-- Strengthened the suspend/resume lifecycle integration test so it now proves
- a background guest process keeps the same PID and continues writing after
- warm resume, giving Apple VZ and KVM the same long-term state-preservation
+- Added strict capsem-doctor Ironbank acceptance checks for functional package
+ manager proof, hermetic doctor fixtures, and no retired escape markers in the
+ installed diagnostic suite.
+- Added bootstrap and Justfile contract tests that prove release gates keep
+ checking project skills, site structure, profile-owned asset materialization,
+ ruff/ty/skill validation, and retired escape-path names.
+- Added a dedicated Ironbank Claude CLI ledger gate that runs `ollama launch claude` through the VM profile and proves the model, tool, file, credential, and security ledger path.
+- Added a dedicated Ironbank Codex CLI ledger gate that runs direct Codex and
+ `ollama launch codex` through the VM profile and proves the model, tool,
+ file, credential, and security ledger path.
+- Added fresh 1.3 release benchmark artifacts and docs for the VM-path
+ mock-server protocol, lifecycle, fork, disk, and EROFS/LZ4HC performance
+ gates.
+- Added benchmark report output for sample counts, error rates, and a generated
+ 1.3 release latency/throughput graph.
+- Added an Ironbank mock-server contract proving the single reusable local
+ mock server serves the HTTP, HTTPS/SSE, DNS, OAuth, MCP, OpenAI, Anthropic,
+ Gemini/AGY, and Ollama fixture surfaces used by release gates.
+- Added a stable Ironbank capsem-doctor acceptance contract that ties the
+ named release gate to the full VM doctor ledger proof and shared mock server.
+- Added an Ironbank profile asset readiness gate proving profile cards can be
+ built from route-owned asset status for `code` and `co-work`, including
+ missing, ensure/download, shared cache reuse, hash-named assets, and manifest
+ provenance.
+
+### Fixed (service control)
+- Fixed CLI status/debug health checks so they use the same `CAPSEM_RUN_DIR`
+ socket and gateway files as the service client, preventing source and
+ installed runs from checking different Capsem runtimes.
+- Fixed the service file API control-channel contract so 1 MiB file
+ read/write round trips no longer tear down the guest agent stream, and
+ restored the initrd repack path to build guest agents from
+ `config/docker/image` instead of the removed `guest/config` tree.
+- Fixed `capsem stop` and other service-control commands so they stay pure
+ local control operations and no longer start the background update/network
+ refresh before dispatch.
+- Fixed explicit service stops so installed clients remember the user stopped
+ Capsem and refuse to auto-launch the service from status/session requests
+ until `capsem start` is run, preventing surprise credential-store hydration
+ and Keychain prompts during stop flows.
+
+### Fixed (terminal throughput)
+- Coalesced desktop terminal output to one xterm write per animation frame and
+ batched bursty terminal input before WebSocket send, preventing high-volume
+ agent output from starving keyboard responsiveness.
+- Coalesced gateway terminal relay bursts in both directions, so adjacent
+ terminal WebSocket/UDS frames are batched without losing byte order while
+ preserving a short interactive flush deadline.
+
+### Fixed (session lifecycle)
+- Fixed MCP snapshot reverts that reported `action: deleted` through the tool
+ result while leaving the created file visible inside the guest workspace.
+- Fixed stale persistent sessions whose preserved boot logs show overlayfs
+ `Stale file handle` / kernel panic failures so they are reconciled as
+ `Defunct`, cannot be resumed, keep the original boot-failure reason in
+ route JSON, and are removed by default purge.
+- Fixed session ledger inspection for incompatible persistent sessions so
+ stats, timeline, and forensic views can still read the preserved
+ `session.db` while the session remains non-resumable and delete-only.
+- Replaced ad hoc temporary session names with profile-scoped session names
+ such as `code-1` and `co-work-1` across service provisioning, the TUI create
+ dialog, and the desktop UI, while preserving focus handoff to newly created
+ sessions.
+
+### Changed (route surfaces and diagnostics)
+- Added a release compliance gate for SBOM, OBOM, and build-ledger evidence,
+ clarifying that OBOMs describe base VM images while build ledgers remain
+ debug evidence.
+- Renamed the private mock-server implementation and benchmark artifact
+ directory so release tests and docs refer to the single reusable
+ mock-server/protocol rail instead of retired MITM-local wording.
+- Exposed model request/response/tool-call validity facts in serialized
+ security events so route JSON matches the first-party CEL model facts used
+ by enforcement.
+- Added a config-layout gate that makes the settings/corp/profiles/docker/data
+ source contract executable and rejects host metadata or generated pins in
+ checked-in profile config.
+- Moved image build defaults out of checked-in `guest` source config and into
+ `config/docker/image`, with `capsem-admin` generating the backend image
+ workspace from the selected profile plus Docker image defaults.
+- Added an Ironbank Gemini API ledger gate proving public Gemini
+ `streamGenerateContent` and `generateContent` traffic through the hermetic
+ mock server records Google provider/protocol rows, tool calls, non-stream
+ output, brokered credentials, DNS/HTTP evidence, and security decisions.
+- Fixed installed asset cleanup so `manifest-origin.json` survives service
+ startup, preserving manifest origin/hash reporting while profile asset
+ readiness and `capsem update --assets` hydrate through the hash-named asset
+ rail.
+- Tightened the TUI session contract so profile launch options come only from
+ `/profiles/list`, no fallback profile is synthesized from stale session
+ rows, and user-facing TUI controls say sessions rather than VMs.
+- Removed retired frontend policy vocabulary from settings origins and dead
+ network-policy IPC types so profile UI surfaces speak enforcement,
+ detection, plugins, MCP, and assets directly.
+- Removed the visible frontend build timestamp from the main toolbar; build and
+ version evidence remain available through debug/status surfaces.
+- Replaced raw toolbar status colors with semantic UI tokens so service chrome
+ follows the Capsem design contract.
+- Added frontend route-contract gates for the Sessions dashboard and profile
+ surfaces so the UI must keep using route-owned profile/session terminology,
+ asset readiness, enforcement, detection, plugins, MCP, and canonical detail
+ payloads.
+- Removed the retired MCP tool `approved` field from profile MCP route
+ responses; the UI/TUI contract now exposes only route-backed
+ `permission_action` / `permission_source` decisions.
+- Cleaned the desktop stats/detail panes so HTTP/model bodies are loaded from
+ the blob ledger rather than preview columns, credential broker rows display
+ verbs/origins instead of substitution refs, and inspector presets use the
+ same broker vocabulary as the session UI.
+- Added a service and gateway route-matrix gate for profile UI surfaces so
+ `code` and `co-work` profile pages must expose assets, enforcement,
+ detection, plugins, credential broker, and MCP routes without 404/501
+ fallbacks.
+- Fixed gateway forwarding for session snapshot status/list routes and added
+ route-contract coverage so the stats UI reads snapshot state through the
+ explicit service route instead of hitting a gateway 404.
+- Added service-level plugin route contract coverage so profile plugin list,
+ info, edit, credential-broker detail, retry, and unknown-plugin responses
+ prove the typed pre/post/logging stage surface through UDS.
+- Fixed profile plugin edits so `/profiles/{profile_id}/plugins/{plugin_id}/edit`
+ persists to the profile file, refreshes route-visible policy immediately, and
+ records a `profile_mutation_events` ledger row instead of using a runtime-only
+ override.
+- Added credential store lifecycle route coverage proving startup hydration,
+ explicit broker retry, memory-only hot reads, empty-versus-ready status, and
+ raw-secret absence from service/plugin route JSON.
+- Tightened the profile plugin UI contract so plugin rows render route-owned
+ stage, version, mode, detection level, counters, latency, and broker
+ capabilities, while credential inventory uses provider/last-seen/counts
+ instead of exposing raw BLAKE references as the primary identity.
+- Added service-side snapshot and DbWriter contract coverage proving snapshot
+ status/list routes are file/IPC-backed, ignore toxic `session.db` rows, and
+ keep per-session SQLite writes on the capsem-process `DbWriter` rail.
+- Added a session dashboard route gate proving defunct and incompatible
+ sessions remain delete-only across list/status/info/resume/delete routes,
+ and cleaned frontend session wording checks so stale VM labels cannot hide in
+ test noise.
+- Cached profile route summaries in service memory so `/profiles/list` no
+ longer reloads profile files or recompiles rule sets on every UI/TUI poll;
+ the Ironbank route-health gate now shows profile list p95 in single-digit
+ milliseconds with negligible service CPU.
+- Renamed the local protocol benchmark internals from the retired
+ `mitm-local` escape-hatch wording to the shared mock-server protocol rail;
+ `capsem-bench protocol` remains the public command and now emits
+ `mock_server_protocol` benchmark JSON.
+- Fixed profile route summaries so `code` and `co-work` expose route-owned
+ rule, plugin, MCP, and asset metadata without leaking host profile paths or
+ falling back to default-only profile assumptions.
+- Refreshed the 1.3 benchmark artifacts and docs from the canonical
+ `just bench` rail, including mock-server HTTP/protocol throughput plus
+ lifecycle and fork timings used by the S05 route-latency gate.
+- Hardened the Ironbank HTTP body ledger proof so upstream transcript
+ assertions ignore non-HTTP records instead of failing on unrelated DNS
+ rows emitted by the hermetic mock server.
+- Added strict model wire-protocol recording to the session ledger so model
+ traffic can preserve both the endpoint owner (`provider`) and the recognized
+ protocol (`protocol`) without collapsing OpenAI-compatible local traffic into
+ a fake provider.
+- Changed `just bench` to use the artifact-recording release benchmark path
+ with the shared local mock server, so HTTP, proxy throughput, and protocol
+ benchmarks fail on skips and publish local numbers alongside lifecycle/fork
+ artifacts.
+- Fixed security decision ledgers so visible default catchall rules remain
+ recorded in `security_rule_events` without emitting a second effective
+ decision after a more specific profile/corp enforcement rule wins. The code
+ and co-work profiles now include an explicit hermetic mock-server allow rule
+ for `127.0.0.1:3713`, so doctor, benchmark, and Ironbank traffic does not
+ trip the default local-network ask rule.
+- Tightened the CEL fact contract exposed by profile enforcement routes:
+ evaluate requests now materialize typed `http`, `dns`, `mcp`, `model`,
+ `file`, `process`, `ip`, `tcp`, and `udp` facts, default rules include
+ unknown-model and unknown-MCP detections, and provider endpoint aliases are
+ rejected in favor of explicit `allowed_remote_targets`.
+- Fixed Ironbank route contracts for MCP tools and file listings so profile
+ MCP routes assert the current permission-action shape and `.txt` uploads are
+ reported deterministically as text/plain instead of Magika-dependent
+ octet-stream.
+- Strengthened `/vms/create` and `/vms/{id}/resume` responses so provision
+ routes return the session profile ID, lifecycle state, persistence bit,
+ resumability, and valid action enum list alongside the VM ID and UDS path.
+ Ironbank route-health now proves create/status/info/list/exec/fork/pause/
+ resume/stop/delete/purge state and latency budgets through service and
+ gateway routes.
+- Strengthened the Ironbank route-health gate so profile enforcement evaluate
+ routes must prove exact `allow`, `ask`, and `block` decisions, detection
+ rows, and plugin execution stages while keeping hot control-route CPU and
+ latency budgets under test.
+- Added a first-class `event_body_blobs` ledger for HTTP, model, and MCP
+ request/response bodies with a 10 MiB bounded capture, original/stored byte
+ counts, BLAKE3 body hash, content type, trace ID, and truncation flag. Stats
+ details now load `request_body`/`response_body` from that ledger instead of
+ treating preview fields as forensic truth.
+- Strengthened the Claude/Anthropic Ironbank ledger proof to cover
+ non-streaming HTTP, streaming SSE, and SDK client paths through the same
+ model/tool/file/security/broker ledger assertions. Repeated same-path model
+ checks now anchor tool rows and tool responses to the current model-call IDs
+ and trace IDs so provider proofs cannot pass on stale rows.
+- Extended the OpenAI/Codex Ironbank ledger proof to cover Responses,
+ embeddings, and image-generation traffic through the same VM/session DB
+ path. OpenAI image endpoints are now classified as model traffic and their
+ generated payloads are recorded in `model_calls.text_content` while brokered
+ credentials remain opaque and raw secrets stay out of DB/log output.
+- Strengthened the Codex CLI Ironbank proof so tool-call IDs are derived from
+ the per-run nonce and local OpenAI-compatible traffic asserts
+ `provider = unknown`, `protocol = openai`, and the unknown-provider
+ detection rule instead of relying on stale fixed identifiers.
+- Added a host `capsem-mcp` Ironbank proof that exercises the real stdio MCP
+ server against `capsem-service`, verifies every advertised tool, calls the
+ session/file/exec/MCP/log/triage routes with deterministic inputs, and
+ reconciles MCP, file, exec, security, route, snapshot, and structured-log
+ ledger output. Host-triggered exec events now carry trace IDs so MCP-driven
+ command activity stays attributable through the session ledger.
+- Added a reusable Ironbank two-turn model ledger assertion surface that
+ computes expected trace/cardinality from externally meaningful client facts
+ and proves exactly matched model item, tool call, tool response, file, DNS,
+ HTTP, security, credential, and upstream transcript rows through a dedicated
+ black-box VM test.
+- Removed the remaining network-side HTTP port denial from the MITM path so
+ routing/capture mechanics no longer issue security verdicts outside the CEL
+ security-event rail. The former `NetworkPolicy` type is now named
+ `NetworkMechanics`, and Ironbank now guards old policy-v2, MCP decision,
+ fallback logger, side-write, and retired policy authoring strings from
+ reappearing in live code.
+- Added dedicated Ironbank credential broker and plugin ledger proof. Broker
+ coverage now has its own release-gate entry point for capture, brokered
+ rewrite, injection rows, and raw-secret absence, while plugin route coverage
+ proves profile-scoped list/info/edit, broker inventory/reload, dummy
+ pre/post mode changes, serialized security-event detections, plugin
+ executions, and evaluation decisions.
+- Removed the old settings-tree MCP server rail. Settings metadata and
+ settings responses now expose UI/application preferences only, while MCP
+ remains profile-owned through `/profiles/{profile_id}/mcp/...` routes.
+ Default security-rule catchalls also remain visible in the security ledger
+ after specific rules match, so forensic rows show both the specific verdict
+ and the late default rule.
+- Removed the dead MCP server merge rail that auto-detected host AI CLI MCP
+ configs and merged manual/corp/user inputs outside the profile contract.
+ Runtime MCP server construction is now guarded to use profile-owned
+ `build_profile_server_list()` only, with docs and skills updated to remove
+ the stale fallback language.
+- Renamed the MCP configuration contract from `McpUserConfig` to
+ `McpProfileConfig` and added a no-legacy guard so profile/corp-owned MCP
+ config cannot regress to user-config terminology.
+- Hardened profile parsing so `assets` is a required profile-owned section
+ instead of silently defaulting to the first built-in profile's asset release.
+ Profile contract and admin profile-check tests now prove malformed profiles
+ cannot inherit Code assets by omission.
+- Aligned the shared settings conformance fixture with the 1.3 contract that
+ settings are UI/application preferences only. Python, Rust, and frontend
+ settings schema tests now reject stale AI-provider, credential, profile-file,
+ and `enabled_by` provider surfaces instead of requiring them.
+- Split model wire protocol from endpoint-provider identity so Ollama,
+ OpenAI-compatible, Anthropic-compatible, and unknown model endpoints can be
+ parsed without pretending protocol and provider are aliases. Recognized model
+ protocol traffic on undeclared endpoints now emits `model.provider =
+ "unknown"` and hits a default informational detection rule.
+- Fixed local model enforcement so explicit profile/corp allow rules win over
+ the built-in local-network `ask` default while the default rule remains
+ visible in the security ledger. Model request/response events now carry the
+ same `tcp.port`/`ip.value` transport facts as HTTP events, and Ironbank
+ proves UDS and HTTP latest routes expose the same unknown-provider detection
+ row.
+- Tightened credential brokerage for unknown OpenAI-compatible and
+ Anthropic-compatible model endpoints: `Authorization` and `x-api-key` headers
+ are brokered from protocol/header shape without relabeling the provider, and
+ async file attribution keeps the first credential seen for a trace.
+- Fixed the AGY hermetic replay fixture so Google Code Assist
+ `listExperiments` matches the recorded 68 experiment IDs and 250 flags, and
+ `/log` accepts protobuf play-log telemetry with the recorded empty text/plain
+ acknowledgement instead of fake JSON.
+- Refactored the Ironbank model-client proof into composable script-builder
+ and ledger-assertion helpers, and made the Codex CLI fixture use the same
+ brokered OpenAI credential path as the SDK/API clients instead of a
+ non-secret marker shortcut.
+- Tightened the shared Ironbank AI-client harness so every credentialed model
+ client proof must show broker capture, brokered request rewrite, one shared
+ `credential_ref` across HTTP/model/tool-call/tool-response/file rows, exact
+ substitution ledger verbs, and raw-secret absence from DB/log output. The
+ OpenAI API, OpenAI two-turn, Codex CLI, Claude HTTP, and Claude SDK proofs
+ now all run through that same broker contract.
+- Tightened the OpenAI-compatible Ironbank double-turn ledger so repeated
+ model history is deduplicated by persisted BLAKE3 item hashes, model tool
+ calls register workspace file-path trace hints, and subsequent fs-monitor
+ events plus security-rule rows are attributed to the same model trace. The
+ focused proof now asserts two random tool calls produce exactly two traces,
+ ten model item rows, four model calls, four HTTP rows, one DNS row, two tool
+ calls, two tool responses, and two created file events.
+- Tightened the HTTP Ironbank ledger path so active profiles carry corp network
+ mechanics into `capsem-process`, HTTP security events expose `http.query`,
+ `http.body`, `tcp.port`, and `ip.value` to CEL and forensic rows, and the
+ first plain-JSON HTTP full-chain test reconciles client output, upstream
+ transcript, `net_events`, `security_rule_events`, UDS inspect, gateway
+ inspect, timeline, security status/latest, VM status counters, and structured
+ service/gateway logs.
+- Fixed blocked HTTP telemetry so CEL-denied requests now keep request byte
+ counts, request previews, and client-visible denial response previews in the
+ same ledger path as allowed requests, with Ironbank proof that the denied
+ request never reaches the upstream fixture.
+- Fixed pending HTTP `ask` decisions so clients see an approval-required 403
+ instead of a generic block message, while Ironbank proves the pending
+ `security_ask_events` lifecycle row, `policy_action = ask`, security status,
+ UDS inspect, gateway inspect, counters, and logs all agree.
+- Fixed brokered HTTP credential rewrite accounting so OAuth captures emit
+ exact `captured`/`brokered`/`injected` ledger verbs, broker refs replay into
+ upstream header/query bytes without leaking raw credentials to DB, routes, or
+ logs, and credential inventory merges injected rows with their captured
+ provider identity. Grouped CEL rule matches such as `a && (b || c)` now
+ compile through the same profile rule path used by the HTTP rewrite proof.
+- Changed the macOS credential broker durable store to a single
+ `org.capsem.credentials` Keychain vault item so service startup/reload
+ hydrates captured credentials with one durable read instead of prompting once
+ for an index and again for each stored secret.
+- Tightened HTTP body-handling ledger proof for gzip, chunked, SSE, truncated
+ preview, and HTTPS override traffic. Decoded gzip responses now log the same
+ materialized headers and body bytes delivered to the guest instead of stale
+ compressed response metadata.
+- Added DNS Ironbank ledger proof for allowed and blocked UDP DNS traffic.
+ Allowed DNS rows now carry the matched security rule and policy fields just
+ like blocked rows, hermetic DNS upstream transcripts prove blocked
+ exfiltration never leaves the VM boundary, and security status exposes
+ detection-level counters regenerated from `session.db`.
+- Added MCP Ironbank ledger proof for profile-owned builtin MCP and observed
+ remote MCP traffic. MCP security events now carry request arguments,
+ response content, trace IDs, and transport facts through CEL, DB rows, UDS
+ inspection, gateway inspection, latest/status routes, and structured logs.
+- Added Ironbank file/process/snapshot and package-manager ledger proofs.
+ The new black-box coverage exercises file import/export/create/modify/delete
+ rows, symlink escape rejection, process audit versus exec semantics,
+ snapshot route hermeticity, package-manager functional probes, route
+ serialization, and DB-backed security rows.
+- Tightened Ironbank model/client coverage so the mock server replays an
+ Ollama-compatible OpenAI chat-completion shape with native tool calls, the
+ OpenAI SDK/Anthropic SDK/LiteLLM/Ollama SDK/Codex CLI paths assert full
+ model, HTTP, security, file, exec, credential, and session DB ledger fields,
+ and the tests now fail on any public HTTP or DNS side traffic. This caught and
+ closed Codex plugin/OTLP side calls and LiteLLM's default public cost-map
+ fetch during hermetic release proof.
+- Added a full mock-server JSONL request ledger and upgraded the Codex CLI
+ Ironbank proof to drive the OpenAI Responses API through a native
+ `exec_command` tool call, require Codex to write a random UUID4 hex value to a
+ random filename, return only the successful tool status to the model, and
+ reconcile exact HTTP bodies with
+ `model_calls`, `tool_calls`, `fs_events`, `net_events`, and
+ `security_rule_events`.
+- Upgraded the mock server and Ironbank launcher proof for
+ `ollama launch claude`: the mock now replays Anthropic streaming `tool_use`
+ and final-message SSE shapes, structurally detects real `tool_result` blocks,
+ and the ledger proof covers Claude's real `Bash` tool call, tool response,
+ token usage, file write, HTTP/model rows, DNS, and security rules. AI request
+ capture is now bounded at 1 MiB by default so large real agent continuations
+ are parseable instead of clipping away trailing tool results.
+- Tightened the config authority guard so `config/` can only contain the
+ declared `settings/`, `corp/`, `profiles/`, `docker/`, and `data/` roots;
+ active docs and skills now explicitly reject admin/default/guest/preset/
+ registry/template roots, clarify that settings have schemas while profiles
+ have catalogs, and describe `capsem-admin` as a validation/materialization
+ tool rather than a product authoring surface.
+- Tightened the profile-derived image/config contract in docs and developer
+ skills: `config/` is now documented as settings/corp/profiles/docker/data,
+ `capsem-admin` is explicitly a validator/materializer/build tool rather
+ than a config authority, stale `guest/config` authoring and source-profile
+ pin language is removed from active docs/skills, and `capsem-admin image
+ build --dry-run` is no longer a public product rail. The internal settings UI
+ metadata parser no longer calls itself a registry, preserving the rule that
+ profiles and corp own runtime truth while settings only describe
+ UI/application preferences; private capsem-admin scaffold helpers are now
+ burned by a guard test too.
+- Burned the public `capsem-builder build`, `validate`, `inspect`, `mcp`, and
+ `--dry-run` rails so product image/config work can only enter through
+ profile-owned config plus `capsem-admin`; docs, skills, and CLI tests now
+ document and enforce `capsem-builder` as a backend helper only.
+- Kept profile image builds behind the `capsem-admin image build` rail while
+ moving Docker/template execution to a private Python backend module, and
+ tightened partial asset generation so rootfs-only or kernel-only outputs
+ cannot mint a bootable manifest or delete unrelated arch assets.
+- Fixed PR CI Python coverage so the schema/builder coverage step runs the
+ explicit Python contract suite that exercises `src/capsem`, instead of
+ replaying VM, serial, install, MCP, service, and Ironbank suites under one
+ monolithic `pytest tests/ --cov` command; the gate now also covers malformed
+ dev skill frontmatter, symlink, empty-root, and bad-entry cases so remote
+ runner coverage drift no longer drops the Python gate below threshold.
+- Fixed PR CI non-VM Python integration setup so bootstrap, codesign, and
+ rootfs artifact tests generate their ignored local test assets through
+ `capsem-admin`, build the exact debug host binaries under inspection, and
+ ad-hoc sign them with the canonical entitlement before asserting the package
+ and signing contracts.
+- Fixed PR CI frontend coverage by moving generated settings/mock fixture
+ creation onto a shared `scripts/generate-settings.sh` rail, running that rail
+ before frontend build/check in CI, declaring the Vitest coverage provider,
+ uploading the actual `frontend/coverage/coverage-final.json`, and excluding
+ generated coverage output from later frontend type checks.
+- Fixed PR CI Rust coverage so `cargo llvm-cov` reports and uploads coverage
+ without aborting the rest of the release gate on a local percentage
+ threshold; Codecov remains the coverage ledger while Python, frontend,
+ schema, cross-compile, and artifact checks now still run.
+- Fixed the Docker install e2e package path so Linux `.deb` repacking
+ materializes profile-owned runtime config before copying profiles into the
+ package, using the same shared materializer as local dev recipes instead of
+ assuming `just` exists inside the package-test container.
+- Fixed Docker install e2e asset bootstrap so the ignored local `assets/`
+ working tree is prepared with tiny test boot files and a `capsem-admin`
+ generated manifest before profile materialization.
+- Fixed CI regressions where macOS Rust coverage compiled the Tauri app before
+ `frontend/dist` existed, and Linux ARM agent exec tests selected `/root` as
+ cwd for a non-root runner user simply because the directory existed.
+- Fixed ARM Linux CI compilation for KVM checkpoint tests by keeping portable
+ checkpoint header decode coverage on every target while gating x86 KVM vCPU,
+ IRQ, PIT, and MMIO serialization tests to x86_64 where those structs exist.
+- Fixed CI release gates so Rust coverage no longer references the deleted
+ `capsem-debug-upstream` crate and Python lint validates the top-level
+ `skills/` library instead of the retired `config/skills` path.
+- Made the credential broker memory-first behind an opaque `CredentialStore`:
+ captures update runtime memory before durable storage, replay/status checks
+ no longer hit Keychain or disk, real substitutions can hydrate on cache
+ miss, service `/status` reports only ready/degraded state, and
+ `/profiles/{id}/plugins/credential_broker/credentials/{info,reload}` exposes
+ the detailed broker store object plus explicit retry.
+- Routed the profile-scoped credential broker retry endpoint through the HTTP
+ gateway and pinned it in the explicit route allowlist so the UI cannot see a
+ 404 for a service-supported profile/plugin operation.
+- Added a real-service gateway contract test for the profile overview route
+ bundle so profile info, credential broker status/retry, asset status,
+ enforcement rules, and detection rules must all survive the HTTP gateway with
+ the UI-facing JSON field shape intact.
+- Extended file-boundary IPC so plugin `rewrite` decisions can return mutated
+ bytes to the service for import/export/read/write boundaries; the service
+ now writes or returns only the bytes approved by the plugin-aware security
+ rail, while block still fails closed.
+- Fixed file-boundary rewrite materialization so logging-stage sanitizers and
+ large-content security previews cannot truncate or replace guest file bytes;
+ data-plane rewrites now require a complete payload and an applied
+ non-logging `rewrite` plugin.
+- Fixed the Linux installed-package build by scoping the Keychain credential
+ index type to macOS, keeping the non-macOS credential store warning-clean
+ under the package e2e `-D warnings` gate.
+- Tightened plugin route regression coverage so `rewrite` mode proves an
+ actual event mutation and `block` mode remains the only plugin mode that
+ denies the evaluated security event.
+- Tightened Ironbank plugin matrix coverage so postprocess plugin detections
+ must appear in the security event detection vector, closing the explicit
+ allow/ask/block/disable/rewrite/pre/post/detection-level proof item.
+- Removed fake confidence from broker-created credential observations and
+ injections; substitution rows keep the historical nullable column, but
+ broker emissions now record `NULL` confidence.
+- Hardened file import/export security boundaries so explicit file writes run
+ through the plugin-aware security rail, plugin `block` decisions deny the
+ VM-facing file operation before bytes are written or returned, and profile
+ plugin edits reload matching active VMs before returning. Ironbank now proves
+ the denied EICAR import, live plugin disable, allowed import, and exact
+ session DB plugin decision/execution ledger.
+- Split security plugins into explicit preprocess, postprocess, and logging
+ stages while preserving the single `SecurityEvent -> SecurityEvent` plugin
+ contract; the credential broker now owns credential observation/storage as a
+ security plugin, and the log sanitizer owns the ledger-safe projection before
+ emission. The profile/corp plugin policy and route-visible plugin catalog now
+ expose all three stages instead of hiding logging plugins behind a
+ compatibility bucket.
+- Renamed the core security plugin stage contract to
+ `preprocess`/`postprocess`/`logging` and extended the security action
+ benchmark matrix to cover all three plugin kinds, including the logging
+ sanitizer.
+- Extended credential broker replay so broker refs in HTTP headers or queries
+ are treated as preprocess injection events, materialized only for upstream
+ runtime bytes, and recorded in the substitution ledger as `injected` without
+ leaking raw secrets or broker refs through sanitized header payloads.
+- Expanded the Ironbank credential broker ledger proof to cover query replay,
+ JSON request bodies, form request bodies, OAuth response token bodies, and
+ generic credential response bodies through the real VM path and hermetic
+ mock server.
+- Added route-visible plugin execution counters and latency totals for
+ security plugins, and moved MITM rule-ledger emission onto the plugin-aware
+ security event path so broker and log-sanitizer executions are preserved in
+ session DB forensic payloads and `/profiles/{id}/plugins/list`.
+- Documented the runtime-vs-ledger materialization split across security
+ policy, network isolation, MITM architecture, and developer skills so future
+ work keeps credential capture/injection in the broker plugin and ledger
+ projection in logging plugins instead of network formatters, routes, DB
+ readers, frontend transforms, or test harnesses.
+- Hardened the local OpenAI-compatible model path: bounded request sniffing now
+ promotes unknown localhost model traffic before CEL/plugin evaluation, the
+ credential broker uses the parsed provider hint for SDK bearer headers, and
+ Ironbank proves the VM-visible OpenAI SDK response, tool call, file write,
+ broker reference, substitution ledger, route counters, raw-secret absence,
+ explicit model allow rules, and the default local-network `ask` guard end to
+ end.
+- Removed provider-aware credential brokering from MITM header formatting so
+ network helpers no longer create credential refs or credential observations.
+- Replaced the Rust mock-server crate with the shared Python mock server
+ runtime for doctor, integration, recorder, benchmark, and Ironbank tests, so
+ there is one hermetic protocol lab and no duplicate fixture implementation.
+- Extended `capsem-mock-server` with deterministic DNS fixtures over UDP and
+ TCP, reported in its ready JSON, so doctor, recorder, benchmark, and
+ Ironbank work can exercise DNS without public resolvers or a second fixture
+ server.
+- Extended `capsem-mock-server` with a real local HTTPS listener that serves
+ the same deterministic fixtures as HTTP, giving doctor, recorder, benchmark,
+ and Ironbank work one protocol lab for HTTP, HTTPS/MITM, DNS, SSE,
+ WebSocket, MCP, OAuth, and model replay.
+- Extended the protocol fixture recorder to capture and replay DNS fixtures
+ from `capsem-mock-server`, keeping DNS in the same sanitized fixture corpus
+ as model, MCP, OAuth, credential, and HTTP-like flows.
+- Removed the env-gated local MITM benchmark skip from the serial release
+ tests and restored its default load to 50,000 requests at concurrency 64, so
+ `just test` always produces meaningful local HTTP/SSE/WebSocket MITM
+ baseline numbers through the shared mock server.
+- Hardened the in-VM network doctor so missing or unroutable
+ `CAPSEM_MOCK_SERVER_BASE_URL` fails the local HTTP/SSE/WebSocket/OAuth/model
+ proof instead of silently skipping deterministic protocol coverage.
+- Clarified the shared skills contract for profile `build.sh`: it is a
+ rootfs-only build hook, not an installer/runtime/config path, and changes
+ require profile descriptor updates, asset rebuilds, and black-box VM proof.
+- Routed service-initiated profile MCP tool calls through the logged MCP
+ JSON-RPC security rail instead of calling the aggregator directly, so
+ `capsem_mcp_call` now writes `mcp_calls`, built-in MCP HTTP `net_events`,
+ and matching `mcp.tool_call` security-rule rows through the process
+ `DbWriter`.
+- Added an Ironbank-native profile MCP ledger proof for `capsem_mcp_call` that
+ drives `capsem-mcp`, profile MCP routes, a fresh VM, the shared mock server,
+ and read-only session DB checks in one black-box release gate.
+- Hardened agent bootstrap packaging: profile build hooks now remove
+ installer-created OAuth/token/history/cache/log residue before rootfs
+ packaging, AGY runs through the Capsem sandbox wrapper by default, and Gemini
+ is wrapped without copying its npm entrypoint so relative JS chunk imports
+ still work. Ironbank now boots a fresh VM and proves AGY, Claude, Codex, and
+ Gemini bootstrap commands plus route/session ledgers from the outside.
+- Extended the Ironbank model ledger proof to drive real Anthropic, LiteLLM,
+ and native Ollama Python SDK clients through the shared mock server, and
+ fixed native Ollama `/api/chat` classification so session DB rows, security
+ ledgers, route output, token counts, byte counts, and file writes agree.
+- Extended gateway `/status` to preserve the service profile catalog and
+ installed asset manifest provenance, including profile readiness, manifest
+ origin/source/hash, validation status, and current asset/binary versions.
+- Included installed asset manifest provenance in support bundles so debug
+ reports preserve the manifest origin/source/hash trail alongside the active
+ asset manifest.
+- Extended support-bundle debug diagnostics with the current profile route
+ inventory and profile OBOM descriptors, including `/profiles/{id}/obom`,
+ BLAKE3 hash, generator metadata, size, and base-image scope.
+- Added support-bundle supply-chain references for the host SPDX SBOM release
+ artifact, GitHub attestation source, profile CycloneDX OBOM routes, and
+ manifest provenance paths.
+- Hardened package artifact tests so local and remote manifest overrides prove
+ the packaged manifest payload and `manifest-origin.json` provenance instead
+ of only checking installer script text.
+- Added the manifest file BLAKE3 to `capsem-admin manifest check --json` and
+ logged manifest report/provenance events during package postinstall.
+- Tightened the Ironbank doctor ledger gate so local-network `ask` decisions,
+ informational detections, serialized detection payloads, and security plugin
+ execution timings are proven from session DB rows instead of only counted.
+- Renamed the deterministic local fixture upstream to `capsem-mock-server` and
+ made `CAPSEM_MOCK_SERVER_BASE_URL` the shared contract for doctor,
+ integration, recorder, benchmark, and Ironbank-style black-box tests.
+- Added an Ironbank package-manager ledger proof that boots a VM through public
+ service routes, verifies apt, npm, uv, pip, and node packages perform real
+ work, and audits session history plus `exec_events`/`fs_events` fields.
+- Hardened VM fork cloning so `session.db` is snapshotted through SQLite
+ instead of copied as a raw file. Forks of forks now preserve WAL-backed
+ committed ledger rows as a standalone quick-check-clean database, preventing
+ boot failures from malformed copied session DBs.
+- Hardened Apple VZ suspend/resume and benchmark gates: checkpoint files now
+ require an fsynced completion marker before a VM can be considered
+ suspended, save/restore remain exclusive across service workers, cold starts
+ stay concurrent, and timing probes run isolated after the `-n 4` integration
+ canary so published boot/lifecycle numbers remain meaningful.
+- Replaced fork-package proof in MCP and lifecycle benchmarks with a hermetic
+ local `.deb` probe installed through the public VM file/exec routes, so fork
+ preservation no longer depends on public `apt` repositories while still
+ proving rootfs overlay package state survives the fork.
+- Pointed the injection test runner at the materialized profile catalog and a
+ short `/tmp` CAPSEM_HOME so injection scenarios exercise package/CI-style
+ profile config without tripping macOS Unix-socket path limits.
+- Made `doctor --fix` rebuild VM assets for every checked-in profile through a
+ named profile loop instead of a default-only asset build, with a release
+ contract test guarding the recipe.
+- Aligned support-bundle and gateway test fixtures with the current
+ profile/settings layout and VM `available_actions` contract, and cleaned up
+ Rust formatting debt from the release cleanup branch.
+- Hardened profile routing assumptions by passing the full release gate under
+ temporary arbitrary profile ids before restoring the shipping `code` and
+ `co-work` profile identities. This keeps profile-aware routes, UI/TUI
+ helpers, admin materialization, and install packaging from silently depending
+ on a single hardcoded profile.
+- Added a real checked-in `co-work` profile as source profile data, and
+ tightened Profile UI/TUI/service tests so profile-aware surfaces consume
+ route-provided profile ids instead of silently falling back to `code`.
+- Advanced the 1.3 release metadata to `1.3.1781205836`, pinned the frontend
+ `esbuild` override through the lockfile, and archived fresh lifecycle, fork,
+ in-VM storage, and parallel benchmark ledgers for the current build.
+- Fixed the gateway profile MCP surface so the UI/TUI route for reading and
+ editing a profile's default MCP permission forwards to the service instead
+ of returning a route-level 404.
+- Moved dashboard session creation controls onto each profile card: ready
+ profiles expose a primary `New` action, profiles with missing assets expose
+ `Download`, and `Customize` opens the session dialog preselected to that
+ profile.
+- Added a compact route-backed VM asset checklist to each profile launcher
+ card so users can see which kernel/initrd/rootfs assets are present or
+ missing before starting or downloading a profile.
+- Fixed dashboard session actions so incompatible or defunct sessions remain
+ non-openable and expose only the delete action even if a stale status payload
+ includes start, resume, or fork actions.
+- Tightened the MCP profile UI so default and per-tool permission controls use
+ the same typed allow/ask/block option list as the route contract.
+- Fixed credential broker stats so captured, brokered, injected, and error
+ events are counted independently instead of treating every broker row as a
+ captured credential.
+- Made credential capture write the full durable verb trail: observed secrets
+ now emit `captured` and `brokered`, while replayed references emit
+ `injected`.
+- Fixed the hermetic credential broker test store so concurrent captures cannot
+ corrupt the store or lose refs before replay.
+- Added Ironbank coverage for unknown-host OpenAI-compatible body-shape
+ detection: neutral-path model traffic now proves model rows, broker refs, and
+ detection-rule ledger output.
+- Added Ironbank coverage for unknown remote MCP-over-HTTP JSON-RPC activity:
+ observed initialize/list/tool-call traffic now proves MCP DB rows, timeline
+ route evidence, and `mcp.tool_list`/`mcp.tool_call` security ledger entries.
+- Added Ironbank coverage for declaration-only model tools: an
+ OpenAI-compatible request may advertise tools without creating executed
+ `tool_calls` rows unless the model response actually emits a tool call.
+- Tightened Ironbank tool-call ledger coverage so executed model tool calls
+ must have exact row counts, declaration-only tools stay absent, and observed
+ MCP `tools/call` rows correlate by trace and tool name without protocol
+ chatter becoming phantom executions.
+- Added Ironbank coverage for Gemini/Google and Claude/Anthropic streaming
+ model traffic through hermetic SSE fixtures, proving client-visible bytes,
+ parsed model rows, security-ledger entries, and brokered API-key references.
+- Fixed the credential broker so Google `x-goog-api-key` headers are captured
+ as Google credentials even before a provider hint exists.
+- Hardened profile root bootstrap packaging: `capsem-admin profile check` now
+ rejects unpinned files under a profile root seed, profile payload tests prove
+ AGY/Claude/Codex/MCP non-secret bootstrap files are pinned exactly, and
+ OAuth tokens, logs, conversations, history, and cache payloads cannot be
+ baked into checked-in profile roots silently.
+- Tightened the VM Stats Process panel so it reports command executions and
+ observed processes as separate ledgers, replaces the unrelated credential-ref
+ counter with unique binary counts, and removes tutorial prose from the app UI.
+- Made Stats detail payload rendering content-aware: HTTP header fields use an
+ HTTP grammar, JSON previews are parsed and formatted as JSON, and non-JSON
+ payloads stay as escaped text instead of being forced through a JSON view.
+- Cleaned up Profile overview credential inventory so it shows provider,
+ last-seen, observed, and injected counts without rendering raw broker
+ credential references in the primary UI.
+- Moved frontend MCP controls off settings-backed `mcp.servers.*` mutation and
+ onto profile-scoped MCP routes. Settings now stays focused on UI/app
+ preferences, while the Profile surface owns rules, plugins, MCP, and assets.
+- Moved `capsem-process` and the built-in MCP server onto the materialized
+ runtime profile directory. Runtime rules, plugins, MCP, model endpoints, and
+ service-supplied corp overlays now load from the profile contract instead of
+ global settings/user config files.
+- Updated the Sessions launcher to render profile-owned icon/name/description
+ from `/profiles/list`, check assets per profile, show a download action while
+ assets are missing/downloading, and pass the selected `profile_id` on VM
+ creation.
+- Unified the frontend VM list around one profile-owned VM model: profile
+ launches, keyboard creation, and the custom VM dialog now create named
+ retained VMs, and both the list and active-VM toolbar expose pause/resume,
+ stop/start, fork, and delete without temporary-vs-persistent UI branches.
+- Rebuilt the VM Stats tab around the current session database and VM-scoped
+ ledger routes. It now surfaces Model, MCP, HTTP, DNS, Files, Process,
+ and Security evidence, links directly to raw session DB inspection, and uses
+ DB-backed security/detection/enforcement rows for forensic details. Hypervisor
+ snapshot internals no longer appear as a generic Stats tab; explicit snapshot
+ MCP calls still surface through MCP activity, but host snapshot state is no
+ longer written to or exposed from `session.db`.
+- Hardened the black-box integration gate so credential-broker tests use an
+ isolated file-backed broker store instead of the developer's native keychain,
+ and bounded the VM model fixture call so model/credential regressions fail
+ quickly with ledger evidence instead of hanging the release test.
+- Hardened the integration service startup wait so a clean `capsem-service`
+ idempotent exit during a compatible peer-start race keeps probing the UDS
+ route instead of failing the release gate before `/list` becomes ready.
+- Isolated each integration gate invocation under its own test CAPSEM_HOME so
+ focused and full runs do not share stale service sockets, pidfiles, or broker
+ stores; `CAPSEM_INTEGRATION_HOME` remains available as an explicit debug
+ override.
+- Pinned integration-test `CAPSEM_RUN_DIR` and `capsem-service --uds-path` to
+ the same process-scoped runtime directory so inherited test environment
+ cannot redirect service startup to a foreign singleton socket.
+- Made package postinstall hydrate VM assets through `capsem update --assets`
+ after copying the selected manifest/profile ledgers. Local dev/corp manifests
+ now use `manifest-origin.json` to hydrate from the source asset tree with the
+ same hash-named layout and blake3 verification as remote downloads, while the
+ package payload remains free of rootfs/initrd/kernel blobs.
+- Made `bootstrap.sh` frontend dependency installation non-interactive by
+ running `pnpm install` with `CI=true`, matching the full test gate contract
+ and avoiding TTY-only confirmation prompts during unattended bootstrap.
+- Added VM-scoped snapshot status/list routes backed by the running
+ `capsem-process` in-memory snapshot scheduler. Stopped VMs reconstruct
+ snapshot status from that VM's snapshot metadata only when requested, and
+ migrated session databases drop the old `snapshot_events` table.
+- Compact `snapshots_list` output now defaults to created/edited/deleted counts
+ so AI-facing MCP responses stay small; callers must pass
+ `include_changes=true` to request full per-file snapshot diffs.
+- Hardened workspace snapshot storage so capture, compaction, deletion, and
+ eviction refuse to operate when snapshot storage or a slot resolves inside
+ the live workspace. Regression tests prove snapshot capture/compaction leave
+ live workspace entries unchanged and reject symlinked storage back into the
+ workspace.
+- Hardened `snapshots_revert` against symlink escape/pull-in regressions:
+ restore now rejects symlinked parent components in checkpoint storage, avoids
+ following live workspace symlinks during no-op checks, and reads regular
+ snapshot sources with no-follow file opens. Regression tests cover the old
+ “symlink out of workspace, pull outside file bytes into restore” class.
+- Clarified the VM Stats process tab by separating command execution rows from
+ audit-port process observations, removing the vague “Process Audit Events”
+ label from the user-facing table.
+- Updated public architecture docs and internal development skills to reflect
+ the 1.3 contract: profile-owned assets/rules/MCP/plugins, settings as UI/app
+ preferences only, explicit gateway routes, ledger-backed Stats/Inspector,
+ and the single SecurityEvent/CEL rule rail.
+- Added a `capsem debug` CLI alias for redacted support bundles and expanded
+ `capsem status` with profile catalog readiness and corp config
+ presence/source/hash information when the service is running.
+- Expanded `capsem debug` support bundles with a machine-readable runtime
+ boundary contract covering first-party host VSOCK services, explicitly closed
+ raw ports, and diagnostic/status routes for bug reports.
+- Updated package installation diagnostics: macOS and Linux package scripts now
+ write a durable `~/.capsem/logs/install.log`, package builders accept local
+ paths plus `file://`, `http://`, and `https://` manifest overrides, and
+ service status reports the installed manifest hash and package provenance.
+- Hardened macOS `.pkg` and Linux `.deb` package composition so closed
+ packages contain the app/binaries, profile config, and selected
+ `manifest.json`/`manifest-origin.json` only; VM asset payloads are never
+ embedded and are reconciled by the service from the installed manifest.
+- Reorganized checked-in config source into `config/settings`, `config/corp`,
+ `config/profiles`, `config/docker`, and `config/data`, documented the layout,
+ and made source profiles unpinned by contract. `config/settings` owns only
+ UI/application preferences; profile/corp own runtime behavior.
+- Added per-install timestamped logs under `~/.capsem/logs/install-*.log` plus
+ `install-latest.log`, while preserving the aggregate `install.log`.
+- Expanded manifest status reporting with mutable-manifest semantics:
+ `/profiles/status`, `/profiles/{id}/assets/status`, and CLI status output now
+ report the current manifest hash, source, refresh timestamp, and validation
+ result instead of treating the install-time hash as immutable.
+- Hardened doctor/Ironbank diagnostics so credential-shaped model and OAuth
+ probes no longer place synthetic secrets in process argv, and removed the
+ guest `shutdown` sysutil alias now that VM shutdown is owned by the TUI.
+- Made `capsem-admin manifest generate ` the documented manifest
+ production rail for local, release, and corp custom builds; package builders
+ consume the selected manifest but no longer document or rely on direct
+ generator internals.
+- Added a route-backed frontend debug snapshot:
+ `window.__capsemDebug.snapshot()` now returns frontend version/log context,
+ websocket tail, gateway status, profile catalog status, and corp info for
+ pasteable bug reports.
+- Updated the session UI to display each VM's backend-provided `profile_id` and
+ replaced hard-coded About runtime/kernel claims with live diagnostic status.
+- Updated the Profile overview to render route-backed surface availability
+ (web, shell, mobile) and broker-visible credential inventory/grant status, so
+ profile readiness is visible before users dig into Plugins or raw stats.
+- Removed the mistaken checked-in `config/skills/` mirror and restored
+ repository `skills/` as the developer skill source; profile/product skills
+ must be introduced through the profile ledger instead of a global config
+ escape hatch.
+- Moved the code profile ledger to `config/profiles/code/profile.toml` and
+ materialize generated/installed profiles with the same directory shape, so
+ source and runtime config use one profile path contract.
+- Added profile-owned VM base-image OBOM evidence: materialized profiles can
+ pin `obom.cdx.json` with BLAKE3 hash, size, cdxgen generator metadata, and
+ the rootfs hash it describes, and `/profiles/{id}/info` plus
+ `/profiles/{id}/obom` expose that base-image-only contract.
+- Added profile-owned image payload declarations for the code profile: MCP
+ config, apt/Python/npm package lists, build-time hook script, tips, and
+ packaged guest-root seed files are now declared from `profile.toml`.
+ `capsem-admin profile check` verifies those source payloads plus the root
+ seed manifest, and `capsem-admin image build` materializes a pinned,
+ self-contained generated guest workspace before invoking the backend builder.
+- Renamed profile image hooks from `install.sh`/`files.install` to
+ `build.sh`/`files.build` and added Ollama to the shipped Code and Co-work
+ profile images through that builder rail, with `zstd` included for the
+ official Ollama installer.
+- Pruned Ollama CUDA libraries from profile-built images and added the Python
+ Ollama SDK to Code and Co-work profiles so local Ollama client tests do not
+ require ad-hoc VM package repair or waste guest disk on unused GPU payloads.
+- Added non-secret Claude MCP approval state to Code and Co-work profile roots
+ so fresh profile-built sessions do not prompt users to trust the built-in
+ `capsem` MCP server before agents can use it.
+- Added OpenAI, Anthropic, and LiteLLM Python SDKs to the Code and Co-work
+ profile package ledgers so Ironbank real-client model tests can run from the
+ VM without ad-hoc guest installs.
+- Added an Ironbank `capsem-doctor` ledger proof that boots a VM through public
+ service routes, runs the hermetic mock protocol lab, and verifies HTTP, DNS,
+ MCP, model, tool-call, file, exec, security-rule, and credential broker rows
+ agree in `session.db`.
+- Made the VirtioFS doctor pip probe hermetic by installing a generated local
+ wheel with `--no-index` instead of reaching out to PyPI for `cowsay`.
+- Expanded per-architecture VM build ledgers with a `rootfs.config_inputs`
+ stage that records declared package config, rendered rootfs install inputs,
+ profile root/build-script inputs, and EROFS settings. Installed package
+ names and versions remain OBOM evidence, not build-ledger claims.
+- Cleaned active architecture/development docs and internal skills around the
+ profile/admin image contract: public guidance now points at profile-owned
+ package/MCP/rule/root files, generated `target/config`, `capsem-admin image
+ build`, build ledgers, and OBOM evidence instead of retired builder
+ scaffolding or image-owned provider configuration.
+- Added the first profile mutation rail: enforcement and detection rule files
+ are now profile-owned files, `Profile` owns core status/check/download and
+ MCP tool permission mutation, backend-managed rules carry typed ownership
+ annotations, and profile mutations have a DB-writer ledger event.
+- Wired service profile routes onto that rail: profile status now verifies
+ pinned profile files plus asset hashes, profile asset ensure repairs corrupt
+ hash-prefixed assets, MCP tool permission edits write managed profile
+ enforcement rules and profile mutation ledger rows, and enforcement/detection
+ route listing and authoring compile from profile files plus corp overlays
+ without reading or writing user settings.
+- Made MCP tool permissions round-trip through the same profile enforcement
+ contract: tool list responses now include the effective `allow`/`ask`/`block`
+ action and source rule, the frontend edits tools with `{ action }` instead of
+ the retired `{ approved: true }` cache shape, and unsupported server
+ add/toggle/delete controls are no longer exposed in the MCP UI.
+- Clarified MCP builtin display semantics: the profile-owned `local` Capsem MCP
+ entry is rendered as built-in capability, not as a stopped external server,
+ and frontend runtime counts exclude static builtin MCP entries.
+- Split the Profile UI's retired generic `Policy` section into explicit
+ `Enforcement` and `Detection` route-backed tabs, with a frontend contract
+ test guarding against reintroducing the old policy tab.
+- Replaced the Profile UI's raw asset JSON dump with a route-backed asset
+ checklist that shows manifest status, VM assets, profile files, verified/
+ missing/invalid/downloading state, paths, and size details from
+ `/profiles/{profile_id}/assets/status`.
+- Disabled debug-only dummy plugins by default and updated the plugin UI to
+ show enum-backed mode badges/icons for allow, ask, block, rewrite, and
+ disabled states without hiding inactive plugins.
+- Added plugin-owned capability metadata to `/profiles/{profile_id}/plugins/*`.
+ The credential broker now reports watched event families, supported
+ providers, and credential source shapes, and the Plugin UI renders those
+ fields alongside broker inventory/counters instead of guessing.
+- Updated the Profile rule lists and MCP tool list to use the same
+ enum-backed visual language for allow/ask/block/rewrite/detection levels,
+ while keeping MCP tool permission changes on the route-backed selector.
+- Added an explicit `enabled` field to the security rule contract. Disabled
+ rules remain visible in profile enforcement/detection inventories but are
+ skipped by `SecurityRuleSet` evaluation and rendered inactive in the UI.
+- Grouped Profile enforcement and detection rule lists into `default_rule`
+ and profile/corp sections so built-in catchalls are visible without creating
+ a second rule engine.
+- Added a visible MCP default permission selector backed by `default.mcp`.
+ The UI reads and edits `/profiles/{profile_id}/mcp/default/*`, while the
+ service mutates the pinned enforcement file and writes the same profile
+ mutation ledger used by per-tool MCP overrides.
+- Cleaned the admin/doctor/status/debug rails so diagnostics follow the profile
+ contract: builder doctor delegates profile validation to `capsem-admin
+ profile check`, Justfile asset builds no longer pass legacy guest-config
+ knobs, `capsem status`/default health read profile readiness from the service,
+ and support bundles collect `settings.toml`/corp diagnostics without
+ preserving `user.toml` as a config contract.
+- Added structured `capsem.profile_mutation` logs for profile mutation routes
+ and ledger writes. MCP tool edits plus enforcement/detection rule upserts and
+ deletes now log route requests, validation rejections, ledger-open failures,
+ and applied mutations with the same stable profile, target, operation, rule,
+ hash, size, status, and mutation identifiers stored in the mutation ledger.
+- Updated in-VM diagnostics to validate that the profile-owned Gemini,
+ Antigravity, Claude, Codex, and MCP config files are actually projected into
+ runtime `/root`, point at the canonical Capsem MCP bridge where applicable,
+ and do not contain obvious credential-shaped secrets. The arm64 code-profile
+ EROFS rootfs and initrd pins were refreshed from the rebuilt assets.
+- Added a coverage-infra guard for release prep: PR Rust coverage now includes
+ every workspace crate across the macOS/Linux jobs, Codecov components map
+ each crate, and build-chain tests fail if a future crate is left out.
+- Hardened AGY/manual-loop diagnostics: missing `capsem-mcp-aggregator` now
+ fails loud instead of returning an empty MCP tool stub, unknown private
+ model gateways are promoted from bounded JSON protocol shape while preserving
+ the original HTTP body, broker credential inventory reports whether a stored
+ reference is actually replayable, unknown remote MCP-over-HTTP JSON-RPC is
+ promoted into first-party MCP ledger/security events, and boot/dispatch
+ consume one typed host VSOCK service registry.
+
+### Added (kernel 7.0 + EROFS)
+- Added a stable-kernel upgrade path for guest builds: `kernel_branch = "7.0"`
+ now resolves against kernel.org stable releases, while `auto` remains
+ LTS-only for conservative release automation.
+- Restored Linux KVM guest-memory hardening from the lost Linux line:
+ guest memory reads/writes now reject offset overflow, and virtio-blk validates
+ complete guest physical ranges before exposing raw host pointers to vectored
+ I/O.
+- Added experimental EROFS rootfs image generation with `lz4`, `lz4hc`, and
+ `zstd` compression. EROFS zstd uses a newer `erofs-utils` container image,
+ both guest defconfigs enable kernel-side EROFS zstd decompression, and
+ `capsem-init` mounts EROFS when the VM cmdline carries `capsem.rootfs=erofs`.
+- Added an opt-in Mac/VZ EROFS DAX probe lane:
+ `CAPSEM_EXPERIMENTAL_EROFS_DAX=1` forwards to `capsem-process`, appends
+ `capsem.rootfs=erofs-dax`, and makes `capsem-init` attempt an EROFS
+ `ro,dax` mount so we can verify whether the VZ block transport can support
+ the Linux-style DAX win locally.
+- Moved guest NAT setup for the kernel 7.0 lane to `iptables-nft`: defconfigs
+ enable nf_tables with the required nft/xt compatibility objects, legacy
+ `IP_NF_*` tables are forbidden by tests, `capsem-init` fails closed on NAT
+ rule insertion errors, and the rootfs build strips Debian's legacy iptables
+ frontend binaries.
+- Promoted EROFS lz4hc rootfs assets into the normal asset contract:
+ `just build-assets code [arch]`, manifests, service resolution, setup status,
+ release attestation, and installer download tests now use `rootfs.erofs` as
+ the 1.3 runtime rootfs.
+- Removed squashfs as a runtime/build fallback for 1.3 assets: the builder emits
+ only `rootfs.erofs`, manifests require EROFS rootfs entries, service/core
+ asset resolution no longer selects `rootfs.squashfs`, and in-VM doctor checks
+ require `/dev/vda` to be EROFS.
+- Added per-architecture VM asset `build-ledger.log` JSONL output from the real
+ builder path, covering rendered Dockerfile/build-context hashes, rootfs tar,
+ EROFS, kernel assets, tool-version output, compression settings, git revision,
+ and project version; release CI uploads the ledger separately for retraceable
+ failures.
+- Added Python quality gates: Ruff now runs across the repository, and `ty`
+ type-checks `src/capsem` in CI plus the local `just test`/`just smoke`
+ fast-fail stages.
+
+### Added (benchmarks)
+- Added a deterministic `/model/response` fixture to `capsem-mock-server`
+ and wired `capsem-bench protocol` to exercise both SSE model streams and
+ JSON model responses without public-network dependencies.
+- Added a shared `capsem-bench` load harness for MITM, MCP, DNS, and local
+ mock-server tests: `CAPSEM_BENCH_CONCURRENCY`,
+ `CAPSEM_BENCH_DURATION_S`, `CAPSEM_BENCH_TOTAL_REQUESTS`, and
+ `CAPSEM_BENCH_SCENARIOS` now drive one tested config path, and load rows
+ share the same request/error/rps/p50/p95/p99/p999/RSS schema.
+- Added `scripts/benchmark_report.py`, a Pydantic-validated host reporter that
+ renders benchmark JSON as Markdown and can produce matplotlib PNG graphs for
+ committed load artifacts.
+- Expanded the security-action Criterion benchmark to cover runtime event
+ classification for HTTP, DNS, MCP, model, file, and process events in
+ addition to rule matching, plugin dispatch, broker substitution, and MCP
+ brokered OAuth credential-reference resolution.
+- Refreshed the VM `mitm-local` release artifact so the local fixture corpus now
+ includes JSON model responses, credential-shaped responses, WebSocket control,
+ and session DB/no-secret verification through the profile-selected VM path.
+- Added a retired security-rail guard test that fails if old Policy V2,
+ domain-policy, or MCP decision-provider code paths reappear in live crates or
+ configuration.
+
+### Fixed (install/setup)
+- Fixed `capsem stop` on macOS so it unloads the LaunchAgent instead of sending
+ SIGTERM to a `KeepAlive` job that launchd immediately restarts. The command
+ now verifies the service is no longer loaded before reporting success, so
+ stopping Capsem no longer re-enters service startup or prompts for Keychain.
+- macOS package postinstall now adds `~/.capsem/bin` to fish shell startup via
+ an idempotent `fish_add_path --path "$HOME/.capsem/bin"` entry.
+- Rebuilt install/startup flow around service readiness and asset state instead
+ of setup wizard state: package installs surface postinstall failures, assets
+ resolve through the manifest contract, and the UI waits on the service rather
+ than opening against a dead daemon.
+- Removed the old setup/onboarding authority path. Provider credentials are now
+ discovered or brokered by the credential broker plugin through runtime
+ security events and broker-owned references instead of being copied through a
+ setup wizard.
+- Removed the dead host credential detection module that could scan raw host
+ API keys/OAuth files and write them into settings. Credential capture now
+ stays behind the credential broker/plugin path, and the retired settings key
+ validation surface remains fail-closed at the gateway.
+- Stopped settings-derived guest config from materializing brokered provider
+ credentials, repository tokens, generated `.git-credentials`, provider allow
+ env vars, or AI CLI config files into VM boot env/files. Settings can still
+ provide UI/app preferences and explicit non-secret `guest.env.*`; credential
+ materialization is broker/plugin-owned.
+- Removed the generated/UI `settings.ai.*` provider registry and the stale
+ settings-based API-key injection tests. Retired flat AI setting IDs now fail
+ validation for both settings file loads and inline corp config installs;
+ provider control remains profile/corp rule-owned and credential handling
+ remains plugin-owned.
+- Removed the retired settings preset subsystem and cleaned root `config/` so
+ MITM CA key material lives under `security/keys/` instead of looking like
+ editable runtime configuration. Profile assets are selected by URL and
+ verified by BLAKE3 hash/size, while release evidence stays in SBOM and
+ provenance attestations.
+- Fixed local install/package asset materialization so literal build outputs
+ and already hash-prefixed assets both install through the same
+ manifest-driven hash-prefixed layout, and package/simulated installs now
+ include the full host tool set including `capsem-admin`,
+ `capsem-tui`, `capsem-mcp-aggregator`, and `capsem-mcp-builtin`.
+- Updated the built-in code profile's arm64 asset pins to the current
+ EROFS/LZ4HC release artifacts so profile-owned VM boot resolution and the
+ installed asset manifest agree.
+- Fixed EROFS asset generation to disable the internal superblock CRC feature;
+ BLAKE3 remains the release/boot integrity contract, and the repaired LZ4HC
+ rootfs now passes `fsck.erofs` before install.
+- Hardened the install test harness so the Linux package/systemd user unit is
+ stopped before scoped process cleanup, and renamed the internal dev-readiness
+ just helper away from setup wording while keeping `capsem setup` removed.
+
+### Changed (release proof)
+- Added shared runtime config materialization through
+ `capsem-admin profile materialize`: local dev, smoke/test/install recipes,
+ and release package jobs now generate `target/config` from checked-in
+ `config/` plus `assets/manifest.json` instead of hand-editing source
+ profiles. Service test helpers and `just _ensure-service` load
+ `target/config/profiles` fail-closed.
+- Updated docs and developer skills to document the same generated-config rail:
+ checked-in `config/` is source/support material, current-build runtime config
+ lives under `target/config`, and EROFS/LZ4HC level 12 is the 1.3 rootfs
+ contract rather than a best-effort fallback.
+- Restored the Linux-team KVM/FUSE performance work and storage benchmark
+ harness into the current EROFS/LZ4HC rail, including bounded VM proof for
+ `capsem-bench storage` from the generated profile-selected asset chain.
+- Replaced public-service release proof with deterministic local fixtures:
+ `capsem doctor` now starts/passes a local `capsem-mock-server`, doctor MCP
+ content checks use local text/HTML fixtures, integration tests use local
+ allowed/throughput/blocked HTTP paths, and session DB row-generation tests no
+ longer curl public services.
+- Routed local release-proof network traffic through the normal guest
+ iptables-nft redirect rail. The local fixture is only the upstream target;
+ doctor, integration, and benchmark paths no longer inject proxy environment
+ variables or explicit WebSocket proxy sockets.
+- Expanded the shipped plain-HTTP redirect/allowlist mechanics to
+ `80`, `3128`, `3713`, `8080`, and `11434`, with doctor and local release
+ proof pinned to `127.0.0.1:3713` to avoid colliding with real Ollama.
+
+### Changed (service/API)
+- Updated architecture docs and local development skills to match the 1.3
+ contract: settings endpoints are `/settings/info|edit` and expose only
+ `tree`/`issues`, install is service/profile-asset readiness rather than a
+ setup wizard, and EROFS/LZ4HC is the rootfs contract.
+- Moved VM APIs under the explicit `/vms/...` contract. VM creation, listing,
+ info, stop, pause, delete, resume, save, fork, exec, logs, inspect, history,
+ timeline, and file read/write/list/content routes now live under
+ `/vms`/`/vms/{vm_id}`; the retired top-level routes fail closed in the
+ service/gateway route contract.
+- Tightened the Python service, gateway, and E2E harnesses around the
+ profile-owned VM contract: every VM creation and one-shot run test now passes
+ the real `code` profile id explicitly, and the gateway mock rejects missing
+ profile ids instead of accepting old default-profile payloads.
+- Fixed runtime config loading so env-supplied corp/profile config preserves
+ direct `corp.rules`, `profiles.rules`, `default`, `plugins`, and refresh
+ groups when materializing `MergedPolicies`. Negative-priority corp rules now
+ survive into VM processes and are covered by deterministic local MITM
+ telemetry proof.
+- Added `GET /vms/{vm_id}/status` as the runtime-state endpoint for one VM so
+ UI state reads no longer need to treat `/vms/{vm_id}/info` as a status API.
+- Added `PATCH /vms/{vm_id}/edit` as a fail-closed VM edit gate: attempts to
+ mutate immutable `profile_id` or unknown fields are rejected, and resource
+ edits return explicit unsupported status until live edit semantics are
+ implemented.
+- Added `GET /vms/{vm_id}/save/status` and
+ `GET /vms/{vm_id}/fork/status`; because save/fork are synchronous today,
+ existing VMs report explicit `idle` operation state rather than fake progress.
+- Added VM action route coverage for `POST /vms/{vm_id}/start`,
+ `POST /vms/{vm_id}/restart`, and `POST /vms/{vm_id}/reload-profile`.
+ `start` uses the existing resume/start path; restart and reload-profile
+ verify the VM exists and fail explicitly until real semantics land.
+- Added profile inventory routes `GET /profiles/list` and
+ `GET /profiles/status`, `POST /profiles/reload`, and
+ `GET /profiles/{profile_id}/info`. Profile identity now comes from the typed
+ profile catalog: the built-in `code` profile is a real `ProfileConfigFile`,
+ route validation no longer uses a hard-coded `default` profile stub, and
+ catalog reload/status reports profile readiness through the profile asset
contract.
-- Added Linux host doctor smoke probes for `KVM_GET_API_VERSION` and
- `/dev/vhost-vsock` openability so bootstrap verifies usable KVM devices, not
- just filesystem permissions.
-- Added structured `capsem-tui` help and session-list tables, an explicit
- `Alt+l` sessions overlay, and clearer `Alt+i` session info.
-- Added focused-field highlighting to `capsem-tui` create and fork dialogs so
- the active input and selected profile are visible.
-- Added an empty-state `capsem-tui` startup path that opens the new-session
- modal directly and brands it with a compact gradient CAPSEM wordmark.
-- Changed the `capsem-tui` status hint to `help: alt+?` and moved it to the
- far right after active-session statistics, including the empty-session state.
-- Changed `capsem shell` to launch `capsem-tui` as the single interactive VM
- control surface; `capsem shell ` now opens the TUI focused on that
- session instead of using the legacy direct PTY bridge.
-- Added Linux KVM doctor coverage that creates and resolves symlinks under
- `/tmp`, keeping link-heavy cache/tool probes off the VirtioFS workspace while
- leaving snapshot symlink restore scoped to `/root`.
-- Reduced the top-level sprint inventory to active Profile V2 work plus the
- credential detection pipeline, moving completed boards to `sprints/done/` and
- stale or superseded boards to `sprints/retired/`.
-- Inventoried sprint planning docs and moved retired Profile V2, release, and
- legacy boards under `sprints/retired/` so active release planning starts from
- `sprints/policy-settings-profiles/`.
-
-### Added
-- Added rootfs benchmark sub-metrics for large binary sequential reads, small
- JS/package file reads, and metadata-heavy `lstat` walks so Linux/macOS rootfs
- gaps can be attributed to data reads versus loader-style metadata pressure.
-- Added an opt-in `capsem-bench storage` diagnostic that records mount metadata
- and splits rootfs reads from writable-path I/O across workspace, tmpfs,
- overlay, and runtime directories for Linux/macOS performance comparisons,
- including detailed sequential and random IOPS/latency profiles per path and
- the booted squashfs compression/block-size, kernel cmdline, block queue, and
- FUSE connection metadata.
-- Added Linux release-candidate benchmark artifact plumbing with arch-scoped
- output paths, host/git metadata, optional run IDs, and gross in-VM
- `capsem-bench` gates for disk, rootfs, CLI startup, HTTP, throughput, and
- snapshot operations.
-- Added an in-guest `capsem-doctor` SMP diagnostic that compares `nproc` with
- `/proc/cpuinfo` and requires at least two visible vCPUs.
-- Added live x86_64 KVM SMP boot support with synthetic ACPI RSDP/RSDT/MADT
- tables and guest CPUID topology so Linux discovers all configured vCPUs.
-- Added x86_64 KVM checkpoint trait support for cooperative pause/resume,
- atomic guest-memory checkpoint writes, and checkpoint restore of guest RAM
- plus vCPU regs/sregs, with targeted vCPU kicks for blocking `KVM_RUN` pause
- and unsupported KVM restore paths failing closed instead of silently
- cold-booting.
-
-### Fixed
-- Fixed service purge so `all=false` still removes defunct or profile-corrupted
- persistent VMs while preserving healthy persistent VMs, making TUI cleanup
- actually clear broken profile-pin sessions from refreshed VM lists.
-- Fixed `capsem-tui` recovery for stopped VMs with corrupted profile pins:
- the inactive pane now explains that Enter creates a replacement VM, while
- `Alt+d` remains available to delete the bad VM entry.
-- Fixed `capsem-tui` suspend feedback so `Alt+s` shows a full-pane
- `suspending...` state while the suspend action runs instead of only updating
- the bottom status bar.
-- Fixed `capsem-tui` terminal input after suspend/resume so a failed or closed
- terminal WebSocket clears the connected marker, reconnects the active session
- after resume, and does not drop typed input into a stale terminal task.
-- Fixed `capsem-tui` create flow focus so a newly provisioned VM becomes the
- active tab even when the first gateway refresh after `/provision` does not
- list the VM yet.
-- Fixed `capsem-tui` corrupted profile-pin handling so non-resumable sessions
- are hidden from the bottom VM tab strip, still appear in the full `Alt+l`
- session inventory, and explain that the VM must be recreated from a signed
- profile if explicitly selected.
-- Fixed `capsem-tui` service-offline startup so the TUI shows an offline
- service surface and asks to start Capsem before opening the new-session flow;
- confirming the prompt runs the local `capsem start` command and refreshes
- with a fresh gateway token.
-- Fixed `capsem-tui` empty-session creation so the TUI no longer invents a
- `default` profile when `/profiles` is unavailable; the new-session modal now
- blocks Enter until a real profile list is loaded and has unit plus gateway
- E2E coverage for the profile-backed create contract.
-- Fixed `capsem-tui` stopped-session rendering so stopped/suspended/failed
- tabs are greyed, the main pane shows a `Press Enter to resume` affordance
- instead of going blank, and the terminal bridge disconnects instead of trying
- to attach a WebSocket to an inactive VM.
-- Fixed a `capsem-process` IPC file-descriptor leak where short-lived
- status/metrics connections left writer and lifecycle-forwarder tasks alive
- after the client disconnected.
-- Fixed `capsem-tui` live gateway attention handling so sessions with
- `profile_status=current` are not marked stale, and proved the installed
- terminal WebSocket path against two running service sessions.
-- Fixed `capsem-tui` terminal rendering to use a real VT/xterm parser with
- color/style preservation, adjacent output coalescing, and dirty-frame
- redraws instead of a hand-rolled ANSI text flattener.
-- Fixed `capsem-tui` service latency rendering to reserve four digits so the
- bottom status bar does not shift as latency changes.
-- Fixed `capsem-tui` service latency rendering to keep the status dot glued to
- the latency field, making the service block read as one unit.
-- Fixed `capsem-tui` shell controls to use an app-owned Alt namespace:
- `Alt+Left/Right`, `Alt+1..9`, `Alt+n/f/r/s/c/t/d`, `Alt+?`, `Alt+i`,
- `Alt+l`, and `Alt+q`, instead of terminal-dependent Cmd/Ctrl forwarding or
- prefix fallbacks.
-- Fixed `capsem-tui` help and modal handling by using `Alt+?` for help,
- rendering overlays through Ratatui modal widgets, and resending the active
- terminal geometry whenever the real terminal size changes.
-- Fixed `capsem-tui` modal input ownership so `Esc` closes non-confirmation
- overlays, visible modals consume normal keys, and plain VM input resumes
- forwarding as soon as the modal closes.
-- Fixed `capsem-tui` tab colors so the selected VM is yellow and every other
- VM tab is blue, removing the previous gray/attention color ambiguity.
-- Fixed macOS release builds of the service debug report by widening filesystem
- block counts before computing disk byte totals.
-- Fixed macOS release builds of `capsem-process` shutdown handling by returning
- the VM stop result from the main-thread stop task and avoiding a macOS-only
- unused signal receiver.
-- Fixed install profile materialization so manifest aliases and legacy local
- alias directories do not make package assembly look for non-existent VM
- assets.
-- Added Linux KVM virtio-blk discard handling so explicit guest discard/trim
- requests can punch holes in writable virtio block backing files.
-- Refreshed local profile asset pins during dev service startup so benchmark
- runs after `_pack-initrd` use matching initrd/rootfs hashes.
-- Expanded x86_64 KVM warm-restore groundwork by checkpointing VM interrupt
- controller, PIT, clock, extended vCPU, Virtio-MMIO transport, and vhost-vsock
- queue state, and by making guest snapshot preparation force a post-resume
- vsock reconnect. The durable process-preserving KVM resume contract still
- fails because restored guests stop making timer-driven forward progress.
-- Improved Linux KVM VirtioFS throughput by negotiating 1 MB FUSE request
- pages and matching read-ahead when the guest kernel supports `FUSE_MAX_PAGES`,
- with structured init logging for the negotiated FUSE limits.
-- Improved Linux KVM VirtioFS read/write handling by using positional host I/O
- for FUSE file operations, removing an extra seek from the hot path and
- keeping shared host file cursors stable across guest offset reads and writes.
-- Fixed Linux `capsem-process` SIGTERM handling so external process death
- drains telemetry and exits instead of leaving the VM listed until service
- teardown.
-- Fixed API file-upload observability by recording a synchronous `fs_events`
- row with ambient trace context, so service-originated writes do not depend
- solely on the polling filesystem monitor.
-- Fixed Linux fork/snapshot fallback copies to preserve sparse VM disk holes
- when `FICLONE` is unavailable, avoiding 2 GB physical copies on filesystems
- without reflink support.
-- Fixed full-test gate assumptions around KVM load by aligning VM-limit tests
- with the service's default eight-VM cap and giving suspend calls enough
- timeout budget to queue behind the host-wide save/restore lock.
-- Fixed full-test setup/gateway harness contracts so `/setup/assets` may report
- per-asset download progress and mock terminal WebSocket teardown cannot race
- its shutdown event under parallel pytest.
-- Fixed the local Python coverage gate to match the CI-owned 89% schema floor,
- with a regression test that prevents local/CI coverage threshold drift.
-- Fixed serial benchmark gates for Linux KVM by separating backend-dependent
- provision latency from steady-state exec/delete latency and cleaning transient
- apt metadata out of the fork image-size workload.
-- Fixed the serial log gate to accept early KVM ACPI/PCI boot messages and the
- guest banner when the log stream starts after the Linux version line.
-- Fixed `just cross-compile` so its Linux boot test installs the repacked
- `.deb` with CLI/service companion binaries, packaged admin payload, signed
- manifest, payload verification, and Docker vsock permissions instead of the
- raw Tauri desktop package, with the package verifier isolated from the
- checkout venv, frontend dependencies isolated from the host checkout, install
- e2e Docker state isolated from host `.venv`/`node_modules` ownership, and
- session validation accepting current `*-tmp` VM names.
-- Fixed the Linux full-test gate under current Rust by cleaning KVM, service,
- and app clippy warnings that were promoted to errors.
-- Fixed native guest-agent rebuilds so readonly `target/linux-agent` outputs
- are replaced atomically instead of failing with `Permission denied`.
-- Fixed host-side `capsem-pty-agent` exec tests by avoiding inaccessible
- `/root` working directories outside the guest.
-- Fixed the PTY/vsock bridge to use nonblocking bidirectional polling with
- bounded buffers, preventing full-duplex terminal traffic from deadlocking or
- dropping queued bytes during peer shutdown.
-- Fixed the full test harness to put pytest and VM temporary files under
- `target/tmp` instead of the host `/tmp` tmpfs, avoiding disk-pressure
- cascades during the four-worker VM integration phase.
-- Fixed service settings reload isolation by pinning each service instance to
- its startup `service.toml` path, so tests and running services do not follow
- later `CAPSEM_HOME` environment changes.
-- Fixed Linux KVM multi-VM vsock boot by allocating a per-VM host port block
- and passing the offset to guest agents through the kernel command line,
- preventing concurrent VMs from racing on fixed host ports 5000-5007.
-- Fixed KVM suspend timing by giving the guest agent time to leave the
- pre-checkpoint vsock bridge and enter its post-resume reconnect loop before
- VM state is saved.
-- Fixed x86_64 KVM process-preserving warm resume by checkpointing VM interrupt
- controller, PIT, clock, extended vCPU state, selected timer/paravirtual MSRs,
- Virtio-MMIO transport state, vhost-vsock queue state, and by restoring timer
- MSRs after LAPIC state so resumed guests keep making forward progress.
-- Added warm-restore Virtio queue reconstruction and a pre-checkpoint
- VirtioFS quiesce hook with structured queue/IRQ telemetry so KVM checkpoints
- do not replay pre-suspend userspace FUSE work through fresh device workers.
-- Improved x86_64 KVM checkpoint restore correctness by preserving vCPU MP
- state and avoiding cold-boot x86 setup writes over restored guest RAM.
-- Fixed the Linux KVM full `capsem-doctor -x -v` gate, which now passes on the
- nested-KVM proving host after the SMP, VirtioFS, runtime cache, Git trust, and
- network proxy fixes.
-- Fixed Git workflows in Linux KVM workspaces by adding guest system Git trust
- for VirtioFS-owned `/root` repositories, avoiding dubious-ownership failures
- when commands run as guest root.
-- Fixed Linux KVM guest `uv pip install` by moving the uv cache off the
- VirtioFS workspace to `/var/cache/capsem/uv`, avoiding wheel/archive symlink
- failures under `/root/.cache/uv`.
-- Fixed Linux KVM VirtioFS symlink reads by correcting the FUSE `READLINK`
- opcode from the `GETXATTR` slot to Linux opcode 5, which also stops xattr
- probes from being misrouted as symlink reads.
-- Fixed Linux KVM VirtioFS rename-over-existing semantics so atomic CLI config
- rewrites keep the moved inode bound to the target path instead of making the
- rewritten file disappear from the guest dentry cache.
-- Fixed KVM vCPU run-loop handling so application processors continue across
- guest HLT exits and transient `KVM_RUN` `EAGAIN` responses instead of
- silently dropping out of the VM.
-- Fixed guest doctor readiness on Linux KVM by keeping the DNS and MITM network
- proxies alive across init shell transitions, failing closed when either proxy
- cannot start, and moving the Python virtualenv off the VirtioFS workspace to
- `/var/lib/capsem/venv`.
-- Fixed the Gemini doctor wrapper lookup to use portable POSIX `command -v`
- instead of a shell-specific `type -P`.
-- Fixed Linux developer bootstrap so fresh hosts install the C toolchain,
- Node/npm, and sqlite before cargo tool setup, and so pnpm is pinned to the
- lockfile-compatible 10.x installer path instead of picking up stale pnpm 11
- shims.
-- Fixed `doctor --fix` VM asset setup to build the host architecture instead
- of requiring cross-architecture Docker emulation during first setup.
-- Fixed KVM pure-logic regressions by correcting the vhost-vsock vring ioctl
- size and tightening VirtioFS namespace path handling.
-
-## [1.2.1779673506] - 2026-05-24
-
-### Fixed
-- Fixed release package profile asset URLs so packaged Profile V2 installs
- download VM assets from the live GitHub Release, and updated the post-release
- verifier to seed packaged profiles before running `capsem update --assets`.
-
-## [1.2.1779668968] - 2026-05-24
-
-### Fixed
-- Fixed macOS package notarization for the packaged `capsem-admin` Python
- payload by signing native Mach-O wheel extension files before building the
- installer package.
-
-## [1.2.1779665197] - 2026-05-24
-
-### Fixed
-- Fixed release metadata stamping so the Python lockfile records the same
- package version as the workspace, Tauri app, and Python project metadata.
-
-## [1.2.1779665141] - 2026-05-24
-
-### Fixed
-- Fixed the Linux install test harness clean-state path to stop the systemd
- user unit before killing scoped Capsem processes, preventing `Restart=always`
- from racing tests that intentionally replace `capsem-service` with a broken
- binary.
-
-## [1.2.1779662531] - 2026-05-24
-
-### Fixed
-- Fixed package setup for manifest-only installs so packaged Profile V2
- sidecars install before local heavy VM asset fallback, allowing `.deb`
- postinstall to complete from signed packaged profiles without bundled
- kernel/initrd/rootfs files.
-
-## [1.2.1779658398] - 2026-05-24
-
-### Fixed
-- Fixed guest `localhost` resolution during boot by restoring a deterministic
- `/etc/hosts`, so CLIs that bind local helper servers such as Google
- Antigravity (`agy`) do not send `localhost` lookups through Capsem DNS.
-- Fixed live VM header model counters so VM-scoped model calls update the
- in-memory metrics snapshot used by `/status`, while host-scoped model calls
- remain excluded from VM accounting.
-- Fixed Settings loading against the Profile V2 `/settings` contract so the UI
- accepts typed `profile_presets`, `effective_rules`, and `settings_profiles`
- responses without requiring the removed legacy settings tree.
-- Fixed Gemini guest setup for Profile V2 sessions: saved Google AI
- credentials now project to `GEMINI_API_KEY`, and non-interactive Gemini
- launches use a real wrapper that defaults to `--yolo` instead of relying on a
- shell alias.
-- Fixed dashboard status polling to retry gateway initialization before
- reporting the service offline, avoiding a stale offline state after
- start/install races when the gateway is actually healthy.
-- Fixed dashboard connected-state polling to confirm `/status` before showing
- the service offline after a transient gateway health miss.
-- Fixed human `capsem status` output to summarize profile assets compactly and
- move profile provenance into a trailing block instead of dumping every asset
- URL and hash inline.
-- Fixed the local install harness to restore the packaged `capsem-admin`
- wrapper and Python payload when repairing or simulating an installed layout.
-- Fixed frontend gateway API calls to refresh the localhost auth token and
- retry once after a 401, preventing the onboarding Profile step from blocking
- on stale gateway credentials.
-- Fixed onboarding provider credentials for the Profile V2 cutover: detected
- service credentials now show as configured, and manually entered keys are
- saved as Profile V2 credential IDs instead of legacy settings keys.
-- Fixed the final onboarding screen to use session/profile language and show
- profile cards instead of exposing VM asset readiness internals.
-- Fixed profile listing launchability so `/profiles` and `/profiles/catalog`
- mark profiles without an installed signed catalog revision unusable even
- when their VM asset files are present.
-- Fixed local setup for packaged Profile V2 installs so `capsem run` and
- temporary `capsem shell` can pin profile/package/asset metadata from the
- packaged base profile without generating a duplicate corp profile.
-- Fixed Profile V2 runtime defaults so packaged base profiles emit
- schema-valid profile payload JSON instead of defaulting profile accent colors
- to the service-settings-only `"blue"` value.
-- Fixed the local install simulation to codesign macOS Mach-O binaries with the
- Virtualization entitlement, matching package postinstall behavior so release
- smoke tests do not boot unsigned `capsem-process` binaries.
-- Fixed `just install` so it reruns non-interactive setup after restoring
- preserved settings and syncing assets, preventing local reinstalls from
- undoing package postinstall setup and leaving profile pins incomplete.
-- Fixed `just install` so it no longer restores package-owned `profiles/base`
- or stale profile catalog sidecars over the freshly materialized package
- profiles, preventing VM asset hash drift after initrd repacks.
-- Fixed `just install` so the initrd repack runs inside the recipe and repairs
- the existing local profile metadata before any sudo/package step, keeping the
- installed product coherent even if the user cancels or cannot complete sudo.
-- Fixed `just install` so local installs rebuild the host-arch profile-derived
- VM assets before repacking/syncing them, preventing an old rootfs from
- surviving after base profile package/tool contracts change.
-- Fixed ARM64 guest kernel configuration to use a 48-bit userspace virtual
- address layout, so TCMalloc-based Linux ARM64 CLIs such as Google
- Antigravity (`agy`) can run inside Capsem VMs instead of crashing during
- startup.
-- Fixed the local install simulator to tolerate repo `assets/` being the same
- filesystem tree as `~/.capsem/assets`, avoiding same-file copy failures while
- repairing a dev install.
-- Fixed the macOS package postinstall hook so it waits for the service socket
- and gateway health endpoint before opening the desktop app, preventing the UI
- from launching into a stale offline screen during install.
-- Fixed package postinstall hooks to fail loudly when no target user can be
- determined for per-user setup instead of leaving a package that requires
- manual `capsem setup`.
-- Fixed Profile V2 HTTP write enforcement so derived `http.read` and
- `http.write` rules compile into guarded runtime CEL, preserve rule priority,
- let runtime overlays override profile defaults, and resolve profile `ask`
- decisions as allow/pass until S15 ships interactive confirm resolution.
-- Fixed in-guest doctor diagnostics to treat positive MCP network probes as
- conditional on the selected profile while still requiring write requests to
- be blocked when `CAPSEM_WEB_ALLOW_WRITE=0`.
-- Cleared the local Docker/Colima initrd packaging caveat after restoring the
- half-running Colima VM and proving `just _pack-initrd` with Docker
- cross-compilation, initrd repack, hash-named assets, and manifest signature
- verification.
-- Updated developer skills to require a Colima stop/start recovery attempt
- before reporting macOS Docker-backed asset builds as blocked.
-
-### Changed
-- Changed default VM sizing to the agent-friendly `4 CPU / 8 GB RAM / 8 active
- VMs` baseline across Profile V2 base profiles, builder defaults, service
- admission defaults, onboarding, and the create-session override UI, and
- removed stale onboarding resource selectors that no longer write through
- Profile V2.
-- Bumped the active release line and default stamping recipe from `1.1` to
- `1.2` for the Profile V2/bedrock engine release.
-- Expanded human `capsem profile show` and `capsem profile resolve` output with
- package, tool, MCP, VM sizing, and VM asset contract summaries.
-- Changed `capsem create`, `capsem resume`, and `capsem restart` to preserve
- typed Profile V2 provision metadata and print profile id/revision/status,
- package contract hashes, pinned VM asset hashes, and asset-health progress
- without changing the first-line VM id output.
-- Changed `capsem info ` to preserve and render Profile V2 VM pins,
- including profile payload hash, package contract hash, and pinned
- kernel/initrd/rootfs hashes.
-- Changed the onboarding wizard to select Profile V2 profiles through the
- profile catalog/select routes and to show profile identity in the ready
- summary instead of the old security-preset wording.
-- Changed frontend VM launch to refresh selected-profile asset status at first
- launch and show a modal download/progress state instead of silently blocking
- creation while assets are checking or downloading.
-- Changed profile catalog/status surfaces to report VM asset readiness per
- profile, including missing local paths, so one broken profile cannot hide or
- block usable profiles.
-- Changed the frontend profile catalog and launch flows to refuse profiles
- whose VM assets are missing or invalid while still showing the missing asset
- path needed to repair the profile.
-
-### Added
-- Added Google Antigravity CLI (`agy`) to the Profile V2 guest tool contract:
- base profiles declare the official `https://antigravity.google/cli/install.sh`
- curl install, `capsem-admin` schemas model it as typed `packages.curl_installs`,
- and image-workspace/rootfs generation materializes and verifies it as a
- required guest tool.
-- Added `capsem mcp list` and `capsem mcp show` aliases for the Profile V2 MCP
- connector inspection path.
-- Added typed Profile V2 document CLI coverage for `capsem profile create
- --file` and `capsem profile update --file`.
-- Added `capsem confirm list` to expose the current disabled S15 ask/confirm
- resolver state through the CLI.
-- Added typed Profile V2 mutation CLI coverage for `capsem profile fork` and
- `capsem profile delete`.
-- Added read-only Profile V2 CLI inspection with `capsem profile list`,
- `capsem profile show`, and `capsem profile resolve`.
-- Added `capsem skills list/show/add/delete` for Profile V2 skill inspection
- and direct user-profile skill mutations through the service `/skills` routes.
-- Added broader `capsem enforcement` and `capsem detection` CLI coverage for
- runtime rule compile, update, file-backed backtest, and detection hunt flows.
-- Added the first `capsem-file-engine` crate so file activity normalization has
- a first-class Bedrock Engine boundary outside `capsem-core`.
-- Added the first `capsem-process-engine` crate so process exec normalization,
- command classification, and inline process Security Engine evaluation have a
- first-class Bedrock Engine boundary outside `capsem-core`.
-- Added the first `capsem-network-engine` crate and moved domain/HTTP network
- policy primitives out of `capsem-core`, with process runtime and builtin MCP
- tooling consuming the new boundary directly.
-- Moved the DNS wire parser and adversarial fixture/property tests into
- `capsem-network-engine`, with DNS handler, process dispatch, examples, and
- fuzz targets consuming the Network Engine parser directly.
-- Moved DNS transport result and DNS SecurityEvent projection into
- `capsem-network-engine`, so DNS runtime blocks, resolved-event rows, and
- legacy `dns_events` projection share the Network Engine boundary.
-- Added Network Engine-owned HTTP SecurityEvent projection, with MITM telemetry
- adapting request/response stats into a typed `HttpSecurityEventInput` instead
- of constructing HTTP subjects directly inside `capsem-core`.
-- Added Network Engine-owned MCP SecurityEvent projection, with framed MCP
- dispatch adapting JSON-RPC summaries into a typed `McpSecurityEventInput`
- before runtime CEL evaluation and resolved-event journaling.
-- Moved the SSE wire parser and parser tests into `capsem-network-engine`, so
- AI/model stream parsing now starts at the Network Engine boundary instead of
- the old `capsem-core::net::parsers` path.
-- Moved provider-neutral AI stream events, summaries, provider identity, and
- non-streaming usage parsing into `capsem-network-engine`, leaving
- `capsem-core` to own only MITM provider routing and key injection.
-- Moved typed AI request parsing for Anthropic, OpenAI, and Google/Gemini into
- `capsem-network-engine`, including tool-result extraction and malformed-body
- fallback tests.
-- Moved canonical AI interaction evidence projection into
- `capsem-network-engine`, so model request/response/tool-call/tool-result
- evidence is built at the Network Engine boundary before core telemetry
- persistence.
-- Added Network Engine-owned model SecurityEvent projection, and switched
- session-backed detection hunt reconstruction to build model events through
- that boundary instead of constructing model subjects inside the service.
-- Added persisted runtime enforcement/detection overlay recovery: service
- runtime rule mutations now atomically write a typed
- `capsem.runtime-security-rules.v1` store, and startup recompiles the saved
- overlays back into the CEL registries while failing closed on invalid rules.
-- Disabled runtime `ask` overlays until the S15 confirm prompter lands, so
- enforcement validate/compile/install/backtest and persisted restore fail
- closed instead of exposing an approval workflow with no resolver.
-- Added runtime Security Engine health to `/debug/report`, including the
- persisted runtime-rule store path, enforcement/detection registry counts,
- match counters, rule attribution, and the current confirm resolver state.
-- Added runtime Security Engine health to `capsem status`: JSON status now
- carries the typed security summary from `/debug/report`, and text status
- shows compact enforcement/detection rule and match counts.
-- Added a resolved Security Event summary to `capsem logs`, so session logs show
- event, block, detection, family, and rule counts before the raw structured
- security-event JSON lines.
-- Added a Settings -> Policy Security Engine health panel that renders typed
- `/debug/report` runtime enforcement/detection counts, match totals, runtime
- rule-store state, and confirm resolver availability.
-- Added a Settings -> Profiles catalog panel that renders typed profile
- catalog revisions, current/installed drift, and the canonical
- `active`/`deprecated`/`revoked` lifecycle states.
-- Added profile selection through `POST /profiles/{id}/select` and surfaced the
- selected/default profile in the Settings -> Profiles UI.
-- Added profile-backed VM create requests in the frontend quick-session and
- customize-session flows, forwarding service-reported profile id/revision and
- showing the active profile in the create dialog.
-- Added VM profile identity and lifecycle status to the frontend session list,
- including a corrupted marker when a VM lacks an explicit profile pin.
-- Added a profile asset readiness panel to the frontend Sessions screen,
- showing the active profile revision, architecture, payload hash, and
- per-asset source/hash/size provenance from `/status`.
-- Added runtime rule backtesting to the Settings -> Policy Live Rules editor,
- posting draft enforcement/detection rules with a JSON event corpus and
- rendering deduplicated evidence rows from the service backtest result.
-- Added session detection hunting to the Settings -> Policy Live Rules editor,
- letting operators run a draft detection rule against a specific session via
- `/sessions/{id}/detection/hunt` and inspect the returned evidence rows.
-- Added the first S08d Security Engine Criterion benchmark harness for
- canonical CEL compile/evaluate, policy-context materialization, 100-rule
- last-match evaluation, and native HTTP lookup comparison.
-- Added the first committed Security Engine CEL microbenchmark artifact under
- `benchmarks/security-engine/` and surfaced the host-side numbers in the
- benchmark results docs with explicit non-VM-originated caveats.
-- Added the first VM-originated Security Engine benchmark for process
- enforcement: a serial live-service/VM test installs a runtime CEL block rule,
- measures repeated blocked exec decisions, verifies runtime match counters,
- `session.db` resolved-event rows, and `logs` attribution, and archives the
- result under `benchmarks/security-engine/`.
-- Expanded the Security Engine Criterion benchmark artifact with runtime
- detection evaluation, backtest evidence deduplication, and runtime rule
- registry operation timings.
-- Wired `just bench` to run the Security Engine Criterion microbenchmarks and
- VM-originated process-enforcement benchmark alongside the existing in-VM and
- lifecycle/fork benchmark stages.
-- Added a VM-originated HTTP request enforcement benchmark that blocks a
- guest HTTPS request through the MITM/Security Engine path, verifies runtime
- counters, `session.db` security rows, and `logs` attribution, and archives a
- dedicated security-engine benchmark artifact.
-- Refined the HTTP request enforcement benchmark to separate guest wall-clock
- latency from curl `time_starttransfer`, with a warmup request so cold
- proxy/TLS setup does not masquerade as Security Engine cost.
-- Added curl phase timing deltas to the HTTP request enforcement benchmark so
- DNS, TCP connect, TLS appconnect, post-pretransfer first byte, and response
- tail costs are visible in the committed artifact.
-- Added a persistent TLS keep-alive lane to the VM-originated HTTP enforcement
- benchmark so repeated in-connection block decisions prove sub-millisecond
- MITM/Security Engine response timing and one security log row per request.
-- Added Security Engine benchmark coverage for runtime compiled-plan rebuilds
- and Detection IR parse/lowering/compile costs, with committed artifacts and
- `just bench` wiring for the `capsem-core` security-pack Criterion harness.
-- Added runtime CEL enforcement on the DNS proxy path plus a VM-originated DNS
- request benchmark that blocks guest resolver lookups before upstream
- resolution, verifies `dns_events`, `security_events`, runtime counters, and
- `capsem logs` qname attribution, and archives a dedicated benchmark artifact.
-- Added runtime CEL enforcement on the framed MCP endpoint plus a VM-originated
- MCP request benchmark that blocks guest `local__echo` tool calls, verifies
- `mcp_calls`, canonical `security_events`, runtime counters, and `capsem logs`
- server/tool attribution, and archives a dedicated benchmark artifact.
-- Expanded `capsem logs` security-event projection with family-specific debug
- fields such as DNS qname, HTTP host/path, MCP server/tool, model provider/
- name, file path, and process operation/class.
-- Added the internal "Ledger of the Realm" engineering-quality reference and
- linked the active S08b/canonical-AI-evidence sprint docs to its Lannister,
- Winterfell, Baratheon, and Iron-Bank standards.
-- Added the S08 canonical AI interaction evidence side-sprint so model/MCP
- policy, detection, telemetry, timeline, quotas, and plugin work have a
- provider-neutral substrate for OpenAI, Anthropic, and Google/Gemini traffic.
-- Added explicit host-versus-VM AI attribution requirements so future
- service-owned model prompts charge host telemetry/counters instead of VM
- health totals.
-- Added main sprint release holds for host/service AI counters, resolved-event
- attribution, logger accounting owner fields, and tests proving host prompts
- correlated with a VM do not charge VM metrics.
-- Added S08 canonical AI evidence contracts in `capsem-security-engine`,
- including OpenAI/Anthropic/Gemini/host fixtures, host-vs-VM attribution fields
- on security events and quota dimensions, optional model/MCP evidence subjects,
- and tests proving host AI does not charge VM accounting.
-- Added the first `capsem-core` AI evidence adapter so existing OpenAI,
- Anthropic, and Gemini request/stream parser summaries project into canonical
- `ModelInteractionEvidence` with tool-call, tool-result, usage, argument
- status, and host-vs-VM attribution tests.
-- Added normalized session database tables for canonical AI interaction
- evidence so provider/API/model/tool/linkage fields are queryable directly
- instead of being hidden in an opaque JSON blob.
-- Added explicit canonical-AI-evidence enum persistence traits and SQLite
- `CHECK` constraints so session DB evidence rows can only store approved enum
- spellings.
-- Added first canonical AI/MCP execution linkage: framed MCP tool calls now
- link to model-emitted MCP tool calls when trace id and normalized tool name
- agree, updating both queryable evidence rows and the legacy tool-call
- projection.
-- Added security-engine quota/status projection for canonical AI evidence,
- including API family, parse/evidence status, model tool/result/execution
- counts, linked MCP tool-call counts, and MCP execution link identifiers.
-- Closed the canonical AI evidence side sprint with additional fixtures and
- tests for OpenAI Responses, orphan model tool calls, orphan MCP executions,
- and provider unknown-field drift.
-- Added the first S08b `capsem-security-engine` contract crate with normalized
- security events, resolved-event actions, detection findings, quota dimensions,
- and throttle-ready serialization tests.
-- Added the first S08b Security Engine core pipeline shell, ordering
- preprocessors, enforcement, confirm, detection, postprocessors, and resolved
- event construction with fail-closed enforcement errors.
-- Changed Security Engine `ask` decisions without a configured confirm resolver
- to record an applied confirm step and fail closed to a terminal block, so
- inline process decisions do not leave unresolved prompts in logs or jobs.
-- Added a real CEL-backed S08b enforcement evaluator in `capsem-security-engine`
- so enforcement rules compile through the `cel` crate before install and
- evaluate against normalized `SecurityEvent` values at runtime.
-- Added a real CEL-backed S08b detection evaluator so runtime detection rules
- produce typed findings on normalized `SecurityEvent` values before resolved
- event emission.
-- Added lowering from `capsem.detection.ir.v1` into real CEL runtime detection
- rules, with explicit family/field allowlists so unsupported Sigma-derived
- paths fail closed before runtime install.
-- Added Security Engine match-stat recording hooks so enforcement and detection
- matches update the runtime rule registry counters that future service stats
- routes will expose.
-- Added first service-owned runtime `/enforcement/*` and `/detection/*`
- handlers for validate/compile, live add/update/delete/list, and stats backed
- by real CEL compilation and compile-first registry installs.
-- Added deterministic priority ordering to runtime enforcement/detection
- registries and seeded the default effective profile's enforcement rules into
- the service runtime registry at startup, with profile/user/corp attribution
- and typed callback guards around profile CEL conditions; profile-scoped rules
- are kept out of the global runtime-rule broadcast snapshot.
-- Added service-owned runtime enforcement and detection backtest handlers that
- evaluate candidate CEL rules against typed normalized `SecurityEvent` inputs
- and return the shared deduplicated `BacktestResult` shape.
-- Added the first service-owned detection hunt handler for running multiple
- candidate detection rules over a supplied normalized event corpus.
-- Added the first session-backed detection hunt golden path:
- `/sessions/{id}/detection/hunt` reads a hand-built canonical session DB
- corpus, reconstructs HTTP security events from structured journal/projection
- rows, verifies the reconstructed event projects iso-style into
- `capsem_proto::PolicyContext`, and runs real CEL detection rules against
- paths/hosts from the DB.
-- Extended session-backed detection hunt reconstruction beyond HTTP so
- canonical `security_events` rows can join existing DNS, MCP, model, file,
- process, and snapshot projections into typed `SecurityEvent` values for CEL
- backtest/hunt rules, with common-row reconstruction for VM, profile, and
- conversation events.
-- Added canonical AI evidence reconstruction for session-backed detection hunt:
- model events now prefer `ai_model_interactions` for provider/API family,
- stream, usage, and cost fields, while MCP events attach
- `ai_mcp_execution_evidence` for argument/result status.
-- Added raw file path policy projection for normalized file security events,
- so CEL and Detection IR rules can target `file.activity.path` separately from
- classified `file.activity.path_class`.
-- Added canonical `security_events` output to `capsem logs`, so resolved
- Security Engine decisions from `session.db` are visible as structured JSONL
- with VM/profile/user/rule/finding attribution alongside process and serial
- logs.
-- Added canonical security-log support to the MCP VM log tool's grep/tail
- filtering so agent-side debugging sees the same resolved Security Engine
- events as the CLI.
-- Updated HTTP gateway log contract tests and architecture docs so `/logs/{id}`
- is treated as the typed security/process/serial log envelope.
-- Enriched `/timeline/{id}` security rows with canonical resolved-event rule,
- pack, finding-count, VM, profile, user, and accounting-owner attribution so
- timeline debugging no longer has to jump straight to SQL for those fields.
-- Updated MCP tool metadata and usage docs so `capsem_vm_logs` and
- `capsem_timeline` advertise security-log and security-layer support.
-- Changed runtime enforcement/detection backtest evidence rows to report
- canonical enforcement paths such as `http.request.host` instead of an opaque
- whole-subject blob.
-- Expanded enforcement/detection backtest evidence rows with common
- attribution, HTTP headers/body, MCP request/response/link evidence, and model
- tool-call/tool-result paths so forensic hunts explain the fields rules
- matched.
-- Added HTTP gateway contract coverage for runtime enforcement validation and
- session detection hunt routes so the security API preserves forensic matched
- fields through the gateway.
-- Expanded HTTP gateway contract coverage across the S08b enforcement and
- detection route groups, including compile, backtest, list, stats, live
- create/update/delete, inline hunt, and session hunt passthrough.
-- Improved `capsem detection hunt-session` human output to show matched event
- ids, rules, packs, outcomes, and canonical evidence fields instead of counts
- only.
-- Added typed model tool-call policy projection under
- `model.request.tool_calls`, including name, origin, argument status, status,
- linked MCP call id, and parse confidence, with session-backed detection hunt
- reconstruction from `ai_model_tool_calls`.
-- Added typed model tool-result policy projection under
- `model.response.tool_results`, including content kind, previews, error
- status, returned-to-model state, linked MCP call id, and parse confidence,
- with session-backed detection hunt reconstruction from
- `ai_model_tool_results`.
-- Added a session policy-context export path:
- `GET /sessions/{id}/policy-contexts` and
- `capsem export-policy-contexts ` emit JSONL fixtures from
- `session.db` for admin/runtime corpus work, with live VM proof for blocked
- process enforcement.
-- Added the first committed session-export policy-context fixture and matching
- process enforcement pack/expected report so admin offline backtest and Rust
- CEL parity both cover a real `process.exec` block shape.
-- Added typed process operation and command-class columns to the canonical
- `security_events` ledger so blocked process decisions preserve policy
- evidence even when no downstream exec projection exists.
-- Added a typed frontend API client surface for runtime enforcement and
- detection routes, including validate/compile/install/delete/list/stats,
- backtest, live hunt, and session-backed detection hunt calls.
-- Added a Policy settings "Live Rules" UI for runtime enforcement and detection
- overlays, including rule priority, attribution, match counts, validation,
- install, and guarded runtime-only delete actions.
-- Added the first S08c shared policy-context/CEL corpus fixtures, with Python
- Pydantic loading and Rust CEL parity coverage over canonical
- `http.request.*` roots plus rejected `event.subject.*` authoring.
-- Added `capsem-admin detection backtest` for offline pySigma-backed detection
- checks against typed policy-context fixture JSONL.
-- Added `capsem-admin enforcement backtest` for offline enforcement checks against
- typed policy-context fixture JSONL, with golden expected-result artifacts for
- the first shared S08c corpus.
-- Added Rust S08c parity coverage proving the real CEL evaluator matches the
- committed admin enforcement backtest expected artifact.
-- Added a committed Detection IR artifact for the S08c Sigma corpus and Rust
- parity coverage proving canonical `http.request.*` detection fields match
- the admin detection backtest expected artifact.
-- Added `capsem-admin enforcement compile` to fail closed on unsupported or legacy
- enforcement roots before offline backtest.
-- Added an explicit admin policy path allowlist so `capsem-admin enforcement compile`
- rejects unknown canonical-looking paths and cross-family policy roots before
- offline replay.
-- Fixed `capsem-admin enforcement backtest` to compile-check enforcement packs before
- fixture replay, so an empty corpus cannot report success for invalid policy
- paths.
-- Added an S08c drift test proving the committed Sigma-derived Detection IR
- artifact exactly matches current `capsem-admin` compiler output before Rust
- consumes it.
-- Extended the real process-enforcement E2E so a VM-originated blocked exec is
- verified in both `capsem logs` and the resolved-event `session.db`
- `security_events` / `security_event_steps` journal.
-- Expanded the admin policy-context model and offline enforcement backtest subset
- beyond HTTP so DNS/MCP/model/file/process/profile scalar roots, boolean
- equality, and numeric equality can be tested through `capsem-admin`.
-- Added indexed model tool-call/tool-result enforcement paths to admin backtest so
- rules can match roots such as `model.request.tool_calls[0].name` and
- `model.response.tool_results[0].returned_to_model`.
-- Added rule-corpus workflow documentation tying policy-context fixtures,
- enforcement/detection expected artifacts, admin commands, and Rust parity
- tests together.
-- Expanded the S08c policy-context corpus with detection-only and
- auth-without-secret HTTP rows so enforcement and detection parity tests cover
- divergent outcomes.
-- Added a session-backed detection hunt expected artifact for the hand-built
- `session.db` corpus, pinning matched fields and evidence signatures from the
- resolved-event journal path.
-- Added session-backed detection hunt projection coverage for DNS, MCP, model,
- file, process, snapshot, VM, profile, and conversation rows, including
- canonical profile activity matched fields.
-- Added CLI runtime security commands for enforcement and detection rule
- list/stats/validate/install/delete plus session-backed detection hunt.
-- Added typed runtime rule definitions to the rule registry and service/API
- responses so installed enforcement/detection rules can be rebuilt into live
- Security Engine CEL evaluators without losing decision, severity, Sigma, or
- tag metadata.
-- Added a service-side runtime Security Engine builder that evaluates installed
- enforcement and detection registries together and records live match counts
- back to the correct registry.
-- Added `security_decisions` to session DB triage so normalized
- `security_events` decisions and failed steps surface alongside network, DNS,
- MCP, exec, and audit signals.
-- Added production MITM telemetry dual-write for canonical resolved HTTP
- `security_events` while preserving the existing `net_events` projection, so
- Network Engine traffic now starts entering the S08b normalized event journal.
-- Added inline Network Engine enforcement for HTTP requests: `capsem-process`
- now builds a CEL-backed runtime Security Engine from effective profile HTTP
- rules, MITM evaluates normalized `http.request` events before upstream
- dispatch, and blocked requests journal both `net_events` and canonical
- `security_events`.
-- Added request-body-aware inline HTTP enforcement: when a runtime Security
- Engine is installed, MITM now buffers bounded request bodies before upstream
- dispatch so `http.request.body.text` CEL rules can block without touching the
- network, while preserving the forwarded bytes and telemetry body preview.
-- Added response-body-aware inline HTTP enforcement: when a runtime Security
- Engine is installed, MITM can evaluate decoded `http.response.body.text`
- before guest delivery and synthesize a 403 without leaking the upstream body.
-- Changed MITM security-event telemetry to persist the actual runtime
- `SecurityResult` when inline enforcement runs, preserving response-phase
- event types, rule ids, findings, and resolved steps instead of rebuilding a
- request-shaped event from `NetEvent`.
-- Changed MITM runtime telemetry to persist every resolved request/response
- phase result for a transaction, so an allowed request event is not overwritten
- by a later response-phase block or finding.
-- Added canonical MCP Security Engine journaling for framed MCP tool calls so
- allowed and blocked MCP requests write `security_events` alongside the
- existing `mcp_calls` projection.
-- Added canonical DNS Security Engine journaling so DNS handler results write
- `security_events` alongside the existing `dns_events` projection.
-- Added canonical file Security Engine journaling so file monitor and MCP file
- restore/delete events write `security_events` alongside `fs_events`.
-- Added canonical process Security Engine journaling so exec dispatch writes
- typed observe-only `process.exec` events alongside `exec_events`.
-- Added inline Process Engine enforcement for exec dispatch: `process.exec`
- events now evaluate through the runtime Security Engine before guest
- delivery, blocked exec calls resolve the pending IPC job with an error, and
- the canonical resolved event records the final decision.
-- Added shared Process Engine command classification for session-backed
- detection hunt reconstruction, so historical `process.exec` events use the
- same canonical classes such as `shell`, `python`, and `network` as live exec
- enforcement.
-- Added Process Engine runtime rule match stats coverage and subsystem-neutral
- fail-closed wording for runtime Security Engine compile failures.
-- Added structured Process Engine decision logging for exec evaluation so
- `capsem logs ` includes event ids, attribution, final action, rule/pack,
- reason, and process command class alongside the session database trail.
-- Added JSON serialization coverage for Process Engine decision logs so the
- `security.process` fields that power `capsem logs` remain queryable.
-- Added service log endpoint coverage proving structured process security
- decision lines are returned verbatim with VM/profile/user/rule attribution.
-- Added testable `capsem logs` formatting so structured process security lines
- survive CLI tailing, and taught shell IPC handling to ignore runtime rule
- match-drain replies.
-- Added a real VM e2e for runtime process enforcement: install a shell-blocking
- rule, prove `capsem exec` is blocked, and prove `capsem logs` shows the
- structured `security.process` decision with VM/profile/rule attribution.
-- Fixed stale profile-asset test fixtures and child process log filters so
- old `request.*` policy roots no longer fail closed during boot and
- `security.process` lines are not filtered out of `process.log`.
-- Added live VM status security metrics from the canonical resolved-event
- stream, including security event counts, block counts, detection counts,
- latest block, and latest detection surfaced through process metrics snapshots
- and service list/info responses.
-- Added live VM status counters for canonical HTTP, DNS, model, MCP, file, and
- process security events, with host-attributed model events excluded from VM
- token/cost accounting.
-- Added session database seeding for live VM status metrics so resumed
- persistent VM processes start from durable HTTP, DNS, model, MCP, file,
- process, security, block, and detection counters before adding new live
- canonical events.
-- Added live profile-policy reload for the Network Engine runtime Security
- Engine: `capsem-process` now shares a swappable engine slot with MITM, so
- `ReloadConfig` can replace profile-derived HTTP enforcement without
- rebuilding the proxy config or restarting the VM process.
-- Added typed runtime enforcement/detection rule snapshots to process IPC so
- service-owned `/enforcement/*` and `/detection/*` mutations can push live CEL
- rule state into already-running VM processes and report per-session
- propagation status.
-- Added process-to-service runtime rule match draining so live VM enforcement
- and detection matches are folded back into service `/enforcement/stats` and
- `/detection/stats` without relying on stale service-local counters.
-- Added VM/session/profile/user identity propagation into Network Engine
- security events and canonical AI evidence, including `CAPSEM_SESSION_ID` and
- `CAPSEM_PROFILE_REVISION` handoff through `capsem-process` and the MCP
- aggregator child environment.
-- Fixed local setup-generated profile payloads to include the required UI mode
- when installing a local profile revision from `CAPSEM_ASSETS_DIR`.
-- Added the shared `capsem-proto` policy context schema that future CEL and
- high-level DSL rules mirror, with versioned typed roots for common, HTTP,
- DNS, MCP, model, file, process, and profile activity.
-- Added canonical policy-context CEL evaluation in `capsem-security-engine`, so
- runtime enforcement/detection rules now use roots such as
- `http.request.host` and reject internal `event.*` paths.
-- Added all-family CEL match/pass smoke coverage for the policy context,
- covering dedicated DNS, HTTP, MCP, model, file, process, and profile roots
- plus common-root coverage for credential, VM, conversation, and snapshot
- security events.
-- Added typed HTTP request policy projection for canonical CEL rules, including
- request URL/path, case-insensitive headers, and body text predicates such as
- `http.request.body.text.contains("secret")`.
-- Added Rust Detection IR evaluation against the new S08b normalized
- `SecurityEvent` contract so Sigma-derived findings can run on the shared
- event model instead of a parallel fixture-only shape.
-- Added S08b event identity fields for parent event, stream, activity, sequence,
- source engine, and enforceability so later engine wiring has the correlation
- data needed for timeline, telemetry, and quota work.
-- Added S08b security-event schema versions, enforcement/detection pack identity
- fields, and JSON fixtures covering every normalized event family plus resolved
- event findings.
-- Added the first S08b resolved-event emitter contract with required versus
- best-effort sink semantics, delivery bookkeeping, and shared event/finding id
- tests.
-- Added the first structured resolved-event session ledger:
- `security_events`, `security_event_steps`, `detection_findings`,
- `detection_finding_tags`, and `security_event_links`, with
- `WriteOp::ResolvedSecurityEvent` persistence, canonical enum spelling checks,
- session-schema tooling coverage, and a `/timeline/{id}` `security` layer.
-- Added S08b backtest result shaping with full event refs, mismatch outcomes,
- default 100-row match limits, and evidence-signature deduplication.
-- Added the first S08b runtime rule registry contract with compile-first
- add/update, previous-plan preservation on compile failure, delete, and live
- match stats.
-- Added S08b plugin-groundwork event semantics: first-class ask/block/rewrite/
- throttle decisions, labels/context/history snapshots, findings, declarative
- mutations, mutation target validation, and internal transport projection.
-- Added deterministic S08b plugin transform validation with canonical event
- hashes, immutable core event enforcement, and prior label/finding/mutation
- preservation.
-- Updated S08b security-event JSON fixtures to include plugin-facing context,
- trace labels, decisions, findings, and declarative mutations.
-- Added plugin transform records to resolved security events so replay/audit can
- tie plugin identity to input/output event hashes.
-- Added a deferred S22 rate-limit, budget, and quota sprint while keeping S13
- scoped to remote enforcement/observer plumbing and reserving S08/S12
- compatibility points for future throttle decisions.
-- Added explicit S12 planning for authoritative in-memory running-VM status with
- enforcement/detection counters, latest detection, latest block, and shared
- `/metrics/json` plus Prometheus scrape sources.
-- Added typed `capsem-admin doctor` output that checks admin toolchain
- readiness and optional Profile V2 image-plan derivation without using
- `guest/config` as the operator-facing source of truth.
-- Added bootstrap-managed shared skill symlinks for Claude Code, Gemini CLI,
- Codex, and Cursor.
-- Added the first S08 Profile V2 HTTP gateway contract coverage for profile
- catalog/revision routes, profile CRUD/resolve, skills, standard MCP servers,
- rules/evaluate, confirm-pending reads, profile-selected VM create response
- pins, and gateway `/status` profile/asset provenance.
-- Added S08 gateway coverage for Profile V2 `/setup/assets` download progress,
- `/debug/report` profile asset provenance, exact service typed-error
- passthrough, and service debug-report diagnostics for stale or mismatched
- gateway runtime files.
-- Added S08 live HTTP gateway coverage for selected-profile VM creation: real
- service/gateway processes now prove `/provision` accepts profile id/revision,
- reconciles the selected profile's verified VM assets before boot, execs
- through the gateway, and echoes the pinned profile state through
- `/info/{vm_id}`.
-- Added S08 adversarial HTTP gateway coverage proving Profile V2 typed-error
- status/body passthrough for malformed profile creation, locked
- skill/MCP/rule mutations, invalid rule evaluation, asset cleanup while
- updating, and revoked profile revision install.
-- Added regroup sprint specs for service-settings schema/admin parity and the
- policy-rule versus detection/Sigma architecture decision before CLI,
- telemetry, plugins, rule UI, and Confirm UX continue.
-- Added `capsem-admin detection compile|check` with pySigma-backed Sigma
- parsing, typed `capsem.detection.ir.v1` output, JSONL normalized-event
- fixture checks, and fail-closed unsupported Sigma subset coverage.
-- Added Rust Detection IR V1 schema/serde/evaluator parity fixtures so
- `capsem-core` consumes the same `capsem.detection.ir.v1` artifact emitted by
- `capsem-admin detection compile`.
-- Added corp-facing admin CLI, enforcement, and detection-format docs covering
- PyPI install, developer editable usage, pySigma validation, Detection IR, and
- policy/detection command proofs.
-- Added Profile V2 settings/profile provenance to the redacted service debug
- report, including selected profile, profile roots, effective VM summary,
- resolver trace summary, and credential-id-only reporting.
-- Added Profile V2 service-settings runtime wiring for service asset locations,
- default VM sizing, and per-session `vm-effective-settings` plus resolver
- trace attachments.
-- Added capsem-process consumption of session-attached Profile V2 effective
- settings for network defaults, MCP defaults, and Policy V2 runtime rules.
-- Added framed MCP Policy V2 `ask` confirmation resolution through the shared
- confirmer/backoff contract before request dispatch and response surfacing,
- with redacted confirmation snapshots.
-- Added HTTP Policy V2 `ask` confirmation resolution through the same
- confirmer/backoff contract before upstream request dispatch or guest response
- surfacing.
-- Added model Policy V2 `ask` confirmation resolution through the shared
- confirmer/backoff contract before model request dispatch, model response
- surfacing, and tool-call/tool-response delivery, with redacted metadata-only
- confirmation snapshots.
-- Added model Policy V2 `model.request` body rewrite support for
- `request.data` rules, forwarding only the rewritten bytes upstream and
- recording rewritten request previews in telemetry.
-- Added a `net::policy_v2` runtime import surface plus CEL, gzip model-response,
- and builder config/defaults tests to keep Profile V2 policy enforcement and
- image-generated settings aligned.
-- Added hardening coverage for HTTP gzip decompression, CEL quoted-literal
- parsing, and builder image/defaults alignment.
-- Added guard coverage to keep generated builder/frontend settings fixtures from
- being treated as Profile V2 runtime authority.
-- Added the first S07 UDS foundation: typed VM metrics snapshot structs plus
- service/process IPC request and response variants for live metrics.
-- Added read-only Profile V2 UDS profile routes for listing profiles, fetching
- a profile record, and resolving VM-effective settings with resolver trace.
-- Added Profile V2 UDS profile mutation routes for creating, forking, updating,
- and deleting user-owned profiles.
-- Added Profile V2 UDS rules routes for listing resolved rules, fetching a
- rule with provenance, and dry-running V2 policy evaluation against synthetic
- subjects without enforcing or prompting.
-- Added Profile V2 UDS rule mutation routes for creating user-authored rules
- and deleting direct user rules, including default built-in profile override
- materialization, duplicate-rule rejection, and locked-rule delete failures.
-- Added chained functional and bounded performance coverage for the Profile V2
- UDS Rules API before mirroring it through the HTTP gateway.
-- Added Profile V2 service tests proving profile creation cannot shadow locked
- profile roots and settings saves follow the currently selected user profile.
-- Added the S07 UDS closeout surface: typed `GET /confirm/pending`, Profile V2
- `GET /skills` / `POST /skills` / `DELETE /skills/{id}`, locked/duplicate
- skills mutation coverage including inherited same-kind duplicates, and a
- chained profile/skills/MCP/rules route proof.
-- Changed MCP management to use Profile V2 MCP servers: profiles now use the
- standard top-level `mcpServers` map with Capsem governance under
- `mcpServers..capsem`; `/mcp/connectors` now
- lists/adds servers, `/mcp/connectors/{id}` deletes direct user servers,
- and the old `/mcp/{servers,tools,policy}` plus `/mcp/tools/*` service/CLI
- surface, capsem-mcp debug tools, and service-to-process management IPC are
- removed.
-- Added typed Profile V2 package/tool contracts and per-architecture VM asset
- declarations, including canonical BLAKE3 hash validation, path-traversal
- rejection, VM-effective serialization, and inherited resolver merge coverage.
-- Added the formal Profile V2 JSON Schema Draft 2020-12 artifact with valid
- and invalid golden fixtures plus a Rust `jsonschema` validation gate.
-- Added Pydantic v2 Profile V2 payload and manifest models for admin tooling,
- including Pydantic-only JSON validation/dumping helpers, TOML-to-Pydantic
- validation, and the canonical `active`/`deprecated`/`revoked` status enum.
-- Added the first Service Settings V2 admin contract slice: Pydantic v2
- service-settings models, Pydantic-only JSON/TOML validation and dump helpers,
- a committed Draft 2020-12 schema artifact, valid/invalid golden fixtures, and
- Rust/Python fixture parity tests.
-- Added the first `capsem-admin settings` commands: schema export,
- TOML/JSON validation, doctor summaries, typed JSON reports, and focused CLI
- coverage over the Service Settings V2 contract.
-- Added a shared Service Settings V2 defaults fixture checked by both Python
- and Rust, and aligned Python's default user profile roots with the Rust
- `CAPSEM_HOME` / `$HOME/.capsem` path contract.
-- Added `capsem-admin settings init` to emit Pydantic-generated Service
- Settings V2 JSON or TOML drafts with profile-root options, asset cache
- selection, overwrite protection, and validation tests.
-- Documented the Service Settings V2 versus Profile V2 boundary, the
- `capsem-admin settings` validation flow, and the split from the guest/UI
- descriptor schema.
-- Added `capsem-admin profile schema` and `capsem-admin profile validate`
- for Profile V2 JSON/TOML payloads, including typed JSON reports with profile
- id and revision.
-- Added `capsem-admin profile init ` to emit a valid Profile V2
- JSON or TOML draft through the Pydantic model, with all-architecture VM asset
- placeholders, package/tool contract defaults, optional file output, and
- parity tests proving init JSON matches init TOML after reparsing.
-- Added `capsem-admin image plan ` to derive a typed image build plan
- from Profile V2 package/tool/VM asset contracts, with `--arch all` by default,
- single-arch narrowing, and fail-closed missing-asset checks.
-- Added `capsem-admin image verify --assets-dir ` to verify
- profile-declared local kernel/initrd/rootfs assets by architecture, size, and
- BLAKE3 hash, with typed `capsem.image-verification.v1` JSON output and
- non-zero exits on missing or mismatched assets.
-- Added typed `capsem.image-inventory.v1` package/tool inventory checks to
- `capsem-admin image verify --inventory`, comparing apt, Python, node, and
- required guest tool versions against the Profile V2 image plan while
- preserving Pydantic-only JSON input/output.
-- Added rootfs build extraction of `image-inventory.json`, collecting installed
- apt, Python, node, and tool versions from the built container and validating
- the artifact through the same Pydantic model used by `image verify`.
-- Changed `capsem-admin image verify` to auto-discover per-architecture
- `image-inventory.json` files under the asset directory and report inventory
- contract checks by architecture, rejecting ambiguous all-arch single-file
- inventory input.
-- Changed profile image verification to fail closed when any selected
- architecture is missing its `image-inventory.json`, so package/tool contract
- proof is required rather than silently falling back to asset-only checks.
-- Added `capsem-admin image verify --doctor-bundle` support for
- `capsem-doctor --bundle` tar files, parsing the JUnit probe result without
- extracting the archive and failing image verification on in-VM test failures.
-- Added `capsem-admin image sbom` to generate per-architecture SPDX 2.3 guest
- image SBOM JSON from typed `image-inventory.json` artifacts, including
- profile/revision/package-contract identity and package-manager purl refs.
-- Added a profile-backed release-image boot gate that requires host-arch
- `image-inventory.json`, boots the profile image, captures
- `capsem-doctor --bundle`, and verifies the bundle through
- `capsem-admin image verify`; local asset preflight now rebuilds when the
- host-arch image inventory is missing.
-- Documented the S08a policy/detection contract: `capsem.enforcement-pack.v1`,
- `capsem.detection-pack.v1`, `capsem.detection.ir.v1`, normalized security
- event taxonomy, typed findings, admin validation/check commands,
- implementation ordering, and test matrix.
-- Added typed `capsem-admin enforcement validate|schema` and
- `capsem-admin detection validate|schema` support for strict Pydantic policy
- and detection pack envelopes, including YAML detection envelopes, with
- committed JSON Schema artifacts.
-- Added `capsem-admin manifest check --fast` with typed
- `capsem.manifest-check.v1` reports, Pydantic manifest validation, local
- `file://` profile payload hash/id/revision checks, remote HTTP(S) `HEAD`
- checks, and non-zero exits on missing or mismatched profile payloads or
- signatures.
-- Added `capsem-admin manifest check --download` to fetch every
- referenced profile payload, profile signature, VM asset, and VM asset
- signature into a temp or explicit download directory, verifying profile
- payload hashes and profile-declared VM asset sizes and BLAKE3 hashes.
-- Added `capsem-admin manifest generate --profiles ` to produce typed
- Profile V2 catalog manifests from local JSON/TOML profile payloads, deriving
- exact payload hashes, `.minisig` URLs, status/current-revision overrides, and
- file or hosted profile URLs without hand-authored manifest JSON.
-- Added minisign-backed `capsem-admin manifest sign`,
- `manifest verify-signature`, and `manifest check --download --pubkey`
- cryptographic verification for downloaded profile payload and VM asset
- signatures.
-- Added a developer bootstrap proof that `uv sync` exposes the `capsem-admin`
- entrypoint and that `uv run capsem-admin --version` succeeds after Python
- dependencies are installed.
-- Added release package layout proof for `capsem-admin`: macOS `.pkg` and
- Linux `.deb` assembly now require the relocatable admin wrapper plus its
- packaged Python payload, and release policy tests verify the helper is
- prepared before OS packages are built.
-- Added `capsem-admin image build-workspace` to materialize a profile-derived
- build workspace from the Profile V2 package/tool contract, emitting
- `capsem.image-workspace.v1` reports and generated `guest/config`-compatible
- TOML without reading repo hand-authored image settings.
-- Added `capsem-admin image build` as the public profile-derived image build
- entrypoint, routing generated workspaces into the existing kernel/rootfs
- Docker builder with typed `capsem.image-build.v1` JSON reports and dry-run
- support.
-- Added the required Profile V2 `ui` contract (`everyday` or `coding`) across
- Pydantic, JSON Schema, Rust profile parsing/effective settings, fixtures, and
- generated built-in profile drafts.
-- Added `capsem-admin profile init-builtins` to generate typed
- `everyday-work` and `coding` base profiles, plus committed generated base
- profile TOML drafts under `config/profiles/base/`.
-- Changed built-in profile generation to derive package, tool, AI provider,
- MCP server, and VM resource contracts from `guest/config`, preserving the
- current release image inputs while making the profiles the source of truth.
-- Added profile-aware `scripts/build-assets.sh --profile` and Justfile
- `build-assets` / `build-kernel` / `build-rootfs` profile arguments so local
- asset builds can route through `capsem-admin image build`.
-- Changed VM asset build recipes and PR install CI to require a Profile V2
- payload, using `config/profiles/base/coding.profile.toml` by default and
- removing the unprofiled `capsem-builder build guest/` fallback from live
- build lanes.
-- Fixed release SBOM attestation to cover Linux `.deb` packages as well as the
- macOS `.pkg`, and documented that the current `cargo-sbom` artifact is the
- Rust host SBOM while profile-derived guest package/tool SBOMs remain S07b
- image-verification work.
-- Added Profile V2 section-level editability gates so profiles can allow user
- skill or MCP edits while locking AI providers, rules, VM assets, package
- contracts, or other sections; service mutations enforce the locks and forks
- preserve them. The editability map itself is immutable through profile update
- routes to prevent unlock-then-edit bypasses.
-- Changed service settings reload fallback to reuse the startup settings
- snapshot when `service.toml` is absent or unreadable, preventing profile roots
- from silently falling back to defaults.
-- Added Rust Profile V2 payload schema validation helpers for JSON and TOML
- payloads backed by the production Draft 2020-12 schema artifact.
-- Changed the signed profile catalog manifest to the canonical
- `ProfileManifest` / `format = 1` contract, removing the transitional
- generation naming and old asset-manifest compatibility language.
-- Changed VM asset readiness to be profile-driven: service startup now resolves
- boot assets from the selected profile's per-architecture declarations,
- downloads missing assets from profile URLs, and forwards expected hashes to
- `capsem-process` for boot-time verification.
-- Added durable per-session telemetry identity: `session.db` now records the
- VM id, resolved profile id, and local user id, and `/info` exposes those
- fields for support/status flows.
-- Added VM profile pins for persistent/running VM metadata, including resolved
- profile id, signed profile revision, profile payload hash,
- package-contract hash, and pinned boot asset identity.
-- Changed VM profile pins to read the installed profile revision sidecar and
- include the installed profile payload hash when a verified catalog payload is
- present.
-- Added core profile catalog reconciliation so active revisions install/update
- from signed payloads, deprecated installed revisions stay available for
- existing VMs, and revoked installed revisions lose their launchable profile
- plus current state.
-- Added `POST /profiles/catalog/reconcile` on the service API so UDS/gateway
- callers can apply signed profile catalog lifecycle state and receive a typed
- install/deprecate/revoke/error summary.
-- Added `capsem profile reconcile-catalog --manifest --pubkey `
- so the native CLI can apply a signed profile catalog through the service
- reconciler and print either a compact lifecycle summary or raw JSON.
-- Added `capsem profile reconcile-catalog --manifest-url ` so
- operators can reconcile a signed Profile V2 catalog from a remote source,
- with `http://` accepted only for loopback development/test hosts and a
- bounded manifest body.
-- Added typed `[profile_catalog]` service settings plus service-side scheduled
- profile catalog reconciliation from the configured signed catalog URL and
- profile payload public key.
-- Added a read-only profile catalog status surface plus `capsem profile
- catalog [--json]` so operators can inspect the persisted signed catalog,
- installed profile revisions, revision lifecycle status, and configured
- catalog source.
-- Added per-profile catalog revision inspection through
- `GET /profiles/{id}/revisions` and `capsem profile revisions [--json]`,
- including current/installed revision markers and canonical lifecycle status.
-- Added profile revision lifecycle actions through the service and CLI:
- `install`, `update`, and `remove` now operate on signed catalog revisions,
- reject revoked installs, clean revoked installed revisions, and remove local
- launchable state while preserving archived payload material.
-- Changed profile catalog reconciliation to remove launchable installed
- profiles whose profile id is absent from the signed catalog while preserving
- the archived installed payload for retention/VM-pin cleanup.
-- Added profile-aware asset retention sources so cleanup can preserve VM assets
- referenced by installed profile payloads and by persistent VM profile pins.
-- Added `POST /setup/assets/cleanup`, a profile-era asset cleanup endpoint that
- removes unreferenced hash-named/legacy asset files without old manifest
- authority, preserves installed-profile and saved-VM pins, and refuses to run
- while assets are still checking or updating.
-- Added `POST /setup/assets/reconcile` so callers can force the service-owned
- Profile V2 asset reconciler to check/download profile VM assets on demand.
-- Added explicit profile selection for fresh VM create/provision requests and
- `capsem create --profile [--profile-revision]`, with selected profile asset
- reconciliation and VM-effective profile attachment before process spawn.
-- Changed `capsem update --assets` to call the service Profile V2 asset
- reconciler instead of the old asset-manifest downloader.
-- Changed VM profile pinning to require complete installed profile revision
- authority when present, including the runtime profile file, archived verified
- payload, and matching payload hash.
-- Added structured profile asset check/download lifecycle logs with redacted
- asset URLs, plus status propagation for the service asset check timestamp.
-- Added explicit Profile V2 asset provenance to service/CLI asset health,
- including profile id, profile revision, installed profile payload hash, and
- redacted per-asset source/hash metadata in reconcile, list/status, setup
- asset status, and debug-report payloads.
-- Added adversarial coverage proving concurrent profile asset reconciles share
- one download run and asset cleanup refuses while a profile asset download is
- active.
-- Changed first-use VM create/run to await the service Profile V2 asset
- reconciler before process spawn, and made create-from-source, fork, and
- persist derive boot-asset identity from the VM profile pin while rejecting
- pin/registry drift.
-- Added chained service-level coverage proving a profile asset reconcile is
- reflected consistently in `/setup/assets`, `/list`, debug reports, and
- service logs after downloading from a local asset server.
-- Added formal `file://` Profile V2 VM asset reconciliation support plus live
- E2E coverage proving `capsem update --assets` can fill an empty asset cache,
- boot a real VM from the reconciled hash-named assets, exec inside it, and
- preserve the installed profile revision pin in `capsem info --json`.
-- Added a real-VM fork-lineage E2E proof that writes a file, forks, deletes the
- source, resumes the fork, mutates filesystem state, forks again, deletes the
- middle VM, and proves the final fork preserved only the expected descendant
- state.
-- Added current UI baseline screenshots for the marketing-site refresh sprint,
- covering the hero plus the feature, security, how-it-works, and FAQ sections.
-- Changed `capsem update --assets` to honor the selected service UDS socket
- instead of assuming the default runtime socket.
-- Changed the runtime network policy module names from transitional
- `policy_v2`/`policy_v2_*` paths to the forward `policy` and `policy_model`
- surfaces, with DNS/MITM tests split into focused behavior modules.
-- Removed the legacy MITM HTTP policy hook runtime path. Request/response-head
- HTTP enforcement must now move through the S08b canonical Security Engine
- path instead of the old pipeline hook.
-- Removed the remaining legacy named-policy runtime: `net::policy`,
- `policy_confirm`, model-policy helpers, Policy Hook Spec0 API/artifact,
- policy-only DNS/MCP/MITM tests, the old policy benchmark, and the
- `policy_hook_events` session table/write path. HTTP, MCP, DNS, model, file,
- and process policy work now has one forward path: canonical Security Engine
- events.
-- Removed the old Rust VM asset `ManifestV2` model, verified-manifest loaders,
- manifest-driven downloader, and manifest-driven cleanup path. CLI status and
- service debug reports now rely on Profile V2 asset health instead of legacy
- asset manifests, and cleanup removes stale legacy asset metadata files.
-- Changed persistent VM resume to require forward profile pins and pinned asset
- identity; unpinned registry entries no longer fall back to the current
- profile/assets.
-- Changed VM profile pinning to require a signed profile catalog revision,
- profile payload hash, and pinned asset identity before create-from-source,
- fork, or persist can produce durable VM state.
-- Fixed VM forks to preserve VM-effective profile attachments and fail closed
- on profile drift before the fork is registered or executed.
-- Added profile identity and status to VM list/status payloads, `capsem list`,
- and `capsem info`: each VM now reports its pinned profile/revision plus
- `current`, `needs_update`, `deprecated`, `revoked`, `corrupted`, or
- `unknown`.
-- Removed legacy `assets.manifest.*` service settings and setup-time asset
- manifest checks; old asset-only manifests are no longer runtime authority.
-- Changed `/setup/corp-config` inline and URL installs to accept Profile V2
- corp profile TOML and refresh the typed settings-profile surface.
-- Changed guest boot config ownership so `GuestConfig`/`GuestFile` live under
- the VM namespace instead of the legacy policy-config namespace.
-- Removed the legacy `net::policy_config` module, v1 settings-file runtime
- fallbacks, v1 install/setup fixtures, and old `user.toml`/`corp.toml`
- support-bundle/uninstall preservation paths in favor of Profile V2
- `service.toml` and profile roots.
-
-### Changed
-- Renamed the public admin enforcement-pack surface from `capsem-admin policy`
- to `capsem-admin enforcement`, including the Pydantic model/schema ids
- (`capsem.enforcement-pack.v1`, `capsem.enforcement-compile.v1`, and
- `capsem.enforcement-backtest.v1`), committed fixtures, docs, and tests. The
- old `policy` command group is not kept as a public alias.
-
-### Fixed
-- Fixed same-millisecond Security Event ID collisions across HTTP, DNS, MCP,
- and file logging. HTTP now carries a per-request event seed, and DNS/MCP/file
- event IDs use nanosecond timestamps so bursty decisions no longer collapse
- rows in `security_events`.
-- Fixed synthetic HTTP block/error telemetry to enqueue Security Engine
- `net_events` and resolved `security_events` at the decision point instead of
- relying on response-body finalization, preserving fast denied keep-alive
- requests in `session.db` and `capsem logs`.
-- Fixed settings policy-rule saves to reject unsupported `.match(` condition
- terms before writing a user profile override.
-- Fixed HTTP gzip handling so comma-separated `Content-Encoding` token lists are
- recognized case-insensitively and malformed gzip headers with reserved flags
- pass through instead of dropping bytes.
-- Fixed Policy V2 CEL parsing so method-looking text inside quoted string
- literals is not mistaken for `.contains()`/`.matches()` calls.
-- Fixed Policy V2 dry-run/runtime callback coverage for generated `http.read`
- and `http.write` rules, including boolean `true` CEL catch-all conditions.
-- Fixed `POST /profiles` so it rejects ids that already exist in built-in,
- base, corp, or user profile roots instead of writing a shadowing user file.
-- Fixed `just smoke`, `just test`, and `build-ui` ordering so Tauri frontend
- assets are built before Rust workspace compile/clippy/test phases that need
- `frontend/dist`.
-- Fixed isolated smoke/doctor runs to avoid installed gateway-port collisions
- and to skip persistent service-unit checks when a test-scoped service unit is
- intentionally not required.
-- Fixed Profile V2 VM runtime migration compatibility so sessions consume only
- Profile V2 `vm-effective-settings.toml` instead of reopening legacy settings
- files at runtime.
-- Fixed running VM reloads to refresh Profile V2 effective policy from each
- session attachment, including MCP builtin domain policy and Policy V2 rules.
-- Fixed Profile V2 conditional MCP/HTTP rules so narrow argument/path rules no
- longer collapse into broad legacy tool/domain allow-block lists.
-- Fixed default user profile discovery to resolve under `CAPSEM_HOME`/`HOME`
- instead of a literal `./~` directory, keeping local artifacts out of runtime
- and test profile resolution.
-- Fixed install E2E asset handling when the repo `assets/` path is a symlink,
- including file-only asset copying so nested/stale arch directories cannot
- poison install fixture refresh.
-- Fixed the Profile V2 valid-payload minisign fixture so profile catalog
- install/reconcile tests exercise real signature verification with a matching
- test public key.
-- Fixed service test fixtures so profile roots are created consistently and
- asset lifecycle log assertions tolerate equivalent download event ordering.
-- Fixed full smoke stability by closing inherited Python fixture log fds,
- provisioning E2E services with Profile V2 asset homes, separating signed MCP
- VM-lifecycle fixtures from editable profile-mutation fixtures, and running
- VM-heavy service/CLI and MCP smoke groups sequentially to avoid Apple VZ
- cleanup starvation.
-
-## [1.1.1778860037] - 2026-05-15
-
-## [1.1.1778855131] - 2026-05-15
-
-### Added
-- Added a dedicated marketing FAQ page with a hypervisor-vs-container answer
- as the first FAQ.
-- Added `capsem status --json` with a typed `capsem.status.v1` health report
- for install verification and UI/test consumers.
-- Added a Settings -> About debug report action that copies redacted
- version, runtime, and VM asset/initrd fingerprints for GitHub bug reports.
-- Added `capsem debug` and the `capsem.debug.v1` JSON debug report so release
- bugs can include status/doctor readiness issues, setup-state, runtime, asset
- hash, host binary hash, disk-space, install-layout, process-liveness, and
- redacted log-tail evidence from the same `/debug/report` service endpoint
- used by the UI.
-- Added `scripts/capture-install-status.py`, a release verification harness
- helper that captures `capsem status --json` into a structured evidence bundle
- with raw command output, parsed status JSON, metadata, version output, and a
- shallow `CAPSEM_HOME` tree snapshot. The bundle also captures optional
- `capsem debug` output and service/gateway pid, socket, and port breadcrumbs
- while redacting `gateway.token`, plus a focused installed-layout index for
- helper binaries, asset manifests, setup state, the platform service unit, and
- the macOS app bundle path. Saved VM registry and persistent-session summaries
- are captured without leaking saved VM environment variable values.
-- Added a service-owned VM asset supervisor that reports `checking`,
- `updating`, `ready`, and `error` states with progress and retry detail.
-- Added saved-VM base asset dependency tracking so persistent VMs can record the
- rootfs/kernel/initrd hashes, asset version, arch, and guest ABI they require.
-- Added a reusable `.deb` payload verifier and wired release CI to validate
- Linux package helper binaries, signed manifests, and manifest signatures.
-- Added a macOS release CI gate that requires a Developer ID Installer identity
- and runs `pkgutil --check-signature` plus Gatekeeper assessment after
- notarization and stapling.
-- Added `capsem purge --product` for explicit whole-product resets that remove
- runtime files plus durable Capsem state after confirmation.
-- Added an OpenTelemetry metrics handoff for the follow-up sprint, including
- the service/process IPC boundary, the live VM counter source of truth, and
- the split between JSON status surfaces and `/metrics`.
-
-### Changed
-- Changed setup/profile fixture policy roots from legacy `qname` /
- `request.*` conditions to canonical `dns.request.*` and `http.request.*`
- CEL paths.
-- Closed the Profile V2 S07/Post-S06 sprint ledger after reconciling later
- S07c/S07b/S08 proof: remaining confirm, event-journal, UI, debug, telemetry,
- docs, and release-replay work is now assigned to later sprints instead of
- sitting as unowned S07 debt.
-- Changed Profile V2 asset reconciliation logging so the asset supervisor emits
- a `profile_asset_check_finish` lifecycle event for every check path, including
- scheduled/background checks rather than only route-triggered reconciles.
-- Changed `capsem uninstall` to remove the installed runtime while preserving
- durable user state such as config, setup state, assets, logs, session/audit
- data, and persistent VM state.
-- Changed the runtime replacement proof to exercise uninstall plus fresh
- install while preserving user config, persistent VM state, and saved-VM asset
- blobs.
-- Changed `capsem doctor` to preflight through the same typed health checks
- used by `capsem status` before provisioning a diagnostic VM. Status blockers
- now carry stable issue codes and severity before they are rendered.
-- Changed `capsem status` to report missing or non-executable host helper
- binaries as typed health blockers.
-- Changed `capsem status` to report stale `capsem-service` and
- `capsem-process` helper binary versions as typed health blockers.
-- Changed `capsem status` to report stale/missing service units, asset manifest
- problems, and missing/corrupt/incomplete setup state as typed health blockers.
-- Changed `capsem status` to report a missing `/Applications/Capsem.app` as a
- typed health blocker for real installed macOS runtimes.
-- Changed `capsem status` to report stale `capsem-gateway` and `capsem-tray`
- helper binary versions as typed health blockers. Their `--version` paths now
- answer before runtime initialization, so status can check them safely.
-- Changed `capsem status --json` to include a top-level `state` plus grouped
- `checks` for host binaries, service unit, setup, assets, app bundle, service
- endpoint, and gateway readiness.
-- Changed service `/list`, gateway `/status`, and `capsem status --json` to
- preserve the service asset supervisor state instead of collapsing asset work
- into only ready/missing booleans.
-- Changed the tray menu to show asset `checking`/`updating`/`error` states and
- disable New Session until VM assets are ready.
-- Changed asset cleanup, saved-VM resume/fork, service `/list`, gateway
- `/status`, tray status, frontend types, and `capsem status --json` to preserve
- and report saved-VM asset dependencies. Missing saved-VM assets now surface as
- typed `saved_vm_asset_missing` status blockers without blocking new current-
- version VM creation.
-- Hardened `just install` for local release reproduction: it now removes and
- verifies the old runtime while preserving durable state, installs through the
- same native package commands as `install.sh`, captures typed installed
- `capsem status --json` evidence, and fails if service, gateway, status, guest
- DNS, or guest HTTPS checks do not pass.
-- Hardened the Python install-test fixture so local simulated install tests
- build the default host binaries once, then refresh installed helpers when
- they differ from `CAPSEM_BIN_SRC`, not only when missing.
-- Hardened the install-status capture harness with dirty-state evidence for
- missing tray helpers and missing macOS app bundles without mutating
- `/Applications`.
-- Hardened the install-status capture harness to preserve grouped status
- checks in metadata and capture saved-VM asset-reference fields when present,
- including file-state evidence for referenced asset paths.
-- Added black-box simulated install coverage for reinstalling after
- `capsem uninstall` and reinstalling over a corrupted helper binary, both
- gated by `capsem status --json` runtime-layout issue codes.
-- Changed service `/list` to avoid per-VM `session.db` telemetry scans on the
- hot status path. `/info` keeps the historical SQLite enrichment for now,
- while live list metrics are deferred to the OpenTelemetry sprint.
-- Changed the full release gate so benchmark/doctor E2E checks run in the
- serial stage instead of racing the parallel Python shard, keeping the
- expensive VM and benchmark paths deterministic.
-
-### Fixed
-- Fixed first-run CLI auto-launch when `capsem-service` exits before binding
- its socket, so broken installed service binaries return a clear startup
- error instead of waiting through repeated socket timeouts.
-- Fixed the built-in `local` MCP server toggle so
- `mcp.servers.local.enabled = false` persists, stays visible in settings, stops
- injecting or preserving the local stdio bridge in agent configs, and disables
- the runtime built-in server list entry.
-- Fixed the marketing-site installer for the stamped v1.1 package assets:
- macOS now installs the downloaded `.pkg` with the native installer, and
- package downloads are checked against the release manifest when local tools
- are available.
-- Fixed `capsem uninstall --yes` so it no longer recreates
- `~/.capsem/update-check.json` via the background update checker while
- uninstalling.
-- Fixed repeat local installs when stale Tauri app bundles under
- `target/release/bundle/macos/` are not removable by the normal build step.
-- Fixed `.deb` payload verification for zstd-compressed packages without an
- embedded content-size header, matching the published Debian package format.
-- Fixed Linux KVM unit-test compilation issues surfaced by PR CI before the
- site/download installer hardening can merge.
-- Fixed macOS PR CI's clean-checkout Rust unit gate by creating a minimal
- frontend dist before `capsem-app`'s Tauri test build runs.
-- Fixed macOS PR CI codesigning races during `nextest` discovery by
- serializing the ad-hoc signing runner and preserving its build log on
- workflow failures.
-- Fixed PR install E2E's clean-checkout host setup so missing VM assets can be
- built with `uv`, checked through pnpm-backed doctor paths, and signed with
- `minisign`.
-- Fixed PR CI coverage drift by aligning the workflow's Rust coverage floor
- with the documented `just test` gate.
-- Fixed clean-checkout install E2E asset alias creation by copying hash-named
- assets when Linux protected-hardlink rules reject Docker-produced files.
-- Fixed PR install E2E's Docker test runner to include the project dev
- dependency group before invoking pytest inside the installed-package
- container.
-- Fixed release-gate flakiness in gateway and install harness tests by making
- the mock Unix-socket gateway concurrent, restoring runtime fixtures after
- destructive uninstall/purge tests, and localizing the large-payload MITM
- upstream instead of relying on external network behavior.
-- Fixed macOS PR CI's Python coverage step so it collects top-level Python
- contract tests without accidentally booting VM integration suites.
-- Fixed the shared `just` execution lock on macOS hosts without a `flock`
- binary by falling back to a Python `fcntl` lock holder.
-- Fixed macOS PR CI's scoped Python coverage floor so the top-level contract
- lane matches clean-runner coverage while the full `just test` gate stays at
- 90%.
-- Fixed macOS PR CI's no-VM Python integration lane so clean runners execute
- only suites without generated asset/signing prerequisites while still
- import-checking every integration suite.
-- Fixed Linux PR CI so hosted ARM runners compile the KVM backend and test
- binaries without hanging in live KVM probes or unbounded hosted-runner test
- execution; release CI remains the real-KVM exercise gate.
-- Fixed ordinary CI hardening gaps: Linux KVM diagnostics no longer emit red
- success annotations, Rust integration coverage is release-blocking, coverage
- summary errors are not hidden by `tee`, and Codecov test analytics use the
- supported uploader.
-
-## [1.1.1778542197] - 2026-05-11
-
-### Changed
-- Disabled the unsupported desktop self-updater surface for the next release:
- Tauri updater config, updater permissions, launch-time checks, and frontend
- update controls are removed until release artifacts support full-install
- updates.
-- Package installers now fail loudly when release-critical `capsem install` or
- `capsem setup` fails, instead of reporting success for a non-bootable install.
-- Policy Hook Spec0 remains infrastructure-only for the next release:
- configured external hook dispatch is not exposed as a shipped settings/UI
- surface until a production integration gate wires and verifies it.
-
-### Fixed
-- macOS `.pkg` and Linux `.deb` package flows now carry signed
- `manifest.json` snapshots plus all host helper binaries, and release CI
- verifies package payload signatures before publishing.
-- Release install E2E now consumes clean-checkout VM assets, locally signs the
- package manifest, and repacks the Linux `.deb` in place so CI installs the
- tested package instead of the unrepacked Tauri artifact.
-- Linux release app builds now install `minisign` before package payload
- manifest signing, matching the clean install E2E gate and preventing
- release-only `minisign: command not found` failures.
-- Setup, `capsem update --assets`, service startup, status, and doctor
- diagnostics now use verified manifest loading so unsigned or invalid
- manifests cannot silently downgrade asset verification.
-- Release preflight now validates the manifest signing key against
- `config/manifest-sign.pub`, keeps Linux package publication
- release-blocking, and includes the signed manifest plus boot assets in
- provenance attestation.
-- VM asset manifests now use consistent same-day patch selection across
- full image builds and local initrd repacks, preserve numeric asset-version
- ordering, clean stale per-arch hash aliases, and validate rootfs contents
- from the canonical guest artifact lists before release publication.
-- Settings save and frontend import now reject new `policy.hook.*` rules, so
- users cannot save inert hook-decision policy that appears enforced.
-- Settings reload failures now return structured saved-but-not-applied state,
- including affected session IDs, so the UI can keep a persistent retry banner.
-
-### Security
-- Manifest loading now verifies release signatures in setup, update, service,
- status, and doctor paths so unsigned or invalid asset manifests cannot
- silently downgrade boot asset verification.
-- Policy hook controls and `policy.hook.*` writes are hidden or rejected until
- configured external hook dispatch has a production integration path and
- black-box E2E proof.
-
-## [1.0.1778378133] - 2026-05-10
-
-### Added (enforcement rules)
-- Added the MCP policy sprint plan and tracker to productize MCP
- rules as typed `allow`, `ask`, and `block` decisions across TOML,
- settings, MITM enforcement, telemetry, and VM E2E tests.
-- Expanded policy planning beyond MCP to cover HTTP and DNS with the
- same typed decision model, including capture-aware `rewrite`, HTTP
- method/URL path/query/header rules, header stripping, DNS rewrite rules,
- credential-broker-safe redaction expectations, and explicit E2E/session
- proof for `mcp_calls`, `net_events`, and `dns_events`.
-- Expanded policy planning again to include model request/response,
- model tool-call/tool-response policy, and Policy Hook Spec0: an
- OpenAPI 3.1 export generated from runtime wire types so third-party
- HTTPS hook servers can receive normalized policy requests and return
- typed allow/ask/block/rewrite decisions.
-- Clarified the enforcement rule shape as named
- `policy..` TOML tables with `on`, CEL `if`,
- `decision`, `priority`, and capture-aware
- `rewrite_target`/`rewrite_value` fields; simple UI allow/block/header
- controls must compile into the same enforcement rule IR.
-- Added the first policy settings slice: settings files can now parse,
- preserve, return, and save priority-bearing named enforcement rules through
- the `/settings` API so frontend policy editors can post rule objects.
-- Hardened policy config validation with adversarial rewrite tests:
- bogus rewrite shapes, malformed regex targets, callback/table
- mismatches, invalid rule names, invalid policy key saves, header-strip
- normalization, and atomic rejection now fail closed before settings are
- written.
-- Added strict policy condition validation for the documented
- CEL-compatible subset: conjunctions, comparisons, `has(...)`, string
- helper methods, regex `matches(...)`, and per-callback subject fields
- are checked before TOML or `/settings` policy saves can persist.
-- Added the first enforcement rule evaluator over normalized subjects, with
- priority/name-ordered rule selection for MCP argument, HTTP path, and
- model response conditions.
-- Wired merged enforcement rules into the framed MITM MCP endpoint: named
- MCP request `block` rules now stop dispatch and record `policy.mcp.*`
- in `mcp_calls`, while `ask` rules fail closed without aggregator
- dispatch and record `policy_action=ask`.
-- Added framed MITM MCP response enforcement for `mcp.response`
- block rules: secret-bearing tool results are replaced with policy
- errors before reaching the guest and the original result is omitted from
- `mcp_calls.response_preview`.
-- Added `mcp.response` rewrite enforcement for framed MITM MCP:
- regex/capture rewrite targets mutate matched response text before it
- reaches the guest and telemetry records only the rewritten payload.
-- Added `mcp.request` rewrite enforcement for framed MITM MCP:
- argument regex rewrites mutate dispatch payloads before the aggregator
- sees them, request telemetry records only redacted arguments, and
- rewrite-target errors fail closed without leaking original arguments to
+- Removed the `ProfileConfigFile::builtin_default()` compatibility alias and
+ updated built-in profile validation/tests to name the real `code` profile.
+- Fixed CLI and `capsem-mcp` MCP commands to use the real built-in `code`
+ profile instead of the retired `default` profile when listing servers/tools,
+ refreshing tools, calling profile-scoped MCP tools, or creating one-shot VMs.
+ “Default” now refers only to visible default rules, not a hidden profile id.
+- Restored the terminal control UI as the `capsem-tui` host binary and made
+ `capsem shell` launch it. The TUI is wired to the current `/profiles/list`,
+ `/status`, and `/vms/...` contracts, restores Alt-owned shortcuts,
+ create/fork/pause/resume/stop/delete/recovery flows, vt-backed terminal
+ reconnect behavior, and deterministic text/SVG snapshot inspection.
+- Moved the service route table into a single shared router builder so startup
+ and route-level tests exercise the same mounted API contract, including
+ detection-rule authoring through `/profiles/.../detection/rules/...` and
+ ledger readback through `/vms/.../security/latest`.
+- Tightened gateway and service release fixtures around the explicit API
+ contract: generic fallback proxy paths stay rejected, body-limit tests use
+ real file-content routes, MCP credential status remains opaque, and macOS
+ process leak detection survives `KERN_PROCARGS2` permission denials.
+- Expanded mounted service route contract tests across fail-closed profile/VM
+ stubs, profile/settings/corp reads, corp edit/reload, plugin edit/evaluate,
+ MCP profile scoping, service-wide security ledgers, and file import/export
+ boundary logging.
+- Moved remote MCP auth onto the credential broker contract. MCP profile/corp
+ config now carries `auth.kind` plus opaque `auth.credential_ref` for bearer
+ or OAuth material; raw `bearer_token`/`bearerToken` imports are rejected or
+ skipped, secret-bearing MCP headers fail validation, and UI status reports
+ `has_auth_credential` instead of token presence.
+- Replaced internet-backed MCP manager proof with local recording test
+ infrastructure. The normal MCP manager suite now uses a local Streamable
+ HTTP MCP server and HTTP recorder to prove broker-owned auth resolution,
+ tool discovery, tool dispatch, and fail-closed missing credentials without
+ contacting public services.
+- Replaced builtin MCP HTTP tool tests that fetched `elie.net` and Wikipedia
+ with local static HTTP fixture responses. `fetch_http`, `grep_http`, and
+ `http_headers` still exercise the real reqwest/tool/security path, but
+ normal tests no longer require public network availability.
+- Added a profile-owned rule-file compilation guard: profile enforcement TOML
+ and Sigma detection YAML now materialize as `SecurityRuleProfile` and compile
+ only through the unified `SecurityRuleSet`/CEL rail, rejecting old policy
+ syntax and profile-file attempts to smuggle `corp.rules`.
+- Restored the `capsem-admin` executable as a Rust admin front door. Its
+ product surface is intentionally narrow: profile validate/check/materialize,
+ settings validate, enforcement/detection validate, manifest check/generate,
+ and profile-derived image build.
+- Added `capsem-admin manifest check|generate` for the current format-2 asset
+ manifest. The commands validate top-level `refresh_policy`, report asset
+ releases/arches, and regenerate the canonical `assets/manifest.json` from
+ built assets without restoring manifest signing or a second asset path.
+- Added profile-derived `capsem-admin image build` and moved
+ `just build-assets` onto that rail. Asset builds now require an explicit
+ profile, validate the profile and rule files first, preserve the Code profile
+ defaults, build EROFS `lz4hc` level 12 rootfs assets, and reject raw
+ no-profile build attempts.
+- Updated the release workflow to call the profile-derived asset build rail
+ explicitly (`code` profile) and to package/sign the full restored host binary
+ set, including `capsem-admin`.
+- Replaced the temporary flat profile asset triplet with per-architecture
+ profile asset declarations. `config/profiles/code/profile.toml` now parses as
+ the checked-in contract for EROFS/LZ4HC kernel, initrd, and rootfs assets with
+ URL/hash/size metadata.
+- Made `/profiles/{profile_id}/assets/status` report the selected profile's
+ current-architecture asset contract instead of a service-global asset guess,
+ including profile id, revision, profile payload hash, expected hashes,
+ sizes, source URLs, and present/missing state from the same hash-prefixed
+ resolver used by boot.
+- Made VM creation profile-explicit. `POST /vms/create`/provision and
+ one-shot `run` payloads now require `profile_id`; unknown profiles fail
+ before boot state is created, persistent registry rows store `profile_id`,
+ fork/save/resume preserve it, and list/info responses expose it. A VM's
+ `profile_id` remains immutable after creation.
+- Made VM boot preflight and process spawn resolve kernel, initrd, and rootfs
+ from the selected profile asset contract. Profile resolution supports the
+ approved hash-prefixed downloaded layout and logical-name dev layout, but
+ both are derived from profile asset descriptors instead of the old
+ service-global file guess.
+- Made `/profiles/{profile_id}/assets/ensure` profile-owned. It downloads the
+ selected profile's current-architecture kernel, initrd, and rootfs URLs into
+ hash-prefixed asset files, verifies each file with the profile BLAKE3 hash,
+ updates reconcile status, and skips already-verified profile assets.
+- Made `capsem assets status` and `capsem assets ensure` profile-aware. Both
+ commands now target the real `code` profile by default, accept `--profile`,
+ and call `/profiles/{profile_id}/assets/...` instead of the burned
+ `/profiles/default` path; gateway route coverage also forwards
+ `/profiles/status` and `/profiles/reload` explicitly.
+- Updated the frontend MCP and plugin settings surfaces to target the real
+ `code` profile instead of the burned `default` profile id.
+- Made startup asset cleanup preserve profile catalog assets and persistent VM
+ boot asset pins. Hash-prefixed files referenced by active profile
+ descriptors or saved VM pins are retained even when they are not listed in
+ the release manifest.
+- Made persistent VM lifecycle state pin the selected profile revision, profile
+ payload hash, and boot asset descriptors. Create/save/fork/resume preserve
+ the pinned profile revision, typed profile payload BLAKE3 hash, and
+ kernel/initrd/rootfs name+hash pins; save/fork/resume fail closed when the
+ current profile revision, profile payload hash, or boot asset pins drift.
+- Added profile management route gates:
+ `POST /profiles/create`, `PATCH /profiles/{profile_id}/edit`,
+ `DELETE /profiles/{profile_id}/delete`, `POST /profiles/{profile_id}/clone`,
+ and `POST /profiles/{profile_id}/validate`. Validation is real over the
+ typed `ProfileConfigFile`; mutation routes fail explicitly until profile file
+ persistence is implemented instead of writing through settings.
+- Added `GET /profiles/{profile_id}/enforcement/rules/list`, returning the
+ compiled profile rule inventory with source, default-rule, priority, action,
+ detection level, and lock metadata so the UI can reflect backend rule
+ truth instead of inventing grouping state.
+- Added `GET /profiles/{profile_id}/enforcement/info`, returning compiled
+ enforcement configuration counts by source/action plus default/custom,
+ detection, and corp-lock totals. Runtime counters remain table-backed under
+ VM enforcement status.
+- Added profile-scoped detection rule routes
+ `/profiles/{profile_id}/detection/info`,
+ `/profiles/{profile_id}/detection/rules/list`,
+ `/profiles/{profile_id}/detection/evaluate`,
+ `/profiles/{profile_id}/detection/rules/{rule_id}/edit`,
+ `/profiles/{profile_id}/detection/rules/{rule_id}/delete`, and
+ `/profiles/{profile_id}/detection/reload`. They reuse the same compiled
+ security-rule contract as enforcement and only list/write rules with an
+ explicit `detection_level`.
+- Moved asset readiness/reconciliation to profile-owned routes
+ `/profiles/{profile_id}/assets/status` and
+ `/profiles/{profile_id}/assets/ensure`; retired global `/assets/status` and
+ `/assets/ensure` so asset selection stays under the profile contract.
+- Removed the retired service-global asset status helper from the service
+ binary and converted its reconcile-progress unit coverage to the
+ profile-owned asset status contract.
+- Added profile-scoped skills route surfaces. Skills `info|list` reflect the
+ typed profile manifest; add/edit/delete fail explicitly until profile
+ persistence is implemented.
+- Removed the profile credential API surface before release: there is no
+ `/profiles/{profile_id}/credentials/*` route and no `[credentials]` profile
+ block. Credential capture/substitution state belongs to the credential broker
+ plugin runtime contract.
+- Added profile-scoped assets `info|edit`, plugins `info`, and MCP `info`
+ routes. Info routes summarize existing profile/config state; asset edits
+ fail explicitly until profile persistence lands.
+- Made profile MCP inventory profile-owned. `/profiles/{profile_id}/mcp/...`
+ now reads the selected profile's MCP section instead of settings/corp MCP
+ sections, `config/profiles/code/profile.toml` explicitly enables the real
+ built-in `local` MCP server, and unknown profile server ids fail closed.
+- Added service-wide runtime ledger routes `/security/latest|status`,
+ `/enforcement/latest|status`, and `/detection/latest|status`. These aggregate
+ per-VM `session.db` security-rule ledger rows through `DbReader`; detection
+ routes filter to rows with an explicit detection level.
+
+### Added (security event rule spine)
+- Replaced callback-shaped Policy V2 authoring with one native rule contract
+ over canonical `SecurityEvent`: `[corp.rules.*]`, `[profiles.rules.*]`, and
+ provider convenience `[ai..rules.*]` all compile into the same
+ `SecurityRuleSet`.
+- Added typed rule actions `allow`, `ask`, `block`, `preprocess`, `rewrite`,
+ and `postprocess`, plus optional `detection_level` metadata for
+ `informational`, `low`, `medium`, `high`, and `critical` detections.
+- Added source-aware priority discipline: built-in defaults use the named
+ `default` priority sentinel after the numeric user range, user/plugin rules
+ default to `10`, corp-locked rules default negative, and non-corp rules
+ cannot use negative priorities.
+- Added shared external rule files: both user and corp settings can reference
+ native enforcement TOML with `[rule_files].enforcement` and Sigma YAML with
+ `[rule_files].sigma`; both compile into the same runtime rules. Corp settings
+ also carry the future `corp_rule_files.sigma_output_endpoint` integration
+ field for SIEM/export delivery.
+- Hardened security rule validation with adversarial parser/compiler tests:
+ malformed CEL, stale callback fields, callback/table mismatches, invalid
+ rule names, invalid priorities, invalid plugin shapes, and atomic rejection
+ now fail closed before settings are written.
+- Added strict CEL validation against first-party `SecurityEvent` roots
+ (`http`, `dns`, `mcp`, `model`, `file`, `process`, and `security`) so stale
+ callback-local fields fail before rules persist. Credential substitution
+ remains a ledger event type, while snapshot lifecycle state is host recovery
+ state exposed through VM snapshot routes rather than CEL roots or
`session.db`.
-- Added the first HTTP policy enforcement path in the MITM hook
- pipeline: named `http.request` block and ask rules stop before upstream
- dispatch, rewrite rules can mutate request URLs and strip request
- headers before telemetry/upstream construction, and `net_events` now
- carries typed policy mode/action/rule/reason fields.
-- Added HTTP response policy enforcement in the MITM hook pipeline:
- named `http.response` rewrite rules can strip response headers and
- rewrite response header/status targets before guest delivery and
- telemetry capture, while unsupported response rewrite targets fail
- closed without leaking upstream response headers or bodies.
-- Added DNS query policy enforcement: named `dns.query` allow rules now
- dispatch with audit fields, block and ask rules fail closed before
- upstream resolution, rewrite rules synthesize configured A/AAAA answers
- without touching upstream DNS, live policy reload is checked before
- cached answers, and `dns_events` now carries typed policy
- mode/action/rule/reason fields.
-- Added model request policy enforcement before provider dispatch:
- named `model.request` allow rules dispatch with audit fields, block
- and ask rules fail closed before upstream connection, unsupported
- request rewrite rules fail closed without dispatch, and `net_events`
- records policy fields plus byte counts without retaining denied request
- bodies.
-- Added adversarial and VM E2E coverage for model request policy:
- truncated JSON matching, invalid runtime conditions, non-LLM path
- bypass, `/settings` model-policy saves, callback/type mismatch
- rejection, and a real guest OpenAI-shaped HTTPS request blocked from
- `user.toml` with `session.db` no-leak assertions.
-- Added configured MCP Policy V2 VM E2E coverage: a saved
- `policy.mcp.*` argument-name block now goes through `/settings`,
- `/reload-config`, the real guest framed MCP relay, and `session.db`
- assertions for decision, rule, reason, process attribution, and
- redacted previews.
-- Added more configured MCP Policy V2 VM E2E coverage for T5:
- argument-value `ask`, request-argument `rewrite`, external stdio MCP
- request `block` with no dispatch, and external MCP return-value `block`
- with no response-preview leak are now proven through `/settings`, the
- real guest framed MCP relay, and `session.db`.
-- Added a policy product-surface subsprint covering docs site updates,
- session database references, just recipe documentation, and settings UI
- work so the framed MITM MCP and policy user-facing surfaces stay in sync
- with the implementation.
-- Added the policy product surface: a docs reference page, refreshed
- framed-MITM MCP/settings/session/just recipe docs, settings import/export
- of named enforcement rules, and a settings UI panel that edits, deletes, and
- stages generated `policy..` rules.
-- Added Policy V2 T5 VM proof for HTTP, DNS, and model traffic: real guest
- sessions now cover configured HTTP method/path/query/header blocks,
- HTTP request/response header stripping with no-leak `net_events`,
- configured DNS block/rewrite with `dns_events`, model request ask/rewrite
- fail-closed no-leak behavior, and model tool-response block/rewrite
- telemetry redaction.
-- Added model `tool_response` Policy V2 enforcement before provider
- dispatch: OpenAI-shaped tool-result messages can now be blocked or
- rewritten before local tool output reaches the model provider, with
- rewritten request bodies updating `Content-Length` and redacted
- `net_events`, `model_calls`, and `tool_responses` previews.
-- Added model response and provider-emitted model tool-call Policy V2
- enforcement before guest delivery: OpenAI-shaped responses can now be
- blocked, asked, or rewritten with no-leak `net_events`, redacted
- `model_calls.text_content`, and redacted nested `tool_calls` session
- rows on the host MITM fixture path.
-- Added Policy Hook Spec0 as checked-in OpenAPI generated from Rust wire
- types, exposed it from `GET /policy-hook/spec`, and added a strict hook
- endpoint runtime with HTTPS/auth/body-cap/schema-version fail-closed
- handling plus `policy_hook_events` session DB audit rows.
-- Added deterministic VM E2E coverage for model response block/rewrite and
- provider-emitted tool-call block/rewrite through a local OpenAI-shaped
- upstream fixture, with guest-visible no-leak assertions and `net_events`
- policy proof.
-- Added scoped Policy V2 Criterion microbenchmarks for HTTP, DNS, model
- response, model tool-call, hook-decision matching, and Policy Hook response
- decoding, with sample results recorded under `benchmarks/policy-v2/`.
-
-### Fixed (service)
-- Fixed failed-session preservation idempotency: duplicate cleanup paths that
- race on the same session directory now treat an already-renamed or already-
- removed directory as a quiet no-op instead of warning that logs were lost
- and the session was orphaned. Real rename/remove failures still warn with
- the actual filesystem outcome, and regression tests cover preserved,
- already-absent, and double-call behavior.
-- Fixed the Slack redaction regression fixture so it no longer contains a
- contiguous token-shaped literal that trips GitHub push protection while still
- constructing the same runtime string for the redactor test.
-
-### Fixed (enforcement rules)
+- Added typed runtime-family markers for first-party CEL roots versus
+ ledger-only `credential.substitution` rows, with regression tests tying the
+ markers to `SECURITY_EVENT_CEL_ROOTS`.
+- Replaced legacy `[profiles.defaults.*]` rule authoring with the visible
+ `[default.]` contract. Default rules still compile into ordinary late
+ CEL rules under `profiles.rules.default_`, and the old namespace is
+ rejected instead of aliased.
+- Removed static `tool_config_sources` from settings/profile contracts and the
+ settings UI response. Tool config observations now belong to runtime
+ plugin/security-ledger evidence with BLAKE3 references, and static
+ `tool_config_sources` tables fail closed.
+- Removed static credential/config-file metadata from `[ai.*]` provider
+ endpoint records. Provider records now carry routing/rule/discovery
+ information only; `credential_setting_id`, provider-level `credential_ref`,
+ and provider `files` fail closed, and settings provider cards no longer expose
+ brokered credential refs.
+- Removed provider status from `/settings/info` and the settings UI/model.
+ Provider-like behavior is no longer a settings object: profile/corp rules own
+ enforcement and credential/plugin runtime status owns credential evidence.
+- Stopped the credential broker from writing brokered references into settings.
+ Observed credentials are stored in the credential store/keychain, emitted to
+ the substitution/security ledger, and can record provider discovery; settings
+ files no longer become a credential-reference inventory.
+- Added a security-event engine that runs configured preprocess plugins before
+ detection/enforcement, evaluates CEL once against the canonical event, then
+ runs configured postprocess plugins only after the decision allows
+ materialization.
+- Added the typed plugin contract `plugin(SecurityEvent) -> SecurityEvent`;
+ plugins own their filtering and runtime state, plugin failures fail closed,
+ and plugin effects are recorded in the security rule ledger.
+- Added typed profile/corp plugin policy with `mode` and `detection_level`.
+ Enabled plugins append `SecurityDetectionEvent` records onto
+ `SecurityEvent.detections`, rules with `detection_level` append the same
+ reporting vector, and `rewrite` is the canonical mutation mode.
+- Extended profile plugin API responses with backend-owned plugin metadata and
+ runtime status: stage, version, counters, errors, and brokered credential
+ references. The settings UI now reads brokered credential refs only from the
+ credential-broker plugin runtime status shape.
+- Hardened plugin edit requests so unknown fields are rejected instead of
+ ignored. Invalid modes, invalid detection levels, unknown plugins/profiles,
+ and credential-reference smuggling attempts fail closed.
+- Hardened profile skill mutation routes with typed, strict payloads. Add/edit
+ requests now reject unknown fields and empty paths before the current
+ profile-persistence gate returns `501 Not Implemented`.
+- Added the plugin/detection/enforcement endpoint taxonomy:
+ `/profiles/{profile_id}/plugins/list`,
+ `/profiles/{profile_id}/plugins/{plugin_id}/info`, and
+ `/profiles/{profile_id}/plugins/{plugin_id}/edit` report and update
+ profile-owned plugin config,
+ `/profiles/{profile_id}/enforcement/evaluate` sends a profile-scoped test
+ event through the real engine, and
+ `/vms/{vm_id}/detection/latest|status` plus
+ `/vms/{vm_id}/enforcement/latest|status` remain table-backed ledger views.
+- Added enforcement rule-management endpoints:
+ `PUT /profiles/{profile_id}/enforcement/rules/{rule_id}/edit` and
+ `DELETE /profiles/{profile_id}/enforcement/rules/{rule_id}/delete`
+ validate profile rules against the native `SecurityRuleProfile` compiler
+ before writing `user.toml`, and
+ `POST /profiles/{profile_id}/enforcement/reload` reloads that profile's
+ enforcement rules.
+- Replaced the retired `/corp-config` provisioning route with
+ `PUT /corp/edit`; the gateway and service now reject the old route instead
+ of forwarding it.
+- Added the rest of the corp plane routes: `GET /corp/info`,
+ `POST /corp/validate`, and `POST /corp/reload`, all forwarded explicitly by
+ the gateway.
+- Replaced the ambiguous `GET|POST /settings` route with
+ `GET /settings/info` and `PATCH /settings/edit`; the old magic settings
+ route now fails closed in the service and gateway.
+- Split core config mutation by owner: `PATCH /settings/edit` now uses the
+ UI-settings writer, while VM/security/AI behavior uses profile-owned config
+ writers. Credential brokerage state belongs to the broker plugin runtime
+ contract.
+- Added a first-class profile manifest contract covering profile identity,
+ description, icon SVG, web/shell/mobile availability, VM asset selection,
+ VM defaults, rule files/default rules, plugins, MCP servers, skills,
+ AI/provider convenience rules, and tool config source metadata.
+- Profile inventory now sources the built-in `default` profile summary from
+ the profile manifest contract instead of service-local placeholder text.
+- Removed retired settings utility routes `/settings/lint` and
+ `/settings/validate-key`; settings now expose only `info` and `edit` until
+ profile/corp validation and credential broker endpoints own those workflows.
+- Removed retired settings preset endpoints and UI selector; security/profile
+ defaults no longer mutate behavior through `/settings/presets`.
+- Removed preset metadata from `/settings/info`; settings responses now carry
+ settings tree/issues plus status fields only, not behavior presets.
+- Replaced the global `POST /reload-config` route with
+ `POST /profiles/{profile_id}/reload`; the old global reload route now fails
+ closed in the service and gateway.
+- Added `SerializableSecurityEvent` as the public evaluated-event wire DTO:
+ every first-party event root is present, absent roots serialize as `null`,
+ and raw credential observation buffers are excluded.
+- Added credential broker plugin support with Keychain-backed storage on macOS
+ and BLAKE3 `credential:blake3:` references in broker runtime status,
+ logs, and `session.db`; raw credentials stay broker-private.
+- Added brokered credential capture from observed HTTP headers/body responses
+ and `.env` files, plus upstream-only substitution of broker references for
+ allowed HTTP materialization.
+- Added a closed runtime security-event identity contract and routed HTTP/net,
+ model, MCP, DNS, file, process exec/audit/completion, broker substitution,
+ and snapshot session DB rows through the security-engine emitter handoff.
+- Removed the old MITM PolicyHook/Policy V2 runtime rails and the MCP built-in
+ legacy domain bridge. HTTP request, model request/response, framed MCP
+ request/response, MCP built-in HTTP tools, and DNS query blocking now enforce
+ through the canonical `SecurityEvent` + CEL rule path before dispatch.
+- Added contract tests proving built-in default rules match HTTP, DNS, MCP,
+ model, file, and process security events as ordinary late-priority CEL rules;
+ specific rules run first, and editing a default rule changes evaluation
+ without any hidden network fallback.
+- Removed retired web decision settings (`security.web.allow_read`,
+ `security.web.allow_write`, `security.web.custom_allow`, and
+ `security.web.custom_block`) from defaults, presets, builder schemas,
+ frontend fixtures, guest diagnostics, and integration fixtures. Network
+ settings now expose only mechanics such as `security.web.http_upstream_ports`;
+ HTTP/DNS allow/block behavior belongs to profile security rules.
+- Replaced global MCP service/gateway/frontend routes with profile/server
+ routes: servers live under `/profiles/{profile_id}/mcp/servers/list`, tools
+ live under `/profiles/{profile_id}/mcp/servers/{server_id}/tools/list`, and
+ tool edit/call/refresh operations are scoped to the same profile/server path.
+- Replaced global enforcement authoring routes with profile-owned routes:
+ `/profiles/{profile_id}/enforcement/evaluate`,
+ `/profiles/{profile_id}/enforcement/rules/{rule_id}/edit`,
+ `/profiles/{profile_id}/enforcement/rules/{rule_id}/delete`, and
+ `/profiles/{profile_id}/enforcement/reload`.
+- Routed explicit file import/export/read/write boundaries through the
+ process-owned security-event emitter so `fs_events` and
+ `security_rule_events` share the same primary event id without a service-side
+ DB writer or fallback logger.
+- Added a release guard that keeps session event writes behind
+ `capsem_logger::DbWriter`: production protocol, plugin, security, service,
+ and process code may not open ad-hoc SQLite writers or insert event rows
+ directly.
+- Added a security rule forensic ledger: `security_rule_events` stores the
+ triggering event id/type, rule id/name/action/detection level, rule snapshot,
+ matched `SecurityEvent` payload, and trace id. `security_ask_events` records
+ append-only pending/approved/denied ask lifecycle rows.
+- Added DB-backed security endpoints: `/vms/{vm_id}/security/latest` returns
+ full stored rule ledger rows and `/vms/{vm_id}/security/status` regenerates
+ counters from `session.db`.
+- Replaced retired top-level VM lifecycle routes with the profile-era VM
+ namespace across service, gateway, CLI, MCP, tray, frontend, and tests:
+ `POST /vms/{vm_id}/pause`, `DELETE /vms/{vm_id}/delete`,
+ `POST /vms/{vm_id}/resume`, `POST /vms/{vm_id}/save`, and
+ `POST /vms/{vm_id}/fork`. The gateway now rejects the old
+ `/suspend`, `/delete`, `/resume`, `/persist`, and `/fork` route family.
+- Moved core VM create/list/info/stop routes into the same VM namespace across
+ service, gateway, CLI, MCP, tray, frontend, status aggregation, docs, and
+ tests: `POST /vms/create`, `GET /vms/list`,
+ `GET /vms/{vm_id}/info`, and `POST /vms/{vm_id}/stop`. The gateway now
+ rejects retired `/provision`, `/list`, `/info/{id}`, and `/stop/{id}` paths.
+- Added built-in provider-owned AI rules for OpenAI/Codex, Anthropic/Claude,
+ Google/Gemini, and Ollama. The rules live under `[ai..rules.*]`,
+ merge as defaults < user < corp, enforce corp-only negative priorities, and
+ compile into deterministic `profiles.rules.*` security-event rules whose
+ matches are written to the `security_rule_events` session DB ledger and
+ exposed through `/vms/{vm_id}/security/latest`.
+- Added Sigma import support that parses Sigma YAML into typed `SecurityRule`
+ entries, derives valid rule ids/names, validates generated CEL against
+ `SecurityEvent` roots, and keeps security-team detection authoring on the
+ same ledger/enforcement rail as native rules.
+- Added `capsem-core` security-action microbenchmarks for rule matching,
+ action-chain overhead, runtime event classification, and brokered HTTP
+ credential materialization.
+
+### Added (observability and benchmarks)
+- Added OpenTelemetry-style spans and local-only metrics around MITM/network
+ stages, security-event emission, DB enqueue/write behavior, and launch paths
+ for benchmark/debug use without exposing upstream telemetry by default.
+- Added a local MITM debug benchmark server with HTTP, gzip, SSE/model-like,
+ credential-response, deny-target, and WebSocket scenarios so network/security
+ hot paths can be measured without public internet variance.
+- Added logger-owned DB writer pressure benchmarks and metrics for enqueue
+ latency, batch writes, shutdown flushes, and coalesced event pressure.
+
+### Changed (security policy enforcement)
+- Unified HTTP, DNS, MCP, model, file, and process detection/enforcement on
+ the security-event rule engine. Producers now emit canonical security events,
+ evaluate the active `SecurityRuleSet`, and write matched rule rows with the
+ same primary event id as the underlying `session.db` event. Credential
+ substitution and snapshot lifecycle writes remain canonical ledger event
+ types, not fake rule roots.
+- Removed the global MCP policy API/UI/CLI surface (`/mcp/policy`,
+ `capsem mcp policy`, and frontend MCP policy mutators). MCP runtime endpoints
+ now report mechanics only; MCP decisions must be expressed as security rules.
+- Removed the old `McpPolicy`/`ToolDecision` decision object from core config.
+ Security presets no longer write MCP tool permissions, retired
+ `mcp.global_policy`, `mcp.default_tool_permission`, and
+ `mcp.tool_permissions` keys fail closed at settings load, and MCP blocking
+ tests now use profile security rules.
+- Removed `NetworkPolicy::evaluate`, `PolicyDecision`, and
+ `NetworkPolicy::is_fully_blocked` from the network engine. Network policy
+ code now carries only mechanics such as DNS redirects, HTTP port metadata,
+ and body-capture settings; HTTP/DNS allow, ask, block, and default behavior
+ must come from profile/corp security rules.
+- Removed the remaining domain allow/read/write/default fields from
+ `NetworkPolicy` itself. The network object can no longer carry hidden
+ domain enforcement state; tests now assert default and provider behavior
+ through compiled `SecurityRuleSet` entries.
+- Stopped exporting retired web default toggles as guest authority env vars
+ (`CAPSEM_WEB_ALLOW_READ` and `CAPSEM_WEB_ALLOW_WRITE`). The guest now relies
+ on security events and rules for HTTP/DNS behavior rather than stale
+ settings-derived hints.
+- Replaced the old callback-demux rule authoring language with CEL over
+ first-party event roots. Admin-visible rules use `match = ...` and typed
+ actions rather than callback-local `on`/`if`/`decision` fields.
+- Preserved enforcement semantics for real boundaries: HTTP/model dispatch,
+ DNS handling, framed MCP calls/notifications, file import/export/read/write,
+ process exec/audit/completion, credential substitution, and snapshot events
+ all pass through the shared security-event emitter and rule ledger.
+- Added VM and integration coverage proving configured security rules block,
+ ask, or log HTTP, DNS, MCP, model, file, and process events without leaking
+ denied request/response payloads into previews.
+- Updated the policy product surface and docs around the new
+ `SecurityEvent` rule contract, Sigma import, DB-backed latest/info
+ endpoints, and forensic `session.db` ledger instead of generated
+ callback-specific policy stanzas.
+
+### Fixed (policy rules)
- Fixed model telemetry parsing for explicit/local OpenAI-compatible
provider paths by carrying the request's provider classification through
the MITM chunk-hook metadata, so enforcement and SSE interpretation use
@@ -1785,9 +1467,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed warnings-as-errors issues found during policy verification by
removing a redundant setup detection closure and switching settings
endpoint env-serialization tests to an async mutex.
-- Fixed a Policy V2 MCP telemetry leak: pre-dispatch `policy.mcp.*`
- block/ask denials now redact original request arguments before writing
- `mcp_calls.request_preview`.
+- Fixed an MCP telemetry leak: pre-dispatch block/ask denials now avoid
+ writing raw denied request arguments into `mcp_calls.request_preview`.
- Fixed MITM body handling regressions found during T6 verification:
HTTP decompression now honors `Content-Encoding: gzip` instead of raw
gzip magic bytes, and decoded responses drop stale compressed
@@ -1801,13 +1482,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
invocations shared one leak-attribution file and could report another
still-running pytest process's service fixture as a leak; `just smoke`
now gives each pytest phase a distinct leak-log namespace.
-- Fixed clean ephemeral session shutdown cleanup so non-persistent session
- directories are removed on expected process exit while unexpected process
- deaths remain available for postmortem inspection.
-- Fixed local release gate recipes so `just test` can complete on macOS:
- optional Tauri signing arguments no longer trip Bash 3.2 nounset in
- `just cross-compile`, and `just test-install` recreates the Docker host
- builder base image if cross-compile cleanup pruned it.
### Fixed (mitm-mcp-unification T4 coverage hardening)
- Preserved all JSON-RPC request id shapes in framed MCP telemetry:
@@ -1854,7 +1528,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
as visible debt instead of implied by benchmarks or unit tests.
- Expanded the MCP development skill with the framed MITM MCP hardening
matrix: parser/interpreter adversarial cases, dispatch coverage,
- enforcement rule enforcement, telemetry assertions, VM E2E checks, and the
+ policy rule enforcement, telemetry assertions, VM E2E checks, and the
aggregator DB-free boundary.
### Fixed (mitm-mcp-unification T3 hardening)
@@ -2214,7 +1888,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
session per the resume prompt.
### Added (mitm-redesign T3 follow-up `d`)
-- **`DnsRedirect` enforcement rule -- admin-configured DNS overrides.**
+- **`DnsRedirect` policy rule -- admin-configured DNS overrides.**
New `DnsRedirect { matcher, qtype, answers, ttl }` rule kind on
`NetworkPolicy::dns_redirects` lets an admin override DNS
resolution for a specific qname (and optionally a specific
@@ -2598,13 +2272,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
with `port=11434, conn_type=http-mitm, decision=allowed,
status=200`. As part of the verification,
`DEFAULT_HTTP_UPSTREAM_PORTS` is bumped from `[80]` to
- `[80, 11434]` so the host policy default mirrors the iptables
+ `[80, 3128, 3713, 8080, 11434]` so the host policy default mirrors the iptables
rules in `capsem-init` -- otherwise port 11434 traffic gets
redirected to 10080, hits the host proxy, and is rejected by
the policy gate, which is the wrong default for the canonical
local-LLM workflow this protocol path was designed for. New
- ports get added by editing both lists in tandem until the
- policy_config plumb (deferred follow-up) lands.
+ ports get added by editing the shared policy config and guest redirect lists
+ in tandem.
- **T2 (agent-side): plain-HTTP listener + iptables redirects.**
`capsem-net-proxy` now listens on `127.0.0.1:10080` in addition to
the original `:10443`; a `run_listener(port)` helper drives the
@@ -3483,10 +3157,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed (observability)
- **W6 trace_id wiring completed across capsem-logger / capsem-core /
capsem-process.** The `trace_id` column on `net_events`, `mcp_calls`,
- `tool_calls`, `tool_responses`, `fs_events`, `snapshot_events`, and
+ `tool_calls`, `tool_responses`, `fs_events`, and
`audit_events` is now populated end-to-end. Write-side: every event
emitter (`mitm_proxy`, `mcp/{gateway,builtin_tools,file_tools}`,
- `fs_monitor`, `capsem-process`'s snapshot/audit paths) calls
+ `fs_monitor`, and `capsem-process` audit paths) calls
`capsem_core::telemetry::ambient_capsem_trace_id()`. INSERT statements
in `writer.rs` now include the new column. `tool_calls.trace_id` and
`tool_responses.trace_id` fall back to the parent `model_calls.trace_id`
@@ -3562,7 +3236,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
doesn't lose context that pre-dates the trace propagation.
- **`trace_id TEXT` column on every event table.** Added to
- `mcp_calls`, `net_events`, `fs_events`, `snapshot_events`,
+ `mcp_calls`, `net_events`, `fs_events`,
`tool_calls`, `tool_responses`, `audit_events` (model_calls and
exec_events already had it). Indexes added on each. Fresh DBs get
the column from `CREATE_SCHEMA`; existing DBs get it via
@@ -3781,13 +3455,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`JoinHandle::abort` does).
### Changed (kernel)
-- `guest/config/build.toml` ships `kernel_branch = "auto"` instead of a
+- The backend image spec ships `kernel_branch = "auto"` instead of a
hardcoded `"6.6"`. `resolve_kernel_version("auto")` queries
kernel.org/releases.json and picks the newest non-EOL longterm branch's
latest patch (today: `6.18.26`). Pin to a specific branch by setting
`kernel_branch = "X.Y"` (e.g. `"6.6"`) for reproducibility / security
freeze. Killed the duplicated `"6.6"` literal in `models.py` /
- `scaffold.py` -- single source of truth is now `build.toml`.
+ the removed scaffold rail -- single source of truth is now the profile-derived
+ backend image spec.
### Changed (bootstrap)
- `bootstrap.sh` moved to the repo root (was `scripts/bootstrap.sh`).
@@ -3958,25 +3633,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [1.0.1776980020] - 2026-04-23
### Security
-- **Verify manifest signatures at boot before trusting asset hashes.**
- The previous commit wired asset hash verification to the on-disk
- `manifest.json`, but an attacker with write access to `assets/` could
- swap both the rootfs and the manifest to match. Closed the gap with
- minisign signature verification: the release pubkey
- (`config/manifest-sign.pub`, key id `93A070CBB288AC9B`) is now baked
- into `capsem-core` via `include_str!`, and
- `asset_manager::load_verified_manifest_for_assets` rejects any
- manifest whose sibling `.minisig` is missing or invalid. Release
- builds (`cfg!(debug_assertions) == false`) hard-fail on a manifest
- without a valid signature; debug builds allow unsigned manifests so
- local dev loops with locally built assets keep working. Added the
- `minisign-verify = "0.2"` crate; covered by 9 new unit tests
- including verify-accepts/rejects-tampered-manifest/rejects-mangled-
- signature/rejects-wrong-pubkey/bails-when-sig-required-but-missing/
- accepts-unsigned-when-allowed/bails-on-bad-signature and a regression
- guard that the baked pubkey file parses as valid minisign. Updated
- `docs/src/content/docs/architecture/asset-pipeline.md` to describe
- the full tamper-resistance chain.
+- **Simplified asset authorization to the profile/corp contract.** URLs are
+ profile/corp-selected, downloaded bytes are verified by BLAKE3 hash/size, and
+ release evidence is SBOM plus provenance attestations.
- **Asset hash verification at boot was silently disabled on every release.**
`crates/capsem-core/src/vm/boot.rs` read three expected hashes via
@@ -4001,9 +3660,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
a manifest. Missing or malformed manifest falls back to disabled
verification with an explicit `[boot-audit] asset hash verification
disabled` log line, keeping dev loops without a manifest working.
- Tamper resistance for release environments now depends on manifest
- signature verification in the asset-download path; that path is a
- separate, tracked gap.
Updated `docs/src/content/docs/architecture/asset-pipeline.md` to
describe the runtime-lookup flow (replacing the old "Compile-Time
Hash Embedding" section) and fixed the mermaid diagram to match.
@@ -6184,7 +5840,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- **Cross-arch Docker builds fail on macOS** -- Docker's legacy builder shared intermediate layer cache across `--platform` values, causing arm64 layers to be reused for x86_64 builds. Fixed by requiring Docker BuildKit (buildx), which properly includes platform in cache keys. Added buildx to `just doctor` and `scripts/bootstrap.sh`.
-- **Snapshots tab shows nothing during long sessions** -- the tab called `callMcpTool('snapshots_list')` once on mount, never refreshed, and failed silently if the MCP gateway wasn't wired yet. Replaced with SQL queries against a new `snapshot_events` table in `session.db`, consistent with all other stats tabs. Each snapshot event stores a self-contained `(start_fs_event_id, stop_fs_event_id]` range for efficient per-snapshot change counts via `fs_events` cross-reference.
+- **Snapshots tab shows nothing during long sessions** -- the tab called `callMcpTool('snapshots_list')` once on mount, never refreshed, and failed silently if the MCP gateway wasn't wired yet. An intermediate implementation used SQL rows, but the current 1.3 contract supersedes that: snapshot state is exposed through VM snapshot routes and is not stored in `session.db`.
- **Symlink loop hangs app on startup** -- `disk_usage_bytes()` used `is_dir()` / `metadata()` which follow symlinks. A `.venv/lib64 -> lib` relative symlink in session workspaces caused infinite recursion, hanging the app at boot. Fixed to use `symlink_metadata()` throughout. Added regression tests for symlink loops, absolute escapes, and real session timing.
- **Wizard flashes briefly on app launch** -- the setup wizard appeared for one frame before settings finished loading. Added `!settingsStore.loading` guard to prevent the wizard from rendering until settings are fully resolved.
- **KVM boot path compile errors** -- `vm/boot.rs` referenced `rootfs_path()` and `virtiofs_share()` methods that were renamed. Fixed to use `disk_path()` and `virtio_fs_share()`.
@@ -6572,7 +6228,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Wizard validates API keys in real-time against provider endpoints (spinner, check/X inline)
- API key detection now checks `~/.config/openai/api_key` and `~/.anthropic/api_key`
-- Build verification documentation (SBOM, attestation, manifest signatures)
+- Build verification documentation (SBOM and attestation)
### Fixed
- `svelte-check` failing on `dist/` build artifacts (excluded from tsconfig)
@@ -6590,7 +6246,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Rootfs removed from DMG bundle (was 463 MB, now ~15 MB) -- rootfs is downloaded on first launch
- Build attestation (SBOM + provenance) restored after CI refactor
-- Manifest.json now signed with minisign (same key as updater artifacts)
+- Manifest metadata published with asset hashes and release attestations
## [0.9.3] - 2026-03-18
@@ -7189,8 +6845,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- SNI proxy replaced by MITM transparent proxy for full HTTP-level traffic inspection and policy enforcement
-- Domain policy (`DomainPolicy`) wrapped by `HttpPolicy` which adds method+path rules while preserving backward compatibility
-- `load_merged_policy()` now returns `HttpPolicy` instead of `DomainPolicy`
- HTTPS proxy connections spawn as async tokio tasks instead of blocking threads
- Control protocol split into disjoint `HostToGuest`/`GuestToHost` enums with reserved variants for file operations and lifecycle management
- Guest agent boot sequence restructured: vsock connects first, receives clock + env from host before forking bash
@@ -7224,7 +6878,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `CONFIG_EXPERT=y` in kernel defconfig ensures all hardening options (KALLSYMS=n, MODULES=n, etc.) are respected by `make olddefconfig`
- Kernel symbol table (`/proc/kallsyms`) now empty -- eliminates kernel ASLR bypass vector
- MITM proxy enables full HTTP audit trail: every request method, path, status code, and headers are logged to web.db
-- HTTP-level enforcement rules allow fine-grained control (e.g., allow GET but deny POST to specific paths)
+- HTTP-level policy rules allow fine-grained control (e.g., allow GET but deny POST to specific paths)
- Default-deny domain policy: only explicitly allowed domains are reachable from the guest
- No DNS leaves the VM: all resolution is faked to a local IP
- Corporate policy (`/etc/capsem/corp.toml`) overrides user settings for enterprise lockdown
diff --git a/CLAUDE.md b/CLAUDE.md
index a166fcb90..07d8a5a5d 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -45,17 +45,19 @@ skills/ Shared AI agent skills (SKILL.md format)
## Skills
-Skills live in `skills/` at the project root. Both Claude Code and Gemini CLI discover them via symlinks:
+Skills live in `skills/` at the project root. This is the canonical checked-in
+developer skill library. Agent-specific discovery may symlink or copy from this
+path; runtime product config must not mirror developer skills under `config/`.
```
-skills//SKILL.md One skill per directory
-.claude/skills -> ../skills Claude Code symlink
-.agents/skills -> ../skills Gemini CLI symlink
+skills//SKILL.md One skill per directory
```
Prefix-based grouping: `dev-*`, `build-*`, `release-*`, `site-*`, `frontend-*`, `meta-*`. `asset-pipeline` covers the build-to-boot asset flow. See `/meta-organize-skills` for conventions.
-**Do not** put files in `.claude/skills/` or `.agents/skills/` directly -- those are symlinks.
+**Do not** put skill source files in `.claude/`, `.codex/`, `.gemini/`, or
+`config/skills/`. Those roots are agent-local settings or product config, not
+the developer skill source.
## Skills -- LOAD BEFORE CODING
diff --git a/Cargo.toml b/Cargo.toml
index 3993b4f4c..c764c70c8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,12 +6,9 @@ members = [
"crates/capsem-app",
"crates/capsem-agent",
"crates/capsem-logger",
- "crates/capsem-security-engine",
- "crates/capsem-file-engine",
- "crates/capsem-network-engine",
- "crates/capsem-process-engine",
"crates/capsem-process",
"crates/capsem-service",
+ "crates/capsem-admin",
"crates/capsem",
"crates/capsem-tui",
"crates/capsem-mcp",
@@ -23,7 +20,7 @@ members = [
]
[workspace.package]
-version = "1.2.1780103109"
+version = "1.3.1781720230"
edition = "2021"
rust-version = "1.91"
license = "Apache-2.0"
@@ -68,9 +65,10 @@ tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
tracing-appender = "0.2"
serde = { version = "1", features = ["derive"] }
serde_json = { version = "1", features = ["raw_value"] }
+serde_yaml = "0.9"
rmp-serde = "1.3.0"
toml = "0.8"
-rusqlite = { version = "0.32", features = ["bundled", "hooks"] }
+rusqlite = { version = "0.32", features = ["bundled"] }
humantime = "2"
objc2 = "0.6"
objc2-virtualization = { version = "0.3", features = [
@@ -103,8 +101,8 @@ base64 = "0.22"
bytes = "1"
regex = "1"
clap = { version = "4", features = ["derive"] }
-ratatui = "0.30.0"
-crossterm = "0.29.0"
+crossterm = "0.29"
+ratatui = "0.30"
tokio-unix-ipc = "0.4"
rmcp = { version = "1.3", features = ["client", "server"] }
# Low-level DNS protocol (wire-format codec). Used host-side by the
diff --git a/GEMINI.md b/GEMINI.md
index 5528efb9d..d71fb74f7 100644
--- a/GEMINI.md
+++ b/GEMINI.md
@@ -22,4 +22,4 @@ Skills contain hard-won lessons and project-specific patterns. **Before writing
| Release | `/release-process` | CI, signing, notarization, changelog |
| Architecture | `/site-architecture` | System design, Tauri, vsock, key files |
-Skills live in `skills/` (symlinked to `.agents/skills/`). Start with `/dev-capsem` to orient, then load the specific skill for your area.
\ No newline at end of file
+Skills live in repository `skills/`. Start with `/dev-capsem` to orient, then load the specific skill for your area. Do not mirror developer skills under `config/skills`.
diff --git a/LATEST_RELEASE.md b/LATEST_RELEASE.md
index 8b50fee0f..bf259d113 100644
--- a/LATEST_RELEASE.md
+++ b/LATEST_RELEASE.md
@@ -1,6 +1,6 @@
-version: 1.2.1779673506
+version: 1.0.1777065213
---
-### Fixed
-- Fixed release package profile asset URLs so packaged Profile V2 installs
- download VM assets from the live GitHub Release, and updated the post-release
- verifier to seed packaged profiles before running `capsem update --assets`.
+### Fixed (CI)
+- Codesign companion binaries with --options runtime + --timestamp;
+ notary rejected the .pkg because the 8 companion binaries lacked
+ hardened runtime.
diff --git a/README.md b/README.md
index 2c9a74f12..6e932dc01 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@
curl -fsSL https://capsem.org/install.sh | sh
```
-Pre-built packages (`.pkg` for macOS and `.deb` for Linux) are also available from the [latest release](https://github.com/google/capsem/releases/latest). See the [Getting Started](https://capsem.org/getting-started/) guide for details.
+Pre-built binaries (DMG, .deb, .AppImage) are also available from the [latest release](https://github.com/google/capsem/releases/latest). See the [Getting Started](https://capsem.org/getting-started/) guide for details.
## Quick start
diff --git a/benchmarks/archive/benchmark-prerun-20260530T123916Z.zip b/benchmarks/archive/benchmark-prerun-20260530T123916Z.zip
deleted file mode 100644
index dcc225609..000000000
Binary files a/benchmarks/archive/benchmark-prerun-20260530T123916Z.zip and /dev/null differ
diff --git a/benchmarks/capsem-bench/data_1.0.1776688771_arm64.json b/benchmarks/capsem-bench/data_1.0.1776688771_arm64.json
new file mode 100644
index 000000000..cb7c5ad80
--- /dev/null
+++ b/benchmarks/capsem-bench/data_1.0.1776688771_arm64.json
@@ -0,0 +1,200 @@
+{
+ "version": "0.3.0",
+ "timestamp": 1776965821.3383114,
+ "hostname": "bench-32cf113e",
+ "disk": {
+ "directory": "/root",
+ "size_mb": 256,
+ "seq_write": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 202.3,
+ "throughput_mbps": 1265.5
+ },
+ "seq_read": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 78.4,
+ "throughput_mbps": 3264.5
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1107.4,
+ "iops": 9029.9,
+ "throughput_mbps": 35.3
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 209.1,
+ "iops": 47828.6,
+ "throughput_mbps": 186.8
+ }
+ },
+ "rootfs": {
+ "scan_dirs": [
+ "/usr/bin",
+ "/usr/lib",
+ "/opt/ai-clis"
+ ],
+ "largest_file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/codex/codex",
+ "largest_file_size": 140188592,
+ "seq_read": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/codex/codex",
+ "size_bytes": 140188592,
+ "block_size": 1048576,
+ "duration_ms": 196.9,
+ "throughput_mbps": 678.9
+ },
+ "files_found": 3335,
+ "rand_read_4k": {
+ "count": 5000,
+ "files_sampled": 2591,
+ "block_size": 4096,
+ "duration_ms": 656.1,
+ "iops": 7621.0,
+ "throughput_mbps": 29.8
+ }
+ },
+ "startup": {
+ "runs_per_command": 3,
+ "commands": {
+ "python3": {
+ "command": [
+ "python3",
+ "--version"
+ ],
+ "timings_ms": [
+ 4.9,
+ 7.5,
+ 4.6
+ ],
+ "min_ms": 4.6,
+ "mean_ms": 5.7,
+ "max_ms": 7.5
+ },
+ "node": {
+ "command": [
+ "node",
+ "--version"
+ ],
+ "timings_ms": [
+ 127.0,
+ 130.4,
+ 82.4
+ ],
+ "min_ms": 82.4,
+ "mean_ms": 113.3,
+ "max_ms": 130.4
+ },
+ "claude": {
+ "command": [
+ "claude",
+ "--version"
+ ],
+ "timings_ms": [
+ 282.7,
+ 292.2,
+ 291.9
+ ],
+ "min_ms": 282.7,
+ "mean_ms": 288.9,
+ "max_ms": 292.2
+ },
+ "gemini": {
+ "command": [
+ "gemini",
+ "--version"
+ ],
+ "timings_ms": [
+ 608.3,
+ 604.7,
+ 604.8
+ ],
+ "min_ms": 604.7,
+ "mean_ms": 605.9,
+ "max_ms": 608.3
+ },
+ "codex": {
+ "command": [
+ "codex",
+ "--version"
+ ],
+ "timings_ms": [
+ 241.0,
+ 237.1,
+ 241.1
+ ],
+ "min_ms": 237.1,
+ "mean_ms": 239.7,
+ "max_ms": 241.1
+ }
+ }
+ },
+ "http": {
+ "url": "https://www.google.com/",
+ "total_requests": 50,
+ "concurrency": 5,
+ "successful": 5,
+ "failed": 45,
+ "total_duration_ms": 555.2,
+ "requests_per_sec": 90.1,
+ "transfer_bytes": 406607,
+ "latency_ms": {
+ "min": 30.2,
+ "max": 177.7,
+ "mean": 52.7,
+ "p50": 33.5,
+ "p95": 176.3,
+ "p99": 177.3
+ }
+ },
+ "throughput": {
+ "url": "https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-slides.pdf",
+ "http_code": 200,
+ "size_bytes": 9984968,
+ "duration_s": 0.412,
+ "throughput_mbps": 23.13
+ },
+ "snapshot": {
+ "10_files": {
+ "create_ms": 843.7,
+ "create_ok": true,
+ "list_ms": 360.4,
+ "list_ok": true,
+ "changes_ms": 357.7,
+ "changes_ok": true,
+ "revert_ms": 364.7,
+ "revert_ok": true,
+ "delete_ms": 356.0,
+ "delete_ok": true
+ },
+ "100_files": {
+ "create_ms": 354.4,
+ "create_ok": true,
+ "list_ms": 353.8,
+ "list_ok": true,
+ "changes_ms": 365.4,
+ "changes_ok": true,
+ "revert_ms": 361.7,
+ "revert_ok": true,
+ "delete_ms": 374.6,
+ "delete_ok": true
+ },
+ "500_files": {
+ "create_ms": 361.8,
+ "create_ok": true,
+ "list_ms": 364.2,
+ "list_ok": true,
+ "changes_ms": 399.0,
+ "changes_ok": true,
+ "revert_ms": 364.6,
+ "revert_ok": true,
+ "delete_ms": 394.7,
+ "delete_ok": true
+ }
+ },
+ "host_recorded_at": 1776965835.584404,
+ "arch": "arm64"
+}
\ No newline at end of file
diff --git a/benchmarks/capsem-bench/data_1.0.1777065213_arm64.json b/benchmarks/capsem-bench/data_1.0.1777065213_arm64.json
new file mode 100644
index 000000000..4ba9f3550
--- /dev/null
+++ b/benchmarks/capsem-bench/data_1.0.1777065213_arm64.json
@@ -0,0 +1,200 @@
+{
+ "version": "0.3.0",
+ "timestamp": 1780609605.243969,
+ "hostname": "bench-f4788375",
+ "disk": {
+ "directory": "/root",
+ "size_mb": 256,
+ "seq_write": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 113.5,
+ "throughput_mbps": 2254.7
+ },
+ "seq_read": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 64.4,
+ "throughput_mbps": 3976.1
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1391.0,
+ "iops": 7188.9,
+ "throughput_mbps": 28.1
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 185.9,
+ "iops": 53795.6,
+ "throughput_mbps": 210.1
+ }
+ },
+ "rootfs": {
+ "scan_dirs": [
+ "/usr/bin",
+ "/usr/lib",
+ "/opt/ai-clis"
+ ],
+ "largest_file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "largest_file_size": 193339016,
+ "seq_read": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 193339016,
+ "block_size": 1048576,
+ "duration_ms": 58.7,
+ "throughput_mbps": 3138.7
+ },
+ "files_found": 3317,
+ "rand_read_4k": {
+ "count": 5000,
+ "files_sampled": 2633,
+ "block_size": 4096,
+ "duration_ms": 159.8,
+ "iops": 31283.9,
+ "throughput_mbps": 122.2
+ }
+ },
+ "startup": {
+ "runs_per_command": 3,
+ "commands": {
+ "python3": {
+ "command": [
+ "python3",
+ "--version"
+ ],
+ "timings_ms": [
+ 3.7,
+ 3.7,
+ 5.7
+ ],
+ "min_ms": 3.7,
+ "mean_ms": 4.4,
+ "max_ms": 5.7
+ },
+ "node": {
+ "command": [
+ "node",
+ "--version"
+ ],
+ "timings_ms": [
+ 25.7,
+ 23.3,
+ 26.9
+ ],
+ "min_ms": 23.3,
+ "mean_ms": 25.3,
+ "max_ms": 26.9
+ },
+ "claude": {
+ "command": [
+ "claude",
+ "--version"
+ ],
+ "timings_ms": [
+ 138.2,
+ 131.4,
+ 134.9
+ ],
+ "min_ms": 131.4,
+ "mean_ms": 134.8,
+ "max_ms": 138.2
+ },
+ "gemini": {
+ "command": [
+ "gemini",
+ "--version"
+ ],
+ "timings_ms": [
+ 658.5,
+ 653.4,
+ 701.5
+ ],
+ "min_ms": 653.4,
+ "mean_ms": 671.1,
+ "max_ms": 701.5
+ },
+ "codex": {
+ "command": [
+ "codex",
+ "--version"
+ ],
+ "timings_ms": [
+ 80.2,
+ 79.6,
+ 79.8
+ ],
+ "min_ms": 79.6,
+ "mean_ms": 79.9,
+ "max_ms": 80.2
+ }
+ }
+ },
+ "http": {
+ "url": "https://www.google.com/",
+ "total_requests": 50,
+ "concurrency": 5,
+ "successful": 50,
+ "failed": 0,
+ "total_duration_ms": 1068.5,
+ "requests_per_sec": 46.8,
+ "transfer_bytes": 4015061,
+ "latency_ms": {
+ "min": 55.9,
+ "max": 223.9,
+ "mean": 89.4,
+ "p50": 85.1,
+ "p95": 197.6,
+ "p99": 219.8
+ }
+ },
+ "throughput": {
+ "url": "https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-slides.pdf",
+ "http_code": 200,
+ "size_bytes": 9984968,
+ "duration_s": 0.407,
+ "throughput_mbps": 23.39
+ },
+ "snapshot": {
+ "10_files": {
+ "create_ms": 591.3,
+ "create_ok": true,
+ "list_ms": 246.9,
+ "list_ok": true,
+ "changes_ms": 248.8,
+ "changes_ok": true,
+ "revert_ms": 275.3,
+ "revert_ok": true,
+ "delete_ms": 259.5,
+ "delete_ok": true
+ },
+ "100_files": {
+ "create_ms": 268.8,
+ "create_ok": true,
+ "list_ms": 270.2,
+ "list_ok": true,
+ "changes_ms": 255.2,
+ "changes_ok": true,
+ "revert_ms": 271.4,
+ "revert_ok": true,
+ "delete_ms": 251.2,
+ "delete_ok": true
+ },
+ "500_files": {
+ "create_ms": 259.5,
+ "create_ok": true,
+ "list_ms": 270.5,
+ "list_ok": true,
+ "changes_ms": 274.2,
+ "changes_ok": true,
+ "revert_ms": 269.0,
+ "revert_ok": true,
+ "delete_ms": 274.7,
+ "delete_ok": true
+ }
+ },
+ "host_recorded_at": 1780609617.394242,
+ "arch": "arm64"
+}
\ No newline at end of file
diff --git a/benchmarks/capsem-bench/data_1.0.1780610732_arm64.json b/benchmarks/capsem-bench/data_1.0.1780610732_arm64.json
new file mode 100644
index 000000000..0c6ab8b04
--- /dev/null
+++ b/benchmarks/capsem-bench/data_1.0.1780610732_arm64.json
@@ -0,0 +1,200 @@
+{
+ "version": "0.3.0",
+ "timestamp": 1780761728.0924034,
+ "hostname": "bench-6c283fc9",
+ "disk": {
+ "directory": "/root",
+ "size_mb": 256,
+ "seq_write": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 144.0,
+ "throughput_mbps": 1777.7
+ },
+ "seq_read": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 59.2,
+ "throughput_mbps": 4326.0
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1350.1,
+ "iops": 7407.0,
+ "throughput_mbps": 28.9
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 188.7,
+ "iops": 52983.3,
+ "throughput_mbps": 207.0
+ }
+ },
+ "rootfs": {
+ "scan_dirs": [
+ "/usr/bin",
+ "/usr/lib",
+ "/opt/ai-clis"
+ ],
+ "largest_file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "largest_file_size": 193339016,
+ "seq_read": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 193339016,
+ "block_size": 1048576,
+ "duration_ms": 57.6,
+ "throughput_mbps": 3198.6
+ },
+ "files_found": 3317,
+ "rand_read_4k": {
+ "count": 5000,
+ "files_sampled": 2598,
+ "block_size": 4096,
+ "duration_ms": 152.6,
+ "iops": 32775.1,
+ "throughput_mbps": 128.0
+ }
+ },
+ "startup": {
+ "runs_per_command": 3,
+ "commands": {
+ "python3": {
+ "command": [
+ "python3",
+ "--version"
+ ],
+ "timings_ms": [
+ 7.6,
+ 6.8,
+ 3.1
+ ],
+ "min_ms": 3.1,
+ "mean_ms": 5.8,
+ "max_ms": 7.6
+ },
+ "node": {
+ "command": [
+ "node",
+ "--version"
+ ],
+ "timings_ms": [
+ 25.6,
+ 21.9,
+ 27.1
+ ],
+ "min_ms": 21.9,
+ "mean_ms": 24.9,
+ "max_ms": 27.1
+ },
+ "claude": {
+ "command": [
+ "claude",
+ "--version"
+ ],
+ "timings_ms": [
+ 138.1,
+ 131.8,
+ 131.5
+ ],
+ "min_ms": 131.5,
+ "mean_ms": 133.8,
+ "max_ms": 138.1
+ },
+ "gemini": {
+ "command": [
+ "gemini",
+ "--version"
+ ],
+ "timings_ms": [
+ 710.4,
+ 655.0,
+ 673.1
+ ],
+ "min_ms": 655.0,
+ "mean_ms": 679.5,
+ "max_ms": 710.4
+ },
+ "codex": {
+ "command": [
+ "codex",
+ "--version"
+ ],
+ "timings_ms": [
+ 81.4,
+ 75.9,
+ 80.7
+ ],
+ "min_ms": 75.9,
+ "mean_ms": 79.3,
+ "max_ms": 81.4
+ }
+ }
+ },
+ "http": {
+ "url": "https://www.google.com/",
+ "total_requests": 50,
+ "concurrency": 5,
+ "successful": 50,
+ "failed": 0,
+ "total_duration_ms": 760.8,
+ "requests_per_sec": 65.7,
+ "transfer_bytes": 4013601,
+ "latency_ms": {
+ "min": 52.0,
+ "max": 208.3,
+ "mean": 74.9,
+ "p50": 59.0,
+ "p95": 203.0,
+ "p99": 207.5
+ }
+ },
+ "throughput": {
+ "url": "https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-slides.pdf",
+ "http_code": 200,
+ "size_bytes": 9984968,
+ "duration_s": 0.422,
+ "throughput_mbps": 22.54
+ },
+ "snapshot": {
+ "10_files": {
+ "create_ms": 621.8,
+ "create_ok": true,
+ "list_ms": 252.2,
+ "list_ok": true,
+ "changes_ms": 245.8,
+ "changes_ok": true,
+ "revert_ms": 259.1,
+ "revert_ok": true,
+ "delete_ms": 243.8,
+ "delete_ok": true
+ },
+ "100_files": {
+ "create_ms": 246.5,
+ "create_ok": true,
+ "list_ms": 256.8,
+ "list_ok": true,
+ "changes_ms": 249.7,
+ "changes_ok": true,
+ "revert_ms": 256.8,
+ "revert_ok": true,
+ "delete_ms": 250.8,
+ "delete_ok": true
+ },
+ "500_files": {
+ "create_ms": 252.4,
+ "create_ok": true,
+ "list_ms": 249.9,
+ "list_ok": true,
+ "changes_ms": 265.8,
+ "changes_ok": true,
+ "revert_ms": 256.3,
+ "revert_ok": true,
+ "delete_ms": 258.7,
+ "delete_ok": true
+ }
+ },
+ "host_recorded_at": 1780761739.914814,
+ "arch": "arm64"
+}
\ No newline at end of file
diff --git a/benchmarks/capsem-bench/data_1.0.1780977620_arm64.json b/benchmarks/capsem-bench/data_1.0.1780977620_arm64.json
new file mode 100644
index 000000000..60b85e672
--- /dev/null
+++ b/benchmarks/capsem-bench/data_1.0.1780977620_arm64.json
@@ -0,0 +1,1479 @@
+{
+ "version": "0.3.0",
+ "timestamp": 1781016632.2157617,
+ "hostname": "bench-df79ad33",
+ "disk": {
+ "directory": "/root",
+ "size_mb": 256,
+ "seq_write": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 139.1,
+ "throughput_mbps": 1841.0
+ },
+ "seq_read": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 64.5,
+ "throughput_mbps": 3967.2
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1289.1,
+ "iops": 7757.4,
+ "throughput_mbps": 30.3
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 196.6,
+ "iops": 50855.3,
+ "throughput_mbps": 198.7
+ }
+ },
+ "rootfs": {
+ "scan_dirs": [
+ "/usr/bin",
+ "/usr/lib",
+ "/opt/ai-clis"
+ ],
+ "largest_file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "largest_file_size": 193339016,
+ "seq_read": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 193339016,
+ "block_size": 1048576,
+ "duration_ms": 54.3,
+ "throughput_mbps": 3396.7
+ },
+ "files_found": 5548,
+ "rand_read_4k": {
+ "count": 5000,
+ "files_sampled": 2597,
+ "block_size": 4096,
+ "duration_ms": 171.4,
+ "iops": 29169.0,
+ "throughput_mbps": 113.9
+ },
+ "large_binary_seq_read": {
+ "count": 2,
+ "files": [
+ {
+ "path": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 193339016,
+ "cold": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 193339016,
+ "block_size": 1048576,
+ "duration_ms": 56.0,
+ "throughput_mbps": 3295.4
+ },
+ "warm": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 193339016,
+ "block_size": 1048576,
+ "duration_ms": 8.7,
+ "throughput_mbps": 21230.8
+ }
+ },
+ {
+ "path": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "cold": {
+ "file": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "block_size": 1048576,
+ "duration_ms": 7.9,
+ "throughput_mbps": 4728.0
+ },
+ "warm": {
+ "file": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "block_size": 1048576,
+ "duration_ms": 1.7,
+ "throughput_mbps": 22236.6
+ }
+ }
+ ],
+ "bytes_read": 232501520,
+ "cold_duration_ms": 63.9,
+ "warm_duration_ms": 10.4,
+ "cold_throughput_mbps": 3470.0,
+ "warm_throughput_mbps": 21320.3
+ },
+ "small_js_read": {
+ "count": 5000,
+ "files_sampled": 110,
+ "bytes_read": 51356173,
+ "duration_ms": 7.7,
+ "ops_per_sec": 648273.7,
+ "throughput_mbps": 6350.1
+ },
+ "metadata_stat": {
+ "entries": 6552,
+ "files": 5548,
+ "dirs": 661,
+ "symlinks": 343,
+ "errors": 0,
+ "duration_ms": 46.1,
+ "stats_per_sec": 142110.5
+ }
+ },
+ "storage": {
+ "kernel": {
+ "cmdline": {
+ "raw": "console=hvc0 ro loglevel=1 quiet init_on_alloc=1 slab_nomerge page_alloc.shuffle=1 random.trust_cpu=1 capsem.storage=virtiofs capsem.rootfs=erofs",
+ "args": [
+ "console=hvc0",
+ "ro",
+ "loglevel=1",
+ "quiet",
+ "init_on_alloc=1",
+ "slab_nomerge",
+ "page_alloc.shuffle=1",
+ "random.trust_cpu=1",
+ "capsem.storage=virtiofs",
+ "capsem.rootfs=erofs"
+ ]
+ },
+ "block_queues": {
+ "vda": {
+ "scheduler": "[none] mq-deadline kyber",
+ "read_ahead_kb": 4096,
+ "nr_requests": 256,
+ "rotational": 1,
+ "logical_block_size": 512,
+ "physical_block_size": 512,
+ "max_sectors_kb": 4096,
+ "nomerges": 0,
+ "rq_affinity": 1,
+ "io_poll": 0,
+ "selected_scheduler": "none"
+ },
+ "vdb": {
+ "scheduler": "[none] mq-deadline kyber",
+ "read_ahead_kb": 4096,
+ "nr_requests": 256,
+ "rotational": 1,
+ "logical_block_size": 512,
+ "physical_block_size": 512,
+ "max_sectors_kb": 4096,
+ "nomerges": 0,
+ "rq_affinity": 1,
+ "io_poll": 0,
+ "selected_scheduler": "none"
+ }
+ },
+ "fuse_connections": {},
+ "known_host_queue_sizes": {
+ "kvm_virtio_blk": 256,
+ "kvm_virtio_fs": [
+ 256,
+ 256
+ ]
+ }
+ },
+ "mounts": [
+ {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ {
+ "mount_point": "/proc",
+ "root": "/",
+ "fs_type": "proc",
+ "source": "proc",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/sys",
+ "root": "/",
+ "fs_type": "sysfs",
+ "source": "sysfs",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/dev",
+ "root": "/",
+ "fs_type": "devtmpfs",
+ "source": "devtmpfs",
+ "options": "rw,size=1021592k,nr_inodes=255398,mode=755"
+ },
+ {
+ "mount_point": "/dev/pts",
+ "root": "/",
+ "fs_type": "devpts",
+ "source": "devpts",
+ "options": "rw,mode=600,ptmxmode=000"
+ },
+ {
+ "mount_point": "/root",
+ "root": "/workspace",
+ "fs_type": "virtiofs",
+ "source": "capsem",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/etc/resolv.conf",
+ "root": "/run/resolv.conf",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ }
+ ],
+ "paths": {
+ "/": {
+ "path": "/",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496853,
+ "blocks_available": 492757,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/root": {
+ "path": "/root",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/root",
+ "root": "/workspace",
+ "fs_type": "virtiofs",
+ "source": "capsem",
+ "options": "rw"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 1048576,
+ "fragment_size": 4096,
+ "blocks": 975653540,
+ "blocks_free": 716930835,
+ "blocks_available": 716930835,
+ "files": 2911018441,
+ "files_free": 2907429624
+ }
+ },
+ "/tmp": {
+ "path": "/tmp",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxrwxrwt",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496853,
+ "blocks_available": 492757,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/var/tmp": {
+ "path": "/var/tmp",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxrwxrwt",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496853,
+ "blocks_available": 492757,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/var/log": {
+ "path": "/var/log",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496853,
+ "blocks_available": 492757,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/run": {
+ "path": "/run",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496853,
+ "blocks_available": 492757,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/usr/bin": {
+ "path": "/usr/bin",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496853,
+ "blocks_available": 492757,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/usr/lib": {
+ "path": "/usr/lib",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496853,
+ "blocks_available": 492757,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/opt/ai-clis": {
+ "path": "/opt/ai-clis",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496853,
+ "blocks_available": 492757,
+ "files": 131072,
+ "files_free": 130928
+ }
+ }
+ },
+ "rootfs": {
+ "scan_dirs": [
+ "/usr/bin",
+ "/usr/lib",
+ "/opt/ai-clis"
+ ],
+ "files_found": 3328,
+ "largest_file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "largest_file_size": 193339016,
+ "backing": {
+ "root_mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "overlay_lowerdir": "/mnt/a",
+ "overlay_upperdir": "/mnt/system/upper",
+ "overlay_workdir": "/mnt/system/work",
+ "squashfs_mounts": [],
+ "squashfs_superblock": {
+ "device": "/dev/vda",
+ "magic": "0x00000000",
+ "error": "not squashfs",
+ "read_ahead_kb": 4096
+ }
+ },
+ "seq_reads": [
+ {
+ "label": "largest",
+ "path": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 193339016,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 193339016,
+ "block_size": 1048576,
+ "duration_ms": 52.8,
+ "throughput_mbps": 3492.1
+ },
+ "warm": {
+ "size_bytes": 193339016,
+ "block_size": 1048576,
+ "duration_ms": 8.0,
+ "throughput_mbps": 22968.0
+ }
+ },
+ {
+ "label": "bash",
+ "path": "/bin/bash",
+ "size_bytes": 1346480,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 1346480,
+ "block_size": 1048576,
+ "duration_ms": 0.3,
+ "throughput_mbps": 4922.3
+ },
+ "warm": {
+ "size_bytes": 1346480,
+ "block_size": 1048576,
+ "duration_ms": 0.3,
+ "throughput_mbps": 4597.0
+ }
+ },
+ {
+ "label": "python3",
+ "path": "/usr/bin/python3",
+ "size_bytes": 6616880,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 6616880,
+ "block_size": 1048576,
+ "duration_ms": 1.1,
+ "throughput_mbps": 5541.7
+ },
+ "warm": {
+ "size_bytes": 6616880,
+ "block_size": 1048576,
+ "duration_ms": 0.3,
+ "throughput_mbps": 23929.2
+ }
+ }
+ ],
+ "rand_read_4k": {
+ "count": 2000,
+ "files_sampled": 1483,
+ "duration_ms": 79.5,
+ "iops": 25169.5,
+ "throughput_mbps": 98.3
+ }
+ },
+ "writable": {
+ "/root": {
+ "path": "/root",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 21.6,
+ "throughput_mbps": 2967.1
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 14.5,
+ "throughput_mbps": 4407.7
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 14.3,
+ "throughput_mbps": 4470.9
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1247.4,
+ "iops": 8016.4,
+ "throughput_mbps": 31.3
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 189.0,
+ "iops": 52909.5,
+ "throughput_mbps": 206.7
+ },
+ "io_profile": {
+ "path": "/root",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 968.2,
+ "iops": 16922.4,
+ "throughput_mbps": 66.1,
+ "avg_latency_ms": 0.059
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 18.3,
+ "iops": 895390.2,
+ "throughput_mbps": 3497.6,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 17.1,
+ "iops": 955792.7,
+ "throughput_mbps": 3733.6,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 72.4,
+ "iops": 14143.0,
+ "throughput_mbps": 883.9,
+ "avg_latency_ms": 0.071
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 15.7,
+ "iops": 65304.2,
+ "throughput_mbps": 4081.5,
+ "avg_latency_ms": 0.015
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 15.2,
+ "iops": 67392.4,
+ "throughput_mbps": 4212.0,
+ "avg_latency_ms": 0.015
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 26.4,
+ "iops": 2424.8,
+ "throughput_mbps": 2424.8,
+ "avg_latency_ms": 0.412
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 14.9,
+ "iops": 4289.3,
+ "throughput_mbps": 4289.3,
+ "avg_latency_ms": 0.233
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 14.9,
+ "iops": 4283.3,
+ "throughput_mbps": 4283.3,
+ "avg_latency_ms": 0.233
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 47.9,
+ "iops": 41719.7,
+ "throughput_mbps": 163.0,
+ "avg_latency_ms": 0.024,
+ "latency_ms": {
+ "p50": 0.025,
+ "p95": 0.03,
+ "p99": 0.034,
+ "max": 0.05
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 219.5,
+ "iops": 9110.4,
+ "throughput_mbps": 35.6,
+ "avg_latency_ms": 0.11,
+ "latency_ms": {
+ "p50": 0.109,
+ "p95": 0.123,
+ "p99": 0.131,
+ "max": 0.379
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/tmp": {
+ "path": "/tmp",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 9.9,
+ "throughput_mbps": 6450.8
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 6.5,
+ "throughput_mbps": 9857.7
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 4.5,
+ "throughput_mbps": 14239.4
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1570.8,
+ "iops": 6366.4,
+ "throughput_mbps": 24.9
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.0,
+ "iops": 1434385.8,
+ "throughput_mbps": 5603.1
+ },
+ "io_profile": {
+ "path": "/tmp",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 16.7,
+ "iops": 979640.6,
+ "throughput_mbps": 3826.7,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 11.7,
+ "iops": 1399444.8,
+ "throughput_mbps": 5466.6,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 10.5,
+ "iops": 1567259.4,
+ "throughput_mbps": 6122.1,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 10.8,
+ "iops": 95036.3,
+ "throughput_mbps": 5939.8,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.8,
+ "iops": 149812.6,
+ "throughput_mbps": 9363.3,
+ "avg_latency_ms": 0.007
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 5.9,
+ "iops": 172181.6,
+ "throughput_mbps": 10761.4,
+ "avg_latency_ms": 0.006
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 43.9,
+ "iops": 1456.2,
+ "throughput_mbps": 1456.2,
+ "avg_latency_ms": 0.687
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 6.5,
+ "iops": 9881.1,
+ "throughput_mbps": 9881.1,
+ "avg_latency_ms": 0.101
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 5.2,
+ "iops": 12299.8,
+ "throughput_mbps": 12299.8,
+ "avg_latency_ms": 0.081
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 60.8,
+ "iops": 32883.9,
+ "throughput_mbps": 128.5,
+ "avg_latency_ms": 0.03,
+ "latency_ms": {
+ "p50": 0.032,
+ "p95": 0.037,
+ "p99": 0.041,
+ "max": 0.06
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 126.4,
+ "iops": 15817.9,
+ "throughput_mbps": 61.8,
+ "avg_latency_ms": 0.063,
+ "latency_ms": {
+ "p50": 0.062,
+ "p95": 0.073,
+ "p99": 0.136,
+ "max": 0.185
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/var/tmp": {
+ "path": "/var/tmp",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 14.3,
+ "throughput_mbps": 4470.1
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 6.4,
+ "throughput_mbps": 9952.9
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.2,
+ "throughput_mbps": 12358.5
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1343.1,
+ "iops": 7445.7,
+ "throughput_mbps": 29.1
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.4,
+ "iops": 1348648.0,
+ "throughput_mbps": 5268.2
+ },
+ "io_profile": {
+ "path": "/var/tmp",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 18.3,
+ "iops": 895404.5,
+ "throughput_mbps": 3497.7,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 11.4,
+ "iops": 1431974.8,
+ "throughput_mbps": 5593.7,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 10.6,
+ "iops": 1551999.0,
+ "throughput_mbps": 6062.5,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 10.9,
+ "iops": 93794.0,
+ "throughput_mbps": 5862.1,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 7.1,
+ "iops": 144702.6,
+ "throughput_mbps": 9043.9,
+ "avg_latency_ms": 0.007
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.1,
+ "iops": 166679.1,
+ "throughput_mbps": 10417.4,
+ "avg_latency_ms": 0.006
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 11.7,
+ "iops": 5460.2,
+ "throughput_mbps": 5460.2,
+ "avg_latency_ms": 0.183
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 6.3,
+ "iops": 10088.0,
+ "throughput_mbps": 10088.0,
+ "avg_latency_ms": 0.099
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 5.4,
+ "iops": 11858.3,
+ "throughput_mbps": 11858.3,
+ "avg_latency_ms": 0.084
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 60.1,
+ "iops": 33280.5,
+ "throughput_mbps": 130.0,
+ "avg_latency_ms": 0.03,
+ "latency_ms": {
+ "p50": 0.032,
+ "p95": 0.036,
+ "p99": 0.041,
+ "max": 0.056
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 124.5,
+ "iops": 16067.1,
+ "throughput_mbps": 62.8,
+ "avg_latency_ms": 0.062,
+ "latency_ms": {
+ "p50": 0.06,
+ "p95": 0.071,
+ "p99": 0.14,
+ "max": 0.191
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/var/log": {
+ "path": "/var/log",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 10.5,
+ "throughput_mbps": 6122.4
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 7.0,
+ "throughput_mbps": 9168.9
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.6,
+ "throughput_mbps": 11426.3
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1351.4,
+ "iops": 7399.7,
+ "throughput_mbps": 28.9
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.8,
+ "iops": 1273892.0,
+ "throughput_mbps": 4976.1
+ },
+ "io_profile": {
+ "path": "/var/log",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 22.4,
+ "iops": 731308.9,
+ "throughput_mbps": 2856.7,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 12.3,
+ "iops": 1332533.6,
+ "throughput_mbps": 5205.2,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 9.7,
+ "iops": 1693327.3,
+ "throughput_mbps": 6614.6,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 10.9,
+ "iops": 94354.3,
+ "throughput_mbps": 5897.1,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 7.8,
+ "iops": 131846.2,
+ "throughput_mbps": 8240.4,
+ "avg_latency_ms": 0.008
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 5.4,
+ "iops": 189201.9,
+ "throughput_mbps": 11825.1,
+ "avg_latency_ms": 0.005
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 12.4,
+ "iops": 5146.9,
+ "throughput_mbps": 5146.9,
+ "avg_latency_ms": 0.194
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 7.1,
+ "iops": 9029.2,
+ "throughput_mbps": 9029.2,
+ "avg_latency_ms": 0.111
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 4.6,
+ "iops": 13804.8,
+ "throughput_mbps": 13804.8,
+ "avg_latency_ms": 0.072
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 39.8,
+ "iops": 50306.9,
+ "throughput_mbps": 196.5,
+ "avg_latency_ms": 0.02,
+ "latency_ms": {
+ "p50": 0.021,
+ "p95": 0.024,
+ "p99": 0.028,
+ "max": 0.044
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 88.8,
+ "iops": 22526.3,
+ "throughput_mbps": 88.0,
+ "avg_latency_ms": 0.044,
+ "latency_ms": {
+ "p50": 0.041,
+ "p95": 0.062,
+ "p99": 0.138,
+ "max": 0.188
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/run": {
+ "path": "/run",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 10.9,
+ "throughput_mbps": 5884.4
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 7.2,
+ "throughput_mbps": 8905.0
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.8,
+ "throughput_mbps": 11076.7
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1345.7,
+ "iops": 7430.9,
+ "throughput_mbps": 29.0
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.7,
+ "iops": 1299481.8,
+ "throughput_mbps": 5076.1
+ },
+ "io_profile": {
+ "path": "/run",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 19.1,
+ "iops": 859067.9,
+ "throughput_mbps": 3355.7,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 12.9,
+ "iops": 1265377.3,
+ "throughput_mbps": 4942.9,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 10.9,
+ "iops": 1506707.4,
+ "throughput_mbps": 5885.6,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 11.3,
+ "iops": 90274.6,
+ "throughput_mbps": 5642.2,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 8.8,
+ "iops": 116792.2,
+ "throughput_mbps": 7299.5,
+ "avg_latency_ms": 0.009
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.6,
+ "iops": 156294.1,
+ "throughput_mbps": 9768.4,
+ "avg_latency_ms": 0.006
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 12.1,
+ "iops": 5282.4,
+ "throughput_mbps": 5282.4,
+ "avg_latency_ms": 0.189
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 7.8,
+ "iops": 8198.7,
+ "throughput_mbps": 8198.7,
+ "avg_latency_ms": 0.122
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 5.7,
+ "iops": 11170.5,
+ "throughput_mbps": 11170.5,
+ "avg_latency_ms": 0.09
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 39.9,
+ "iops": 50101.5,
+ "throughput_mbps": 195.7,
+ "avg_latency_ms": 0.02,
+ "latency_ms": {
+ "p50": 0.021,
+ "p95": 0.025,
+ "p99": 0.028,
+ "max": 0.062
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 98.6,
+ "iops": 20293.6,
+ "throughput_mbps": 79.3,
+ "avg_latency_ms": 0.049,
+ "latency_ms": {
+ "p50": 0.042,
+ "p95": 0.067,
+ "p99": 0.135,
+ "max": 0.198
+ },
+ "sync_each": true
+ }
+ }
+ }
+ }
+ }
+ },
+ "startup": {
+ "runs_per_command": 3,
+ "commands": {
+ "python3": {
+ "command": [
+ "python3",
+ "--version"
+ ],
+ "timings_ms": [
+ 2.7,
+ 4.3,
+ 3.3
+ ],
+ "min_ms": 2.7,
+ "mean_ms": 3.4,
+ "max_ms": 4.3
+ },
+ "node": {
+ "command": [
+ "node",
+ "--version"
+ ],
+ "timings_ms": [
+ 25.1,
+ 26.3,
+ 26.7
+ ],
+ "min_ms": 25.1,
+ "mean_ms": 26.0,
+ "max_ms": 26.7
+ },
+ "claude": {
+ "command": [
+ "claude",
+ "--version"
+ ],
+ "timings_ms": [
+ 137.8,
+ 139.2,
+ 139.2
+ ],
+ "min_ms": 137.8,
+ "mean_ms": 138.7,
+ "max_ms": 139.2
+ },
+ "gemini": {
+ "command": [
+ "gemini",
+ "--version"
+ ],
+ "timings_ms": [
+ 666.8,
+ 656.8,
+ 660.6
+ ],
+ "min_ms": 656.8,
+ "mean_ms": 661.4,
+ "max_ms": 666.8
+ },
+ "codex": {
+ "command": [
+ "codex",
+ "--version"
+ ],
+ "timings_ms": [
+ 80.9,
+ 79.2,
+ 81.0
+ ],
+ "min_ms": 79.2,
+ "mean_ms": 80.4,
+ "max_ms": 81.0
+ }
+ }
+ },
+ "http": {
+ "skipped": true,
+ "reason": "set CAPSEM_BENCH_MITM_LOCAL_BASE_URL for local lab or CAPSEM_BENCH_ALLOW_PUBLIC_NETWORK=1 for explicit public smoke"
+ },
+ "throughput": {
+ "skipped": true,
+ "reason": "set CAPSEM_BENCH_MITM_LOCAL_BASE_URL for local lab or CAPSEM_BENCH_ALLOW_PUBLIC_NETWORK=1 for explicit public smoke"
+ },
+ "snapshot": {
+ "10_files": {
+ "create_ms": 711.2,
+ "create_ok": true,
+ "list_ms": 249.1,
+ "list_ok": true,
+ "changes_ms": 260.9,
+ "changes_ok": true,
+ "revert_ms": 262.2,
+ "revert_ok": true,
+ "delete_ms": 333.9,
+ "delete_ok": true
+ },
+ "100_files": {
+ "create_ms": 262.4,
+ "create_ok": true,
+ "list_ms": 261.9,
+ "list_ok": true,
+ "changes_ms": 256.3,
+ "changes_ok": true,
+ "revert_ms": 266.1,
+ "revert_ok": true,
+ "delete_ms": 299.2,
+ "delete_ok": true
+ },
+ "500_files": {
+ "create_ms": 265.4,
+ "create_ok": true,
+ "list_ms": 252.2,
+ "list_ok": true,
+ "changes_ms": 268.4,
+ "changes_ok": true,
+ "revert_ms": 268.5,
+ "revert_ok": true,
+ "delete_ms": 329.9,
+ "delete_ok": true
+ }
+ },
+ "host_recorded_at": 1781016653.162519,
+ "arch": "arm64"
+}
\ No newline at end of file
diff --git a/benchmarks/capsem-bench/data_1.2.1779673506_x86_64.json b/benchmarks/capsem-bench/data_1.2.1779673506_x86_64.json
deleted file mode 100644
index a03ce866c..000000000
--- a/benchmarks/capsem-bench/data_1.2.1779673506_x86_64.json
+++ /dev/null
@@ -1,1560 +0,0 @@
-{
- "version": "0.3.0",
- "timestamp": 1780145036.0179684,
- "hostname": "bench-f7b66ad7",
- "disk": {
- "directory": "/root",
- "size_mb": 256,
- "seq_write": {
- "size_bytes": 268435456,
- "block_size": 1048576,
- "duration_ms": 1620.1,
- "throughput_mbps": 158.0
- },
- "seq_read": {
- "size_bytes": 268435456,
- "block_size": 1048576,
- "duration_ms": 612.1,
- "throughput_mbps": 418.3
- },
- "rand_write_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 3635.9,
- "iops": 2750.4,
- "throughput_mbps": 10.7
- },
- "rand_read_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 1316.0,
- "iops": 7598.8,
- "throughput_mbps": 29.7
- }
- },
- "rootfs": {
- "scan_dirs": [
- "/usr/bin",
- "/usr/lib",
- "/opt/ai-clis"
- ],
- "largest_file": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe",
- "largest_file_size": 239650512,
- "seq_read": {
- "file": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe",
- "size_bytes": 239650512,
- "block_size": 1048576,
- "duration_ms": 1175.8,
- "throughput_mbps": 194.4
- },
- "files_found": 5554,
- "rand_read_4k": {
- "count": 5000,
- "files_sampled": 2577,
- "block_size": 4096,
- "duration_ms": 2999.5,
- "iops": 1666.9,
- "throughput_mbps": 6.5
- },
- "large_binary_seq_read": {
- "count": 3,
- "files": [
- {
- "path": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe",
- "size_bytes": 239650512,
- "cold": {
- "file": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe",
- "size_bytes": 239650512,
- "block_size": 1048576,
- "duration_ms": 1265.5,
- "throughput_mbps": 180.6
- },
- "warm": {
- "file": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe",
- "size_bytes": 239650512,
- "block_size": 1048576,
- "duration_ms": 44.4,
- "throughput_mbps": 5151.2
- }
- },
- {
- "path": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/node_modules/@anthropic-ai/claude-code-linux-x64/claude",
- "size_bytes": 239650512,
- "cold": {
- "file": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/node_modules/@anthropic-ai/claude-code-linux-x64/claude",
- "size_bytes": 239650512,
- "block_size": 1048576,
- "duration_ms": 1126.1,
- "throughput_mbps": 203.0
- },
- "warm": {
- "file": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/node_modules/@anthropic-ai/claude-code-linux-x64/claude",
- "size_bytes": 239650512,
- "block_size": 1048576,
- "duration_ms": 40.8,
- "throughput_mbps": 5603.1
- }
- },
- {
- "path": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-x64/vendor/x86_64-unknown-linux-musl/bin/codex",
- "size_bytes": 222019904,
- "cold": {
- "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-x64/vendor/x86_64-unknown-linux-musl/bin/codex",
- "size_bytes": 222019904,
- "block_size": 1048576,
- "duration_ms": 1013.6,
- "throughput_mbps": 208.9
- },
- "warm": {
- "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-x64/vendor/x86_64-unknown-linux-musl/bin/codex",
- "size_bytes": 222019904,
- "block_size": 1048576,
- "duration_ms": 38.0,
- "throughput_mbps": 5576.9
- }
- }
- ],
- "bytes_read": 701320928,
- "cold_duration_ms": 3405.2,
- "warm_duration_ms": 123.2,
- "cold_throughput_mbps": 196.4,
- "warm_throughput_mbps": 5428.8
- },
- "small_js_read": {
- "count": 5000,
- "files_sampled": 113,
- "bytes_read": 44646123,
- "duration_ms": 59.1,
- "ops_per_sec": 84616.0,
- "throughput_mbps": 720.6
- },
- "metadata_stat": {
- "entries": 6573,
- "files": 5554,
- "dirs": 670,
- "symlinks": 349,
- "errors": 0,
- "duration_ms": 153.7,
- "stats_per_sec": 42766.4
- }
- },
- "storage": {
- "kernel": {
- "cmdline": {
- "raw": "console=ttyS0 root=/dev/vda ro loglevel=1 quiet init_on_alloc=1 slab_nomerge page_alloc.shuffle=1 random.trust_cpu=1 capsem.storage=virtiofs capsem.vsock_port_offset=38280 virtio_mmio.device=0x200@0xd0000000:5 virtio_mmio.device=0x200@0xd0000200:6 virtio_mmio.device=0x200@0xd0000400:7 virtio_mmio.device=0x200@0xd0000600:8 virtio_mmio.device=0x200@0xd0000800:9",
- "args": [
- "console=ttyS0",
- "root=/dev/vda",
- "ro",
- "loglevel=1",
- "quiet",
- "init_on_alloc=1",
- "slab_nomerge",
- "page_alloc.shuffle=1",
- "random.trust_cpu=1",
- "capsem.storage=virtiofs",
- "capsem.vsock_port_offset=38280",
- "virtio_mmio.device=0x200@0xd0000000:5",
- "virtio_mmio.device=0x200@0xd0000200:6",
- "virtio_mmio.device=0x200@0xd0000400:7",
- "virtio_mmio.device=0x200@0xd0000600:8",
- "virtio_mmio.device=0x200@0xd0000800:9"
- ]
- },
- "block_queues": {
- "vda": {
- "scheduler": "[none] mq-deadline kyber",
- "read_ahead_kb": 4096,
- "nr_requests": 128,
- "rotational": 0,
- "logical_block_size": 512,
- "physical_block_size": 512,
- "max_sectors_kb": 1280,
- "nomerges": 0,
- "rq_affinity": 1,
- "io_poll": 0,
- "selected_scheduler": "none"
- },
- "vdb": {
- "scheduler": "[none] mq-deadline kyber",
- "read_ahead_kb": 4096,
- "nr_requests": 128,
- "rotational": 0,
- "logical_block_size": 512,
- "physical_block_size": 512,
- "max_sectors_kb": 1280,
- "nomerges": 0,
- "rq_affinity": 1,
- "io_poll": 0,
- "selected_scheduler": "none"
- }
- },
- "fuse_connections": {},
- "known_host_queue_sizes": {
- "kvm_virtio_blk": 256,
- "kvm_virtio_fs": [
- 256,
- 256
- ]
- }
- },
- "mounts": [
- {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- {
- "mount_point": "/proc",
- "root": "/",
- "fs_type": "proc",
- "source": "proc",
- "options": "rw"
- },
- {
- "mount_point": "/sys",
- "root": "/",
- "fs_type": "sysfs",
- "source": "sysfs",
- "options": "rw"
- },
- {
- "mount_point": "/dev",
- "root": "/",
- "fs_type": "devtmpfs",
- "source": "devtmpfs",
- "options": "rw,size=1019200k,nr_inodes=254800,mode=755"
- },
- {
- "mount_point": "/dev/pts",
- "root": "/",
- "fs_type": "devpts",
- "source": "devpts",
- "options": "rw,mode=600,ptmxmode=000"
- },
- {
- "mount_point": "/root",
- "root": "/workspace",
- "fs_type": "virtiofs",
- "source": "capsem",
- "options": "rw"
- },
- {
- "mount_point": "/etc/resolv.conf",
- "root": "/run/resolv.conf",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- }
- ],
- "paths": {
- "/": {
- "path": "/",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "mode": "drwxr-xr-x",
- "statvfs": {
- "block_size": 4096,
- "fragment_size": 4096,
- "blocks": 498138,
- "blocks_free": 496739,
- "blocks_available": 492643,
- "files": 131072,
- "files_free": 130886
- }
- },
- "/root": {
- "path": "/root",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/root",
- "root": "/workspace",
- "fs_type": "virtiofs",
- "source": "capsem",
- "options": "rw"
- },
- "mode": "drwxrwxr-x",
- "statvfs": {
- "block_size": 4096,
- "fragment_size": 4096,
- "blocks": 8229461,
- "blocks_free": 8068005,
- "blocks_available": 8068005,
- "files": 1048576,
- "files_free": 1047823
- }
- },
- "/tmp": {
- "path": "/tmp",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "mode": "drwxrwxrwt",
- "statvfs": {
- "block_size": 4096,
- "fragment_size": 4096,
- "blocks": 498138,
- "blocks_free": 496739,
- "blocks_available": 492643,
- "files": 131072,
- "files_free": 130886
- }
- },
- "/var/tmp": {
- "path": "/var/tmp",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "mode": "drwxrwxrwt",
- "statvfs": {
- "block_size": 4096,
- "fragment_size": 4096,
- "blocks": 498138,
- "blocks_free": 496739,
- "blocks_available": 492643,
- "files": 131072,
- "files_free": 130886
- }
- },
- "/var/log": {
- "path": "/var/log",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "mode": "drwxr-xr-x",
- "statvfs": {
- "block_size": 4096,
- "fragment_size": 4096,
- "blocks": 498138,
- "blocks_free": 496739,
- "blocks_available": 492643,
- "files": 131072,
- "files_free": 130886
- }
- },
- "/run": {
- "path": "/run",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "mode": "drwxr-xr-x",
- "statvfs": {
- "block_size": 4096,
- "fragment_size": 4096,
- "blocks": 498138,
- "blocks_free": 496739,
- "blocks_available": 492643,
- "files": 131072,
- "files_free": 130886
- }
- },
- "/usr/bin": {
- "path": "/usr/bin",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "mode": "drwxr-xr-x",
- "statvfs": {
- "block_size": 4096,
- "fragment_size": 4096,
- "blocks": 498138,
- "blocks_free": 496739,
- "blocks_available": 492643,
- "files": 131072,
- "files_free": 130886
- }
- },
- "/usr/lib": {
- "path": "/usr/lib",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "mode": "drwxr-xr-x",
- "statvfs": {
- "block_size": 4096,
- "fragment_size": 4096,
- "blocks": 498138,
- "blocks_free": 496739,
- "blocks_available": 492643,
- "files": 131072,
- "files_free": 130886
- }
- },
- "/opt/ai-clis": {
- "path": "/opt/ai-clis",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "mode": "drwxr-xr-x",
- "statvfs": {
- "block_size": 4096,
- "fragment_size": 4096,
- "blocks": 498138,
- "blocks_free": 496739,
- "blocks_available": 492643,
- "files": 131072,
- "files_free": 130886
- }
- }
- },
- "rootfs": {
- "scan_dirs": [
- "/usr/bin",
- "/usr/lib",
- "/opt/ai-clis"
- ],
- "files_found": 3332,
- "largest_file": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe",
- "largest_file_size": 239650512,
- "backing": {
- "root_mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "overlay_lowerdir": "/mnt/a",
- "overlay_upperdir": "/mnt/system/upper",
- "overlay_workdir": "/mnt/system/work",
- "squashfs_mounts": [],
- "squashfs_superblock": {
- "device": "/dev/vda",
- "magic": "0x73717368",
- "version": "4.0",
- "compression_id": 6,
- "compression": "zstd",
- "block_size_bytes": 131072,
- "block_size": "128.0 KB",
- "block_log": 17,
- "flags": 192,
- "inodes": 32134,
- "fragments": 2213,
- "mkfs_time": 1780069854,
- "id_count": 1,
- "read_ahead_kb": 4096
- }
- },
- "seq_reads": [
- {
- "label": "largest",
- "path": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe",
- "size_bytes": 239650512,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "cold": {
- "size_bytes": 239650512,
- "block_size": 1048576,
- "duration_ms": 1184.3,
- "throughput_mbps": 193.0
- },
- "warm": {
- "size_bytes": 239650512,
- "block_size": 1048576,
- "duration_ms": 39.5,
- "throughput_mbps": 5786.5
- }
- },
- {
- "label": "bash",
- "path": "/bin/bash",
- "size_bytes": 1265648,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "cold": {
- "size_bytes": 1265648,
- "block_size": 1048576,
- "duration_ms": 2.1,
- "throughput_mbps": 574.5
- },
- "warm": {
- "size_bytes": 1265648,
- "block_size": 1048576,
- "duration_ms": 0.2,
- "throughput_mbps": 5158.5
- }
- },
- {
- "label": "python3",
- "path": "/usr/bin/python3",
- "size_bytes": 6834424,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "cold": {
- "size_bytes": 6834424,
- "block_size": 1048576,
- "duration_ms": 17.7,
- "throughput_mbps": 369.1
- },
- "warm": {
- "size_bytes": 6834424,
- "block_size": 1048576,
- "duration_ms": 1.2,
- "throughput_mbps": 5345.1
- }
- }
- ],
- "rand_read_4k": {
- "count": 2000,
- "files_sampled": 1475,
- "duration_ms": 1753.8,
- "iops": 1140.4,
- "throughput_mbps": 4.5
- }
- },
- "writable": {
- "/root": {
- "path": "/root",
- "size_mb": 64,
- "seq_write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 114.3,
- "throughput_mbps": 559.8
- },
- "seq_read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 122.3,
- "throughput_mbps": 523.2
- },
- "seq_read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 107.9,
- "throughput_mbps": 593.4
- },
- "rand_write_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 3542.9,
- "iops": 2822.6,
- "throughput_mbps": 11.0
- },
- "rand_read_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 1335.9,
- "iops": 7485.4,
- "throughput_mbps": 29.2
- },
- "io_profile": {
- "path": "/root",
- "size_mb": 64,
- "random_ops": 2000,
- "sequential": {
- "4k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 2978.3,
- "iops": 5501.1,
- "throughput_mbps": 21.5,
- "avg_latency_ms": 0.182
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 92.6,
- "iops": 176891.0,
- "throughput_mbps": 691.0,
- "avg_latency_ms": 0.006
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 98.2,
- "iops": 166847.5,
- "throughput_mbps": 651.7,
- "avg_latency_ms": 0.006
- }
- },
- "64k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 249.7,
- "iops": 4100.7,
- "throughput_mbps": 256.3,
- "avg_latency_ms": 0.244
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 118.8,
- "iops": 8620.8,
- "throughput_mbps": 538.8,
- "avg_latency_ms": 0.116
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 118.1,
- "iops": 8669.8,
- "throughput_mbps": 541.9,
- "avg_latency_ms": 0.115
- }
- },
- "1m": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 96.6,
- "iops": 662.4,
- "throughput_mbps": 662.4,
- "avg_latency_ms": 1.51
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 115.7,
- "iops": 553.3,
- "throughput_mbps": 553.3,
- "avg_latency_ms": 1.807
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 128.7,
- "iops": 497.4,
- "throughput_mbps": 497.4,
- "avg_latency_ms": 2.011
- }
- }
- },
- "random": {
- "read_4k": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 349.6,
- "iops": 5720.6,
- "throughput_mbps": 22.3,
- "avg_latency_ms": 0.175,
- "latency_ms": {
- "p50": 0.171,
- "p95": 0.253,
- "p99": 0.318,
- "max": 1.042
- }
- },
- "write_4k_sync": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 718.3,
- "iops": 2784.3,
- "throughput_mbps": 10.9,
- "avg_latency_ms": 0.359,
- "latency_ms": {
- "p50": 0.343,
- "p95": 0.451,
- "p99": 0.535,
- "max": 0.791
- },
- "sync_each": true
- }
- }
- }
- },
- "/tmp": {
- "path": "/tmp",
- "size_mb": 64,
- "seq_write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 71.7,
- "throughput_mbps": 893.2
- },
- "seq_read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 35.6,
- "throughput_mbps": 1796.9
- },
- "seq_read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 11.7,
- "throughput_mbps": 5489.7
- },
- "rand_write_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 3568.1,
- "iops": 2802.6,
- "throughput_mbps": 10.9
- },
- "rand_read_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 23.0,
- "iops": 435560.0,
- "throughput_mbps": 1701.4
- },
- "io_profile": {
- "path": "/tmp",
- "size_mb": 64,
- "random_ops": 2000,
- "sequential": {
- "4k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 60.3,
- "iops": 271672.5,
- "throughput_mbps": 1061.2,
- "avg_latency_ms": 0.004
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 54.1,
- "iops": 303040.5,
- "throughput_mbps": 1183.8,
- "avg_latency_ms": 0.003
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 23.2,
- "iops": 706809.7,
- "throughput_mbps": 2761.0,
- "avg_latency_ms": 0.001
- }
- },
- "64k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 54.8,
- "iops": 18686.4,
- "throughput_mbps": 1167.9,
- "avg_latency_ms": 0.054
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 41.5,
- "iops": 24666.1,
- "throughput_mbps": 1541.6,
- "avg_latency_ms": 0.041
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 10.9,
- "iops": 93779.1,
- "throughput_mbps": 5861.2,
- "avg_latency_ms": 0.011
- }
- },
- "1m": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 57.9,
- "iops": 1106.1,
- "throughput_mbps": 1106.1,
- "avg_latency_ms": 0.904
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 38.4,
- "iops": 1664.6,
- "throughput_mbps": 1664.6,
- "avg_latency_ms": 0.601
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 11.6,
- "iops": 5510.5,
- "throughput_mbps": 5510.5,
- "avg_latency_ms": 0.181
- }
- }
- },
- "random": {
- "read_4k": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 206.2,
- "iops": 9697.5,
- "throughput_mbps": 37.9,
- "avg_latency_ms": 0.103,
- "latency_ms": {
- "p50": 0.104,
- "p95": 0.137,
- "p99": 0.192,
- "max": 0.45
- }
- },
- "write_4k_sync": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 245.3,
- "iops": 8154.7,
- "throughput_mbps": 31.9,
- "avg_latency_ms": 0.123,
- "latency_ms": {
- "p50": 0.109,
- "p95": 0.187,
- "p99": 0.363,
- "max": 0.511
- },
- "sync_each": true
- }
- }
- }
- },
- "/var/tmp": {
- "path": "/var/tmp",
- "size_mb": 64,
- "seq_write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 57.5,
- "throughput_mbps": 1113.9
- },
- "seq_read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 38.5,
- "throughput_mbps": 1662.0
- },
- "seq_read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 11.7,
- "throughput_mbps": 5465.2
- },
- "rand_write_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 3561.0,
- "iops": 2808.2,
- "throughput_mbps": 11.0
- },
- "rand_read_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 21.7,
- "iops": 460630.7,
- "throughput_mbps": 1799.3
- },
- "io_profile": {
- "path": "/var/tmp",
- "size_mb": 64,
- "random_ops": 2000,
- "sequential": {
- "4k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 58.6,
- "iops": 279399.4,
- "throughput_mbps": 1091.4,
- "avg_latency_ms": 0.004
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 58.1,
- "iops": 282064.5,
- "throughput_mbps": 1101.8,
- "avg_latency_ms": 0.004
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 23.4,
- "iops": 698705.7,
- "throughput_mbps": 2729.3,
- "avg_latency_ms": 0.001
- }
- },
- "64k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 60.9,
- "iops": 16811.2,
- "throughput_mbps": 1050.7,
- "avg_latency_ms": 0.059
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 37.9,
- "iops": 27023.4,
- "throughput_mbps": 1689.0,
- "avg_latency_ms": 0.037
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 10.9,
- "iops": 93543.0,
- "throughput_mbps": 5846.4,
- "avg_latency_ms": 0.011
- }
- },
- "1m": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 58.9,
- "iops": 1086.6,
- "throughput_mbps": 1086.6,
- "avg_latency_ms": 0.92
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 39.8,
- "iops": 1609.9,
- "throughput_mbps": 1609.9,
- "avg_latency_ms": 0.621
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 11.8,
- "iops": 5429.7,
- "throughput_mbps": 5429.7,
- "avg_latency_ms": 0.184
- }
- }
- },
- "random": {
- "read_4k": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 205.4,
- "iops": 9737.2,
- "throughput_mbps": 38.0,
- "avg_latency_ms": 0.103,
- "latency_ms": {
- "p50": 0.104,
- "p95": 0.137,
- "p99": 0.182,
- "max": 0.277
- }
- },
- "write_4k_sync": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 242.0,
- "iops": 8264.0,
- "throughput_mbps": 32.3,
- "avg_latency_ms": 0.121,
- "latency_ms": {
- "p50": 0.107,
- "p95": 0.181,
- "p99": 0.372,
- "max": 0.814
- },
- "sync_each": true
- }
- }
- }
- },
- "/var/log": {
- "path": "/var/log",
- "size_mb": 64,
- "seq_write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 59.7,
- "throughput_mbps": 1071.5
- },
- "seq_read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 42.0,
- "throughput_mbps": 1523.0
- },
- "seq_read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 12.0,
- "throughput_mbps": 5324.6
- },
- "rand_write_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 3652.1,
- "iops": 2738.2,
- "throughput_mbps": 10.7
- },
- "rand_read_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 22.6,
- "iops": 443317.0,
- "throughput_mbps": 1731.7
- },
- "io_profile": {
- "path": "/var/log",
- "size_mb": 64,
- "random_ops": 2000,
- "sequential": {
- "4k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 61.9,
- "iops": 264472.4,
- "throughput_mbps": 1033.1,
- "avg_latency_ms": 0.004
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 48.5,
- "iops": 337729.8,
- "throughput_mbps": 1319.3,
- "avg_latency_ms": 0.003
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 23.3,
- "iops": 702192.5,
- "throughput_mbps": 2742.9,
- "avg_latency_ms": 0.001
- }
- },
- "64k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 54.7,
- "iops": 18714.3,
- "throughput_mbps": 1169.6,
- "avg_latency_ms": 0.053
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 37.3,
- "iops": 27444.4,
- "throughput_mbps": 1715.3,
- "avg_latency_ms": 0.036
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 10.6,
- "iops": 96452.3,
- "throughput_mbps": 6028.3,
- "avg_latency_ms": 0.01
- }
- },
- "1m": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 56.1,
- "iops": 1141.1,
- "throughput_mbps": 1141.1,
- "avg_latency_ms": 0.876
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 38.2,
- "iops": 1676.6,
- "throughput_mbps": 1676.6,
- "avg_latency_ms": 0.596
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 11.8,
- "iops": 5430.4,
- "throughput_mbps": 5430.4,
- "avg_latency_ms": 0.184
- }
- }
- },
- "random": {
- "read_4k": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 206.5,
- "iops": 9683.2,
- "throughput_mbps": 37.8,
- "avg_latency_ms": 0.103,
- "latency_ms": {
- "p50": 0.104,
- "p95": 0.135,
- "p99": 0.193,
- "max": 0.477
- }
- },
- "write_4k_sync": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 239.2,
- "iops": 8362.1,
- "throughput_mbps": 32.7,
- "avg_latency_ms": 0.12,
- "latency_ms": {
- "p50": 0.108,
- "p95": 0.156,
- "p99": 0.358,
- "max": 0.548
- },
- "sync_each": true
- }
- }
- }
- },
- "/run": {
- "path": "/run",
- "size_mb": 64,
- "seq_write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 57.5,
- "throughput_mbps": 1112.4
- },
- "seq_read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 41.9,
- "throughput_mbps": 1527.9
- },
- "seq_read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 11.8,
- "throughput_mbps": 5402.9
- },
- "rand_write_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 3515.9,
- "iops": 2844.2,
- "throughput_mbps": 11.1
- },
- "rand_read_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 21.9,
- "iops": 456056.9,
- "throughput_mbps": 1781.5
- },
- "io_profile": {
- "path": "/run",
- "size_mb": 64,
- "random_ops": 2000,
- "sequential": {
- "4k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 59.5,
- "iops": 275471.9,
- "throughput_mbps": 1076.1,
- "avg_latency_ms": 0.004
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 49.7,
- "iops": 329719.6,
- "throughput_mbps": 1288.0,
- "avg_latency_ms": 0.003
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 23.2,
- "iops": 707464.5,
- "throughput_mbps": 2763.5,
- "avg_latency_ms": 0.001
- }
- },
- "64k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 59.0,
- "iops": 17370.2,
- "throughput_mbps": 1085.6,
- "avg_latency_ms": 0.058
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 39.1,
- "iops": 26193.3,
- "throughput_mbps": 1637.1,
- "avg_latency_ms": 0.038
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 11.0,
- "iops": 92678.8,
- "throughput_mbps": 5792.4,
- "avg_latency_ms": 0.011
- }
- },
- "1m": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 59.8,
- "iops": 1070.2,
- "throughput_mbps": 1070.2,
- "avg_latency_ms": 0.934
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 37.5,
- "iops": 1708.2,
- "throughput_mbps": 1708.2,
- "avg_latency_ms": 0.585
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 11.8,
- "iops": 5446.1,
- "throughput_mbps": 5446.1,
- "avg_latency_ms": 0.184
- }
- }
- },
- "random": {
- "read_4k": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 207.8,
- "iops": 9625.3,
- "throughput_mbps": 37.6,
- "avg_latency_ms": 0.104,
- "latency_ms": {
- "p50": 0.103,
- "p95": 0.133,
- "p99": 0.187,
- "max": 0.44
- }
- },
- "write_4k_sync": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 237.0,
- "iops": 8438.4,
- "throughput_mbps": 33.0,
- "avg_latency_ms": 0.119,
- "latency_ms": {
- "p50": 0.107,
- "p95": 0.143,
- "p99": 0.358,
- "max": 0.494
- },
- "sync_each": true
- }
- }
- }
- }
- }
- },
- "startup": {
- "runs_per_command": 3,
- "commands": {
- "python3": {
- "command": [
- "python3",
- "--version"
- ],
- "timings_ms": [
- 30.5,
- 31.2,
- 31.2
- ],
- "min_ms": 30.5,
- "mean_ms": 31.0,
- "max_ms": 31.2
- },
- "node": {
- "command": [
- "node",
- "--version"
- ],
- "timings_ms": [
- 299.2,
- 299.8,
- 303.8
- ],
- "min_ms": 299.2,
- "mean_ms": 300.9,
- "max_ms": 303.8
- },
- "claude": {
- "command": [
- "claude",
- "--version"
- ],
- "timings_ms": [
- 1599.7,
- 1183.7,
- 1391.6
- ],
- "min_ms": 1183.7,
- "mean_ms": 1391.7,
- "max_ms": 1599.7
- },
- "gemini": {
- "command": [
- "gemini",
- "--version"
- ],
- "timings_ms": [
- 3275.7,
- 3232.2,
- 3068.7
- ],
- "min_ms": 3068.7,
- "mean_ms": 3192.2,
- "max_ms": 3275.7
- },
- "codex": {
- "command": [
- "codex",
- "--version"
- ],
- "timings_ms": [
- 820.5,
- 917.3,
- 1133.2
- ],
- "min_ms": 820.5,
- "mean_ms": 957.0,
- "max_ms": 1133.2
- }
- }
- },
- "http": {
- "url": "https://www.google.com/",
- "total_requests": 50,
- "concurrency": 5,
- "successful": 50,
- "failed": 0,
- "total_duration_ms": 882.0,
- "requests_per_sec": 56.7,
- "transfer_bytes": 3982566,
- "latency_ms": {
- "min": 49.2,
- "max": 331.9,
- "mean": 87.0,
- "p50": 58.1,
- "p95": 323.7,
- "p99": 331.6
- }
- },
- "throughput": {
- "url": "https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-slides.pdf",
- "http_code": 200,
- "size_bytes": 9984968,
- "duration_s": 0.521,
- "throughput_mbps": 18.27
- },
- "snapshot": {
- "10_files": {
- "create_ms": 3015.2,
- "create_ok": true,
- "list_ms": 964.8,
- "list_ok": true,
- "changes_ms": 955.1,
- "changes_ok": true,
- "revert_ms": 960.5,
- "revert_ok": true,
- "delete_ms": 987.3,
- "delete_ok": true
- },
- "100_files": {
- "create_ms": 1108.3,
- "create_ok": true,
- "list_ms": 932.5,
- "list_ok": true,
- "changes_ms": 948.0,
- "changes_ok": true,
- "revert_ms": 943.6,
- "revert_ok": true,
- "delete_ms": 969.1,
- "delete_ok": true
- },
- "500_files": {
- "create_ms": 1115.3,
- "create_ok": true,
- "list_ms": 978.0,
- "list_ok": true,
- "changes_ms": 1025.1,
- "changes_ok": true,
- "revert_ms": 956.9,
- "revert_ok": true,
- "delete_ms": 970.1,
- "delete_ok": true
- }
- },
- "schema": "capsem.benchmark-artifact.v1",
- "project_version": "1.2.1779673506",
- "arch": "x86_64",
- "recorded_at": 1780145123.6715438,
- "recorded_at_utc": "2026-05-30T12:45:23.671548+00:00",
- "command": "capsem-bench all",
- "host": {
- "platform": "Linux",
- "release": "7.0.0-1003-gcp",
- "version": "#3-Ubuntu SMP PREEMPT Mon Apr 13 16:29:20 UTC 2026",
- "machine": "x86_64",
- "processor": "",
- "python_version": "3.14.4",
- "cpu_count": 16,
- "cpu_count_logical": 16,
- "cpu_model": "Intel(R) Xeon(R) CPU @ 2.80GHz",
- "cpu_count_physical": 8,
- "memory_total_bytes": 67415740416,
- "memory_total_gb": 62.79,
- "os_pretty_name": "Ubuntu 26.04 LTS",
- "os_id": "ubuntu",
- "os_version_id": "26.04"
- },
- "git": {
- "commit": "b6f9b6e2342496f7c9c5dadd77548aa8d138678e",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_security_packs_microbench.json"
- ]
- }
-}
\ No newline at end of file
diff --git a/benchmarks/capsem-bench/data_1.2.1780103109_arm64.json b/benchmarks/capsem-bench/data_1.2.1780103109_arm64.json
deleted file mode 100644
index 6c8229b1f..000000000
--- a/benchmarks/capsem-bench/data_1.2.1780103109_arm64.json
+++ /dev/null
@@ -1,1552 +0,0 @@
-{
- "version": "0.3.0",
- "timestamp": 1780149812.1400814,
- "hostname": "bench-bb62f401",
- "disk": {
- "directory": "/root",
- "size_mb": 256,
- "seq_write": {
- "size_bytes": 268435456,
- "block_size": 1048576,
- "duration_ms": 148.9,
- "throughput_mbps": 1719.0
- },
- "seq_read": {
- "size_bytes": 268435456,
- "block_size": 1048576,
- "duration_ms": 63.3,
- "throughput_mbps": 4043.0
- },
- "rand_write_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 1019.0,
- "iops": 9813.4,
- "throughput_mbps": 38.3
- },
- "rand_read_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 111.3,
- "iops": 89808.6,
- "throughput_mbps": 350.8
- }
- },
- "rootfs": {
- "scan_dirs": [
- "/usr/bin",
- "/usr/lib",
- "/opt/ai-clis"
- ],
- "largest_file": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe",
- "largest_file_size": 238401160,
- "seq_read": {
- "file": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe",
- "size_bytes": 238401160,
- "block_size": 1048576,
- "duration_ms": 240.5,
- "throughput_mbps": 945.3
- },
- "files_found": 5557,
- "rand_read_4k": {
- "count": 5000,
- "files_sampled": 2580,
- "block_size": 4096,
- "duration_ms": 572.5,
- "iops": 8733.5,
- "throughput_mbps": 34.1
- },
- "large_binary_seq_read": {
- "count": 3,
- "files": [
- {
- "path": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe",
- "size_bytes": 238401160,
- "cold": {
- "file": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe",
- "size_bytes": 238401160,
- "block_size": 1048576,
- "duration_ms": 221.2,
- "throughput_mbps": 1027.9
- },
- "warm": {
- "file": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe",
- "size_bytes": 238401160,
- "block_size": 1048576,
- "duration_ms": 8.4,
- "throughput_mbps": 26972.3
- }
- },
- {
- "path": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/node_modules/@anthropic-ai/claude-code-linux-arm64/claude",
- "size_bytes": 238401160,
- "cold": {
- "file": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/node_modules/@anthropic-ai/claude-code-linux-arm64/claude",
- "size_bytes": 238401160,
- "block_size": 1048576,
- "duration_ms": 221.2,
- "throughput_mbps": 1027.7
- },
- "warm": {
- "file": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/node_modules/@anthropic-ai/claude-code-linux-arm64/claude",
- "size_bytes": 238401160,
- "block_size": 1048576,
- "duration_ms": 8.8,
- "throughput_mbps": 25827.0
- }
- },
- {
- "path": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
- "size_bytes": 187965064,
- "cold": {
- "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
- "size_bytes": 187965064,
- "block_size": 1048576,
- "duration_ms": 206.3,
- "throughput_mbps": 868.8
- },
- "warm": {
- "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
- "size_bytes": 187965064,
- "block_size": 1048576,
- "duration_ms": 7.9,
- "throughput_mbps": 22630.1
- }
- }
- ],
- "bytes_read": 664767384,
- "cold_duration_ms": 648.7,
- "warm_duration_ms": 25.1,
- "cold_throughput_mbps": 977.3,
- "warm_throughput_mbps": 25257.8
- },
- "small_js_read": {
- "count": 5000,
- "files_sampled": 113,
- "bytes_read": 45195287,
- "duration_ms": 12.5,
- "ops_per_sec": 399176.4,
- "throughput_mbps": 3441.0
- },
- "metadata_stat": {
- "entries": 6571,
- "files": 5557,
- "dirs": 670,
- "symlinks": 344,
- "errors": 0,
- "duration_ms": 32.9,
- "stats_per_sec": 199915.3
- }
- },
- "storage": {
- "kernel": {
- "cmdline": {
- "raw": "console=hvc0 root=/dev/vda ro loglevel=1 quiet init_on_alloc=1 slab_nomerge page_alloc.shuffle=1 random.trust_cpu=1 capsem.storage=virtiofs",
- "args": [
- "console=hvc0",
- "root=/dev/vda",
- "ro",
- "loglevel=1",
- "quiet",
- "init_on_alloc=1",
- "slab_nomerge",
- "page_alloc.shuffle=1",
- "random.trust_cpu=1",
- "capsem.storage=virtiofs"
- ]
- },
- "block_queues": {
- "vda": {
- "scheduler": "[none] mq-deadline kyber",
- "read_ahead_kb": 4096,
- "nr_requests": 256,
- "rotational": 0,
- "logical_block_size": 512,
- "physical_block_size": 512,
- "max_sectors_kb": 1280,
- "nomerges": 0,
- "rq_affinity": 1,
- "io_poll": 0,
- "selected_scheduler": "none"
- },
- "vdb": {
- "scheduler": "[none] mq-deadline kyber",
- "read_ahead_kb": 4096,
- "nr_requests": 256,
- "rotational": 0,
- "logical_block_size": 512,
- "physical_block_size": 512,
- "max_sectors_kb": 1280,
- "nomerges": 0,
- "rq_affinity": 1,
- "io_poll": 0,
- "selected_scheduler": "none"
- }
- },
- "fuse_connections": {},
- "known_host_queue_sizes": {
- "kvm_virtio_blk": 256,
- "kvm_virtio_fs": [
- 256,
- 256
- ]
- }
- },
- "mounts": [
- {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- {
- "mount_point": "/proc",
- "root": "/",
- "fs_type": "proc",
- "source": "proc",
- "options": "rw"
- },
- {
- "mount_point": "/sys",
- "root": "/",
- "fs_type": "sysfs",
- "source": "sysfs",
- "options": "rw"
- },
- {
- "mount_point": "/dev",
- "root": "/",
- "fs_type": "devtmpfs",
- "source": "devtmpfs",
- "options": "rw,size=989876k,nr_inodes=247469,mode=755"
- },
- {
- "mount_point": "/dev/pts",
- "root": "/",
- "fs_type": "devpts",
- "source": "devpts",
- "options": "rw,mode=600,ptmxmode=000"
- },
- {
- "mount_point": "/root",
- "root": "/workspace",
- "fs_type": "virtiofs",
- "source": "capsem",
- "options": "rw"
- },
- {
- "mount_point": "/etc/resolv.conf",
- "root": "/run/resolv.conf",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- }
- ],
- "paths": {
- "/": {
- "path": "/",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "mode": "drwxr-xr-x",
- "statvfs": {
- "block_size": 4096,
- "fragment_size": 4096,
- "blocks": 498138,
- "blocks_free": 496821,
- "blocks_available": 492725,
- "files": 131072,
- "files_free": 130886
- }
- },
- "/root": {
- "path": "/root",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/root",
- "root": "/workspace",
- "fs_type": "virtiofs",
- "source": "capsem",
- "options": "rw"
- },
- "mode": "drwxr-xr-x",
- "statvfs": {
- "block_size": 1048576,
- "fragment_size": 4096,
- "blocks": 975653540,
- "blocks_free": 740729211,
- "blocks_available": 740729211,
- "files": 3862112702,
- "files_free": 3859364664
- }
- },
- "/tmp": {
- "path": "/tmp",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "mode": "drwxrwxrwt",
- "statvfs": {
- "block_size": 4096,
- "fragment_size": 4096,
- "blocks": 498138,
- "blocks_free": 496821,
- "blocks_available": 492725,
- "files": 131072,
- "files_free": 130886
- }
- },
- "/var/tmp": {
- "path": "/var/tmp",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "mode": "drwxrwxrwt",
- "statvfs": {
- "block_size": 4096,
- "fragment_size": 4096,
- "blocks": 498138,
- "blocks_free": 496821,
- "blocks_available": 492725,
- "files": 131072,
- "files_free": 130886
- }
- },
- "/var/log": {
- "path": "/var/log",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "mode": "drwxr-xr-x",
- "statvfs": {
- "block_size": 4096,
- "fragment_size": 4096,
- "blocks": 498138,
- "blocks_free": 496821,
- "blocks_available": 492725,
- "files": 131072,
- "files_free": 130886
- }
- },
- "/run": {
- "path": "/run",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "mode": "drwxr-xr-x",
- "statvfs": {
- "block_size": 4096,
- "fragment_size": 4096,
- "blocks": 498138,
- "blocks_free": 496821,
- "blocks_available": 492725,
- "files": 131072,
- "files_free": 130886
- }
- },
- "/usr/bin": {
- "path": "/usr/bin",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "mode": "drwxr-xr-x",
- "statvfs": {
- "block_size": 4096,
- "fragment_size": 4096,
- "blocks": 498138,
- "blocks_free": 496821,
- "blocks_available": 492725,
- "files": 131072,
- "files_free": 130886
- }
- },
- "/usr/lib": {
- "path": "/usr/lib",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "mode": "drwxr-xr-x",
- "statvfs": {
- "block_size": 4096,
- "fragment_size": 4096,
- "blocks": 498138,
- "blocks_free": 496821,
- "blocks_available": 492725,
- "files": 131072,
- "files_free": 130886
- }
- },
- "/opt/ai-clis": {
- "path": "/opt/ai-clis",
- "exists": true,
- "writable": true,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "mode": "drwxr-xr-x",
- "statvfs": {
- "block_size": 4096,
- "fragment_size": 4096,
- "blocks": 498138,
- "blocks_free": 496821,
- "blocks_available": 492725,
- "files": 131072,
- "files_free": 130886
- }
- }
- },
- "rootfs": {
- "scan_dirs": [
- "/usr/bin",
- "/usr/lib",
- "/opt/ai-clis"
- ],
- "files_found": 3326,
- "largest_file": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe",
- "largest_file_size": 238401160,
- "backing": {
- "root_mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "overlay_lowerdir": "/mnt/a",
- "overlay_upperdir": "/mnt/system/upper",
- "overlay_workdir": "/mnt/system/work",
- "squashfs_mounts": [],
- "squashfs_superblock": {
- "device": "/dev/vda",
- "magic": "0x73717368",
- "version": "4.0",
- "compression_id": 6,
- "compression": "zstd",
- "block_size_bytes": 131072,
- "block_size": "128.0 KB",
- "block_log": 17,
- "flags": 192,
- "inodes": 32132,
- "fragments": 2600,
- "mkfs_time": 1780149433,
- "id_count": 9,
- "read_ahead_kb": 4096
- }
- },
- "seq_reads": [
- {
- "label": "largest",
- "path": "/opt/ai-clis/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe",
- "size_bytes": 238401160,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "cold": {
- "size_bytes": 238401160,
- "block_size": 1048576,
- "duration_ms": 221.8,
- "throughput_mbps": 1025.0
- },
- "warm": {
- "size_bytes": 238401160,
- "block_size": 1048576,
- "duration_ms": 9.2,
- "throughput_mbps": 24634.6
- }
- },
- {
- "label": "bash",
- "path": "/bin/bash",
- "size_bytes": 1346480,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "cold": {
- "size_bytes": 1346480,
- "block_size": 1048576,
- "duration_ms": 0.6,
- "throughput_mbps": 2295.3
- },
- "warm": {
- "size_bytes": 1346480,
- "block_size": 1048576,
- "duration_ms": 0.1,
- "throughput_mbps": 19456.1
- }
- },
- {
- "label": "python3",
- "path": "/usr/bin/python3",
- "size_bytes": 6616880,
- "mount": {
- "mount_point": "/",
- "root": "/",
- "fs_type": "overlay",
- "source": "overlay",
- "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
- },
- "cold": {
- "size_bytes": 6616880,
- "block_size": 1048576,
- "duration_ms": 4.1,
- "throughput_mbps": 1537.0
- },
- "warm": {
- "size_bytes": 6616880,
- "block_size": 1048576,
- "duration_ms": 0.2,
- "throughput_mbps": 27426.4
- }
- }
- ],
- "rand_read_4k": {
- "count": 2000,
- "files_sampled": 1507,
- "duration_ms": 338.5,
- "iops": 5909.2,
- "throughput_mbps": 23.1
- }
- },
- "writable": {
- "/root": {
- "path": "/root",
- "size_mb": 64,
- "seq_write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 29.0,
- "throughput_mbps": 2204.3
- },
- "seq_read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 13.8,
- "throughput_mbps": 4647.3
- },
- "seq_read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 13.2,
- "throughput_mbps": 4837.0
- },
- "rand_write_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 947.6,
- "iops": 10553.2,
- "throughput_mbps": 41.2
- },
- "rand_read_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 111.9,
- "iops": 89343.4,
- "throughput_mbps": 349.0
- },
- "io_profile": {
- "path": "/root",
- "size_mb": 64,
- "random_ops": 2000,
- "sequential": {
- "4k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 688.4,
- "iops": 23800.7,
- "throughput_mbps": 93.0,
- "avg_latency_ms": 0.042
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 14.7,
- "iops": 1114463.1,
- "throughput_mbps": 4353.4,
- "avg_latency_ms": 0.001
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 14.9,
- "iops": 1102294.5,
- "throughput_mbps": 4305.8,
- "avg_latency_ms": 0.001
- }
- },
- "64k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 58.0,
- "iops": 17650.5,
- "throughput_mbps": 1103.2,
- "avg_latency_ms": 0.057
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 12.9,
- "iops": 79298.1,
- "throughput_mbps": 4956.1,
- "avg_latency_ms": 0.013
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 13.1,
- "iops": 78274.7,
- "throughput_mbps": 4892.2,
- "avg_latency_ms": 0.013
- }
- },
- "1m": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 32.9,
- "iops": 1946.9,
- "throughput_mbps": 1946.9,
- "avg_latency_ms": 0.514
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 12.2,
- "iops": 5240.9,
- "throughput_mbps": 5240.9,
- "avg_latency_ms": 0.191
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 12.8,
- "iops": 5014.7,
- "throughput_mbps": 5014.7,
- "avg_latency_ms": 0.199
- }
- }
- },
- "random": {
- "read_4k": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 29.3,
- "iops": 68338.0,
- "throughput_mbps": 266.9,
- "avg_latency_ms": 0.015,
- "latency_ms": {
- "p50": 0.013,
- "p95": 0.024,
- "p99": 0.03,
- "max": 0.097
- }
- },
- "write_4k_sync": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 167.3,
- "iops": 11957.0,
- "throughput_mbps": 46.7,
- "avg_latency_ms": 0.084,
- "latency_ms": {
- "p50": 0.072,
- "p95": 0.093,
- "p99": 0.115,
- "max": 5.827
- },
- "sync_each": true
- }
- }
- }
- },
- "/tmp": {
- "path": "/tmp",
- "size_mb": 64,
- "seq_write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 7.7,
- "throughput_mbps": 8287.9
- },
- "seq_read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 6.2,
- "throughput_mbps": 10403.6
- },
- "seq_read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 2.8,
- "throughput_mbps": 22761.0
- },
- "rand_write_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 1345.5,
- "iops": 7432.0,
- "throughput_mbps": 29.0
- },
- "rand_read_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 5.8,
- "iops": 1714396.0,
- "throughput_mbps": 6696.9
- },
- "io_profile": {
- "path": "/tmp",
- "size_mb": 64,
- "random_ops": 2000,
- "sequential": {
- "4k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 10.6,
- "iops": 1549644.1,
- "throughput_mbps": 6053.3,
- "avg_latency_ms": 0.001
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 8.7,
- "iops": 1894076.7,
- "throughput_mbps": 7398.7,
- "avg_latency_ms": 0.001
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 6.4,
- "iops": 2548419.0,
- "throughput_mbps": 9954.8,
- "avg_latency_ms": 0.0
- }
- },
- "64k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 7.6,
- "iops": 133908.7,
- "throughput_mbps": 8369.3,
- "avg_latency_ms": 0.007
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 5.5,
- "iops": 187211.5,
- "throughput_mbps": 11700.7,
- "avg_latency_ms": 0.005
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 3.1,
- "iops": 326326.9,
- "throughput_mbps": 20395.4,
- "avg_latency_ms": 0.003
- }
- },
- "1m": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 7.9,
- "iops": 8086.3,
- "throughput_mbps": 8086.3,
- "avg_latency_ms": 0.124
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 5.5,
- "iops": 11589.9,
- "throughput_mbps": 11589.9,
- "avg_latency_ms": 0.086
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 2.9,
- "iops": 22337.9,
- "throughput_mbps": 22337.9,
- "avg_latency_ms": 0.045
- }
- }
- },
- "random": {
- "read_4k": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 38.9,
- "iops": 51448.0,
- "throughput_mbps": 201.0,
- "avg_latency_ms": 0.019,
- "latency_ms": {
- "p50": 0.02,
- "p95": 0.026,
- "p99": 0.031,
- "max": 0.06
- }
- },
- "write_4k_sync": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 80.5,
- "iops": 24833.0,
- "throughput_mbps": 97.0,
- "avg_latency_ms": 0.04,
- "latency_ms": {
- "p50": 0.038,
- "p95": 0.05,
- "p99": 0.137,
- "max": 0.212
- },
- "sync_each": true
- }
- }
- }
- },
- "/var/tmp": {
- "path": "/var/tmp",
- "size_mb": 64,
- "seq_write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 7.7,
- "throughput_mbps": 8353.3
- },
- "seq_read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 6.0,
- "throughput_mbps": 10594.3
- },
- "seq_read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 2.9,
- "throughput_mbps": 22281.5
- },
- "rand_write_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 1315.4,
- "iops": 7602.4,
- "throughput_mbps": 29.7
- },
- "rand_read_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 5.6,
- "iops": 1784081.5,
- "throughput_mbps": 6969.1
- },
- "io_profile": {
- "path": "/var/tmp",
- "size_mb": 64,
- "random_ops": 2000,
- "sequential": {
- "4k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 10.3,
- "iops": 1588482.0,
- "throughput_mbps": 6205.0,
- "avg_latency_ms": 0.001
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 8.2,
- "iops": 1999328.8,
- "throughput_mbps": 7809.9,
- "avg_latency_ms": 0.001
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 6.3,
- "iops": 2584413.8,
- "throughput_mbps": 10095.4,
- "avg_latency_ms": 0.0
- }
- },
- "64k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 8.0,
- "iops": 128344.9,
- "throughput_mbps": 8021.6,
- "avg_latency_ms": 0.008
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 5.4,
- "iops": 191287.2,
- "throughput_mbps": 11955.4,
- "avg_latency_ms": 0.005
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 3.3,
- "iops": 308879.6,
- "throughput_mbps": 19305.0,
- "avg_latency_ms": 0.003
- }
- },
- "1m": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 7.8,
- "iops": 8199.2,
- "throughput_mbps": 8199.2,
- "avg_latency_ms": 0.122
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 5.7,
- "iops": 11190.0,
- "throughput_mbps": 11190.0,
- "avg_latency_ms": 0.089
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 3.1,
- "iops": 20319.9,
- "throughput_mbps": 20319.9,
- "avg_latency_ms": 0.049
- }
- }
- },
- "random": {
- "read_4k": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 39.3,
- "iops": 50866.2,
- "throughput_mbps": 198.7,
- "avg_latency_ms": 0.02,
- "latency_ms": {
- "p50": 0.02,
- "p95": 0.027,
- "p99": 0.032,
- "max": 0.075
- }
- },
- "write_4k_sync": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 81.0,
- "iops": 24703.2,
- "throughput_mbps": 96.5,
- "avg_latency_ms": 0.04,
- "latency_ms": {
- "p50": 0.038,
- "p95": 0.05,
- "p99": 0.139,
- "max": 0.205
- },
- "sync_each": true
- }
- }
- }
- },
- "/var/log": {
- "path": "/var/log",
- "size_mb": 64,
- "seq_write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 8.3,
- "throughput_mbps": 7744.5
- },
- "seq_read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 6.0,
- "throughput_mbps": 10607.7
- },
- "seq_read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 3.0,
- "throughput_mbps": 21018.4
- },
- "rand_write_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 1379.5,
- "iops": 7248.8,
- "throughput_mbps": 28.3
- },
- "rand_read_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 5.7,
- "iops": 1752400.5,
- "throughput_mbps": 6845.3
- },
- "io_profile": {
- "path": "/var/log",
- "size_mb": 64,
- "random_ops": 2000,
- "sequential": {
- "4k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 11.0,
- "iops": 1492190.1,
- "throughput_mbps": 5828.9,
- "avg_latency_ms": 0.001
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 8.4,
- "iops": 1961353.1,
- "throughput_mbps": 7661.5,
- "avg_latency_ms": 0.001
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 6.4,
- "iops": 2559383.3,
- "throughput_mbps": 9997.6,
- "avg_latency_ms": 0.0
- }
- },
- "64k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 8.6,
- "iops": 118856.7,
- "throughput_mbps": 7428.5,
- "avg_latency_ms": 0.008
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 5.5,
- "iops": 185491.8,
- "throughput_mbps": 11593.2,
- "avg_latency_ms": 0.005
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 3.2,
- "iops": 324084.9,
- "throughput_mbps": 20255.3,
- "avg_latency_ms": 0.003
- }
- },
- "1m": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 8.6,
- "iops": 7414.4,
- "throughput_mbps": 7414.4,
- "avg_latency_ms": 0.135
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 5.4,
- "iops": 11802.6,
- "throughput_mbps": 11802.6,
- "avg_latency_ms": 0.085
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 3.0,
- "iops": 21595.8,
- "throughput_mbps": 21595.8,
- "avg_latency_ms": 0.046
- }
- }
- },
- "random": {
- "read_4k": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 39.5,
- "iops": 50639.3,
- "throughput_mbps": 197.8,
- "avg_latency_ms": 0.02,
- "latency_ms": {
- "p50": 0.02,
- "p95": 0.027,
- "p99": 0.032,
- "max": 0.062
- }
- },
- "write_4k_sync": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 82.7,
- "iops": 24181.8,
- "throughput_mbps": 94.5,
- "avg_latency_ms": 0.041,
- "latency_ms": {
- "p50": 0.038,
- "p95": 0.052,
- "p99": 0.11,
- "max": 0.274
- },
- "sync_each": true
- }
- }
- }
- },
- "/run": {
- "path": "/run",
- "size_mb": 64,
- "seq_write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 10.7,
- "throughput_mbps": 5994.9
- },
- "seq_read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 6.7,
- "throughput_mbps": 9488.8
- },
- "seq_read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "duration_ms": 3.1,
- "throughput_mbps": 20661.3
- },
- "rand_write_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 1037.8,
- "iops": 9635.4,
- "throughput_mbps": 37.6
- },
- "rand_read_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 7.1,
- "iops": 1413419.4,
- "throughput_mbps": 5521.2
- },
- "io_profile": {
- "path": "/run",
- "size_mb": 64,
- "random_ops": 2000,
- "sequential": {
- "4k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 11.1,
- "iops": 1470142.2,
- "throughput_mbps": 5742.7,
- "avg_latency_ms": 0.001
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 8.6,
- "iops": 1897320.9,
- "throughput_mbps": 7411.4,
- "avg_latency_ms": 0.001
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 4096,
- "count": 16384,
- "duration_ms": 6.6,
- "iops": 2481124.3,
- "throughput_mbps": 9691.9,
- "avg_latency_ms": 0.0
- }
- },
- "64k": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 8.3,
- "iops": 123198.5,
- "throughput_mbps": 7699.9,
- "avg_latency_ms": 0.008
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 5.4,
- "iops": 189500.9,
- "throughput_mbps": 11843.8,
- "avg_latency_ms": 0.005
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 65536,
- "count": 1024,
- "duration_ms": 3.3,
- "iops": 307257.6,
- "throughput_mbps": 19203.6,
- "avg_latency_ms": 0.003
- }
- },
- "1m": {
- "write": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 8.6,
- "iops": 7477.3,
- "throughput_mbps": 7477.3,
- "avg_latency_ms": 0.134
- },
- "read_cold": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 5.7,
- "iops": 11317.2,
- "throughput_mbps": 11317.2,
- "avg_latency_ms": 0.088
- },
- "read_warm": {
- "size_bytes": 67108864,
- "block_size": 1048576,
- "count": 64,
- "duration_ms": 3.0,
- "iops": 21481.0,
- "throughput_mbps": 21481.0,
- "avg_latency_ms": 0.047
- }
- }
- },
- "random": {
- "read_4k": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 39.6,
- "iops": 50553.5,
- "throughput_mbps": 197.5,
- "avg_latency_ms": 0.02,
- "latency_ms": {
- "p50": 0.02,
- "p95": 0.027,
- "p99": 0.032,
- "max": 0.069
- }
- },
- "write_4k_sync": {
- "size_bytes": 8192000,
- "block_size": 4096,
- "count": 2000,
- "duration_ms": 80.0,
- "iops": 25009.5,
- "throughput_mbps": 97.7,
- "avg_latency_ms": 0.04,
- "latency_ms": {
- "p50": 0.038,
- "p95": 0.049,
- "p99": 0.094,
- "max": 0.137
- },
- "sync_each": true
- }
- }
- }
- }
- }
- },
- "startup": {
- "runs_per_command": 3,
- "commands": {
- "python3": {
- "command": [
- "python3",
- "--version"
- ],
- "timings_ms": [
- 9.4,
- 7.3,
- 7.6
- ],
- "min_ms": 7.3,
- "mean_ms": 8.1,
- "max_ms": 9.4
- },
- "node": {
- "command": [
- "node",
- "--version"
- ],
- "timings_ms": [
- 75.4,
- 79.4,
- 78.0
- ],
- "min_ms": 75.4,
- "mean_ms": 77.6,
- "max_ms": 79.4
- },
- "claude": {
- "command": [
- "claude",
- "--version"
- ],
- "timings_ms": [
- 343.2,
- 291.9,
- 292.0
- ],
- "min_ms": 291.9,
- "mean_ms": 309.0,
- "max_ms": 343.2
- },
- "gemini": {
- "command": [
- "gemini",
- "--version"
- ],
- "timings_ms": [
- 859.3,
- 802.5,
- 809.4
- ],
- "min_ms": 802.5,
- "mean_ms": 823.7,
- "max_ms": 859.3
- },
- "codex": {
- "command": [
- "codex",
- "--version"
- ],
- "timings_ms": [
- 229.5,
- 240.9,
- 241.0
- ],
- "min_ms": 229.5,
- "mean_ms": 237.1,
- "max_ms": 241.0
- }
- }
- },
- "http": {
- "url": "https://www.google.com/",
- "total_requests": 50,
- "concurrency": 5,
- "successful": 50,
- "failed": 0,
- "total_duration_ms": 760.5,
- "requests_per_sec": 65.7,
- "transfer_bytes": 4010697,
- "latency_ms": {
- "min": 50.6,
- "max": 198.8,
- "mean": 75.4,
- "p50": 60.3,
- "p95": 186.3,
- "p99": 196.4
- }
- },
- "throughput": {
- "url": "https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-slides.pdf",
- "http_code": 200,
- "size_bytes": 9984968,
- "duration_s": 0.51,
- "throughput_mbps": 18.69
- },
- "snapshot": {
- "10_files": {
- "create_ms": 760.6,
- "create_ok": true,
- "list_ms": 287.6,
- "list_ok": true,
- "changes_ms": 280.4,
- "changes_ok": true,
- "revert_ms": 307.4,
- "revert_ok": true,
- "delete_ms": 313.8,
- "delete_ok": true
- },
- "100_files": {
- "create_ms": 302.7,
- "create_ok": true,
- "list_ms": 285.5,
- "list_ok": true,
- "changes_ms": 298.0,
- "changes_ok": true,
- "revert_ms": 314.9,
- "revert_ok": true,
- "delete_ms": 282.6,
- "delete_ok": true
- },
- "500_files": {
- "create_ms": 308.3,
- "create_ok": true,
- "list_ms": 308.9,
- "list_ok": true,
- "changes_ms": 336.0,
- "changes_ok": true,
- "revert_ms": 304.8,
- "revert_ok": true,
- "delete_ms": 301.6,
- "delete_ok": true
- }
- },
- "schema": "capsem.benchmark-artifact.v1",
- "project_version": "1.2.1780103109",
- "arch": "arm64",
- "recorded_at": 1780149836.1162949,
- "recorded_at_utc": "2026-05-30T14:03:56.116298+00:00",
- "command": "capsem-bench all",
- "host": {
- "platform": "Darwin",
- "release": "25.5.0",
- "version": "Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:12 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T6050",
- "machine": "arm64",
- "processor": "arm",
- "python_version": "3.14.4",
- "cpu_count": 18,
- "cpu_count_logical": 18,
- "cpu_model": "Apple M5 Max",
- "cpu_count_physical": 18,
- "memory_total_bytes": 137438953472,
- "os_product_version": "26.5",
- "memory_total_gb": 128.0
- },
- "git": {
- "commit": "0a425541fbdc03cc9821aafb238a0dd4b26ccdcd",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/security-engine/data_1.2.1780103109_arm64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_security_packs_microbench.json"
- ]
- }
-}
\ No newline at end of file
diff --git a/benchmarks/capsem-bench/data_1.3.1781050981_arm64.json b/benchmarks/capsem-bench/data_1.3.1781050981_arm64.json
new file mode 100644
index 000000000..cc3eb2a10
--- /dev/null
+++ b/benchmarks/capsem-bench/data_1.3.1781050981_arm64.json
@@ -0,0 +1,1479 @@
+{
+ "version": "0.3.0",
+ "timestamp": 1781107826.1934004,
+ "hostname": "bench-bc9218d0",
+ "disk": {
+ "directory": "/root",
+ "size_mb": 256,
+ "seq_write": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 143.1,
+ "throughput_mbps": 1789.0
+ },
+ "seq_read": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 60.9,
+ "throughput_mbps": 4202.3
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1297.5,
+ "iops": 7707.2,
+ "throughput_mbps": 30.1
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 188.7,
+ "iops": 53006.3,
+ "throughput_mbps": 207.1
+ }
+ },
+ "rootfs": {
+ "scan_dirs": [
+ "/usr/bin",
+ "/usr/lib",
+ "/opt/ai-clis"
+ ],
+ "largest_file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "largest_file_size": 197796880,
+ "seq_read": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 55.0,
+ "throughput_mbps": 3428.1
+ },
+ "files_found": 5533,
+ "rand_read_4k": {
+ "count": 5000,
+ "files_sampled": 2558,
+ "block_size": 4096,
+ "duration_ms": 151.9,
+ "iops": 32908.7,
+ "throughput_mbps": 128.5
+ },
+ "large_binary_seq_read": {
+ "count": 2,
+ "files": [
+ {
+ "path": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "cold": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 57.2,
+ "throughput_mbps": 3298.8
+ },
+ "warm": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 9.4,
+ "throughput_mbps": 19977.8
+ }
+ },
+ {
+ "path": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "cold": {
+ "file": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "block_size": 1048576,
+ "duration_ms": 8.6,
+ "throughput_mbps": 4333.5
+ },
+ "warm": {
+ "file": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "block_size": 1048576,
+ "duration_ms": 1.8,
+ "throughput_mbps": 21312.4
+ }
+ }
+ ],
+ "bytes_read": 236959384,
+ "cold_duration_ms": 65.8,
+ "warm_duration_ms": 11.2,
+ "cold_throughput_mbps": 3434.4,
+ "warm_throughput_mbps": 20177.0
+ },
+ "small_js_read": {
+ "count": 5000,
+ "files_sampled": 99,
+ "bytes_read": 49942885,
+ "duration_ms": 7.3,
+ "ops_per_sec": 688061.5,
+ "throughput_mbps": 6554.4
+ },
+ "metadata_stat": {
+ "entries": 6538,
+ "files": 5533,
+ "dirs": 662,
+ "symlinks": 343,
+ "errors": 0,
+ "duration_ms": 47.7,
+ "stats_per_sec": 137003.1
+ }
+ },
+ "storage": {
+ "kernel": {
+ "cmdline": {
+ "raw": "console=hvc0 ro loglevel=1 quiet init_on_alloc=1 slab_nomerge page_alloc.shuffle=1 random.trust_cpu=1 capsem.storage=virtiofs capsem.rootfs=erofs",
+ "args": [
+ "console=hvc0",
+ "ro",
+ "loglevel=1",
+ "quiet",
+ "init_on_alloc=1",
+ "slab_nomerge",
+ "page_alloc.shuffle=1",
+ "random.trust_cpu=1",
+ "capsem.storage=virtiofs",
+ "capsem.rootfs=erofs"
+ ]
+ },
+ "block_queues": {
+ "vda": {
+ "scheduler": "[none] mq-deadline kyber",
+ "read_ahead_kb": 4096,
+ "nr_requests": 256,
+ "rotational": 1,
+ "logical_block_size": 512,
+ "physical_block_size": 512,
+ "max_sectors_kb": 4096,
+ "nomerges": 0,
+ "rq_affinity": 1,
+ "io_poll": 0,
+ "selected_scheduler": "none"
+ },
+ "vdb": {
+ "scheduler": "[none] mq-deadline kyber",
+ "read_ahead_kb": 4096,
+ "nr_requests": 256,
+ "rotational": 1,
+ "logical_block_size": 512,
+ "physical_block_size": 512,
+ "max_sectors_kb": 4096,
+ "nomerges": 0,
+ "rq_affinity": 1,
+ "io_poll": 0,
+ "selected_scheduler": "none"
+ }
+ },
+ "fuse_connections": {},
+ "known_host_queue_sizes": {
+ "kvm_virtio_blk": 256,
+ "kvm_virtio_fs": [
+ 256,
+ 256
+ ]
+ }
+ },
+ "mounts": [
+ {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ {
+ "mount_point": "/proc",
+ "root": "/",
+ "fs_type": "proc",
+ "source": "proc",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/sys",
+ "root": "/",
+ "fs_type": "sysfs",
+ "source": "sysfs",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/dev",
+ "root": "/",
+ "fs_type": "devtmpfs",
+ "source": "devtmpfs",
+ "options": "rw,size=1021592k,nr_inodes=255398,mode=755"
+ },
+ {
+ "mount_point": "/dev/pts",
+ "root": "/",
+ "fs_type": "devpts",
+ "source": "devpts",
+ "options": "rw,mode=600,ptmxmode=000"
+ },
+ {
+ "mount_point": "/root",
+ "root": "/workspace",
+ "fs_type": "virtiofs",
+ "source": "capsem",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/etc/resolv.conf",
+ "root": "/run/resolv.conf",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ }
+ ],
+ "paths": {
+ "/": {
+ "path": "/",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwx------",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496852,
+ "blocks_available": 492756,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/root": {
+ "path": "/root",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/root",
+ "root": "/workspace",
+ "fs_type": "virtiofs",
+ "source": "capsem",
+ "options": "rw"
+ },
+ "mode": "drwx------",
+ "statvfs": {
+ "block_size": 1048576,
+ "fragment_size": 4096,
+ "blocks": 975653540,
+ "blocks_free": 719537759,
+ "blocks_available": 719537759,
+ "files": 3015377753,
+ "files_free": 3011706584
+ }
+ },
+ "/tmp": {
+ "path": "/tmp",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxrwxrwt",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496852,
+ "blocks_available": 492756,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/var/tmp": {
+ "path": "/var/tmp",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxrwxrwt",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496852,
+ "blocks_available": 492756,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/var/log": {
+ "path": "/var/log",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496852,
+ "blocks_available": 492756,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/run": {
+ "path": "/run",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496852,
+ "blocks_available": 492756,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/usr/bin": {
+ "path": "/usr/bin",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496852,
+ "blocks_available": 492756,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/usr/lib": {
+ "path": "/usr/lib",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496852,
+ "blocks_available": 492756,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/opt/ai-clis": {
+ "path": "/opt/ai-clis",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496852,
+ "blocks_available": 492756,
+ "files": 131072,
+ "files_free": 130928
+ }
+ }
+ },
+ "rootfs": {
+ "scan_dirs": [
+ "/usr/bin",
+ "/usr/lib",
+ "/opt/ai-clis"
+ ],
+ "files_found": 3316,
+ "largest_file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "largest_file_size": 197796880,
+ "backing": {
+ "root_mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "overlay_lowerdir": "/mnt/a",
+ "overlay_upperdir": "/mnt/system/upper",
+ "overlay_workdir": "/mnt/system/work",
+ "squashfs_mounts": [],
+ "squashfs_superblock": {
+ "device": "/dev/vda",
+ "magic": "0x00000000",
+ "error": "not squashfs",
+ "read_ahead_kb": 4096
+ }
+ },
+ "seq_reads": [
+ {
+ "label": "largest",
+ "path": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 55.8,
+ "throughput_mbps": 3382.6
+ },
+ "warm": {
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 8.4,
+ "throughput_mbps": 22489.8
+ }
+ },
+ {
+ "label": "bash",
+ "path": "/bin/bash",
+ "size_bytes": 1346480,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 1346480,
+ "block_size": 1048576,
+ "duration_ms": 0.2,
+ "throughput_mbps": 5469.1
+ },
+ "warm": {
+ "size_bytes": 1346480,
+ "block_size": 1048576,
+ "duration_ms": 0.1,
+ "throughput_mbps": 25302.5
+ }
+ },
+ {
+ "label": "python3",
+ "path": "/usr/bin/python3",
+ "size_bytes": 6616880,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 6616880,
+ "block_size": 1048576,
+ "duration_ms": 1.0,
+ "throughput_mbps": 6566.4
+ },
+ "warm": {
+ "size_bytes": 6616880,
+ "block_size": 1048576,
+ "duration_ms": 0.3,
+ "throughput_mbps": 24333.0
+ }
+ }
+ ],
+ "rand_read_4k": {
+ "count": 2000,
+ "files_sampled": 1500,
+ "duration_ms": 102.0,
+ "iops": 19617.2,
+ "throughput_mbps": 76.6
+ }
+ },
+ "writable": {
+ "/root": {
+ "path": "/root",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 33.8,
+ "throughput_mbps": 1895.3
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 14.8,
+ "throughput_mbps": 4325.6
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 14.6,
+ "throughput_mbps": 4372.4
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1213.2,
+ "iops": 8242.7,
+ "throughput_mbps": 32.2
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 196.8,
+ "iops": 50802.1,
+ "throughput_mbps": 198.4
+ },
+ "io_profile": {
+ "path": "/root",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 1040.1,
+ "iops": 15751.8,
+ "throughput_mbps": 61.5,
+ "avg_latency_ms": 0.063
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 17.8,
+ "iops": 918355.6,
+ "throughput_mbps": 3587.3,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 16.9,
+ "iops": 972204.8,
+ "throughput_mbps": 3797.7,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 72.9,
+ "iops": 14037.8,
+ "throughput_mbps": 877.4,
+ "avg_latency_ms": 0.071
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 15.7,
+ "iops": 65063.6,
+ "throughput_mbps": 4066.5,
+ "avg_latency_ms": 0.015
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 15.2,
+ "iops": 67413.5,
+ "throughput_mbps": 4213.3,
+ "avg_latency_ms": 0.015
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 26.5,
+ "iops": 2414.4,
+ "throughput_mbps": 2414.4,
+ "avg_latency_ms": 0.414
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 14.3,
+ "iops": 4489.4,
+ "throughput_mbps": 4489.4,
+ "avg_latency_ms": 0.223
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 14.5,
+ "iops": 4423.1,
+ "throughput_mbps": 4423.1,
+ "avg_latency_ms": 0.226
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 47.9,
+ "iops": 41792.0,
+ "throughput_mbps": 163.3,
+ "avg_latency_ms": 0.024,
+ "latency_ms": {
+ "p50": 0.025,
+ "p95": 0.03,
+ "p99": 0.034,
+ "max": 0.043
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 215.7,
+ "iops": 9274.1,
+ "throughput_mbps": 36.2,
+ "avg_latency_ms": 0.108,
+ "latency_ms": {
+ "p50": 0.107,
+ "p95": 0.12,
+ "p99": 0.128,
+ "max": 0.379
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/tmp": {
+ "path": "/tmp",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 10.1,
+ "throughput_mbps": 6319.9
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 6.8,
+ "throughput_mbps": 9372.9
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 4.9,
+ "throughput_mbps": 12989.5
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1579.2,
+ "iops": 6332.5,
+ "throughput_mbps": 24.7
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.3,
+ "iops": 1364784.1,
+ "throughput_mbps": 5331.2
+ },
+ "io_profile": {
+ "path": "/tmp",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 16.6,
+ "iops": 987092.0,
+ "throughput_mbps": 3855.8,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 11.7,
+ "iops": 1405934.6,
+ "throughput_mbps": 5491.9,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 10.3,
+ "iops": 1598341.6,
+ "throughput_mbps": 6243.5,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 10.7,
+ "iops": 96015.7,
+ "throughput_mbps": 6001.0,
+ "avg_latency_ms": 0.01
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.8,
+ "iops": 150997.2,
+ "throughput_mbps": 9437.3,
+ "avg_latency_ms": 0.007
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 5.9,
+ "iops": 172529.7,
+ "throughput_mbps": 10783.1,
+ "avg_latency_ms": 0.006
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 58.9,
+ "iops": 1086.0,
+ "throughput_mbps": 1086.0,
+ "avg_latency_ms": 0.921
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 7.1,
+ "iops": 8963.8,
+ "throughput_mbps": 8963.8,
+ "avg_latency_ms": 0.112
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 5.0,
+ "iops": 12879.5,
+ "throughput_mbps": 12879.5,
+ "avg_latency_ms": 0.078
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 40.0,
+ "iops": 49939.1,
+ "throughput_mbps": 195.1,
+ "avg_latency_ms": 0.02,
+ "latency_ms": {
+ "p50": 0.021,
+ "p95": 0.024,
+ "p99": 0.027,
+ "max": 0.05
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 84.1,
+ "iops": 23795.2,
+ "throughput_mbps": 92.9,
+ "avg_latency_ms": 0.042,
+ "latency_ms": {
+ "p50": 0.04,
+ "p95": 0.049,
+ "p99": 0.135,
+ "max": 0.191
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/var/tmp": {
+ "path": "/var/tmp",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 23.3,
+ "throughput_mbps": 2742.1
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 7.8,
+ "throughput_mbps": 8202.3
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.6,
+ "throughput_mbps": 11452.5
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1367.8,
+ "iops": 7311.2,
+ "throughput_mbps": 28.6
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 8.2,
+ "iops": 1217162.0,
+ "throughput_mbps": 4754.5
+ },
+ "io_profile": {
+ "path": "/var/tmp",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 20.1,
+ "iops": 815941.3,
+ "throughput_mbps": 3187.3,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 12.6,
+ "iops": 1300119.7,
+ "throughput_mbps": 5078.6,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 10.8,
+ "iops": 1515213.2,
+ "throughput_mbps": 5918.8,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 11.1,
+ "iops": 92053.6,
+ "throughput_mbps": 5753.3,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 8.3,
+ "iops": 123072.6,
+ "throughput_mbps": 7692.0,
+ "avg_latency_ms": 0.008
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.1,
+ "iops": 167267.9,
+ "throughput_mbps": 10454.2,
+ "avg_latency_ms": 0.006
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 12.1,
+ "iops": 5293.3,
+ "throughput_mbps": 5293.3,
+ "avg_latency_ms": 0.189
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 7.5,
+ "iops": 8554.1,
+ "throughput_mbps": 8554.1,
+ "avg_latency_ms": 0.117
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 5.6,
+ "iops": 11360.4,
+ "throughput_mbps": 11360.4,
+ "avg_latency_ms": 0.088
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 39.5,
+ "iops": 50647.5,
+ "throughput_mbps": 197.8,
+ "avg_latency_ms": 0.02,
+ "latency_ms": {
+ "p50": 0.021,
+ "p95": 0.024,
+ "p99": 0.028,
+ "max": 0.055
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 99.9,
+ "iops": 20026.3,
+ "throughput_mbps": 78.2,
+ "avg_latency_ms": 0.05,
+ "latency_ms": {
+ "p50": 0.044,
+ "p95": 0.069,
+ "p99": 0.14,
+ "max": 0.225
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/var/log": {
+ "path": "/var/log",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 11.8,
+ "throughput_mbps": 5429.3
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.5,
+ "throughput_mbps": 11606.9
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 3.4,
+ "throughput_mbps": 18869.1
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1370.6,
+ "iops": 7295.8,
+ "throughput_mbps": 28.5
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 6.8,
+ "iops": 1466992.6,
+ "throughput_mbps": 5730.4
+ },
+ "io_profile": {
+ "path": "/var/log",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 18.9,
+ "iops": 868197.0,
+ "throughput_mbps": 3391.4,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 12.1,
+ "iops": 1357115.2,
+ "throughput_mbps": 5301.2,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 10.9,
+ "iops": 1502843.5,
+ "throughput_mbps": 5870.5,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 11.4,
+ "iops": 90155.7,
+ "throughput_mbps": 5634.7,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 7.7,
+ "iops": 133484.7,
+ "throughput_mbps": 8342.8,
+ "avg_latency_ms": 0.007
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.5,
+ "iops": 158475.1,
+ "throughput_mbps": 9904.7,
+ "avg_latency_ms": 0.006
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 12.0,
+ "iops": 5337.0,
+ "throughput_mbps": 5337.0,
+ "avg_latency_ms": 0.187
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 7.4,
+ "iops": 8616.4,
+ "throughput_mbps": 8616.4,
+ "avg_latency_ms": 0.116
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 5.6,
+ "iops": 11347.4,
+ "throughput_mbps": 11347.4,
+ "avg_latency_ms": 0.088
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 34.4,
+ "iops": 58057.5,
+ "throughput_mbps": 226.8,
+ "avg_latency_ms": 0.017,
+ "latency_ms": {
+ "p50": 0.017,
+ "p95": 0.023,
+ "p99": 0.026,
+ "max": 0.045
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 85.9,
+ "iops": 23287.2,
+ "throughput_mbps": 91.0,
+ "avg_latency_ms": 0.043,
+ "latency_ms": {
+ "p50": 0.04,
+ "p95": 0.058,
+ "p99": 0.147,
+ "max": 0.191
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/run": {
+ "path": "/run",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 11.3,
+ "throughput_mbps": 5677.1
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 8.2,
+ "throughput_mbps": 7792.2
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.6,
+ "throughput_mbps": 11362.6
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1366.1,
+ "iops": 7319.9,
+ "throughput_mbps": 28.6
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.5,
+ "iops": 1326641.2,
+ "throughput_mbps": 5182.2
+ },
+ "io_profile": {
+ "path": "/run",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 21.6,
+ "iops": 759597.0,
+ "throughput_mbps": 2967.2,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 11.2,
+ "iops": 1457240.8,
+ "throughput_mbps": 5692.3,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 9.8,
+ "iops": 1679297.8,
+ "throughput_mbps": 6559.8,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 11.3,
+ "iops": 90613.5,
+ "throughput_mbps": 5663.3,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.9,
+ "iops": 147534.5,
+ "throughput_mbps": 9220.9,
+ "avg_latency_ms": 0.007
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 5.6,
+ "iops": 181529.4,
+ "throughput_mbps": 11345.6,
+ "avg_latency_ms": 0.006
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 11.8,
+ "iops": 5407.4,
+ "throughput_mbps": 5407.4,
+ "avg_latency_ms": 0.185
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 6.4,
+ "iops": 10054.0,
+ "throughput_mbps": 10054.0,
+ "avg_latency_ms": 0.099
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 4.8,
+ "iops": 13471.7,
+ "throughput_mbps": 13471.7,
+ "avg_latency_ms": 0.074
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 60.6,
+ "iops": 33026.7,
+ "throughput_mbps": 129.0,
+ "avg_latency_ms": 0.03,
+ "latency_ms": {
+ "p50": 0.032,
+ "p95": 0.036,
+ "p99": 0.041,
+ "max": 0.065
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 124.5,
+ "iops": 16061.9,
+ "throughput_mbps": 62.7,
+ "avg_latency_ms": 0.062,
+ "latency_ms": {
+ "p50": 0.061,
+ "p95": 0.071,
+ "p99": 0.138,
+ "max": 0.19
+ },
+ "sync_each": true
+ }
+ }
+ }
+ }
+ }
+ },
+ "startup": {
+ "runs_per_command": 3,
+ "commands": {
+ "python3": {
+ "command": [
+ "python3",
+ "--version"
+ ],
+ "timings_ms": [
+ 6.7,
+ 2.3,
+ 4.4
+ ],
+ "min_ms": 2.3,
+ "mean_ms": 4.5,
+ "max_ms": 6.7
+ },
+ "node": {
+ "command": [
+ "node",
+ "--version"
+ ],
+ "timings_ms": [
+ 24.8,
+ 27.2,
+ 25.9
+ ],
+ "min_ms": 24.8,
+ "mean_ms": 26.0,
+ "max_ms": 27.2
+ },
+ "claude": {
+ "command": [
+ "claude",
+ "--version"
+ ],
+ "timings_ms": [
+ 138.4,
+ 138.7,
+ 139.1
+ ],
+ "min_ms": 138.4,
+ "mean_ms": 138.7,
+ "max_ms": 139.1
+ },
+ "gemini": {
+ "command": [
+ "gemini",
+ "--version"
+ ],
+ "timings_ms": [
+ 659.1,
+ 664.3,
+ 660.8
+ ],
+ "min_ms": 659.1,
+ "mean_ms": 661.4,
+ "max_ms": 664.3
+ },
+ "codex": {
+ "command": [
+ "codex",
+ "--version"
+ ],
+ "timings_ms": [
+ 81.0,
+ 79.9,
+ 80.6
+ ],
+ "min_ms": 79.9,
+ "mean_ms": 80.5,
+ "max_ms": 81.0
+ }
+ }
+ },
+ "http": {
+ "skipped": true,
+ "reason": "set CAPSEM_BENCH_MITM_LOCAL_BASE_URL for local lab or CAPSEM_BENCH_ALLOW_PUBLIC_NETWORK=1 for explicit public smoke"
+ },
+ "throughput": {
+ "skipped": true,
+ "reason": "set CAPSEM_BENCH_MITM_LOCAL_BASE_URL for local lab or CAPSEM_BENCH_ALLOW_PUBLIC_NETWORK=1 for explicit public smoke"
+ },
+ "snapshot": {
+ "10_files": {
+ "create_ms": 702.1,
+ "create_ok": true,
+ "list_ms": 245.5,
+ "list_ok": true,
+ "changes_ms": 245.3,
+ "changes_ok": true,
+ "revert_ms": 277.2,
+ "revert_ok": true,
+ "delete_ms": 304.4,
+ "delete_ok": true
+ },
+ "100_files": {
+ "create_ms": 246.4,
+ "create_ok": true,
+ "list_ms": 245.6,
+ "list_ok": true,
+ "changes_ms": 248.6,
+ "changes_ok": true,
+ "revert_ms": 277.8,
+ "revert_ok": true,
+ "delete_ms": 303.7,
+ "delete_ok": true
+ },
+ "500_files": {
+ "create_ms": 267.0,
+ "create_ok": true,
+ "list_ms": 256.9,
+ "list_ok": true,
+ "changes_ms": 267.5,
+ "changes_ok": true,
+ "revert_ms": 250.1,
+ "revert_ok": true,
+ "delete_ms": 322.5,
+ "delete_ok": true
+ }
+ },
+ "host_recorded_at": 1781107846.432296,
+ "arch": "arm64"
+}
\ No newline at end of file
diff --git a/benchmarks/capsem-bench/data_1.3.1781124728_arm64.json b/benchmarks/capsem-bench/data_1.3.1781124728_arm64.json
new file mode 100644
index 000000000..67d1f3941
--- /dev/null
+++ b/benchmarks/capsem-bench/data_1.3.1781124728_arm64.json
@@ -0,0 +1,1479 @@
+{
+ "version": "0.3.0",
+ "timestamp": 1781205469.2184863,
+ "hostname": "bench-b7422b10",
+ "disk": {
+ "directory": "/root",
+ "size_mb": 256,
+ "seq_write": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 140.1,
+ "throughput_mbps": 1827.1
+ },
+ "seq_read": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 61.8,
+ "throughput_mbps": 4141.8
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1315.5,
+ "iops": 7601.9,
+ "throughput_mbps": 29.7
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 186.4,
+ "iops": 53650.9,
+ "throughput_mbps": 209.6
+ }
+ },
+ "rootfs": {
+ "scan_dirs": [
+ "/usr/bin",
+ "/usr/lib",
+ "/opt/ai-clis"
+ ],
+ "largest_file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "largest_file_size": 197796880,
+ "seq_read": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 58.2,
+ "throughput_mbps": 3238.5
+ },
+ "files_found": 5533,
+ "rand_read_4k": {
+ "count": 5000,
+ "files_sampled": 2581,
+ "block_size": 4096,
+ "duration_ms": 174.5,
+ "iops": 28649.8,
+ "throughput_mbps": 111.9
+ },
+ "large_binary_seq_read": {
+ "count": 2,
+ "files": [
+ {
+ "path": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "cold": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 57.0,
+ "throughput_mbps": 3310.5
+ },
+ "warm": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 10.0,
+ "throughput_mbps": 18907.5
+ }
+ },
+ {
+ "path": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "cold": {
+ "file": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "block_size": 1048576,
+ "duration_ms": 8.6,
+ "throughput_mbps": 4321.2
+ },
+ "warm": {
+ "file": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "block_size": 1048576,
+ "duration_ms": 2.3,
+ "throughput_mbps": 16574.1
+ }
+ }
+ ],
+ "bytes_read": 236959384,
+ "cold_duration_ms": 65.6,
+ "warm_duration_ms": 12.3,
+ "cold_throughput_mbps": 3444.8,
+ "warm_throughput_mbps": 18372.5
+ },
+ "small_js_read": {
+ "count": 5000,
+ "files_sampled": 99,
+ "bytes_read": 47398245,
+ "duration_ms": 7.4,
+ "ops_per_sec": 671546.6,
+ "throughput_mbps": 6071.1
+ },
+ "metadata_stat": {
+ "entries": 6538,
+ "files": 5533,
+ "dirs": 662,
+ "symlinks": 343,
+ "errors": 0,
+ "duration_ms": 46.6,
+ "stats_per_sec": 140347.2
+ }
+ },
+ "storage": {
+ "kernel": {
+ "cmdline": {
+ "raw": "console=hvc0 ro loglevel=1 quiet init_on_alloc=1 slab_nomerge page_alloc.shuffle=1 random.trust_cpu=1 capsem.storage=virtiofs capsem.rootfs=erofs",
+ "args": [
+ "console=hvc0",
+ "ro",
+ "loglevel=1",
+ "quiet",
+ "init_on_alloc=1",
+ "slab_nomerge",
+ "page_alloc.shuffle=1",
+ "random.trust_cpu=1",
+ "capsem.storage=virtiofs",
+ "capsem.rootfs=erofs"
+ ]
+ },
+ "block_queues": {
+ "vda": {
+ "scheduler": "[none] mq-deadline kyber",
+ "read_ahead_kb": 4096,
+ "nr_requests": 256,
+ "rotational": 1,
+ "logical_block_size": 512,
+ "physical_block_size": 512,
+ "max_sectors_kb": 4096,
+ "nomerges": 0,
+ "rq_affinity": 1,
+ "io_poll": 0,
+ "selected_scheduler": "none"
+ },
+ "vdb": {
+ "scheduler": "[none] mq-deadline kyber",
+ "read_ahead_kb": 4096,
+ "nr_requests": 256,
+ "rotational": 1,
+ "logical_block_size": 512,
+ "physical_block_size": 512,
+ "max_sectors_kb": 4096,
+ "nomerges": 0,
+ "rq_affinity": 1,
+ "io_poll": 0,
+ "selected_scheduler": "none"
+ }
+ },
+ "fuse_connections": {},
+ "known_host_queue_sizes": {
+ "kvm_virtio_blk": 256,
+ "kvm_virtio_fs": [
+ 256,
+ 256
+ ]
+ }
+ },
+ "mounts": [
+ {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ {
+ "mount_point": "/proc",
+ "root": "/",
+ "fs_type": "proc",
+ "source": "proc",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/sys",
+ "root": "/",
+ "fs_type": "sysfs",
+ "source": "sysfs",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/dev",
+ "root": "/",
+ "fs_type": "devtmpfs",
+ "source": "devtmpfs",
+ "options": "rw,size=1021592k,nr_inodes=255398,mode=755"
+ },
+ {
+ "mount_point": "/dev/pts",
+ "root": "/",
+ "fs_type": "devpts",
+ "source": "devpts",
+ "options": "rw,mode=600,ptmxmode=000"
+ },
+ {
+ "mount_point": "/root",
+ "root": "/workspace",
+ "fs_type": "virtiofs",
+ "source": "capsem",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/etc/resolv.conf",
+ "root": "/run/resolv.conf",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ }
+ ],
+ "paths": {
+ "/": {
+ "path": "/",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwx------",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496851,
+ "blocks_available": 492755,
+ "files": 131072,
+ "files_free": 130927
+ }
+ },
+ "/root": {
+ "path": "/root",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/root",
+ "root": "/workspace",
+ "fs_type": "virtiofs",
+ "source": "capsem",
+ "options": "rw"
+ },
+ "mode": "drwx------",
+ "statvfs": {
+ "block_size": 1048576,
+ "fragment_size": 4096,
+ "blocks": 975653540,
+ "blocks_free": 715012151,
+ "blocks_available": 715012151,
+ "files": 2834398439,
+ "files_free": 2830682264
+ }
+ },
+ "/tmp": {
+ "path": "/tmp",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxrwxrwt",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496851,
+ "blocks_available": 492755,
+ "files": 131072,
+ "files_free": 130927
+ }
+ },
+ "/var/tmp": {
+ "path": "/var/tmp",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxrwxrwt",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496851,
+ "blocks_available": 492755,
+ "files": 131072,
+ "files_free": 130927
+ }
+ },
+ "/var/log": {
+ "path": "/var/log",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496851,
+ "blocks_available": 492755,
+ "files": 131072,
+ "files_free": 130927
+ }
+ },
+ "/run": {
+ "path": "/run",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496851,
+ "blocks_available": 492755,
+ "files": 131072,
+ "files_free": 130927
+ }
+ },
+ "/usr/bin": {
+ "path": "/usr/bin",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496851,
+ "blocks_available": 492755,
+ "files": 131072,
+ "files_free": 130927
+ }
+ },
+ "/usr/lib": {
+ "path": "/usr/lib",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496851,
+ "blocks_available": 492755,
+ "files": 131072,
+ "files_free": 130927
+ }
+ },
+ "/opt/ai-clis": {
+ "path": "/opt/ai-clis",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496851,
+ "blocks_available": 492755,
+ "files": 131072,
+ "files_free": 130927
+ }
+ }
+ },
+ "rootfs": {
+ "scan_dirs": [
+ "/usr/bin",
+ "/usr/lib",
+ "/opt/ai-clis"
+ ],
+ "files_found": 3316,
+ "largest_file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "largest_file_size": 197796880,
+ "backing": {
+ "root_mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "overlay_lowerdir": "/mnt/a",
+ "overlay_upperdir": "/mnt/system/upper",
+ "overlay_workdir": "/mnt/system/work",
+ "squashfs_mounts": [],
+ "squashfs_superblock": {
+ "device": "/dev/vda",
+ "magic": "0x00000000",
+ "error": "not squashfs",
+ "read_ahead_kb": 4096
+ }
+ },
+ "seq_reads": [
+ {
+ "label": "largest",
+ "path": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 53.9,
+ "throughput_mbps": 3500.1
+ },
+ "warm": {
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 9.5,
+ "throughput_mbps": 19872.0
+ }
+ },
+ {
+ "label": "bash",
+ "path": "/bin/bash",
+ "size_bytes": 1346480,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 1346480,
+ "block_size": 1048576,
+ "duration_ms": 0.9,
+ "throughput_mbps": 1401.4
+ },
+ "warm": {
+ "size_bytes": 1346480,
+ "block_size": 1048576,
+ "duration_ms": 0.1,
+ "throughput_mbps": 19934.2
+ }
+ },
+ {
+ "label": "python3",
+ "path": "/usr/bin/python3",
+ "size_bytes": 6616880,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 6616880,
+ "block_size": 1048576,
+ "duration_ms": 1.0,
+ "throughput_mbps": 6471.1
+ },
+ "warm": {
+ "size_bytes": 6616880,
+ "block_size": 1048576,
+ "duration_ms": 0.3,
+ "throughput_mbps": 20529.8
+ }
+ }
+ ],
+ "rand_read_4k": {
+ "count": 2000,
+ "files_sampled": 1478,
+ "duration_ms": 102.2,
+ "iops": 19570.7,
+ "throughput_mbps": 76.4
+ }
+ },
+ "writable": {
+ "/root": {
+ "path": "/root",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 26.6,
+ "throughput_mbps": 2405.7
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 15.4,
+ "throughput_mbps": 4156.7
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 14.6,
+ "throughput_mbps": 4378.6
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1258.5,
+ "iops": 7946.1,
+ "throughput_mbps": 31.0
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 195.0,
+ "iops": 51276.4,
+ "throughput_mbps": 200.3
+ },
+ "io_profile": {
+ "path": "/root",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 985.7,
+ "iops": 16621.5,
+ "throughput_mbps": 64.9,
+ "avg_latency_ms": 0.06
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 19.8,
+ "iops": 828534.8,
+ "throughput_mbps": 3236.5,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 16.2,
+ "iops": 1008284.9,
+ "throughput_mbps": 3938.6,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 72.5,
+ "iops": 14117.9,
+ "throughput_mbps": 882.4,
+ "avg_latency_ms": 0.071
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 16.8,
+ "iops": 60975.4,
+ "throughput_mbps": 3811.0,
+ "avg_latency_ms": 0.016
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 19.7,
+ "iops": 51959.0,
+ "throughput_mbps": 3247.4,
+ "avg_latency_ms": 0.019
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 28.0,
+ "iops": 2287.2,
+ "throughput_mbps": 2287.2,
+ "avg_latency_ms": 0.437
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 15.3,
+ "iops": 4196.1,
+ "throughput_mbps": 4196.1,
+ "avg_latency_ms": 0.238
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 15.6,
+ "iops": 4102.7,
+ "throughput_mbps": 4102.7,
+ "avg_latency_ms": 0.244
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 47.9,
+ "iops": 41732.2,
+ "throughput_mbps": 163.0,
+ "avg_latency_ms": 0.024,
+ "latency_ms": {
+ "p50": 0.025,
+ "p95": 0.031,
+ "p99": 0.036,
+ "max": 0.045
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 214.9,
+ "iops": 9305.0,
+ "throughput_mbps": 36.3,
+ "avg_latency_ms": 0.107,
+ "latency_ms": {
+ "p50": 0.107,
+ "p95": 0.121,
+ "p99": 0.128,
+ "max": 0.348
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/tmp": {
+ "path": "/tmp",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 11.4,
+ "throughput_mbps": 5616.6
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 6.8,
+ "throughput_mbps": 9431.5
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.3,
+ "throughput_mbps": 12099.4
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1644.8,
+ "iops": 6079.8,
+ "throughput_mbps": 23.7
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.5,
+ "iops": 1329964.1,
+ "throughput_mbps": 5195.2
+ },
+ "io_profile": {
+ "path": "/tmp",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 17.0,
+ "iops": 965565.7,
+ "throughput_mbps": 3771.7,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 12.1,
+ "iops": 1348787.3,
+ "throughput_mbps": 5268.7,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 9.7,
+ "iops": 1696776.2,
+ "throughput_mbps": 6628.0,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 11.1,
+ "iops": 92141.2,
+ "throughput_mbps": 5758.8,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 7.6,
+ "iops": 135081.2,
+ "throughput_mbps": 8442.6,
+ "avg_latency_ms": 0.007
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 5.2,
+ "iops": 196697.7,
+ "throughput_mbps": 12293.6,
+ "avg_latency_ms": 0.005
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 52.4,
+ "iops": 1222.3,
+ "throughput_mbps": 1222.3,
+ "avg_latency_ms": 0.818
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 7.2,
+ "iops": 8882.2,
+ "throughput_mbps": 8882.2,
+ "avg_latency_ms": 0.113
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 4.5,
+ "iops": 14278.4,
+ "throughput_mbps": 14278.4,
+ "avg_latency_ms": 0.07
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 39.4,
+ "iops": 50818.1,
+ "throughput_mbps": 198.5,
+ "avg_latency_ms": 0.02,
+ "latency_ms": {
+ "p50": 0.021,
+ "p95": 0.024,
+ "p99": 0.028,
+ "max": 0.049
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 86.6,
+ "iops": 23085.4,
+ "throughput_mbps": 90.2,
+ "avg_latency_ms": 0.043,
+ "latency_ms": {
+ "p50": 0.041,
+ "p95": 0.052,
+ "p99": 0.143,
+ "max": 0.211
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/var/tmp": {
+ "path": "/var/tmp",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 14.0,
+ "throughput_mbps": 4558.0
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 7.5,
+ "throughput_mbps": 8564.6
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.0,
+ "throughput_mbps": 12841.4
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1334.6,
+ "iops": 7492.7,
+ "throughput_mbps": 29.3
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.7,
+ "iops": 1302938.7,
+ "throughput_mbps": 5089.6
+ },
+ "io_profile": {
+ "path": "/var/tmp",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 23.3,
+ "iops": 704315.8,
+ "throughput_mbps": 2751.2,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 11.2,
+ "iops": 1459821.4,
+ "throughput_mbps": 5702.4,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 9.7,
+ "iops": 1694545.9,
+ "throughput_mbps": 6619.3,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 10.8,
+ "iops": 94999.5,
+ "throughput_mbps": 5937.5,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.7,
+ "iops": 151881.8,
+ "throughput_mbps": 9492.6,
+ "avg_latency_ms": 0.007
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 5.6,
+ "iops": 182669.6,
+ "throughput_mbps": 11416.8,
+ "avg_latency_ms": 0.005
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 13.3,
+ "iops": 4825.2,
+ "throughput_mbps": 4825.2,
+ "avg_latency_ms": 0.207
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 8.0,
+ "iops": 7979.5,
+ "throughput_mbps": 7979.5,
+ "avg_latency_ms": 0.125
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 5.1,
+ "iops": 12547.3,
+ "throughput_mbps": 12547.3,
+ "avg_latency_ms": 0.08
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 41.3,
+ "iops": 48372.7,
+ "throughput_mbps": 189.0,
+ "avg_latency_ms": 0.021,
+ "latency_ms": {
+ "p50": 0.022,
+ "p95": 0.028,
+ "p99": 0.035,
+ "max": 0.09
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 85.7,
+ "iops": 23338.8,
+ "throughput_mbps": 91.2,
+ "avg_latency_ms": 0.043,
+ "latency_ms": {
+ "p50": 0.041,
+ "p95": 0.052,
+ "p99": 0.146,
+ "max": 0.212
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/var/log": {
+ "path": "/var/log",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 11.0,
+ "throughput_mbps": 5807.9
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 7.4,
+ "throughput_mbps": 8622.1
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.3,
+ "throughput_mbps": 12078.5
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1358.9,
+ "iops": 7359.1,
+ "throughput_mbps": 28.7
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.5,
+ "iops": 1339009.1,
+ "throughput_mbps": 5230.5
+ },
+ "io_profile": {
+ "path": "/var/log",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 18.5,
+ "iops": 884615.5,
+ "throughput_mbps": 3455.5,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 12.5,
+ "iops": 1305576.0,
+ "throughput_mbps": 5099.9,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 10.6,
+ "iops": 1542616.3,
+ "throughput_mbps": 6025.8,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 11.2,
+ "iops": 91053.6,
+ "throughput_mbps": 5690.8,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 8.2,
+ "iops": 125516.5,
+ "throughput_mbps": 7844.8,
+ "avg_latency_ms": 0.008
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.0,
+ "iops": 171706.4,
+ "throughput_mbps": 10731.7,
+ "avg_latency_ms": 0.006
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 13.5,
+ "iops": 4729.5,
+ "throughput_mbps": 4729.5,
+ "avg_latency_ms": 0.211
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 6.6,
+ "iops": 9624.6,
+ "throughput_mbps": 9624.6,
+ "avg_latency_ms": 0.104
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 5.0,
+ "iops": 12678.9,
+ "throughput_mbps": 12678.9,
+ "avg_latency_ms": 0.079
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 51.6,
+ "iops": 38729.0,
+ "throughput_mbps": 151.3,
+ "avg_latency_ms": 0.026,
+ "latency_ms": {
+ "p50": 0.026,
+ "p95": 0.032,
+ "p99": 0.037,
+ "max": 0.053
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 128.3,
+ "iops": 15584.2,
+ "throughput_mbps": 60.9,
+ "avg_latency_ms": 0.064,
+ "latency_ms": {
+ "p50": 0.062,
+ "p95": 0.076,
+ "p99": 0.141,
+ "max": 0.168
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/run": {
+ "path": "/run",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 10.8,
+ "throughput_mbps": 5952.6
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 6.9,
+ "throughput_mbps": 9322.7
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.3,
+ "throughput_mbps": 12106.6
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1253.1,
+ "iops": 7980.2,
+ "throughput_mbps": 31.2
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.6,
+ "iops": 1309114.7,
+ "throughput_mbps": 5113.7
+ },
+ "io_profile": {
+ "path": "/run",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 17.5,
+ "iops": 938801.3,
+ "throughput_mbps": 3667.2,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 11.4,
+ "iops": 1436961.9,
+ "throughput_mbps": 5613.1,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 10.4,
+ "iops": 1572002.5,
+ "throughput_mbps": 6140.6,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 10.8,
+ "iops": 94926.1,
+ "throughput_mbps": 5932.9,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.9,
+ "iops": 147588.5,
+ "throughput_mbps": 9224.3,
+ "avg_latency_ms": 0.007
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.2,
+ "iops": 166097.8,
+ "throughput_mbps": 10381.1,
+ "avg_latency_ms": 0.006
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 10.8,
+ "iops": 5948.3,
+ "throughput_mbps": 5948.3,
+ "avg_latency_ms": 0.168
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 6.5,
+ "iops": 9863.3,
+ "throughput_mbps": 9863.3,
+ "avg_latency_ms": 0.101
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 5.3,
+ "iops": 12011.2,
+ "throughput_mbps": 12011.2,
+ "avg_latency_ms": 0.083
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 60.8,
+ "iops": 32871.4,
+ "throughput_mbps": 128.4,
+ "avg_latency_ms": 0.03,
+ "latency_ms": {
+ "p50": 0.032,
+ "p95": 0.036,
+ "p99": 0.04,
+ "max": 0.074
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 121.2,
+ "iops": 16496.2,
+ "throughput_mbps": 64.4,
+ "avg_latency_ms": 0.061,
+ "latency_ms": {
+ "p50": 0.058,
+ "p95": 0.069,
+ "p99": 0.13,
+ "max": 0.167
+ },
+ "sync_each": true
+ }
+ }
+ }
+ }
+ }
+ },
+ "startup": {
+ "runs_per_command": 3,
+ "commands": {
+ "python3": {
+ "command": [
+ "python3",
+ "--version"
+ ],
+ "timings_ms": [
+ 3.8,
+ 3.7,
+ 3.9
+ ],
+ "min_ms": 3.7,
+ "mean_ms": 3.8,
+ "max_ms": 3.9
+ },
+ "node": {
+ "command": [
+ "node",
+ "--version"
+ ],
+ "timings_ms": [
+ 25.0,
+ 26.7,
+ 26.0
+ ],
+ "min_ms": 25.0,
+ "mean_ms": 25.9,
+ "max_ms": 26.7
+ },
+ "claude": {
+ "command": [
+ "claude",
+ "--version"
+ ],
+ "timings_ms": [
+ 138.5,
+ 134.9,
+ 139.2
+ ],
+ "min_ms": 134.9,
+ "mean_ms": 137.5,
+ "max_ms": 139.2
+ },
+ "gemini": {
+ "command": [
+ "gemini",
+ "--version"
+ ],
+ "timings_ms": [
+ 663.0,
+ 708.7,
+ 657.3
+ ],
+ "min_ms": 657.3,
+ "mean_ms": 676.3,
+ "max_ms": 708.7
+ },
+ "codex": {
+ "command": [
+ "codex",
+ "--version"
+ ],
+ "timings_ms": [
+ 80.8,
+ 80.0,
+ 80.6
+ ],
+ "min_ms": 80.0,
+ "mean_ms": 80.5,
+ "max_ms": 80.8
+ }
+ }
+ },
+ "http": {
+ "skipped": true,
+ "reason": "set CAPSEM_BENCH_MITM_LOCAL_BASE_URL for local lab or CAPSEM_BENCH_ALLOW_PUBLIC_NETWORK=1 for explicit public smoke"
+ },
+ "throughput": {
+ "skipped": true,
+ "reason": "set CAPSEM_BENCH_MITM_LOCAL_BASE_URL for local lab or CAPSEM_BENCH_ALLOW_PUBLIC_NETWORK=1 for explicit public smoke"
+ },
+ "snapshot": {
+ "10_files": {
+ "create_ms": 690.9,
+ "create_ok": true,
+ "list_ms": 244.9,
+ "list_ok": true,
+ "changes_ms": 245.8,
+ "changes_ok": true,
+ "revert_ms": 273.2,
+ "revert_ok": true,
+ "delete_ms": 302.1,
+ "delete_ok": true
+ },
+ "100_files": {
+ "create_ms": 247.8,
+ "create_ok": true,
+ "list_ms": 245.3,
+ "list_ok": true,
+ "changes_ms": 248.7,
+ "changes_ok": true,
+ "revert_ms": 268.9,
+ "revert_ok": true,
+ "delete_ms": 302.0,
+ "delete_ok": true
+ },
+ "500_files": {
+ "create_ms": 257.6,
+ "create_ok": true,
+ "list_ms": 250.0,
+ "list_ok": true,
+ "changes_ms": 277.0,
+ "changes_ok": true,
+ "revert_ms": 276.8,
+ "revert_ok": true,
+ "delete_ms": 313.0,
+ "delete_ok": true
+ }
+ },
+ "host_recorded_at": 1781205489.9733708,
+ "arch": "arm64"
+}
\ No newline at end of file
diff --git a/benchmarks/capsem-bench/data_1.3.1781205836_arm64.json b/benchmarks/capsem-bench/data_1.3.1781205836_arm64.json
new file mode 100644
index 000000000..3e9bf6200
--- /dev/null
+++ b/benchmarks/capsem-bench/data_1.3.1781205836_arm64.json
@@ -0,0 +1,1593 @@
+{
+ "version": "0.3.0",
+ "timestamp": 1781633306.11044,
+ "hostname": "bench-d0210a24",
+ "disk": {
+ "directory": "/root",
+ "size_mb": 256,
+ "seq_write": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 142.0,
+ "throughput_mbps": 1802.7
+ },
+ "seq_read": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 60.1,
+ "throughput_mbps": 4261.9
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1366.3,
+ "iops": 7319.0,
+ "throughput_mbps": 28.6
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 127.7,
+ "iops": 78298.9,
+ "throughput_mbps": 305.9
+ }
+ },
+ "rootfs": {
+ "scan_dirs": [
+ "/usr/bin",
+ "/usr/lib",
+ "/opt/ai-clis"
+ ],
+ "largest_file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "largest_file_size": 197796880,
+ "seq_read": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 57.3,
+ "throughput_mbps": 3290.3
+ },
+ "files_found": 5538,
+ "rand_read_4k": {
+ "count": 5000,
+ "files_sampled": 2604,
+ "block_size": 4096,
+ "duration_ms": 176.7,
+ "iops": 28292.0,
+ "throughput_mbps": 110.5
+ },
+ "large_binary_seq_read": {
+ "count": 2,
+ "files": [
+ {
+ "path": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "cold": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 53.8,
+ "throughput_mbps": 3503.7
+ },
+ "warm": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 9.8,
+ "throughput_mbps": 19240.6
+ }
+ },
+ {
+ "path": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "cold": {
+ "file": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "block_size": 1048576,
+ "duration_ms": 9.1,
+ "throughput_mbps": 4106.0
+ },
+ "warm": {
+ "file": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "block_size": 1048576,
+ "duration_ms": 2.6,
+ "throughput_mbps": 14514.8
+ }
+ }
+ ],
+ "bytes_read": 236959384,
+ "cold_duration_ms": 62.9,
+ "warm_duration_ms": 12.4,
+ "cold_throughput_mbps": 3592.7,
+ "warm_throughput_mbps": 18224.4
+ },
+ "small_js_read": {
+ "count": 5000,
+ "files_sampled": 99,
+ "bytes_read": 48917990,
+ "duration_ms": 7.5,
+ "ops_per_sec": 665550.0,
+ "throughput_mbps": 6209.8
+ },
+ "metadata_stat": {
+ "entries": 6546,
+ "files": 5538,
+ "dirs": 662,
+ "symlinks": 346,
+ "errors": 0,
+ "duration_ms": 60.3,
+ "stats_per_sec": 108594.7
+ }
+ },
+ "storage": {
+ "kernel": {
+ "cmdline": {
+ "raw": "console=hvc0 ro loglevel=1 quiet init_on_alloc=1 slab_nomerge page_alloc.shuffle=1 random.trust_cpu=1 capsem.storage=virtiofs capsem.rootfs=erofs",
+ "args": [
+ "console=hvc0",
+ "ro",
+ "loglevel=1",
+ "quiet",
+ "init_on_alloc=1",
+ "slab_nomerge",
+ "page_alloc.shuffle=1",
+ "random.trust_cpu=1",
+ "capsem.storage=virtiofs",
+ "capsem.rootfs=erofs"
+ ]
+ },
+ "block_queues": {
+ "vda": {
+ "scheduler": "[none] mq-deadline kyber",
+ "read_ahead_kb": 4096,
+ "nr_requests": 256,
+ "rotational": 1,
+ "logical_block_size": 512,
+ "physical_block_size": 512,
+ "max_sectors_kb": 4096,
+ "nomerges": 0,
+ "rq_affinity": 1,
+ "io_poll": 0,
+ "selected_scheduler": "none"
+ },
+ "vdb": {
+ "scheduler": "[none] mq-deadline kyber",
+ "read_ahead_kb": 4096,
+ "nr_requests": 256,
+ "rotational": 1,
+ "logical_block_size": 512,
+ "physical_block_size": 512,
+ "max_sectors_kb": 4096,
+ "nomerges": 0,
+ "rq_affinity": 1,
+ "io_poll": 0,
+ "selected_scheduler": "none"
+ }
+ },
+ "fuse_connections": {},
+ "known_host_queue_sizes": {
+ "kvm_virtio_blk": 256,
+ "kvm_virtio_fs": [
+ 256,
+ 256
+ ]
+ }
+ },
+ "mounts": [
+ {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ {
+ "mount_point": "/proc",
+ "root": "/",
+ "fs_type": "proc",
+ "source": "proc",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/sys",
+ "root": "/",
+ "fs_type": "sysfs",
+ "source": "sysfs",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/dev",
+ "root": "/",
+ "fs_type": "devtmpfs",
+ "source": "devtmpfs",
+ "options": "rw,size=1021556k,nr_inodes=255389,mode=755"
+ },
+ {
+ "mount_point": "/dev/pts",
+ "root": "/",
+ "fs_type": "devpts",
+ "source": "devpts",
+ "options": "rw,mode=600,ptmxmode=000"
+ },
+ {
+ "mount_point": "/root",
+ "root": "/workspace",
+ "fs_type": "virtiofs",
+ "source": "capsem",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/etc/resolv.conf",
+ "root": "/run/resolv.conf",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ }
+ ],
+ "paths": {
+ "/": {
+ "path": "/",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 16369547,
+ "blocks_free": 16368196,
+ "blocks_available": 16364100,
+ "files": 4194304,
+ "files_free": 4194151
+ }
+ },
+ "/root": {
+ "path": "/root",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/root",
+ "root": "/workspace",
+ "fs_type": "virtiofs",
+ "source": "capsem",
+ "options": "rw"
+ },
+ "mode": "drwx------",
+ "statvfs": {
+ "block_size": 1048576,
+ "fragment_size": 4096,
+ "blocks": 975653540,
+ "blocks_free": 694606428,
+ "blocks_available": 694606428,
+ "files": 2019184956,
+ "files_free": 2014453344
+ }
+ },
+ "/tmp": {
+ "path": "/tmp",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxrwxrwt",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 16369547,
+ "blocks_free": 16368196,
+ "blocks_available": 16364100,
+ "files": 4194304,
+ "files_free": 4194151
+ }
+ },
+ "/var/tmp": {
+ "path": "/var/tmp",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxrwxrwt",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 16369547,
+ "blocks_free": 16368196,
+ "blocks_available": 16364100,
+ "files": 4194304,
+ "files_free": 4194151
+ }
+ },
+ "/var/log": {
+ "path": "/var/log",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 16369547,
+ "blocks_free": 16368196,
+ "blocks_available": 16364100,
+ "files": 4194304,
+ "files_free": 4194151
+ }
+ },
+ "/run": {
+ "path": "/run",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 16369547,
+ "blocks_free": 16368196,
+ "blocks_available": 16364100,
+ "files": 4194304,
+ "files_free": 4194151
+ }
+ },
+ "/usr/bin": {
+ "path": "/usr/bin",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 16369547,
+ "blocks_free": 16368196,
+ "blocks_available": 16364100,
+ "files": 4194304,
+ "files_free": 4194151
+ }
+ },
+ "/usr/lib": {
+ "path": "/usr/lib",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 16369547,
+ "blocks_free": 16368196,
+ "blocks_available": 16364100,
+ "files": 4194304,
+ "files_free": 4194151
+ }
+ },
+ "/opt/ai-clis": {
+ "path": "/opt/ai-clis",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 16369547,
+ "blocks_free": 16368196,
+ "blocks_available": 16364100,
+ "files": 4194304,
+ "files_free": 4194151
+ }
+ }
+ },
+ "rootfs": {
+ "scan_dirs": [
+ "/usr/bin",
+ "/usr/lib",
+ "/opt/ai-clis"
+ ],
+ "files_found": 3318,
+ "largest_file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "largest_file_size": 197796880,
+ "backing": {
+ "root_mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "overlay_lowerdir": "/mnt/a",
+ "overlay_upperdir": "/mnt/system/upper",
+ "overlay_workdir": "/mnt/system/work",
+ "erofs_mounts": [],
+ "squashfs_superblock": {
+ "device": "/dev/vda",
+ "magic": "0x00000000",
+ "error": "not squashfs",
+ "read_ahead_kb": 4096
+ }
+ },
+ "seq_reads": [
+ {
+ "label": "largest",
+ "path": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 54.4,
+ "throughput_mbps": 3470.0
+ },
+ "warm": {
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 9.4,
+ "throughput_mbps": 20158.8
+ }
+ },
+ {
+ "label": "bash",
+ "path": "/bin/bash",
+ "size_bytes": 1346480,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 1346480,
+ "block_size": 1048576,
+ "duration_ms": 0.3,
+ "throughput_mbps": 4804.1
+ },
+ "warm": {
+ "size_bytes": 1346480,
+ "block_size": 1048576,
+ "duration_ms": 0.1,
+ "throughput_mbps": 22930.4
+ }
+ },
+ {
+ "label": "python3",
+ "path": "/usr/bin/python3",
+ "size_bytes": 6616880,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 6616880,
+ "block_size": 1048576,
+ "duration_ms": 1.0,
+ "throughput_mbps": 6270.9
+ },
+ "warm": {
+ "size_bytes": 6616880,
+ "block_size": 1048576,
+ "duration_ms": 0.3,
+ "throughput_mbps": 23238.9
+ }
+ }
+ ],
+ "rand_read_4k": {
+ "count": 2000,
+ "files_sampled": 1507,
+ "duration_ms": 101.1,
+ "iops": 19774.0,
+ "throughput_mbps": 77.2
+ }
+ },
+ "writable": {
+ "/root": {
+ "path": "/root",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 22.1,
+ "throughput_mbps": 2898.9
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 15.0,
+ "throughput_mbps": 4263.1
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 14.4,
+ "throughput_mbps": 4456.5
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1349.3,
+ "iops": 7411.4,
+ "throughput_mbps": 29.0
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 193.1,
+ "iops": 51774.7,
+ "throughput_mbps": 202.2
+ },
+ "io_profile": {
+ "path": "/root",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 1013.3,
+ "iops": 16168.5,
+ "throughput_mbps": 63.2,
+ "avg_latency_ms": 0.062
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 17.8,
+ "iops": 920902.1,
+ "throughput_mbps": 3597.3,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 17.6,
+ "iops": 928497.7,
+ "throughput_mbps": 3626.9,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 75.7,
+ "iops": 13529.8,
+ "throughput_mbps": 845.6,
+ "avg_latency_ms": 0.074
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 16.2,
+ "iops": 63363.4,
+ "throughput_mbps": 3960.2,
+ "avg_latency_ms": 0.016
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 15.8,
+ "iops": 64855.3,
+ "throughput_mbps": 4053.5,
+ "avg_latency_ms": 0.015
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 30.9,
+ "iops": 2070.8,
+ "throughput_mbps": 2070.8,
+ "avg_latency_ms": 0.483
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 14.9,
+ "iops": 4304.2,
+ "throughput_mbps": 4304.2,
+ "avg_latency_ms": 0.232
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 14.5,
+ "iops": 4428.3,
+ "throughput_mbps": 4428.3,
+ "avg_latency_ms": 0.226
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 48.6,
+ "iops": 41125.4,
+ "throughput_mbps": 160.6,
+ "avg_latency_ms": 0.024,
+ "latency_ms": {
+ "p50": 0.025,
+ "p95": 0.031,
+ "p99": 0.037,
+ "max": 0.062
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 221.9,
+ "iops": 9011.6,
+ "throughput_mbps": 35.2,
+ "avg_latency_ms": 0.111,
+ "latency_ms": {
+ "p50": 0.11,
+ "p95": 0.123,
+ "p99": 0.13,
+ "max": 0.431
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/tmp": {
+ "path": "/tmp",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 10.3,
+ "throughput_mbps": 6196.4
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 6.4,
+ "throughput_mbps": 9935.0
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 4.8,
+ "throughput_mbps": 13451.1
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1924.2,
+ "iops": 5196.9,
+ "throughput_mbps": 20.3
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.7,
+ "iops": 1290669.6,
+ "throughput_mbps": 5041.7
+ },
+ "io_profile": {
+ "path": "/tmp",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 16.7,
+ "iops": 983013.0,
+ "throughput_mbps": 3839.9,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 12.8,
+ "iops": 1282688.9,
+ "throughput_mbps": 5010.5,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 11.2,
+ "iops": 1464306.3,
+ "throughput_mbps": 5719.9,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 11.8,
+ "iops": 86906.4,
+ "throughput_mbps": 5431.6,
+ "avg_latency_ms": 0.012
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 7.6,
+ "iops": 134266.5,
+ "throughput_mbps": 8391.7,
+ "avg_latency_ms": 0.007
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.6,
+ "iops": 154279.8,
+ "throughput_mbps": 9642.5,
+ "avg_latency_ms": 0.006
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 82.1,
+ "iops": 779.4,
+ "throughput_mbps": 779.4,
+ "avg_latency_ms": 1.283
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 8.2,
+ "iops": 7772.4,
+ "throughput_mbps": 7772.4,
+ "avg_latency_ms": 0.129
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 6.3,
+ "iops": 10239.5,
+ "throughput_mbps": 10239.5,
+ "avg_latency_ms": 0.098
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 59.0,
+ "iops": 33878.9,
+ "throughput_mbps": 132.3,
+ "avg_latency_ms": 0.03,
+ "latency_ms": {
+ "p50": 0.032,
+ "p95": 0.037,
+ "p99": 0.042,
+ "max": 0.058
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 138.2,
+ "iops": 14471.6,
+ "throughput_mbps": 56.5,
+ "avg_latency_ms": 0.069,
+ "latency_ms": {
+ "p50": 0.064,
+ "p95": 0.076,
+ "p99": 0.198,
+ "max": 4.291
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/var/tmp": {
+ "path": "/var/tmp",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 15.4,
+ "throughput_mbps": 4164.3
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 7.7,
+ "throughput_mbps": 8303.9
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.9,
+ "throughput_mbps": 10897.1
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1688.6,
+ "iops": 5922.1,
+ "throughput_mbps": 23.1
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.3,
+ "iops": 1368652.2,
+ "throughput_mbps": 5346.3
+ },
+ "io_profile": {
+ "path": "/var/tmp",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 19.2,
+ "iops": 852301.2,
+ "throughput_mbps": 3329.3,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 12.7,
+ "iops": 1286541.7,
+ "throughput_mbps": 5025.6,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 10.4,
+ "iops": 1575138.5,
+ "throughput_mbps": 6152.9,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 11.1,
+ "iops": 91968.1,
+ "throughput_mbps": 5748.0,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 7.1,
+ "iops": 144962.1,
+ "throughput_mbps": 9060.1,
+ "avg_latency_ms": 0.007
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.0,
+ "iops": 171299.5,
+ "throughput_mbps": 10706.2,
+ "avg_latency_ms": 0.006
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 11.8,
+ "iops": 5433.8,
+ "throughput_mbps": 5433.8,
+ "avg_latency_ms": 0.184
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 7.2,
+ "iops": 8933.0,
+ "throughput_mbps": 8933.0,
+ "avg_latency_ms": 0.112
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 5.7,
+ "iops": 11266.4,
+ "throughput_mbps": 11266.4,
+ "avg_latency_ms": 0.089
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 61.5,
+ "iops": 32511.0,
+ "throughput_mbps": 127.0,
+ "avg_latency_ms": 0.031,
+ "latency_ms": {
+ "p50": 0.032,
+ "p95": 0.037,
+ "p99": 0.04,
+ "max": 0.059
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 129.3,
+ "iops": 15463.8,
+ "throughput_mbps": 60.4,
+ "avg_latency_ms": 0.065,
+ "latency_ms": {
+ "p50": 0.062,
+ "p95": 0.072,
+ "p99": 0.211,
+ "max": 0.405
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/var/log": {
+ "path": "/var/log",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 11.0,
+ "throughput_mbps": 5817.3
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 7.4,
+ "throughput_mbps": 8612.8
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.9,
+ "throughput_mbps": 10856.1
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1625.8,
+ "iops": 6150.9,
+ "throughput_mbps": 24.0
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.3,
+ "iops": 1368550.7,
+ "throughput_mbps": 5345.9
+ },
+ "io_profile": {
+ "path": "/var/log",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 19.9,
+ "iops": 821756.0,
+ "throughput_mbps": 3210.0,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 11.9,
+ "iops": 1379410.1,
+ "throughput_mbps": 5388.3,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 11.0,
+ "iops": 1495555.7,
+ "throughput_mbps": 5842.0,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 11.0,
+ "iops": 93086.3,
+ "throughput_mbps": 5817.9,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 7.2,
+ "iops": 142272.4,
+ "throughput_mbps": 8892.0,
+ "avg_latency_ms": 0.007
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.3,
+ "iops": 161923.9,
+ "throughput_mbps": 10120.2,
+ "avg_latency_ms": 0.006
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 11.6,
+ "iops": 5529.7,
+ "throughput_mbps": 5529.7,
+ "avg_latency_ms": 0.181
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 6.9,
+ "iops": 9327.6,
+ "throughput_mbps": 9327.6,
+ "avg_latency_ms": 0.107
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 5.7,
+ "iops": 11280.4,
+ "throughput_mbps": 11280.4,
+ "avg_latency_ms": 0.089
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 61.3,
+ "iops": 32640.5,
+ "throughput_mbps": 127.5,
+ "avg_latency_ms": 0.031,
+ "latency_ms": {
+ "p50": 0.032,
+ "p95": 0.036,
+ "p99": 0.041,
+ "max": 0.056
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 124.7,
+ "iops": 16032.2,
+ "throughput_mbps": 62.6,
+ "avg_latency_ms": 0.062,
+ "latency_ms": {
+ "p50": 0.061,
+ "p95": 0.071,
+ "p99": 0.141,
+ "max": 0.194
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/run": {
+ "path": "/run",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 10.6,
+ "throughput_mbps": 6021.8
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 7.2,
+ "throughput_mbps": 8852.2
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.7,
+ "throughput_mbps": 11178.5
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1420.3,
+ "iops": 7040.8,
+ "throughput_mbps": 27.5
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.5,
+ "iops": 1327022.5,
+ "throughput_mbps": 5183.7
+ },
+ "io_profile": {
+ "path": "/run",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 21.1,
+ "iops": 776905.6,
+ "throughput_mbps": 3034.8,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 16.6,
+ "iops": 989187.8,
+ "throughput_mbps": 3864.0,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 10.7,
+ "iops": 1531179.2,
+ "throughput_mbps": 5981.2,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 11.7,
+ "iops": 87729.1,
+ "throughput_mbps": 5483.1,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 8.7,
+ "iops": 117892.6,
+ "throughput_mbps": 7368.3,
+ "avg_latency_ms": 0.008
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.1,
+ "iops": 166759.4,
+ "throughput_mbps": 10422.5,
+ "avg_latency_ms": 0.006
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 11.1,
+ "iops": 5764.4,
+ "throughput_mbps": 5764.4,
+ "avg_latency_ms": 0.173
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 8.0,
+ "iops": 8012.6,
+ "throughput_mbps": 8012.6,
+ "avg_latency_ms": 0.125
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 5.5,
+ "iops": 11630.6,
+ "throughput_mbps": 11630.6,
+ "avg_latency_ms": 0.086
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 48.0,
+ "iops": 41629.8,
+ "throughput_mbps": 162.6,
+ "avg_latency_ms": 0.024,
+ "latency_ms": {
+ "p50": 0.024,
+ "p95": 0.033,
+ "p99": 0.047,
+ "max": 0.209
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 134.2,
+ "iops": 14905.0,
+ "throughput_mbps": 58.2,
+ "avg_latency_ms": 0.067,
+ "latency_ms": {
+ "p50": 0.061,
+ "p95": 0.092,
+ "p99": 0.186,
+ "max": 0.469
+ },
+ "sync_each": true
+ }
+ }
+ }
+ }
+ }
+ },
+ "startup": {
+ "runs_per_command": 3,
+ "commands": {
+ "python3": {
+ "command": [
+ "python3",
+ "--version"
+ ],
+ "timings_ms": [
+ 3.2,
+ 3.8,
+ 3.7
+ ],
+ "min_ms": 3.2,
+ "mean_ms": 3.6,
+ "max_ms": 3.8
+ },
+ "node": {
+ "command": [
+ "node",
+ "--version"
+ ],
+ "timings_ms": [
+ 27.9,
+ 26.5,
+ 22.3
+ ],
+ "min_ms": 22.3,
+ "mean_ms": 25.6,
+ "max_ms": 27.9
+ },
+ "claude": {
+ "command": [
+ "claude",
+ "--version"
+ ],
+ "timings_ms": [
+ 127.0,
+ 135.4,
+ 134.9
+ ],
+ "min_ms": 127.0,
+ "mean_ms": 132.4,
+ "max_ms": 135.4
+ },
+ "gemini": {
+ "command": [
+ "gemini",
+ "--version"
+ ],
+ "timings_ms": [
+ 651.0,
+ 652.6,
+ 657.2
+ ],
+ "min_ms": 651.0,
+ "mean_ms": 653.6,
+ "max_ms": 657.2
+ },
+ "codex": {
+ "command": [
+ "codex",
+ "--version"
+ ],
+ "timings_ms": [
+ 80.7,
+ 83.9,
+ 83.4
+ ],
+ "min_ms": 80.7,
+ "mean_ms": 82.7,
+ "max_ms": 83.9
+ }
+ }
+ },
+ "http": {
+ "url": "http://127.0.0.1:3713/tiny",
+ "total_requests": 50,
+ "concurrency": 5,
+ "successful": 50,
+ "failed": 0,
+ "total_duration_ms": 26.5,
+ "requests_per_sec": 1886.9,
+ "transfer_bytes": 1200,
+ "latency_ms": {
+ "min": 1.1,
+ "max": 8.7,
+ "mean": 2.5,
+ "p50": 1.9,
+ "p95": 7.5,
+ "p99": 8.3
+ }
+ },
+ "throughput": {
+ "url": "http://127.0.0.1:3713/bytes/10mb",
+ "source": "local",
+ "http_code": 200,
+ "size_bytes": 10485760,
+ "duration_s": 0.268,
+ "throughput_mbps": 37.34
+ },
+ "snapshot": {
+ "10_files": {
+ "create_ms": 646.4,
+ "create_ok": true,
+ "list_ms": 251.0,
+ "list_ok": true,
+ "changes_ms": 250.3,
+ "changes_ok": true,
+ "revert_ms": 279.9,
+ "revert_ok": true,
+ "delete_ms": 450.6,
+ "delete_ok": true
+ },
+ "100_files": {
+ "create_ms": 248.5,
+ "create_ok": true,
+ "list_ms": 252.2,
+ "list_ok": true,
+ "changes_ms": 252.5,
+ "changes_ok": true,
+ "revert_ms": 261.3,
+ "revert_ok": true,
+ "delete_ms": 455.7,
+ "delete_ok": true
+ },
+ "500_files": {
+ "create_ms": 261.7,
+ "create_ok": true,
+ "list_ms": 247.6,
+ "list_ok": true,
+ "changes_ms": 282.1,
+ "changes_ok": true,
+ "revert_ms": 263.6,
+ "revert_ok": true,
+ "delete_ms": 488.0,
+ "delete_ok": true
+ }
+ },
+ "mock_server_protocol": {
+ "version": "1.0",
+ "base_url": "http://127.0.0.1:3713",
+ "total_requests": 1000,
+ "concurrency": 32,
+ "timeout_s": 30.0,
+ "selected_scenarios": [
+ "model_json_response",
+ "credential_response"
+ ],
+ "scenarios": [
+ {
+ "name": "model_json_response",
+ "path": "/model/response",
+ "body_kind": "model_json",
+ "total_requests": 1000,
+ "concurrency": 32,
+ "successful": 1000,
+ "failed": 0,
+ "total_duration_ms": 355.8,
+ "requests_per_sec": 2810.4,
+ "transfer_bytes": 586000,
+ "bytes_per_sec": 1646900.3,
+ "latency_ms": {
+ "min": 1.0,
+ "max": 32.4,
+ "mean": 9.9,
+ "p50": 8.8,
+ "p95": 20.1,
+ "p99": 27.5
+ },
+ "errors": {}
+ },
+ {
+ "name": "credential_response",
+ "path": "/credential/response",
+ "body_kind": "credential",
+ "total_requests": 1000,
+ "concurrency": 32,
+ "successful": 1000,
+ "failed": 0,
+ "total_duration_ms": 655.8,
+ "requests_per_sec": 1524.9,
+ "transfer_bytes": 239000,
+ "bytes_per_sec": 364445.4,
+ "latency_ms": {
+ "min": 0.9,
+ "max": 73.8,
+ "mean": 18.8,
+ "p50": 11.0,
+ "p95": 55.1,
+ "p99": 64.9
+ },
+ "errors": {},
+ "secret_shaped_fixture_seen": true,
+ "raw_secret_stored_in_result": false
+ }
+ ],
+ "websocket": [
+ {
+ "name": "websocket_echo",
+ "path": "/ws/echo",
+ "skipped": false,
+ "frames": 10,
+ "failed": false,
+ "duration_ms": 6.9,
+ "frames_per_sec": 1454.6,
+ "latency_ms": {
+ "min": 0.2,
+ "max": 2.8,
+ "mean": 0.5,
+ "p50": 0.2,
+ "p95": 1.7,
+ "p99": 2.6
+ }
+ },
+ {
+ "name": "websocket_close",
+ "path": "/ws/close",
+ "skipped": false,
+ "frames": 1,
+ "failed": false,
+ "duration_ms": 5.9,
+ "frames_per_sec": 169.8,
+ "latency_ms": {
+ "min": 5.9,
+ "max": 5.9,
+ "mean": 5.9,
+ "p50": 5.9,
+ "p95": 5.9,
+ "p99": 5.9
+ }
+ }
+ ]
+ },
+ "host_recorded_at": 1781633331.6863518,
+ "arch": "arm64",
+ "mock_server_base_url": "http://127.0.0.1:3713"
+}
\ No newline at end of file
diff --git a/benchmarks/capsem-bench/data_1.3.1781720230_arm64.json b/benchmarks/capsem-bench/data_1.3.1781720230_arm64.json
new file mode 100644
index 000000000..412dd1e04
--- /dev/null
+++ b/benchmarks/capsem-bench/data_1.3.1781720230_arm64.json
@@ -0,0 +1,1593 @@
+{
+ "version": "0.3.0",
+ "timestamp": 1781731114.0767453,
+ "hostname": "bench-8d5e6cc3",
+ "disk": {
+ "directory": "/root",
+ "size_mb": 256,
+ "seq_write": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 121.3,
+ "throughput_mbps": 2111.1
+ },
+ "seq_read": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 61.9,
+ "throughput_mbps": 4138.9
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1290.1,
+ "iops": 7751.5,
+ "throughput_mbps": 30.3
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 200.4,
+ "iops": 49900.4,
+ "throughput_mbps": 194.9
+ }
+ },
+ "rootfs": {
+ "scan_dirs": [
+ "/usr/bin",
+ "/usr/lib",
+ "/opt/ai-clis"
+ ],
+ "largest_file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "largest_file_size": 197796880,
+ "seq_read": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 56.0,
+ "throughput_mbps": 3368.5
+ },
+ "files_found": 5538,
+ "rand_read_4k": {
+ "count": 5000,
+ "files_sampled": 2562,
+ "block_size": 4096,
+ "duration_ms": 171.6,
+ "iops": 29138.7,
+ "throughput_mbps": 113.8
+ },
+ "large_binary_seq_read": {
+ "count": 2,
+ "files": [
+ {
+ "path": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "cold": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 52.9,
+ "throughput_mbps": 3563.0
+ },
+ "warm": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 8.8,
+ "throughput_mbps": 21444.0
+ }
+ },
+ {
+ "path": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "cold": {
+ "file": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "block_size": 1048576,
+ "duration_ms": 8.1,
+ "throughput_mbps": 4619.5
+ },
+ "warm": {
+ "file": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "block_size": 1048576,
+ "duration_ms": 1.9,
+ "throughput_mbps": 19885.9
+ }
+ }
+ ],
+ "bytes_read": 236959384,
+ "cold_duration_ms": 61.0,
+ "warm_duration_ms": 10.7,
+ "cold_throughput_mbps": 3704.6,
+ "warm_throughput_mbps": 21119.8
+ },
+ "small_js_read": {
+ "count": 5000,
+ "files_sampled": 99,
+ "bytes_read": 47986400,
+ "duration_ms": 7.7,
+ "ops_per_sec": 649498.3,
+ "throughput_mbps": 5944.6
+ },
+ "metadata_stat": {
+ "entries": 6546,
+ "files": 5538,
+ "dirs": 662,
+ "symlinks": 346,
+ "errors": 0,
+ "duration_ms": 47.2,
+ "stats_per_sec": 138686.3
+ }
+ },
+ "storage": {
+ "kernel": {
+ "cmdline": {
+ "raw": "console=hvc0 ro loglevel=1 quiet init_on_alloc=1 slab_nomerge page_alloc.shuffle=1 random.trust_cpu=1 capsem.storage=virtiofs capsem.rootfs=erofs",
+ "args": [
+ "console=hvc0",
+ "ro",
+ "loglevel=1",
+ "quiet",
+ "init_on_alloc=1",
+ "slab_nomerge",
+ "page_alloc.shuffle=1",
+ "random.trust_cpu=1",
+ "capsem.storage=virtiofs",
+ "capsem.rootfs=erofs"
+ ]
+ },
+ "block_queues": {
+ "vda": {
+ "scheduler": "[none] mq-deadline kyber",
+ "read_ahead_kb": 4096,
+ "nr_requests": 256,
+ "rotational": 1,
+ "logical_block_size": 512,
+ "physical_block_size": 512,
+ "max_sectors_kb": 4096,
+ "nomerges": 0,
+ "rq_affinity": 1,
+ "io_poll": 0,
+ "selected_scheduler": "none"
+ },
+ "vdb": {
+ "scheduler": "[none] mq-deadline kyber",
+ "read_ahead_kb": 4096,
+ "nr_requests": 256,
+ "rotational": 1,
+ "logical_block_size": 512,
+ "physical_block_size": 512,
+ "max_sectors_kb": 4096,
+ "nomerges": 0,
+ "rq_affinity": 1,
+ "io_poll": 0,
+ "selected_scheduler": "none"
+ }
+ },
+ "fuse_connections": {},
+ "known_host_queue_sizes": {
+ "kvm_virtio_blk": 256,
+ "kvm_virtio_fs": [
+ 256,
+ 256
+ ]
+ }
+ },
+ "mounts": [
+ {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ {
+ "mount_point": "/proc",
+ "root": "/",
+ "fs_type": "proc",
+ "source": "proc",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/sys",
+ "root": "/",
+ "fs_type": "sysfs",
+ "source": "sysfs",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/dev",
+ "root": "/",
+ "fs_type": "devtmpfs",
+ "source": "devtmpfs",
+ "options": "rw,size=1021552k,nr_inodes=255388,mode=755"
+ },
+ {
+ "mount_point": "/dev/pts",
+ "root": "/",
+ "fs_type": "devpts",
+ "source": "devpts",
+ "options": "rw,mode=600,ptmxmode=000"
+ },
+ {
+ "mount_point": "/root",
+ "root": "/workspace",
+ "fs_type": "virtiofs",
+ "source": "capsem",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/etc/resolv.conf",
+ "root": "/run/resolv.conf",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ }
+ ],
+ "paths": {
+ "/": {
+ "path": "/",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 16369547,
+ "blocks_free": 16368196,
+ "blocks_available": 16364100,
+ "files": 4194304,
+ "files_free": 4194151
+ }
+ },
+ "/root": {
+ "path": "/root",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/root",
+ "root": "/workspace",
+ "fs_type": "virtiofs",
+ "source": "capsem",
+ "options": "rw"
+ },
+ "mode": "drwx------",
+ "statvfs": {
+ "block_size": 1048576,
+ "fragment_size": 4096,
+ "blocks": 975653540,
+ "blocks_free": 706041198,
+ "blocks_available": 706041198,
+ "files": 2476508436,
+ "files_free": 2471844144
+ }
+ },
+ "/tmp": {
+ "path": "/tmp",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxrwxrwt",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 16369547,
+ "blocks_free": 16368196,
+ "blocks_available": 16364100,
+ "files": 4194304,
+ "files_free": 4194151
+ }
+ },
+ "/var/tmp": {
+ "path": "/var/tmp",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxrwxrwt",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 16369547,
+ "blocks_free": 16368196,
+ "blocks_available": 16364100,
+ "files": 4194304,
+ "files_free": 4194151
+ }
+ },
+ "/var/log": {
+ "path": "/var/log",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 16369547,
+ "blocks_free": 16368196,
+ "blocks_available": 16364100,
+ "files": 4194304,
+ "files_free": 4194151
+ }
+ },
+ "/run": {
+ "path": "/run",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 16369547,
+ "blocks_free": 16368196,
+ "blocks_available": 16364100,
+ "files": 4194304,
+ "files_free": 4194151
+ }
+ },
+ "/usr/bin": {
+ "path": "/usr/bin",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 16369547,
+ "blocks_free": 16368196,
+ "blocks_available": 16364100,
+ "files": 4194304,
+ "files_free": 4194151
+ }
+ },
+ "/usr/lib": {
+ "path": "/usr/lib",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 16369547,
+ "blocks_free": 16368196,
+ "blocks_available": 16364100,
+ "files": 4194304,
+ "files_free": 4194151
+ }
+ },
+ "/opt/ai-clis": {
+ "path": "/opt/ai-clis",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 16369547,
+ "blocks_free": 16368196,
+ "blocks_available": 16364100,
+ "files": 4194304,
+ "files_free": 4194151
+ }
+ }
+ },
+ "rootfs": {
+ "scan_dirs": [
+ "/usr/bin",
+ "/usr/lib",
+ "/opt/ai-clis"
+ ],
+ "files_found": 3318,
+ "largest_file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "largest_file_size": 197796880,
+ "backing": {
+ "root_mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "overlay_lowerdir": "/mnt/a",
+ "overlay_upperdir": "/mnt/system/upper",
+ "overlay_workdir": "/mnt/system/work",
+ "erofs_mounts": [],
+ "squashfs_superblock": {
+ "device": "/dev/vda",
+ "magic": "0x00000000",
+ "error": "not squashfs",
+ "read_ahead_kb": 4096
+ }
+ },
+ "seq_reads": [
+ {
+ "label": "largest",
+ "path": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 197796880,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 56.8,
+ "throughput_mbps": 3319.3
+ },
+ "warm": {
+ "size_bytes": 197796880,
+ "block_size": 1048576,
+ "duration_ms": 7.9,
+ "throughput_mbps": 23818.0
+ }
+ },
+ {
+ "label": "bash",
+ "path": "/bin/bash",
+ "size_bytes": 1346480,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 1346480,
+ "block_size": 1048576,
+ "duration_ms": 0.2,
+ "throughput_mbps": 5305.3
+ },
+ "warm": {
+ "size_bytes": 1346480,
+ "block_size": 1048576,
+ "duration_ms": 0.0,
+ "throughput_mbps": 26775.0
+ }
+ },
+ {
+ "label": "python3",
+ "path": "/usr/bin/python3",
+ "size_bytes": 6616880,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 6616880,
+ "block_size": 1048576,
+ "duration_ms": 1.0,
+ "throughput_mbps": 6105.6
+ },
+ "warm": {
+ "size_bytes": 6616880,
+ "block_size": 1048576,
+ "duration_ms": 0.3,
+ "throughput_mbps": 24317.3
+ }
+ }
+ ],
+ "rand_read_4k": {
+ "count": 2000,
+ "files_sampled": 1512,
+ "duration_ms": 107.3,
+ "iops": 18643.4,
+ "throughput_mbps": 72.8
+ }
+ },
+ "writable": {
+ "/root": {
+ "path": "/root",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 33.1,
+ "throughput_mbps": 1936.2
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 16.4,
+ "throughput_mbps": 3895.4
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 15.0,
+ "throughput_mbps": 4263.4
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1464.6,
+ "iops": 6827.9,
+ "throughput_mbps": 26.7
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 191.8,
+ "iops": 52132.2,
+ "throughput_mbps": 203.6
+ },
+ "io_profile": {
+ "path": "/root",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 1009.7,
+ "iops": 16226.4,
+ "throughput_mbps": 63.4,
+ "avg_latency_ms": 0.062
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 18.2,
+ "iops": 898013.8,
+ "throughput_mbps": 3507.9,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 16.8,
+ "iops": 978052.0,
+ "throughput_mbps": 3820.5,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 74.3,
+ "iops": 13781.4,
+ "throughput_mbps": 861.3,
+ "avg_latency_ms": 0.073
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 16.4,
+ "iops": 62402.6,
+ "throughput_mbps": 3900.2,
+ "avg_latency_ms": 0.016
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 15.9,
+ "iops": 64292.8,
+ "throughput_mbps": 4018.3,
+ "avg_latency_ms": 0.016
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 27.8,
+ "iops": 2302.5,
+ "throughput_mbps": 2302.5,
+ "avg_latency_ms": 0.434
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 15.1,
+ "iops": 4227.4,
+ "throughput_mbps": 4227.4,
+ "avg_latency_ms": 0.237
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 15.5,
+ "iops": 4123.8,
+ "throughput_mbps": 4123.8,
+ "avg_latency_ms": 0.242
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 48.5,
+ "iops": 41278.7,
+ "throughput_mbps": 161.2,
+ "avg_latency_ms": 0.024,
+ "latency_ms": {
+ "p50": 0.025,
+ "p95": 0.03,
+ "p99": 0.036,
+ "max": 0.046
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 231.8,
+ "iops": 8627.6,
+ "throughput_mbps": 33.7,
+ "avg_latency_ms": 0.116,
+ "latency_ms": {
+ "p50": 0.105,
+ "p95": 0.13,
+ "p99": 0.219,
+ "max": 5.895
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/tmp": {
+ "path": "/tmp",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 10.2,
+ "throughput_mbps": 6296.6
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 7.0,
+ "throughput_mbps": 9123.0
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 4.8,
+ "throughput_mbps": 13437.1
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1758.9,
+ "iops": 5685.2,
+ "throughput_mbps": 22.2
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.7,
+ "iops": 1300404.3,
+ "throughput_mbps": 5079.7
+ },
+ "io_profile": {
+ "path": "/tmp",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 19.4,
+ "iops": 846199.0,
+ "throughput_mbps": 3305.5,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 12.6,
+ "iops": 1297751.2,
+ "throughput_mbps": 5069.3,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 9.9,
+ "iops": 1658985.2,
+ "throughput_mbps": 6480.4,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 11.0,
+ "iops": 92966.6,
+ "throughput_mbps": 5810.4,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 7.7,
+ "iops": 132759.3,
+ "throughput_mbps": 8297.5,
+ "avg_latency_ms": 0.008
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 5.3,
+ "iops": 192436.0,
+ "throughput_mbps": 12027.2,
+ "avg_latency_ms": 0.005
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 68.5,
+ "iops": 934.4,
+ "throughput_mbps": 934.4,
+ "avg_latency_ms": 1.07
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 7.4,
+ "iops": 8637.9,
+ "throughput_mbps": 8637.9,
+ "avg_latency_ms": 0.116
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 4.5,
+ "iops": 14370.2,
+ "throughput_mbps": 14370.2,
+ "avg_latency_ms": 0.07
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 39.6,
+ "iops": 50447.1,
+ "throughput_mbps": 197.1,
+ "avg_latency_ms": 0.02,
+ "latency_ms": {
+ "p50": 0.021,
+ "p95": 0.026,
+ "p99": 0.03,
+ "max": 0.053
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 87.4,
+ "iops": 22873.8,
+ "throughput_mbps": 89.4,
+ "avg_latency_ms": 0.044,
+ "latency_ms": {
+ "p50": 0.041,
+ "p95": 0.051,
+ "p99": 0.175,
+ "max": 0.533
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/var/tmp": {
+ "path": "/var/tmp",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 13.8,
+ "throughput_mbps": 4622.1
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 7.5,
+ "throughput_mbps": 8545.2
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.1,
+ "throughput_mbps": 12478.3
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1694.8,
+ "iops": 5900.3,
+ "throughput_mbps": 23.0
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.6,
+ "iops": 1308615.0,
+ "throughput_mbps": 5111.8
+ },
+ "io_profile": {
+ "path": "/var/tmp",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 22.4,
+ "iops": 732705.6,
+ "throughput_mbps": 2862.1,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 12.7,
+ "iops": 1291858.9,
+ "throughput_mbps": 5046.3,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 11.3,
+ "iops": 1446604.3,
+ "throughput_mbps": 5650.8,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 11.7,
+ "iops": 87339.4,
+ "throughput_mbps": 5458.7,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 7.4,
+ "iops": 138730.7,
+ "throughput_mbps": 8670.7,
+ "avg_latency_ms": 0.007
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.4,
+ "iops": 160787.2,
+ "throughput_mbps": 10049.2,
+ "avg_latency_ms": 0.006
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 11.9,
+ "iops": 5397.5,
+ "throughput_mbps": 5397.5,
+ "avg_latency_ms": 0.185
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 7.0,
+ "iops": 9127.2,
+ "throughput_mbps": 9127.2,
+ "avg_latency_ms": 0.11
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 5.2,
+ "iops": 12348.1,
+ "throughput_mbps": 12348.1,
+ "avg_latency_ms": 0.081
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 51.6,
+ "iops": 38728.5,
+ "throughput_mbps": 151.3,
+ "avg_latency_ms": 0.026,
+ "latency_ms": {
+ "p50": 0.026,
+ "p95": 0.033,
+ "p99": 0.037,
+ "max": 0.055
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 117.6,
+ "iops": 17007.7,
+ "throughput_mbps": 66.4,
+ "avg_latency_ms": 0.059,
+ "latency_ms": {
+ "p50": 0.055,
+ "p95": 0.066,
+ "p99": 0.181,
+ "max": 0.516
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/var/log": {
+ "path": "/var/log",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 11.3,
+ "throughput_mbps": 5682.0
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 8.7,
+ "throughput_mbps": 7346.5
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.9,
+ "throughput_mbps": 10910.3
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1698.4,
+ "iops": 5888.0,
+ "throughput_mbps": 23.0
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 8.3,
+ "iops": 1202049.5,
+ "throughput_mbps": 4695.5
+ },
+ "io_profile": {
+ "path": "/var/log",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 20.2,
+ "iops": 811375.3,
+ "throughput_mbps": 3169.4,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 14.7,
+ "iops": 1117154.4,
+ "throughput_mbps": 4363.9,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 12.7,
+ "iops": 1291519.3,
+ "throughput_mbps": 5045.0,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 13.0,
+ "iops": 78879.2,
+ "throughput_mbps": 4930.0,
+ "avg_latency_ms": 0.013
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 9.2,
+ "iops": 111701.5,
+ "throughput_mbps": 6981.3,
+ "avg_latency_ms": 0.009
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 7.8,
+ "iops": 130452.1,
+ "throughput_mbps": 8153.3,
+ "avg_latency_ms": 0.008
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 13.2,
+ "iops": 4841.8,
+ "throughput_mbps": 4841.8,
+ "avg_latency_ms": 0.207
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 7.4,
+ "iops": 8647.4,
+ "throughput_mbps": 8647.4,
+ "avg_latency_ms": 0.116
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 6.1,
+ "iops": 10525.3,
+ "throughput_mbps": 10525.3,
+ "avg_latency_ms": 0.095
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 51.6,
+ "iops": 38760.9,
+ "throughput_mbps": 151.4,
+ "avg_latency_ms": 0.026,
+ "latency_ms": {
+ "p50": 0.026,
+ "p95": 0.034,
+ "p99": 0.037,
+ "max": 0.051
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 114.0,
+ "iops": 17548.3,
+ "throughput_mbps": 68.5,
+ "avg_latency_ms": 0.057,
+ "latency_ms": {
+ "p50": 0.055,
+ "p95": 0.065,
+ "p99": 0.127,
+ "max": 0.203
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/run": {
+ "path": "/run",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 11.5,
+ "throughput_mbps": 5552.4
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 11.4,
+ "throughput_mbps": 5610.5
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 8.8,
+ "throughput_mbps": 7257.2
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1341.5,
+ "iops": 7454.6,
+ "throughput_mbps": 29.1
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 8.3,
+ "iops": 1199238.5,
+ "throughput_mbps": 4684.5
+ },
+ "io_profile": {
+ "path": "/run",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 21.6,
+ "iops": 758694.1,
+ "throughput_mbps": 2963.6,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 14.8,
+ "iops": 1110262.2,
+ "throughput_mbps": 4337.0,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 11.5,
+ "iops": 1419731.8,
+ "throughput_mbps": 5545.8,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 12.4,
+ "iops": 82814.4,
+ "throughput_mbps": 5175.9,
+ "avg_latency_ms": 0.012
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 8.7,
+ "iops": 118325.1,
+ "throughput_mbps": 7395.3,
+ "avg_latency_ms": 0.008
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.8,
+ "iops": 150275.2,
+ "throughput_mbps": 9392.2,
+ "avg_latency_ms": 0.007
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 12.9,
+ "iops": 4970.0,
+ "throughput_mbps": 4970.0,
+ "avg_latency_ms": 0.201
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 8.6,
+ "iops": 7418.3,
+ "throughput_mbps": 7418.3,
+ "avg_latency_ms": 0.135
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 5.4,
+ "iops": 11824.2,
+ "throughput_mbps": 11824.2,
+ "avg_latency_ms": 0.085
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 36.0,
+ "iops": 55625.7,
+ "throughput_mbps": 217.3,
+ "avg_latency_ms": 0.018,
+ "latency_ms": {
+ "p50": 0.019,
+ "p95": 0.024,
+ "p99": 0.03,
+ "max": 0.082
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 85.8,
+ "iops": 23297.7,
+ "throughput_mbps": 91.0,
+ "avg_latency_ms": 0.043,
+ "latency_ms": {
+ "p50": 0.04,
+ "p95": 0.053,
+ "p99": 0.155,
+ "max": 0.278
+ },
+ "sync_each": true
+ }
+ }
+ }
+ }
+ }
+ },
+ "startup": {
+ "runs_per_command": 3,
+ "commands": {
+ "python3": {
+ "command": [
+ "python3",
+ "--version"
+ ],
+ "timings_ms": [
+ 4.7,
+ 3.3,
+ 3.6
+ ],
+ "min_ms": 3.3,
+ "mean_ms": 3.9,
+ "max_ms": 4.7
+ },
+ "node": {
+ "command": [
+ "node",
+ "--version"
+ ],
+ "timings_ms": [
+ 24.1,
+ 26.2,
+ 26.3
+ ],
+ "min_ms": 24.1,
+ "mean_ms": 25.5,
+ "max_ms": 26.3
+ },
+ "claude": {
+ "command": [
+ "claude",
+ "--version"
+ ],
+ "timings_ms": [
+ 137.9,
+ 130.7,
+ 135.4
+ ],
+ "min_ms": 130.7,
+ "mean_ms": 134.7,
+ "max_ms": 137.9
+ },
+ "gemini": {
+ "command": [
+ "gemini",
+ "--version"
+ ],
+ "timings_ms": [
+ 758.8,
+ 761.7,
+ 716.2
+ ],
+ "min_ms": 716.2,
+ "mean_ms": 745.6,
+ "max_ms": 761.7
+ },
+ "codex": {
+ "command": [
+ "codex",
+ "--version"
+ ],
+ "timings_ms": [
+ 85.7,
+ 82.9,
+ 82.9
+ ],
+ "min_ms": 82.9,
+ "mean_ms": 83.8,
+ "max_ms": 85.7
+ }
+ }
+ },
+ "http": {
+ "url": "http://127.0.0.1:3713/tiny",
+ "total_requests": 50,
+ "concurrency": 5,
+ "successful": 50,
+ "failed": 0,
+ "total_duration_ms": 30.5,
+ "requests_per_sec": 1637.3,
+ "transfer_bytes": 1200,
+ "latency_ms": {
+ "min": 1.2,
+ "max": 9.7,
+ "mean": 2.8,
+ "p50": 2.2,
+ "p95": 7.6,
+ "p99": 9.3
+ }
+ },
+ "throughput": {
+ "url": "http://127.0.0.1:3713/bytes/10mb",
+ "source": "local",
+ "http_code": 200,
+ "size_bytes": 10485760,
+ "duration_s": 0.281,
+ "throughput_mbps": 35.63
+ },
+ "snapshot": {
+ "10_files": {
+ "create_ms": 1066.4,
+ "create_ok": true,
+ "list_ms": 292.2,
+ "list_ok": true,
+ "changes_ms": 293.5,
+ "changes_ok": true,
+ "revert_ms": 292.2,
+ "revert_ok": true,
+ "delete_ms": 482.9,
+ "delete_ok": true
+ },
+ "100_files": {
+ "create_ms": 285.6,
+ "create_ok": true,
+ "list_ms": 279.4,
+ "list_ok": true,
+ "changes_ms": 266.7,
+ "changes_ok": true,
+ "revert_ms": 275.4,
+ "revert_ok": true,
+ "delete_ms": 482.3,
+ "delete_ok": true
+ },
+ "500_files": {
+ "create_ms": 278.4,
+ "create_ok": true,
+ "list_ms": 263.2,
+ "list_ok": true,
+ "changes_ms": 295.7,
+ "changes_ok": true,
+ "revert_ms": 268.7,
+ "revert_ok": true,
+ "delete_ms": 519.6,
+ "delete_ok": true
+ }
+ },
+ "mock_server_protocol": {
+ "version": "1.0",
+ "base_url": "http://127.0.0.1:3713",
+ "total_requests": 50000,
+ "concurrency": 64,
+ "timeout_s": 30.0,
+ "selected_scenarios": [
+ "model_json_response",
+ "credential_response"
+ ],
+ "scenarios": [
+ {
+ "name": "model_json_response",
+ "path": "/model/response",
+ "body_kind": "model_json",
+ "total_requests": 50000,
+ "concurrency": 64,
+ "successful": 50000,
+ "failed": 0,
+ "total_duration_ms": 21399.9,
+ "requests_per_sec": 2336.5,
+ "transfer_bytes": 29300000,
+ "bytes_per_sec": 1369166.1,
+ "latency_ms": {
+ "min": 0.7,
+ "max": 139.5,
+ "mean": 26.9,
+ "p50": 24.0,
+ "p95": 56.2,
+ "p99": 75.5
+ },
+ "errors": {}
+ },
+ {
+ "name": "credential_response",
+ "path": "/credential/response",
+ "body_kind": "credential",
+ "total_requests": 50000,
+ "concurrency": 64,
+ "successful": 50000,
+ "failed": 0,
+ "total_duration_ms": 35095.4,
+ "requests_per_sec": 1424.7,
+ "transfer_bytes": 11950000,
+ "bytes_per_sec": 340500.5,
+ "latency_ms": {
+ "min": 0.9,
+ "max": 238.6,
+ "mean": 44.3,
+ "p50": 37.5,
+ "p95": 98.8,
+ "p99": 133.0
+ },
+ "errors": {},
+ "secret_shaped_fixture_seen": true,
+ "raw_secret_stored_in_result": false
+ }
+ ],
+ "websocket": [
+ {
+ "name": "websocket_echo",
+ "path": "/ws/echo",
+ "skipped": false,
+ "frames": 10,
+ "failed": false,
+ "duration_ms": 17.9,
+ "frames_per_sec": 560.0,
+ "latency_ms": {
+ "min": 0.2,
+ "max": 3.5,
+ "mean": 0.5,
+ "p50": 0.2,
+ "p95": 2.0,
+ "p99": 3.2
+ }
+ },
+ {
+ "name": "websocket_close",
+ "path": "/ws/close",
+ "skipped": false,
+ "frames": 1,
+ "failed": false,
+ "duration_ms": 3.9,
+ "frames_per_sec": 256.5,
+ "latency_ms": {
+ "min": 3.9,
+ "max": 3.9,
+ "mean": 3.9,
+ "p50": 3.9,
+ "p95": 3.9,
+ "p99": 3.9
+ }
+ }
+ ]
+ },
+ "host_recorded_at": 1781731202.2562618,
+ "arch": "arm64",
+ "mock_server_base_url": "http://127.0.0.1:3713"
+}
\ No newline at end of file
diff --git a/benchmarks/db-writer/data_1.0.1780763638_arm64.json b/benchmarks/db-writer/data_1.0.1780763638_arm64.json
new file mode 100644
index 000000000..835138f24
--- /dev/null
+++ b/benchmarks/db-writer/data_1.0.1780763638_arm64.json
@@ -0,0 +1,80 @@
+{
+ "version": "1.0",
+ "benchmark": "db_writer_pressure",
+ "source": "/Users/elie/.codex/worktrees/5ce6/capsem/target/criterion/db_writer_pressure",
+ "rows": [
+ {
+ "name": "file_events_1024",
+ "burst_size": 1024,
+ "mean_ms": 6.916,
+ "median_ms": 6.8931,
+ "events_per_sec_mean": 148062.5,
+ "events_per_sec_median": 148554.4,
+ "sample_percentiles": {
+ "p50_ms": 6.8931,
+ "p95_ms": 7.0277,
+ "p99_ms": 7.0382
+ },
+ "mean_confidence": {
+ "confidence_level": 0.95,
+ "lower_ms": 6.8822,
+ "upper_ms": 6.9558
+ },
+ "median_confidence": {
+ "confidence_level": 0.95,
+ "lower_ms": 6.8739,
+ "upper_ms": 6.961
+ }
+ },
+ {
+ "name": "file_events_128",
+ "burst_size": 128,
+ "mean_ms": 1.525,
+ "median_ms": 1.5188,
+ "events_per_sec_mean": 83934.4,
+ "events_per_sec_median": 84277.1,
+ "sample_percentiles": {
+ "p50_ms": 1.5188,
+ "p95_ms": 1.5538,
+ "p99_ms": 1.5588
+ },
+ "mean_confidence": {
+ "confidence_level": 0.95,
+ "lower_ms": 1.5146,
+ "upper_ms": 1.5364
+ },
+ "median_confidence": {
+ "confidence_level": 0.95,
+ "lower_ms": 1.5111,
+ "upper_ms": 1.5399
+ }
+ },
+ {
+ "name": "file_events_4096",
+ "burst_size": 4096,
+ "mean_ms": 27.1623,
+ "median_ms": 27.02,
+ "events_per_sec_mean": 150797.2,
+ "events_per_sec_median": 151591.4,
+ "sample_percentiles": {
+ "p50_ms": 27.02,
+ "p95_ms": 27.8743,
+ "p99_ms": 28.0951
+ },
+ "mean_confidence": {
+ "confidence_level": 0.95,
+ "lower_ms": 26.9564,
+ "upper_ms": 27.4277
+ },
+ "median_confidence": {
+ "confidence_level": 0.95,
+ "lower_ms": 26.9391,
+ "upper_ms": 27.3255
+ }
+ }
+ ],
+ "project_version": "1.0.1780763638",
+ "arch": "arm64",
+ "host_recorded_at": 1780771539.468837,
+ "notes": "Criterion benchmark of the real capsem_logger::DbWriter writing file-event bursts to SQLite and shutting down cleanly."
+}
diff --git a/benchmarks/dns-load/README.md b/benchmarks/dns-load/README.md
index d4a7eb3da..15c602da4 100644
--- a/benchmarks/dns-load/README.md
+++ b/benchmarks/dns-load/README.md
@@ -3,10 +3,9 @@
Locked output of `capsem-bench dns-load` captured during T3
closure (mitm-redesign sprint, T3.4). The baseline represents the
expected steady-state of the capsem DNS proxy serving the default
-qname (`api.openai.com`) with the user's `~/.capsem/user.toml`
-allowing it (so every query goes through the upstream-forward
-path -> answer cache hot loop, which is the dominant in-agent
-workload).
+qname (`api.openai.com`) with the active profile rules allowing it
+(so every query goes through the upstream-forward path -> answer
+cache hot loop, which is the dominant in-agent workload).
| concurrency | rps | p50 ms | p99 ms | errors |
|-------------|-------|--------|--------|--------|
@@ -46,7 +45,7 @@ Per the mitm-redesign sprint discipline:
cache qid bug that caused 100% errors before the fix)
The decision distribution must match what the policy says: if
-`api.openai.com` is in `security.web.openai.allow = true`, every
-row should be `decision_distribution = {"allowed": N}`. If the
-user has it blocked, expect `{"denied": N}`. Any `transport_error`
-> 0 outside that shape is a real proxy bug, not bench noise.
+the active profile allows `api.openai.com`, every row should be
+`decision_distribution = {"allowed": N}`. If the profile or corp
+rules block it, expect `{"denied": N}`. Any `transport_error` > 0
+outside that shape is a real proxy bug, not bench noise.
diff --git a/benchmarks/endpoint-latency/data_1.2.1780103109_arm64.json b/benchmarks/endpoint-latency/data_1.2.1780103109_arm64.json
deleted file mode 100644
index 8fe51c70c..000000000
--- a/benchmarks/endpoint-latency/data_1.2.1780103109_arm64.json
+++ /dev/null
@@ -1,735 +0,0 @@
-{
- "version": "0.1.0",
- "timestamp": 1780149845.194092,
- "vm_count": 8,
- "iterations": {
- "service_global": 16,
- "service_vm": 4,
- "gateway": 32
- },
- "gates": {
- "service_global": {
- "p95_ms": 3.0,
- "max_ms": 10.0
- },
- "service_vm": {
- "p95_ms": 12.0,
- "max_ms": 35.0
- },
- "gateway": {
- "p95_ms": 2.0,
- "max_ms": 8.0
- }
- },
- "groups": {
- "service_global": {
- "/version": {
- "count": 16,
- "min_ms": 0.145,
- "p50_ms": 0.17,
- "p95_ms": 0.245,
- "p99_ms": 0.245,
- "max_ms": 0.245
- },
- "/list": {
- "count": 16,
- "min_ms": 0.577,
- "p50_ms": 0.607,
- "p95_ms": 0.684,
- "p99_ms": 0.684,
- "max_ms": 0.684
- },
- "/stats": {
- "count": 16,
- "min_ms": 2.526,
- "p50_ms": 2.713,
- "p95_ms": 2.913,
- "p99_ms": 2.913,
- "max_ms": 2.913
- },
- "/settings": {
- "count": 16,
- "min_ms": 1.218,
- "p50_ms": 1.338,
- "p95_ms": 1.474,
- "p99_ms": 1.474,
- "max_ms": 1.474
- },
- "/settings/presets": {
- "count": 16,
- "min_ms": 0.86,
- "p50_ms": 0.909,
- "p95_ms": 1.041,
- "p99_ms": 1.041,
- "max_ms": 1.041
- },
- "/profiles": {
- "count": 16,
- "min_ms": 1.713,
- "p50_ms": 1.771,
- "p95_ms": 2.022,
- "p99_ms": 2.022,
- "max_ms": 2.022
- },
- "/profiles/catalog": {
- "count": 16,
- "min_ms": 0.252,
- "p50_ms": 0.278,
- "p95_ms": 0.34,
- "p99_ms": 0.34,
- "max_ms": 0.34
- },
- "/rules": {
- "count": 16,
- "min_ms": 0.86,
- "p50_ms": 0.9,
- "p95_ms": 1.12,
- "p99_ms": 1.12,
- "max_ms": 1.12
- },
- "/enforcement": {
- "count": 16,
- "min_ms": 0.288,
- "p50_ms": 0.304,
- "p95_ms": 0.33,
- "p99_ms": 0.33,
- "max_ms": 0.33
- },
- "/enforcement/stats": {
- "count": 16,
- "min_ms": 0.698,
- "p50_ms": 0.786,
- "p95_ms": 0.977,
- "p99_ms": 0.977,
- "max_ms": 0.977
- },
- "/detection": {
- "count": 16,
- "min_ms": 0.141,
- "p50_ms": 0.149,
- "p95_ms": 0.164,
- "p99_ms": 0.164,
- "max_ms": 0.164
- },
- "/detection/stats": {
- "count": 16,
- "min_ms": 0.535,
- "p50_ms": 0.6,
- "p95_ms": 0.664,
- "p99_ms": 0.664,
- "max_ms": 0.664
- },
- "/confirm/pending": {
- "count": 16,
- "min_ms": 0.151,
- "p50_ms": 0.16,
- "p95_ms": 0.186,
- "p99_ms": 0.186,
- "max_ms": 0.186
- },
- "/skills": {
- "count": 16,
- "min_ms": 0.857,
- "p50_ms": 0.891,
- "p95_ms": 1.045,
- "p99_ms": 1.045,
- "max_ms": 1.045
- },
- "/setup/state": {
- "count": 16,
- "min_ms": 0.169,
- "p50_ms": 0.18,
- "p95_ms": 0.2,
- "p99_ms": 0.2,
- "max_ms": 0.2
- },
- "/setup/assets": {
- "count": 16,
- "min_ms": 0.218,
- "p50_ms": 0.233,
- "p95_ms": 0.26,
- "p99_ms": 0.26,
- "max_ms": 0.26
- },
- "/mcp/connectors": {
- "count": 16,
- "min_ms": 0.85,
- "p50_ms": 0.885,
- "p95_ms": 0.92,
- "p99_ms": 0.92,
- "max_ms": 0.92
- }
- },
- "service_vm": {
- "/info/epbench-a133189f-0": {
- "count": 4,
- "min_ms": 0.928,
- "p50_ms": 0.96,
- "p95_ms": 1.15,
- "p99_ms": 1.15,
- "max_ms": 1.15
- },
- "/logs/epbench-a133189f-0": {
- "count": 4,
- "min_ms": 3.189,
- "p50_ms": 3.237,
- "p95_ms": 3.275,
- "p99_ms": 3.275,
- "max_ms": 3.275
- },
- "/history/epbench-a133189f-0": {
- "count": 4,
- "min_ms": 0.846,
- "p50_ms": 0.898,
- "p95_ms": 0.911,
- "p99_ms": 0.911,
- "max_ms": 0.911
- },
- "/history/epbench-a133189f-0/counts": {
- "count": 4,
- "min_ms": 0.62,
- "p50_ms": 0.62,
- "p95_ms": 0.696,
- "p99_ms": 0.696,
- "max_ms": 0.696
- },
- "/history/epbench-a133189f-0/processes": {
- "count": 4,
- "min_ms": 0.655,
- "p50_ms": 0.688,
- "p95_ms": 0.747,
- "p99_ms": 0.747,
- "max_ms": 0.747
- },
- "/history/epbench-a133189f-0/transcript": {
- "count": 4,
- "min_ms": 0.18,
- "p50_ms": 0.18,
- "p95_ms": 0.199,
- "p99_ms": 0.199,
- "max_ms": 0.199
- },
- "/files/epbench-a133189f-0": {
- "count": 4,
- "min_ms": 2.394,
- "p50_ms": 2.471,
- "p95_ms": 2.694,
- "p99_ms": 2.694,
- "max_ms": 2.694
- },
- "/sessions/epbench-a133189f-0/policy-contexts": {
- "count": 4,
- "min_ms": 2.281,
- "p50_ms": 2.287,
- "p95_ms": 2.411,
- "p99_ms": 2.411,
- "max_ms": 2.411
- },
- "/info/epbench-a133189f-1": {
- "count": 4,
- "min_ms": 0.96,
- "p50_ms": 1.017,
- "p95_ms": 1.081,
- "p99_ms": 1.081,
- "max_ms": 1.081
- },
- "/logs/epbench-a133189f-1": {
- "count": 4,
- "min_ms": 3.154,
- "p50_ms": 3.188,
- "p95_ms": 3.221,
- "p99_ms": 3.221,
- "max_ms": 3.221
- },
- "/history/epbench-a133189f-1": {
- "count": 4,
- "min_ms": 0.852,
- "p50_ms": 0.854,
- "p95_ms": 0.931,
- "p99_ms": 0.931,
- "max_ms": 0.931
- },
- "/history/epbench-a133189f-1/counts": {
- "count": 4,
- "min_ms": 0.594,
- "p50_ms": 0.597,
- "p95_ms": 0.61,
- "p99_ms": 0.61,
- "max_ms": 0.61
- },
- "/history/epbench-a133189f-1/processes": {
- "count": 4,
- "min_ms": 0.642,
- "p50_ms": 0.649,
- "p95_ms": 0.685,
- "p99_ms": 0.685,
- "max_ms": 0.685
- },
- "/history/epbench-a133189f-1/transcript": {
- "count": 4,
- "min_ms": 0.18,
- "p50_ms": 0.183,
- "p95_ms": 0.195,
- "p99_ms": 0.195,
- "max_ms": 0.195
- },
- "/files/epbench-a133189f-1": {
- "count": 4,
- "min_ms": 2.359,
- "p50_ms": 2.456,
- "p95_ms": 2.535,
- "p99_ms": 2.535,
- "max_ms": 2.535
- },
- "/sessions/epbench-a133189f-1/policy-contexts": {
- "count": 4,
- "min_ms": 2.255,
- "p50_ms": 2.298,
- "p95_ms": 2.487,
- "p99_ms": 2.487,
- "max_ms": 2.487
- },
- "/info/epbench-a133189f-2": {
- "count": 4,
- "min_ms": 0.894,
- "p50_ms": 0.985,
- "p95_ms": 1.024,
- "p99_ms": 1.024,
- "max_ms": 1.024
- },
- "/logs/epbench-a133189f-2": {
- "count": 4,
- "min_ms": 2.979,
- "p50_ms": 3.068,
- "p95_ms": 3.265,
- "p99_ms": 3.265,
- "max_ms": 3.265
- },
- "/history/epbench-a133189f-2": {
- "count": 4,
- "min_ms": 0.826,
- "p50_ms": 0.837,
- "p95_ms": 0.902,
- "p99_ms": 0.902,
- "max_ms": 0.902
- },
- "/history/epbench-a133189f-2/counts": {
- "count": 4,
- "min_ms": 0.605,
- "p50_ms": 0.621,
- "p95_ms": 0.677,
- "p99_ms": 0.677,
- "max_ms": 0.677
- },
- "/history/epbench-a133189f-2/processes": {
- "count": 4,
- "min_ms": 0.641,
- "p50_ms": 0.65,
- "p95_ms": 0.711,
- "p99_ms": 0.711,
- "max_ms": 0.711
- },
- "/history/epbench-a133189f-2/transcript": {
- "count": 4,
- "min_ms": 0.187,
- "p50_ms": 0.192,
- "p95_ms": 0.201,
- "p99_ms": 0.201,
- "max_ms": 0.201
- },
- "/files/epbench-a133189f-2": {
- "count": 4,
- "min_ms": 2.398,
- "p50_ms": 2.404,
- "p95_ms": 2.535,
- "p99_ms": 2.535,
- "max_ms": 2.535
- },
- "/sessions/epbench-a133189f-2/policy-contexts": {
- "count": 4,
- "min_ms": 2.299,
- "p50_ms": 2.306,
- "p95_ms": 2.338,
- "p99_ms": 2.338,
- "max_ms": 2.338
- },
- "/info/epbench-a133189f-3": {
- "count": 4,
- "min_ms": 0.865,
- "p50_ms": 0.946,
- "p95_ms": 0.993,
- "p99_ms": 0.993,
- "max_ms": 0.993
- },
- "/logs/epbench-a133189f-3": {
- "count": 4,
- "min_ms": 3.048,
- "p50_ms": 3.164,
- "p95_ms": 3.247,
- "p99_ms": 3.247,
- "max_ms": 3.247
- },
- "/history/epbench-a133189f-3": {
- "count": 4,
- "min_ms": 0.824,
- "p50_ms": 0.841,
- "p95_ms": 0.861,
- "p99_ms": 0.861,
- "max_ms": 0.861
- },
- "/history/epbench-a133189f-3/counts": {
- "count": 4,
- "min_ms": 0.602,
- "p50_ms": 0.604,
- "p95_ms": 0.642,
- "p99_ms": 0.642,
- "max_ms": 0.642
- },
- "/history/epbench-a133189f-3/processes": {
- "count": 4,
- "min_ms": 0.652,
- "p50_ms": 0.704,
- "p95_ms": 0.721,
- "p99_ms": 0.721,
- "max_ms": 0.721
- },
- "/history/epbench-a133189f-3/transcript": {
- "count": 4,
- "min_ms": 0.193,
- "p50_ms": 0.199,
- "p95_ms": 0.207,
- "p99_ms": 0.207,
- "max_ms": 0.207
- },
- "/files/epbench-a133189f-3": {
- "count": 4,
- "min_ms": 2.373,
- "p50_ms": 2.422,
- "p95_ms": 2.456,
- "p99_ms": 2.456,
- "max_ms": 2.456
- },
- "/sessions/epbench-a133189f-3/policy-contexts": {
- "count": 4,
- "min_ms": 2.239,
- "p50_ms": 2.286,
- "p95_ms": 2.387,
- "p99_ms": 2.387,
- "max_ms": 2.387
- },
- "/info/epbench-a133189f-4": {
- "count": 4,
- "min_ms": 0.923,
- "p50_ms": 0.95,
- "p95_ms": 1.015,
- "p99_ms": 1.015,
- "max_ms": 1.015
- },
- "/logs/epbench-a133189f-4": {
- "count": 4,
- "min_ms": 3.041,
- "p50_ms": 3.061,
- "p95_ms": 3.176,
- "p99_ms": 3.176,
- "max_ms": 3.176
- },
- "/history/epbench-a133189f-4": {
- "count": 4,
- "min_ms": 0.851,
- "p50_ms": 0.856,
- "p95_ms": 0.897,
- "p99_ms": 0.897,
- "max_ms": 0.897
- },
- "/history/epbench-a133189f-4/counts": {
- "count": 4,
- "min_ms": 0.592,
- "p50_ms": 0.61,
- "p95_ms": 0.629,
- "p99_ms": 0.629,
- "max_ms": 0.629
- },
- "/history/epbench-a133189f-4/processes": {
- "count": 4,
- "min_ms": 0.669,
- "p50_ms": 0.693,
- "p95_ms": 0.762,
- "p99_ms": 0.762,
- "max_ms": 0.762
- },
- "/history/epbench-a133189f-4/transcript": {
- "count": 4,
- "min_ms": 0.2,
- "p50_ms": 0.203,
- "p95_ms": 0.225,
- "p99_ms": 0.225,
- "max_ms": 0.225
- },
- "/files/epbench-a133189f-4": {
- "count": 4,
- "min_ms": 2.355,
- "p50_ms": 2.447,
- "p95_ms": 2.57,
- "p99_ms": 2.57,
- "max_ms": 2.57
- },
- "/sessions/epbench-a133189f-4/policy-contexts": {
- "count": 4,
- "min_ms": 2.27,
- "p50_ms": 2.317,
- "p95_ms": 2.376,
- "p99_ms": 2.376,
- "max_ms": 2.376
- },
- "/info/epbench-a133189f-5": {
- "count": 4,
- "min_ms": 0.929,
- "p50_ms": 0.93,
- "p95_ms": 0.943,
- "p99_ms": 0.943,
- "max_ms": 0.943
- },
- "/logs/epbench-a133189f-5": {
- "count": 4,
- "min_ms": 3.047,
- "p50_ms": 3.093,
- "p95_ms": 3.174,
- "p99_ms": 3.174,
- "max_ms": 3.174
- },
- "/history/epbench-a133189f-5": {
- "count": 4,
- "min_ms": 0.83,
- "p50_ms": 0.866,
- "p95_ms": 0.968,
- "p99_ms": 0.968,
- "max_ms": 0.968
- },
- "/history/epbench-a133189f-5/counts": {
- "count": 4,
- "min_ms": 0.592,
- "p50_ms": 0.619,
- "p95_ms": 0.656,
- "p99_ms": 0.656,
- "max_ms": 0.656
- },
- "/history/epbench-a133189f-5/processes": {
- "count": 4,
- "min_ms": 0.657,
- "p50_ms": 0.658,
- "p95_ms": 0.661,
- "p99_ms": 0.661,
- "max_ms": 0.661
- },
- "/history/epbench-a133189f-5/transcript": {
- "count": 4,
- "min_ms": 0.197,
- "p50_ms": 0.198,
- "p95_ms": 0.21,
- "p99_ms": 0.21,
- "max_ms": 0.21
- },
- "/files/epbench-a133189f-5": {
- "count": 4,
- "min_ms": 2.388,
- "p50_ms": 2.431,
- "p95_ms": 2.518,
- "p99_ms": 2.518,
- "max_ms": 2.518
- },
- "/sessions/epbench-a133189f-5/policy-contexts": {
- "count": 4,
- "min_ms": 2.243,
- "p50_ms": 2.317,
- "p95_ms": 2.365,
- "p99_ms": 2.365,
- "max_ms": 2.365
- },
- "/info/epbench-a133189f-6": {
- "count": 4,
- "min_ms": 0.868,
- "p50_ms": 0.941,
- "p95_ms": 1.028,
- "p99_ms": 1.028,
- "max_ms": 1.028
- },
- "/logs/epbench-a133189f-6": {
- "count": 4,
- "min_ms": 3.024,
- "p50_ms": 3.084,
- "p95_ms": 3.197,
- "p99_ms": 3.197,
- "max_ms": 3.197
- },
- "/history/epbench-a133189f-6": {
- "count": 4,
- "min_ms": 0.822,
- "p50_ms": 0.828,
- "p95_ms": 0.883,
- "p99_ms": 0.883,
- "max_ms": 0.883
- },
- "/history/epbench-a133189f-6/counts": {
- "count": 4,
- "min_ms": 0.615,
- "p50_ms": 0.642,
- "p95_ms": 0.761,
- "p99_ms": 0.761,
- "max_ms": 0.761
- },
- "/history/epbench-a133189f-6/processes": {
- "count": 4,
- "min_ms": 0.664,
- "p50_ms": 0.676,
- "p95_ms": 0.718,
- "p99_ms": 0.718,
- "max_ms": 0.718
- },
- "/history/epbench-a133189f-6/transcript": {
- "count": 4,
- "min_ms": 0.197,
- "p50_ms": 0.209,
- "p95_ms": 0.217,
- "p99_ms": 0.217,
- "max_ms": 0.217
- },
- "/files/epbench-a133189f-6": {
- "count": 4,
- "min_ms": 2.382,
- "p50_ms": 2.42,
- "p95_ms": 2.587,
- "p99_ms": 2.587,
- "max_ms": 2.587
- },
- "/sessions/epbench-a133189f-6/policy-contexts": {
- "count": 4,
- "min_ms": 2.298,
- "p50_ms": 2.343,
- "p95_ms": 2.373,
- "p99_ms": 2.373,
- "max_ms": 2.373
- },
- "/info/epbench-a133189f-7": {
- "count": 4,
- "min_ms": 0.867,
- "p50_ms": 0.947,
- "p95_ms": 0.992,
- "p99_ms": 0.992,
- "max_ms": 0.992
- },
- "/logs/epbench-a133189f-7": {
- "count": 4,
- "min_ms": 3.115,
- "p50_ms": 3.13,
- "p95_ms": 3.184,
- "p99_ms": 3.184,
- "max_ms": 3.184
- },
- "/history/epbench-a133189f-7": {
- "count": 4,
- "min_ms": 0.864,
- "p50_ms": 0.87,
- "p95_ms": 0.958,
- "p99_ms": 0.958,
- "max_ms": 0.958
- },
- "/history/epbench-a133189f-7/counts": {
- "count": 4,
- "min_ms": 0.601,
- "p50_ms": 0.601,
- "p95_ms": 0.635,
- "p99_ms": 0.635,
- "max_ms": 0.635
- },
- "/history/epbench-a133189f-7/processes": {
- "count": 4,
- "min_ms": 0.635,
- "p50_ms": 0.649,
- "p95_ms": 0.676,
- "p99_ms": 0.676,
- "max_ms": 0.676
- },
- "/history/epbench-a133189f-7/transcript": {
- "count": 4,
- "min_ms": 0.193,
- "p50_ms": 0.196,
- "p95_ms": 0.218,
- "p99_ms": 0.218,
- "max_ms": 0.218
- },
- "/files/epbench-a133189f-7": {
- "count": 4,
- "min_ms": 2.365,
- "p50_ms": 2.482,
- "p95_ms": 2.53,
- "p99_ms": 2.53,
- "max_ms": 2.53
- },
- "/sessions/epbench-a133189f-7/policy-contexts": {
- "count": 4,
- "min_ms": 2.233,
- "p50_ms": 2.3,
- "p95_ms": 2.4,
- "p99_ms": 2.4,
- "max_ms": 2.4
- }
- },
- "gateway": {
- "/health": {
- "count": 32,
- "min_ms": 0.124,
- "p50_ms": 0.151,
- "p95_ms": 0.232,
- "p99_ms": 0.259,
- "max_ms": 0.259
- },
- "/token": {
- "count": 32,
- "min_ms": 0.117,
- "p50_ms": 0.13,
- "p95_ms": 0.179,
- "p99_ms": 0.183,
- "max_ms": 0.183
- },
- "/status": {
- "count": 32,
- "min_ms": 0.209,
- "p50_ms": 0.227,
- "p95_ms": 0.252,
- "p99_ms": 0.261,
- "max_ms": 0.261
- }
- }
- },
- "schema": "capsem.benchmark-artifact.v1",
- "project_version": "1.2.1780103109",
- "arch": "arm64",
- "recorded_at": 1780149845.194512,
- "recorded_at_utc": "2026-05-30T14:04:05.194515+00:00",
- "command": "uv run pytest tests/capsem-serial/test_endpoint_latency_benchmark.py -xvs",
- "host": {
- "platform": "Darwin",
- "release": "25.5.0",
- "version": "Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:12 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T6050",
- "machine": "arm64",
- "processor": "arm",
- "python_version": "3.14.4",
- "cpu_count": 18,
- "cpu_count_logical": 18,
- "cpu_model": "Apple M5 Max",
- "cpu_count_physical": 18,
- "memory_total_bytes": 137438953472,
- "os_product_version": "26.5",
- "memory_total_gb": 128.0
- },
- "git": {
- "commit": "0a425541fbdc03cc9821aafb238a0dd4b26ccdcd",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/capsem-bench/data_1.2.1780103109_arm64.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_security_packs_microbench.json"
- ]
- }
-}
\ No newline at end of file
diff --git a/benchmarks/fork/data_0.16.1.json b/benchmarks/fork/data_0.16.1.json
new file mode 100644
index 000000000..ee21f7b2a
--- /dev/null
+++ b/benchmarks/fork/data_0.16.1.json
@@ -0,0 +1,47 @@
+{
+ "version": "0.1.0",
+ "timestamp": 1775917876.2788422,
+ "runs": 3,
+ "fork": {
+ "fork_ms": {
+ "min": 104.3,
+ "mean": 107.9,
+ "max": 110.7,
+ "values": [
+ 104.3,
+ 110.7,
+ 108.8
+ ]
+ },
+ "image_size_mb": {
+ "min": 7.9,
+ "mean": 7.9,
+ "max": 7.9,
+ "values": [
+ 7.86,
+ 7.86,
+ 7.86
+ ]
+ },
+ "boot_provision_ms": {
+ "min": 22.0,
+ "mean": 23.4,
+ "max": 24.8,
+ "values": [
+ 24.8,
+ 23.4,
+ 22.0
+ ]
+ },
+ "boot_ready_ms": {
+ "min": 363.6,
+ "mean": 401.1,
+ "max": 420.3,
+ "values": [
+ 363.6,
+ 419.3,
+ 420.3
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/fork/data_1.0.1776445634.json b/benchmarks/fork/data_1.0.1776445634.json
new file mode 100644
index 000000000..b1d45b013
--- /dev/null
+++ b/benchmarks/fork/data_1.0.1776445634.json
@@ -0,0 +1,47 @@
+{
+ "version": "0.1.0",
+ "timestamp": 1776676074.007592,
+ "runs": 3,
+ "fork": {
+ "fork_ms": {
+ "min": 93.2,
+ "mean": 107.7,
+ "max": 119.8,
+ "values": [
+ 119.8,
+ 93.2,
+ 110.0
+ ]
+ },
+ "image_size_mb": {
+ "min": 7.9,
+ "mean": 7.9,
+ "max": 7.9,
+ "values": [
+ 7.93,
+ 7.91,
+ 7.91
+ ]
+ },
+ "boot_provision_ms": {
+ "min": 33.1,
+ "mean": 37.3,
+ "max": 42.5,
+ "values": [
+ 36.3,
+ 33.1,
+ 42.5
+ ]
+ },
+ "boot_ready_ms": {
+ "min": 417.1,
+ "mean": 418.9,
+ "max": 420.6,
+ "values": [
+ 417.1,
+ 418.9,
+ 420.6
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/fork/data_1.0.1776686294.json b/benchmarks/fork/data_1.0.1776686294.json
new file mode 100644
index 000000000..6cdb03357
--- /dev/null
+++ b/benchmarks/fork/data_1.0.1776686294.json
@@ -0,0 +1,47 @@
+{
+ "version": "0.1.0",
+ "timestamp": 1776687143.067568,
+ "runs": 3,
+ "fork": {
+ "fork_ms": {
+ "min": 113.1,
+ "mean": 163.3,
+ "max": 256.4,
+ "values": [
+ 120.3,
+ 113.1,
+ 256.4
+ ]
+ },
+ "image_size_mb": {
+ "min": 7.9,
+ "mean": 7.9,
+ "max": 8.0,
+ "values": [
+ 7.93,
+ 7.93,
+ 7.95
+ ]
+ },
+ "boot_provision_ms": {
+ "min": 39.2,
+ "mean": 45.4,
+ "max": 56.2,
+ "values": [
+ 39.2,
+ 40.9,
+ 56.2
+ ]
+ },
+ "boot_ready_ms": {
+ "min": 469.9,
+ "mean": 680.5,
+ "max": 1087.1,
+ "values": [
+ 469.9,
+ 1087.1,
+ 484.5
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/fork/data_1.0.1776688771.json b/benchmarks/fork/data_1.0.1776688771.json
new file mode 100644
index 000000000..950cf12f5
--- /dev/null
+++ b/benchmarks/fork/data_1.0.1776688771.json
@@ -0,0 +1,47 @@
+{
+ "version": "0.1.0",
+ "timestamp": 1776965655.903796,
+ "runs": 3,
+ "fork": {
+ "fork_ms": {
+ "min": 94.1,
+ "mean": 109.2,
+ "max": 120.0,
+ "values": [
+ 120.0,
+ 113.5,
+ 94.1
+ ]
+ },
+ "image_size_mb": {
+ "min": 7.9,
+ "mean": 7.9,
+ "max": 8.0,
+ "values": [
+ 7.95,
+ 7.93,
+ 7.95
+ ]
+ },
+ "boot_provision_ms": {
+ "min": 30.3,
+ "mean": 31.4,
+ "max": 32.2,
+ "values": [
+ 30.3,
+ 32.2,
+ 31.6
+ ]
+ },
+ "boot_ready_ms": {
+ "min": 616.7,
+ "mean": 619.0,
+ "max": 620.5,
+ "values": [
+ 620.5,
+ 619.7,
+ 616.7
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/fork/data_1.0.1777065213.json b/benchmarks/fork/data_1.0.1777065213.json
new file mode 100644
index 000000000..f1907e49d
--- /dev/null
+++ b/benchmarks/fork/data_1.0.1777065213.json
@@ -0,0 +1,47 @@
+{
+ "version": "0.1.0",
+ "timestamp": 1780609494.2233,
+ "runs": 3,
+ "fork": {
+ "fork_ms": {
+ "min": 33.3,
+ "mean": 36.3,
+ "max": 40.5,
+ "values": [
+ 35.0,
+ 40.5,
+ 33.3
+ ]
+ },
+ "image_size_mb": {
+ "min": 11.9,
+ "mean": 11.9,
+ "max": 12.0,
+ "values": [
+ 11.88,
+ 11.91,
+ 11.96
+ ]
+ },
+ "boot_provision_ms": {
+ "min": 908.8,
+ "mean": 941.2,
+ "max": 958.8,
+ "values": [
+ 958.8,
+ 908.8,
+ 956.0
+ ]
+ },
+ "boot_ready_ms": {
+ "min": 12.8,
+ "mean": 14.6,
+ "max": 16.4,
+ "values": [
+ 16.4,
+ 12.8,
+ 14.7
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/fork/data_1.0.1780610732.json b/benchmarks/fork/data_1.0.1780610732.json
new file mode 100644
index 000000000..0ba6f7164
--- /dev/null
+++ b/benchmarks/fork/data_1.0.1780610732.json
@@ -0,0 +1,47 @@
+{
+ "version": "0.1.0",
+ "timestamp": 1780761590.0556989,
+ "runs": 3,
+ "fork": {
+ "fork_ms": {
+ "min": 31.3,
+ "mean": 33.0,
+ "max": 34.0,
+ "values": [
+ 34.0,
+ 31.3,
+ 33.7
+ ]
+ },
+ "image_size_mb": {
+ "min": 12.5,
+ "mean": 12.6,
+ "max": 12.7,
+ "values": [
+ 12.65,
+ 12.51,
+ 12.63
+ ]
+ },
+ "boot_provision_ms": {
+ "min": 988.9,
+ "mean": 1024.8,
+ "max": 1047.9,
+ "values": [
+ 1037.6,
+ 1047.9,
+ 988.9
+ ]
+ },
+ "boot_ready_ms": {
+ "min": 11.6,
+ "mean": 12.7,
+ "max": 13.6,
+ "values": [
+ 13.6,
+ 11.6,
+ 12.8
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/fork/data_1.0.1780977620.json b/benchmarks/fork/data_1.0.1780977620.json
new file mode 100644
index 000000000..0ad652dc5
--- /dev/null
+++ b/benchmarks/fork/data_1.0.1780977620.json
@@ -0,0 +1,47 @@
+{
+ "version": "0.1.0",
+ "timestamp": 1781016486.6162329,
+ "runs": 3,
+ "fork": {
+ "fork_ms": {
+ "min": 30.5,
+ "mean": 33.7,
+ "max": 36.1,
+ "values": [
+ 30.5,
+ 36.1,
+ 34.4
+ ]
+ },
+ "image_size_mb": {
+ "min": 13.1,
+ "mean": 13.2,
+ "max": 13.2,
+ "values": [
+ 13.25,
+ 13.17,
+ 13.1
+ ]
+ },
+ "boot_provision_ms": {
+ "min": 967.8,
+ "mean": 990.3,
+ "max": 1026.7,
+ "values": [
+ 976.5,
+ 1026.7,
+ 967.8
+ ]
+ },
+ "boot_ready_ms": {
+ "min": 13.0,
+ "mean": 16.7,
+ "max": 18.8,
+ "values": [
+ 18.3,
+ 18.8,
+ 13.0
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/fork/data_1.2.1779673506_x86_64.json b/benchmarks/fork/data_1.2.1779673506_x86_64.json
deleted file mode 100644
index 78f56db5a..000000000
--- a/benchmarks/fork/data_1.2.1779673506_x86_64.json
+++ /dev/null
@@ -1,82 +0,0 @@
-{
- "version": "0.1.0",
- "timestamp": 1780145173.583271,
- "runs": 3,
- "fork": {
- "fork_ms": {
- "min": 104.2,
- "mean": 112.3,
- "max": 117.1,
- "values": [
- 104.2,
- 117.1,
- 115.7
- ]
- },
- "image_size_mb": {
- "min": 85.8,
- "mean": 99.1,
- "max": 105.8,
- "values": [
- 85.79,
- 105.79,
- 105.79
- ]
- },
- "boot_provision_ms": {
- "min": 1419.5,
- "mean": 1429.9,
- "max": 1438.4,
- "values": [
- 1419.5,
- 1438.4,
- 1431.7
- ]
- },
- "boot_ready_ms": {
- "min": 23.7,
- "mean": 29.5,
- "max": 33.1,
- "values": [
- 33.1,
- 31.6,
- 23.7
- ]
- }
- },
- "schema": "capsem.benchmark-artifact.v1",
- "project_version": "1.2.1779673506",
- "arch": "x86_64",
- "recorded_at": 1780145173.5836608,
- "recorded_at_utc": "2026-05-30T12:46:13.583663+00:00",
- "command": "uv run pytest tests/capsem-serial/test_lifecycle_benchmark.py::test_fork_benchmark -xvs",
- "host": {
- "platform": "Linux",
- "release": "7.0.0-1003-gcp",
- "version": "#3-Ubuntu SMP PREEMPT Mon Apr 13 16:29:20 UTC 2026",
- "machine": "x86_64",
- "processor": "",
- "python_version": "3.14.4",
- "cpu_count": 16,
- "cpu_count_logical": 16,
- "cpu_model": "Intel(R) Xeon(R) CPU @ 2.80GHz",
- "cpu_count_physical": 8,
- "memory_total_bytes": 67415740416,
- "memory_total_gb": 62.79,
- "os_pretty_name": "Ubuntu 26.04 LTS",
- "os_id": "ubuntu",
- "os_version_id": "26.04"
- },
- "git": {
- "commit": "b6f9b6e2342496f7c9c5dadd77548aa8d138678e",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/capsem-bench/data_1.2.1779673506_x86_64.json",
- "benchmarks/host-native/data_1.2.1779673506_x86_64.json",
- "benchmarks/lifecycle/data_1.2.1779673506_x86_64.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_security_packs_microbench.json"
- ]
- }
-}
\ No newline at end of file
diff --git a/benchmarks/fork/data_1.2.1780103109_arm64.json b/benchmarks/fork/data_1.2.1780103109_arm64.json
deleted file mode 100644
index 74e76e5cd..000000000
--- a/benchmarks/fork/data_1.2.1780103109_arm64.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "version": "0.1.0",
- "timestamp": 1780149863.9396212,
- "runs": 3,
- "fork": {
- "fork_ms": {
- "min": 34.0,
- "mean": 35.5,
- "max": 37.6,
- "values": [
- 37.6,
- 35.0,
- 34.0
- ]
- },
- "image_size_mb": {
- "min": 13.1,
- "mean": 13.1,
- "max": 13.1,
- "values": [
- 13.05,
- 13.05,
- 13.14
- ]
- },
- "boot_provision_ms": {
- "min": 746.3,
- "mean": 782.1,
- "max": 852.6,
- "values": [
- 746.3,
- 747.3,
- 852.6
- ]
- },
- "boot_ready_ms": {
- "min": 15.1,
- "mean": 15.5,
- "max": 16.3,
- "values": [
- 15.1,
- 15.1,
- 16.3
- ]
- }
- },
- "schema": "capsem.benchmark-artifact.v1",
- "project_version": "1.2.1780103109",
- "arch": "arm64",
- "recorded_at": 1780149863.939942,
- "recorded_at_utc": "2026-05-30T14:04:23.939945+00:00",
- "command": "uv run pytest tests/capsem-serial/test_lifecycle_benchmark.py::test_fork_benchmark -xvs",
- "host": {
- "platform": "Darwin",
- "release": "25.5.0",
- "version": "Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:12 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T6050",
- "machine": "arm64",
- "processor": "arm",
- "python_version": "3.14.4",
- "cpu_count": 18,
- "cpu_count_logical": 18,
- "cpu_model": "Apple M5 Max",
- "cpu_count_physical": 18,
- "memory_total_bytes": 137438953472,
- "os_product_version": "26.5",
- "memory_total_gb": 128.0
- },
- "git": {
- "commit": "0a425541fbdc03cc9821aafb238a0dd4b26ccdcd",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/endpoint-latency/data_1.2.1780103109_arm64.json",
- "benchmarks/capsem-bench/data_1.2.1780103109_arm64.json",
- "benchmarks/host-native/data_1.2.1780103109_arm64.json",
- "benchmarks/lifecycle/data_1.2.1780103109_arm64.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_security_packs_microbench.json"
- ]
- }
-}
\ No newline at end of file
diff --git a/benchmarks/fork/data_1.3.1781050981.json b/benchmarks/fork/data_1.3.1781050981.json
new file mode 100644
index 000000000..419069204
--- /dev/null
+++ b/benchmarks/fork/data_1.3.1781050981.json
@@ -0,0 +1,47 @@
+{
+ "version": "0.1.0",
+ "timestamp": 1781107671.621803,
+ "runs": 3,
+ "fork": {
+ "fork_ms": {
+ "min": 33.4,
+ "mean": 35.7,
+ "max": 39.4,
+ "values": [
+ 34.3,
+ 33.4,
+ 39.4
+ ]
+ },
+ "image_size_mb": {
+ "min": 13.0,
+ "mean": 13.1,
+ "max": 13.1,
+ "values": [
+ 13.12,
+ 13.11,
+ 13.0
+ ]
+ },
+ "boot_provision_ms": {
+ "min": 975.1,
+ "mean": 976.4,
+ "max": 977.1,
+ "values": [
+ 977.1,
+ 975.1,
+ 977.1
+ ]
+ },
+ "boot_ready_ms": {
+ "min": 12.2,
+ "mean": 14.9,
+ "max": 18.9,
+ "values": [
+ 12.2,
+ 18.9,
+ 13.5
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/fork/data_1.3.1781124728.json b/benchmarks/fork/data_1.3.1781124728.json
new file mode 100644
index 000000000..06b21fd99
--- /dev/null
+++ b/benchmarks/fork/data_1.3.1781124728.json
@@ -0,0 +1,47 @@
+{
+ "version": "0.1.0",
+ "timestamp": 1781205344.635825,
+ "runs": 3,
+ "fork": {
+ "fork_ms": {
+ "min": 30.6,
+ "mean": 33.8,
+ "max": 36.1,
+ "values": [
+ 34.7,
+ 30.6,
+ 36.1
+ ]
+ },
+ "image_size_mb": {
+ "min": 13.1,
+ "mean": 13.1,
+ "max": 13.2,
+ "values": [
+ 13.12,
+ 13.06,
+ 13.18
+ ]
+ },
+ "boot_provision_ms": {
+ "min": 925.6,
+ "mean": 946.8,
+ "max": 983.3,
+ "values": [
+ 925.6,
+ 983.3,
+ 931.4
+ ]
+ },
+ "boot_ready_ms": {
+ "min": 13.5,
+ "mean": 15.2,
+ "max": 17.1,
+ "values": [
+ 13.5,
+ 17.1,
+ 15.1
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/fork/data_1.3.1781205836.json b/benchmarks/fork/data_1.3.1781205836.json
new file mode 100644
index 000000000..b1a40fd07
--- /dev/null
+++ b/benchmarks/fork/data_1.3.1781205836.json
@@ -0,0 +1,47 @@
+{
+ "version": "0.1.0",
+ "timestamp": 1781633343.764544,
+ "runs": 3,
+ "fork": {
+ "fork_ms": {
+ "min": 38.0,
+ "mean": 40.5,
+ "max": 43.3,
+ "values": [
+ 43.3,
+ 38.0,
+ 40.2
+ ]
+ },
+ "image_size_mb": {
+ "min": 11.8,
+ "mean": 11.8,
+ "max": 11.8,
+ "values": [
+ 11.8,
+ 11.78,
+ 11.82
+ ]
+ },
+ "boot_provision_ms": {
+ "min": 930.6,
+ "mean": 948.6,
+ "max": 983.8,
+ "values": [
+ 930.6,
+ 931.4,
+ 983.8
+ ]
+ },
+ "boot_ready_ms": {
+ "min": 12.3,
+ "mean": 12.6,
+ "max": 13.1,
+ "values": [
+ 13.1,
+ 12.4,
+ 12.3
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/fork/data_1.3.1781720230.json b/benchmarks/fork/data_1.3.1781720230.json
new file mode 100644
index 000000000..760627e61
--- /dev/null
+++ b/benchmarks/fork/data_1.3.1781720230.json
@@ -0,0 +1,47 @@
+{
+ "version": "0.1.0",
+ "timestamp": 1781731214.7992399,
+ "runs": 3,
+ "fork": {
+ "fork_ms": {
+ "min": 32.5,
+ "mean": 36.1,
+ "max": 39.7,
+ "values": [
+ 39.7,
+ 36.2,
+ 32.5
+ ]
+ },
+ "image_size_mb": {
+ "min": 11.8,
+ "mean": 11.8,
+ "max": 11.8,
+ "values": [
+ 11.81,
+ 11.81,
+ 11.79
+ ]
+ },
+ "boot_provision_ms": {
+ "min": 936.9,
+ "mean": 974.9,
+ "max": 996.1,
+ "values": [
+ 996.1,
+ 991.6,
+ 936.9
+ ]
+ },
+ "boot_ready_ms": {
+ "min": 11.3,
+ "mean": 12.6,
+ "max": 13.7,
+ "values": [
+ 12.7,
+ 11.3,
+ 13.7
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/host-native/data_1.2.1779673506_x86_64.json b/benchmarks/host-native/data_1.2.1779673506_x86_64.json
deleted file mode 100644
index dd15dddf2..000000000
--- a/benchmarks/host-native/data_1.2.1779673506_x86_64.json
+++ /dev/null
@@ -1,167 +0,0 @@
-{
- "kind": "host_native_baseline",
- "version": "0.1.0",
- "timestamp": 1780145124.1649601,
- "filesystem": {
- "directory": "/home/elieb_google_com/capsem/target/host-native-benchmark/tmp9j36_vav",
- "disk_usage": {
- "total_bytes": 519537790976,
- "used_bytes": 300807548928,
- "free_bytes": 218713464832
- },
- "df": {
- "source": "/dev/root",
- "fstype": "ext4",
- "blocks_1k": 507361124,
- "used_1k": 293757372,
- "available_1k": 213587368,
- "capacity": "58%",
- "mount": "/"
- }
- },
- "disk": {
- "directory": "/home/elieb_google_com/capsem/target/host-native-benchmark/tmp9j36_vav",
- "size_mb": 256,
- "seq_write": {
- "size_bytes": 268435456,
- "block_size": 1048576,
- "duration_ms": 582.3,
- "throughput_mbps": 439.6
- },
- "seq_read": {
- "size_bytes": 268435456,
- "block_size": 1048576,
- "duration_ms": 39.6,
- "throughput_mbps": 6457.8
- },
- "rand_write_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 14341.4,
- "iops": 697.3,
- "throughput_mbps": 2.7
- },
- "rand_read_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 27.0,
- "iops": 370534.0,
- "throughput_mbps": 1447.4
- }
- },
- "startup": {
- "runs_per_command": 3,
- "commands": {
- "python3": {
- "command": [
- "python3",
- "--version"
- ],
- "timings_ms": [
- 1.8,
- 1.6,
- 1.5
- ],
- "min_ms": 1.5,
- "mean_ms": 1.6,
- "max_ms": 1.8
- },
- "node": {
- "command": [
- "node",
- "--version"
- ],
- "timings_ms": [
- 64.0,
- 64.5,
- 64.2
- ],
- "min_ms": 64.0,
- "mean_ms": 64.2,
- "max_ms": 64.5
- },
- "claude": {
- "command": [
- "claude",
- "--version"
- ],
- "error": "not found or timed out"
- },
- "gemini": {
- "command": [
- "gemini",
- "--version"
- ],
- "error": "not found or timed out"
- },
- "codex": {
- "command": [
- "codex",
- "--version"
- ],
- "timings_ms": [
- 15.8,
- 15.9,
- 15.9
- ],
- "min_ms": 15.8,
- "mean_ms": 15.9,
- "max_ms": 15.9
- }
- }
- },
- "small_file_read": {
- "count": 5000,
- "files_sampled": 128,
- "bytes_read": 3280000,
- "duration_ms": 28.0,
- "ops_per_sec": 178786.0,
- "throughput_mbps": 111.9
- },
- "metadata_stat": {
- "entries": 5050,
- "files": 5000,
- "dirs": 50,
- "errors": 0,
- "duration_ms": 21.8,
- "stats_per_sec": 231718.2
- },
- "io_shape": {
- "sequential_block_size": 1048576,
- "random_block_size": 4096,
- "size_mb": 256
- },
- "schema": "capsem.benchmark-artifact.v1",
- "project_version": "1.2.1779673506",
- "arch": "x86_64",
- "recorded_at": 1780145140.4303405,
- "recorded_at_utc": "2026-05-30T12:45:40.430344+00:00",
- "command": "uv run pytest tests/capsem-serial/test_host_native_benchmark.py -xvs",
- "host": {
- "platform": "Linux",
- "release": "7.0.0-1003-gcp",
- "version": "#3-Ubuntu SMP PREEMPT Mon Apr 13 16:29:20 UTC 2026",
- "machine": "x86_64",
- "processor": "",
- "python_version": "3.14.4",
- "cpu_count": 16,
- "cpu_count_logical": 16,
- "cpu_model": "Intel(R) Xeon(R) CPU @ 2.80GHz",
- "cpu_count_physical": 8,
- "memory_total_bytes": 67415740416,
- "memory_total_gb": 62.79,
- "os_pretty_name": "Ubuntu 26.04 LTS",
- "os_id": "ubuntu",
- "os_version_id": "26.04"
- },
- "git": {
- "commit": "b6f9b6e2342496f7c9c5dadd77548aa8d138678e",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/capsem-bench/data_1.2.1779673506_x86_64.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_security_packs_microbench.json"
- ]
- }
-}
\ No newline at end of file
diff --git a/benchmarks/host-native/data_1.2.1780103109_arm64.json b/benchmarks/host-native/data_1.2.1780103109_arm64.json
deleted file mode 100644
index c63153102..000000000
--- a/benchmarks/host-native/data_1.2.1780103109_arm64.json
+++ /dev/null
@@ -1,164 +0,0 @@
-{
- "kind": "host_native_baseline",
- "version": "0.1.0",
- "timestamp": 1780149845.810327,
- "filesystem": {
- "directory": "/Users/elie/git/capsem-tui-control/target/host-native-benchmark/tmp5i2863d0",
- "disk_usage": {
- "total_bytes": 3996276899840,
- "used_bytes": 961723437056,
- "free_bytes": 3034553462784
- }
- },
- "disk": {
- "directory": "/Users/elie/git/capsem-tui-control/target/host-native-benchmark/tmp5i2863d0",
- "size_mb": 256,
- "seq_write": {
- "size_bytes": 268435456,
- "block_size": 1048576,
- "duration_ms": 22.5,
- "throughput_mbps": 11381.3
- },
- "seq_read": {
- "size_bytes": 268435456,
- "block_size": 1048576,
- "duration_ms": 13.2,
- "throughput_mbps": 19417.4
- },
- "rand_write_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 510.4,
- "iops": 19592.2,
- "throughput_mbps": 76.5
- },
- "rand_read_4k": {
- "count": 10000,
- "block_size": 4096,
- "duration_ms": 10.9,
- "iops": 913471.4,
- "throughput_mbps": 3568.2
- }
- },
- "startup": {
- "runs_per_command": 3,
- "commands": {
- "python3": {
- "command": [
- "python3",
- "--version"
- ],
- "timings_ms": [
- 10.9,
- 10.7,
- 10.7
- ],
- "min_ms": 10.7,
- "mean_ms": 10.8,
- "max_ms": 10.9
- },
- "node": {
- "command": [
- "node",
- "--version"
- ],
- "timings_ms": [
- 21.2,
- 21.3,
- 26.8
- ],
- "min_ms": 21.2,
- "mean_ms": 23.1,
- "max_ms": 26.8
- },
- "claude": {
- "command": [
- "claude",
- "--version"
- ],
- "timings_ms": [
- 2534.3,
- 74.9,
- 44.0
- ],
- "min_ms": 44.0,
- "mean_ms": 884.4,
- "max_ms": 2534.3
- },
- "gemini": {
- "command": [
- "gemini",
- "--version"
- ],
- "error": "not found or timed out"
- },
- "codex": {
- "command": [
- "codex",
- "--version"
- ],
- "timings_ms": [
- 20.7,
- 11.2,
- 20.2
- ],
- "min_ms": 11.2,
- "mean_ms": 17.4,
- "max_ms": 20.7
- }
- }
- },
- "small_file_read": {
- "count": 5000,
- "files_sampled": 128,
- "bytes_read": 3280000,
- "duration_ms": 47.5,
- "ops_per_sec": 105356.4,
- "throughput_mbps": 65.9
- },
- "metadata_stat": {
- "entries": 5050,
- "files": 5000,
- "dirs": 50,
- "errors": 0,
- "duration_ms": 14.2,
- "stats_per_sec": 356587.0
- },
- "io_shape": {
- "sequential_block_size": 1048576,
- "random_block_size": 4096,
- "size_mb": 256
- },
- "schema": "capsem.benchmark-artifact.v1",
- "project_version": "1.2.1780103109",
- "arch": "arm64",
- "recorded_at": 1780149849.75119,
- "recorded_at_utc": "2026-05-30T14:04:09.751193+00:00",
- "command": "uv run pytest tests/capsem-serial/test_host_native_benchmark.py -xvs",
- "host": {
- "platform": "Darwin",
- "release": "25.5.0",
- "version": "Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:12 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T6050",
- "machine": "arm64",
- "processor": "arm",
- "python_version": "3.14.4",
- "cpu_count": 18,
- "cpu_count_logical": 18,
- "cpu_model": "Apple M5 Max",
- "cpu_count_physical": 18,
- "memory_total_bytes": 137438953472,
- "os_product_version": "26.5",
- "memory_total_gb": 128.0
- },
- "git": {
- "commit": "0a425541fbdc03cc9821aafb238a0dd4b26ccdcd",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/endpoint-latency/data_1.2.1780103109_arm64.json",
- "benchmarks/capsem-bench/data_1.2.1780103109_arm64.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_security_packs_microbench.json"
- ]
- }
-}
\ No newline at end of file
diff --git a/benchmarks/lifecycle/data_0.16.1.json b/benchmarks/lifecycle/data_0.16.1.json
new file mode 100644
index 000000000..bd6fc9664
--- /dev/null
+++ b/benchmarks/lifecycle/data_0.16.1.json
@@ -0,0 +1,57 @@
+{
+ "version": "0.1.0",
+ "timestamp": 1775918287.6311638,
+ "runs": 3,
+ "operations": {
+ "provision_ms": {
+ "min": 32.5,
+ "mean": 36.2,
+ "max": 42.2,
+ "values": [
+ 32.5,
+ 34.0,
+ 42.2
+ ]
+ },
+ "exec_ready_ms": {
+ "min": 576.2,
+ "mean": 785.6,
+ "max": 1200.0,
+ "values": [
+ 1200.0,
+ 580.7,
+ 576.2
+ ]
+ },
+ "exec_ms": {
+ "min": 19.4,
+ "mean": 22.2,
+ "max": 25.9,
+ "values": [
+ 21.2,
+ 25.9,
+ 19.4
+ ]
+ },
+ "delete_ms": {
+ "min": 589.8,
+ "mean": 590.3,
+ "max": 590.7,
+ "values": [
+ 590.3,
+ 589.8,
+ 590.7
+ ]
+ },
+ "total_ms": {
+ "min": 1228.5,
+ "mean": 1434.3,
+ "max": 1844.0,
+ "values": [
+ 1844.0,
+ 1230.4,
+ 1228.5
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/lifecycle/data_1.0.1776445634.json b/benchmarks/lifecycle/data_1.0.1776445634.json
new file mode 100644
index 000000000..263865945
--- /dev/null
+++ b/benchmarks/lifecycle/data_1.0.1776445634.json
@@ -0,0 +1,57 @@
+{
+ "version": "0.1.0",
+ "timestamp": 1776684094.896384,
+ "runs": 3,
+ "operations": {
+ "provision_ms": {
+ "min": 32.7,
+ "mean": 34.9,
+ "max": 37.0,
+ "values": [
+ 37.0,
+ 32.7,
+ 34.9
+ ]
+ },
+ "exec_ready_ms": {
+ "min": 566.4,
+ "mean": 571.8,
+ "max": 582.4,
+ "values": [
+ 566.5,
+ 566.4,
+ 582.4
+ ]
+ },
+ "exec_ms": {
+ "min": 20.4,
+ "mean": 20.8,
+ "max": 21.3,
+ "values": [
+ 20.4,
+ 20.8,
+ 21.3
+ ]
+ },
+ "delete_ms": {
+ "min": 584.7,
+ "mean": 590.0,
+ "max": 592.9,
+ "values": [
+ 584.7,
+ 592.9,
+ 592.3
+ ]
+ },
+ "total_ms": {
+ "min": 1208.6,
+ "mean": 1217.4,
+ "max": 1230.9,
+ "values": [
+ 1208.6,
+ 1212.8,
+ 1230.9
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/lifecycle/data_1.0.1776686294.json b/benchmarks/lifecycle/data_1.0.1776686294.json
new file mode 100644
index 000000000..2c2a7ba78
--- /dev/null
+++ b/benchmarks/lifecycle/data_1.0.1776686294.json
@@ -0,0 +1,57 @@
+{
+ "version": "0.1.0",
+ "timestamp": 1776687129.33116,
+ "runs": 3,
+ "operations": {
+ "provision_ms": {
+ "min": 29.2,
+ "mean": 30.1,
+ "max": 31.3,
+ "values": [
+ 29.2,
+ 29.7,
+ 31.3
+ ]
+ },
+ "exec_ready_ms": {
+ "min": 574.0,
+ "mean": 575.3,
+ "max": 576.9,
+ "values": [
+ 576.9,
+ 574.0,
+ 575.1
+ ]
+ },
+ "exec_ms": {
+ "min": 19.3,
+ "mean": 21.1,
+ "max": 23.3,
+ "values": [
+ 23.3,
+ 20.8,
+ 19.3
+ ]
+ },
+ "delete_ms": {
+ "min": 580.4,
+ "mean": 585.0,
+ "max": 588.7,
+ "values": [
+ 580.4,
+ 586.0,
+ 588.7
+ ]
+ },
+ "total_ms": {
+ "min": 1209.8,
+ "mean": 1211.6,
+ "max": 1214.4,
+ "values": [
+ 1209.8,
+ 1210.5,
+ 1214.4
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/lifecycle/data_1.0.1776688771.json b/benchmarks/lifecycle/data_1.0.1776688771.json
new file mode 100644
index 000000000..f93ebac44
--- /dev/null
+++ b/benchmarks/lifecycle/data_1.0.1776688771.json
@@ -0,0 +1,57 @@
+{
+ "version": "0.1.0",
+ "timestamp": 1776965645.5371468,
+ "runs": 3,
+ "operations": {
+ "provision_ms": {
+ "min": 23.9,
+ "mean": 25.9,
+ "max": 28.3,
+ "values": [
+ 28.3,
+ 25.4,
+ 23.9
+ ]
+ },
+ "exec_ready_ms": {
+ "min": 778.2,
+ "mean": 799.2,
+ "max": 832.8,
+ "values": [
+ 786.5,
+ 778.2,
+ 832.8
+ ]
+ },
+ "exec_ms": {
+ "min": 17.3,
+ "mean": 17.4,
+ "max": 17.6,
+ "values": [
+ 17.3,
+ 17.3,
+ 17.6
+ ]
+ },
+ "delete_ms": {
+ "min": 69.2,
+ "mean": 69.9,
+ "max": 71.2,
+ "values": [
+ 69.2,
+ 69.4,
+ 71.2
+ ]
+ },
+ "total_ms": {
+ "min": 890.3,
+ "mean": 912.4,
+ "max": 945.5,
+ "values": [
+ 901.3,
+ 890.3,
+ 945.5
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/lifecycle/data_1.0.1777065213.json b/benchmarks/lifecycle/data_1.0.1777065213.json
new file mode 100644
index 000000000..6e91b29e5
--- /dev/null
+++ b/benchmarks/lifecycle/data_1.0.1777065213.json
@@ -0,0 +1,57 @@
+{
+ "version": "0.1.0",
+ "timestamp": 1780609482.6448672,
+ "runs": 3,
+ "operations": {
+ "provision_ms": {
+ "min": 999.4,
+ "mean": 1018.3,
+ "max": 1053.1,
+ "values": [
+ 999.4,
+ 1002.5,
+ 1053.1
+ ]
+ },
+ "exec_ready_ms": {
+ "min": 11.9,
+ "mean": 12.4,
+ "max": 13.1,
+ "values": [
+ 13.1,
+ 11.9,
+ 12.2
+ ]
+ },
+ "exec_ms": {
+ "min": 10.3,
+ "mean": 11.4,
+ "max": 12.5,
+ "values": [
+ 12.5,
+ 10.3,
+ 11.4
+ ]
+ },
+ "delete_ms": {
+ "min": 61.0,
+ "mean": 61.2,
+ "max": 61.4,
+ "values": [
+ 61.3,
+ 61.4,
+ 61.0
+ ]
+ },
+ "total_ms": {
+ "min": 1086.1,
+ "mean": 1103.4,
+ "max": 1137.7,
+ "values": [
+ 1086.3,
+ 1086.1,
+ 1137.7
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/lifecycle/data_1.0.1780610732.json b/benchmarks/lifecycle/data_1.0.1780610732.json
new file mode 100644
index 000000000..4e7747403
--- /dev/null
+++ b/benchmarks/lifecycle/data_1.0.1780610732.json
@@ -0,0 +1,57 @@
+{
+ "version": "0.1.0",
+ "timestamp": 1780761578.446922,
+ "runs": 3,
+ "operations": {
+ "provision_ms": {
+ "min": 971.9,
+ "mean": 993.2,
+ "max": 1030.9,
+ "values": [
+ 976.9,
+ 971.9,
+ 1030.9
+ ]
+ },
+ "exec_ready_ms": {
+ "min": 10.9,
+ "mean": 11.8,
+ "max": 12.9,
+ "values": [
+ 12.9,
+ 10.9,
+ 11.5
+ ]
+ },
+ "exec_ms": {
+ "min": 9.8,
+ "mean": 10.2,
+ "max": 10.6,
+ "values": [
+ 9.8,
+ 10.6,
+ 10.3
+ ]
+ },
+ "delete_ms": {
+ "min": 59.3,
+ "mean": 60.4,
+ "max": 61.1,
+ "values": [
+ 60.9,
+ 59.3,
+ 61.1
+ ]
+ },
+ "total_ms": {
+ "min": 1052.7,
+ "mean": 1075.7,
+ "max": 1113.8,
+ "values": [
+ 1060.5,
+ 1052.7,
+ 1113.8
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/lifecycle/data_1.0.1780763638.json b/benchmarks/lifecycle/data_1.0.1780763638.json
new file mode 100644
index 000000000..790813ee7
--- /dev/null
+++ b/benchmarks/lifecycle/data_1.0.1780763638.json
@@ -0,0 +1,80 @@
+{
+ "version": "0.2.0",
+ "timestamp": 1780771151.262416,
+ "runs": 3,
+ "operations": {
+ "provision_ms": {
+ "min": 970.8,
+ "mean": 975.7,
+ "p50": 973.2,
+ "p95": 982.1,
+ "p99": 982.9,
+ "max": 983.1,
+ "values": [
+ 983.1,
+ 970.8,
+ 973.2
+ ]
+ },
+ "exec_ready_ms": {
+ "min": 11.6,
+ "mean": 11.6,
+ "p50": 11.6,
+ "p95": 11.6,
+ "p99": 11.6,
+ "max": 11.6,
+ "values": [
+ 11.6,
+ 11.6,
+ 11.6
+ ]
+ },
+ "exec_ms": {
+ "min": 11.1,
+ "mean": 11.3,
+ "p50": 11.3,
+ "p95": 11.4,
+ "p99": 11.4,
+ "max": 11.4,
+ "values": [
+ 11.3,
+ 11.4,
+ 11.1
+ ]
+ },
+ "delete_ms": {
+ "min": 59.9,
+ "mean": 60.3,
+ "p50": 60.0,
+ "p95": 61.0,
+ "p99": 61.1,
+ "max": 61.1,
+ "values": [
+ 60.0,
+ 59.9,
+ 61.1
+ ]
+ },
+ "total_ms": {
+ "min": 1053.7,
+ "mean": 1058.9,
+ "p50": 1057.0,
+ "p95": 1065.1,
+ "p99": 1065.8,
+ "max": 1066.0,
+ "values": [
+ 1066.0,
+ 1053.7,
+ 1057.0
+ ]
+ }
+ },
+ "launch_span_contract": [
+ "capsem.launch.service",
+ "capsem.launch.gateway",
+ "capsem.launch.process_spawn",
+ "capsem.launch.vm_boot",
+ "capsem.launch.vsock_ready",
+ "capsem.launch.first_network_ready"
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/lifecycle/data_1.0.1780977620.json b/benchmarks/lifecycle/data_1.0.1780977620.json
new file mode 100644
index 000000000..0b9d3d441
--- /dev/null
+++ b/benchmarks/lifecycle/data_1.0.1780977620.json
@@ -0,0 +1,80 @@
+{
+ "version": "0.2.0",
+ "timestamp": 1781016475.0477288,
+ "runs": 3,
+ "operations": {
+ "provision_ms": {
+ "min": 1070.4,
+ "mean": 1071.3,
+ "p50": 1071.7,
+ "p95": 1071.9,
+ "p99": 1071.9,
+ "max": 1071.9,
+ "values": [
+ 1071.9,
+ 1070.4,
+ 1071.7
+ ]
+ },
+ "exec_ready_ms": {
+ "min": 11.5,
+ "mean": 14.5,
+ "p50": 13.1,
+ "p95": 18.3,
+ "p99": 18.8,
+ "max": 18.9,
+ "values": [
+ 13.1,
+ 11.5,
+ 18.9
+ ]
+ },
+ "exec_ms": {
+ "min": 10.9,
+ "mean": 12.7,
+ "p50": 13.4,
+ "p95": 13.7,
+ "p99": 13.7,
+ "max": 13.7,
+ "values": [
+ 13.4,
+ 10.9,
+ 13.7
+ ]
+ },
+ "delete_ms": {
+ "min": 60.1,
+ "mean": 60.9,
+ "p50": 60.2,
+ "p95": 62.1,
+ "p99": 62.3,
+ "max": 62.3,
+ "values": [
+ 60.2,
+ 60.1,
+ 62.3
+ ]
+ },
+ "total_ms": {
+ "min": 1152.9,
+ "mean": 1159.4,
+ "p50": 1158.6,
+ "p95": 1165.8,
+ "p99": 1166.4,
+ "max": 1166.6,
+ "values": [
+ 1158.6,
+ 1152.9,
+ 1166.6
+ ]
+ }
+ },
+ "launch_span_contract": [
+ "capsem.launch.service",
+ "capsem.launch.gateway",
+ "capsem.launch.process_spawn",
+ "capsem.launch.vm_boot",
+ "capsem.launch.vsock_ready",
+ "capsem.launch.first_network_ready"
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/lifecycle/data_1.2.1779673506_x86_64.json b/benchmarks/lifecycle/data_1.2.1779673506_x86_64.json
deleted file mode 100644
index ac651495c..000000000
--- a/benchmarks/lifecycle/data_1.2.1779673506_x86_64.json
+++ /dev/null
@@ -1,91 +0,0 @@
-{
- "version": "0.1.0",
- "timestamp": 1780145148.6184819,
- "runs": 3,
- "operations": {
- "provision_ms": {
- "min": 2235.0,
- "mean": 2238.6,
- "max": 2243.4,
- "values": [
- 2235.0,
- 2243.4,
- 2237.4
- ]
- },
- "exec_ready_ms": {
- "min": 23.0,
- "mean": 23.3,
- "max": 23.8,
- "values": [
- 23.0,
- 23.8,
- 23.2
- ]
- },
- "exec_ms": {
- "min": 21.9,
- "mean": 22.6,
- "max": 23.6,
- "values": [
- 21.9,
- 23.6,
- 22.2
- ]
- },
- "delete_ms": {
- "min": 165.0,
- "mean": 165.6,
- "max": 166.3,
- "values": [
- 166.3,
- 165.6,
- 165.0
- ]
- },
- "total_ms": {
- "min": 2446.2,
- "mean": 2450.1,
- "max": 2456.4,
- "values": [
- 2446.2,
- 2456.4,
- 2447.8
- ]
- }
- },
- "schema": "capsem.benchmark-artifact.v1",
- "project_version": "1.2.1779673506",
- "arch": "x86_64",
- "recorded_at": 1780145148.6188924,
- "recorded_at_utc": "2026-05-30T12:45:48.618896+00:00",
- "command": "uv run pytest tests/capsem-serial/test_lifecycle_benchmark.py::test_lifecycle_benchmark -xvs",
- "host": {
- "platform": "Linux",
- "release": "7.0.0-1003-gcp",
- "version": "#3-Ubuntu SMP PREEMPT Mon Apr 13 16:29:20 UTC 2026",
- "machine": "x86_64",
- "processor": "",
- "python_version": "3.14.4",
- "cpu_count": 16,
- "cpu_count_logical": 16,
- "cpu_model": "Intel(R) Xeon(R) CPU @ 2.80GHz",
- "cpu_count_physical": 8,
- "memory_total_bytes": 67415740416,
- "memory_total_gb": 62.79,
- "os_pretty_name": "Ubuntu 26.04 LTS",
- "os_id": "ubuntu",
- "os_version_id": "26.04"
- },
- "git": {
- "commit": "b6f9b6e2342496f7c9c5dadd77548aa8d138678e",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/capsem-bench/data_1.2.1779673506_x86_64.json",
- "benchmarks/host-native/data_1.2.1779673506_x86_64.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_security_packs_microbench.json"
- ]
- }
-}
\ No newline at end of file
diff --git a/benchmarks/lifecycle/data_1.2.1780103109_arm64.json b/benchmarks/lifecycle/data_1.2.1780103109_arm64.json
deleted file mode 100644
index 84a553776..000000000
--- a/benchmarks/lifecycle/data_1.2.1780103109_arm64.json
+++ /dev/null
@@ -1,90 +0,0 @@
-{
- "version": "0.1.0",
- "timestamp": 1780149853.5451891,
- "runs": 3,
- "operations": {
- "provision_ms": {
- "min": 847.4,
- "mean": 849.1,
- "max": 851.9,
- "values": [
- 851.9,
- 847.4,
- 847.9
- ]
- },
- "exec_ready_ms": {
- "min": 12.9,
- "mean": 13.0,
- "max": 13.1,
- "values": [
- 13.1,
- 12.9,
- 12.9
- ]
- },
- "exec_ms": {
- "min": 11.8,
- "mean": 12.0,
- "max": 12.3,
- "values": [
- 11.9,
- 12.3,
- 11.8
- ]
- },
- "delete_ms": {
- "min": 61.2,
- "mean": 61.4,
- "max": 61.7,
- "values": [
- 61.7,
- 61.3,
- 61.2
- ]
- },
- "total_ms": {
- "min": 933.8,
- "mean": 935.4,
- "max": 938.6,
- "values": [
- 938.6,
- 933.9,
- 933.8
- ]
- }
- },
- "schema": "capsem.benchmark-artifact.v1",
- "project_version": "1.2.1780103109",
- "arch": "arm64",
- "recorded_at": 1780149853.5454772,
- "recorded_at_utc": "2026-05-30T14:04:13.545479+00:00",
- "command": "uv run pytest tests/capsem-serial/test_lifecycle_benchmark.py::test_lifecycle_benchmark -xvs",
- "host": {
- "platform": "Darwin",
- "release": "25.5.0",
- "version": "Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:12 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T6050",
- "machine": "arm64",
- "processor": "arm",
- "python_version": "3.14.4",
- "cpu_count": 18,
- "cpu_count_logical": 18,
- "cpu_model": "Apple M5 Max",
- "cpu_count_physical": 18,
- "memory_total_bytes": 137438953472,
- "os_product_version": "26.5",
- "memory_total_gb": 128.0
- },
- "git": {
- "commit": "0a425541fbdc03cc9821aafb238a0dd4b26ccdcd",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/endpoint-latency/data_1.2.1780103109_arm64.json",
- "benchmarks/capsem-bench/data_1.2.1780103109_arm64.json",
- "benchmarks/host-native/data_1.2.1780103109_arm64.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_security_packs_microbench.json"
- ]
- }
-}
\ No newline at end of file
diff --git a/benchmarks/lifecycle/data_1.3.1781050981.json b/benchmarks/lifecycle/data_1.3.1781050981.json
new file mode 100644
index 000000000..7c77cf188
--- /dev/null
+++ b/benchmarks/lifecycle/data_1.3.1781050981.json
@@ -0,0 +1,80 @@
+{
+ "version": "0.2.0",
+ "timestamp": 1781107660.29217,
+ "runs": 3,
+ "operations": {
+ "provision_ms": {
+ "min": 1018.4,
+ "mean": 1053.2,
+ "p50": 1067.1,
+ "p95": 1073.4,
+ "p99": 1074.0,
+ "max": 1074.1,
+ "values": [
+ 1074.1,
+ 1018.4,
+ 1067.1
+ ]
+ },
+ "exec_ready_ms": {
+ "min": 10.3,
+ "mean": 12.6,
+ "p50": 13.4,
+ "p95": 14.1,
+ "p99": 14.2,
+ "max": 14.2,
+ "values": [
+ 14.2,
+ 13.4,
+ 10.3
+ ]
+ },
+ "exec_ms": {
+ "min": 11.9,
+ "mean": 12.3,
+ "p50": 12.3,
+ "p95": 12.8,
+ "p99": 12.8,
+ "max": 12.8,
+ "values": [
+ 11.9,
+ 12.3,
+ 12.8
+ ]
+ },
+ "delete_ms": {
+ "min": 60.0,
+ "mean": 61.5,
+ "p50": 61.7,
+ "p95": 62.7,
+ "p99": 62.8,
+ "max": 62.8,
+ "values": [
+ 61.7,
+ 62.8,
+ 60.0
+ ]
+ },
+ "total_ms": {
+ "min": 1106.9,
+ "mean": 1139.7,
+ "p50": 1150.2,
+ "p95": 1160.7,
+ "p99": 1161.7,
+ "max": 1161.9,
+ "values": [
+ 1161.9,
+ 1106.9,
+ 1150.2
+ ]
+ }
+ },
+ "launch_span_contract": [
+ "capsem.launch.service",
+ "capsem.launch.gateway",
+ "capsem.launch.process_spawn",
+ "capsem.launch.vm_boot",
+ "capsem.launch.vsock_ready",
+ "capsem.launch.first_network_ready"
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/lifecycle/data_1.3.1781124728.json b/benchmarks/lifecycle/data_1.3.1781124728.json
new file mode 100644
index 000000000..8802d051b
--- /dev/null
+++ b/benchmarks/lifecycle/data_1.3.1781124728.json
@@ -0,0 +1,80 @@
+{
+ "version": "0.2.0",
+ "timestamp": 1781205333.248508,
+ "runs": 3,
+ "operations": {
+ "provision_ms": {
+ "min": 1021.8,
+ "mean": 1042.4,
+ "p50": 1027.8,
+ "p95": 1072.6,
+ "p99": 1076.6,
+ "max": 1077.6,
+ "values": [
+ 1027.8,
+ 1021.8,
+ 1077.6
+ ]
+ },
+ "exec_ready_ms": {
+ "min": 12.1,
+ "mean": 12.4,
+ "p50": 12.2,
+ "p95": 12.7,
+ "p99": 12.8,
+ "max": 12.8,
+ "values": [
+ 12.2,
+ 12.8,
+ 12.1
+ ]
+ },
+ "exec_ms": {
+ "min": 10.6,
+ "mean": 11.2,
+ "p50": 11.1,
+ "p95": 11.7,
+ "p99": 11.8,
+ "max": 11.8,
+ "values": [
+ 10.6,
+ 11.1,
+ 11.8
+ ]
+ },
+ "delete_ms": {
+ "min": 59.5,
+ "mean": 61.0,
+ "p50": 60.3,
+ "p95": 62.8,
+ "p99": 63.0,
+ "max": 63.1,
+ "values": [
+ 60.3,
+ 63.1,
+ 59.5
+ ]
+ },
+ "total_ms": {
+ "min": 1108.8,
+ "mean": 1126.9,
+ "p50": 1110.9,
+ "p95": 1156.0,
+ "p99": 1160.0,
+ "max": 1161.0,
+ "values": [
+ 1110.9,
+ 1108.8,
+ 1161.0
+ ]
+ }
+ },
+ "launch_span_contract": [
+ "capsem.launch.service",
+ "capsem.launch.gateway",
+ "capsem.launch.process_spawn",
+ "capsem.launch.vm_boot",
+ "capsem.launch.vsock_ready",
+ "capsem.launch.first_network_ready"
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/lifecycle/data_1.3.1781205836.json b/benchmarks/lifecycle/data_1.3.1781205836.json
new file mode 100644
index 000000000..76b677ab0
--- /dev/null
+++ b/benchmarks/lifecycle/data_1.3.1781205836.json
@@ -0,0 +1,80 @@
+{
+ "version": "0.2.0",
+ "timestamp": 1781633336.178196,
+ "runs": 3,
+ "operations": {
+ "provision_ms": {
+ "min": 1032.6,
+ "mean": 1034.3,
+ "p50": 1034.5,
+ "p95": 1035.8,
+ "p99": 1035.9,
+ "max": 1035.9,
+ "values": [
+ 1032.6,
+ 1034.5,
+ 1035.9
+ ]
+ },
+ "exec_ready_ms": {
+ "min": 12.6,
+ "mean": 12.8,
+ "p50": 12.7,
+ "p95": 13.0,
+ "p99": 13.0,
+ "max": 13.0,
+ "values": [
+ 12.7,
+ 13.0,
+ 12.6
+ ]
+ },
+ "exec_ms": {
+ "min": 10.3,
+ "mean": 11.5,
+ "p50": 11.9,
+ "p95": 12.3,
+ "p99": 12.3,
+ "max": 12.3,
+ "values": [
+ 10.3,
+ 12.3,
+ 11.9
+ ]
+ },
+ "delete_ms": {
+ "min": 59.5,
+ "mean": 60.8,
+ "p50": 61.0,
+ "p95": 61.9,
+ "p99": 62.0,
+ "max": 62.0,
+ "values": [
+ 59.5,
+ 62.0,
+ 61.0
+ ]
+ },
+ "total_ms": {
+ "min": 1115.1,
+ "mean": 1119.4,
+ "p50": 1121.4,
+ "p95": 1121.8,
+ "p99": 1121.8,
+ "max": 1121.8,
+ "values": [
+ 1115.1,
+ 1121.8,
+ 1121.4
+ ]
+ }
+ },
+ "launch_span_contract": [
+ "capsem.launch.service",
+ "capsem.launch.gateway",
+ "capsem.launch.process_spawn",
+ "capsem.launch.vm_boot",
+ "capsem.launch.vsock_ready",
+ "capsem.launch.first_network_ready"
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/lifecycle/data_1.3.1781720230.json b/benchmarks/lifecycle/data_1.3.1781720230.json
new file mode 100644
index 000000000..169276bb0
--- /dev/null
+++ b/benchmarks/lifecycle/data_1.3.1781720230.json
@@ -0,0 +1,80 @@
+{
+ "version": "0.2.0",
+ "timestamp": 1781731207.043808,
+ "runs": 3,
+ "operations": {
+ "provision_ms": {
+ "min": 1083.8,
+ "mean": 1084.7,
+ "p50": 1084.2,
+ "p95": 1085.9,
+ "p99": 1086.1,
+ "max": 1086.1,
+ "values": [
+ 1086.1,
+ 1084.2,
+ 1083.8
+ ]
+ },
+ "exec_ready_ms": {
+ "min": 11.8,
+ "mean": 12.3,
+ "p50": 12.4,
+ "p95": 12.7,
+ "p99": 12.7,
+ "max": 12.7,
+ "values": [
+ 11.8,
+ 12.4,
+ 12.7
+ ]
+ },
+ "exec_ms": {
+ "min": 9.6,
+ "mean": 13.2,
+ "p50": 11.8,
+ "p95": 17.5,
+ "p99": 18.0,
+ "max": 18.1,
+ "values": [
+ 9.6,
+ 18.1,
+ 11.8
+ ]
+ },
+ "delete_ms": {
+ "min": 59.5,
+ "mean": 61.0,
+ "p50": 60.9,
+ "p95": 62.3,
+ "p99": 62.5,
+ "max": 62.5,
+ "values": [
+ 59.5,
+ 60.9,
+ 62.5
+ ]
+ },
+ "total_ms": {
+ "min": 1167.0,
+ "mean": 1171.1,
+ "p50": 1170.8,
+ "p95": 1175.1,
+ "p99": 1175.5,
+ "max": 1175.6,
+ "values": [
+ 1167.0,
+ 1175.6,
+ 1170.8
+ ]
+ }
+ },
+ "launch_span_contract": [
+ "capsem.launch.service",
+ "capsem.launch.gateway",
+ "capsem.launch.process_spawn",
+ "capsem.launch.vm_boot",
+ "capsem.launch.vsock_ready",
+ "capsem.launch.first_network_ready"
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/load_baseline_report.png b/benchmarks/load_baseline_report.png
new file mode 100644
index 000000000..737c2a319
Binary files /dev/null and b/benchmarks/load_baseline_report.png differ
diff --git a/benchmarks/mock-server-protocol/control_host_direct_1.0.1780763638_arm64.json b/benchmarks/mock-server-protocol/control_host_direct_1.0.1780763638_arm64.json
new file mode 100644
index 000000000..17d1e0630
--- /dev/null
+++ b/benchmarks/mock-server-protocol/control_host_direct_1.0.1780763638_arm64.json
@@ -0,0 +1,191 @@
+{
+ "version": "0.3.0",
+ "timestamp": 1780770405.9584372,
+ "hostname": "Saphyr.local",
+ "mock_server_protocol": {
+ "version": "1.0",
+ "base_url": "http://127.0.0.1:50233",
+ "total_requests": 20,
+ "concurrency": 1,
+ "timeout_s": 30.0,
+ "scenarios": [
+ {
+ "name": "tiny_http",
+ "path": "/tiny",
+ "body_kind": "tiny",
+ "total_requests": 20,
+ "concurrency": 1,
+ "successful": 20,
+ "failed": 0,
+ "total_duration_ms": 11.8,
+ "requests_per_sec": 1693.0,
+ "transfer_bytes": 540,
+ "bytes_per_sec": 45710.1,
+ "latency_ms": {
+ "min": 0.3,
+ "max": 4.2,
+ "mean": 0.6,
+ "p50": 0.4,
+ "p95": 0.7,
+ "p99": 3.5
+ },
+ "errors": {}
+ },
+ {
+ "name": "http_1mb",
+ "path": "/bytes/1mb",
+ "body_kind": "1mb",
+ "total_requests": 20,
+ "concurrency": 1,
+ "successful": 20,
+ "failed": 0,
+ "total_duration_ms": 204.9,
+ "requests_per_sec": 97.6,
+ "transfer_bytes": 20971520,
+ "bytes_per_sec": 102366344.6,
+ "latency_ms": {
+ "min": 9.7,
+ "max": 10.7,
+ "mean": 10.2,
+ "p50": 10.2,
+ "p95": 10.7,
+ "p99": 10.7
+ },
+ "errors": {}
+ },
+ {
+ "name": "gzip_1mb",
+ "path": "/gzip/1mb",
+ "body_kind": "gzip",
+ "total_requests": 20,
+ "concurrency": 1,
+ "successful": 20,
+ "failed": 0,
+ "total_duration_ms": 415.6,
+ "requests_per_sec": 48.1,
+ "transfer_bytes": 20971520,
+ "bytes_per_sec": 50460043.5,
+ "latency_ms": {
+ "min": 20.4,
+ "max": 21.4,
+ "mean": 20.8,
+ "p50": 20.7,
+ "p95": 21.3,
+ "p99": 21.4
+ },
+ "errors": {}
+ },
+ {
+ "name": "sse_model",
+ "path": "/sse/model",
+ "body_kind": "sse",
+ "total_requests": 20,
+ "concurrency": 1,
+ "successful": 20,
+ "failed": 0,
+ "total_duration_ms": 8.1,
+ "requests_per_sec": 2467.8,
+ "transfer_bytes": 4780,
+ "bytes_per_sec": 589798.8,
+ "latency_ms": {
+ "min": 0.3,
+ "max": 0.9,
+ "mean": 0.4,
+ "p50": 0.3,
+ "p95": 0.5,
+ "p99": 0.8
+ },
+ "errors": {}
+ },
+ {
+ "name": "denied_target",
+ "path": "/deny-target",
+ "body_kind": "tiny",
+ "total_requests": 20,
+ "concurrency": 1,
+ "successful": 20,
+ "failed": 0,
+ "total_duration_ms": 7.0,
+ "requests_per_sec": 2863.4,
+ "transfer_bytes": 680,
+ "bytes_per_sec": 97356.1,
+ "latency_ms": {
+ "min": 0.3,
+ "max": 0.5,
+ "mean": 0.3,
+ "p50": 0.3,
+ "p95": 0.4,
+ "p99": 0.5
+ },
+ "errors": {}
+ },
+ {
+ "name": "credential_response",
+ "path": "/credential/response",
+ "body_kind": "credential",
+ "total_requests": 20,
+ "concurrency": 1,
+ "successful": 20,
+ "failed": 0,
+ "total_duration_ms": 7.0,
+ "requests_per_sec": 2871.3,
+ "transfer_bytes": 4720,
+ "bytes_per_sec": 677633.5,
+ "latency_ms": {
+ "min": 0.3,
+ "max": 0.7,
+ "mean": 0.3,
+ "p50": 0.3,
+ "p95": 0.4,
+ "p99": 0.6
+ },
+ "errors": {},
+ "secret_shaped_fixture_seen": true,
+ "raw_secret_stored_in_result": false
+ }
+ ],
+ "websocket": [
+ {
+ "name": "websocket_echo",
+ "path": "/ws/echo",
+ "skipped": false,
+ "frames": 10,
+ "failed": false,
+ "duration_ms": 1.9,
+ "frames_per_sec": 5161.8,
+ "latency_ms": {
+ "min": 0.1,
+ "max": 0.1,
+ "mean": 0.1,
+ "p50": 0.1,
+ "p95": 0.1,
+ "p99": 0.1
+ }
+ },
+ {
+ "name": "websocket_close",
+ "path": "/ws/close",
+ "skipped": false,
+ "frames": 1,
+ "failed": false,
+ "duration_ms": 0.6,
+ "frames_per_sec": 1596.5,
+ "latency_ms": {
+ "min": 0.6,
+ "max": 0.6,
+ "mean": 0.6,
+ "p50": 0.6,
+ "p95": 0.6,
+ "p99": 0.6
+ }
+ }
+ ]
+ },
+ "run_context": {
+ "kind": "host_direct_control",
+ "note": "Direct host-to-mock-server control baseline; not through VM/MITM.",
+ "command": "PYTHONPATH=guest/artifacts uv run --with rich --with requests python -m capsem_bench mock-server-protocol http://127.0.0.1:50233 20 1",
+ "arch": "arm64",
+ "archived_at_unix": 1780770446.31937
+ }
+}
diff --git a/benchmarks/mock-server-protocol/control_host_direct_c64_model_credential_1.0.1780954707_arm64.json b/benchmarks/mock-server-protocol/control_host_direct_c64_model_credential_1.0.1780954707_arm64.json
new file mode 100644
index 000000000..d74a78c64
--- /dev/null
+++ b/benchmarks/mock-server-protocol/control_host_direct_c64_model_credential_1.0.1780954707_arm64.json
@@ -0,0 +1,100 @@
+{
+ "version": "0.3.0",
+ "timestamp": 1780973597.878732,
+ "hostname": "Saphyr.localdomain",
+ "mock_server_protocol": {
+ "version": "1.0",
+ "base_url": "http://127.0.0.1:61416",
+ "total_requests": 50000,
+ "concurrency": 64,
+ "timeout_s": 30.0,
+ "selected_scenarios": [
+ "model_json_response",
+ "credential_response"
+ ],
+ "scenarios": [
+ {
+ "name": "model_json_response",
+ "path": "/model/response",
+ "body_kind": "model_json",
+ "total_requests": 50000,
+ "concurrency": 64,
+ "successful": 50000,
+ "failed": 0,
+ "total_duration_ms": 11569.1,
+ "requests_per_sec": 4321.8,
+ "transfer_bytes": 20900000,
+ "bytes_per_sec": 1806530.2,
+ "latency_ms": {
+ "min": 0.3,
+ "max": 49.3,
+ "mean": 14.7,
+ "p50": 13.9,
+ "p95": 25.0,
+ "p99": 30.7
+ },
+ "errors": {}
+ },
+ {
+ "name": "credential_response",
+ "path": "/credential/response",
+ "body_kind": "credential",
+ "total_requests": 50000,
+ "concurrency": 64,
+ "successful": 50000,
+ "failed": 0,
+ "total_duration_ms": 11463.2,
+ "requests_per_sec": 4361.8,
+ "transfer_bytes": 11800000,
+ "bytes_per_sec": 1029377.7,
+ "latency_ms": {
+ "min": 0.3,
+ "max": 53.8,
+ "mean": 14.5,
+ "p50": 13.8,
+ "p95": 24.6,
+ "p99": 30.2
+ },
+ "errors": {},
+ "secret_shaped_fixture_seen": true,
+ "raw_secret_stored_in_result": false
+ }
+ ],
+ "websocket": [
+ {
+ "name": "websocket_echo",
+ "path": "/ws/echo",
+ "skipped": false,
+ "frames": 10,
+ "failed": false,
+ "duration_ms": 1.7,
+ "frames_per_sec": 5722.1,
+ "latency_ms": {
+ "min": 0.1,
+ "max": 0.1,
+ "mean": 0.1,
+ "p50": 0.1,
+ "p95": 0.1,
+ "p99": 0.1
+ }
+ },
+ {
+ "name": "websocket_close",
+ "path": "/ws/close",
+ "skipped": false,
+ "frames": 1,
+ "failed": false,
+ "duration_ms": 0.5,
+ "frames_per_sec": 2084.6,
+ "latency_ms": {
+ "min": 0.4,
+ "max": 0.4,
+ "mean": 0.4,
+ "p50": 0.4,
+ "p95": 0.4,
+ "p99": 0.4
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/mock-server-protocol/data_1.0.1780763638_arm64.json b/benchmarks/mock-server-protocol/data_1.0.1780763638_arm64.json
new file mode 100644
index 000000000..07e1b4fca
--- /dev/null
+++ b/benchmarks/mock-server-protocol/data_1.0.1780763638_arm64.json
@@ -0,0 +1,187 @@
+{
+ "version": "0.3.0",
+ "timestamp": 1780771050.111751,
+ "hostname": "mock-server-protocol-9399fad7",
+ "mock_server_protocol": {
+ "version": "1.0",
+ "base_url": "http://127.0.0.1:50233",
+ "total_requests": 10,
+ "concurrency": 1,
+ "timeout_s": 30.0,
+ "scenarios": [
+ {
+ "name": "tiny_http",
+ "path": "/tiny",
+ "body_kind": "tiny",
+ "total_requests": 10,
+ "concurrency": 1,
+ "successful": 10,
+ "failed": 0,
+ "total_duration_ms": 16.6,
+ "requests_per_sec": 602.9,
+ "transfer_bytes": 270,
+ "bytes_per_sec": 16278.9,
+ "latency_ms": {
+ "min": 1.0,
+ "max": 4.2,
+ "mean": 1.6,
+ "p50": 1.3,
+ "p95": 3.1,
+ "p99": 4.0
+ },
+ "errors": {}
+ },
+ {
+ "name": "http_1mb",
+ "path": "/bytes/1mb",
+ "body_kind": "1mb",
+ "total_requests": 10,
+ "concurrency": 1,
+ "successful": 10,
+ "failed": 0,
+ "total_duration_ms": 138.6,
+ "requests_per_sec": 72.1,
+ "transfer_bytes": 10485760,
+ "bytes_per_sec": 75638030.5,
+ "latency_ms": {
+ "min": 13.2,
+ "max": 15.0,
+ "mean": 13.8,
+ "p50": 13.7,
+ "p95": 14.7,
+ "p99": 15.0
+ },
+ "errors": {}
+ },
+ {
+ "name": "gzip_1mb",
+ "path": "/gzip/1mb",
+ "body_kind": "gzip",
+ "total_requests": 10,
+ "concurrency": 1,
+ "successful": 10,
+ "failed": 0,
+ "total_duration_ms": 335.3,
+ "requests_per_sec": 29.8,
+ "transfer_bytes": 10485760,
+ "bytes_per_sec": 31272918.3,
+ "latency_ms": {
+ "min": 33.0,
+ "max": 34.8,
+ "mean": 33.5,
+ "p50": 33.3,
+ "p95": 34.5,
+ "p99": 34.7
+ },
+ "errors": {}
+ },
+ {
+ "name": "sse_model",
+ "path": "/sse/model",
+ "body_kind": "sse",
+ "total_requests": 10,
+ "concurrency": 1,
+ "successful": 10,
+ "failed": 0,
+ "total_duration_ms": 14.6,
+ "requests_per_sec": 683.1,
+ "transfer_bytes": 2390,
+ "bytes_per_sec": 163250.9,
+ "latency_ms": {
+ "min": 1.1,
+ "max": 2.6,
+ "mean": 1.4,
+ "p50": 1.3,
+ "p95": 2.1,
+ "p99": 2.5
+ },
+ "errors": {}
+ },
+ {
+ "name": "denied_target",
+ "path": "/deny-target",
+ "body_kind": "tiny",
+ "total_requests": 10,
+ "concurrency": 1,
+ "successful": 10,
+ "failed": 0,
+ "total_duration_ms": 12.5,
+ "requests_per_sec": 799.8,
+ "transfer_bytes": 340,
+ "bytes_per_sec": 27193.4,
+ "latency_ms": {
+ "min": 1.0,
+ "max": 2.2,
+ "mean": 1.2,
+ "p50": 1.1,
+ "p95": 1.8,
+ "p99": 2.1
+ },
+ "errors": {}
+ },
+ {
+ "name": "credential_response",
+ "path": "/credential/response",
+ "body_kind": "credential",
+ "total_requests": 10,
+ "concurrency": 1,
+ "successful": 10,
+ "failed": 0,
+ "total_duration_ms": 12.0,
+ "requests_per_sec": 833.2,
+ "transfer_bytes": 2360,
+ "bytes_per_sec": 196631.2,
+ "latency_ms": {
+ "min": 0.9,
+ "max": 2.1,
+ "mean": 1.2,
+ "p50": 1.1,
+ "p95": 1.7,
+ "p99": 2.0
+ },
+ "errors": {},
+ "secret_shaped_fixture_seen": true,
+ "raw_secret_stored_in_result": false
+ }
+ ],
+ "websocket": [
+ {
+ "name": "websocket_echo",
+ "path": "/ws/echo",
+ "skipped": false,
+ "frames": 10,
+ "failed": false,
+ "duration_ms": 3.8,
+ "frames_per_sec": 2656.0,
+ "latency_ms": {
+ "min": 0.1,
+ "max": 0.2,
+ "mean": 0.2,
+ "p50": 0.2,
+ "p95": 0.2,
+ "p99": 0.2
+ }
+ },
+ {
+ "name": "websocket_close",
+ "path": "/ws/close",
+ "skipped": false,
+ "frames": 1,
+ "failed": false,
+ "duration_ms": 1.8,
+ "frames_per_sec": 556.1,
+ "latency_ms": {
+ "min": 1.7,
+ "max": 1.7,
+ "mean": 1.7,
+ "p50": 1.7,
+ "p95": 1.7,
+ "p99": 1.7
+ }
+ }
+ ]
+ },
+ "host_recorded_at": 1780771051.390916,
+ "arch": "arm64",
+ "debug_upstream_base_url": "http://127.0.0.1:50233"
+}
\ No newline at end of file
diff --git a/benchmarks/mock-server-protocol/data_1.0.1780954707_arm64.json b/benchmarks/mock-server-protocol/data_1.0.1780954707_arm64.json
new file mode 100644
index 000000000..2d5612aa0
--- /dev/null
+++ b/benchmarks/mock-server-protocol/data_1.0.1780954707_arm64.json
@@ -0,0 +1,218 @@
+{
+ "version": "0.3.0",
+ "timestamp": 1780974390.0724423,
+ "hostname": "mock-server-protocol-dd0b9f4e",
+ "mock_server_protocol": {
+ "version": "1.0",
+ "base_url": "http://127.0.0.1:3713",
+ "total_requests": 10,
+ "concurrency": 1,
+ "timeout_s": 30.0,
+ "selected_scenarios": [
+ "tiny_http",
+ "http_1mb",
+ "gzip_1mb",
+ "sse_model",
+ "model_json_response",
+ "denied_target",
+ "credential_response"
+ ],
+ "scenarios": [
+ {
+ "name": "tiny_http",
+ "path": "/tiny",
+ "body_kind": "tiny",
+ "total_requests": 10,
+ "concurrency": 1,
+ "successful": 10,
+ "failed": 0,
+ "total_duration_ms": 12.0,
+ "requests_per_sec": 831.7,
+ "transfer_bytes": 270,
+ "bytes_per_sec": 22454.7,
+ "latency_ms": {
+ "min": 0.8,
+ "max": 3.6,
+ "mean": 1.2,
+ "p50": 0.9,
+ "p95": 2.4,
+ "p99": 3.4
+ },
+ "errors": {}
+ },
+ {
+ "name": "http_1mb",
+ "path": "/bytes/1mb",
+ "body_kind": "1mb",
+ "total_requests": 10,
+ "concurrency": 1,
+ "successful": 10,
+ "failed": 0,
+ "total_duration_ms": 119.5,
+ "requests_per_sec": 83.7,
+ "transfer_bytes": 10485760,
+ "bytes_per_sec": 87756003.2,
+ "latency_ms": {
+ "min": 11.6,
+ "max": 13.3,
+ "mean": 11.9,
+ "p50": 11.7,
+ "p95": 12.7,
+ "p99": 13.2
+ },
+ "errors": {}
+ },
+ {
+ "name": "gzip_1mb",
+ "path": "/gzip/1mb",
+ "body_kind": "gzip",
+ "total_requests": 10,
+ "concurrency": 1,
+ "successful": 10,
+ "failed": 0,
+ "total_duration_ms": 261.9,
+ "requests_per_sec": 38.2,
+ "transfer_bytes": 10485760,
+ "bytes_per_sec": 40037565.5,
+ "latency_ms": {
+ "min": 25.8,
+ "max": 27.1,
+ "mean": 26.2,
+ "p50": 26.1,
+ "p95": 26.8,
+ "p99": 27.1
+ },
+ "errors": {}
+ },
+ {
+ "name": "sse_model",
+ "path": "/sse/model",
+ "body_kind": "sse",
+ "total_requests": 10,
+ "concurrency": 1,
+ "successful": 10,
+ "failed": 0,
+ "total_duration_ms": 10.1,
+ "requests_per_sec": 986.2,
+ "transfer_bytes": 2390,
+ "bytes_per_sec": 235704.1,
+ "latency_ms": {
+ "min": 0.9,
+ "max": 1.9,
+ "mean": 1.0,
+ "p50": 0.9,
+ "p95": 1.5,
+ "p99": 1.8
+ },
+ "errors": {}
+ },
+ {
+ "name": "model_json_response",
+ "path": "/model/response",
+ "body_kind": "model_json",
+ "total_requests": 10,
+ "concurrency": 1,
+ "successful": 10,
+ "failed": 0,
+ "total_duration_ms": 9.1,
+ "requests_per_sec": 1102.8,
+ "transfer_bytes": 4180,
+ "bytes_per_sec": 460985.0,
+ "latency_ms": {
+ "min": 0.8,
+ "max": 1.7,
+ "mean": 0.9,
+ "p50": 0.8,
+ "p95": 1.3,
+ "p99": 1.6
+ },
+ "errors": {}
+ },
+ {
+ "name": "denied_target",
+ "path": "/deny-target",
+ "body_kind": "tiny",
+ "total_requests": 10,
+ "concurrency": 1,
+ "successful": 10,
+ "failed": 0,
+ "total_duration_ms": 8.6,
+ "requests_per_sec": 1165.8,
+ "transfer_bytes": 340,
+ "bytes_per_sec": 39635.7,
+ "latency_ms": {
+ "min": 0.7,
+ "max": 1.5,
+ "mean": 0.8,
+ "p50": 0.8,
+ "p95": 1.2,
+ "p99": 1.5
+ },
+ "errors": {}
+ },
+ {
+ "name": "credential_response",
+ "path": "/credential/response",
+ "body_kind": "credential",
+ "total_requests": 10,
+ "concurrency": 1,
+ "successful": 10,
+ "failed": 0,
+ "total_duration_ms": 8.9,
+ "requests_per_sec": 1129.8,
+ "transfer_bytes": 2360,
+ "bytes_per_sec": 266621.5,
+ "latency_ms": {
+ "min": 0.8,
+ "max": 1.6,
+ "mean": 0.9,
+ "p50": 0.8,
+ "p95": 1.2,
+ "p99": 1.5
+ },
+ "errors": {},
+ "secret_shaped_fixture_seen": true,
+ "raw_secret_stored_in_result": false
+ }
+ ],
+ "websocket": [
+ {
+ "name": "websocket_echo",
+ "path": "/ws/echo",
+ "skipped": false,
+ "frames": 10,
+ "failed": false,
+ "duration_ms": 4.0,
+ "frames_per_sec": 2499.5,
+ "latency_ms": {
+ "min": 0.2,
+ "max": 0.2,
+ "mean": 0.2,
+ "p50": 0.2,
+ "p95": 0.2,
+ "p99": 0.2
+ }
+ },
+ {
+ "name": "websocket_close",
+ "path": "/ws/close",
+ "skipped": false,
+ "frames": 1,
+ "failed": false,
+ "duration_ms": 1.4,
+ "frames_per_sec": 727.8,
+ "latency_ms": {
+ "min": 1.3,
+ "max": 1.3,
+ "mean": 1.3,
+ "p50": 1.3,
+ "p95": 1.3,
+ "p99": 1.3
+ }
+ }
+ ]
+ },
+ "host_recorded_at": 1780974391.50797,
+ "arch": "arm64",
+ "debug_upstream_base_url": "http://127.0.0.1:3713"
+}
\ No newline at end of file
diff --git a/benchmarks/mock-server-protocol/data_1.0.1780977620_arm64.json b/benchmarks/mock-server-protocol/data_1.0.1780977620_arm64.json
new file mode 100644
index 000000000..c27116c27
--- /dev/null
+++ b/benchmarks/mock-server-protocol/data_1.0.1780977620_arm64.json
@@ -0,0 +1,218 @@
+{
+ "version": "0.3.0",
+ "timestamp": 1781017070.0901988,
+ "hostname": "mock-server-protocol-166cc9a8",
+ "mock_server_protocol": {
+ "version": "1.0",
+ "base_url": "http://127.0.0.1:3713",
+ "total_requests": 50000,
+ "concurrency": 64,
+ "timeout_s": 30.0,
+ "selected_scenarios": [
+ "tiny_http",
+ "http_1mb",
+ "gzip_1mb",
+ "sse_model",
+ "model_json_response",
+ "denied_target",
+ "credential_response"
+ ],
+ "scenarios": [
+ {
+ "name": "tiny_http",
+ "path": "/tiny",
+ "body_kind": "tiny",
+ "total_requests": 50000,
+ "concurrency": 64,
+ "successful": 50000,
+ "failed": 0,
+ "total_duration_ms": 15214.2,
+ "requests_per_sec": 3286.4,
+ "transfer_bytes": 1350000,
+ "bytes_per_sec": 88732.8,
+ "latency_ms": {
+ "min": 0.7,
+ "max": 96.6,
+ "mean": 19.2,
+ "p50": 17.1,
+ "p95": 40.7,
+ "p99": 55.0
+ },
+ "errors": {}
+ },
+ {
+ "name": "http_1mb",
+ "path": "/bytes/1mb",
+ "body_kind": "1mb",
+ "total_requests": 50000,
+ "concurrency": 64,
+ "successful": 50000,
+ "failed": 0,
+ "total_duration_ms": 105006.4,
+ "requests_per_sec": 476.2,
+ "transfer_bytes": 52428800000,
+ "bytes_per_sec": 499291616.0,
+ "latency_ms": {
+ "min": 11.6,
+ "max": 344.1,
+ "mean": 133.1,
+ "p50": 139.1,
+ "p95": 220.7,
+ "p99": 251.0
+ },
+ "errors": {}
+ },
+ {
+ "name": "gzip_1mb",
+ "path": "/gzip/1mb",
+ "body_kind": "gzip",
+ "total_requests": 50000,
+ "concurrency": 64,
+ "successful": 50000,
+ "failed": 0,
+ "total_duration_ms": 100315.8,
+ "requests_per_sec": 498.4,
+ "transfer_bytes": 52428800000,
+ "bytes_per_sec": 522637273.5,
+ "latency_ms": {
+ "min": 27.1,
+ "max": 450.4,
+ "mean": 127.3,
+ "p50": 126.5,
+ "p95": 184.1,
+ "p99": 210.1
+ },
+ "errors": {}
+ },
+ {
+ "name": "sse_model",
+ "path": "/sse/model",
+ "body_kind": "sse",
+ "total_requests": 50000,
+ "concurrency": 64,
+ "successful": 50000,
+ "failed": 0,
+ "total_duration_ms": 15856.4,
+ "requests_per_sec": 3153.3,
+ "transfer_bytes": 11950000,
+ "bytes_per_sec": 753637.5,
+ "latency_ms": {
+ "min": 0.8,
+ "max": 93.4,
+ "mean": 19.9,
+ "p50": 18.0,
+ "p95": 40.2,
+ "p99": 52.5
+ },
+ "errors": {}
+ },
+ {
+ "name": "model_json_response",
+ "path": "/model/response",
+ "body_kind": "model_json",
+ "total_requests": 50000,
+ "concurrency": 64,
+ "successful": 50000,
+ "failed": 0,
+ "total_duration_ms": 15261.9,
+ "requests_per_sec": 3276.1,
+ "transfer_bytes": 20900000,
+ "bytes_per_sec": 1369420.9,
+ "latency_ms": {
+ "min": 0.7,
+ "max": 109.3,
+ "mean": 19.2,
+ "p50": 17.3,
+ "p95": 39.4,
+ "p99": 52.2
+ },
+ "errors": {}
+ },
+ {
+ "name": "denied_target",
+ "path": "/deny-target",
+ "body_kind": "tiny",
+ "total_requests": 50000,
+ "concurrency": 64,
+ "successful": 50000,
+ "failed": 0,
+ "total_duration_ms": 15137.9,
+ "requests_per_sec": 3303.0,
+ "transfer_bytes": 1700000,
+ "bytes_per_sec": 112300.8,
+ "latency_ms": {
+ "min": 0.7,
+ "max": 97.0,
+ "mean": 19.0,
+ "p50": 17.1,
+ "p95": 39.0,
+ "p99": 52.0
+ },
+ "errors": {}
+ },
+ {
+ "name": "credential_response",
+ "path": "/credential/response",
+ "body_kind": "credential",
+ "total_requests": 50000,
+ "concurrency": 64,
+ "successful": 50000,
+ "failed": 0,
+ "total_duration_ms": 15357.1,
+ "requests_per_sec": 3255.8,
+ "transfer_bytes": 11800000,
+ "bytes_per_sec": 768373.0,
+ "latency_ms": {
+ "min": 0.7,
+ "max": 95.7,
+ "mean": 19.3,
+ "p50": 17.3,
+ "p95": 39.4,
+ "p99": 52.4
+ },
+ "errors": {},
+ "secret_shaped_fixture_seen": true,
+ "raw_secret_stored_in_result": false
+ }
+ ],
+ "websocket": [
+ {
+ "name": "websocket_echo",
+ "path": "/ws/echo",
+ "skipped": false,
+ "frames": 10,
+ "failed": false,
+ "duration_ms": 4.0,
+ "frames_per_sec": 2477.8,
+ "latency_ms": {
+ "min": 0.1,
+ "max": 0.2,
+ "mean": 0.2,
+ "p50": 0.2,
+ "p95": 0.2,
+ "p99": 0.2
+ }
+ },
+ {
+ "name": "websocket_close",
+ "path": "/ws/close",
+ "skipped": false,
+ "frames": 1,
+ "failed": false,
+ "duration_ms": 1.5,
+ "frames_per_sec": 674.3,
+ "latency_ms": {
+ "min": 1.4,
+ "max": 1.4,
+ "mean": 1.4,
+ "p50": 1.4,
+ "p95": 1.4,
+ "p99": 1.4
+ }
+ }
+ ]
+ },
+ "host_recorded_at": 1781017353.4056761,
+ "arch": "arm64",
+ "debug_upstream_base_url": "http://127.0.0.1:3713"
+}
\ No newline at end of file
diff --git a/benchmarks/mock-server-protocol/data_1.3.1781205836_arm64.json b/benchmarks/mock-server-protocol/data_1.3.1781205836_arm64.json
new file mode 100644
index 000000000..860e23c4f
--- /dev/null
+++ b/benchmarks/mock-server-protocol/data_1.3.1781205836_arm64.json
@@ -0,0 +1,103 @@
+{
+ "version": "0.3.0",
+ "timestamp": 1781364242.2236643,
+ "hostname": "mock-server-protocol-ff029701",
+ "mock_server_protocol": {
+ "version": "1.0",
+ "base_url": "http://127.0.0.1:3713",
+ "total_requests": 50000,
+ "concurrency": 64,
+ "timeout_s": 30.0,
+ "selected_scenarios": [
+ "model_json_response",
+ "credential_response"
+ ],
+ "scenarios": [
+ {
+ "name": "model_json_response",
+ "path": "/model/response",
+ "body_kind": "model_json",
+ "total_requests": 50000,
+ "concurrency": 64,
+ "successful": 50000,
+ "failed": 0,
+ "total_duration_ms": 20589.0,
+ "requests_per_sec": 2428.5,
+ "transfer_bytes": 22700000,
+ "bytes_per_sec": 1102530.6,
+ "latency_ms": {
+ "min": 0.7,
+ "max": 147.7,
+ "mean": 25.9,
+ "p50": 23.2,
+ "p95": 53.3,
+ "p99": 70.6
+ },
+ "errors": {}
+ },
+ {
+ "name": "credential_response",
+ "path": "/credential/response",
+ "body_kind": "credential",
+ "total_requests": 50000,
+ "concurrency": 64,
+ "successful": 50000,
+ "failed": 0,
+ "total_duration_ms": 37351.2,
+ "requests_per_sec": 1338.6,
+ "transfer_bytes": 11950000,
+ "bytes_per_sec": 319936.1,
+ "latency_ms": {
+ "min": 0.9,
+ "max": 271.1,
+ "mean": 47.3,
+ "p50": 40.1,
+ "p95": 102.3,
+ "p99": 137.3
+ },
+ "errors": {},
+ "secret_shaped_fixture_seen": true,
+ "raw_secret_stored_in_result": false
+ }
+ ],
+ "websocket": [
+ {
+ "name": "websocket_echo",
+ "path": "/ws/echo",
+ "skipped": false,
+ "frames": 10,
+ "failed": false,
+ "duration_ms": 20.0,
+ "frames_per_sec": 499.0,
+ "latency_ms": {
+ "min": 0.2,
+ "max": 0.8,
+ "mean": 0.2,
+ "p50": 0.2,
+ "p95": 0.5,
+ "p99": 0.7
+ }
+ },
+ {
+ "name": "websocket_close",
+ "path": "/ws/close",
+ "skipped": false,
+ "frames": 1,
+ "failed": false,
+ "duration_ms": 2.1,
+ "frames_per_sec": 475.6,
+ "latency_ms": {
+ "min": 2.1,
+ "max": 2.1,
+ "mean": 2.1,
+ "p50": 2.1,
+ "p95": 2.1,
+ "p99": 2.1
+ }
+ }
+ ]
+ },
+ "host_recorded_at": 1781364310.028512,
+ "arch": "arm64",
+ "mock_server_base_url": "http://127.0.0.1:3713"
+}
\ No newline at end of file
diff --git a/benchmarks/parallel/data_1.0.1776445634.json b/benchmarks/parallel/data_1.0.1776445634.json
new file mode 100644
index 000000000..1525eb109
--- /dev/null
+++ b/benchmarks/parallel/data_1.0.1776445634.json
@@ -0,0 +1,32 @@
+{
+ "version": "1.0",
+ "timestamp": 1776683808.151938,
+ "num_vms": 4,
+ "total_duration_ms": 105611.9264169829,
+ "results": [
+ {
+ "vm": "par-bench-f844ab-0",
+ "status": "success",
+ "duration_ms": 80213.33520801272,
+ "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 703.8 MB/s \u2502 - \u2502 363.8 ms \u2502\n\u2502 Seq read (1MB) \u2502 2644.2 MB/s \u2502 - \u2502 96.8 ms \u2502\n\u2502 Rand write (4K) \u2502 20.0 MB/s \u2502 5112 \u2502 1956.1 ms \u2502\n\u2502 Rand read (4K) \u2502 120.4 MB/s \u2502 30814 \u2502 324.5 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 codex (133.7 MB) \u2502 487.0 MB/s \u2502 - \u2502 274.5 ms \u2502\n\u2502 Rand read (4K) \u2502 2585 files \u2502 17.7 MB/s \u2502 4524 \u2502 1105.2 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 8.0 \u2502 9.1 \u2502 10.7 \u2502\n\u2502 node \u2502 126.1 \u2502 130.4 \u2502 134.3 \u2502\n\u2502 claude \u2502 343.4 \u2502 375.5 \u2502 394.7 \u2502\n\u2502 gemini \u2502 652.5 \u2502 653.2 \u2502 653.6 \u2502\n\u2502 codex \u2502 284.8 \u2502 302.2 \u2502 336.9 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 50/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 23.8 \u2502\n\u2502 Transfer \u2502 1.8 MB \u2502\n\u2502 Duration \u2502 2098.5 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 171.2 ms \u2502\n\u2502 Latency mean \u2502 205.2 ms \u2502\n\u2502 Latency p50 \u2502 183.9 ms \u2502\n\u2502 Latency p95 \u2502 306.5 ms \u2502\n\u2502 Latency p99 \u2502 323.9 ms \u2502\n\u2502 Latency max \u2502 328.0 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://ash-speed.hetzner.com/100MB.bin] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://ash-speed.hetzner.com/100MB.bin \u2502\n\u2502 Downloaded \u2502 100.0 MB \u2502\n\u2502 Duration \u2502 61.76s \u2502\n\u2502 Throughput \u2502 1.62 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 885.1 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 382.4 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 370.6 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 364.5 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 378.3 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 386.4 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 391.2 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 386.1 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 399.1 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 396.7 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 416.6 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 390.5 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 420.6 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 382.7 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 410.7 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
+ },
+ {
+ "vm": "par-bench-02ba37-1",
+ "status": "success",
+ "duration_ms": 67084.03891703347,
+ "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 695.2 MB/s \u2502 - \u2502 368.2 ms \u2502\n\u2502 Seq read (1MB) \u2502 2588.0 MB/s \u2502 - \u2502 98.9 ms \u2502\n\u2502 Rand write (4K) \u2502 17.9 MB/s \u2502 4570 \u2502 2187.9 ms \u2502\n\u2502 Rand read (4K) \u2502 115.8 MB/s \u2502 29654 \u2502 337.2 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 codex (133.7 MB) \u2502 475.6 MB/s \u2502 - \u2502 281.1 ms \u2502\n\u2502 Rand read (4K) \u2502 2556 files \u2502 17.5 MB/s \u2502 4469 \u2502 1118.9 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 7.1 \u2502 7.4 \u2502 7.7 \u2502\n\u2502 node \u2502 130.2 \u2502 133.3 \u2502 138.3 \u2502\n\u2502 claude \u2502 343.7 \u2502 375.5 \u2502 392.5 \u2502\n\u2502 gemini \u2502 653.4 \u2502 656.9 \u2502 661.3 \u2502\n\u2502 codex \u2502 285.1 \u2502 303.4 \u2502 332.6 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 50/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 24.0 \u2502\n\u2502 Transfer \u2502 1.8 MB \u2502\n\u2502 Duration \u2502 2079.5 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 173.4 ms \u2502\n\u2502 Latency mean \u2502 205.6 ms \u2502\n\u2502 Latency p50 \u2502 182.5 ms \u2502\n\u2502 Latency p95 \u2502 292.9 ms \u2502\n\u2502 Latency p99 \u2502 301.1 ms \u2502\n\u2502 Latency max \u2502 306.8 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://ash-speed.hetzner.com/100MB.bin] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://ash-speed.hetzner.com/100MB.bin \u2502\n\u2502 Downloaded \u2502 100.0 MB \u2502\n\u2502 Duration \u2502 48.61s \u2502\n\u2502 Throughput \u2502 2.06 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 930.2 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 370.8 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 380.5 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 375.3 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 372.2 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 377.9 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 363.5 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 365.9 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 369.5 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 391.4 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 445.0 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 425.0 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 413.8 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 366.6 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 399.9 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
+ },
+ {
+ "vm": "par-bench-7335dd-2",
+ "status": "success",
+ "duration_ms": 99624.9816250056,
+ "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 733.6 MB/s \u2502 - \u2502 349.0 ms \u2502\n\u2502 Seq read (1MB) \u2502 3169.5 MB/s \u2502 - \u2502 80.8 ms \u2502\n\u2502 Rand write (4K) \u2502 23.9 MB/s \u2502 6114 \u2502 1635.6 ms \u2502\n\u2502 Rand read (4K) \u2502 230.1 MB/s \u2502 58900 \u2502 169.8 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 codex (133.7 MB) \u2502 589.0 MB/s \u2502 - \u2502 227.0 ms \u2502\n\u2502 Rand read (4K) \u2502 2559 files \u2502 23.8 MB/s \u2502 6105 \u2502 818.9 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 8.1 \u2502 10.2 \u2502 11.9 \u2502\n\u2502 node \u2502 138.4 \u2502 173.5 \u2502 191.8 \u2502\n\u2502 claude \u2502 388.1 \u2502 410.2 \u2502 450.5 \u2502\n\u2502 gemini \u2502 648.9 \u2502 670.1 \u2502 704.0 \u2502\n\u2502 codex \u2502 289.3 \u2502 306.3 \u2502 336.6 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 50/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 23.3 \u2502\n\u2502 Transfer \u2502 1.8 MB \u2502\n\u2502 Duration \u2502 2145.8 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 171.4 ms \u2502\n\u2502 Latency mean \u2502 212.5 ms \u2502\n\u2502 Latency p50 \u2502 183.4 ms \u2502\n\u2502 Latency p95 \u2502 358.6 ms \u2502\n\u2502 Latency p99 \u2502 366.5 ms \u2502\n\u2502 Latency max \u2502 370.4 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://ash-speed.hetzner.com/100MB.bin] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://ash-speed.hetzner.com/100MB.bin \u2502\n\u2502 Downloaded \u2502 100.0 MB \u2502\n\u2502 Duration \u2502 80.92s \u2502\n\u2502 Throughput \u2502 1.24 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 1082.0 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 511.9 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 461.6 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 452.3 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 393.1 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 421.8 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 410.7 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 390.8 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 407.7 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 412.6 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 450.3 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 402.6 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 419.2 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 413.4 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 462.9 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
+ },
+ {
+ "vm": "par-bench-a76c6e-3",
+ "status": "success",
+ "duration_ms": 105609.71049999353,
+ "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 722.8 MB/s \u2502 - \u2502 354.2 ms \u2502\n\u2502 Seq read (1MB) \u2502 3091.0 MB/s \u2502 - \u2502 82.8 ms \u2502\n\u2502 Rand write (4K) \u2502 22.5 MB/s \u2502 5758 \u2502 1736.7 ms \u2502\n\u2502 Rand read (4K) \u2502 228.7 MB/s \u2502 58555 \u2502 170.8 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 codex (133.7 MB) \u2502 587.1 MB/s \u2502 - \u2502 227.7 ms \u2502\n\u2502 Rand read (4K) \u2502 2560 files \u2502 24.2 MB/s \u2502 6194 \u2502 807.2 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 11.0 \u2502 11.2 \u2502 11.6 \u2502\n\u2502 node \u2502 142.2 \u2502 174.8 \u2502 191.2 \u2502\n\u2502 claude \u2502 399.7 \u2502 432.6 \u2502 452.4 \u2502\n\u2502 gemini \u2502 653.1 \u2502 674.2 \u2502 712.2 \u2502\n\u2502 codex \u2502 291.9 \u2502 308.7 \u2502 341.4 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 50/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 22.9 \u2502\n\u2502 Transfer \u2502 1.8 MB \u2502\n\u2502 Duration \u2502 2182.3 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 171.5 ms \u2502\n\u2502 Latency mean \u2502 210.5 ms \u2502\n\u2502 Latency p50 \u2502 183.5 ms \u2502\n\u2502 Latency p95 \u2502 309.3 ms \u2502\n\u2502 Latency p99 \u2502 331.0 ms \u2502\n\u2502 Latency max \u2502 350.5 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://ash-speed.hetzner.com/100MB.bin] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://ash-speed.hetzner.com/100MB.bin \u2502\n\u2502 Downloaded \u2502 100.0 MB \u2502\n\u2502 Duration \u2502 87.48s \u2502\n\u2502 Throughput \u2502 1.14 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 1028.8 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 399.9 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 390.4 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 403.6 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 416.4 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 381.3 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 384.7 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 368.6 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 367.0 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 372.6 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 372.2 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 380.0 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 447.8 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 385.7 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 410.8 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/parallel/data_1.0.1776686294.json b/benchmarks/parallel/data_1.0.1776686294.json
new file mode 100644
index 000000000..f59eba674
--- /dev/null
+++ b/benchmarks/parallel/data_1.0.1776686294.json
@@ -0,0 +1,32 @@
+{
+ "version": "1.0",
+ "timestamp": 1776687262.8722749,
+ "num_vms": 4,
+ "total_duration_ms": 116657.44224999798,
+ "results": [
+ {
+ "vm": "par-bench-fce278-0",
+ "status": "success",
+ "duration_ms": 109477.8444999829,
+ "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 608.8 MB/s \u2502 - \u2502 420.5 ms \u2502\n\u2502 Seq read (1MB) \u2502 2289.6 MB/s \u2502 - \u2502 111.8 ms \u2502\n\u2502 Rand write (4K) \u2502 17.9 MB/s \u2502 4594 \u2502 2176.7 ms \u2502\n\u2502 Rand read (4K) \u2502 118.8 MB/s \u2502 30409 \u2502 328.9 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 codex (133.7 MB) \u2502 484.5 MB/s \u2502 - \u2502 276.0 ms \u2502\n\u2502 Rand read (4K) \u2502 2618 files \u2502 19.3 MB/s \u2502 4928 \u2502 1014.5 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 6.5 \u2502 7.4 \u2502 8.3 \u2502\n\u2502 node \u2502 130.4 \u2502 133.3 \u2502 135.6 \u2502\n\u2502 claude \u2502 383.7 \u2502 387.6 \u2502 390.8 \u2502\n\u2502 gemini \u2502 657.7 \u2502 692.7 \u2502 711.2 \u2502\n\u2502 codex \u2502 288.6 \u2502 446.0 \u2502 704.9 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 5/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 62.0 \u2502\n\u2502 Transfer \u2502 395.2 KB \u2502\n\u2502 Duration \u2502 806.7 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 42.2 ms \u2502\n\u2502 Latency mean \u2502 68.4 ms \u2502\n\u2502 Latency p50 \u2502 45.5 ms \u2502\n\u2502 Latency p95 \u2502 187.1 ms \u2502\n\u2502 Latency p99 \u2502 241.2 ms \u2502\n\u2502 Latency max \u2502 288.5 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://ash-speed.hetzner.com/100MB.bin] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://ash-speed.hetzner.com/100MB.bin \u2502\n\u2502 Downloaded \u2502 100.0 MB \u2502\n\u2502 Duration \u2502 91.02s \u2502\n\u2502 Throughput \u2502 1.1 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 994.2 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 429.4 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 419.1 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 410.5 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 424.9 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 420.8 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 413.8 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 413.4 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 413.0 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 432.4 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 440.4 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 441.0 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 470.2 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 436.7 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 474.3 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
+ },
+ {
+ "vm": "par-bench-e9a730-1",
+ "status": "success",
+ "duration_ms": 114373.18083300488,
+ "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 690.5 MB/s \u2502 - \u2502 370.8 ms \u2502\n\u2502 Seq read (1MB) \u2502 2388.2 MB/s \u2502 - \u2502 107.2 ms \u2502\n\u2502 Rand write (4K) \u2502 22.3 MB/s \u2502 5698 \u2502 1754.9 ms \u2502\n\u2502 Rand read (4K) \u2502 194.0 MB/s \u2502 49657 \u2502 201.4 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 codex (133.7 MB) \u2502 576.2 MB/s \u2502 - \u2502 232.0 ms \u2502\n\u2502 Rand read (4K) \u2502 2546 files \u2502 25.4 MB/s \u2502 6498 \u2502 769.4 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 8.8 \u2502 13.3 \u2502 15.6 \u2502\n\u2502 node \u2502 138.4 \u2502 138.8 \u2502 139.4 \u2502\n\u2502 claude \u2502 399.6 \u2502 432.9 \u2502 450.8 \u2502\n\u2502 gemini \u2502 708.5 \u2502 729.8 \u2502 771.5 \u2502\n\u2502 codex \u2502 293.9 \u2502 457.9 \u2502 578.6 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 5/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 52.9 \u2502\n\u2502 Transfer \u2502 395.4 KB \u2502\n\u2502 Duration \u2502 945.0 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 42.7 ms \u2502\n\u2502 Latency mean \u2502 82.5 ms \u2502\n\u2502 Latency p50 \u2502 47.0 ms \u2502\n\u2502 Latency p95 \u2502 315.9 ms \u2502\n\u2502 Latency p99 \u2502 373.0 ms \u2502\n\u2502 Latency max \u2502 425.9 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://ash-speed.hetzner.com/100MB.bin] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://ash-speed.hetzner.com/100MB.bin \u2502\n\u2502 Downloaded \u2502 100.0 MB \u2502\n\u2502 Duration \u2502 96.22s \u2502\n\u2502 Throughput \u2502 1.04 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 1027.0 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 445.7 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 431.3 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 438.9 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 438.4 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 440.9 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 432.1 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 434.4 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 424.4 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 435.1 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 445.9 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 441.5 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 462.8 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 437.1 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 475.0 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
+ },
+ {
+ "vm": "par-bench-63b90f-2",
+ "status": "success",
+ "duration_ms": 116656.21341596125,
+ "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 634.6 MB/s \u2502 - \u2502 403.4 ms \u2502\n\u2502 Seq read (1MB) \u2502 2291.2 MB/s \u2502 - \u2502 111.7 ms \u2502\n\u2502 Rand write (4K) \u2502 18.3 MB/s \u2502 4673 \u2502 2140.0 ms \u2502\n\u2502 Rand read (4K) \u2502 138.5 MB/s \u2502 35460 \u2502 282.0 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 codex (133.7 MB) \u2502 506.5 MB/s \u2502 - \u2502 264.0 ms \u2502\n\u2502 Rand read (4K) \u2502 2593 files \u2502 19.2 MB/s \u2502 4918 \u2502 1016.6 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 7.7 \u2502 9.5 \u2502 10.5 \u2502\n\u2502 node \u2502 129.7 \u2502 130.7 \u2502 131.5 \u2502\n\u2502 claude \u2502 391.9 \u2502 392.8 \u2502 394.4 \u2502\n\u2502 gemini \u2502 653.7 \u2502 686.3 \u2502 703.2 \u2502\n\u2502 codex \u2502 285.1 \u2502 460.8 \u2502 756.4 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 5/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 50.2 \u2502\n\u2502 Transfer \u2502 395.3 KB \u2502\n\u2502 Duration \u2502 995.3 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 41.7 ms \u2502\n\u2502 Latency mean \u2502 77.9 ms \u2502\n\u2502 Latency p50 \u2502 46.0 ms \u2502\n\u2502 Latency p95 \u2502 181.0 ms \u2502\n\u2502 Latency p99 \u2502 232.9 ms \u2502\n\u2502 Latency max \u2502 281.8 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://ash-speed.hetzner.com/100MB.bin] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://ash-speed.hetzner.com/100MB.bin \u2502\n\u2502 Downloaded \u2502 100.0 MB \u2502\n\u2502 Duration \u2502 98.01s \u2502\n\u2502 Throughput \u2502 1.02 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 1058.9 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 443.2 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 424.7 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 430.2 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 429.6 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 437.2 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 436.7 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 433.8 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 439.6 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 434.4 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 418.4 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 423.0 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 444.1 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 410.5 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 476.6 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
+ },
+ {
+ "vm": "par-bench-035081-3",
+ "status": "success",
+ "duration_ms": 97436.26862496603,
+ "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 670.5 MB/s \u2502 - \u2502 381.8 ms \u2502\n\u2502 Seq read (1MB) \u2502 2585.3 MB/s \u2502 - \u2502 99.0 ms \u2502\n\u2502 Rand write (4K) \u2502 21.1 MB/s \u2502 5406 \u2502 1849.6 ms \u2502\n\u2502 Rand read (4K) \u2502 182.1 MB/s \u2502 46618 \u2502 214.5 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 codex (133.7 MB) \u2502 587.4 MB/s \u2502 - \u2502 227.6 ms \u2502\n\u2502 Rand read (4K) \u2502 2603 files \u2502 23.6 MB/s \u2502 6049 \u2502 826.6 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 7.2 \u2502 9.5 \u2502 11.6 \u2502\n\u2502 node \u2502 134.9 \u2502 137.7 \u2502 139.9 \u2502\n\u2502 claude \u2502 397.7 \u2502 416.6 \u2502 451.9 \u2502\n\u2502 gemini \u2502 656.8 \u2502 711.4 \u2502 767.7 \u2502\n\u2502 codex \u2502 293.7 \u2502 466.2 \u2502 552.8 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 5/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 60.0 \u2502\n\u2502 Transfer \u2502 395.2 KB \u2502\n\u2502 Duration \u2502 833.0 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 42.5 ms \u2502\n\u2502 Latency mean \u2502 77.3 ms \u2502\n\u2502 Latency p50 \u2502 48.1 ms \u2502\n\u2502 Latency p95 \u2502 268.2 ms \u2502\n\u2502 Latency p99 \u2502 323.2 ms \u2502\n\u2502 Latency max \u2502 374.9 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://ash-speed.hetzner.com/100MB.bin] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://ash-speed.hetzner.com/100MB.bin \u2502\n\u2502 Downloaded \u2502 100.0 MB \u2502\n\u2502 Duration \u2502 79.56s \u2502\n\u2502 Throughput \u2502 1.26 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 1001.1 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 434.1 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 417.8 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 420.6 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 429.8 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 415.5 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 417.4 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 410.5 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 427.8 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 421.8 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 477.2 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 414.3 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 446.1 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 416.0 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 448.8 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/parallel/data_1.0.1776688771.json b/benchmarks/parallel/data_1.0.1776688771.json
new file mode 100644
index 000000000..29170e7f9
--- /dev/null
+++ b/benchmarks/parallel/data_1.0.1776688771.json
@@ -0,0 +1,32 @@
+{
+ "version": "1.0",
+ "timestamp": 1776965682.814875,
+ "num_vms": 4,
+ "total_duration_ms": 22269.966417050455,
+ "results": [
+ {
+ "vm": "par-bench-b1cf21-0",
+ "status": "success",
+ "duration_ms": 22091.69995796401,
+ "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 429.5 MB/s \u2502 - \u2502 596.0 ms \u2502\n\u2502 Seq read (1MB) \u2502 1071.4 MB/s \u2502 - \u2502 238.9 ms \u2502\n\u2502 Rand write (4K) \u2502 16.9 MB/s \u2502 4317 \u2502 2316.2 ms \u2502\n\u2502 Rand read (4K) \u2502 99.6 MB/s \u2502 25508 \u2502 392.0 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 codex (133.7 MB) \u2502 491.3 MB/s \u2502 - \u2502 272.1 ms \u2502\n\u2502 Rand read (4K) \u2502 2609 files \u2502 18.2 MB/s \u2502 4653 \u2502 1074.7 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 7.8 \u2502 9.9 \u2502 11.6 \u2502\n\u2502 node \u2502 130.8 \u2502 134.7 \u2502 138.0 \u2502\n\u2502 claude \u2502 386.4 \u2502 391.2 \u2502 395.2 \u2502\n\u2502 gemini \u2502 705.4 \u2502 737.0 \u2502 753.3 \u2502\n\u2502 codex \u2502 340.5 \u2502 359.3 \u2502 396.5 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 5/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 43.7 \u2502\n\u2502 Transfer \u2502 397.2 KB \u2502\n\u2502 Duration \u2502 1145.5 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 29.4 ms \u2502\n\u2502 Latency mean \u2502 84.5 ms \u2502\n\u2502 Latency p50 \u2502 36.1 ms \u2502\n\u2502 Latency p95 \u2502 329.8 ms \u2502\n\u2502 Latency p99 \u2502 439.6 ms \u2502\n\u2502 Latency max \u2502 541.6 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-slides.pdf] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-\u2026 \u2502\n\u2502 Downloaded \u2502 9.5 MB \u2502\n\u2502 Duration \u2502 0.66s \u2502\n\u2502 Throughput \u2502 14.43 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 1241.6 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 559.0 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 505.7 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 486.4 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 480.2 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 477.8 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 485.3 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 522.9 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 513.7 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 537.3 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 497.5 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 502.4 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 540.8 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 503.6 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 544.4 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
+ },
+ {
+ "vm": "par-bench-a22f97-1",
+ "status": "success",
+ "duration_ms": 22267.32066704426,
+ "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 428.9 MB/s \u2502 - \u2502 596.9 ms \u2502\n\u2502 Seq read (1MB) \u2502 976.4 MB/s \u2502 - \u2502 262.2 ms \u2502\n\u2502 Rand write (4K) \u2502 16.7 MB/s \u2502 4270 \u2502 2341.7 ms \u2502\n\u2502 Rand read (4K) \u2502 98.0 MB/s \u2502 25083 \u2502 398.7 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 codex (133.7 MB) \u2502 489.4 MB/s \u2502 - \u2502 273.2 ms \u2502\n\u2502 Rand read (4K) \u2502 2592 files \u2502 18.1 MB/s \u2502 4645 \u2502 1076.4 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 6.7 \u2502 7.9 \u2502 8.6 \u2502\n\u2502 node \u2502 130.0 \u2502 133.2 \u2502 135.4 \u2502\n\u2502 claude \u2502 386.4 \u2502 391.4 \u2502 395.6 \u2502\n\u2502 gemini \u2502 701.5 \u2502 722.1 \u2502 755.1 \u2502\n\u2502 codex \u2502 341.0 \u2502 358.1 \u2502 388.7 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 5/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 28.0 \u2502\n\u2502 Transfer \u2502 397.3 KB \u2502\n\u2502 Duration \u2502 1788.4 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 31.1 ms \u2502\n\u2502 Latency mean \u2502 112.2 ms \u2502\n\u2502 Latency p50 \u2502 36.2 ms \u2502\n\u2502 Latency p95 \u2502 391.5 ms \u2502\n\u2502 Latency p99 \u2502 397.3 ms \u2502\n\u2502 Latency max \u2502 397.9 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-slides.pdf] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-\u2026 \u2502\n\u2502 Downloaded \u2502 9.5 MB \u2502\n\u2502 Duration \u2502 0.36s \u2502\n\u2502 Throughput \u2502 26.7 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 1331.7 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 541.4 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 498.0 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 481.2 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 475.4 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 476.6 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 508.8 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 518.7 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 525.2 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 512.7 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 502.3 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 510.0 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 518.9 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 510.8 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 528.5 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
+ },
+ {
+ "vm": "par-bench-51ff9f-2",
+ "status": "success",
+ "duration_ms": 22080.987833964173,
+ "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 385.1 MB/s \u2502 - \u2502 664.8 ms \u2502\n\u2502 Seq read (1MB) \u2502 1131.5 MB/s \u2502 - \u2502 226.2 ms \u2502\n\u2502 Rand write (4K) \u2502 16.7 MB/s \u2502 4271 \u2502 2341.3 ms \u2502\n\u2502 Rand read (4K) \u2502 106.0 MB/s \u2502 27147 \u2502 368.4 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 codex (133.7 MB) \u2502 488.3 MB/s \u2502 - \u2502 273.8 ms \u2502\n\u2502 Rand read (4K) \u2502 2571 files \u2502 18.5 MB/s \u2502 4725 \u2502 1058.1 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 9.2 \u2502 10.6 \u2502 11.5 \u2502\n\u2502 node \u2502 134.8 \u2502 137.1 \u2502 138.2 \u2502\n\u2502 claude \u2502 399.8 \u2502 416.7 \u2502 450.4 \u2502\n\u2502 gemini \u2502 710.1 \u2502 743.6 \u2502 761.0 \u2502\n\u2502 codex \u2502 339.4 \u2502 341.7 \u2502 345.4 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 5/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 47.1 \u2502\n\u2502 Transfer \u2502 397.2 KB \u2502\n\u2502 Duration \u2502 1060.7 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 29.8 ms \u2502\n\u2502 Latency mean \u2502 70.2 ms \u2502\n\u2502 Latency p50 \u2502 35.6 ms \u2502\n\u2502 Latency p95 \u2502 252.9 ms \u2502\n\u2502 Latency p99 \u2502 258.9 ms \u2502\n\u2502 Latency max \u2502 259.2 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-slides.pdf] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-\u2026 \u2502\n\u2502 Downloaded \u2502 9.5 MB \u2502\n\u2502 Duration \u2502 0.56s \u2502\n\u2502 Throughput \u2502 16.89 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 1255.1 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 558.6 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 519.9 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 494.3 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 489.1 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 481.9 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 487.9 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 521.4 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 531.6 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 536.0 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 507.3 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 500.1 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 540.5 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 503.7 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 555.7 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
+ },
+ {
+ "vm": "par-bench-7c3eb9-3",
+ "status": "success",
+ "duration_ms": 21404.337041953113,
+ "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 292.1 MB/s \u2502 - \u2502 876.5 ms \u2502\n\u2502 Seq read (1MB) \u2502 2250.6 MB/s \u2502 - \u2502 113.7 ms \u2502\n\u2502 Rand write (4K) \u2502 17.2 MB/s \u2502 4404 \u2502 2270.7 ms \u2502\n\u2502 Rand read (4K) \u2502 105.8 MB/s \u2502 27075 \u2502 369.3 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 codex (133.7 MB) \u2502 496.9 MB/s \u2502 - \u2502 269.1 ms \u2502\n\u2502 Rand read (4K) \u2502 2615 files \u2502 18.1 MB/s \u2502 4634 \u2502 1079.1 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 7.4 \u2502 8.6 \u2502 10.7 \u2502\n\u2502 node \u2502 130.3 \u2502 132.1 \u2502 135.4 \u2502\n\u2502 claude \u2502 391.4 \u2502 411.3 \u2502 450.5 \u2502\n\u2502 gemini \u2502 657.2 \u2502 692.7 \u2502 715.7 \u2502\n\u2502 codex \u2502 333.5 \u2502 352.9 \u2502 389.1 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 5/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 65.3 \u2502\n\u2502 Transfer \u2502 397.3 KB \u2502\n\u2502 Duration \u2502 765.6 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 31.1 ms \u2502\n\u2502 Latency mean \u2502 75.6 ms \u2502\n\u2502 Latency p50 \u2502 35.0 ms \u2502\n\u2502 Latency p95 \u2502 389.9 ms \u2502\n\u2502 Latency p99 \u2502 392.7 ms \u2502\n\u2502 Latency max \u2502 393.3 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-slides.pdf] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-\u2026 \u2502\n\u2502 Downloaded \u2502 9.5 MB \u2502\n\u2502 Duration \u2502 0.39s \u2502\n\u2502 Throughput \u2502 24.64 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 1284.3 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 538.0 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 546.2 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 538.1 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 493.6 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 489.2 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 477.9 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 494.1 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 525.4 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 521.3 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 538.7 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 498.5 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 542.5 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 503.1 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 534.2 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/parallel/data_1.0.json b/benchmarks/parallel/data_1.0.json
new file mode 100644
index 000000000..0675b3896
--- /dev/null
+++ b/benchmarks/parallel/data_1.0.json
@@ -0,0 +1,32 @@
+{
+ "version": "1.0",
+ "timestamp": 1781364352.162539,
+ "num_vms": 4,
+ "total_duration_ms": 36865.429750061594,
+ "results": [
+ {
+ "vm": "par-bench-80a260-0",
+ "status": "success",
+ "duration_ms": 36851.86541592702,
+ "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 1077.0 MB/s \u2502 - \u2502 237.7 ms \u2502\n\u2502 Seq read (1MB) \u2502 2691.1 MB/s \u2502 - \u2502 95.1 ms \u2502\n\u2502 Rand write (4K) \u2502 21.6 MB/s \u2502 5519 \u2502 1811.8 ms \u2502\n\u2502 Rand read (4K) \u2502 128.6 MB/s \u2502 32924 \u2502 303.7 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 codex (188.6 MB) \u2502 2564.2 MB/s \u2502 - \u2502 73.6 ms \u2502\n\u2502 Rand read (4K) \u2502 2562 files \u2502 80.6 MB/s \u2502 20643 \u2502 242.2 ms \u2502\n\u2502 Large bin cold \u2502 2 files \u2502 2643.1 MB/s \u2502 - \u2502 85.5 ms \u2502\n\u2502 Large bin warm \u2502 2 files \u2502 16027.1 MB/s \u2502 - \u2502 14.1 ms \u2502\n\u2502 Small JS reads \u2502 99 files \u2502 4767.0 MB/s \u2502 512488 \u2502 9.8 ms \u2502\n\u2502 Metadata stat \u2502 6546 entries \u2502 - \u2502 95236 \u2502 68.7 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage Path Diagnostics \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 \u2503 \u2503 \u2503 Cold \u2503 \u2503 Rand \u2503 Rand \u2503\n\u2503 Path \u2503 FS \u2503 Write \u2503 Read \u2503 Warm Read \u2503 Read \u2503 Write \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 virtiofs \u2502 1613.8 \u2502 3113.8 \u2502 3275.6 \u2502 31398 \u2502 4908 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /tmp \u2502 overlay \u2502 5263.1 \u2502 7010.7 \u2502 9072.4 \u2502 1256117 \u2502 3168 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/tmp \u2502 overlay \u2502 3555.4 \u2502 7073.9 \u2502 11064.4 \u2502 1177752 \u2502 3847 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/log \u2502 overlay \u2502 5030.6 \u2502 4164.3 \u2502 8145.5 \u2502 1083619 \u2502 4009 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /run \u2502 overlay \u2502 4771.7 \u2502 5895.6 \u2502 7998.8 \u2502 856653 \u2502 4568 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 2294.7 \u2502 16347.3 \u2502 - \u2502 - \u2502\n\u2502 (188.6 \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 MB) \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 3579.8 \u2502 14130.4 \u2502 - \u2502 - \u2502\n\u2502 (1.3 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 3581.3 \u2502 11912.9 \u2502 - \u2502 - \u2502\n\u2502 (6.3 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage I/O Profile \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Path \u2503 Workload \u2503 Block \u2503 IOPS \u2503 Throughput \u2503 Avg Lat \u2503 P95 Lat \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 seq_write \u2502 4k \u2502 10347 \u2502 40.4 MB/s \u2502 0.097 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 4k \u2502 713181 \u2502 2785.9 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 4k \u2502 698861 \u2502 2729.9 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 64k \u2502 7913 \u2502 494.6 MB/s \u2502 0.126 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 64k \u2502 47598 \u2502 2974.9 MB/s \u2502 0.021 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 64k \u2502 48729 \u2502 3045.6 MB/s \u2502 0.021 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 1m \u2502 1430 \u2502 1430.0 MB/s \u2502 0.699 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 1m \u2502 3234 \u2502 3234.4 MB/s \u2502 0.309 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 1m \u2502 2801 \u2502 2800.8 MB/s \u2502 0.357 ms \u2502 - \u2502\n\u2502 /root \u2502 read_4k \u2502 4k \u2502 21419 \u2502 83.7 MB/s \u2502 0.047 ms \u2502 0.077 ms \u2502\n\u2502 /root \u2502 write_4k_s\u2026 \u2502 4k \u2502 6660 \u2502 26.0 MB/s \u2502 0.15 ms \u2502 0.202 ms \u2502\n\u2502 /tmp \u2502 seq_write \u2502 4k \u2502 871893 \u2502 3405.8 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 4k \u2502 1068359 \u2502 4173.3 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 4k \u2502 1490595 \u2502 5822.6 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 64k \u2502 69593 \u2502 4349.6 MB/s \u2502 0.014 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 64k \u2502 83778 \u2502 5236.1 MB/s \u2502 0.012 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 64k \u2502 123812 \u2502 7738.2 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 1m \u2502 1075 \u2502 1075.0 MB/s \u2502 0.93 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 1m \u2502 4968 \u2502 4968.5 MB/s \u2502 0.201 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 1m \u2502 8004 \u2502 8004.3 MB/s \u2502 0.125 ms \u2502 - \u2502\n\u2502 /tmp \u2502 read_4k \u2502 4k \u2502 30989 \u2502 121.1 MB/s \u2502 0.032 ms \u2502 0.073 ms \u2502\n\u2502 /tmp \u2502 write_4k_s\u2026 \u2502 4k \u2502 10090 \u2502 39.4 MB/s \u2502 0.099 ms \u2502 0.146 ms \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 4k \u2502 723540 \u2502 2826.3 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 4k \u2502 944080 \u2502 3687.8 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 4k \u2502 1171168 \u2502 4574.9 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 64k \u2502 76976 \u2502 4811.0 MB/s \u2502 0.013 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 64k \u2502 109241 \u2502 6827.6 MB/s \u2502 0.009 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 64k \u2502 131737 \u2502 8233.6 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 1m \u2502 4381 \u2502 4380.6 MB/s \u2502 0.228 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 1m \u2502 6330 \u2502 6329.8 MB/s \u2502 0.158 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 1m \u2502 7894 \u2502 7893.6 MB/s \u2502 0.127 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 read_4k \u2502 4k \u2502 21920 \u2502 85.6 MB/s \u2502 0.046 ms \u2502 0.083 ms \u2502\n\u2502 /var/tmp \u2502 write_4k_s\u2026 \u2502 4k \u2502 9526 \u2502 37.2 MB/s \u2502 0.105 ms \u2502 0.173 ms \u2502\n\u2502 /var/log \u2502 seq_write \u2502 4k \u2502 640877 \u2502 2503.4 MB/s \u2502 0.002 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 4k \u2502 947511 \u2502 3701.2 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 4k \u2502 1234080 \u2502 4820.6 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 64k \u2502 64676 \u2502 4042.2 MB/s \u2502 0.015 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 64k \u2502 79754 \u2502 4984.6 MB/s \u2502 0.013 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 64k \u2502 109744 \u2502 6859.0 MB/s \u2502 0.009 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 1m \u2502 2980 \u2502 2979.9 MB/s \u2502 0.336 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 1m \u2502 4396 \u2502 4395.5 MB/s \u2502 0.228 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 1m \u2502 6516 \u2502 6515.6 MB/s \u2502 0.153 ms \u2502 - \u2502\n\u2502 /var/log \u2502 read_4k \u2502 4k \u2502 21651 \u2502 84.6 MB/s \u2502 0.046 ms \u2502 0.074 ms \u2502\n\u2502 /var/log \u2502 write_4k_s\u2026 \u2502 4k \u2502 9018 \u2502 35.2 MB/s \u2502 0.111 ms \u2502 0.184 ms \u2502\n\u2502 /run \u2502 seq_write \u2502 4k \u2502 632775 \u2502 2471.8 MB/s \u2502 0.002 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 4k \u2502 886652 \u2502 3463.5 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 4k \u2502 1134548 \u2502 4431.8 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 64k \u2502 62589 \u2502 3911.8 MB/s \u2502 0.016 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 64k \u2502 76623 \u2502 4788.9 MB/s \u2502 0.013 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 64k \u2502 99648 \u2502 6228.0 MB/s \u2502 0.01 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 1m \u2502 3154 \u2502 3154.1 MB/s \u2502 0.317 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 1m \u2502 4506 \u2502 4506.3 MB/s \u2502 0.222 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 1m \u2502 5554 \u2502 5554.5 MB/s \u2502 0.18 ms \u2502 - \u2502\n\u2502 /run \u2502 read_4k \u2502 4k \u2502 21098 \u2502 82.4 MB/s \u2502 0.047 ms \u2502 0.077 ms \u2502\n\u2502 /run \u2502 write_4k_s\u2026 \u2502 4k \u2502 8681 \u2502 33.9 MB/s \u2502 0.115 ms \u2502 0.185 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 5.9 \u2502 7.1 \u2502 7.9 \u2502\n\u2502 node \u2502 29.8 \u2502 38.4 \u2502 43.4 \u2502\n\u2502 claude \u2502 130.5 \u2502 133.9 \u2502 137.7 \u2502\n\u2502 gemini \u2502 811.9 \u2502 833.4 \u2502 874.8 \u2502\n\u2502 codex \u2502 135.1 \u2502 137.1 \u2502 138.9 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Skipped \u2502 set CAPSEM_MOCK_SERVER_BASE_URL for local lab or \u2502\n\u2502 \u2502 CAPSEM_BENCH_ALLOW_PUBLIC_NETWORK=1 for explicit public smoke \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Skipped \u2502 set CAPSEM_MOCK_SERVER_BASE_URL for local lab or \u2502\n\u2502 \u2502 CAPSEM_BENCH_ALLOW_PUBLIC_NETWORK=1 for explicit public smoke \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 1054.5 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 481.7 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 528.6 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 468.8 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 1601.7 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 395.6 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 481.9 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 529.0 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 490.2 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 1763.6 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 402.1 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 538.9 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 584.6 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 418.8 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 1700.7 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
+ },
+ {
+ "vm": "par-bench-4d71b3-1",
+ "status": "success",
+ "duration_ms": 36415.94970796723,
+ "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 1064.2 MB/s \u2502 - \u2502 240.6 ms \u2502\n\u2502 Seq read (1MB) \u2502 2786.9 MB/s \u2502 - \u2502 91.9 ms \u2502\n\u2502 Rand write (4K) \u2502 18.7 MB/s \u2502 4783 \u2502 2090.6 ms \u2502\n\u2502 Rand read (4K) \u2502 119.8 MB/s \u2502 30660 \u2502 326.2 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 codex (188.6 MB) \u2502 2609.4 MB/s \u2502 - \u2502 72.3 ms \u2502\n\u2502 Rand read (4K) \u2502 2595 files \u2502 78.5 MB/s \u2502 20092 \u2502 248.9 ms \u2502\n\u2502 Large bin cold \u2502 2 files \u2502 2530.6 MB/s \u2502 - \u2502 89.3 ms \u2502\n\u2502 Large bin warm \u2502 2 files \u2502 14036.2 MB/s \u2502 - \u2502 16.1 ms \u2502\n\u2502 Small JS reads \u2502 99 files \u2502 4223.8 MB/s \u2502 480482 \u2502 10.4 ms \u2502\n\u2502 Metadata stat \u2502 6546 entries \u2502 - \u2502 94886 \u2502 69.0 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage Path Diagnostics \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 \u2503 \u2503 \u2503 Cold \u2503 \u2503 Rand \u2503 Rand \u2503\n\u2503 Path \u2503 FS \u2503 Write \u2503 Read \u2503 Warm Read \u2503 Read \u2503 Write \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 virtiofs \u2502 1843.6 \u2502 3303.4 \u2502 3588.2 \u2502 30409 \u2502 5447 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /tmp \u2502 overlay \u2502 5550.7 \u2502 5795.2 \u2502 11356.2 \u2502 1283491 \u2502 3157 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/tmp \u2502 overlay \u2502 3665.8 \u2502 8433.3 \u2502 17502.7 \u2502 1111981 \u2502 3794 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/log \u2502 overlay \u2502 5433.4 \u2502 7095.0 \u2502 12658.6 \u2502 1170823 \u2502 4120 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /run \u2502 overlay \u2502 4633.7 \u2502 6395.4 \u2502 9848.6 \u2502 937599 \u2502 4468 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 2658.6 \u2502 19547.4 \u2502 - \u2502 - \u2502\n\u2502 (188.6 \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 MB) \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 3515.3 \u2502 16905.4 \u2502 - \u2502 - \u2502\n\u2502 (1.3 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 5077.4 \u2502 23378.8 \u2502 - \u2502 - \u2502\n\u2502 (6.3 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage I/O Profile \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Path \u2503 Workload \u2503 Block \u2503 IOPS \u2503 Throughput \u2503 Avg Lat \u2503 P95 Lat \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 seq_write \u2502 4k \u2502 10392 \u2502 40.6 MB/s \u2502 0.096 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 4k \u2502 611530 \u2502 2388.8 MB/s \u2502 0.002 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 4k \u2502 698090 \u2502 2726.9 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 64k \u2502 8261 \u2502 516.3 MB/s \u2502 0.121 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 64k \u2502 47001 \u2502 2937.5 MB/s \u2502 0.021 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 64k \u2502 45267 \u2502 2829.2 MB/s \u2502 0.022 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 1m \u2502 1592 \u2502 1592.1 MB/s \u2502 0.628 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 1m \u2502 2532 \u2502 2531.6 MB/s \u2502 0.395 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 1m \u2502 2738 \u2502 2737.9 MB/s \u2502 0.365 ms \u2502 - \u2502\n\u2502 /root \u2502 read_4k \u2502 4k \u2502 23823 \u2502 93.1 MB/s \u2502 0.042 ms \u2502 0.068 ms \u2502\n\u2502 /root \u2502 write_4k_s\u2026 \u2502 4k \u2502 6617 \u2502 25.8 MB/s \u2502 0.151 ms \u2502 0.203 ms \u2502\n\u2502 /tmp \u2502 seq_write \u2502 4k \u2502 868878 \u2502 3394.1 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 4k \u2502 963016 \u2502 3761.8 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 4k \u2502 1442513 \u2502 5634.8 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 64k \u2502 60357 \u2502 3772.3 MB/s \u2502 0.017 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 64k \u2502 82653 \u2502 5165.8 MB/s \u2502 0.012 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 64k \u2502 137502 \u2502 8593.9 MB/s \u2502 0.007 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 1m \u2502 728 \u2502 728.4 MB/s \u2502 1.373 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 1m \u2502 5992 \u2502 5991.7 MB/s \u2502 0.167 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 1m \u2502 10025 \u2502 10025.0 \u2502 0.1 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /tmp \u2502 read_4k \u2502 4k \u2502 33842 \u2502 132.2 MB/s \u2502 0.03 ms \u2502 0.053 ms \u2502\n\u2502 /tmp \u2502 write_4k_s\u2026 \u2502 4k \u2502 8888 \u2502 34.7 MB/s \u2502 0.113 ms \u2502 0.16 ms \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 4k \u2502 638004 \u2502 2492.2 MB/s \u2502 0.002 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 4k \u2502 978373 \u2502 3821.8 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 4k \u2502 1262363 \u2502 4931.1 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 64k \u2502 73817 \u2502 4613.5 MB/s \u2502 0.014 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 64k \u2502 84653 \u2502 5290.8 MB/s \u2502 0.012 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 64k \u2502 126800 \u2502 7925.0 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 1m \u2502 3663 \u2502 3663.0 MB/s \u2502 0.273 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 1m \u2502 5173 \u2502 5172.6 MB/s \u2502 0.193 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 1m \u2502 7689 \u2502 7689.2 MB/s \u2502 0.13 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 read_4k \u2502 4k \u2502 28944 \u2502 113.1 MB/s \u2502 0.035 ms \u2502 0.065 ms \u2502\n\u2502 /var/tmp \u2502 write_4k_s\u2026 \u2502 4k \u2502 11505 \u2502 44.9 MB/s \u2502 0.087 ms \u2502 0.142 ms \u2502\n\u2502 /var/log \u2502 seq_write \u2502 4k \u2502 656495 \u2502 2564.4 MB/s \u2502 0.002 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 4k \u2502 902058 \u2502 3523.7 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 4k \u2502 1269393 \u2502 4958.6 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 64k \u2502 63266 \u2502 3954.1 MB/s \u2502 0.016 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 64k \u2502 76747 \u2502 4796.7 MB/s \u2502 0.013 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 64k \u2502 110613 \u2502 6913.3 MB/s \u2502 0.009 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 1m \u2502 2936 \u2502 2936.1 MB/s \u2502 0.341 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 1m \u2502 4156 \u2502 4156.2 MB/s \u2502 0.241 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 1m \u2502 6880 \u2502 6880.0 MB/s \u2502 0.145 ms \u2502 - \u2502\n\u2502 /var/log \u2502 read_4k \u2502 4k \u2502 29148 \u2502 113.9 MB/s \u2502 0.034 ms \u2502 0.057 ms \u2502\n\u2502 /var/log \u2502 write_4k_s\u2026 \u2502 4k \u2502 10205 \u2502 39.9 MB/s \u2502 0.098 ms \u2502 0.171 ms \u2502\n\u2502 /run \u2502 seq_write \u2502 4k \u2502 635044 \u2502 2480.6 MB/s \u2502 0.002 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 4k \u2502 866932 \u2502 3386.5 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 4k \u2502 1209981 \u2502 4726.5 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 64k \u2502 66228 \u2502 4139.3 MB/s \u2502 0.015 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 64k \u2502 69118 \u2502 4319.8 MB/s \u2502 0.014 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 64k \u2502 100323 \u2502 6270.2 MB/s \u2502 0.01 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 1m \u2502 3164 \u2502 3164.4 MB/s \u2502 0.316 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 1m \u2502 4140 \u2502 4140.3 MB/s \u2502 0.242 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 1m \u2502 5864 \u2502 5863.6 MB/s \u2502 0.171 ms \u2502 - \u2502\n\u2502 /run \u2502 read_4k \u2502 4k \u2502 21610 \u2502 84.4 MB/s \u2502 0.046 ms \u2502 0.077 ms \u2502\n\u2502 /run \u2502 write_4k_s\u2026 \u2502 4k \u2502 8665 \u2502 33.8 MB/s \u2502 0.115 ms \u2502 0.183 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 6.7 \u2502 7.6 \u2502 8.5 \u2502\n\u2502 node \u2502 30.1 \u2502 38.5 \u2502 43.2 \u2502\n\u2502 claude \u2502 137.2 \u2502 138.1 \u2502 138.6 \u2502\n\u2502 gemini \u2502 812.6 \u2502 835.5 \u2502 870.0 \u2502\n\u2502 codex \u2502 136.0 \u2502 137.4 \u2502 138.8 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Skipped \u2502 set CAPSEM_MOCK_SERVER_BASE_URL for local lab or \u2502\n\u2502 \u2502 CAPSEM_BENCH_ALLOW_PUBLIC_NETWORK=1 for explicit public smoke \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Skipped \u2502 set CAPSEM_MOCK_SERVER_BASE_URL for local lab or \u2502\n\u2502 \u2502 CAPSEM_BENCH_ALLOW_PUBLIC_NETWORK=1 for explicit public smoke \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 1039.2 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 487.1 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 527.0 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 460.5 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 1564.2 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 403.3 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 475.5 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 515.2 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 535.2 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 1707.3 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 377.2 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 525.6 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 592.0 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 427.8 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 1326.9 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
+ },
+ {
+ "vm": "par-bench-67d4b7-2",
+ "status": "success",
+ "duration_ms": 36833.88945797924,
+ "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 1232.7 MB/s \u2502 - \u2502 207.7 ms \u2502\n\u2502 Seq read (1MB) \u2502 2752.8 MB/s \u2502 - \u2502 93.0 ms \u2502\n\u2502 Rand write (4K) \u2502 18.9 MB/s \u2502 4837 \u2502 2067.2 ms \u2502\n\u2502 Rand read (4K) \u2502 122.5 MB/s \u2502 31352 \u2502 319.0 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 codex (188.6 MB) \u2502 2605.9 MB/s \u2502 - \u2502 72.4 ms \u2502\n\u2502 Rand read (4K) \u2502 2591 files \u2502 71.8 MB/s \u2502 18370 \u2502 272.2 ms \u2502\n\u2502 Large bin cold \u2502 2 files \u2502 2451.0 MB/s \u2502 - \u2502 92.2 ms \u2502\n\u2502 Large bin warm \u2502 2 files \u2502 17383.2 MB/s \u2502 - \u2502 13.0 ms \u2502\n\u2502 Small JS reads \u2502 99 files \u2502 4393.6 MB/s \u2502 490463 \u2502 10.2 ms \u2502\n\u2502 Metadata stat \u2502 6546 entries \u2502 - \u2502 81596 \u2502 80.2 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage Path Diagnostics \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 \u2503 \u2503 \u2503 Cold \u2503 \u2503 Rand \u2503 Rand \u2503\n\u2503 Path \u2503 FS \u2503 Write \u2503 Read \u2503 Warm Read \u2503 Read \u2503 Write \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 virtiofs \u2502 1886.9 \u2502 3258.8 \u2502 3707.3 \u2502 30188 \u2502 5088 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /tmp \u2502 overlay \u2502 5235.4 \u2502 6895.6 \u2502 11495.6 \u2502 1008997 \u2502 3144 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/tmp \u2502 overlay \u2502 3514.5 \u2502 8017.2 \u2502 10668.2 \u2502 1126925 \u2502 3790 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/log \u2502 overlay \u2502 5024.8 \u2502 7851.6 \u2502 12906.7 \u2502 1250892 \u2502 3888 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /run \u2502 overlay \u2502 4991.0 \u2502 6561.0 \u2502 10070.8 \u2502 782281 \u2502 4602 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 2640.5 \u2502 20409.4 \u2502 - \u2502 - \u2502\n\u2502 (188.6 \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 MB) \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 3411.8 \u2502 17865.8 \u2502 - \u2502 - \u2502\n\u2502 (1.3 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 3538.9 \u2502 17492.3 \u2502 - \u2502 - \u2502\n\u2502 (6.3 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage I/O Profile \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Path \u2503 Workload \u2503 Block \u2503 IOPS \u2503 Throughput \u2503 Avg Lat \u2503 P95 Lat \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 seq_write \u2502 4k \u2502 10431 \u2502 40.7 MB/s \u2502 0.096 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 4k \u2502 647951 \u2502 2531.1 MB/s \u2502 0.002 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 4k \u2502 711359 \u2502 2778.7 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 64k \u2502 8323 \u2502 520.2 MB/s \u2502 0.12 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 64k \u2502 47315 \u2502 2957.2 MB/s \u2502 0.021 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 64k \u2502 43949 \u2502 2746.8 MB/s \u2502 0.023 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 1m \u2502 1526 \u2502 1525.7 MB/s \u2502 0.655 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 1m \u2502 2638 \u2502 2637.5 MB/s \u2502 0.379 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 1m \u2502 2724 \u2502 2724.1 MB/s \u2502 0.367 ms \u2502 - \u2502\n\u2502 /root \u2502 read_4k \u2502 4k \u2502 24157 \u2502 94.4 MB/s \u2502 0.041 ms \u2502 0.065 ms \u2502\n\u2502 /root \u2502 write_4k_s\u2026 \u2502 4k \u2502 6641 \u2502 25.9 MB/s \u2502 0.151 ms \u2502 0.209 ms \u2502\n\u2502 /tmp \u2502 seq_write \u2502 4k \u2502 782194 \u2502 3055.4 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 4k \u2502 947184 \u2502 3699.9 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 4k \u2502 1352904 \u2502 5284.8 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 64k \u2502 69734 \u2502 4358.4 MB/s \u2502 0.014 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 64k \u2502 95444 \u2502 5965.2 MB/s \u2502 0.01 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 64k \u2502 123256 \u2502 7703.5 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 1m \u2502 614 \u2502 613.5 MB/s \u2502 1.63 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 1m \u2502 6577 \u2502 6576.7 MB/s \u2502 0.152 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 1m \u2502 11870 \u2502 11870.4 \u2502 0.084 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /tmp \u2502 read_4k \u2502 4k \u2502 29278 \u2502 114.4 MB/s \u2502 0.034 ms \u2502 0.062 ms \u2502\n\u2502 /tmp \u2502 write_4k_s\u2026 \u2502 4k \u2502 9791 \u2502 38.2 MB/s \u2502 0.102 ms \u2502 0.154 ms \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 4k \u2502 758476 \u2502 2962.8 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 4k \u2502 937103 \u2502 3660.6 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 4k \u2502 1279567 \u2502 4998.3 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 64k \u2502 65626 \u2502 4101.6 MB/s \u2502 0.015 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 64k \u2502 67659 \u2502 4228.7 MB/s \u2502 0.015 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 64k \u2502 108111 \u2502 6757.0 MB/s \u2502 0.009 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 1m \u2502 4114 \u2502 4114.0 MB/s \u2502 0.243 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 1m \u2502 4808 \u2502 4807.8 MB/s \u2502 0.208 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 1m \u2502 7273 \u2502 7272.9 MB/s \u2502 0.137 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 read_4k \u2502 4k \u2502 31075 \u2502 121.4 MB/s \u2502 0.032 ms \u2502 0.053 ms \u2502\n\u2502 /var/tmp \u2502 write_4k_s\u2026 \u2502 4k \u2502 8844 \u2502 34.5 MB/s \u2502 0.113 ms \u2502 0.191 ms \u2502\n\u2502 /var/log \u2502 seq_write \u2502 4k \u2502 779210 \u2502 3043.8 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 4k \u2502 972104 \u2502 3797.3 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 4k \u2502 1203077 \u2502 4699.5 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 64k \u2502 72861 \u2502 4553.8 MB/s \u2502 0.014 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 64k \u2502 78049 \u2502 4878.1 MB/s \u2502 0.013 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 64k \u2502 97014 \u2502 6063.4 MB/s \u2502 0.01 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 1m \u2502 3600 \u2502 3600.4 MB/s \u2502 0.278 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 1m \u2502 4460 \u2502 4460.3 MB/s \u2502 0.224 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 1m \u2502 7016 \u2502 7016.0 MB/s \u2502 0.143 ms \u2502 - \u2502\n\u2502 /var/log \u2502 read_4k \u2502 4k \u2502 30470 \u2502 119.0 MB/s \u2502 0.033 ms \u2502 0.058 ms \u2502\n\u2502 /var/log \u2502 write_4k_s\u2026 \u2502 4k \u2502 11145 \u2502 43.5 MB/s \u2502 0.09 ms \u2502 0.136 ms \u2502\n\u2502 /run \u2502 seq_write \u2502 4k \u2502 728386 \u2502 2845.3 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 4k \u2502 1036011 \u2502 4046.9 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 4k \u2502 1272676 \u2502 4971.4 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 64k \u2502 72892 \u2502 4555.8 MB/s \u2502 0.014 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 64k \u2502 93789 \u2502 5861.8 MB/s \u2502 0.011 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 64k \u2502 113828 \u2502 7114.3 MB/s \u2502 0.009 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 1m \u2502 4200 \u2502 4200.1 MB/s \u2502 0.238 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 1m \u2502 5953 \u2502 5953.0 MB/s \u2502 0.168 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 1m \u2502 7214 \u2502 7214.1 MB/s \u2502 0.139 ms \u2502 - \u2502\n\u2502 /run \u2502 read_4k \u2502 4k \u2502 19318 \u2502 75.5 MB/s \u2502 0.052 ms \u2502 0.085 ms \u2502\n\u2502 /run \u2502 write_4k_s\u2026 \u2502 4k \u2502 12071 \u2502 47.2 MB/s \u2502 0.083 ms \u2502 0.144 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 3.0 \u2502 4.3 \u2502 6.1 \u2502\n\u2502 node \u2502 29.6 \u2502 34.8 \u2502 44.2 \u2502\n\u2502 claude \u2502 133.7 \u2502 153.7 \u2502 189.7 \u2502\n\u2502 gemini \u2502 812.0 \u2502 831.8 \u2502 866.8 \u2502\n\u2502 codex \u2502 132.3 \u2502 134.5 \u2502 136.0 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Skipped \u2502 set CAPSEM_MOCK_SERVER_BASE_URL for local lab or \u2502\n\u2502 \u2502 CAPSEM_BENCH_ALLOW_PUBLIC_NETWORK=1 for explicit public smoke \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Skipped \u2502 set CAPSEM_MOCK_SERVER_BASE_URL for local lab or \u2502\n\u2502 \u2502 CAPSEM_BENCH_ALLOW_PUBLIC_NETWORK=1 for explicit public smoke \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 1050.0 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 504.9 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 539.7 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 405.1 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 1596.3 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 397.9 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 479.7 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 546.9 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 460.1 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 1759.8 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 407.0 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 531.0 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 577.0 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 407.0 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 1676.4 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
+ },
+ {
+ "vm": "par-bench-41ab93-3",
+ "status": "success",
+ "duration_ms": 36860.50820793025,
+ "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 1232.1 MB/s \u2502 - \u2502 207.8 ms \u2502\n\u2502 Seq read (1MB) \u2502 2762.5 MB/s \u2502 - \u2502 92.7 ms \u2502\n\u2502 Rand write (4K) \u2502 21.0 MB/s \u2502 5386 \u2502 1856.6 ms \u2502\n\u2502 Rand read (4K) \u2502 129.7 MB/s \u2502 33216 \u2502 301.1 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 codex (188.6 MB) \u2502 2703.7 MB/s \u2502 - \u2502 69.8 ms \u2502\n\u2502 Rand read (4K) \u2502 2563 files \u2502 73.7 MB/s \u2502 18868 \u2502 265.0 ms \u2502\n\u2502 Large bin cold \u2502 2 files \u2502 2752.5 MB/s \u2502 - \u2502 82.1 ms \u2502\n\u2502 Large bin warm \u2502 2 files \u2502 18224.4 MB/s \u2502 - \u2502 12.4 ms \u2502\n\u2502 Small JS reads \u2502 99 files \u2502 4675.7 MB/s \u2502 505992 \u2502 9.9 ms \u2502\n\u2502 Metadata stat \u2502 6546 entries \u2502 - \u2502 71707 \u2502 91.3 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage Path Diagnostics \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 \u2503 \u2503 \u2503 Cold \u2503 \u2503 Rand \u2503 Rand \u2503\n\u2503 Path \u2503 FS \u2503 Write \u2503 Read \u2503 Warm Read \u2503 Read \u2503 Write \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 virtiofs \u2502 1711.3 \u2502 3161.8 \u2502 3597.1 \u2502 30114 \u2502 4608 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /tmp \u2502 overlay \u2502 5498.2 \u2502 8150.1 \u2502 14161.4 \u2502 913917 \u2502 3172 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/tmp \u2502 overlay \u2502 4033.6 \u2502 6363.0 \u2502 9894.0 \u2502 1164772 \u2502 3762 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/log \u2502 overlay \u2502 4162.9 \u2502 5395.9 \u2502 8411.1 \u2502 1064372 \u2502 3898 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /run \u2502 overlay \u2502 5154.3 \u2502 8301.3 \u2502 12630.1 \u2502 1074749 \u2502 4416 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 2642.2 \u2502 17232.6 \u2502 - \u2502 - \u2502\n\u2502 (188.6 \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 MB) \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 2934.3 \u2502 17600.6 \u2502 - \u2502 - \u2502\n\u2502 (1.3 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 4415.4 \u2502 21415.2 \u2502 - \u2502 - \u2502\n\u2502 (6.3 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage I/O Profile \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Path \u2503 Workload \u2503 Block \u2503 IOPS \u2503 Throughput \u2503 Avg Lat \u2503 P95 Lat \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 seq_write \u2502 4k \u2502 10339 \u2502 40.4 MB/s \u2502 0.097 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 4k \u2502 686238 \u2502 2680.6 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 4k \u2502 598121 \u2502 2336.4 MB/s \u2502 0.002 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 64k \u2502 8400 \u2502 525.0 MB/s \u2502 0.119 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 64k \u2502 43135 \u2502 2696.0 MB/s \u2502 0.023 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 64k \u2502 40908 \u2502 2556.8 MB/s \u2502 0.024 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 1m \u2502 1295 \u2502 1294.7 MB/s \u2502 0.772 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 1m \u2502 3134 \u2502 3133.8 MB/s \u2502 0.319 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 1m \u2502 3388 \u2502 3388.4 MB/s \u2502 0.295 ms \u2502 - \u2502\n\u2502 /root \u2502 read_4k \u2502 4k \u2502 26671 \u2502 104.2 MB/s \u2502 0.037 ms \u2502 0.06 ms \u2502\n\u2502 /root \u2502 write_4k_s\u2026 \u2502 4k \u2502 6655 \u2502 26.0 MB/s \u2502 0.15 ms \u2502 0.211 ms \u2502\n\u2502 /tmp \u2502 seq_write \u2502 4k \u2502 756513 \u2502 2955.1 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 4k \u2502 1051858 \u2502 4108.8 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 4k \u2502 1272976 \u2502 4972.6 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 64k \u2502 70250 \u2502 4390.6 MB/s \u2502 0.014 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 64k \u2502 79050 \u2502 4940.7 MB/s \u2502 0.013 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 64k \u2502 137215 \u2502 8575.9 MB/s \u2502 0.007 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 1m \u2502 758 \u2502 757.7 MB/s \u2502 1.32 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 1m \u2502 8117 \u2502 8116.9 MB/s \u2502 0.123 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 1m \u2502 11985 \u2502 11984.7 \u2502 0.083 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /tmp \u2502 read_4k \u2502 4k \u2502 22657 \u2502 88.5 MB/s \u2502 0.044 ms \u2502 0.071 ms \u2502\n\u2502 /tmp \u2502 write_4k_s\u2026 \u2502 4k \u2502 9902 \u2502 38.7 MB/s \u2502 0.101 ms \u2502 0.162 ms \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 4k \u2502 747833 \u2502 2921.2 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 4k \u2502 953651 \u2502 3725.2 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 4k \u2502 1330271 \u2502 5196.4 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 64k \u2502 69155 \u2502 4322.2 MB/s \u2502 0.014 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 64k \u2502 97392 \u2502 6087.0 MB/s \u2502 0.01 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 64k \u2502 128415 \u2502 8025.9 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 1m \u2502 4385 \u2502 4384.9 MB/s \u2502 0.228 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 1m \u2502 6346 \u2502 6345.5 MB/s \u2502 0.158 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 1m \u2502 8116 \u2502 8115.9 MB/s \u2502 0.123 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 read_4k \u2502 4k \u2502 22504 \u2502 87.9 MB/s \u2502 0.044 ms \u2502 0.072 ms \u2502\n\u2502 /var/tmp \u2502 write_4k_s\u2026 \u2502 4k \u2502 8905 \u2502 34.8 MB/s \u2502 0.112 ms \u2502 0.209 ms \u2502\n\u2502 /var/log \u2502 seq_write \u2502 4k \u2502 677774 \u2502 2647.6 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 4k \u2502 847125 \u2502 3309.1 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 4k \u2502 1240151 \u2502 4844.3 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 64k \u2502 76141 \u2502 4758.8 MB/s \u2502 0.013 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 64k \u2502 85989 \u2502 5374.3 MB/s \u2502 0.012 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 64k \u2502 124139 \u2502 7758.7 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 1m \u2502 4498 \u2502 4498.1 MB/s \u2502 0.222 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 1m \u2502 5150 \u2502 5149.9 MB/s \u2502 0.194 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 1m \u2502 6974 \u2502 6974.0 MB/s \u2502 0.143 ms \u2502 - \u2502\n\u2502 /var/log \u2502 read_4k \u2502 4k \u2502 23922 \u2502 93.4 MB/s \u2502 0.042 ms \u2502 0.074 ms \u2502\n\u2502 /var/log \u2502 write_4k_s\u2026 \u2502 4k \u2502 10124 \u2502 39.5 MB/s \u2502 0.099 ms \u2502 0.147 ms \u2502\n\u2502 /run \u2502 seq_write \u2502 4k \u2502 704042 \u2502 2750.2 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 4k \u2502 936061 \u2502 3656.5 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 4k \u2502 1271803 \u2502 4968.0 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 64k \u2502 70081 \u2502 4380.0 MB/s \u2502 0.014 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 64k \u2502 81156 \u2502 5072.2 MB/s \u2502 0.012 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 64k \u2502 116141 \u2502 7258.8 MB/s \u2502 0.009 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 1m \u2502 4033 \u2502 4033.0 MB/s \u2502 0.248 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 1m \u2502 5010 \u2502 5010.0 MB/s \u2502 0.2 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 1m \u2502 7629 \u2502 7628.7 MB/s \u2502 0.131 ms \u2502 - \u2502\n\u2502 /run \u2502 read_4k \u2502 4k \u2502 30447 \u2502 118.9 MB/s \u2502 0.033 ms \u2502 0.056 ms \u2502\n\u2502 /run \u2502 write_4k_s\u2026 \u2502 4k \u2502 11754 \u2502 45.9 MB/s \u2502 0.085 ms \u2502 0.17 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 6.2 \u2502 7.1 \u2502 7.8 \u2502\n\u2502 node \u2502 27.5 \u2502 29.1 \u2502 30.2 \u2502\n\u2502 claude \u2502 138.4 \u2502 154.4 \u2502 186.0 \u2502\n\u2502 gemini \u2502 812.9 \u2502 863.4 \u2502 912.0 \u2502\n\u2502 codex \u2502 134.6 \u2502 136.5 \u2502 138.3 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Skipped \u2502 set CAPSEM_MOCK_SERVER_BASE_URL for local lab or \u2502\n\u2502 \u2502 CAPSEM_BENCH_ALLOW_PUBLIC_NETWORK=1 for explicit public smoke \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Skipped \u2502 set CAPSEM_MOCK_SERVER_BASE_URL for local lab or \u2502\n\u2502 \u2502 CAPSEM_BENCH_ALLOW_PUBLIC_NETWORK=1 for explicit public smoke \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 1049.1 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 512.9 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 500.0 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 370.8 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 1476.9 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 420.3 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 456.4 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 556.0 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 449.4 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 1726.7 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 419.1 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 535.8 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 579.1 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 383.4 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 1678.8 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/parallel/data_1.2.1779673506_x86_64.json b/benchmarks/parallel/data_1.2.1779673506_x86_64.json
deleted file mode 100644
index 64a2f4fe5..000000000
--- a/benchmarks/parallel/data_1.2.1779673506_x86_64.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "version": "1.0",
- "timestamp": 1780145289.8252459,
- "num_vms": 4,
- "total_duration_ms": 106522.5769369863,
- "results": [
- {
- "vm": "par-bench-d34ade-0",
- "status": "success",
- "duration_ms": 106008.23470400064,
- "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 152.7 MB/s \u2502 - \u2502 1676.8 ms \u2502\n\u2502 Seq read (1MB) \u2502 378.1 MB/s \u2502 - \u2502 677.1 ms \u2502\n\u2502 Rand write (4K) \u2502 8.0 MB/s \u2502 2050 \u2502 4877.1 ms \u2502\n\u2502 Rand read (4K) \u2502 18.7 MB/s \u2502 4779 \u2502 2092.3 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 claude.exe (228.5 MB) \u2502 161.0 MB/s \u2502 - \u2502 1419.9 ms \u2502\n\u2502 Rand read (4K) \u2502 2582 files \u2502 5.0 MB/s \u2502 1287 \u2502 3885.3 ms \u2502\n\u2502 Large bin cold \u2502 3 files \u2502 157.2 MB/s \u2502 - \u2502 4254.9 ms \u2502\n\u2502 Large bin warm \u2502 3 files \u2502 5459.9 MB/s \u2502 - \u2502 122.5 ms \u2502\n\u2502 Small JS reads \u2502 113 files \u2502 767.4 MB/s \u2502 88290 \u2502 56.6 ms \u2502\n\u2502 Metadata stat \u2502 6573 entries \u2502 - \u2502 37758 \u2502 174.1 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage Path Diagnostics \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 \u2503 \u2503 \u2503 Cold \u2503 \u2503 Rand \u2503 Rand \u2503\n\u2503 Path \u2503 FS \u2503 Write \u2503 Read \u2503 Warm Read \u2503 Read \u2503 Write \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 virtiofs \u2502 533.0 \u2502 506.3 \u2502 474.7 \u2502 5019 \u2502 1874 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /tmp \u2502 overlay \u2502 810.4 \u2502 1478.8 \u2502 4829.7 \u2502 348067 \u2502 2067 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/tmp \u2502 overlay \u2502 844.2 \u2502 1268.4 \u2502 4925.4 \u2502 336957 \u2502 2114 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/log \u2502 overlay \u2502 683.0 \u2502 1383.6 \u2502 4828.7 \u2502 457619 \u2502 2111 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /run \u2502 overlay \u2502 789.9 \u2502 1294.3 \u2502 4823.9 \u2502 440878 \u2502 2032 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 169.9 \u2502 5147.2 \u2502 - \u2502 - \u2502\n\u2502 (228.5 \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 MB) \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 549.3 \u2502 5078.1 \u2502 - \u2502 - \u2502\n\u2502 (1.2 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 320.2 \u2502 5304.7 \u2502 - \u2502 - \u2502\n\u2502 (6.5 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage I/O Profile \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Path \u2503 Workload \u2503 Block \u2503 IOPS \u2503 Throughput \u2503 Avg Lat \u2503 P95 Lat \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 seq_write \u2502 4k \u2502 3581 \u2502 14.0 MB/s \u2502 0.279 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_co\u2026 \u2502 4k \u2502 108855 \u2502 425.2 MB/s \u2502 0.009 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_wa\u2026 \u2502 4k \u2502 113604 \u2502 443.8 MB/s \u2502 0.009 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 64k \u2502 2308 \u2502 144.3 MB/s \u2502 0.433 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_co\u2026 \u2502 64k \u2502 7969 \u2502 498.1 MB/s \u2502 0.125 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_wa\u2026 \u2502 64k \u2502 7090 \u2502 443.1 MB/s \u2502 0.141 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 1m \u2502 538 \u2502 537.6 MB/s \u2502 1.86 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_co\u2026 \u2502 1m \u2502 432 \u2502 431.8 MB/s \u2502 2.316 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_wa\u2026 \u2502 1m \u2502 423 \u2502 422.9 MB/s \u2502 2.364 ms \u2502 - \u2502\n\u2502 /root \u2502 read_4k \u2502 4k \u2502 4317 \u2502 16.9 MB/s \u2502 0.232 ms \u2502 0.344 ms \u2502\n\u2502 /root \u2502 write_4k_sy\u2026 \u2502 4k \u2502 1960 \u2502 7.7 MB/s \u2502 0.51 ms \u2502 0.688 ms \u2502\n\u2502 /tmp \u2502 seq_write \u2502 4k \u2502 206445 \u2502 806.4 MB/s \u2502 0.005 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_co\u2026 \u2502 4k \u2502 244860 \u2502 956.5 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_wa\u2026 \u2502 4k \u2502 686074 \u2502 2680.0 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 64k \u2502 18556 \u2502 1159.7 MB/s \u2502 0.054 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_co\u2026 \u2502 64k \u2502 23132 \u2502 1445.8 MB/s \u2502 0.043 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_wa\u2026 \u2502 64k \u2502 88079 \u2502 5505.0 MB/s \u2502 0.011 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 1m \u2502 861 \u2502 861.2 MB/s \u2502 1.161 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_co\u2026 \u2502 1m \u2502 1284 \u2502 1284.4 MB/s \u2502 0.779 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_wa\u2026 \u2502 1m \u2502 5062 \u2502 5061.9 MB/s \u2502 0.198 ms \u2502 - \u2502\n\u2502 /tmp \u2502 read_4k \u2502 4k \u2502 7362 \u2502 28.8 MB/s \u2502 0.136 ms \u2502 0.192 ms \u2502\n\u2502 /tmp \u2502 write_4k_sy\u2026 \u2502 4k \u2502 5839 \u2502 22.8 MB/s \u2502 0.171 ms \u2502 0.244 ms \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 4k \u2502 234893 \u2502 917.6 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_co\u2026 \u2502 4k \u2502 230179 \u2502 899.1 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_wa\u2026 \u2502 4k \u2502 681107 \u2502 2660.6 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 64k \u2502 17475 \u2502 1092.2 MB/s \u2502 0.057 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_co\u2026 \u2502 64k \u2502 24598 \u2502 1537.3 MB/s \u2502 0.041 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_wa\u2026 \u2502 64k \u2502 75687 \u2502 4730.5 MB/s \u2502 0.013 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 1m \u2502 1000 \u2502 999.8 MB/s \u2502 1.0 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_co\u2026 \u2502 1m \u2502 1544 \u2502 1544.1 MB/s \u2502 0.648 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_wa\u2026 \u2502 1m \u2502 5255 \u2502 5255.2 MB/s \u2502 0.19 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 read_4k \u2502 4k \u2502 7520 \u2502 29.4 MB/s \u2502 0.133 ms \u2502 0.177 ms \u2502\n\u2502 /var/tmp \u2502 write_4k_sy\u2026 \u2502 4k \u2502 6162 \u2502 24.1 MB/s \u2502 0.162 ms \u2502 0.221 ms \u2502\n\u2502 /var/log \u2502 seq_write \u2502 4k \u2502 269841 \u2502 1054.1 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_co\u2026 \u2502 4k \u2502 246040 \u2502 961.1 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_wa\u2026 \u2502 4k \u2502 548773 \u2502 2143.6 MB/s \u2502 0.002 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 64k \u2502 15204 \u2502 950.2 MB/s \u2502 0.066 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_co\u2026 \u2502 64k \u2502 22368 \u2502 1398.0 MB/s \u2502 0.045 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_wa\u2026 \u2502 64k \u2502 90107 \u2502 5631.7 MB/s \u2502 0.011 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 1m \u2502 965 \u2502 965.2 MB/s \u2502 1.036 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_co\u2026 \u2502 1m \u2502 1344 \u2502 1344.2 MB/s \u2502 0.744 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_wa\u2026 \u2502 1m \u2502 5444 \u2502 5443.7 MB/s \u2502 0.184 ms \u2502 - \u2502\n\u2502 /var/log \u2502 read_4k \u2502 4k \u2502 9574 \u2502 37.4 MB/s \u2502 0.104 ms \u2502 0.141 ms \u2502\n\u2502 /var/log \u2502 write_4k_sy\u2026 \u2502 4k \u2502 6059 \u2502 23.7 MB/s \u2502 0.165 ms \u2502 0.238 ms \u2502\n\u2502 /run \u2502 seq_write \u2502 4k \u2502 231885 \u2502 905.8 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_co\u2026 \u2502 4k \u2502 239519 \u2502 935.6 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_wa\u2026 \u2502 4k \u2502 693114 \u2502 2707.5 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 64k \u2502 17583 \u2502 1098.9 MB/s \u2502 0.057 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_co\u2026 \u2502 64k \u2502 26493 \u2502 1655.8 MB/s \u2502 0.038 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_wa\u2026 \u2502 64k \u2502 91603 \u2502 5725.2 MB/s \u2502 0.011 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 1m \u2502 842 \u2502 842.4 MB/s \u2502 1.187 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_co\u2026 \u2502 1m \u2502 1542 \u2502 1541.8 MB/s \u2502 0.649 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_wa\u2026 \u2502 1m \u2502 5380 \u2502 5380.5 MB/s \u2502 0.186 ms \u2502 - \u2502\n\u2502 /run \u2502 read_4k \u2502 4k \u2502 8820 \u2502 34.5 MB/s \u2502 0.113 ms \u2502 0.159 ms \u2502\n\u2502 /run \u2502 write_4k_sy\u2026 \u2502 4k \u2502 6209 \u2502 24.3 MB/s \u2502 0.161 ms \u2502 0.211 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 31.2 \u2502 31.6 \u2502 32.5 \u2502\n\u2502 node \u2502 303.7 \u2502 338.2 \u2502 355.8 \u2502\n\u2502 claude \u2502 1497.7 \u2502 1531.1 \u2502 1548.1 \u2502\n\u2502 gemini \u2502 3120.6 \u2502 3233.6 \u2502 3403.7 \u2502\n\u2502 codex \u2502 1024.0 \u2502 1130.6 \u2502 1289.1 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 50/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 55.3 \u2502\n\u2502 Transfer \u2502 3.8 MB \u2502\n\u2502 Duration \u2502 904.0 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 49.5 ms \u2502\n\u2502 Latency mean \u2502 83.6 ms \u2502\n\u2502 Latency p50 \u2502 58.3 ms \u2502\n\u2502 Latency p95 \u2502 274.4 ms \u2502\n\u2502 Latency p99 \u2502 313.6 ms \u2502\n\u2502 Latency max \u2502 313.6 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-slides.pdf] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-\u2026 \u2502\n\u2502 Downloaded \u2502 9.5 MB \u2502\n\u2502 Duration \u2502 0.43s \u2502\n\u2502 Throughput \u2502 22.27 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 3293.9 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 1053.6 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 1143.4 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 1037.3 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 1078.6 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 1158.3 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 1010.6 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 1016.0 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 1047.1 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 1091.7 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 1189.9 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 1025.0 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 1067.9 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 982.5 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 1032.1 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
- },
- {
- "vm": "par-bench-b51851-1",
- "status": "success",
- "duration_ms": 105129.10781800747,
- "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 153.7 MB/s \u2502 - \u2502 1665.7 ms \u2502\n\u2502 Seq read (1MB) \u2502 360.9 MB/s \u2502 - \u2502 709.4 ms \u2502\n\u2502 Rand write (4K) \u2502 7.9 MB/s \u2502 2018 \u2502 4956.3 ms \u2502\n\u2502 Rand read (4K) \u2502 19.0 MB/s \u2502 4869 \u2502 2053.7 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 claude.exe (228.5 MB) \u2502 147.0 MB/s \u2502 - \u2502 1555.1 ms \u2502\n\u2502 Rand read (4K) \u2502 2561 files \u2502 4.9 MB/s \u2502 1249 \u2502 4004.5 ms \u2502\n\u2502 Large bin cold \u2502 3 files \u2502 176.8 MB/s \u2502 - \u2502 3783.8 ms \u2502\n\u2502 Large bin warm \u2502 3 files \u2502 5346.4 MB/s \u2502 - \u2502 125.1 ms \u2502\n\u2502 Small JS reads \u2502 113 files \u2502 724.0 MB/s \u2502 86686 \u2502 57.7 ms \u2502\n\u2502 Metadata stat \u2502 6573 entries \u2502 - \u2502 41100 \u2502 159.9 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage Path Diagnostics \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 \u2503 \u2503 \u2503 Cold \u2503 \u2503 Rand \u2503 Rand \u2503\n\u2503 Path \u2503 FS \u2503 Write \u2503 Read \u2503 Warm Read \u2503 Read \u2503 Write \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 virtiofs \u2502 500.9 \u2502 427.2 \u2502 481.7 \u2502 5532 \u2502 1790 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /tmp \u2502 overlay \u2502 674.4 \u2502 1412.4 \u2502 5281.8 \u2502 443329 \u2502 2094 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/tmp \u2502 overlay \u2502 874.0 \u2502 1320.9 \u2502 5247.2 \u2502 307424 \u2502 2110 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/log \u2502 overlay \u2502 851.8 \u2502 1288.8 \u2502 4771.7 \u2502 375921 \u2502 2144 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /run \u2502 overlay \u2502 994.2 \u2502 1490.1 \u2502 4857.6 \u2502 433949 \u2502 2157 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 192.4 \u2502 5321.5 \u2502 - \u2502 - \u2502\n\u2502 (228.5 \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 MB) \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 648.2 \u2502 5551.0 \u2502 - \u2502 - \u2502\n\u2502 (1.2 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 372.3 \u2502 5645.4 \u2502 - \u2502 - \u2502\n\u2502 (6.5 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage I/O Profile \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Path \u2503 Workload \u2503 Block \u2503 IOPS \u2503 Throughput \u2503 Avg Lat \u2503 P95 Lat \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 seq_write \u2502 4k \u2502 3724 \u2502 14.5 MB/s \u2502 0.269 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_co\u2026 \u2502 4k \u2502 126660 \u2502 494.8 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_wa\u2026 \u2502 4k \u2502 125920 \u2502 491.9 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 64k \u2502 2398 \u2502 149.9 MB/s \u2502 0.417 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_co\u2026 \u2502 64k \u2502 7129 \u2502 445.5 MB/s \u2502 0.14 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_wa\u2026 \u2502 64k \u2502 6596 \u2502 412.3 MB/s \u2502 0.152 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 1m \u2502 562 \u2502 562.3 MB/s \u2502 1.779 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_co\u2026 \u2502 1m \u2502 416 \u2502 415.9 MB/s \u2502 2.405 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_wa\u2026 \u2502 1m \u2502 427 \u2502 427.1 MB/s \u2502 2.342 ms \u2502 - \u2502\n\u2502 /root \u2502 read_4k \u2502 4k \u2502 4307 \u2502 16.8 MB/s \u2502 0.232 ms \u2502 0.356 ms \u2502\n\u2502 /root \u2502 write_4k_sy\u2026 \u2502 4k \u2502 1872 \u2502 7.3 MB/s \u2502 0.534 ms \u2502 0.702 ms \u2502\n\u2502 /tmp \u2502 seq_write \u2502 4k \u2502 251232 \u2502 981.4 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_co\u2026 \u2502 4k \u2502 299177 \u2502 1168.7 MB/s \u2502 0.003 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_wa\u2026 \u2502 4k \u2502 702023 \u2502 2742.3 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 64k \u2502 16438 \u2502 1027.3 MB/s \u2502 0.061 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_co\u2026 \u2502 64k \u2502 22711 \u2502 1419.4 MB/s \u2502 0.044 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_wa\u2026 \u2502 64k \u2502 94110 \u2502 5881.9 MB/s \u2502 0.011 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 1m \u2502 994 \u2502 993.5 MB/s \u2502 1.007 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_co\u2026 \u2502 1m \u2502 1421 \u2502 1420.8 MB/s \u2502 0.704 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_wa\u2026 \u2502 1m \u2502 5467 \u2502 5467.3 MB/s \u2502 0.183 ms \u2502 - \u2502\n\u2502 /tmp \u2502 read_4k \u2502 4k \u2502 8053 \u2502 31.5 MB/s \u2502 0.124 ms \u2502 0.163 ms \u2502\n\u2502 /tmp \u2502 write_4k_sy\u2026 \u2502 4k \u2502 6659 \u2502 26.0 MB/s \u2502 0.15 ms \u2502 0.21 ms \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 4k \u2502 201940 \u2502 788.8 MB/s \u2502 0.005 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_co\u2026 \u2502 4k \u2502 239016 \u2502 933.7 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_wa\u2026 \u2502 4k \u2502 690966 \u2502 2699.1 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 64k \u2502 13688 \u2502 855.5 MB/s \u2502 0.073 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_co\u2026 \u2502 64k \u2502 19827 \u2502 1239.2 MB/s \u2502 0.05 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_wa\u2026 \u2502 64k \u2502 93782 \u2502 5861.4 MB/s \u2502 0.011 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 1m \u2502 925 \u2502 925.4 MB/s \u2502 1.081 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_co\u2026 \u2502 1m \u2502 1423 \u2502 1423.2 MB/s \u2502 0.703 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_wa\u2026 \u2502 1m \u2502 4961 \u2502 4960.6 MB/s \u2502 0.202 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 read_4k \u2502 4k \u2502 7828 \u2502 30.6 MB/s \u2502 0.128 ms \u2502 0.176 ms \u2502\n\u2502 /var/tmp \u2502 write_4k_sy\u2026 \u2502 4k \u2502 6826 \u2502 26.7 MB/s \u2502 0.146 ms \u2502 0.199 ms \u2502\n\u2502 /var/log \u2502 seq_write \u2502 4k \u2502 226335 \u2502 884.1 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_co\u2026 \u2502 4k \u2502 248001 \u2502 968.8 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_wa\u2026 \u2502 4k \u2502 642604 \u2502 2510.2 MB/s \u2502 0.002 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 64k \u2502 13823 \u2502 863.9 MB/s \u2502 0.072 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_co\u2026 \u2502 64k \u2502 19082 \u2502 1192.6 MB/s \u2502 0.052 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_wa\u2026 \u2502 64k \u2502 89325 \u2502 5582.8 MB/s \u2502 0.011 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 1m \u2502 884 \u2502 883.9 MB/s \u2502 1.131 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_co\u2026 \u2502 1m \u2502 1426 \u2502 1425.7 MB/s \u2502 0.701 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_wa\u2026 \u2502 1m \u2502 5314 \u2502 5313.5 MB/s \u2502 0.188 ms \u2502 - \u2502\n\u2502 /var/log \u2502 read_4k \u2502 4k \u2502 7259 \u2502 28.4 MB/s \u2502 0.138 ms \u2502 0.181 ms \u2502\n\u2502 /var/log \u2502 write_4k_sy\u2026 \u2502 4k \u2502 6154 \u2502 24.0 MB/s \u2502 0.162 ms \u2502 0.22 ms \u2502\n\u2502 /run \u2502 seq_write \u2502 4k \u2502 267597 \u2502 1045.3 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_co\u2026 \u2502 4k \u2502 215706 \u2502 842.6 MB/s \u2502 0.005 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_wa\u2026 \u2502 4k \u2502 685931 \u2502 2679.4 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 64k \u2502 13314 \u2502 832.2 MB/s \u2502 0.075 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_co\u2026 \u2502 64k \u2502 18089 \u2502 1130.6 MB/s \u2502 0.055 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_wa\u2026 \u2502 64k \u2502 81918 \u2502 5119.9 MB/s \u2502 0.012 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 1m \u2502 864 \u2502 864.4 MB/s \u2502 1.157 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_co\u2026 \u2502 1m \u2502 1528 \u2502 1527.5 MB/s \u2502 0.655 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_wa\u2026 \u2502 1m \u2502 5348 \u2502 5347.6 MB/s \u2502 0.187 ms \u2502 - \u2502\n\u2502 /run \u2502 read_4k \u2502 4k \u2502 7737 \u2502 30.2 MB/s \u2502 0.129 ms \u2502 0.172 ms \u2502\n\u2502 /run \u2502 write_4k_sy\u2026 \u2502 4k \u2502 6296 \u2502 24.6 MB/s \u2502 0.159 ms \u2502 0.21 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 31.1 \u2502 31.3 \u2502 31.8 \u2502\n\u2502 node \u2502 302.9 \u2502 338.6 \u2502 357.5 \u2502\n\u2502 claude \u2502 1338.4 \u2502 1580.9 \u2502 1804.8 \u2502\n\u2502 gemini \u2502 3116.2 \u2502 3315.4 \u2502 3447.4 \u2502\n\u2502 codex \u2502 1028.9 \u2502 1047.1 \u2502 1083.3 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 50/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 53.4 \u2502\n\u2502 Transfer \u2502 3.8 MB \u2502\n\u2502 Duration \u2502 936.3 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 50.6 ms \u2502\n\u2502 Latency mean \u2502 87.3 ms \u2502\n\u2502 Latency p50 \u2502 58.6 ms \u2502\n\u2502 Latency p95 \u2502 313.7 ms \u2502\n\u2502 Latency p99 \u2502 320.7 ms \u2502\n\u2502 Latency max \u2502 324.0 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-slides.pdf] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-\u2026 \u2502\n\u2502 Downloaded \u2502 9.5 MB \u2502\n\u2502 Duration \u2502 0.48s \u2502\n\u2502 Throughput \u2502 19.89 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 3482.0 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 1008.0 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 1000.0 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 1075.0 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 1021.0 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 1212.9 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 1020.3 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 1030.6 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 1006.5 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 1027.6 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 1302.7 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 1077.9 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 1161.9 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 1020.4 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 1023.6 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
- },
- {
- "vm": "par-bench-e6be41-2",
- "status": "success",
- "duration_ms": 105721.47011599736,
- "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 153.0 MB/s \u2502 - \u2502 1673.0 ms \u2502\n\u2502 Seq read (1MB) \u2502 305.0 MB/s \u2502 - \u2502 839.4 ms \u2502\n\u2502 Rand write (4K) \u2502 7.7 MB/s \u2502 1974 \u2502 5064.5 ms \u2502\n\u2502 Rand read (4K) \u2502 21.2 MB/s \u2502 5417 \u2502 1846.1 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 claude.exe (228.5 MB) \u2502 167.6 MB/s \u2502 - \u2502 1363.3 ms \u2502\n\u2502 Rand read (4K) \u2502 2581 files \u2502 4.8 MB/s \u2502 1226 \u2502 4077.7 ms \u2502\n\u2502 Large bin cold \u2502 3 files \u2502 150.7 MB/s \u2502 - \u2502 4439.5 ms \u2502\n\u2502 Large bin warm \u2502 3 files \u2502 5225.2 MB/s \u2502 - \u2502 128.0 ms \u2502\n\u2502 Small JS reads \u2502 113 files \u2502 577.9 MB/s \u2502 70190 \u2502 71.2 ms \u2502\n\u2502 Metadata stat \u2502 6573 entries \u2502 - \u2502 38686 \u2502 169.9 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage Path Diagnostics \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 \u2503 \u2503 \u2503 Cold \u2503 \u2503 Rand \u2503 Rand \u2503\n\u2503 Path \u2503 FS \u2503 Write \u2503 Read \u2503 Warm Read \u2503 Read \u2503 Write \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 virtiofs \u2502 514.4 \u2502 603.6 \u2502 519.8 \u2502 4988 \u2502 1920 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /tmp \u2502 overlay \u2502 855.5 \u2502 1643.8 \u2502 5326.1 \u2502 452240 \u2502 2072 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/tmp \u2502 overlay \u2502 887.6 \u2502 1278.6 \u2502 5212.0 \u2502 424973 \u2502 2087 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/log \u2502 overlay \u2502 787.7 \u2502 1480.4 \u2502 4725.5 \u2502 342612 \u2502 2035 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /run \u2502 overlay \u2502 944.9 \u2502 1258.2 \u2502 4723.1 \u2502 452761 \u2502 2063 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 187.3 \u2502 5608.0 \u2502 - \u2502 - \u2502\n\u2502 (228.5 \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 MB) \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 610.0 \u2502 5311.7 \u2502 - \u2502 - \u2502\n\u2502 (1.2 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 305.2 \u2502 4792.5 \u2502 - \u2502 - \u2502\n\u2502 (6.5 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage I/O Profile \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Path \u2503 Workload \u2503 Block \u2503 IOPS \u2503 Throughput \u2503 Avg Lat \u2503 P95 Lat \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 seq_write \u2502 4k \u2502 3876 \u2502 15.1 MB/s \u2502 0.258 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_co\u2026 \u2502 4k \u2502 114279 \u2502 446.4 MB/s \u2502 0.009 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_wa\u2026 \u2502 4k \u2502 114640 \u2502 447.8 MB/s \u2502 0.009 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 64k \u2502 2289 \u2502 143.0 MB/s \u2502 0.437 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_co\u2026 \u2502 64k \u2502 6940 \u2502 433.8 MB/s \u2502 0.144 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_wa\u2026 \u2502 64k \u2502 6421 \u2502 401.3 MB/s \u2502 0.156 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 1m \u2502 542 \u2502 542.1 MB/s \u2502 1.845 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_co\u2026 \u2502 1m \u2502 473 \u2502 472.6 MB/s \u2502 2.116 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_wa\u2026 \u2502 1m \u2502 484 \u2502 484.0 MB/s \u2502 2.066 ms \u2502 - \u2502\n\u2502 /root \u2502 read_4k \u2502 4k \u2502 4087 \u2502 16.0 MB/s \u2502 0.245 ms \u2502 0.354 ms \u2502\n\u2502 /root \u2502 write_4k_sy\u2026 \u2502 4k \u2502 1824 \u2502 7.1 MB/s \u2502 0.548 ms \u2502 0.746 ms \u2502\n\u2502 /tmp \u2502 seq_write \u2502 4k \u2502 274519 \u2502 1072.3 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_co\u2026 \u2502 4k \u2502 209693 \u2502 819.1 MB/s \u2502 0.005 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_wa\u2026 \u2502 4k \u2502 655644 \u2502 2561.1 MB/s \u2502 0.002 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 64k \u2502 14296 \u2502 893.5 MB/s \u2502 0.07 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_co\u2026 \u2502 64k \u2502 20695 \u2502 1293.4 MB/s \u2502 0.048 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_wa\u2026 \u2502 64k \u2502 85255 \u2502 5328.4 MB/s \u2502 0.012 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 1m \u2502 824 \u2502 824.0 MB/s \u2502 1.214 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_co\u2026 \u2502 1m \u2502 1241 \u2502 1241.2 MB/s \u2502 0.806 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_wa\u2026 \u2502 1m \u2502 5469 \u2502 5469.2 MB/s \u2502 0.183 ms \u2502 - \u2502\n\u2502 /tmp \u2502 read_4k \u2502 4k \u2502 7408 \u2502 28.9 MB/s \u2502 0.135 ms \u2502 0.17 ms \u2502\n\u2502 /tmp \u2502 write_4k_sy\u2026 \u2502 4k \u2502 6374 \u2502 24.9 MB/s \u2502 0.157 ms \u2502 0.197 ms \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 4k \u2502 258371 \u2502 1009.3 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_co\u2026 \u2502 4k \u2502 213502 \u2502 834.0 MB/s \u2502 0.005 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_wa\u2026 \u2502 4k \u2502 550638 \u2502 2150.9 MB/s \u2502 0.002 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 64k \u2502 14456 \u2502 903.5 MB/s \u2502 0.069 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_co\u2026 \u2502 64k \u2502 22998 \u2502 1437.4 MB/s \u2502 0.043 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_wa\u2026 \u2502 64k \u2502 89556 \u2502 5597.2 MB/s \u2502 0.011 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 1m \u2502 900 \u2502 899.6 MB/s \u2502 1.112 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_co\u2026 \u2502 1m \u2502 1410 \u2502 1410.5 MB/s \u2502 0.709 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_wa\u2026 \u2502 1m \u2502 4747 \u2502 4747.0 MB/s \u2502 0.211 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 read_4k \u2502 4k \u2502 7206 \u2502 28.1 MB/s \u2502 0.139 ms \u2502 0.186 ms \u2502\n\u2502 /var/tmp \u2502 write_4k_sy\u2026 \u2502 4k \u2502 5622 \u2502 22.0 MB/s \u2502 0.178 ms \u2502 0.287 ms \u2502\n\u2502 /var/log \u2502 seq_write \u2502 4k \u2502 248460 \u2502 970.5 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_co\u2026 \u2502 4k \u2502 242922 \u2502 948.9 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_wa\u2026 \u2502 4k \u2502 687437 \u2502 2685.3 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 64k \u2502 16214 \u2502 1013.4 MB/s \u2502 0.062 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_co\u2026 \u2502 64k \u2502 22330 \u2502 1395.6 MB/s \u2502 0.045 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_wa\u2026 \u2502 64k \u2502 91401 \u2502 5712.6 MB/s \u2502 0.011 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 1m \u2502 973 \u2502 972.6 MB/s \u2502 1.028 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_co\u2026 \u2502 1m \u2502 1461 \u2502 1461.2 MB/s \u2502 0.684 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_wa\u2026 \u2502 1m \u2502 5028 \u2502 5028.2 MB/s \u2502 0.199 ms \u2502 - \u2502\n\u2502 /var/log \u2502 read_4k \u2502 4k \u2502 8224 \u2502 32.1 MB/s \u2502 0.122 ms \u2502 0.159 ms \u2502\n\u2502 /var/log \u2502 write_4k_sy\u2026 \u2502 4k \u2502 6109 \u2502 23.9 MB/s \u2502 0.164 ms \u2502 0.219 ms \u2502\n\u2502 /run \u2502 seq_write \u2502 4k \u2502 283997 \u2502 1109.4 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_co\u2026 \u2502 4k \u2502 318896 \u2502 1245.7 MB/s \u2502 0.003 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_wa\u2026 \u2502 4k \u2502 697559 \u2502 2724.8 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 64k \u2502 13266 \u2502 829.1 MB/s \u2502 0.075 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_co\u2026 \u2502 64k \u2502 23873 \u2502 1492.1 MB/s \u2502 0.042 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_wa\u2026 \u2502 64k \u2502 89766 \u2502 5610.4 MB/s \u2502 0.011 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 1m \u2502 922 \u2502 921.9 MB/s \u2502 1.085 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_co\u2026 \u2502 1m \u2502 1226 \u2502 1225.9 MB/s \u2502 0.816 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_wa\u2026 \u2502 1m \u2502 4650 \u2502 4649.6 MB/s \u2502 0.215 ms \u2502 - \u2502\n\u2502 /run \u2502 read_4k \u2502 4k \u2502 7692 \u2502 30.0 MB/s \u2502 0.13 ms \u2502 0.173 ms \u2502\n\u2502 /run \u2502 write_4k_sy\u2026 \u2502 4k \u2502 7336 \u2502 28.7 MB/s \u2502 0.136 ms \u2502 0.186 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 30.9 \u2502 31.3 \u2502 31.8 \u2502\n\u2502 node \u2502 300.0 \u2502 302.2 \u2502 303.8 \u2502\n\u2502 claude \u2502 1439.7 \u2502 1511.5 \u2502 1595.4 \u2502\n\u2502 gemini \u2502 3176.2 \u2502 3306.5 \u2502 3511.0 \u2502\n\u2502 codex \u2502 871.3 \u2502 994.7 \u2502 1080.9 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 50/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 57.5 \u2502\n\u2502 Transfer \u2502 3.8 MB \u2502\n\u2502 Duration \u2502 869.1 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 49.4 ms \u2502\n\u2502 Latency mean \u2502 83.9 ms \u2502\n\u2502 Latency p50 \u2502 58.4 ms \u2502\n\u2502 Latency p95 \u2502 291.1 ms \u2502\n\u2502 Latency p99 \u2502 315.2 ms \u2502\n\u2502 Latency max \u2502 318.8 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-slides.pdf] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-\u2026 \u2502\n\u2502 Downloaded \u2502 9.5 MB \u2502\n\u2502 Duration \u2502 0.47s \u2502\n\u2502 Throughput \u2502 20.36 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 3329.7 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 1025.0 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 1118.8 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 1010.3 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 1035.1 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 1220.4 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 1016.9 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 1022.4 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 1002.8 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 1078.7 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 1188.9 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 1033.3 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 1109.2 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 1016.3 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 1028.0 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
- },
- {
- "vm": "par-bench-924f80-3",
- "status": "success",
- "duration_ms": 106519.86509701237,
- "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 149.3 MB/s \u2502 - \u2502 1714.6 ms \u2502\n\u2502 Seq read (1MB) \u2502 355.8 MB/s \u2502 - \u2502 719.5 ms \u2502\n\u2502 Rand write (4K) \u2502 7.4 MB/s \u2502 1886 \u2502 5302.4 ms \u2502\n\u2502 Rand read (4K) \u2502 19.8 MB/s \u2502 5076 \u2502 1970.3 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 claude.exe (228.5 MB) \u2502 148.2 MB/s \u2502 - \u2502 1542.5 ms \u2502\n\u2502 Rand read (4K) \u2502 2605 files \u2502 4.9 MB/s \u2502 1258 \u2502 3975.5 ms \u2502\n\u2502 Large bin cold \u2502 3 files \u2502 157.9 MB/s \u2502 - \u2502 4235.9 ms \u2502\n\u2502 Large bin warm \u2502 3 files \u2502 5270.5 MB/s \u2502 - \u2502 126.9 ms \u2502\n\u2502 Small JS reads \u2502 113 files \u2502 610.8 MB/s \u2502 72054 \u2502 69.4 ms \u2502\n\u2502 Metadata stat \u2502 6573 entries \u2502 - \u2502 35859 \u2502 183.3 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage Path Diagnostics \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 \u2503 \u2503 \u2503 Cold \u2503 \u2503 Rand \u2503 Rand \u2503\n\u2503 Path \u2503 FS \u2503 Write \u2503 Read \u2503 Warm Read \u2503 Read \u2503 Write \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 virtiofs \u2502 501.9 \u2502 450.0 \u2502 422.6 \u2502 5180 \u2502 1874 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /tmp \u2502 overlay \u2502 746.3 \u2502 1419.6 \u2502 4877.4 \u2502 454519 \u2502 2109 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/tmp \u2502 overlay \u2502 1020.5 \u2502 1494.9 \u2502 5435.6 \u2502 455182 \u2502 2133 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/log \u2502 overlay \u2502 700.6 \u2502 1305.4 \u2502 5550.9 \u2502 449355 \u2502 2200 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /run \u2502 overlay \u2502 852.2 \u2502 1390.7 \u2502 4709.7 \u2502 439342 \u2502 2127 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 157.9 \u2502 5403.6 \u2502 - \u2502 - \u2502\n\u2502 (228.5 \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 MB) \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 543.6 \u2502 3650.8 \u2502 - \u2502 - \u2502\n\u2502 (1.2 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 306.4 \u2502 4701.0 \u2502 - \u2502 - \u2502\n\u2502 (6.5 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage I/O Profile \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Path \u2503 Workload \u2503 Block \u2503 IOPS \u2503 Throughput \u2503 Avg Lat \u2503 P95 Lat \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 seq_write \u2502 4k \u2502 3473 \u2502 13.6 MB/s \u2502 0.288 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_co\u2026 \u2502 4k \u2502 111558 \u2502 435.8 MB/s \u2502 0.009 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_wa\u2026 \u2502 4k \u2502 125834 \u2502 491.5 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 64k \u2502 2339 \u2502 146.2 MB/s \u2502 0.427 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_co\u2026 \u2502 64k \u2502 7163 \u2502 447.7 MB/s \u2502 0.14 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_wa\u2026 \u2502 64k \u2502 7370 \u2502 460.6 MB/s \u2502 0.136 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 1m \u2502 564 \u2502 564.5 MB/s \u2502 1.771 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_co\u2026 \u2502 1m \u2502 437 \u2502 436.9 MB/s \u2502 2.289 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_wa\u2026 \u2502 1m \u2502 431 \u2502 430.6 MB/s \u2502 2.323 ms \u2502 - \u2502\n\u2502 /root \u2502 read_4k \u2502 4k \u2502 3981 \u2502 15.6 MB/s \u2502 0.251 ms \u2502 0.359 ms \u2502\n\u2502 /root \u2502 write_4k_sy\u2026 \u2502 4k \u2502 1817 \u2502 7.1 MB/s \u2502 0.55 ms \u2502 0.746 ms \u2502\n\u2502 /tmp \u2502 seq_write \u2502 4k \u2502 270425 \u2502 1056.3 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_co\u2026 \u2502 4k \u2502 244171 \u2502 953.8 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_wa\u2026 \u2502 4k \u2502 493882 \u2502 1929.2 MB/s \u2502 0.002 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 64k \u2502 15224 \u2502 951.5 MB/s \u2502 0.066 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_co\u2026 \u2502 64k \u2502 24423 \u2502 1526.4 MB/s \u2502 0.041 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_wa\u2026 \u2502 64k \u2502 89774 \u2502 5610.9 MB/s \u2502 0.011 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 1m \u2502 1001 \u2502 1001.2 MB/s \u2502 0.999 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_co\u2026 \u2502 1m \u2502 1247 \u2502 1246.6 MB/s \u2502 0.802 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_wa\u2026 \u2502 1m \u2502 5030 \u2502 5030.5 MB/s \u2502 0.199 ms \u2502 - \u2502\n\u2502 /tmp \u2502 read_4k \u2502 4k \u2502 8185 \u2502 32.0 MB/s \u2502 0.122 ms \u2502 0.158 ms \u2502\n\u2502 /tmp \u2502 write_4k_sy\u2026 \u2502 4k \u2502 6330 \u2502 24.7 MB/s \u2502 0.158 ms \u2502 0.198 ms \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 4k \u2502 263174 \u2502 1028.0 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_co\u2026 \u2502 4k \u2502 215903 \u2502 843.4 MB/s \u2502 0.005 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_wa\u2026 \u2502 4k \u2502 679938 \u2502 2656.0 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 64k \u2502 13689 \u2502 855.5 MB/s \u2502 0.073 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_co\u2026 \u2502 64k \u2502 22845 \u2502 1427.8 MB/s \u2502 0.044 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_wa\u2026 \u2502 64k \u2502 89735 \u2502 5608.4 MB/s \u2502 0.011 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 1m \u2502 923 \u2502 923.1 MB/s \u2502 1.083 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_co\u2026 \u2502 1m \u2502 1208 \u2502 1208.0 MB/s \u2502 0.828 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_wa\u2026 \u2502 1m \u2502 4492 \u2502 4492.2 MB/s \u2502 0.223 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 read_4k \u2502 4k \u2502 7535 \u2502 29.4 MB/s \u2502 0.133 ms \u2502 0.185 ms \u2502\n\u2502 /var/tmp \u2502 write_4k_sy\u2026 \u2502 4k \u2502 7016 \u2502 27.4 MB/s \u2502 0.143 ms \u2502 0.196 ms \u2502\n\u2502 /var/log \u2502 seq_write \u2502 4k \u2502 220460 \u2502 861.2 MB/s \u2502 0.005 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_co\u2026 \u2502 4k \u2502 274642 \u2502 1072.8 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_wa\u2026 \u2502 4k \u2502 693798 \u2502 2710.1 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 64k \u2502 15591 \u2502 974.4 MB/s \u2502 0.064 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_co\u2026 \u2502 64k \u2502 24249 \u2502 1515.6 MB/s \u2502 0.041 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_wa\u2026 \u2502 64k \u2502 78140 \u2502 4883.8 MB/s \u2502 0.013 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 1m \u2502 930 \u2502 929.6 MB/s \u2502 1.076 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_co\u2026 \u2502 1m \u2502 1392 \u2502 1391.6 MB/s \u2502 0.719 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_wa\u2026 \u2502 1m \u2502 5589 \u2502 5589.1 MB/s \u2502 0.179 ms \u2502 - \u2502\n\u2502 /var/log \u2502 read_4k \u2502 4k \u2502 9018 \u2502 35.2 MB/s \u2502 0.111 ms \u2502 0.152 ms \u2502\n\u2502 /var/log \u2502 write_4k_sy\u2026 \u2502 4k \u2502 6016 \u2502 23.5 MB/s \u2502 0.166 ms \u2502 0.233 ms \u2502\n\u2502 /run \u2502 seq_write \u2502 4k \u2502 209272 \u2502 817.5 MB/s \u2502 0.005 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_co\u2026 \u2502 4k \u2502 276713 \u2502 1080.9 MB/s \u2502 0.004 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_wa\u2026 \u2502 4k \u2502 627116 \u2502 2449.7 MB/s \u2502 0.002 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 64k \u2502 14908 \u2502 931.7 MB/s \u2502 0.067 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_co\u2026 \u2502 64k \u2502 19001 \u2502 1187.6 MB/s \u2502 0.053 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_wa\u2026 \u2502 64k \u2502 79087 \u2502 4943.0 MB/s \u2502 0.013 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 1m \u2502 753 \u2502 753.1 MB/s \u2502 1.328 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_co\u2026 \u2502 1m \u2502 1181 \u2502 1181.3 MB/s \u2502 0.847 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_wa\u2026 \u2502 1m \u2502 5316 \u2502 5316.2 MB/s \u2502 0.188 ms \u2502 - \u2502\n\u2502 /run \u2502 read_4k \u2502 4k \u2502 7702 \u2502 30.1 MB/s \u2502 0.13 ms \u2502 0.169 ms \u2502\n\u2502 /run \u2502 write_4k_sy\u2026 \u2502 4k \u2502 7182 \u2502 28.1 MB/s \u2502 0.139 ms \u2502 0.193 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 31.0 \u2502 31.5 \u2502 32.5 \u2502\n\u2502 node \u2502 352.8 \u2502 353.8 \u2502 354.9 \u2502\n\u2502 claude \u2502 1339.6 \u2502 1549.2 \u2502 1757.0 \u2502\n\u2502 gemini \u2502 3172.0 \u2502 3378.4 \u2502 3527.7 \u2502\n\u2502 codex \u2502 977.2 \u2502 995.8 \u2502 1029.2 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 50/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 53.4 \u2502\n\u2502 Transfer \u2502 3.8 MB \u2502\n\u2502 Duration \u2502 936.5 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 48.7 ms \u2502\n\u2502 Latency mean \u2502 88.2 ms \u2502\n\u2502 Latency p50 \u2502 57.8 ms \u2502\n\u2502 Latency p95 \u2502 329.4 ms \u2502\n\u2502 Latency p99 \u2502 340.3 ms \u2502\n\u2502 Latency max \u2502 341.4 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-slides.pdf] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-\u2026 \u2502\n\u2502 Downloaded \u2502 9.5 MB \u2502\n\u2502 Duration \u2502 0.46s \u2502\n\u2502 Throughput \u2502 20.91 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 3409.7 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 1054.1 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 1014.5 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 1037.4 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 1081.0 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 1145.1 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 1029.0 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 1044.7 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 1003.8 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 1101.8 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 1185.8 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 1029.8 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 1068.7 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 992.0 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 1022.7 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
- }
- ],
- "schema": "capsem.benchmark-artifact.v1",
- "project_version": "1.2.1779673506",
- "arch": "x86_64",
- "recorded_at": 1780145289.8255649,
- "recorded_at_utc": "2026-05-30T12:48:09.825568+00:00",
- "command": "uv run pytest tests/capsem-serial/test_parallel_benchmark.py -xvs",
- "host": {
- "platform": "Linux",
- "release": "7.0.0-1003-gcp",
- "version": "#3-Ubuntu SMP PREEMPT Mon Apr 13 16:29:20 UTC 2026",
- "machine": "x86_64",
- "processor": "",
- "python_version": "3.14.4",
- "cpu_count": 16,
- "cpu_count_logical": 16,
- "cpu_model": "Intel(R) Xeon(R) CPU @ 2.80GHz",
- "cpu_count_physical": 8,
- "memory_total_bytes": 67415740416,
- "memory_total_gb": 62.79,
- "os_pretty_name": "Ubuntu 26.04 LTS",
- "os_id": "ubuntu",
- "os_version_id": "26.04"
- },
- "git": {
- "commit": "b6f9b6e2342496f7c9c5dadd77548aa8d138678e",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/capsem-bench/data_1.2.1779673506_x86_64.json",
- "benchmarks/fork/data_1.2.1779673506_x86_64.json",
- "benchmarks/host-native/data_1.2.1779673506_x86_64.json",
- "benchmarks/lifecycle/data_1.2.1779673506_x86_64.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_security_packs_microbench.json"
- ]
- }
-}
\ No newline at end of file
diff --git a/benchmarks/parallel/data_1.2.1780103109_arm64.json b/benchmarks/parallel/data_1.2.1780103109_arm64.json
deleted file mode 100644
index 9ee77ff1b..000000000
--- a/benchmarks/parallel/data_1.2.1780103109_arm64.json
+++ /dev/null
@@ -1,67 +0,0 @@
-{
- "version": "1.0",
- "timestamp": 1780149901.62083,
- "num_vms": 4,
- "total_duration_ms": 33184.21941692941,
- "results": [
- {
- "vm": "par-bench-a578d8-0",
- "status": "success",
- "duration_ms": 33183.09783306904,
- "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 813.6 MB/s \u2502 - \u2502 314.6 ms \u2502\n\u2502 Seq read (1MB) \u2502 1817.6 MB/s \u2502 - \u2502 140.8 ms \u2502\n\u2502 Rand write (4K) \u2502 22.2 MB/s \u2502 5679 \u2502 1760.9 ms \u2502\n\u2502 Rand read (4K) \u2502 126.5 MB/s \u2502 32373 \u2502 308.9 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 claude.exe (227.4 MB) \u2502 652.6 MB/s \u2502 - \u2502 348.4 ms \u2502\n\u2502 Rand read (4K) \u2502 2575 files \u2502 17.1 MB/s \u2502 4376 \u2502 1142.5 ms \u2502\n\u2502 Large bin cold \u2502 3 files \u2502 815.0 MB/s \u2502 - \u2502 777.9 ms \u2502\n\u2502 Large bin warm \u2502 3 files \u2502 24014.1 MB/s \u2502 - \u2502 26.4 ms \u2502\n\u2502 Small JS reads \u2502 113 files \u2502 2299.2 MB/s \u2502 276803 \u2502 18.1 ms \u2502\n\u2502 Metadata stat \u2502 6571 entries \u2502 - \u2502 152768 \u2502 43.0 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage Path Diagnostics \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 \u2503 \u2503 \u2503 Cold \u2503 \u2503 Rand \u2503 Rand \u2503\n\u2503 Path \u2503 FS \u2503 Write \u2503 Read \u2503 Warm Read \u2503 Read \u2503 Write \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 virtiofs \u2502 1632.7 \u2502 2935.7 \u2502 3423.6 \u2502 35930 \u2502 5449 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /tmp \u2502 overlay \u2502 7442.4 \u2502 8349.2 \u2502 22022.1 \u2502 1411034 \u2502 4973 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/tmp \u2502 overlay \u2502 7640.5 \u2502 8692.6 \u2502 21253.6 \u2502 1658868 \u2502 4968 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/log \u2502 overlay \u2502 7883.2 \u2502 10002.3 \u2502 22782.2 \u2502 1693779 \u2502 5287 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /run \u2502 overlay \u2502 8060.3 \u2502 10042.2 \u2502 24190.9 \u2502 778862 \u2502 5054 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 862.8 \u2502 19436.8 \u2502 - \u2502 - \u2502\n\u2502 (227.4 \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 MB) \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 2084.3 \u2502 20795.2 \u2502 - \u2502 - \u2502\n\u2502 (1.3 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 1276.1 \u2502 24474.6 \u2502 - \u2502 - \u2502\n\u2502 (6.3 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage I/O Profile \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Path \u2503 Workload \u2503 Block \u2503 IOPS \u2503 Throughput \u2503 Avg Lat \u2503 P95 Lat \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 seq_write \u2502 4k \u2502 11083 \u2502 43.3 MB/s \u2502 0.09 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 4k \u2502 674750 \u2502 2635.7 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 4k \u2502 695436 \u2502 2716.5 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 64k \u2502 7910 \u2502 494.4 MB/s \u2502 0.126 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 64k \u2502 48212 \u2502 3013.3 MB/s \u2502 0.021 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 64k \u2502 47124 \u2502 2945.3 MB/s \u2502 0.021 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 1m \u2502 1647 \u2502 1647.0 MB/s \u2502 0.607 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 1m \u2502 3531 \u2502 3530.6 MB/s \u2502 0.283 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 1m \u2502 3540 \u2502 3539.5 MB/s \u2502 0.283 ms \u2502 - \u2502\n\u2502 /root \u2502 read_4k \u2502 4k \u2502 27814 \u2502 108.6 MB/s \u2502 0.036 ms \u2502 0.055 ms \u2502\n\u2502 /root \u2502 write_4k_s\u2026 \u2502 4k \u2502 6547 \u2502 25.6 MB/s \u2502 0.153 ms \u2502 0.213 ms \u2502\n\u2502 /tmp \u2502 seq_write \u2502 4k \u2502 1305693 \u2502 5100.4 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 4k \u2502 1603863 \u2502 6265.1 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 4k \u2502 2231595 \u2502 8717.2 MB/s \u2502 0.0 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 64k \u2502 120578 \u2502 7536.1 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 64k \u2502 153563 \u2502 9597.7 MB/s \u2502 0.007 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 64k \u2502 328231 \u2502 20514.5 \u2502 0.003 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /tmp \u2502 seq_write \u2502 1m \u2502 7905 \u2502 7905.0 MB/s \u2502 0.127 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 1m \u2502 9374 \u2502 9374.0 MB/s \u2502 0.107 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 1m \u2502 21561 \u2502 21560.9 \u2502 0.046 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /tmp \u2502 read_4k \u2502 4k \u2502 20698 \u2502 80.8 MB/s \u2502 0.048 ms \u2502 0.076 ms \u2502\n\u2502 /tmp \u2502 write_4k_s\u2026 \u2502 4k \u2502 9391 \u2502 36.7 MB/s \u2502 0.106 ms \u2502 0.156 ms \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 4k \u2502 1477856 \u2502 5772.9 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 4k \u2502 1831663 \u2502 7154.9 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 4k \u2502 2394155 \u2502 9352.2 MB/s \u2502 0.0 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 64k \u2502 132435 \u2502 8277.2 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 64k \u2502 173188 \u2502 10824.2 \u2502 0.006 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 64k \u2502 350875 \u2502 21929.7 \u2502 0.003 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 1m \u2502 8268 \u2502 8268.2 MB/s \u2502 0.121 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 1m \u2502 11128 \u2502 11128.2 \u2502 0.09 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 1m \u2502 23323 \u2502 23322.6 \u2502 0.043 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/tmp \u2502 read_4k \u2502 4k \u2502 24638 \u2502 96.2 MB/s \u2502 0.041 ms \u2502 0.064 ms \u2502\n\u2502 /var/tmp \u2502 write_4k_s\u2026 \u2502 4k \u2502 11264 \u2502 44.0 MB/s \u2502 0.089 ms \u2502 0.13 ms \u2502\n\u2502 /var/log \u2502 seq_write \u2502 4k \u2502 1501690 \u2502 5866.0 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 4k \u2502 1956036 \u2502 7640.8 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 4k \u2502 2654766 \u2502 10370.2 \u2502 0.0 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/log \u2502 seq_write \u2502 64k \u2502 131294 \u2502 8205.9 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 64k \u2502 178541 \u2502 11158.8 \u2502 0.006 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 64k \u2502 339288 \u2502 21205.5 \u2502 0.003 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/log \u2502 seq_write \u2502 1m \u2502 8318 \u2502 8317.7 MB/s \u2502 0.12 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 1m \u2502 10478 \u2502 10477.5 \u2502 0.095 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 1m \u2502 24097 \u2502 24097.1 \u2502 0.041 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/log \u2502 read_4k \u2502 4k \u2502 24990 \u2502 97.6 MB/s \u2502 0.04 ms \u2502 0.062 ms \u2502\n\u2502 /var/log \u2502 write_4k_s\u2026 \u2502 4k \u2502 10182 \u2502 39.8 MB/s \u2502 0.098 ms \u2502 0.148 ms \u2502\n\u2502 /run \u2502 seq_write \u2502 4k \u2502 926730 \u2502 3620.0 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 4k \u2502 1591723 \u2502 6217.7 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 4k \u2502 2368828 \u2502 9253.2 MB/s \u2502 0.0 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 64k \u2502 96914 \u2502 6057.1 MB/s \u2502 0.01 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 64k \u2502 116551 \u2502 7284.4 MB/s \u2502 0.009 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 64k \u2502 298687 \u2502 18668.0 \u2502 0.003 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /run \u2502 seq_write \u2502 1m \u2502 7192 \u2502 7192.3 MB/s \u2502 0.139 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 1m \u2502 7227 \u2502 7227.0 MB/s \u2502 0.138 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 1m \u2502 16157 \u2502 16157.0 \u2502 0.062 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /run \u2502 read_4k \u2502 4k \u2502 17437 \u2502 68.1 MB/s \u2502 0.057 ms \u2502 0.131 ms \u2502\n\u2502 /run \u2502 write_4k_s\u2026 \u2502 4k \u2502 12536 \u2502 49.0 MB/s \u2502 0.08 ms \u2502 0.14 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 7.3 \u2502 8.3 \u2502 9.2 \u2502\n\u2502 node \u2502 79.6 \u2502 81.4 \u2502 82.6 \u2502\n\u2502 claude \u2502 335.2 \u2502 338.0 \u2502 343.0 \u2502\n\u2502 gemini \u2502 865.7 \u2502 914.7 \u2502 972.7 \u2502\n\u2502 codex \u2502 233.2 \u2502 235.9 \u2502 237.4 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 50/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 28.3 \u2502\n\u2502 Transfer \u2502 3.8 MB \u2502\n\u2502 Duration \u2502 1765.6 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 53.5 ms \u2502\n\u2502 Latency mean \u2502 156.3 ms \u2502\n\u2502 Latency p50 \u2502 60.7 ms \u2502\n\u2502 Latency p95 \u2502 918.9 ms \u2502\n\u2502 Latency p99 \u2502 1162.9 ms \u2502\n\u2502 Latency max \u2502 1199.7 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-slides.pdf] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-\u2026 \u2502\n\u2502 Downloaded \u2502 9.5 MB \u2502\n\u2502 Duration \u2502 0.45s \u2502\n\u2502 Throughput \u2502 21.16 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 871.5 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 368.7 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 341.0 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 332.1 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 348.5 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 331.4 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 350.0 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 337.7 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 322.6 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 293.3 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 288.0 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 281.4 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 298.9 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 288.9 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 289.3 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
- },
- {
- "vm": "par-bench-17e28d-1",
- "status": "success",
- "duration_ms": 30974.315082887188,
- "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 975.0 MB/s \u2502 - \u2502 262.6 ms \u2502\n\u2502 Seq read (1MB) \u2502 1959.8 MB/s \u2502 - \u2502 130.6 ms \u2502\n\u2502 Rand write (4K) \u2502 24.7 MB/s \u2502 6322 \u2502 1581.7 ms \u2502\n\u2502 Rand read (4K) \u2502 195.7 MB/s \u2502 50097 \u2502 199.6 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 claude.exe (227.4 MB) \u2502 791.6 MB/s \u2502 - \u2502 287.2 ms \u2502\n\u2502 Rand read (4K) \u2502 2592 files \u2502 21.1 MB/s \u2502 5392 \u2502 927.4 ms \u2502\n\u2502 Large bin cold \u2502 3 files \u2502 744.3 MB/s \u2502 - \u2502 851.8 ms \u2502\n\u2502 Large bin warm \u2502 3 files \u2502 21637.3 MB/s \u2502 - \u2502 29.3 ms \u2502\n\u2502 Small JS reads \u2502 113 files \u2502 2729.4 MB/s \u2502 316232 \u2502 15.8 ms \u2502\n\u2502 Metadata stat \u2502 6571 entries \u2502 - \u2502 156951 \u2502 41.9 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage Path Diagnostics \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 \u2503 \u2503 \u2503 Cold \u2503 \u2503 Rand \u2503 Rand \u2503\n\u2503 Path \u2503 FS \u2503 Write \u2503 Read \u2503 Warm Read \u2503 Read \u2503 Write \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 virtiofs \u2502 2022.8 \u2502 4000.6 \u2502 4558.6 \u2502 60426 \u2502 7472 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /tmp \u2502 overlay \u2502 6986.3 \u2502 9928.1 \u2502 20361.1 \u2502 1277160 \u2502 4592 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/tmp \u2502 overlay \u2502 7055.5 \u2502 7969.0 \u2502 17371.0 \u2502 1681862 \u2502 4711 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/log \u2502 overlay \u2502 7548.1 \u2502 8859.4 \u2502 19077.7 \u2502 1608202 \u2502 5618 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /run \u2502 overlay \u2502 8079.4 \u2502 9909.2 \u2502 20061.6 \u2502 1694568 \u2502 5565 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 941.6 \u2502 22290.6 \u2502 - \u2502 - \u2502\n\u2502 (227.4 \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 MB) \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 2250.8 \u2502 19468.5 \u2502 - \u2502 - \u2502\n\u2502 (1.3 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 1349.9 \u2502 25552.3 \u2502 - \u2502 - \u2502\n\u2502 (6.3 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage I/O Profile \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Path \u2503 Workload \u2503 Block \u2503 IOPS \u2503 Throughput \u2503 Avg Lat \u2503 P95 Lat \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 seq_write \u2502 4k \u2502 15664 \u2502 61.2 MB/s \u2502 0.064 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 4k \u2502 1024945 \u2502 4003.7 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 4k \u2502 1010197 \u2502 3946.1 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 64k \u2502 13340 \u2502 833.8 MB/s \u2502 0.075 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 64k \u2502 65533 \u2502 4095.8 MB/s \u2502 0.015 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 64k \u2502 64796 \u2502 4049.8 MB/s \u2502 0.015 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 1m \u2502 2273 \u2502 2272.8 MB/s \u2502 0.44 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 1m \u2502 4525 \u2502 4525.0 MB/s \u2502 0.221 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 1m \u2502 4232 \u2502 4232.0 MB/s \u2502 0.236 ms \u2502 - \u2502\n\u2502 /root \u2502 read_4k \u2502 4k \u2502 38109 \u2502 148.9 MB/s \u2502 0.026 ms \u2502 0.046 ms \u2502\n\u2502 /root \u2502 write_4k_s\u2026 \u2502 4k \u2502 8771 \u2502 34.3 MB/s \u2502 0.114 ms \u2502 0.15 ms \u2502\n\u2502 /tmp \u2502 seq_write \u2502 4k \u2502 1083956 \u2502 4234.2 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 4k \u2502 1780096 \u2502 6953.5 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 4k \u2502 2413478 \u2502 9427.7 MB/s \u2502 0.0 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 64k \u2502 119846 \u2502 7490.4 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 64k \u2502 158043 \u2502 9877.7 MB/s \u2502 0.006 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 64k \u2502 280650 \u2502 17540.7 \u2502 0.004 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /tmp \u2502 seq_write \u2502 1m \u2502 6862 \u2502 6862.0 MB/s \u2502 0.146 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 1m \u2502 9436 \u2502 9436.1 MB/s \u2502 0.106 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 1m \u2502 17820 \u2502 17819.9 \u2502 0.056 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /tmp \u2502 read_4k \u2502 4k \u2502 33306 \u2502 130.1 MB/s \u2502 0.03 ms \u2502 0.049 ms \u2502\n\u2502 /tmp \u2502 write_4k_s\u2026 \u2502 4k \u2502 14039 \u2502 54.8 MB/s \u2502 0.071 ms \u2502 0.106 ms \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 4k \u2502 1436007 \u2502 5609.4 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 4k \u2502 1812022 \u2502 7078.2 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 4k \u2502 2330376 \u2502 9103.0 MB/s \u2502 0.0 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 64k \u2502 111092 \u2502 6943.3 MB/s \u2502 0.009 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 64k \u2502 170745 \u2502 10671.6 \u2502 0.006 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 64k \u2502 302332 \u2502 18895.8 \u2502 0.003 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 1m \u2502 7454 \u2502 7454.3 MB/s \u2502 0.134 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 1m \u2502 9792 \u2502 9792.5 MB/s \u2502 0.102 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 1m \u2502 19100 \u2502 19100.0 \u2502 0.052 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/tmp \u2502 read_4k \u2502 4k \u2502 34086 \u2502 133.1 MB/s \u2502 0.029 ms \u2502 0.047 ms \u2502\n\u2502 /var/tmp \u2502 write_4k_s\u2026 \u2502 4k \u2502 15517 \u2502 60.6 MB/s \u2502 0.064 ms \u2502 0.097 ms \u2502\n\u2502 /var/log \u2502 seq_write \u2502 4k \u2502 1478039 \u2502 5773.6 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 4k \u2502 1674264 \u2502 6540.1 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 4k \u2502 2306712 \u2502 9010.6 MB/s \u2502 0.0 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 64k \u2502 124310 \u2502 7769.3 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 64k \u2502 163628 \u2502 10226.8 \u2502 0.006 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 64k \u2502 297548 \u2502 18596.8 \u2502 0.003 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/log \u2502 seq_write \u2502 1m \u2502 8006 \u2502 8006.5 MB/s \u2502 0.125 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 1m \u2502 10216 \u2502 10216.5 \u2502 0.098 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 1m \u2502 18565 \u2502 18565.3 \u2502 0.054 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/log \u2502 read_4k \u2502 4k \u2502 25339 \u2502 99.0 MB/s \u2502 0.039 ms \u2502 0.06 ms \u2502\n\u2502 /var/log \u2502 write_4k_s\u2026 \u2502 4k \u2502 11555 \u2502 45.1 MB/s \u2502 0.087 ms \u2502 0.125 ms \u2502\n\u2502 /run \u2502 seq_write \u2502 4k \u2502 1511050 \u2502 5902.5 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 4k \u2502 1867974 \u2502 7296.8 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 4k \u2502 2516115 \u2502 9828.6 MB/s \u2502 0.0 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 64k \u2502 126266 \u2502 7891.6 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 64k \u2502 153817 \u2502 9613.6 MB/s \u2502 0.007 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 64k \u2502 290820 \u2502 18176.2 \u2502 0.003 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /run \u2502 seq_write \u2502 1m \u2502 7514 \u2502 7514.5 MB/s \u2502 0.133 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 1m \u2502 9149 \u2502 9148.7 MB/s \u2502 0.109 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 1m \u2502 19866 \u2502 19866.0 \u2502 0.05 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /run \u2502 read_4k \u2502 4k \u2502 22228 \u2502 86.8 MB/s \u2502 0.045 ms \u2502 0.071 ms \u2502\n\u2502 /run \u2502 write_4k_s\u2026 \u2502 4k \u2502 10858 \u2502 42.4 MB/s \u2502 0.092 ms \u2502 0.134 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 5.4 \u2502 7.0 \u2502 8.5 \u2502\n\u2502 node \u2502 128.0 \u2502 129.7 \u2502 130.7 \u2502\n\u2502 claude \u2502 340.2 \u2502 342.2 \u2502 343.9 \u2502\n\u2502 gemini \u2502 925.8 \u2502 971.1 \u2502 1018.4 \u2502\n\u2502 codex \u2502 241.3 \u2502 274.4 \u2502 292.8 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 50/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 66.4 \u2502\n\u2502 Transfer \u2502 3.8 MB \u2502\n\u2502 Duration \u2502 753.5 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 51.5 ms \u2502\n\u2502 Latency mean \u2502 72.8 ms \u2502\n\u2502 Latency p50 \u2502 59.9 ms \u2502\n\u2502 Latency p95 \u2502 176.3 ms \u2502\n\u2502 Latency p99 \u2502 185.0 ms \u2502\n\u2502 Latency max \u2502 189.6 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-slides.pdf] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-\u2026 \u2502\n\u2502 Downloaded \u2502 9.5 MB \u2502\n\u2502 Duration \u2502 0.52s \u2502\n\u2502 Throughput \u2502 18.31 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 812.1 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 371.2 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 394.7 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 396.5 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 358.3 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 355.8 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 335.5 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 339.4 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 359.8 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 354.9 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 339.1 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 345.9 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 363.4 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 351.3 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 346.0 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
- },
- {
- "vm": "par-bench-21c4d7-2",
- "status": "success",
- "duration_ms": 31158.650916069746,
- "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 975.2 MB/s \u2502 - \u2502 262.5 ms \u2502\n\u2502 Seq read (1MB) \u2502 1969.6 MB/s \u2502 - \u2502 130.0 ms \u2502\n\u2502 Rand write (4K) \u2502 25.4 MB/s \u2502 6493 \u2502 1540.1 ms \u2502\n\u2502 Rand read (4K) \u2502 194.6 MB/s \u2502 49814 \u2502 200.7 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 claude.exe (227.4 MB) \u2502 799.9 MB/s \u2502 - \u2502 284.2 ms \u2502\n\u2502 Rand read (4K) \u2502 2568 files \u2502 21.5 MB/s \u2502 5508 \u2502 907.7 ms \u2502\n\u2502 Large bin cold \u2502 3 files \u2502 748.6 MB/s \u2502 - \u2502 846.9 ms \u2502\n\u2502 Large bin warm \u2502 3 files \u2502 19999.1 MB/s \u2502 - \u2502 31.7 ms \u2502\n\u2502 Small JS reads \u2502 113 files \u2502 2900.5 MB/s \u2502 327330 \u2502 15.3 ms \u2502\n\u2502 Metadata stat \u2502 6571 entries \u2502 - \u2502 162362 \u2502 40.5 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage Path Diagnostics \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 \u2503 \u2503 \u2503 Cold \u2503 \u2503 Rand \u2503 Rand \u2503\n\u2503 Path \u2503 FS \u2503 Write \u2503 Read \u2503 Warm Read \u2503 Read \u2503 Write \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 virtiofs \u2502 2083.2 \u2502 3822.1 \u2502 4428.0 \u2502 55322 \u2502 6961 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /tmp \u2502 overlay \u2502 7796.9 \u2502 10239.3 \u2502 21317.9 \u2502 1451247 \u2502 4977 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/tmp \u2502 overlay \u2502 7999.2 \u2502 8988.1 \u2502 17511.3 \u2502 1524836 \u2502 4751 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/log \u2502 overlay \u2502 7569.6 \u2502 8217.2 \u2502 16622.7 \u2502 1592336 \u2502 4859 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /run \u2502 overlay \u2502 7782.2 \u2502 9525.1 \u2502 18867.7 \u2502 1571123 \u2502 5065 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 938.5 \u2502 23837.4 \u2502 - \u2502 - \u2502\n\u2502 (227.4 \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 MB) \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 1904.3 \u2502 18246.6 \u2502 - \u2502 - \u2502\n\u2502 (1.3 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 1405.3 \u2502 20468.8 \u2502 - \u2502 - \u2502\n\u2502 (6.3 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage I/O Profile \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Path \u2503 Workload \u2503 Block \u2503 IOPS \u2503 Throughput \u2503 Avg Lat \u2503 P95 Lat \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 seq_write \u2502 4k \u2502 15635 \u2502 61.1 MB/s \u2502 0.064 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 4k \u2502 986921 \u2502 3855.2 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 4k \u2502 989200 \u2502 3864.1 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 64k \u2502 13393 \u2502 837.0 MB/s \u2502 0.075 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 64k \u2502 59832 \u2502 3739.5 MB/s \u2502 0.017 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 64k \u2502 62197 \u2502 3887.3 MB/s \u2502 0.016 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 1m \u2502 2327 \u2502 2326.9 MB/s \u2502 0.43 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 1m \u2502 4569 \u2502 4568.6 MB/s \u2502 0.219 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 1m \u2502 4542 \u2502 4541.5 MB/s \u2502 0.22 ms \u2502 - \u2502\n\u2502 /root \u2502 read_4k \u2502 4k \u2502 42685 \u2502 166.7 MB/s \u2502 0.023 ms \u2502 0.043 ms \u2502\n\u2502 /root \u2502 write_4k_s\u2026 \u2502 4k \u2502 9202 \u2502 35.9 MB/s \u2502 0.109 ms \u2502 0.141 ms \u2502\n\u2502 /tmp \u2502 seq_write \u2502 4k \u2502 1129288 \u2502 4411.3 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 4k \u2502 1891999 \u2502 7390.6 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 4k \u2502 2502711 \u2502 9776.2 MB/s \u2502 0.0 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 64k \u2502 123887 \u2502 7742.9 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 64k \u2502 169463 \u2502 10591.4 \u2502 0.006 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 64k \u2502 291925 \u2502 18245.3 \u2502 0.003 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /tmp \u2502 seq_write \u2502 1m \u2502 7866 \u2502 7865.6 MB/s \u2502 0.127 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 1m \u2502 9854 \u2502 9853.6 MB/s \u2502 0.101 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 1m \u2502 17552 \u2502 17552.3 \u2502 0.057 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /tmp \u2502 read_4k \u2502 4k \u2502 42010 \u2502 164.1 MB/s \u2502 0.024 ms \u2502 0.048 ms \u2502\n\u2502 /tmp \u2502 write_4k_s\u2026 \u2502 4k \u2502 15842 \u2502 61.9 MB/s \u2502 0.063 ms \u2502 0.093 ms \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 4k \u2502 1464372 \u2502 5720.2 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 4k \u2502 1885304 \u2502 7364.5 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 4k \u2502 2448952 \u2502 9566.2 MB/s \u2502 0.0 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 64k \u2502 126133 \u2502 7883.3 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 64k \u2502 170807 \u2502 10675.4 \u2502 0.006 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 64k \u2502 283493 \u2502 17718.3 \u2502 0.004 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 1m \u2502 8008 \u2502 8007.9 MB/s \u2502 0.125 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 1m \u2502 10199 \u2502 10198.7 \u2502 0.098 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 1m \u2502 20588 \u2502 20588.4 \u2502 0.049 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/tmp \u2502 read_4k \u2502 4k \u2502 34698 \u2502 135.5 MB/s \u2502 0.029 ms \u2502 0.046 ms \u2502\n\u2502 /var/tmp \u2502 write_4k_s\u2026 \u2502 4k \u2502 15492 \u2502 60.5 MB/s \u2502 0.065 ms \u2502 0.101 ms \u2502\n\u2502 /var/log \u2502 seq_write \u2502 4k \u2502 1470434 \u2502 5743.9 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 4k \u2502 1857351 \u2502 7255.3 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 4k \u2502 2475220 \u2502 9668.8 MB/s \u2502 0.0 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 64k \u2502 121994 \u2502 7624.6 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 64k \u2502 176901 \u2502 11056.3 \u2502 0.006 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 64k \u2502 287385 \u2502 17961.5 \u2502 0.003 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/log \u2502 seq_write \u2502 1m \u2502 8037 \u2502 8037.2 MB/s \u2502 0.124 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 1m \u2502 9880 \u2502 9879.9 MB/s \u2502 0.101 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 1m \u2502 19987 \u2502 19986.7 \u2502 0.05 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/log \u2502 read_4k \u2502 4k \u2502 33716 \u2502 131.7 MB/s \u2502 0.03 ms \u2502 0.046 ms \u2502\n\u2502 /var/log \u2502 write_4k_s\u2026 \u2502 4k \u2502 15407 \u2502 60.2 MB/s \u2502 0.065 ms \u2502 0.093 ms \u2502\n\u2502 /run \u2502 seq_write \u2502 4k \u2502 1500320 \u2502 5860.6 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 4k \u2502 1794876 \u2502 7011.2 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 4k \u2502 2311553 \u2502 9029.5 MB/s \u2502 0.0 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 64k \u2502 120309 \u2502 7519.3 MB/s \u2502 0.008 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 64k \u2502 177858 \u2502 11116.1 \u2502 0.006 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 64k \u2502 311566 \u2502 19472.9 \u2502 0.003 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /run \u2502 seq_write \u2502 1m \u2502 7822 \u2502 7822.5 MB/s \u2502 0.128 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 1m \u2502 9849 \u2502 9849.2 MB/s \u2502 0.102 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 1m \u2502 19717 \u2502 19716.8 \u2502 0.051 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /run \u2502 read_4k \u2502 4k \u2502 34581 \u2502 135.1 MB/s \u2502 0.029 ms \u2502 0.047 ms \u2502\n\u2502 /run \u2502 write_4k_s\u2026 \u2502 4k \u2502 15569 \u2502 60.8 MB/s \u2502 0.064 ms \u2502 0.092 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 7.5 \u2502 8.3 \u2502 9.7 \u2502\n\u2502 node \u2502 127.6 \u2502 129.9 \u2502 131.5 \u2502\n\u2502 claude \u2502 338.4 \u2502 339.5 \u2502 340.7 \u2502\n\u2502 gemini \u2502 917.4 \u2502 951.1 \u2502 1013.9 \u2502\n\u2502 codex \u2502 240.5 \u2502 258.2 \u2502 293.5 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 50/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 65.2 \u2502\n\u2502 Transfer \u2502 3.8 MB \u2502\n\u2502 Duration \u2502 767.4 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 52.8 ms \u2502\n\u2502 Latency mean \u2502 75.5 ms \u2502\n\u2502 Latency p50 \u2502 60.3 ms \u2502\n\u2502 Latency p95 \u2502 195.2 ms \u2502\n\u2502 Latency p99 \u2502 203.1 ms \u2502\n\u2502 Latency max \u2502 203.8 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-slides.pdf] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-\u2026 \u2502\n\u2502 Downloaded \u2502 9.5 MB \u2502\n\u2502 Duration \u2502 0.62s \u2502\n\u2502 Throughput \u2502 15.29 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 822.3 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 420.4 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 392.7 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 376.0 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 360.1 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 338.4 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 337.4 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 340.0 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 370.3 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 333.8 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 354.8 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 337.2 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 374.4 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 348.8 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 331.5 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
- },
- {
- "vm": "par-bench-97976a-3",
- "status": "success",
- "duration_ms": 31644.89100011997,
- "stdout": " Scratch Disk I/O [/root, 256 MB] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq write (1MB) \u2502 966.6 MB/s \u2502 - \u2502 264.8 ms \u2502\n\u2502 Seq read (1MB) \u2502 1922.0 MB/s \u2502 - \u2502 133.2 ms \u2502\n\u2502 Rand write (4K) \u2502 23.2 MB/s \u2502 5931 \u2502 1686.0 ms \u2502\n\u2502 Rand read (4K) \u2502 202.4 MB/s \u2502 51823 \u2502 193.0 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Rootfs Read I/O \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Test \u2503 Detail \u2503 Throughput \u2503 IOPS \u2503 Duration \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Seq read (1MB) \u2502 claude.exe (227.4 MB) \u2502 770.4 MB/s \u2502 - \u2502 295.1 ms \u2502\n\u2502 Rand read (4K) \u2502 2593 files \u2502 21.2 MB/s \u2502 5422 \u2502 922.1 ms \u2502\n\u2502 Large bin cold \u2502 3 files \u2502 748.3 MB/s \u2502 - \u2502 847.2 ms \u2502\n\u2502 Large bin warm \u2502 3 files \u2502 22089.6 MB/s \u2502 - \u2502 28.7 ms \u2502\n\u2502 Small JS reads \u2502 113 files \u2502 2692.5 MB/s \u2502 316986 \u2502 15.8 ms \u2502\n\u2502 Metadata stat \u2502 6571 entries \u2502 - \u2502 174101 \u2502 37.7 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage Path Diagnostics \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 \u2503 \u2503 \u2503 Cold \u2503 \u2503 Rand \u2503 Rand \u2503\n\u2503 Path \u2503 FS \u2503 Write \u2503 Read \u2503 Warm Read \u2503 Read \u2503 Write \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 virtiofs \u2502 1857.9 \u2502 3911.7 \u2502 4431.3 \u2502 53911 \u2502 6730 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /tmp \u2502 overlay \u2502 5221.7 \u2502 7990.2 \u2502 19932.5 \u2502 1330185 \u2502 5053 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/tmp \u2502 overlay \u2502 6542.2 \u2502 7688.8 \u2502 18062.5 \u2502 1609680 \u2502 4473 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /var/log \u2502 overlay \u2502 7032.4 \u2502 8884.7 \u2502 18182.9 \u2502 1664090 \u2502 4607 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 /run \u2502 overlay \u2502 7004.6 \u2502 9517.4 \u2502 19917.3 \u2502 1535096 \u2502 5239 IOPS \u2502\n\u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 MB/s \u2502 IOPS \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 944.4 \u2502 23888.5 \u2502 - \u2502 - \u2502\n\u2502 (227.4 \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 MB) \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 1972.4 \u2502 17865.8 \u2502 - \u2502 - \u2502\n\u2502 (1.3 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 rootfs:\u2026 \u2502 overlay \u2502 - \u2502 1299.9 \u2502 24905.2 \u2502 - \u2502 - \u2502\n\u2502 (6.3 MB) \u2502 \u2502 \u2502 MB/s \u2502 MB/s \u2502 \u2502 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Storage I/O Profile \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Path \u2503 Workload \u2503 Block \u2503 IOPS \u2503 Throughput \u2503 Avg Lat \u2503 P95 Lat \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 /root \u2502 seq_write \u2502 4k \u2502 15592 \u2502 60.9 MB/s \u2502 0.064 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 4k \u2502 1065098 \u2502 4160.5 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 4k \u2502 858241 \u2502 3352.5 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 64k \u2502 13408 \u2502 838.0 MB/s \u2502 0.075 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 64k \u2502 71519 \u2502 4469.9 MB/s \u2502 0.014 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 64k \u2502 70723 \u2502 4420.2 MB/s \u2502 0.014 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_write \u2502 1m \u2502 1839 \u2502 1839.3 MB/s \u2502 0.544 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_c\u2026 \u2502 1m \u2502 4665 \u2502 4664.7 MB/s \u2502 0.214 ms \u2502 - \u2502\n\u2502 /root \u2502 seq_read_w\u2026 \u2502 1m \u2502 4541 \u2502 4541.3 MB/s \u2502 0.22 ms \u2502 - \u2502\n\u2502 /root \u2502 read_4k \u2502 4k \u2502 44110 \u2502 172.3 MB/s \u2502 0.023 ms \u2502 0.033 ms \u2502\n\u2502 /root \u2502 write_4k_s\u2026 \u2502 4k \u2502 9257 \u2502 36.2 MB/s \u2502 0.108 ms \u2502 0.144 ms \u2502\n\u2502 /tmp \u2502 seq_write \u2502 4k \u2502 1290570 \u2502 5041.3 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 4k \u2502 1768137 \u2502 6906.8 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 4k \u2502 2441001 \u2502 9535.2 MB/s \u2502 0.0 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_write \u2502 64k \u2502 116433 \u2502 7277.1 MB/s \u2502 0.009 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 64k \u2502 155985 \u2502 9749.0 MB/s \u2502 0.006 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 64k \u2502 312668 \u2502 19541.7 \u2502 0.003 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /tmp \u2502 seq_write \u2502 1m \u2502 7163 \u2502 7163.0 MB/s \u2502 0.14 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_c\u2026 \u2502 1m \u2502 8779 \u2502 8779.2 MB/s \u2502 0.114 ms \u2502 - \u2502\n\u2502 /tmp \u2502 seq_read_w\u2026 \u2502 1m \u2502 19284 \u2502 19283.9 \u2502 0.052 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /tmp \u2502 read_4k \u2502 4k \u2502 32585 \u2502 127.3 MB/s \u2502 0.031 ms \u2502 0.05 ms \u2502\n\u2502 /tmp \u2502 write_4k_s\u2026 \u2502 4k \u2502 14324 \u2502 56.0 MB/s \u2502 0.07 ms \u2502 0.104 ms \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 4k \u2502 1476047 \u2502 5765.8 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 4k \u2502 1882029 \u2502 7351.7 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 4k \u2502 2400542 \u2502 9377.1 MB/s \u2502 0.0 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 64k \u2502 111605 \u2502 6975.3 MB/s \u2502 0.009 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 64k \u2502 156365 \u2502 9772.8 MB/s \u2502 0.006 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 64k \u2502 276262 \u2502 17266.4 \u2502 0.004 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/tmp \u2502 seq_write \u2502 1m \u2502 7070 \u2502 7070.0 MB/s \u2502 0.141 ms \u2502 - \u2502\n\u2502 /var/tmp \u2502 seq_read_c\u2026 \u2502 1m \u2502 10394 \u2502 10394.0 \u2502 0.096 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/tmp \u2502 seq_read_w\u2026 \u2502 1m \u2502 20352 \u2502 20351.9 \u2502 0.049 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/tmp \u2502 read_4k \u2502 4k \u2502 34238 \u2502 133.7 MB/s \u2502 0.029 ms \u2502 0.045 ms \u2502\n\u2502 /var/tmp \u2502 write_4k_s\u2026 \u2502 4k \u2502 11939 \u2502 46.6 MB/s \u2502 0.084 ms \u2502 0.122 ms \u2502\n\u2502 /var/log \u2502 seq_write \u2502 4k \u2502 1457062 \u2502 5691.7 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 4k \u2502 1913693 \u2502 7475.4 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 4k \u2502 2429569 \u2502 9490.5 MB/s \u2502 0.0 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_write \u2502 64k \u2502 104315 \u2502 6519.7 MB/s \u2502 0.01 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 64k \u2502 171591 \u2502 10724.5 \u2502 0.006 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 64k \u2502 291908 \u2502 18244.2 \u2502 0.003 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/log \u2502 seq_write \u2502 1m \u2502 6401 \u2502 6401.3 MB/s \u2502 0.156 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_c\u2026 \u2502 1m \u2502 9935 \u2502 9934.9 MB/s \u2502 0.101 ms \u2502 - \u2502\n\u2502 /var/log \u2502 seq_read_w\u2026 \u2502 1m \u2502 19577 \u2502 19577.4 \u2502 0.051 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /var/log \u2502 read_4k \u2502 4k \u2502 32515 \u2502 127.0 MB/s \u2502 0.031 ms \u2502 0.051 ms \u2502\n\u2502 /var/log \u2502 write_4k_s\u2026 \u2502 4k \u2502 15291 \u2502 59.7 MB/s \u2502 0.065 ms \u2502 0.09 ms \u2502\n\u2502 /run \u2502 seq_write \u2502 4k \u2502 1410853 \u2502 5511.1 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 4k \u2502 1764155 \u2502 6891.2 MB/s \u2502 0.001 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 4k \u2502 2372258 \u2502 9266.6 MB/s \u2502 0.0 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_write \u2502 64k \u2502 114680 \u2502 7167.5 MB/s \u2502 0.009 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 64k \u2502 167801 \u2502 10487.6 \u2502 0.006 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 64k \u2502 305558 \u2502 19097.4 \u2502 0.003 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /run \u2502 seq_write \u2502 1m \u2502 6966 \u2502 6966.2 MB/s \u2502 0.144 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_c\u2026 \u2502 1m \u2502 9468 \u2502 9467.6 MB/s \u2502 0.106 ms \u2502 - \u2502\n\u2502 /run \u2502 seq_read_w\u2026 \u2502 1m \u2502 19348 \u2502 19347.8 \u2502 0.052 ms \u2502 - \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 MB/s \u2502 \u2502 \u2502\n\u2502 /run \u2502 read_4k \u2502 4k \u2502 28693 \u2502 112.1 MB/s \u2502 0.035 ms \u2502 0.059 ms \u2502\n\u2502 /run \u2502 write_4k_s\u2026 \u2502 4k \u2502 12733 \u2502 49.7 MB/s \u2502 0.079 ms \u2502 0.117 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n CLI Cold Start Latency [3 runs each] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Command \u2503 Min (ms) \u2503 Mean (ms) \u2503 Max (ms) \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 python3 \u2502 7.3 \u2502 7.5 \u2502 7.9 \u2502\n\u2502 node \u2502 134.6 \u2502 135.1 \u2502 136.0 \u2502\n\u2502 claude \u2502 398.6 \u2502 399.1 \u2502 399.6 \u2502\n\u2502 gemini \u2502 917.5 \u2502 935.7 \u2502 971.8 \u2502\n\u2502 codex \u2502 236.8 \u2502 255.8 \u2502 293.3 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n HTTP Benchmark \n [https://www.google.com/] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Requests \u2502 50/50 \u2502\n\u2502 Concurrency \u2502 5 \u2502\n\u2502 Requests/sec \u2502 53.6 \u2502\n\u2502 Transfer \u2502 3.8 MB \u2502\n\u2502 Duration \u2502 932.0 ms \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Latency min \u2502 53.0 ms \u2502\n\u2502 Latency mean \u2502 84.8 ms \u2502\n\u2502 Latency p50 \u2502 78.4 ms \u2502\n\u2502 Latency p95 \u2502 175.5 ms \u2502\n\u2502 Latency p99 \u2502 210.6 ms \u2502\n\u2502 Latency max \u2502 224.2 ms \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Proxy Throughput \n [https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-slides.pdf] \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 URL \u2502 https://cdn.elie.net/static/files/i-am-a-legend/i-am-a-legend-\u2026 \u2502\n\u2502 Downloaded \u2502 9.5 MB \u2502\n\u2502 Duration \u2502 0.44s \u2502\n\u2502 Throughput \u2502 21.46 MB/s \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Snapshot Operations (e2e via MCP) \n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Operation \u2503 Files \u2503 Latency (ms) \u2503 Status \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 create \u2502 10 files \u2502 961.9 \u2502 ok \u2502\n\u2502 list \u2502 10 files \u2502 389.7 \u2502 ok \u2502\n\u2502 changes \u2502 10 files \u2502 363.5 \u2502 ok \u2502\n\u2502 revert \u2502 10 files \u2502 364.1 \u2502 ok \u2502\n\u2502 delete \u2502 10 files \u2502 331.4 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 100 files \u2502 334.5 \u2502 ok \u2502\n\u2502 list \u2502 100 files \u2502 353.1 \u2502 ok \u2502\n\u2502 changes \u2502 100 files \u2502 349.1 \u2502 ok \u2502\n\u2502 revert \u2502 100 files \u2502 341.6 \u2502 ok \u2502\n\u2502 delete \u2502 100 files \u2502 350.3 \u2502 ok \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 create \u2502 500 files \u2502 344.4 \u2502 ok \u2502\n\u2502 list \u2502 500 files \u2502 365.5 \u2502 ok \u2502\n\u2502 changes \u2502 500 files \u2502 351.0 \u2502 ok \u2502\n\u2502 revert \u2502 500 files \u2502 312.5 \u2502 ok \u2502\n\u2502 delete \u2502 500 files \u2502 306.7 \u2502 ok \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nJSON results saved to /tmp/capsem-benchmark.json\n"
- }
- ],
- "schema": "capsem.benchmark-artifact.v1",
- "project_version": "1.2.1780103109",
- "arch": "arm64",
- "recorded_at": 1780149901.6211681,
- "recorded_at_utc": "2026-05-30T14:05:01.621174+00:00",
- "command": "uv run pytest tests/capsem-serial/test_parallel_benchmark.py -xvs",
- "host": {
- "platform": "Darwin",
- "release": "25.5.0",
- "version": "Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:12 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T6050",
- "machine": "arm64",
- "processor": "arm",
- "python_version": "3.14.4",
- "cpu_count": 18,
- "cpu_count_logical": 18,
- "cpu_model": "Apple M5 Max",
- "cpu_count_physical": 18,
- "memory_total_bytes": 137438953472,
- "os_product_version": "26.5",
- "memory_total_gb": 128.0
- },
- "git": {
- "commit": "0a425541fbdc03cc9821aafb238a0dd4b26ccdcd",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/endpoint-latency/data_1.2.1780103109_arm64.json",
- "benchmarks/capsem-bench/data_1.2.1780103109_arm64.json",
- "benchmarks/fork/data_1.2.1780103109_arm64.json",
- "benchmarks/host-native/data_1.2.1780103109_arm64.json",
- "benchmarks/lifecycle/data_1.2.1780103109_arm64.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_security_packs_microbench.json"
- ]
- }
-}
\ No newline at end of file
diff --git a/benchmarks/policy-v2/README.md b/benchmarks/policy-v2/README.md
deleted file mode 100644
index 122e58d32..000000000
--- a/benchmarks/policy-v2/README.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# Policy V2 Microbenchmarks
-
-Scoped Policy V2 closure benchmark for MCP-policy-v2 release prep.
-
-Command:
-
-```bash
-cargo bench -p capsem-core --bench policy_v2 -- --sample-size 10 --warm-up-time 0.1 --measurement-time 0.2
-```
-
-Sample captured on 2026-05-10:
-
-| Benchmark | Median-ish range |
-| --- | ---: |
-| `policy_v2_http_request_match` | 1.61-1.76 us |
-| `policy_v2_dns_query_match` | 960-967 ns |
-| `policy_v2_model_response_match` | 1.32-1.37 us |
-| `policy_v2_model_tool_call_match` | 2.11-2.12 us |
-| `policy_v2_hook_decision_match` | 1.51-1.52 us |
-| `policy_hook_response_decode` | 330-335 ns |
diff --git a/benchmarks/release-hermetic/capsem_bench_all_1.0.1780977620_arm64.json b/benchmarks/release-hermetic/capsem_bench_all_1.0.1780977620_arm64.json
new file mode 100644
index 000000000..979fbfcd5
--- /dev/null
+++ b/benchmarks/release-hermetic/capsem_bench_all_1.0.1780977620_arm64.json
@@ -0,0 +1,1498 @@
+{
+ "version": "0.3.0",
+ "timestamp": 1781017584.1776047,
+ "hostname": "release-bench-hermetic",
+ "disk": {
+ "directory": "/root",
+ "size_mb": 256,
+ "seq_write": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 111.2,
+ "throughput_mbps": 2301.3
+ },
+ "seq_read": {
+ "size_bytes": 268435456,
+ "block_size": 1048576,
+ "duration_ms": 59.4,
+ "throughput_mbps": 4310.2
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1261.6,
+ "iops": 7926.4,
+ "throughput_mbps": 31.0
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 188.3,
+ "iops": 53109.7,
+ "throughput_mbps": 207.5
+ }
+ },
+ "rootfs": {
+ "scan_dirs": [
+ "/usr/bin",
+ "/usr/lib",
+ "/opt/ai-clis"
+ ],
+ "largest_file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "largest_file_size": 193339016,
+ "seq_read": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 193339016,
+ "block_size": 1048576,
+ "duration_ms": 68.6,
+ "throughput_mbps": 2687.7
+ },
+ "files_found": 5548,
+ "rand_read_4k": {
+ "count": 5000,
+ "files_sampled": 2588,
+ "block_size": 4096,
+ "duration_ms": 154.4,
+ "iops": 32387.4,
+ "throughput_mbps": 126.5
+ },
+ "large_binary_seq_read": {
+ "count": 2,
+ "files": [
+ {
+ "path": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 193339016,
+ "cold": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 193339016,
+ "block_size": 1048576,
+ "duration_ms": 62.3,
+ "throughput_mbps": 2961.1
+ },
+ "warm": {
+ "file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 193339016,
+ "block_size": 1048576,
+ "duration_ms": 9.4,
+ "throughput_mbps": 19596.4
+ }
+ },
+ {
+ "path": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "cold": {
+ "file": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "block_size": 1048576,
+ "duration_ms": 9.7,
+ "throughput_mbps": 3866.4
+ },
+ "warm": {
+ "file": "/usr/bin/gh",
+ "size_bytes": 39162504,
+ "block_size": 1048576,
+ "duration_ms": 1.7,
+ "throughput_mbps": 22289.7
+ }
+ }
+ ],
+ "bytes_read": 232501520,
+ "cold_duration_ms": 72.0,
+ "warm_duration_ms": 11.1,
+ "cold_throughput_mbps": 3079.6,
+ "warm_throughput_mbps": 19975.7
+ },
+ "small_js_read": {
+ "count": 5000,
+ "files_sampled": 110,
+ "bytes_read": 49873080,
+ "duration_ms": 7.6,
+ "ops_per_sec": 661441.3,
+ "throughput_mbps": 6292.0
+ },
+ "metadata_stat": {
+ "entries": 6552,
+ "files": 5548,
+ "dirs": 661,
+ "symlinks": 343,
+ "errors": 0,
+ "duration_ms": 45.8,
+ "stats_per_sec": 143019.7
+ }
+ },
+ "storage": {
+ "kernel": {
+ "cmdline": {
+ "raw": "console=hvc0 ro loglevel=1 quiet init_on_alloc=1 slab_nomerge page_alloc.shuffle=1 random.trust_cpu=1 capsem.storage=virtiofs capsem.rootfs=erofs",
+ "args": [
+ "console=hvc0",
+ "ro",
+ "loglevel=1",
+ "quiet",
+ "init_on_alloc=1",
+ "slab_nomerge",
+ "page_alloc.shuffle=1",
+ "random.trust_cpu=1",
+ "capsem.storage=virtiofs",
+ "capsem.rootfs=erofs"
+ ]
+ },
+ "block_queues": {
+ "vda": {
+ "scheduler": "[none] mq-deadline kyber",
+ "read_ahead_kb": 4096,
+ "nr_requests": 256,
+ "rotational": 1,
+ "logical_block_size": 512,
+ "physical_block_size": 512,
+ "max_sectors_kb": 4096,
+ "nomerges": 0,
+ "rq_affinity": 1,
+ "io_poll": 0,
+ "selected_scheduler": "none"
+ },
+ "vdb": {
+ "scheduler": "[none] mq-deadline kyber",
+ "read_ahead_kb": 4096,
+ "nr_requests": 256,
+ "rotational": 1,
+ "logical_block_size": 512,
+ "physical_block_size": 512,
+ "max_sectors_kb": 4096,
+ "nomerges": 0,
+ "rq_affinity": 1,
+ "io_poll": 0,
+ "selected_scheduler": "none"
+ }
+ },
+ "fuse_connections": {},
+ "known_host_queue_sizes": {
+ "kvm_virtio_blk": 256,
+ "kvm_virtio_fs": [
+ 256,
+ 256
+ ]
+ }
+ },
+ "mounts": [
+ {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ {
+ "mount_point": "/proc",
+ "root": "/",
+ "fs_type": "proc",
+ "source": "proc",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/sys",
+ "root": "/",
+ "fs_type": "sysfs",
+ "source": "sysfs",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/dev",
+ "root": "/",
+ "fs_type": "devtmpfs",
+ "source": "devtmpfs",
+ "options": "rw,size=1021592k,nr_inodes=255398,mode=755"
+ },
+ {
+ "mount_point": "/dev/pts",
+ "root": "/",
+ "fs_type": "devpts",
+ "source": "devpts",
+ "options": "rw,mode=600,ptmxmode=000"
+ },
+ {
+ "mount_point": "/root",
+ "root": "/workspace",
+ "fs_type": "virtiofs",
+ "source": "capsem",
+ "options": "rw"
+ },
+ {
+ "mount_point": "/etc/resolv.conf",
+ "root": "/run/resolv.conf",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ }
+ ],
+ "paths": {
+ "/": {
+ "path": "/",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496852,
+ "blocks_available": 492756,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/root": {
+ "path": "/root",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/root",
+ "root": "/workspace",
+ "fs_type": "virtiofs",
+ "source": "capsem",
+ "options": "rw"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 1048576,
+ "fragment_size": 4096,
+ "blocks": 975653540,
+ "blocks_free": 722705865,
+ "blocks_available": 722705865,
+ "files": 3141988793,
+ "files_free": 3138430824
+ }
+ },
+ "/tmp": {
+ "path": "/tmp",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxrwxrwt",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496852,
+ "blocks_available": 492756,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/var/tmp": {
+ "path": "/var/tmp",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxrwxrwt",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496852,
+ "blocks_available": 492756,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/var/log": {
+ "path": "/var/log",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496852,
+ "blocks_available": 492756,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/run": {
+ "path": "/run",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496852,
+ "blocks_available": 492756,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/usr/bin": {
+ "path": "/usr/bin",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496852,
+ "blocks_available": 492756,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/usr/lib": {
+ "path": "/usr/lib",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496852,
+ "blocks_available": 492756,
+ "files": 131072,
+ "files_free": 130928
+ }
+ },
+ "/opt/ai-clis": {
+ "path": "/opt/ai-clis",
+ "exists": true,
+ "writable": true,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "mode": "drwxr-xr-x",
+ "statvfs": {
+ "block_size": 4096,
+ "fragment_size": 4096,
+ "blocks": 498138,
+ "blocks_free": 496852,
+ "blocks_available": 492756,
+ "files": 131072,
+ "files_free": 130928
+ }
+ }
+ },
+ "rootfs": {
+ "scan_dirs": [
+ "/usr/bin",
+ "/usr/lib",
+ "/opt/ai-clis"
+ ],
+ "files_found": 3328,
+ "largest_file": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "largest_file_size": 193339016,
+ "backing": {
+ "root_mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "overlay_lowerdir": "/mnt/a",
+ "overlay_upperdir": "/mnt/system/upper",
+ "overlay_workdir": "/mnt/system/work",
+ "squashfs_mounts": [],
+ "squashfs_superblock": {
+ "device": "/dev/vda",
+ "magic": "0x00000000",
+ "error": "not squashfs",
+ "read_ahead_kb": 4096
+ }
+ },
+ "seq_reads": [
+ {
+ "label": "largest",
+ "path": "/opt/ai-clis/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/bin/codex",
+ "size_bytes": 193339016,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 193339016,
+ "block_size": 1048576,
+ "duration_ms": 55.3,
+ "throughput_mbps": 3335.4
+ },
+ "warm": {
+ "size_bytes": 193339016,
+ "block_size": 1048576,
+ "duration_ms": 9.3,
+ "throughput_mbps": 19776.9
+ }
+ },
+ {
+ "label": "bash",
+ "path": "/bin/bash",
+ "size_bytes": 1346480,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 1346480,
+ "block_size": 1048576,
+ "duration_ms": 0.3,
+ "throughput_mbps": 4883.3
+ },
+ "warm": {
+ "size_bytes": 1346480,
+ "block_size": 1048576,
+ "duration_ms": 0.1,
+ "throughput_mbps": 24266.4
+ }
+ },
+ {
+ "label": "python3",
+ "path": "/usr/bin/python3",
+ "size_bytes": 6616880,
+ "mount": {
+ "mount_point": "/",
+ "root": "/",
+ "fs_type": "overlay",
+ "source": "overlay",
+ "options": "rw,lowerdir=/mnt/a,upperdir=/mnt/system/upper,workdir=/mnt/system/work,uuid=on,metacopy=on"
+ },
+ "cold": {
+ "size_bytes": 6616880,
+ "block_size": 1048576,
+ "duration_ms": 1.2,
+ "throughput_mbps": 5060.8
+ },
+ "warm": {
+ "size_bytes": 6616880,
+ "block_size": 1048576,
+ "duration_ms": 0.3,
+ "throughput_mbps": 24387.8
+ }
+ }
+ ],
+ "rand_read_4k": {
+ "count": 2000,
+ "files_sampled": 1494,
+ "duration_ms": 81.3,
+ "iops": 24600.9,
+ "throughput_mbps": 96.1
+ }
+ },
+ "writable": {
+ "/root": {
+ "path": "/root",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 21.4,
+ "throughput_mbps": 2990.8
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 12.1,
+ "throughput_mbps": 5278.3
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 12.9,
+ "throughput_mbps": 4950.2
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1101.3,
+ "iops": 9080.2,
+ "throughput_mbps": 35.5
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 190.0,
+ "iops": 52636.3,
+ "throughput_mbps": 205.6
+ },
+ "io_profile": {
+ "path": "/root",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 978.3,
+ "iops": 16747.4,
+ "throughput_mbps": 65.4,
+ "avg_latency_ms": 0.06
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 17.9,
+ "iops": 914190.1,
+ "throughput_mbps": 3571.1,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 16.8,
+ "iops": 975649.5,
+ "throughput_mbps": 3811.1,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 73.2,
+ "iops": 13994.1,
+ "throughput_mbps": 874.6,
+ "avg_latency_ms": 0.071
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 15.4,
+ "iops": 66332.3,
+ "throughput_mbps": 4145.8,
+ "avg_latency_ms": 0.015
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 15.3,
+ "iops": 67030.3,
+ "throughput_mbps": 4189.4,
+ "avg_latency_ms": 0.015
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 26.5,
+ "iops": 2414.5,
+ "throughput_mbps": 2414.5,
+ "avg_latency_ms": 0.414
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 14.3,
+ "iops": 4478.1,
+ "throughput_mbps": 4478.1,
+ "avg_latency_ms": 0.223
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 14.3,
+ "iops": 4462.3,
+ "throughput_mbps": 4462.3,
+ "avg_latency_ms": 0.224
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 47.4,
+ "iops": 42234.5,
+ "throughput_mbps": 165.0,
+ "avg_latency_ms": 0.024,
+ "latency_ms": {
+ "p50": 0.025,
+ "p95": 0.03,
+ "p99": 0.035,
+ "max": 0.047
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 220.8,
+ "iops": 9059.8,
+ "throughput_mbps": 35.4,
+ "avg_latency_ms": 0.11,
+ "latency_ms": {
+ "p50": 0.109,
+ "p95": 0.121,
+ "p99": 0.128,
+ "max": 0.402
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/tmp": {
+ "path": "/tmp",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 9.7,
+ "throughput_mbps": 6587.0
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 6.7,
+ "throughput_mbps": 9581.5
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 4.7,
+ "throughput_mbps": 13727.2
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1517.9,
+ "iops": 6588.0,
+ "throughput_mbps": 25.7
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.1,
+ "iops": 1405250.9,
+ "throughput_mbps": 5489.3
+ },
+ "io_profile": {
+ "path": "/tmp",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 17.0,
+ "iops": 962474.3,
+ "throughput_mbps": 3759.7,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 12.6,
+ "iops": 1303140.1,
+ "throughput_mbps": 5090.4,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 10.0,
+ "iops": 1632882.2,
+ "throughput_mbps": 6378.4,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 10.7,
+ "iops": 95946.0,
+ "throughput_mbps": 5996.6,
+ "avg_latency_ms": 0.01
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 7.8,
+ "iops": 131594.2,
+ "throughput_mbps": 8224.6,
+ "avg_latency_ms": 0.008
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 5.6,
+ "iops": 182245.6,
+ "throughput_mbps": 11390.3,
+ "avg_latency_ms": 0.005
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 41.2,
+ "iops": 1552.8,
+ "throughput_mbps": 1552.8,
+ "avg_latency_ms": 0.644
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 7.3,
+ "iops": 8803.0,
+ "throughput_mbps": 8803.0,
+ "avg_latency_ms": 0.114
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 4.8,
+ "iops": 13349.3,
+ "throughput_mbps": 13349.3,
+ "avg_latency_ms": 0.075
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 39.1,
+ "iops": 51163.1,
+ "throughput_mbps": 199.9,
+ "avg_latency_ms": 0.02,
+ "latency_ms": {
+ "p50": 0.021,
+ "p95": 0.024,
+ "p99": 0.028,
+ "max": 0.066
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 85.1,
+ "iops": 23504.4,
+ "throughput_mbps": 91.8,
+ "avg_latency_ms": 0.043,
+ "latency_ms": {
+ "p50": 0.04,
+ "p95": 0.051,
+ "p99": 0.145,
+ "max": 0.201
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/var/tmp": {
+ "path": "/var/tmp",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 18.0,
+ "throughput_mbps": 3547.9
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 7.5,
+ "throughput_mbps": 8526.1
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.2,
+ "throughput_mbps": 12309.2
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1341.1,
+ "iops": 7456.6,
+ "throughput_mbps": 29.1
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.7,
+ "iops": 1299678.9,
+ "throughput_mbps": 5076.9
+ },
+ "io_profile": {
+ "path": "/var/tmp",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 17.8,
+ "iops": 922152.6,
+ "throughput_mbps": 3602.2,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 12.7,
+ "iops": 1290591.0,
+ "throughput_mbps": 5041.4,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 10.9,
+ "iops": 1504545.5,
+ "throughput_mbps": 5877.1,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 11.4,
+ "iops": 89546.0,
+ "throughput_mbps": 5596.6,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 8.6,
+ "iops": 119302.1,
+ "throughput_mbps": 7456.4,
+ "avg_latency_ms": 0.008
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.5,
+ "iops": 158673.6,
+ "throughput_mbps": 9917.1,
+ "avg_latency_ms": 0.006
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 11.0,
+ "iops": 5839.6,
+ "throughput_mbps": 5839.6,
+ "avg_latency_ms": 0.171
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 7.9,
+ "iops": 8097.3,
+ "throughput_mbps": 8097.3,
+ "avg_latency_ms": 0.123
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 5.7,
+ "iops": 11177.3,
+ "throughput_mbps": 11177.3,
+ "avg_latency_ms": 0.089
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 39.9,
+ "iops": 50153.2,
+ "throughput_mbps": 195.9,
+ "avg_latency_ms": 0.02,
+ "latency_ms": {
+ "p50": 0.021,
+ "p95": 0.025,
+ "p99": 0.028,
+ "max": 0.059
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 112.1,
+ "iops": 17837.5,
+ "throughput_mbps": 69.7,
+ "avg_latency_ms": 0.056,
+ "latency_ms": {
+ "p50": 0.057,
+ "p95": 0.068,
+ "p99": 0.132,
+ "max": 0.164
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/var/log": {
+ "path": "/var/log",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 9.6,
+ "throughput_mbps": 6663.3
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.8,
+ "throughput_mbps": 11125.1
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 3.7,
+ "throughput_mbps": 17505.7
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1292.2,
+ "iops": 7738.8,
+ "throughput_mbps": 30.2
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.0,
+ "iops": 1436351.7,
+ "throughput_mbps": 5610.7
+ },
+ "io_profile": {
+ "path": "/var/log",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 17.8,
+ "iops": 922018.5,
+ "throughput_mbps": 3601.6,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 13.0,
+ "iops": 1256955.8,
+ "throughput_mbps": 4910.0,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 11.1,
+ "iops": 1476706.8,
+ "throughput_mbps": 5768.4,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 11.1,
+ "iops": 92190.7,
+ "throughput_mbps": 5761.9,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 9.2,
+ "iops": 111707.1,
+ "throughput_mbps": 6981.7,
+ "avg_latency_ms": 0.009
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.7,
+ "iops": 153603.8,
+ "throughput_mbps": 9600.2,
+ "avg_latency_ms": 0.007
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 11.0,
+ "iops": 5830.2,
+ "throughput_mbps": 5830.2,
+ "avg_latency_ms": 0.172
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 8.3,
+ "iops": 7728.3,
+ "throughput_mbps": 7728.3,
+ "avg_latency_ms": 0.129
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 6.0,
+ "iops": 10670.5,
+ "throughput_mbps": 10670.5,
+ "avg_latency_ms": 0.094
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 49.2,
+ "iops": 40618.1,
+ "throughput_mbps": 158.7,
+ "avg_latency_ms": 0.025,
+ "latency_ms": {
+ "p50": 0.023,
+ "p95": 0.035,
+ "p99": 0.039,
+ "max": 0.049
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 120.9,
+ "iops": 16537.6,
+ "throughput_mbps": 64.6,
+ "avg_latency_ms": 0.06,
+ "latency_ms": {
+ "p50": 0.058,
+ "p95": 0.07,
+ "p99": 0.128,
+ "max": 0.19
+ },
+ "sync_each": true
+ }
+ }
+ }
+ },
+ "/run": {
+ "path": "/run",
+ "size_mb": 64,
+ "seq_write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 10.6,
+ "throughput_mbps": 6035.3
+ },
+ "seq_read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 6.7,
+ "throughput_mbps": 9605.0
+ },
+ "seq_read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "duration_ms": 5.0,
+ "throughput_mbps": 12861.5
+ },
+ "rand_write_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 1264.0,
+ "iops": 7911.3,
+ "throughput_mbps": 30.9
+ },
+ "rand_read_4k": {
+ "count": 10000,
+ "block_size": 4096,
+ "duration_ms": 7.4,
+ "iops": 1342454.7,
+ "throughput_mbps": 5244.0
+ },
+ "io_profile": {
+ "path": "/run",
+ "size_mb": 64,
+ "random_ops": 2000,
+ "sequential": {
+ "4k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 17.6,
+ "iops": 928342.1,
+ "throughput_mbps": 3626.3,
+ "avg_latency_ms": 0.001
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 13.0,
+ "iops": 1260016.9,
+ "throughput_mbps": 4921.9,
+ "avg_latency_ms": 0.001
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 4096,
+ "count": 16384,
+ "duration_ms": 10.9,
+ "iops": 1500309.1,
+ "throughput_mbps": 5860.6,
+ "avg_latency_ms": 0.001
+ }
+ },
+ "64k": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 11.3,
+ "iops": 90354.3,
+ "throughput_mbps": 5647.1,
+ "avg_latency_ms": 0.011
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 9.0,
+ "iops": 113163.2,
+ "throughput_mbps": 7072.7,
+ "avg_latency_ms": 0.009
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 65536,
+ "count": 1024,
+ "duration_ms": 6.6,
+ "iops": 154078.6,
+ "throughput_mbps": 9629.9,
+ "avg_latency_ms": 0.006
+ }
+ },
+ "1m": {
+ "write": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 11.0,
+ "iops": 5836.4,
+ "throughput_mbps": 5836.4,
+ "avg_latency_ms": 0.171
+ },
+ "read_cold": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 8.2,
+ "iops": 7775.5,
+ "throughput_mbps": 7775.5,
+ "avg_latency_ms": 0.129
+ },
+ "read_warm": {
+ "size_bytes": 67108864,
+ "block_size": 1048576,
+ "count": 64,
+ "duration_ms": 5.9,
+ "iops": 10876.5,
+ "throughput_mbps": 10876.5,
+ "avg_latency_ms": 0.092
+ }
+ }
+ },
+ "random": {
+ "read_4k": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 39.6,
+ "iops": 50456.2,
+ "throughput_mbps": 197.1,
+ "avg_latency_ms": 0.02,
+ "latency_ms": {
+ "p50": 0.021,
+ "p95": 0.024,
+ "p99": 0.027,
+ "max": 0.049
+ }
+ },
+ "write_4k_sync": {
+ "size_bytes": 8192000,
+ "block_size": 4096,
+ "count": 2000,
+ "duration_ms": 93.4,
+ "iops": 21412.0,
+ "throughput_mbps": 83.6,
+ "avg_latency_ms": 0.047,
+ "latency_ms": {
+ "p50": 0.041,
+ "p95": 0.065,
+ "p99": 0.134,
+ "max": 0.167
+ },
+ "sync_each": true
+ }
+ }
+ }
+ }
+ }
+ },
+ "startup": {
+ "runs_per_command": 3,
+ "commands": {
+ "python3": {
+ "command": [
+ "python3",
+ "--version"
+ ],
+ "timings_ms": [
+ 2.9,
+ 4.2,
+ 3.5
+ ],
+ "min_ms": 2.9,
+ "mean_ms": 3.5,
+ "max_ms": 4.2
+ },
+ "node": {
+ "command": [
+ "node",
+ "--version"
+ ],
+ "timings_ms": [
+ 25.0,
+ 26.3,
+ 26.1
+ ],
+ "min_ms": 25.0,
+ "mean_ms": 25.8,
+ "max_ms": 26.3
+ },
+ "claude": {
+ "command": [
+ "claude",
+ "--version"
+ ],
+ "timings_ms": [
+ 134.8,
+ 138.8,
+ 138.8
+ ],
+ "min_ms": 134.8,
+ "mean_ms": 137.5,
+ "max_ms": 138.8
+ },
+ "gemini": {
+ "command": [
+ "gemini",
+ "--version"
+ ],
+ "timings_ms": [
+ 654.7,
+ 656.3,
+ 660.5
+ ],
+ "min_ms": 654.7,
+ "mean_ms": 657.2,
+ "max_ms": 660.5
+ },
+ "codex": {
+ "command": [
+ "codex",
+ "--version"
+ ],
+ "timings_ms": [
+ 79.6,
+ 80.3,
+ 77.2
+ ],
+ "min_ms": 77.2,
+ "mean_ms": 79.0,
+ "max_ms": 80.3
+ }
+ }
+ },
+ "http": {
+ "url": "http://127.0.0.1:3713/tiny",
+ "total_requests": 50,
+ "concurrency": 5,
+ "successful": 50,
+ "failed": 0,
+ "total_duration_ms": 22.0,
+ "requests_per_sec": 2269.1,
+ "transfer_bytes": 1350,
+ "latency_ms": {
+ "min": 1.0,
+ "max": 6.8,
+ "mean": 2.1,
+ "p50": 1.7,
+ "p95": 5.5,
+ "p99": 6.3
+ }
+ },
+ "throughput": {
+ "url": "http://127.0.0.1:3713/bytes/10mb",
+ "source": "local",
+ "http_code": 200,
+ "size_bytes": 10485760,
+ "duration_s": 0.111,
+ "throughput_mbps": 90.33
+ },
+ "snapshot": {
+ "10_files": {
+ "create_ms": 666.8,
+ "create_ok": true,
+ "list_ms": 249.7,
+ "list_ok": true,
+ "changes_ms": 242.7,
+ "changes_ok": true,
+ "revert_ms": 263.6,
+ "revert_ok": true,
+ "delete_ms": 296.2,
+ "delete_ok": true
+ },
+ "100_files": {
+ "create_ms": 244.5,
+ "create_ok": true,
+ "list_ms": 244.0,
+ "list_ok": true,
+ "changes_ms": 244.9,
+ "changes_ok": true,
+ "revert_ms": 266.9,
+ "revert_ok": true,
+ "delete_ms": 295.6,
+ "delete_ok": true
+ },
+ "500_files": {
+ "create_ms": 260.4,
+ "create_ok": true,
+ "list_ms": 249.7,
+ "list_ok": true,
+ "changes_ms": 265.2,
+ "changes_ok": true,
+ "revert_ms": 261.3,
+ "revert_ok": true,
+ "delete_ms": 317.9,
+ "delete_ok": true
+ }
+ },
+ "host_recorded_at": 1781017604.6161761,
+ "arch": "arm64",
+ "debug_upstream_base_url": "http://127.0.0.1:3713"
+}
diff --git a/benchmarks/release-hermetic/dns_load_blocked_c1_16_64_1.0.1780977620_arm64.json b/benchmarks/release-hermetic/dns_load_blocked_c1_16_64_1.0.1780977620_arm64.json
new file mode 100644
index 000000000..870bff962
--- /dev/null
+++ b/benchmarks/release-hermetic/dns_load_blocked_c1_16_64_1.0.1780977620_arm64.json
@@ -0,0 +1,60 @@
+{
+ "version": "0.3.0",
+ "timestamp": 1781017822.1791599,
+ "hostname": "release-bench-dns-blocked",
+ "dns_load": {
+ "version": "1.0",
+ "qname": "blocked.example.com",
+ "qtype": 1,
+ "concurrency_levels": [
+ {
+ "concurrency": 1,
+ "duration_s": 10.0,
+ "total_requests": 15091,
+ "errors": 0,
+ "rps": 1509.1,
+ "p50_ms": 0.6440829999991848,
+ "p95_ms": 0.741583499999976,
+ "p99_ms": 0.8140493999999611,
+ "p999_ms": 1.4099857499996806,
+ "rss_peak_mb": 24.7578125,
+ "decision_distribution": {
+ "denied": 15091
+ }
+ },
+ {
+ "concurrency": 16,
+ "duration_s": 10.0,
+ "total_requests": 42141,
+ "errors": 0,
+ "rps": 4214.1,
+ "p50_ms": 3.2752920000014285,
+ "p95_ms": 12.489791000000139,
+ "p99_ms": 14.399816399998855,
+ "p999_ms": 15.91881750000028,
+ "rss_peak_mb": 26.31640625,
+ "decision_distribution": {
+ "denied": 42141
+ }
+ },
+ {
+ "concurrency": 64,
+ "duration_s": 10.0,
+ "total_requests": 39055,
+ "errors": 0,
+ "rps": 3905.5,
+ "p50_ms": 14.272207999997732,
+ "p95_ms": 30.33112520000003,
+ "p99_ms": 34.87302481999741,
+ "p999_ms": 37.12447357200147,
+ "rss_peak_mb": 30.81640625,
+ "decision_distribution": {
+ "denied": 39055
+ }
+ }
+ ]
+ },
+ "host_recorded_at": 1781017853.103043,
+ "arch": "arm64",
+ "corp_rule_file": "/var/folders/l5/jg8zh4215ll399vd5mcp9sp40000gn/T/capsem-bench-corp-1sneg4pl/corp.toml"
+}
diff --git a/benchmarks/release-hermetic/mcp_load_c1_16_64_1.0.1780977620_arm64.json b/benchmarks/release-hermetic/mcp_load_c1_16_64_1.0.1780977620_arm64.json
new file mode 100644
index 000000000..d3ed8d2f3
--- /dev/null
+++ b/benchmarks/release-hermetic/mcp_load_c1_16_64_1.0.1780977620_arm64.json
@@ -0,0 +1,51 @@
+{
+ "version": "0.3.0",
+ "timestamp": 1781017603.8582294,
+ "hostname": "release-bench-hermetic",
+ "mcp_load": {
+ "version": "1.0",
+ "tool": "local__echo",
+ "payload_bytes": 4,
+ "concurrency_levels": [
+ {
+ "concurrency": 1,
+ "duration_s": 10.0,
+ "total_requests": 13370,
+ "errors": 0,
+ "rps": 1337.0,
+ "p50_ms": 0.737750000002535,
+ "p95_ms": 0.8367122000013438,
+ "p99_ms": 0.9642412500015849,
+ "p999_ms": 1.503433243999201,
+ "rss_peak_mb": 63.05859375
+ },
+ {
+ "concurrency": 16,
+ "duration_s": 10.0,
+ "total_requests": 65105,
+ "errors": 0,
+ "rps": 6510.5,
+ "p50_ms": 2.2802920000017934,
+ "p95_ms": 3.345875000000831,
+ "p99_ms": 7.856205320006493,
+ "p999_ms": 11.031686367997738,
+ "rss_peak_mb": 66.63671875
+ },
+ {
+ "concurrency": 64,
+ "duration_s": 10.0,
+ "total_requests": 57234,
+ "errors": 0,
+ "rps": 5723.4,
+ "p50_ms": 9.043895500003174,
+ "p95_ms": 22.331806350002736,
+ "p99_ms": 26.96201752999748,
+ "p999_ms": 31.635199161003882,
+ "rss_peak_mb": 69.8515625
+ }
+ ]
+ },
+ "host_recorded_at": 1781017634.9125068,
+ "arch": "arm64",
+ "debug_upstream_base_url": "http://127.0.0.1:3713"
+}
diff --git a/benchmarks/release_1.3.1781720230_report.png b/benchmarks/release_1.3.1781720230_report.png
new file mode 100644
index 000000000..2d045a403
Binary files /dev/null and b/benchmarks/release_1.3.1781720230_report.png differ
diff --git a/benchmarks/security-engine/README.md b/benchmarks/security-engine/README.md
deleted file mode 100644
index c01b959c8..000000000
--- a/benchmarks/security-engine/README.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# Security Engine Benchmarks
-
-This directory stores committed Security Engine benchmark artifacts.
-
-Artifacts currently cover three lanes:
-
-- host-side Rust Criterion microbenchmarks for canonical CEL paths in
- `capsem-security-engine`;
-- host-side Rust Criterion microbenchmarks for Detection IR parse/lowering in
- `capsem-core`;
-- host-side serial pytest runs that exercise VM-originated Security Engine
- events through the real service/process IPC, DNS, and network transport paths
- and verify session DB, runtime counters, and log projection.
-
-The Criterion numbers explain evaluator, detection, Detection IR lowering,
-backtest dedupe, runtime registry, compiled-plan rebuild, policy-context
-materialization, rule-count, and native lookup costs across commits. The serial
-pytest numbers are the first product-path latency artifacts and are appropriate
-for engineering regression tracking when quoted with their workload and host.
-
-## Run
-
-```bash
-cargo bench -p capsem-security-engine --bench security_engine_cel
-cargo bench -p capsem-core --bench security_packs
-uv run pytest tests/capsem-serial/test_security_engine_benchmark.py -xvs
-```
diff --git a/benchmarks/security-engine/data_1.2.1779673506_x86_64_cel_microbench.json b/benchmarks/security-engine/data_1.2.1779673506_x86_64_cel_microbench.json
deleted file mode 100644
index 87cda87c0..000000000
--- a/benchmarks/security-engine/data_1.2.1779673506_x86_64_cel_microbench.json
+++ /dev/null
@@ -1,771 +0,0 @@
-{
- "schema": "capsem.security-engine-benchmark.v1",
- "kind": "criterion_cel_microbench",
- "source_commit": "b6f9b6e2",
- "profile": {
- "cargo_profile": "bench",
- "criterion_samples": 100,
- "criterion_warmup_seconds": 3,
- "criterion_target_seconds": 5
- },
- "scope": {
- "vm_originated": false,
- "notes": [
- "Host-side microbenchmark only.",
- "Measures canonical policy-context CEL paths, detection evaluation, backtest dedupe, runtime registry operations, compiled-plan rebuild cost, and native lookup comparators.",
- "Does not include guest transport, service IPC, Security Engine emitter, or session.db journal write latency."
- ]
- },
- "measurements": [
- {
- "group": "security_engine_backtest_dedupe",
- "name": "dedupe_1000_rows_100_unique_limit_100",
- "full_id": "security_engine_backtest_dedupe/dedupe_1000_rows_100_unique_limit_100",
- "estimate_kind": "slope",
- "estimate_ns": 591262.9788458697,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 590348.9093195724,
- "upper_bound": 592311.8662276164
- },
- "estimate_standard_error_ns": 502.08238601673463,
- "mean_ns": 590693.1693284088,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 590130.5617742834,
- "upper_bound": 591324.4719164213
- },
- "median_ns": 589885.075770548,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 589294.845626072,
- "upper_bound": 590472.4570774231
- },
- "slope_ns": 591262.9788458697,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 590348.9093195724,
- "upper_bound": 592311.8662276164
- },
- "slope_standard_error_ns": 502.08238601673463
- },
- {
- "group": "security_engine_backtest_dedupe",
- "name": "dedupe_100_unique_limit_100",
- "full_id": "security_engine_backtest_dedupe/dedupe_100_unique_limit_100",
- "estimate_kind": "slope",
- "estimate_ns": 67479.55111767893,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 67397.18351515464,
- "upper_bound": 67569.26084919523
- },
- "estimate_standard_error_ns": 43.96595466261251,
- "mean_ns": 67364.20269799902,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 67311.03075601521,
- "upper_bound": 67421.04584902195
- },
- "median_ns": 67329.0045045045,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 67244.11597222222,
- "upper_bound": 67369.78445624825
- },
- "slope_ns": 67479.55111767893,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 67397.18351515464,
- "upper_bound": 67569.26084919523
- },
- "slope_standard_error_ns": 43.96595466261251
- },
- {
- "group": "security_engine_cel_compile",
- "name": "canonical_http_policy",
- "full_id": "security_engine_cel_compile/canonical_http_policy",
- "estimate_kind": "slope",
- "estimate_ns": 107767.89919728092,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 107659.21623820123,
- "upper_bound": 107889.29228048201
- },
- "estimate_standard_error_ns": 58.77886449556312,
- "mean_ns": 107919.54918084279,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 107782.50169078092,
- "upper_bound": 108073.75056870663
- },
- "median_ns": 107745.03181818181,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 107594.09195512821,
- "upper_bound": 107831.2
- },
- "slope_ns": 107767.89919728092,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 107659.21623820123,
- "upper_bound": 107889.29228048201
- },
- "slope_standard_error_ns": 58.77886449556312
- },
- {
- "group": "security_engine_cel_compile",
- "name": "header_authorization_exists",
- "full_id": "security_engine_cel_compile/header_authorization_exists",
- "estimate_kind": "slope",
- "estimate_ns": 18626.333421287403,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 18590.542730275858,
- "upper_bound": 18665.898864255436
- },
- "estimate_standard_error_ns": 19.34445900564701,
- "mean_ns": 18685.665388557358,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 18643.193830746008,
- "upper_bound": 18736.666450717497
- },
- "median_ns": 18613.30935846561,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 18583.790650406503,
- "upper_bound": 18694.914951989027
- },
- "slope_ns": 18626.333421287403,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 18590.542730275858,
- "upper_bound": 18665.898864255436
- },
- "slope_standard_error_ns": 19.34445900564701
- },
- {
- "group": "security_engine_cel_compile",
- "name": "host_contains_google",
- "full_id": "security_engine_cel_compile/host_contains_google",
- "estimate_kind": "slope",
- "estimate_ns": 18074.56684998052,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 18036.772168113024,
- "upper_bound": 18122.884636763854
- },
- "estimate_standard_error_ns": 22.033203926032186,
- "mean_ns": 18134.312357045397,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 18093.9662668723,
- "upper_bound": 18179.770045938778
- },
- "median_ns": 18087.198708677686,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 18042.276109936574,
- "upper_bound": 18107.85107928601
- },
- "slope_ns": 18074.56684998052,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 18036.772168113024,
- "upper_bound": 18122.884636763854
- },
- "slope_standard_error_ns": 22.033203926032186
- },
- {
- "group": "security_engine_cel_evaluate",
- "name": "body_contains_secret",
- "full_id": "security_engine_cel_evaluate/body_contains_secret",
- "estimate_kind": "slope",
- "estimate_ns": 41343.32092150633,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 41311.92731182123,
- "upper_bound": 41377.261936875504
- },
- "estimate_standard_error_ns": 16.598972743974233,
- "mean_ns": 41358.95032724107,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 41323.75045720949,
- "upper_bound": 41398.41037572502
- },
- "median_ns": 41307.80380446506,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 41287.68551587302,
- "upper_bound": 41344.316287878784
- },
- "slope_ns": 41343.32092150633,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 41311.92731182123,
- "upper_bound": 41377.261936875504
- },
- "slope_standard_error_ns": 16.598972743974233
- },
- {
- "group": "security_engine_cel_evaluate",
- "name": "canonical_http_policy",
- "full_id": "security_engine_cel_evaluate/canonical_http_policy",
- "estimate_kind": "slope",
- "estimate_ns": 66220.33734357913,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 66129.03857460813,
- "upper_bound": 66322.4494866858
- },
- "estimate_standard_error_ns": 49.69376681346862,
- "mean_ns": 66100.9921001623,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 66029.78845374951,
- "upper_bound": 66185.93614172123
- },
- "median_ns": 66015.15768369177,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 65941.24848484849,
- "upper_bound": 66077.4201058201
- },
- "slope_ns": 66220.33734357913,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 66129.03857460813,
- "upper_bound": 66322.4494866858
- },
- "slope_standard_error_ns": 49.69376681346862
- },
- {
- "group": "security_engine_cel_evaluate",
- "name": "canonical_http_policy_last_match_100_rules",
- "full_id": "security_engine_cel_evaluate/canonical_http_policy_last_match_100_rules",
- "estimate_kind": "mean",
- "estimate_ns": 3491887.9539999985,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 3489363.970299999,
- "upper_bound": 3494737.5903999987
- },
- "estimate_standard_error_ns": 1368.8064422908137,
- "mean_ns": 3491887.9539999985,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 3489363.970299999,
- "upper_bound": 3494737.5903999987
- },
- "median_ns": 3488330.0,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 3486978.2666666666,
- "upper_bound": 3489824.533333333
- }
- },
- {
- "group": "security_engine_cel_evaluate",
- "name": "header_authorization_exists",
- "full_id": "security_engine_cel_evaluate/header_authorization_exists",
- "estimate_kind": "slope",
- "estimate_ns": 47075.76590915808,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 46998.563673738965,
- "upper_bound": 47167.31849533967
- },
- "estimate_standard_error_ns": 43.22166191362982,
- "mean_ns": 47091.318290886935,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 47041.044598681096,
- "upper_bound": 47146.84545607513
- },
- "median_ns": 47033.79318181818,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 46990.194414019716,
- "upper_bound": 47092.38723513328
- },
- "slope_ns": 47075.76590915808,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 46998.563673738965,
- "upper_bound": 47167.31849533967
- },
- "slope_standard_error_ns": 43.22166191362982
- },
- {
- "group": "security_engine_cel_evaluate",
- "name": "host_contains_google",
- "full_id": "security_engine_cel_evaluate/host_contains_google",
- "estimate_kind": "slope",
- "estimate_ns": 39897.580200266,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 39846.65681037321,
- "upper_bound": 39952.77357269512
- },
- "estimate_standard_error_ns": 27.019122507695727,
- "mean_ns": 39821.62868324748,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 39766.726847837286,
- "upper_bound": 39880.22634115194
- },
- "median_ns": 39749.13849385908,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 39714.917677419355,
- "upper_bound": 39823.2915
- },
- "slope_ns": 39897.580200266,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 39846.65681037321,
- "upper_bound": 39952.77357269512
- },
- "slope_standard_error_ns": 27.019122507695727
- },
- {
- "group": "security_engine_cel_evaluate",
- "name": "path_starts_admin",
- "full_id": "security_engine_cel_evaluate/path_starts_admin",
- "estimate_kind": "slope",
- "estimate_ns": 39812.151115353925,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 39771.37127509612,
- "upper_bound": 39858.81325912529
- },
- "estimate_standard_error_ns": 22.409450248194673,
- "mean_ns": 39881.69766634722,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 39831.45017038117,
- "upper_bound": 39937.573594234585
- },
- "median_ns": 39780.331158357774,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 39752.60712554112,
- "upper_bound": 39847.25
- },
- "slope_ns": 39812.151115353925,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 39771.37127509612,
- "upper_bound": 39858.81325912529
- },
- "slope_standard_error_ns": 22.409450248194673
- },
- {
- "group": "security_engine_cel_evaluate",
- "name": "url_contains_google",
- "full_id": "security_engine_cel_evaluate/url_contains_google",
- "estimate_kind": "slope",
- "estimate_ns": 39797.9865308704,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 39750.681591691464,
- "upper_bound": 39853.597303646646
- },
- "estimate_standard_error_ns": 26.47178883596522,
- "mean_ns": 39760.3849481763,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 39730.91069259672,
- "upper_bound": 39793.96062719199
- },
- "median_ns": 39715.91318037975,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 39699.923172987976,
- "upper_bound": 39729.69553977273
- },
- "slope_ns": 39797.9865308704,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 39750.681591691464,
- "upper_bound": 39853.597303646646
- },
- "slope_standard_error_ns": 26.47178883596522
- },
- {
- "group": "security_engine_detection_evaluate",
- "name": "canonical_http_policy_last_match_100_rules",
- "full_id": "security_engine_detection_evaluate/canonical_http_policy_last_match_100_rules",
- "estimate_kind": "mean",
- "estimate_ns": 3465612.8826666684,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 3462627.312549999,
- "upper_bound": 3468968.9069499997
- },
- "estimate_standard_error_ns": 1623.7278443378545,
- "mean_ns": 3465612.8826666684,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 3462627.312549999,
- "upper_bound": 3468968.9069499997
- },
- "median_ns": 3460216.2333333334,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 3458752.8,
- "upper_bound": 3463260.478333333
- }
- },
- {
- "group": "security_engine_detection_evaluate",
- "name": "canonical_http_policy_single_rule",
- "full_id": "security_engine_detection_evaluate/canonical_http_policy_single_rule",
- "estimate_kind": "slope",
- "estimate_ns": 66328.38278311414,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 66270.24123812251,
- "upper_bound": 66397.52723100144
- },
- "estimate_standard_error_ns": 32.444455367304386,
- "mean_ns": 66421.69694559548,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 66354.23051101336,
- "upper_bound": 66503.84182325898
- },
- "median_ns": 66329.50392156863,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 66308.95514077425,
- "upper_bound": 66364.25731922398
- },
- "slope_ns": 66328.38278311414,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 66270.24123812251,
- "upper_bound": 66397.52723100144
- },
- "slope_standard_error_ns": 32.444455367304386
- },
- {
- "group": "security_engine_native_lookup",
- "name": "canonical_http_policy",
- "full_id": "security_engine_native_lookup/canonical_http_policy",
- "estimate_kind": "slope",
- "estimate_ns": 40.371739503238544,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 40.35250771498922,
- "upper_bound": 40.39225459680748
- },
- "estimate_standard_error_ns": 0.010120477803880496,
- "mean_ns": 40.38291684893973,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 40.35125547466624,
- "upper_bound": 40.4225444187702
- },
- "median_ns": 40.36573511887253,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 40.33944614903277,
- "upper_bound": 40.386838510765244
- },
- "slope_ns": 40.371739503238544,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 40.35250771498922,
- "upper_bound": 40.39225459680748
- },
- "slope_standard_error_ns": 0.010120477803880496
- },
- {
- "group": "security_engine_policy_context",
- "name": "project_and_serialize_policy_context",
- "full_id": "security_engine_policy_context/project_and_serialize_policy_context",
- "estimate_kind": "slope",
- "estimate_ns": 6763.1576853859615,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 6757.461616498088,
- "upper_bound": 6769.753491734433
- },
- "estimate_standard_error_ns": 3.1384328390478835,
- "mean_ns": 6763.64784146405,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 6758.705226323678,
- "upper_bound": 6768.989526379192
- },
- "median_ns": 6758.171276405299,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 6753.118907837107,
- "upper_bound": 6762.851360544218
- },
- "slope_ns": 6763.1576853859615,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 6757.461616498088,
- "upper_bound": 6769.753491734433
- },
- "slope_standard_error_ns": 3.1384328390478835
- },
- {
- "group": "security_engine_policy_context",
- "name": "project_security_event_to_policy_context",
- "full_id": "security_engine_policy_context/project_security_event_to_policy_context",
- "estimate_kind": "slope",
- "estimate_ns": 985.9388411888614,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 985.2855612374204,
- "upper_bound": 986.6594307482547
- },
- "estimate_standard_error_ns": 0.3507954822542139,
- "mean_ns": 986.2417990600875,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 985.4339181935894,
- "upper_bound": 987.2359712963062
- },
- "median_ns": 985.473422787194,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 984.5586398698641,
- "upper_bound": 985.8121850664223
- },
- "slope_ns": 985.9388411888614,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 985.2855612374204,
- "upper_bound": 986.6594307482547
- },
- "slope_standard_error_ns": 0.3507954822542139
- },
- {
- "group": "security_engine_runtime_registry",
- "name": "add_or_update_single_rule",
- "full_id": "security_engine_runtime_registry/add_or_update_single_rule",
- "estimate_kind": "slope",
- "estimate_ns": 188.4628086026432,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 188.35160812226692,
- "upper_bound": 188.5844230620128
- },
- "estimate_standard_error_ns": 0.059464746532955616,
- "mean_ns": 188.2931206437213,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 188.16715218198067,
- "upper_bound": 188.42980449764653
- },
- "median_ns": 188.18273409876178,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 188.06564907117217,
- "upper_bound": 188.31857871698895
- },
- "slope_ns": 188.4628086026432,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 188.35160812226692,
- "upper_bound": 188.5844230620128
- },
- "slope_standard_error_ns": 0.059464746532955616
- },
- {
- "group": "security_engine_runtime_registry",
- "name": "enabled_enforcement_rules_100_rules",
- "full_id": "security_engine_runtime_registry/enabled_enforcement_rules_100_rules",
- "estimate_kind": "slope",
- "estimate_ns": 23521.095335090606,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 23497.988702101295,
- "upper_bound": 23545.303838338452
- },
- "estimate_standard_error_ns": 12.027858852749146,
- "mean_ns": 23533.17986237268,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 23510.749045726152,
- "upper_bound": 23556.51504224543
- },
- "median_ns": 23513.7238372093,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 23495.03947454255,
- "upper_bound": 23534.985720674675
- },
- "slope_ns": 23521.095335090606,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 23497.988702101295,
- "upper_bound": 23545.303838338452
- },
- "slope_standard_error_ns": 12.027858852749146
- },
- {
- "group": "security_engine_runtime_registry",
- "name": "project_and_compile_detection_100_rules",
- "full_id": "security_engine_runtime_registry/project_and_compile_detection_100_rules",
- "estimate_kind": "slope",
- "estimate_ns": 533852.6369070489,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 533039.3972336316,
- "upper_bound": 534735.0260904786
- },
- "estimate_standard_error_ns": 431.5751836156948,
- "mean_ns": 535821.5775200609,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 534658.811058647,
- "upper_bound": 537096.6499760682
- },
- "median_ns": 533951.9915700738,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 533352.9891304348,
- "upper_bound": 534816.0487804879
- },
- "slope_ns": 533852.6369070489,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 533039.3972336316,
- "upper_bound": 534735.0260904786
- },
- "slope_standard_error_ns": 431.5751836156948
- },
- {
- "group": "security_engine_runtime_registry",
- "name": "project_and_compile_enforcement_100_rules",
- "full_id": "security_engine_runtime_registry/project_and_compile_enforcement_100_rules",
- "estimate_kind": "slope",
- "estimate_ns": 512342.5508881336,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 511161.2698452019,
- "upper_bound": 513632.01471840026
- },
- "estimate_standard_error_ns": 631.7805555642186,
- "mean_ns": 511697.82242114656,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 510964.9937468752,
- "upper_bound": 512483.50030658394
- },
- "median_ns": 510557.43055555556,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 510270.9492753623,
- "upper_bound": 511283.0625
- },
- "slope_ns": 512342.5508881336,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 511161.2698452019,
- "upper_bound": 513632.01471840026
- },
- "slope_standard_error_ns": 631.7805555642186
- },
- {
- "group": "security_engine_runtime_registry",
- "name": "rebuild_engine_from_100_enforcement_100_detection",
- "full_id": "security_engine_runtime_registry/rebuild_engine_from_100_enforcement_100_detection",
- "estimate_kind": "slope",
- "estimate_ns": 1054397.2972661445,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1052511.587913497,
- "upper_bound": 1056368.6155000762
- },
- "estimate_standard_error_ns": 984.9794723578124,
- "mean_ns": 1055346.9344030323,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1054072.5961773724,
- "upper_bound": 1056660.2342762698
- },
- "median_ns": 1053582.935095637,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1052698.9093137255,
- "upper_bound": 1055803.8804081632
- },
- "slope_ns": 1054397.2972661445,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1052511.587913497,
- "upper_bound": 1056368.6155000762
- },
- "slope_standard_error_ns": 984.9794723578124
- },
- {
- "group": "security_engine_runtime_registry",
- "name": "update_existing_then_rebuild_100_rule_plan",
- "full_id": "security_engine_runtime_registry/update_existing_then_rebuild_100_rule_plan",
- "estimate_kind": "slope",
- "estimate_ns": 704524.8117674006,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 698976.2132121614,
- "upper_bound": 711206.9254437375
- },
- "estimate_standard_error_ns": 3142.713594042952,
- "mean_ns": 702196.3154454917,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 699211.5330677731,
- "upper_bound": 705862.7720580617
- },
- "median_ns": 698149.1469827585,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 697052.4666666667,
- "upper_bound": 699361.925
- },
- "slope_ns": 704524.8117674006,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 698976.2132121614,
- "upper_bound": 711206.9254437375
- },
- "slope_standard_error_ns": 3142.713594042952
- }
- ],
- "project_version": "1.2.1779673506",
- "arch": "x86_64",
- "recorded_at": 1780145033.0922406,
- "recorded_at_utc": "2026-05-30T12:43:53.092250+00:00",
- "command": "cargo bench -p capsem-security-engine --bench security_engine_cel",
- "host": {
- "platform": "Linux",
- "release": "7.0.0-1003-gcp",
- "version": "#3-Ubuntu SMP PREEMPT Mon Apr 13 16:29:20 UTC 2026",
- "machine": "x86_64",
- "processor": "",
- "python_version": "3.14.4",
- "cpu_count": 16,
- "cpu_count_logical": 16,
- "cpu_model": "Intel(R) Xeon(R) CPU @ 2.80GHz",
- "cpu_count_physical": 8,
- "memory_total_bytes": 67415740416,
- "memory_total_gb": 62.79,
- "os_pretty_name": "Ubuntu 26.04 LTS",
- "os_id": "ubuntu",
- "os_version_id": "26.04"
- },
- "git": {
- "commit": "b6f9b6e2342496f7c9c5dadd77548aa8d138678e",
- "dirty": false,
- "source_dirty": false,
- "dirty_paths": []
- }
-}
diff --git a/benchmarks/security-engine/data_1.2.1779673506_x86_64_dns_request_enforcement.json b/benchmarks/security-engine/data_1.2.1779673506_x86_64_dns_request_enforcement.json
deleted file mode 100644
index 8beb1a0b2..000000000
--- a/benchmarks/security-engine/data_1.2.1779673506_x86_64_dns_request_enforcement.json
+++ /dev/null
@@ -1,105 +0,0 @@
-{
- "schema": "capsem.security-engine-benchmark.v1",
- "kind": "vm_originated_dns_request_enforcement",
- "version": "1.2.1779673506",
- "source_commit": "b6f9b6e2",
- "timestamp": 1780145303.5515158,
- "arch": "x86_64",
- "host": {
- "platform": "Linux",
- "release": "7.0.0-1003-gcp",
- "version": "#3-Ubuntu SMP PREEMPT Mon Apr 13 16:29:20 UTC 2026",
- "machine": "x86_64",
- "processor": "",
- "python_version": "3.14.4",
- "cpu_count": 16,
- "cpu_count_logical": 16,
- "cpu_model": "Intel(R) Xeon(R) CPU @ 2.80GHz",
- "cpu_count_physical": 8,
- "memory_total_bytes": 67415740416,
- "memory_total_gb": 62.79,
- "os_pretty_name": "Ubuntu 26.04 LTS",
- "os_id": "ubuntu",
- "os_version_id": "26.04"
- },
- "command": "uv run pytest tests/capsem-serial/test_security_engine_benchmark.py::test_dns_request_enforcement_benchmark_records_vm_originated_path -xvs",
- "workload": {
- "event_family": "dns",
- "event_type": "dns.request",
- "source": "vm_originated",
- "path": "guest_resolver_to_dns_proxy_to_security_engine"
- },
- "runs": 8,
- "gate_ms": 1000,
- "rule": {
- "id": "runtime.block-dns-bench.25d35d40",
- "pack_id": "runtime-benchmark",
- "condition": "dns.request.qname == 'security-engine-bench-2cc1fc4e.example.com'",
- "decision": "block"
- },
- "operations": {
- "blocked_dns_request_ms": {
- "min": 1.344,
- "mean": 2.385,
- "median": 1.71,
- "p95": 7.741,
- "p99": 7.741,
- "max": 7.741,
- "values": [
- 7.741,
- 1.654,
- 1.896,
- 1.766,
- 1.835,
- 1.344,
- 1.351,
- 1.494
- ]
- }
- },
- "assertions": {
- "session_db_security_events": {
- "row_count": 16,
- "distinct_event_ids": 16,
- "blocked_count": 16,
- "vm_id": "secdns-a8ab9cd5",
- "profile_id": "profile-asset-boot",
- "user_id": "elieb_google_com",
- "process_operation": null,
- "process_command_class": null,
- "rule_id": "runtime.block-dns-bench.25d35d40",
- "reason": "DNS request blocked by security benchmark"
- },
- "session_db_dns_events": {
- "row_count": 16,
- "denied_count": 16,
- "qname": "security-engine-bench-2cc1fc4e.example.com",
- "policy_mode": "runtime",
- "policy_action": "block",
- "policy_rule": "runtime.block-dns-bench.25d35d40",
- "policy_reason": "DNS request blocked by security benchmark"
- },
- "runtime_match_count": 16,
- "runtime_last_event_id": "dns-ed2523d1dfe64559",
- "logs_exposed_security_decision": true
- },
- "project_version": "1.2.1779673506",
- "recorded_at": 1780145303.5518346,
- "recorded_at_utc": "2026-05-30T12:48:23.551838+00:00",
- "git": {
- "commit": "b6f9b6e2342496f7c9c5dadd77548aa8d138678e",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/capsem-bench/data_1.2.1779673506_x86_64.json",
- "benchmarks/fork/data_1.2.1779673506_x86_64.json",
- "benchmarks/host-native/data_1.2.1779673506_x86_64.json",
- "benchmarks/lifecycle/data_1.2.1779673506_x86_64.json",
- "benchmarks/parallel/data_1.2.1779673506_x86_64.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_http_request_enforcement.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_process_enforcement.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_security_packs_microbench.json"
- ]
- }
-}
diff --git a/benchmarks/security-engine/data_1.2.1779673506_x86_64_http_request_enforcement.json b/benchmarks/security-engine/data_1.2.1779673506_x86_64_http_request_enforcement.json
deleted file mode 100644
index e83372131..000000000
--- a/benchmarks/security-engine/data_1.2.1779673506_x86_64_http_request_enforcement.json
+++ /dev/null
@@ -1,375 +0,0 @@
-{
- "schema": "capsem.security-engine-benchmark.v1",
- "kind": "vm_originated_http_request_enforcement",
- "version": "1.2.1779673506",
- "source_commit": "b6f9b6e2",
- "timestamp": 1780145299.5754488,
- "arch": "x86_64",
- "host": {
- "platform": "Linux",
- "release": "7.0.0-1003-gcp",
- "version": "#3-Ubuntu SMP PREEMPT Mon Apr 13 16:29:20 UTC 2026",
- "machine": "x86_64",
- "processor": "",
- "python_version": "3.14.4",
- "cpu_count": 16,
- "cpu_count_logical": 16,
- "cpu_model": "Intel(R) Xeon(R) CPU @ 2.80GHz",
- "cpu_count_physical": 8,
- "memory_total_bytes": 67415740416,
- "memory_total_gb": 62.79,
- "os_pretty_name": "Ubuntu 26.04 LTS",
- "os_id": "ubuntu",
- "os_version_id": "26.04"
- },
- "command": "uv run pytest tests/capsem-serial/test_security_engine_benchmark.py::test_http_request_enforcement_benchmark_records_vm_originated_path -xvs",
- "workload": {
- "event_family": "network",
- "event_type": "http.request",
- "source": "vm_originated",
- "path": "guest_curl_to_mitm_to_security_engine"
- },
- "runs": 8,
- "warmup_runs": 1,
- "keepalive_runs": 8,
- "gate_ms": 1000,
- "rule": {
- "id": "runtime.block-http-bench.8e69bcd9",
- "pack_id": "runtime-benchmark",
- "condition": "http.request.host == 'example.com' && http.request.path == '/security-engine-bench-block-eed35761'",
- "decision": "block"
- },
- "operations": {
- "blocked_http_request_wall_ms": {
- "min": 20.56,
- "mean": 22.67,
- "median": 21.474,
- "p95": 30.516,
- "p99": 30.516,
- "max": 30.516,
- "values": [
- 23.134,
- 30.516,
- 20.56,
- 21.658,
- 22.081,
- 21.29,
- 21.062,
- 21.063
- ]
- },
- "blocked_http_request_starttransfer_ms": {
- "min": 9.991,
- "mean": 11.272,
- "median": 11.008,
- "p95": 12.958,
- "p99": 12.958,
- "max": 12.958,
- "values": [
- 12.958,
- 12.748,
- 9.991,
- 10.887,
- 11.21,
- 10.961,
- 11.054,
- 10.37
- ]
- },
- "curl_phase_ms": {
- "appconnect": {
- "min": 8.21,
- "mean": 9.446,
- "median": 9.214,
- "p95": 11.001,
- "p99": 11.001,
- "max": 11.001,
- "values": [
- 10.815,
- 11.001,
- 8.21,
- 9.009,
- 9.394,
- 9.214,
- 9.214,
- 8.707
- ]
- },
- "connect": {
- "min": 2.784,
- "mean": 3.204,
- "median": 3.005,
- "p95": 4.804,
- "p99": 4.804,
- "max": 4.804,
- "values": [
- 4.804,
- 3.096,
- 2.784,
- 3.112,
- 3.196,
- 2.906,
- 2.914,
- 2.821
- ]
- },
- "namelookup": {
- "min": 2.684,
- "mean": 3.099,
- "median": 2.897,
- "p95": 4.703,
- "p99": 4.703,
- "max": 4.703,
- "values": [
- 4.703,
- 2.99,
- 2.684,
- 3.004,
- 3.088,
- 2.799,
- 2.804,
- 2.723
- ]
- },
- "pretransfer": {
- "min": 8.285,
- "mean": 9.55,
- "median": 9.287,
- "p95": 11.106,
- "p99": 11.106,
- "max": 11.106,
- "values": [
- 10.989,
- 11.106,
- 8.285,
- 9.086,
- 9.572,
- 9.28,
- 9.295,
- 8.788
- ]
- },
- "starttransfer": {
- "min": 9.991,
- "mean": 11.272,
- "median": 11.008,
- "p95": 12.958,
- "p99": 12.958,
- "max": 12.958,
- "values": [
- 12.958,
- 12.748,
- 9.991,
- 10.887,
- 11.21,
- 10.961,
- 11.054,
- 10.37
- ]
- },
- "total": {
- "min": 10.025,
- "mean": 11.32,
- "median": 11.095,
- "p95": 12.986,
- "p99": 12.986,
- "max": 12.986,
- "values": [
- 12.986,
- 12.8,
- 10.025,
- 10.919,
- 11.238,
- 11.106,
- 11.084,
- 10.402
- ]
- }
- },
- "curl_phase_delta_ms": {
- "dns": {
- "min": 2.684,
- "mean": 3.099,
- "median": 2.897,
- "p95": 4.703,
- "p99": 4.703,
- "max": 4.703,
- "values": [
- 4.703,
- 2.99,
- 2.684,
- 3.004,
- 3.088,
- 2.799,
- 2.804,
- 2.723
- ]
- },
- "pretransfer_after_tls": {
- "min": 0.066,
- "mean": 0.105,
- "median": 0.081,
- "p95": 0.178,
- "p99": 0.178,
- "max": 0.178,
- "values": [
- 0.174,
- 0.105,
- 0.075,
- 0.077,
- 0.178,
- 0.066,
- 0.081,
- 0.081
- ]
- },
- "response_tail_after_first_byte": {
- "min": 0.028,
- "mean": 0.048,
- "median": 0.032,
- "p95": 0.145,
- "p99": 0.145,
- "max": 0.145,
- "values": [
- 0.028,
- 0.052,
- 0.034,
- 0.032,
- 0.028,
- 0.145,
- 0.03,
- 0.032
- ]
- },
- "server_first_byte_after_pretransfer": {
- "min": 1.582,
- "mean": 1.722,
- "median": 1.694,
- "p95": 1.969,
- "p99": 1.969,
- "max": 1.969,
- "values": [
- 1.969,
- 1.642,
- 1.706,
- 1.801,
- 1.638,
- 1.681,
- 1.759,
- 1.582
- ]
- },
- "tcp_connect": {
- "min": 0.098,
- "mean": 0.105,
- "median": 0.106,
- "p95": 0.11,
- "p99": 0.11,
- "max": 0.11,
- "values": [
- 0.101,
- 0.106,
- 0.1,
- 0.108,
- 0.108,
- 0.107,
- 0.11,
- 0.098
- ]
- },
- "tls_appconnect": {
- "min": 5.426,
- "mean": 6.241,
- "median": 6.104,
- "p95": 7.905,
- "p99": 7.905,
- "max": 7.905,
- "values": [
- 6.011,
- 7.905,
- 5.426,
- 5.897,
- 6.198,
- 6.308,
- 6.3,
- 5.886
- ]
- }
- },
- "keepalive_http_request_starttransfer_ms": {
- "min": 1.55,
- "mean": 1.822,
- "median": 1.747,
- "p95": 2.384,
- "p99": 2.384,
- "max": 2.384,
- "values": [
- 2.384,
- 1.706,
- 1.662,
- 1.756,
- 1.739,
- 1.822,
- 1.55,
- 1.959
- ]
- },
- "keepalive_http_request_total_ms": {
- "min": 1.568,
- "mean": 1.848,
- "median": 1.773,
- "p95": 2.425,
- "p99": 2.425,
- "max": 2.425,
- "values": [
- 2.425,
- 1.732,
- 1.692,
- 1.786,
- 1.759,
- 1.845,
- 1.568,
- 1.978
- ]
- },
- "keepalive_connection_ms": {
- "connect_ms": 23.883,
- "tls_handshake_ms": 4.364
- }
- },
- "assertions": {
- "session_db_security_events": {
- "row_count": 17,
- "distinct_event_ids": 17,
- "blocked_count": 17,
- "vm_id": "sechttp-e57923fc",
- "profile_id": "profile-asset-boot",
- "user_id": "elieb_google_com",
- "process_operation": null,
- "process_command_class": null,
- "rule_id": "runtime.block-http-bench.8e69bcd9",
- "reason": "HTTP request blocked by security benchmark"
- },
- "runtime_match_count": 17,
- "runtime_last_event_id": "net-http-d97e90334c51bba8",
- "logs_exposed_security_decision": true
- },
- "project_version": "1.2.1779673506",
- "recorded_at": 1780145299.5762308,
- "recorded_at_utc": "2026-05-30T12:48:19.576233+00:00",
- "git": {
- "commit": "b6f9b6e2342496f7c9c5dadd77548aa8d138678e",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/capsem-bench/data_1.2.1779673506_x86_64.json",
- "benchmarks/fork/data_1.2.1779673506_x86_64.json",
- "benchmarks/host-native/data_1.2.1779673506_x86_64.json",
- "benchmarks/lifecycle/data_1.2.1779673506_x86_64.json",
- "benchmarks/parallel/data_1.2.1779673506_x86_64.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_process_enforcement.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_security_packs_microbench.json"
- ]
- }
-}
diff --git a/benchmarks/security-engine/data_1.2.1779673506_x86_64_mcp_request_enforcement.json b/benchmarks/security-engine/data_1.2.1779673506_x86_64_mcp_request_enforcement.json
deleted file mode 100644
index 93148ee9f..000000000
--- a/benchmarks/security-engine/data_1.2.1779673506_x86_64_mcp_request_enforcement.json
+++ /dev/null
@@ -1,107 +0,0 @@
-{
- "schema": "capsem.security-engine-benchmark.v1",
- "kind": "vm_originated_mcp_request_enforcement",
- "version": "1.2.1779673506",
- "source_commit": "b6f9b6e2",
- "timestamp": 1780145307.6642792,
- "arch": "x86_64",
- "host": {
- "platform": "Linux",
- "release": "7.0.0-1003-gcp",
- "version": "#3-Ubuntu SMP PREEMPT Mon Apr 13 16:29:20 UTC 2026",
- "machine": "x86_64",
- "processor": "",
- "python_version": "3.14.4",
- "cpu_count": 16,
- "cpu_count_logical": 16,
- "cpu_model": "Intel(R) Xeon(R) CPU @ 2.80GHz",
- "cpu_count_physical": 8,
- "memory_total_bytes": 67415740416,
- "memory_total_gb": 62.79,
- "os_pretty_name": "Ubuntu 26.04 LTS",
- "os_id": "ubuntu",
- "os_version_id": "26.04"
- },
- "command": "uv run pytest tests/capsem-serial/test_security_engine_benchmark.py::test_mcp_request_enforcement_benchmark_records_vm_originated_path -xvs",
- "workload": {
- "event_family": "mcp",
- "event_type": "mcp.request",
- "source": "vm_originated",
- "path": "guest_mcp_server_to_framed_vsock_to_security_engine"
- },
- "runs": 8,
- "gate_ms": 1000,
- "rule": {
- "id": "runtime.block-mcp-bench.1444939a",
- "pack_id": "runtime-benchmark",
- "condition": "mcp.request.server_id == 'local' && mcp.request.tool_name == 'echo'",
- "decision": "block"
- },
- "operations": {
- "blocked_mcp_request_ms": {
- "min": 0.685,
- "mean": 0.961,
- "median": 0.792,
- "p95": 2.149,
- "p99": 2.149,
- "max": 2.149,
- "values": [
- 2.149,
- 0.918,
- 0.787,
- 0.797,
- 0.819,
- 0.757,
- 0.78,
- 0.685
- ]
- }
- },
- "assertions": {
- "session_db_security_events": {
- "row_count": 8,
- "distinct_event_ids": 8,
- "blocked_count": 8,
- "vm_id": "secmcp-64467680",
- "profile_id": "profile-asset-boot",
- "user_id": "elieb_google_com",
- "process_operation": null,
- "process_command_class": null,
- "rule_id": "runtime.block-mcp-bench.1444939a",
- "reason": "MCP request blocked by security benchmark"
- },
- "session_db_mcp_calls": {
- "row_count": 8,
- "denied_count": 8,
- "server_name": "local",
- "tool_name": "local__echo",
- "policy_mode": "enforce",
- "policy_action": "block",
- "policy_rule": "runtime.block-mcp-bench.1444939a",
- "policy_reason": "MCP request blocked by security benchmark"
- },
- "runtime_match_count": 8,
- "runtime_last_event_id": "mcp-12e57b21ea8e3007",
- "logs_exposed_security_decision": true
- },
- "project_version": "1.2.1779673506",
- "recorded_at": 1780145307.6646392,
- "recorded_at_utc": "2026-05-30T12:48:27.664641+00:00",
- "git": {
- "commit": "b6f9b6e2342496f7c9c5dadd77548aa8d138678e",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/capsem-bench/data_1.2.1779673506_x86_64.json",
- "benchmarks/fork/data_1.2.1779673506_x86_64.json",
- "benchmarks/host-native/data_1.2.1779673506_x86_64.json",
- "benchmarks/lifecycle/data_1.2.1779673506_x86_64.json",
- "benchmarks/parallel/data_1.2.1779673506_x86_64.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_dns_request_enforcement.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_http_request_enforcement.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_process_enforcement.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_security_packs_microbench.json"
- ]
- }
-}
diff --git a/benchmarks/security-engine/data_1.2.1779673506_x86_64_process_enforcement.json b/benchmarks/security-engine/data_1.2.1779673506_x86_64_process_enforcement.json
deleted file mode 100644
index a413071ea..000000000
--- a/benchmarks/security-engine/data_1.2.1779673506_x86_64_process_enforcement.json
+++ /dev/null
@@ -1,94 +0,0 @@
-{
- "schema": "capsem.security-engine-benchmark.v1",
- "kind": "vm_originated_process_enforcement",
- "version": "1.2.1779673506",
- "source_commit": "b6f9b6e2",
- "timestamp": 1780145295.0205843,
- "arch": "x86_64",
- "host": {
- "platform": "Linux",
- "release": "7.0.0-1003-gcp",
- "version": "#3-Ubuntu SMP PREEMPT Mon Apr 13 16:29:20 UTC 2026",
- "machine": "x86_64",
- "processor": "",
- "python_version": "3.14.4",
- "cpu_count": 16,
- "cpu_count_logical": 16,
- "cpu_model": "Intel(R) Xeon(R) CPU @ 2.80GHz",
- "cpu_count_physical": 8,
- "memory_total_bytes": 67415740416,
- "memory_total_gb": 62.79,
- "os_pretty_name": "Ubuntu 26.04 LTS",
- "os_id": "ubuntu",
- "os_version_id": "26.04"
- },
- "command": "uv run pytest tests/capsem-serial/test_security_engine_benchmark.py -xvs",
- "workload": {
- "event_family": "process",
- "event_type": "process.exec",
- "source": "vm_originated",
- "path": "service_api_to_capsem_process_to_security_engine"
- },
- "runs": 8,
- "gate_ms": 750,
- "rule": {
- "id": "runtime.block-shell-bench.879f2b24",
- "pack_id": "runtime-benchmark",
- "condition": "process.activity.operation == 'exec' && process.activity.command_class == 'shell'",
- "decision": "block"
- },
- "operations": {
- "blocked_process_exec_ms": {
- "min": 14.421,
- "mean": 14.852,
- "median": 14.733,
- "p95": 16.043,
- "p99": 16.043,
- "max": 16.043,
- "values": [
- 16.043,
- 14.421,
- 14.796,
- 14.94,
- 14.925,
- 14.592,
- 14.671,
- 14.428
- ]
- }
- },
- "assertions": {
- "session_db_security_events": {
- "row_count": 8,
- "distinct_event_ids": 8,
- "blocked_count": 8,
- "vm_id": "secbench-7ffd4997",
- "profile_id": "profile-asset-boot",
- "user_id": "elieb_google_com",
- "process_operation": "exec",
- "process_command_class": "shell",
- "rule_id": "runtime.block-shell-bench.879f2b24",
- "reason": "shell exec blocked by security benchmark"
- },
- "runtime_match_count": 8,
- "runtime_last_event_id": "process-85286ef6940cfc1b",
- "logs_exposed_security_decision": true
- },
- "project_version": "1.2.1779673506",
- "recorded_at": 1780145295.0209706,
- "recorded_at_utc": "2026-05-30T12:48:15.020972+00:00",
- "git": {
- "commit": "b6f9b6e2342496f7c9c5dadd77548aa8d138678e",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/capsem-bench/data_1.2.1779673506_x86_64.json",
- "benchmarks/fork/data_1.2.1779673506_x86_64.json",
- "benchmarks/host-native/data_1.2.1779673506_x86_64.json",
- "benchmarks/lifecycle/data_1.2.1779673506_x86_64.json",
- "benchmarks/parallel/data_1.2.1779673506_x86_64.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_security_packs_microbench.json"
- ]
- }
-}
diff --git a/benchmarks/security-engine/data_1.2.1779673506_x86_64_security_packs_microbench.json b/benchmarks/security-engine/data_1.2.1779673506_x86_64_security_packs_microbench.json
deleted file mode 100644
index b717b11a6..000000000
--- a/benchmarks/security-engine/data_1.2.1779673506_x86_64_security_packs_microbench.json
+++ /dev/null
@@ -1,172 +0,0 @@
-{
- "schema": "capsem.security-engine-benchmark.v1",
- "kind": "criterion_security_packs_microbench",
- "source_commit": "b6f9b6e2",
- "profile": {
- "cargo_profile": "bench",
- "criterion_samples": 100,
- "criterion_warmup_seconds": 3,
- "criterion_target_seconds": 5
- },
- "scope": {
- "vm_originated": false,
- "notes": [
- "Host-side microbenchmark only.",
- "Measures Detection IR V1 JSON parse/validate, Detection IR to CEL detection-rule lowering, and lower-plus-compile costs.",
- "Does not include VM transport, service IPC, runtime registry propagation, Security Engine dispatch, or session.db journal write latency."
- ]
- },
- "measurements": [
- {
- "group": "security_packs_detection_ir_lowering",
- "name": "lower_100_http_rules_to_cel_rules",
- "full_id": "security_packs_detection_ir_lowering/lower_100_http_rules_to_cel_rules",
- "estimate_kind": "slope",
- "estimate_ns": 189741.18075809075,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 189626.03321424022,
- "upper_bound": 189868.80782624744
- },
- "estimate_standard_error_ns": 61.97646959541508,
- "mean_ns": 189806.21686738997,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 189669.48774469423,
- "upper_bound": 189960.31734998964
- },
- "median_ns": 189597.0007259001,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 189500.59333333332,
- "upper_bound": 189698.66666666666
- },
- "slope_ns": 189741.18075809075,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 189626.03321424022,
- "upper_bound": 189868.80782624744
- },
- "slope_standard_error_ns": 61.97646959541508
- },
- {
- "group": "security_packs_detection_ir_lowering",
- "name": "lower_and_compile_100_http_rules",
- "full_id": "security_packs_detection_ir_lowering/lower_and_compile_100_http_rules",
- "estimate_kind": "mean",
- "estimate_ns": 7138522.0475,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 7132971.71103125,
- "upper_bound": 7144332.31546875
- },
- "estimate_standard_error_ns": 2902.6598592019623,
- "mean_ns": 7138522.0475,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 7132971.71103125,
- "upper_bound": 7144332.31546875
- },
- "median_ns": 7129469.0,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 7125616.8125,
- "upper_bound": 7139407.375
- }
- },
- {
- "group": "security_packs_detection_ir_lowering",
- "name": "lower_google_secret_fixture_to_cel_rules",
- "full_id": "security_packs_detection_ir_lowering/lower_google_secret_fixture_to_cel_rules",
- "estimate_kind": "slope",
- "estimate_ns": 1567.0444299148373,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1566.2791833906192,
- "upper_bound": 1567.901408348624
- },
- "estimate_standard_error_ns": 0.41596628794601065,
- "mean_ns": 1567.9796794447682,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1567.2360519527151,
- "upper_bound": 1568.771086933813
- },
- "median_ns": 1566.8038043699808,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1566.30421865716,
- "upper_bound": 1567.8704292527823
- },
- "slope_ns": 1567.0444299148373,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1566.2791833906192,
- "upper_bound": 1567.901408348624
- },
- "slope_standard_error_ns": 0.41596628794601065
- },
- {
- "group": "security_packs_detection_ir_parse",
- "name": "parse_validate_google_secret_fixture",
- "full_id": "security_packs_detection_ir_parse/parse_validate_google_secret_fixture",
- "estimate_kind": "slope",
- "estimate_ns": 411174.2217279937,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 410629.64961807866,
- "upper_bound": 411793.88237786817
- },
- "estimate_standard_error_ns": 297.2961395517204,
- "mean_ns": 411704.57488336274,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 411070.29921236366,
- "upper_bound": 412457.3747830594
- },
- "median_ns": 410666.5648434813,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 410326.75757575757,
- "upper_bound": 410950.9212121212
- },
- "slope_ns": 411174.2217279937,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 410629.64961807866,
- "upper_bound": 411793.88237786817
- },
- "slope_standard_error_ns": 297.2961395517204
- }
- ],
- "project_version": "1.2.1779673506",
- "arch": "x86_64",
- "recorded_at": 1780145033.1146164,
- "recorded_at_utc": "2026-05-30T12:43:53.114619+00:00",
- "command": "cargo bench -p capsem-core --bench security_packs",
- "host": {
- "platform": "Linux",
- "release": "7.0.0-1003-gcp",
- "version": "#3-Ubuntu SMP PREEMPT Mon Apr 13 16:29:20 UTC 2026",
- "machine": "x86_64",
- "processor": "",
- "python_version": "3.14.4",
- "cpu_count": 16,
- "cpu_count_logical": 16,
- "cpu_model": "Intel(R) Xeon(R) CPU @ 2.80GHz",
- "cpu_count_physical": 8,
- "memory_total_bytes": 67415740416,
- "memory_total_gb": 62.79,
- "os_pretty_name": "Ubuntu 26.04 LTS",
- "os_id": "ubuntu",
- "os_version_id": "26.04"
- },
- "git": {
- "commit": "b6f9b6e2342496f7c9c5dadd77548aa8d138678e",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/security-engine/data_1.2.1779673506_x86_64_cel_microbench.json"
- ]
- }
-}
diff --git a/benchmarks/security-engine/data_1.2.1780103109_arm64_cel_microbench.json b/benchmarks/security-engine/data_1.2.1780103109_arm64_cel_microbench.json
deleted file mode 100644
index 1ce87834b..000000000
--- a/benchmarks/security-engine/data_1.2.1780103109_arm64_cel_microbench.json
+++ /dev/null
@@ -1,783 +0,0 @@
-{
- "schema": "capsem.security-engine-benchmark.v1",
- "kind": "criterion_cel_microbench",
- "source_commit": "0a425541",
- "profile": {
- "cargo_profile": "bench",
- "criterion_samples": 100,
- "criterion_warmup_seconds": 3,
- "criterion_target_seconds": 5
- },
- "scope": {
- "vm_originated": false,
- "notes": [
- "Host-side microbenchmark only.",
- "Measures canonical policy-context CEL paths, detection evaluation, backtest dedupe, runtime registry operations, compiled-plan rebuild cost, and native lookup comparators.",
- "Does not include guest transport, service IPC, Security Engine emitter, or session.db journal write latency."
- ]
- },
- "measurements": [
- {
- "group": "security_engine_backtest_dedupe",
- "name": "dedupe_1000_rows_100_unique_limit_100",
- "full_id": "security_engine_backtest_dedupe/dedupe_1000_rows_100_unique_limit_100",
- "estimate_kind": "slope",
- "estimate_ns": 169765.76354120485,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 168948.6094514328,
- "upper_bound": 170622.6829797996
- },
- "estimate_standard_error_ns": 426.86650908326123,
- "mean_ns": 171216.60629213433,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 170292.6807284613,
- "upper_bound": 172210.95309741155
- },
- "median_ns": 170047.25065322884,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 169286.69047619047,
- "upper_bound": 171392.61366959065
- },
- "slope_ns": 169765.76354120485,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 168948.6094514328,
- "upper_bound": 170622.6829797996
- },
- "slope_standard_error_ns": 426.86650908326123
- },
- {
- "group": "security_engine_backtest_dedupe",
- "name": "dedupe_100_unique_limit_100",
- "full_id": "security_engine_backtest_dedupe/dedupe_100_unique_limit_100",
- "estimate_kind": "slope",
- "estimate_ns": 19643.4602894091,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 19552.792439124063,
- "upper_bound": 19737.559866098803
- },
- "estimate_standard_error_ns": 47.102449961664554,
- "mean_ns": 19659.581435361728,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 19586.21140557635,
- "upper_bound": 19734.076385783923
- },
- "median_ns": 19685.2679698415,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 19570.28081232493,
- "upper_bound": 19759.64892623716
- },
- "slope_ns": 19643.4602894091,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 19552.792439124063,
- "upper_bound": 19737.559866098803
- },
- "slope_standard_error_ns": 47.102449961664554
- },
- {
- "group": "security_engine_cel_compile",
- "name": "canonical_http_policy",
- "full_id": "security_engine_cel_compile/canonical_http_policy",
- "estimate_kind": "slope",
- "estimate_ns": 41718.609581917146,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 41224.817075029096,
- "upper_bound": 42293.88939537181
- },
- "estimate_standard_error_ns": 273.085274173881,
- "mean_ns": 41933.07568435598,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 41397.779468702225,
- "upper_bound": 42503.21114396413
- },
- "median_ns": 40700.916075650115,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 40347.49038461538,
- "upper_bound": 41581.90202702703
- },
- "slope_ns": 41718.609581917146,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 41224.817075029096,
- "upper_bound": 42293.88939537181
- },
- "slope_standard_error_ns": 273.085274173881
- },
- {
- "group": "security_engine_cel_compile",
- "name": "header_authorization_exists",
- "full_id": "security_engine_cel_compile/header_authorization_exists",
- "estimate_kind": "slope",
- "estimate_ns": 8616.623499101677,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 8567.865543645008,
- "upper_bound": 8688.037120183591
- },
- "estimate_standard_error_ns": 31.431303882251754,
- "mean_ns": 8646.883889357558,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 8608.062641921015,
- "upper_bound": 8697.130460181477
- },
- "median_ns": 8608.474806073971,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 8584.462183235868,
- "upper_bound": 8642.336231884059
- },
- "slope_ns": 8616.623499101677,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 8567.865543645008,
- "upper_bound": 8688.037120183591
- },
- "slope_standard_error_ns": 31.431303882251754
- },
- {
- "group": "security_engine_cel_compile",
- "name": "host_contains_google",
- "full_id": "security_engine_cel_compile/host_contains_google",
- "estimate_kind": "slope",
- "estimate_ns": 8649.469081196416,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 8632.146142493075,
- "upper_bound": 8665.754753135845
- },
- "estimate_standard_error_ns": 8.584168809417832,
- "mean_ns": 8638.20767255532,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 8622.42341217505,
- "upper_bound": 8654.950240387221
- },
- "median_ns": 8639.604678362573,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 8626.475019461672,
- "upper_bound": 8647.890023566379
- },
- "slope_ns": 8649.469081196416,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 8632.146142493075,
- "upper_bound": 8665.754753135845
- },
- "slope_standard_error_ns": 8.584168809417832
- },
- {
- "group": "security_engine_cel_evaluate",
- "name": "body_contains_secret",
- "full_id": "security_engine_cel_evaluate/body_contains_secret",
- "estimate_kind": "slope",
- "estimate_ns": 19632.66307365065,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 18775.692965899267,
- "upper_bound": 20533.670403222477
- },
- "estimate_standard_error_ns": 449.75127613926065,
- "mean_ns": 17565.682046035974,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 16855.14303723588,
- "upper_bound": 18317.033249668944
- },
- "median_ns": 15223.358585858587,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 14833.491895990255,
- "upper_bound": 17712.206597222223
- },
- "slope_ns": 19632.66307365065,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 18775.692965899267,
- "upper_bound": 20533.670403222477
- },
- "slope_standard_error_ns": 449.75127613926065
- },
- {
- "group": "security_engine_cel_evaluate",
- "name": "canonical_http_policy",
- "full_id": "security_engine_cel_evaluate/canonical_http_policy",
- "estimate_kind": "slope",
- "estimate_ns": 23654.551517587144,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 23295.368881249542,
- "upper_bound": 24018.33365434777
- },
- "estimate_standard_error_ns": 184.92987734881797,
- "mean_ns": 23354.650129986963,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 23137.079444453,
- "upper_bound": 23592.87084374474
- },
- "median_ns": 22954.423742201732,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 22730.390798226163,
- "upper_bound": 23170.869222372778
- },
- "slope_ns": 23654.551517587144,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 23295.368881249542,
- "upper_bound": 24018.33365434777
- },
- "slope_standard_error_ns": 184.92987734881797
- },
- {
- "group": "security_engine_cel_evaluate",
- "name": "canonical_http_policy_last_match_100_rules",
- "full_id": "security_engine_cel_evaluate/canonical_http_policy_last_match_100_rules",
- "estimate_kind": "slope",
- "estimate_ns": 1287960.3025565243,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1284711.6400885107,
- "upper_bound": 1291444.1344560254
- },
- "estimate_standard_error_ns": 1710.4207686994357,
- "mean_ns": 1288414.0467362802,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1285448.5141307209,
- "upper_bound": 1291464.5838861351
- },
- "median_ns": 1285466.1458333335,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1283516.0500578703,
- "upper_bound": 1288519.3452380951
- },
- "slope_ns": 1287960.3025565243,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1284711.6400885107,
- "upper_bound": 1291444.1344560254
- },
- "slope_standard_error_ns": 1710.4207686994357
- },
- {
- "group": "security_engine_cel_evaluate",
- "name": "header_authorization_exists",
- "full_id": "security_engine_cel_evaluate/header_authorization_exists",
- "estimate_kind": "slope",
- "estimate_ns": 16276.505282579152,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 16194.231808248274,
- "upper_bound": 16387.62454698775
- },
- "estimate_standard_error_ns": 50.180476651381504,
- "mean_ns": 16270.042171429142,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 16214.527098586868,
- "upper_bound": 16330.087184283091
- },
- "median_ns": 16244.39186764726,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 16195.171518138395,
- "upper_bound": 16285.002107728336
- },
- "slope_ns": 16276.505282579152,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 16194.231808248274,
- "upper_bound": 16387.62454698775
- },
- "slope_standard_error_ns": 50.180476651381504
- },
- {
- "group": "security_engine_cel_evaluate",
- "name": "host_contains_google",
- "full_id": "security_engine_cel_evaluate/host_contains_google",
- "estimate_kind": "slope",
- "estimate_ns": 14632.247152357028,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 14488.3952780408,
- "upper_bound": 14795.354188064981
- },
- "estimate_standard_error_ns": 78.58762769461745,
- "mean_ns": 14540.814346765674,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 14441.685386020818,
- "upper_bound": 14650.448341172358
- },
- "median_ns": 14381.457539682538,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 14293.054761904761,
- "upper_bound": 14422.896957343732
- },
- "slope_ns": 14632.247152357028,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 14488.3952780408,
- "upper_bound": 14795.354188064981
- },
- "slope_standard_error_ns": 78.58762769461745
- },
- {
- "group": "security_engine_cel_evaluate",
- "name": "path_starts_admin",
- "full_id": "security_engine_cel_evaluate/path_starts_admin",
- "estimate_kind": "slope",
- "estimate_ns": 14508.100129186183,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 14456.007960182962,
- "upper_bound": 14561.990739449777
- },
- "estimate_standard_error_ns": 27.032526114726025,
- "mean_ns": 14537.537372544028,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 14467.188986800234,
- "upper_bound": 14632.85408665708
- },
- "median_ns": 14499.13656918344,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 14470.85984446801,
- "upper_bound": 14524.517391304347
- },
- "slope_ns": 14508.100129186183,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 14456.007960182962,
- "upper_bound": 14561.990739449777
- },
- "slope_standard_error_ns": 27.032526114726025
- },
- {
- "group": "security_engine_cel_evaluate",
- "name": "url_contains_google",
- "full_id": "security_engine_cel_evaluate/url_contains_google",
- "estimate_kind": "slope",
- "estimate_ns": 14258.134954674999,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 14211.341365242857,
- "upper_bound": 14307.707069331746
- },
- "estimate_standard_error_ns": 24.559890730385774,
- "mean_ns": 14235.942664333203,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 14198.738975098966,
- "upper_bound": 14275.447315539737
- },
- "median_ns": 14228.6728613159,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 14158.2943793911,
- "upper_bound": 14277.848979591838
- },
- "slope_ns": 14258.134954674999,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 14211.341365242857,
- "upper_bound": 14307.707069331746
- },
- "slope_standard_error_ns": 24.559890730385774
- },
- {
- "group": "security_engine_detection_evaluate",
- "name": "canonical_http_policy_last_match_100_rules",
- "full_id": "security_engine_detection_evaluate/canonical_http_policy_last_match_100_rules",
- "estimate_kind": "slope",
- "estimate_ns": 1289735.495806118,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1285890.2017830922,
- "upper_bound": 1293567.7830477143
- },
- "estimate_standard_error_ns": 1959.687046365984,
- "mean_ns": 1291649.4525483807,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1284217.3200951158,
- "upper_bound": 1300828.4299138242
- },
- "median_ns": 1283481.7298245616,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1280409.6153846155,
- "upper_bound": 1287562.6042105262
- },
- "slope_ns": 1289735.495806118,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1285890.2017830922,
- "upper_bound": 1293567.7830477143
- },
- "slope_standard_error_ns": 1959.687046365984
- },
- {
- "group": "security_engine_detection_evaluate",
- "name": "canonical_http_policy_single_rule",
- "full_id": "security_engine_detection_evaluate/canonical_http_policy_single_rule",
- "estimate_kind": "slope",
- "estimate_ns": 23534.05278069702,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 23395.27925850916,
- "upper_bound": 23686.89650204526
- },
- "estimate_standard_error_ns": 74.70411278258345,
- "mean_ns": 23492.61610246049,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 23394.70987069618,
- "upper_bound": 23602.553392010082
- },
- "median_ns": 23342.58967284194,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 23274.347783810066,
- "upper_bound": 23423.87354651163
- },
- "slope_ns": 23534.05278069702,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 23395.27925850916,
- "upper_bound": 23686.89650204526
- },
- "slope_standard_error_ns": 74.70411278258345
- },
- {
- "group": "security_engine_native_lookup",
- "name": "canonical_http_policy",
- "full_id": "security_engine_native_lookup/canonical_http_policy",
- "estimate_kind": "slope",
- "estimate_ns": 11.56022872300204,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 11.486627050790734,
- "upper_bound": 11.663479639473673
- },
- "estimate_standard_error_ns": 0.04590679008584831,
- "mean_ns": 11.573955306622276,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 11.514307633577902,
- "upper_bound": 11.650394647595308
- },
- "median_ns": 11.478722441406909,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 11.44869461383292,
- "upper_bound": 11.50303918298771
- },
- "slope_ns": 11.56022872300204,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 11.486627050790734,
- "upper_bound": 11.663479639473673
- },
- "slope_standard_error_ns": 0.04590679008584831
- },
- {
- "group": "security_engine_policy_context",
- "name": "project_and_serialize_policy_context",
- "full_id": "security_engine_policy_context/project_and_serialize_policy_context",
- "estimate_kind": "slope",
- "estimate_ns": 2583.876898586795,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 2572.9095306138915,
- "upper_bound": 2596.388245504242
- },
- "estimate_standard_error_ns": 5.969008483359895,
- "mean_ns": 2597.9580933568045,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 2585.2559255374053,
- "upper_bound": 2610.3152871649054
- },
- "median_ns": 2601.156008611272,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 2580.2553960659225,
- "upper_bound": 2618.791533758639
- },
- "slope_ns": 2583.876898586795,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 2572.9095306138915,
- "upper_bound": 2596.388245504242
- },
- "slope_standard_error_ns": 5.969008483359895
- },
- {
- "group": "security_engine_policy_context",
- "name": "project_security_event_to_policy_context",
- "full_id": "security_engine_policy_context/project_security_event_to_policy_context",
- "estimate_kind": "slope",
- "estimate_ns": 536.2613986337147,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 534.2144146218218,
- "upper_bound": 538.6022172536678
- },
- "estimate_standard_error_ns": 1.1213512408129251,
- "mean_ns": 543.8344729071761,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 540.2625613239089,
- "upper_bound": 547.7085047252102
- },
- "median_ns": 538.7772053950159,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 536.672758152174,
- "upper_bound": 541.2512341485508
- },
- "slope_ns": 536.2613986337147,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 534.2144146218218,
- "upper_bound": 538.6022172536678
- },
- "slope_standard_error_ns": 1.1213512408129251
- },
- {
- "group": "security_engine_runtime_registry",
- "name": "add_or_update_single_rule",
- "full_id": "security_engine_runtime_registry/add_or_update_single_rule",
- "estimate_kind": "slope",
- "estimate_ns": 148.80511032943258,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 148.31668130393106,
- "upper_bound": 149.321235256347
- },
- "estimate_standard_error_ns": 0.25595267601626276,
- "mean_ns": 149.66902817328435,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 149.19307129291133,
- "upper_bound": 150.15543405950103
- },
- "median_ns": 149.31438234798117,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 148.7471829882897,
- "upper_bound": 150.4720254798658
- },
- "slope_ns": 148.80511032943258,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 148.31668130393106,
- "upper_bound": 149.321235256347
- },
- "slope_standard_error_ns": 0.25595267601626276
- },
- {
- "group": "security_engine_runtime_registry",
- "name": "enabled_enforcement_rules_100_rules",
- "full_id": "security_engine_runtime_registry/enabled_enforcement_rules_100_rules",
- "estimate_kind": "slope",
- "estimate_ns": 7631.368825295581,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 7600.289080368191,
- "upper_bound": 7661.7625743694225
- },
- "estimate_standard_error_ns": 15.702187492549706,
- "mean_ns": 7617.5916796176325,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 7587.812324380978,
- "upper_bound": 7647.766577151961
- },
- "median_ns": 7614.80891642548,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 7583.649097564796,
- "upper_bound": 7661.639985014985
- },
- "slope_ns": 7631.368825295581,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 7600.289080368191,
- "upper_bound": 7661.7625743694225
- },
- "slope_standard_error_ns": 15.702187492549706
- },
- {
- "group": "security_engine_runtime_registry",
- "name": "project_and_compile_detection_100_rules",
- "full_id": "security_engine_runtime_registry/project_and_compile_detection_100_rules",
- "estimate_kind": "slope",
- "estimate_ns": 316875.4547251367,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 315314.8606088706,
- "upper_bound": 318445.0754923803
- },
- "estimate_standard_error_ns": 798.071279615365,
- "mean_ns": 318680.90039144084,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 316509.76560837973,
- "upper_bound": 321363.445182746
- },
- "median_ns": 317208.4780595813,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 315323.26666666666,
- "upper_bound": 318262.5890151515
- },
- "slope_ns": 316875.4547251367,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 315314.8606088706,
- "upper_bound": 318445.0754923803
- },
- "slope_standard_error_ns": 798.071279615365
- },
- {
- "group": "security_engine_runtime_registry",
- "name": "project_and_compile_enforcement_100_rules",
- "full_id": "security_engine_runtime_registry/project_and_compile_enforcement_100_rules",
- "estimate_kind": "slope",
- "estimate_ns": 321268.87703783065,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 310757.6904121714,
- "upper_bound": 333952.6763315121
- },
- "estimate_standard_error_ns": 5962.033579203133,
- "mean_ns": 311040.57187868236,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 305960.58828087687,
- "upper_bound": 317243.9182259018
- },
- "median_ns": 304068.9513888889,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 302045.18506493507,
- "upper_bound": 306882.3776041667
- },
- "slope_ns": 321268.87703783065,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 310757.6904121714,
- "upper_bound": 333952.6763315121
- },
- "slope_standard_error_ns": 5962.033579203133
- },
- {
- "group": "security_engine_runtime_registry",
- "name": "rebuild_engine_from_100_enforcement_100_detection",
- "full_id": "security_engine_runtime_registry/rebuild_engine_from_100_enforcement_100_detection",
- "estimate_kind": "slope",
- "estimate_ns": 610565.8707388799,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 607722.8328919687,
- "upper_bound": 613754.440881424
- },
- "estimate_standard_error_ns": 1538.9976078734742,
- "mean_ns": 614268.2281117368,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 612023.6885140041,
- "upper_bound": 616569.9551478114
- },
- "median_ns": 614474.9083867521,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 611592.5147058824,
- "upper_bound": 617119.7964703424
- },
- "slope_ns": 610565.8707388799,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 607722.8328919687,
- "upper_bound": 613754.440881424
- },
- "slope_standard_error_ns": 1538.9976078734742
- },
- {
- "group": "security_engine_runtime_registry",
- "name": "update_existing_then_rebuild_100_rule_plan",
- "full_id": "security_engine_runtime_registry/update_existing_then_rebuild_100_rule_plan",
- "estimate_kind": "slope",
- "estimate_ns": 361728.1459317275,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 360772.6204630322,
- "upper_bound": 362586.44339550304
- },
- "estimate_standard_error_ns": 460.686497051645,
- "mean_ns": 357293.97890017286,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 355779.0692021401,
- "upper_bound": 358743.9188202766
- },
- "median_ns": 358394.9126425218,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 356585.29285714286,
- "upper_bound": 360225.1076923077
- },
- "slope_ns": 361728.1459317275,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 360772.6204630322,
- "upper_bound": 362586.44339550304
- },
- "slope_standard_error_ns": 460.686497051645
- }
- ],
- "project_version": "1.2.1780103109",
- "arch": "arm64",
- "recorded_at": 1780149808.979703,
- "recorded_at_utc": "2026-05-30T14:03:28.979706+00:00",
- "command": "cargo bench -p capsem-security-engine --bench security_engine_cel",
- "host": {
- "platform": "Darwin",
- "release": "25.5.0",
- "version": "Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:12 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T6050",
- "machine": "arm64",
- "processor": "arm",
- "python_version": "3.14.4",
- "cpu_count": 18,
- "cpu_count_logical": 18,
- "cpu_model": "Apple M5 Max",
- "cpu_count_physical": 18,
- "memory_total_bytes": 137438953472,
- "os_product_version": "26.5",
- "memory_total_gb": 128.0
- },
- "git": {
- "commit": "0a425541fbdc03cc9821aafb238a0dd4b26ccdcd",
- "dirty": false,
- "source_dirty": false,
- "dirty_paths": []
- }
-}
diff --git a/benchmarks/security-engine/data_1.2.1780103109_arm64_dns_request_enforcement.json b/benchmarks/security-engine/data_1.2.1780103109_arm64_dns_request_enforcement.json
deleted file mode 100644
index 85f43d616..000000000
--- a/benchmarks/security-engine/data_1.2.1780103109_arm64_dns_request_enforcement.json
+++ /dev/null
@@ -1,104 +0,0 @@
-{
- "schema": "capsem.security-engine-benchmark.v1",
- "kind": "vm_originated_dns_request_enforcement",
- "version": "1.2.1780103109",
- "source_commit": "0a425541",
- "timestamp": 1780149908.35654,
- "arch": "arm64",
- "host": {
- "platform": "Darwin",
- "release": "25.5.0",
- "version": "Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:12 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T6050",
- "machine": "arm64",
- "processor": "arm",
- "python_version": "3.14.4",
- "cpu_count": 18,
- "cpu_count_logical": 18,
- "cpu_model": "Apple M5 Max",
- "cpu_count_physical": 18,
- "memory_total_bytes": 137438953472,
- "os_product_version": "26.5",
- "memory_total_gb": 128.0
- },
- "command": "uv run pytest tests/capsem-serial/test_security_engine_benchmark.py::test_dns_request_enforcement_benchmark_records_vm_originated_path -xvs",
- "workload": {
- "event_family": "dns",
- "event_type": "dns.request",
- "source": "vm_originated",
- "path": "guest_resolver_to_dns_proxy_to_security_engine"
- },
- "runs": 8,
- "gate_ms": 1000,
- "rule": {
- "id": "runtime.block-dns-bench.92040423",
- "pack_id": "runtime-benchmark",
- "condition": "dns.request.qname == 'security-engine-bench-d006d8eb.example.com'",
- "decision": "block"
- },
- "operations": {
- "blocked_dns_request_ms": {
- "min": 0.403,
- "mean": 0.729,
- "median": 0.435,
- "p95": 2.758,
- "p99": 2.758,
- "max": 2.758,
- "values": [
- 2.758,
- 0.498,
- 0.429,
- 0.409,
- 0.403,
- 0.466,
- 0.441,
- 0.428
- ]
- }
- },
- "assertions": {
- "session_db_security_events": {
- "row_count": 16,
- "distinct_event_ids": 16,
- "blocked_count": 16,
- "vm_id": "secdns-c171f156",
- "profile_id": "profile-asset-boot",
- "user_id": "elie",
- "process_operation": null,
- "process_command_class": null,
- "rule_id": "runtime.block-dns-bench.92040423",
- "reason": "DNS request blocked by security benchmark"
- },
- "session_db_dns_events": {
- "row_count": 16,
- "denied_count": 16,
- "qname": "security-engine-bench-d006d8eb.example.com",
- "policy_mode": "runtime",
- "policy_action": "block",
- "policy_rule": "runtime.block-dns-bench.92040423",
- "policy_reason": "DNS request blocked by security benchmark"
- },
- "runtime_match_count": 16,
- "runtime_last_event_id": "dns-aeca09eb3090d8fa",
- "logs_exposed_security_decision": true
- },
- "project_version": "1.2.1780103109",
- "recorded_at": 1780149908.356926,
- "recorded_at_utc": "2026-05-30T14:05:08.356927+00:00",
- "git": {
- "commit": "0a425541fbdc03cc9821aafb238a0dd4b26ccdcd",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/endpoint-latency/data_1.2.1780103109_arm64.json",
- "benchmarks/capsem-bench/data_1.2.1780103109_arm64.json",
- "benchmarks/fork/data_1.2.1780103109_arm64.json",
- "benchmarks/host-native/data_1.2.1780103109_arm64.json",
- "benchmarks/lifecycle/data_1.2.1780103109_arm64.json",
- "benchmarks/parallel/data_1.2.1780103109_arm64.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_http_request_enforcement.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_process_enforcement.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_security_packs_microbench.json"
- ]
- }
-}
diff --git a/benchmarks/security-engine/data_1.2.1780103109_arm64_http_request_enforcement.json b/benchmarks/security-engine/data_1.2.1780103109_arm64_http_request_enforcement.json
deleted file mode 100644
index d4bcbb457..000000000
--- a/benchmarks/security-engine/data_1.2.1780103109_arm64_http_request_enforcement.json
+++ /dev/null
@@ -1,374 +0,0 @@
-{
- "schema": "capsem.security-engine-benchmark.v1",
- "kind": "vm_originated_http_request_enforcement",
- "version": "1.2.1780103109",
- "source_commit": "0a425541",
- "timestamp": 1780149906.213564,
- "arch": "arm64",
- "host": {
- "platform": "Darwin",
- "release": "25.5.0",
- "version": "Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:12 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T6050",
- "machine": "arm64",
- "processor": "arm",
- "python_version": "3.14.4",
- "cpu_count": 18,
- "cpu_count_logical": 18,
- "cpu_model": "Apple M5 Max",
- "cpu_count_physical": 18,
- "memory_total_bytes": 137438953472,
- "os_product_version": "26.5",
- "memory_total_gb": 128.0
- },
- "command": "uv run pytest tests/capsem-serial/test_security_engine_benchmark.py::test_http_request_enforcement_benchmark_records_vm_originated_path -xvs",
- "workload": {
- "event_family": "network",
- "event_type": "http.request",
- "source": "vm_originated",
- "path": "guest_curl_to_mitm_to_security_engine"
- },
- "runs": 8,
- "warmup_runs": 1,
- "keepalive_runs": 8,
- "gate_ms": 1000,
- "rule": {
- "id": "runtime.block-http-bench.4be78026",
- "pack_id": "runtime-benchmark",
- "condition": "http.request.host == 'example.com' && http.request.path == '/security-engine-bench-block-dca4f33f'",
- "decision": "block"
- },
- "operations": {
- "blocked_http_request_wall_ms": {
- "min": 5.378,
- "mean": 7.142,
- "median": 5.858,
- "p95": 12.245,
- "p99": 12.245,
- "max": 12.245,
- "values": [
- 10.628,
- 12.245,
- 6.012,
- 6.192,
- 5.704,
- 5.448,
- 5.531,
- 5.378
- ]
- },
- "blocked_http_request_starttransfer_ms": {
- "min": 2.788,
- "mean": 3.199,
- "median": 3.097,
- "p95": 3.668,
- "p99": 3.668,
- "max": 3.668,
- "values": [
- 3.668,
- 3.596,
- 3.083,
- 3.418,
- 3.067,
- 2.788,
- 3.111,
- 2.861
- ]
- },
- "curl_phase_ms": {
- "appconnect": {
- "min": 2.263,
- "mean": 2.732,
- "median": 2.635,
- "p95": 3.156,
- "p99": 3.156,
- "max": 3.156,
- "values": [
- 3.156,
- 3.133,
- 2.587,
- 3.016,
- 2.618,
- 2.263,
- 2.651,
- 2.43
- ]
- },
- "connect": {
- "min": 0.815,
- "mean": 1.002,
- "median": 0.956,
- "p95": 1.383,
- "p99": 1.383,
- "max": 1.383,
- "values": [
- 0.958,
- 1.383,
- 0.955,
- 0.961,
- 0.955,
- 0.815,
- 1.112,
- 0.874
- ]
- },
- "namelookup": {
- "min": 0.788,
- "mean": 0.925,
- "median": 0.919,
- "p95": 1.079,
- "p99": 1.079,
- "max": 1.079,
- "values": [
- 0.918,
- 1.045,
- 0.92,
- 0.924,
- 0.902,
- 0.788,
- 1.079,
- 0.822
- ]
- },
- "pretransfer": {
- "min": 2.278,
- "mean": 2.749,
- "median": 2.647,
- "p95": 3.178,
- "p99": 3.178,
- "max": 3.178,
- "values": [
- 3.178,
- 3.153,
- 2.61,
- 3.034,
- 2.633,
- 2.278,
- 2.661,
- 2.446
- ]
- },
- "starttransfer": {
- "min": 2.788,
- "mean": 3.199,
- "median": 3.097,
- "p95": 3.668,
- "p99": 3.668,
- "max": 3.668,
- "values": [
- 3.668,
- 3.596,
- 3.083,
- 3.418,
- 3.067,
- 2.788,
- 3.111,
- 2.861
- ]
- },
- "total": {
- "min": 2.797,
- "mean": 3.209,
- "median": 3.106,
- "p95": 3.68,
- "p99": 3.68,
- "max": 3.68,
- "values": [
- 3.68,
- 3.607,
- 3.094,
- 3.429,
- 3.078,
- 2.797,
- 3.119,
- 2.871
- ]
- }
- },
- "curl_phase_delta_ms": {
- "dns": {
- "min": 0.788,
- "mean": 0.925,
- "median": 0.919,
- "p95": 1.079,
- "p99": 1.079,
- "max": 1.079,
- "values": [
- 0.918,
- 1.045,
- 0.92,
- 0.924,
- 0.902,
- 0.788,
- 1.079,
- 0.822
- ]
- },
- "pretransfer_after_tls": {
- "min": 0.01,
- "mean": 0.017,
- "median": 0.017,
- "p95": 0.023,
- "p99": 0.023,
- "max": 0.023,
- "values": [
- 0.022,
- 0.02,
- 0.023,
- 0.018,
- 0.015,
- 0.015,
- 0.01,
- 0.016
- ]
- },
- "response_tail_after_first_byte": {
- "min": 0.008,
- "mean": 0.01,
- "median": 0.011,
- "p95": 0.012,
- "p99": 0.012,
- "max": 0.012,
- "values": [
- 0.012,
- 0.011,
- 0.011,
- 0.011,
- 0.011,
- 0.009,
- 0.008,
- 0.01
- ]
- },
- "server_first_byte_after_pretransfer": {
- "min": 0.384,
- "mean": 0.45,
- "median": 0.446,
- "p95": 0.51,
- "p99": 0.51,
- "max": 0.51,
- "values": [
- 0.49,
- 0.443,
- 0.473,
- 0.384,
- 0.434,
- 0.51,
- 0.45,
- 0.415
- ]
- },
- "tcp_connect": {
- "min": 0.027,
- "mean": 0.077,
- "median": 0.039,
- "p95": 0.338,
- "p99": 0.338,
- "max": 0.338,
- "values": [
- 0.04,
- 0.338,
- 0.035,
- 0.037,
- 0.053,
- 0.027,
- 0.033,
- 0.052
- ]
- },
- "tls_appconnect": {
- "min": 1.448,
- "mean": 1.73,
- "median": 1.647,
- "p95": 2.198,
- "p99": 2.198,
- "max": 2.198,
- "values": [
- 2.198,
- 1.75,
- 1.632,
- 2.055,
- 1.663,
- 1.448,
- 1.539,
- 1.556
- ]
- }
- },
- "keepalive_http_request_starttransfer_ms": {
- "min": 0.315,
- "mean": 0.364,
- "median": 0.339,
- "p95": 0.588,
- "p99": 0.588,
- "max": 0.588,
- "values": [
- 0.588,
- 0.339,
- 0.315,
- 0.315,
- 0.339,
- 0.338,
- 0.344,
- 0.331
- ]
- },
- "keepalive_http_request_total_ms": {
- "min": 0.321,
- "mean": 0.37,
- "median": 0.342,
- "p95": 0.598,
- "p99": 0.598,
- "max": 0.598,
- "values": [
- 0.598,
- 0.343,
- 0.324,
- 0.321,
- 0.344,
- 0.342,
- 0.35,
- 0.335
- ]
- },
- "keepalive_connection_ms": {
- "connect_ms": 12.394,
- "tls_handshake_ms": 1.155
- }
- },
- "assertions": {
- "session_db_security_events": {
- "row_count": 17,
- "distinct_event_ids": 17,
- "blocked_count": 17,
- "vm_id": "sechttp-b082fd18",
- "profile_id": "profile-asset-boot",
- "user_id": "elie",
- "process_operation": null,
- "process_command_class": null,
- "rule_id": "runtime.block-http-bench.4be78026",
- "reason": "HTTP request blocked by security benchmark"
- },
- "runtime_match_count": 17,
- "runtime_last_event_id": "net-http-6a748a70b8613fba",
- "logs_exposed_security_decision": true
- },
- "project_version": "1.2.1780103109",
- "recorded_at": 1780149906.21412,
- "recorded_at_utc": "2026-05-30T14:05:06.214122+00:00",
- "git": {
- "commit": "0a425541fbdc03cc9821aafb238a0dd4b26ccdcd",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/endpoint-latency/data_1.2.1780103109_arm64.json",
- "benchmarks/capsem-bench/data_1.2.1780103109_arm64.json",
- "benchmarks/fork/data_1.2.1780103109_arm64.json",
- "benchmarks/host-native/data_1.2.1780103109_arm64.json",
- "benchmarks/lifecycle/data_1.2.1780103109_arm64.json",
- "benchmarks/parallel/data_1.2.1780103109_arm64.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_process_enforcement.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_security_packs_microbench.json"
- ]
- }
-}
diff --git a/benchmarks/security-engine/data_1.2.1780103109_arm64_mcp_request_enforcement.json b/benchmarks/security-engine/data_1.2.1780103109_arm64_mcp_request_enforcement.json
deleted file mode 100644
index 4b01ef2db..000000000
--- a/benchmarks/security-engine/data_1.2.1780103109_arm64_mcp_request_enforcement.json
+++ /dev/null
@@ -1,106 +0,0 @@
-{
- "schema": "capsem.security-engine-benchmark.v1",
- "kind": "vm_originated_mcp_request_enforcement",
- "version": "1.2.1780103109",
- "source_commit": "0a425541",
- "timestamp": 1780149910.48114,
- "arch": "arm64",
- "host": {
- "platform": "Darwin",
- "release": "25.5.0",
- "version": "Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:12 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T6050",
- "machine": "arm64",
- "processor": "arm",
- "python_version": "3.14.4",
- "cpu_count": 18,
- "cpu_count_logical": 18,
- "cpu_model": "Apple M5 Max",
- "cpu_count_physical": 18,
- "memory_total_bytes": 137438953472,
- "os_product_version": "26.5",
- "memory_total_gb": 128.0
- },
- "command": "uv run pytest tests/capsem-serial/test_security_engine_benchmark.py::test_mcp_request_enforcement_benchmark_records_vm_originated_path -xvs",
- "workload": {
- "event_family": "mcp",
- "event_type": "mcp.request",
- "source": "vm_originated",
- "path": "guest_mcp_server_to_framed_vsock_to_security_engine"
- },
- "runs": 8,
- "gate_ms": 1000,
- "rule": {
- "id": "runtime.block-mcp-bench.22a9c133",
- "pack_id": "runtime-benchmark",
- "condition": "mcp.request.server_id == 'local' && mcp.request.tool_name == 'echo'",
- "decision": "block"
- },
- "operations": {
- "blocked_mcp_request_ms": {
- "min": 0.174,
- "mean": 0.251,
- "median": 0.189,
- "p95": 0.661,
- "p99": 0.661,
- "max": 0.661,
- "values": [
- 0.661,
- 0.236,
- 0.186,
- 0.189,
- 0.18,
- 0.174,
- 0.189,
- 0.189
- ]
- }
- },
- "assertions": {
- "session_db_security_events": {
- "row_count": 8,
- "distinct_event_ids": 8,
- "blocked_count": 8,
- "vm_id": "secmcp-2f6cb4ed",
- "profile_id": "profile-asset-boot",
- "user_id": "elie",
- "process_operation": null,
- "process_command_class": null,
- "rule_id": "runtime.block-mcp-bench.22a9c133",
- "reason": "MCP request blocked by security benchmark"
- },
- "session_db_mcp_calls": {
- "row_count": 8,
- "denied_count": 8,
- "server_name": "local",
- "tool_name": "local__echo",
- "policy_mode": "enforce",
- "policy_action": "block",
- "policy_rule": "runtime.block-mcp-bench.22a9c133",
- "policy_reason": "MCP request blocked by security benchmark"
- },
- "runtime_match_count": 8,
- "runtime_last_event_id": "mcp-b93ff5c5aa69107e",
- "logs_exposed_security_decision": true
- },
- "project_version": "1.2.1780103109",
- "recorded_at": 1780149910.48156,
- "recorded_at_utc": "2026-05-30T14:05:10.481562+00:00",
- "git": {
- "commit": "0a425541fbdc03cc9821aafb238a0dd4b26ccdcd",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/endpoint-latency/data_1.2.1780103109_arm64.json",
- "benchmarks/capsem-bench/data_1.2.1780103109_arm64.json",
- "benchmarks/fork/data_1.2.1780103109_arm64.json",
- "benchmarks/host-native/data_1.2.1780103109_arm64.json",
- "benchmarks/lifecycle/data_1.2.1780103109_arm64.json",
- "benchmarks/parallel/data_1.2.1780103109_arm64.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_dns_request_enforcement.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_http_request_enforcement.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_process_enforcement.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_security_packs_microbench.json"
- ]
- }
-}
diff --git a/benchmarks/security-engine/data_1.2.1780103109_arm64_process_enforcement.json b/benchmarks/security-engine/data_1.2.1780103109_arm64_process_enforcement.json
deleted file mode 100644
index cdb489a90..000000000
--- a/benchmarks/security-engine/data_1.2.1780103109_arm64_process_enforcement.json
+++ /dev/null
@@ -1,93 +0,0 @@
-{
- "schema": "capsem.security-engine-benchmark.v1",
- "kind": "vm_originated_process_enforcement",
- "version": "1.2.1780103109",
- "source_commit": "0a425541",
- "timestamp": 1780149903.954738,
- "arch": "arm64",
- "host": {
- "platform": "Darwin",
- "release": "25.5.0",
- "version": "Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:12 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T6050",
- "machine": "arm64",
- "processor": "arm",
- "python_version": "3.14.4",
- "cpu_count": 18,
- "cpu_count_logical": 18,
- "cpu_model": "Apple M5 Max",
- "cpu_count_physical": 18,
- "memory_total_bytes": 137438953472,
- "os_product_version": "26.5",
- "memory_total_gb": 128.0
- },
- "command": "uv run pytest tests/capsem-serial/test_security_engine_benchmark.py -xvs",
- "workload": {
- "event_family": "process",
- "event_type": "process.exec",
- "source": "vm_originated",
- "path": "service_api_to_capsem_process_to_security_engine"
- },
- "runs": 8,
- "gate_ms": 750,
- "rule": {
- "id": "runtime.block-shell-bench.9a1332c1",
- "pack_id": "runtime-benchmark",
- "condition": "process.activity.operation == 'exec' && process.activity.command_class == 'shell'",
- "decision": "block"
- },
- "operations": {
- "blocked_process_exec_ms": {
- "min": 9.21,
- "mean": 9.624,
- "median": 9.618,
- "p95": 9.937,
- "p99": 9.937,
- "max": 9.937,
- "values": [
- 9.727,
- 9.21,
- 9.937,
- 9.508,
- 9.871,
- 9.831,
- 9.428,
- 9.478
- ]
- }
- },
- "assertions": {
- "session_db_security_events": {
- "row_count": 8,
- "distinct_event_ids": 8,
- "blocked_count": 8,
- "vm_id": "secbench-bd2f8976",
- "profile_id": "profile-asset-boot",
- "user_id": "elie",
- "process_operation": "exec",
- "process_command_class": "shell",
- "rule_id": "runtime.block-shell-bench.9a1332c1",
- "reason": "shell exec blocked by security benchmark"
- },
- "runtime_match_count": 8,
- "runtime_last_event_id": "process-a4e9824a05fed037",
- "logs_exposed_security_decision": true
- },
- "project_version": "1.2.1780103109",
- "recorded_at": 1780149903.9552379,
- "recorded_at_utc": "2026-05-30T14:05:03.955240+00:00",
- "git": {
- "commit": "0a425541fbdc03cc9821aafb238a0dd4b26ccdcd",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/endpoint-latency/data_1.2.1780103109_arm64.json",
- "benchmarks/capsem-bench/data_1.2.1780103109_arm64.json",
- "benchmarks/fork/data_1.2.1780103109_arm64.json",
- "benchmarks/host-native/data_1.2.1780103109_arm64.json",
- "benchmarks/lifecycle/data_1.2.1780103109_arm64.json",
- "benchmarks/parallel/data_1.2.1780103109_arm64.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_cel_microbench.json",
- "benchmarks/security-engine/data_1.2.1780103109_arm64_security_packs_microbench.json"
- ]
- }
-}
diff --git a/benchmarks/security-engine/data_1.2.1780103109_arm64_security_packs_microbench.json b/benchmarks/security-engine/data_1.2.1780103109_arm64_security_packs_microbench.json
deleted file mode 100644
index d580318b9..000000000
--- a/benchmarks/security-engine/data_1.2.1780103109_arm64_security_packs_microbench.json
+++ /dev/null
@@ -1,170 +0,0 @@
-{
- "schema": "capsem.security-engine-benchmark.v1",
- "kind": "criterion_security_packs_microbench",
- "source_commit": "0a425541",
- "profile": {
- "cargo_profile": "bench",
- "criterion_samples": 100,
- "criterion_warmup_seconds": 3,
- "criterion_target_seconds": 5
- },
- "scope": {
- "vm_originated": false,
- "notes": [
- "Host-side microbenchmark only.",
- "Measures Detection IR V1 JSON parse/validate, Detection IR to CEL detection-rule lowering, and lower-plus-compile costs.",
- "Does not include VM transport, service IPC, runtime registry propagation, Security Engine dispatch, or session.db journal write latency."
- ]
- },
- "measurements": [
- {
- "group": "security_packs_detection_ir_lowering",
- "name": "lower_100_http_rules_to_cel_rules",
- "full_id": "security_packs_detection_ir_lowering/lower_100_http_rules_to_cel_rules",
- "estimate_kind": "slope",
- "estimate_ns": 95640.41941628492,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 95045.14970432255,
- "upper_bound": 96329.87718679853
- },
- "estimate_standard_error_ns": 327.56878700404326,
- "mean_ns": 96446.10542150575,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 95853.13148354982,
- "upper_bound": 97096.61599060171
- },
- "median_ns": 95467.98268272425,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 95114.03684210527,
- "upper_bound": 95981.43939393939
- },
- "slope_ns": 95640.41941628492,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 95045.14970432255,
- "upper_bound": 96329.87718679853
- },
- "slope_standard_error_ns": 327.56878700404326
- },
- {
- "group": "security_packs_detection_ir_lowering",
- "name": "lower_and_compile_100_http_rules",
- "full_id": "security_packs_detection_ir_lowering/lower_and_compile_100_http_rules",
- "estimate_kind": "mean",
- "estimate_ns": 2725164.212777778,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 2705721.8505555554,
- "upper_bound": 2745918.545555556
- },
- "estimate_standard_error_ns": 10264.84329494887,
- "mean_ns": 2725164.212777778,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 2705721.8505555554,
- "upper_bound": 2745918.545555556
- },
- "median_ns": 2692247.6944444445,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 2681824.0555555555,
- "upper_bound": 2719081.0555555555
- }
- },
- {
- "group": "security_packs_detection_ir_lowering",
- "name": "lower_google_secret_fixture_to_cel_rules",
- "full_id": "security_packs_detection_ir_lowering/lower_google_secret_fixture_to_cel_rules",
- "estimate_kind": "slope",
- "estimate_ns": 1038.3981670183268,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1025.0317368968088,
- "upper_bound": 1053.929184224994
- },
- "estimate_standard_error_ns": 7.382723794168417,
- "mean_ns": 1076.374246032845,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1058.739251624613,
- "upper_bound": 1096.4471027116813
- },
- "median_ns": 1065.9041099792303,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1045.7117690002306,
- "upper_bound": 1076.2621004935872
- },
- "slope_ns": 1038.3981670183268,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 1025.0317368968088,
- "upper_bound": 1053.929184224994
- },
- "slope_standard_error_ns": 7.382723794168417
- },
- {
- "group": "security_packs_detection_ir_parse",
- "name": "parse_validate_google_secret_fixture",
- "full_id": "security_packs_detection_ir_parse/parse_validate_google_secret_fixture",
- "estimate_kind": "slope",
- "estimate_ns": 119488.19164277622,
- "estimate_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 118802.76608230414,
- "upper_bound": 120276.238150184
- },
- "estimate_standard_error_ns": 376.4519778173829,
- "mean_ns": 121207.2188062783,
- "mean_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 120533.83105893468,
- "upper_bound": 121909.26397870253
- },
- "median_ns": 120325.47878592879,
- "median_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 119782.95293565455,
- "upper_bound": 120929.23898225957
- },
- "slope_ns": 119488.19164277622,
- "slope_ci_ns": {
- "confidence_level": 0.95,
- "lower_bound": 118802.76608230414,
- "upper_bound": 120276.238150184
- },
- "slope_standard_error_ns": 376.4519778173829
- }
- ],
- "project_version": "1.2.1780103109",
- "arch": "arm64",
- "recorded_at": 1780149809.041745,
- "recorded_at_utc": "2026-05-30T14:03:29.041748+00:00",
- "command": "cargo bench -p capsem-core --bench security_packs",
- "host": {
- "platform": "Darwin",
- "release": "25.5.0",
- "version": "Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:12 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T6050",
- "machine": "arm64",
- "processor": "arm",
- "python_version": "3.14.4",
- "cpu_count": 18,
- "cpu_count_logical": 18,
- "cpu_model": "Apple M5 Max",
- "cpu_count_physical": 18,
- "memory_total_bytes": 137438953472,
- "os_product_version": "26.5",
- "memory_total_gb": 128.0
- },
- "git": {
- "commit": "0a425541fbdc03cc9821aafb238a0dd4b26ccdcd",
- "dirty": true,
- "source_dirty": false,
- "dirty_paths": [
- "benchmarks/security-engine/data_1.2.1780103109_arm64_cel_microbench.json"
- ]
- }
-}
diff --git a/bootstrap.sh b/bootstrap.sh
index 1cf9d55b4..3abadce84 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -19,6 +19,33 @@ for arg in "$@"; do
esac
done
+check_bootstrap_shape() {
+ cd "$SCRIPT_DIR"
+ for link in .agents/skills .claude/skills .codex/skills .cursor/skills .gemini/skills; do
+ [ "$(readlink "$link" 2>/dev/null || true)" = "../skills" ] || {
+ printf " [FAIL] %s must be a symlink to ../skills\n" "$link" >&2
+ exit 1
+ }
+ done
+ for file in \
+ skills/dev-sprint/SKILL.md \
+ skills/dev-testing/SKILL.md \
+ skills/dev-capsem/SKILL.md \
+ skills/ironbank/SKILL.md \
+ skills/frontend-design/SKILL.md \
+ site/package.json \
+ site/astro.config.mjs \
+ site/src/components/FAQ.svelte \
+ site/src/lib/data.ts; do
+ [ -f "$file" ] || { printf " [FAIL] missing %s\n" "$file" >&2; exit 1; }
+ done
+ SKILL_COUNT=$(find skills -mindepth 2 -name SKILL.md | wc -l | tr -d ' ')
+ [ "$SKILL_COUNT" -ge 25 ] || { printf " [FAIL] expected at least 25 project skills, found %s\n" "$SKILL_COUNT" >&2; exit 1; }
+ printf " [ok] project skills symlinks, key skills, and site surface\n"
+}
+
+check_bootstrap_shape
+
# Ask the developer "Install ? [Y/n]". Returns 0 on yes, 1 on no.
# Default is YES (just press enter). Auto-yes when -y is set; auto-yes when
# stdin isn't a tty either (CI/pipelines should bootstrap fully -- pass an
@@ -64,26 +91,6 @@ fi
# script -- both installers drop binaries there but don't reload PATH.
export PATH="$HOME/.cargo/bin:$HOME/.local/bin:$PATH"
-install_agent_skill_links() {
- echo ""
- echo "== Agent skills =="
- for dir in .claude .agents .gemini .codex .cursor; do
- mkdir -p "$SCRIPT_DIR/$dir"
- skill_link="$SCRIPT_DIR/$dir/skills"
- if [ -e "$skill_link" ] && [ ! -L "$skill_link" ]; then
- printf " [SKIP] %s/skills exists and is not a symlink\n" "$dir"
- continue
- fi
- if [ -L "$skill_link" ]; then
- rm "$skill_link"
- fi
- ln -s ../skills "$skill_link"
- printf " [ok] %s/skills -> ../skills\n" "$dir"
- done
-}
-
-install_agent_skill_links
-
if command -v rustup >/dev/null 2>&1; then
printf " [ok] rustup\n"
elif confirm "rustup (Rust toolchain manager, via sh.rustup.rs)"; then
@@ -113,34 +120,6 @@ done
echo ""
echo "== Installing dependencies =="
-if [ "$(uname -s)" = "Linux" ] && command -v apt-get >/dev/null 2>&1; then
- _apt_packages=""
- command -v cc >/dev/null 2>&1 || _apt_packages="$_apt_packages build-essential"
- command -v node >/dev/null 2>&1 || _apt_packages="$_apt_packages nodejs npm"
- command -v sqlite3 >/dev/null 2>&1 || _apt_packages="$_apt_packages sqlite3"
- command -v pkg-config >/dev/null 2>&1 || _apt_packages="$_apt_packages pkg-config"
- if ! command -v pkg-config >/dev/null 2>&1 ||
- ! pkg-config --exists openssl gtk+-3.0 webkit2gtk-4.1 ayatana-appindicator3-0.1 librsvg-2.0 2>/dev/null ||
- [ ! -f /usr/include/xdo.h ]; then
- _apt_packages="$_apt_packages libssl-dev libgtk-3-dev libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev libxdo-dev"
- fi
- if [ -n "$_apt_packages" ]; then
- if confirm "Linux development packages via apt ($_apt_packages)"; then
- sudo apt-get update
- # shellcheck disable=SC2086
- sudo apt-get install -y $_apt_packages
- fi
- fi
-fi
-
-if [ "$(uname -s)" = "Linux" ] && grep -Eq '(^flags|^Features)[[:space:]]*:.*\b(vmx|svm)\b' /proc/cpuinfo; then
- if [ ! -r /dev/kvm ] || [ ! -w /dev/kvm ] || [ ! -r /dev/vhost-vsock ] || [ ! -w /dev/vhost-vsock ]; then
- if confirm "Linux KVM/vhost-vsock device access (requires sudo)"; then
- "$SCRIPT_DIR/scripts/fix-linux-kvm-devices.sh"
- fi
- fi
-fi
-
if ! command -v uv >/dev/null 2>&1; then
if confirm "uv (Python package manager, via astral.sh -> ~/.local/bin)"; then
curl --proto '=https' --tlsv1.2 -LsSf https://astral.sh/uv/install.sh \
@@ -150,8 +129,6 @@ fi
if command -v uv >/dev/null 2>&1; then
printf " Python deps (uv sync)...\n"
uv sync
- printf " Python admin CLI (capsem-admin)...\n"
- uv run capsem-admin --version >/dev/null
else
printf " [SKIP] Python deps (uv not installed -- some just recipes will fail)\n"
fi
@@ -173,38 +150,9 @@ if ! command -v flock >/dev/null 2>&1; then
esac
fi
-# minisign is required for the local dev manifest signature. `just exec`
-# repacks assets/manifest.json and the service refuses unsigned manifests, so
-# bootstrap must install it before doctor or VM recipes can honestly pass.
-if ! command -v minisign >/dev/null 2>&1; then
- case "$(uname -s)" in
- Darwin)
- if command -v brew >/dev/null 2>&1; then
- if confirm "minisign (local asset manifest signing, via brew)"; then
- brew install minisign
- fi
- else
- printf " [SKIP] minisign (Homebrew not installed -- install brew, then: brew install minisign)\n"
- fi ;;
- Linux)
- if command -v apt-get >/dev/null 2>&1; then
- if confirm "minisign (local asset manifest signing, via apt)"; then
- sudo apt-get update
- sudo apt-get install -y minisign
- fi
- elif command -v dnf >/dev/null 2>&1; then
- if confirm "minisign (local asset manifest signing, via dnf)"; then
- sudo dnf install -y minisign
- fi
- else
- printf " [SKIP] minisign (install minisign via your OS package manager)\n"
- fi ;;
- esac
-fi
-
if command -v pnpm >/dev/null 2>&1; then
printf " Frontend deps (pnpm install)...\n"
- (cd frontend && pnpm install --frozen-lockfile)
+ (cd frontend && CI=true pnpm install --frozen-lockfile)
else
case "$(uname -s)" in
Darwin)
@@ -215,14 +163,14 @@ else
# Official installer; no npm or sudo required. Drops to ~/.local/share/pnpm.
if confirm "pnpm (Node package manager, via get.pnpm.io)"; then
curl --proto '=https' --tlsv1.2 -fsSL https://get.pnpm.io/install.sh \
- | env SHELL=/bin/bash PNPM_VERSION=10.33.4 PNPM_HOME="$HOME/.local/share/pnpm" sh -
+ | env SHELL=/bin/sh ENV="" PNPM_HOME="$HOME/.local/share/pnpm" sh -
export PNPM_HOME="$HOME/.local/share/pnpm"
- export PATH="$PNPM_HOME:$PNPM_HOME/bin:$PATH"
+ export PATH="$PNPM_HOME:$PATH"
fi ;;
esac
if command -v pnpm >/dev/null 2>&1; then
printf " Frontend deps (pnpm install)...\n"
- (cd frontend && pnpm install --frozen-lockfile)
+ (cd frontend && CI=true pnpm install --frozen-lockfile)
else
printf " [SKIP] Frontend deps (pnpm not installed -- doctor will catch this)\n"
fi
@@ -250,11 +198,16 @@ case "$(uname -s)" in
fi
# Start Colima if installed but not running. Doctor's fix can't
# do this -- it would just print the suggestion and fail.
- if command -v colima >/dev/null 2>&1 && ! colima status >/dev/null 2>&1; then
+ if command -v colima >/dev/null 2>&1 && ! colima status 2>&1 | grep -qi "running"; then
if confirm "start Colima now (vz, 16 GB, 8 CPU -- needed for build-assets + tauri install-test)"; then
colima start --vm-type vz --vz-rosetta --memory 16 --cpu 8
fi
fi
+ if command -v docker >/dev/null 2>&1; then
+ docker info >/dev/null
+ docker run --rm --pull=missing alpine:3.20 true >/dev/null
+ printf " [ok] docker VM probe (info + pull/run)\n"
+ fi
fi ;;
Linux)
if ! command -v docker >/dev/null 2>&1; then
diff --git a/codecov.yml b/codecov.yml
index a65857396..c6e1c2aa0 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -141,6 +141,13 @@ component_management:
- type: project
target: 80%
+ # Admin/profile tooling: manifest generation, profile materialization,
+ # image build orchestration, and release asset validation.
+ - component_id: admin
+ name: Admin
+ paths:
+ - crates/capsem-admin/src/**
+
# CLI client: start, stop, exec, shell, list, status, delete.
- component_id: cli
name: CLI
@@ -168,6 +175,12 @@ component_management:
- type: project
target: 80%
+ # Terminal UI: profile/session control over the service API.
+ - component_id: tui
+ name: TUI
+ paths:
+ - crates/capsem-tui/src/**
+
# System tray host: menu wiring, gateway client, icon rendering.
- component_id: systray
name: System Tray
@@ -198,6 +211,12 @@ component_management:
paths:
- src/capsem/**
+ # Local fixture server used for doctor, benchmark, recorder, and Ironbank proof.
+ - component_id: mock-server
+ name: Mock Server
+ paths:
+ - crates/capsem-mock-server/src/**
+
ignore:
- crates/*/tests/**
- crates/capsem-app/gen/**
diff --git a/config/README.md b/config/README.md
new file mode 100644
index 000000000..fe7624463
--- /dev/null
+++ b/config/README.md
@@ -0,0 +1,89 @@
+# Capsem Config Layout
+
+`config/` contains source contracts and templates. Generated runtime config
+belongs under `target/config/` and must be produced by `capsem-admin`.
+
+There are exactly five top-level config directories:
+
+- `settings/`
+- `corp/`
+- `profiles/`
+- `docker/`
+- `data/`
+
+Do not add `admin/`, `default/`, `defaults/`, `guest/`, `preset/`,
+`presets/`, `registry/`, `schemas/`, `templates/`, or provider-specific config
+roots. If a new product input is needed, it belongs under settings, corp, or a
+profile, then the existing admin validation and materialization rail must learn
+it.
+
+## Directories
+
+- `settings/` contains UI/application preference source and generated support
+ artifacts. `settings.toml` is the only settings source file.
+ `schema.generated.json` validates the settings shape. `ui-metadata.toml` and
+ `ui-metadata.generated.json` exist only for UI rendering metadata; they must
+ not control profile runtime behavior.
+- `corp/` contains corporate source contracts such as `corp.toml`,
+ `enforcement.toml`, and `detection.yaml`.
+- `profiles//` contains profile source ledgers and profile-owned
+ payloads: rules, Sigma detections, MCP declarations, package lists, build
+ hooks, tips, and guest root seed manifests.
+- `docker/` contains Docker/Jinja templates and image build defaults used by
+ the profile image builder. Profile-specific package lists, build hooks, and
+ root payloads still belong under `profiles//`.
+- `data/` contains project data embedded or loaded by code, such as model
+ pricing tables.
+
+## Source vs Runtime
+
+Checked-in `config/profiles//profile.toml` is source. It must not
+contain asset or sibling-file `hash` or `size` pins. `capsem-admin` validates
+source profiles, materializes hashes and sizes into `target/config/`, and uses
+that same materialized output for local builds, CI, packages, and installed
+runtime config.
+
+Do not hand-edit generated `target/config` output. Do not hand-edit profile
+hashes. If a source payload changes, fix the admin materialization rail and its
+tests.
+
+## Naming Contract
+
+- `schema` validates the shape of one contract.
+- `catalog` lists discovered or materialized instances.
+- `metadata` describes UI rendering hints.
+
+Do not introduce `admin`, `guest`, or `registry` as config authorities.
+`capsem-admin` is a tool; it does not own product configuration. Profiles and
+corp own runtime behavior. Settings may have generated UI metadata and JSON
+Schema, but those artifacts describe settings only; they do not define profile,
+corp, MCP, AI, package, or security truth. Settings have a schema; profiles may
+have a catalog. Settings do not have a registry.
+
+## Admin Tool Surface
+
+`capsem-admin` may validate, check, materialize, build, and generate artifacts
+from this config. It must not scaffold product config or create a second source
+of truth.
+
+Supported public rails:
+
+- `profile validate|check|materialize`
+- `settings validate`
+- `enforcement validate`
+- `detection validate`
+- `manifest check|generate`
+- `image build`
+
+If a new product input is needed, add it to the profile/corp/settings contract
+and make the existing validation/materialization rail understand it. Do not add
+`init`, `new`, `add`, provider-specific, or backend-workspace authoring
+commands.
+
+## Non-Config
+
+Developer skills live in the repository-level `skills/` directory. Product or
+user skills are not mirrored under `config/skills`; when implemented, they must
+be profile-owned payloads with an explicit profile contract.
+
+Test fixtures belong under `tests/fixtures/`, not in this source config tree.
diff --git a/config/corp/corp.toml b/config/corp/corp.toml
new file mode 100644
index 000000000..9b830b8f8
--- /dev/null
+++ b/config/corp/corp.toml
@@ -0,0 +1,21 @@
+# Capsem corporate constraints and reporting.
+#
+# Corp owns constraints, locks, and reporting integrations over profiles. It
+# does not own UI/application settings.
+
+refresh_policy = "24h"
+
+[corp_rule_files]
+enforcement = "corp/enforcement.toml"
+sigma = "corp/detection.yaml"
+sigma_output_endpoint = "https://siem.example.invalid/capsem/sigma"
+open_telemetry = "https://otel.example.invalid/v1/traces"
+remote_enforcement = "https://security.example.invalid/capsem/enforcement"
+
+[plugins.credential_broker]
+mode = "rewrite"
+detection_level = "informational"
+
+[plugins.log_sanitizer]
+mode = "rewrite"
+detection_level = "informational"
diff --git a/config/corp/detection.yaml b/config/corp/detection.yaml
new file mode 100644
index 000000000..47349dee2
--- /dev/null
+++ b/config/corp/detection.yaml
@@ -0,0 +1,12 @@
+title: corp_example_destination_seen
+level: informational
+logsource:
+ product: capsem
+ service: security_event
+detection:
+ selection:
+ http.host: example.com
+ condition: selection
+capsem:
+ action: allow
+ reason: Example corp Sigma detection proving destination logging.
diff --git a/config/corp/enforcement.toml b/config/corp/enforcement.toml
new file mode 100644
index 000000000..a1e152d10
--- /dev/null
+++ b/config/corp/enforcement.toml
@@ -0,0 +1,9 @@
+# Minimal corporate enforcement proof fixture.
+
+[corp.rules.block_evil_example]
+name = "block_evil_example"
+action = "block"
+priority = -100
+detection_level = "high"
+reason = "Example corp rule proving negative-priority enforcement from corp source."
+match = 'http.host.matches("(^|.*\\.)evil\\.example$")'
diff --git a/config/data/README.md b/config/data/README.md
new file mode 100644
index 000000000..233280729
--- /dev/null
+++ b/config/data/README.md
@@ -0,0 +1,25 @@
+# Config Data
+
+`genai-prices.json` is Capsem's compact bundled model pricing ledger used by
+runtime cost estimation.
+
+Source:
+
+- Repository: https://github.com/pydantic/genai-prices
+- File: `prices/data.json`
+- Raw URL:
+ https://raw.githubusercontent.com/pydantic/genai-prices/main/prices/data.json
+
+The committed file is not the raw upstream blob. `just update-prices` fetches
+the upstream file and transforms it through
+`scripts/update_genai_prices.py`. The runtime ledger keeps only Capsem's
+first-party provider pricing blocks (`anthropic`, `google`, `openai`) and the
+fields used by the runtime (`id`, `match`, `context_window`, `prices`). Model
+lookup uses the upstream `match` clauses exactly; Capsem does not fuzzy-price
+unknown model names.
+
+Refresh with:
+
+```sh
+just update-prices
+```
diff --git a/config/data/genai-prices.json b/config/data/genai-prices.json
new file mode 100644
index 000000000..be28e0825
--- /dev/null
+++ b/config/data/genai-prices.json
@@ -0,0 +1 @@
+[{"api_pattern":"https://api\\.anthropic\\.com","id":"anthropic","models":[{"context_window":200000,"id":"claude-2","match":{"or":[{"starts_with":"claude-2"},{"contains":"claude-v2"}]},"prices":{"input_mtok":8,"output_mtok":24}},{"context_window":200000,"id":"claude-3-5-haiku-latest","match":{"or":[{"starts_with":"claude-3-5-haiku"},{"starts_with":"claude-3.5-haiku"}]},"prices":{"cache_read_mtok":0.08,"cache_write_mtok":1,"input_mtok":0.8,"output_mtok":4}},{"context_window":200000,"id":"claude-3-5-sonnet","match":{"or":[{"starts_with":"claude-3-5-sonnet"},{"starts_with":"claude-3.5-sonnet"}]},"prices":{"cache_read_mtok":0.3,"cache_write_mtok":3.75,"input_mtok":3,"output_mtok":15}},{"context_window":200000,"id":"claude-3-7-sonnet-latest","match":{"or":[{"starts_with":"claude-3-7-sonnet"},{"starts_with":"claude-3.7-sonnet"},{"starts_with":"claude-sonnet-3.7"},{"starts_with":"claude-sonnet-3-7"}]},"prices":{"cache_read_mtok":0.3,"cache_write_mtok":3.75,"input_mtok":3,"output_mtok":15}},{"context_window":200000,"id":"claude-3-haiku","match":{"starts_with":"claude-3-haiku"},"prices":{"cache_read_mtok":0.03,"cache_write_mtok":0.3,"input_mtok":0.25,"output_mtok":1.25}},{"context_window":200000,"id":"claude-3-opus-latest","match":{"starts_with":"claude-3-opus"},"prices":{"cache_read_mtok":1.5,"cache_write_mtok":18.75,"input_mtok":15,"output_mtok":75}},{"context_window":200000,"id":"claude-3-sonnet","match":{"starts_with":"claude-3-sonnet"},"prices":{"cache_read_mtok":0.3,"cache_write_mtok":3.75,"input_mtok":3,"output_mtok":15}},{"context_window":1000000,"id":"claude-fable-5","match":{"starts_with":"claude-fable-5"},"prices":{"cache_read_mtok":1,"cache_write_mtok":12.5,"input_mtok":10,"output_mtok":50}},{"context_window":200000,"id":"claude-haiku-4-5","match":{"or":[{"starts_with":"claude-haiku-4-5"},{"starts_with":"claude-haiku-4.5"},{"starts_with":"claude-4-5-haiku"},{"starts_with":"claude-4.5-haiku"}]},"prices":{"cache_read_mtok":0.1,"cache_write_mtok":1.25,"input_mtok":1,"output_mtok":5}},{"context_window":200000,"id":"claude-opus-4-0","match":{"or":[{"starts_with":"claude-opus-4-0"},{"starts_with":"claude-4-opus"},{"equals":"claude-opus-4"},{"equals":"claude-opus-4-20250514"}]},"prices":{"cache_read_mtok":1.5,"cache_write_mtok":18.75,"input_mtok":15,"output_mtok":75}},{"context_window":200000,"id":"claude-opus-4-1","match":{"or":[{"starts_with":"claude-opus-4-1"},{"starts_with":"claude-opus-4.1"}]},"prices":{"cache_read_mtok":1.5,"cache_write_mtok":18.75,"input_mtok":15,"output_mtok":75}},{"context_window":200000,"id":"claude-opus-4-5","match":{"or":[{"starts_with":"claude-opus-4-5"},{"starts_with":"claude-opus-4.5"},{"starts_with":"claude-4-5-opus"},{"starts_with":"claude-4.5-opus"}]},"prices":{"cache_read_mtok":0.5,"cache_write_mtok":6.25,"input_mtok":5,"output_mtok":25}},{"context_window":200000,"id":"claude-opus-4-6","match":{"or":[{"starts_with":"claude-opus-4-6"},{"starts_with":"claude-opus-4.6"},{"starts_with":"claude-4-6-opus"},{"starts_with":"claude-4.6-opus"}]},"prices":[{"prices":{"cache_read_mtok":{"base":0.5,"tiers":[{"price":1,"start":200000}]},"cache_write_mtok":{"base":6.25,"tiers":[{"price":12.5,"start":200000}]},"input_mtok":{"base":5,"tiers":[{"price":10,"start":200000}]},"output_mtok":{"base":25,"tiers":[{"price":37.5,"start":200000}]}}},{"constraint":{"start_date":"2026-03-13"},"prices":{"cache_read_mtok":0.5,"cache_write_mtok":6.25,"input_mtok":5,"output_mtok":25}}]},{"context_window":1000000,"id":"claude-opus-4-7","match":{"or":[{"starts_with":"claude-opus-4-7"},{"starts_with":"claude-opus-4.7"},{"starts_with":"claude-4-7-opus"},{"starts_with":"claude-4.7-opus"}]},"prices":{"cache_read_mtok":0.5,"cache_write_mtok":6.25,"input_mtok":5,"output_mtok":25}},{"context_window":1000000,"id":"claude-opus-4-8","match":{"or":[{"starts_with":"claude-opus-4-8"},{"starts_with":"claude-opus-4.8"},{"starts_with":"claude-4-8-opus"},{"starts_with":"claude-4.8-opus"}]},"prices":{"cache_read_mtok":0.5,"cache_write_mtok":6.25,"input_mtok":5,"output_mtok":25}},{"context_window":200000,"id":"claude-sonnet-4-0","match":{"or":[{"starts_with":"claude-sonnet-4-2025"},{"starts_with":"claude-sonnet-4-0"},{"starts_with":"claude-sonnet-4@"},{"equals":"claude-sonnet-4"},{"starts_with":"claude-4-sonnet"}]},"prices":{"cache_read_mtok":0.3,"cache_write_mtok":3.75,"input_mtok":3,"output_mtok":15}},{"context_window":1000000,"id":"claude-sonnet-4-5","match":{"or":[{"starts_with":"claude-sonnet-4-5"},{"starts_with":"claude-sonnet-4.5"}]},"prices":{"cache_read_mtok":{"base":0.3,"tiers":[{"price":0.6,"start":200000}]},"cache_write_mtok":{"base":3.75,"tiers":[{"price":7.5,"start":200000}]},"input_mtok":{"base":3,"tiers":[{"price":6,"start":200000}]},"output_mtok":{"base":15,"tiers":[{"price":22.5,"start":200000}]}}},{"context_window":1000000,"id":"claude-sonnet-4-6","match":{"or":[{"starts_with":"claude-sonnet-4-6"},{"starts_with":"claude-sonnet-4.6"}]},"prices":[{"prices":{"cache_read_mtok":{"base":0.3,"tiers":[{"price":0.6,"start":200000}]},"cache_write_mtok":{"base":3.75,"tiers":[{"price":7.5,"start":200000}]},"input_mtok":{"base":3,"tiers":[{"price":6,"start":200000}]},"output_mtok":{"base":15,"tiers":[{"price":22.5,"start":200000}]}}},{"constraint":{"start_date":"2026-03-13"},"prices":{"cache_read_mtok":0.3,"cache_write_mtok":3.75,"input_mtok":3,"output_mtok":15}}]},{"id":"claude-v1","match":{"equals":"claude-v1"},"prices":{"input_mtok":8,"output_mtok":24}}],"name":"Anthropic","pricing_urls":["https://www.anthropic.com/pricing#api"]},{"api_pattern":"https://(.*\\.)?googleapis\\.com","id":"google","models":[{"context_window":32768,"id":"gemini-1.0-pro-vision-001","match":{"equals":"gemini-1.0-pro-vision-001"},"prices":{"input_mtok":0.125,"output_mtok":0.375}},{"context_window":1000000,"id":"gemini-1.5-flash","match":{"contains":"gemini-1.5-flash"},"prices":{"cache_read_mtok":{"base":0.01875,"tiers":[{"price":0.0375,"start":128000}]},"input_mtok":{"base":0.075,"tiers":[{"price":0.15,"start":128000}]},"output_mtok":{"base":0.3,"tiers":[{"price":0.6,"start":128000}]}}},{"context_window":1000000,"id":"gemini-1.5-pro","match":{"contains":"gemini-1.5-pro"},"prices":{"input_mtok":{"base":1.25,"tiers":[{"price":2.5,"start":128000}]},"output_mtok":{"base":5,"tiers":[{"price":10,"start":128000}]}}},{"context_window":1000000,"id":"gemini-2.0-flash","match":{"or":[{"ends_with":"gemini-2.0-flash"},{"contains":"gemini-2.0-flash-0"},{"contains":"gemini-2.0-flash-exp"},{"contains":"gemini-2.0-flash-thinking"},{"contains":"gemini-2.0-flash-latest"}]},"prices":{"cache_audio_read_mtok":0.175,"cache_read_mtok":0.025,"input_audio_mtok":0.7,"input_mtok":0.1,"output_mtok":0.4}},{"context_window":1000000,"id":"gemini-2.0-flash-lite","match":{"contains":"gemini-2.0-flash-lite"},"prices":{"input_mtok":0.075,"output_mtok":0.3}},{"id":"gemini-2.5-flash","match":{"or":[{"equals":"gemini-2.5-flash"},{"equals":"gemini-2.5-flash-latest"},{"equals":"gemini-2.5-flash-preview-09-2025"}]},"prices":{"cache_audio_read_mtok":0.1,"cache_read_mtok":0.03,"input_audio_mtok":1,"input_mtok":0.3,"output_mtok":2.5}},{"context_window":1000000,"id":"gemini-2.5-flash-image","match":{"or":[{"equals":"gemini-2.5-flash-image"},{"equals":"gemini-2.5-flash-image-preview"}]},"prices":{"input_mtok":0.3,"output_mtok":30}},{"context_window":1000000,"id":"gemini-2.5-flash-lite","match":{"or":[{"equals":"gemini-2.5-flash-lite"},{"starts_with":"gemini-2.5-flash-lite-preview"}]},"prices":{"cache_audio_read_mtok":0.03,"cache_read_mtok":0.01,"input_audio_mtok":0.3,"input_mtok":0.1,"output_mtok":0.4}},{"id":"gemini-2.5-flash-preview","match":{"or":[{"contains":"gemini-2.5-flash-preview-05-20"},{"contains":"gemini-2.5-flash-preview-04-17"},{"equals":"gemini-2.5-flash-preview-05-20:thinking"},{"equals":"gemini-2.5-flash-preview"},{"equals":"gemini-2.5-flash-preview:thinking"}]},"prices":{"input_mtok":0.15,"output_mtok":0.6}},{"id":"gemini-2.5-pro","match":{"starts_with":"gemini-2.5-pro"},"prices":{"cache_read_mtok":{"base":0.125,"tiers":[{"price":0.25,"start":200000}]},"input_mtok":{"base":1.25,"tiers":[{"price":2.5,"start":200000}]},"output_mtok":{"base":10,"tiers":[{"price":15,"start":200000}]}}},{"context_window":1000000,"id":"gemini-3-flash-preview","match":{"or":[{"equals":"gemini-3-flash-preview"},{"starts_with":"gemini-3-flash-preview-"}]},"prices":{"cache_audio_read_mtok":0.1,"cache_read_mtok":0.05,"input_audio_mtok":1,"input_mtok":0.5,"output_mtok":3}},{"context_window":1000000,"id":"gemini-3-pro-image-preview","match":{"or":[{"starts_with":"gemini-3-pro-image-preview"},{"equals":"gemini-3-pro-image-preview"}]},"prices":{"input_mtok":2,"output_mtok":120}},{"id":"gemini-3-pro-preview","match":{"or":[{"starts_with":"gemini-3-pro-preview"},{"equals":"gemini-3-pro-text-preview"}]},"prices":{"cache_read_mtok":{"base":0.2,"tiers":[{"price":0.4,"start":200000}]},"input_mtok":{"base":2,"tiers":[{"price":4,"start":200000}]},"output_mtok":{"base":12,"tiers":[{"price":18,"start":200000}]}}},{"context_window":1000000,"id":"gemini-3.1-flash-image-preview","match":{"starts_with":"gemini-3.1-flash-image-preview"},"prices":{"input_mtok":0.5,"output_mtok":60}},{"context_window":1000000,"id":"gemini-3.1-flash-lite","match":{"starts_with":"gemini-3.1-flash-lite"},"prices":{"cache_audio_read_mtok":0.05,"cache_read_mtok":0.025,"input_audio_mtok":0.5,"input_mtok":0.25,"output_mtok":1.5}},{"id":"gemini-3.1-pro-preview","match":{"starts_with":"gemini-3.1-pro-preview"},"prices":{"cache_read_mtok":{"base":0.2,"tiers":[{"price":0.4,"start":200000}]},"input_mtok":{"base":2,"tiers":[{"price":4,"start":200000}]},"output_mtok":{"base":12,"tiers":[{"price":18,"start":200000}]}}},{"context_window":1000000,"id":"gemini-3.5-flash","match":{"starts_with":"gemini-3.5-flash"},"prices":{"cache_read_mtok":0.15,"input_mtok":1.5,"output_mtok":9}},{"id":"gemini-embedding-001","match":{"equals":"gemini-embedding-001"},"prices":{"input_mtok":0.15}},{"id":"gemini-flash-1.5","match":{"equals":"gemini-flash-1.5"},"prices":{"cache_read_mtok":{"base":0.01875,"tiers":[{"price":0.0375,"start":128000}]},"input_mtok":{"base":0.075,"tiers":[{"price":0.15,"start":128000}]},"output_mtok":{"base":0.3,"tiers":[{"price":0.6,"start":128000}]}}},{"context_window":1000000,"id":"gemini-flash-1.5-8b","match":{"equals":"gemini-flash-1.5-8b"},"prices":{"cache_read_mtok":{"base":0.01,"tiers":[{"price":0.02,"start":128000}]},"input_mtok":{"base":0.0375,"tiers":[{"price":0.075,"start":128000}]},"output_mtok":{"base":0.15,"tiers":[{"price":0.3,"start":128000}]}}},{"id":"gemini-live-2.5-flash-preview","match":{"or":[{"starts_with":"gemini-live-2.5-flash-preview"},{"starts_with":"gemini-2.5-flash-native-audio-preview"}]},"prices":{"input_audio_mtok":3,"input_mtok":0.5,"output_audio_mtok":12,"output_mtok":2}},{"context_window":32768,"id":"gemini-pro","match":{"or":[{"equals":"gemini-pro"},{"equals":"gemini-1.0-pro"}]},"prices":{"input_mtok":0.125,"output_mtok":0.375}},{"context_window":2000000,"id":"gemini-pro-1.5","match":{"equals":"gemini-pro-1.5"},"prices":{"cache_read_mtok":{"base":0.3125,"tiers":[{"price":0.625,"start":128000}]},"input_mtok":{"base":1.25,"tiers":[{"price":2.5,"start":128000}]},"output_mtok":{"base":5,"tiers":[{"price":10,"start":128000}]}}},{"id":"gemma-3","match":{"or":[{"starts_with":"gemma-3-"},{"equals":"gemma-3"}]},"prices":{}},{"id":"gemma-3n","match":{"or":[{"starts_with":"gemma-3n"}]},"prices":{}}],"name":"Google","pricing_urls":["https://ai.google.dev/gemini-api/docs/pricing","https://cloud.google.com/vertex-ai/generative-ai/pricing"]},{"api_pattern":"https://api\\.openai\\.com","id":"openai","models":[{"id":"chatgpt-4o-latest","match":{"equals":"chatgpt-4o-latest"},"prices":{"input_mtok":5,"output_mtok":15}},{"id":"codex-mini","match":{"or":[{"equals":"codex-mini"},{"equals":"codex-mini-latest"}]},"prices":{"cache_read_mtok":0.375,"input_mtok":1.5,"output_mtok":6}},{"id":"computer-use","match":{"starts_with":"computer-use"},"prices":{"input_mtok":3,"output_mtok":12}},{"id":"ft:gpt-3.5-turbo-","match":{"starts_with":"ft:gpt-3.5-turbo"},"prices":{"input_mtok":3,"output_mtok":6}},{"id":"ft:gpt-4o","match":{"starts_with":"ft:gpt-4o-2024-"},"prices":{"input_mtok":3.75,"output_mtok":15}},{"id":"ft:gpt-4o-mini","match":{"starts_with":"ft:gpt-4o-mini-2024-"},"prices":{"input_mtok":0.3,"output_mtok":1.2}},{"id":"gpt-3.5-0301","match":{"or":[{"equals":"gpt-3.5-turbo-0301"},{"equals":"gpt-3.5-0301"}]},"prices":{"input_mtok":1.5,"output_mtok":2}},{"context_window":16385,"id":"gpt-3.5-turbo","match":{"or":[{"equals":"gpt-3.5-turbo"},{"equals":"gpt-35-turbo"},{"equals":"gpt-3.5-turbo-0125"}]},"prices":{"input_mtok":0.5,"output_mtok":1.5}},{"context_window":16385,"id":"gpt-3.5-turbo-0613","match":{"equals":"gpt-3.5-turbo-0613"},"prices":{"input_mtok":1.5,"output_mtok":2}},{"context_window":16385,"id":"gpt-3.5-turbo-1106","match":{"equals":"gpt-3.5-turbo-1106"},"prices":{"input_mtok":1,"output_mtok":2}},{"context_window":16385,"id":"gpt-3.5-turbo-16k","match":{"or":[{"equals":"gpt-3.5-turbo-16k"},{"equals":"gpt-3.5-turbo-16k-0613"},{"equals":"gpt-35-turbo-16k-0613"},{"equals":"gpt-35-turbo-16k"}]},"prices":{"input_mtok":3,"output_mtok":4}},{"context_window":16385,"id":"gpt-3.5-turbo-instruct","match":{"or":[{"starts_with":"gpt-3.5-turbo-instruct"},{"equals":"gpt-3.5-turbo-instruct-0914"}]},"prices":{"input_mtok":1.5,"output_mtok":2}},{"context_window":8192,"id":"gpt-4","match":{"or":[{"equals":"gpt-4"},{"equals":"gpt-4-0314"},{"equals":"gpt-4-0613"},{"starts_with":"ft:gpt-4-0"}]},"prices":{"input_mtok":30,"output_mtok":60}},{"context_window":32000,"id":"gpt-4-32k","match":{"or":[{"equals":"gpt-4-32k"},{"equals":"gpt-4-32k-0314"},{"equals":"gpt-4-32k-0613"}]},"prices":{"input_mtok":60,"output_mtok":120}},{"context_window":128000,"id":"gpt-4-turbo","match":{"or":[{"equals":"gpt-4-turbo"},{"equals":"gpt-4-turbo-2024-04-09"},{"equals":"gpt-4-turbo-0125-preview"},{"equals":"gpt-4-0125-preview"},{"equals":"gpt-4-1106-preview"},{"equals":"gpt-4-turbo-preview"}]},"prices":{"input_mtok":10,"output_mtok":30}},{"context_window":128000,"id":"gpt-4-vision-preview","match":{"or":[{"equals":"gpt-4-vision-preview"},{"equals":"gpt-4-1106-vision-preview"}]},"prices":{"input_mtok":10,"output_mtok":30}},{"context_window":1000000,"id":"gpt-4.1","match":{"or":[{"equals":"gpt-4.1"},{"equals":"gpt-4.1-2025-04-14"}]},"prices":{"cache_read_mtok":0.5,"input_mtok":2,"output_mtok":8}},{"context_window":1000000,"id":"gpt-4.1-mini","match":{"or":[{"equals":"gpt-4.1-mini"},{"equals":"gpt-4.1-mini-2025-04-14"}]},"prices":{"cache_read_mtok":0.1,"input_mtok":0.4,"output_mtok":1.6}},{"context_window":1000000,"id":"gpt-4.1-nano","match":{"or":[{"equals":"gpt-4.1-nano"},{"equals":"gpt-4.1-nano-2025-04-14"}]},"prices":{"cache_read_mtok":0.025,"input_mtok":0.1,"output_mtok":0.4}},{"id":"gpt-4.5-preview","match":{"starts_with":"gpt-4.5-preview"},"prices":{"cache_read_mtok":37.5,"input_mtok":75,"output_mtok":150}},{"context_window":128000,"id":"gpt-4o","match":{"or":[{"equals":"gpt-4o"},{"equals":"gpt-4o-2024-05-13"},{"equals":"gpt-4o-2024-08-06"},{"equals":"gpt-4o-2024-11-20"}]},"prices":{"cache_read_mtok":1.25,"input_mtok":2.5,"output_mtok":10}},{"context_window":128000,"id":"gpt-4o-audio-preview","match":{"starts_with":"gpt-4o-audio-preview"},"prices":{"input_audio_mtok":2.5,"input_mtok":2.5,"output_mtok":10}},{"context_window":128000,"id":"gpt-4o-mini","match":{"or":[{"equals":"gpt-4o-mini"},{"equals":"gpt-4o-mini-2024-07-18"},{"equals":"gpt-4o-mini-search-preview"},{"equals":"gpt-4o-mini-search-preview-2025-03-11"}]},"prices":{"cache_read_mtok":0.075,"input_mtok":0.15,"output_mtok":0.6}},{"id":"gpt-4o-mini-2024-07-18.ft-","match":{"starts_with":"gpt-4o-mini-2024-07-18.ft-"},"prices":{"input_mtok":0.3,"output_mtok":1.2}},{"id":"gpt-4o-mini-audio-preview","match":{"starts_with":"gpt-4o-mini-audio"},"prices":{"input_audio_mtok":0.15,"input_mtok":0.15,"output_mtok":0.6}},{"id":"gpt-4o-mini-realtime-preview","match":{"starts_with":"gpt-4o-mini-realtime"},"prices":{"cache_audio_read_mtok":0.3,"cache_read_mtok":0.3,"input_audio_mtok":10,"input_mtok":0.6,"output_audio_mtok":20,"output_mtok":2.4}},{"id":"gpt-4o-mini-transcribe","match":{"equals":"gpt-4o-mini-transcribe"},"prices":{"input_audio_mtok":3,"input_mtok":1.25,"output_mtok":5}},{"id":"gpt-4o-mini-tts","match":{"equals":"gpt-4o-mini-tts"},"prices":{"input_mtok":0.6,"output_audio_mtok":12,"output_mtok":12}},{"id":"gpt-4o-realtime-preview","match":{"starts_with":"gpt-4o-realtime"},"prices":{"cache_audio_read_mtok":2.5,"cache_read_mtok":2.5,"input_audio_mtok":40,"input_mtok":5,"output_audio_mtok":80,"output_mtok":20}},{"id":"gpt-4o-search-preview","match":{"or":[{"equals":"gpt-4o-search-preview"},{"equals":"gpt-4o-search-preview-2025-03-11"}]},"prices":{"input_mtok":2.5,"output_mtok":10}},{"id":"gpt-4o-transcribe","match":{"or":[{"equals":"gpt-4o-transcribe"},{"equals":"gpt-4o-transcribe-diarize"}]},"prices":{"input_audio_mtok":6,"input_mtok":2.5,"output_mtok":10}},{"id":"gpt-4o:extended","match":{"equals":"gpt-4o:extended"},"prices":{"input_mtok":6,"output_mtok":18}},{"context_window":400000,"id":"gpt-5","match":{"or":[{"equals":"gpt-5"},{"equals":"gpt-5-2025-08-07"},{"equals":"gpt-5-chat"},{"equals":"gpt-5-chat-latest"},{"equals":"gpt-5-codex"}]},"prices":{"cache_read_mtok":0.125,"input_mtok":1.25,"output_mtok":10}},{"id":"gpt-5-image","match":{"equals":"gpt-5-image"},"prices":{"cache_read_mtok":1.25,"input_mtok":10,"output_mtok":10}},{"id":"gpt-5-image-mini","match":{"equals":"gpt-5-image-mini"},"prices":{"cache_read_mtok":0.25,"input_mtok":2.5,"output_mtok":2}},{"context_window":400000,"id":"gpt-5-mini","match":{"or":[{"equals":"gpt-5-mini"},{"equals":"gpt-5-mini-2025-08-07"}]},"prices":{"cache_read_mtok":0.025,"input_mtok":0.25,"output_mtok":2}},{"context_window":400000,"id":"gpt-5-nano","match":{"or":[{"equals":"gpt-5-nano"},{"starts_with":"gpt-5-nano-"}]},"prices":{"cache_read_mtok":0.005,"input_mtok":0.05,"output_mtok":0.4}},{"context_window":400000,"id":"gpt-5-pro","match":{"or":[{"equals":"gpt-5-pro"},{"equals":"gpt-5-pro-2025-10-06"}]},"prices":{"input_mtok":15,"output_mtok":120}},{"context_window":400000,"id":"gpt-5.1","match":{"or":[{"equals":"gpt-5.1"},{"equals":"gpt-5.1-2025-11-13"},{"equals":"gpt-5.1-codex"},{"equals":"gpt-5.1-codex-max"},{"equals":"gpt-5.1-chat"},{"equals":"gpt-5.1-chat-latest"},{"equals":"gpt-5-1"},{"equals":"gpt-5-1-2025-11-13"},{"equals":"gpt-5-1-codex"},{"equals":"gpt-5-1-codex-max"},{"equals":"gpt-5-1-chat"},{"equals":"gpt-5-1-chat-latest"}]},"prices":{"cache_read_mtok":0.125,"input_mtok":1.25,"output_mtok":10}},{"context_window":400000,"id":"gpt-5.1-codex-mini","match":{"or":[{"equals":"gpt-5.1-codex-mini"},{"equals":"gpt-5.1-mini"},{"equals":"gpt-5-1-codex-mini"},{"equals":"gpt-5-1-mini"}]},"prices":{"cache_read_mtok":0.025,"input_mtok":0.25,"output_mtok":2}},{"context_window":400000,"id":"gpt-5.2","match":{"or":[{"equals":"gpt-5.2"},{"equals":"gpt-5.2-2025-12-11"},{"equals":"gpt-5-2"},{"equals":"gpt-5-2-2025-12-11"},{"equals":"gpt-5.2-chat"},{"equals":"gpt-5.2-chat-latest"},{"equals":"gpt-5-2-chat"},{"equals":"gpt-5-2-chat-latest"},{"equals":"gpt-5.2-codex"},{"equals":"gpt-5-2-codex"}]},"prices":{"cache_read_mtok":0.175,"input_mtok":1.75,"output_mtok":14}},{"context_window":400000,"id":"gpt-5.2-pro","match":{"or":[{"equals":"gpt-5.2-pro"},{"equals":"gpt-5.2-pro-2025-12-11"},{"equals":"gpt-5-2-pro-2025-12-11"}]},"prices":{"input_mtok":21,"output_mtok":168}},{"context_window":128000,"id":"gpt-5.3","match":{"or":[{"equals":"gpt-5.3"},{"equals":"gpt-5-3"},{"equals":"gpt-5.3-chat"},{"equals":"gpt-5.3-chat-latest"},{"equals":"gpt-5-3-chat"},{"equals":"gpt-5-3-chat-latest"}]},"prices":{"cache_read_mtok":0.175,"input_mtok":1.75,"output_mtok":14}},{"context_window":400000,"id":"gpt-5.3-codex","match":{"or":[{"equals":"gpt-5.3-codex"},{"equals":"gpt-5-3-codex"}]},"prices":{"cache_read_mtok":0.175,"input_mtok":1.75,"output_mtok":14}},{"context_window":1050000,"id":"gpt-5.4","match":{"or":[{"equals":"gpt-5.4"},{"equals":"gpt-5.4-2026-03-05"},{"equals":"gpt-5-4"},{"equals":"gpt-5-4-2026-03-05"}]},"prices":{"cache_read_mtok":{"base":0.25,"tiers":[{"price":0.5,"start":272000}]},"input_mtok":{"base":2.5,"tiers":[{"price":5,"start":272000}]},"output_mtok":{"base":15,"tiers":[{"price":22.5,"start":272000}]}}},{"context_window":400000,"id":"gpt-5.4-mini","match":{"or":[{"equals":"gpt-5.4-mini"},{"equals":"gpt-5.4-mini-2026-03-17"},{"equals":"gpt-5-4-mini"},{"equals":"gpt-5-4-mini-2026-03-17"}]},"prices":{"cache_read_mtok":0.075,"input_mtok":0.75,"output_mtok":4.5}},{"context_window":400000,"id":"gpt-5.4-nano","match":{"or":[{"equals":"gpt-5.4-nano"},{"equals":"gpt-5.4-nano-2026-03-17"},{"equals":"gpt-5-4-nano"},{"equals":"gpt-5-4-nano-2026-03-17"}]},"prices":{"cache_read_mtok":0.02,"input_mtok":0.2,"output_mtok":1.25}},{"context_window":1050000,"id":"gpt-5.4-pro","match":{"or":[{"equals":"gpt-5.4-pro"},{"equals":"gpt-5.4-pro-2026-03-05"},{"equals":"gpt-5-4-pro"},{"equals":"gpt-5-4-pro-2026-03-05"}]},"prices":{"input_mtok":{"base":30,"tiers":[{"price":60,"start":272000}]},"output_mtok":{"base":180,"tiers":[{"price":270,"start":272000}]}}},{"context_window":1000000,"id":"gpt-5.5","match":{"or":[{"equals":"gpt-5.5"},{"equals":"gpt-5.5-2026-04-23"},{"equals":"gpt-5.5-2026-04-24"},{"equals":"gpt-5-5"},{"equals":"gpt-5-5-2026-04-23"},{"equals":"gpt-5-5-2026-04-24"},{"equals":"gpt-5.5-chat"},{"equals":"gpt-5.5-chat-latest"},{"equals":"gpt-5-5-chat"},{"equals":"gpt-5-5-chat-latest"},{"equals":"gpt-5.5-codex"},{"equals":"gpt-5-5-codex"}]},"prices":{"cache_read_mtok":0.5,"input_mtok":5,"output_mtok":30}},{"context_window":1000000,"id":"gpt-5.5-pro","match":{"or":[{"equals":"gpt-5.5-pro"},{"equals":"gpt-5.5-pro-2026-04-23"},{"equals":"gpt-5-5-pro"},{"equals":"gpt-5-5-pro-2026-04-23"}]},"prices":{"input_mtok":30,"output_mtok":180}},{"id":"gpt-realtime","match":{"or":[{"equals":"gpt-realtime"},{"equals":"gpt-realtime-2025-08-28"}]},"prices":{"cache_audio_read_mtok":0.4,"cache_read_mtok":0.4,"input_audio_mtok":32,"input_mtok":4,"output_audio_mtok":64,"output_mtok":16}},{"id":"gpt-realtime-mini","match":{"equals":"gpt-realtime-mini"},"prices":{"cache_audio_read_mtok":0.3,"cache_read_mtok":0.06,"input_audio_mtok":10,"input_mtok":0.6,"output_audio_mtok":20,"output_mtok":2.4}},{"context_window":128000,"id":"o1","match":{"or":[{"equals":"o1"},{"equals":"o1-2024-12-17"},{"equals":"o1-preview"},{"equals":"o1-preview-2024-09-12"}]},"prices":{"cache_read_mtok":7.5,"input_mtok":15,"output_mtok":60}},{"context_window":128000,"id":"o1-mini","match":{"or":[{"equals":"o1-mini"},{"equals":"o1-mini-2024-09-12"}]},"prices":{"cache_read_mtok":0.55,"input_mtok":1.1,"output_mtok":4.4}},{"id":"o1-pro","match":{"or":[{"equals":"o1-pro"},{"equals":"o1-pro-2025-03-19"}]},"prices":{"input_mtok":150,"output_mtok":600}},{"id":"o3","match":{"or":[{"equals":"o3"},{"equals":"o3-2025-04-16"}]},"prices":[{"prices":{"cache_read_mtok":0.5,"input_mtok":10,"output_mtok":40}},{"constraint":{"start_date":"2025-06-10"},"prices":{"cache_read_mtok":0.5,"input_mtok":2,"output_mtok":8}}]},{"id":"o3-deep-research","match":{"or":[{"equals":"o3-deep-research"},{"equals":"o3-deep-research-2025-06-26"}]},"prices":{"cache_read_mtok":2.5,"input_mtok":10,"output_mtok":40}},{"id":"o3-mini","match":{"or":[{"equals":"o3-mini"},{"equals":"o3-mini-2025-01-31"},{"equals":"o3-mini-high"}]},"prices":{"cache_read_mtok":0.55,"input_mtok":1.1,"output_mtok":4.4}},{"id":"o3-pro","match":{"or":[{"equals":"o3-pro"},{"equals":"o3-pro-2025-06-10"}]},"prices":{"input_mtok":20,"output_mtok":80}},{"id":"o4-mini","match":{"or":[{"equals":"o4-mini-2025-04-16"},{"equals":"o4-mini-high"},{"equals":"o4-mini"}]},"prices":{"cache_read_mtok":0.275,"input_mtok":1.1,"output_mtok":4.4}},{"id":"o4-mini-deep-research","match":{"or":[{"equals":"o4-mini-deep-research"},{"equals":"o4-mini-deep-research-2025-06-26"}]},"prices":{"cache_read_mtok":0.5,"input_mtok":2,"output_mtok":8}},{"id":"text-davinci-002","match":{"equals":"text-davinci-002"},"prices":{"input_mtok":20,"output_mtok":20}},{"id":"text-davinci-003","match":{"equals":"text-davinci-003"},"prices":{"input_mtok":20,"output_mtok":20}},{"context_window":8192,"id":"text-embedding-3-large","match":{"equals":"text-embedding-3-large"},"prices":{"input_mtok":0.13}},{"context_window":8192,"id":"text-embedding-3-small","match":{"equals":"text-embedding-3-small"},"prices":{"input_mtok":0.02}},{"context_window":8192,"id":"text-embedding-ada-002","match":{"or":[{"equals":"text-embedding-ada"},{"equals":"text-embedding-ada-002"},{"equals":"text-embedding-ada-002-v2"}]},"prices":{"input_mtok":0.1}}],"name":"OpenAI","pricing_urls":["https://platform.openai.com/docs/pricing","https://openai.com/api/pricing/","https://platform.openai.com/docs/models","https://help.openai.com/en/articles/7127956-how-much-does-gpt-4-cost"]}]
diff --git a/config/defaults.json b/config/defaults.json
deleted file mode 100644
index 21769cd6e..000000000
--- a/config/defaults.json
+++ /dev/null
@@ -1,933 +0,0 @@
-{
- "settings": {
- "app": {
- "name": "App",
- "description": "Application settings",
- "collapsed": false
- },
- "ai": {
- "name": "AI Providers",
- "description": "AI model provider configuration",
- "collapsed": false,
- "anthropic": {
- "name": "Anthropic",
- "description": "Claude Code AI agent",
- "enabled_by": "ai.anthropic.allow",
- "collapsed": false,
- "allow": {
- "name": "Allow Anthropic",
- "description": "Enable API access to Anthropic (*.anthropic.com).",
- "type": "bool",
- "default": true,
- "meta": {
- "rules": {
- "default": {
- "get": true,
- "post": true
- }
- }
- }
- },
- "api_key": {
- "name": "Anthropic API Key",
- "description": "API key for Anthropic. Injected as ANTHROPIC_API_KEY env var.",
- "type": "apikey",
- "default": "",
- "meta": {
- "env_vars": [
- "ANTHROPIC_API_KEY"
- ],
- "docs_url": "https://console.anthropic.com/settings/keys",
- "prefix": "sk-ant-"
- }
- },
- "domains": {
- "name": "Anthropic Domains",
- "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
- "type": "text",
- "default": "*.anthropic.com, *.claude.com"
- },
- "claude": {
- "name": "Claude Code",
- "description": "Claude Code configuration files",
- "settings_json": {
- "name": "Claude Code settings.json",
- "description": "Content for /root/.claude/settings.json. Bypass permissions, disable telemetry/updates for sandboxed execution.",
- "type": "file",
- "default": {
- "path": "/root/.claude/settings.json",
- "content": "{\"permissions\":{\"defaultMode\":\"bypassPermissions\"},\"env\":{\"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC\":\"1\"}}"
- },
- "meta": {
- "filetype": "json"
- }
- },
- "state_json": {
- "name": "Claude Code state (.claude.json)",
- "description": "Content for /root/.claude.json. Skips onboarding, trust dialogs, and keybinding prompts.",
- "type": "file",
- "default": {
- "path": "/root/.claude.json",
- "content": "{\"hasCompletedOnboarding\":true,\"hasTrustDialogAccepted\":true,\"hasTrustDialogHooksAccepted\":true,\"shiftEnterKeyBindingInstalled\":true,\"theme\":\"dark\",\"numStartups\":1,\"opusProMigrationComplete\":true,\"sonnet1m45MigrationComplete\":true,\"projects\":{\"/root\":{\"allowedTools\":[],\"hasTrustDialogAccepted\":true,\"projectOnboardingSeenCount\":1}}}"
- },
- "meta": {
- "filetype": "json"
- }
- },
- "credentials_json": {
- "name": "Claude Code OAuth credentials",
- "description": "Content for /root/.claude/.credentials.json. OAuth tokens for subscription-based auth (Pro/Max). Injected from host when detected.",
- "type": "file",
- "default": {
- "path": "/root/.claude/.credentials.json",
- "content": ""
- },
- "meta": {
- "filetype": "json"
- }
- }
- }
- },
- "google": {
- "name": "Google AI",
- "description": "Google Gemini AI provider",
- "enabled_by": "ai.google.allow",
- "collapsed": false,
- "allow": {
- "name": "Allow Google AI",
- "description": "Enable API access to Google AI (*.googleapis.com).",
- "type": "bool",
- "default": true,
- "meta": {
- "rules": {
- "default": {
- "get": true,
- "post": true
- }
- }
- }
- },
- "api_key": {
- "name": "Google AI API Key",
- "description": "API key for Google AI. Injected as GEMINI_API_KEY env var.",
- "type": "apikey",
- "default": "",
- "meta": {
- "env_vars": [
- "GEMINI_API_KEY"
- ],
- "docs_url": "https://aistudio.google.com/apikey",
- "prefix": "AIza"
- }
- },
- "domains": {
- "name": "Google AI Domains",
- "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
- "type": "text",
- "default": "*.googleapis.com"
- },
- "gemini": {
- "name": "Gemini CLI",
- "description": "Gemini CLI configuration files",
- "settings_json": {
- "name": "Gemini CLI settings.json",
- "description": "Content for /root/.gemini/settings.json. Bypass permissions, disable telemetry/updates for sandboxed execution.",
- "type": "file",
- "default": {
- "path": "/root/.gemini/settings.json",
- "content": "{\"homeDirectoryWarningDismissed\":true,\"general\":{\"disableAutoUpdate\":true,\"disableUpdateNag\":true},\"ui\":{\"hideTips\":true,\"hideBanner\":false},\"privacy\":{\"usageStatisticsEnabled\":false,\"sessionRetention\":\"none\"},\"telemetry\":{\"enabled\":false},\"security\":{\"auth\":{\"selectedType\":\"gemini-api-key\"},\"folderTrust.enabled\":false},\"ide\":{\"hasSeenNudge\":true},\"tools\":{\"sandbox\":false}}"
- },
- "meta": {
- "filetype": "json"
- }
- },
- "projects_json": {
- "name": "Gemini CLI projects.json",
- "description": "Content for /root/.gemini/projects.json. Project directory mappings.",
- "type": "file",
- "default": {
- "path": "/root/.gemini/projects.json",
- "content": "{\"projects\":{\"/root\":\"root\"}}"
- },
- "meta": {
- "filetype": "json"
- }
- },
- "trusted_folders_json": {
- "name": "Gemini CLI trustedFolders.json",
- "description": "Content for /root/.gemini/trustedFolders.json. Pre-trusted workspace dirs.",
- "type": "file",
- "default": {
- "path": "/root/.gemini/trustedFolders.json",
- "content": "{\"/root\":\"TRUST_FOLDER\"}"
- },
- "meta": {
- "filetype": "json"
- }
- },
- "installation_id": {
- "name": "Gemini CLI installation_id",
- "description": "Content for /root/.gemini/installation_id. Stable UUID avoids first-run prompts.",
- "type": "file",
- "default": {
- "path": "/root/.gemini/installation_id",
- "content": "capsem-sandbox-00000000-0000-0000-0000-000000000000"
- }
- },
- "google_adc_json": {
- "name": "Google Cloud ADC",
- "description": "Content for /root/.config/gcloud/application_default_credentials.json. OAuth credentials for Google Cloud auth. Injected from host when detected.",
- "type": "file",
- "default": {
- "path": "/root/.config/gcloud/application_default_credentials.json",
- "content": ""
- },
- "meta": {
- "filetype": "json"
- }
- }
- }
- },
- "openai": {
- "name": "OpenAI",
- "description": "OpenAI API provider",
- "enabled_by": "ai.openai.allow",
- "collapsed": false,
- "allow": {
- "name": "Allow OpenAI",
- "description": "Enable API access to OpenAI (*.openai.com).",
- "type": "bool",
- "default": true,
- "meta": {
- "rules": {
- "default": {
- "get": true,
- "post": true
- }
- }
- }
- },
- "api_key": {
- "name": "OpenAI API Key",
- "description": "API key for OpenAI. Injected as OPENAI_API_KEY env var.",
- "type": "apikey",
- "default": "",
- "meta": {
- "env_vars": [
- "OPENAI_API_KEY"
- ],
- "docs_url": "https://platform.openai.com/api-keys",
- "prefix": "sk-"
- }
- },
- "domains": {
- "name": "OpenAI Domains",
- "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
- "type": "text",
- "default": "*.openai.com"
- },
- "codex": {
- "name": "Codex CLI",
- "description": "Codex CLI configuration files",
- "config_toml": {
- "name": "Codex CLI config.toml",
- "description": "Content for /root/.codex/config.toml. MCP servers, auth, etc.",
- "type": "file",
- "default": {
- "path": "/root/.codex/config.toml",
- "content": "[mcp_servers.capsem]\ncommand = \"/run/capsem-mcp-server\""
- },
- "meta": {
- "filetype": "toml"
- }
- }
- }
- }
- },
- "repository": {
- "name": "Repositories",
- "description": "Code hosting and git configuration",
- "collapsed": false,
- "git": {
- "identity": {
- "name": "Git Identity",
- "description": "Author name and email for commits inside the VM",
- "author_name": {
- "name": "Author name",
- "description": "Name used for git commits. Injected as GIT_AUTHOR_NAME and GIT_COMMITTER_NAME.",
- "type": "text",
- "default": "",
- "meta": {
- "env_vars": [
- "GIT_AUTHOR_NAME",
- "GIT_COMMITTER_NAME"
- ]
- }
- },
- "author_email": {
- "name": "Author email",
- "description": "Email used for git commits. Injected as GIT_AUTHOR_EMAIL and GIT_COMMITTER_EMAIL.",
- "type": "text",
- "default": "",
- "meta": {
- "env_vars": [
- "GIT_AUTHOR_EMAIL",
- "GIT_COMMITTER_EMAIL"
- ]
- }
- }
- }
- },
- "providers": {
- "name": "Providers",
- "description": "Code hosting platforms",
- "github": {
- "name": "GitHub",
- "description": "GitHub and GitHub-hosted content",
- "enabled_by": "repository.providers.github.allow",
- "allow": {
- "name": "Allow GitHub",
- "description": "Enable access to GitHub and GitHub-hosted content.",
- "type": "bool",
- "default": true,
- "meta": {
- "domains": [
- "github.com",
- "*.github.com",
- "*.githubusercontent.com"
- ],
- "rules": {
- "default": {
- "get": true,
- "post": true
- }
- }
- }
- },
- "domains": {
- "name": "GitHub Domains",
- "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
- "type": "text",
- "default": "github.com, *.github.com, *.githubusercontent.com",
- "meta": {
- "format": "domain_list"
- }
- },
- "token": {
- "name": "GitHub Token",
- "description": "Personal access token for git push over HTTPS. Injected into .git-credentials.",
- "type": "apikey",
- "default": "",
- "meta": {
- "env_vars": [
- "GH_TOKEN",
- "GITHUB_TOKEN"
- ],
- "docs_url": "https://github.com/settings/tokens",
- "prefix": "ghp_"
- }
- }
- },
- "gitlab": {
- "name": "GitLab",
- "description": "GitLab and GitLab-hosted content",
- "enabled_by": "repository.providers.gitlab.allow",
- "allow": {
- "name": "Allow GitLab",
- "description": "Enable access to GitLab and GitLab-hosted content.",
- "type": "bool",
- "default": false,
- "meta": {
- "domains": [
- "gitlab.com",
- "*.gitlab.com"
- ],
- "rules": {
- "default": {
- "get": true,
- "post": true
- }
- }
- }
- },
- "domains": {
- "name": "GitLab Domains",
- "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
- "type": "text",
- "default": "gitlab.com, *.gitlab.com",
- "meta": {
- "format": "domain_list"
- }
- },
- "token": {
- "name": "GitLab Token",
- "description": "Personal access token for git push over HTTPS. Injected into .git-credentials.",
- "type": "apikey",
- "default": "",
- "meta": {
- "env_vars": [
- "GITLAB_TOKEN"
- ],
- "docs_url": "https://gitlab.com/-/user_settings/personal_access_tokens",
- "prefix": "glpat-"
- }
- }
- }
- }
- },
- "security": {
- "name": "Security",
- "description": "Network access control, web services, and security presets",
- "collapsed": false,
- "preset": {
- "name": "Security Preset",
- "description": "Predefined security configurations",
- "action": "preset_select"
- },
- "web": {
- "name": "Web",
- "description": "Default actions for unknown domains",
- "allow_read": {
- "name": "Allow read requests",
- "description": "Allow GET/HEAD/OPTIONS for domains not in any allow/block list.",
- "type": "bool",
- "default": false
- },
- "allow_write": {
- "name": "Allow write requests",
- "description": "Allow POST/PUT/DELETE/PATCH for domains not in any allow/block list.",
- "type": "bool",
- "default": false
- },
- "custom_allow": {
- "name": "Allowed domains",
- "description": "Comma-separated domain patterns to allow. Wildcards supported (*.example.com).",
- "type": "text",
- "default": "elie.net, *.elie.net, en.wikipedia.org, *.wikipedia.org",
- "meta": {
- "format": "domain_list"
- }
- },
- "custom_block": {
- "name": "Blocked domains",
- "description": "Comma-separated domain patterns to block. Takes priority over custom allow list.",
- "type": "text",
- "default": "",
- "meta": {
- "format": "domain_list"
- }
- }
- },
- "services": {
- "name": "Services",
- "description": "Search engines and package registries",
- "search": {
- "name": "Search Engines",
- "description": "Web search engine access",
- "google": {
- "name": "Google",
- "description": "Google web search",
- "enabled_by": "security.services.search.google.allow",
- "allow": {
- "name": "Allow Google",
- "description": "Enable access to Google web search.",
- "type": "bool",
- "default": true,
- "meta": {
- "domains": [
- "www.google.com",
- "google.com"
- ],
- "rules": {
- "default": {
- "get": true
- }
- }
- }
- },
- "domains": {
- "name": "Google Domains",
- "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
- "type": "text",
- "default": "www.google.com, google.com",
- "meta": {
- "format": "domain_list"
- }
- }
- },
- "bing": {
- "name": "Bing",
- "description": "Bing web search",
- "enabled_by": "security.services.search.bing.allow",
- "allow": {
- "name": "Allow Bing",
- "description": "Enable access to Bing web search.",
- "type": "bool",
- "default": false,
- "meta": {
- "domains": [
- "www.bing.com",
- "bing.com"
- ],
- "rules": {
- "default": {
- "get": true
- }
- }
- }
- },
- "domains": {
- "name": "Bing Domains",
- "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
- "type": "text",
- "default": "www.bing.com, bing.com",
- "meta": {
- "format": "domain_list"
- }
- }
- },
- "duckduckgo": {
- "name": "DuckDuckGo",
- "description": "DuckDuckGo web search",
- "enabled_by": "security.services.search.duckduckgo.allow",
- "allow": {
- "name": "Allow DuckDuckGo",
- "description": "Enable access to DuckDuckGo web search.",
- "type": "bool",
- "default": false,
- "meta": {
- "domains": [
- "duckduckgo.com",
- "*.duckduckgo.com"
- ],
- "rules": {
- "default": {
- "get": true
- }
- }
- }
- },
- "domains": {
- "name": "DuckDuckGo Domains",
- "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
- "type": "text",
- "default": "duckduckgo.com, *.duckduckgo.com",
- "meta": {
- "format": "domain_list"
- }
- }
- }
- },
- "registry": {
- "name": "Package Registries",
- "description": "Package manager registries",
- "debian": {
- "name": "Debian",
- "description": "Debian package registry",
- "enabled_by": "security.services.registry.debian.allow",
- "allow": {
- "name": "Allow Debian",
- "description": "Enable access to Debian.",
- "type": "bool",
- "default": true,
- "meta": {
- "domains": [
- "deb.debian.org",
- "security.debian.org"
- ],
- "rules": {
- "default": {
- "get": true
- }
- }
- }
- },
- "domains": {
- "name": "Debian Domains",
- "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
- "type": "text",
- "default": "deb.debian.org, security.debian.org",
- "meta": {
- "format": "domain_list"
- }
- }
- },
- "npm": {
- "name": "npm",
- "description": "npm package registry",
- "enabled_by": "security.services.registry.npm.allow",
- "allow": {
- "name": "Allow npm",
- "description": "Enable access to npm.",
- "type": "bool",
- "default": true,
- "meta": {
- "domains": [
- "registry.npmjs.org",
- "*.npmjs.org"
- ],
- "rules": {
- "default": {
- "get": true
- }
- }
- }
- },
- "domains": {
- "name": "npm Domains",
- "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
- "type": "text",
- "default": "registry.npmjs.org, *.npmjs.org",
- "meta": {
- "format": "domain_list"
- }
- }
- },
- "pypi": {
- "name": "PyPI",
- "description": "PyPI package registry",
- "enabled_by": "security.services.registry.pypi.allow",
- "allow": {
- "name": "Allow PyPI",
- "description": "Enable access to PyPI.",
- "type": "bool",
- "default": true,
- "meta": {
- "domains": [
- "pypi.org",
- "files.pythonhosted.org"
- ],
- "rules": {
- "default": {
- "get": true
- }
- }
- }
- },
- "domains": {
- "name": "PyPI Domains",
- "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
- "type": "text",
- "default": "pypi.org, files.pythonhosted.org",
- "meta": {
- "format": "domain_list"
- }
- }
- },
- "crates": {
- "name": "crates.io",
- "description": "crates.io package registry",
- "enabled_by": "security.services.registry.crates.allow",
- "allow": {
- "name": "Allow crates.io",
- "description": "Enable access to crates.io.",
- "type": "bool",
- "default": true,
- "meta": {
- "domains": [
- "crates.io",
- "static.crates.io"
- ],
- "rules": {
- "default": {
- "get": true
- }
- }
- }
- },
- "domains": {
- "name": "crates.io Domains",
- "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
- "type": "text",
- "default": "crates.io, static.crates.io",
- "meta": {
- "format": "domain_list"
- }
- }
- }
- }
- }
- },
- "vm": {
- "name": "VM",
- "description": "Virtual machine configuration",
- "collapsed": false,
- "rerun_wizard": {
- "name": "Setup Wizard",
- "description": "Re-run the first-time setup wizard to reconfigure providers, repositories, and security.",
- "action": "rerun_wizard"
- },
- "snapshots": {
- "name": "Snapshots",
- "description": "Automatic and manual workspace snapshot settings",
- "auto_max": {
- "name": "Auto snapshot limit",
- "description": "Maximum number of automatic rolling snapshots.",
- "type": "number",
- "default": 10,
- "meta": {
- "min": 1,
- "max": 50
- }
- },
- "manual_max": {
- "name": "Manual snapshot limit",
- "description": "Maximum number of named manual snapshots.",
- "type": "number",
- "default": 12,
- "meta": {
- "min": 1,
- "max": 50
- }
- },
- "auto_interval": {
- "name": "Auto snapshot interval",
- "description": "Seconds between automatic snapshots.",
- "type": "number",
- "default": 300,
- "meta": {
- "min": 30,
- "max": 3600
- }
- }
- },
- "environment": {
- "name": "Environment",
- "description": "Shell and environment variables",
- "shell": {
- "name": "Shell",
- "description": "Guest shell settings",
- "term": {
- "name": "TERM",
- "description": "Terminal type for the guest shell.",
- "type": "text",
- "default": "xterm-256color",
- "meta": {
- "env_vars": [
- "TERM"
- ]
- }
- },
- "home": {
- "name": "HOME",
- "description": "Home directory for the guest shell.",
- "type": "text",
- "default": "/root",
- "meta": {
- "env_vars": [
- "HOME"
- ]
- }
- },
- "path": {
- "name": "PATH",
- "description": "Executable search path for the guest shell.",
- "type": "text",
- "default": "/opt/ai-clis/bin:/root/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
- "meta": {
- "env_vars": [
- "PATH"
- ]
- }
- },
- "lang": {
- "name": "LANG",
- "description": "Locale for the guest shell.",
- "type": "text",
- "default": "C",
- "meta": {
- "env_vars": [
- "LANG"
- ]
- }
- },
- "bashrc": {
- "name": "Bash configuration",
- "description": "User shell config sourced at login. Customize prompt, aliases, and functions.",
- "type": "file",
- "default": {
- "path": "/root/.bashrc",
- "content": "# Prompt: green bold hostname with blue directory\nPS1='\\[\\033[1;32m\\]\\h\\[\\033[0m\\]:\\[\\033[1;34m\\]\\w\\[\\033[0m\\]\\$ '\n\n# Aliases\nalias pip='uv pip'\nalias pip3='uv pip'\nalias python='uv run python'\nalias python3='uv run python3'\nalias claude='claude --dangerously-skip-permissions'\nalias gemini='gemini --yolo'\nalias ls='ls --color=auto'\nalias ll='ls -la --color=auto'\nalias grep='grep --color=auto'\n"
- },
- "meta": {
- "filetype": "bash"
- }
- },
- "tmux_conf": {
- "name": "tmux configuration",
- "description": "tmux terminal multiplexer config. Customize appearance, keybindings, and behavior.",
- "type": "file",
- "default": {
- "path": "/root/.tmux.conf",
- "content": "set -g default-terminal \"tmux-256color\"\nset -ag terminal-features \",xterm-256color:RGB\"\nset -g mouse on\nset -g escape-time 0\nset -g history-limit 50000\nset -g status-style \"bg=default,fg=colour8\"\nset -g status-left \"\"\nset -g status-right \"\"\nset -g pane-border-style \"fg=colour8\"\nset -g pane-active-border-style \"fg=colour4\"\nset -g message-style \"bg=default,fg=colour4\"\n"
- },
- "meta": {
- "filetype": "conf"
- }
- }
- },
- "ssh": {
- "name": "SSH",
- "description": "SSH key configuration",
- "public_key": {
- "name": "SSH public key",
- "description": "Public key injected as /root/.ssh/authorized_keys in the guest VM.",
- "type": "text",
- "default": ""
- }
- },
- "tls": {
- "name": "TLS",
- "description": "TLS certificate configuration",
- "ca_bundle": {
- "name": "CA bundle path",
- "description": "Path to the CA certificate bundle in the guest. Injected as REQUESTS_CA_BUNDLE, NODE_EXTRA_CA_CERTS, and SSL_CERT_FILE.",
- "type": "text",
- "default": "/etc/ssl/certs/ca-certificates.crt",
- "meta": {
- "env_vars": [
- "REQUESTS_CA_BUNDLE",
- "NODE_EXTRA_CA_CERTS",
- "SSL_CERT_FILE"
- ]
- }
- }
- }
- },
- "resources": {
- "name": "Resources",
- "description": "Hardware, telemetry, and session limits",
- "cpu_count": {
- "name": "CPU cores",
- "description": "Number of CPU cores allocated to the VM.",
- "type": "number",
- "default": 4,
- "meta": {
- "min": 1,
- "max": 8
- }
- },
- "ram_gb": {
- "name": "RAM",
- "description": "Amount of RAM allocated to the VM in GB.",
- "type": "number",
- "default": 8,
- "meta": {
- "min": 1,
- "max": 16
- }
- },
- "scratch_disk_size_gb": {
- "name": "Scratch disk size",
- "description": "Size of the ephemeral scratch disk in GB.",
- "type": "number",
- "default": 16,
- "meta": {
- "min": 1,
- "max": 128
- }
- },
- "log_bodies": {
- "name": "Log request bodies",
- "description": "Capture request/response bodies in telemetry.",
- "type": "bool",
- "default": false
- },
- "max_body_capture": {
- "name": "Max body capture",
- "description": "Maximum bytes of body to capture in telemetry.",
- "type": "number",
- "default": 4096,
- "meta": {
- "min": 0,
- "max": 1048576
- }
- },
- "retention_days": {
- "name": "Session retention",
- "description": "Number of days to retain session data.",
- "type": "number",
- "default": 30,
- "meta": {
- "min": 1,
- "max": 365
- }
- },
- "max_sessions": {
- "name": "Maximum sessions",
- "description": "Keep at most this many sessions (oldest culled first).",
- "type": "number",
- "default": 100,
- "meta": {
- "min": 1,
- "max": 10000
- }
- },
- "min_content_sessions": {
- "name": "Minimum content sessions",
- "description": "Always keep at least this many sessions that contain AI activity, regardless of age. Empty test sessions are terminated first.",
- "type": "number",
- "default": 25,
- "meta": {
- "min": 0,
- "max": 1000,
- "step": 1
- }
- },
- "max_disk_gb": {
- "name": "Maximum disk usage",
- "description": "Maximum total disk usage for all sessions in GB.",
- "type": "number",
- "default": 100,
- "meta": {
- "min": 1,
- "max": 1000
- }
- },
- "terminated_retention_days": {
- "name": "Terminated session retention",
- "description": "Days to keep terminated session records in the index. After this, the record is permanently deleted.",
- "type": "number",
- "default": 365,
- "meta": {
- "min": 30,
- "max": 3650
- }
- }
- }
- },
- "appearance": {
- "name": "Appearance",
- "description": "UI appearance and display settings",
- "collapsed": false,
- "dark_mode": {
- "name": "Dark mode",
- "description": "Use dark color scheme in the UI.",
- "type": "bool",
- "default": true,
- "meta": {
- "side_effect": "toggle_theme"
- }
- },
- "font_size": {
- "name": "Font size",
- "description": "Terminal font size in pixels.",
- "type": "number",
- "default": 14,
- "meta": {
- "min": 8,
- "max": 32
- }
- }
- }
- },
- "mcp": {
- "local": {
- "name": "Local",
- "description": "Built-in local tools: HTTP fetch, workspace snapshots",
- "transport": "stdio",
- "command": "/run/capsem-mcp-server",
- "builtin": true
- }
- }
-}
diff --git a/config/defaults.toml b/config/defaults.toml
deleted file mode 100644
index c0aa8f378..000000000
--- a/config/defaults.toml
+++ /dev/null
@@ -1,920 +0,0 @@
-# ============================================================================
-# Capsem Settings Registry
-# ============================================================================
-#
-# Single source of truth for all built-in settings. Embedded at compile time
-# via include_str!(). See docs/config.md for the format reference.
-#
-# Three node types, distinguished by presence of `type`:
-# - Category/group: has `name` but no `type` -- grouping with metadata
-# - Setting leaf: has `name` and `type` -- actual setting
-# - Meta: sub-table under a leaf -- extra metadata (env_vars, etc.)
-
-# -- App ---------------------------------------------------------------------
-
-[settings.app]
-name = "App"
-description = "Application settings"
-collapsed = false
-
-# -- AI Providers ------------------------------------------------------------
-
-[settings.ai]
-name = "AI Providers"
-description = "AI model provider configuration"
-collapsed = false
-
-# -- Anthropic ---------------------------------------------------------------
-
-[settings.ai.anthropic]
-name = "Anthropic"
-description = "Claude Code AI agent"
-enabled_by = "ai.anthropic.allow"
-collapsed = false
-
-[settings.ai.anthropic.allow]
-name = "Allow Anthropic"
-description = "Enable API access to Anthropic (api.anthropic.com)."
-type = "bool"
-default = true
-
-[settings.ai.anthropic.allow.meta.rules.default]
-get = true
-post = true
-
-[settings.ai.anthropic.api_key]
-name = "Anthropic API Key"
-description = "API key for Anthropic. Injected as ANTHROPIC_API_KEY env var."
-type = "apikey"
-default = ""
-
-[settings.ai.anthropic.api_key.meta]
-env_vars = ["ANTHROPIC_API_KEY"]
-docs_url = "https://console.anthropic.com/settings/keys"
-prefix = "sk-ant-"
-
-[settings.ai.anthropic.domains]
-name = "Anthropic Domains"
-description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
-type = "text"
-default = "*.anthropic.com, *.claude.com"
-
-[settings.ai.anthropic.claude]
-name = "Claude Code"
-description = "Claude Code configuration files"
-
-[settings.ai.anthropic.claude.settings_json]
-name = "Claude Code settings.json"
-description = "Content for ~/.claude/settings.json. Bypass permissions, disable telemetry/updates for sandboxed execution."
-type = "file"
-
-[settings.ai.anthropic.claude.settings_json.default]
-path = "/root/.claude/settings.json"
-content = '{"permissions":{"defaultMode":"bypassPermissions"},"env":{"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC":"1"}}'
-
-[settings.ai.anthropic.claude.settings_json.meta]
-filetype = "json"
-
-[settings.ai.anthropic.claude.state_json]
-name = "Claude Code state (.claude.json)"
-description = "Content for ~/.claude.json. Skips onboarding, trust dialogs, and keybinding prompts."
-type = "file"
-
-[settings.ai.anthropic.claude.state_json.default]
-path = "/root/.claude.json"
-content = '{"hasCompletedOnboarding":true,"hasTrustDialogAccepted":true,"hasTrustDialogHooksAccepted":true,"shiftEnterKeyBindingInstalled":true,"theme":"dark","numStartups":1,"opusProMigrationComplete":true,"sonnet1m45MigrationComplete":true,"projects":{"/root":{"allowedTools":[],"hasTrustDialogAccepted":true,"projectOnboardingSeenCount":1}}}'
-
-[settings.ai.anthropic.claude.state_json.meta]
-filetype = "json"
-
-[settings.ai.anthropic.claude.credentials_json]
-name = "Claude Code OAuth credentials"
-description = "Content for ~/.claude/.credentials.json. OAuth tokens for subscription-based auth (Pro/Max). Injected from host when detected."
-type = "file"
-
-[settings.ai.anthropic.claude.credentials_json.default]
-path = "/root/.claude/.credentials.json"
-content = ""
-
-[settings.ai.anthropic.claude.credentials_json.meta]
-filetype = "json"
-
-# -- OpenAI ------------------------------------------------------------------
-
-[settings.ai.openai]
-name = "OpenAI"
-description = "OpenAI API provider"
-enabled_by = "ai.openai.allow"
-collapsed = false
-
-[settings.ai.openai.allow]
-name = "Allow OpenAI"
-description = "Enable API access to OpenAI (api.openai.com)."
-type = "bool"
-default = true
-
-[settings.ai.openai.allow.meta.rules.default]
-get = true
-post = true
-
-[settings.ai.openai.api_key]
-name = "OpenAI API Key"
-description = "API key for OpenAI. Injected as OPENAI_API_KEY env var."
-type = "apikey"
-default = ""
-
-[settings.ai.openai.api_key.meta]
-env_vars = ["OPENAI_API_KEY"]
-docs_url = "https://platform.openai.com/api-keys"
-prefix = "sk-"
-
-[settings.ai.openai.domains]
-name = "OpenAI Domains"
-description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
-type = "text"
-default = "*.openai.com"
-
-[settings.ai.openai.codex]
-name = "Codex CLI"
-description = "Codex CLI configuration files"
-
-[settings.ai.openai.codex.config_toml]
-name = "Codex config.toml"
-description = "Content for ~/.codex/config.toml. MCP servers, auth, etc."
-type = "file"
-
-[settings.ai.openai.codex.config_toml.default]
-path = "/root/.codex/config.toml"
-content = "[mcp_servers.capsem]\ncommand = \"/run/capsem-mcp-server\""
-
-[settings.ai.openai.codex.config_toml.meta]
-filetype = "toml"
-
-# -- Google AI ---------------------------------------------------------------
-
-[settings.ai.google]
-name = "Google AI"
-description = "Google Gemini AI provider"
-enabled_by = "ai.google.allow"
-collapsed = false
-
-[settings.ai.google.allow]
-name = "Allow Google AI"
-description = "Enable API access to Google AI (*.googleapis.com)."
-type = "bool"
-default = true
-
-[settings.ai.google.allow.meta.rules.default]
-get = true
-post = true
-
-[settings.ai.google.api_key]
-name = "Google AI API Key"
-description = "API key for Google AI. Injected as GEMINI_API_KEY env var."
-type = "apikey"
-default = ""
-
-[settings.ai.google.api_key.meta]
-env_vars = ["GEMINI_API_KEY"]
-docs_url = "https://aistudio.google.com/apikey"
-prefix = "AIza"
-
-[settings.ai.google.domains]
-name = "Google AI Domains"
-description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
-type = "text"
-default = "*.googleapis.com"
-
-[settings.ai.google.gemini]
-name = "Gemini CLI"
-description = "Gemini CLI configuration files"
-
-[settings.ai.google.gemini.settings_json]
-name = "Gemini settings.json"
-description = "Content for ~/.gemini/settings.json. Session retention, auth, MCP servers, etc."
-type = "file"
-
-[settings.ai.google.gemini.settings_json.default]
-path = "/root/.gemini/settings.json"
-content = '{"homeDirectoryWarningDismissed":true,"general":{"disableAutoUpdate":true,"disableUpdateNag":true},"ui":{"hideTips":true,"hideBanner":false},"privacy":{"usageStatisticsEnabled":false,"sessionRetention":"none"},"telemetry":{"enabled":false},"security":{"auth":{"selectedType":"gemini-api-key"},"folderTrust.enabled":false},"ide":{"hasSeenNudge":true},"tools":{"sandbox":false}}'
-
-[settings.ai.google.gemini.settings_json.meta]
-filetype = "json"
-
-[settings.ai.google.gemini.projects_json]
-name = "Gemini projects.json"
-description = "Content for ~/.gemini/projects.json. Project directory mappings."
-type = "file"
-
-[settings.ai.google.gemini.projects_json.default]
-path = "/root/.gemini/projects.json"
-content = '{"projects":{"/root":"root"}}'
-
-[settings.ai.google.gemini.projects_json.meta]
-filetype = "json"
-
-[settings.ai.google.gemini.trusted_folders_json]
-name = "Gemini trustedFolders.json"
-description = "Content for ~/.gemini/trustedFolders.json. Pre-trusted workspace dirs."
-type = "file"
-
-[settings.ai.google.gemini.trusted_folders_json.default]
-path = "/root/.gemini/trustedFolders.json"
-content = '{"/root":"TRUST_FOLDER"}'
-
-[settings.ai.google.gemini.trusted_folders_json.meta]
-filetype = "json"
-
-[settings.ai.google.gemini.installation_id]
-name = "Gemini installation_id"
-description = "Content for ~/.gemini/installation_id. Stable UUID avoids first-run prompts."
-type = "file"
-
-[settings.ai.google.gemini.installation_id.default]
-path = "/root/.gemini/installation_id"
-content = "capsem-sandbox-00000000-0000-0000-0000-000000000000"
-
-[settings.ai.google.gemini.google_adc_json]
-name = "Google Cloud ADC"
-description = "Content for application_default_credentials.json. OAuth credentials for Google Cloud auth. Injected from host when detected."
-type = "file"
-
-[settings.ai.google.gemini.google_adc_json.default]
-path = "/root/.config/gcloud/application_default_credentials.json"
-content = ""
-
-[settings.ai.google.gemini.google_adc_json.meta]
-filetype = "json"
-
-# -- Repositories --------------------------------------------------------------
-
-[settings.repository]
-name = "Repositories"
-description = "Code hosting and git configuration"
-collapsed = false
-
-# -- Git Identity --------------------------------------------------------------
-
-[settings.repository.git]
-# No name -- avoids an empty heading; Identity renders directly under Repositories.
-
-[settings.repository.git.identity]
-name = "Git Identity"
-description = "Author name and email for commits inside the VM"
-
-[settings.repository.git.identity.author_name]
-name = "Author name"
-description = "Name used for git commits. Injected as GIT_AUTHOR_NAME and GIT_COMMITTER_NAME."
-type = "text"
-default = ""
-
-[settings.repository.git.identity.author_name.meta]
-env_vars = ["GIT_AUTHOR_NAME", "GIT_COMMITTER_NAME"]
-
-[settings.repository.git.identity.author_email]
-name = "Author email"
-description = "Email used for git commits. Injected as GIT_AUTHOR_EMAIL and GIT_COMMITTER_EMAIL."
-type = "text"
-default = ""
-
-[settings.repository.git.identity.author_email.meta]
-env_vars = ["GIT_AUTHOR_EMAIL", "GIT_COMMITTER_EMAIL"]
-
-# -- Repository Providers ------------------------------------------------------
-
-[settings.repository.providers]
-name = "Providers"
-description = "Code hosting platforms"
-
-# -- GitHub --------------------------------------------------------------------
-
-[settings.repository.providers.github]
-name = "GitHub"
-description = "GitHub and GitHub-hosted content"
-enabled_by = "repository.providers.github.allow"
-
-[settings.repository.providers.github.allow]
-name = "Allow GitHub"
-description = "Enable access to GitHub and GitHub-hosted content."
-type = "bool"
-default = true
-
-[settings.repository.providers.github.allow.meta]
-domains = ["github.com", "*.github.com", "*.githubusercontent.com"]
-
-[settings.repository.providers.github.allow.meta.rules.default]
-get = true
-post = true
-
-[settings.repository.providers.github.domains]
-name = "GitHub Domains"
-description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
-type = "text"
-default = "github.com, *.github.com, *.githubusercontent.com"
-
-[settings.repository.providers.github.domains.meta]
-format = "domain_list"
-
-[settings.repository.providers.github.token]
-name = "GitHub Token"
-description = "Personal access token for git push over HTTPS. Injected into .git-credentials."
-type = "apikey"
-default = ""
-
-[settings.repository.providers.github.token.meta]
-env_vars = ["GH_TOKEN", "GITHUB_TOKEN"]
-docs_url = "https://github.com/settings/tokens"
-prefix = "ghp_"
-
-# -- GitLab --------------------------------------------------------------------
-
-[settings.repository.providers.gitlab]
-name = "GitLab"
-description = "GitLab and GitLab-hosted content"
-enabled_by = "repository.providers.gitlab.allow"
-
-[settings.repository.providers.gitlab.allow]
-name = "Allow GitLab"
-description = "Enable access to GitLab and GitLab-hosted content."
-type = "bool"
-default = false
-
-[settings.repository.providers.gitlab.allow.meta]
-domains = ["gitlab.com", "*.gitlab.com"]
-
-[settings.repository.providers.gitlab.allow.meta.rules.default]
-get = true
-post = true
-
-[settings.repository.providers.gitlab.domains]
-name = "GitLab Domains"
-description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
-type = "text"
-default = "gitlab.com, *.gitlab.com"
-
-[settings.repository.providers.gitlab.domains.meta]
-format = "domain_list"
-
-[settings.repository.providers.gitlab.token]
-name = "GitLab Token"
-description = "Personal access token for git push over HTTPS. Injected into .git-credentials."
-type = "apikey"
-default = ""
-
-[settings.repository.providers.gitlab.token.meta]
-env_vars = ["GITLAB_TOKEN"]
-docs_url = "https://gitlab.com/-/user_settings/personal_access_tokens"
-prefix = "glpat-"
-
-# -- Security ----------------------------------------------------------------
-
-[settings.security]
-name = "Security"
-description = "Network access control, web services, and security presets"
-collapsed = false
-
-[settings.security.preset]
-name = "Security Preset"
-description = "Predefined security configurations"
-action = "preset_select"
-
-# -- Security > Web ----------------------------------------------------------
-
-[settings.security.web]
-name = "Web"
-description = "Default actions for unknown domains"
-
-[settings.security.web.allow_read]
-name = "Allow read requests"
-description = "Allow GET/HEAD/OPTIONS for domains not in any allow/block list."
-type = "bool"
-default = false
-
-[settings.security.web.allow_write]
-name = "Allow write requests"
-description = "Allow POST/PUT/DELETE/PATCH for domains not in any allow/block list."
-type = "bool"
-default = false
-
-[settings.security.web.custom_allow]
-name = "Allowed domains"
-description = "Comma-separated domain patterns to allow. Wildcards supported (*.example.com)."
-type = "text"
-default = "elie.net, *.elie.net, en.wikipedia.org, *.wikipedia.org"
-
-[settings.security.web.custom_allow.meta]
-format = "domain_list"
-
-[settings.security.web.custom_block]
-name = "Blocked domains"
-description = "Comma-separated domain patterns to block. Takes priority over custom allow list."
-type = "text"
-default = ""
-
-[settings.security.web.custom_block.meta]
-format = "domain_list"
-
-# -- Security > Services -----------------------------------------------------
-
-[settings.security.services]
-name = "Services"
-description = "Search engines and package registries"
-
-# -- Security > Services > Search Engines ------------------------------------
-
-[settings.security.services.search]
-name = "Search Engines"
-description = "Web search engine access"
-
-[settings.security.services.search.google]
-name = "Google"
-description = "Google web search"
-enabled_by = "security.services.search.google.allow"
-
-[settings.security.services.search.google.allow]
-name = "Allow Google"
-description = "Enable access to Google web search."
-type = "bool"
-default = true
-
-[settings.security.services.search.google.allow.meta]
-domains = ["www.google.com", "google.com"]
-
-[settings.security.services.search.google.allow.meta.rules.default]
-get = true
-
-[settings.security.services.search.google.domains]
-name = "Google Domains"
-description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
-type = "text"
-default = "www.google.com, google.com"
-
-[settings.security.services.search.google.domains.meta]
-format = "domain_list"
-
-[settings.security.services.search.bing]
-name = "Bing"
-description = "Microsoft Bing web search"
-enabled_by = "security.services.search.bing.allow"
-
-[settings.security.services.search.bing.allow]
-name = "Allow Bing"
-description = "Enable access to Bing web search."
-type = "bool"
-default = false
-
-[settings.security.services.search.bing.allow.meta]
-domains = ["www.bing.com", "bing.com"]
-
-[settings.security.services.search.bing.allow.meta.rules.default]
-get = true
-
-[settings.security.services.search.bing.domains]
-name = "Bing Domains"
-description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
-type = "text"
-default = "www.bing.com, bing.com"
-
-[settings.security.services.search.bing.domains.meta]
-format = "domain_list"
-
-[settings.security.services.search.duckduckgo]
-name = "DuckDuckGo"
-description = "DuckDuckGo web search"
-enabled_by = "security.services.search.duckduckgo.allow"
-
-[settings.security.services.search.duckduckgo.allow]
-name = "Allow DuckDuckGo"
-description = "Enable access to DuckDuckGo web search."
-type = "bool"
-default = false
-
-[settings.security.services.search.duckduckgo.allow.meta]
-domains = ["duckduckgo.com", "*.duckduckgo.com"]
-
-[settings.security.services.search.duckduckgo.allow.meta.rules.default]
-get = true
-
-[settings.security.services.search.duckduckgo.domains]
-name = "DuckDuckGo Domains"
-description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
-type = "text"
-default = "duckduckgo.com, *.duckduckgo.com"
-
-[settings.security.services.search.duckduckgo.domains.meta]
-format = "domain_list"
-
-# -- Security > Services > Package Registries --------------------------------
-
-[settings.security.services.registry]
-name = "Package Registries"
-description = "Package manager registries"
-
-[settings.security.services.registry.debian]
-name = "Debian"
-description = "Debian package repositories"
-enabled_by = "security.services.registry.debian.allow"
-
-[settings.security.services.registry.debian.allow]
-name = "Allow Debian"
-description = "Enable access to deb.debian.org and security.debian.org for apt package installs."
-type = "bool"
-default = true
-
-[settings.security.services.registry.debian.allow.meta]
-domains = ["deb.debian.org", "security.debian.org"]
-
-[settings.security.services.registry.debian.allow.meta.rules.default]
-get = true
-
-[settings.security.services.registry.debian.domains]
-name = "Debian Domains"
-description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
-type = "text"
-default = "deb.debian.org, security.debian.org"
-
-[settings.security.services.registry.debian.domains.meta]
-format = "domain_list"
-
-[settings.security.services.registry.npm]
-name = "npm"
-description = "npm package registry"
-enabled_by = "security.services.registry.npm.allow"
-
-[settings.security.services.registry.npm.allow]
-name = "Allow npm"
-description = "Enable access to the npm package registry."
-type = "bool"
-default = true
-
-[settings.security.services.registry.npm.allow.meta]
-domains = ["registry.npmjs.org", "*.npmjs.org"]
-
-[settings.security.services.registry.npm.allow.meta.rules.default]
-get = true
-
-[settings.security.services.registry.npm.domains]
-name = "npm Domains"
-description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
-type = "text"
-default = "registry.npmjs.org, *.npmjs.org"
-
-[settings.security.services.registry.npm.domains.meta]
-format = "domain_list"
-
-[settings.security.services.registry.pypi]
-name = "PyPI"
-description = "Python Package Index"
-enabled_by = "security.services.registry.pypi.allow"
-
-[settings.security.services.registry.pypi.allow]
-name = "Allow PyPI"
-description = "Enable access to the Python Package Index."
-type = "bool"
-default = true
-
-[settings.security.services.registry.pypi.allow.meta]
-domains = ["pypi.org", "files.pythonhosted.org"]
-
-[settings.security.services.registry.pypi.allow.meta.rules.default]
-get = true
-
-[settings.security.services.registry.pypi.domains]
-name = "PyPI Domains"
-description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
-type = "text"
-default = "pypi.org, files.pythonhosted.org"
-
-[settings.security.services.registry.pypi.domains.meta]
-format = "domain_list"
-
-[settings.security.services.registry.crates]
-name = "crates.io"
-description = "Rust crate registry"
-enabled_by = "security.services.registry.crates.allow"
-
-[settings.security.services.registry.crates.allow]
-name = "Allow crates.io"
-description = "Enable access to the Rust crate registry."
-type = "bool"
-default = true
-
-[settings.security.services.registry.crates.allow.meta]
-domains = ["crates.io", "static.crates.io"]
-
-[settings.security.services.registry.crates.allow.meta.rules.default]
-get = true
-
-[settings.security.services.registry.crates.domains]
-name = "crates.io Domains"
-description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
-type = "text"
-default = "crates.io, static.crates.io"
-
-[settings.security.services.registry.crates.domains.meta]
-format = "domain_list"
-
-# -- VM ----------------------------------------------------------------------
-
-[settings.vm]
-name = "VM"
-description = "Virtual machine configuration"
-collapsed = false
-
-[settings.vm.rerun_wizard]
-name = "Setup Wizard"
-description = "Re-run the first-time setup wizard to reconfigure providers, repositories, and security."
-action = "rerun_wizard"
-
-# -- VM > Snapshots ----------------------------------------------------------
-
-[settings.vm.snapshots]
-name = "Snapshots"
-description = "Automatic and manual workspace snapshot settings"
-
-[settings.vm.snapshots.auto_max]
-name = "Auto snapshot limit"
-description = "Maximum number of automatic rolling snapshots."
-type = "number"
-default = 10
-
-[settings.vm.snapshots.auto_max.meta]
-min = 1
-max = 50
-
-[settings.vm.snapshots.manual_max]
-name = "Manual snapshot limit"
-description = "Maximum number of named manual snapshots."
-type = "number"
-default = 12
-
-[settings.vm.snapshots.manual_max.meta]
-min = 1
-max = 50
-
-[settings.vm.snapshots.auto_interval]
-name = "Auto snapshot interval"
-description = "Seconds between automatic snapshots."
-type = "number"
-default = 300
-
-[settings.vm.snapshots.auto_interval.meta]
-min = 30
-max = 3600
-
-# -- VM > Environment --------------------------------------------------------
-
-[settings.vm.environment]
-name = "Environment"
-description = "Shell and environment variables"
-
-[settings.vm.environment.shell]
-name = "Shell"
-description = "Guest shell settings"
-
-[settings.vm.environment.shell.term]
-name = "TERM"
-description = "Terminal type for the guest shell."
-type = "text"
-default = "xterm-256color"
-
-[settings.vm.environment.shell.term.meta]
-env_vars = ["TERM"]
-
-[settings.vm.environment.shell.home]
-name = "HOME"
-description = "Home directory for the guest shell."
-type = "text"
-default = "/root"
-
-[settings.vm.environment.shell.home.meta]
-env_vars = ["HOME"]
-
-[settings.vm.environment.shell.path]
-name = "PATH"
-description = "Executable search path for the guest shell."
-type = "text"
-default = "/opt/ai-clis/bin:/root/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-
-[settings.vm.environment.shell.path.meta]
-env_vars = ["PATH"]
-
-[settings.vm.environment.shell.lang]
-name = "LANG"
-description = "Locale for the guest shell."
-type = "text"
-default = "C"
-
-[settings.vm.environment.shell.lang.meta]
-env_vars = ["LANG"]
-
-[settings.vm.environment.shell.bashrc]
-name = "Bash configuration"
-description = "User shell config sourced at login. Customize prompt, aliases, and functions."
-type = "file"
-
-[settings.vm.environment.shell.bashrc.default]
-path = "/root/.bashrc"
-content = '''
-# Prompt: green bold hostname with blue directory
-PS1='\[\033[1;32m\]\h\[\033[0m\]:\[\033[1;34m\]\w\[\033[0m\]\$ '
-
-# Aliases
-alias pip='uv pip'
-alias pip3='uv pip'
-alias python='uv run python'
-alias python3='uv run python3'
-alias gemini='gemini --yolo'
-alias ls='ls --color=auto'
-alias ll='ls -la --color=auto'
-alias grep='grep --color=auto'
-'''
-
-[settings.vm.environment.shell.bashrc.meta]
-filetype = "bash"
-
-[settings.vm.environment.shell.tmux_conf]
-name = "tmux configuration"
-description = "tmux terminal multiplexer config. Customize appearance, keybindings, and behavior."
-type = "file"
-
-[settings.vm.environment.shell.tmux_conf.default]
-path = "/root/.tmux.conf"
-content = '''
-set -g default-terminal "tmux-256color"
-set -ag terminal-features ",xterm-256color:RGB"
-set -g mouse on
-set -g escape-time 0
-set -g history-limit 50000
-set -g status-style "bg=default,fg=colour8"
-set -g status-left ""
-set -g status-right ""
-set -g pane-border-style "fg=colour8"
-set -g pane-active-border-style "fg=colour4"
-set -g message-style "bg=default,fg=colour4"
-'''
-
-[settings.vm.environment.shell.tmux_conf.meta]
-filetype = "conf"
-
-[settings.vm.environment.ssh]
-name = "SSH"
-description = "SSH key configuration"
-
-[settings.vm.environment.ssh.public_key]
-name = "SSH public key"
-description = "Public key injected as /root/.ssh/authorized_keys in the guest VM."
-type = "text"
-default = ""
-
-[settings.vm.environment.tls]
-name = "TLS"
-description = "TLS certificate configuration"
-
-[settings.vm.environment.tls.ca_bundle]
-name = "CA bundle path"
-description = "Path to the CA certificate bundle in the guest. Injected as REQUESTS_CA_BUNDLE, NODE_EXTRA_CA_CERTS, and SSL_CERT_FILE."
-type = "text"
-default = "/etc/ssl/certs/ca-certificates.crt"
-
-[settings.vm.environment.tls.ca_bundle.meta]
-env_vars = ["REQUESTS_CA_BUNDLE", "NODE_EXTRA_CA_CERTS", "SSL_CERT_FILE"]
-
-# -- VM > Resources ----------------------------------------------------------
-
-[settings.vm.resources]
-name = "Resources"
-description = "Hardware, telemetry, and session limits"
-
-[settings.vm.resources.cpu_count]
-name = "CPU cores"
-description = "Number of CPU cores allocated to the VM."
-type = "number"
-default = 4
-
-[settings.vm.resources.cpu_count.meta]
-min = 1
-max = 8
-
-[settings.vm.resources.max_concurrent_vms]
-name = "Max concurrent VMs"
-description = "Maximum number of sandbox VMs that can be running simultaneously."
-type = "number"
-default = 8
-
-[settings.vm.resources.max_concurrent_vms.meta]
-min = 1
-max = 20
-
-[settings.vm.resources.ram_gb]
-name = "RAM"
-description = "Amount of RAM allocated to the VM in GB."
-type = "number"
-default = 8
-
-[settings.vm.resources.ram_gb.meta]
-min = 1
-max = 16
-
-[settings.vm.resources.scratch_disk_size_gb]
-name = "Scratch disk size"
-description = "Size of the ephemeral scratch disk in GB."
-type = "number"
-default = 16
-
-[settings.vm.resources.scratch_disk_size_gb.meta]
-min = 1
-max = 128
-
-[settings.vm.resources.log_bodies]
-name = "Log request bodies"
-description = "Capture request/response bodies in telemetry."
-type = "bool"
-default = false
-
-[settings.vm.resources.max_body_capture]
-name = "Max body capture"
-description = "Maximum bytes of body to capture in telemetry."
-type = "number"
-default = 4096
-
-[settings.vm.resources.max_body_capture.meta]
-min = 0
-max = 1048576
-
-[settings.vm.resources.retention_days]
-name = "Session retention"
-description = "Number of days to retain session data."
-type = "number"
-default = 30
-
-[settings.vm.resources.retention_days.meta]
-min = 1
-max = 365
-
-[settings.vm.resources.max_sessions]
-name = "Maximum sessions"
-description = "Keep at most this many sessions (oldest culled first)."
-type = "number"
-default = 100
-
-[settings.vm.resources.max_sessions.meta]
-min = 1
-max = 10000
-
-[settings.vm.resources.max_disk_gb]
-name = "Maximum disk usage"
-description = "Maximum total disk usage for all sessions in GB."
-type = "number"
-default = 100
-
-[settings.vm.resources.max_disk_gb.meta]
-min = 1
-max = 1000
-
-[settings.vm.resources.terminated_retention_days]
-name = "Terminated session retention"
-description = "Days to keep terminated session records in the index. After this, the record is permanently deleted."
-type = "number"
-default = 365
-
-[settings.vm.resources.terminated_retention_days.meta]
-min = 30
-max = 3650
-
-# -- Appearance --------------------------------------------------------------
-
-[settings.appearance]
-name = "Appearance"
-description = "UI appearance and display settings"
-collapsed = false
-
-[settings.appearance.dark_mode]
-name = "Dark mode"
-description = "Use dark color scheme in the UI."
-type = "bool"
-default = true
-
-[settings.appearance.dark_mode.meta]
-side_effect = "toggle_theme"
-
-[settings.appearance.font_size]
-name = "Font size"
-description = "Terminal font size in pixels."
-type = "number"
-default = 14
-
-[settings.appearance.font_size.meta]
-min = 8
-max = 32
-
-# -- MCP Servers -------------------------------------------------------------
-# Declarative MCP server definitions. Auto-injected into AI agent configs at boot.
-# Historical v1 defaults file; Profile V2 MCP connector policy lives in profiles.
-
-[mcp.local]
-name = "Local"
-description = "Built-in local tools: HTTP fetch, workspace snapshots"
-transport = "stdio"
-command = "/run/capsem-mcp-server"
-builtin = true
diff --git a/config/demo-corp-openai-openclaw.toml b/config/demo-corp-openai-openclaw.toml
deleted file mode 100644
index faa9e06ac..000000000
--- a/config/demo-corp-openai-openclaw.toml
+++ /dev/null
@@ -1,39 +0,0 @@
-# Capsem demo corporate Profile V2 policy.
-#
-# Apply locally:
-# ~/.capsem/bin/capsem setup --corp-config config/demo-corp-openai-openclaw.toml --non-interactive --accept-detected --force
-
-version = 1
-id = "demo-corp-openai-openclaw"
-name = "Demo Corp OpenAI/OpenClaw Block"
-description = "Corp-managed demo profile that disables OpenAI and blocks OpenClaw."
-best_for = "Demonstrating Profile V2 corp policy enforcement."
-profile_type = "coding"
-extends_profile_id = "everyday-work"
-
-[ai.providers.openai]
-enabled = false
-
-[security.capabilities]
-network_egress = "ask"
-
-[security.rules.model.block_openai_model_requests]
-on = "model.request"
-if = 'model.provider == "openai"'
-decision = "block"
-priority = -10
-reason = "Corporate policy disables OpenAI model calls for this workspace."
-
-[security.rules.http.block_openai_http]
-on = "http.request"
-if = 'http.request.host.matches("(^|\\.)openai\\.com\\.?$")'
-decision = "block"
-priority = -9
-reason = "Corporate policy blocks OpenAI HTTP/S domains."
-
-[security.rules.http.block_openclaw_http]
-on = "http.request"
-if = 'http.request.host == "github.com" && http.request.path.matches("^/openclaw(/|$)")'
-decision = "block"
-priority = -8
-reason = "Corporate policy blocks the OpenClaw GitHub namespace at the HTTP layer."
diff --git a/config/docker/Dockerfile.kernel.j2 b/config/docker/Dockerfile.kernel.j2
new file mode 100644
index 000000000..349a61c43
--- /dev/null
+++ b/config/docker/Dockerfile.kernel.j2
@@ -0,0 +1,65 @@
+# Compile a hardened, minimal kernel for capsem VM virtualization.
+# Architecture: {{ arch_name }} ({{ arch.docker_platform }})
+# Produces vmlinuz and initrd.img with busybox + capsem-init.
+#
+# The kernel is compiled from source with a custom defconfig that:
+# - Enables only VirtIO drivers (the only hardware in the VM)
+# - Disables loadable modules (CONFIG_MODULES=n)
+# - Enables KASLR, stack protector, FORTIFY_SOURCE
+#
+# Generated by capsem-builder from profile-derived image inputs.
+
+FROM --platform={{ arch.docker_platform }} {{ arch.base_image }} AS build
+
+ARG KERNEL_VERSION={{ kernel_version }}
+
+# Install build tools
+RUN apt-get -o Acquire::Check-Valid-Until=false -o Acquire::Check-Date=false update && \
+ apt-get install -y --no-install-recommends \
+ build-essential bc bison flex libssl-dev libelf-dev \
+ wget ca-certificates xz-utils cpio \
+ busybox-static && \
+ rm -rf /var/lib/apt/lists/*
+
+# Download kernel source
+RUN MAJOR=$(echo ${KERNEL_VERSION} | cut -d. -f1) && \
+ wget -q "https://cdn.kernel.org/pub/linux/kernel/v${MAJOR}.x/linux-${KERNEL_VERSION}.tar.xz" \
+ -O /tmp/linux.tar.xz && \
+ tar xf /tmp/linux.tar.xz -C /usr/src && \
+ rm /tmp/linux.tar.xz && \
+ ln -s /usr/src/linux-${KERNEL_VERSION} /usr/src/linux
+
+WORKDIR /usr/src/linux
+
+# Apply capsem hardened defconfig (allnoconfig base + our overrides)
+COPY {{ arch.defconfig }} .config
+RUN make olddefconfig
+
+# Compile kernel
+RUN make -j$(nproc) {{ arch.kernel_image | replace('arch/' ~ arch_name ~ '/boot/', '') }} && \
+ ls -lh {{ arch.kernel_image }}
+
+# ---- Build minimal initrd with busybox + capsem-init ----
+COPY capsem-init /tmp/capsem-init
+RUN mkdir -p /tmp/initrd/bin /tmp/initrd/sbin /tmp/initrd/dev /tmp/initrd/proc \
+ /tmp/initrd/sys /tmp/initrd/newroot /tmp/initrd/tmp /tmp/initrd/conf \
+ /tmp/initrd/dev/pts /tmp/initrd/var/log /tmp/initrd/var/tmp && \
+ # Busybox-static provides all userspace tools capsem-init needs
+ cp /usr/bin/busybox /tmp/initrd/bin/busybox && \
+ for cmd in sh mount umount mkdir rmdir sleep ls echo cat chmod cp ln \
+ chroot mknod mv rm find grep sed awk; do \
+ ln -s busybox /tmp/initrd/bin/$cmd; \
+ done && \
+ for cmd in modprobe; do \
+ ln -s ../bin/busybox /tmp/initrd/sbin/$cmd; \
+ done && \
+ cp /tmp/capsem-init /tmp/initrd/init && \
+ chmod 755 /tmp/initrd/init && \
+ cd /tmp/initrd && \
+ find . | cpio -o -H newc 2>/dev/null | gzip > /tmp/initrd.img && \
+ echo "initrd.img: $(ls -lh /tmp/initrd.img | awk '{print $5}')"
+
+# ---- Output stage ----
+FROM scratch AS output
+COPY --from=build /usr/src/linux/{{ arch.kernel_image }} /vmlinuz
+COPY --from=build /tmp/initrd.img /initrd.img
diff --git a/src/capsem/builder/templates/Dockerfile.rootfs.j2 b/config/docker/Dockerfile.rootfs.j2
similarity index 89%
rename from src/capsem/builder/templates/Dockerfile.rootfs.j2
rename to config/docker/Dockerfile.rootfs.j2
index 47e1f9db4..6b03bee73 100644
--- a/src/capsem/builder/templates/Dockerfile.rootfs.j2
+++ b/config/docker/Dockerfile.rootfs.j2
@@ -2,7 +2,7 @@
# Contains developer tools, runtimes, and AI coding CLIs.
# Mounted read-only at boot; only /root is writable (tmpfs).
# Architecture: {{ arch_name }} ({{ arch.docker_platform }})
-# Generated by capsem-builder from guest/config/ TOML files.
+# Generated by capsem-builder from profile-derived image inputs.
FROM --platform={{ arch.docker_platform }} {{ arch.base_image }}
@@ -13,6 +13,8 @@ RUN apt-get -o Acquire::Check-Valid-Until=false -o Acquire::Check-Date=false upd
apt-get install -y --no-install-recommends \
{{ apt_packages | join(' \\\n ') }} && \
ln -sf vim.tiny /usr/bin/vim && \
+ rm -f /usr/sbin/iptables-legacy /usr/sbin/iptables-legacy-restore /usr/sbin/iptables-legacy-save \
+ /usr/sbin/ip6tables-legacy /usr/sbin/ip6tables-legacy-restore /usr/sbin/ip6tables-legacy-save && \
pip3 install --break-system-packages --upgrade pip
# Node.js {{ arch.node_major }} LTS via nvm (Debian bookworm ships v18 which lacks the 'v'
@@ -39,6 +41,11 @@ RUN npm install -g --prefix {{ npm_prefix }} \
ENV PATH="{{ npm_prefix }}/bin:$PATH"
{% endif %}
+{% if profile_build_script %}
+COPY profile-build.sh /tmp/profile-build.sh
+RUN chmod 555 /tmp/profile-build.sh && /tmp/profile-build.sh && rm -f /tmp/profile-build.sh
+{% endif %}
+
# Install MITM CA certificate into system trust store
# (copied into build context by capsem-builder before docker build)
COPY capsem-ca.crt /usr/local/share/ca-certificates/capsem-ca.crt
@@ -59,6 +66,10 @@ RUN chmod 555 /usr/local/bin/{{ binary }}
COPY capsem-bashrc /etc/capsem-bashrc
COPY banner.txt /etc/capsem-banner.txt
COPY tips.txt /etc/capsem-tips.txt
+{% if profile_root_seed %}
+COPY profile-root/ /usr/local/share/capsem/profile-root/
+RUN chmod -R go-rwx /usr/local/share/capsem/profile-root
+{% endif %}
{% if python_packages %}
# Common Python packages (pre-installed so they're available immediately).
diff --git a/guest/config/build.toml b/config/docker/image/build.toml
similarity index 85%
rename from guest/config/build.toml
rename to config/docker/image/build.toml
index eecbd9bd4..4d05b4e07 100644
--- a/guest/config/build.toml
+++ b/config/docker/image/build.toml
@@ -1,7 +1,11 @@
[build]
compression = "zstd"
compression_level = 15
-squashfs_block_size = "128K"
+
+[build.erofs]
+enabled = true
+compression = "lz4hc"
+compression_level = 12
[build.version_commands]
node = "node --version 2>&1 | tr -d v"
@@ -13,7 +17,7 @@ pip = "pip3 --version 2>&1 | awk '{print $2}'"
base_image = "debian:bookworm-slim"
docker_platform = "linux/arm64"
rust_target = "aarch64-unknown-linux-musl"
-kernel_branch = "6.6"
+kernel_branch = "7.0"
kernel_image = "arch/arm64/boot/Image"
defconfig = "kernel/defconfig.arm64"
node_major = 24
@@ -22,7 +26,7 @@ node_major = 24
base_image = "debian:bookworm-slim"
docker_platform = "linux/amd64"
rust_target = "x86_64-unknown-linux-musl"
-kernel_branch = "6.6"
+kernel_branch = "7.0"
kernel_image = "arch/x86_64/boot/bzImage"
defconfig = "kernel/defconfig.x86_64"
node_major = 24
diff --git a/guest/config/kernel/defconfig.arm64 b/config/docker/image/kernel/defconfig.arm64
similarity index 89%
rename from guest/config/kernel/defconfig.arm64
rename to config/docker/image/kernel/defconfig.arm64
index 24ae86485..dc4385f0e 100644
--- a/guest/config/kernel/defconfig.arm64
+++ b/config/docker/image/kernel/defconfig.arm64
@@ -18,17 +18,6 @@ CONFIG_ARM_GIC_V3=y
CONFIG_ARM_ARCH_TIMER=y
CONFIG_OF=y
-# Userspace virtual address space.
-#
-# Google Antigravity CLI's Linux ARM64 binary uses TCMalloc and assumes a
-# 48-bit userspace VA layout. The allnoconfig ARM64 default is a smaller
-# 39-bit layout with 4K pages, which boots fine but makes that binary crash
-# before it can print --version. Keep 4K pages for ordinary Linux userland
-# compatibility and move to 4-level, 48-bit VA tables.
-CONFIG_ARM64_4K_PAGES=y
-CONFIG_ARM64_VA_BITS_48=y
-CONFIG_ARM64_VA_BITS=48
-
# ARM64 hardware security (Apple Silicon supports BTI + PAC)
CONFIG_ARM64_BTI=y
CONFIG_ARM64_PTR_AUTH=y
@@ -80,6 +69,9 @@ CONFIG_EXT4_FS=y
CONFIG_EXT4_USE_FOR_EXT2=y
CONFIG_SQUASHFS=y
CONFIG_SQUASHFS_ZSTD=y
+CONFIG_EROFS_FS=y
+CONFIG_EROFS_FS_ZIP=y
+CONFIG_EROFS_FS_ZIP_ZSTD=y
CONFIG_OVERLAY_FS=y
CONFIG_OVERLAY_FS_REDIRECT_DIR=y
CONFIG_OVERLAY_FS_INDEX=y
@@ -117,19 +109,19 @@ CONFIG_DUMMY=y
CONFIG_ETHERNET=n
CONFIG_NET_VENDOR_VIRTIO=n
-# Netfilter/iptables: REDIRECT target for transparent proxy
+# Netfilter/iptables-nft: REDIRECT target for transparent proxy
CONFIG_NETFILTER=y
CONFIG_NETFILTER_ADVANCED=y
CONFIG_NF_CONNTRACK=y
CONFIG_NF_NAT=y
-CONFIG_NF_TABLES=n
-CONFIG_IP_NF_IPTABLES=y
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_NAT=y
-CONFIG_NF_NAT_REDIRECT=y
+CONFIG_NF_TABLES=y
+CONFIG_NF_TABLES_IPV4=y
+CONFIG_NFT_NAT=y
+CONFIG_NFT_REDIR=y
CONFIG_NETFILTER_XTABLES=y
+CONFIG_NFT_COMPAT=y
CONFIG_NETFILTER_XT_TARGET_REDIRECT=y
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NF_NAT_REDIRECT=y
# ==========================================
# 8. PROCESS MANAGEMENT
diff --git a/guest/config/kernel/defconfig.x86_64 b/config/docker/image/kernel/defconfig.x86_64
similarity index 95%
rename from guest/config/kernel/defconfig.x86_64
rename to config/docker/image/kernel/defconfig.x86_64
index d5680d964..11e5afeaa 100644
--- a/guest/config/kernel/defconfig.x86_64
+++ b/config/docker/image/kernel/defconfig.x86_64
@@ -36,8 +36,6 @@ CONFIG_PCI_HOST_GENERIC=y
CONFIG_VIRTIO_MENU=y
CONFIG_VIRTIO=y
CONFIG_VIRTIO_PCI=y
-CONFIG_VIRTIO_MMIO=y
-CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
CONFIG_VIRTIO_CONSOLE=y
CONFIG_VIRTIO_BLK=y
CONFIG_HW_RANDOM=y
@@ -67,6 +65,9 @@ CONFIG_EXT4_FS=y
CONFIG_EXT4_USE_FOR_EXT2=y
CONFIG_SQUASHFS=y
CONFIG_SQUASHFS_ZSTD=y
+CONFIG_EROFS_FS=y
+CONFIG_EROFS_FS_ZIP=y
+CONFIG_EROFS_FS_ZIP_ZSTD=y
CONFIG_OVERLAY_FS=y
CONFIG_OVERLAY_FS_REDIRECT_DIR=y
CONFIG_OVERLAY_FS_INDEX=y
@@ -104,19 +105,19 @@ CONFIG_DUMMY=y
CONFIG_ETHERNET=n
CONFIG_NET_VENDOR_VIRTIO=n
-# Netfilter/iptables: REDIRECT target for transparent proxy
+# Netfilter/iptables-nft: REDIRECT target for transparent proxy
CONFIG_NETFILTER=y
CONFIG_NETFILTER_ADVANCED=y
CONFIG_NF_CONNTRACK=y
CONFIG_NF_NAT=y
-CONFIG_NF_TABLES=n
-CONFIG_IP_NF_IPTABLES=y
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_NAT=y
-CONFIG_NF_NAT_REDIRECT=y
+CONFIG_NF_TABLES=y
+CONFIG_NF_TABLES_IPV4=y
+CONFIG_NFT_NAT=y
+CONFIG_NFT_REDIR=y
CONFIG_NETFILTER_XTABLES=y
+CONFIG_NFT_COMPAT=y
CONFIG_NETFILTER_XT_TARGET_REDIRECT=y
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NF_NAT_REDIRECT=y
# ==========================================
# 8. PROCESS MANAGEMENT
diff --git a/guest/config/manifest.toml b/config/docker/image/manifest.toml
similarity index 100%
rename from guest/config/manifest.toml
rename to config/docker/image/manifest.toml
diff --git a/guest/config/security/web.toml b/config/docker/image/security/web.toml
similarity index 88%
rename from guest/config/security/web.toml
rename to config/docker/image/security/web.toml
index 5663c4295..13e69ec6c 100644
--- a/guest/config/security/web.toml
+++ b/config/docker/image/security/web.toml
@@ -1,8 +1,5 @@
[web]
-allow_read = false
-allow_write = false
-custom_allow = ["elie.net", "*.elie.net", "en.wikipedia.org", "*.wikipedia.org"]
-custom_block = []
+http_upstream_ports = [80, 3128, 3713, 8080, 11434]
[web.search.google]
name = "Google"
diff --git a/guest/config/vm/environment.toml b/config/docker/image/vm/environment.toml
similarity index 100%
rename from guest/config/vm/environment.toml
rename to config/docker/image/vm/environment.toml
diff --git a/config/genai-prices.json b/config/genai-prices.json
deleted file mode 100644
index b67f1ed21..000000000
--- a/config/genai-prices.json
+++ /dev/null
@@ -1 +0,0 @@
-[{"id":"anthropic","name":"Anthropic","pricing_urls":["https://www.anthropic.com/pricing#api"],"api_pattern":"https://api\\.anthropic\\.com","model_match":{"contains":"claude"},"provider_match":{"contains":"anthropic"},"extractors":[{"api_flavor":"default","root":"usage","model_path":"model","mappings":[{"path":"input_tokens","dest":"input_tokens","required":true},{"path":"cache_creation_input_tokens","dest":"input_tokens","required":false},{"path":"cache_read_input_tokens","dest":"input_tokens","required":false},{"path":"cache_creation_input_tokens","dest":"cache_write_tokens","required":false},{"path":"cache_read_input_tokens","dest":"cache_read_tokens","required":false},{"path":"output_tokens","dest":"output_tokens","required":true}]},{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":"cached_tokens","dest":"cache_read_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"claude-2","match":{"or":[{"starts_with":"claude-2"},{"contains":"claude-v2"}]},"context_window":200000,"prices":{"input_mtok":8,"output_mtok":24}},{"id":"claude-3-5-haiku-latest","match":{"or":[{"starts_with":"claude-3-5-haiku"},{"starts_with":"claude-3.5-haiku"}]},"context_window":200000,"prices":{"input_mtok":0.8,"cache_write_mtok":1,"cache_read_mtok":0.08,"output_mtok":4}},{"id":"claude-3-5-sonnet","match":{"or":[{"starts_with":"claude-3-5-sonnet"},{"starts_with":"claude-3.5-sonnet"}]},"context_window":200000,"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"claude-3-7-sonnet-latest","match":{"or":[{"starts_with":"claude-3-7-sonnet"},{"starts_with":"claude-3.7-sonnet"},{"starts_with":"claude-sonnet-3.7"},{"starts_with":"claude-sonnet-3-7"}]},"context_window":200000,"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"claude-3-haiku","match":{"starts_with":"claude-3-haiku"},"context_window":200000,"prices":{"input_mtok":0.25,"cache_write_mtok":0.3,"cache_read_mtok":0.03,"output_mtok":1.25}},{"id":"claude-3-opus-latest","match":{"starts_with":"claude-3-opus"},"context_window":200000,"prices":{"input_mtok":15,"cache_write_mtok":18.75,"cache_read_mtok":1.5,"output_mtok":75}},{"id":"claude-3-sonnet","match":{"starts_with":"claude-3-sonnet"},"context_window":200000,"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"claude-haiku-4-5","match":{"or":[{"starts_with":"claude-haiku-4-5"},{"starts_with":"claude-haiku-4.5"},{"starts_with":"claude-4-5-haiku"},{"starts_with":"claude-4.5-haiku"}]},"context_window":200000,"prices":{"input_mtok":1,"cache_write_mtok":1.25,"cache_read_mtok":0.1,"output_mtok":5}},{"id":"claude-opus-4-0","match":{"or":[{"starts_with":"claude-opus-4-0"},{"starts_with":"claude-4-opus"},{"equals":"claude-opus-4"},{"equals":"claude-opus-4-20250514"}]},"context_window":200000,"prices":{"input_mtok":15,"cache_write_mtok":18.75,"cache_read_mtok":1.5,"output_mtok":75}},{"id":"claude-opus-4-1","match":{"or":[{"starts_with":"claude-opus-4-1"},{"starts_with":"claude-opus-4.1"}]},"context_window":200000,"prices":{"input_mtok":15,"cache_write_mtok":18.75,"cache_read_mtok":1.5,"output_mtok":75}},{"id":"claude-opus-4-5","match":{"or":[{"starts_with":"claude-opus-4-5"},{"starts_with":"claude-opus-4.5"},{"starts_with":"claude-4-5-opus"},{"starts_with":"claude-4.5-opus"}]},"context_window":200000,"prices":{"input_mtok":5,"cache_write_mtok":6.25,"cache_read_mtok":0.5,"output_mtok":25}},{"id":"claude-opus-4-6","match":{"or":[{"starts_with":"claude-opus-4-6"},{"starts_with":"claude-opus-4.6"},{"starts_with":"claude-4-6-opus"},{"starts_with":"claude-4.6-opus"}]},"context_window":200000,"prices":{"input_mtok":{"base":5,"tiers":[{"start":200000,"price":10}]},"cache_write_mtok":{"base":6.25,"tiers":[{"start":200000,"price":12.5}]},"cache_read_mtok":{"base":0.5,"tiers":[{"start":200000,"price":1}]},"output_mtok":{"base":25,"tiers":[{"start":200000,"price":37.5}]}}},{"id":"claude-sonnet-4-0","match":{"or":[{"starts_with":"claude-sonnet-4-2025"},{"starts_with":"claude-sonnet-4-0"},{"starts_with":"claude-sonnet-4@"},{"equals":"claude-sonnet-4"},{"starts_with":"claude-4-sonnet"}]},"context_window":200000,"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"claude-sonnet-4-5","match":{"or":[{"starts_with":"claude-sonnet-4-5"},{"starts_with":"claude-sonnet-4.5"}]},"context_window":1000000,"prices":{"input_mtok":{"base":3,"tiers":[{"start":200000,"price":6}]},"cache_write_mtok":{"base":3.75,"tiers":[{"start":200000,"price":7.5}]},"cache_read_mtok":{"base":0.3,"tiers":[{"start":200000,"price":0.6}]},"output_mtok":{"base":15,"tiers":[{"start":200000,"price":22.5}]}}},{"id":"claude-sonnet-4-6","match":{"or":[{"starts_with":"claude-sonnet-4-6"},{"starts_with":"claude-sonnet-4.6"}]},"context_window":1000000,"prices":{"input_mtok":{"base":3,"tiers":[{"start":200000,"price":6}]},"cache_write_mtok":{"base":3.75,"tiers":[{"start":200000,"price":7.5}]},"cache_read_mtok":{"base":0.3,"tiers":[{"start":200000,"price":0.6}]},"output_mtok":{"base":15,"tiers":[{"start":200000,"price":22.5}]}}},{"id":"claude-v1","match":{"equals":"claude-v1"},"prices":{"input_mtok":8,"output_mtok":24}}]},{"id":"avian","name":"Avian","pricing_urls":["https://avian.io/pricing/"],"api_pattern":"https://api\\.avian\\.io","models":[{"id":"Meta-Llama-3.1-405B-Instruct","match":{"equals":"Meta-Llama-3.1-405B-Instruct"},"prices":{"input_mtok":1.5,"output_mtok":1.5}},{"id":"Meta-Llama-3.1-70B-Instruct","match":{"equals":"Meta-Llama-3.1-70B-Instruct"},"prices":{"input_mtok":0.45,"output_mtok":0.45}},{"id":"Meta-Llama-3.1-8B-Instruct","match":{"equals":"Meta-Llama-3.1-8B-Instruct"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"Meta-Llama-3.3-70B-Instruct","match":{"equals":"Meta-Llama-3.3-70B-Instruct"},"prices":{"input_mtok":0.45,"output_mtok":0.45}}]},{"id":"aws","name":"AWS Bedrock","pricing_urls":["https://aws.amazon.com/bedrock/pricing/"],"api_pattern":"https://bedrock-runtime\\.[a-z0-9-]+\\.amazonaws\\.com/","provider_match":{"contains":"bedrock"},"extractors":[{"api_flavor":"default","root":"usage","model_path":"model","mappings":[{"path":"inputTokens","dest":"input_tokens","required":true},{"path":"outputTokens","dest":"output_tokens","required":true}]},{"api_flavor":"anthropic","root":"usage","model_path":"model","mappings":[{"path":"input_tokens","dest":"input_tokens","required":true},{"path":"cache_creation_input_tokens","dest":"input_tokens","required":false},{"path":"cache_read_input_tokens","dest":"input_tokens","required":false},{"path":"cache_creation_input_tokens","dest":"cache_write_tokens","required":false},{"path":"cache_read_input_tokens","dest":"cache_read_tokens","required":false},{"path":"output_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"amazon.nova-lite-v1:0","match":{"contains":"amazon.nova-lite-v1"},"prices":{"input_mtok":0.06,"cache_read_mtok":0.015,"output_mtok":0.24}},{"id":"amazon.nova-micro-v1:0","match":{"contains":"amazon.nova-micro-v1"},"prices":{"input_mtok":0.035,"cache_read_mtok":0.00875,"output_mtok":0.14}},{"id":"amazon.nova-premier-v1:0","match":{"contains":"amazon.nova-premier-v1"},"prices":{"input_mtok":2.5,"cache_read_mtok":0.625,"output_mtok":12.5}},{"id":"amazon.nova-pro-v1:0","match":{"contains":"amazon.nova-pro-v1"},"prices":{"input_mtok":0.8,"cache_read_mtok":0.2,"output_mtok":3.2}},{"id":"amazon.nova-sonic-v1:0","match":{"contains":"amazon.nova-sonic-v1"},"prices":{"input_mtok":0.06,"output_mtok":0.24,"input_audio_mtok":3.4,"output_audio_mtok":13.6}},{"id":"amazon.titan-embed-text-v1","match":{"contains":"amazon.titan-embed-text-v1"},"prices":{"input_mtok":0.1}},{"id":"amazon.titan-text-express-v1","match":{"contains":"titan-text-express"},"prices":{"input_mtok":0.2,"output_mtok":0.6}},{"id":"amazon.titan-text-lite-v1","match":{"contains":"titan-text-lite"},"prices":{"input_mtok":0.15,"output_mtok":0.2}},{"id":"deepseek.r1-v1:0","match":{"contains":"deepseek.r1-v1"},"prices":{"input_mtok":1.35,"output_mtok":5.4}},{"id":"global.anthropic.claude-haiku-4-5-20251001-v1:0","match":{"contains":"global.anthropic.claude-haiku-4-5-20251001-v1"},"prices":{"input_mtok":1,"cache_write_mtok":1.25,"cache_read_mtok":0.1,"output_mtok":5}},{"id":"global.anthropic.claude-opus-4-5-v1:0","match":{"contains":"global.anthropic.claude-opus-4-5"},"prices":{"input_mtok":5,"cache_write_mtok":6.25,"cache_read_mtok":0.5,"output_mtok":25}},{"id":"global.anthropic.claude-opus-4-6-v1:0","match":{"contains":"global.anthropic.claude-opus-4-6"},"prices":{"input_mtok":{"base":5,"tiers":[{"start":200000,"price":10}]},"cache_write_mtok":{"base":6.25,"tiers":[{"start":200000,"price":12.5}]},"cache_read_mtok":{"base":0.5,"tiers":[{"start":200000,"price":1}]},"output_mtok":{"base":25,"tiers":[{"start":200000,"price":37.5}]}}},{"id":"global.anthropic.claude-sonnet-4-20250514-v1:0","match":{"contains":"global.anthropic.claude-sonnet-4-20250514-v1"},"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"global.anthropic.claude-sonnet-4-5-20250929-v1:0","match":{"contains":"global.anthropic.claude-sonnet-4-5-20250929-v1"},"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"global.anthropic.claude-sonnet-4-6-v1:0","match":{"contains":"global.anthropic.claude-sonnet-4-6"},"prices":{"input_mtok":{"base":3,"tiers":[{"start":200000,"price":6}]},"cache_write_mtok":{"base":3.75,"tiers":[{"start":200000,"price":7.5}]},"cache_read_mtok":{"base":0.3,"tiers":[{"start":200000,"price":0.6}]},"output_mtok":{"base":15,"tiers":[{"start":200000,"price":22.5}]}}},{"id":"meta.llama3-1-70b-instruct-v1:0","match":{"contains":"meta.llama3-1-70b-instruct-v1"},"prices":{"input_mtok":0.72,"output_mtok":0.72}},{"id":"meta.llama3-1-8b-instruct-v1:0","match":{"contains":"meta.llama3-1-8b-instruct-v1"},"prices":{"input_mtok":0.22,"output_mtok":0.22}},{"id":"meta.llama3-2-11b-instruct-v1:0","match":{"contains":"meta.llama3-2-11b-instruct-v1"},"prices":{"input_mtok":0.16,"output_mtok":0.16}},{"id":"meta.llama3-2-1b-instruct-v1:0","match":{"contains":"meta.llama3-2-1b-instruct-v1"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"meta.llama3-2-3b-instruct-v1:0","match":{"contains":"meta.llama3-2-3b-instruct-v1"},"prices":{"input_mtok":0.15,"output_mtok":0.15}},{"id":"meta.llama3-2-90b-instruct-v1:0","match":{"contains":"meta.llama3-2-90b-instruct-v1"},"prices":{"input_mtok":0.72,"output_mtok":0.72}},{"id":"meta.llama3-3-70b-instruct-v1:0","match":{"contains":"meta.llama3-3-70b-instruct-v1"},"prices":{"input_mtok":0.72,"output_mtok":0.72}},{"id":"meta.llama3-70b-instruct-v1:0","match":{"contains":"meta.llama3-70b-instruct-v1"},"prices":{"input_mtok":2.65,"output_mtok":3.5}},{"id":"meta.llama3-8b-instruct-v1:0","match":{"contains":"meta.llama3-8b-instruct-v1"},"prices":{"input_mtok":0.3,"output_mtok":0.6}},{"id":"meta.llama4-maverick-17b-instruct-v1:0","match":{"contains":"meta.llama4-maverick-17b-instruct-v1"},"prices":{"input_mtok":0.24,"output_mtok":0.97}},{"id":"meta.llama4-scout-17b-instruct-v1:0","match":{"contains":"meta.llama4-scout-17b-instruct-v1"},"prices":{"input_mtok":0.17,"output_mtok":0.66}},{"id":"mistral.mistral-7b-instruct-v0:2","match":{"contains":"mistral.mistral-7b-instruct-v0"},"prices":{"input_mtok":0.15,"output_mtok":0.2}},{"id":"mistral.mistral-large-2402-v1:0","match":{"contains":"mistral.mistral-large-2402-v1"},"prices":{"input_mtok":4,"output_mtok":12}},{"id":"mistral.mistral-small-2402-v1:0","match":{"contains":"mistral.mistral-small-2402-v1"},"prices":{"input_mtok":1,"output_mtok":3}},{"id":"mistral.mixtral-8x7b-instruct-v0:1","match":{"contains":"mistral.mixtral-8x7b-instruct-v0"},"prices":{"input_mtok":0.45,"output_mtok":0.7}},{"id":"mistral.pixtral-large-2502-v1:0","match":{"contains":"mistral.pixtral-large-2502-v1"},"prices":{"input_mtok":2,"output_mtok":6}},{"id":"openai.gpt-oss-120b-1:0","match":{"contains":"openai.gpt-oss-120b-1"},"prices":{"input_mtok":0.15,"output_mtok":0.6}},{"id":"openai.gpt-oss-20b-1:0","match":{"contains":"openai.gpt-oss-20b-1"},"prices":{"input_mtok":0.07,"output_mtok":0.3}},{"id":"qwen.qwen3-32b-v1:0","match":{"contains":"qwen.qwen3-32b-v1"},"prices":{"input_mtok":0.15,"output_mtok":0.6}},{"id":"qwen.qwen3-coder-30b-a3b-v1:0","match":{"contains":"qwen.qwen3-coder-30b-a3b-v1"},"prices":{"input_mtok":0.15,"output_mtok":0.6}},{"id":"qwen.qwen3-coder-480b-a35b-v1:0","match":{"contains":"qwen.qwen3-coder-480b-a35b-v1"},"prices":{"input_mtok":0.45,"output_mtok":1.8}},{"id":"regional.anthropic.claude-3-5-haiku-20241022-v1:0","match":{"or":[{"contains":"us.anthropic.claude-3-5-haiku-20241022-v1"},{"contains":"au.anthropic.claude-3-5-haiku-20241022-v1"},{"contains":"apac.anthropic.claude-3-5-haiku-20241022-v1"},{"contains":"eu.anthropic.claude-3-5-haiku-20241022-v1"},{"contains":"us-gov.anthropic.claude-3-5-haiku-20241022-v1"},{"contains":"jp.anthropic.claude-3-5-haiku-20241022-v1"}]},"prices":{"input_mtok":0.8,"cache_write_mtok":1,"cache_read_mtok":0.08,"output_mtok":4}},{"id":"regional.anthropic.claude-3-5-sonnet-20240620-v1:0","match":{"or":[{"contains":"us.anthropic.claude-3-5-sonnet-20240620-v1"},{"contains":"au.anthropic.claude-3-5-sonnet-20240620-v1"},{"contains":"apac.anthropic.claude-3-5-sonnet-20240620-v1"},{"contains":"eu.anthropic.claude-3-5-sonnet-20240620-v1"},{"contains":"us-gov.anthropic.claude-3-5-sonnet-20240620-v1"},{"contains":"jp.anthropic.claude-3-5-sonnet-20240620-v1"}]},"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"regional.anthropic.claude-3-5-sonnet-20241022-v2:0","match":{"or":[{"contains":"us.anthropic.claude-3-5-sonnet-20241022-v2"},{"contains":"au.anthropic.claude-3-5-sonnet-20241022-v2"},{"contains":"apac.anthropic.claude-3-5-sonnet-20241022-v2"},{"contains":"eu.anthropic.claude-3-5-sonnet-20241022-v2"},{"contains":"us-gov.anthropic.claude-3-5-sonnet-20241022-v2"},{"contains":"jp.anthropic.claude-3-5-sonnet-20241022-v2"}]},"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"regional.anthropic.claude-3-7-sonnet-20250219-v1:0","match":{"or":[{"contains":"us.anthropic.claude-3-7-sonnet-20250219-v1"},{"contains":"au.anthropic.claude-3-7-sonnet-20250219-v1"},{"contains":"apac.anthropic.claude-3-7-sonnet-20250219-v1"},{"contains":"eu.anthropic.claude-3-7-sonnet-20250219-v1"},{"contains":"us-gov.anthropic.claude-3-7-sonnet-20250219-v1"},{"contains":"jp.anthropic.claude-3-7-sonnet-20250219-v1"}]},"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"regional.anthropic.claude-3-haiku-20240307-v1:0","match":{"or":[{"contains":"us.anthropic.claude-3-haiku-20240307-v1"},{"contains":"au.anthropic.claude-3-haiku-20240307-v1"},{"contains":"apac.anthropic.claude-3-haiku-20240307-v1"},{"contains":"eu.anthropic.claude-3-haiku-20240307-v1"},{"contains":"us-gov.anthropic.claude-3-haiku-20240307-v1"},{"contains":"jp.anthropic.claude-3-haiku-20240307-v1"}]},"prices":{"input_mtok":0.25,"output_mtok":1.25}},{"id":"regional.anthropic.claude-3-opus-20240229-v1:0","match":{"or":[{"contains":"us.anthropic.claude-3-opus-20240229-v1"},{"contains":"au.anthropic.claude-3-opus-20240229-v1"},{"contains":"apac.anthropic.claude-3-opus-20240229-v1"},{"contains":"eu.anthropic.claude-3-opus-20240229-v1"},{"contains":"us-gov.anthropic.claude-3-opus-20240229-v1"},{"contains":"jp.anthropic.claude-3-opus-20240229-v1"}]},"prices":{"input_mtok":15,"output_mtok":75}},{"id":"regional.anthropic.claude-3-sonnet-20240229-v1:0","match":{"or":[{"contains":"us.anthropic.claude-3-sonnet-20240229-v1"},{"contains":"au.anthropic.claude-3-sonnet-20240229-v1"},{"contains":"apac.anthropic.claude-3-sonnet-20240229-v1"},{"contains":"eu.anthropic.claude-3-sonnet-20240229-v1"},{"contains":"us-gov.anthropic.claude-3-sonnet-20240229-v1"},{"contains":"jp.anthropic.claude-3-sonnet-20240229-v1"}]},"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"regional.anthropic.claude-haiku-4-5-20251001-v1:0","match":{"or":[{"contains":"us.anthropic.claude-haiku-4-5-20251001-v1"},{"contains":"au.anthropic.claude-haiku-4-5-20251001-v1"},{"contains":"apac.anthropic.claude-haiku-4-5-20251001-v1"},{"contains":"eu.anthropic.claude-haiku-4-5-20251001-v1"},{"contains":"us-gov.anthropic.claude-haiku-4-5-20251001-v1"},{"contains":"jp.anthropic.claude-haiku-4-5-20251001-v1"}]},"prices":{"input_mtok":1.1,"cache_write_mtok":1.375,"cache_read_mtok":0.11,"output_mtok":5.5}},{"id":"regional.anthropic.claude-opus-4-1-20250805-v1:0","match":{"or":[{"contains":"us.anthropic.claude-opus-4-1-20250805-v1"},{"contains":"au.anthropic.claude-opus-4-1-20250805-v1"},{"contains":"apac.anthropic.claude-opus-4-1-20250805-v1"},{"contains":"eu.anthropic.claude-opus-4-1-20250805-v1"},{"contains":"us-gov.anthropic.claude-opus-4-1-20250805-v1"},{"contains":"jp.anthropic.claude-opus-4-1-20250805-v1"}]},"prices":{"input_mtok":15,"cache_write_mtok":18.75,"cache_read_mtok":1.5,"output_mtok":75}},{"id":"regional.anthropic.claude-opus-4-20250514-v1:0","match":{"or":[{"contains":"us.anthropic.claude-opus-4-20250514-v1"},{"contains":"au.anthropic.claude-opus-4-20250514-v1"},{"contains":"apac.anthropic.claude-opus-4-20250514-v1"},{"contains":"eu.anthropic.claude-opus-4-20250514-v1"},{"contains":"us-gov.anthropic.claude-opus-4-20250514-v1"},{"contains":"jp.anthropic.claude-opus-4-20250514-v1"}]},"prices":{"input_mtok":15,"cache_write_mtok":18.75,"cache_read_mtok":1.5,"output_mtok":75}},{"id":"regional.anthropic.claude-opus-4-5-v1:0","match":{"or":[{"contains":"us.anthropic.claude-opus-4-5"},{"contains":"au.anthropic.claude-opus-4-5"},{"contains":"apac.anthropic.claude-opus-4-5"},{"contains":"eu.anthropic.claude-opus-4-5"},{"contains":"us-gov.anthropic.claude-opus-4-5"},{"contains":"jp.anthropic.claude-opus-4-5"}]},"prices":{"input_mtok":5.5,"cache_write_mtok":6.875,"cache_read_mtok":0.55,"output_mtok":27.5}},{"id":"regional.anthropic.claude-opus-4-6-v1:0","match":{"or":[{"contains":"us.anthropic.claude-opus-4-6"},{"contains":"au.anthropic.claude-opus-4-6"},{"contains":"apac.anthropic.claude-opus-4-6"},{"contains":"eu.anthropic.claude-opus-4-6"},{"contains":"us-gov.anthropic.claude-opus-4-6"},{"contains":"jp.anthropic.claude-opus-4-6"}]},"prices":{"input_mtok":{"base":5.5,"tiers":[{"start":200000,"price":11}]},"cache_write_mtok":{"base":6.875,"tiers":[{"start":200000,"price":13.75}]},"cache_read_mtok":{"base":0.55,"tiers":[{"start":200000,"price":1.1}]},"output_mtok":{"base":27.5,"tiers":[{"start":200000,"price":41.25}]}}},{"id":"regional.anthropic.claude-sonnet-4-20250514-v1:0","match":{"or":[{"contains":"us.anthropic.claude-sonnet-4-20250514-v1"},{"contains":"au.anthropic.claude-sonnet-4-20250514-v1"},{"contains":"apac.anthropic.claude-sonnet-4-20250514-v1"},{"contains":"eu.anthropic.claude-sonnet-4-20250514-v1"},{"contains":"us-gov.anthropic.claude-sonnet-4-20250514-v1"},{"contains":"jp.anthropic.claude-sonnet-4-20250514-v1"}]},"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"regional.anthropic.claude-sonnet-4-5-20250929-v1:0","match":{"or":[{"contains":"us.anthropic.claude-sonnet-4-5-20250929-v1"},{"contains":"au.anthropic.claude-sonnet-4-5-20250929-v1"},{"contains":"apac.anthropic.claude-sonnet-4-5-20250929-v1"},{"contains":"eu.anthropic.claude-sonnet-4-5-20250929-v1"},{"contains":"us-gov.anthropic.claude-sonnet-4-5-20250929-v1"},{"contains":"jp.anthropic.claude-sonnet-4-5-20250929-v1"}]},"prices":{"input_mtok":3.3,"cache_write_mtok":4.125,"cache_read_mtok":0.33,"output_mtok":16.5}},{"id":"regional.anthropic.claude-sonnet-4-6-v1:0","match":{"or":[{"contains":"us.anthropic.claude-sonnet-4-6"},{"contains":"au.anthropic.claude-sonnet-4-6"},{"contains":"apac.anthropic.claude-sonnet-4-6"},{"contains":"eu.anthropic.claude-sonnet-4-6"},{"contains":"us-gov.anthropic.claude-sonnet-4-6"},{"contains":"jp.anthropic.claude-sonnet-4-6"}]},"prices":{"input_mtok":{"base":3.3,"tiers":[{"start":200000,"price":6.6}]},"cache_write_mtok":{"base":4.125,"tiers":[{"start":200000,"price":8.25}]},"cache_read_mtok":{"base":0.33,"tiers":[{"start":200000,"price":0.66}]},"output_mtok":{"base":16.5,"tiers":[{"start":200000,"price":24.75}]}}}]},{"id":"azure","name":"Microsoft Azure","pricing_urls":["https://azure.microsoft.com/en-us/pricing/details/cognitive-services/openai-service/#pricing"],"api_pattern":"(https?://)?([^.]*\\.)?(?:openai\\.azure\\.com|azure-api\\.net|cognitiveservices\\.azure\\.com)","extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["prompt_tokens_details","audio_tokens"],"dest":"input_audio_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]},{"api_flavor":"responses","root":"usage","model_path":"model","mappings":[{"path":"input_tokens","dest":"input_tokens","required":true},{"path":["input_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":"output_tokens","dest":"output_tokens","required":true}]},{"api_flavor":"embeddings","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true}]},{"api_flavor":"anthropic","root":"usage","model_path":"model","mappings":[{"path":"input_tokens","dest":"input_tokens","required":true},{"path":"cache_creation_input_tokens","dest":"input_tokens","required":false},{"path":"cache_read_input_tokens","dest":"input_tokens","required":false},{"path":"cache_creation_input_tokens","dest":"cache_write_tokens","required":false},{"path":"cache_read_input_tokens","dest":"cache_read_tokens","required":false},{"path":"output_tokens","dest":"output_tokens","required":true}]}],"fallback_model_providers":["openai","anthropic"],"models":[{"id":"ada","match":{"or":[{"equals":"ada"},{"equals":"text-embedding-ada"},{"equals":"text-embedding-ada-002"},{"equals":"text-embedding-ada-002-v2"}]},"prices":{"input_mtok":0.1}},{"id":"babbage","match":{"or":[{"equals":"babbage"},{"equals":"babbage-002"}]},"prices":{"input_mtok":0.4}},{"id":"curie","match":{"or":[{"equals":"curie"},{"equals":"text-curie"},{"equals":"text-curie-001"}]},"prices":{"input_mtok":2}},{"id":"davinci","match":{"or":[{"equals":"davinci"},{"equals":"davinci-002"},{"equals":"text-davinci"},{"equals":"text-davinci-002"}]},"prices":{"input_mtok":2}},{"id":"o1","match":{"or":[{"equals":"o1"},{"equals":"o1-2024-12-17"},{"equals":"o1-preview"},{"equals":"o1-preview-2024-09-12"}]},"prices":{"input_mtok":15,"cache_read_mtok":7.5,"output_mtok":60}},{"id":"o1-mini","match":{"or":[{"equals":"o1-mini"},{"equals":"o1-mini-2024-09-12"}]},"prices":{"input_mtok":1.1,"cache_read_mtok":0.55,"output_mtok":4.4}},{"id":"o3-2025-04-16","match":{"or":[{"equals":"o3"},{"equals":"o3-2025-04-16"}]},"prices":{"input_mtok":2,"cache_read_mtok":0.5,"output_mtok":8}},{"id":"o3-mini","match":{"or":[{"equals":"o3-mini"},{"equals":"o3-mini-2025-01-31"}]},"prices":{"input_mtok":1.1,"cache_read_mtok":0.55,"output_mtok":4.4}},{"id":"o4-mini","match":{"or":[{"contains":"o4-mini"},{"contains":"o4-mini-2025-04-16"}]},"prices":{"input_mtok":1.1,"cache_read_mtok":0.28,"output_mtok":4.4}},{"id":"phi-3-medium-128k-instruct","match":{"equals":"phi-3-medium-128k-instruct"},"prices":{"input_mtok":1,"output_mtok":1}},{"id":"phi-3-mini-128k-instruct","match":{"equals":"phi-3-mini-128k-instruct"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"phi-3.5-mini-128k-instruct","match":{"equals":"phi-3.5-mini-128k-instruct"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"phi-4","match":{"equals":"phi-4"},"prices":{"input_mtok":0.07,"output_mtok":0.14}},{"id":"phi-4-multimodal-instruct","match":{"equals":"phi-4-multimodal-instruct"},"prices":{"input_mtok":0.05,"output_mtok":0.1}},{"id":"phi-4-reasoning-plus","match":{"equals":"phi-4-reasoning-plus"},"prices":{"input_mtok":0.07,"output_mtok":0.35}},{"id":"text-embedding-3-large","match":{"equals":"text-embedding-3-large"},"prices":{"input_mtok":0.13}},{"id":"text-embedding-3-small","match":{"equals":"text-embedding-3-small"},"prices":{"input_mtok":0.02}},{"id":"wizardlm-2-8x22b","match":{"equals":"wizardlm-2-8x22b"},"prices":{"input_mtok":0.48,"output_mtok":0.48}}]},{"id":"cerebras","name":"Cerebras","pricing_urls":["https://www.cerebras.ai/pricing#pricing","https://inference-docs.cerebras.ai/models/openai-oss"],"api_pattern":"https://api\\.cerebras\\.ai","model_match":{"contains":"cerebras"},"provider_match":{"contains":"cerebras"},"extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"gpt-oss-120b","match":{"or":[{"equals":"gpt-oss-120b"},{"starts_with":"cerebras/gpt-oss-120b"},{"starts_with":"cerebras:gpt-oss-120b"}]},"context_window":131072,"prices":{"input_mtok":0.35,"output_mtok":0.75}},{"id":"llama-3.3-70b","match":{"or":[{"equals":"llama-3.3-70b"},{"starts_with":"cerebras/llama-3.3-70b"},{"starts_with":"cerebras:llama-3.3-70b"}]},"context_window":128000,"prices":{"input_mtok":0.85,"output_mtok":1.2}},{"id":"llama3.1-8b","match":{"or":[{"equals":"llama3.1-8b"},{"starts_with":"cerebras/llama3.1-8b"},{"starts_with":"cerebras:llama3.1-8b"}]},"context_window":32768,"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"qwen-3-32b","match":{"or":[{"equals":"qwen-3-32b"},{"starts_with":"cerebras/qwen-3-32b"},{"starts_with":"cerebras:qwen-3-32b"}]},"context_window":131072,"prices":{"input_mtok":0.4,"output_mtok":0.8}}]},{"id":"cohere","name":"Cohere","pricing_urls":["https://cohere.com/pricing"],"api_pattern":"https://api\\.cohere\\.ai","model_match":{"starts_with":"command-"},"provider_match":{"contains":"cohere"},"extractors":[{"api_flavor":"default","root":["usage","billed_units"],"model_path":"model","mappings":[{"path":"input_tokens","dest":"input_tokens","required":true},{"path":"output_tokens","dest":"output_tokens","required":true}]},{"api_flavor":"embeddings","root":["meta","billed_units"],"model_path":"model","mappings":[{"path":"input_tokens","dest":"input_tokens","required":true}]}],"models":[{"id":"command","match":{"equals":"command"},"prices":{"input_mtok":1,"output_mtok":2}},{"id":"command-a","match":{"starts_with":"command-a"},"prices":{"input_mtok":2.5,"output_mtok":10}},{"id":"command-r","match":{"or":[{"equals":"command-r"},{"equals":"command-r-08-2024"}]},"prices":{"input_mtok":0.15,"output_mtok":0.6}},{"id":"command-r-plus","match":{"or":[{"equals":"command-r-plus"},{"equals":"command-r-plus-08-2024"}]},"prices":{"input_mtok":2.5,"output_mtok":10}},{"id":"command-r7b","match":{"or":[{"equals":"command-r7b"},{"equals":"command-r7b-12-2024"}]},"prices":{"input_mtok":0.0375,"output_mtok":0.15}},{"id":"embed-v4.0","match":{"equals":"embed-v4.0"},"context_window":128000,"prices":{"input_mtok":0.12}}]},{"id":"deepseek","name":"Deepseek","pricing_urls":["https://api-docs.deepseek.com/quick_start/pricing"],"api_pattern":"https://api\\.deepseek\\.com","model_match":{"contains":"deepseek"},"extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"deepseek-chat","match":{"or":[{"starts_with":"deepseek-chat"},{"equals":"deepseek-chat-v3-0324"}]},"context_window":64000,"prices":[{"prices":{"input_mtok":0.135,"cache_read_mtok":0.035,"output_mtok":0.55}},{"constraint":{"start_time":"00:30:00Z","end_time":"16:30:00Z"},"prices":{"input_mtok":0.27,"cache_read_mtok":0.07,"output_mtok":1.1}}]},{"id":"deepseek-reasoner","match":{"or":[{"equals":"deepseek-reasoner"},{"starts_with":"deepseek-r1"},{"equals":"deepseek-r1-0528"}]},"context_window":64000,"prices":[{"prices":{"input_mtok":0.135,"cache_read_mtok":0.035,"output_mtok":0.55}},{"constraint":{"start_time":"00:30:00Z","end_time":"16:30:00Z"},"prices":{"input_mtok":0.55,"cache_read_mtok":0.14,"output_mtok":2.19}}]}]},{"id":"fireworks","name":"Fireworks","pricing_urls":["https://fireworks.ai/pricing"],"api_pattern":"https://api\\.fireworks\\.ai","model_match":{"starts_with":"accounts/fireworks/models/"},"extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"deepseek-r1-0528","match":{"equals":"accounts/fireworks/models/deepseek-r1-0528"},"context_window":160000,"prices":{"input_mtok":3,"output_mtok":8}},{"id":"deepseek-v3-0324","match":{"equals":"accounts/fireworks/models/deepseek-v3-0324"},"context_window":160000,"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"deepseek-v3p2","match":{"equals":"accounts/fireworks/models/deepseek-v3p2"},"context_window":163840,"prices":{"input_mtok":0.56,"cache_read_mtok":0.28,"output_mtok":1.68}},{"id":"gemma-3-27b-it","match":{"equals":"accounts/fireworks/models/gemma-3-27b-it"},"context_window":131000,"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"glm-4p7","match":{"equals":"accounts/fireworks/models/glm-4p7"},"context_window":202752,"prices":{"input_mtok":0.6,"output_mtok":2.2}},{"id":"gpt-oss-120b","match":{"equals":"accounts/fireworks/models/gpt-oss-120b"},"context_window":131072,"prices":{"input_mtok":0.15,"cache_read_mtok":0.07,"output_mtok":0.6}},{"id":"gpt-oss-20b","match":{"equals":"accounts/fireworks/models/gpt-oss-20b"},"context_window":131072,"prices":{"input_mtok":0.07,"cache_read_mtok":0.04,"output_mtok":0.3}},{"id":"kimi-k2p5","match":{"equals":"accounts/fireworks/models/kimi-k2p5"},"context_window":262144,"prices":{"input_mtok":0.6,"cache_read_mtok":0.1,"output_mtok":3}},{"id":"llama-v3p1-8b-instruct","match":{"equals":"accounts/fireworks/models/llama-v3p1-8b-instruct"},"context_window":131000,"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"llama4-maverick-instruct-basic","match":{"equals":"accounts/fireworks/models/llama4-maverick-instruct-basic"},"context_window":1000000,"prices":{"input_mtok":0.22,"output_mtok":0.88}},{"id":"minimax-m2p1","match":{"equals":"accounts/fireworks/models/minimax-m2p1"},"context_window":204800,"prices":{"input_mtok":0.3,"output_mtok":1.2}},{"id":"qwen2p5-vl-72b-instruct","match":{"equals":"accounts/fireworks/models/qwen2p5-vl-72b-instruct"},"context_window":128000,"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"qwen3-235b-a22b","match":{"equals":"accounts/fireworks/models/qwen3-235b-a22b"},"context_window":128000,"prices":{"input_mtok":0.22,"output_mtok":0.88}}]},{"id":"google","name":"Google","pricing_urls":["https://ai.google.dev/gemini-api/docs/pricing","https://cloud.google.com/vertex-ai/generative-ai/pricing"],"api_pattern":"https://(.*\\.)?googleapis\\.com","model_match":{"contains":"gemini"},"provider_match":{"or":[{"contains":"google"},{"contains":"vertex"},{"contains":"gemini"}]},"extractors":[{"api_flavor":"default","root":"usageMetadata","model_path":"modelVersion","mappings":[{"path":"promptTokenCount","dest":"input_tokens","required":false},{"path":"cachedContentTokenCount","dest":"cache_read_tokens","required":false},{"path":["cacheTokensDetails",{"type":"array-match","field":"modality","match":{"equals":"AUDIO"}},"tokenCount"],"dest":"cache_audio_read_tokens","required":false},{"path":["promptTokensDetails",{"type":"array-match","field":"modality","match":{"equals":"AUDIO"}},"tokenCount"],"dest":"input_audio_tokens","required":false},{"path":["candidatesTokensDetails",{"type":"array-match","field":"modality","match":{"equals":"AUDIO"}},"tokenCount"],"dest":"output_audio_tokens","required":false},{"path":"candidatesTokenCount","dest":"output_tokens","required":false},{"path":"thoughtsTokenCount","dest":"output_tokens","required":false},{"path":"toolUsePromptTokenCount","dest":"output_tokens","required":false}]},{"api_flavor":"anthropic","root":"usage","model_path":"model","mappings":[{"path":"input_tokens","dest":"input_tokens","required":true},{"path":"cache_creation_input_tokens","dest":"input_tokens","required":false},{"path":"cache_read_input_tokens","dest":"input_tokens","required":false},{"path":"cache_creation_input_tokens","dest":"cache_write_tokens","required":false},{"path":"cache_read_input_tokens","dest":"cache_read_tokens","required":false},{"path":"output_tokens","dest":"output_tokens","required":true}]},{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["prompt_tokens_details","audio_tokens"],"dest":"input_audio_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"fallback_model_providers":["anthropic"],"models":[{"id":"claude-3-5-haiku","match":{"contains":"claude-3-5-haiku"},"context_window":200000,"prices":{"input_mtok":0.8,"cache_write_mtok":1,"cache_read_mtok":0.08,"output_mtok":4}},{"id":"claude-3-5-sonnet","match":{"contains":"claude-3-5-sonnet"},"context_window":200000,"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"claude-3-7-sonnet","match":{"contains":"claude-3-7-sonnet"},"context_window":200000,"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"claude-3-haiku","match":{"contains":"claude-3-haiku"},"context_window":200000,"prices":{"input_mtok":0.25,"cache_write_mtok":0.3,"cache_read_mtok":0.03,"output_mtok":1.25}},{"id":"claude-3-opus","match":{"contains":"claude-3-opus"},"prices":{"input_mtok":15,"cache_write_mtok":18.75,"cache_read_mtok":1.5,"output_mtok":75}},{"id":"claude-4-opus","match":{"or":[{"contains":"claude-4-opus"},{"contains":"claude-opus-4@"},{"contains":"claude-opus-4-0"},{"contains":"claude-opus-4-1"},{"equals":"claude-opus-4"}]},"context_window":200000,"prices":{"input_mtok":15,"cache_write_mtok":18.75,"cache_read_mtok":1.5,"output_mtok":75}},{"id":"claude-4-sonnet","match":{"or":[{"contains":"claude-4-sonnet"},{"contains":"claude-sonnet-4"}]},"context_window":200000,"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"claude-opus-4-6","match":{"or":[{"contains":"claude-4-6-opus"},{"contains":"claude-opus-4-6"},{"contains":"claude-4.6-opus"},{"contains":"claude-opus-4.6"}]},"context_window":200000,"prices":{"input_mtok":{"base":5,"tiers":[{"start":200000,"price":10}]},"cache_write_mtok":{"base":6.25,"tiers":[{"start":200000,"price":12.5}]},"cache_read_mtok":{"base":0.5,"tiers":[{"start":200000,"price":1}]},"output_mtok":{"base":25,"tiers":[{"start":200000,"price":37.5}]}}},{"id":"gemini-1.0-pro-vision-001","match":{"equals":"gemini-1.0-pro-vision-001"},"context_window":32768,"prices":{"input_mtok":0.125,"output_mtok":0.375}},{"id":"gemini-1.5-flash","match":{"contains":"gemini-1.5-flash"},"context_window":1000000,"prices":{"input_mtok":{"base":0.075,"tiers":[{"start":128000,"price":0.15}]},"cache_read_mtok":{"base":0.01875,"tiers":[{"start":128000,"price":0.0375}]},"output_mtok":{"base":0.3,"tiers":[{"start":128000,"price":0.6}]}}},{"id":"gemini-1.5-pro","match":{"contains":"gemini-1.5-pro"},"context_window":1000000,"prices":{"input_mtok":{"base":1.25,"tiers":[{"start":128000,"price":2.5}]},"output_mtok":{"base":5,"tiers":[{"start":128000,"price":10}]}}},{"id":"gemini-2.0-flash","match":{"or":[{"ends_with":"gemini-2.0-flash"},{"contains":"gemini-2.0-flash-0"},{"contains":"gemini-2.0-flash-exp"},{"contains":"gemini-2.0-flash-thinking"},{"contains":"gemini-2.0-flash-latest"}]},"context_window":1000000,"prices":{"input_mtok":0.1,"cache_read_mtok":{"base":0.025,"tiers":[{"start":1000000,"price":0.175}]},"output_mtok":0.4,"input_audio_mtok":0.7}},{"id":"gemini-2.0-flash-lite","match":{"contains":"gemini-2.0-flash-lite"},"context_window":1000000,"prices":{"input_mtok":0.075,"output_mtok":0.3}},{"id":"gemini-2.5-flash","match":{"or":[{"equals":"gemini-2.5-flash"},{"equals":"gemini-2.5-flash-latest"},{"equals":"gemini-2.5-flash-preview-09-2025"}]},"prices":{"input_mtok":0.3,"cache_read_mtok":0.03,"output_mtok":2.5,"input_audio_mtok":1,"cache_audio_read_mtok":0.1}},{"id":"gemini-2.5-flash-image","match":{"or":[{"equals":"gemini-2.5-flash-image"},{"equals":"gemini-2.5-flash-image-preview"}]},"context_window":1000000,"prices":{"input_mtok":0.3,"output_mtok":30}},{"id":"gemini-2.5-flash-lite","match":{"or":[{"equals":"gemini-2.5-flash-lite"},{"starts_with":"gemini-2.5-flash-lite-preview"}]},"context_window":1000000,"prices":{"input_mtok":0.1,"cache_read_mtok":0.01,"output_mtok":0.4,"input_audio_mtok":0.3,"cache_audio_read_mtok":0.03}},{"id":"gemini-2.5-flash-preview","match":{"or":[{"contains":"gemini-2.5-flash-preview-05-20"},{"contains":"gemini-2.5-flash-preview-04-17"},{"equals":"gemini-2.5-flash-preview-05-20:thinking"},{"equals":"gemini-2.5-flash-preview"},{"equals":"gemini-2.5-flash-preview:thinking"}]},"prices":{"input_mtok":0.15,"output_mtok":0.6},"deprecated":true},{"id":"gemini-2.5-pro","match":{"starts_with":"gemini-2.5-pro"},"prices":{"input_mtok":{"base":1.25,"tiers":[{"start":200000,"price":2.5}]},"cache_read_mtok":{"base":0.125,"tiers":[{"start":200000,"price":0.25}]},"output_mtok":{"base":10,"tiers":[{"start":200000,"price":15}]}}},{"id":"gemini-3-flash-preview","match":{"or":[{"equals":"gemini-3-flash-preview"},{"starts_with":"gemini-3-flash-preview-"}]},"context_window":1000000,"prices":{"input_mtok":0.5,"cache_read_mtok":0.05,"output_mtok":3,"input_audio_mtok":1,"cache_audio_read_mtok":0.1}},{"id":"gemini-3-pro-image-preview","match":{"or":[{"starts_with":"gemini-3-pro-image-preview"},{"equals":"gemini-3-pro-image-preview"}]},"context_window":1000000,"prices":{"input_mtok":2,"output_mtok":120}},{"id":"gemini-3-pro-preview","match":{"or":[{"starts_with":"gemini-3-pro-preview"},{"equals":"gemini-3-pro-text-preview"}]},"prices":{"input_mtok":{"base":2,"tiers":[{"start":200000,"price":4}]},"cache_read_mtok":{"base":0.2,"tiers":[{"start":200000,"price":0.4}]},"output_mtok":{"base":12,"tiers":[{"start":200000,"price":18}]}}},{"id":"gemini-3.1-pro-preview","match":{"starts_with":"gemini-3.1-pro-preview"},"prices":{"input_mtok":{"base":2,"tiers":[{"start":200000,"price":4}]},"cache_read_mtok":{"base":0.2,"tiers":[{"start":200000,"price":0.4}]},"output_mtok":{"base":12,"tiers":[{"start":200000,"price":18}]}}},{"id":"gemini-embedding-001","match":{"equals":"gemini-embedding-001"},"prices":{"input_mtok":0.15}},{"id":"gemini-flash-1.5","match":{"equals":"gemini-flash-1.5"},"prices":{"input_mtok":{"base":0.075,"tiers":[{"start":128000,"price":0.15}]},"cache_read_mtok":{"base":0.01875,"tiers":[{"start":128000,"price":0.0375}]},"output_mtok":{"base":0.3,"tiers":[{"start":128000,"price":0.6}]}}},{"id":"gemini-flash-1.5-8b","match":{"equals":"gemini-flash-1.5-8b"},"context_window":1000000,"prices":{"input_mtok":{"base":0.0375,"tiers":[{"start":128000,"price":0.075}]},"cache_read_mtok":{"base":0.01,"tiers":[{"start":128000,"price":0.02}]},"output_mtok":{"base":0.15,"tiers":[{"start":128000,"price":0.3}]}}},{"id":"gemini-live-2.5-flash-preview","match":{"or":[{"starts_with":"gemini-live-2.5-flash-preview"},{"starts_with":"gemini-2.5-flash-native-audio-preview"}]},"prices":{"input_mtok":0.5,"output_mtok":2,"input_audio_mtok":3,"output_audio_mtok":12}},{"id":"gemini-pro","match":{"or":[{"equals":"gemini-pro"},{"equals":"gemini-1.0-pro"}]},"context_window":32768,"prices":{"input_mtok":0.125,"output_mtok":0.375}},{"id":"gemini-pro-1.5","match":{"equals":"gemini-pro-1.5"},"context_window":2000000,"prices":{"input_mtok":{"base":1.25,"tiers":[{"start":128000,"price":2.5}]},"cache_read_mtok":{"base":0.3125,"tiers":[{"start":128000,"price":0.625}]},"output_mtok":{"base":5,"tiers":[{"start":128000,"price":10}]}}}]},{"id":"groq","name":"Groq","pricing_urls":["https://groq.com/pricing/"],"api_pattern":"https://api\\.groq\\.com","extractors":[{"api_flavor":"default","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"deepseek-r1-distill-llama-70b","match":{"equals":"deepseek-r1-distill-llama-70b"},"context_window":131072,"prices":{"input_mtok":0.75,"output_mtok":0.99}},{"id":"gemma-7b-it","match":{"equals":"gemma-7b-it"},"prices":{"input_mtok":0.07,"output_mtok":0.07}},{"id":"gemma2-9b-it","match":{"or":[{"equals":"gemma2-9b-it"},{"equals":"gemma2-9b"}]},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"llama-3.1-405b-reasoning","match":{"equals":"llama-3.1-405b-reasoning"},"prices":{"input_mtok":0.59,"output_mtok":0.79}},{"id":"llama-3.1-70b-versatile","match":{"equals":"llama-3.1-70b-versatile"},"prices":{"input_mtok":0.59,"output_mtok":0.79}},{"id":"llama-3.1-8b-instant","match":{"equals":"llama-3.1-8b-instant"},"prices":{"input_mtok":0.05,"output_mtok":0.08}},{"id":"llama-3.2-11b-text-preview","match":{"equals":"llama-3.2-11b-text-preview"},"prices":{"input_mtok":0.18,"output_mtok":0.18}},{"id":"llama-3.2-11b-vision-preview","match":{"equals":"llama-3.2-11b-vision-preview"},"prices":{"input_mtok":0.18,"output_mtok":0.18}},{"id":"llama-3.2-1b-preview","match":{"equals":"llama-3.2-1b-preview"},"prices":{"input_mtok":0.04,"output_mtok":0.04}},{"id":"llama-3.2-3b-preview","match":{"equals":"llama-3.2-3b-preview"},"prices":{"input_mtok":0.06,"output_mtok":0.06}},{"id":"llama-3.2-90b-text-preview","match":{"equals":"llama-3.2-90b-text-preview"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"llama-3.2-90b-vision-preview","match":{"equals":"llama-3.2-90b-vision-preview"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"llama-3.3-70b-specdec","match":{"equals":"llama-3.3-70b-specdec"},"prices":{"input_mtok":0.59,"output_mtok":0.99}},{"id":"llama-3.3-70b-versatile","match":{"equals":"llama-3.3-70b-versatile"},"prices":{"input_mtok":0.59,"output_mtok":0.79}},{"id":"llama-guard-3-8b","match":{"equals":"llama-guard-3-8b"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"llama2-70b-4096","match":{"equals":"llama2-70b-4096"},"prices":{"input_mtok":0.7,"output_mtok":0.8}},{"id":"llama3-70b-8192","match":{"equals":"llama3-70b-8192"},"prices":{"input_mtok":0.59,"output_mtok":0.79}},{"id":"llama3-8b-8192","match":{"equals":"llama3-8b-8192"},"prices":{"input_mtok":0.05,"output_mtok":0.08}},{"id":"llama3-groq-70b-8192-tool-use-preview","match":{"equals":"llama3-groq-70b-8192-tool-use-preview"},"prices":{"input_mtok":0.89,"output_mtok":0.89}},{"id":"llama3-groq-8b-8192-tool-use-preview","match":{"equals":"llama3-groq-8b-8192-tool-use-preview"},"prices":{"input_mtok":0.19,"output_mtok":0.19}},{"id":"meta-llama/llama-4-maverick-17b-128e-instruct","match":{"equals":"meta-llama/llama-4-maverick-17b-128e-instruct"},"context_window":131072,"prices":{"input_mtok":0.2,"output_mtok":0.6}},{"id":"meta-llama/llama-4-scout-17b-16e-instruct","match":{"equals":"meta-llama/llama-4-scout-17b-16e-instruct"},"prices":{"input_mtok":0.11,"output_mtok":0.34}},{"id":"meta-llama/llama-guard-4-12b","match":{"equals":"meta-llama/llama-guard-4-12b"},"context_window":131072,"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"mistral-saba-24b","match":{"equals":"mistral-saba-24b"},"prices":{"input_mtok":0.79,"output_mtok":0.79}},{"id":"mixtral-8x7b-32768","match":{"equals":"mixtral-8x7b-32768"},"prices":{"input_mtok":0.24,"output_mtok":0.24}},{"id":"moonshotai/kimi-k2-instruct","match":{"or":[{"equals":"moonshotai/kimi-k2-instruct"},{"equals":"moonshotai/kimi-k2-instruct-0905"}]},"context_window":131072,"prices":{"input_mtok":1,"cache_read_mtok":0.5,"output_mtok":3}},{"id":"openai/gpt-oss-120b","match":{"or":[{"equals":"openai/gpt-oss-120b"},{"equals":"openai/gpt-oss-safeguard-20b"}]},"context_window":131072,"prices":{"input_mtok":0.15,"cache_read_mtok":0.075,"output_mtok":0.6}},{"id":"openai/gpt-oss-20b","match":{"equals":"openai/gpt-oss-20b"},"context_window":131072,"prices":{"input_mtok":0.075,"cache_read_mtok":0.0375,"output_mtok":0.3}},{"id":"qwen/qwen3-32b","match":{"equals":"qwen/qwen3-32b"},"prices":{"input_mtok":0.29,"output_mtok":0.59}}]},{"id":"huggingface_cerebras","name":"HuggingFace (cerebras)","pricing_urls":["https://router.huggingface.co/v1/models","https://huggingface.co/inference/models"],"api_pattern":"https://router\\.huggingface\\.co/cerebras","provider_match":{"and":[{"contains":"huggingface"},{"contains":"cerebras"}]},"extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["prompt_tokens_details","audio_tokens"],"dest":"input_audio_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"Qwen/Qwen3-235B-A22B-Instruct-2507","match":{"or":[{"equals":"qwen/qwen3-235b-a22b-instruct-2507"},{"equals":"qwen/qwen3-235b-a22b-instruct-2507-fast"}]},"prices":{"input_mtok":0.6,"output_mtok":1.2}},{"id":"Qwen/Qwen3-32B","match":{"or":[{"equals":"qwen/qwen3-32b"},{"equals":"qwen/qwen3-32b-fast"}]},"prices":{"input_mtok":0.4,"output_mtok":0.8}},{"id":"meta-llama/Llama-3.1-8B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.1-8b-instruct"},{"equals":"meta-llama/llama-3.1-8b-instruct-fast"}]},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"meta-llama/Llama-3.3-70B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.3-70b-instruct"},{"equals":"meta-llama/llama-3.3-70b-instruct-fast"}]},"prices":{"input_mtok":0.85,"output_mtok":1.2}},{"id":"openai/gpt-oss-120b","match":{"or":[{"equals":"openai/gpt-oss-120b"},{"equals":"openai/gpt-oss-120b-fast"}]},"prices":{"input_mtok":0.25,"output_mtok":0.69}}]},{"id":"huggingface_fireworks-ai","name":"HuggingFace (fireworks-ai)","pricing_urls":["https://router.huggingface.co/v1/models","https://huggingface.co/inference/models"],"api_pattern":"https://router\\.huggingface\\.co/fireworks-ai","provider_match":{"and":[{"contains":"huggingface"},{"contains":"fireworks-ai"}]},"extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["prompt_tokens_details","audio_tokens"],"dest":"input_audio_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"Qwen/Qwen2.5-VL-32B-Instruct","match":{"or":[{"equals":"qwen/qwen2.5-vl-32b-instruct"},{"equals":"qwen/qwen2.5-vl-32b-instruct-fast"}]},"context_window":128000,"prices":{"input_mtok":0.22,"output_mtok":0.88}},{"id":"Qwen/Qwen3-235B-A22B","match":{"or":[{"equals":"qwen/qwen3-235b-a22b"},{"equals":"qwen/qwen3-235b-a22b-fast"},{"equals":"qwen/qwen3-235b-a22b-instruct-2507"},{"equals":"qwen/qwen3-235b-a22b-instruct-2507-fast"},{"equals":"qwen/qwen3-235b-a22b-thinking-2507"},{"equals":"qwen/qwen3-235b-a22b-thinking-2507-fast"}]},"context_window":131072,"prices":{"input_mtok":0.22,"output_mtok":0.88}},{"id":"Qwen/Qwen3-30B-A3B","match":{"or":[{"equals":"qwen/qwen3-30b-a3b"},{"equals":"qwen/qwen3-30b-a3b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.15,"output_mtok":0.6}},{"id":"Qwen/Qwen3-Coder-480B-A35B-Instruct","match":{"or":[{"equals":"qwen/qwen3-coder-480b-a35b-instruct"},{"equals":"qwen/qwen3-coder-480b-a35b-instruct-fast"}]},"context_window":262144,"prices":{"input_mtok":0.45,"output_mtok":1.8}},{"id":"deepseek-ai/DeepSeek-R1-0528","match":{"or":[{"equals":"deepseek-ai/deepseek-r1-0528"},{"equals":"deepseek-ai/deepseek-r1-0528-fast"}]},"context_window":163840,"prices":{"input_mtok":3,"output_mtok":8}},{"id":"deepseek-ai/DeepSeek-V3-0324","match":{"or":[{"equals":"deepseek-ai/deepseek-v3-0324"},{"equals":"deepseek-ai/deepseek-v3-0324-fast"}]},"context_window":163840,"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"meta-llama/Llama-3.3-70B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.3-70b-instruct"},{"equals":"meta-llama/llama-3.3-70b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"openai/gpt-oss-120b","match":{"or":[{"equals":"openai/gpt-oss-120b"},{"equals":"openai/gpt-oss-120b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.15,"output_mtok":0.6}},{"id":"zai-org/GLM-4.5","match":{"or":[{"equals":"zai-org/glm-4.5"},{"equals":"zai-org/glm-4.5-fast"}]},"context_window":131072,"prices":{"input_mtok":0.55,"output_mtok":2.19}}]},{"id":"huggingface_groq","name":"HuggingFace (groq)","pricing_urls":["https://router.huggingface.co/v1/models","https://huggingface.co/inference/models"],"api_pattern":"https://router\\.huggingface\\.co/groq","provider_match":{"and":[{"contains":"huggingface"},{"contains":"groq"}]},"extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["prompt_tokens_details","audio_tokens"],"dest":"input_audio_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"Qwen/Qwen3-32B","match":{"or":[{"equals":"qwen/qwen3-32b"},{"equals":"qwen/qwen3-32b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.29,"output_mtok":0.59}},{"id":"meta-llama/Llama-3.3-70B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.3-70b-instruct"},{"equals":"meta-llama/llama-3.3-70b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.59,"output_mtok":0.79}},{"id":"openai/gpt-oss-120b","match":{"or":[{"equals":"openai/gpt-oss-120b"},{"equals":"openai/gpt-oss-120b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.15,"output_mtok":0.75}}]},{"id":"huggingface_hyperbolic","name":"HuggingFace (hyperbolic)","pricing_urls":["https://router.huggingface.co/v1/models","https://huggingface.co/inference/models"],"api_pattern":"https://router\\.huggingface\\.co/hyperbolic","provider_match":{"and":[{"contains":"huggingface"},{"contains":"hyperbolic"}]},"extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["prompt_tokens_details","audio_tokens"],"dest":"input_audio_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"Qwen/QwQ-32B","match":{"or":[{"equals":"qwen/qwq-32b"},{"equals":"qwen/qwq-32b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.4,"output_mtok":0.4}},{"id":"Qwen/Qwen2.5-72B-Instruct","match":{"or":[{"equals":"qwen/qwen2.5-72b-instruct"},{"equals":"qwen/qwen2.5-72b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.4,"output_mtok":0.4}},{"id":"Qwen/Qwen2.5-Coder-32B-Instruct","match":{"or":[{"equals":"qwen/qwen2.5-coder-32b-instruct"},{"equals":"qwen/qwen2.5-coder-32b-instruct-fast"}]},"context_window":32768,"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"Qwen/Qwen2.5-VL-72B-Instruct","match":{"or":[{"equals":"qwen/qwen2.5-vl-72b-instruct"},{"equals":"qwen/qwen2.5-vl-72b-instruct-fast"}]},"context_window":32768,"prices":{"input_mtok":0.6,"output_mtok":0.6}},{"id":"Qwen/Qwen2.5-VL-7B-Instruct","match":{"or":[{"equals":"qwen/qwen2.5-vl-7b-instruct"},{"equals":"qwen/qwen2.5-vl-7b-instruct-fast"}]},"context_window":32768,"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"Qwen/Qwen3-235B-A22B-Instruct-2507","match":{"or":[{"equals":"qwen/qwen3-235b-a22b-instruct-2507"},{"equals":"qwen/qwen3-235b-a22b-instruct-2507-fast"}]},"context_window":262144,"prices":{"input_mtok":2,"output_mtok":2}},{"id":"Qwen/Qwen3-Coder-480B-A35B-Instruct","match":{"or":[{"equals":"qwen/qwen3-coder-480b-a35b-instruct"},{"equals":"qwen/qwen3-coder-480b-a35b-instruct-fast"}]},"context_window":262144,"prices":{"input_mtok":2,"output_mtok":2}},{"id":"Qwen/Qwen3-Next-80B-A3B-Instruct","match":{"or":[{"equals":"qwen/qwen3-next-80b-a3b-instruct"},{"equals":"qwen/qwen3-next-80b-a3b-instruct-fast"}]},"context_window":262144,"prices":{"input_mtok":0.3,"output_mtok":0.3}},{"id":"Qwen/Qwen3-Next-80B-A3B-Thinking","match":{"or":[{"equals":"qwen/qwen3-next-80b-a3b-thinking"},{"equals":"qwen/qwen3-next-80b-a3b-thinking-fast"}]},"context_window":262144,"prices":{"input_mtok":0.3,"output_mtok":0.3}},{"id":"deepseek-ai/DeepSeek-R1","match":{"or":[{"equals":"deepseek-ai/deepseek-r1"},{"equals":"deepseek-ai/deepseek-r1-fast"}]},"context_window":163840,"prices":{"input_mtok":2,"output_mtok":2}},{"id":"deepseek-ai/DeepSeek-R1-0528","match":{"or":[{"equals":"deepseek-ai/deepseek-r1-0528"},{"equals":"deepseek-ai/deepseek-r1-0528-fast"}]},"context_window":163840,"prices":{"input_mtok":3,"output_mtok":3}},{"id":"deepseek-ai/DeepSeek-V3-0324","match":{"or":[{"equals":"deepseek-ai/deepseek-v3-0324"},{"equals":"deepseek-ai/deepseek-v3-0324-fast"}]},"context_window":163840,"prices":{"input_mtok":1.25,"output_mtok":1.25}},{"id":"meta-llama/Llama-3.1-8B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.1-8b-instruct"},{"equals":"meta-llama/llama-3.1-8b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"meta-llama/Llama-3.2-3B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.2-3b-instruct"},{"equals":"meta-llama/llama-3.2-3b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"meta-llama/Llama-3.3-70B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.3-70b-instruct"},{"equals":"meta-llama/llama-3.3-70b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.4,"output_mtok":0.4}},{"id":"meta-llama/Meta-Llama-3-70B-Instruct","match":{"or":[{"equals":"meta-llama/meta-llama-3-70b-instruct"},{"equals":"meta-llama/meta-llama-3-70b-instruct-fast"}]},"context_window":8192,"prices":{"input_mtok":0.4,"output_mtok":0.4}},{"id":"openai/gpt-oss-120b","match":{"or":[{"equals":"openai/gpt-oss-120b"},{"equals":"openai/gpt-oss-120b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.3,"output_mtok":0.3}}]},{"id":"huggingface_nebius","name":"HuggingFace (nebius)","pricing_urls":["https://router.huggingface.co/v1/models","https://huggingface.co/inference/models"],"api_pattern":"https://router\\.huggingface\\.co/nebius","provider_match":{"and":[{"contains":"huggingface"},{"contains":"nebius"}]},"extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["prompt_tokens_details","audio_tokens"],"dest":"input_audio_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"NousResearch/Hermes-4-405B","match":{"or":[{"equals":"nousresearch/hermes-4-405b"},{"equals":"nousresearch/hermes-4-405b-fast"}]},"context_window":131072,"prices":{"input_mtok":1,"output_mtok":3}},{"id":"NousResearch/Hermes-4-70B","match":{"or":[{"equals":"nousresearch/hermes-4-70b"},{"equals":"nousresearch/hermes-4-70b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.13,"output_mtok":0.4}},{"id":"PrimeIntellect/INTELLECT-3-FP8","match":{"or":[{"equals":"primeintellect/intellect-3-fp8"},{"equals":"primeintellect/intellect-3-fp8-fast"}]},"context_window":131072,"prices":{"input_mtok":0.2,"output_mtok":1.1}},{"id":"Qwen/Qwen2.5-Coder-7B","match":{"or":[{"equals":"qwen/qwen2.5-coder-7b"},{"equals":"qwen/qwen2.5-coder-7b-fast"}]},"context_window":32768,"prices":{"input_mtok":0.03,"output_mtok":0.09}},{"id":"Qwen/Qwen2.5-VL-72B-Instruct","match":{"or":[{"equals":"qwen/qwen2.5-vl-72b-instruct"},{"equals":"qwen/qwen2.5-vl-72b-instruct-fast"}]},"context_window":32000,"prices":{"input_mtok":0.25,"output_mtok":0.75}},{"id":"Qwen/Qwen3-235B-A22B-Instruct-2507","match":{"or":[{"equals":"qwen/qwen3-235b-a22b-instruct-2507"},{"equals":"qwen/qwen3-235b-a22b-instruct-2507-fast"}]},"context_window":262144,"prices":{"input_mtok":0.2,"output_mtok":0.6}},{"id":"Qwen/Qwen3-235B-A22B-Thinking-2507","match":{"or":[{"equals":"qwen/qwen3-235b-a22b-thinking-2507"},{"equals":"qwen/qwen3-235b-a22b-thinking-2507-fast"}]},"context_window":262144,"prices":{"input_mtok":0.2,"output_mtok":0.8}},{"id":"Qwen/Qwen3-30B-A3B-Instruct-2507","match":{"or":[{"equals":"qwen/qwen3-30b-a3b-instruct-2507"},{"equals":"qwen/qwen3-30b-a3b-instruct-2507-fast"}]},"context_window":262144,"prices":{"input_mtok":0.1,"output_mtok":0.3}},{"id":"Qwen/Qwen3-30B-A3B-Thinking-2507","match":{"or":[{"equals":"qwen/qwen3-30b-a3b-thinking-2507"},{"equals":"qwen/qwen3-30b-a3b-thinking-2507-fast"}]},"context_window":262144,"prices":{"input_mtok":0.1,"output_mtok":0.3}},{"id":"Qwen/Qwen3-32B","match":{"or":[{"equals":"qwen/qwen3-32b"},{"equals":"qwen/qwen3-32b-fast"}]},"context_window":40960,"prices":{"input_mtok":0.1,"output_mtok":0.3}},{"id":"Qwen/Qwen3-Coder-30B-A3B-Instruct","match":{"or":[{"equals":"qwen/qwen3-coder-30b-a3b-instruct"},{"equals":"qwen/qwen3-coder-30b-a3b-instruct-fast"}]},"context_window":262144,"prices":{"input_mtok":0.1,"output_mtok":0.3}},{"id":"Qwen/Qwen3-Coder-480B-A35B-Instruct","match":{"or":[{"equals":"qwen/qwen3-coder-480b-a35b-instruct"},{"equals":"qwen/qwen3-coder-480b-a35b-instruct-fast"}]},"context_window":262144,"prices":{"input_mtok":0.4,"output_mtok":1.8}},{"id":"deepseek-ai/DeepSeek-R1-0528","match":{"or":[{"equals":"deepseek-ai/deepseek-r1-0528"},{"equals":"deepseek-ai/deepseek-r1-0528-fast"}]},"context_window":163840,"prices":{"input_mtok":0.8,"output_mtok":2.4}},{"id":"deepseek-ai/DeepSeek-V3-0324","match":{"or":[{"equals":"deepseek-ai/deepseek-v3-0324"},{"equals":"deepseek-ai/deepseek-v3-0324-fast"}]},"context_window":32768,"prices":{"input_mtok":0.75,"output_mtok":2.25}},{"id":"google/gemma-2-2b-it","match":{"or":[{"equals":"google/gemma-2-2b-it"},{"equals":"google/gemma-2-2b-it-fast"}]},"context_window":8192,"prices":{"input_mtok":0.02,"output_mtok":0.06}},{"id":"google/gemma-2-9b-it","match":{"or":[{"equals":"google/gemma-2-9b-it"},{"equals":"google/gemma-2-9b-it-fast"}]},"context_window":8192,"prices":{"input_mtok":0.03,"output_mtok":0.09}},{"id":"google/gemma-3-27b-it","match":{"or":[{"equals":"google/gemma-3-27b-it"},{"equals":"google/gemma-3-27b-it-fast"}]},"context_window":110000,"prices":{"input_mtok":0.2,"output_mtok":0.6}},{"id":"meta-llama/Llama-3.1-8B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.1-8b-instruct"},{"equals":"meta-llama/llama-3.1-8b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.03,"output_mtok":0.09}},{"id":"meta-llama/Llama-3.3-70B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.3-70b-instruct"},{"equals":"meta-llama/llama-3.3-70b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.25,"output_mtok":0.75}},{"id":"moonshotai/Kimi-K2-Instruct","match":{"or":[{"equals":"moonshotai/kimi-k2-instruct"},{"equals":"moonshotai/kimi-k2-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.5,"output_mtok":2.4}},{"id":"moonshotai/Kimi-K2-Thinking","match":{"or":[{"equals":"moonshotai/kimi-k2-thinking"},{"equals":"moonshotai/kimi-k2-thinking-fast"}]},"context_window":262144,"prices":{"input_mtok":0.6,"output_mtok":2.5}},{"id":"nvidia/Llama-3_1-Nemotron-Ultra-253B-v1","match":{"or":[{"equals":"nvidia/llama-3_1-nemotron-ultra-253b-v1"},{"equals":"nvidia/llama-3_1-nemotron-ultra-253b-v1-fast"}]},"context_window":131072,"prices":{"input_mtok":0.6,"output_mtok":1.8}},{"id":"nvidia/NVIDIA-Nemotron-Nano-12B-v2","match":{"or":[{"equals":"nvidia/nvidia-nemotron-nano-12b-v2"},{"equals":"nvidia/nvidia-nemotron-nano-12b-v2-fast"}]},"context_window":131072,"prices":{"input_mtok":0.07,"output_mtok":0.2}},{"id":"openai/gpt-oss-120b","match":{"or":[{"equals":"openai/gpt-oss-120b"},{"equals":"openai/gpt-oss-120b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.15,"output_mtok":0.6}},{"id":"zai-org/GLM-4.5","match":{"or":[{"equals":"zai-org/glm-4.5"},{"equals":"zai-org/glm-4.5-fast"}]},"context_window":131072,"prices":{"input_mtok":0.6,"output_mtok":2.2}},{"id":"zai-org/GLM-4.5-Air","match":{"or":[{"equals":"zai-org/glm-4.5-air"},{"equals":"zai-org/glm-4.5-air-fast"}]},"context_window":131072,"prices":{"input_mtok":0.2,"output_mtok":1.2}}]},{"id":"huggingface_novita","name":"HuggingFace (novita)","pricing_urls":["https://router.huggingface.co/v1/models","https://huggingface.co/inference/models"],"api_pattern":"https://router\\.huggingface\\.co/novita","provider_match":{"and":[{"contains":"huggingface"},{"contains":"novita"}]},"extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["prompt_tokens_details","audio_tokens"],"dest":"input_audio_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"MiniMaxAI/MiniMax-M1-80k","match":{"or":[{"equals":"minimaxai/minimax-m1-80k"},{"equals":"minimaxai/minimax-m1-80k-fast"}]},"context_window":1000000,"prices":{"input_mtok":0.44,"output_mtok":1.76}},{"id":"MiniMaxAI/MiniMax-M2","match":{"or":[{"equals":"minimaxai/minimax-m2"},{"equals":"minimaxai/minimax-m2-fast"}]},"context_window":204800,"prices":{"input_mtok":0.3,"output_mtok":1.2}},{"id":"NousResearch/Hermes-2-Pro-Llama-3-8B","match":{"or":[{"equals":"nousresearch/hermes-2-pro-llama-3-8b"},{"equals":"nousresearch/hermes-2-pro-llama-3-8b-fast"}]},"context_window":8192,"prices":{"input_mtok":0.14,"output_mtok":0.14}},{"id":"Qwen/Qwen2.5-72B-Instruct","match":{"or":[{"equals":"qwen/qwen2.5-72b-instruct"},{"equals":"qwen/qwen2.5-72b-instruct-fast"}]},"context_window":32000,"prices":{"input_mtok":0.304,"output_mtok":0.32}},{"id":"Qwen/Qwen3-235B-A22B","match":{"or":[{"equals":"qwen/qwen3-235b-a22b"},{"equals":"qwen/qwen3-235b-a22b-fast"}]},"context_window":40960,"prices":{"input_mtok":0.16,"output_mtok":0.64}},{"id":"Qwen/Qwen3-235B-A22B-Instruct-2507","match":{"or":[{"equals":"qwen/qwen3-235b-a22b-instruct-2507"},{"equals":"qwen/qwen3-235b-a22b-instruct-2507-fast"}]},"context_window":131072,"prices":{"input_mtok":0.072,"output_mtok":0.464}},{"id":"Qwen/Qwen3-235B-A22B-Thinking-2507","match":{"or":[{"equals":"qwen/qwen3-235b-a22b-thinking-2507"},{"equals":"qwen/qwen3-235b-a22b-thinking-2507-fast"}]},"context_window":131072,"prices":{"input_mtok":0.24,"output_mtok":2.4}},{"id":"Qwen/Qwen3-30B-A3B","match":{"or":[{"equals":"qwen/qwen3-30b-a3b"},{"equals":"qwen/qwen3-30b-a3b-fast"}]},"context_window":40960,"prices":{"input_mtok":0.072,"output_mtok":0.36}},{"id":"Qwen/Qwen3-32B","match":{"or":[{"equals":"qwen/qwen3-32b"},{"equals":"qwen/qwen3-32b-fast"}]},"context_window":40960,"prices":{"input_mtok":0.08,"output_mtok":0.36}},{"id":"Qwen/Qwen3-Coder-480B-A35B-Instruct","match":{"or":[{"equals":"qwen/qwen3-coder-480b-a35b-instruct"},{"equals":"qwen/qwen3-coder-480b-a35b-instruct-fast"}]},"context_window":262144,"prices":{"input_mtok":0.3,"output_mtok":1.3}},{"id":"Qwen/Qwen3-Next-80B-A3B-Instruct","match":{"or":[{"equals":"qwen/qwen3-next-80b-a3b-instruct"},{"equals":"qwen/qwen3-next-80b-a3b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.12,"output_mtok":1.2}},{"id":"Qwen/Qwen3-Next-80B-A3B-Thinking","match":{"or":[{"equals":"qwen/qwen3-next-80b-a3b-thinking"},{"equals":"qwen/qwen3-next-80b-a3b-thinking-fast"}]},"context_window":131072,"prices":{"input_mtok":0.12,"output_mtok":1.2}},{"id":"Qwen/Qwen3-VL-235B-A22B-Instruct","match":{"or":[{"equals":"qwen/qwen3-vl-235b-a22b-instruct"},{"equals":"qwen/qwen3-vl-235b-a22b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.24,"output_mtok":1.2}},{"id":"Qwen/Qwen3-VL-235B-A22B-Thinking","match":{"or":[{"equals":"qwen/qwen3-vl-235b-a22b-thinking"},{"equals":"qwen/qwen3-vl-235b-a22b-thinking-fast"}]},"context_window":131072,"prices":{"input_mtok":0.784,"output_mtok":3.16}},{"id":"Qwen/Qwen3-VL-30B-A3B-Instruct","match":{"or":[{"equals":"qwen/qwen3-vl-30b-a3b-instruct"},{"equals":"qwen/qwen3-vl-30b-a3b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.16,"output_mtok":0.56}},{"id":"Qwen/Qwen3-VL-30B-A3B-Thinking","match":{"or":[{"equals":"qwen/qwen3-vl-30b-a3b-thinking"},{"equals":"qwen/qwen3-vl-30b-a3b-thinking-fast"}]},"context_window":131072,"prices":{"input_mtok":0.16,"output_mtok":0.8}},{"id":"Qwen/Qwen3-VL-8B-Instruct","match":{"or":[{"equals":"qwen/qwen3-vl-8b-instruct"},{"equals":"qwen/qwen3-vl-8b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.064,"output_mtok":0.4}},{"id":"Sao10K/L3-70B-Euryale-v2.1","match":{"or":[{"equals":"sao10k/l3-70b-euryale-v2.1"},{"equals":"sao10k/l3-70b-euryale-v2.1-fast"}]},"context_window":8192,"prices":{"input_mtok":1.48,"output_mtok":1.48}},{"id":"Sao10K/L3-8B-Lunaris-v1","match":{"or":[{"equals":"sao10k/l3-8b-lunaris-v1"},{"equals":"sao10k/l3-8b-lunaris-v1-fast"}]},"context_window":8192,"prices":{"input_mtok":0.05,"output_mtok":0.05}},{"id":"Sao10K/L3-8B-Stheno-v3.2","match":{"or":[{"equals":"sao10k/l3-8b-stheno-v3.2"},{"equals":"sao10k/l3-8b-stheno-v3.2-fast"}]},"context_window":8192,"prices":{"input_mtok":0.05,"output_mtok":0.05}},{"id":"XiaomiMiMo/MiMo-V2-Flash","match":{"or":[{"equals":"xiaomimimo/mimo-v2-flash"},{"equals":"xiaomimimo/mimo-v2-flash-fast"}]},"context_window":262144,"prices":{"input_mtok":0.098,"output_mtok":0.293}},{"id":"alpindale/WizardLM-2-8x22B","match":{"or":[{"equals":"alpindale/wizardlm-2-8x22b"},{"equals":"alpindale/wizardlm-2-8x22b-fast"}]},"context_window":65535,"prices":{"input_mtok":0.496,"output_mtok":0.496}},{"id":"baichuan-inc/Baichuan-M2-32B","match":{"or":[{"equals":"baichuan-inc/baichuan-m2-32b"},{"equals":"baichuan-inc/baichuan-m2-32b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.056,"output_mtok":0.056}},{"id":"baidu/ERNIE-4.5-21B-A3B-PT","match":{"or":[{"equals":"baidu/ernie-4.5-21b-a3b-pt"},{"equals":"baidu/ernie-4.5-21b-a3b-pt-fast"}]},"context_window":120000,"prices":{"input_mtok":0.056,"output_mtok":0.224}},{"id":"baidu/ERNIE-4.5-300B-A47B-Base-PT","match":{"or":[{"equals":"baidu/ernie-4.5-300b-a47b-base-pt"},{"equals":"baidu/ernie-4.5-300b-a47b-base-pt-fast"}]},"context_window":123000,"prices":{"input_mtok":0.224,"output_mtok":0.88}},{"id":"baidu/ERNIE-4.5-VL-28B-A3B-PT","match":{"or":[{"equals":"baidu/ernie-4.5-vl-28b-a3b-pt"},{"equals":"baidu/ernie-4.5-vl-28b-a3b-pt-fast"}]},"context_window":30000,"prices":{"input_mtok":0.112,"output_mtok":0.448}},{"id":"baidu/ERNIE-4.5-VL-424B-A47B-Base-PT","match":{"or":[{"equals":"baidu/ernie-4.5-vl-424b-a47b-base-pt"},{"equals":"baidu/ernie-4.5-vl-424b-a47b-base-pt-fast"}]},"context_window":123000,"prices":{"input_mtok":0.336,"output_mtok":1}},{"id":"deepseek-ai/DeepSeek-Prover-V2-671B","match":{"or":[{"equals":"deepseek-ai/deepseek-prover-v2-671b"},{"equals":"deepseek-ai/deepseek-prover-v2-671b-fast"}]},"context_window":160000,"prices":{"input_mtok":0.56,"output_mtok":2}},{"id":"deepseek-ai/DeepSeek-R1","match":{"or":[{"equals":"deepseek-ai/deepseek-r1"},{"equals":"deepseek-ai/deepseek-r1-fast"},{"equals":"deepseek-ai/deepseek-r1-0528"},{"equals":"deepseek-ai/deepseek-r1-0528-fast"}]},"context_window":64000,"prices":{"input_mtok":0.56,"output_mtok":2}},{"id":"deepseek-ai/DeepSeek-R1-0528-Qwen3-8B","match":{"or":[{"equals":"deepseek-ai/deepseek-r1-0528-qwen3-8b"},{"equals":"deepseek-ai/deepseek-r1-0528-qwen3-8b-fast"}]},"context_window":128000,"prices":{"input_mtok":0.048,"output_mtok":0.072}},{"id":"deepseek-ai/DeepSeek-R1-Distill-Llama-70B","match":{"or":[{"equals":"deepseek-ai/deepseek-r1-distill-llama-70b"},{"equals":"deepseek-ai/deepseek-r1-distill-llama-70b-fast"}]},"context_window":8192,"prices":{"input_mtok":0.64,"output_mtok":0.64}},{"id":"deepseek-ai/DeepSeek-R1-Distill-Qwen-14B","match":{"or":[{"equals":"deepseek-ai/deepseek-r1-distill-qwen-14b"},{"equals":"deepseek-ai/deepseek-r1-distill-qwen-14b-fast"}]},"context_window":32768,"prices":{"input_mtok":0.12,"output_mtok":0.12}},{"id":"deepseek-ai/DeepSeek-R1-Distill-Qwen-32B","match":{"or":[{"equals":"deepseek-ai/deepseek-r1-distill-qwen-32b"},{"equals":"deepseek-ai/deepseek-r1-distill-qwen-32b-fast"}]},"context_window":64000,"prices":{"input_mtok":0.24,"output_mtok":0.24}},{"id":"deepseek-ai/DeepSeek-V3","match":{"or":[{"equals":"deepseek-ai/deepseek-v3"},{"equals":"deepseek-ai/deepseek-v3-fast"}]},"context_window":64000,"prices":{"input_mtok":0.32,"output_mtok":1.04}},{"id":"deepseek-ai/DeepSeek-V3-0324","match":{"or":[{"equals":"deepseek-ai/deepseek-v3-0324"},{"equals":"deepseek-ai/deepseek-v3-0324-fast"}]},"context_window":163840,"prices":{"input_mtok":0.216,"output_mtok":0.896}},{"id":"deepseek-ai/DeepSeek-V3.1","match":{"or":[{"equals":"deepseek-ai/deepseek-v3.1"},{"equals":"deepseek-ai/deepseek-v3.1-fast"},{"equals":"deepseek-ai/deepseek-v3.1-terminus"},{"equals":"deepseek-ai/deepseek-v3.1-terminus-fast"}]},"context_window":131072,"prices":{"input_mtok":0.216,"output_mtok":0.8}},{"id":"deepseek-ai/DeepSeek-V3.2","match":{"or":[{"equals":"deepseek-ai/deepseek-v3.2"},{"equals":"deepseek-ai/deepseek-v3.2-fast"}]},"context_window":163840,"prices":{"input_mtok":0.269,"output_mtok":0.4}},{"id":"deepseek-ai/DeepSeek-V3.2-Exp","match":{"or":[{"equals":"deepseek-ai/deepseek-v3.2-exp"},{"equals":"deepseek-ai/deepseek-v3.2-exp-fast"}]},"context_window":163840,"prices":{"input_mtok":0.216,"output_mtok":0.328}},{"id":"meta-llama/Llama-3.1-8B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.1-8b-instruct"},{"equals":"meta-llama/llama-3.1-8b-instruct-fast"}]},"context_window":16384,"prices":{"input_mtok":0.02,"output_mtok":0.05}},{"id":"meta-llama/Llama-3.2-3B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.2-3b-instruct"},{"equals":"meta-llama/llama-3.2-3b-instruct-fast"}]},"context_window":32768,"prices":{"input_mtok":0.024,"output_mtok":0.04}},{"id":"meta-llama/Llama-3.3-70B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.3-70b-instruct"},{"equals":"meta-llama/llama-3.3-70b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.108,"output_mtok":0.32}},{"id":"meta-llama/Meta-Llama-3-70B-Instruct","match":{"or":[{"equals":"meta-llama/meta-llama-3-70b-instruct"},{"equals":"meta-llama/meta-llama-3-70b-instruct-fast"}]},"context_window":8192,"prices":{"input_mtok":0.51,"output_mtok":0.74}},{"id":"meta-llama/Meta-Llama-3-8B-Instruct","match":{"or":[{"equals":"meta-llama/meta-llama-3-8b-instruct"},{"equals":"meta-llama/meta-llama-3-8b-instruct-fast"}]},"context_window":8192,"prices":{"input_mtok":0.032,"output_mtok":0.032}},{"id":"moonshotai/Kimi-K2-Instruct","match":{"or":[{"equals":"moonshotai/kimi-k2-instruct"},{"equals":"moonshotai/kimi-k2-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.456,"output_mtok":1.84}},{"id":"moonshotai/Kimi-K2-Thinking","match":{"or":[{"equals":"moonshotai/kimi-k2-thinking"},{"equals":"moonshotai/kimi-k2-thinking-fast"}]},"context_window":262144,"prices":{"input_mtok":0.48,"output_mtok":2}},{"id":"openai/gpt-oss-120b","match":{"or":[{"equals":"openai/gpt-oss-120b"},{"equals":"openai/gpt-oss-120b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.04,"output_mtok":0.2}},{"id":"zai-org/AutoGLM-Phone-9B-Multilingual","match":{"or":[{"equals":"zai-org/autoglm-phone-9b-multilingual"},{"equals":"zai-org/autoglm-phone-9b-multilingual-fast"}]},"context_window":65536,"prices":{"input_mtok":0.035,"output_mtok":0.138}},{"id":"zai-org/GLM-4.1V-9B-Thinking","match":{"or":[{"equals":"zai-org/glm-4.1v-9b-thinking"},{"equals":"zai-org/glm-4.1v-9b-thinking-fast"}]},"context_window":65536,"prices":{"input_mtok":0.028,"output_mtok":0.1104}},{"id":"zai-org/GLM-4.5","match":{"or":[{"equals":"zai-org/glm-4.5"},{"equals":"zai-org/glm-4.5-fast"}]},"context_window":131072,"prices":{"input_mtok":0.48,"output_mtok":1.76}},{"id":"zai-org/GLM-4.5-Air","match":{"or":[{"equals":"zai-org/glm-4.5-air"},{"equals":"zai-org/glm-4.5-air-fast"}]},"context_window":131072,"prices":{"input_mtok":0.104,"output_mtok":0.68}},{"id":"zai-org/GLM-4.5V","match":{"or":[{"equals":"zai-org/glm-4.5v"},{"equals":"zai-org/glm-4.5v-fast"}]},"context_window":65536,"prices":{"input_mtok":0.48,"output_mtok":1.44}},{"id":"zai-org/GLM-4.6","match":{"or":[{"equals":"zai-org/glm-4.6"},{"equals":"zai-org/glm-4.6-fast"}]},"context_window":204800,"prices":{"input_mtok":0.44,"output_mtok":1.76}},{"id":"zai-org/GLM-4.6V-Flash","match":{"or":[{"equals":"zai-org/glm-4.6v-flash"},{"equals":"zai-org/glm-4.6v-flash-fast"}]},"context_window":131072,"prices":{"input_mtok":0.3,"output_mtok":0.9}}]},{"id":"huggingface_nscale","name":"HuggingFace (nscale)","pricing_urls":["https://router.huggingface.co/v1/models","https://huggingface.co/inference/models"],"api_pattern":"https://router\\.huggingface\\.co/nscale","provider_match":{"and":[{"contains":"huggingface"},{"contains":"nscale"}]},"extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["prompt_tokens_details","audio_tokens"],"dest":"input_audio_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"Qwen/QwQ-32B","match":{"or":[{"equals":"qwen/qwq-32b"},{"equals":"qwen/qwq-32b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.18,"output_mtok":0.2}},{"id":"Qwen/Qwen2.5-Coder-32B-Instruct","match":{"or":[{"equals":"qwen/qwen2.5-coder-32b-instruct"},{"equals":"qwen/qwen2.5-coder-32b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.06,"output_mtok":0.2}},{"id":"Qwen/Qwen2.5-Coder-3B-Instruct","match":{"or":[{"equals":"qwen/qwen2.5-coder-3b-instruct"},{"equals":"qwen/qwen2.5-coder-3b-instruct-fast"}]},"context_window":32768,"prices":{"input_mtok":0.01,"output_mtok":0.03}},{"id":"Qwen/Qwen2.5-Coder-7B-Instruct","match":{"or":[{"equals":"qwen/qwen2.5-coder-7b-instruct"},{"equals":"qwen/qwen2.5-coder-7b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.01,"output_mtok":0.03}},{"id":"Qwen/Qwen3-14B","match":{"or":[{"equals":"qwen/qwen3-14b"},{"equals":"qwen/qwen3-14b-fast"}]},"context_window":40960,"prices":{"input_mtok":0.07,"output_mtok":0.2}},{"id":"Qwen/Qwen3-235B-A22B","match":{"or":[{"equals":"qwen/qwen3-235b-a22b"},{"equals":"qwen/qwen3-235b-a22b-fast"},{"equals":"qwen/qwen3-235b-a22b-instruct-2507"},{"equals":"qwen/qwen3-235b-a22b-instruct-2507-fast"}]},"context_window":32000,"prices":{"input_mtok":0.2,"output_mtok":0.6}},{"id":"Qwen/Qwen3-32B","match":{"or":[{"equals":"qwen/qwen3-32b"},{"equals":"qwen/qwen3-32b-fast"}]},"context_window":40960,"prices":{"input_mtok":0.08,"output_mtok":0.25}},{"id":"Qwen/Qwen3-4B-Instruct-2507","match":{"or":[{"equals":"qwen/qwen3-4b-instruct-2507"},{"equals":"qwen/qwen3-4b-instruct-2507-fast"}]},"context_window":262144,"prices":{"input_mtok":0.01,"output_mtok":0.03}},{"id":"Qwen/Qwen3-4B-Thinking-2507","match":{"or":[{"equals":"qwen/qwen3-4b-thinking-2507"},{"equals":"qwen/qwen3-4b-thinking-2507-fast"}]},"context_window":262144,"prices":{"input_mtok":0.01,"output_mtok":0.03}},{"id":"Qwen/Qwen3-8B","match":{"or":[{"equals":"qwen/qwen3-8b"},{"equals":"qwen/qwen3-8b-fast"}]},"context_window":40960,"prices":{"input_mtok":0.07,"output_mtok":0.18}},{"id":"deepseek-ai/DeepSeek-R1-Distill-Llama-70B","match":{"or":[{"equals":"deepseek-ai/deepseek-r1-distill-llama-70b"},{"equals":"deepseek-ai/deepseek-r1-distill-llama-70b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.75,"output_mtok":0.75}},{"id":"deepseek-ai/DeepSeek-R1-Distill-Llama-8B","match":{"or":[{"equals":"deepseek-ai/deepseek-r1-distill-llama-8b"},{"equals":"deepseek-ai/deepseek-r1-distill-llama-8b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.05,"output_mtok":0.05}},{"id":"deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B","match":{"or":[{"equals":"deepseek-ai/deepseek-r1-distill-qwen-1.5b"},{"equals":"deepseek-ai/deepseek-r1-distill-qwen-1.5b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"deepseek-ai/DeepSeek-R1-Distill-Qwen-14B","match":{"or":[{"equals":"deepseek-ai/deepseek-r1-distill-qwen-14b"},{"equals":"deepseek-ai/deepseek-r1-distill-qwen-14b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"deepseek-ai/DeepSeek-R1-Distill-Qwen-32B","match":{"or":[{"equals":"deepseek-ai/deepseek-r1-distill-qwen-32b"},{"equals":"deepseek-ai/deepseek-r1-distill-qwen-32b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.3,"output_mtok":0.3}},{"id":"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B","match":{"or":[{"equals":"deepseek-ai/deepseek-r1-distill-qwen-7b"},{"equals":"deepseek-ai/deepseek-r1-distill-qwen-7b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.15,"output_mtok":0.15}},{"id":"meta-llama/Llama-3.1-8B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.1-8b-instruct"},{"equals":"meta-llama/llama-3.1-8b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.06,"output_mtok":0.06}},{"id":"meta-llama/Llama-3.3-70B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.3-70b-instruct"},{"equals":"meta-llama/llama-3.3-70b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.4,"output_mtok":0.4}},{"id":"openai/gpt-oss-120b","match":{"or":[{"equals":"openai/gpt-oss-120b"},{"equals":"openai/gpt-oss-120b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.1,"output_mtok":0.4}}]},{"id":"huggingface_ovhcloud","name":"HuggingFace (ovhcloud)","pricing_urls":["https://router.huggingface.co/v1/models","https://huggingface.co/inference/models"],"api_pattern":"https://router\\.huggingface\\.co/ovhcloud","provider_match":{"and":[{"contains":"huggingface"},{"contains":"ovhcloud"}]},"extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["prompt_tokens_details","audio_tokens"],"dest":"input_audio_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"Qwen/Qwen2.5-VL-72B-Instruct","match":{"or":[{"equals":"qwen/qwen2.5-vl-72b-instruct"},{"equals":"qwen/qwen2.5-vl-72b-instruct-fast"}]},"context_window":32768,"prices":{"input_mtok":1.01,"output_mtok":1.01}},{"id":"Qwen/Qwen3-32B","match":{"or":[{"equals":"qwen/qwen3-32b"},{"equals":"qwen/qwen3-32b-fast"}]},"context_window":32768,"prices":{"input_mtok":0.09,"output_mtok":0.25}},{"id":"Qwen/Qwen3-Coder-30B-A3B-Instruct","match":{"or":[{"equals":"qwen/qwen3-coder-30b-a3b-instruct"},{"equals":"qwen/qwen3-coder-30b-a3b-instruct-fast"}]},"context_window":262144,"prices":{"input_mtok":0.07,"output_mtok":0.26}},{"id":"deepseek-ai/DeepSeek-R1-Distill-Llama-70B","match":{"or":[{"equals":"deepseek-ai/deepseek-r1-distill-llama-70b"},{"equals":"deepseek-ai/deepseek-r1-distill-llama-70b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.74,"output_mtok":0.74}},{"id":"meta-llama/Llama-3.1-8B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.1-8b-instruct"},{"equals":"meta-llama/llama-3.1-8b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.11,"output_mtok":0.11}},{"id":"meta-llama/Llama-3.3-70B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.3-70b-instruct"},{"equals":"meta-llama/llama-3.3-70b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.74,"output_mtok":0.74}},{"id":"openai/gpt-oss-120b","match":{"or":[{"equals":"openai/gpt-oss-120b"},{"equals":"openai/gpt-oss-120b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.09,"output_mtok":0.47}}]},{"id":"huggingface_publicai","name":"HuggingFace (publicai)","pricing_urls":["https://router.huggingface.co/v1/models","https://huggingface.co/inference/models"],"api_pattern":"https://router\\.huggingface\\.co/publicai","provider_match":{"and":[{"contains":"huggingface"},{"contains":"publicai"}]},"extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["prompt_tokens_details","audio_tokens"],"dest":"input_audio_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[]},{"id":"huggingface_sambanova","name":"HuggingFace (sambanova)","pricing_urls":["https://router.huggingface.co/v1/models","https://huggingface.co/inference/models"],"api_pattern":"https://router\\.huggingface\\.co/sambanova","provider_match":{"and":[{"contains":"huggingface"},{"contains":"sambanova"}]},"extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["prompt_tokens_details","audio_tokens"],"dest":"input_audio_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"Qwen/Qwen3-32B","match":{"or":[{"equals":"qwen/qwen3-32b"},{"equals":"qwen/qwen3-32b-fast"}]},"context_window":32768,"prices":{"input_mtok":0.4,"output_mtok":0.8}},{"id":"deepseek-ai/DeepSeek-R1-0528","match":{"or":[{"equals":"deepseek-ai/deepseek-r1-0528"},{"equals":"deepseek-ai/deepseek-r1-0528-fast"}]},"context_window":131072,"prices":{"input_mtok":5,"output_mtok":7}},{"id":"deepseek-ai/DeepSeek-R1-Distill-Llama-70B","match":{"or":[{"equals":"deepseek-ai/deepseek-r1-distill-llama-70b"},{"equals":"deepseek-ai/deepseek-r1-distill-llama-70b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.7,"output_mtok":1.4}},{"id":"deepseek-ai/DeepSeek-V3-0324","match":{"or":[{"equals":"deepseek-ai/deepseek-v3-0324"},{"equals":"deepseek-ai/deepseek-v3-0324-fast"}]},"context_window":131072,"prices":{"input_mtok":3,"output_mtok":4.5}},{"id":"meta-llama/Llama-3.1-8B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.1-8b-instruct"},{"equals":"meta-llama/llama-3.1-8b-instruct-fast"}]},"context_window":16384,"prices":{"input_mtok":0.1,"output_mtok":0.2}},{"id":"meta-llama/Llama-3.3-70B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.3-70b-instruct"},{"equals":"meta-llama/llama-3.3-70b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.6,"output_mtok":1.2}},{"id":"openai/gpt-oss-120b","match":{"or":[{"equals":"openai/gpt-oss-120b"},{"equals":"openai/gpt-oss-120b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.22,"output_mtok":0.59}},{"id":"tokyotech-llm/Llama-3.3-Swallow-70B-Instruct-v0.4","match":{"or":[{"equals":"tokyotech-llm/llama-3.3-swallow-70b-instruct-v0.4"},{"equals":"tokyotech-llm/llama-3.3-swallow-70b-instruct-v0.4-fast"}]},"context_window":131072,"prices":{"input_mtok":0.6,"output_mtok":1.2}}]},{"id":"huggingface_together","name":"HuggingFace (together)","pricing_urls":["https://router.huggingface.co/v1/models","https://huggingface.co/inference/models"],"api_pattern":"https://router\\.huggingface\\.co/together","provider_match":{"and":[{"contains":"huggingface"},{"contains":"together"}]},"extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["prompt_tokens_details","audio_tokens"],"dest":"input_audio_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"EssentialAI/rnj-1-instruct","match":{"or":[{"equals":"essentialai/rnj-1-instruct"},{"equals":"essentialai/rnj-1-instruct-fast"}]},"context_window":32768,"prices":{"input_mtok":0.15,"output_mtok":0.15}},{"id":"Qwen/Qwen2.5-72B-Instruct","match":{"or":[{"equals":"qwen/qwen2.5-72b-instruct"},{"equals":"qwen/qwen2.5-72b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":1.2,"output_mtok":1.2}},{"id":"Qwen/Qwen2.5-7B-Instruct","match":{"or":[{"equals":"qwen/qwen2.5-7b-instruct"},{"equals":"qwen/qwen2.5-7b-instruct-fast"}]},"context_window":32768,"prices":{"input_mtok":0.3,"output_mtok":0.3}},{"id":"Qwen/Qwen3-235B-A22B","match":{"or":[{"equals":"qwen/qwen3-235b-a22b"},{"equals":"qwen/qwen3-235b-a22b-fast"},{"equals":"qwen/qwen3-235b-a22b-fp8"},{"equals":"qwen/qwen3-235b-a22b-fp8-fast"},{"equals":"qwen/qwen3-235b-a22b-instruct-2507"},{"equals":"qwen/qwen3-235b-a22b-instruct-2507-fast"}]},"context_window":40960,"prices":{"input_mtok":0.2,"output_mtok":0.6}},{"id":"Qwen/Qwen3-Coder-480B-A35B-Instruct","match":{"or":[{"equals":"qwen/qwen3-coder-480b-a35b-instruct"},{"equals":"qwen/qwen3-coder-480b-a35b-instruct-fast"},{"equals":"qwen/qwen3-coder-480b-a35b-instruct-fp8"},{"equals":"qwen/qwen3-coder-480b-a35b-instruct-fp8-fast"}]},"context_window":262144,"prices":{"input_mtok":2,"output_mtok":2}},{"id":"Qwen/Qwen3-Next-80B-A3B-Instruct","match":{"or":[{"equals":"qwen/qwen3-next-80b-a3b-instruct"},{"equals":"qwen/qwen3-next-80b-a3b-instruct-fast"}]},"context_window":262144,"prices":{"input_mtok":0.15,"output_mtok":1.5}},{"id":"Qwen/Qwen3-Next-80B-A3B-Thinking","match":{"or":[{"equals":"qwen/qwen3-next-80b-a3b-thinking"},{"equals":"qwen/qwen3-next-80b-a3b-thinking-fast"}]},"context_window":262144,"prices":{"input_mtok":0.15,"output_mtok":1.5}},{"id":"Qwen/Qwen3-VL-32B-Instruct","match":{"or":[{"equals":"qwen/qwen3-vl-32b-instruct"},{"equals":"qwen/qwen3-vl-32b-instruct-fast"}]},"context_window":262144,"prices":{"input_mtok":0.5,"output_mtok":1.5}},{"id":"deepcogito/cogito-671b-v2.1","match":{"or":[{"equals":"deepcogito/cogito-671b-v2.1"},{"equals":"deepcogito/cogito-671b-v2.1-fast"},{"equals":"deepcogito/cogito-671b-v2.1-fp8"},{"equals":"deepcogito/cogito-671b-v2.1-fp8-fast"}]},"context_window":163840,"prices":{"input_mtok":1.25,"output_mtok":1.25}},{"id":"deepcogito/cogito-v2-preview-llama-405B","match":{"or":[{"equals":"deepcogito/cogito-v2-preview-llama-405b"},{"equals":"deepcogito/cogito-v2-preview-llama-405b-fast"}]},"context_window":32768,"prices":{"input_mtok":3.5,"output_mtok":3.5}},{"id":"deepcogito/cogito-v2-preview-llama-70B","match":{"or":[{"equals":"deepcogito/cogito-v2-preview-llama-70b"},{"equals":"deepcogito/cogito-v2-preview-llama-70b-fast"}]},"context_window":32768,"prices":{"input_mtok":0.88,"output_mtok":0.88}},{"id":"deepseek-ai/DeepSeek-R1","match":{"or":[{"equals":"deepseek-ai/deepseek-r1"},{"equals":"deepseek-ai/deepseek-r1-fast"},{"equals":"deepseek-ai/deepseek-r1-0528"},{"equals":"deepseek-ai/deepseek-r1-0528-fast"}]},"context_window":163840,"prices":{"input_mtok":3,"output_mtok":7}},{"id":"deepseek-ai/DeepSeek-V3","match":{"or":[{"equals":"deepseek-ai/deepseek-v3"},{"equals":"deepseek-ai/deepseek-v3-fast"},{"equals":"deepseek-ai/deepseek-v3-0324"},{"equals":"deepseek-ai/deepseek-v3-0324-fast"}]},"context_window":131072,"prices":{"input_mtok":1.25,"output_mtok":1.25}},{"id":"deepseek-ai/DeepSeek-V3.1","match":{"or":[{"equals":"deepseek-ai/deepseek-v3.1"},{"equals":"deepseek-ai/deepseek-v3.1-fast"}]},"context_window":131072,"prices":{"input_mtok":0.6,"output_mtok":1.7}},{"id":"marin-community/marin-8b-instruct","match":{"or":[{"equals":"marin-community/marin-8b-instruct"},{"equals":"marin-community/marin-8b-instruct-fast"}]},"context_window":4096,"prices":{"input_mtok":0.18000000000000002,"output_mtok":0.18000000000000002}},{"id":"meta-llama/Llama-3.2-3B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.2-3b-instruct"},{"equals":"meta-llama/llama-3.2-3b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.060000000000000005,"output_mtok":0.060000000000000005}},{"id":"meta-llama/Llama-3.3-70B-Instruct","match":{"or":[{"equals":"meta-llama/llama-3.3-70b-instruct"},{"equals":"meta-llama/llama-3.3-70b-instruct-fast"}]},"context_window":131072,"prices":{"input_mtok":0.88,"output_mtok":0.88}},{"id":"meta-llama/Meta-Llama-3-70B-Instruct","match":{"or":[{"equals":"meta-llama/meta-llama-3-70b-instruct"},{"equals":"meta-llama/meta-llama-3-70b-instruct-fast"}]},"context_window":8192,"prices":{"input_mtok":0.88,"output_mtok":0.88}},{"id":"moonshotai/Kimi-K2-Instruct","match":{"or":[{"equals":"moonshotai/kimi-k2-instruct"},{"equals":"moonshotai/kimi-k2-instruct-fast"},{"equals":"moonshotai/kimi-k2-instruct-0905"},{"equals":"moonshotai/kimi-k2-instruct-0905-fast"}]},"context_window":131072,"prices":{"input_mtok":1,"output_mtok":3}},{"id":"moonshotai/Kimi-K2-Thinking","match":{"or":[{"equals":"moonshotai/kimi-k2-thinking"},{"equals":"moonshotai/kimi-k2-thinking-fast"}]},"context_window":262144,"prices":{"input_mtok":1.2,"output_mtok":4}},{"id":"openai/gpt-oss-120b","match":{"or":[{"equals":"openai/gpt-oss-120b"},{"equals":"openai/gpt-oss-120b-fast"}]},"context_window":131072,"prices":{"input_mtok":0.15,"output_mtok":0.6}},{"id":"zai-org/GLM-4.5-Air-FP8","match":{"or":[{"equals":"zai-org/glm-4.5-air-fp8"},{"equals":"zai-org/glm-4.5-air-fp8-fast"}]},"context_window":131072,"prices":{"input_mtok":0.2,"output_mtok":1.1}}]},{"id":"mistral","name":"Mistral","pricing_urls":["https://mistral.ai/pricing#api-pricing"],"api_pattern":"https://api\\.mistral\\.ai","model_match":{"regex":"(?:mi|code|dev|magi|mini)stral"},"provider_match":{"starts_with":"mistral"},"extractors":[{"api_flavor":"default","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"codestral","match":{"or":[{"equals":"codestral-latest"},{"equals":"codestral-2501"}]},"prices":{"input_mtok":0.3,"output_mtok":0.9}},{"id":"devstral-small","match":{"equals":"devstral-small"},"prices":{"input_mtok":0.06,"output_mtok":0.12}},{"id":"magistral-medium","match":{"or":[{"starts_with":"magistral-medium"}]},"prices":{"input_mtok":2,"output_mtok":5}},{"id":"magistral-small","match":{"starts_with":"magistral-small-"},"prices":{"input_mtok":0.5,"output_mtok":1.5}},{"id":"ministral-3b","match":{"equals":"ministral-3b"},"prices":{"input_mtok":0.04,"output_mtok":0.04}},{"id":"ministral-8b","match":{"starts_with":"ministral-8b"},"prices":{"input_mtok":0.1,"output_mtok":1}},{"id":"mistral-7b","match":{"or":[{"equals":"mistral-7b"},{"equals":"open-mistral-7b"}]},"prices":{"input_mtok":0.25,"output_mtok":0.25}},{"id":"mistral-embed","match":{"equals":"mistral-embed"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"mistral-large","match":{"or":[{"equals":"mistral-large"},{"equals":"mistral-large-latest"},{"equals":"mistral-large-2407"},{"equals":"mistral-large-2411"}]},"prices":{"input_mtok":2,"output_mtok":6}},{"id":"mistral-medium-3","match":{"starts_with":"mistral-medium"},"prices":{"input_mtok":0.4,"output_mtok":2}},{"id":"mistral-nemo","match":{"or":[{"equals":"mistral-nemo"},{"equals":"open-mistral-nemo"}]},"prices":{"input_mtok":0.15,"output_mtok":0.15}},{"id":"mistral-saba","match":{"or":[{"equals":"mistral-saba"},{"equals":"mistral-saba-latest"}]},"prices":{"input_mtok":0.2,"output_mtok":0.6}},{"id":"mistral-small-24b-instruct-2501","match":{"equals":"mistral-small-24b-instruct-2501"},"prices":{"input_mtok":0.05,"output_mtok":0.08}},{"id":"mistral-small-latest","match":{"equals":"mistral-small-latest"},"prices":{"input_mtok":0.1,"output_mtok":0.3}},{"id":"mistral-tiny","match":{"equals":"mistral-tiny"},"prices":{"input_mtok":0.25,"output_mtok":0.25},"deprecated":true},{"id":"mixtral-8x22b-instruct","match":{"equals":"mixtral-8x22b-instruct"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"mixtral-8x7b","match":{"or":[{"starts_with":"mixtral-8x7b"},{"equals":"open-mixtral-8x7b"}]},"prices":{"input_mtok":0.7,"output_mtok":0.7}},{"id":"pixtral-12b","match":{"or":[{"equals":"pixtral-12b"},{"equals":"pixtral-12b-latest"}]},"prices":{"input_mtok":0.15,"output_mtok":0.15}},{"id":"pixtral-large","match":{"or":[{"equals":"pixtral-large-latest"},{"equals":"pixtral-large-2411"}]},"prices":{"input_mtok":2,"output_mtok":6}}]},{"id":"novita","name":"Novita","pricing_urls":["https://novita.ai/pricing"],"api_pattern":"https://api\\.novita\\.ai","models":[{"id":"Sao10K/L3-8B-Stheno-v3.2","match":{"equals":"Sao10K/L3-8B-Stheno-v3.2"},"prices":{"input_mtok":0.05,"output_mtok":0.05}},{"id":"cognitivecomputations/dolphin-mixtral-8x22b","match":{"equals":"cognitivecomputations/dolphin-mixtral-8x22b"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"deepseek/deepseek-r1","match":{"equals":"deepseek/deepseek-r1"},"prices":{"input_mtok":4,"output_mtok":4}},{"id":"deepseek/deepseek-r1-distill-llama-70b","match":{"equals":"deepseek/deepseek-r1-distill-llama-70b"},"prices":{"input_mtok":0.8,"output_mtok":0.8}},{"id":"deepseek/deepseek-r1-distill-llama-8b","match":{"equals":"deepseek/deepseek-r1-distill-llama-8b"},"prices":{"input_mtok":0.04,"output_mtok":0.04}},{"id":"deepseek/deepseek-r1-distill-qwen-14b","match":{"equals":"deepseek/deepseek-r1-distill-qwen-14b"},"prices":{"input_mtok":0.15,"output_mtok":0.15}},{"id":"deepseek/deepseek-r1-distill-qwen-32b","match":{"equals":"deepseek/deepseek-r1-distill-qwen-32b"},"prices":{"input_mtok":0.3,"output_mtok":0.3}},{"id":"deepseek/deepseek_v3","match":{"equals":"deepseek/deepseek_v3"},"prices":{"input_mtok":0.89,"output_mtok":0.89}},{"id":"google/gemma-2-9b-it","match":{"equals":"google/gemma-2-9b-it"},"prices":{"input_mtok":0.08,"output_mtok":0.08}},{"id":"gryphe/mythomax-l2-13b","match":{"equals":"gryphe/mythomax-l2-13b"},"prices":{"input_mtok":0.09,"output_mtok":0.09}},{"id":"jondurbin/airoboros-l2-70b","match":{"equals":"jondurbin/airoboros-l2-70b"},"prices":{"input_mtok":0.5,"output_mtok":0.5}},{"id":"meta-llama/llama-3-70b-instruct","match":{"equals":"meta-llama/llama-3-70b-instruct"},"prices":{"input_mtok":0.51,"output_mtok":0.74}},{"id":"meta-llama/llama-3-8b-instruct","match":{"equals":"meta-llama/llama-3-8b-instruct"},"prices":{"input_mtok":0.04,"output_mtok":0.04}},{"id":"meta-llama/llama-3.1-70b-instruct","match":{"equals":"meta-llama/llama-3.1-70b-instruct"},"prices":{"input_mtok":0.34,"output_mtok":0.39}},{"id":"meta-llama/llama-3.1-8b-instruct","match":{"or":[{"equals":"meta-llama/llama-3.1-8b-instruct"},{"equals":"meta-llama/llama-3.1-8b-instruct-max"}]},"prices":{"input_mtok":0.05,"output_mtok":0.05}},{"id":"meta-llama/llama-3.1-8b-instruct-bf16","match":{"equals":"meta-llama/llama-3.1-8b-instruct-bf16"},"prices":{"input_mtok":0.06,"output_mtok":0.06}},{"id":"meta-llama/llama-3.2-11b-vision-instruct","match":{"equals":"meta-llama/llama-3.2-11b-vision-instruct"},"prices":{"input_mtok":0.06,"output_mtok":0.06}},{"id":"meta-llama/llama-3.2-1b-instruct","match":{"equals":"meta-llama/llama-3.2-1b-instruct"},"prices":{"input_mtok":0.02,"output_mtok":0.02}},{"id":"meta-llama/llama-3.2-3b-instruct","match":{"equals":"meta-llama/llama-3.2-3b-instruct"},"prices":{"input_mtok":0.03,"output_mtok":0.05}},{"id":"meta-llama/llama-3.3-70b-instruct","match":{"equals":"meta-llama/llama-3.3-70b-instruct"},"prices":{"input_mtok":0.39,"output_mtok":0.39}},{"id":"microsoft/wizardlm-2-8x22b","match":{"equals":"microsoft/wizardlm-2-8x22b"},"prices":{"input_mtok":0.62,"output_mtok":0.62}},{"id":"mistralai/mistral-7b-instruct","match":{"equals":"mistralai/mistral-7b-instruct"},"prices":{"input_mtok":0.059,"output_mtok":0.059}},{"id":"mistralai/mistral-nemo","match":{"equals":"mistralai/mistral-nemo"},"prices":{"input_mtok":0.17,"output_mtok":0.17}},{"id":"nousresearch/hermes-2-pro-llama-3-8b","match":{"equals":"nousresearch/hermes-2-pro-llama-3-8b"},"prices":{"input_mtok":0.14,"output_mtok":0.14}},{"id":"nousresearch/nous-hermes-llama2-13b","match":{"equals":"nousresearch/nous-hermes-llama2-13b"},"prices":{"input_mtok":0.17,"output_mtok":0.17}},{"id":"openchat/openchat-7b","match":{"equals":"openchat/openchat-7b"},"prices":{"input_mtok":0.06,"output_mtok":0.06}},{"id":"qwen/qwen-2-7b-instruct","match":{"equals":"qwen/qwen-2-7b-instruct"},"prices":{"input_mtok":0.054,"output_mtok":0.054}},{"id":"qwen/qwen-2-vl-72b-instruct","match":{"equals":"qwen/qwen-2-vl-72b-instruct"},"prices":{"input_mtok":0.45,"output_mtok":0.45}},{"id":"qwen/qwen-2.5-72b-instruct","match":{"equals":"qwen/qwen-2.5-72b-instruct"},"prices":{"input_mtok":0.38,"output_mtok":0.4}},{"id":"sao10k/l3-70b-euryale-v2.1","match":{"equals":"sao10k/l3-70b-euryale-v2.1"},"prices":{"input_mtok":1.48,"output_mtok":1.48}},{"id":"sao10k/l3-8b-lunaris","match":{"equals":"sao10k/l3-8b-lunaris"},"prices":{"input_mtok":0.05,"output_mtok":0.05}},{"id":"sao10k/l31-70b-euryale-v2.2","match":{"equals":"sao10k/l31-70b-euryale-v2.2"},"prices":{"input_mtok":1.48,"output_mtok":1.48}},{"id":"sophosympatheia/midnight-rose-70b","match":{"equals":"sophosympatheia/midnight-rose-70b"},"prices":{"input_mtok":0.8,"output_mtok":0.8}},{"id":"teknium/openhermes-2.5-mistral-7b","match":{"equals":"teknium/openhermes-2.5-mistral-7b"},"prices":{"input_mtok":0.17,"output_mtok":0.17}}]},{"id":"openai","name":"OpenAI","pricing_urls":["https://platform.openai.com/docs/pricing","https://openai.com/api/pricing/","https://platform.openai.com/docs/models","https://help.openai.com/en/articles/7127956-how-much-does-gpt-4-cost"],"api_pattern":"https://api\\.openai\\.com","model_match":{"or":[{"starts_with":"gpt-"},{"regex":"^o[134]"}]},"provider_match":{"contains":"openai"},"extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["prompt_tokens_details","audio_tokens"],"dest":"input_audio_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]},{"api_flavor":"responses","root":"usage","model_path":"model","mappings":[{"path":"input_tokens","dest":"input_tokens","required":true},{"path":["input_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":"output_tokens","dest":"output_tokens","required":true}]},{"api_flavor":"embeddings","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true}]}],"models":[{"id":"ada","match":{"or":[{"equals":"ada"},{"equals":"text-ada-001"}]},"prices":{"input_mtok":0.4,"output_mtok":0.4}},{"id":"babbage","match":{"equals":"babbage"},"prices":{"input_mtok":0.5,"output_mtok":0.5}},{"id":"chatgpt-4o-latest","match":{"equals":"chatgpt-4o-latest"},"prices":{"input_mtok":5,"output_mtok":15}},{"id":"codex-mini","match":{"or":[{"equals":"codex-mini"},{"equals":"codex-mini-latest"}]},"prices":{"input_mtok":1.5,"cache_read_mtok":0.375,"output_mtok":6}},{"id":"computer-use","match":{"starts_with":"computer-use"},"prices":{"input_mtok":3,"output_mtok":12}},{"id":"curie","match":{"or":[{"equals":"curie"},{"equals":"text-curie-001"}]},"prices":{"input_mtok":2,"output_mtok":2}},{"id":"davinci","match":{"or":[{"equals":"davinci"},{"equals":"text-davinci-001"}]},"prices":{"input_mtok":20,"output_mtok":20}},{"id":"ft:gpt-3.5-turbo-","match":{"starts_with":"ft:gpt-3.5-turbo"},"prices":{"input_mtok":3,"output_mtok":6}},{"id":"ft:gpt-4o","match":{"starts_with":"ft:gpt-4o-2024-"},"prices":{"input_mtok":3.75,"output_mtok":15}},{"id":"ft:gpt-4o-mini","match":{"starts_with":"ft:gpt-4o-mini-2024-"},"prices":{"input_mtok":0.3,"output_mtok":1.2}},{"id":"gpt-3.5-0301","match":{"or":[{"equals":"gpt-3.5-turbo-0301"},{"equals":"gpt-3.5-0301"}]},"prices":{"input_mtok":1.5,"output_mtok":2}},{"id":"gpt-3.5-turbo","match":{"or":[{"equals":"gpt-3.5-turbo"},{"equals":"gpt-35-turbo"},{"equals":"gpt-3.5-turbo-0125"}]},"context_window":16385,"prices":{"input_mtok":0.5,"output_mtok":1.5}},{"id":"gpt-3.5-turbo-0613","match":{"equals":"gpt-3.5-turbo-0613"},"context_window":16385,"prices":{"input_mtok":1.5,"output_mtok":2}},{"id":"gpt-3.5-turbo-1106","match":{"equals":"gpt-3.5-turbo-1106"},"context_window":16385,"prices":{"input_mtok":1,"output_mtok":2}},{"id":"gpt-3.5-turbo-16k","match":{"or":[{"equals":"gpt-3.5-turbo-16k"},{"equals":"gpt-3.5-turbo-16k-0613"},{"equals":"gpt-35-turbo-16k-0613"},{"equals":"gpt-35-turbo-16k"}]},"context_window":16385,"prices":{"input_mtok":3,"output_mtok":4}},{"id":"gpt-3.5-turbo-instruct","match":{"or":[{"starts_with":"gpt-3.5-turbo-instruct"},{"equals":"gpt-3.5-turbo-instruct-0914"}]},"context_window":16385,"prices":{"input_mtok":1.5,"output_mtok":2}},{"id":"gpt-4","match":{"or":[{"equals":"gpt-4"},{"equals":"gpt-4-0314"},{"equals":"gpt-4-0613"},{"starts_with":"ft:gpt-4-0"}]},"context_window":8192,"prices":{"input_mtok":30,"output_mtok":60}},{"id":"gpt-4-32k","match":{"or":[{"equals":"gpt-4-32k"},{"equals":"gpt-4-32k-0314"},{"equals":"gpt-4-32k-0613"}]},"context_window":32000,"prices":{"input_mtok":60,"output_mtok":120}},{"id":"gpt-4-turbo","match":{"or":[{"equals":"gpt-4-turbo"},{"equals":"gpt-4-turbo-2024-04-09"},{"equals":"gpt-4-turbo-0125-preview"},{"equals":"gpt-4-0125-preview"},{"equals":"gpt-4-1106-preview"},{"equals":"gpt-4-turbo-preview"}]},"context_window":128000,"prices":{"input_mtok":10,"output_mtok":30}},{"id":"gpt-4-vision-preview","match":{"or":[{"equals":"gpt-4-vision-preview"},{"equals":"gpt-4-1106-vision-preview"}]},"context_window":128000,"prices":{"input_mtok":10,"output_mtok":30}},{"id":"gpt-4.1","match":{"or":[{"equals":"gpt-4.1"},{"equals":"gpt-4.1-2025-04-14"}]},"context_window":1000000,"prices":{"input_mtok":2,"cache_read_mtok":0.5,"output_mtok":8}},{"id":"gpt-4.1-mini","match":{"or":[{"equals":"gpt-4.1-mini"},{"equals":"gpt-4.1-mini-2025-04-14"}]},"context_window":1000000,"prices":{"input_mtok":0.4,"cache_read_mtok":0.1,"output_mtok":1.6}},{"id":"gpt-4.1-nano","match":{"or":[{"equals":"gpt-4.1-nano"},{"equals":"gpt-4.1-nano-2025-04-14"}]},"context_window":1000000,"prices":{"input_mtok":0.1,"cache_read_mtok":0.025,"output_mtok":0.4}},{"id":"gpt-4.5-preview","match":{"starts_with":"gpt-4.5-preview"},"prices":{"input_mtok":75,"cache_read_mtok":37.5,"output_mtok":150}},{"id":"gpt-4o","match":{"or":[{"equals":"gpt-4o"},{"equals":"gpt-4o-2024-05-13"},{"equals":"gpt-4o-2024-08-06"},{"equals":"gpt-4o-2024-11-20"}]},"context_window":128000,"prices":{"input_mtok":2.5,"cache_read_mtok":1.25,"output_mtok":10}},{"id":"gpt-4o-audio-preview","match":{"starts_with":"gpt-4o-audio-preview"},"context_window":128000,"prices":{"output_mtok":10,"input_audio_mtok":2.5}},{"id":"gpt-4o-mini","match":{"or":[{"equals":"gpt-4o-mini"},{"equals":"gpt-4o-mini-2024-07-18"},{"equals":"gpt-4o-mini-search-preview"},{"equals":"gpt-4o-mini-search-preview-2025-03-11"}]},"context_window":128000,"prices":{"input_mtok":0.15,"cache_read_mtok":0.075,"output_mtok":0.6}},{"id":"gpt-4o-mini-2024-07-18.ft-","match":{"starts_with":"gpt-4o-mini-2024-07-18.ft-"},"prices":{"input_mtok":0.3,"output_mtok":1.2}},{"id":"gpt-4o-mini-audio-preview","match":{"starts_with":"gpt-4o-mini-audio"},"prices":{"output_mtok":0.6,"input_audio_mtok":0.15}},{"id":"gpt-4o-mini-realtime-preview","match":{"starts_with":"gpt-4o-mini-realtime"},"prices":{"input_mtok":0.6,"cache_read_mtok":0.3,"output_mtok":2.4,"input_audio_mtok":10,"cache_audio_read_mtok":0.3,"output_audio_mtok":20}},{"id":"gpt-4o-mini-transcribe","match":{"equals":"gpt-4o-mini-transcribe"},"prices":{"input_mtok":1.25,"output_mtok":5,"input_audio_mtok":3}},{"id":"gpt-4o-mini-tts","match":{"equals":"gpt-4o-mini-tts"},"prices":{"input_mtok":0.6,"output_audio_mtok":12}},{"id":"gpt-4o-realtime-preview","match":{"starts_with":"gpt-4o-realtime"},"prices":{"input_mtok":5,"cache_read_mtok":2.5,"output_mtok":20,"input_audio_mtok":40,"cache_audio_read_mtok":2.5,"output_audio_mtok":80}},{"id":"gpt-4o-search-preview","match":{"or":[{"equals":"gpt-4o-search-preview"},{"equals":"gpt-4o-search-preview-2025-03-11"}]},"prices":{"input_mtok":2.5,"output_mtok":10}},{"id":"gpt-4o-transcribe","match":{"or":[{"equals":"gpt-4o-transcribe"},{"equals":"gpt-4o-transcribe-diarize"}]},"prices":{"input_mtok":2.5,"output_mtok":10,"input_audio_mtok":6}},{"id":"gpt-4o:extended","match":{"equals":"gpt-4o:extended"},"prices":{"input_mtok":6,"output_mtok":18}},{"id":"gpt-5","match":{"or":[{"equals":"gpt-5"},{"equals":"gpt-5-2025-08-07"},{"equals":"gpt-5-chat"},{"equals":"gpt-5-chat-latest"},{"equals":"gpt-5-codex"}]},"context_window":400000,"prices":{"input_mtok":1.25,"cache_read_mtok":0.125,"output_mtok":10}},{"id":"gpt-5-image","match":{"equals":"gpt-5-image"},"prices":{"input_mtok":10,"cache_read_mtok":1.25,"output_mtok":10}},{"id":"gpt-5-image-mini","match":{"equals":"gpt-5-image-mini"},"prices":{"input_mtok":2.5,"cache_read_mtok":0.25,"output_mtok":2}},{"id":"gpt-5-mini","match":{"or":[{"equals":"gpt-5-mini"},{"equals":"gpt-5-mini-2025-08-07"}]},"context_window":400000,"prices":{"input_mtok":0.25,"cache_read_mtok":0.025,"output_mtok":2}},{"id":"gpt-5-nano","match":{"or":[{"equals":"gpt-5-nano"},{"starts_with":"gpt-5-nano-"}]},"context_window":400000,"prices":{"input_mtok":0.05,"cache_read_mtok":0.005,"output_mtok":0.4}},{"id":"gpt-5-pro","match":{"or":[{"equals":"gpt-5-pro"},{"equals":"gpt-5-pro-2025-10-06"}]},"context_window":400000,"prices":{"input_mtok":15,"output_mtok":120}},{"id":"gpt-5.1","match":{"or":[{"equals":"gpt-5.1"},{"equals":"gpt-5.1-2025-11-13"},{"equals":"gpt-5.1-codex"},{"equals":"gpt-5.1-codex-max"},{"equals":"gpt-5.1-chat"},{"equals":"gpt-5.1-chat-latest"},{"equals":"gpt-5-1"},{"equals":"gpt-5-1-2025-11-13"},{"equals":"gpt-5-1-codex"},{"equals":"gpt-5-1-codex-max"},{"equals":"gpt-5-1-chat"},{"equals":"gpt-5-1-chat-latest"}]},"context_window":400000,"prices":{"input_mtok":1.25,"cache_read_mtok":0.125,"output_mtok":10}},{"id":"gpt-5.1-codex-mini","match":{"or":[{"equals":"gpt-5.1-codex-mini"},{"equals":"gpt-5.1-mini"},{"equals":"gpt-5-1-codex-mini"},{"equals":"gpt-5-1-mini"}]},"context_window":400000,"prices":{"input_mtok":0.25,"cache_read_mtok":0.025,"output_mtok":2}},{"id":"gpt-5.2","match":{"or":[{"equals":"gpt-5.2"},{"equals":"gpt-5.2-2025-12-11"},{"equals":"gpt-5-2"},{"equals":"gpt-5-2-2025-12-11"},{"equals":"gpt-5.2-chat"},{"equals":"gpt-5.2-chat-latest"},{"equals":"gpt-5-2-chat"},{"equals":"gpt-5-2-chat-latest"},{"equals":"gpt-5.2-codex"},{"equals":"gpt-5-2-codex"}]},"context_window":400000,"prices":{"input_mtok":1.75,"cache_read_mtok":0.175,"output_mtok":14}},{"id":"gpt-5.2-pro","match":{"or":[{"equals":"gpt-5.2-pro"},{"equals":"gpt-5.2-pro-2025-12-11"},{"equals":"gpt-5-2-pro-2025-12-11"}]},"context_window":400000,"prices":{"input_mtok":21,"output_mtok":168}},{"id":"gpt-realtime","match":{"or":[{"equals":"gpt-realtime"},{"equals":"gpt-realtime-2025-08-28"}]},"prices":{"input_mtok":4,"cache_read_mtok":0.4,"output_mtok":16,"input_audio_mtok":32,"cache_audio_read_mtok":0.4,"output_audio_mtok":64}},{"id":"gpt-realtime-mini","match":{"equals":"gpt-realtime-mini"},"prices":{"input_mtok":0.6,"cache_read_mtok":0.06,"output_mtok":2.4,"input_audio_mtok":10,"cache_audio_read_mtok":0.3,"output_audio_mtok":20}},{"id":"o1","match":{"or":[{"equals":"o1"},{"equals":"o1-2024-12-17"},{"equals":"o1-preview"},{"equals":"o1-preview-2024-09-12"}]},"context_window":128000,"prices":{"input_mtok":15,"cache_read_mtok":7.5,"output_mtok":60}},{"id":"o1-mini","match":{"or":[{"equals":"o1-mini"},{"equals":"o1-mini-2024-09-12"}]},"context_window":128000,"prices":{"input_mtok":1.1,"cache_read_mtok":0.55,"output_mtok":4.4}},{"id":"o1-pro","match":{"or":[{"equals":"o1-pro"},{"equals":"o1-pro-2025-03-19"}]},"prices":{"input_mtok":150,"output_mtok":600}},{"id":"o3","match":{"or":[{"equals":"o3"},{"equals":"o3-2025-04-16"}]},"prices":[{"prices":{"input_mtok":10,"cache_read_mtok":0.5,"output_mtok":40}},{"constraint":{"start_date":"2025-06-10"},"prices":{"input_mtok":2,"cache_read_mtok":0.5,"output_mtok":8}}]},{"id":"o3-deep-research","match":{"or":[{"equals":"o3-deep-research"},{"equals":"o3-deep-research-2025-06-26"}]},"prices":{"input_mtok":10,"cache_read_mtok":2.5,"output_mtok":40}},{"id":"o3-mini","match":{"or":[{"equals":"o3-mini"},{"equals":"o3-mini-2025-01-31"},{"equals":"o3-mini-high"}]},"prices":{"input_mtok":1.1,"cache_read_mtok":0.55,"output_mtok":4.4}},{"id":"o3-pro","match":{"or":[{"equals":"o3-pro"},{"equals":"o3-pro-2025-06-10"}]},"prices":{"input_mtok":20,"output_mtok":80}},{"id":"o4-mini","match":{"or":[{"equals":"o4-mini-2025-04-16"},{"equals":"o4-mini-high"},{"equals":"o4-mini"}]},"prices":{"input_mtok":1.1,"cache_read_mtok":0.275,"output_mtok":4.4}},{"id":"o4-mini-deep-research","match":{"or":[{"equals":"o4-mini-deep-research"},{"equals":"o4-mini-deep-research-2025-06-26"}]},"prices":{"input_mtok":2,"cache_read_mtok":0.5,"output_mtok":8}},{"id":"text-davinci-002","match":{"equals":"text-davinci-002"},"prices":{"input_mtok":20,"output_mtok":20}},{"id":"text-davinci-003","match":{"equals":"text-davinci-003"},"prices":{"input_mtok":20,"output_mtok":20}},{"id":"text-embedding-3-large","match":{"equals":"text-embedding-3-large"},"context_window":8192,"prices":{"input_mtok":0.13}},{"id":"text-embedding-3-small","match":{"equals":"text-embedding-3-small"},"context_window":8192,"prices":{"input_mtok":0.02}},{"id":"text-embedding-ada-002","match":{"or":[{"equals":"text-embedding-ada"},{"equals":"text-embedding-ada-002"},{"equals":"text-embedding-ada-002-v2"}]},"context_window":8192,"prices":{"input_mtok":0.1}}]},{"id":"openrouter","name":"OpenRouter","pricing_urls":["https://openrouter.ai/models"],"api_pattern":"https://(api\\.)?openrouter\\.ai","models":[{"id":"01-ai/yi-large","match":{"equals":"01-ai/yi-large"},"prices":{"input_mtok":3,"output_mtok":3}},{"id":"aetherwiing/mn-starcannon-12b","match":{"equals":"aetherwiing/mn-starcannon-12b"},"prices":{"input_mtok":0.8,"output_mtok":1.2}},{"id":"ai21/jamba-1-5-large","match":{"equals":"ai21/jamba-1-5-large"},"prices":{"input_mtok":2,"output_mtok":8}},{"id":"ai21/jamba-1-5-mini","match":{"equals":"ai21/jamba-1-5-mini"},"prices":{"input_mtok":0.2,"output_mtok":0.4}},{"id":"ai21/jamba-1.6-large","match":{"equals":"ai21/jamba-1.6-large"},"prices":{"input_mtok":2,"output_mtok":8}},{"id":"ai21/jamba-1.6-mini","match":{"equals":"ai21/jamba-1.6-mini"},"prices":{"input_mtok":0.2,"output_mtok":0.4}},{"id":"ai21/jamba-instruct","match":{"equals":"ai21/jamba-instruct"},"prices":{"input_mtok":0.5,"output_mtok":0.7}},{"id":"aion-1.0","match":{"equals":"aion-1.0"},"prices":{"input_mtok":4,"output_mtok":8}},{"id":"aion-1.0-mini","match":{"equals":"aion-1.0-mini"},"prices":{"input_mtok":0.7,"output_mtok":1.4}},{"id":"aion-labs/aion-1.0","match":{"equals":"aion-labs/aion-1.0"},"prices":{"input_mtok":4,"output_mtok":8}},{"id":"aion-labs/aion-1.0-mini","match":{"equals":"aion-labs/aion-1.0-mini"},"prices":{"input_mtok":0.7,"output_mtok":1.4}},{"id":"aion-labs/aion-rp-llama-3.1-8b","match":{"equals":"aion-labs/aion-rp-llama-3.1-8b"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"aion-rp-llama-3.1-8b","match":{"equals":"aion-rp-llama-3.1-8b"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"alfredpros/codellama-7b-instruct-solidity","match":{"equals":"alfredpros/codellama-7b-instruct-solidity"},"prices":{"input_mtok":0.8,"output_mtok":1.2}},{"id":"all-hands/openhands-lm-32b-v0.1","match":{"equals":"all-hands/openhands-lm-32b-v0.1"},"prices":{"input_mtok":2.6,"output_mtok":3.4}},{"id":"alpindale/goliath-120b","match":{"equals":"alpindale/goliath-120b"},"prices":{"input_mtok":6.5625,"output_mtok":9.375}},{"id":"alpindale/magnum-72b","match":{"equals":"alpindale/magnum-72b"},"prices":{"input_mtok":1.5,"output_mtok":2.25}},{"id":"amazon/nova-lite-v1","match":{"equals":"amazon/nova-lite-v1"},"prices":{"input_mtok":0.06,"output_mtok":0.24}},{"id":"amazon/nova-micro-v1","match":{"equals":"amazon/nova-micro-v1"},"prices":{"input_mtok":0.035,"output_mtok":0.14}},{"id":"amazon/nova-pro-v1","match":{"equals":"amazon/nova-pro-v1"},"prices":{"input_mtok":0.8,"output_mtok":3.2}},{"id":"anthracite-org/magnum-v2-72b","match":{"equals":"anthracite-org/magnum-v2-72b"},"prices":{"input_mtok":3,"output_mtok":3}},{"id":"anthracite-org/magnum-v4-72b","match":{"equals":"anthracite-org/magnum-v4-72b"},"prices":{"input_mtok":1.5,"output_mtok":2.25}},{"id":"anthropic/claude-2","match":{"or":[{"equals":"anthropic/claude-2"},{"equals":"anthropic/claude-2.0"},{"equals":"anthropic/claude-2.0:beta"},{"equals":"anthropic/claude-2.1"},{"equals":"anthropic/claude-2.1:beta"},{"equals":"anthropic/claude-2:beta"}]},"prices":{"input_mtok":8,"output_mtok":24}},{"id":"anthropic/claude-3-haiku","match":{"or":[{"equals":"anthropic/claude-3-haiku"},{"equals":"anthropic/claude-3-haiku:beta"}]},"prices":{"input_mtok":0.25,"output_mtok":1.25}},{"id":"anthropic/claude-3-opus","match":{"or":[{"equals":"anthropic/claude-3-opus"},{"equals":"anthropic/claude-3-opus:beta"}]},"prices":{"input_mtok":15,"output_mtok":75}},{"id":"anthropic/claude-3-sonnet","match":{"or":[{"equals":"anthropic/claude-3-sonnet"},{"equals":"anthropic/claude-3-sonnet:beta"}]},"prices":{"input_mtok":3,"output_mtok":15}},{"id":"anthropic/claude-3.5-haiku","match":{"or":[{"equals":"anthropic/claude-3.5-haiku"},{"equals":"anthropic/claude-3.5-haiku-20241022"},{"equals":"anthropic/claude-3.5-haiku-20241022:beta"},{"equals":"anthropic/claude-3.5-haiku:beta"}]},"prices":{"input_mtok":0.8,"output_mtok":4}},{"id":"anthropic/claude-3.5-sonnet","match":{"or":[{"equals":"anthropic/claude-3.5-sonnet"},{"equals":"anthropic/claude-3.5-sonnet-20240620"},{"equals":"anthropic/claude-3.5-sonnet-20240620:beta"},{"equals":"anthropic/claude-3.5-sonnet:beta"}]},"prices":{"input_mtok":3,"output_mtok":15}},{"id":"anthropic/claude-3.7-sonnet","match":{"or":[{"equals":"anthropic/claude-3.7-sonnet"},{"equals":"anthropic/claude-3.7-sonnet:beta"},{"equals":"anthropic/claude-3.7-sonnet:thinking"}]},"prices":{"input_mtok":3,"output_mtok":15}},{"id":"anthropic/claude-haiku-4.5","match":{"or":[{"equals":"anthropic/claude-haiku-4.5"},{"equals":"anthropic/claude-haiku-4.5:beta"}]},"prices":{"input_mtok":1,"cache_write_mtok":1.25,"cache_read_mtok":0.1,"output_mtok":5}},{"id":"anthropic/claude-opus-4.5","match":{"or":[{"equals":"anthropic/claude-opus-4.5"},{"equals":"anthropic/claude-opus-4.5:beta"}]},"prices":{"input_mtok":5,"cache_write_mtok":6.25,"cache_read_mtok":0.5,"output_mtok":25}},{"id":"anthropic/claude-opus-4.6","match":{"or":[{"equals":"anthropic/claude-opus-4.6"},{"equals":"anthropic/claude-opus-4.6:beta"}]},"prices":{"input_mtok":{"base":5,"tiers":[{"start":200000,"price":10}]},"cache_write_mtok":{"base":6.25,"tiers":[{"start":200000,"price":12.5}]},"cache_read_mtok":{"base":0.5,"tiers":[{"start":200000,"price":1}]},"output_mtok":{"base":25,"tiers":[{"start":200000,"price":37.5}]}}},{"id":"anthropic/claude-sonnet-4.5","match":{"or":[{"equals":"anthropic/claude-sonnet-4.5"},{"equals":"anthropic/claude-sonnet-4.5:beta"}]},"context_window":1000000,"prices":{"input_mtok":{"base":3,"tiers":[{"start":200000,"price":6}]},"cache_write_mtok":{"base":3.75,"tiers":[{"start":200000,"price":7.5}]},"cache_read_mtok":{"base":0.3,"tiers":[{"start":200000,"price":0.6}]},"output_mtok":{"base":15,"tiers":[{"start":200000,"price":22.5}]}}},{"id":"anubis-pro-105b-v1","match":{"equals":"anubis-pro-105b-v1"},"prices":{"input_mtok":0.8,"output_mtok":1}},{"id":"arcee-blitz","match":{"equals":"arcee-blitz"},"prices":{"input_mtok":0.45,"output_mtok":0.75}},{"id":"caller-large","match":{"equals":"caller-large"},"prices":{"input_mtok":0.55,"output_mtok":0.85}},{"id":"chatgpt-4o-latest","match":{"equals":"chatgpt-4o-latest"},"prices":{"input_mtok":5,"output_mtok":15}},{"id":"claude-2","match":{"or":[{"equals":"claude-2"},{"equals":"claude-2.0"},{"equals":"claude-2.0:beta"},{"equals":"claude-2.1"},{"equals":"claude-2.1:beta"},{"equals":"claude-2:beta"}]},"prices":{"input_mtok":8,"output_mtok":24}},{"id":"claude-3-haiku","match":{"or":[{"equals":"claude-3-haiku"},{"equals":"claude-3-haiku:beta"}]},"prices":{"input_mtok":0.25,"cache_write_mtok":0.3,"cache_read_mtok":0.03,"output_mtok":1.25}},{"id":"claude-3-opus","match":{"or":[{"equals":"claude-3-opus"},{"equals":"claude-3-opus:beta"}]},"prices":{"input_mtok":15,"cache_write_mtok":18.75,"cache_read_mtok":1.5,"output_mtok":75}},{"id":"claude-3-sonnet","match":{"or":[{"equals":"claude-3-sonnet"},{"equals":"claude-3-sonnet:beta"}]},"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"claude-3.5-haiku","match":{"or":[{"equals":"claude-3.5-haiku"},{"equals":"claude-3.5-haiku-20241022"},{"equals":"claude-3.5-haiku-20241022:beta"},{"equals":"claude-3.5-haiku:beta"}]},"prices":{"input_mtok":0.8,"cache_write_mtok":1,"cache_read_mtok":0.08,"output_mtok":4}},{"id":"claude-3.5-sonnet","match":{"or":[{"equals":"claude-3.5-sonnet"},{"equals":"claude-3.5-sonnet-20240620"},{"equals":"claude-3.5-sonnet-20240620:beta"},{"equals":"claude-3.5-sonnet:beta"}]},"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"claude-3.7-sonnet","match":{"or":[{"equals":"claude-3.7-sonnet"},{"equals":"claude-3.7-sonnet:beta"},{"equals":"claude-3.7-sonnet:thinking"}]},"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"claude-opus-4","match":{"equals":"claude-opus-4"},"prices":{"input_mtok":15,"cache_write_mtok":18.75,"cache_read_mtok":1.5,"output_mtok":75}},{"id":"claude-sonnet-4","match":{"equals":"claude-sonnet-4"},"prices":{"input_mtok":3,"cache_write_mtok":3.75,"cache_read_mtok":0.3,"output_mtok":15}},{"id":"codellama-7b-instruct-solidity","match":{"equals":"codellama-7b-instruct-solidity"},"prices":{"input_mtok":0.8,"output_mtok":1.2}},{"id":"coder-large","match":{"equals":"coder-large"},"prices":{"input_mtok":0.5,"output_mtok":0.8}},{"id":"codestral-2501","match":{"equals":"codestral-2501"},"prices":{"input_mtok":0.3,"output_mtok":0.9}},{"id":"codex-mini","match":{"equals":"codex-mini"},"prices":{"input_mtok":1.5,"cache_read_mtok":0.375,"output_mtok":6}},{"id":"cognitivecomputations/dolphin-mixtral-8x22b","match":{"equals":"cognitivecomputations/dolphin-mixtral-8x22b"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"cognitivecomputations/dolphin-mixtral-8x7b","match":{"equals":"cognitivecomputations/dolphin-mixtral-8x7b"},"prices":{"input_mtok":0.5,"output_mtok":0.5}},{"id":"cohere/command","match":{"equals":"cohere/command"},"prices":{"input_mtok":1,"output_mtok":2}},{"id":"cohere/command-a","match":{"equals":"cohere/command-a"},"prices":{"input_mtok":2.5,"output_mtok":10}},{"id":"cohere/command-r","match":{"or":[{"equals":"cohere/command-r"},{"equals":"cohere/command-r-03-2024"}]},"prices":{"input_mtok":0.5,"output_mtok":1.5}},{"id":"cohere/command-r-08-2024","match":{"equals":"cohere/command-r-08-2024"},"prices":{"input_mtok":0.15,"output_mtok":0.6}},{"id":"cohere/command-r-plus","match":{"or":[{"equals":"cohere/command-r-plus"},{"equals":"cohere/command-r-plus-04-2024"}]},"prices":{"input_mtok":3,"output_mtok":15}},{"id":"cohere/command-r-plus-08-2024","match":{"equals":"cohere/command-r-plus-08-2024"},"prices":{"input_mtok":2.5,"output_mtok":10}},{"id":"cohere/command-r7b-12-2024","match":{"equals":"cohere/command-r7b-12-2024"},"prices":{"input_mtok":0.0375,"output_mtok":0.15}},{"id":"command","match":{"equals":"command"},"prices":{"input_mtok":1,"output_mtok":2}},{"id":"command-a","match":{"equals":"command-a"},"prices":{"input_mtok":2.5,"output_mtok":10}},{"id":"command-r","match":{"or":[{"equals":"command-r"},{"equals":"command-r-03-2024"}]},"prices":{"input_mtok":0.5,"output_mtok":1.5}},{"id":"command-r-08-2024","match":{"equals":"command-r-08-2024"},"prices":{"input_mtok":0.15,"output_mtok":0.6}},{"id":"command-r-plus","match":{"or":[{"equals":"command-r-plus"},{"equals":"command-r-plus-04-2024"}]},"prices":{"input_mtok":3,"output_mtok":15}},{"id":"command-r-plus-08-2024","match":{"equals":"command-r-plus-08-2024"},"prices":{"input_mtok":2.5,"output_mtok":10}},{"id":"command-r7b-12-2024","match":{"equals":"command-r7b-12-2024"},"prices":{"input_mtok":0.0375,"output_mtok":0.15}},{"id":"deepseek-chat","match":{"equals":"deepseek-chat"},"prices":{"input_mtok":0.38,"output_mtok":0.89}},{"id":"deepseek-chat-v3-0324","match":{"equals":"deepseek-chat-v3-0324"},"prices":{"input_mtok":0.3,"output_mtok":0.88}},{"id":"deepseek-prover-v2","match":{"equals":"deepseek-prover-v2"},"prices":{"input_mtok":0.5,"output_mtok":2.18}},{"id":"deepseek-r1","match":{"equals":"deepseek-r1"},"prices":{"input_mtok":0.45,"output_mtok":2.15}},{"id":"deepseek-r1-0528","match":{"equals":"deepseek-r1-0528"},"prices":{"input_mtok":0.5,"output_mtok":2.15}},{"id":"deepseek-r1-0528-qwen3-8b","match":{"equals":"deepseek-r1-0528-qwen3-8b"},"prices":{"input_mtok":0.05,"output_mtok":0.1}},{"id":"deepseek-r1-distill-llama-70b","match":{"equals":"deepseek-r1-distill-llama-70b"},"prices":{"input_mtok":0.1,"output_mtok":0.4}},{"id":"deepseek-r1-distill-llama-8b","match":{"equals":"deepseek-r1-distill-llama-8b"},"prices":{"input_mtok":0.04,"output_mtok":0.04}},{"id":"deepseek-r1-distill-qwen-1.5b","match":{"equals":"deepseek-r1-distill-qwen-1.5b"},"prices":{"input_mtok":0.18,"output_mtok":0.18}},{"id":"deepseek-r1-distill-qwen-14b","match":{"equals":"deepseek-r1-distill-qwen-14b"},"prices":{"input_mtok":0.15,"output_mtok":0.15}},{"id":"deepseek-r1-distill-qwen-32b","match":{"equals":"deepseek-r1-distill-qwen-32b"},"prices":{"input_mtok":0.12,"output_mtok":0.18}},{"id":"deepseek-r1-distill-qwen-7b","match":{"equals":"deepseek-r1-distill-qwen-7b"},"prices":{"input_mtok":0.1,"output_mtok":0.2}},{"id":"deepseek-v3.1-terminus","match":{"equals":"deepseek-v3.1-terminus"},"context_window":163840,"prices":{"input_mtok":0.23,"output_mtok":0.9}},{"id":"deepseek/deepseek-chat","match":{"equals":"deepseek/deepseek-chat"},"prices":{"input_mtok":0.38,"output_mtok":0.89}},{"id":"deepseek/deepseek-chat-v3-0324","match":{"equals":"deepseek/deepseek-chat-v3-0324"},"prices":{"input_mtok":0.27,"output_mtok":1.1}},{"id":"deepseek/deepseek-chat-v3.1","match":{"equals":"deepseek/deepseek-chat-v3.1"},"context_window":163840,"prices":{"input_mtok":0.2,"output_mtok":0.8}},{"id":"deepseek/deepseek-r1","match":{"equals":"deepseek/deepseek-r1"},"prices":{"input_mtok":0.5,"output_mtok":3}},{"id":"deepseek/deepseek-r1-distill-llama-70b","match":{"equals":"deepseek/deepseek-r1-distill-llama-70b"},"prices":{"input_mtok":0.1,"output_mtok":0.4}},{"id":"deepseek/deepseek-r1-distill-llama-8b","match":{"equals":"deepseek/deepseek-r1-distill-llama-8b"},"prices":{"input_mtok":0.04,"output_mtok":0.04}},{"id":"deepseek/deepseek-r1-distill-qwen-1.5b","match":{"equals":"deepseek/deepseek-r1-distill-qwen-1.5b"},"prices":{"input_mtok":0.18,"output_mtok":0.18}},{"id":"deepseek/deepseek-r1-distill-qwen-14b","match":{"equals":"deepseek/deepseek-r1-distill-qwen-14b"},"prices":{"input_mtok":0.15,"output_mtok":0.15}},{"id":"deepseek/deepseek-r1-distill-qwen-32b","match":{"equals":"deepseek/deepseek-r1-distill-qwen-32b"},"prices":{"input_mtok":0.12,"output_mtok":0.18}},{"id":"deepseek/deepseek-v3.2-exp","match":{"equals":"deepseek/deepseek-v3.2-exp"},"prices":{"input_mtok":0.27,"output_mtok":0.4}},{"id":"devstral-small","match":{"equals":"devstral-small"},"prices":{"input_mtok":0.06,"output_mtok":0.12}},{"id":"dobby-mini-unhinged-plus-llama-3.1-8b","match":{"equals":"dobby-mini-unhinged-plus-llama-3.1-8b"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"dolphin-mixtral-8x22b","match":{"equals":"dolphin-mixtral-8x22b"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"eleutherai/llemma_7b","match":{"equals":"eleutherai/llemma_7b"},"prices":{"input_mtok":0.8,"output_mtok":1.2}},{"id":"eva-llama-3.33-70b","match":{"equals":"eva-llama-3.33-70b"},"prices":{"input_mtok":4,"output_mtok":6}},{"id":"eva-qwen-2.5-32b","match":{"equals":"eva-qwen-2.5-32b"},"prices":{"input_mtok":2.6,"output_mtok":3.4}},{"id":"eva-qwen-2.5-72b","match":{"equals":"eva-qwen-2.5-72b"},"prices":{"input_mtok":4,"output_mtok":6}},{"id":"eva-unit-01/eva-llama-3.33-70b","match":{"equals":"eva-unit-01/eva-llama-3.33-70b"},"prices":{"input_mtok":4,"output_mtok":6}},{"id":"eva-unit-01/eva-qwen-2.5-32b","match":{"equals":"eva-unit-01/eva-qwen-2.5-32b"},"prices":{"input_mtok":2.6,"output_mtok":3.4}},{"id":"eva-unit-01/eva-qwen-2.5-72b","match":{"equals":"eva-unit-01/eva-qwen-2.5-72b"},"prices":{"input_mtok":0.9,"output_mtok":1.2}},{"id":"fimbulvetr-11b-v2","match":{"equals":"fimbulvetr-11b-v2"},"prices":{"input_mtok":0.8,"output_mtok":1.2}},{"id":"gemini-2.0-flash-001","match":{"equals":"gemini-2.0-flash-001"},"prices":{"input_mtok":0.1,"cache_write_mtok":0.1833,"cache_read_mtok":0.025,"output_mtok":0.4}},{"id":"gemini-2.0-flash-lite-001","match":{"equals":"gemini-2.0-flash-lite-001"},"prices":{"input_mtok":0.075,"output_mtok":0.3}},{"id":"gemini-2.5-flash","match":{"or":[{"equals":"gemini-2.5-flash"},{"equals":"google/gemini-2.5-flash"}]},"prices":{"input_mtok":0.3,"cache_write_mtok":0.3833,"cache_read_mtok":0.075,"output_mtok":2.5}},{"id":"gemini-2.5-flash-lite-preview-06-17","match":{"equals":"gemini-2.5-flash-lite-preview-06-17"},"prices":{"input_mtok":0.1,"output_mtok":0.4}},{"id":"gemini-2.5-flash-preview","match":{"or":[{"equals":"gemini-2.5-flash-preview"},{"equals":"gemini-2.5-flash-preview-05-20"}]},"prices":{"input_mtok":0.15,"cache_write_mtok":0.2333,"cache_read_mtok":0.0375,"output_mtok":0.6}},{"id":"gemini-2.5-flash-preview-05-20:thinking","match":{"equals":"gemini-2.5-flash-preview-05-20:thinking"},"prices":{"input_mtok":0.15,"cache_write_mtok":0.2333,"cache_read_mtok":0.0375,"output_mtok":3.5}},{"id":"gemini-2.5-flash-preview:thinking","match":{"equals":"gemini-2.5-flash-preview:thinking"},"prices":{"input_mtok":0.15,"cache_write_mtok":0.2333,"cache_read_mtok":0.0375,"output_mtok":3.5}},{"id":"gemini-2.5-pro","match":{"or":[{"equals":"gemini-2.5-pro"},{"equals":"gemini-2.5-pro-preview"},{"equals":"gemini-2.5-pro-preview-05-06"},{"equals":"google/gemini-2.5-pro"},{"equals":"google/gemini-2.5-pro-preview"},{"equals":"google/gemini-2.5-pro-preview-05-06"}]},"prices":{"input_mtok":1.25,"cache_write_mtok":1.625,"cache_read_mtok":0.31,"output_mtok":10}},{"id":"gemini-flash-1.5","match":{"equals":"gemini-flash-1.5"},"prices":{"input_mtok":0.075,"cache_write_mtok":0.1583,"cache_read_mtok":0.01875,"output_mtok":0.3}},{"id":"gemini-flash-1.5-8b","match":{"equals":"gemini-flash-1.5-8b"},"prices":{"input_mtok":0.0375,"cache_write_mtok":0.0583,"cache_read_mtok":0.01,"output_mtok":0.15}},{"id":"gemini-pro-1.5","match":{"equals":"gemini-pro-1.5"},"prices":{"input_mtok":1.25,"output_mtok":5}},{"id":"gemma-2-27b-it","match":{"equals":"gemma-2-27b-it"},"prices":{"input_mtok":0.8,"output_mtok":0.8}},{"id":"gemma-2-9b-it","match":{"equals":"gemma-2-9b-it"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"gemma-3-12b-it","match":{"equals":"gemma-3-12b-it"},"prices":{"input_mtok":0.05,"output_mtok":0.1}},{"id":"gemma-3-27b-it","match":{"equals":"gemma-3-27b-it"},"prices":{"input_mtok":0.1,"output_mtok":0.2}},{"id":"gemma-3-4b-it","match":{"equals":"gemma-3-4b-it"},"prices":{"input_mtok":0.02,"output_mtok":0.04}},{"id":"glm-4-32b","match":{"equals":"glm-4-32b"},"prices":{"input_mtok":0.24,"output_mtok":0.24}},{"id":"glm-z1-32b","match":{"equals":"glm-z1-32b"},"prices":{"input_mtok":0.24,"output_mtok":0.24}},{"id":"glm-z1-rumination-32b","match":{"equals":"glm-z1-rumination-32b"},"prices":{"input_mtok":0.24,"output_mtok":0.24}},{"id":"goliath-120b","match":{"equals":"goliath-120b"},"prices":{"input_mtok":10,"output_mtok":12.5}},{"id":"google/gemini-2.0-flash-001","match":{"equals":"google/gemini-2.0-flash-001"},"prices":{"input_mtok":0.1,"output_mtok":0.4}},{"id":"google/gemini-2.0-flash-lite-001","match":{"equals":"google/gemini-2.0-flash-lite-001"},"prices":{"input_mtok":0.075,"output_mtok":0.3}},{"id":"google/gemini-2.5-flash-image","match":{"or":[{"equals":"google/gemini-2.5-flash-image"},{"equals":"google/gemini-2.5-flash-image-preview"}]},"prices":{"input_mtok":0.3,"output_mtok":2.5}},{"id":"google/gemini-2.5-flash-lite","match":{"equals":"google/gemini-2.5-flash-lite"},"prices":{"input_mtok":0.1,"cache_write_mtok":0.183,"cache_read_mtok":0.025,"output_mtok":0.4}},{"id":"google/gemini-2.5-flash-lite-preview-09-2025","match":{"equals":"google/gemini-2.5-flash-lite-preview-09-2025"},"prices":{"input_mtok":0.1,"output_mtok":0.4}},{"id":"google/gemini-2.5-flash-preview","match":{"equals":"google/gemini-2.5-flash-preview"},"prices":{"input_mtok":0.15,"output_mtok":0.6}},{"id":"google/gemini-2.5-flash-preview-09-2025","match":{"equals":"google/gemini-2.5-flash-preview-09-2025"},"prices":{"input_mtok":0.3,"cache_write_mtok":0.383,"cache_read_mtok":0.075,"output_mtok":2.5}},{"id":"google/gemini-2.5-flash-preview:thinking","match":{"equals":"google/gemini-2.5-flash-preview:thinking"},"prices":{"input_mtok":0.15,"output_mtok":3.5}},{"id":"google/gemini-2.5-pro-preview-03-25","match":{"equals":"google/gemini-2.5-pro-preview-03-25"},"prices":{"input_mtok":1.25,"output_mtok":10}},{"id":"google/gemini-flash-1.5","match":{"equals":"google/gemini-flash-1.5"},"prices":{"input_mtok":0.075,"output_mtok":0.3}},{"id":"google/gemini-flash-1.5-8b","match":{"equals":"google/gemini-flash-1.5-8b"},"prices":{"input_mtok":0.0375,"output_mtok":0.15}},{"id":"google/gemini-pro","match":{"or":[{"equals":"google/gemini-pro"},{"equals":"google/gemini-pro-vision"}]},"prices":{"input_mtok":0.5,"output_mtok":1.5}},{"id":"google/gemini-pro-1.5","match":{"equals":"google/gemini-pro-1.5"},"prices":{"input_mtok":1.25,"output_mtok":5}},{"id":"google/gemma-2-27b-it","match":{"equals":"google/gemma-2-27b-it"},"prices":{"input_mtok":0.8,"output_mtok":0.8}},{"id":"google/gemma-2-9b-it","match":{"equals":"google/gemma-2-9b-it"},"prices":{"input_mtok":0.07,"output_mtok":0.07}},{"id":"google/gemma-3-12b-it","match":{"equals":"google/gemma-3-12b-it"},"prices":{"input_mtok":0.05,"output_mtok":0.1}},{"id":"google/gemma-3-27b-it","match":{"equals":"google/gemma-3-27b-it"},"prices":{"input_mtok":0.1,"output_mtok":0.2}},{"id":"google/gemma-3-4b-it","match":{"equals":"google/gemma-3-4b-it"},"prices":{"input_mtok":0.02,"output_mtok":0.04}},{"id":"google/palm-2-chat-bison","match":{"or":[{"equals":"google/palm-2-chat-bison"},{"equals":"google/palm-2-chat-bison-32k"}]},"prices":{"input_mtok":1,"output_mtok":2}},{"id":"google/palm-2-codechat-bison","match":{"or":[{"equals":"google/palm-2-codechat-bison"},{"equals":"google/palm-2-codechat-bison-32k"}]},"prices":{"input_mtok":1,"output_mtok":2}},{"id":"gpt-3.5-turbo","match":{"or":[{"equals":"gpt-3.5-turbo"},{"equals":"gpt-3.5-turbo-0125"}]},"prices":{"input_mtok":0.5,"output_mtok":1.5}},{"id":"gpt-3.5-turbo-0613","match":{"equals":"gpt-3.5-turbo-0613"},"prices":{"input_mtok":1,"output_mtok":2}},{"id":"gpt-3.5-turbo-1106","match":{"equals":"gpt-3.5-turbo-1106"},"prices":{"input_mtok":1,"output_mtok":2}},{"id":"gpt-3.5-turbo-16k","match":{"equals":"gpt-3.5-turbo-16k"},"prices":{"input_mtok":3,"output_mtok":4}},{"id":"gpt-3.5-turbo-instruct","match":{"equals":"gpt-3.5-turbo-instruct"},"prices":{"input_mtok":1.5,"output_mtok":2}},{"id":"gpt-4","match":{"or":[{"equals":"gpt-4"},{"equals":"gpt-4-0314"}]},"prices":{"input_mtok":30,"output_mtok":60}},{"id":"gpt-4-1106-preview","match":{"equals":"gpt-4-1106-preview"},"prices":{"input_mtok":10,"output_mtok":30}},{"id":"gpt-4-turbo","match":{"or":[{"equals":"gpt-4-turbo"},{"equals":"gpt-4-turbo-preview"}]},"prices":{"input_mtok":10,"output_mtok":30}},{"id":"gpt-4.1","match":{"equals":"gpt-4.1"},"prices":{"input_mtok":2,"cache_read_mtok":0.5,"output_mtok":8}},{"id":"gpt-4.1-mini","match":{"equals":"gpt-4.1-mini"},"prices":{"input_mtok":0.4,"cache_read_mtok":0.1,"output_mtok":1.6}},{"id":"gpt-4.1-nano","match":{"equals":"gpt-4.1-nano"},"prices":{"input_mtok":0.1,"cache_read_mtok":0.025,"output_mtok":0.4}},{"id":"gpt-4.5-preview","match":{"equals":"gpt-4.5-preview"},"prices":{"input_mtok":75,"cache_read_mtok":37.5,"output_mtok":150}},{"id":"gpt-4o","match":{"or":[{"equals":"gpt-4o"},{"equals":"gpt-4o-2024-08-06"},{"equals":"gpt-4o-2024-11-20"}]},"prices":{"input_mtok":2.5,"cache_read_mtok":1.25,"output_mtok":10}},{"id":"gpt-4o-2024-05-13","match":{"equals":"gpt-4o-2024-05-13"},"prices":{"input_mtok":5,"output_mtok":15}},{"id":"gpt-4o-mini","match":{"or":[{"equals":"gpt-4o-mini"},{"equals":"gpt-4o-mini-2024-07-18"}]},"prices":{"input_mtok":0.15,"cache_read_mtok":0.075,"output_mtok":0.6}},{"id":"gpt-4o-mini-search-preview","match":{"equals":"gpt-4o-mini-search-preview"},"prices":{"input_mtok":0.15,"output_mtok":0.6}},{"id":"gpt-4o-search-preview","match":{"equals":"gpt-4o-search-preview"},"prices":{"input_mtok":2.5,"output_mtok":10}},{"id":"gpt-4o:extended","match":{"equals":"gpt-4o:extended"},"prices":{"input_mtok":6,"output_mtok":18}},{"id":"grok-2-1212","match":{"equals":"grok-2-1212"},"prices":{"input_mtok":2,"output_mtok":10}},{"id":"grok-2-vision-1212","match":{"equals":"grok-2-vision-1212"},"prices":{"input_mtok":2,"output_mtok":10}},{"id":"grok-3","match":{"or":[{"equals":"grok-3"},{"equals":"grok-3-beta"}]},"prices":{"input_mtok":3,"cache_read_mtok":0.75,"output_mtok":15}},{"id":"grok-3-mini","match":{"or":[{"equals":"grok-3-mini"},{"equals":"grok-3-mini-beta"}]},"prices":{"input_mtok":0.3,"cache_read_mtok":0.075,"output_mtok":0.5}},{"id":"grok-beta","match":{"equals":"grok-beta"},"prices":{"input_mtok":5,"output_mtok":15}},{"id":"grok-vision-beta","match":{"equals":"grok-vision-beta"},"prices":{"input_mtok":5,"output_mtok":15}},{"id":"gryphe/mythomax-l2-13b","match":{"equals":"gryphe/mythomax-l2-13b"},"prices":{"input_mtok":0.065,"output_mtok":0.065}},{"id":"hermes-2-pro-llama-3-8b","match":{"equals":"hermes-2-pro-llama-3-8b"},"prices":{"input_mtok":0.025,"output_mtok":0.04}},{"id":"hermes-3-llama-3.1-405b","match":{"equals":"hermes-3-llama-3.1-405b"},"prices":{"input_mtok":0.7,"output_mtok":0.8}},{"id":"hermes-3-llama-3.1-70b","match":{"equals":"hermes-3-llama-3.1-70b"},"prices":{"input_mtok":0.12,"output_mtok":0.3}},{"id":"infermatic/mn-inferor-12b","match":{"equals":"infermatic/mn-inferor-12b"},"prices":{"input_mtok":0.8,"output_mtok":1.2}},{"id":"inflection-3-pi","match":{"equals":"inflection-3-pi"},"prices":{"input_mtok":2.5,"output_mtok":10}},{"id":"inflection-3-productivity","match":{"equals":"inflection-3-productivity"},"prices":{"input_mtok":2.5,"output_mtok":10}},{"id":"inflection/inflection-3-pi","match":{"equals":"inflection/inflection-3-pi"},"prices":{"input_mtok":2.5,"output_mtok":10}},{"id":"inflection/inflection-3-productivity","match":{"equals":"inflection/inflection-3-productivity"},"prices":{"input_mtok":2.5,"output_mtok":10}},{"id":"jamba-1.6-large","match":{"equals":"jamba-1.6-large"},"prices":{"input_mtok":2,"output_mtok":8}},{"id":"jamba-1.6-mini","match":{"equals":"jamba-1.6-mini"},"prices":{"input_mtok":0.2,"output_mtok":0.4}},{"id":"jondurbin/airoboros-l2-70b","match":{"equals":"jondurbin/airoboros-l2-70b"},"prices":{"input_mtok":0.5,"output_mtok":0.5}},{"id":"l3-euryale-70b","match":{"equals":"l3-euryale-70b"},"prices":{"input_mtok":1.48,"output_mtok":1.48}},{"id":"l3-lunaris-8b","match":{"equals":"l3-lunaris-8b"},"prices":{"input_mtok":0.02,"output_mtok":0.05}},{"id":"l3.1-euryale-70b","match":{"equals":"l3.1-euryale-70b"},"prices":{"input_mtok":0.7,"output_mtok":0.8}},{"id":"l3.3-euryale-70b","match":{"equals":"l3.3-euryale-70b"},"prices":{"input_mtok":0.7,"output_mtok":0.8}},{"id":"latitudegames/wayfarer-large-70b-llama-3.3","match":{"equals":"latitudegames/wayfarer-large-70b-llama-3.3"},"prices":{"input_mtok":0.8,"output_mtok":0.9}},{"id":"lfm-3b","match":{"equals":"lfm-3b"},"prices":{"input_mtok":0.02,"output_mtok":0.02}},{"id":"lfm-40b","match":{"equals":"lfm-40b"},"prices":{"input_mtok":0.15,"output_mtok":0.15}},{"id":"lfm-7b","match":{"equals":"lfm-7b"},"prices":{"input_mtok":0.01,"output_mtok":0.01}},{"id":"liquid/lfm-3b","match":{"equals":"liquid/lfm-3b"},"prices":{"input_mtok":0.02,"output_mtok":0.02}},{"id":"liquid/lfm-40b","match":{"equals":"liquid/lfm-40b"},"prices":{"input_mtok":0.15,"output_mtok":0.15}},{"id":"liquid/lfm-7b","match":{"equals":"liquid/lfm-7b"},"prices":{"input_mtok":0.01,"output_mtok":0.01}},{"id":"llama-3-70b-instruct","match":{"equals":"llama-3-70b-instruct"},"prices":{"input_mtok":0.3,"output_mtok":0.4}},{"id":"llama-3-8b-instruct","match":{"equals":"llama-3-8b-instruct"},"prices":{"input_mtok":0.03,"output_mtok":0.06}},{"id":"llama-3-lumimaid-70b","match":{"equals":"llama-3-lumimaid-70b"},"prices":{"input_mtok":4,"output_mtok":6}},{"id":"llama-3-lumimaid-8b","match":{"equals":"llama-3-lumimaid-8b"},"prices":{"input_mtok":0.2,"output_mtok":1.25}},{"id":"llama-3.1-405b","match":{"equals":"llama-3.1-405b"},"prices":{"input_mtok":2,"output_mtok":2}},{"id":"llama-3.1-405b-instruct","match":{"equals":"llama-3.1-405b-instruct"},"prices":{"input_mtok":0.8,"output_mtok":0.8}},{"id":"llama-3.1-70b-instruct","match":{"equals":"llama-3.1-70b-instruct"},"prices":{"input_mtok":0.1,"output_mtok":0.28}},{"id":"llama-3.1-8b-instruct","match":{"equals":"llama-3.1-8b-instruct"},"prices":{"input_mtok":0.016,"output_mtok":0.029}},{"id":"llama-3.1-lumimaid-70b","match":{"equals":"llama-3.1-lumimaid-70b"},"prices":{"input_mtok":2.5,"output_mtok":3}},{"id":"llama-3.1-lumimaid-8b","match":{"equals":"llama-3.1-lumimaid-8b"},"prices":{"input_mtok":0.2,"output_mtok":1.25}},{"id":"llama-3.1-nemotron-70b-instruct","match":{"equals":"llama-3.1-nemotron-70b-instruct"},"prices":{"input_mtok":0.12,"output_mtok":0.3}},{"id":"llama-3.1-nemotron-ultra-253b-v1","match":{"equals":"llama-3.1-nemotron-ultra-253b-v1"},"prices":{"input_mtok":0.6,"output_mtok":1.8}},{"id":"llama-3.1-sonar-large-128k-online","match":{"equals":"llama-3.1-sonar-large-128k-online"},"prices":{"input_mtok":1,"output_mtok":1}},{"id":"llama-3.1-sonar-small-128k-online","match":{"equals":"llama-3.1-sonar-small-128k-online"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"llama-3.2-11b-vision-instruct","match":{"equals":"llama-3.2-11b-vision-instruct"},"prices":{"input_mtok":0.049,"output_mtok":0.049}},{"id":"llama-3.2-1b-instruct","match":{"equals":"llama-3.2-1b-instruct"},"prices":{"input_mtok":0.005,"output_mtok":0.01}},{"id":"llama-3.2-3b-instruct","match":{"equals":"llama-3.2-3b-instruct"},"prices":{"input_mtok":0.01,"output_mtok":0.02}},{"id":"llama-3.2-90b-vision-instruct","match":{"equals":"llama-3.2-90b-vision-instruct"},"prices":{"input_mtok":1.2,"output_mtok":1.2}},{"id":"llama-3.3-70b-instruct","match":{"equals":"llama-3.3-70b-instruct"},"prices":{"input_mtok":0.05,"output_mtok":0.24}},{"id":"llama-3.3-nemotron-super-49b-v1","match":{"equals":"llama-3.3-nemotron-super-49b-v1"},"prices":{"input_mtok":0.13,"output_mtok":0.4}},{"id":"llama-4-maverick","match":{"equals":"llama-4-maverick"},"prices":{"input_mtok":0.15,"output_mtok":0.6}},{"id":"llama-4-scout","match":{"equals":"llama-4-scout"},"prices":{"input_mtok":0.08,"output_mtok":0.3}},{"id":"llama-guard-2-8b","match":{"equals":"llama-guard-2-8b"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"llama-guard-3-8b","match":{"equals":"llama-guard-3-8b"},"prices":{"input_mtok":0.02,"output_mtok":0.06}},{"id":"llama-guard-4-12b","match":{"equals":"llama-guard-4-12b"},"prices":{"input_mtok":0.05,"output_mtok":0.05}},{"id":"llama3.1-typhoon2-70b-instruct","match":{"equals":"llama3.1-typhoon2-70b-instruct"},"prices":{"input_mtok":0.88,"output_mtok":0.88}},{"id":"llemma_7b","match":{"equals":"llemma_7b"},"prices":{"input_mtok":0.8,"output_mtok":1.2}},{"id":"maestro-reasoning","match":{"equals":"maestro-reasoning"},"prices":{"input_mtok":0.9,"output_mtok":3.3}},{"id":"magistral-medium-2506","match":{"or":[{"equals":"magistral-medium-2506"},{"equals":"magistral-medium-2506:thinking"}]},"prices":{"input_mtok":2,"output_mtok":5}},{"id":"magistral-small-2506","match":{"equals":"magistral-small-2506"},"prices":{"input_mtok":0.5,"output_mtok":1.5}},{"id":"magnum-72b","match":{"equals":"magnum-72b"},"prices":{"input_mtok":4,"output_mtok":6}},{"id":"magnum-v2-72b","match":{"equals":"magnum-v2-72b"},"prices":{"input_mtok":3,"output_mtok":3}},{"id":"magnum-v4-72b","match":{"equals":"magnum-v4-72b"},"prices":{"input_mtok":2.5,"output_mtok":3}},{"id":"mancer/weaver","match":{"equals":"mancer/weaver"},"prices":{"input_mtok":1.125,"output_mtok":1.125}},{"id":"mercury-coder-small-beta","match":{"equals":"mercury-coder-small-beta"},"prices":{"input_mtok":0.25,"output_mtok":1}},{"id":"meta-llama/llama-2-13b-chat","match":{"equals":"meta-llama/llama-2-13b-chat"},"prices":{"input_mtok":0.22,"output_mtok":0.22}},{"id":"meta-llama/llama-2-70b-chat","match":{"equals":"meta-llama/llama-2-70b-chat"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"meta-llama/llama-3-70b-instruct","match":{"equals":"meta-llama/llama-3-70b-instruct"},"prices":{"input_mtok":0.3,"output_mtok":0.4}},{"id":"meta-llama/llama-3-8b-instruct","match":{"equals":"meta-llama/llama-3-8b-instruct"},"prices":{"input_mtok":0.03,"output_mtok":0.06}},{"id":"meta-llama/llama-3.1-405b","match":{"equals":"meta-llama/llama-3.1-405b"},"prices":{"input_mtok":2,"output_mtok":2}},{"id":"meta-llama/llama-3.1-405b-instruct","match":{"equals":"meta-llama/llama-3.1-405b-instruct"},"prices":{"input_mtok":0.8,"output_mtok":0.8}},{"id":"meta-llama/llama-3.1-70b-instruct","match":{"equals":"meta-llama/llama-3.1-70b-instruct"},"prices":{"input_mtok":0.119,"output_mtok":0.39}},{"id":"meta-llama/llama-3.1-8b-instruct","match":{"equals":"meta-llama/llama-3.1-8b-instruct"},"prices":{"input_mtok":0.02,"output_mtok":0.03}},{"id":"meta-llama/llama-3.2-11b-vision-instruct","match":{"equals":"meta-llama/llama-3.2-11b-vision-instruct"},"prices":{"input_mtok":0.049,"output_mtok":0.049}},{"id":"meta-llama/llama-3.2-1b-instruct","match":{"equals":"meta-llama/llama-3.2-1b-instruct"},"prices":{"input_mtok":0.01,"output_mtok":0.01}},{"id":"meta-llama/llama-3.2-3b-instruct","match":{"equals":"meta-llama/llama-3.2-3b-instruct"},"prices":{"input_mtok":0.015,"output_mtok":0.025}},{"id":"meta-llama/llama-3.2-90b-vision-instruct","match":{"equals":"meta-llama/llama-3.2-90b-vision-instruct"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"meta-llama/llama-3.3-70b-instruct","match":{"equals":"meta-llama/llama-3.3-70b-instruct"},"prices":{"input_mtok":0.1,"output_mtok":0.25}},{"id":"meta-llama/llama-4-maverick","match":{"equals":"meta-llama/llama-4-maverick"},"prices":{"input_mtok":0.17,"output_mtok":0.85}},{"id":"meta-llama/llama-4-scout","match":{"equals":"meta-llama/llama-4-scout"},"prices":{"input_mtok":0.08,"output_mtok":0.3}},{"id":"meta-llama/llama-guard-2-8b","match":{"equals":"meta-llama/llama-guard-2-8b"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"meta-llama/llama-guard-3-8b","match":{"equals":"meta-llama/llama-guard-3-8b"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"microsoft/phi-3-medium-128k-instruct","match":{"equals":"microsoft/phi-3-medium-128k-instruct"},"prices":{"input_mtok":1,"output_mtok":1}},{"id":"microsoft/phi-3-mini-128k-instruct","match":{"equals":"microsoft/phi-3-mini-128k-instruct"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"microsoft/phi-3.5-mini-128k-instruct","match":{"equals":"microsoft/phi-3.5-mini-128k-instruct"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"microsoft/phi-4","match":{"equals":"microsoft/phi-4"},"prices":{"input_mtok":0.07,"output_mtok":0.14}},{"id":"microsoft/phi-4-multimodal-instruct","match":{"equals":"microsoft/phi-4-multimodal-instruct"},"prices":{"input_mtok":0.05,"output_mtok":0.1}},{"id":"microsoft/wizardlm-2-7b","match":{"equals":"microsoft/wizardlm-2-7b"},"prices":{"input_mtok":0.07,"output_mtok":0.07}},{"id":"microsoft/wizardlm-2-8x22b","match":{"equals":"microsoft/wizardlm-2-8x22b"},"prices":{"input_mtok":0.5,"output_mtok":0.5}},{"id":"midnight-rose-70b","match":{"equals":"midnight-rose-70b"},"prices":{"input_mtok":0.8,"output_mtok":0.8}},{"id":"minimax-01","match":{"equals":"minimax-01"},"prices":{"input_mtok":0.2,"output_mtok":1.1}},{"id":"minimax-m1","match":{"equals":"minimax-m1"},"prices":{"input_mtok":0.3,"output_mtok":1.65}},{"id":"minimax-m1:extended","match":{"equals":"minimax-m1:extended"},"prices":{"input_mtok":0.55,"output_mtok":2.2}},{"id":"minimax/minimax-01","match":{"equals":"minimax/minimax-01"},"prices":{"input_mtok":0.2,"output_mtok":1.1}},{"id":"ministral-3b","match":{"equals":"ministral-3b"},"prices":{"input_mtok":0.04,"output_mtok":0.04}},{"id":"ministral-8b","match":{"equals":"ministral-8b"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"mistral-7b-instruct","match":{"or":[{"equals":"mistral-7b-instruct"},{"equals":"mistral-7b-instruct-v0.3"}]},"prices":{"input_mtok":0.028,"output_mtok":0.054}},{"id":"mistral-7b-instruct-v0.1","match":{"equals":"mistral-7b-instruct-v0.1"},"prices":{"input_mtok":0.11,"output_mtok":0.19}},{"id":"mistral-7b-instruct-v0.2","match":{"equals":"mistral-7b-instruct-v0.2"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"mistral-large","match":{"or":[{"equals":"mistral-large"},{"equals":"mistral-large-2407"},{"equals":"mistral-large-2411"}]},"prices":{"input_mtok":2,"output_mtok":6}},{"id":"mistral-medium","match":{"equals":"mistral-medium"},"prices":{"input_mtok":2.75,"output_mtok":8.1}},{"id":"mistral-medium-3","match":{"equals":"mistral-medium-3"},"prices":{"input_mtok":0.4,"output_mtok":2}},{"id":"mistral-nemo","match":{"equals":"mistral-nemo"},"prices":{"input_mtok":0.01,"output_mtok":0.019}},{"id":"mistral-saba","match":{"equals":"mistral-saba"},"prices":{"input_mtok":0.2,"output_mtok":0.6}},{"id":"mistral-small","match":{"equals":"mistral-small"},"prices":{"input_mtok":0.2,"output_mtok":0.6}},{"id":"mistral-small-24b-instruct-2501","match":{"equals":"mistral-small-24b-instruct-2501"},"prices":{"input_mtok":0.05,"output_mtok":0.09}},{"id":"mistral-small-3.1-24b-instruct","match":{"equals":"mistral-small-3.1-24b-instruct"},"prices":{"input_mtok":0.05,"output_mtok":0.15}},{"id":"mistral-tiny","match":{"equals":"mistral-tiny"},"prices":{"input_mtok":0.25,"output_mtok":0.25}},{"id":"mistral/ministral-8b","match":{"equals":"mistral/ministral-8b"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"mistralai/codestral-2501","match":{"equals":"mistralai/codestral-2501"},"prices":{"input_mtok":0.3,"output_mtok":0.9}},{"id":"mistralai/codestral-mamba","match":{"equals":"mistralai/codestral-mamba"},"prices":{"input_mtok":0.25,"output_mtok":0.25}},{"id":"mistralai/ministral-3b","match":{"equals":"mistralai/ministral-3b"},"prices":{"input_mtok":0.04,"output_mtok":0.04}},{"id":"mistralai/ministral-8b","match":{"equals":"mistralai/ministral-8b"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"mistralai/mistral-7b-instruct","match":{"or":[{"equals":"mistralai/mistral-7b-instruct"},{"equals":"mistralai/mistral-7b-instruct-v0.3"}]},"prices":{"input_mtok":0.029,"output_mtok":0.059}},{"id":"mistralai/mistral-7b-instruct-v0.1","match":{"equals":"mistralai/mistral-7b-instruct-v0.1"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"mistralai/mistral-7b-instruct-v0.2","match":{"equals":"mistralai/mistral-7b-instruct-v0.2"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"mistralai/mistral-large","match":{"or":[{"equals":"mistralai/mistral-large"},{"equals":"mistralai/mistral-large-2407"},{"equals":"mistralai/mistral-large-2411"}]},"prices":{"input_mtok":2,"output_mtok":6}},{"id":"mistralai/mistral-medium","match":{"equals":"mistralai/mistral-medium"},"prices":{"input_mtok":2.75,"output_mtok":8.1}},{"id":"mistralai/mistral-nemo","match":{"equals":"mistralai/mistral-nemo"},"prices":{"input_mtok":0.035,"output_mtok":0.08}},{"id":"mistralai/mistral-saba","match":{"equals":"mistralai/mistral-saba"},"prices":{"input_mtok":0.2,"output_mtok":0.6}},{"id":"mistralai/mistral-small","match":{"equals":"mistralai/mistral-small"},"prices":{"input_mtok":0.2,"output_mtok":0.6}},{"id":"mistralai/mistral-small-24b-instruct-2501","match":{"equals":"mistralai/mistral-small-24b-instruct-2501"},"prices":{"input_mtok":0.07,"output_mtok":0.14}},{"id":"mistralai/mistral-small-3.1-24b-instruct","match":{"equals":"mistralai/mistral-small-3.1-24b-instruct"},"prices":{"input_mtok":0.1,"output_mtok":0.3}},{"id":"mistralai/mistral-tiny","match":{"equals":"mistralai/mistral-tiny"},"prices":{"input_mtok":0.25,"output_mtok":0.25}},{"id":"mistralai/mixtral-8x22b-instruct","match":{"equals":"mistralai/mixtral-8x22b-instruct"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"mistralai/mixtral-8x7b-instruct","match":{"equals":"mistralai/mixtral-8x7b-instruct"},"prices":{"input_mtok":0.24,"output_mtok":0.24}},{"id":"mistralai/pixtral-12b","match":{"equals":"mistralai/pixtral-12b"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"mistralai/pixtral-large-2411","match":{"equals":"mistralai/pixtral-large-2411"},"prices":{"input_mtok":2,"output_mtok":6}},{"id":"mixtral-8x22b-instruct","match":{"equals":"mixtral-8x22b-instruct"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"mixtral-8x7b-instruct","match":{"equals":"mixtral-8x7b-instruct"},"prices":{"input_mtok":0.08,"output_mtok":0.24}},{"id":"mn-celeste-12b","match":{"equals":"mn-celeste-12b"},"prices":{"input_mtok":0.8,"output_mtok":1.2}},{"id":"mn-inferor-12b","match":{"equals":"mn-inferor-12b"},"prices":{"input_mtok":0.8,"output_mtok":1.2}},{"id":"mn-starcannon-12b","match":{"equals":"mn-starcannon-12b"},"prices":{"input_mtok":0.8,"output_mtok":1.2}},{"id":"moonshotai/kimi-k2.5","match":{"equals":"moonshotai/kimi-k2.5"},"prices":{"input_mtok":0.6,"output_mtok":3}},{"id":"mythalion-13b","match":{"equals":"mythalion-13b"},"prices":{"input_mtok":0.8,"output_mtok":1.2}},{"id":"mythomax-l2-13b","match":{"equals":"mythomax-l2-13b"},"prices":{"input_mtok":0.065,"output_mtok":0.065}},{"id":"neversleep/llama-3-lumimaid-70b","match":{"equals":"neversleep/llama-3-lumimaid-70b"},"prices":{"input_mtok":3.375,"output_mtok":4.5}},{"id":"neversleep/llama-3-lumimaid-8b","match":{"or":[{"equals":"neversleep/llama-3-lumimaid-8b"},{"equals":"neversleep/llama-3-lumimaid-8b:extended"}]},"prices":{"input_mtok":0.09375,"output_mtok":0.75}},{"id":"neversleep/llama-3.1-lumimaid-70b","match":{"equals":"neversleep/llama-3.1-lumimaid-70b"},"prices":{"input_mtok":1.5,"output_mtok":2.25}},{"id":"neversleep/llama-3.1-lumimaid-8b","match":{"equals":"neversleep/llama-3.1-lumimaid-8b"},"prices":{"input_mtok":0.09375,"output_mtok":0.75}},{"id":"neversleep/noromaid-20b","match":{"equals":"neversleep/noromaid-20b"},"prices":{"input_mtok":0.75,"output_mtok":1.5}},{"id":"noromaid-20b","match":{"equals":"noromaid-20b"},"prices":{"input_mtok":1.25,"output_mtok":2}},{"id":"nothingiisreal/mn-celeste-12b","match":{"equals":"nothingiisreal/mn-celeste-12b"},"prices":{"input_mtok":0.8,"output_mtok":1.2}},{"id":"nous-hermes-2-mixtral-8x7b-dpo","match":{"equals":"nous-hermes-2-mixtral-8x7b-dpo"},"prices":{"input_mtok":0.6,"output_mtok":0.6}},{"id":"nousresearch/hermes-2-pro-llama-3-8b","match":{"equals":"nousresearch/hermes-2-pro-llama-3-8b"},"prices":{"input_mtok":0.025,"output_mtok":0.04}},{"id":"nousresearch/hermes-3-llama-3.1-405b","match":{"equals":"nousresearch/hermes-3-llama-3.1-405b"},"prices":{"input_mtok":0.8,"output_mtok":0.8}},{"id":"nousresearch/hermes-3-llama-3.1-70b","match":{"equals":"nousresearch/hermes-3-llama-3.1-70b"},"prices":{"input_mtok":0.12,"output_mtok":0.3}},{"id":"nousresearch/nous-hermes-2-mixtral-8x7b-dpo","match":{"equals":"nousresearch/nous-hermes-2-mixtral-8x7b-dpo"},"prices":{"input_mtok":0.6,"output_mtok":0.6}},{"id":"nousresearch/nous-hermes-llama2-13b","match":{"equals":"nousresearch/nous-hermes-llama2-13b"},"prices":{"input_mtok":0.18,"output_mtok":0.18}},{"id":"nova-lite-v1","match":{"equals":"nova-lite-v1"},"prices":{"input_mtok":0.06,"output_mtok":0.24}},{"id":"nova-micro-v1","match":{"equals":"nova-micro-v1"},"prices":{"input_mtok":0.035,"output_mtok":0.14}},{"id":"nova-pro-v1","match":{"equals":"nova-pro-v1"},"prices":{"input_mtok":0.8,"output_mtok":3.2}},{"id":"nvidia/llama-3.1-nemotron-70b-instruct","match":{"equals":"nvidia/llama-3.1-nemotron-70b-instruct"},"prices":{"input_mtok":0.12,"output_mtok":0.3}},{"id":"o1","match":{"or":[{"equals":"o1"},{"equals":"o1-preview"},{"equals":"o1-preview-2024-09-12"}]},"prices":{"input_mtok":15,"cache_read_mtok":7.5,"output_mtok":60}},{"id":"o1-mini","match":{"or":[{"equals":"o1-mini"},{"equals":"o1-mini-2024-09-12"}]},"prices":{"input_mtok":1.1,"cache_read_mtok":0.55,"output_mtok":4.4}},{"id":"o1-pro","match":{"equals":"o1-pro"},"prices":{"input_mtok":150,"output_mtok":600}},{"id":"o3","match":{"equals":"o3"},"prices":{"input_mtok":2,"cache_read_mtok":0.5,"output_mtok":8}},{"id":"o3-mini","match":{"or":[{"equals":"o3-mini"},{"equals":"o3-mini-high"}]},"prices":{"input_mtok":1.1,"cache_read_mtok":0.55,"output_mtok":4.4}},{"id":"o3-pro","match":{"equals":"o3-pro"},"prices":{"input_mtok":20,"output_mtok":80}},{"id":"o4-mini","match":{"or":[{"equals":"o4-mini"},{"equals":"o4-mini-high"}]},"prices":{"input_mtok":1.1,"cache_read_mtok":0.275,"output_mtok":4.4}},{"id":"openai/chatgpt-4o-latest","match":{"equals":"openai/chatgpt-4o-latest"},"prices":{"input_mtok":5,"output_mtok":15}},{"id":"openai/codex-mini","match":{"equals":"openai/codex-mini"},"prices":{"input_mtok":1.5,"cache_read_mtok":0.375,"output_mtok":6}},{"id":"openai/gpt-3.5-turbo","match":{"or":[{"equals":"openai/gpt-3.5-turbo"},{"equals":"openai/gpt-3.5-turbo-0125"}]},"prices":{"input_mtok":0.5,"output_mtok":1.5}},{"id":"openai/gpt-3.5-turbo-0613","match":{"equals":"openai/gpt-3.5-turbo-0613"},"prices":{"input_mtok":1,"output_mtok":2}},{"id":"openai/gpt-3.5-turbo-1106","match":{"equals":"openai/gpt-3.5-turbo-1106"},"prices":{"input_mtok":1,"output_mtok":2}},{"id":"openai/gpt-3.5-turbo-16k","match":{"equals":"openai/gpt-3.5-turbo-16k"},"prices":{"input_mtok":3,"output_mtok":4}},{"id":"openai/gpt-3.5-turbo-instruct","match":{"equals":"openai/gpt-3.5-turbo-instruct"},"prices":{"input_mtok":1.5,"output_mtok":2}},{"id":"openai/gpt-4","match":{"or":[{"equals":"openai/gpt-4"},{"equals":"openai/gpt-4-0314"}]},"prices":{"input_mtok":30,"output_mtok":60}},{"id":"openai/gpt-4-1106-preview","match":{"equals":"openai/gpt-4-1106-preview"},"prices":{"input_mtok":10,"output_mtok":30}},{"id":"openai/gpt-4-32k","match":{"or":[{"equals":"openai/gpt-4-32k"},{"equals":"openai/gpt-4-32k-0314"}]},"prices":{"input_mtok":60,"output_mtok":120}},{"id":"openai/gpt-4-turbo","match":{"or":[{"equals":"openai/gpt-4-turbo"},{"equals":"openai/gpt-4-turbo-preview"}]},"prices":{"input_mtok":10,"output_mtok":30}},{"id":"openai/gpt-4.1","match":{"equals":"openai/gpt-4.1"},"prices":{"input_mtok":2,"output_mtok":8}},{"id":"openai/gpt-4.1-mini","match":{"equals":"openai/gpt-4.1-mini"},"prices":{"input_mtok":0.4,"output_mtok":1.6}},{"id":"openai/gpt-4.1-nano","match":{"equals":"openai/gpt-4.1-nano"},"prices":{"input_mtok":0.1,"output_mtok":0.4}},{"id":"openai/gpt-4.5-preview","match":{"equals":"openai/gpt-4.5-preview"},"prices":{"input_mtok":75,"output_mtok":150}},{"id":"openai/gpt-4o","match":{"or":[{"equals":"openai/gpt-4o"},{"equals":"openai/gpt-4o-2024-08-06"},{"equals":"openai/gpt-4o-2024-11-20"},{"equals":"openai/gpt-4o-search-preview"},{"equals":"openai/gpt-4o-audio-preview"}]},"prices":{"input_mtok":2.5,"output_mtok":10}},{"id":"openai/gpt-4o-2024-05-13","match":{"equals":"openai/gpt-4o-2024-05-13"},"prices":{"input_mtok":5,"output_mtok":15}},{"id":"openai/gpt-4o-mini","match":{"or":[{"equals":"openai/gpt-4o-mini"},{"equals":"openai/gpt-4o-mini-2024-07-18"},{"equals":"openai/gpt-4o-mini-search-preview"}]},"prices":{"input_mtok":0.15,"output_mtok":0.6}},{"id":"openai/gpt-4o:extended","match":{"equals":"openai/gpt-4o:extended"},"prices":{"input_mtok":6,"output_mtok":18}},{"id":"openai/gpt-5","match":{"or":[{"equals":"openai/gpt-5"},{"equals":"openai/gpt-5-chat"},{"equals":"openai/gpt-5-codex"},{"equals":"openai/gpt-5.1"},{"equals":"openai/gpt-5.1-chat"},{"equals":"openai/gpt-5.1-codex"}]},"prices":{"input_mtok":1.25,"cache_read_mtok":0.125,"output_mtok":10}},{"id":"openai/gpt-5-image","match":{"equals":"openai/gpt-5-image"},"prices":{"input_mtok":10,"cache_read_mtok":1.25,"output_mtok":10}},{"id":"openai/gpt-5-image-mini","match":{"equals":"openai/gpt-5-image-mini"},"prices":{"input_mtok":2.5,"cache_read_mtok":0.25,"output_mtok":2}},{"id":"openai/gpt-5-mini","match":{"equals":"openai/gpt-5-mini"},"prices":{"input_mtok":0.25,"cache_read_mtok":0.025,"output_mtok":2}},{"id":"openai/gpt-5-nano","match":{"equals":"openai/gpt-5-nano"},"prices":{"input_mtok":0.05,"cache_read_mtok":0.005,"output_mtok":0.4}},{"id":"openai/gpt-5-pro","match":{"equals":"openai/gpt-5-pro"},"prices":{"input_mtok":15,"output_mtok":120}},{"id":"openai/gpt-5.1-codex-mini","match":{"equals":"openai/gpt-5.1-codex-mini"},"prices":{"input_mtok":0.25,"cache_read_mtok":0.025,"output_mtok":2}},{"id":"openai/gpt-oss-120b","match":{"or":[{"equals":"openai/gpt-oss-120b"},{"equals":"openai/gpt-oss-120b:exacto"}]},"prices":{"input_mtok":0.04,"output_mtok":0.2}},{"id":"openai/gpt-oss-20b","match":{"equals":"openai/gpt-oss-20b"},"prices":{"input_mtok":0.03,"output_mtok":0.14}},{"id":"openai/gpt-oss-safeguard-20b","match":{"equals":"openai/gpt-oss-safeguard-20b"},"prices":{"input_mtok":0.075,"cache_read_mtok":0.037,"output_mtok":0.3}},{"id":"openai/o1","match":{"or":[{"equals":"openai/o1"},{"equals":"openai/o1-preview"},{"equals":"openai/o1-preview-2024-09-12"}]},"prices":{"input_mtok":15,"output_mtok":60}},{"id":"openai/o1-mini","match":{"or":[{"equals":"openai/o1-mini"},{"equals":"openai/o1-mini-2024-09-12"}]},"prices":{"input_mtok":1.1,"output_mtok":4.4}},{"id":"openai/o1-pro","match":{"equals":"openai/o1-pro"},"prices":{"input_mtok":150,"output_mtok":600}},{"id":"openai/o3","match":{"equals":"openai/o3"},"prices":{"input_mtok":10,"output_mtok":40}},{"id":"openai/o3-deep-research","match":{"equals":"openai/o3-deep-research"},"prices":{"input_mtok":10,"cache_read_mtok":2.5,"output_mtok":40}},{"id":"openai/o3-mini","match":{"or":[{"equals":"openai/o3-mini"},{"equals":"openai/o3-mini-high"}]},"prices":{"input_mtok":1.1,"output_mtok":4.4}},{"id":"openai/o3-pro","match":{"equals":"openai/o3-pro"},"prices":{"input_mtok":20,"output_mtok":80}},{"id":"openai/o4-mini","match":{"or":[{"equals":"openai/o4-mini"},{"equals":"openai/o4-mini-high"}]},"prices":{"input_mtok":1.1,"output_mtok":4.4}},{"id":"openai/o4-mini-deep-research","match":{"equals":"openai/o4-mini-deep-research"},"prices":{"input_mtok":2,"cache_read_mtok":0.5,"output_mtok":8}},{"id":"openchat/openchat-7b","match":{"equals":"openchat/openchat-7b"},"prices":{"input_mtok":0.07,"output_mtok":0.07}},{"id":"openhands-lm-32b-v0.1","match":{"equals":"openhands-lm-32b-v0.1"},"prices":{"input_mtok":2.6,"output_mtok":3.4}},{"id":"perplexity/llama-3.1-sonar-large-128k-online","match":{"equals":"perplexity/llama-3.1-sonar-large-128k-online"},"prices":{"input_mtok":1,"output_mtok":1}},{"id":"perplexity/llama-3.1-sonar-small-128k-online","match":{"equals":"perplexity/llama-3.1-sonar-small-128k-online"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"perplexity/r1-1776","match":{"equals":"perplexity/r1-1776"},"prices":{"input_mtok":2,"output_mtok":8}},{"id":"perplexity/sonar","match":{"equals":"perplexity/sonar"},"prices":{"input_mtok":1,"output_mtok":1}},{"id":"perplexity/sonar-deep-research","match":{"equals":"perplexity/sonar-deep-research"},"prices":{"input_mtok":2,"output_mtok":8}},{"id":"perplexity/sonar-pro","match":{"equals":"perplexity/sonar-pro"},"prices":{"input_mtok":3,"output_mtok":15}},{"id":"perplexity/sonar-reasoning","match":{"equals":"perplexity/sonar-reasoning"},"prices":{"input_mtok":1,"output_mtok":5}},{"id":"perplexity/sonar-reasoning-pro","match":{"equals":"perplexity/sonar-reasoning-pro"},"prices":{"input_mtok":2,"output_mtok":8}},{"id":"phi-3-medium-128k-instruct","match":{"equals":"phi-3-medium-128k-instruct"},"prices":{"input_mtok":1,"output_mtok":1}},{"id":"phi-3-mini-128k-instruct","match":{"equals":"phi-3-mini-128k-instruct"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"phi-3.5-mini-128k-instruct","match":{"equals":"phi-3.5-mini-128k-instruct"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"phi-4","match":{"equals":"phi-4"},"prices":{"input_mtok":0.07,"output_mtok":0.14}},{"id":"phi-4-multimodal-instruct","match":{"equals":"phi-4-multimodal-instruct"},"prices":{"input_mtok":0.05,"output_mtok":0.1}},{"id":"phi-4-reasoning-plus","match":{"equals":"phi-4-reasoning-plus"},"prices":{"input_mtok":0.07,"output_mtok":0.35}},{"id":"pixtral-12b","match":{"equals":"pixtral-12b"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"pixtral-large-2411","match":{"equals":"pixtral-large-2411"},"prices":{"input_mtok":2,"output_mtok":6}},{"id":"pygmalionai/mythalion-13b","match":{"equals":"pygmalionai/mythalion-13b"},"prices":{"input_mtok":0.5625,"output_mtok":1.125}},{"id":"qwen-2-72b-instruct","match":{"equals":"qwen-2-72b-instruct"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"qwen-2.5-72b-instruct","match":{"equals":"qwen-2.5-72b-instruct"},"prices":{"input_mtok":0.12,"output_mtok":0.39}},{"id":"qwen-2.5-7b-instruct","match":{"equals":"qwen-2.5-7b-instruct"},"prices":{"input_mtok":0.04,"output_mtok":0.1}},{"id":"qwen-2.5-coder-32b-instruct","match":{"equals":"qwen-2.5-coder-32b-instruct"},"prices":{"input_mtok":0.06,"output_mtok":0.15}},{"id":"qwen-2.5-vl-7b-instruct","match":{"equals":"qwen-2.5-vl-7b-instruct"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"qwen-max","match":{"equals":"qwen-max"},"prices":{"input_mtok":1.6,"cache_read_mtok":0.64,"output_mtok":6.4}},{"id":"qwen-plus","match":{"equals":"qwen-plus"},"prices":{"input_mtok":0.4,"cache_read_mtok":0.16,"output_mtok":1.2}},{"id":"qwen-turbo","match":{"equals":"qwen-turbo"},"prices":{"input_mtok":0.05,"cache_read_mtok":0.02,"output_mtok":0.2}},{"id":"qwen-vl-max","match":{"equals":"qwen-vl-max"},"prices":{"input_mtok":0.8,"output_mtok":3.2}},{"id":"qwen-vl-plus","match":{"equals":"qwen-vl-plus"},"prices":{"input_mtok":0.21,"output_mtok":0.63}},{"id":"qwen/qwen-2-72b-instruct","match":{"equals":"qwen/qwen-2-72b-instruct"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"qwen/qwen-2.5-72b-instruct","match":{"equals":"qwen/qwen-2.5-72b-instruct"},"prices":{"input_mtok":0.12,"output_mtok":0.39}},{"id":"qwen/qwen-2.5-7b-instruct","match":{"equals":"qwen/qwen-2.5-7b-instruct"},"prices":{"input_mtok":0.05,"output_mtok":0.1}},{"id":"qwen/qwen-2.5-coder-32b-instruct","match":{"equals":"qwen/qwen-2.5-coder-32b-instruct"},"prices":{"input_mtok":0.07,"output_mtok":0.15}},{"id":"qwen/qwen-2.5-vl-72b-instruct","match":{"equals":"qwen/qwen-2.5-vl-72b-instruct"},"prices":{"input_mtok":0.6,"output_mtok":0.6}},{"id":"qwen/qwen-2.5-vl-7b-instruct","match":{"equals":"qwen/qwen-2.5-vl-7b-instruct"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"qwen/qwen-max","match":{"equals":"qwen/qwen-max"},"prices":{"input_mtok":1.6,"output_mtok":6.4}},{"id":"qwen/qwen-plus","match":{"equals":"qwen/qwen-plus"},"prices":{"input_mtok":0.4,"output_mtok":1.2}},{"id":"qwen/qwen-turbo","match":{"equals":"qwen/qwen-turbo"},"prices":{"input_mtok":0.05,"output_mtok":0.2}},{"id":"qwen/qwen-vl-max","match":{"equals":"qwen/qwen-vl-max"},"prices":{"input_mtok":0.8,"output_mtok":3.2}},{"id":"qwen/qwen-vl-plus","match":{"equals":"qwen/qwen-vl-plus"},"prices":{"input_mtok":0.21,"output_mtok":0.63}},{"id":"qwen/qwen2.5-coder-7b-instruct","match":{"equals":"qwen/qwen2.5-coder-7b-instruct"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"qwen/qwen2.5-vl-32b-instruct","match":{"equals":"qwen/qwen2.5-vl-32b-instruct"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"qwen/qwen2.5-vl-72b-instruct","match":{"equals":"qwen/qwen2.5-vl-72b-instruct"},"prices":{"input_mtok":0.7,"output_mtok":0.7}},{"id":"qwen/qwen3-max","match":{"equals":"qwen/qwen3-max"},"prices":{"input_mtok":1.2,"output_mtok":6}},{"id":"qwen/qwq-32b","match":{"equals":"qwen/qwq-32b"},"prices":{"input_mtok":0.15,"output_mtok":0.2}},{"id":"qwen/qwq-32b-preview","match":{"equals":"qwen/qwq-32b-preview"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"qwen2.5-vl-32b-instruct","match":{"equals":"qwen2.5-vl-32b-instruct"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"qwen2.5-vl-72b-instruct","match":{"equals":"qwen2.5-vl-72b-instruct"},"prices":{"input_mtok":0.25,"output_mtok":0.75}},{"id":"qwen3-14b","match":{"equals":"qwen3-14b"},"prices":{"input_mtok":0.06,"output_mtok":0.24}},{"id":"qwen3-235b-a22b","match":{"equals":"qwen3-235b-a22b"},"prices":{"input_mtok":0.13,"output_mtok":0.6}},{"id":"qwen3-30b-a3b","match":{"equals":"qwen3-30b-a3b"},"prices":{"input_mtok":0.08,"output_mtok":0.29}},{"id":"qwen3-32b","match":{"equals":"qwen3-32b"},"prices":{"input_mtok":0.1,"output_mtok":0.3}},{"id":"qwen3-8b","match":{"equals":"qwen3-8b"},"prices":{"input_mtok":0.035,"output_mtok":0.138}},{"id":"qwq-32b","match":{"equals":"qwq-32b"},"prices":{"input_mtok":0.15,"output_mtok":0.2}},{"id":"qwq-32b-preview","match":{"equals":"qwq-32b-preview"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"r1-1776","match":{"equals":"r1-1776"},"prices":{"input_mtok":2,"output_mtok":8}},{"id":"raifle/sorcererlm-8x22b","match":{"equals":"raifle/sorcererlm-8x22b"},"prices":{"input_mtok":4.5,"output_mtok":4.5}},{"id":"remm-slerp-l2-13b","match":{"equals":"remm-slerp-l2-13b"},"prices":{"input_mtok":0.8,"output_mtok":1.2}},{"id":"rocinante-12b","match":{"equals":"rocinante-12b"},"prices":{"input_mtok":0.25,"output_mtok":0.5}},{"id":"sao10k/fimbulvetr-11b-v2","match":{"equals":"sao10k/fimbulvetr-11b-v2"},"prices":{"input_mtok":0.8,"output_mtok":1.2}},{"id":"sao10k/l3-euryale-70b","match":{"equals":"sao10k/l3-euryale-70b"},"prices":{"input_mtok":1.48,"output_mtok":1.48}},{"id":"sao10k/l3-lunaris-8b","match":{"equals":"sao10k/l3-lunaris-8b"},"prices":{"input_mtok":0.02,"output_mtok":0.05}},{"id":"sao10k/l3.1-euryale-70b","match":{"equals":"sao10k/l3.1-euryale-70b"},"prices":{"input_mtok":0.7,"output_mtok":0.8}},{"id":"sao10k/l3.3-euryale-70b","match":{"equals":"sao10k/l3.3-euryale-70b"},"prices":{"input_mtok":0.7,"output_mtok":0.8}},{"id":"scb10x/llama3.1-typhoon2-70b-instruct","match":{"equals":"scb10x/llama3.1-typhoon2-70b-instruct"},"prices":{"input_mtok":0.88,"output_mtok":0.88}},{"id":"scb10x/llama3.1-typhoon2-8b-instruct","match":{"equals":"scb10x/llama3.1-typhoon2-8b-instruct"},"prices":{"input_mtok":0.18,"output_mtok":0.18}},{"id":"skyfall-36b-v2","match":{"equals":"skyfall-36b-v2"},"prices":{"input_mtok":0.5,"output_mtok":0.8}},{"id":"sonar","match":{"equals":"sonar"},"prices":{"input_mtok":1,"output_mtok":1}},{"id":"sonar-deep-research","match":{"equals":"sonar-deep-research"},"prices":{"input_mtok":2,"output_mtok":8}},{"id":"sonar-pro","match":{"equals":"sonar-pro"},"prices":{"input_mtok":3,"output_mtok":15}},{"id":"sonar-reasoning","match":{"equals":"sonar-reasoning"},"prices":{"input_mtok":1,"output_mtok":5}},{"id":"sonar-reasoning-pro","match":{"equals":"sonar-reasoning-pro"},"prices":{"input_mtok":2,"output_mtok":8}},{"id":"sophosympatheia/midnight-rose-70b","match":{"equals":"sophosympatheia/midnight-rose-70b"},"prices":{"input_mtok":0.8,"output_mtok":0.8}},{"id":"sorcererlm-8x22b","match":{"equals":"sorcererlm-8x22b"},"prices":{"input_mtok":4.5,"output_mtok":4.5}},{"id":"spotlight","match":{"equals":"spotlight"},"prices":{"input_mtok":0.18,"output_mtok":0.18}},{"id":"steelskull/l3.3-electra-r1-70b","match":{"equals":"steelskull/l3.3-electra-r1-70b"},"prices":{"input_mtok":0.7,"output_mtok":0.95}},{"id":"thedrummer/anubis-pro-105b-v1","match":{"equals":"thedrummer/anubis-pro-105b-v1"},"prices":{"input_mtok":0.8,"output_mtok":1}},{"id":"thedrummer/rocinante-12b","match":{"equals":"thedrummer/rocinante-12b"},"prices":{"input_mtok":0.25,"output_mtok":0.5}},{"id":"thedrummer/skyfall-36b-v2","match":{"equals":"thedrummer/skyfall-36b-v2"},"prices":{"input_mtok":0.5,"output_mtok":0.8}},{"id":"thedrummer/unslopnemo-12b","match":{"equals":"thedrummer/unslopnemo-12b"},"prices":{"input_mtok":0.5,"output_mtok":0.5}},{"id":"toppy-m-7b","match":{"equals":"toppy-m-7b"},"prices":{"input_mtok":0.8,"output_mtok":1.2}},{"id":"undi95/remm-slerp-l2-13b","match":{"equals":"undi95/remm-slerp-l2-13b"},"prices":{"input_mtok":0.5625,"output_mtok":1.125}},{"id":"undi95/toppy-m-7b","match":{"equals":"undi95/toppy-m-7b"},"prices":{"input_mtok":0.07,"output_mtok":0.07}},{"id":"unslopnemo-12b","match":{"equals":"unslopnemo-12b"},"prices":{"input_mtok":0.45,"output_mtok":0.45}},{"id":"valkyrie-49b-v1","match":{"equals":"valkyrie-49b-v1"},"prices":{"input_mtok":0.5,"output_mtok":0.8}},{"id":"virtuoso-large","match":{"equals":"virtuoso-large"},"prices":{"input_mtok":0.75,"output_mtok":1.2}},{"id":"virtuoso-medium-v2","match":{"equals":"virtuoso-medium-v2"},"prices":{"input_mtok":0.5,"output_mtok":0.8}},{"id":"weaver","match":{"equals":"weaver"},"prices":{"input_mtok":1.5,"output_mtok":1.5}},{"id":"wizardlm-2-8x22b","match":{"equals":"wizardlm-2-8x22b"},"prices":{"input_mtok":0.48,"output_mtok":0.48}},{"id":"x-ai/grok-2-1212","match":{"equals":"x-ai/grok-2-1212"},"prices":{"input_mtok":2,"output_mtok":10}},{"id":"x-ai/grok-2-vision-1212","match":{"equals":"x-ai/grok-2-vision-1212"},"prices":{"input_mtok":2,"output_mtok":10}},{"id":"x-ai/grok-3-beta","match":{"equals":"x-ai/grok-3-beta"},"prices":{"input_mtok":3,"output_mtok":15}},{"id":"x-ai/grok-3-mini-beta","match":{"equals":"x-ai/grok-3-mini-beta"},"prices":{"input_mtok":0.3,"output_mtok":0.5}},{"id":"x-ai/grok-4-fast","match":{"equals":"x-ai/grok-4-fast"},"context_window":2000000,"prices":{"input_mtok":{"base":0.2,"tiers":[{"start":128000,"price":0.4}]},"cache_read_mtok":0.05,"output_mtok":{"base":0.5,"tiers":[{"start":128000,"price":1}]}}},{"id":"x-ai/grok-beta","match":{"equals":"x-ai/grok-beta"},"prices":{"input_mtok":5,"output_mtok":15}},{"id":"x-ai/grok-code-fast-1","match":{"equals":"x-ai/grok-code-fast-1"},"context_window":256000,"prices":{"input_mtok":0.2,"cache_read_mtok":0.02,"output_mtok":1.5}},{"id":"x-ai/grok-vision-beta","match":{"equals":"x-ai/grok-vision-beta"},"prices":{"input_mtok":5,"output_mtok":15}},{"id":"xwin-lm/xwin-lm-70b","match":{"equals":"xwin-lm/xwin-lm-70b"},"prices":{"input_mtok":3.75,"output_mtok":3.75}},{"id":"yi-large","match":{"equals":"yi-large"},"prices":{"input_mtok":3,"output_mtok":3}},{"id":"z-ai/glm-4.5","match":{"equals":"z-ai/glm-4.5"},"context_window":131072,"prices":{"input_mtok":0.35,"output_mtok":1.55}},{"id":"z-ai/glm-4.6","match":{"equals":"z-ai/glm-4.6"},"context_window":202752,"prices":{"input_mtok":0.4,"output_mtok":1.75}}]},{"id":"ovhcloud","name":"OVHcloud AI Endpoints","pricing_urls":["https://oai.endpoints.kepler.ai.cloud.ovh.net/v1/models"],"api_pattern":"https://oai\\.endpoints\\.kepler\\.ai\\.cloud\\.ovh\\.net","extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["prompt_tokens_details","audio_tokens"],"dest":"input_audio_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"DeepSeek-R1-Distill-Llama-70B","match":{"or":[{"equals":"DeepSeek-R1-Distill-Llama-70B"},{"equals":"deepseek-r1-distill-llama-70b"}]},"context_window":131072,"prices":{"input_mtok":0.74,"output_mtok":0.74}},{"id":"Llama-3.1-8B-Instruct","match":{"or":[{"equals":"Llama-3.1-8B-Instruct"},{"equals":"llama-3.1-8b-instruct"}]},"context_window":131072,"prices":{"input_mtok":0.11,"output_mtok":0.11}},{"id":"Meta-Llama-3_1-70B-Instruct","match":{"or":[{"equals":"Meta-Llama-3_1-70B-Instruct"},{"equals":"meta-llama-3_1-70b-instruct"}]},"context_window":131072,"prices":{"input_mtok":0.74,"output_mtok":0.74}},{"id":"Meta-Llama-3_3-70B-Instruct","match":{"or":[{"equals":"Meta-Llama-3_3-70B-Instruct"},{"equals":"meta-llama-3_3-70b-instruct"}]},"context_window":131072,"prices":{"input_mtok":0.74,"output_mtok":0.74}},{"id":"Mistral-7B-Instruct-v0.3","match":{"or":[{"equals":"Mistral-7B-Instruct-v0.3"},{"equals":"mistral-7b-instruct-v0.3"}]},"context_window":65536,"prices":{"input_mtok":0.11,"output_mtok":0.11}},{"id":"Mistral-Nemo-Instruct-2407","match":{"or":[{"equals":"Mistral-Nemo-Instruct-2407"},{"equals":"mistral-nemo-instruct-2407"}]},"context_window":65536,"prices":{"input_mtok":0.14,"output_mtok":0.14}},{"id":"Mistral-Small-3.2-24B-Instruct-2506","match":{"or":[{"equals":"Mistral-Small-3.2-24B-Instruct-2506"},{"equals":"mistral-small-3.2-24b-instruct-2506"}]},"context_window":131072,"prices":{"input_mtok":0.1,"output_mtok":0.31}},{"id":"Mixtral-8x7B-Instruct-v0.1","match":{"or":[{"equals":"Mixtral-8x7B-Instruct-v0.1"},{"equals":"mixtral-8x7b-instruct-v0.1"}]},"context_window":32768,"prices":{"input_mtok":0.7,"output_mtok":0.7}},{"id":"Qwen2.5-Coder-32B-Instruct","match":{"or":[{"equals":"Qwen2.5-Coder-32B-Instruct"},{"equals":"qwen2.5-coder-32b-instruct"}]},"context_window":32768,"prices":{"input_mtok":0.96,"output_mtok":0.96}},{"id":"Qwen2.5-VL-72B-Instruct","match":{"or":[{"equals":"Qwen2.5-VL-72B-Instruct"},{"equals":"qwen2.5-vl-72b-instruct"}]},"context_window":32768,"prices":{"input_mtok":1.01,"output_mtok":1.01}},{"id":"Qwen3-32B","match":{"or":[{"equals":"Qwen3-32B"},{"equals":"qwen3-32b"}]},"context_window":32768,"prices":{"input_mtok":0.09,"output_mtok":0.25}},{"id":"Qwen3-Coder-30B-A3B-Instruct","match":{"or":[{"equals":"Qwen3-Coder-30B-A3B-Instruct"},{"equals":"qwen3-coder-30b-a3b-instruct"}]},"context_window":262144,"prices":{"input_mtok":0.07,"output_mtok":0.26}},{"id":"bge-base-en-v1.5","match":{"equals":"bge-base-en-v1.5"},"context_window":512,"prices":{"input_mtok":0.01}},{"id":"bge-m3","match":{"equals":"bge-m3"},"context_window":8192,"prices":{"input_mtok":0.01}},{"id":"bge-multilingual-gemma2","match":{"equals":"bge-multilingual-gemma2"},"context_window":8192,"prices":{"input_mtok":0.01}},{"id":"gpt-oss-120b","match":{"equals":"gpt-oss-120b"},"context_window":131072,"prices":{"input_mtok":0.09,"output_mtok":0.47}},{"id":"gpt-oss-20b","match":{"equals":"gpt-oss-20b"},"context_window":131072,"prices":{"input_mtok":0.05,"output_mtok":0.18}},{"id":"llava-next-mistral-7b","match":{"equals":"llava-next-mistral-7b"},"context_window":32768,"prices":{"input_mtok":0.32,"output_mtok":0.32}}]},{"id":"perplexity","name":"Perplexity","pricing_urls":["https://docs.perplexity.ai/guides/pricing"],"api_pattern":"https://api\\.perplexity\\.ai","models":[{"id":"llama-3.1-sonar-large-128k-online","match":{"equals":"llama-3.1-sonar-large-128k-online"},"prices":{"input_mtok":1,"output_mtok":1}},{"id":"llama-3.1-sonar-small-128k-online","match":{"equals":"llama-3.1-sonar-small-128k-online"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"r1-1776","match":{"equals":"r1-1776"},"prices":{"input_mtok":2,"output_mtok":8}},{"id":"sonar","match":{"equals":"sonar"},"prices":{"input_mtok":1,"output_mtok":1,"requests_kcount":12}},{"id":"sonar-deep-research","match":{"equals":"sonar-deep-research"},"prices":{"input_mtok":2,"output_mtok":8}},{"id":"sonar-pro","match":{"equals":"sonar-pro"},"prices":{"input_mtok":3,"output_mtok":15,"requests_kcount":14}},{"id":"sonar-reasoning","match":{"equals":"sonar-reasoning"},"prices":{"input_mtok":1,"output_mtok":5,"requests_kcount":12}},{"id":"sonar-reasoning-pro","match":{"equals":"sonar-reasoning-pro"},"prices":{"input_mtok":2,"output_mtok":8,"requests_kcount":14}}]},{"id":"together","name":"Together AI","pricing_urls":["https://www.together.ai/pricing"],"api_pattern":"https://api\\.together\\.xyz","provider_match":{"or":[{"equals":"together-ai"},{"equals":"together_ai"}]},"models":[{"id":"Austism/chronos-hermes-13b","match":{"equals":"Austism/chronos-hermes-13b"},"prices":{"input_mtok":0.3,"output_mtok":0.3}},{"id":"Gryphe/MythoMax-L2-13b","match":{"equals":"Gryphe/MythoMax-L2-13b"},"prices":{"input_mtok":0.3,"output_mtok":0.3}},{"id":"Nexusflow/NexusRaven-V2-13B","match":{"equals":"Nexusflow/NexusRaven-V2-13B"},"prices":{"input_mtok":0.3,"output_mtok":0.3}},{"id":"NousResearch/Nous-Capybara-7B-V1p9","match":{"equals":"NousResearch/Nous-Capybara-7B-V1p9"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO","match":{"equals":"NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"NousResearch/Nous-Hermes-2-Mixtral-8x7B-SFT","match":{"equals":"NousResearch/Nous-Hermes-2-Mixtral-8x7B-SFT"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"NousResearch/Nous-Hermes-2-Yi-34B","match":{"equals":"NousResearch/Nous-Hermes-2-Yi-34B"},"prices":{"input_mtok":0.8,"output_mtok":0.8}},{"id":"NousResearch/Nous-Hermes-Llama2-13b","match":{"equals":"NousResearch/Nous-Hermes-Llama2-13b"},"prices":{"input_mtok":0.225,"output_mtok":0.225}},{"id":"NousResearch/Nous-Hermes-llama-2-7b","match":{"equals":"NousResearch/Nous-Hermes-llama-2-7b"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"Open-Orca/Mistral-7B-OpenOrca","match":{"equals":"Open-Orca/Mistral-7B-OpenOrca"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"Qwen/Qwen1.5-0.5B","match":{"or":[{"equals":"Qwen/Qwen1.5-0.5B"},{"equals":"Qwen/Qwen1.5-0.5B-Chat"}]},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"Qwen/Qwen1.5-1.8B","match":{"or":[{"equals":"Qwen/Qwen1.5-1.8B"},{"equals":"Qwen/Qwen1.5-1.8B-Chat"}]},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"Qwen/Qwen1.5-14B","match":{"or":[{"equals":"Qwen/Qwen1.5-14B"},{"equals":"Qwen/Qwen1.5-14B-Chat"}]},"prices":{"input_mtok":0.3,"output_mtok":0.3}},{"id":"Qwen/Qwen1.5-4B","match":{"or":[{"equals":"Qwen/Qwen1.5-4B"},{"equals":"Qwen/Qwen1.5-4B-Chat"}]},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"Qwen/Qwen1.5-72B","match":{"equals":"Qwen/Qwen1.5-72B"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"Qwen/Qwen1.5-7B","match":{"or":[{"equals":"Qwen/Qwen1.5-7B"},{"equals":"Qwen/Qwen1.5-7B-Chat"}]},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"Undi95/ReMM-SLERP-L2-13B","match":{"equals":"Undi95/ReMM-SLERP-L2-13B"},"prices":{"input_mtok":0.3,"output_mtok":0.3}},{"id":"Undi95/Toppy-M-7B","match":{"equals":"Undi95/Toppy-M-7B"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"WizardLM/WizardLM-13B-V1.2","match":{"equals":"WizardLM/WizardLM-13B-V1.2"},"prices":{"input_mtok":0.3,"output_mtok":0.3}},{"id":"allenai/OLMo-7B","match":{"or":[{"equals":"allenai/OLMo-7B"},{"equals":"allenai/OLMo-7B-Instruct"},{"equals":"allenai/OLMo-7B-Twin-2T"}]},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"codellama/CodeLlama-13b-Instruct-hf","match":{"equals":"codellama/CodeLlama-13b-Instruct-hf"},"prices":{"input_mtok":0.225,"output_mtok":0.225}},{"id":"codellama/CodeLlama-34b-Instruct-hf","match":{"equals":"codellama/CodeLlama-34b-Instruct-hf"},"prices":{"input_mtok":0.776,"output_mtok":0.776}},{"id":"codellama/CodeLlama-70b-Instruct-hf","match":{"equals":"codellama/CodeLlama-70b-Instruct-hf"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"codellama/CodeLlama-7b-Instruct-hf","match":{"equals":"codellama/CodeLlama-7b-Instruct-hf"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"deepseek-ai/deepseek-coder-33b-instruct","match":{"equals":"deepseek-ai/deepseek-coder-33b-instruct"},"prices":{"input_mtok":0.8,"output_mtok":0.8}},{"id":"garage-bAInd/Platypus2-70B-instruct","match":{"equals":"garage-bAInd/Platypus2-70B-instruct"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"google/gemma-2b","match":{"or":[{"equals":"google/gemma-2b"},{"equals":"google/gemma-2b-it"}]},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"google/gemma-7b","match":{"or":[{"equals":"google/gemma-7b"},{"equals":"google/gemma-7b-it"}]},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"lmsys/vicuna-13b-v1.5","match":{"equals":"lmsys/vicuna-13b-v1.5"},"prices":{"input_mtok":0.3,"output_mtok":0.3}},{"id":"lmsys/vicuna-7b-v1.5","match":{"equals":"lmsys/vicuna-7b-v1.5"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"meta-llama/Llama-2-13b-chat-hf","match":{"equals":"meta-llama/Llama-2-13b-chat-hf"},"prices":{"input_mtok":0.225,"output_mtok":0.225}},{"id":"meta-llama/Llama-2-70b-chat-hf","match":{"equals":"meta-llama/Llama-2-70b-chat-hf"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"meta-llama/Llama-2-7b-chat-hf","match":{"equals":"meta-llama/Llama-2-7b-chat-hf"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"meta-llama/Llama-3-70b-chat-hf","match":{"equals":"meta-llama/Llama-3-70b-chat-hf"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"meta-llama/Llama-3-8b-chat-hf","match":{"equals":"meta-llama/Llama-3-8b-chat-hf"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"meta-llama/Llama-3.3-70B-Instruct-Turbo","match":{"equals":"meta-llama/Llama-3.3-70B-Instruct-Turbo"},"prices":{"input_mtok":0.88,"output_mtok":0.88}},{"id":"meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8","match":{"equals":"meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8"},"prices":{"input_mtok":0.27,"output_mtok":0.85}},{"id":"meta-llama/Llama-4-Scout-17B-16E-Instruct","match":{"equals":"meta-llama/Llama-4-Scout-17B-16E-Instruct"},"prices":{"input_mtok":0.18,"output_mtok":0.59}},{"id":"meta-llama/Meta-Llama-3-70B-Instruct-Lite","match":{"equals":"meta-llama/Meta-Llama-3-70B-Instruct-Lite"},"prices":{"input_mtok":0.54,"output_mtok":0.54}},{"id":"meta-llama/Meta-Llama-3-70B-Instruct-Turbo","match":{"equals":"meta-llama/Meta-Llama-3-70B-Instruct-Turbo"},"prices":{"input_mtok":0.88,"output_mtok":0.88}},{"id":"meta-llama/Meta-Llama-3-8B-Instruct-Lite","match":{"equals":"meta-llama/Meta-Llama-3-8B-Instruct-Lite"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"meta-llama/Meta-Llama-3-8B-Instruct-Turbo","match":{"equals":"meta-llama/Meta-Llama-3-8B-Instruct-Turbo"},"prices":{"input_mtok":0.18,"output_mtok":0.18}},{"id":"meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo","match":{"equals":"meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo"},"prices":{"input_mtok":3.5,"output_mtok":3.5}},{"id":"meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo","match":{"equals":"meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo"},"prices":{"input_mtok":0.88,"output_mtok":0.88}},{"id":"meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo","match":{"equals":"meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo"},"prices":{"input_mtok":0.18,"output_mtok":0.18}},{"id":"meta-llama/Meta-Llama-3.3-70B-Instruct-Turbo","match":{"equals":"meta-llama/Meta-Llama-3.3-70B-Instruct-Turbo"},"prices":{"input_mtok":0.88,"output_mtok":0.88}},{"id":"microsoft/WizardLM-2-8x22B","match":{"equals":"microsoft/WizardLM-2-8x22B"},"prices":{"input_mtok":1.2,"output_mtok":1.2}},{"id":"microsoft/phi-2","match":{"equals":"microsoft/phi-2"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"mistralai/Mistral-7B-Instruct-v0.1","match":{"equals":"mistralai/Mistral-7B-Instruct-v0.1"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"mistralai/Mistral-7B-Instruct-v0.2","match":{"equals":"mistralai/Mistral-7B-Instruct-v0.2"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"mistralai/Mistral-7B-v0.1","match":{"equals":"mistralai/Mistral-7B-v0.1"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"mistralai/Mixtral-8x22B-Instruct-v0.1","match":{"equals":"mistralai/Mixtral-8x22B-Instruct-v0.1"},"prices":{"input_mtok":2.4,"output_mtok":2.4}},{"id":"mistralai/Mixtral-8x7B-Instruct-v0.1","match":{"equals":"mistralai/Mixtral-8x7B-Instruct-v0.1"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"mistralai/Mixtral-8x7B-v0.1","match":{"equals":"mistralai/Mixtral-8x7B-v0.1"},"prices":{"input_mtok":0.9,"output_mtok":0.9}},{"id":"openchat/openchat-3.5-1210","match":{"equals":"openchat/openchat-3.5-1210"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"snorkelai/Snorkel-Mistral-PairRM-DPO","match":{"equals":"snorkelai/Snorkel-Mistral-PairRM-DPO"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"teknium/OpenHermes-2-Mistral-7B","match":{"equals":"teknium/OpenHermes-2-Mistral-7B"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"teknium/OpenHermes-2p5-Mistral-7B","match":{"equals":"teknium/OpenHermes-2p5-Mistral-7B"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"togethercomputer/GPT-JT-Moderation-6B","match":{"equals":"togethercomputer/GPT-JT-Moderation-6B"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"togethercomputer/Llama-2-7B-32K-Instruct","match":{"equals":"togethercomputer/Llama-2-7B-32K-Instruct"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"togethercomputer/RedPajama-INCITE-7B-Base","match":{"equals":"togethercomputer/RedPajama-INCITE-7B-Base"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"togethercomputer/RedPajama-INCITE-7B-Chat","match":{"equals":"togethercomputer/RedPajama-INCITE-7B-Chat"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"togethercomputer/RedPajama-INCITE-7B-Instruct","match":{"equals":"togethercomputer/RedPajama-INCITE-7B-Instruct"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"togethercomputer/RedPajama-INCITE-Base-3B-v1","match":{"equals":"togethercomputer/RedPajama-INCITE-Base-3B-v1"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"togethercomputer/RedPajama-INCITE-Chat-3B-v1","match":{"equals":"togethercomputer/RedPajama-INCITE-Chat-3B-v1"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"togethercomputer/RedPajama-INCITE-Instruct-3B-v1","match":{"equals":"togethercomputer/RedPajama-INCITE-Instruct-3B-v1"},"prices":{"input_mtok":0.1,"output_mtok":0.1}},{"id":"togethercomputer/StripedHyena-Hessian-7B","match":{"equals":"togethercomputer/StripedHyena-Hessian-7B"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"togethercomputer/StripedHyena-Nous-7B","match":{"equals":"togethercomputer/StripedHyena-Nous-7B"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"togethercomputer/alpaca-7b","match":{"equals":"togethercomputer/alpaca-7b"},"prices":{"input_mtok":0.2,"output_mtok":0.2}},{"id":"upstage/SOLAR-10.7B-Instruct-v1.0","match":{"equals":"upstage/SOLAR-10.7B-Instruct-v1.0"},"prices":{"input_mtok":0.3,"output_mtok":0.3}},{"id":"zero-one-ai/Yi-34B","match":{"equals":"zero-one-ai/Yi-34B"},"prices":{"input_mtok":0.8,"output_mtok":0.8}},{"id":"zero-one-ai/Yi-6B","match":{"equals":"zero-one-ai/Yi-6B"},"prices":{"input_mtok":0.2,"output_mtok":0.2}}]},{"id":"x-ai","name":"X AI","pricing_urls":["https://docs.x.ai/docs/models"],"api_pattern":"https://api\\.x\\.ai","model_match":{"contains":"grok"},"provider_match":{"equals":"xai"},"extractors":[{"api_flavor":"chat","root":"usage","model_path":"model","mappings":[{"path":"prompt_tokens","dest":"input_tokens","required":true},{"path":["prompt_tokens_details","cached_tokens"],"dest":"cache_read_tokens","required":false},{"path":["completion_tokens_details","audio_tokens"],"dest":"output_audio_tokens","required":false},{"path":"completion_tokens","dest":"output_tokens","required":true}]}],"models":[{"id":"grok-2-1212","match":{"or":[{"equals":"grok-2-1212"},{"equals":"grok-2"},{"equals":"grok-2-latest"}]},"context_window":32768,"prices":{"input_mtok":2,"output_mtok":10},"deprecated":true},{"id":"grok-2-vision-1212","match":{"or":[{"equals":"grok-2-vision-1212"},{"equals":"grok-2-vision"},{"equals":"grok-2-vision-latest"}]},"context_window":32768,"prices":{"input_mtok":2,"output_mtok":10}},{"id":"grok-3","match":{"or":[{"equals":"grok-3"},{"equals":"grok-3-latest"},{"equals":"grok-3-beta"}]},"context_window":131072,"prices":{"input_mtok":3,"cache_read_mtok":0.75,"output_mtok":15}},{"id":"grok-3-fast","match":{"or":[{"equals":"grok-3-fast"},{"equals":"grok-3-fast-latest"},{"equals":"grok-3-fast-beta"}]},"context_window":131072,"prices":{"input_mtok":5,"cache_read_mtok":1.25,"output_mtok":25}},{"id":"grok-3-mini","match":{"or":[{"equals":"grok-3-mini"},{"equals":"grok-3-mini-beta"},{"equals":"grok-3-mini-latest"}]},"context_window":131072,"prices":{"input_mtok":0.3,"cache_read_mtok":0.075,"output_mtok":0.5}},{"id":"grok-3-mini-fast","match":{"or":[{"equals":"grok-3-mini-fast"},{"equals":"grok-3-mini-fast-beta"},{"equals":"grok-3-mini-fast-latest"}]},"context_window":131072,"prices":{"input_mtok":0.6,"cache_read_mtok":0.15,"output_mtok":4}},{"id":"grok-4-0709","match":{"or":[{"equals":"grok-4-0709"},{"equals":"grok-4"},{"equals":"grok-4-latest"}]},"context_window":256000,"prices":{"input_mtok":3,"cache_read_mtok":0.75,"output_mtok":15}},{"id":"grok-4-1-fast-non-reasoning","match":{"or":[{"equals":"grok-4-1-fast-non-reasoning"},{"equals":"grok-4-1-fast-non-reasoning-latest"}]},"context_window":2000000,"prices":{"input_mtok":0.2,"cache_read_mtok":0.05,"output_mtok":0.5}},{"id":"grok-4-1-fast-reasoning","match":{"or":[{"equals":"grok-4-1-fast"},{"equals":"grok-4-1-fast-reasoning"},{"equals":"grok-4-1-fast-reasoning-latest"}]},"context_window":2000000,"prices":{"input_mtok":0.2,"cache_read_mtok":0.05,"output_mtok":0.5}},{"id":"grok-4-fast-non-reasoning","match":{"or":[{"equals":"grok-4-fast-non-reasoning"},{"equals":"grok-4-fast-non-reasoning-latest"}]},"context_window":2000000,"prices":{"input_mtok":0.2,"cache_read_mtok":0.05,"output_mtok":0.5}},{"id":"grok-4-fast-reasoning","match":{"or":[{"equals":"grok-4-fast"},{"equals":"grok-4-fast-reasoning"},{"equals":"grok-4-fast-reasoning-latest"}]},"context_window":2000000,"prices":{"input_mtok":0.2,"cache_read_mtok":0.05,"output_mtok":0.5}},{"id":"grok-code-fast-1","match":{"or":[{"equals":"grok-code-fast"},{"equals":"grok-code-fast-1"},{"equals":"grok-code-fast-1-0825"}]},"context_window":256000,"prices":{"input_mtok":0.2,"cache_read_mtok":0.02,"output_mtok":1.5}}]}]
diff --git a/config/manifest-sign.pub b/config/manifest-sign.pub
deleted file mode 100644
index 44dbdd141..000000000
--- a/config/manifest-sign.pub
+++ /dev/null
@@ -1,2 +0,0 @@
-untrusted comment: minisign public key 93A070CBB288AC9B
-RWSbrIiyy3Cgk9Ax/nqK4QNjnClKlsaXunBHFFgVo4POGZHTkrrvwVr1
diff --git a/config/mcp-tools.json b/config/mcp-tools.json
deleted file mode 100644
index 806083b0e..000000000
--- a/config/mcp-tools.json
+++ /dev/null
@@ -1,339 +0,0 @@
-[
- {
- "namespaced_name": "fetch_http",
- "original_name": "fetch_http",
- "description": "Fetch a URL and return its content. In 'markdown' mode (default), HTML is converted to clean markdown preserving headings, links, lists, bold/italic, and code blocks. In 'content' mode, HTML is stripped to plain text with newlines at block boundaries. In 'raw' mode, the response body is returned unchanged. Output starts with metadata lines (URL, Domain, Content length) followed by the page content. Use start_index and max_length for pagination -- if the response is truncated, a 'Remaining' line shows the next start_index value to continue. The URL's domain must be allowed by network policy; blocked or unknown domains return an error. Errors: domain blocked by policy, invalid URL, HTTP request failed.",
- "input_schema": {
- "properties": {
- "format": {
- "description": "Output format: 'markdown' (default) converts HTML to markdown preserving structure (headings, links, lists, code). 'content' strips to plain text. 'raw' returns the response body unchanged.",
- "enum": [
- "markdown",
- "content",
- "raw"
- ],
- "type": "string"
- },
- "max_length": {
- "description": "Maximum characters to return (default: 5000). If the content exceeds this, a 'Remaining' line indicates how to fetch the rest.",
- "type": "integer"
- },
- "start_index": {
- "description": "Character offset to start reading from (default: 0). Use the value from the 'Remaining' line in a previous response to continue paginating.",
- "type": "integer"
- },
- "url": {
- "description": "The URL to fetch. The domain must be allowed by network policy or the request will be rejected.",
- "type": "string"
- }
- },
- "required": [
- "url"
- ],
- "type": "object"
- },
- "server_name": "builtin",
- "annotations": {
- "title": "Fetch HTTP",
- "read_only_hint": true,
- "destructive_hint": false,
- "idempotent_hint": true,
- "open_world_hint": true
- }
- },
- {
- "namespaced_name": "grep_http",
- "original_name": "grep_http",
- "description": "Fetch a URL and search its content for a regex pattern (case-insensitive). By default, searches extracted text (HTML cleaned as in fetch_http); set raw=true to search the original HTML. Output starts with metadata (URL, Pattern, Matches found), then match blocks. Each match block shows context lines around the matching line, with '>>>' marking the match and line numbers. Use start_index and max_length for pagination of large result sets. The URL's domain must be allowed by network policy; blocked or unknown domains return an error. Errors: domain blocked by policy, invalid URL, invalid regex syntax, HTTP request failed.",
- "input_schema": {
- "properties": {
- "context_lines": {
- "description": "Number of lines to show before and after each matching line (default: 3)",
- "type": "integer"
- },
- "max_length": {
- "description": "Maximum characters to return (default: 5000). If truncated, use the indicated start_index to continue.",
- "type": "integer"
- },
- "max_matches": {
- "description": "Maximum number of matches to return (default: 50). If more matches exist, output notes the truncation.",
- "type": "integer"
- },
- "pattern": {
- "description": "Regex pattern to search for (case-insensitive). Uses Rust regex syntax (similar to PCRE without lookaround).",
- "type": "string"
- },
- "raw": {
- "description": "If true, search the raw HTML source instead of extracted text (default: false)",
- "type": "boolean"
- },
- "start_index": {
- "description": "Character offset to start reading output from (default: 0). Use for paginating large result sets.",
- "type": "integer"
- },
- "url": {
- "description": "The URL to fetch and search. The domain must be allowed by network policy or the request will be rejected.",
- "type": "string"
- }
- },
- "required": [
- "url",
- "pattern"
- ],
- "type": "object"
- },
- "server_name": "builtin",
- "annotations": {
- "title": "Grep HTTP",
- "read_only_hint": true,
- "destructive_hint": false,
- "idempotent_hint": true,
- "open_world_hint": true
- }
- },
- {
- "namespaced_name": "http_headers",
- "original_name": "http_headers",
- "description": "Return HTTP status code and response headers for a URL. By default uses HEAD (no body downloaded, faster). Set method='GET' to see headers from a full response (some servers return different headers for HEAD vs GET). Output format: 'URL:' line, 'Status:' line, then 'Headers:' section with one 'name: value' per line. The URL's domain must be allowed by network policy; blocked or unknown domains return an error. Errors: domain blocked by policy, invalid URL, HTTP request failed.",
- "input_schema": {
- "properties": {
- "max_length": {
- "description": "Maximum characters to return (default: 5000). Rarely needed since header output is typically small.",
- "type": "integer"
- },
- "method": {
- "description": "HTTP method to use (default: HEAD). HEAD is faster as it skips the body, but some servers return different headers for GET.",
- "enum": [
- "HEAD",
- "GET"
- ],
- "type": "string"
- },
- "start_index": {
- "description": "Character offset to start reading from (default: 0). Rarely needed since header output is typically small.",
- "type": "integer"
- },
- "url": {
- "description": "The URL to check. The domain must be allowed by network policy or the request will be rejected.",
- "type": "string"
- }
- },
- "required": [
- "url"
- ],
- "type": "object"
- },
- "server_name": "builtin",
- "annotations": {
- "title": "HTTP Headers",
- "read_only_hint": true,
- "destructive_hint": false,
- "idempotent_hint": true,
- "open_world_hint": true
- }
- },
- {
- "namespaced_name": "snapshots_changes",
- "original_name": "snapshots_changes",
- "description": "List files that have changed in the workspace compared to automatic checkpoints. Each entry includes the file path, operation (created/modified/deleted), size, and a checkpoint ID that can be passed to snapshots_revert. Shows newest changes first. Output is paginated (default 5000 chars).",
- "input_schema": {
- "properties": {
- "format": {
- "description": "Output format: 'text' (default) for a compact table, 'json' for machine-readable JSON array.",
- "enum": [
- "text",
- "json"
- ],
- "type": "string"
- },
- "max_length": {
- "description": "Maximum characters to return (default: 5000). If truncated, a pagination hint shows the next start_index.",
- "type": "integer"
- },
- "start_index": {
- "description": "Character offset to start from (default: 0). Use the value from the pagination hint to continue.",
- "type": "integer"
- }
- },
- "type": "object"
- },
- "server_name": "builtin",
- "annotations": {
- "title": "List changed files",
- "read_only_hint": true,
- "destructive_hint": false,
- "idempotent_hint": true,
- "open_world_hint": false
- }
- },
- {
- "namespaced_name": "snapshots_list",
- "original_name": "snapshots_list",
- "description": "List all workspace snapshots (automatic and manual). Shows slot index, origin (auto/manual), name, age, blake3 hash, file count, and a compact change summary. Output is paginated (default 5000 chars).",
- "input_schema": {
- "properties": {
- "format": {
- "description": "Output format: 'text' (default) for a compact table, 'json' for machine-readable JSON.",
- "enum": [
- "text",
- "json"
- ],
- "type": "string"
- },
- "max_length": {
- "description": "Maximum characters to return (default: 5000). If truncated, a pagination hint shows the next start_index.",
- "type": "integer"
- },
- "start_index": {
- "description": "Character offset to start from (default: 0). Use the value from the pagination hint to continue.",
- "type": "integer"
- }
- },
- "type": "object"
- },
- "server_name": "builtin",
- "annotations": {
- "title": "List snapshots",
- "read_only_hint": true,
- "destructive_hint": false,
- "idempotent_hint": true,
- "open_world_hint": false
- }
- },
- {
- "namespaced_name": "snapshots_revert",
- "original_name": "snapshots_revert",
- "description": "Revert a file to its state at a specific checkpoint. Use the checkpoint ID from snapshots_changes output, or omit checkpoint to auto-select the most recent snapshot containing the file. If the file was created after the checkpoint, it is deleted. If the file was modified, it is restored to its checkpoint state. Changes are reflected immediately in the guest via VirtioFS.",
- "input_schema": {
- "properties": {
- "checkpoint": {
- "description": "Checkpoint ID (e.g., 'cp-0'). Optional: defaults to the most recent snapshot containing the file.",
- "type": "string"
- },
- "path": {
- "description": "Relative file path from snapshots_changes output (e.g., 'project/app.js')",
- "type": "string"
- }
- },
- "required": [
- "path"
- ],
- "type": "object"
- },
- "server_name": "builtin",
- "annotations": {
- "title": "Revert file",
- "read_only_hint": false,
- "destructive_hint": true,
- "idempotent_hint": true,
- "open_world_hint": false
- }
- },
- {
- "namespaced_name": "snapshots_create",
- "original_name": "snapshots_create",
- "description": "Create a named workspace snapshot (checkpoint). The snapshot captures the current state of all files and can be used with snapshots_revert to restore files later. Returns the checkpoint ID, a blake3 hash of the workspace, and the number of remaining snapshot slots.",
- "input_schema": {
- "properties": {
- "name": {
- "description": "Label for this snapshot (alphanumeric, underscore, hyphen; max 64 chars)",
- "type": "string"
- }
- },
- "required": [
- "name"
- ],
- "type": "object"
- },
- "server_name": "builtin",
- "annotations": {
- "title": "Create snapshot",
- "read_only_hint": false,
- "destructive_hint": false,
- "idempotent_hint": false,
- "open_world_hint": false
- }
- },
- {
- "namespaced_name": "snapshots_delete",
- "original_name": "snapshots_delete",
- "description": "Delete a manual snapshot by checkpoint ID. Only manual (named) snapshots can be deleted. Automatic snapshots are managed by the scheduler.",
- "input_schema": {
- "properties": {
- "checkpoint": {
- "description": "Checkpoint ID to delete (e.g., 'cp-12')",
- "type": "string"
- }
- },
- "required": [
- "checkpoint"
- ],
- "type": "object"
- },
- "server_name": "builtin",
- "annotations": {
- "title": "Delete snapshot",
- "read_only_hint": false,
- "destructive_hint": true,
- "idempotent_hint": true,
- "open_world_hint": false
- }
- },
- {
- "namespaced_name": "snapshots_history",
- "original_name": "snapshots_history",
- "description": "Show the history of a specific file across all snapshots. For each snapshot that contains a version of the file, shows the checkpoint, origin, age, size, and whether the file was created, modified, or unchanged. Accepts both relative paths (hello.txt) and absolute guest paths (/root/hello.txt).",
- "input_schema": {
- "properties": {
- "path": {
- "description": "File path (e.g., 'hello.txt' or '/root/hello.txt')",
- "type": "string"
- }
- },
- "required": [
- "path"
- ],
- "type": "object"
- },
- "server_name": "builtin",
- "annotations": {
- "title": "File history",
- "read_only_hint": true,
- "destructive_hint": false,
- "idempotent_hint": true,
- "open_world_hint": false
- }
- },
- {
- "namespaced_name": "snapshots_compact",
- "original_name": "snapshots_compact",
- "description": "Compact multiple snapshots into a single new manual snapshot. Merges workspaces with newest-file-wins strategy. Deletes all source snapshots after successful compaction. Frees snapshot slots while preserving file state.",
- "input_schema": {
- "properties": {
- "checkpoints": {
- "description": "Checkpoint IDs to compact (e.g., ['cp-0', 'cp-1', 'cp-10'])",
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "name": {
- "description": "Name for the compacted snapshot (optional, defaults to timestamp)",
- "type": "string"
- }
- },
- "required": [
- "checkpoints"
- ],
- "type": "object"
- },
- "server_name": "builtin",
- "annotations": {
- "title": "Compact snapshots",
- "read_only_hint": false,
- "destructive_hint": true,
- "idempotent_hint": false,
- "open_world_hint": false
- }
- }
-]
diff --git a/config/presets/high.toml b/config/presets/high.toml
deleted file mode 100644
index e6eec69c5..000000000
--- a/config/presets/high.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-name = "High Security"
-description = "Blocks all web access by default. Only Google search is allowed. MCP tools require confirmation before running."
-
-[settings]
-"security.web.allow_read" = false
-"security.web.allow_write" = false
-"security.services.search.google.allow" = true
-"security.services.search.bing.allow" = false
-"security.services.search.duckduckgo.allow" = false
-
-[mcp]
-default_tool_permission = "warn"
diff --git a/config/presets/medium.toml b/config/presets/medium.toml
deleted file mode 100644
index 5a6b1c6db..000000000
--- a/config/presets/medium.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-name = "Medium Security"
-description = "Allows read-only web access (GET/HEAD) and all search engines. Blocks write requests. MCP tools run without confirmation."
-
-[settings]
-"security.web.allow_read" = true
-"security.web.allow_write" = false
-"security.services.search.google.allow" = true
-"security.services.search.bing.allow" = true
-"security.services.search.duckduckgo.allow" = true
-
-[mcp]
-default_tool_permission = "allow"
diff --git a/config/profiles/base/coding.profile.toml b/config/profiles/base/coding.profile.toml
deleted file mode 100644
index 10d1b37a3..000000000
--- a/config/profiles/base/coding.profile.toml
+++ /dev/null
@@ -1,269 +0,0 @@
-schema = "capsem.profile.v2"
-version = 2
-id = "coding"
-revision = "2026.0520.1"
-name = "Coding"
-description = "Focused defaults for software development sessions."
-best_for = "Coding agents, repository work, tests, and developer tooling."
-profile_type = "coding"
-ui = "coding"
-
-[compatibility]
-min_binary = "1.0.0"
-max_binary = ""
-guest_abi = "capsem-guest-v2"
-
-[general]
-
-[appearance]
-
-[editable]
-general = true
-appearance = true
-ai = true
-mcpServers = true
-skills = true
-packages = true
-tools = true
-vm = true
-security_capabilities = true
-security_rules = true
-
-[ai.providers.anthropic]
-enabled = true
-credential_refs = [
- "anthropic-api-key",
-]
-
-[ai.providers.anthropic.rules.mcp]
-
-[ai.providers.anthropic.rules.http]
-
-[ai.providers.anthropic.rules.dns]
-
-[ai.providers.anthropic.rules.model]
-
-[ai.providers.anthropic.rules.hook]
-
-[ai.providers.google]
-enabled = true
-credential_refs = [
- "google-api-key",
-]
-
-[ai.providers.google.rules.mcp]
-
-[ai.providers.google.rules.http]
-
-[ai.providers.google.rules.dns]
-
-[ai.providers.google.rules.model]
-
-[ai.providers.google.rules.hook]
-
-[ai.providers.openai]
-enabled = true
-credential_refs = [
- "openai-api-key",
-]
-
-[ai.providers.openai.rules.mcp]
-
-[ai.providers.openai.rules.http]
-
-[ai.providers.openai.rules.dns]
-
-[ai.providers.openai.rules.model]
-
-[ai.providers.openai.rules.hook]
-
-[mcpServers.local]
-enabled = true
-type = "stdio"
-command = "/run/capsem-mcp-server"
-args = []
-pool_safe_tools = []
-
-[mcpServers.local.env]
-
-[mcpServers.local.headers]
-
-[mcpServers.local.capsem]
-credential_refs = []
-allowed_tools = []
-
-[mcpServers.local.capsem.rules.mcp]
-
-[mcpServers.local.capsem.rules.http]
-
-[mcpServers.local.capsem.rules.dns]
-
-[mcpServers.local.capsem.rules.model]
-
-[mcpServers.local.capsem.rules.hook]
-
-[skills]
-groups = []
-enabled = []
-disabled = []
-
-[vm]
-memory_mib = 8192
-cpus = 4
-disk_mib = 16384
-network = "proxied"
-track_rootfs_dependencies = true
-
-[vm.assets.arm64.kernel]
-url = "https://assets.example.invalid/capsem/profiles/coding/2026.0520.1/arm64/kernel"
-hash = "blake3:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
-signature_url = "https://assets.example.invalid/capsem/profiles/coding/2026.0520.1/arm64/kernel.minisig"
-size = 1
-content_type = "application/octet-stream"
-
-[vm.assets.arm64.initrd]
-url = "https://assets.example.invalid/capsem/profiles/coding/2026.0520.1/arm64/initrd"
-hash = "blake3:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
-signature_url = "https://assets.example.invalid/capsem/profiles/coding/2026.0520.1/arm64/initrd.minisig"
-size = 1
-content_type = "application/octet-stream"
-
-[vm.assets.arm64.rootfs]
-url = "https://assets.example.invalid/capsem/profiles/coding/2026.0520.1/arm64/rootfs"
-hash = "blake3:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
-signature_url = "https://assets.example.invalid/capsem/profiles/coding/2026.0520.1/arm64/rootfs.minisig"
-size = 1
-content_type = "application/vnd.squashfs"
-
-[vm.assets.x86_64.kernel]
-url = "https://assets.example.invalid/capsem/profiles/coding/2026.0520.1/x86_64/kernel"
-hash = "blake3:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
-signature_url = "https://assets.example.invalid/capsem/profiles/coding/2026.0520.1/x86_64/kernel.minisig"
-size = 1
-content_type = "application/octet-stream"
-
-[vm.assets.x86_64.initrd]
-url = "https://assets.example.invalid/capsem/profiles/coding/2026.0520.1/x86_64/initrd"
-hash = "blake3:eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
-signature_url = "https://assets.example.invalid/capsem/profiles/coding/2026.0520.1/x86_64/initrd.minisig"
-size = 1
-content_type = "application/octet-stream"
-
-[vm.assets.x86_64.rootfs]
-url = "https://assets.example.invalid/capsem/profiles/coding/2026.0520.1/x86_64/rootfs"
-hash = "blake3:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
-signature_url = "https://assets.example.invalid/capsem/profiles/coding/2026.0520.1/x86_64/rootfs.minisig"
-size = 1
-content_type = "application/vnd.squashfs"
-
-[packages.runtimes]
-python = "3.12"
-node = "24"
-npm = "*"
-uv = "*"
-
-[packages.python_modules]
-pytest = "*"
-numpy = "*"
-requests = "*"
-httpx = "*"
-pandas = "*"
-scipy = "*"
-scikit-learn = "*"
-matplotlib = "*"
-pillow = "*"
-pyyaml = "*"
-beautifulsoup4 = "*"
-lxml = "*"
-tqdm = "*"
-rich = "*"
-fastmcp = "*"
-
-[packages.node_packages]
-"@anthropic-ai/claude-code" = "*"
-"@google/gemini-cli" = "*"
-"@openai/codex" = "*"
-
-[packages.curl_installs]
-# The Capsem guest is Linux/aarch64 even on Apple Silicon hosts. Do not swap
-# this for the macOS AGY build; AGY runtime compatibility belongs to the guest
-# Linux kernel/userspace contract.
-agy = "https://antigravity.google/cli/install.sh"
-
-[packages.system]
-distro = "debian"
-release = "bookworm"
-
-[packages.system.apt]
-coreutils = "*"
-util-linux = "*"
-procps = "*"
-psmisc = "*"
-findutils = "*"
-diffutils = "*"
-lsof = "*"
-strace = "*"
-file = "*"
-less = "*"
-man-db = "*"
-tmux = "*"
-grep = "*"
-sed = "*"
-gawk = "*"
-tar = "*"
-gzip = "*"
-bzip2 = "*"
-xz-utils = "*"
-vim-tiny = "*"
-git = "*"
-gh = "*"
-curl = "*"
-ca-certificates = "*"
-wrk = "*"
-iproute2 = "*"
-iptables = "*"
-auditd = "*"
-python3 = "*"
-python3-pip = "*"
-python3-venv = "*"
-
-[tools.capsem_doctor]
-version = "2026.05.20"
-required = true
-source = "guest"
-
-[tools.claude]
-version = "*"
-required = true
-source = "guest"
-
-[tools.gemini]
-version = "*"
-required = true
-source = "guest"
-
-[tools.codex]
-version = "*"
-required = true
-source = "guest"
-
-[tools.agy]
-version = "*"
-required = true
-source = "guest"
-
-[security.capabilities]
-credential_brokerage = "ask"
-network_egress = "ask"
-file_boundaries = "audit"
-audit = "allow"
-
-[security.rules.mcp]
-
-[security.rules.http]
-
-[security.rules.dns]
-
-[security.rules.model]
-
-[security.rules.hook]
diff --git a/config/profiles/base/everyday-work.profile.toml b/config/profiles/base/everyday-work.profile.toml
deleted file mode 100644
index 759ea24cb..000000000
--- a/config/profiles/base/everyday-work.profile.toml
+++ /dev/null
@@ -1,269 +0,0 @@
-schema = "capsem.profile.v2"
-version = 2
-id = "everyday-work"
-revision = "2026.0520.1"
-name = "Everyday Work"
-description = "Balanced defaults for daily work sessions."
-best_for = "Daily work with useful tools and measured security prompts."
-profile_type = "everyday-work"
-ui = "everyday"
-
-[compatibility]
-min_binary = "1.0.0"
-max_binary = ""
-guest_abi = "capsem-guest-v2"
-
-[general]
-
-[appearance]
-
-[editable]
-general = true
-appearance = true
-ai = true
-mcpServers = true
-skills = true
-packages = true
-tools = true
-vm = true
-security_capabilities = true
-security_rules = true
-
-[ai.providers.anthropic]
-enabled = true
-credential_refs = [
- "anthropic-api-key",
-]
-
-[ai.providers.anthropic.rules.mcp]
-
-[ai.providers.anthropic.rules.http]
-
-[ai.providers.anthropic.rules.dns]
-
-[ai.providers.anthropic.rules.model]
-
-[ai.providers.anthropic.rules.hook]
-
-[ai.providers.google]
-enabled = true
-credential_refs = [
- "google-api-key",
-]
-
-[ai.providers.google.rules.mcp]
-
-[ai.providers.google.rules.http]
-
-[ai.providers.google.rules.dns]
-
-[ai.providers.google.rules.model]
-
-[ai.providers.google.rules.hook]
-
-[ai.providers.openai]
-enabled = true
-credential_refs = [
- "openai-api-key",
-]
-
-[ai.providers.openai.rules.mcp]
-
-[ai.providers.openai.rules.http]
-
-[ai.providers.openai.rules.dns]
-
-[ai.providers.openai.rules.model]
-
-[ai.providers.openai.rules.hook]
-
-[mcpServers.local]
-enabled = true
-type = "stdio"
-command = "/run/capsem-mcp-server"
-args = []
-pool_safe_tools = []
-
-[mcpServers.local.env]
-
-[mcpServers.local.headers]
-
-[mcpServers.local.capsem]
-credential_refs = []
-allowed_tools = []
-
-[mcpServers.local.capsem.rules.mcp]
-
-[mcpServers.local.capsem.rules.http]
-
-[mcpServers.local.capsem.rules.dns]
-
-[mcpServers.local.capsem.rules.model]
-
-[mcpServers.local.capsem.rules.hook]
-
-[skills]
-groups = []
-enabled = []
-disabled = []
-
-[vm]
-memory_mib = 8192
-cpus = 4
-disk_mib = 16384
-network = "proxied"
-track_rootfs_dependencies = true
-
-[vm.assets.arm64.kernel]
-url = "https://assets.example.invalid/capsem/profiles/everyday-work/2026.0520.1/arm64/kernel"
-hash = "blake3:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
-signature_url = "https://assets.example.invalid/capsem/profiles/everyday-work/2026.0520.1/arm64/kernel.minisig"
-size = 1
-content_type = "application/octet-stream"
-
-[vm.assets.arm64.initrd]
-url = "https://assets.example.invalid/capsem/profiles/everyday-work/2026.0520.1/arm64/initrd"
-hash = "blake3:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
-signature_url = "https://assets.example.invalid/capsem/profiles/everyday-work/2026.0520.1/arm64/initrd.minisig"
-size = 1
-content_type = "application/octet-stream"
-
-[vm.assets.arm64.rootfs]
-url = "https://assets.example.invalid/capsem/profiles/everyday-work/2026.0520.1/arm64/rootfs"
-hash = "blake3:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
-signature_url = "https://assets.example.invalid/capsem/profiles/everyday-work/2026.0520.1/arm64/rootfs.minisig"
-size = 1
-content_type = "application/vnd.squashfs"
-
-[vm.assets.x86_64.kernel]
-url = "https://assets.example.invalid/capsem/profiles/everyday-work/2026.0520.1/x86_64/kernel"
-hash = "blake3:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
-signature_url = "https://assets.example.invalid/capsem/profiles/everyday-work/2026.0520.1/x86_64/kernel.minisig"
-size = 1
-content_type = "application/octet-stream"
-
-[vm.assets.x86_64.initrd]
-url = "https://assets.example.invalid/capsem/profiles/everyday-work/2026.0520.1/x86_64/initrd"
-hash = "blake3:eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
-signature_url = "https://assets.example.invalid/capsem/profiles/everyday-work/2026.0520.1/x86_64/initrd.minisig"
-size = 1
-content_type = "application/octet-stream"
-
-[vm.assets.x86_64.rootfs]
-url = "https://assets.example.invalid/capsem/profiles/everyday-work/2026.0520.1/x86_64/rootfs"
-hash = "blake3:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
-signature_url = "https://assets.example.invalid/capsem/profiles/everyday-work/2026.0520.1/x86_64/rootfs.minisig"
-size = 1
-content_type = "application/vnd.squashfs"
-
-[packages.runtimes]
-python = "3.12"
-node = "24"
-npm = "*"
-uv = "*"
-
-[packages.python_modules]
-pytest = "*"
-numpy = "*"
-requests = "*"
-httpx = "*"
-pandas = "*"
-scipy = "*"
-scikit-learn = "*"
-matplotlib = "*"
-pillow = "*"
-pyyaml = "*"
-beautifulsoup4 = "*"
-lxml = "*"
-tqdm = "*"
-rich = "*"
-fastmcp = "*"
-
-[packages.node_packages]
-"@anthropic-ai/claude-code" = "*"
-"@google/gemini-cli" = "*"
-"@openai/codex" = "*"
-
-[packages.curl_installs]
-# The Capsem guest is Linux/aarch64 even on Apple Silicon hosts. Do not swap
-# this for the macOS AGY build; AGY runtime compatibility belongs to the guest
-# Linux kernel/userspace contract.
-agy = "https://antigravity.google/cli/install.sh"
-
-[packages.system]
-distro = "debian"
-release = "bookworm"
-
-[packages.system.apt]
-coreutils = "*"
-util-linux = "*"
-procps = "*"
-psmisc = "*"
-findutils = "*"
-diffutils = "*"
-lsof = "*"
-strace = "*"
-file = "*"
-less = "*"
-man-db = "*"
-tmux = "*"
-grep = "*"
-sed = "*"
-gawk = "*"
-tar = "*"
-gzip = "*"
-bzip2 = "*"
-xz-utils = "*"
-vim-tiny = "*"
-git = "*"
-gh = "*"
-curl = "*"
-ca-certificates = "*"
-wrk = "*"
-iproute2 = "*"
-iptables = "*"
-auditd = "*"
-python3 = "*"
-python3-pip = "*"
-python3-venv = "*"
-
-[tools.capsem_doctor]
-version = "2026.05.20"
-required = true
-source = "guest"
-
-[tools.claude]
-version = "*"
-required = true
-source = "guest"
-
-[tools.gemini]
-version = "*"
-required = true
-source = "guest"
-
-[tools.codex]
-version = "*"
-required = true
-source = "guest"
-
-[tools.agy]
-version = "*"
-required = true
-source = "guest"
-
-[security.capabilities]
-credential_brokerage = "ask"
-network_egress = "ask"
-file_boundaries = "audit"
-audit = "allow"
-
-[security.rules.mcp]
-
-[security.rules.http]
-
-[security.rules.dns]
-
-[security.rules.model]
-
-[security.rules.hook]
diff --git a/config/profiles/co-work/apt-packages.txt b/config/profiles/co-work/apt-packages.txt
new file mode 100644
index 000000000..4a259f8a8
--- /dev/null
+++ b/config/profiles/co-work/apt-packages.txt
@@ -0,0 +1,32 @@
+coreutils
+util-linux
+procps
+psmisc
+findutils
+diffutils
+lsof
+strace
+file
+less
+man-db
+tmux
+grep
+sed
+gawk
+tar
+gzip
+bzip2
+xz-utils
+zstd
+vim-tiny
+git
+gh
+curl
+ca-certificates
+wrk
+iproute2
+iptables
+auditd
+python3
+python3-pip
+python3-venv
diff --git a/config/profiles/co-work/build.sh b/config/profiles/co-work/build.sh
new file mode 100755
index 000000000..b0048f8ee
--- /dev/null
+++ b/config/profiles/co-work/build.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+set -eu
+
+install_from_url() {
+ url="$1"
+ name="$2"
+ tmp="$(mktemp -d)"
+ trap 'rm -rf "$tmp"' EXIT
+ curl -fsSL "$url" -o "$tmp/install.sh"
+ bash "$tmp/install.sh"
+ if [ -x "/root/.local/bin/$name" ]; then
+ install -m 555 "/root/.local/bin/$name" "/usr/local/bin/$name"
+ elif command -v "$name" >/dev/null 2>&1; then
+ src="$(command -v "$name")"
+ install -m 555 "$src" "/usr/local/bin/$name"
+ else
+ echo "installer did not produce $name" >&2
+ exit 1
+ fi
+ rm -rf "$tmp"
+ trap - EXIT
+}
+
+install_from_url "https://claude.ai/install.sh" "claude"
+install_from_url "https://antigravity.google/cli/install.sh" "agy"
+
+curl -fsSL https://ollama.com/install.sh | sh
+command -v ollama >/dev/null 2>&1
+rm -rf /usr/local/lib/ollama/cuda_*
+
+cleanup_agent_runtime_state() {
+ rm -rf \
+ /root/.antigravity/*oauth* \
+ /root/.antigravity/*token* \
+ /root/.antigravity/cache \
+ /root/.antigravity/history \
+ /root/.antigravity/logs \
+ /root/.claude/cache \
+ /root/.claude/history \
+ /root/.claude/logs \
+ /root/.codex/cache \
+ /root/.codex/history \
+ /root/.codex/logs \
+ /root/.gemini/cache \
+ /root/.gemini/history \
+ /root/.gemini/logs \
+ /root/.gemini/tmp
+}
+
+if [ ! -x /usr/local/bin/agy-real ]; then
+ install -m 555 /usr/local/bin/agy /usr/local/bin/agy-real
+fi
+cat >/usr/local/bin/agy <<'EOF'
+#!/bin/sh
+exec /usr/local/bin/agy-real --dangerously-skip-permissions "$@"
+EOF
+chmod 555 /usr/local/bin/agy
+
+gemini_path="$(command -v gemini)"
+gemini_dir="$(dirname "$gemini_path")"
+gemini_target="$(readlink -f "$gemini_path")"
+ln -sfn "$gemini_target" "$gemini_dir/gemini-real"
+rm -f "$gemini_path"
+cat >"$gemini_path" <"
+revision = "2026.06.08.7"
+refresh_policy = "24h"
+
+[availability]
+web = true
+shell = true
+mobile = true
+
+[assets]
+format = "profile-assets.v1"
+refresh_policy = "on_profile_refresh"
+
+[assets.arch.arm64.kernel]
+name = "vmlinuz"
+url = "https://github.com/google/capsem/releases/download/v1.0.1780954707/arm64-vmlinuz"
+
+[assets.arch.arm64.initrd]
+name = "initrd.img"
+url = "https://github.com/google/capsem/releases/download/v1.0.1780954707/arm64-initrd.img"
+
+[assets.arch.arm64.rootfs]
+name = "rootfs.erofs"
+url = "https://github.com/google/capsem/releases/download/v1.0.1780954707/arm64-rootfs.erofs"
+
+[assets.arch.x86_64.kernel]
+name = "vmlinuz"
+url = "https://github.com/google/capsem/releases/download/v1.0.1780763638/x86_64-vmlinuz"
+
+[assets.arch.x86_64.initrd]
+name = "initrd.img"
+url = "https://github.com/google/capsem/releases/download/v1.0.1780763638/x86_64-initrd.img"
+
+[assets.arch.x86_64.rootfs]
+name = "rootfs.erofs"
+url = "https://github.com/google/capsem/releases/download/v1.0.1780763638/x86_64-rootfs.erofs"
+
+[vm]
+cpu_count = 4
+ram_gb = 12
+scratch_disk_size_gb = 64
+
+[rule_files]
+enforcement = "profiles/co-work/enforcement.toml"
+sigma = "profiles/co-work/detection.yaml"
+
+[plugins.credential_broker]
+mode = "rewrite"
+detection_level = "informational"
+
+[plugins.log_sanitizer]
+mode = "rewrite"
+detection_level = "informational"
+
+[mcp]
+health_check_interval_secs = 60
+servers = []
+
+[mcp.server_enabled]
+local = true
+
+[files.enforcement]
+path = "profiles/co-work/enforcement.toml"
+
+[files.detection]
+path = "profiles/co-work/detection.yaml"
+
+[files.mcp]
+path = "profiles/co-work/mcp.json"
+
+[files.apt_packages]
+path = "profiles/co-work/apt-packages.txt"
+
+[files.python_requirements]
+path = "profiles/co-work/python-requirements.txt"
+
+[files.npm_packages]
+path = "profiles/co-work/npm-packages.txt"
+
+[files.build]
+path = "profiles/co-work/build.sh"
+
+[files.tips]
+path = "profiles/co-work/tips.txt"
+
+[files.root_manifest]
+path = "profiles/co-work/root.manifest.json"
+
+[skills]
diff --git a/config/profiles/co-work/python-requirements.txt b/config/profiles/co-work/python-requirements.txt
new file mode 100644
index 000000000..790e6be1b
--- /dev/null
+++ b/config/profiles/co-work/python-requirements.txt
@@ -0,0 +1,19 @@
+pytest
+numpy
+requests
+httpx
+pandas
+scipy
+scikit-learn
+matplotlib
+pillow
+pyyaml
+beautifulsoup4
+lxml
+tqdm
+rich
+fastmcp
+openai
+anthropic
+litellm
+ollama
diff --git a/config/profiles/co-work/root.manifest.json b/config/profiles/co-work/root.manifest.json
new file mode 100644
index 000000000..53e1d7db0
--- /dev/null
+++ b/config/profiles/co-work/root.manifest.json
@@ -0,0 +1,75 @@
+{
+ "format": "capsem.profile-root.v1",
+ "files": [
+ {
+ "path": "root/.antigravity/config.json",
+ "hash": "blake3:98e5a1ada9e176cc6e4576abb70891ed3057416e7129670d42e0ed90c98835de",
+ "size": 141
+ },
+ {
+ "path": "root/.antigravity/settings.json",
+ "hash": "blake3:908708b4f57d80de8f4005dd9ff577f73421b04ab44149120285b6c798cce212",
+ "size": 148
+ },
+ {
+ "path": "root/.claude.json",
+ "hash": "blake3:72cffdfb37c41367018d13de7d2bb5c267f960437fcf9a29a0fe8bd33dbe572d",
+ "size": 334
+ },
+ {
+ "path": "root/.claude/settings.json",
+ "hash": "blake3:202e424564e073ee2ae36fe1cda983d35b26fe329172cb27c143f0aaf22cf0a6",
+ "size": 134
+ },
+ {
+ "path": "root/.claude/settings.local.json",
+ "hash": "blake3:8077c4c062c6674ba40a6aeb194a672f85df2273cc7939bc7e209f8215a5a400",
+ "size": 50
+ },
+ {
+ "path": "root/.codex/config.toml",
+ "hash": "blake3:3188ac3aab345b563e2a549bcb55fff90b04dbcc4fb5c21431f160710e089aac",
+ "size": 200
+ },
+ {
+ "path": "root/.gemini/installation_id",
+ "hash": "blake3:5a70807784783b42a4e973003b6117a81666411dd5cb4c0ae52bee01baae2cdd",
+ "size": 52
+ },
+ {
+ "path": "root/.gemini/antigravity-cli/settings.json",
+ "hash": "blake3:b79afea5264eda1f2a0af2566398f2856ac81b39d3d055197f4ddf1ed2371899",
+ "size": 157
+ },
+ {
+ "path": "root/.gemini/config/config.json",
+ "hash": "blake3:98e5a1ada9e176cc6e4576abb70891ed3057416e7129670d42e0ed90c98835de",
+ "size": 141
+ },
+ {
+ "path": "root/.gemini/projects.json",
+ "hash": "blake3:12d1884de84d3717377da1e2e4b6df3011b27aa54f32f39415625b6405330baf",
+ "size": 44
+ },
+ {
+ "path": "root/.gemini/settings.json",
+ "hash": "blake3:4a21022ba945a84fba5ff5a81adcbe742a0d8ebcb383ec2a362866889d07b48e",
+ "size": 523
+ },
+ {
+ "path": "root/.gemini/trustedFolders.json",
+ "hash": "blake3:2497a7bede84b29c0cbdb604ce4597d17637f61a3d37a8d9445d4c3757b46963",
+ "size": 30
+ },
+ {
+ "path": "root/.mcp.json",
+ "hash": "blake3:44dbee07dcb89910a47cd195f6b324d51260b2f4e34a13a8bd85e2e5039ea67b",
+ "size": 90
+ },
+ {
+ "path": "etc/hosts",
+ "hash": "blake3:b3d43bdb7ed2a8e246a342895e0b0c2ba9fa53da1009ae489464aa51b00e747e",
+ "size": 61
+ }
+ ]
+}
diff --git a/config/profiles/co-work/root/etc/hosts b/config/profiles/co-work/root/etc/hosts
new file mode 100644
index 000000000..99bc3c549
--- /dev/null
+++ b/config/profiles/co-work/root/etc/hosts
@@ -0,0 +1,2 @@
+127.0.0.1 localhost
+::1 localhost ip6-localhost ip6-loopback
diff --git a/config/profiles/co-work/root/root/.antigravity/config.json b/config/profiles/co-work/root/root/.antigravity/config.json
new file mode 100644
index 000000000..ee17ecd0b
--- /dev/null
+++ b/config/profiles/co-work/root/root/.antigravity/config.json
@@ -0,0 +1,8 @@
+{
+ "ai": {
+ "provider": "ollama",
+ "baseUrl": "http://127.0.0.1:11434",
+ "model": "gemma4:latest",
+ "contextLength": 8192
+ }
+}
diff --git a/config/profiles/co-work/root/root/.antigravity/settings.json b/config/profiles/co-work/root/root/.antigravity/settings.json
new file mode 100644
index 000000000..1fdb58abd
--- /dev/null
+++ b/config/profiles/co-work/root/root/.antigravity/settings.json
@@ -0,0 +1,11 @@
+{
+ "colorScheme": "dark",
+ "trustedWorkspaces": [
+ "/root"
+ ],
+ "statusLine": {
+ "enabled": true,
+ "type": "",
+ "command": ""
+ }
+}
diff --git a/config/profiles/co-work/root/root/.claude.json b/config/profiles/co-work/root/root/.claude.json
new file mode 100644
index 000000000..0a287533f
--- /dev/null
+++ b/config/profiles/co-work/root/root/.claude.json
@@ -0,0 +1,15 @@
+{
+ "hasCompletedOnboarding": true,
+ "hasTrustDialogAccepted": true,
+ "hasTrustDialogHooksAccepted": true,
+ "shiftEnterKeyBindingInstalled": true,
+ "theme": "dark",
+ "numStartups": 1,
+ "projects": {
+ "/root": {
+ "allowedTools": [],
+ "hasTrustDialogAccepted": true,
+ "projectOnboardingSeenCount": 1
+ }
+ }
+}
diff --git a/config/profiles/co-work/root/root/.claude/settings.json b/config/profiles/co-work/root/root/.claude/settings.json
new file mode 100644
index 000000000..e61a4ea09
--- /dev/null
+++ b/config/profiles/co-work/root/root/.claude/settings.json
@@ -0,0 +1,8 @@
+{
+ "permissions": {
+ "defaultMode": "bypassPermissions"
+ },
+ "env": {
+ "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
+ }
+}
diff --git a/config/profiles/co-work/root/root/.claude/settings.local.json b/config/profiles/co-work/root/root/.claude/settings.local.json
new file mode 100644
index 000000000..4b3904cc7
--- /dev/null
+++ b/config/profiles/co-work/root/root/.claude/settings.local.json
@@ -0,0 +1,5 @@
+{
+ "enabledMcpjsonServers": [
+ "capsem"
+ ]
+}
diff --git a/config/profiles/co-work/root/root/.codex/config.toml b/config/profiles/co-work/root/root/.codex/config.toml
new file mode 100644
index 000000000..e11bf0dde
--- /dev/null
+++ b/config/profiles/co-work/root/root/.codex/config.toml
@@ -0,0 +1,9 @@
+model = "gemma4:latest"
+model_provider = "local_ollama"
+
+[model_providers.local_ollama]
+name = "Ollama"
+base_url = "http://127.0.0.1:11434/v1"
+
+[mcp_servers.capsem]
+command = "/run/capsem-mcp-server"
diff --git a/config/profiles/co-work/root/root/.gemini/antigravity-cli/settings.json b/config/profiles/co-work/root/root/.gemini/antigravity-cli/settings.json
new file mode 100644
index 000000000..4e30c42c8
--- /dev/null
+++ b/config/profiles/co-work/root/root/.gemini/antigravity-cli/settings.json
@@ -0,0 +1,12 @@
+{
+ "colorScheme": "dark",
+ "trustedWorkspaces": [
+ "/root"
+ ],
+ "telemetry": {
+ "enabled": false
+ },
+ "autoUpdate": {
+ "enabled": false
+ }
+}
diff --git a/config/profiles/co-work/root/root/.gemini/config/config.json b/config/profiles/co-work/root/root/.gemini/config/config.json
new file mode 100644
index 000000000..ee17ecd0b
--- /dev/null
+++ b/config/profiles/co-work/root/root/.gemini/config/config.json
@@ -0,0 +1,8 @@
+{
+ "ai": {
+ "provider": "ollama",
+ "baseUrl": "http://127.0.0.1:11434",
+ "model": "gemma4:latest",
+ "contextLength": 8192
+ }
+}
diff --git a/config/profiles/co-work/root/root/.gemini/installation_id b/config/profiles/co-work/root/root/.gemini/installation_id
new file mode 100644
index 000000000..0dc0bd380
--- /dev/null
+++ b/config/profiles/co-work/root/root/.gemini/installation_id
@@ -0,0 +1 @@
+capsem-sandbox-00000000-0000-0000-0000-000000000000
diff --git a/config/profiles/co-work/root/root/.gemini/projects.json b/config/profiles/co-work/root/root/.gemini/projects.json
new file mode 100644
index 000000000..d932d9940
--- /dev/null
+++ b/config/profiles/co-work/root/root/.gemini/projects.json
@@ -0,0 +1,5 @@
+{
+ "projects": {
+ "/root": "root"
+ }
+}
diff --git a/config/profiles/co-work/root/root/.gemini/settings.json b/config/profiles/co-work/root/root/.gemini/settings.json
new file mode 100644
index 000000000..daff0788b
--- /dev/null
+++ b/config/profiles/co-work/root/root/.gemini/settings.json
@@ -0,0 +1,30 @@
+{
+ "homeDirectoryWarningDismissed": true,
+ "general": {
+ "enableAutoUpdate": false,
+ "enableAutoUpdateNotification": false
+ },
+ "ui": {
+ "hideTips": true,
+ "hideBanner": false
+ },
+ "privacy": {
+ "usageStatisticsEnabled": false,
+ "sessionRetention": "none"
+ },
+ "telemetry": {
+ "enabled": false
+ },
+ "security": {
+ "auth": {
+ "selectedType": "gemini-api-key"
+ },
+ "folderTrust.enabled": false
+ },
+ "ide": {
+ "hasSeenNudge": true
+ },
+ "tools": {
+ "sandbox": false
+ }
+}
diff --git a/config/profiles/co-work/root/root/.gemini/trustedFolders.json b/config/profiles/co-work/root/root/.gemini/trustedFolders.json
new file mode 100644
index 000000000..41caf4f85
--- /dev/null
+++ b/config/profiles/co-work/root/root/.gemini/trustedFolders.json
@@ -0,0 +1,3 @@
+{
+ "/root": "TRUST_FOLDER"
+}
diff --git a/config/profiles/co-work/root/root/.mcp.json b/config/profiles/co-work/root/root/.mcp.json
new file mode 100644
index 000000000..45be308b2
--- /dev/null
+++ b/config/profiles/co-work/root/root/.mcp.json
@@ -0,0 +1,7 @@
+{
+ "mcpServers": {
+ "capsem": {
+ "command": "/run/capsem-mcp-server"
+ }
+ }
+}
diff --git a/config/profiles/co-work/tips.txt b/config/profiles/co-work/tips.txt
new file mode 100644
index 000000000..7dd9efe79
--- /dev/null
+++ b/config/profiles/co-work/tips.txt
@@ -0,0 +1,5 @@
+# Tips shown randomly at login. One tip per line. Lines starting with # are ignored.
+Run capsem-doctor when something feels off.
+Your /root directory is the VM workspace for this profile.
+MCP tools are brokered through Capsem; inspect profile MCP settings on the host.
+Credentials are brokered by Capsem; do not bake secrets into the image.
diff --git a/config/profiles/code/apt-packages.txt b/config/profiles/code/apt-packages.txt
new file mode 100644
index 000000000..4a259f8a8
--- /dev/null
+++ b/config/profiles/code/apt-packages.txt
@@ -0,0 +1,32 @@
+coreutils
+util-linux
+procps
+psmisc
+findutils
+diffutils
+lsof
+strace
+file
+less
+man-db
+tmux
+grep
+sed
+gawk
+tar
+gzip
+bzip2
+xz-utils
+zstd
+vim-tiny
+git
+gh
+curl
+ca-certificates
+wrk
+iproute2
+iptables
+auditd
+python3
+python3-pip
+python3-venv
diff --git a/config/profiles/code/build.sh b/config/profiles/code/build.sh
new file mode 100755
index 000000000..b0048f8ee
--- /dev/null
+++ b/config/profiles/code/build.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+set -eu
+
+install_from_url() {
+ url="$1"
+ name="$2"
+ tmp="$(mktemp -d)"
+ trap 'rm -rf "$tmp"' EXIT
+ curl -fsSL "$url" -o "$tmp/install.sh"
+ bash "$tmp/install.sh"
+ if [ -x "/root/.local/bin/$name" ]; then
+ install -m 555 "/root/.local/bin/$name" "/usr/local/bin/$name"
+ elif command -v "$name" >/dev/null 2>&1; then
+ src="$(command -v "$name")"
+ install -m 555 "$src" "/usr/local/bin/$name"
+ else
+ echo "installer did not produce $name" >&2
+ exit 1
+ fi
+ rm -rf "$tmp"
+ trap - EXIT
+}
+
+install_from_url "https://claude.ai/install.sh" "claude"
+install_from_url "https://antigravity.google/cli/install.sh" "agy"
+
+curl -fsSL https://ollama.com/install.sh | sh
+command -v ollama >/dev/null 2>&1
+rm -rf /usr/local/lib/ollama/cuda_*
+
+cleanup_agent_runtime_state() {
+ rm -rf \
+ /root/.antigravity/*oauth* \
+ /root/.antigravity/*token* \
+ /root/.antigravity/cache \
+ /root/.antigravity/history \
+ /root/.antigravity/logs \
+ /root/.claude/cache \
+ /root/.claude/history \
+ /root/.claude/logs \
+ /root/.codex/cache \
+ /root/.codex/history \
+ /root/.codex/logs \
+ /root/.gemini/cache \
+ /root/.gemini/history \
+ /root/.gemini/logs \
+ /root/.gemini/tmp
+}
+
+if [ ! -x /usr/local/bin/agy-real ]; then
+ install -m 555 /usr/local/bin/agy /usr/local/bin/agy-real
+fi
+cat >/usr/local/bin/agy <<'EOF'
+#!/bin/sh
+exec /usr/local/bin/agy-real --dangerously-skip-permissions "$@"
+EOF
+chmod 555 /usr/local/bin/agy
+
+gemini_path="$(command -v gemini)"
+gemini_dir="$(dirname "$gemini_path")"
+gemini_target="$(readlink -f "$gemini_path")"
+ln -sfn "$gemini_target" "$gemini_dir/gemini-real"
+rm -f "$gemini_path"
+cat >"$gemini_path" <"
+revision = "2026.06.08.7"
+refresh_policy = "24h"
+
+[availability]
+web = true
+shell = true
+mobile = true
+
+[vm]
+cpu_count = 4
+ram_gb = 12
+scratch_disk_size_gb = 64
+
+[assets]
+format = "profile-assets.v1"
+refresh_policy = "on_profile_refresh"
+
+[assets.arch.arm64.kernel]
+name = "vmlinuz"
+url = "https://github.com/google/capsem/releases/download/v1.0.1780954707/arm64-vmlinuz"
+
+[assets.arch.arm64.initrd]
+name = "initrd.img"
+url = "https://github.com/google/capsem/releases/download/v1.0.1780954707/arm64-initrd.img"
+
+[assets.arch.arm64.rootfs]
+name = "rootfs.erofs"
+url = "https://github.com/google/capsem/releases/download/v1.0.1780954707/arm64-rootfs.erofs"
+
+[assets.arch.x86_64.kernel]
+name = "vmlinuz"
+url = "https://github.com/google/capsem/releases/download/v1.0.1780763638/x86_64-vmlinuz"
+
+[assets.arch.x86_64.initrd]
+name = "initrd.img"
+url = "https://github.com/google/capsem/releases/download/v1.0.1780763638/x86_64-initrd.img"
+
+[assets.arch.x86_64.rootfs]
+name = "rootfs.erofs"
+url = "https://github.com/google/capsem/releases/download/v1.0.1780763638/x86_64-rootfs.erofs"
+
+[rule_files]
+enforcement = "profiles/code/enforcement.toml"
+sigma = "profiles/code/detection.yaml"
+
+[files.enforcement]
+path = "profiles/code/enforcement.toml"
+
+[files.detection]
+path = "profiles/code/detection.yaml"
+
+[files.mcp]
+path = "profiles/code/mcp.json"
+
+[files.apt_packages]
+path = "profiles/code/apt-packages.txt"
+
+[files.python_requirements]
+path = "profiles/code/python-requirements.txt"
+
+[files.npm_packages]
+path = "profiles/code/npm-packages.txt"
+
+[files.build]
+path = "profiles/code/build.sh"
+
+[files.tips]
+path = "profiles/code/tips.txt"
+
+[files.root_manifest]
+path = "profiles/code/root.manifest.json"
+
+[plugins.credential_broker]
+mode = "rewrite"
+detection_level = "informational"
+
+[plugins.log_sanitizer]
+mode = "rewrite"
+detection_level = "informational"
+
+[mcp]
+health_check_interval_secs = 60
+
+[mcp.server_enabled]
+local = true
diff --git a/config/profiles/code/python-requirements.txt b/config/profiles/code/python-requirements.txt
new file mode 100644
index 000000000..790e6be1b
--- /dev/null
+++ b/config/profiles/code/python-requirements.txt
@@ -0,0 +1,19 @@
+pytest
+numpy
+requests
+httpx
+pandas
+scipy
+scikit-learn
+matplotlib
+pillow
+pyyaml
+beautifulsoup4
+lxml
+tqdm
+rich
+fastmcp
+openai
+anthropic
+litellm
+ollama
diff --git a/config/profiles/code/root.manifest.json b/config/profiles/code/root.manifest.json
new file mode 100644
index 000000000..53e1d7db0
--- /dev/null
+++ b/config/profiles/code/root.manifest.json
@@ -0,0 +1,75 @@
+{
+ "format": "capsem.profile-root.v1",
+ "files": [
+ {
+ "path": "root/.antigravity/config.json",
+ "hash": "blake3:98e5a1ada9e176cc6e4576abb70891ed3057416e7129670d42e0ed90c98835de",
+ "size": 141
+ },
+ {
+ "path": "root/.antigravity/settings.json",
+ "hash": "blake3:908708b4f57d80de8f4005dd9ff577f73421b04ab44149120285b6c798cce212",
+ "size": 148
+ },
+ {
+ "path": "root/.claude.json",
+ "hash": "blake3:72cffdfb37c41367018d13de7d2bb5c267f960437fcf9a29a0fe8bd33dbe572d",
+ "size": 334
+ },
+ {
+ "path": "root/.claude/settings.json",
+ "hash": "blake3:202e424564e073ee2ae36fe1cda983d35b26fe329172cb27c143f0aaf22cf0a6",
+ "size": 134
+ },
+ {
+ "path": "root/.claude/settings.local.json",
+ "hash": "blake3:8077c4c062c6674ba40a6aeb194a672f85df2273cc7939bc7e209f8215a5a400",
+ "size": 50
+ },
+ {
+ "path": "root/.codex/config.toml",
+ "hash": "blake3:3188ac3aab345b563e2a549bcb55fff90b04dbcc4fb5c21431f160710e089aac",
+ "size": 200
+ },
+ {
+ "path": "root/.gemini/installation_id",
+ "hash": "blake3:5a70807784783b42a4e973003b6117a81666411dd5cb4c0ae52bee01baae2cdd",
+ "size": 52
+ },
+ {
+ "path": "root/.gemini/antigravity-cli/settings.json",
+ "hash": "blake3:b79afea5264eda1f2a0af2566398f2856ac81b39d3d055197f4ddf1ed2371899",
+ "size": 157
+ },
+ {
+ "path": "root/.gemini/config/config.json",
+ "hash": "blake3:98e5a1ada9e176cc6e4576abb70891ed3057416e7129670d42e0ed90c98835de",
+ "size": 141
+ },
+ {
+ "path": "root/.gemini/projects.json",
+ "hash": "blake3:12d1884de84d3717377da1e2e4b6df3011b27aa54f32f39415625b6405330baf",
+ "size": 44
+ },
+ {
+ "path": "root/.gemini/settings.json",
+ "hash": "blake3:4a21022ba945a84fba5ff5a81adcbe742a0d8ebcb383ec2a362866889d07b48e",
+ "size": 523
+ },
+ {
+ "path": "root/.gemini/trustedFolders.json",
+ "hash": "blake3:2497a7bede84b29c0cbdb604ce4597d17637f61a3d37a8d9445d4c3757b46963",
+ "size": 30
+ },
+ {
+ "path": "root/.mcp.json",
+ "hash": "blake3:44dbee07dcb89910a47cd195f6b324d51260b2f4e34a13a8bd85e2e5039ea67b",
+ "size": 90
+ },
+ {
+ "path": "etc/hosts",
+ "hash": "blake3:b3d43bdb7ed2a8e246a342895e0b0c2ba9fa53da1009ae489464aa51b00e747e",
+ "size": 61
+ }
+ ]
+}
diff --git a/config/profiles/code/root/etc/hosts b/config/profiles/code/root/etc/hosts
new file mode 100644
index 000000000..99bc3c549
--- /dev/null
+++ b/config/profiles/code/root/etc/hosts
@@ -0,0 +1,2 @@
+127.0.0.1 localhost
+::1 localhost ip6-localhost ip6-loopback
diff --git a/config/profiles/code/root/root/.antigravity/config.json b/config/profiles/code/root/root/.antigravity/config.json
new file mode 100644
index 000000000..ee17ecd0b
--- /dev/null
+++ b/config/profiles/code/root/root/.antigravity/config.json
@@ -0,0 +1,8 @@
+{
+ "ai": {
+ "provider": "ollama",
+ "baseUrl": "http://127.0.0.1:11434",
+ "model": "gemma4:latest",
+ "contextLength": 8192
+ }
+}
diff --git a/config/profiles/code/root/root/.antigravity/settings.json b/config/profiles/code/root/root/.antigravity/settings.json
new file mode 100644
index 000000000..1fdb58abd
--- /dev/null
+++ b/config/profiles/code/root/root/.antigravity/settings.json
@@ -0,0 +1,11 @@
+{
+ "colorScheme": "dark",
+ "trustedWorkspaces": [
+ "/root"
+ ],
+ "statusLine": {
+ "enabled": true,
+ "type": "",
+ "command": ""
+ }
+}
diff --git a/config/profiles/code/root/root/.claude.json b/config/profiles/code/root/root/.claude.json
new file mode 100644
index 000000000..0a287533f
--- /dev/null
+++ b/config/profiles/code/root/root/.claude.json
@@ -0,0 +1,15 @@
+{
+ "hasCompletedOnboarding": true,
+ "hasTrustDialogAccepted": true,
+ "hasTrustDialogHooksAccepted": true,
+ "shiftEnterKeyBindingInstalled": true,
+ "theme": "dark",
+ "numStartups": 1,
+ "projects": {
+ "/root": {
+ "allowedTools": [],
+ "hasTrustDialogAccepted": true,
+ "projectOnboardingSeenCount": 1
+ }
+ }
+}
diff --git a/config/profiles/code/root/root/.claude/settings.json b/config/profiles/code/root/root/.claude/settings.json
new file mode 100644
index 000000000..e61a4ea09
--- /dev/null
+++ b/config/profiles/code/root/root/.claude/settings.json
@@ -0,0 +1,8 @@
+{
+ "permissions": {
+ "defaultMode": "bypassPermissions"
+ },
+ "env": {
+ "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
+ }
+}
diff --git a/config/profiles/code/root/root/.claude/settings.local.json b/config/profiles/code/root/root/.claude/settings.local.json
new file mode 100644
index 000000000..4b3904cc7
--- /dev/null
+++ b/config/profiles/code/root/root/.claude/settings.local.json
@@ -0,0 +1,5 @@
+{
+ "enabledMcpjsonServers": [
+ "capsem"
+ ]
+}
diff --git a/config/profiles/code/root/root/.codex/config.toml b/config/profiles/code/root/root/.codex/config.toml
new file mode 100644
index 000000000..e11bf0dde
--- /dev/null
+++ b/config/profiles/code/root/root/.codex/config.toml
@@ -0,0 +1,9 @@
+model = "gemma4:latest"
+model_provider = "local_ollama"
+
+[model_providers.local_ollama]
+name = "Ollama"
+base_url = "http://127.0.0.1:11434/v1"
+
+[mcp_servers.capsem]
+command = "/run/capsem-mcp-server"
diff --git a/config/profiles/code/root/root/.gemini/antigravity-cli/settings.json b/config/profiles/code/root/root/.gemini/antigravity-cli/settings.json
new file mode 100644
index 000000000..4e30c42c8
--- /dev/null
+++ b/config/profiles/code/root/root/.gemini/antigravity-cli/settings.json
@@ -0,0 +1,12 @@
+{
+ "colorScheme": "dark",
+ "trustedWorkspaces": [
+ "/root"
+ ],
+ "telemetry": {
+ "enabled": false
+ },
+ "autoUpdate": {
+ "enabled": false
+ }
+}
diff --git a/config/profiles/code/root/root/.gemini/config/config.json b/config/profiles/code/root/root/.gemini/config/config.json
new file mode 100644
index 000000000..ee17ecd0b
--- /dev/null
+++ b/config/profiles/code/root/root/.gemini/config/config.json
@@ -0,0 +1,8 @@
+{
+ "ai": {
+ "provider": "ollama",
+ "baseUrl": "http://127.0.0.1:11434",
+ "model": "gemma4:latest",
+ "contextLength": 8192
+ }
+}
diff --git a/config/profiles/code/root/root/.gemini/installation_id b/config/profiles/code/root/root/.gemini/installation_id
new file mode 100644
index 000000000..0dc0bd380
--- /dev/null
+++ b/config/profiles/code/root/root/.gemini/installation_id
@@ -0,0 +1 @@
+capsem-sandbox-00000000-0000-0000-0000-000000000000
diff --git a/config/profiles/code/root/root/.gemini/projects.json b/config/profiles/code/root/root/.gemini/projects.json
new file mode 100644
index 000000000..d932d9940
--- /dev/null
+++ b/config/profiles/code/root/root/.gemini/projects.json
@@ -0,0 +1,5 @@
+{
+ "projects": {
+ "/root": "root"
+ }
+}
diff --git a/config/profiles/code/root/root/.gemini/settings.json b/config/profiles/code/root/root/.gemini/settings.json
new file mode 100644
index 000000000..daff0788b
--- /dev/null
+++ b/config/profiles/code/root/root/.gemini/settings.json
@@ -0,0 +1,30 @@
+{
+ "homeDirectoryWarningDismissed": true,
+ "general": {
+ "enableAutoUpdate": false,
+ "enableAutoUpdateNotification": false
+ },
+ "ui": {
+ "hideTips": true,
+ "hideBanner": false
+ },
+ "privacy": {
+ "usageStatisticsEnabled": false,
+ "sessionRetention": "none"
+ },
+ "telemetry": {
+ "enabled": false
+ },
+ "security": {
+ "auth": {
+ "selectedType": "gemini-api-key"
+ },
+ "folderTrust.enabled": false
+ },
+ "ide": {
+ "hasSeenNudge": true
+ },
+ "tools": {
+ "sandbox": false
+ }
+}
diff --git a/config/profiles/code/root/root/.gemini/trustedFolders.json b/config/profiles/code/root/root/.gemini/trustedFolders.json
new file mode 100644
index 000000000..41caf4f85
--- /dev/null
+++ b/config/profiles/code/root/root/.gemini/trustedFolders.json
@@ -0,0 +1,3 @@
+{
+ "/root": "TRUST_FOLDER"
+}
diff --git a/config/profiles/code/root/root/.mcp.json b/config/profiles/code/root/root/.mcp.json
new file mode 100644
index 000000000..45be308b2
--- /dev/null
+++ b/config/profiles/code/root/root/.mcp.json
@@ -0,0 +1,7 @@
+{
+ "mcpServers": {
+ "capsem": {
+ "command": "/run/capsem-mcp-server"
+ }
+ }
+}
diff --git a/config/profiles/code/tips.txt b/config/profiles/code/tips.txt
new file mode 100644
index 000000000..7dd9efe79
--- /dev/null
+++ b/config/profiles/code/tips.txt
@@ -0,0 +1,5 @@
+# Tips shown randomly at login. One tip per line. Lines starting with # are ignored.
+Run capsem-doctor when something feels off.
+Your /root directory is the VM workspace for this profile.
+MCP tools are brokered through Capsem; inspect profile MCP settings on the host.
+Credentials are brokered by Capsem; do not bake secrets into the image.
diff --git a/config/settings-schema.json b/config/settings-schema.json
deleted file mode 100644
index 2744dc90d..000000000
--- a/config/settings-schema.json
+++ /dev/null
@@ -1,605 +0,0 @@
-{
- "$defs": {
- "ActionKind": {
- "description": "Action identifier for action-type settings.",
- "enum": [
- "check_update",
- "preset_select",
- "rerun_wizard"
- ],
- "title": "ActionKind",
- "type": "string"
- },
- "GroupNode": {
- "description": "A group node (kind=\"group\"). Container with children.",
- "properties": {
- "kind": {
- "const": "group",
- "default": "group",
- "title": "Kind",
- "type": "string"
- },
- "key": {
- "title": "Key",
- "type": "string"
- },
- "name": {
- "title": "Name",
- "type": "string"
- },
- "description": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null,
- "title": "Description"
- },
- "enabled_by": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null,
- "title": "Enabled By"
- },
- "enabled": {
- "default": true,
- "title": "Enabled",
- "type": "boolean"
- },
- "collapsed": {
- "title": "Collapsed",
- "type": "boolean"
- },
- "children": {
- "items": {
- "discriminator": {
- "mapping": {
- "group": "#/$defs/GroupNode",
- "setting": "#/$defs/SettingNode"
- },
- "propertyName": "kind"
- },
- "oneOf": [
- {
- "$ref": "#/$defs/GroupNode"
- },
- {
- "$ref": "#/$defs/SettingNode"
- }
- ]
- },
- "title": "Children",
- "type": "array"
- }
- },
- "required": [
- "key",
- "name",
- "collapsed",
- "children"
- ],
- "title": "GroupNode",
- "type": "object"
- },
- "HistoryEntry": {
- "description": "A single value change record for audit trail.",
- "properties": {
- "timestamp": {
- "title": "Timestamp",
- "type": "string"
- },
- "value": {
- "title": "Value"
- },
- "source": {
- "$ref": "#/$defs/PolicySource"
- }
- },
- "required": [
- "timestamp",
- "value",
- "source"
- ],
- "title": "HistoryEntry",
- "type": "object"
- },
- "HttpMethodPermissions": {
- "description": "Per-rule HTTP method permissions.",
- "properties": {
- "domains": {
- "items": {
- "type": "string"
- },
- "title": "Domains",
- "type": "array"
- },
- "path": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null,
- "title": "Path"
- },
- "get": {
- "default": false,
- "title": "Get",
- "type": "boolean"
- },
- "post": {
- "default": false,
- "title": "Post",
- "type": "boolean"
- },
- "put": {
- "default": false,
- "title": "Put",
- "type": "boolean"
- },
- "delete": {
- "default": false,
- "title": "Delete",
- "type": "boolean"
- },
- "other": {
- "default": false,
- "title": "Other",
- "type": "boolean"
- }
- },
- "title": "HttpMethodPermissions",
- "type": "object"
- },
- "McpToolOrigin": {
- "description": "Where an MCP tool runs.",
- "enum": [
- "builtin",
- "remote",
- "in_vm"
- ],
- "title": "McpToolOrigin",
- "type": "string"
- },
- "McpTransport": {
- "description": "MCP server transport protocol.",
- "enum": [
- "stdio",
- "sse"
- ],
- "title": "McpTransport",
- "type": "string"
- },
- "PolicySource": {
- "description": "Where a setting's effective value came from.",
- "enum": [
- "default",
- "user",
- "corp"
- ],
- "title": "PolicySource",
- "type": "string"
- },
- "SettingMetadata": {
- "description": "Structured metadata for a setting.\n\nContains fields for all setting types:\n- Common: domains, choices, min, max, rules, env_vars, mask, validator, etc.\n- Action-specific: action (ActionKind)\n- MCP tool-specific: origin (McpToolOrigin)\n- MCP server-specific: transport, command, url, args, env, headers",
- "properties": {
- "domains": {
- "items": {
- "type": "string"
- },
- "title": "Domains",
- "type": "array"
- },
- "choices": {
- "items": {
- "type": "string"
- },
- "title": "Choices",
- "type": "array"
- },
- "min": {
- "anyOf": [
- {
- "type": "integer"
- },
- {
- "type": "null"
- }
- ],
- "default": null,
- "title": "Min"
- },
- "max": {
- "anyOf": [
- {
- "type": "integer"
- },
- {
- "type": "null"
- }
- ],
- "default": null,
- "title": "Max"
- },
- "rules": {
- "additionalProperties": {
- "$ref": "#/$defs/HttpMethodPermissions"
- },
- "title": "Rules",
- "type": "object"
- },
- "env_vars": {
- "items": {
- "type": "string"
- },
- "title": "Env Vars",
- "type": "array"
- },
- "collapsed": {
- "default": false,
- "title": "Collapsed",
- "type": "boolean"
- },
- "format": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null,
- "title": "Format"
- },
- "docs_url": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null,
- "title": "Docs Url"
- },
- "prefix": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null,
- "title": "Prefix"
- },
- "filetype": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null,
- "title": "Filetype"
- },
- "widget": {
- "anyOf": [
- {
- "$ref": "#/$defs/Widget"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "side_effect": {
- "anyOf": [
- {
- "$ref": "#/$defs/SideEffect"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "hidden": {
- "default": false,
- "title": "Hidden",
- "type": "boolean"
- },
- "builtin": {
- "default": false,
- "title": "Builtin",
- "type": "boolean"
- },
- "mask": {
- "default": false,
- "title": "Mask",
- "type": "boolean"
- },
- "validator": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null,
- "title": "Validator"
- },
- "action": {
- "anyOf": [
- {
- "$ref": "#/$defs/ActionKind"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "origin": {
- "anyOf": [
- {
- "$ref": "#/$defs/McpToolOrigin"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "transport": {
- "anyOf": [
- {
- "$ref": "#/$defs/McpTransport"
- },
- {
- "type": "null"
- }
- ],
- "default": null
- },
- "command": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null,
- "title": "Command"
- },
- "url": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null,
- "title": "Url"
- },
- "args": {
- "items": {
- "type": "string"
- },
- "title": "Args",
- "type": "array"
- },
- "env": {
- "additionalProperties": {
- "type": "string"
- },
- "title": "Env",
- "type": "object"
- },
- "headers": {
- "additionalProperties": {
- "type": "string"
- },
- "title": "Headers",
- "type": "object"
- }
- },
- "title": "SettingMetadata",
- "type": "object"
- },
- "SettingNode": {
- "description": "A setting node (kind=\"setting\").\n\nCovers regular settings, actions, and MCP tools.\nConsumers check setting_type to know which fields are relevant.",
- "properties": {
- "kind": {
- "const": "setting",
- "default": "setting",
- "title": "Kind",
- "type": "string"
- },
- "key": {
- "title": "Key",
- "type": "string"
- },
- "name": {
- "title": "Name",
- "type": "string"
- },
- "description": {
- "title": "Description",
- "type": "string"
- },
- "setting_type": {
- "$ref": "#/$defs/SettingType"
- },
- "default_value": {
- "default": null,
- "title": "Default Value"
- },
- "effective_value": {
- "default": null,
- "title": "Effective Value"
- },
- "source": {
- "$ref": "#/$defs/PolicySource",
- "default": "default"
- },
- "modified": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null,
- "title": "Modified"
- },
- "corp_locked": {
- "default": false,
- "title": "Corp Locked",
- "type": "boolean"
- },
- "enabled_by": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "default": null,
- "title": "Enabled By"
- },
- "enabled": {
- "default": true,
- "title": "Enabled",
- "type": "boolean"
- },
- "collapsed": {
- "default": false,
- "title": "Collapsed",
- "type": "boolean"
- },
- "metadata": {
- "$ref": "#/$defs/SettingMetadata"
- },
- "history": {
- "items": {
- "$ref": "#/$defs/HistoryEntry"
- },
- "title": "History",
- "type": "array"
- }
- },
- "required": [
- "key",
- "name",
- "description",
- "setting_type"
- ],
- "title": "SettingNode",
- "type": "object"
- },
- "SettingType": {
- "description": "Data type of a setting (drives UI rendering).",
- "enum": [
- "text",
- "number",
- "url",
- "email",
- "apikey",
- "bool",
- "file",
- "kv_map",
- "string_list",
- "int_list",
- "float_list",
- "action",
- "mcp_tool"
- ],
- "title": "SettingType",
- "type": "string"
- },
- "SideEffect": {
- "description": "Frontend side effect triggered on value change.",
- "enum": [
- "toggle_theme"
- ],
- "title": "SideEffect",
- "type": "string"
- },
- "Widget": {
- "description": "Explicit UI widget override.",
- "enum": [
- "toggle",
- "text_input",
- "number_input",
- "password_input",
- "select",
- "file_editor",
- "domain_chips",
- "string_chips",
- "slider",
- "kv_editor"
- ],
- "title": "Widget",
- "type": "string"
- }
- },
- "description": "Top-level settings document.",
- "properties": {
- "settings": {
- "items": {
- "discriminator": {
- "mapping": {
- "group": "#/$defs/GroupNode",
- "setting": "#/$defs/SettingNode"
- },
- "propertyName": "kind"
- },
- "oneOf": [
- {
- "$ref": "#/$defs/GroupNode"
- },
- {
- "$ref": "#/$defs/SettingNode"
- }
- ]
- },
- "title": "Settings",
- "type": "array"
- }
- },
- "required": [
- "settings"
- ],
- "title": "SettingsRoot",
- "type": "object"
-}
diff --git a/config/settings/schema.generated.json b/config/settings/schema.generated.json
new file mode 100644
index 000000000..2748986ba
--- /dev/null
+++ b/config/settings/schema.generated.json
@@ -0,0 +1,603 @@
+{
+ "$defs": {
+ "ActionKind": {
+ "description": "Action identifier for action-type settings.",
+ "enum": [
+ "check_update"
+ ],
+ "title": "ActionKind",
+ "type": "string"
+ },
+ "GroupNode": {
+ "description": "A group node (kind=\"group\"). Container with children.",
+ "properties": {
+ "kind": {
+ "const": "group",
+ "default": "group",
+ "title": "Kind",
+ "type": "string"
+ },
+ "key": {
+ "title": "Key",
+ "type": "string"
+ },
+ "name": {
+ "title": "Name",
+ "type": "string"
+ },
+ "description": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Description"
+ },
+ "enabled_by": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Enabled By"
+ },
+ "enabled": {
+ "default": true,
+ "title": "Enabled",
+ "type": "boolean"
+ },
+ "collapsed": {
+ "title": "Collapsed",
+ "type": "boolean"
+ },
+ "children": {
+ "items": {
+ "discriminator": {
+ "mapping": {
+ "group": "#/$defs/GroupNode",
+ "setting": "#/$defs/SettingNode"
+ },
+ "propertyName": "kind"
+ },
+ "oneOf": [
+ {
+ "$ref": "#/$defs/GroupNode"
+ },
+ {
+ "$ref": "#/$defs/SettingNode"
+ }
+ ]
+ },
+ "title": "Children",
+ "type": "array"
+ }
+ },
+ "required": [
+ "key",
+ "name",
+ "collapsed",
+ "children"
+ ],
+ "title": "GroupNode",
+ "type": "object"
+ },
+ "HistoryEntry": {
+ "description": "A single value change record for audit trail.",
+ "properties": {
+ "timestamp": {
+ "title": "Timestamp",
+ "type": "string"
+ },
+ "value": {
+ "title": "Value"
+ },
+ "source": {
+ "$ref": "#/$defs/PolicySource"
+ }
+ },
+ "required": [
+ "timestamp",
+ "value",
+ "source"
+ ],
+ "title": "HistoryEntry",
+ "type": "object"
+ },
+ "HttpMethodPermissions": {
+ "description": "Per-rule HTTP method permissions.",
+ "properties": {
+ "domains": {
+ "items": {
+ "type": "string"
+ },
+ "title": "Domains",
+ "type": "array"
+ },
+ "path": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Path"
+ },
+ "get": {
+ "default": false,
+ "title": "Get",
+ "type": "boolean"
+ },
+ "post": {
+ "default": false,
+ "title": "Post",
+ "type": "boolean"
+ },
+ "put": {
+ "default": false,
+ "title": "Put",
+ "type": "boolean"
+ },
+ "delete": {
+ "default": false,
+ "title": "Delete",
+ "type": "boolean"
+ },
+ "other": {
+ "default": false,
+ "title": "Other",
+ "type": "boolean"
+ }
+ },
+ "title": "HttpMethodPermissions",
+ "type": "object"
+ },
+ "McpToolOrigin": {
+ "description": "Where an MCP tool runs.",
+ "enum": [
+ "builtin",
+ "remote",
+ "in_vm"
+ ],
+ "title": "McpToolOrigin",
+ "type": "string"
+ },
+ "McpTransport": {
+ "description": "MCP server transport protocol.",
+ "enum": [
+ "stdio",
+ "sse"
+ ],
+ "title": "McpTransport",
+ "type": "string"
+ },
+ "PolicySource": {
+ "description": "Where a setting's effective value came from.",
+ "enum": [
+ "default",
+ "user",
+ "corp"
+ ],
+ "title": "PolicySource",
+ "type": "string"
+ },
+ "SettingMetadata": {
+ "description": "Structured metadata for a setting.\n\nContains fields for all setting types:\n- Common: domains, choices, min, max, rules, env_vars, mask, validator, etc.\n- Action-specific: action (ActionKind)\n\nMCP runtime configuration is profile-owned and should not be authored here.",
+ "properties": {
+ "domains": {
+ "items": {
+ "type": "string"
+ },
+ "title": "Domains",
+ "type": "array"
+ },
+ "choices": {
+ "items": {
+ "type": "string"
+ },
+ "title": "Choices",
+ "type": "array"
+ },
+ "min": {
+ "anyOf": [
+ {
+ "type": "integer"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Min"
+ },
+ "max": {
+ "anyOf": [
+ {
+ "type": "integer"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Max"
+ },
+ "rules": {
+ "additionalProperties": {
+ "$ref": "#/$defs/HttpMethodPermissions"
+ },
+ "title": "Rules",
+ "type": "object"
+ },
+ "env_vars": {
+ "items": {
+ "type": "string"
+ },
+ "title": "Env Vars",
+ "type": "array"
+ },
+ "collapsed": {
+ "default": false,
+ "title": "Collapsed",
+ "type": "boolean"
+ },
+ "format": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Format"
+ },
+ "docs_url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Docs Url"
+ },
+ "prefix": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Prefix"
+ },
+ "filetype": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Filetype"
+ },
+ "widget": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/Widget"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "side_effect": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/SideEffect"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "hidden": {
+ "default": false,
+ "title": "Hidden",
+ "type": "boolean"
+ },
+ "builtin": {
+ "default": false,
+ "title": "Builtin",
+ "type": "boolean"
+ },
+ "mask": {
+ "default": false,
+ "title": "Mask",
+ "type": "boolean"
+ },
+ "validator": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Validator"
+ },
+ "action": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/ActionKind"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "origin": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/McpToolOrigin"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "transport": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/McpTransport"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null
+ },
+ "command": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Command"
+ },
+ "url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Url"
+ },
+ "args": {
+ "items": {
+ "type": "string"
+ },
+ "title": "Args",
+ "type": "array"
+ },
+ "env": {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "title": "Env",
+ "type": "object"
+ },
+ "headers": {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "title": "Headers",
+ "type": "object"
+ }
+ },
+ "title": "SettingMetadata",
+ "type": "object"
+ },
+ "SettingNode": {
+ "description": "A setting node (kind=\"setting\").\n\nCovers regular settings, actions, and MCP tools.\nConsumers check setting_type to know which fields are relevant.",
+ "properties": {
+ "kind": {
+ "const": "setting",
+ "default": "setting",
+ "title": "Kind",
+ "type": "string"
+ },
+ "key": {
+ "title": "Key",
+ "type": "string"
+ },
+ "name": {
+ "title": "Name",
+ "type": "string"
+ },
+ "description": {
+ "title": "Description",
+ "type": "string"
+ },
+ "setting_type": {
+ "$ref": "#/$defs/SettingType"
+ },
+ "default_value": {
+ "default": null,
+ "title": "Default Value"
+ },
+ "effective_value": {
+ "default": null,
+ "title": "Effective Value"
+ },
+ "source": {
+ "$ref": "#/$defs/PolicySource",
+ "default": "default"
+ },
+ "modified": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Modified"
+ },
+ "corp_locked": {
+ "default": false,
+ "title": "Corp Locked",
+ "type": "boolean"
+ },
+ "enabled_by": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Enabled By"
+ },
+ "enabled": {
+ "default": true,
+ "title": "Enabled",
+ "type": "boolean"
+ },
+ "collapsed": {
+ "default": false,
+ "title": "Collapsed",
+ "type": "boolean"
+ },
+ "metadata": {
+ "$ref": "#/$defs/SettingMetadata"
+ },
+ "history": {
+ "items": {
+ "$ref": "#/$defs/HistoryEntry"
+ },
+ "title": "History",
+ "type": "array"
+ }
+ },
+ "required": [
+ "key",
+ "name",
+ "description",
+ "setting_type"
+ ],
+ "title": "SettingNode",
+ "type": "object"
+ },
+ "SettingType": {
+ "description": "Data type of a setting (drives UI rendering).",
+ "enum": [
+ "text",
+ "number",
+ "url",
+ "email",
+ "apikey",
+ "bool",
+ "file",
+ "kv_map",
+ "string_list",
+ "int_list",
+ "float_list",
+ "action",
+ "mcp_tool"
+ ],
+ "title": "SettingType",
+ "type": "string"
+ },
+ "SideEffect": {
+ "description": "Frontend side effect triggered on value change.",
+ "enum": [
+ "toggle_theme"
+ ],
+ "title": "SideEffect",
+ "type": "string"
+ },
+ "Widget": {
+ "description": "Explicit UI widget override.",
+ "enum": [
+ "toggle",
+ "text_input",
+ "number_input",
+ "password_input",
+ "select",
+ "file_editor",
+ "domain_chips",
+ "string_chips",
+ "slider",
+ "kv_editor"
+ ],
+ "title": "Widget",
+ "type": "string"
+ }
+ },
+ "description": "Top-level settings document.",
+ "properties": {
+ "settings": {
+ "items": {
+ "discriminator": {
+ "mapping": {
+ "group": "#/$defs/GroupNode",
+ "setting": "#/$defs/SettingNode"
+ },
+ "propertyName": "kind"
+ },
+ "oneOf": [
+ {
+ "$ref": "#/$defs/GroupNode"
+ },
+ {
+ "$ref": "#/$defs/SettingNode"
+ }
+ ]
+ },
+ "title": "Settings",
+ "type": "array"
+ }
+ },
+ "required": [
+ "settings"
+ ],
+ "title": "SettingsRoot",
+ "type": "object"
+}
diff --git a/config/settings/settings.toml b/config/settings/settings.toml
new file mode 100644
index 000000000..f6d35aa31
--- /dev/null
+++ b/config/settings/settings.toml
@@ -0,0 +1,14 @@
+# Capsem UI/application settings.
+#
+# This file intentionally contains only app and appearance preferences.
+# Runtime behavior belongs to profiles and corp policy.
+
+[app]
+auto_update = true
+notifications = true
+start_service_at_login = true
+
+[appearance]
+theme = "system"
+font_size = 14
+reduced_motion = false
diff --git a/config/settings/ui-metadata.generated.json b/config/settings/ui-metadata.generated.json
new file mode 100644
index 000000000..236c83607
--- /dev/null
+++ b/config/settings/ui-metadata.generated.json
@@ -0,0 +1,668 @@
+{
+ "settings": {
+ "app": {
+ "name": "App",
+ "description": "Application settings",
+ "collapsed": false,
+ "auto_update": {
+ "name": "Auto-check for updates",
+ "description": "Check for new Capsem versions on launch",
+ "type": "bool",
+ "default": true
+ },
+ "check_update": {
+ "name": "Check for updates",
+ "description": "Manually check if a new version is available",
+ "action": "check_update"
+ }
+ },
+ "repository": {
+ "name": "Repositories",
+ "description": "Code hosting and git configuration",
+ "collapsed": false,
+ "git": {
+ "identity": {
+ "name": "Git Identity",
+ "description": "Author name and email for commits inside the VM",
+ "author_name": {
+ "name": "Author name",
+ "description": "Name used for git commits. Injected as GIT_AUTHOR_NAME and GIT_COMMITTER_NAME.",
+ "type": "text",
+ "default": "",
+ "meta": {
+ "env_vars": [
+ "GIT_AUTHOR_NAME",
+ "GIT_COMMITTER_NAME"
+ ]
+ }
+ },
+ "author_email": {
+ "name": "Author email",
+ "description": "Email used for git commits. Injected as GIT_AUTHOR_EMAIL and GIT_COMMITTER_EMAIL.",
+ "type": "text",
+ "default": "",
+ "meta": {
+ "env_vars": [
+ "GIT_AUTHOR_EMAIL",
+ "GIT_COMMITTER_EMAIL"
+ ]
+ }
+ }
+ }
+ },
+ "providers": {
+ "name": "Providers",
+ "description": "Code hosting platforms",
+ "github": {
+ "name": "GitHub",
+ "description": "GitHub and GitHub-hosted content",
+ "enabled_by": "repository.providers.github.allow",
+ "allow": {
+ "name": "Allow GitHub",
+ "description": "Enable access to GitHub and GitHub-hosted content.",
+ "type": "bool",
+ "default": true,
+ "meta": {
+ "domains": [
+ "github.com",
+ "*.github.com",
+ "*.githubusercontent.com"
+ ],
+ "rules": {
+ "default": {
+ "get": true,
+ "post": true
+ }
+ }
+ }
+ },
+ "domains": {
+ "name": "GitHub Domains",
+ "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
+ "type": "text",
+ "default": "github.com, *.github.com, *.githubusercontent.com",
+ "meta": {
+ "format": "domain_list"
+ }
+ },
+ "token": {
+ "name": "GitHub Token",
+ "description": "Personal access token for git push over HTTPS. Injected into .git-credentials.",
+ "type": "apikey",
+ "default": "",
+ "meta": {
+ "env_vars": [
+ "GH_TOKEN",
+ "GITHUB_TOKEN"
+ ],
+ "docs_url": "https://github.com/settings/tokens",
+ "prefix": "ghp_"
+ }
+ }
+ },
+ "gitlab": {
+ "name": "GitLab",
+ "description": "GitLab and GitLab-hosted content",
+ "enabled_by": "repository.providers.gitlab.allow",
+ "allow": {
+ "name": "Allow GitLab",
+ "description": "Enable access to GitLab and GitLab-hosted content.",
+ "type": "bool",
+ "default": false,
+ "meta": {
+ "domains": [
+ "gitlab.com",
+ "*.gitlab.com"
+ ],
+ "rules": {
+ "default": {
+ "get": true,
+ "post": true
+ }
+ }
+ }
+ },
+ "domains": {
+ "name": "GitLab Domains",
+ "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
+ "type": "text",
+ "default": "gitlab.com, *.gitlab.com",
+ "meta": {
+ "format": "domain_list"
+ }
+ },
+ "token": {
+ "name": "GitLab Token",
+ "description": "Personal access token for git push over HTTPS. Injected into .git-credentials.",
+ "type": "apikey",
+ "default": "",
+ "meta": {
+ "env_vars": [
+ "GITLAB_TOKEN"
+ ],
+ "docs_url": "https://gitlab.com/-/user_settings/personal_access_tokens",
+ "prefix": "glpat-"
+ }
+ }
+ }
+ }
+ },
+ "security": {
+ "name": "Security",
+ "description": "Network mechanics and service access controls",
+ "collapsed": false,
+ "web": {
+ "name": "Network Mechanics",
+ "description": "Network engine mechanics. HTTP/DNS decisions are profile security rules.",
+ "http_upstream_ports": {
+ "name": "Allowed plain HTTP upstream ports",
+ "description": "Plain HTTP upstream ports the MITM may dial after guest traffic reaches the local proxy.",
+ "type": "int_list",
+ "default": [
+ 80,
+ 3128,
+ 3713,
+ 8080,
+ 11434
+ ]
+ }
+ },
+ "services": {
+ "name": "Services",
+ "description": "Search engines and package registries",
+ "search": {
+ "name": "Search Engines",
+ "description": "Web search engine access",
+ "google": {
+ "name": "Google",
+ "description": "Google web search",
+ "enabled_by": "security.services.search.google.allow",
+ "allow": {
+ "name": "Allow Google",
+ "description": "Enable access to Google web search.",
+ "type": "bool",
+ "default": true,
+ "meta": {
+ "domains": [
+ "www.google.com",
+ "google.com"
+ ],
+ "rules": {
+ "default": {
+ "get": true
+ }
+ }
+ }
+ },
+ "domains": {
+ "name": "Google Domains",
+ "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
+ "type": "text",
+ "default": "www.google.com, google.com",
+ "meta": {
+ "format": "domain_list"
+ }
+ }
+ },
+ "bing": {
+ "name": "Bing",
+ "description": "Bing web search",
+ "enabled_by": "security.services.search.bing.allow",
+ "allow": {
+ "name": "Allow Bing",
+ "description": "Enable access to Bing web search.",
+ "type": "bool",
+ "default": false,
+ "meta": {
+ "domains": [
+ "www.bing.com",
+ "bing.com"
+ ],
+ "rules": {
+ "default": {
+ "get": true
+ }
+ }
+ }
+ },
+ "domains": {
+ "name": "Bing Domains",
+ "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
+ "type": "text",
+ "default": "www.bing.com, bing.com",
+ "meta": {
+ "format": "domain_list"
+ }
+ }
+ },
+ "duckduckgo": {
+ "name": "DuckDuckGo",
+ "description": "DuckDuckGo web search",
+ "enabled_by": "security.services.search.duckduckgo.allow",
+ "allow": {
+ "name": "Allow DuckDuckGo",
+ "description": "Enable access to DuckDuckGo web search.",
+ "type": "bool",
+ "default": false,
+ "meta": {
+ "domains": [
+ "duckduckgo.com",
+ "*.duckduckgo.com"
+ ],
+ "rules": {
+ "default": {
+ "get": true
+ }
+ }
+ }
+ },
+ "domains": {
+ "name": "DuckDuckGo Domains",
+ "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
+ "type": "text",
+ "default": "duckduckgo.com, *.duckduckgo.com",
+ "meta": {
+ "format": "domain_list"
+ }
+ }
+ }
+ },
+ "registry": {
+ "name": "Package Registries",
+ "description": "Package manager registries",
+ "debian": {
+ "name": "Debian",
+ "description": "Debian package registry",
+ "enabled_by": "security.services.registry.debian.allow",
+ "allow": {
+ "name": "Allow Debian",
+ "description": "Enable access to Debian.",
+ "type": "bool",
+ "default": true,
+ "meta": {
+ "domains": [
+ "deb.debian.org",
+ "security.debian.org"
+ ],
+ "rules": {
+ "default": {
+ "get": true
+ }
+ }
+ }
+ },
+ "domains": {
+ "name": "Debian Domains",
+ "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
+ "type": "text",
+ "default": "deb.debian.org, security.debian.org",
+ "meta": {
+ "format": "domain_list"
+ }
+ }
+ },
+ "npm": {
+ "name": "npm",
+ "description": "npm package registry",
+ "enabled_by": "security.services.registry.npm.allow",
+ "allow": {
+ "name": "Allow npm",
+ "description": "Enable access to npm.",
+ "type": "bool",
+ "default": true,
+ "meta": {
+ "domains": [
+ "registry.npmjs.org",
+ "*.npmjs.org"
+ ],
+ "rules": {
+ "default": {
+ "get": true
+ }
+ }
+ }
+ },
+ "domains": {
+ "name": "npm Domains",
+ "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
+ "type": "text",
+ "default": "registry.npmjs.org, *.npmjs.org",
+ "meta": {
+ "format": "domain_list"
+ }
+ }
+ },
+ "pypi": {
+ "name": "PyPI",
+ "description": "PyPI package registry",
+ "enabled_by": "security.services.registry.pypi.allow",
+ "allow": {
+ "name": "Allow PyPI",
+ "description": "Enable access to PyPI.",
+ "type": "bool",
+ "default": true,
+ "meta": {
+ "domains": [
+ "pypi.org",
+ "files.pythonhosted.org"
+ ],
+ "rules": {
+ "default": {
+ "get": true
+ }
+ }
+ }
+ },
+ "domains": {
+ "name": "PyPI Domains",
+ "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
+ "type": "text",
+ "default": "pypi.org, files.pythonhosted.org",
+ "meta": {
+ "format": "domain_list"
+ }
+ }
+ },
+ "crates": {
+ "name": "crates.io",
+ "description": "crates.io package registry",
+ "enabled_by": "security.services.registry.crates.allow",
+ "allow": {
+ "name": "Allow crates.io",
+ "description": "Enable access to crates.io.",
+ "type": "bool",
+ "default": true,
+ "meta": {
+ "domains": [
+ "crates.io",
+ "static.crates.io"
+ ],
+ "rules": {
+ "default": {
+ "get": true
+ }
+ }
+ }
+ },
+ "domains": {
+ "name": "crates.io Domains",
+ "description": "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains.",
+ "type": "text",
+ "default": "crates.io, static.crates.io",
+ "meta": {
+ "format": "domain_list"
+ }
+ }
+ }
+ }
+ }
+ },
+ "vm": {
+ "name": "VM",
+ "description": "Virtual machine configuration",
+ "collapsed": false,
+ "snapshots": {
+ "name": "Snapshots",
+ "description": "Automatic and manual workspace snapshot settings",
+ "auto_max": {
+ "name": "Auto snapshot limit",
+ "description": "Maximum number of automatic rolling snapshots.",
+ "type": "number",
+ "default": 10,
+ "meta": {
+ "min": 1,
+ "max": 50
+ }
+ },
+ "manual_max": {
+ "name": "Manual snapshot limit",
+ "description": "Maximum number of named manual snapshots.",
+ "type": "number",
+ "default": 12,
+ "meta": {
+ "min": 1,
+ "max": 50
+ }
+ },
+ "auto_interval": {
+ "name": "Auto snapshot interval",
+ "description": "Seconds between automatic snapshots.",
+ "type": "number",
+ "default": 300,
+ "meta": {
+ "min": 30,
+ "max": 3600
+ }
+ }
+ },
+ "environment": {
+ "name": "Environment",
+ "description": "Shell and environment variables",
+ "shell": {
+ "name": "Shell",
+ "description": "Guest shell settings",
+ "term": {
+ "name": "TERM",
+ "description": "Terminal type for the guest shell.",
+ "type": "text",
+ "default": "xterm-256color",
+ "meta": {
+ "env_vars": [
+ "TERM"
+ ]
+ }
+ },
+ "home": {
+ "name": "HOME",
+ "description": "Home directory for the guest shell.",
+ "type": "text",
+ "default": "/root",
+ "meta": {
+ "env_vars": [
+ "HOME"
+ ]
+ }
+ },
+ "path": {
+ "name": "PATH",
+ "description": "Executable search path for the guest shell.",
+ "type": "text",
+ "default": "/opt/ai-clis/bin:/root/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
+ "meta": {
+ "env_vars": [
+ "PATH"
+ ]
+ }
+ },
+ "lang": {
+ "name": "LANG",
+ "description": "Locale for the guest shell.",
+ "type": "text",
+ "default": "C",
+ "meta": {
+ "env_vars": [
+ "LANG"
+ ]
+ }
+ },
+ "bashrc": {
+ "name": "Bash configuration",
+ "description": "User shell config sourced at login. Customize prompt, aliases, and functions.",
+ "type": "file",
+ "default": {
+ "path": "/root/.bashrc",
+ "content": "# Prompt: green bold hostname with blue directory\nPS1='\\[\\033[1;32m\\]\\h\\[\\033[0m\\]:\\[\\033[1;34m\\]\\w\\[\\033[0m\\]\\$ '\n\n# Aliases\nalias pip='uv pip'\nalias pip3='uv pip'\nalias python='uv run python'\nalias python3='uv run python3'\nalias claude='claude --dangerously-skip-permissions'\nalias gemini='gemini --yolo'\nalias ls='ls --color=auto'\nalias ll='ls -la --color=auto'\nalias grep='grep --color=auto'\n"
+ },
+ "meta": {
+ "filetype": "bash"
+ }
+ },
+ "tmux_conf": {
+ "name": "tmux configuration",
+ "description": "tmux terminal multiplexer config. Customize appearance, keybindings, and behavior.",
+ "type": "file",
+ "default": {
+ "path": "/root/.tmux.conf",
+ "content": "set -g default-terminal \"tmux-256color\"\nset -ag terminal-features \",xterm-256color:RGB\"\nset -g mouse on\nset -g escape-time 0\nset -g history-limit 50000\nset -g status-style \"bg=default,fg=colour8\"\nset -g status-left \"\"\nset -g status-right \"\"\nset -g pane-border-style \"fg=colour8\"\nset -g pane-active-border-style \"fg=colour4\"\nset -g message-style \"bg=default,fg=colour4\"\n"
+ },
+ "meta": {
+ "filetype": "conf"
+ }
+ }
+ },
+ "ssh": {
+ "name": "SSH",
+ "description": "SSH key configuration",
+ "public_key": {
+ "name": "SSH public key",
+ "description": "Public key injected as /root/.ssh/authorized_keys in the guest VM.",
+ "type": "text",
+ "default": ""
+ }
+ },
+ "tls": {
+ "name": "TLS",
+ "description": "TLS certificate configuration",
+ "ca_bundle": {
+ "name": "CA bundle path",
+ "description": "Path to the CA certificate bundle in the guest. Injected as REQUESTS_CA_BUNDLE, NODE_EXTRA_CA_CERTS, and SSL_CERT_FILE.",
+ "type": "text",
+ "default": "/etc/ssl/certs/ca-certificates.crt",
+ "meta": {
+ "env_vars": [
+ "REQUESTS_CA_BUNDLE",
+ "NODE_EXTRA_CA_CERTS",
+ "SSL_CERT_FILE"
+ ]
+ }
+ }
+ }
+ },
+ "resources": {
+ "name": "Resources",
+ "description": "Hardware, telemetry, and session limits",
+ "cpu_count": {
+ "name": "CPU cores",
+ "description": "Number of CPU cores allocated to the VM.",
+ "type": "number",
+ "default": 4,
+ "meta": {
+ "min": 1,
+ "max": 8
+ }
+ },
+ "ram_gb": {
+ "name": "RAM",
+ "description": "Amount of RAM allocated to the VM in GB.",
+ "type": "number",
+ "default": 4,
+ "meta": {
+ "min": 1,
+ "max": 16
+ }
+ },
+ "scratch_disk_size_gb": {
+ "name": "Scratch disk size",
+ "description": "Size of the ephemeral scratch disk in GB.",
+ "type": "number",
+ "default": 16,
+ "meta": {
+ "min": 1,
+ "max": 128
+ }
+ },
+ "log_bodies": {
+ "name": "Log request bodies",
+ "description": "Capture request/response bodies in telemetry.",
+ "type": "bool",
+ "default": false
+ },
+ "max_body_capture": {
+ "name": "Max body capture",
+ "description": "Maximum bytes of body to capture in telemetry.",
+ "type": "number",
+ "default": 4096,
+ "meta": {
+ "min": 0,
+ "max": 1048576
+ }
+ },
+ "retention_days": {
+ "name": "Session retention",
+ "description": "Number of days to retain session data.",
+ "type": "number",
+ "default": 30,
+ "meta": {
+ "min": 1,
+ "max": 365
+ }
+ },
+ "max_sessions": {
+ "name": "Maximum sessions",
+ "description": "Keep at most this many sessions (oldest culled first).",
+ "type": "number",
+ "default": 100,
+ "meta": {
+ "min": 1,
+ "max": 10000
+ }
+ },
+ "min_content_sessions": {
+ "name": "Minimum content sessions",
+ "description": "Always keep at least this many sessions that contain AI activity, regardless of age. Empty test sessions are terminated first.",
+ "type": "number",
+ "default": 25,
+ "meta": {
+ "min": 0,
+ "max": 1000,
+ "step": 1
+ }
+ },
+ "max_disk_gb": {
+ "name": "Maximum disk usage",
+ "description": "Maximum total disk usage for all sessions in GB.",
+ "type": "number",
+ "default": 100,
+ "meta": {
+ "min": 1,
+ "max": 1000
+ }
+ },
+ "terminated_retention_days": {
+ "name": "Terminated session retention",
+ "description": "Days to keep terminated session records in the index. After this, the record is permanently deleted.",
+ "type": "number",
+ "default": 365,
+ "meta": {
+ "min": 30,
+ "max": 3650
+ }
+ }
+ }
+ },
+ "appearance": {
+ "name": "Appearance",
+ "description": "UI appearance and display settings",
+ "collapsed": false,
+ "dark_mode": {
+ "name": "Dark mode",
+ "description": "Use dark color scheme in the UI.",
+ "type": "bool",
+ "default": true,
+ "meta": {
+ "side_effect": "toggle_theme"
+ }
+ },
+ "font_size": {
+ "name": "Font size",
+ "description": "Terminal font size in pixels.",
+ "type": "number",
+ "default": 14,
+ "meta": {
+ "min": 8,
+ "max": 32
+ }
+ }
+ }
+ }
+}
diff --git a/config/settings/ui-metadata.toml b/config/settings/ui-metadata.toml
new file mode 100644
index 000000000..f12e15541
--- /dev/null
+++ b/config/settings/ui-metadata.toml
@@ -0,0 +1,643 @@
+# ============================================================================
+# Capsem Settings Registry
+# ============================================================================
+#
+# Single source of truth for all built-in settings. Embedded at compile time
+# via include_str!(). See docs/config.md for the format reference.
+#
+# Three node types, distinguished by presence of `type`:
+# - Category/group: has `name` but no `type` -- grouping with metadata
+# - Setting leaf: has `name` and `type` -- actual setting
+# - Meta: sub-table under a leaf -- extra metadata (env_vars, etc.)
+
+# -- App ---------------------------------------------------------------------
+
+[settings.app]
+name = "App"
+description = "Application settings"
+collapsed = false
+
+[settings.app.auto_update]
+name = "Auto-check for updates"
+description = "Check for new Capsem versions on launch"
+type = "bool"
+default = true
+
+[settings.app.check_update]
+name = "Check for updates"
+description = "Manually check if a new version is available"
+action = "check_update"
+
+# -- Repositories --------------------------------------------------------------
+
+[settings.repository]
+name = "Repositories"
+description = "Code hosting and git configuration"
+collapsed = false
+
+# -- Git Identity --------------------------------------------------------------
+
+[settings.repository.git]
+# No name -- avoids an empty heading; Identity renders directly under Repositories.
+
+[settings.repository.git.identity]
+name = "Git Identity"
+description = "Author name and email for commits inside the VM"
+
+[settings.repository.git.identity.author_name]
+name = "Author name"
+description = "Name used for git commits. Injected as GIT_AUTHOR_NAME and GIT_COMMITTER_NAME."
+type = "text"
+default = ""
+
+[settings.repository.git.identity.author_name.meta]
+env_vars = ["GIT_AUTHOR_NAME", "GIT_COMMITTER_NAME"]
+
+[settings.repository.git.identity.author_email]
+name = "Author email"
+description = "Email used for git commits. Injected as GIT_AUTHOR_EMAIL and GIT_COMMITTER_EMAIL."
+type = "text"
+default = ""
+
+[settings.repository.git.identity.author_email.meta]
+env_vars = ["GIT_AUTHOR_EMAIL", "GIT_COMMITTER_EMAIL"]
+
+# -- Repository Providers ------------------------------------------------------
+
+[settings.repository.providers]
+name = "Providers"
+description = "Code hosting platforms"
+
+# -- GitHub --------------------------------------------------------------------
+
+[settings.repository.providers.github]
+name = "GitHub"
+description = "GitHub and GitHub-hosted content"
+enabled_by = "repository.providers.github.allow"
+
+[settings.repository.providers.github.allow]
+name = "Allow GitHub"
+description = "Enable access to GitHub and GitHub-hosted content."
+type = "bool"
+default = true
+
+[settings.repository.providers.github.allow.meta]
+domains = ["github.com", "*.github.com", "*.githubusercontent.com"]
+
+[settings.repository.providers.github.allow.meta.rules.default]
+get = true
+post = true
+
+[settings.repository.providers.github.domains]
+name = "GitHub Domains"
+description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
+type = "text"
+default = "github.com, *.github.com, *.githubusercontent.com"
+
+[settings.repository.providers.github.domains.meta]
+format = "domain_list"
+
+[settings.repository.providers.github.token]
+name = "GitHub Token"
+description = "Brokered credential reference for GitHub HTTPS access."
+type = "apikey"
+default = ""
+
+[settings.repository.providers.github.token.meta]
+docs_url = "https://github.com/settings/tokens"
+prefix = "ghp_"
+
+# -- GitLab --------------------------------------------------------------------
+
+[settings.repository.providers.gitlab]
+name = "GitLab"
+description = "GitLab and GitLab-hosted content"
+enabled_by = "repository.providers.gitlab.allow"
+
+[settings.repository.providers.gitlab.allow]
+name = "Allow GitLab"
+description = "Enable access to GitLab and GitLab-hosted content."
+type = "bool"
+default = false
+
+[settings.repository.providers.gitlab.allow.meta]
+domains = ["gitlab.com", "*.gitlab.com"]
+
+[settings.repository.providers.gitlab.allow.meta.rules.default]
+get = true
+post = true
+
+[settings.repository.providers.gitlab.domains]
+name = "GitLab Domains"
+description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
+type = "text"
+default = "gitlab.com, *.gitlab.com"
+
+[settings.repository.providers.gitlab.domains.meta]
+format = "domain_list"
+
+[settings.repository.providers.gitlab.token]
+name = "GitLab Token"
+description = "Brokered credential reference for GitLab HTTPS access."
+type = "apikey"
+default = ""
+
+[settings.repository.providers.gitlab.token.meta]
+docs_url = "https://gitlab.com/-/user_settings/personal_access_tokens"
+prefix = "glpat-"
+
+# -- Security ----------------------------------------------------------------
+
+[settings.security]
+name = "Security"
+description = "Network mechanics and service access controls"
+collapsed = false
+
+# -- Security > Services -----------------------------------------------------
+
+[settings.security.services]
+name = "Services"
+description = "Search engines and package registries"
+
+# -- Security > Services > Search Engines ------------------------------------
+
+[settings.security.services.search]
+name = "Search Engines"
+description = "Web search engine access"
+
+[settings.security.services.search.google]
+name = "Google"
+description = "Google web search"
+enabled_by = "security.services.search.google.allow"
+
+[settings.security.services.search.google.allow]
+name = "Allow Google"
+description = "Enable access to Google web search."
+type = "bool"
+default = true
+
+[settings.security.services.search.google.allow.meta]
+domains = ["www.google.com", "google.com"]
+
+[settings.security.services.search.google.allow.meta.rules.default]
+get = true
+
+[settings.security.services.search.google.domains]
+name = "Google Domains"
+description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
+type = "text"
+default = "www.google.com, google.com"
+
+[settings.security.services.search.google.domains.meta]
+format = "domain_list"
+
+[settings.security.services.search.bing]
+name = "Bing"
+description = "Microsoft Bing web search"
+enabled_by = "security.services.search.bing.allow"
+
+[settings.security.services.search.bing.allow]
+name = "Allow Bing"
+description = "Enable access to Bing web search."
+type = "bool"
+default = false
+
+[settings.security.services.search.bing.allow.meta]
+domains = ["www.bing.com", "bing.com"]
+
+[settings.security.services.search.bing.allow.meta.rules.default]
+get = true
+
+[settings.security.services.search.bing.domains]
+name = "Bing Domains"
+description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
+type = "text"
+default = "www.bing.com, bing.com"
+
+[settings.security.services.search.bing.domains.meta]
+format = "domain_list"
+
+[settings.security.services.search.duckduckgo]
+name = "DuckDuckGo"
+description = "DuckDuckGo web search"
+enabled_by = "security.services.search.duckduckgo.allow"
+
+[settings.security.services.search.duckduckgo.allow]
+name = "Allow DuckDuckGo"
+description = "Enable access to DuckDuckGo web search."
+type = "bool"
+default = false
+
+[settings.security.services.search.duckduckgo.allow.meta]
+domains = ["duckduckgo.com", "*.duckduckgo.com"]
+
+[settings.security.services.search.duckduckgo.allow.meta.rules.default]
+get = true
+
+[settings.security.services.search.duckduckgo.domains]
+name = "DuckDuckGo Domains"
+description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
+type = "text"
+default = "duckduckgo.com, *.duckduckgo.com"
+
+[settings.security.services.search.duckduckgo.domains.meta]
+format = "domain_list"
+
+# -- Security > Services > Package Registries --------------------------------
+
+[settings.security.services.registry]
+name = "Package Registries"
+description = "Package manager registries"
+
+[settings.security.services.registry.debian]
+name = "Debian"
+description = "Debian package repositories"
+enabled_by = "security.services.registry.debian.allow"
+
+[settings.security.services.registry.debian.allow]
+name = "Allow Debian"
+description = "Enable access to deb.debian.org and security.debian.org for apt package installs."
+type = "bool"
+default = true
+
+[settings.security.services.registry.debian.allow.meta]
+domains = ["deb.debian.org", "security.debian.org"]
+
+[settings.security.services.registry.debian.allow.meta.rules.default]
+get = true
+
+[settings.security.services.registry.debian.domains]
+name = "Debian Domains"
+description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
+type = "text"
+default = "deb.debian.org, security.debian.org"
+
+[settings.security.services.registry.debian.domains.meta]
+format = "domain_list"
+
+[settings.security.services.registry.npm]
+name = "npm"
+description = "npm package registry"
+enabled_by = "security.services.registry.npm.allow"
+
+[settings.security.services.registry.npm.allow]
+name = "Allow npm"
+description = "Enable access to the npm package registry."
+type = "bool"
+default = true
+
+[settings.security.services.registry.npm.allow.meta]
+domains = ["registry.npmjs.org", "*.npmjs.org"]
+
+[settings.security.services.registry.npm.allow.meta.rules.default]
+get = true
+
+[settings.security.services.registry.npm.domains]
+name = "npm Domains"
+description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
+type = "text"
+default = "registry.npmjs.org, *.npmjs.org"
+
+[settings.security.services.registry.npm.domains.meta]
+format = "domain_list"
+
+[settings.security.services.registry.pypi]
+name = "PyPI"
+description = "Python Package Index"
+enabled_by = "security.services.registry.pypi.allow"
+
+[settings.security.services.registry.pypi.allow]
+name = "Allow PyPI"
+description = "Enable access to the Python Package Index."
+type = "bool"
+default = true
+
+[settings.security.services.registry.pypi.allow.meta]
+domains = ["pypi.org", "files.pythonhosted.org"]
+
+[settings.security.services.registry.pypi.allow.meta.rules.default]
+get = true
+
+[settings.security.services.registry.pypi.domains]
+name = "PyPI Domains"
+description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
+type = "text"
+default = "pypi.org, files.pythonhosted.org"
+
+[settings.security.services.registry.pypi.domains.meta]
+format = "domain_list"
+
+[settings.security.services.registry.crates]
+name = "crates.io"
+description = "Rust crate registry"
+enabled_by = "security.services.registry.crates.allow"
+
+[settings.security.services.registry.crates.allow]
+name = "Allow crates.io"
+description = "Enable access to the Rust crate registry."
+type = "bool"
+default = true
+
+[settings.security.services.registry.crates.allow.meta]
+domains = ["crates.io", "static.crates.io"]
+
+[settings.security.services.registry.crates.allow.meta.rules.default]
+get = true
+
+[settings.security.services.registry.crates.domains]
+name = "crates.io Domains"
+description = "Comma-separated domain patterns. Wildcards (*.example.com) match all subdomains."
+type = "text"
+default = "crates.io, static.crates.io"
+
+[settings.security.services.registry.crates.domains.meta]
+format = "domain_list"
+
+# -- VM ----------------------------------------------------------------------
+
+[settings.vm]
+name = "VM"
+description = "Virtual machine configuration"
+collapsed = false
+
+# -- VM > Snapshots ----------------------------------------------------------
+
+[settings.vm.snapshots]
+name = "Snapshots"
+description = "Automatic and manual workspace snapshot settings"
+
+[settings.vm.snapshots.auto_max]
+name = "Auto snapshot limit"
+description = "Maximum number of automatic rolling snapshots."
+type = "number"
+default = 10
+
+[settings.vm.snapshots.auto_max.meta]
+min = 1
+max = 50
+
+[settings.vm.snapshots.manual_max]
+name = "Manual snapshot limit"
+description = "Maximum number of named manual snapshots."
+type = "number"
+default = 12
+
+[settings.vm.snapshots.manual_max.meta]
+min = 1
+max = 50
+
+[settings.vm.snapshots.auto_interval]
+name = "Auto snapshot interval"
+description = "Seconds between automatic snapshots."
+type = "number"
+default = 300
+
+[settings.vm.snapshots.auto_interval.meta]
+min = 30
+max = 3600
+
+# -- VM > Environment --------------------------------------------------------
+
+[settings.vm.environment]
+name = "Environment"
+description = "Shell and environment variables"
+
+[settings.vm.environment.shell]
+name = "Shell"
+description = "Guest shell settings"
+
+[settings.vm.environment.shell.term]
+name = "TERM"
+description = "Terminal type for the guest shell."
+type = "text"
+default = "xterm-256color"
+
+[settings.vm.environment.shell.term.meta]
+env_vars = ["TERM"]
+
+[settings.vm.environment.shell.home]
+name = "HOME"
+description = "Home directory for the guest shell."
+type = "text"
+default = "/root"
+
+[settings.vm.environment.shell.home.meta]
+env_vars = ["HOME"]
+
+[settings.vm.environment.shell.path]
+name = "PATH"
+description = "Executable search path for the guest shell."
+type = "text"
+default = "/opt/ai-clis/bin:/root/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
+
+[settings.vm.environment.shell.path.meta]
+env_vars = ["PATH"]
+
+[settings.vm.environment.shell.lang]
+name = "LANG"
+description = "Locale for the guest shell."
+type = "text"
+default = "C"
+
+[settings.vm.environment.shell.lang.meta]
+env_vars = ["LANG"]
+
+[settings.vm.environment.shell.bashrc]
+name = "Bash configuration"
+description = "User shell config sourced at login. Customize prompt, aliases, and functions."
+type = "file"
+
+[settings.vm.environment.shell.bashrc.default]
+path = "/root/.bashrc"
+content = '''
+# Prompt: green bold hostname with blue directory
+PS1='\[\033[1;32m\]\h\[\033[0m\]:\[\033[1;34m\]\w\[\033[0m\]\$ '
+
+# Aliases
+alias pip='uv pip'
+alias pip3='uv pip'
+alias python='uv run python'
+alias python3='uv run python3'
+alias gemini='gemini --yolo'
+alias ls='ls --color=auto'
+alias ll='ls -la --color=auto'
+alias grep='grep --color=auto'
+'''
+
+[settings.vm.environment.shell.bashrc.meta]
+filetype = "bash"
+
+[settings.vm.environment.shell.tmux_conf]
+name = "tmux configuration"
+description = "tmux terminal multiplexer config. Customize appearance, keybindings, and behavior."
+type = "file"
+
+[settings.vm.environment.shell.tmux_conf.default]
+path = "/root/.tmux.conf"
+content = '''
+set -g default-terminal "tmux-256color"
+set -ag terminal-features ",xterm-256color:RGB"
+set -g mouse on
+set -g escape-time 0
+set -g history-limit 50000
+set -g status-style "bg=default,fg=colour8"
+set -g status-left ""
+set -g status-right ""
+set -g pane-border-style "fg=colour8"
+set -g pane-active-border-style "fg=colour4"
+set -g message-style "bg=default,fg=colour4"
+'''
+
+[settings.vm.environment.shell.tmux_conf.meta]
+filetype = "conf"
+
+[settings.vm.environment.ssh]
+name = "SSH"
+description = "SSH key configuration"
+
+[settings.vm.environment.ssh.public_key]
+name = "SSH public key"
+description = "Public key injected as /root/.ssh/authorized_keys in the guest VM."
+type = "text"
+default = ""
+
+[settings.vm.environment.tls]
+name = "TLS"
+description = "TLS certificate configuration"
+
+[settings.vm.environment.tls.ca_bundle]
+name = "CA bundle path"
+description = "Path to the CA certificate bundle in the guest. Injected as REQUESTS_CA_BUNDLE, NODE_EXTRA_CA_CERTS, and SSL_CERT_FILE."
+type = "text"
+default = "/etc/ssl/certs/ca-certificates.crt"
+
+[settings.vm.environment.tls.ca_bundle.meta]
+env_vars = ["REQUESTS_CA_BUNDLE", "NODE_EXTRA_CA_CERTS", "SSL_CERT_FILE"]
+
+# -- VM > Resources ----------------------------------------------------------
+
+[settings.vm.resources]
+name = "Resources"
+description = "Hardware, telemetry, and session limits"
+
+[settings.vm.resources.cpu_count]
+name = "CPU cores"
+description = "Number of CPU cores allocated to the VM."
+type = "number"
+default = 4
+
+[settings.vm.resources.cpu_count.meta]
+min = 1
+max = 8
+
+[settings.vm.resources.max_concurrent_vms]
+name = "Max concurrent VMs"
+description = "Maximum number of sandbox VMs that can be running simultaneously."
+type = "number"
+default = 10
+
+[settings.vm.resources.max_concurrent_vms.meta]
+min = 1
+max = 20
+
+[settings.vm.resources.ram_gb]
+name = "RAM"
+description = "Amount of RAM allocated to the VM in GB."
+type = "number"
+default = 4
+
+[settings.vm.resources.ram_gb.meta]
+min = 1
+max = 16
+
+[settings.vm.resources.scratch_disk_size_gb]
+name = "Scratch disk size"
+description = "Size of the ephemeral scratch disk in GB."
+type = "number"
+default = 16
+
+[settings.vm.resources.scratch_disk_size_gb.meta]
+min = 1
+max = 128
+
+[settings.vm.resources.log_bodies]
+name = "Log request bodies"
+description = "Capture request/response bodies in telemetry."
+type = "bool"
+default = false
+
+[settings.vm.resources.max_body_capture]
+name = "Max body capture"
+description = "Maximum bytes of body to capture in telemetry."
+type = "number"
+default = 4096
+
+[settings.vm.resources.max_body_capture.meta]
+min = 0
+max = 1048576
+
+[settings.vm.resources.retention_days]
+name = "Session retention"
+description = "Number of days to retain session data."
+type = "number"
+default = 30
+
+[settings.vm.resources.retention_days.meta]
+min = 1
+max = 365
+
+[settings.vm.resources.max_sessions]
+name = "Maximum sessions"
+description = "Keep at most this many sessions (oldest culled first)."
+type = "number"
+default = 100
+
+[settings.vm.resources.max_sessions.meta]
+min = 1
+max = 10000
+
+[settings.vm.resources.max_disk_gb]
+name = "Maximum disk usage"
+description = "Maximum total disk usage for all sessions in GB."
+type = "number"
+default = 100
+
+[settings.vm.resources.max_disk_gb.meta]
+min = 1
+max = 1000
+
+[settings.vm.resources.terminated_retention_days]
+name = "Terminated session retention"
+description = "Days to keep terminated session records in the index. After this, the record is permanently deleted."
+type = "number"
+default = 365
+
+[settings.vm.resources.terminated_retention_days.meta]
+min = 30
+max = 3650
+
+# -- Appearance --------------------------------------------------------------
+
+[settings.appearance]
+name = "Appearance"
+description = "UI appearance and display settings"
+collapsed = false
+
+[settings.appearance.dark_mode]
+name = "Dark mode"
+description = "Use dark color scheme in the UI."
+type = "bool"
+default = true
+
+[settings.appearance.dark_mode.meta]
+side_effect = "toggle_theme"
+
+[settings.appearance.font_size]
+name = "Font size"
+description = "Terminal font size in pixels."
+type = "number"
+default = 14
+
+[settings.appearance.font_size.meta]
+min = 8
+max = 32
diff --git a/crates/capsem-admin/Cargo.toml b/crates/capsem-admin/Cargo.toml
new file mode 100644
index 000000000..4ca034c1f
--- /dev/null
+++ b/crates/capsem-admin/Cargo.toml
@@ -0,0 +1,29 @@
+[package]
+name = "capsem-admin"
+version.workspace = true
+edition = "2021"
+rust-version.workspace = true
+license.workspace = true
+description.workspace = true
+homepage.workspace = true
+repository.workspace = true
+authors.workspace = true
+
+[[bin]]
+name = "capsem-admin"
+path = "src/main.rs"
+
+[dependencies]
+capsem-core = { path = "../capsem-core" }
+anyhow.workspace = true
+clap.workspace = true
+serde.workspace = true
+serde_json.workspace = true
+toml.workspace = true
+blake3 = "1"
+
+[dev-dependencies]
+tempfile = "3"
+
+[lints]
+workspace = true
diff --git a/crates/capsem-admin/src/main.rs b/crates/capsem-admin/src/main.rs
new file mode 100644
index 000000000..1539f900f
--- /dev/null
+++ b/crates/capsem-admin/src/main.rs
@@ -0,0 +1,3876 @@
+use std::{
+ collections::{BTreeMap, BTreeSet},
+ fs,
+ io::Read,
+ path::{Path, PathBuf},
+ process::{Command, Stdio},
+};
+
+use anyhow::{anyhow, Context, Result};
+use capsem_core::asset_manager::ManifestV2;
+use capsem_core::net::policy_config::{
+ resolve_profile_rule_file_path, validate_corp_toml_contract, CompiledSecurityRule,
+ ProfileCatalog, ProfileConfigFile, ProfileObomConfig, ProfileObomDescriptor,
+ SecurityRuleProfile, SecurityRuleSet, SecurityRuleSource, SettingsFile,
+};
+use clap::{Parser, Subcommand};
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Parser)]
+#[command(name = "capsem-admin")]
+#[command(about = "Capsem profile and asset administration")]
+struct Cli {
+ #[command(subcommand)]
+ command: Commands,
+}
+
+#[derive(Debug, Subcommand)]
+enum Commands {
+ Profile(ProfileCommand),
+ Settings(SettingsCommand),
+ Enforcement(RuleFileCommand),
+ Detection(RuleFileCommand),
+ Manifest(ManifestCommand),
+ Image(ImageCommand),
+}
+
+#[derive(Debug, Parser)]
+struct ProfileCommand {
+ #[command(subcommand)]
+ command: ProfileSubcommand,
+}
+
+#[derive(Debug, Subcommand)]
+enum ProfileSubcommand {
+ Validate(ProfileValidateArgs),
+ Check(ProfileCheckArgs),
+ Materialize(ProfileMaterializeArgs),
+}
+
+#[derive(Debug, Parser)]
+struct SettingsCommand {
+ #[command(subcommand)]
+ command: SettingsSubcommand,
+}
+
+#[derive(Debug, Subcommand)]
+enum SettingsSubcommand {
+ Validate(SettingsValidateArgs),
+}
+
+#[derive(Debug, Parser)]
+struct RuleFileCommand {
+ #[command(subcommand)]
+ command: RuleFileSubcommand,
+}
+
+#[derive(Debug, Subcommand)]
+enum RuleFileSubcommand {
+ Validate(RuleFileArgs),
+}
+
+#[derive(Debug, Parser)]
+struct ManifestCommand {
+ #[command(subcommand)]
+ command: ManifestSubcommand,
+}
+
+#[derive(Debug, Subcommand)]
+enum ManifestSubcommand {
+ Check(ManifestCheckArgs),
+ Generate(ManifestGenerateArgs),
+}
+
+#[derive(Debug, Parser)]
+struct ImageCommand {
+ #[command(subcommand)]
+ command: ImageSubcommand,
+}
+
+#[derive(Debug, Subcommand)]
+enum ImageSubcommand {
+ Build(ImageBuildArgs),
+}
+
+#[derive(Debug, Parser)]
+struct ProfileValidateArgs {
+ /// Profile TOML to validate.
+ path: PathBuf,
+ /// Config root used to resolve profile rule files.
+ #[arg(long)]
+ config_root: Option,
+ /// Emit a machine-readable validation report.
+ #[arg(long)]
+ json: bool,
+}
+
+#[derive(Debug, Parser)]
+struct ProfileCheckArgs {
+ /// Profile TOML to check.
+ path: PathBuf,
+ /// Config root used to resolve profile rule files.
+ #[arg(long)]
+ config_root: Option,
+ /// Restrict file:// asset verification to one profile arch.
+ #[arg(long)]
+ arch: Option,
+ /// Emit a machine-readable check report.
+ #[arg(long)]
+ json: bool,
+}
+
+#[derive(Debug, Parser)]
+struct ProfileMaterializeArgs {
+ /// Source profile TOML to materialize.
+ #[arg(long)]
+ profile: PathBuf,
+ /// Source config root containing settings, corp, profiles, and rule files.
+ #[arg(long, default_value = "config")]
+ config_root: PathBuf,
+ /// Generated asset manifest to use for current build hashes.
+ #[arg(long, default_value = "assets/manifest.json")]
+ manifest: PathBuf,
+ /// Built asset root containing per-arch logical asset files.
+ #[arg(long, default_value = "assets")]
+ assets_dir: PathBuf,
+ /// Generated runtime config output root.
+ #[arg(long, default_value = "target/config")]
+ output_root: PathBuf,
+ /// Restrict materialization to one architecture.
+ #[arg(long)]
+ arch: Option,
+ /// Remove output root before materializing.
+ #[arg(long)]
+ clean: bool,
+ /// Emit a machine-readable materialization report.
+ #[arg(long)]
+ json: bool,
+}
+
+#[derive(Debug, Parser)]
+struct SettingsValidateArgs {
+ /// Settings TOML to validate.
+ path: PathBuf,
+ /// Emit a machine-readable validation report.
+ #[arg(long)]
+ json: bool,
+}
+
+#[derive(Debug, Parser)]
+struct RuleFileArgs {
+ /// Enforcement TOML or Sigma YAML file to validate.
+ path: PathBuf,
+ /// Treat the rules as this source when resolving priority.
+ #[arg(long, value_enum, default_value_t = RuleFileSourceArg::User)]
+ source: RuleFileSourceArg,
+ /// Emit a machine-readable validation report.
+ #[arg(long)]
+ json: bool,
+}
+
+#[derive(Debug, Parser)]
+struct ManifestCheckArgs {
+ /// Manifest JSON file to validate.
+ path: PathBuf,
+ /// Emit a machine-readable manifest report.
+ #[arg(long)]
+ json: bool,
+}
+
+#[derive(Debug, Parser)]
+struct ManifestGenerateArgs {
+ /// Asset directory containing built per-arch assets.
+ #[arg(default_value = "assets")]
+ assets_dir: PathBuf,
+ /// Binary version to record. Defaults to capsem-builder's project version.
+ #[arg(long)]
+ version: Option,
+ /// Emit the generated manifest after writing it.
+ #[arg(long)]
+ json: bool,
+}
+
+#[derive(Debug, Parser)]
+struct ImageBuildArgs {
+ /// Profile TOML that owns the asset build.
+ #[arg(long)]
+ profile: PathBuf,
+ /// Config root used to validate profile rule files.
+ #[arg(long, default_value = "config")]
+ config_root: PathBuf,
+ /// Guest image source directory consumed by capsem-builder.
+ #[arg(long, default_value = "guest")]
+ guest_dir: PathBuf,
+ /// Output directory for built assets.
+ #[arg(long, default_value = "assets")]
+ output: PathBuf,
+ /// Restrict the build to one profile architecture.
+ #[arg(long)]
+ arch: Option,
+ /// Build only kernel, only rootfs, or both.
+ #[arg(long, value_enum, default_value_t = ImageBuildTemplate::All)]
+ template: ImageBuildTemplate,
+ /// Remove selected output assets before building.
+ #[arg(long)]
+ clean: bool,
+ /// Emit a machine-readable build plan/report.
+ #[arg(long)]
+ json: bool,
+}
+
+#[derive(Debug, Parser)]
+struct ImageWorkspaceArgs {
+ /// Profile TOML that owns the image workspace.
+ #[arg(long)]
+ profile: PathBuf,
+ /// Config root used to resolve profile rule files.
+ #[arg(long, default_value = "config")]
+ config_root: PathBuf,
+ /// Guest image source directory consumed by capsem-builder.
+ #[arg(long, default_value = "guest")]
+ guest_dir: PathBuf,
+ /// Directory to materialize the image workspace into.
+ #[arg(long)]
+ output: PathBuf,
+ /// Restrict the workspace build plan to one profile architecture.
+ #[arg(long)]
+ arch: Option,
+ /// Emit a machine-readable workspace report.
+ #[arg(long)]
+ json: bool,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]
+enum ImageBuildTemplate {
+ All,
+ Kernel,
+ Rootfs,
+}
+
+#[derive(Debug, Clone, Copy, clap::ValueEnum)]
+enum RuleFileSourceArg {
+ User,
+ Corp,
+ BuiltinDefault,
+}
+
+impl RuleFileSourceArg {
+ const fn into_security_rule_source(self) -> SecurityRuleSource {
+ match self {
+ Self::User => SecurityRuleSource::User,
+ Self::Corp => SecurityRuleSource::Corp,
+ Self::BuiltinDefault => SecurityRuleSource::BuiltinDefault,
+ }
+ }
+}
+
+#[derive(Debug, Serialize)]
+struct ProfileValidationReport {
+ schema: &'static str,
+ ok: bool,
+ profile_id: String,
+ path: String,
+ config_root: String,
+ compiled_rules: usize,
+}
+
+#[derive(Debug, Serialize)]
+struct ProfileCheckReport {
+ schema: &'static str,
+ ok: bool,
+ validation: ProfileValidationReport,
+ assets: Vec,
+ profile_files: Vec,
+}
+
+#[derive(Debug, Serialize)]
+struct ConfigRootCheckReport {
+ schema: &'static str,
+ ok: bool,
+ config_root: String,
+ settings: SettingsValidationReport,
+ corp_rules: usize,
+ profiles: Vec,
+}
+
+#[derive(Debug, Serialize)]
+struct ProfileMaterializeReport {
+ schema: &'static str,
+ ok: bool,
+ profile_id: String,
+ profile_revision: String,
+ source_config_root: String,
+ output_config_root: String,
+ profile_path: String,
+ manifest: String,
+ current_assets: String,
+ materialized_assets: Vec,
+ materialized_obom: Vec,
+}
+
+#[derive(Debug, Serialize)]
+struct ProfileMaterializedAssetReport {
+ arch: String,
+ logical_name: String,
+ url: String,
+ hash: String,
+ size: u64,
+}
+
+#[derive(Debug, Serialize)]
+struct ProfileMaterializedObomReport {
+ arch: String,
+ url: String,
+ hash: String,
+ size: u64,
+ generator: String,
+ generator_version: String,
+ rootfs_hash: String,
+ scope: &'static str,
+}
+
+#[derive(Debug, Serialize)]
+struct SettingsValidationReport {
+ schema: &'static str,
+ ok: bool,
+ path: String,
+ app: SettingsAppReport,
+ appearance: SettingsAppearanceReport,
+}
+
+#[derive(Debug, Serialize)]
+struct SettingsAppReport {
+ auto_update: bool,
+ notifications: bool,
+ start_service_at_login: bool,
+}
+
+#[derive(Debug, Serialize)]
+struct SettingsAppearanceReport {
+ theme: String,
+ font_size: u32,
+ reduced_motion: bool,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct SettingsConfigFile {
+ app: SettingsApp,
+ appearance: SettingsAppearance,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct SettingsApp {
+ auto_update: bool,
+ notifications: bool,
+ start_service_at_login: bool,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct SettingsAppearance {
+ theme: String,
+ font_size: u32,
+ reduced_motion: bool,
+}
+
+#[derive(Debug, Serialize)]
+struct RuleFileReport {
+ schema: &'static str,
+ ok: bool,
+ kind: &'static str,
+ source: &'static str,
+ path: String,
+ compiled_rules: usize,
+ rules: Vec,
+}
+
+#[derive(Debug, Serialize)]
+struct CompiledRuleReport {
+ rule_id: String,
+ provider: String,
+ namespace: String,
+ rule_key: String,
+ default_rule: bool,
+ name: String,
+ action: &'static str,
+ detection_level: Option<&'static str>,
+ priority: i32,
+ condition: String,
+ reason: Option,
+ corp_locked: bool,
+}
+
+#[derive(Debug, Serialize)]
+struct ManifestReport {
+ schema: &'static str,
+ ok: bool,
+ path: String,
+ blake3: String,
+ refresh_policy: String,
+ current_assets: String,
+ current_binary: String,
+ releases: usize,
+ arches: Vec,
+}
+
+#[derive(Debug, Serialize)]
+struct ManifestArchReport {
+ asset_version: String,
+ arch: String,
+ assets: Vec,
+}
+
+#[derive(Debug, Serialize)]
+struct ManifestAssetReport {
+ logical_name: String,
+ hash: String,
+ size: u64,
+ path: Option,
+ present: bool,
+ size_ok: Option,
+ blake3_ok: Option,
+}
+
+#[derive(Debug, Serialize)]
+struct ImageBuildPlan {
+ schema: &'static str,
+ profile_id: String,
+ profile_revision: String,
+ guest_dir: String,
+ output: String,
+ clean: bool,
+ template: &'static str,
+ arches: Vec,
+ commands: Vec,
+}
+
+#[cfg(test)]
+#[derive(Debug, Serialize)]
+struct ImageVerifyReport {
+ schema: &'static str,
+ ok: bool,
+ profile_id: String,
+ profile_revision: String,
+ output: String,
+ manifest: String,
+ arches: Vec,
+}
+
+#[derive(Debug, Serialize)]
+struct ImageWorkspaceReport {
+ schema: &'static str,
+ ok: bool,
+ profile_id: String,
+ profile_revision: String,
+ workspace: String,
+ config_root: String,
+ profile_path: String,
+ profile_blake3: String,
+ build_plan_path: String,
+ rule_files: Vec,
+ arches: Vec,
+}
+
+#[derive(Debug, Serialize)]
+struct ImageWorkspaceRuleFileReport {
+ kind: &'static str,
+ source: String,
+ path: String,
+ blake3: String,
+ size: u64,
+}
+
+#[cfg(test)]
+#[derive(Debug, Serialize)]
+struct ImageVerifyArchReport {
+ arch: String,
+ assets: Vec,
+}
+
+#[derive(Debug, Serialize)]
+struct LocalAssetCheckReport {
+ arch: String,
+ logical_name: String,
+ expected_hash: String,
+ expected_size: u64,
+ path: Option,
+ present: bool,
+ size_ok: Option,
+ blake3_ok: Option,
+}
+
+#[derive(Debug, Serialize)]
+struct ImageBuildArchPlan {
+ arch: String,
+ kernel: String,
+ initrd: String,
+ rootfs: String,
+}
+
+#[derive(Debug, Serialize, Clone)]
+struct CommandReport {
+ step: String,
+ arch: Option,
+ env: BTreeMap,
+ argv: Vec,
+}
+
+fn main() -> Result<()> {
+ let cli = Cli::parse();
+ match cli.command {
+ Commands::Profile(command) => match command.command {
+ ProfileSubcommand::Validate(args) => validate_profile_command(args),
+ ProfileSubcommand::Check(args) => profile_check_command(args),
+ ProfileSubcommand::Materialize(args) => profile_materialize_command(args),
+ },
+ Commands::Settings(command) => match command.command {
+ SettingsSubcommand::Validate(args) => validate_settings_command(args),
+ },
+ Commands::Enforcement(command) => match command.command {
+ RuleFileSubcommand::Validate(args) => validate_rule_file_command("enforcement", args),
+ },
+ Commands::Detection(command) => match command.command {
+ RuleFileSubcommand::Validate(args) => validate_rule_file_command("detection", args),
+ },
+ Commands::Manifest(command) => match command.command {
+ ManifestSubcommand::Check(args) => manifest_check_command(args),
+ ManifestSubcommand::Generate(args) => manifest_generate_command(args),
+ },
+ Commands::Image(command) => match command.command {
+ ImageSubcommand::Build(args) => image_build_command(args),
+ },
+ }
+}
+
+fn validate_profile_command(args: ProfileValidateArgs) -> Result<()> {
+ let report = validate_profile(&args.path, args.config_root.as_deref())?;
+ if args.json {
+ println!("{}", serde_json::to_string_pretty(&report)?);
+ } else {
+ println!(
+ "valid: profile {} ({} compiled rules)",
+ report.profile_id, report.compiled_rules
+ );
+ }
+ Ok(())
+}
+
+fn profile_check_command(args: ProfileCheckArgs) -> Result<()> {
+ let report = check_profile(&args)?;
+ if args.json {
+ println!("{}", serde_json::to_string_pretty(&report)?);
+ } else {
+ println!(
+ "valid: profile {} ({} compiled rules)",
+ report.validation.profile_id, report.validation.compiled_rules
+ );
+ if !report.assets.is_empty() {
+ println!(
+ "valid: profile file assets ({} assets)",
+ report.assets.len()
+ );
+ }
+ }
+ Ok(())
+}
+
+fn profile_materialize_command(args: ProfileMaterializeArgs) -> Result<()> {
+ let report = materialize_profile_config(&args)?;
+ if args.json {
+ println!("{}", serde_json::to_string_pretty(&report)?);
+ } else {
+ println!(
+ "materialized: profile {} at {}",
+ report.profile_id, report.output_config_root
+ );
+ }
+ Ok(())
+}
+
+fn check_config_root(config_root: &Path, arch: Option<&str>) -> Result {
+ let settings = validate_settings(&config_root.join("settings/settings.toml"))?;
+ let corp_rules = validate_corp_config(&config_root.join("corp/corp.toml"), config_root)?;
+ let catalog =
+ ProfileCatalog::load_from_dir(&config_root.join("profiles")).map_err(|error| {
+ anyhow!(
+ "load profile catalog {}: {error}",
+ config_root.join("profiles").display()
+ )
+ })?;
+ let mut profiles = Vec::new();
+ for profile in catalog.profiles() {
+ profiles.push(check_profile(&ProfileCheckArgs {
+ path: config_root
+ .join("profiles")
+ .join(&profile.id)
+ .join("profile.toml"),
+ config_root: Some(config_root.to_path_buf()),
+ arch: arch.map(ToOwned::to_owned),
+ json: true,
+ })?);
+ }
+ Ok(ConfigRootCheckReport {
+ schema: "capsem.admin.config_root_check.v1",
+ ok: true,
+ config_root: config_root.display().to_string(),
+ settings,
+ corp_rules,
+ profiles,
+ })
+}
+
+fn validate_corp_config(path: &Path, config_root: &Path) -> Result {
+ let content =
+ fs::read_to_string(path).with_context(|| format!("read corp {}", path.display()))?;
+ let file: SettingsFile =
+ toml::from_str(&content).with_context(|| format!("parse corp {}", path.display()))?;
+ file.validate_metadata_contract()
+ .map_err(|error| anyhow!("validate corp {}: {error}", path.display()))?;
+ validate_corp_toml_contract(&file)
+ .map_err(|error| anyhow!("validate corp ownership {}: {error}", path.display()))?;
+
+ let inline_profile = SecurityRuleProfile {
+ default: file.default.clone(),
+ corp: file.corp.clone(),
+ profiles: file.profiles.clone(),
+ ai: file.ai.clone(),
+ plugins: file.plugins.clone(),
+ };
+ let mut compiled = inline_profile
+ .compile(SecurityRuleSource::Corp)
+ .map_err(|error| anyhow!("compile corp inline rules {}: {error}", path.display()))?
+ .len();
+ if let Some(enforcement) = file.corp_rule_files.enforcement.as_deref() {
+ compiled += compile_rule_file(
+ "enforcement",
+ &config_root.join(enforcement),
+ RuleFileSourceArg::Corp,
+ )?
+ .compiled_rules;
+ }
+ if let Some(sigma) = file.corp_rule_files.sigma.as_deref() {
+ compiled += compile_rule_file(
+ "detection",
+ &config_root.join(sigma),
+ RuleFileSourceArg::Corp,
+ )?
+ .compiled_rules;
+ }
+ Ok(compiled)
+}
+
+fn validate_settings_command(args: SettingsValidateArgs) -> Result<()> {
+ let report = validate_settings(&args.path)?;
+ if args.json {
+ println!("{}", serde_json::to_string_pretty(&report)?);
+ } else {
+ println!("valid: settings {}", args.path.display());
+ }
+ Ok(())
+}
+
+fn validate_rule_file_command(kind: &'static str, args: RuleFileArgs) -> Result<()> {
+ let report = compile_rule_file(kind, &args.path, args.source)?;
+ if args.json {
+ println!("{}", serde_json::to_string_pretty(&report)?);
+ } else {
+ println!(
+ "valid: {kind} {} ({} compiled rules)",
+ args.path.display(),
+ report.compiled_rules
+ );
+ }
+ Ok(())
+}
+
+fn manifest_check_command(args: ManifestCheckArgs) -> Result<()> {
+ let manifest = load_manifest(&args.path)?;
+ let report = manifest_report(&args.path, &manifest, None, None)?;
+ if args.json {
+ println!("{}", serde_json::to_string_pretty(&report)?);
+ } else {
+ println!(
+ "valid: manifest {} ({} asset releases)",
+ args.path.display(),
+ report.releases
+ );
+ }
+ Ok(())
+}
+
+fn manifest_generate_command(args: ManifestGenerateArgs) -> Result<()> {
+ let command = manifest_generate_command_report(&args);
+ run_command(&command)?;
+ if args.json {
+ let manifest_path = args.assets_dir.join("manifest.json");
+ let manifest = load_manifest(&manifest_path)?;
+ let report = manifest_report(&manifest_path, &manifest, None, None)?;
+ println!("{}", serde_json::to_string_pretty(&report)?);
+ } else {
+ println!(
+ "generated manifest {}",
+ args.assets_dir.join("manifest.json").display()
+ );
+ }
+ Ok(())
+}
+
+fn image_build_command(args: ImageBuildArgs) -> Result<()> {
+ let source_profile = load_profile(&args.profile)?;
+ let workspace = PathBuf::from("target")
+ .join("image-workspace")
+ .join(&source_profile.id);
+ let workspace_report = materialize_image_workspace(&ImageWorkspaceArgs {
+ profile: args.profile.clone(),
+ config_root: args.config_root.clone(),
+ guest_dir: args.guest_dir.clone(),
+ output: workspace,
+ arch: args.arch.clone(),
+ json: true,
+ })?;
+ let plan = image_build_plan(&ImageBuildArgs {
+ profile: PathBuf::from(&workspace_report.profile_path),
+ config_root: PathBuf::from(&workspace_report.config_root),
+ guest_dir: PathBuf::from(&workspace_report.workspace).join("guest"),
+ output: args.output.clone(),
+ arch: args.arch.clone(),
+ template: args.template,
+ clean: args.clean,
+ json: args.json,
+ })?;
+ if plan.clean {
+ clean_image_outputs(&plan)?;
+ }
+ for command in &plan.commands {
+ run_command(command)?;
+ }
+ print_image_build_plan(&plan, args.json)?;
+ Ok(())
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum ProfilePinMode {
+ Source,
+ Materialized,
+}
+
+fn validate_profile(path: &Path, config_root: Option<&Path>) -> Result {
+ validate_profile_with_pin_mode(path, config_root, ProfilePinMode::Source)
+}
+
+fn validate_materialized_profile(
+ path: &Path,
+ config_root: Option<&Path>,
+) -> Result {
+ validate_profile_with_pin_mode(path, config_root, ProfilePinMode::Materialized)
+}
+
+fn validate_profile_with_pin_mode(
+ path: &Path,
+ config_root: Option<&Path>,
+ pin_mode: ProfilePinMode,
+) -> Result {
+ let content =
+ fs::read_to_string(path).with_context(|| format!("read profile {}", path.display()))?;
+ let profile: ProfileConfigFile =
+ toml::from_str(&content).with_context(|| format!("parse profile {}", path.display()))?;
+ profile
+ .validate()
+ .map_err(|error| anyhow!("validate profile {}: {error}", path.display()))?;
+ match pin_mode {
+ ProfilePinMode::Source => ensure_source_profile_unpinned(&profile, path)?,
+ ProfilePinMode::Materialized => ensure_materialized_profile_pinned(&profile, path)?,
+ }
+
+ let config_root = match config_root {
+ Some(root) => root.to_path_buf(),
+ None => infer_config_root(path)?,
+ };
+ let rules = profile
+ .compile_security_rule_set_from_files(&config_root, SecurityRuleSource::User)
+ .map_err(|error| {
+ anyhow!(
+ "compile profile rule files for {} with config root {}: {error}",
+ path.display(),
+ config_root.display()
+ )
+ })?;
+
+ Ok(ProfileValidationReport {
+ schema: "capsem.admin.profile_validation.v1",
+ ok: true,
+ profile_id: profile.id,
+ path: path.display().to_string(),
+ config_root: config_root.display().to_string(),
+ compiled_rules: rules.rules().len(),
+ })
+}
+
+fn ensure_source_profile_unpinned(profile: &ProfileConfigFile, path: &Path) -> Result<()> {
+ let location = path.display();
+ if profile.obom.is_some() {
+ return Err(anyhow!(
+ "source profile {location} must not contain generated obom pins"
+ ));
+ }
+ for (arch, assets) in &profile.assets.arch {
+ for (kind, descriptor) in [
+ ("kernel", &assets.kernel),
+ ("initrd", &assets.initrd),
+ ("rootfs", &assets.rootfs),
+ ] {
+ if descriptor.hash.is_some() || descriptor.size.is_some() {
+ return Err(anyhow!(
+ "source profile {location} must not contain hash/size pins for assets.arch.{arch}.{kind}"
+ ));
+ }
+ }
+ }
+ for (kind, descriptor) in profile.files.iter() {
+ if descriptor.hash.is_some() || descriptor.size.is_some() {
+ return Err(anyhow!(
+ "source profile {location} must not contain hash/size pins for files.{kind}"
+ ));
+ }
+ }
+ Ok(())
+}
+
+fn ensure_materialized_profile_pinned(profile: &ProfileConfigFile, path: &Path) -> Result<()> {
+ let location = path.display();
+ for (arch, assets) in &profile.assets.arch {
+ for (kind, descriptor) in [
+ ("kernel", &assets.kernel),
+ ("initrd", &assets.initrd),
+ ("rootfs", &assets.rootfs),
+ ] {
+ descriptor
+ .resolved_hash(&format!("profile.assets.arch.{arch}.{kind}"))
+ .map_err(|error| anyhow!("materialized profile {location}: {error}"))?;
+ descriptor
+ .resolved_size(&format!("profile.assets.arch.{arch}.{kind}"))
+ .map_err(|error| anyhow!("materialized profile {location}: {error}"))?;
+ }
+ }
+ for (kind, descriptor) in profile.files.iter() {
+ descriptor
+ .resolved_hash(&format!("profile.files.{kind}"))
+ .map_err(|error| anyhow!("materialized profile {location}: {error}"))?;
+ descriptor
+ .resolved_size(&format!("profile.files.{kind}"))
+ .map_err(|error| anyhow!("materialized profile {location}: {error}"))?;
+ }
+ Ok(())
+}
+
+fn check_profile(args: &ProfileCheckArgs) -> Result {
+ let validation = validate_profile(&args.path, args.config_root.as_deref())?;
+ let profile = load_profile(&args.path)?;
+ let config_root = match &args.config_root {
+ Some(root) => root.clone(),
+ None => infer_config_root(&args.path)?,
+ };
+ let assets: Vec = Vec::new();
+ let arches = selected_profile_arches(&profile, args.arch.as_deref())?;
+ for arch in arches {
+ let arch_assets = profile
+ .assets
+ .arch
+ .get(&arch)
+ .expect("arch came from selected_profile_arches");
+ for descriptor in [
+ &arch_assets.kernel,
+ &arch_assets.initrd,
+ &arch_assets.rootfs,
+ ] {
+ if descriptor.url.starts_with("file://")
+ && (descriptor.hash.is_some() || descriptor.size.is_some())
+ {
+ return Err(anyhow!(
+ "source profile {} must not contain file:// asset pins for {arch}/{}",
+ args.path.display(),
+ descriptor.name
+ ));
+ }
+ }
+ }
+ fail_if_local_asset_checks_failed("profile file:// asset pin check", &assets)?;
+ let profile_files = check_profile_payload_files(&profile, &config_root)?;
+ fail_if_local_asset_checks_failed("profile payload file pin check", &profile_files)?;
+ Ok(ProfileCheckReport {
+ schema: "capsem.admin.profile_check.v1",
+ ok: true,
+ validation,
+ assets,
+ profile_files,
+ })
+}
+
+fn check_profile_payload_files(
+ profile: &ProfileConfigFile,
+ config_root: &Path,
+) -> Result> {
+ let mut reports = Vec::new();
+ for (kind, descriptor) in profile.files.iter() {
+ let path = config_root.join(&descriptor.path);
+ let present = path.is_file();
+ reports.push(LocalAssetCheckReport {
+ arch: "profile".to_string(),
+ logical_name: kind.to_string(),
+ expected_hash: "unpinned-source".to_string(),
+ expected_size: 0,
+ path: Some(path.display().to_string()),
+ present,
+ size_ok: None,
+ blake3_ok: None,
+ });
+ if !present {
+ continue;
+ }
+ validate_profile_payload_semantics(kind, &path)?;
+ if kind == "root_manifest" {
+ reports.extend(check_profile_root_manifest(&path)?);
+ }
+ }
+ Ok(reports)
+}
+
+fn validate_profile_payload_semantics(kind: &str, path: &Path) -> Result<()> {
+ match kind {
+ "mcp" => validate_profile_mcp_file(path),
+ "apt_packages" | "python_requirements" | "npm_packages" => {
+ read_profile_package_lines(path).map(|_| ())
+ }
+ _ => Ok(()),
+ }
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct ProfileMcpJsonConfig {
+ #[serde(rename = "mcpServers")]
+ mcp_servers: BTreeMap,
+}
+
+fn validate_profile_mcp_file(path: &Path) -> Result<()> {
+ let content = fs::read_to_string(path)
+ .with_context(|| format!("read profile MCP config {}", path.display()))?;
+ let config: ProfileMcpJsonConfig = serde_json::from_str(&content)
+ .with_context(|| format!("parse profile MCP config {}", path.display()))?;
+ if config.mcp_servers.is_empty() {
+ return Err(anyhow!(
+ "profile MCP config {} must declare at least one server",
+ path.display()
+ ));
+ }
+ Ok(())
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct ProfileRootManifest {
+ format: String,
+ files: Vec,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct ProfileRootManifestFile {
+ path: String,
+ hash: String,
+ size: u64,
+}
+
+fn check_profile_root_manifest(path: &Path) -> Result> {
+ let content = fs::read_to_string(path)
+ .with_context(|| format!("read profile root manifest {}", path.display()))?;
+ let manifest: ProfileRootManifest = serde_json::from_str(&content)
+ .with_context(|| format!("parse profile root manifest {}", path.display()))?;
+ if manifest.format != "capsem.profile-root.v1" {
+ return Err(anyhow!(
+ "profile root manifest {} has unsupported format {}",
+ path.display(),
+ manifest.format
+ ));
+ }
+ if manifest.files.is_empty() {
+ return Err(anyhow!(
+ "profile root manifest {} must list at least one file",
+ path.display()
+ ));
+ }
+ let root_dir = path
+ .parent()
+ .ok_or_else(|| anyhow!("profile root manifest has no parent: {}", path.display()))?
+ .join("root");
+ let mut listed_files = BTreeSet::new();
+ for entry in &manifest.files {
+ validate_relative_manifest_path("profile root manifest file", &entry.path)?;
+ if !listed_files.insert(entry.path.clone()) {
+ return Err(anyhow!(
+ "profile root manifest {} lists duplicate payload file {}",
+ path.display(),
+ entry.path
+ ));
+ }
+ if entry.size == 0 {
+ return Err(anyhow!(
+ "profile root manifest {} entry {} has zero size",
+ path.display(),
+ entry.path
+ ));
+ }
+ }
+ let actual_files = collect_profile_root_files(&root_dir)?;
+ if let Some(unlisted) = actual_files.difference(&listed_files).next() {
+ return Err(anyhow!(
+ "unlisted profile root payload file {} under {}",
+ unlisted,
+ root_dir.display()
+ ));
+ }
+ if let Some(missing) = listed_files.difference(&actual_files).next() {
+ return Err(anyhow!(
+ "profile root manifest {} lists missing payload file {}",
+ path.display(),
+ missing
+ ));
+ }
+ let mut reports = Vec::new();
+ for entry in manifest.files {
+ reports.push(check_exact_local_asset(
+ &root_dir.join(&entry.path),
+ "profile-root",
+ &entry.path,
+ normalized_blake3(&entry.hash)?,
+ entry.size,
+ )?);
+ }
+ Ok(reports)
+}
+
+fn collect_profile_root_files(root_dir: &Path) -> Result> {
+ let mut files = BTreeSet::new();
+ if !root_dir.is_dir() {
+ return Err(anyhow!(
+ "profile root directory {} is missing",
+ root_dir.display()
+ ));
+ }
+ collect_profile_root_files_into(root_dir, root_dir, &mut files)?;
+ Ok(files)
+}
+
+fn collect_profile_root_files_into(
+ root_dir: &Path,
+ current: &Path,
+ files: &mut BTreeSet,
+) -> Result<()> {
+ for entry in fs::read_dir(current)
+ .with_context(|| format!("read profile root directory {}", current.display()))?
+ {
+ let entry = entry.with_context(|| format!("read entry in {}", current.display()))?;
+ let path = entry.path();
+ let metadata = entry
+ .metadata()
+ .with_context(|| format!("stat profile root payload {}", path.display()))?;
+ if metadata.is_dir() {
+ collect_profile_root_files_into(root_dir, &path, files)?;
+ continue;
+ }
+ if !metadata.is_file() {
+ return Err(anyhow!(
+ "profile root payload {} is not a regular file",
+ path.display()
+ ));
+ }
+ let relative = path
+ .strip_prefix(root_dir)
+ .with_context(|| format!("strip profile root prefix for {}", path.display()))?;
+ let relative = relative
+ .to_string_lossy()
+ .replace(std::path::MAIN_SEPARATOR, "/");
+ validate_relative_manifest_path("profile root payload file", &relative)?;
+ files.insert(relative);
+ }
+ Ok(())
+}
+
+fn materialize_profile_config(args: &ProfileMaterializeArgs) -> Result {
+ check_config_root(&args.config_root, args.arch.as_deref())?;
+ if args.output_root == args.config_root {
+ return Err(anyhow!(
+ "output root {} must differ from source config root {}",
+ args.output_root.display(),
+ args.config_root.display()
+ ));
+ }
+ if args.clean && args.output_root.exists() {
+ fs::remove_dir_all(&args.output_root)
+ .with_context(|| format!("remove {}", args.output_root.display()))?;
+ }
+ if !args.output_root.exists() {
+ copy_dir_recursive(&args.config_root, &args.output_root)?;
+ }
+
+ let manifest = load_manifest(&args.manifest)?;
+ let current_release = manifest
+ .assets
+ .releases
+ .get(&manifest.assets.current)
+ .ok_or_else(|| {
+ anyhow!(
+ "manifest {} current asset release {} is missing",
+ args.manifest.display(),
+ manifest.assets.current
+ )
+ })?;
+
+ let mut profile = load_profile(&args.profile)?;
+ profile
+ .validate()
+ .map_err(|error| anyhow!("validate profile {}: {error}", args.profile.display()))?;
+
+ let selected_arches = selected_profile_arches(&profile, args.arch.as_deref())?;
+ if args.arch.is_some() {
+ profile
+ .assets
+ .arch
+ .retain(|arch, _| selected_arches.iter().any(|selected| selected == arch));
+ }
+ copy_profile_descriptor_files(&profile, &args.config_root, &args.output_root)?;
+ materialize_profile_file_descriptors(&mut profile, &args.output_root)?;
+
+ let mut materialized_assets = Vec::new();
+ let mut materialized_obom = Vec::new();
+ for arch in selected_arches {
+ let manifest_assets = current_release.arches.get(&arch).ok_or_else(|| {
+ anyhow!(
+ "manifest {} current release {} does not contain profile arch {arch}",
+ args.manifest.display(),
+ manifest.assets.current
+ )
+ })?;
+ let rootfs_hash = {
+ let profile_assets = profile
+ .assets
+ .arch
+ .get_mut(&arch)
+ .expect("arch came from selected_profile_arches");
+ materialize_profile_asset_descriptor(
+ &args.assets_dir,
+ &arch,
+ &mut profile_assets.kernel,
+ manifest_assets,
+ &mut materialized_assets,
+ )?;
+ materialize_profile_asset_descriptor(
+ &args.assets_dir,
+ &arch,
+ &mut profile_assets.initrd,
+ manifest_assets,
+ &mut materialized_assets,
+ )?;
+ materialize_profile_asset_descriptor(
+ &args.assets_dir,
+ &arch,
+ &mut profile_assets.rootfs,
+ manifest_assets,
+ &mut materialized_assets,
+ )?;
+ profile_assets
+ .rootfs
+ .hash
+ .clone()
+ .ok_or_else(|| anyhow!("materialized {arch} rootfs hash is unresolved"))?
+ };
+ materialize_profile_obom_descriptor(
+ &args.assets_dir,
+ &arch,
+ manifest_assets,
+ rootfs_hash,
+ &mut profile,
+ &mut materialized_obom,
+ )?;
+ }
+
+ let output_profile_path = args
+ .output_root
+ .join("profiles")
+ .join(&profile.id)
+ .join("profile.toml");
+ fs::create_dir_all(
+ output_profile_path
+ .parent()
+ .ok_or_else(|| anyhow!("materialized profile path has no parent"))?,
+ )
+ .with_context(|| format!("create parent for {}", output_profile_path.display()))?;
+ fs::write(
+ &output_profile_path,
+ toml::to_string_pretty(&profile).context("serialize materialized profile")?,
+ )
+ .with_context(|| format!("write {}", output_profile_path.display()))?;
+
+ let manifest_output = args.output_root.join("assets/manifest.json");
+ fs::create_dir_all(
+ manifest_output
+ .parent()
+ .ok_or_else(|| anyhow!("materialized manifest path has no parent"))?,
+ )
+ .with_context(|| format!("create parent for {}", manifest_output.display()))?;
+ fs::copy(&args.manifest, &manifest_output).with_context(|| {
+ format!(
+ "copy manifest {} to {}",
+ args.manifest.display(),
+ manifest_output.display()
+ )
+ })?;
+
+ let copied_validation =
+ validate_materialized_profile(&output_profile_path, Some(&args.output_root))?;
+ if copied_validation.profile_id != profile.id {
+ return Err(anyhow!(
+ "materialized profile id drifted: expected {}, got {}",
+ profile.id,
+ copied_validation.profile_id
+ ));
+ }
+
+ Ok(ProfileMaterializeReport {
+ schema: "capsem.admin.profile_materialize.v1",
+ ok: true,
+ profile_id: profile.id,
+ profile_revision: profile.revision,
+ source_config_root: args.config_root.display().to_string(),
+ output_config_root: args.output_root.display().to_string(),
+ profile_path: output_profile_path.display().to_string(),
+ manifest: manifest_output.display().to_string(),
+ current_assets: manifest.assets.current,
+ materialized_assets,
+ materialized_obom,
+ })
+}
+
+fn materialize_profile_asset_descriptor(
+ assets_dir: &Path,
+ arch: &str,
+ descriptor: &mut capsem_core::net::policy_config::ProfileAssetDescriptor,
+ manifest_assets: &std::collections::HashMap,
+ reports: &mut Vec,
+) -> Result<()> {
+ let entry = manifest_assets.get(&descriptor.name).ok_or_else(|| {
+ anyhow!(
+ "manifest current release arch {arch} is missing {}",
+ descriptor.name
+ )
+ })?;
+ let check = check_local_asset(assets_dir, arch, &descriptor.name, &entry.hash, entry.size)?;
+ fail_if_local_asset_checks_failed("profile materialize asset check", &[check])?;
+ let asset_path = assets_dir.join(arch).join(&descriptor.name);
+ let asset_path = asset_path
+ .canonicalize()
+ .with_context(|| format!("canonicalize {}", asset_path.display()))?;
+ descriptor.url = format!("file://{}", asset_path.display());
+ descriptor.hash = Some(format!("blake3:{}", entry.hash));
+ descriptor.size = Some(entry.size);
+ reports.push(ProfileMaterializedAssetReport {
+ arch: arch.to_string(),
+ logical_name: descriptor.name.clone(),
+ url: descriptor.url.clone(),
+ hash: descriptor
+ .hash
+ .clone()
+ .expect("materialized asset hash was just set"),
+ size: descriptor
+ .size
+ .expect("materialized asset size was just set"),
+ });
+ Ok(())
+}
+
+fn materialize_profile_file_descriptors(
+ profile: &mut ProfileConfigFile,
+ config_root: &Path,
+) -> Result<()> {
+ fn pin(
+ descriptor: Option<&mut capsem_core::net::policy_config::ProfileFileDescriptor>,
+ config_root: &Path,
+ ) -> Result<()> {
+ let Some(descriptor) = descriptor else {
+ return Ok(());
+ };
+ let path = config_root.join(&descriptor.path);
+ let hash =
+ hash_file(&path).with_context(|| format!("hash profile payload {}", path.display()))?;
+ let size = fs::metadata(&path)
+ .with_context(|| format!("stat profile payload {}", path.display()))?
+ .len();
+ if size == 0 {
+ return Err(anyhow!(
+ "profile payload {} must not be empty",
+ path.display()
+ ));
+ }
+ descriptor.hash = Some(format!("blake3:{hash}"));
+ descriptor.size = Some(size);
+ Ok(())
+ }
+
+ pin(profile.files.enforcement.as_mut(), config_root)?;
+ pin(profile.files.detection.as_mut(), config_root)?;
+ pin(profile.files.mcp.as_mut(), config_root)?;
+ pin(profile.files.apt_packages.as_mut(), config_root)?;
+ pin(profile.files.python_requirements.as_mut(), config_root)?;
+ pin(profile.files.npm_packages.as_mut(), config_root)?;
+ pin(profile.files.build.as_mut(), config_root)?;
+ pin(profile.files.tips.as_mut(), config_root)?;
+ pin(profile.files.root_manifest.as_mut(), config_root)?;
+ Ok(())
+}
+
+fn materialize_profile_obom_descriptor(
+ assets_dir: &Path,
+ arch: &str,
+ manifest_assets: &std::collections::HashMap,
+ rootfs_hash: String,
+ profile: &mut ProfileConfigFile,
+ reports: &mut Vec,
+) -> Result<()> {
+ let Some(entry) = manifest_assets.get("obom.cdx.json") else {
+ return Ok(());
+ };
+ let check = check_local_asset(assets_dir, arch, "obom.cdx.json", &entry.hash, entry.size)?;
+ fail_if_local_asset_checks_failed("profile materialize OBOM check", &[check])?;
+ let obom_path = assets_dir.join(arch).join("obom.cdx.json");
+ let obom_path = obom_path
+ .canonicalize()
+ .with_context(|| format!("canonicalize {}", obom_path.display()))?;
+ let (generator, generator_version) = read_obom_generator(&obom_path)?;
+ let descriptor = ProfileObomDescriptor {
+ name: "obom.cdx.json".to_string(),
+ url: format!("file://{}", obom_path.display()),
+ hash: format!("blake3:{}", entry.hash),
+ size: entry.size,
+ generator: generator.clone(),
+ generator_version: generator_version.clone(),
+ };
+ profile
+ .obom
+ .get_or_insert_with(|| ProfileObomConfig {
+ format: "cyclonedx-obom.v1".to_string(),
+ arch: BTreeMap::new(),
+ })
+ .arch
+ .insert(arch.to_string(), descriptor.clone());
+ reports.push(ProfileMaterializedObomReport {
+ arch: arch.to_string(),
+ url: descriptor.url,
+ hash: descriptor.hash,
+ size: descriptor.size,
+ generator,
+ generator_version,
+ rootfs_hash,
+ scope: "base_image",
+ });
+ Ok(())
+}
+
+fn read_obom_generator(path: &Path) -> Result<(String, String)> {
+ let content = fs::read_to_string(path)
+ .with_context(|| format!("read CycloneDX OBOM {}", path.display()))?;
+ let document: serde_json::Value = serde_json::from_str(&content)
+ .with_context(|| format!("parse CycloneDX OBOM {}", path.display()))?;
+ let metadata = document
+ .get("metadata")
+ .ok_or_else(|| anyhow!("CycloneDX OBOM {} is missing metadata", path.display()))?;
+ let tools = metadata.get("tools").ok_or_else(|| {
+ anyhow!(
+ "CycloneDX OBOM {} is missing metadata.tools",
+ path.display()
+ )
+ })?;
+ let candidates: Vec<&serde_json::Value> = tools
+ .get("components")
+ .and_then(|components| components.as_array())
+ .map(|components| components.iter().collect())
+ .or_else(|| tools.as_array().map(|tools| tools.iter().collect()))
+ .unwrap_or_default();
+ let preferred = candidates
+ .iter()
+ .copied()
+ .find(|candidate| {
+ candidate
+ .get("name")
+ .and_then(|name| name.as_str())
+ .is_some_and(|name| name.eq_ignore_ascii_case("cdxgen"))
+ })
+ .or_else(|| {
+ candidates.iter().copied().find(|candidate| {
+ candidate
+ .get("name")
+ .and_then(|name| name.as_str())
+ .is_some()
+ && candidate
+ .get("version")
+ .and_then(|version| version.as_str())
+ .is_some()
+ })
+ })
+ .ok_or_else(|| {
+ anyhow!(
+ "CycloneDX OBOM {} must record a generator name and version in metadata.tools",
+ path.display()
+ )
+ })?;
+ let name = preferred
+ .get("name")
+ .and_then(|name| name.as_str())
+ .ok_or_else(|| {
+ anyhow!(
+ "CycloneDX OBOM {} generator is missing name",
+ path.display()
+ )
+ })?;
+ let version = preferred
+ .get("version")
+ .and_then(|version| version.as_str())
+ .ok_or_else(|| {
+ anyhow!(
+ "CycloneDX OBOM {} generator is missing version",
+ path.display()
+ )
+ })?;
+ Ok((name.to_string(), version.to_string()))
+}
+
+fn copy_dir_recursive(source: &Path, destination: &Path) -> Result<()> {
+ fs::create_dir_all(destination).with_context(|| format!("create {}", destination.display()))?;
+ for entry in fs::read_dir(source).with_context(|| format!("read {}", source.display()))? {
+ let entry = entry.with_context(|| format!("read entry in {}", source.display()))?;
+ let source_path = entry.path();
+ let destination_path = destination.join(entry.file_name());
+ let file_type = entry
+ .file_type()
+ .with_context(|| format!("stat {}", source_path.display()))?;
+ if file_type.is_dir() {
+ copy_dir_recursive(&source_path, &destination_path)?;
+ } else if file_type.is_file() {
+ if let Some(parent) = destination_path.parent() {
+ fs::create_dir_all(parent)
+ .with_context(|| format!("create {}", parent.display()))?;
+ }
+ fs::copy(&source_path, &destination_path).with_context(|| {
+ format!(
+ "copy {} to {}",
+ source_path.display(),
+ destination_path.display()
+ )
+ })?;
+ }
+ }
+ Ok(())
+}
+
+fn load_profile(path: &Path) -> Result {
+ let content =
+ fs::read_to_string(path).with_context(|| format!("read profile {}", path.display()))?;
+ toml::from_str(&content).with_context(|| format!("parse profile {}", path.display()))
+}
+
+fn validate_settings(path: &Path) -> Result {
+ let content =
+ fs::read_to_string(path).with_context(|| format!("read settings {}", path.display()))?;
+ let settings: SettingsConfigFile =
+ toml::from_str(&content).with_context(|| format!("parse settings {}", path.display()))?;
+ settings
+ .validate()
+ .map_err(|error| anyhow!("validate settings {}: {error}", path.display()))?;
+ Ok(SettingsValidationReport {
+ schema: "capsem.admin.settings_validation.v1",
+ ok: true,
+ path: path.display().to_string(),
+ app: SettingsAppReport {
+ auto_update: settings.app.auto_update,
+ notifications: settings.app.notifications,
+ start_service_at_login: settings.app.start_service_at_login,
+ },
+ appearance: SettingsAppearanceReport {
+ theme: settings.appearance.theme,
+ font_size: settings.appearance.font_size,
+ reduced_motion: settings.appearance.reduced_motion,
+ },
+ })
+}
+
+impl SettingsConfigFile {
+ fn validate(&self) -> Result<(), String> {
+ match self.appearance.theme.as_str() {
+ "system" | "light" | "dark" => {}
+ other => {
+ return Err(format!(
+ "appearance.theme must be system, light, or dark, got {other}"
+ ));
+ }
+ }
+ if !(8..=32).contains(&self.appearance.font_size) {
+ return Err(format!(
+ "appearance.font_size must be between 8 and 32, got {}",
+ self.appearance.font_size
+ ));
+ }
+ Ok(())
+ }
+}
+
+fn image_build_plan(args: &ImageBuildArgs) -> Result {
+ let profile = load_profile(&args.profile)?;
+ profile
+ .validate()
+ .map_err(|error| anyhow!("validate profile {}: {error}", args.profile.display()))?;
+ profile
+ .compile_security_rule_set_from_files(&args.config_root, SecurityRuleSource::User)
+ .map_err(|error| {
+ anyhow!(
+ "compile profile rule files for {} with config root {}: {error}",
+ args.profile.display(),
+ args.config_root.display()
+ )
+ })?;
+
+ let mut arches = profile.assets.arch.keys().cloned().collect::>();
+ arches.sort();
+ if let Some(arch) = &args.arch {
+ if !profile.assets.arch.contains_key(arch) {
+ return Err(anyhow!(
+ "profile {} does not define assets for arch {arch}",
+ profile.id
+ ));
+ }
+ arches = vec![arch.clone()];
+ }
+ if arches.is_empty() {
+ return Err(anyhow!(
+ "profile {} defines no asset architectures",
+ profile.id
+ ));
+ }
+
+ let mut arch_plans = Vec::new();
+ let mut commands = Vec::new();
+ for arch in &arches {
+ let assets = profile
+ .assets
+ .arch
+ .get(arch)
+ .expect("arch came from profile asset map");
+ arch_plans.push(ImageBuildArchPlan {
+ arch: arch.clone(),
+ kernel: assets.kernel.name.clone(),
+ initrd: assets.initrd.name.clone(),
+ rootfs: assets.rootfs.name.clone(),
+ });
+ if matches!(
+ args.template,
+ ImageBuildTemplate::All | ImageBuildTemplate::Kernel
+ ) {
+ commands.push(CommandReport {
+ step: "kernel".to_string(),
+ arch: Some(arch.clone()),
+ env: BTreeMap::new(),
+ argv: vec![
+ "uv".to_string(),
+ "run".to_string(),
+ "python".to_string(),
+ "-m".to_string(),
+ "capsem.builder.image_build_backend".to_string(),
+ args.guest_dir.display().to_string(),
+ "--arch".to_string(),
+ arch.clone(),
+ "--template".to_string(),
+ "kernel".to_string(),
+ "--output".to_string(),
+ format!("{}/", args.output.display()),
+ ],
+ });
+ }
+ if matches!(
+ args.template,
+ ImageBuildTemplate::All | ImageBuildTemplate::Rootfs
+ ) {
+ let mut env = BTreeMap::new();
+ env.insert(
+ "CAPSEM_BUILD_EXPERIMENTAL_EROFS".to_string(),
+ "1".to_string(),
+ );
+ env.insert(
+ "CAPSEM_BUILD_EROFS_COMPRESSION".to_string(),
+ "lz4hc".to_string(),
+ );
+ env.insert(
+ "CAPSEM_BUILD_EROFS_COMPRESSION_LEVEL".to_string(),
+ "12".to_string(),
+ );
+ commands.push(CommandReport {
+ step: "rootfs".to_string(),
+ arch: Some(arch.clone()),
+ env,
+ argv: vec![
+ "uv".to_string(),
+ "run".to_string(),
+ "python".to_string(),
+ "-m".to_string(),
+ "capsem.builder.image_build_backend".to_string(),
+ args.guest_dir.display().to_string(),
+ "--arch".to_string(),
+ arch.clone(),
+ "--template".to_string(),
+ "rootfs".to_string(),
+ "--output".to_string(),
+ format!("{}/", args.output.display()),
+ ],
+ });
+ }
+ }
+ commands.push(manifest_generate_command_report(&ManifestGenerateArgs {
+ assets_dir: args.output.clone(),
+ version: None,
+ json: false,
+ }));
+
+ Ok(ImageBuildPlan {
+ schema: "capsem.admin.image_build_plan.v1",
+ profile_id: profile.id,
+ profile_revision: profile.revision,
+ guest_dir: args.guest_dir.display().to_string(),
+ output: args.output.display().to_string(),
+ clean: args.clean,
+ template: match args.template {
+ ImageBuildTemplate::All => "all",
+ ImageBuildTemplate::Kernel => "kernel",
+ ImageBuildTemplate::Rootfs => "rootfs",
+ },
+ arches: arch_plans,
+ commands,
+ })
+}
+
+#[cfg(test)]
+fn verify_image_outputs(args: &ImageVerifyArgs) -> Result {
+ let profile = load_profile(&args.profile)?;
+ profile
+ .validate()
+ .map_err(|error| anyhow!("validate profile {}: {error}", args.profile.display()))?;
+ profile
+ .compile_security_rule_set_from_files(&args.config_root, SecurityRuleSource::User)
+ .map_err(|error| {
+ anyhow!(
+ "compile profile rule files for {} with config root {}: {error}",
+ args.profile.display(),
+ args.config_root.display()
+ )
+ })?;
+
+ let manifest_path = args
+ .manifest
+ .clone()
+ .unwrap_or_else(|| args.output.join("manifest.json"));
+ let manifest = load_manifest(&manifest_path)?;
+ let current_release = manifest
+ .assets
+ .releases
+ .get(&manifest.assets.current)
+ .ok_or_else(|| {
+ anyhow!(
+ "manifest {} current asset release {} is missing",
+ manifest_path.display(),
+ manifest.assets.current
+ )
+ })?;
+
+ let mut arches = Vec::new();
+ for arch in selected_profile_arches(&profile, args.arch.as_deref())? {
+ let manifest_assets = current_release.arches.get(&arch).ok_or_else(|| {
+ anyhow!(
+ "manifest {} current release {} does not contain profile arch {arch}",
+ manifest_path.display(),
+ manifest.assets.current
+ )
+ })?;
+ let profile_assets = profile
+ .assets
+ .arch
+ .get(&arch)
+ .expect("arch came from selected_profile_arches");
+ let mut asset_reports = Vec::new();
+ for descriptor in [
+ &profile_assets.kernel,
+ &profile_assets.initrd,
+ &profile_assets.rootfs,
+ ] {
+ let entry = manifest_assets.get(&descriptor.name).ok_or_else(|| {
+ anyhow!(
+ "manifest {} current release {} arch {arch} is missing {}",
+ manifest_path.display(),
+ manifest.assets.current,
+ descriptor.name
+ )
+ })?;
+ asset_reports.push(check_local_asset(
+ &args.output,
+ &arch,
+ &descriptor.name,
+ &entry.hash,
+ entry.size,
+ )?);
+ }
+ fail_if_local_asset_checks_failed("image output verify", &asset_reports)?;
+ arches.push(ImageVerifyArchReport {
+ arch,
+ assets: asset_reports,
+ });
+ }
+
+ Ok(ImageVerifyReport {
+ schema: "capsem.admin.image_verify.v1",
+ ok: true,
+ profile_id: profile.id,
+ profile_revision: profile.revision,
+ output: args.output.display().to_string(),
+ manifest: manifest_path.display().to_string(),
+ arches,
+ })
+}
+
+fn materialize_image_workspace(args: &ImageWorkspaceArgs) -> Result {
+ check_config_root(&args.config_root, args.arch.as_deref())?;
+ check_profile(&ProfileCheckArgs {
+ path: args.profile.clone(),
+ config_root: Some(args.config_root.clone()),
+ arch: args.arch.clone(),
+ json: true,
+ })?;
+ let profile = load_profile(&args.profile)?;
+ profile
+ .validate()
+ .map_err(|error| anyhow!("validate profile {}: {error}", args.profile.display()))?;
+ profile
+ .compile_security_rule_set_from_files(&args.config_root, SecurityRuleSource::User)
+ .map_err(|error| {
+ anyhow!(
+ "compile profile rule files for {} with config root {}: {error}",
+ args.profile.display(),
+ args.config_root.display()
+ )
+ })?;
+ let arches = selected_profile_arches(&profile, args.arch.as_deref())?;
+
+ let workspace = &args.output;
+ let workspace_config_root = workspace.join("config");
+ let workspace_guest_dir = workspace.join("guest");
+ let workspace_profile_path = workspace_config_root
+ .join("profiles")
+ .join(&profile.id)
+ .join("profile.toml");
+ let workspace_rules_root = workspace_config_root.join("profiles").join(&profile.id);
+ fs::create_dir_all(
+ workspace_profile_path
+ .parent()
+ .expect("workspace profile path has parent"),
+ )
+ .with_context(|| format!("create {}", workspace_profile_path.display()))?;
+ fs::create_dir_all(&workspace_rules_root)
+ .with_context(|| format!("create {}", workspace_rules_root.display()))?;
+
+ let profile_toml =
+ fs::read(&args.profile).with_context(|| format!("read {}", args.profile.display()))?;
+ fs::write(&workspace_profile_path, &profile_toml)
+ .with_context(|| format!("write {}", workspace_profile_path.display()))?;
+
+ let mut rule_files = Vec::new();
+ copy_profile_rule_file(
+ &args.config_root,
+ &workspace_config_root,
+ profile.rule_files.enforcement.as_deref(),
+ "enforcement",
+ &mut rule_files,
+ )?;
+ copy_profile_rule_file(
+ &args.config_root,
+ &workspace_config_root,
+ profile.rule_files.sigma.as_deref(),
+ "sigma",
+ &mut rule_files,
+ )?;
+ copy_profile_descriptor_files(&profile, &args.config_root, &workspace_config_root)?;
+ materialize_profile_guest_inputs(
+ &profile,
+ &args.config_root,
+ &args.guest_dir,
+ &workspace_guest_dir,
+ )?;
+
+ let copied_check = check_profile(&ProfileCheckArgs {
+ path: workspace_profile_path.clone(),
+ config_root: Some(workspace_config_root.clone()),
+ arch: args.arch.clone(),
+ json: true,
+ })?;
+ if copied_check.validation.profile_id != profile.id {
+ return Err(anyhow!(
+ "workspace profile id drifted: expected {}, got {}",
+ profile.id,
+ copied_check.validation.profile_id
+ ));
+ }
+
+ let plan = image_build_plan(&ImageBuildArgs {
+ profile: workspace_profile_path.clone(),
+ config_root: workspace_config_root.clone(),
+ guest_dir: workspace_guest_dir.clone(),
+ output: workspace.join("assets"),
+ arch: args.arch.clone(),
+ template: ImageBuildTemplate::All,
+ clean: false,
+ json: true,
+ })?;
+ let build_plan_path = workspace.join("build-plan.json");
+ fs::write(&build_plan_path, serde_json::to_vec_pretty(&plan)?)
+ .with_context(|| format!("write {}", build_plan_path.display()))?;
+
+ let report = ImageWorkspaceReport {
+ schema: "capsem.admin.image_workspace.v1",
+ ok: true,
+ profile_id: profile.id,
+ profile_revision: profile.revision,
+ workspace: workspace.display().to_string(),
+ config_root: workspace_config_root.display().to_string(),
+ profile_path: workspace_profile_path.display().to_string(),
+ profile_blake3: blake3::hash(&profile_toml).to_hex().to_string(),
+ build_plan_path: build_plan_path.display().to_string(),
+ rule_files,
+ arches: plan
+ .arches
+ .into_iter()
+ .filter(|arch| arches.iter().any(|selected| selected == &arch.arch))
+ .collect(),
+ };
+ fs::write(
+ workspace.join("workspace.json"),
+ serde_json::to_vec_pretty(&report)?,
+ )
+ .with_context(|| format!("write {}", workspace.join("workspace.json").display()))?;
+ Ok(report)
+}
+
+fn copy_profile_descriptor_files(
+ profile: &ProfileConfigFile,
+ source_config_root: &Path,
+ destination_config_root: &Path,
+) -> Result<()> {
+ for (kind, descriptor) in profile.files.iter() {
+ validate_relative_manifest_path("profile file descriptor path", &descriptor.path)?;
+ let source = source_config_root.join(&descriptor.path);
+ let destination = destination_config_root.join(&descriptor.path);
+ if let Some(parent) = destination.parent() {
+ fs::create_dir_all(parent).with_context(|| format!("create {}", parent.display()))?;
+ }
+ fs::copy(&source, &destination).with_context(|| {
+ format!(
+ "copy profile {kind} {} to {}",
+ source.display(),
+ destination.display()
+ )
+ })?;
+
+ if kind == "root_manifest" {
+ let source_root = source
+ .parent()
+ .ok_or_else(|| anyhow!("profile root manifest has no parent"))?
+ .join("root");
+ let destination_root = destination
+ .parent()
+ .ok_or_else(|| anyhow!("workspace profile root manifest has no parent"))?
+ .join("root");
+ if destination_root.exists() {
+ fs::remove_dir_all(&destination_root)
+ .with_context(|| format!("remove {}", destination_root.display()))?;
+ }
+ copy_dir_recursive(&source_root, &destination_root)?;
+ }
+ }
+ Ok(())
+}
+
+fn materialize_profile_guest_inputs(
+ profile: &ProfileConfigFile,
+ config_root: &Path,
+ source_guest_dir: &Path,
+ workspace_guest_dir: &Path,
+) -> Result<()> {
+ let source_config = config_root.join("docker").join("image");
+ let workspace_config = workspace_guest_dir.join("config");
+ fs::create_dir_all(&workspace_config)
+ .with_context(|| format!("create {}", workspace_config.display()))?;
+ for relative in ["build.toml", "manifest.toml"] {
+ let source = source_config.join(relative);
+ let destination = workspace_config.join(relative);
+ fs::copy(&source, &destination)
+ .with_context(|| format!("copy {} to {}", source.display(), destination.display()))?;
+ }
+ copy_dir_recursive(
+ &source_config.join("kernel"),
+ &workspace_config.join("kernel"),
+ )?;
+ copy_dir_recursive(
+ &source_config.join("security"),
+ &workspace_config.join("security"),
+ )?;
+ copy_dir_recursive(&source_config.join("vm"), &workspace_config.join("vm"))?;
+ write_profile_vm_resources_toml(&workspace_config.join("vm").join("resources.toml"), profile)?;
+ copy_dir_recursive(
+ &source_guest_dir.join("artifacts"),
+ &workspace_guest_dir.join("artifacts"),
+ )?;
+
+ let packages_dir = workspace_config.join("packages");
+ fs::create_dir_all(&packages_dir)
+ .with_context(|| format!("create {}", packages_dir.display()))?;
+ if let Some(descriptor) = profile.files.apt_packages.as_ref() {
+ let packages = read_profile_package_lines(&config_root.join(&descriptor.path))?;
+ write_profile_package_toml(
+ &packages_dir.join("apt.toml"),
+ "apt",
+ "System Packages",
+ "apt",
+ "apt-get install -y --no-install-recommends",
+ &packages,
+ )?;
+ }
+ if let Some(descriptor) = profile.files.python_requirements.as_ref() {
+ let packages = read_profile_package_lines(&config_root.join(&descriptor.path))?;
+ write_profile_package_toml(
+ &packages_dir.join("python.toml"),
+ "python",
+ "Python Packages",
+ "uv",
+ "uv pip install --system --break-system-packages",
+ &packages,
+ )?;
+ }
+ if let Some(descriptor) = profile.files.npm_packages.as_ref() {
+ let packages = read_profile_package_lines(&config_root.join(&descriptor.path))?;
+ write_profile_package_toml(
+ &packages_dir.join("npm.toml"),
+ "npm",
+ "Node Packages",
+ "npm",
+ "npm install -g --prefix /opt/ai-clis",
+ &packages,
+ )?;
+ }
+ if let Some(descriptor) = profile.files.build.as_ref() {
+ let source = config_root.join(&descriptor.path);
+ let destination = workspace_guest_dir.join("profile-build.sh");
+ fs::copy(&source, &destination)
+ .with_context(|| format!("copy {} to {}", source.display(), destination.display()))?;
+ }
+ if let Some(descriptor) = profile.files.tips.as_ref() {
+ let source = config_root.join(&descriptor.path);
+ let artifacts_dir = workspace_guest_dir.join("artifacts");
+ fs::create_dir_all(&artifacts_dir)
+ .with_context(|| format!("create {}", artifacts_dir.display()))?;
+ fs::copy(&source, artifacts_dir.join("tips.txt"))
+ .with_context(|| format!("copy profile tips {}", source.display()))?;
+ }
+ if let Some(descriptor) = profile.files.root_manifest.as_ref() {
+ let manifest_path = config_root.join(&descriptor.path);
+ let source_root = manifest_path
+ .parent()
+ .ok_or_else(|| anyhow!("profile root manifest has no parent"))?
+ .join("root");
+ copy_dir_recursive(&source_root, &workspace_guest_dir.join("profile-root"))?;
+ }
+ Ok(())
+}
+
+fn write_profile_vm_resources_toml(path: &Path, profile: &ProfileConfigFile) -> Result<()> {
+ if let Some(parent) = path.parent() {
+ fs::create_dir_all(parent).with_context(|| format!("create {}", parent.display()))?;
+ }
+ let content = format!(
+ "[resources]\n\
+ cpu_count = {}\n\
+ ram_gb = {}\n\
+ scratch_disk_size_gb = {}\n\
+ log_bodies = false\n\
+ max_body_capture = 4096\n\
+ retention_days = 30\n\
+ max_sessions = 100\n\
+ min_content_sessions = 25\n\
+ max_disk_gb = 100\n\
+ terminated_retention_days = 365\n",
+ profile.vm.cpu_count, profile.vm.ram_gb, profile.vm.scratch_disk_size_gb
+ );
+ fs::write(path, content).with_context(|| format!("write {}", path.display()))
+}
+
+fn read_profile_package_lines(path: &Path) -> Result> {
+ let content = fs::read_to_string(path)
+ .with_context(|| format!("read package list {}", path.display()))?;
+ let packages = content
+ .lines()
+ .map(str::trim)
+ .filter(|line| !line.is_empty() && !line.starts_with('#'))
+ .map(ToOwned::to_owned)
+ .collect::>();
+ if packages.is_empty() {
+ return Err(anyhow!("package list {} is empty", path.display()));
+ }
+ Ok(packages)
+}
+
+fn write_profile_package_toml(
+ path: &Path,
+ key: &str,
+ name: &str,
+ manager: &str,
+ install_cmd: &str,
+ packages: &[String],
+) -> Result<()> {
+ let parent = path
+ .parent()
+ .ok_or_else(|| anyhow!("package TOML path has no parent: {}", path.display()))?;
+ fs::create_dir_all(parent).with_context(|| format!("create {}", parent.display()))?;
+ let packages = packages
+ .iter()
+ .map(|package| format!(" {package:?}"))
+ .collect::>()
+ .join(",\n");
+ let content = format!(
+ r#"[{key}]
+name = {name:?}
+manager = {manager:?}
+install_cmd = {install_cmd:?}
+packages = [
+{packages},
+]
+"#
+ );
+ fs::write(path, content).with_context(|| format!("write {}", path.display()))?;
+ Ok(())
+}
+
+fn copy_profile_rule_file(
+ config_root: &Path,
+ workspace_config_root: &Path,
+ rule_file: Option<&str>,
+ kind: &'static str,
+ reports: &mut Vec,
+) -> Result<()> {
+ let Some(rule_file) = rule_file else {
+ return Ok(());
+ };
+ if Path::new(rule_file).is_absolute() {
+ return Err(anyhow!(
+ "image workspace requires profile rule files to be relative, got {rule_file}"
+ ));
+ }
+ let source_path = resolve_profile_rule_file_path(config_root, rule_file);
+ let destination_path = workspace_config_root.join(rule_file);
+ fs::create_dir_all(
+ destination_path
+ .parent()
+ .ok_or_else(|| anyhow!("rule file destination has no parent"))?,
+ )
+ .with_context(|| format!("create parent for {}", destination_path.display()))?;
+ let bytes = fs::read(&source_path)
+ .with_context(|| format!("read rule file {}", source_path.display()))?;
+ fs::write(&destination_path, &bytes)
+ .with_context(|| format!("write rule file {}", destination_path.display()))?;
+ reports.push(ImageWorkspaceRuleFileReport {
+ kind,
+ source: source_path.display().to_string(),
+ path: destination_path.display().to_string(),
+ blake3: blake3::hash(&bytes).to_hex().to_string(),
+ size: bytes.len() as u64,
+ });
+ Ok(())
+}
+
+fn manifest_generate_command_report(args: &ManifestGenerateArgs) -> CommandReport {
+ let version_expr = match &args.version {
+ Some(version) => format!("{version:?}"),
+ None => "get_project_version(Path('.'))".to_string(),
+ };
+ CommandReport {
+ step: "manifest".to_string(),
+ arch: None,
+ env: BTreeMap::new(),
+ argv: vec![
+ "uv".to_string(),
+ "run".to_string(),
+ "python3".to_string(),
+ "-c".to_string(),
+ format!(
+ "from pathlib import Path; from capsem.builder.docker import generate_checksums, get_project_version; v = {version_expr}; generate_checksums(Path({:?}), v); print(f'manifest.json generated (v{{v}})')",
+ args.assets_dir.display().to_string()
+ ),
+ ],
+ }
+}
+
+fn selected_profile_arches(
+ profile: &ProfileConfigFile,
+ only_arch: Option<&str>,
+) -> Result> {
+ let mut arches = profile.assets.arch.keys().cloned().collect::>();
+ arches.sort();
+ if let Some(arch) = only_arch {
+ if !profile.assets.arch.contains_key(arch) {
+ return Err(anyhow!(
+ "profile {} does not define assets for arch {arch}",
+ profile.id
+ ));
+ }
+ arches = vec![arch.to_string()];
+ }
+ if arches.is_empty() {
+ return Err(anyhow!(
+ "profile {} defines no asset architectures",
+ profile.id
+ ));
+ }
+ Ok(arches)
+}
+
+fn check_local_asset(
+ assets_dir: &Path,
+ arch: &str,
+ logical_name: &str,
+ expected_hash: &str,
+ expected_size: u64,
+) -> Result {
+ let path = assets_dir.join(arch).join(logical_name);
+ check_exact_local_asset(&path, arch, logical_name, expected_hash, expected_size)
+}
+
+fn check_exact_local_asset(
+ path: &Path,
+ arch: &str,
+ logical_name: &str,
+ expected_hash: &str,
+ expected_size: u64,
+) -> Result {
+ if !path.is_file() {
+ return Ok(LocalAssetCheckReport {
+ arch: arch.to_string(),
+ logical_name: logical_name.to_string(),
+ expected_hash: expected_hash.to_string(),
+ expected_size,
+ path: Some(path.display().to_string()),
+ present: false,
+ size_ok: None,
+ blake3_ok: None,
+ });
+ }
+ let metadata =
+ fs::metadata(path).with_context(|| format!("stat local asset {}", path.display()))?;
+ let digest = hash_file(path)?;
+ Ok(LocalAssetCheckReport {
+ arch: arch.to_string(),
+ logical_name: logical_name.to_string(),
+ expected_hash: expected_hash.to_string(),
+ expected_size,
+ path: Some(path.display().to_string()),
+ present: true,
+ size_ok: Some(metadata.len() == expected_size),
+ blake3_ok: Some(digest == expected_hash),
+ })
+}
+
+fn fail_if_local_asset_checks_failed(
+ context: &str,
+ assets: &[LocalAssetCheckReport],
+) -> Result<()> {
+ let failed = assets.iter().any(|asset| {
+ !asset.present
+ || asset.size_ok.is_some_and(|ok| !ok)
+ || asset.blake3_ok.is_some_and(|ok| !ok)
+ });
+ if failed {
+ return Err(anyhow!("{context} failed"));
+ }
+ Ok(())
+}
+
+fn normalized_blake3(value: &str) -> Result<&str> {
+ value
+ .strip_prefix("blake3:")
+ .ok_or_else(|| anyhow!("expected blake3:, got {value}"))
+}
+
+fn validate_relative_manifest_path(field: &str, value: &str) -> Result<()> {
+ if value.is_empty()
+ || value.starts_with('/')
+ || value.starts_with("file://")
+ || value.contains("..")
+ || value.contains('\\')
+ || value.trim() != value
+ {
+ return Err(anyhow!(
+ "{field} must be a relative path without traversal: {value}"
+ ));
+ }
+ Ok(())
+}
+
+fn print_image_build_plan(plan: &ImageBuildPlan, json: bool) -> Result<()> {
+ if json {
+ println!("{}", serde_json::to_string_pretty(plan)?);
+ return Ok(());
+ }
+ println!(
+ "profile {} rev {} -> {}",
+ plan.profile_id, plan.profile_revision, plan.output
+ );
+ for arch in &plan.arches {
+ println!(
+ " {}: {}, {}, {}",
+ arch.arch, arch.kernel, arch.initrd, arch.rootfs
+ );
+ }
+ for command in &plan.commands {
+ let env = if command.env.is_empty() {
+ String::new()
+ } else {
+ format!(
+ "{} ",
+ command
+ .env
+ .iter()
+ .map(|(key, value)| format!("{key}={value}"))
+ .collect::>()
+ .join(" ")
+ )
+ };
+ println!(" {}{}", env, command.argv.join(" "));
+ }
+ Ok(())
+}
+
+fn clean_image_outputs(plan: &ImageBuildPlan) -> Result<()> {
+ let output = PathBuf::from(&plan.output);
+ for arch in &plan.arches {
+ let path = output.join(&arch.arch);
+ if !path.exists() {
+ continue;
+ }
+ match plan.template {
+ "all" => {
+ fs::remove_dir_all(&path).with_context(|| format!("remove {}", path.display()))?;
+ }
+ "kernel" => {
+ for name in [&arch.kernel, &arch.initrd] {
+ let file = path.join(name);
+ if file.exists() {
+ fs::remove_file(&file)
+ .with_context(|| format!("remove {}", file.display()))?;
+ }
+ }
+ }
+ "rootfs" => {
+ for name in [
+ arch.rootfs.as_str(),
+ "rootfs.squashfs",
+ "obom.cdx.json",
+ "build-ledger.log",
+ "tool-versions.txt",
+ ] {
+ let file = path.join(name);
+ if file.exists() {
+ fs::remove_file(&file)
+ .with_context(|| format!("remove {}", file.display()))?;
+ }
+ }
+ }
+ other => return Err(anyhow!("unsupported image build template {other}")),
+ }
+ }
+ if plan.arches.len() > 1 {
+ for name in ["manifest.json", "B3SUMS"] {
+ let path = output.join(name);
+ if path.exists() {
+ fs::remove_file(&path).with_context(|| format!("remove {}", path.display()))?;
+ }
+ }
+ }
+ Ok(())
+}
+
+fn run_command(command: &CommandReport) -> Result<()> {
+ let (program, args) = command
+ .argv
+ .split_first()
+ .ok_or_else(|| anyhow!("empty command for step {}", command.step))?;
+ let status = Command::new(program)
+ .args(args)
+ .envs(&command.env)
+ .stdin(Stdio::null())
+ .status()
+ .with_context(|| format!("run image build step {}", command.step))?;
+ if !status.success() {
+ return Err(anyhow!(
+ "image build step {} failed with status {status}",
+ command.step
+ ));
+ }
+ Ok(())
+}
+
+fn compile_rule_file(
+ kind: &'static str,
+ path: &Path,
+ source: RuleFileSourceArg,
+) -> Result {
+ let content =
+ fs::read_to_string(path).with_context(|| format!("read {kind} {}", path.display()))?;
+ let profile = match kind {
+ "enforcement" => SecurityRuleProfile::parse_toml(&content)
+ .map_err(|error| anyhow!("parse enforcement {}: {error}", path.display()))?,
+ "detection" => SecurityRuleProfile::parse_sigma_yaml(&content)
+ .map_err(|error| anyhow!("parse detection {}: {error}", path.display()))?,
+ other => return Err(anyhow!("unsupported rule file kind: {other}")),
+ };
+ let source = source.into_security_rule_source();
+ let rule_set = SecurityRuleSet::compile_profile(&profile, source)
+ .map_err(|error| anyhow!("compile {kind} {}: {error}", path.display()))?;
+ let rules = rule_set
+ .rules()
+ .iter()
+ .map(compiled_rule_report)
+ .collect::>();
+ Ok(RuleFileReport {
+ schema: "capsem.admin.rule_file_report.v1",
+ ok: true,
+ kind,
+ source: match source {
+ SecurityRuleSource::User => "user",
+ SecurityRuleSource::Corp => "corp",
+ SecurityRuleSource::BuiltinDefault => "builtin_default",
+ },
+ path: path.display().to_string(),
+ compiled_rules: rules.len(),
+ rules,
+ })
+}
+
+fn compiled_rule_report(rule: &CompiledSecurityRule) -> CompiledRuleReport {
+ CompiledRuleReport {
+ rule_id: rule.rule_id.clone(),
+ provider: rule.provider.clone(),
+ namespace: rule.namespace.clone(),
+ rule_key: rule.rule_key.clone(),
+ default_rule: rule.default_rule,
+ name: rule.name.clone(),
+ action: rule.action.as_str(),
+ detection_level: rule.detection_level.map(|level| level.as_str()),
+ priority: rule.priority,
+ condition: rule.condition.clone(),
+ reason: rule.reason.clone(),
+ corp_locked: rule.corp_locked,
+ }
+}
+
+fn load_manifest(path: &Path) -> Result {
+ let content =
+ fs::read_to_string(path).with_context(|| format!("read manifest {}", path.display()))?;
+ ManifestV2::from_json(&content).with_context(|| format!("parse manifest {}", path.display()))
+}
+
+fn manifest_report(
+ path: &Path,
+ manifest: &ManifestV2,
+ assets_dir: Option<&Path>,
+ only_arch: Option<&str>,
+) -> Result {
+ let mut arches = Vec::new();
+ for (asset_version, release) in &manifest.assets.releases {
+ for (arch, assets) in &release.arches {
+ if only_arch.is_some_and(|only| only != arch) {
+ continue;
+ }
+ let mut asset_reports = Vec::new();
+ let mut names = assets.keys().collect::>();
+ names.sort();
+ for name in names {
+ let entry = assets.get(name).expect("asset name from keys");
+ let (path, present, size_ok, blake3_ok) = match assets_dir {
+ Some(dir) => {
+ let file_path = dir.join(arch).join(name);
+ if !file_path.is_file() {
+ (Some(file_path.display().to_string()), false, None, None)
+ } else {
+ let metadata = fs::metadata(&file_path).with_context(|| {
+ format!("stat manifest asset {}", file_path.display())
+ })?;
+ let digest = hash_file(&file_path)?;
+ (
+ Some(file_path.display().to_string()),
+ true,
+ Some(metadata.len() == entry.size),
+ Some(digest == entry.hash),
+ )
+ }
+ }
+ None => (None, false, None, None),
+ };
+ asset_reports.push(ManifestAssetReport {
+ logical_name: name.clone(),
+ hash: entry.hash.clone(),
+ size: entry.size,
+ path,
+ present,
+ size_ok,
+ blake3_ok,
+ });
+ }
+ arches.push(ManifestArchReport {
+ asset_version: asset_version.clone(),
+ arch: arch.clone(),
+ assets: asset_reports,
+ });
+ }
+ }
+ arches.sort_by(|left, right| {
+ left.asset_version
+ .cmp(&right.asset_version)
+ .then_with(|| left.arch.cmp(&right.arch))
+ });
+ if let Some(only_arch) = only_arch {
+ if arches.is_empty() {
+ return Err(anyhow!(
+ "manifest {} does not contain arch {only_arch}",
+ path.display()
+ ));
+ }
+ }
+ Ok(ManifestReport {
+ schema: "capsem.admin.manifest_report.v1",
+ ok: true,
+ path: path.display().to_string(),
+ blake3: hash_file(path)?,
+ refresh_policy: manifest.refresh_policy.clone(),
+ current_assets: manifest.assets.current.clone(),
+ current_binary: manifest.binaries.current.clone(),
+ releases: manifest.assets.releases.len(),
+ arches,
+ })
+}
+
+fn hash_file(path: &Path) -> Result {
+ let mut file = fs::File::open(path).with_context(|| format!("open {}", path.display()))?;
+ let mut hasher = blake3::Hasher::new();
+ let mut buffer = [0_u8; 128 * 1024];
+ loop {
+ let read = file
+ .read(&mut buffer)
+ .with_context(|| format!("read {}", path.display()))?;
+ if read == 0 {
+ break;
+ }
+ hasher.update(&buffer[..read]);
+ }
+ Ok(hasher.finalize().to_hex().to_string())
+}
+
+fn infer_config_root(profile_path: &Path) -> Result {
+ let parent = profile_path.parent().ok_or_else(|| {
+ anyhow!(
+ "cannot infer config root for profile path without parent: {}",
+ profile_path.display()
+ )
+ })?;
+ if profile_path
+ .file_name()
+ .is_some_and(|name| name == "profile.toml")
+ && parent
+ .parent()
+ .and_then(Path::file_name)
+ .is_some_and(|name| name == "profiles")
+ {
+ return parent
+ .parent()
+ .and_then(Path::parent)
+ .map(Path::to_path_buf)
+ .ok_or_else(|| {
+ anyhow!(
+ "cannot infer config root from profile path {}",
+ profile_path.display()
+ )
+ });
+ }
+ if parent.file_name().is_some_and(|name| name == "profiles") {
+ return parent.parent().map(Path::to_path_buf).ok_or_else(|| {
+ anyhow!(
+ "cannot infer config root from profile path {}",
+ profile_path.display()
+ )
+ });
+ }
+ Ok(parent.to_path_buf())
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use std::fs;
+
+ #[test]
+ fn validates_checked_in_code_profile_through_security_rule_set() {
+ let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+ let repo_root = manifest_dir
+ .parent()
+ .and_then(Path::parent)
+ .expect("repo root");
+ let config_root = repo_root.join("config");
+ let profile_path = config_root.join("profiles/code/profile.toml");
+
+ let report =
+ validate_profile(&profile_path, Some(&config_root)).expect("profile validates");
+
+ assert!(report.ok);
+ assert_eq!(report.profile_id, "code");
+ assert!(report.compiled_rules >= 7);
+ }
+
+ #[test]
+ fn source_profile_validation_rejects_generated_pins() {
+ let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+ let repo_root = manifest_dir
+ .parent()
+ .and_then(Path::parent)
+ .expect("repo root");
+ let config_root = repo_root.join("config");
+ let source = fs::read_to_string(config_root.join("profiles/code/profile.toml"))
+ .expect("read source profile");
+ let pinned = source.replace(
+ "url = \"https://github.com/google/capsem/releases/download/v1.0.1780954707/arm64-vmlinuz\"\n",
+ "url = \"https://github.com/google/capsem/releases/download/v1.0.1780954707/arm64-vmlinuz\"\nhash = \"blake3:aa933a569fe27ed014ae76b58eb278d72fbde8a3cbd4c06a23da2987e70d0bd1\"\nsize = 8786432\n",
+ );
+ let temp = tempfile::tempdir().expect("tempdir");
+ let profile_path = temp.path().join("profile.toml");
+ fs::write(&profile_path, pinned).expect("write pinned profile");
+
+ let error = validate_profile(&profile_path, Some(&config_root))
+ .expect_err("source profile pins rejected");
+
+ assert!(
+ error.to_string().contains("source profile")
+ && error.to_string().contains("hash/size pins"),
+ "{error:#}"
+ );
+ }
+
+ #[test]
+ fn validates_checked_in_settings_file() {
+ let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+ let repo_root = manifest_dir
+ .parent()
+ .and_then(Path::parent)
+ .expect("repo root");
+ let path = repo_root.join("config/settings/settings.toml");
+
+ let report = validate_settings(&path).expect("settings validates");
+
+ assert!(report.ok);
+ assert!(report.app.auto_update);
+ assert_eq!(report.appearance.theme, "system");
+ }
+
+ #[test]
+ fn settings_validation_rejects_runtime_profile_fields() {
+ let temp = tempfile::tempdir().expect("tempdir");
+ let path = temp.path().join("settings.toml");
+ fs::write(
+ &path,
+ r#"
+[app]
+auto_update = true
+notifications = true
+start_service_at_login = true
+
+[appearance]
+theme = "system"
+font_size = 14
+reduced_motion = false
+
+[profiles]
+code = true
+"#,
+ )
+ .expect("settings");
+
+ let error = validate_settings(&path).expect_err("profile fields rejected");
+
+ assert!(
+ format!("{error:#}").contains("unknown field `profiles`"),
+ "{error:#}"
+ );
+ }
+
+ #[test]
+ fn checked_in_config_root_passes_admin_lint() {
+ let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+ let repo_root = manifest_dir
+ .parent()
+ .and_then(Path::parent)
+ .expect("repo root");
+
+ let report = check_config_root(&repo_root.join("config"), Some("arm64"))
+ .expect("config root checks");
+
+ assert!(report.ok);
+ assert!(report
+ .profiles
+ .iter()
+ .any(|profile| profile.validation.profile_id == "code"));
+ assert!(report
+ .profiles
+ .iter()
+ .any(|profile| profile.validation.profile_id == "co-work"));
+ }
+
+ #[test]
+ fn config_root_lint_rejects_profile_catalog_id_mismatch() {
+ let temp = tempfile::tempdir().expect("tempdir");
+ let config_root = temp.path().join("config");
+ fs::create_dir_all(config_root.join("profiles/wrong")).expect("profile dir");
+ fs::create_dir_all(config_root.join("settings")).expect("settings dir");
+ fs::create_dir_all(config_root.join("corp")).expect("corp dir");
+ fs::write(
+ config_root.join("settings/settings.toml"),
+ include_str!("../../../config/settings/settings.toml"),
+ )
+ .expect("settings");
+ fs::write(
+ config_root.join("corp/corp.toml"),
+ "refresh_policy = \"24h\"\n",
+ )
+ .expect("corp");
+ fs::write(
+ config_root.join("profiles/wrong/profile.toml"),
+ include_str!("../../../config/profiles/code/profile.toml"),
+ )
+ .expect("profile");
+
+ let error = check_config_root(&config_root, Some("arm64"))
+ .expect_err("catalog id mismatch rejected");
+
+ assert!(format!("{error:#}").contains("id mismatch"), "{error:#}");
+ }
+
+ #[test]
+ fn rejects_profile_rule_files_with_old_policy_syntax() {
+ let temp = tempfile::tempdir().expect("tempdir");
+ let config_root = temp.path();
+ fs::create_dir_all(config_root.join("profiles/code")).expect("profile rules dir");
+ let old_table = "policy".to_string() + ".http.block_old";
+ fs::write(
+ config_root.join("profiles/code/enforcement.toml"),
+ r#"
+[__OLD_TABLE__]
+on = ["http.request"]
+if = "http.host == 'evil.test'"
+decision = "block"
+"#
+ .replace("__OLD_TABLE__", &old_table),
+ )
+ .expect("old policy file");
+ fs::write(
+ config_root.join("profiles/code/profile.toml"),
+ r#"
+id = "code"
+name = "Code"
+description = "Optimized for coding and long-running agents."
+revision = "2026.06.08.3"
+refresh_policy = "24h"
+
+[assets]
+format = "profile-assets.v1"
+refresh_policy = "on_profile_refresh"
+
+[assets.arch.arm64.kernel]
+name = "vmlinuz"
+url = "https://example.test/vmlinuz"
+
+[assets.arch.arm64.initrd]
+name = "initrd.img"
+url = "https://example.test/initrd.img"
+
+[assets.arch.arm64.rootfs]
+name = "rootfs.erofs"
+url = "https://example.test/rootfs.erofs"
+
+[rule_files]
+enforcement = "profiles/code/enforcement.toml"
+"#,
+ )
+ .expect("profile");
+
+ let error = validate_profile(
+ &config_root.join("profiles/code/profile.toml"),
+ Some(config_root),
+ )
+ .expect_err("old policy syntax rejected");
+
+ assert!(
+ error.to_string().contains("unknown field `policy`")
+ || format!("{error:#}").contains("unknown field `policy`"),
+ "{error:#}"
+ );
+ }
+
+ #[test]
+ fn compiles_checked_in_enforcement_file() {
+ let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+ let repo_root = manifest_dir
+ .parent()
+ .and_then(Path::parent)
+ .expect("repo root");
+ let path = repo_root.join("config/profiles/code/enforcement.toml");
+
+ let report =
+ compile_rule_file("enforcement", &path, RuleFileSourceArg::User).expect("compile");
+
+ assert_eq!(report.kind, "enforcement");
+ let rule_ids = report
+ .rules
+ .iter()
+ .map(|rule| rule.rule_id.as_str())
+ .collect::>();
+ assert_eq!(
+ rule_ids,
+ BTreeSet::from([
+ "profiles.rules.capsem_mock_server",
+ "profiles.rules.default_http",
+ "profiles.rules.default_dns",
+ "profiles.rules.default_mcp",
+ "profiles.rules.default_model",
+ "profiles.rules.default_unknown_model_provider",
+ "profiles.rules.default_unknown_mcp_server",
+ "profiles.rules.default_file",
+ "profiles.rules.default_process",
+ ])
+ );
+ assert_eq!(report.compiled_rules, rule_ids.len());
+ assert_eq!(
+ report
+ .rules
+ .iter()
+ .filter(|rule| !rule.default_rule)
+ .map(|rule| rule.rule_id.as_str())
+ .collect::>(),
+ vec!["profiles.rules.capsem_mock_server"]
+ );
+ assert!(report.rules.iter().all(|rule| rule.action == "allow"));
+ assert!(report.rules.iter().all(|rule| rule.priority > 0));
+ assert_eq!(
+ report
+ .rules
+ .iter()
+ .filter(|rule| rule.detection_level.is_some())
+ .map(|rule| (rule.rule_id.as_str(), rule.detection_level))
+ .collect::>(),
+ BTreeSet::from([
+ (
+ "profiles.rules.default_unknown_model_provider",
+ Some("informational")
+ ),
+ (
+ "profiles.rules.default_unknown_mcp_server",
+ Some("informational")
+ ),
+ ])
+ );
+ }
+
+ #[test]
+ fn compiles_checked_in_detection_file() {
+ let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+ let repo_root = manifest_dir
+ .parent()
+ .and_then(Path::parent)
+ .expect("repo root");
+ let path = repo_root.join("config/profiles/code/detection.yaml");
+
+ let report =
+ compile_rule_file("detection", &path, RuleFileSourceArg::User).expect("compile");
+
+ assert_eq!(report.kind, "detection");
+ assert_eq!(report.compiled_rules, 1);
+ assert_eq!(report.rules[0].rule_id, "profiles.rules.skill_loaded");
+ assert_eq!(report.rules[0].detection_level, Some("informational"));
+ }
+
+ #[test]
+ fn checked_in_profile_build_wraps_agy_with_skip_permissions() {
+ let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+ let repo_root = manifest_dir
+ .parent()
+ .and_then(Path::parent)
+ .expect("repo root");
+ let path = repo_root.join("config/profiles/code/build.sh");
+ let content = fs::read_to_string(path).expect("profile build script");
+
+ assert!(
+ content.contains("/usr/local/bin/agy-real"),
+ "profile build script must preserve the real AGY binary behind a wrapper"
+ );
+ assert!(
+ content.contains("--dangerously-skip-permissions"),
+ "profile-owned AGY wrapper must opt into the Capsem permission model"
+ );
+ assert!(
+ content.contains("https://ollama.com/install.sh"),
+ "profile build script must ship Ollama through its official installer"
+ );
+ }
+
+ #[test]
+ fn enforcement_compile_rejects_old_on_if_decision_shape() {
+ let temp = tempfile::tempdir().expect("tempdir");
+ let path = temp.path().join("old.toml");
+ fs::write(
+ &path,
+ r#"
+[profiles.rules.old_http]
+name = "old_http"
+on = ["http.request"]
+if = "http.host == 'evil.test'"
+decision = "block"
+"#,
+ )
+ .expect("old rule");
+
+ let error = compile_rule_file("enforcement", &path, RuleFileSourceArg::User)
+ .expect_err("old shape rejected");
+
+ assert!(
+ format!("{error:#}").contains("missing field `action`"),
+ "{error:#}"
+ );
+ }
+
+ #[test]
+ fn infers_config_root_for_profiles_directory() {
+ let root = PathBuf::from("/tmp/capsem-config");
+ let path = root.join("profiles/code/profile.toml");
+ assert_eq!(infer_config_root(&path).unwrap(), root);
+ }
+
+ #[test]
+ fn checks_manifest_contract() {
+ let temp = tempfile::tempdir().expect("tempdir");
+ let path = temp.path().join("manifest.json");
+ fs::write(&path, minimal_manifest_json(None, true)).expect("manifest");
+
+ let manifest = load_manifest(&path).expect("manifest parses");
+ let report = manifest_report(&path, &manifest, None, None).expect("report");
+
+ assert_eq!(
+ report.blake3,
+ blake3::hash(fs::read(&path).unwrap().as_slice())
+ .to_hex()
+ .to_string()
+ );
+ assert_eq!(report.refresh_policy, "24h");
+ assert_eq!(report.current_assets, "2026.0607.1");
+ assert!(report.arches.iter().any(|arch| arch.arch == "arm64"));
+ }
+
+ #[test]
+ fn manifest_check_rejects_missing_refresh_policy() {
+ let temp = tempfile::tempdir().expect("tempdir");
+ let path = temp.path().join("manifest.json");
+ fs::write(&path, minimal_manifest_json(None, false)).expect("manifest");
+
+ let error = load_manifest(&path).expect_err("refresh policy required");
+
+ assert!(format!("{error:#}").contains("refresh_policy"), "{error:#}");
+ }
+
+ #[test]
+ fn manifest_verify_checks_literal_sibling_assets() {
+ let temp = tempfile::tempdir().expect("tempdir");
+ let payload = b"capsem test asset";
+ let hash = blake3::hash(payload).to_hex().to_string();
+ let manifest_path = temp.path().join("manifest.json");
+ fs::write(&manifest_path, minimal_manifest_json(Some(&hash), true)).expect("manifest");
+ let assets_root = temp.path().join("assets");
+ let assets_dir = assets_root.join("arm64");
+ fs::create_dir_all(&assets_dir).expect("assets dir");
+ fs::write(assets_dir.join("rootfs.erofs"), payload).expect("asset");
+
+ let manifest = load_manifest(&manifest_path).expect("manifest");
+ let report = manifest_report(&manifest_path, &manifest, Some(&assets_root), Some("arm64"))
+ .expect("manifest verify");
+
+ let asset = &report.arches[0].assets[0];
+ assert!(asset.present);
+ assert_eq!(asset.size_ok, Some(true));
+ assert_eq!(asset.blake3_ok, Some(true));
+ }
+
+ #[test]
+ fn profile_check_verifies_only_declared_file_urls() {
+ let temp = tempfile::tempdir().expect("tempdir");
+ let mut profile = ProfileConfigFile::builtin_primary();
+ profile.rule_files.enforcement = None;
+ profile.rule_files.sigma = None;
+ profile.files = Default::default();
+ profile.assets.arch.retain(|arch, _| arch == "arm64");
+ let arch_assets = profile.assets.arch.get_mut("arm64").expect("arm64 assets");
+ for descriptor in [
+ &mut arch_assets.kernel,
+ &mut arch_assets.initrd,
+ &mut arch_assets.rootfs,
+ ] {
+ let payload = format!("{} bytes", descriptor.name);
+ let path = temp.path().join(&descriptor.name);
+ fs::write(&path, payload.as_bytes()).expect("asset");
+ descriptor.url = format!("file://{}", path.display());
+ }
+ let profile_path = temp.path().join("profile.toml");
+ fs::write(
+ &profile_path,
+ toml::to_string(&profile).expect("serialize profile"),
+ )
+ .expect("profile");
+
+ let report = check_profile(&ProfileCheckArgs {
+ path: profile_path,
+ config_root: Some(temp.path().to_path_buf()),
+ arch: Some("arm64".to_string()),
+ json: true,
+ })
+ .expect("profile check");
+
+ assert!(report.assets.is_empty());
+ assert!(report.profile_files.is_empty());
+ }
+
+ #[test]
+ fn profile_check_validates_profile_payload_files_and_root_manifest() {
+ let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+ let repo_root = manifest_dir
+ .parent()
+ .and_then(Path::parent)
+ .expect("repo root");
+ let profile_path = repo_root.join("config/profiles/code/profile.toml");
+
+ let report = check_profile(&ProfileCheckArgs {
+ path: profile_path,
+ config_root: Some(repo_root.join("config")),
+ arch: Some("arm64".to_string()),
+ json: true,
+ })
+ .expect("checked-in profile payload files validate");
+
+ assert!(report
+ .profile_files
+ .iter()
+ .any(|file| file.logical_name == "mcp"));
+ assert!(report
+ .profile_files
+ .iter()
+ .any(|file| file.logical_name == "root/.codex/config.toml"));
+ assert!(report.profile_files.iter().all(|file| file.present));
+ assert!(report
+ .profile_files
+ .iter()
+ .any(|file| file.size_ok == Some(true) && file.blake3_ok == Some(true)));
+ }
+
+ #[test]
+ fn profile_check_rejects_missing_profile_payload_file() {
+ let temp = tempfile::tempdir().expect("tempdir");
+ let config_root = temp.path().join("config");
+ let profile_dir = config_root.join("profiles/code");
+ fs::create_dir_all(&profile_dir).expect("profile dir");
+ let mut profile = ProfileConfigFile::builtin_primary();
+ profile.rule_files.enforcement = None;
+ profile.rule_files.sigma = None;
+ profile.assets.arch.retain(|arch, _| arch == "arm64");
+ profile.files = Default::default();
+ profile.files.mcp = Some(capsem_core::net::policy_config::ProfileFileDescriptor {
+ path: "profiles/code/mcp.json".to_string(),
+ hash: None,
+ size: None,
+ });
+ let profile_path = profile_dir.join("profile.toml");
+ fs::write(&profile_path, toml::to_string(&profile).unwrap()).expect("profile");
+
+ let error = check_profile(&ProfileCheckArgs {
+ path: profile_path,
+ config_root: Some(config_root),
+ arch: Some("arm64".to_string()),
+ json: true,
+ })
+ .expect_err("missing payload file rejected");
+ assert!(error.to_string().contains("profile payload file pin check"));
+ }
+
+ #[test]
+ fn profile_check_rejects_malformed_profile_mcp_file_even_when_hash_matches() {
+ let temp = tempfile::tempdir().expect("tempdir");
+ let config_root = temp.path().join("config");
+ let profile_dir = config_root.join("profiles/code");
+ fs::create_dir_all(&profile_dir).expect("profile dir");
+ let mcp = "{ definitely not json";
+ fs::write(profile_dir.join("mcp.json"), mcp).expect("mcp");
+ let mut profile = ProfileConfigFile::builtin_primary();
+ profile.rule_files.enforcement = None;
+ profile.rule_files.sigma = None;
+ profile.assets.arch.retain(|arch, _| arch == "arm64");
+ profile.files = Default::default();
+ profile.files.mcp = Some(capsem_core::net::policy_config::ProfileFileDescriptor {
+ path: "profiles/code/mcp.json".to_string(),
+ hash: None,
+ size: None,
+ });
+ let profile_path = profile_dir.join("profile.toml");
+ fs::write(&profile_path, toml::to_string(&profile).unwrap()).expect("profile");
+
+ let error = check_profile(&ProfileCheckArgs {
+ path: profile_path,
+ config_root: Some(config_root),
+ arch: Some("arm64".to_string()),
+ json: true,
+ })
+ .expect_err("malformed MCP config rejected");
+
+ assert!(
+ format!("{error:#}").contains("parse profile MCP config"),
+ "{error:#}"
+ );
+ }
+
+ #[test]
+ fn profile_check_rejects_empty_profile_package_file_even_when_hash_matches() {
+ let temp = tempfile::tempdir().expect("tempdir");
+ let config_root = temp.path().join("config");
+ let profile_dir = config_root.join("profiles/code");
+ fs::create_dir_all(&profile_dir).expect("profile dir");
+ let packages = "# intentionally empty\n";
+ fs::write(profile_dir.join("python-requirements.txt"), packages).expect("packages");
+ let mut profile = ProfileConfigFile::builtin_primary();
+ profile.rule_files.enforcement = None;
+ profile.rule_files.sigma = None;
+ profile.assets.arch.retain(|arch, _| arch == "arm64");
+ profile.files = Default::default();
+ profile.files.python_requirements =
+ Some(capsem_core::net::policy_config::ProfileFileDescriptor {
+ path: "profiles/code/python-requirements.txt".to_string(),
+ hash: None,
+ size: None,
+ });
+ let profile_path = profile_dir.join("profile.toml");
+ fs::write(&profile_path, toml::to_string(&profile).unwrap()).expect("profile");
+
+ let error = check_profile(&ProfileCheckArgs {
+ path: profile_path,
+ config_root: Some(config_root),
+ arch: Some("arm64".to_string()),
+ json: true,
+ })
+ .expect_err("empty package file rejected");
+
+ assert!(format!("{error:#}").contains("package list"), "{error:#}");
+ }
+
+ #[test]
+ fn profile_check_rejects_profile_root_manifest_escape_paths() {
+ let temp = tempfile::tempdir().expect("tempdir");
+ let config_root = temp.path().join("config");
+ let profile_dir = config_root.join("profiles/code");
+ fs::create_dir_all(&profile_dir).expect("profile dir");
+ let root_manifest = r#"{
+ "format": "capsem.profile-root.v1",
+ "files": [
+ {
+ "path": "../outside",
+ "hash": "blake3:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "size": 1
+ }
+ ]
+}
+"#;
+ fs::write(profile_dir.join("root.manifest.json"), root_manifest).expect("root manifest");
+ let mut profile = ProfileConfigFile::builtin_primary();
+ profile.rule_files.enforcement = None;
+ profile.rule_files.sigma = None;
+ profile.assets.arch.retain(|arch, _| arch == "arm64");
+ profile.files = Default::default();
+ profile.files.root_manifest =
+ Some(capsem_core::net::policy_config::ProfileFileDescriptor {
+ path: "profiles/code/root.manifest.json".to_string(),
+ hash: None,
+ size: None,
+ });
+ let profile_path = profile_dir.join("profile.toml");
+ fs::write(&profile_path, toml::to_string(&profile).unwrap()).expect("profile");
+
+ let error = check_profile(&ProfileCheckArgs {
+ path: profile_path,
+ config_root: Some(config_root),
+ arch: Some("arm64".to_string()),
+ json: true,
+ })
+ .expect_err("root manifest escape rejected");
+
+ assert!(
+ error.to_string().contains("profile root manifest file"),
+ "{error:#}"
+ );
+ }
+
+ #[test]
+ fn profile_check_rejects_unpinned_profile_root_payload_files() {
+ let temp = tempfile::tempdir().expect("tempdir");
+ let config_root = temp.path().join("config");
+ let profile_dir = config_root.join("profiles/code");
+ let profile_root = profile_dir.join("root");
+ fs::create_dir_all(profile_root.join("root/.codex")).expect("profile root");
+ fs::create_dir_all(profile_root.join("root/.antigravity")).expect("agy root");
+ let codex_payload = b"[mcp_servers.capsem]\ncommand = \"/run/capsem-mcp-server\"\n";
+ fs::write(profile_root.join("root/.codex/config.toml"), codex_payload)
+ .expect("codex config");
+ fs::write(
+ profile_root.join("root/.antigravity/antigravity-oauth-token"),
+ b"secret",
+ )
+ .expect("unlisted token");
+ let root_manifest = format!(
+ r#"{{
+ "format": "capsem.profile-root.v1",
+ "files": [
+ {{
+ "path": "root/.codex/config.toml",
+ "hash": "blake3:{}",
+ "size": {}
+ }}
+ ]
+}}
+"#,
+ blake3::hash(codex_payload).to_hex(),
+ codex_payload.len()
+ );
+ fs::write(profile_dir.join("root.manifest.json"), root_manifest).expect("root manifest");
+ let mut profile = ProfileConfigFile::builtin_primary();
+ profile.rule_files.enforcement = None;
+ profile.rule_files.sigma = None;
+ profile.assets.arch.retain(|arch, _| arch == "arm64");
+ profile.files = Default::default();
+ profile.files.root_manifest =
+ Some(capsem_core::net::policy_config::ProfileFileDescriptor {
+ path: "profiles/code/root.manifest.json".to_string(),
+ hash: None,
+ size: None,
+ });
+ let profile_path = profile_dir.join("profile.toml");
+ fs::write(&profile_path, toml::to_string(&profile).unwrap()).expect("profile");
+
+ let error = check_profile(&ProfileCheckArgs {
+ path: profile_path,
+ config_root: Some(config_root),
+ arch: Some("arm64".to_string()),
+ json: true,
+ })
+ .expect_err("unlisted profile root payload rejected");
+
+ assert!(
+ format!("{error:#}").contains("unlisted profile root payload file"),
+ "{error:#}"
+ );
+ }
+
+ #[test]
+ fn image_verify_rejects_profile_manifest_pin_drift() {
+ let temp = tempfile::tempdir().expect("tempdir");
+ let output = temp.path().join("assets");
+ let arch_dir = output.join("arm64");
+ fs::create_dir_all(&arch_dir).expect("asset dir");
+ let kernel = b"kernel";
+ let initrd = b"initrd";
+ let rootfs = b"rootfs";
+ fs::write(arch_dir.join("vmlinuz"), kernel).expect("kernel");
+ fs::write(arch_dir.join("initrd.img"), initrd).expect("initrd");
+ fs::write(arch_dir.join("rootfs.erofs"), rootfs).expect("rootfs");
+ let kernel_hash = blake3::hash(kernel).to_hex().to_string();
+ let rootfs_hash = blake3::hash(rootfs).to_hex().to_string();
+ let wrong_initrd_hash = "1111111111111111111111111111111111111111111111111111111111111111";
+ fs::write(
+ output.join("manifest.json"),
+ format!(
+ r#"{{
+ "format": 2,
+ "refresh_policy": "24h",
+ "assets": {{
+ "current": "2030.0101.1",
+ "releases": {{
+ "2030.0101.1": {{
+ "date": "2030-01-01",
+ "deprecated": false,
+ "min_binary": "1.0.0",
+ "arches": {{
+ "arm64": {{
+ "vmlinuz": {{"hash": "{kernel_hash}", "size": {kernel_size}}},
+ "initrd.img": {{"hash": "{wrong_initrd_hash}", "size": {initrd_size}}},
+ "rootfs.erofs": {{"hash": "{rootfs_hash}", "size": {rootfs_size}}}
+ }}
+ }}
+ }}
+ }}
+ }},
+ "binaries": {{
+ "current": "1.0.0",
+ "releases": {{"1.0.0": {{"date": "2030-01-01", "deprecated": false, "min_assets": "2030.0101.1"}}}}
+ }}
+}}"#,
+ kernel_size = kernel.len(),
+ initrd_size = initrd.len(),
+ rootfs_size = rootfs.len(),
+ ),
+ )
+ .expect("manifest");
+
+ let mut profile = ProfileConfigFile::builtin_primary();
+ profile.rule_files.enforcement = None;
+ profile.rule_files.sigma = None;
+ profile.assets.arch.retain(|arch, _| arch == "arm64");
+ let profile_path = temp.path().join("profile.toml");
+ fs::write(
+ &profile_path,
+ toml::to_string(&profile).expect("serialize profile"),
+ )
+ .expect("profile");
+
+ let error = verify_image_outputs(&ImageVerifyArgs {
+ profile: profile_path,
+ config_root: temp.path().to_path_buf(),
+ output,
+ manifest: None,
+ arch: Some("arm64".to_string()),
+ })
+ .expect_err("manifest/output drift rejected");
+
+ assert!(
+ format!("{error:#}").contains("image output verify failed"),
+ "{error:#}"
+ );
+ }
+
+ #[test]
+ fn image_build_requires_profile_argument() {
+ let error = Cli::try_parse_from(["capsem-admin", "image", "build"])
+ .expect_err("profile is required");
+
+ assert!(error.to_string().contains("--profile"), "{error}");
+ }
+
+ #[test]
+ fn image_build_rejects_dry_run_escape_hatch() {
+ let error = Cli::try_parse_from([
+ "capsem-admin",
+ "image",
+ "build",
+ "--profile",
+ "config/profiles/code/profile.toml",
+ "--dry-run",
+ ])
+ .expect_err("dry-run is not a public product rail");
+
+ assert!(
+ error
+ .to_string()
+ .contains("unexpected argument '--dry-run'"),
+ "{error}"
+ );
+ }
+
+ #[test]
+ fn removed_admin_authoring_commands_are_not_parseable() {
+ for argv in [
+ ["capsem-admin", "profile", "init"],
+ ["capsem-admin", "settings", "init"],
+ ["capsem-admin", "enforcement", "compile"],
+ ["capsem-admin", "detection", "compile"],
+ ["capsem-admin", "manifest", "verify"],
+ ["capsem-admin", "image", "plan"],
+ ["capsem-admin", "image", "workspace"],
+ ["capsem-admin", "image", "verify"],
+ ] {
+ let error = Cli::try_parse_from(argv).expect_err("removed command rejected");
+ assert!(
+ error.to_string().contains("unrecognized subcommand"),
+ "{error}"
+ );
+ }
+ }
+
+ #[test]
+ fn image_plan_is_profile_derived_and_uses_erofs_lz4hc() {
+ let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+ let repo_root = manifest_dir
+ .parent()
+ .and_then(Path::parent)
+ .expect("repo root");
+ let args = ImageBuildArgs {
+ profile: repo_root.join("config/profiles/code/profile.toml"),
+ config_root: repo_root.join("config"),
+ guest_dir: repo_root.join("guest"),
+ output: repo_root.join("assets"),
+ arch: Some("arm64".to_string()),
+ template: ImageBuildTemplate::All,
+ clean: true,
+ json: true,
+ };
+
+ let plan = image_build_plan(&args).expect("image plan");
+
+ assert_eq!(plan.profile_id, "code");
+ assert_eq!(plan.arches.len(), 1);
+ assert_eq!(plan.arches[0].arch, "arm64");
+ assert_eq!(plan.arches[0].rootfs, "rootfs.erofs");
+ assert_eq!(plan.commands.len(), 3);
+ assert_eq!(plan.commands[0].step, "kernel");
+ assert_eq!(
+ plan.commands[0].argv[0..5]
+ .iter()
+ .map(String::as_str)
+ .collect::>(),
+ vec![
+ "uv",
+ "run",
+ "python",
+ "-m",
+ "capsem.builder.image_build_backend",
+ ]
+ );
+ assert!(!plan.commands[0]
+ .argv
+ .windows(2)
+ .any(|window| window[0] == "capsem-builder" && window[1] == "build"));
+ assert_eq!(plan.commands[1].step, "rootfs");
+ assert_eq!(
+ plan.commands[1].argv[0..5]
+ .iter()
+ .map(String::as_str)
+ .collect::>(),
+ vec![
+ "uv",
+ "run",
+ "python",
+ "-m",
+ "capsem.builder.image_build_backend",
+ ]
+ );
+ assert!(!plan.commands[1]
+ .argv
+ .windows(2)
+ .any(|window| window[0] == "capsem-builder" && window[1] == "build"));
+ assert_eq!(
+ plan.commands[1].env.get("CAPSEM_BUILD_EROFS_COMPRESSION"),
+ Some(&"lz4hc".to_string())
+ );
+ assert_eq!(
+ plan.commands[1]
+ .env
+ .get("CAPSEM_BUILD_EROFS_COMPRESSION_LEVEL"),
+ Some(&"12".to_string())
+ );
+ assert_eq!(plan.commands[2].step, "manifest");
+ }
+
+ #[test]
+ fn image_clean_rootfs_preserves_kernel_and_initrd() {
+ let temp = tempfile::tempdir().expect("tempdir");
+ let arch_dir = temp.path().join("arm64");
+ fs::create_dir_all(&arch_dir).expect("arch dir");
+ fs::write(arch_dir.join("vmlinuz"), b"kernel").expect("kernel");
+ fs::write(arch_dir.join("initrd.img"), b"initrd").expect("initrd");
+ fs::write(arch_dir.join("rootfs.erofs"), b"rootfs").expect("rootfs");
+ fs::write(arch_dir.join("obom.cdx.json"), b"obom").expect("obom");
+
+ clean_image_outputs(&ImageBuildPlan {
+ schema: "test",
+ profile_id: "code".to_string(),
+ profile_revision: "test".to_string(),
+ guest_dir: "guest".to_string(),
+ output: temp.path().display().to_string(),
+ clean: true,
+ template: "rootfs",
+ arches: vec![ImageBuildArchPlan {
+ arch: "arm64".to_string(),
+ kernel: "vmlinuz".to_string(),
+ initrd: "initrd.img".to_string(),
+ rootfs: "rootfs.erofs".to_string(),
+ }],
+ commands: Vec::new(),
+ })
+ .expect("rootfs clean");
+
+ assert!(arch_dir.join("vmlinuz").is_file());
+ assert!(arch_dir.join("initrd.img").is_file());
+ assert!(!arch_dir.join("rootfs.erofs").exists());
+ assert!(!arch_dir.join("obom.cdx.json").exists());
+ }
+
+ #[test]
+ fn image_clean_kernel_preserves_rootfs() {
+ let temp = tempfile::tempdir().expect("tempdir");
+ let arch_dir = temp.path().join("arm64");
+ fs::create_dir_all(&arch_dir).expect("arch dir");
+ fs::write(arch_dir.join("vmlinuz"), b"kernel").expect("kernel");
+ fs::write(arch_dir.join("initrd.img"), b"initrd").expect("initrd");
+ fs::write(arch_dir.join("rootfs.erofs"), b"rootfs").expect("rootfs");
+
+ clean_image_outputs(&ImageBuildPlan {
+ schema: "test",
+ profile_id: "code".to_string(),
+ profile_revision: "test".to_string(),
+ guest_dir: "guest".to_string(),
+ output: temp.path().display().to_string(),
+ clean: true,
+ template: "kernel",
+ arches: vec![ImageBuildArchPlan {
+ arch: "arm64".to_string(),
+ kernel: "vmlinuz".to_string(),
+ initrd: "initrd.img".to_string(),
+ rootfs: "rootfs.erofs".to_string(),
+ }],
+ commands: Vec::new(),
+ })
+ .expect("kernel clean");
+
+ assert!(!arch_dir.join("vmlinuz").exists());
+ assert!(!arch_dir.join("initrd.img").exists());
+ assert!(arch_dir.join("rootfs.erofs").is_file());
+ }
+
+ #[test]
+ fn image_plan_rejects_arch_missing_from_profile() {
+ let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+ let repo_root = manifest_dir
+ .parent()
+ .and_then(Path::parent)
+ .expect("repo root");
+ let args = ImageBuildArgs {
+ profile: repo_root.join("config/profiles/code/profile.toml"),
+ config_root: repo_root.join("config"),
+ guest_dir: repo_root.join("guest"),
+ output: repo_root.join("assets"),
+ arch: Some("riscv64".to_string()),
+ template: ImageBuildTemplate::All,
+ clean: false,
+ json: false,
+ };
+
+ let error = image_build_plan(&args).expect_err("unknown arch rejected");
+
+ assert!(
+ error
+ .to_string()
+ .contains("does not define assets for arch riscv64"),
+ "{error:#}"
+ );
+ }
+
+ #[test]
+ fn image_workspace_materializes_self_contained_profile_config() {
+ let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+ let repo_root = manifest_dir
+ .parent()
+ .and_then(Path::parent)
+ .expect("repo root");
+ let temp = tempfile::tempdir().expect("tempdir");
+ let args = ImageWorkspaceArgs {
+ profile: repo_root.join("config/profiles/code/profile.toml"),
+ config_root: repo_root.join("config"),
+ guest_dir: repo_root.join("guest"),
+ output: temp.path().join("workspace"),
+ arch: Some("arm64".to_string()),
+ json: true,
+ };
+
+ let report = materialize_image_workspace(&args).expect("workspace");
+
+ assert_eq!(report.profile_id, "code");
+ assert_eq!(report.arches.len(), 1);
+ assert_eq!(report.arches[0].arch, "arm64");
+ assert_eq!(report.rule_files.len(), 2);
+ let workspace_profile = args.output.join("config/profiles/code/profile.toml");
+ assert!(workspace_profile.is_file());
+ assert!(args
+ .output
+ .join("config/profiles/code/enforcement.toml")
+ .is_file());
+ assert!(args
+ .output
+ .join("config/profiles/code/detection.yaml")
+ .is_file());
+ assert!(args.output.join("build-plan.json").is_file());
+ assert!(args.output.join("workspace.json").is_file());
+ let generated_config = args.output.join("guest").join("config");
+ assert!(generated_config.join("packages/apt.toml").is_file());
+ let apt_packages = fs::read_to_string(generated_config.join("packages/apt.toml"))
+ .expect("materialized apt packages");
+ assert!(
+ apt_packages.contains("\"zstd\""),
+ "Ollama's official installer consumes .tar.zst payloads, so shipped profiles must include zstd"
+ );
+ assert!(generated_config.join("packages/python.toml").is_file());
+ assert!(generated_config.join("packages/npm.toml").is_file());
+ let resources = fs::read_to_string(generated_config.join("vm/resources.toml"))
+ .expect("materialized VM resources");
+ assert!(resources.contains("ram_gb = 12"));
+ assert!(resources.contains("scratch_disk_size_gb = 64"));
+ assert!(args.output.join("guest/profile-build.sh").is_file());
+ let profile_build = fs::read_to_string(args.output.join("guest/profile-build.sh"))
+ .expect("materialized profile build script");
+ assert!(profile_build.contains("https://ollama.com/install.sh"));
+ assert!(args
+ .output
+ .join("guest/profile-root/root/.codex/config.toml")
+ .is_file());
+ assert!(args.output.join("guest/artifacts/tips.txt").is_file());
+ let build_plan: serde_json::Value =
+ serde_json::from_slice(&fs::read(args.output.join("build-plan.json")).unwrap())
+ .unwrap();
+ assert!(build_plan["commands"]
+ .as_array()
+ .unwrap()
+ .iter()
+ .any(|command| command["argv"]
+ .as_array()
+ .unwrap()
+ .iter()
+ .any(|arg| arg == args.output.join("guest").display().to_string().as_str())));
+
+ let copied = check_profile(&ProfileCheckArgs {
+ path: workspace_profile,
+ config_root: Some(args.output.join("config")),
+ arch: None,
+ json: true,
+ })
+ .expect("copied workspace profile validates and owns every pinned payload");
+ assert_eq!(copied.validation.profile_id, "code");
+ assert!(copied.profile_files.iter().all(|file| file.present));
+ }
+
+ #[test]
+ fn profile_materialize_writes_generated_config_from_manifest() {
+ let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+ let repo_root = manifest_dir
+ .parent()
+ .and_then(Path::parent)
+ .expect("repo root");
+ let temp = tempfile::tempdir().expect("tempdir");
+ let assets_dir = temp.path().join("assets");
+ let manifest_path = write_test_assets_manifest(temp.path(), "arm64");
+ let output_root = temp.path().join("target/config");
+ let source_profile = repo_root.join("config/profiles/code/profile.toml");
+ let original_source = fs::read_to_string(&source_profile).expect("read source profile");
+
+ let report = materialize_profile_config(&ProfileMaterializeArgs {
+ profile: source_profile.clone(),
+ config_root: repo_root.join("config"),
+ manifest: manifest_path,
+ assets_dir: assets_dir.clone(),
+ output_root: output_root.clone(),
+ arch: Some("arm64".to_string()),
+ clean: true,
+ json: true,
+ })
+ .expect("materialize profile config");
+
+ assert_eq!(report.profile_id, "code");
+ assert_eq!(report.materialized_assets.len(), 3);
+ assert_eq!(report.materialized_obom.len(), 1);
+ assert!(output_root.join("settings/settings.toml").is_file());
+ assert!(output_root.join("corp/corp.toml").is_file());
+ assert!(output_root.join("assets/manifest.json").is_file());
+ assert!(output_root.join("profiles/code/enforcement.toml").is_file());
+ assert!(output_root.join("profiles/code/detection.yaml").is_file());
+
+ let generated_profile_path = output_root.join("profiles/code/profile.toml");
+ let generated: ProfileConfigFile =
+ toml::from_str(&fs::read_to_string(&generated_profile_path).expect("read generated"))
+ .expect("parse generated profile");
+ let arm64 = generated.assets.arch.get("arm64").expect("arm64 assets");
+ assert!(arm64.kernel.url.starts_with("file://"));
+ assert!(arm64.initrd.url.starts_with("file://"));
+ assert!(arm64.rootfs.url.starts_with("file://"));
+ assert_eq!(
+ arm64.kernel.hash,
+ Some(format!("blake3:{}", blake3::hash(b"kernel-arm64").to_hex()))
+ );
+ assert_eq!(arm64.initrd.size, Some(b"initrd-arm64".len() as u64));
+ assert_eq!(arm64.rootfs.name, "rootfs.erofs");
+ assert!(generated
+ .files
+ .iter()
+ .all(|(_, descriptor)| descriptor.hash.is_some() && descriptor.size.is_some()));
+ let obom = generated
+ .obom
+ .as_ref()
+ .expect("materialized profile has base-image OBOM")
+ .arch
+ .get("arm64")
+ .expect("arm64 OBOM");
+ assert!(obom.url.starts_with("file://"));
+ assert_eq!(
+ obom.hash,
+ format!(
+ "blake3:{}",
+ blake3::hash(test_obom_json().as_bytes()).to_hex()
+ )
+ );
+ assert_eq!(obom.generator, "cdxgen");
+ assert_eq!(obom.generator_version, "11.0.0");
+
+ let validation = validate_materialized_profile(&generated_profile_path, Some(&output_root))
+ .expect("valid materialized output");
+ assert_eq!(validation.profile_id, "code");
+ assert_eq!(
+ fs::read_to_string(source_profile).expect("read source profile after"),
+ original_source,
+ "materialization must not mutate checked-in source profile"
+ );
+ }
+
+ #[test]
+ fn profile_materialize_preserves_previous_profiles_in_same_output_catalog() {
+ let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+ let repo_root = manifest_dir
+ .parent()
+ .and_then(Path::parent)
+ .expect("repo root");
+ let temp = tempfile::tempdir().expect("tempdir");
+ let assets_dir = temp.path().join("assets");
+ let manifest_path = write_test_assets_manifest(temp.path(), "arm64");
+ let output_root = temp.path().join("target/config");
+ let config_root = repo_root.join("config");
+
+ materialize_profile_config(&ProfileMaterializeArgs {
+ profile: config_root.join("profiles/co-work/profile.toml"),
+ config_root: config_root.clone(),
+ manifest: manifest_path.clone(),
+ assets_dir: assets_dir.clone(),
+ output_root: output_root.clone(),
+ arch: Some("arm64".to_string()),
+ clean: true,
+ json: true,
+ })
+ .expect("materialize co-work");
+
+ materialize_profile_config(&ProfileMaterializeArgs {
+ profile: config_root.join("profiles/code/profile.toml"),
+ config_root,
+ manifest: manifest_path,
+ assets_dir,
+ output_root: output_root.clone(),
+ arch: Some("arm64".to_string()),
+ clean: false,
+ json: true,
+ })
+ .expect("materialize code");
+
+ for profile_id in ["co-work", "code"] {
+ let generated_profile_path = output_root
+ .join("profiles")
+ .join(profile_id)
+ .join("profile.toml");
+ let generated: ProfileConfigFile = toml::from_str(
+ &fs::read_to_string(&generated_profile_path).expect("read generated profile"),
+ )
+ .expect("generated profile parses");
+ let arm64 = generated.assets.arch.get("arm64").expect("arm64 assets");
+ assert_eq!(
+ arm64.kernel.hash,
+ Some(format!("blake3:{}", blake3::hash(b"kernel-arm64").to_hex())),
+ "{profile_id} kernel pin must remain generated"
+ );
+ assert_eq!(
+ arm64.initrd.hash,
+ Some(format!("blake3:{}", blake3::hash(b"initrd-arm64").to_hex())),
+ "{profile_id} initrd pin must remain generated"
+ );
+ assert_eq!(
+ arm64.rootfs.hash,
+ Some(format!("blake3:{}", blake3::hash(b"rootfs-arm64").to_hex())),
+ "{profile_id} rootfs pin must remain generated"
+ );
+ assert!(arm64.kernel.url.starts_with("file://"));
+ assert!(arm64.initrd.url.starts_with("file://"));
+ assert!(arm64.rootfs.url.starts_with("file://"));
+ }
+ }
+
+ #[test]
+ fn profile_materialize_rejects_arch_missing_from_manifest() {
+ let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+ let repo_root = manifest_dir
+ .parent()
+ .and_then(Path::parent)
+ .expect("repo root");
+ let temp = tempfile::tempdir().expect("tempdir");
+ let manifest_path = write_test_assets_manifest(temp.path(), "arm64");
+
+ let error = materialize_profile_config(&ProfileMaterializeArgs {
+ profile: repo_root.join("config/profiles/code/profile.toml"),
+ config_root: repo_root.join("config"),
+ manifest: manifest_path,
+ assets_dir: temp.path().join("assets"),
+ output_root: temp.path().join("target/config"),
+ arch: Some("x86_64".to_string()),
+ clean: true,
+ json: false,
+ })
+ .expect_err("missing manifest arch rejected");
+
+ assert!(
+ format!("{error:#}").contains("does not contain profile arch x86_64"),
+ "{error:#}"
+ );
+ }
+
+ fn minimal_manifest_json(hash: Option<&str>, include_refresh_policy: bool) -> String {
+ let hash =
+ hash.unwrap_or("1111111111111111111111111111111111111111111111111111111111111111");
+ format!(
+ r#"{{
+ "format": 2,
+ {refresh}
+ "assets": {{
+ "current": "2026.0607.1",
+ "releases": {{
+ "2026.0607.1": {{
+ "arches": {{
+ "arm64": {{
+ "rootfs.erofs": {{
+ "hash": "{hash}",
+ "size": 17
+ }}
+ }}
+ }}
+ }}
+ }}
+ }},
+ "binaries": {{
+ "current": "1.0.0",
+ "releases": {{
+ "1.0.0": {{
+ "min_assets": "2026.0607.1"
+ }}
+ }}
+ }}
+}}"#,
+ refresh = if include_refresh_policy {
+ r#""refresh_policy": "24h","#
+ } else {
+ ""
+ },
+ hash = hash,
+ )
+ }
+
+ fn write_test_assets_manifest(root: &Path, arch: &str) -> PathBuf {
+ let assets_dir = root.join("assets").join(arch);
+ fs::create_dir_all(&assets_dir).expect("assets dir");
+ let kernel = format!("kernel-{arch}");
+ let initrd = format!("initrd-{arch}");
+ let rootfs = format!("rootfs-{arch}");
+ let obom = test_obom_json();
+ fs::write(assets_dir.join("vmlinuz"), kernel.as_bytes()).expect("kernel");
+ fs::write(assets_dir.join("initrd.img"), initrd.as_bytes()).expect("initrd");
+ fs::write(assets_dir.join("rootfs.erofs"), rootfs.as_bytes()).expect("rootfs");
+ fs::write(assets_dir.join("obom.cdx.json"), obom.as_bytes()).expect("obom");
+ let manifest_path = root.join("assets/manifest.json");
+ fs::write(
+ &manifest_path,
+ format!(
+ r#"{{
+ "format": 2,
+ "refresh_policy": "24h",
+ "assets": {{
+ "current": "2030.0101.1",
+ "releases": {{
+ "2030.0101.1": {{
+ "date": "2030-01-01",
+ "deprecated": false,
+ "min_binary": "1.0.0",
+ "arches": {{
+ "{arch}": {{
+ "vmlinuz": {{"hash": "{kernel_hash}", "size": {kernel_size}}},
+ "initrd.img": {{"hash": "{initrd_hash}", "size": {initrd_size}}},
+ "rootfs.erofs": {{"hash": "{rootfs_hash}", "size": {rootfs_size}}},
+ "obom.cdx.json": {{"hash": "{obom_hash}", "size": {obom_size}}}
+ }}
+ }}
+ }}
+ }}
+ }},
+ "binaries": {{
+ "current": "1.0.0",
+ "releases": {{"1.0.0": {{"date": "2030-01-01", "deprecated": false, "min_assets": "2030.0101.1"}}}}
+ }}
+}}"#,
+ arch = arch,
+ kernel_hash = blake3::hash(kernel.as_bytes()).to_hex(),
+ kernel_size = kernel.len(),
+ initrd_hash = blake3::hash(initrd.as_bytes()).to_hex(),
+ initrd_size = initrd.len(),
+ rootfs_hash = blake3::hash(rootfs.as_bytes()).to_hex(),
+ rootfs_size = rootfs.len(),
+ obom_hash = blake3::hash(obom.as_bytes()).to_hex(),
+ obom_size = obom.len(),
+ ),
+ )
+ .expect("manifest");
+ manifest_path
+ }
+
+ fn test_obom_json() -> String {
+ serde_json::json!({
+ "bomFormat": "CycloneDX",
+ "specVersion": "1.6",
+ "metadata": {
+ "tools": {
+ "components": [
+ {"name": "cdxgen", "version": "11.0.0", "type": "application"}
+ ]
+ },
+ "component": {
+ "name": "capsem-code-rootfs",
+ "type": "operating-system"
+ }
+ },
+ "components": [
+ {"name": "bash", "version": "5.2", "type": "library"}
+ ]
+ })
+ .to_string()
+ }
+}
+#[cfg(test)]
+#[derive(Debug)]
+struct ImageVerifyArgs {
+ profile: PathBuf,
+ config_root: PathBuf,
+ output: PathBuf,
+ manifest: Option,
+ arch: Option,
+}
diff --git a/crates/capsem-agent/src/bin/capsem_sysutil.rs b/crates/capsem-agent/src/bin/capsem_sysutil.rs
index 53bb898e3..860934e8f 100644
--- a/crates/capsem-agent/src/bin/capsem_sysutil.rs
+++ b/crates/capsem-agent/src/bin/capsem_sysutil.rs
@@ -1,10 +1,14 @@
-// capsem-sysutil: Guest system utility for host-owned VM lifecycle commands.
+// capsem-sysutil: Multi-call guest system binary for VM lifecycle commands.
//
// Dispatches on argv[0] (busybox pattern). Symlinked at boot by capsem-init:
+// /sbin/shutdown -> /run/capsem-sysutil
+// /sbin/halt -> /run/capsem-sysutil
+// /sbin/poweroff -> /run/capsem-sysutil
+// /sbin/reboot -> /run/capsem-sysutil
// /usr/local/bin/suspend -> /run/capsem-sysutil
//
// Opens its own vsock:5004 connection directly (independent of capsem-pty-agent).
-// This means suspend works even if the agent is hung.
+// This means shutdown works even if the agent is hung.
#[path = "../vsock_io.rs"]
mod vsock_io;
@@ -59,23 +63,14 @@ fn is_reboot_request(cmd: &str, args: &[String]) -> bool {
cmd == "shutdown" && args.iter().any(|a| a == "-r")
}
-fn is_shutdown_command(cmd: &str) -> bool {
- matches!(cmd, "shutdown" | "halt" | "poweroff")
-}
-
-fn print_shutdown_removed() {
- eprintln!(
- "[capsem] in-VM shutdown is disabled; use host controls: capsem stop, capsem delete, or the TUI"
- );
-}
-
fn print_help(cmd: &str) {
println!("Usage: {cmd} [OPTIONS]");
println!("Capsem sandbox lifecycle command.");
println!();
match cmd {
"shutdown" | "halt" | "poweroff" => {
- println!("Disabled: use host controls instead.");
+ println!("Stops the sandbox cleanly through the host service.");
+ println!("Accepted flags: -h, -P (default behavior), -r (error: reboot not supported)");
}
"suspend" => {
println!("Suspends the sandbox (persistent VMs only).");
@@ -85,7 +80,7 @@ fn print_help(cmd: &str) {
println!("Reboot is not supported in capsem sandbox.");
}
_ => {
- println!("Commands: suspend");
+ println!("Commands: shutdown, halt, poweroff, reboot, suspend");
}
}
}
@@ -104,13 +99,16 @@ fn main() {
}
match cmd {
- cmd if is_shutdown_command(cmd) => {
+ "shutdown" | "halt" | "poweroff" => {
if is_reboot_request(cmd, &args[1..]) {
eprintln!("[capsem] reboot is not supported in capsem sandbox");
process::exit(1);
}
- print_shutdown_removed();
- process::exit(1);
+ countdown("Shutting down");
+ if let Err(e) = send_lifecycle_msg(&GuestToHost::ShutdownRequest) {
+ eprintln!("[capsem] failed to send shutdown request: {e}");
+ process::exit(1);
+ }
}
"reboot" => {
eprintln!("[capsem] reboot is not supported in capsem sandbox");
@@ -127,9 +125,12 @@ fn main() {
// Direct invocation as capsem-sysutil
if args.len() > 1 {
match args[1].as_str() {
- cmd if is_shutdown_command(cmd) => {
- print_shutdown_removed();
- process::exit(1);
+ "shutdown" | "halt" | "poweroff" => {
+ countdown("Shutting down");
+ if let Err(e) = send_lifecycle_msg(&GuestToHost::ShutdownRequest) {
+ eprintln!("[capsem] failed to send shutdown request: {e}");
+ process::exit(1);
+ }
}
"suspend" => {
countdown("Suspending");
@@ -148,7 +149,7 @@ fn main() {
}
other => {
eprintln!("[capsem] unknown command: {other}");
- eprintln!("Available: suspend");
+ eprintln!("Available: shutdown, halt, poweroff, reboot, suspend");
process::exit(1);
}
}
@@ -190,14 +191,6 @@ mod tests {
assert!(!is_reboot_request("poweroff", &["-r".into()]));
}
- #[test]
- fn shutdown_commands_are_disabled() {
- assert!(is_shutdown_command("shutdown"));
- assert!(is_shutdown_command("halt"));
- assert!(is_shutdown_command("poweroff"));
- assert!(!is_shutdown_command("suspend"));
- }
-
#[test]
fn command_name_handles_empty_string() {
assert_eq!(command_name(""), "");
diff --git a/crates/capsem-agent/src/main.rs b/crates/capsem-agent/src/main.rs
index ff2f7f90f..fcbf7a887 100644
--- a/crates/capsem-agent/src/main.rs
+++ b/crates/capsem-agent/src/main.rs
@@ -21,7 +21,6 @@ use capsem_proto::{
MAX_BOOT_ENV_VARS, MAX_BOOT_FILES, MAX_BOOT_FILE_BYTES, MAX_FRAME_SIZE, SHUTDOWN_GRACE_SECS,
VSOCK_PORT_AUDIT, VSOCK_PORT_CONTROL, VSOCK_PORT_EXEC, VSOCK_PORT_TERMINAL,
};
-use nix::fcntl::{fcntl, FcntlArg, OFlag};
use nix::libc;
use nix::poll::{poll, PollFd, PollFlags, PollTimeout};
use nix::pty::openpty;
@@ -33,7 +32,6 @@ use vsock_io::{read_exact_fd, vsock_connect, vsock_connect_retry, write_all_fd,
const BOOT_LOG_PATH: &str = "/var/log/capsem-boot.log";
/// Reconnect timeout before giving up (seconds).
const RECONNECT_TIMEOUT_SECS: u64 = 30;
-const SNAPSHOT_RECONNECT_DELAY: std::time::Duration = std::time::Duration::from_secs(2);
// ---------------------------------------------------------------------------
// Control message framing (using capsem-proto types)
@@ -369,7 +367,7 @@ fn main() {
// Step 4b: Activate Python venv if capsem-init created one.
// capsem-init creates the venv in the background and touches a ready flag when done.
// Wait briefly for it to finish before checking.
- const VENV_DIR: &str = "/var/lib/capsem/venv";
+ const VENV_DIR: &str = "/root/.venv";
const VENV_READY: &str = "/run/capsem-venv-ready";
let venv_activate = std::path::Path::new(VENV_DIR).join("bin/activate");
if !venv_activate.exists() && !std::path::Path::new(VENV_READY).exists() {
@@ -384,10 +382,7 @@ fn main() {
boot_env.push(("VIRTUAL_ENV".into(), VENV_DIR.into()));
// Prepend venv bin to PATH if PATH exists in boot_env.
if let Some((_, path_val)) = boot_env.iter_mut().find(|(k, _)| k == "PATH") {
- let venv_bin = format!("{VENV_DIR}/bin");
- if !path_val.split(':').any(|entry| entry == venv_bin) {
- *path_val = format!("{venv_bin}:{path_val}");
- }
+ *path_val = format!("{VENV_DIR}/bin:{path_val}");
}
blog_line(&mut blog, "venv activated in boot_env");
} else {
@@ -860,7 +855,6 @@ fn run_bridge(
thread::spawn(move || {
control_loop(
control_fd,
- terminal_fd,
master_fd,
child_pid,
&boot_env_owned,
@@ -884,116 +878,60 @@ fn run_bridge(
eprintln!("[capsem-agent] bridge exited");
}
-const BRIDGE_BUF_CAP: usize = 1024 * 1024;
-
-fn set_fd_nonblocking(fd: RawFd) -> io::Result<()> {
- let flags = fcntl(fd, FcntlArg::F_GETFL).map_err(io::Error::from)?;
- let mut flags = OFlag::from_bits_truncate(flags);
- flags.insert(OFlag::O_NONBLOCK);
- fcntl(fd, FcntlArg::F_SETFL(flags))
- .map(|_| ())
- .map_err(io::Error::from)
-}
-
-fn read_bridge_chunk(
- fd: RawFd,
- buffer: &mut std::collections::VecDeque,
- scratch: &mut [u8],
-) -> io::Result {
- let available = BRIDGE_BUF_CAP.saturating_sub(buffer.len());
- if available == 0 {
- return Ok(true);
- }
-
- let read_len = available.min(scratch.len());
- match nix::unistd::read(fd, &mut scratch[..read_len]) {
- Ok(0) => Ok(false),
- Ok(n) => {
- buffer.extend(&scratch[..n]);
- Ok(true)
- }
- Err(nix::errno::Errno::EAGAIN) | Err(nix::errno::Errno::EINTR) => Ok(true),
- Err(e) => Err(e.into()),
- }
-}
-
-fn write_bridge_buffer(fd: RawFd, buffer: &mut std::collections::VecDeque) -> io::Result<()> {
- while !buffer.is_empty() {
- let (front, _) = buffer.as_slices();
- if front.is_empty() {
- break;
- }
+fn bridge_loop(master_fd: RawFd, vsock_fd: RawFd) {
+ let mut buf = [0u8; 8192];
- match nix::unistd::write(
- unsafe { std::os::unix::io::BorrowedFd::borrow_raw(fd) },
- front,
- ) {
- Ok(0) => {
- return Err(io::Error::new(
- io::ErrorKind::WriteZero,
- "bridge write returned 0 bytes",
- ));
+ // Spawn a dedicated thread for vsock -> Master PTY (stdin direction)
+ // This prevents deadlocks when both master_fd and vsock_fd buffers are full.
+ let master_fd_clone = master_fd;
+ let vsock_fd_clone = vsock_fd;
+ std::thread::spawn(move || {
+ let mut local_buf = [0u8; 8192];
+ loop {
+ let mut poll_fds = [PollFd::new(
+ unsafe { std::os::unix::io::BorrowedFd::borrow_raw(vsock_fd_clone) },
+ PollFlags::POLLIN,
+ )];
+
+ match poll(&mut poll_fds, PollTimeout::from(1000u16)) {
+ Ok(0) => continue,
+ Ok(_) => {}
+ Err(nix::errno::Errno::EINTR) => continue,
+ Err(_) => break,
}
- Ok(n) => {
- drop(buffer.drain(..n));
+
+ if let Some(revents) = poll_fds[0].revents() {
+ if revents.contains(PollFlags::POLLIN) {
+ match nix::unistd::read(vsock_fd_clone, &mut local_buf) {
+ Ok(0) => break,
+ Ok(n) => {
+ if write_all_fd(master_fd_clone, &local_buf[..n]).is_err() {
+ break;
+ }
+ }
+ Err(nix::errno::Errno::EAGAIN) => {}
+ Err(_) => break,
+ }
+ }
+ if revents.intersects(PollFlags::POLLHUP | PollFlags::POLLERR) {
+ break;
+ }
}
- Err(nix::errno::Errno::EAGAIN) | Err(nix::errno::Errno::EINTR) => return Ok(()),
- Err(e) => return Err(e.into()),
}
- }
- Ok(())
-}
-
-fn bridge_loop(master_fd: RawFd, vsock_fd: RawFd) {
- if let Err(e) = set_fd_nonblocking(master_fd) {
- eprintln!("[capsem-agent] failed to set pty nonblocking: {e}");
- return;
- }
- if let Err(e) = set_fd_nonblocking(vsock_fd) {
- eprintln!("[capsem-agent] failed to set terminal vsock nonblocking: {e}");
- return;
- }
-
- let mut to_master = std::collections::VecDeque::new();
- let mut to_vsock = std::collections::VecDeque::new();
- let mut master_open = true;
- let mut vsock_open = true;
- let mut master_scratch = [0u8; 8192];
- let mut vsock_scratch = [0u8; 8192];
+ });
loop {
- if (!master_open && to_vsock.is_empty()) || (!vsock_open && to_master.is_empty()) {
- break;
- }
-
- let mut master_events = PollFlags::empty();
- if master_open && to_vsock.len() < BRIDGE_BUF_CAP {
- master_events |= PollFlags::POLLIN;
- }
- if master_open && !to_master.is_empty() {
- master_events |= PollFlags::POLLOUT;
- }
-
- let mut vsock_events = PollFlags::empty();
- if vsock_open && to_master.len() < BRIDGE_BUF_CAP {
- vsock_events |= PollFlags::POLLIN;
- }
- if vsock_open && !to_vsock.is_empty() {
- vsock_events |= PollFlags::POLLOUT;
- }
-
- if master_events.is_empty() && vsock_events.is_empty() {
- break;
- }
-
+ // Poll vsock_fd too so a local shutdown (triggered by the heartbeat
+ // detecting host death) wakes us up via POLLHUP. Otherwise we'd sit
+ // in poll forever waiting for PTY activity that never comes.
let mut poll_fds = [
PollFd::new(
unsafe { std::os::unix::io::BorrowedFd::borrow_raw(master_fd) },
- master_events,
+ PollFlags::POLLIN,
),
PollFd::new(
unsafe { std::os::unix::io::BorrowedFd::borrow_raw(vsock_fd) },
- vsock_events,
+ PollFlags::empty(),
),
];
@@ -1002,60 +940,35 @@ fn bridge_loop(master_fd: RawFd, vsock_fd: RawFd) {
Ok(_) => {}
Err(nix::errno::Errno::EINTR) => continue,
Err(e) => {
- eprintln!("[capsem-agent] bridge poll error: {e}");
+ eprintln!("[capsem-agent] poll error: {e}");
break;
}
}
- let master_revents = poll_fds[0].revents().unwrap_or_else(PollFlags::empty);
- let vsock_revents = poll_fds[1].revents().unwrap_or_else(PollFlags::empty);
-
- if master_revents.contains(PollFlags::POLLIN) {
- match read_bridge_chunk(master_fd, &mut to_vsock, &mut master_scratch) {
- Ok(true) => {}
- Ok(false) => master_open = false,
- Err(e) => {
- eprintln!("[capsem-agent] bridge pty read error: {e}");
- break;
- }
- }
- }
- if vsock_revents.contains(PollFlags::POLLIN) {
- match read_bridge_chunk(vsock_fd, &mut to_master, &mut vsock_scratch) {
- Ok(true) => {}
- Ok(false) => vsock_open = false,
- Err(e) => {
- eprintln!("[capsem-agent] bridge vsock read error: {e}");
- break;
- }
+ if let Some(revents) = poll_fds[1].revents() {
+ if revents.intersects(PollFlags::POLLHUP | PollFlags::POLLERR | PollFlags::POLLNVAL) {
+ break;
}
}
- if master_revents.contains(PollFlags::POLLOUT) {
- if let Err(e) = write_bridge_buffer(master_fd, &mut to_master) {
- eprintln!("[capsem-agent] bridge pty write error: {e}");
- break;
+ // Master PTY -> vsock (stdout direction)
+ if let Some(revents) = poll_fds[0].revents() {
+ if revents.contains(PollFlags::POLLIN) {
+ match nix::unistd::read(master_fd, &mut buf) {
+ Ok(0) => break,
+ Ok(n) => {
+ if write_all_fd(vsock_fd, &buf[..n]).is_err() {
+ break;
+ }
+ }
+ Err(nix::errno::Errno::EAGAIN) => {}
+ Err(_) => break,
+ }
}
- }
- if vsock_revents.contains(PollFlags::POLLOUT) {
- if let Err(e) = write_bridge_buffer(vsock_fd, &mut to_vsock) {
- eprintln!("[capsem-agent] bridge vsock write error: {e}");
+ if revents.intersects(PollFlags::POLLHUP | PollFlags::POLLERR) {
break;
}
}
-
- if master_revents.intersects(PollFlags::POLLERR | PollFlags::POLLNVAL)
- || (master_revents.contains(PollFlags::POLLHUP)
- && !master_revents.contains(PollFlags::POLLIN))
- {
- master_open = false;
- }
- if vsock_revents.intersects(PollFlags::POLLERR | PollFlags::POLLNVAL)
- || (vsock_revents.contains(PollFlags::POLLHUP)
- && !vsock_revents.contains(PollFlags::POLLIN))
- {
- vsock_open = false;
- }
}
}
@@ -1394,13 +1307,8 @@ fn run_exec_on_fds(
}
// Spawn child process with piped stdout and stderr.
- let root_cwd = std::path::Path::new("/root");
- let cwd = if root_cwd.is_dir() && std::fs::read_dir(root_cwd).is_ok() {
- root_cwd
- } else {
- std::path::Path::new("/")
- };
- let mut child = match std::process::Command::new("/bin/bash")
+ let cwd = default_exec_cwd();
+ let mut child = match std::process::Command::new("bash")
.arg("-c")
.arg(command)
.stdout(std::process::Stdio::piped())
@@ -1471,6 +1379,14 @@ fn run_exec_on_fds(
exit_code
}
+fn default_exec_cwd() -> &'static str {
+ if unsafe { libc::geteuid() } == 0 && std::path::Path::new("/root").is_dir() {
+ "/root"
+ } else {
+ "/"
+ }
+}
+
/// Guest workspace root (VirtioFS mount point).
const GUEST_WORKSPACE_ROOT: &str = "/root";
@@ -1534,7 +1450,6 @@ fn delete_nofollow(path: &str) -> io::Result<()> {
#[allow(clippy::too_many_arguments)]
fn control_loop(
control_fd: RawFd,
- terminal_fd: RawFd,
master_fd: RawFd,
child_pid: Pid,
boot_env: &[(String, String)],
@@ -1789,15 +1704,6 @@ fn control_loop(
if ctrl_tx.send(GuestToHost::SnapshotReady).is_err() {
break;
}
- eprintln!(
- "[capsem-agent] PrepareSnapshot: snapshot ready; closing vsock pair for post-resume reconnect"
- );
- unsafe {
- libc::shutdown(control_fd, libc::SHUT_RDWR);
- libc::shutdown(terminal_fd, libc::SHUT_RDWR);
- }
- thread::sleep(SNAPSHOT_RECONNECT_DELAY);
- break;
}
Ok(HostToGuest::Unfreeze) => {
eprintln!("[capsem-agent] Unfreeze: thawing /");
@@ -2278,15 +2184,6 @@ mod tests {
let (mut master_host, master_guest) = UnixStream::pair().unwrap();
let (mut vsock_host, vsock_guest) = UnixStream::pair().unwrap();
- let timeout = Some(std::time::Duration::from_secs(30));
- master_host.set_read_timeout(timeout).unwrap();
- master_host.set_write_timeout(timeout).unwrap();
- master_guest.set_read_timeout(timeout).unwrap();
- master_guest.set_write_timeout(timeout).unwrap();
- vsock_host.set_read_timeout(timeout).unwrap();
- vsock_host.set_write_timeout(timeout).unwrap();
- vsock_guest.set_read_timeout(timeout).unwrap();
- vsock_guest.set_write_timeout(timeout).unwrap();
let master_fd = master_guest.as_raw_fd();
let vsock_fd = vsock_guest.as_raw_fd();
@@ -2365,6 +2262,15 @@ mod tests {
}
}
+ #[test]
+ fn exec_default_cwd_uses_root_only_for_root_user() {
+ if unsafe { libc::geteuid() } == 0 && std::path::Path::new("/root").is_dir() {
+ assert_eq!(default_exec_cwd(), "/root");
+ } else {
+ assert_eq!(default_exec_cwd(), "/");
+ }
+ }
+
#[test]
fn exec_echo_captures_output_and_exit_code() {
use std::io::Read;
@@ -3209,7 +3115,6 @@ mod tests {
control_loop(
ctrl_read_fd,
master_fd,
- master_fd,
child_pid,
&[],
ctrl_tx,
@@ -3256,14 +3161,6 @@ mod tests {
}
}
- #[test]
- fn control_loop_prepare_snapshot_sends_ready_then_exits_for_reconnect() {
- let responses = run_control_loop_with_messages(vec![HostToGuest::PrepareSnapshot]);
-
- assert_eq!(responses.len(), 1);
- assert!(matches!(responses[0], GuestToHost::SnapshotReady));
- }
-
#[test]
fn control_loop_resize_changes_pty_winsize() {
let (ctrl_read_fd, ctrl_write_fd) = make_pipe();
@@ -3292,7 +3189,6 @@ mod tests {
control_loop(
ctrl_read_fd,
master_fd,
- master_fd,
child_pid,
&[],
ctrl_tx,
diff --git a/crates/capsem-agent/src/mcp_server.rs b/crates/capsem-agent/src/mcp_server.rs
index 1c3a2594d..da00574c3 100644
--- a/crates/capsem-agent/src/mcp_server.rs
+++ b/crates/capsem-agent/src/mcp_server.rs
@@ -37,6 +37,7 @@ struct PendingRequests {
struct PendingRequest {
json_id: Value,
method: Option,
+ snapshot_revert_path: Option,
}
impl PendingRequests {
@@ -53,11 +54,11 @@ impl PendingRequests {
.insert(stream_id, request);
}
- fn remove(&self, stream_id: u32) {
+ fn remove(&self, stream_id: u32) -> Option {
self.inner
.lock()
.expect("pending MCP requests mutex poisoned")
- .remove(&stream_id);
+ .remove(&stream_id)
}
fn take_all(&self) -> Vec {
@@ -148,10 +149,15 @@ fn main() {
}
let id = next_stream_id;
next_stream_id += 1;
+ let snapshot_revert_path = extract_snapshot_revert_path(&line);
(
id,
0,
- json_id.map(|json_id| PendingRequest { json_id, method }),
+ json_id.map(|json_id| PendingRequest {
+ json_id,
+ method,
+ snapshot_revert_path,
+ }),
)
}
};
@@ -266,11 +272,14 @@ fn framed_vsock_to_stdout(
}
};
if frame.payload.is_empty() {
- pending.remove(frame.stream_id);
+ let _ = pending.remove(frame.stream_id);
continue;
}
- pending.remove(frame.stream_id);
+ let pending_request = pending.remove(frame.stream_id);
+ if let Some(request) = pending_request.as_ref() {
+ apply_guest_snapshot_revert_side_effect(request, &frame.payload);
+ }
let mut out = stdout.lock().expect("stdout mutex poisoned");
if out.write_all(&frame.payload).is_err() {
break;
@@ -296,6 +305,101 @@ fn framed_vsock_to_stdout(
}
}
+fn extract_snapshot_revert_path(line: &str) -> Option {
+ let value: Value = serde_json::from_str(line).ok()?;
+ let object = value.as_object()?;
+ if object.get("method")?.as_str()? != "tools/call" {
+ return None;
+ }
+ let params = object.get("params")?.as_object()?;
+ let name = params.get("name")?.as_str()?;
+ if name != "snapshots_revert" && name != "local__snapshots_revert" {
+ return None;
+ }
+ params
+ .get("arguments")?
+ .as_object()?
+ .get("path")?
+ .as_str()
+ .map(str::to_string)
+}
+
+fn response_reports_snapshot_delete(payload: &[u8]) -> bool {
+ let value: Value = match serde_json::from_slice(payload) {
+ Ok(value) => value,
+ Err(_) => return false,
+ };
+ if value.get("error").is_some() {
+ return false;
+ }
+ let Some(content) = value
+ .get("result")
+ .and_then(|result| result.get("content"))
+ .and_then(|content| content.as_array())
+ else {
+ return false;
+ };
+ content.iter().any(|item| {
+ item.get("text")
+ .and_then(|text| text.as_str())
+ .and_then(|text| serde_json::from_str::(text).ok())
+ .and_then(|inner| {
+ inner
+ .get("action")
+ .and_then(|action| action.as_str())
+ .map(str::to_string)
+ })
+ .as_deref()
+ == Some("deleted")
+ })
+}
+
+fn normalize_guest_snapshot_path(raw: &str) -> Option {
+ if raw.contains('\0') {
+ return None;
+ }
+ let stripped = raw.strip_prefix("/root/").unwrap_or(raw);
+ let path = std::path::Path::new(stripped);
+ if path.is_absolute()
+ || path
+ .components()
+ .any(|c| matches!(c, std::path::Component::ParentDir))
+ {
+ return None;
+ }
+ Some(std::path::Path::new("/root").join(path))
+}
+
+fn apply_guest_snapshot_revert_side_effect(request: &PendingRequest, payload: &[u8]) {
+ let Some(path) = request.snapshot_revert_path.as_deref() else {
+ return;
+ };
+ if !response_reports_snapshot_delete(payload) {
+ return;
+ }
+ let Some(guest_path) = normalize_guest_snapshot_path(path) else {
+ eprintln!("[capsem-mcp-server] refusing unsafe snapshot delete path: {path}");
+ return;
+ };
+ match std::fs::symlink_metadata(&guest_path) {
+ Ok(meta) if meta.is_file() || meta.file_type().is_symlink() => {
+ if let Err(e) = std::fs::remove_file(&guest_path) {
+ eprintln!(
+ "[capsem-mcp-server] failed to apply guest-visible snapshot delete for {}: {e}",
+ guest_path.display()
+ );
+ }
+ }
+ Ok(_) => {
+ eprintln!(
+ "[capsem-mcp-server] refusing snapshot delete for non-file path: {}",
+ guest_path.display()
+ );
+ }
+ Err(_) => {}
+ }
+}
+
fn classify_jsonrpc_line(line: &str) -> JsonRpcLineKind {
let Ok(value) = serde_json::from_str::(line) else {
return JsonRpcLineKind::Request {
diff --git a/crates/capsem-agent/src/mcp_server/tests.rs b/crates/capsem-agent/src/mcp_server/tests.rs
index 61ea94ade..ef0683c6a 100644
--- a/crates/capsem-agent/src/mcp_server/tests.rs
+++ b/crates/capsem-agent/src/mcp_server/tests.rs
@@ -62,6 +62,7 @@ fn pending_disconnect_errors_are_emitted_once_with_original_ids() {
PendingRequest {
json_id: Value::from(7),
method: Some("tools/call".to_string()),
+ snapshot_revert_path: None,
},
);
pending.insert(
@@ -69,6 +70,7 @@ fn pending_disconnect_errors_are_emitted_once_with_original_ids() {
PendingRequest {
json_id: Value::String("abc".to_string()),
method: Some("resources/list".to_string()),
+ snapshot_revert_path: None,
},
);
@@ -157,3 +159,56 @@ fn large_json_line_preserved() {
assert_eq!(lines.len(), 1);
assert!(lines[0].len() > 100_000);
}
+
+#[test]
+fn extracts_snapshot_revert_path_from_tool_call() {
+ let line = r#"{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"snapshots_revert","arguments":{"path":"/root/poem.md","checkpoint":"cp-0"}}}"#;
+
+ assert_eq!(
+ extract_snapshot_revert_path(line).as_deref(),
+ Some("/root/poem.md")
+ );
+}
+
+#[test]
+fn extracts_namespaced_snapshot_revert_path_from_tool_call() {
+ let line = r#"{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"local__snapshots_revert","arguments":{"path":"poem.md","checkpoint":"cp-0"}}}"#;
+
+ assert_eq!(
+ extract_snapshot_revert_path(line).as_deref(),
+ Some("poem.md")
+ );
+}
+
+#[test]
+fn ignores_non_snapshot_tool_calls_for_guest_side_effects() {
+ let line = r#"{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"fetch_http","arguments":{"url":"https://example.com"}}}"#;
+
+ assert!(extract_snapshot_revert_path(line).is_none());
+}
+
+#[test]
+fn snapshot_delete_response_must_be_successful_deleted_action() {
+ let ok = br#"{"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"{\"reverted\":true,\"action\":\"deleted\"}"}]}}"#;
+ let restored = br#"{"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"{\"reverted\":true,\"action\":\"restored\"}"}]}}"#;
+ let error = br#"{"jsonrpc":"2.0","id":1,"error":{"code":-32603,"message":"nope"}}"#;
+
+ assert!(response_reports_snapshot_delete(ok));
+ assert!(!response_reports_snapshot_delete(restored));
+ assert!(!response_reports_snapshot_delete(error));
+}
+
+#[test]
+fn normalizes_guest_snapshot_paths_under_root_only() {
+ assert_eq!(
+ normalize_guest_snapshot_path("nested/file.txt").unwrap(),
+ std::path::PathBuf::from("/root/nested/file.txt")
+ );
+ assert_eq!(
+ normalize_guest_snapshot_path("/root/poem.md").unwrap(),
+ std::path::PathBuf::from("/root/poem.md")
+ );
+ assert!(normalize_guest_snapshot_path("../escape").is_none());
+ assert!(normalize_guest_snapshot_path("/etc/passwd").is_none());
+ assert!(normalize_guest_snapshot_path("bad\0path").is_none());
+}
diff --git a/crates/capsem-agent/src/net_proxy.rs b/crates/capsem-agent/src/net_proxy.rs
index 6e1187043..64a902d6b 100644
--- a/crates/capsem-agent/src/net_proxy.rs
+++ b/crates/capsem-agent/src/net_proxy.rs
@@ -4,8 +4,9 @@
// MITM proxy via vsock port 5002:
// * 127.0.0.1:10443 -- intercepts iptables-redirected port 443 (HTTPS).
// * 127.0.0.1:10080 -- intercepts iptables-redirected plain-HTTP ports
-// (80 + the configured allowlist, e.g. 11434 for
-// Ollama). T2.2 added this listener.
+// (80 + the configured allowlist, including
+// 3128/3713/8080 and 11434 for Ollama). T2.2 added
+// this listener.
//
// The host proxy runs a first-byte sniff (T2.1) and routes TLS handshakes
// to the rustls termination path and plain HTTP request lines to the
@@ -41,7 +42,7 @@ use vsock_io::{vsock_connect, VSOCK_HOST_CID};
const LISTEN_PORT_HTTPS: u16 = 10443;
/// TCP port to listen on for plain-HTTP traffic (iptables REDIRECT
/// target for outbound :80 + the configurable allowlist, e.g.
-/// :11434 for Ollama). Added in T2.2; the host proxy's first-byte
+/// :3128/:3713/:8080/:11434). Added in T2.2; the host proxy's first-byte
/// sniff distinguishes TLS from plain HTTP, so a dedicated guest
/// listener is just an iptables-target convenience.
const LISTEN_PORT_HTTP: u16 = 10080;
diff --git a/crates/capsem-agent/src/vsock_io.rs b/crates/capsem-agent/src/vsock_io.rs
index aa49f19ae..8e52d94b8 100644
--- a/crates/capsem-agent/src/vsock_io.rs
+++ b/crates/capsem-agent/src/vsock_io.rs
@@ -8,7 +8,6 @@
use std::io;
use std::os::unix::io::RawFd;
-use std::sync::OnceLock;
use std::time::Duration;
use nix::libc;
@@ -32,42 +31,6 @@ pub struct SockaddrVm {
/// longer than this, it returns EAGAIN instead of hanging forever.
/// 30s is generous -- vsock to hypervisor should drain in milliseconds.
const IO_TIMEOUT_SECS: i64 = 30;
-const CAPSEM_LOGICAL_PORT_MIN: u32 = 5000;
-const CAPSEM_LOGICAL_PORT_MAX: u32 = 5007;
-
-static VSOCK_PORT_OFFSET: OnceLock = OnceLock::new();
-
-pub fn host_vsock_port(logical_port: u32) -> u32 {
- if !(CAPSEM_LOGICAL_PORT_MIN..=CAPSEM_LOGICAL_PORT_MAX).contains(&logical_port) {
- return logical_port;
- }
- logical_port.saturating_add(*VSOCK_PORT_OFFSET.get_or_init(read_vsock_port_offset))
-}
-
-fn read_vsock_port_offset() -> u32 {
- let Ok(cmdline) = std::fs::read_to_string("/proc/cmdline") else {
- return 0;
- };
- parse_vsock_port_offset(&cmdline)
-}
-
-fn parse_vsock_port_offset(cmdline: &str) -> u32 {
- for part in cmdline.split_whitespace() {
- let Some(raw) = part.strip_prefix("capsem.vsock_port_offset=") else {
- continue;
- };
- let Ok(offset) = raw.parse::() else {
- eprintln!("[capsem-agent] ignoring invalid capsem.vsock_port_offset={raw}");
- return 0;
- };
- if CAPSEM_LOGICAL_PORT_MAX.saturating_add(offset) > u16::MAX as u32 {
- eprintln!("[capsem-agent] ignoring out-of-range capsem.vsock_port_offset={offset}");
- return 0;
- }
- return offset;
- }
- 0
-}
/// Connect to a vsock port on the given CID.
///
@@ -75,7 +38,6 @@ fn parse_vsock_port_offset(cmdline: &str) -> u32 {
/// return EAGAIN after IO_TIMEOUT_SECS instead of hanging indefinitely
/// if the host stops draining the buffer.
pub fn vsock_connect(cid: u32, port: u32) -> io::Result {
- let port = host_vsock_port(port);
let fd = unsafe { libc::socket(AF_VSOCK, libc::SOCK_STREAM, 0) };
if fd < 0 {
return Err(io::Error::last_os_error());
@@ -145,38 +107,17 @@ pub fn vsock_connect_retry(cid: u32, port: u32, label: &str) -> RawFd {
// Leak a &'static str for the label so RetryOpts can use it.
let static_label: &'static str = Box::leak(format!("vsock-{label}").into_boxed_str());
- let mut attempts: u32 = 0;
- let mut last_err: Option = None;
- let physical_port = host_vsock_port(port);
match retry_with_backoff(
&RetryOpts::new(static_label, Duration::from_secs(30)),
- || {
- attempts += 1;
- eprintln!("[capsem-agent] {label} connect attempt {attempts} (port {physical_port})");
- match vsock_connect(cid, port) {
- Ok(fd) => Some(fd),
- Err(e) => {
- eprintln!("[capsem-agent] {label} connect attempt {attempts} failed: {e}");
- last_err = Some(e);
- None
- }
- }
- },
+ || vsock_connect(cid, port).ok(),
) {
Ok(fd) => {
- eprintln!("[capsem-agent] {label} connected (port {physical_port})");
+ eprintln!("[capsem-agent] {label} connected (port {port})");
fd
}
Err(e) => {
- match last_err {
- Some(err) => {
- eprintln!("[capsem-agent] {label} connect timed out: {e}; last error: {err}");
- }
- None => {
- eprintln!("[capsem-agent] {label} connect timed out: {e}");
- }
- }
+ eprintln!("[capsem-agent] {label} connect timed out: {e}");
std::process::exit(1);
}
}
@@ -267,21 +208,6 @@ mod tests {
);
}
- #[test]
- fn parse_vsock_port_offset_from_kernel_cmdline() {
- assert_eq!(
- parse_vsock_port_offset("console=ttyS0 capsem.vsock_port_offset=15016 quiet"),
- 15016
- );
- }
-
- #[test]
- fn parse_vsock_port_offset_rejects_invalid_values() {
- assert_eq!(parse_vsock_port_offset("capsem.vsock_port_offset=nope"), 0);
- assert_eq!(parse_vsock_port_offset("capsem.vsock_port_offset=65000"), 0);
- assert_eq!(parse_vsock_port_offset("console=ttyS0 quiet"), 0);
- }
-
#[test]
fn read_write_exact_fd() {
let (client, server) = UnixStream::pair().unwrap();
diff --git a/crates/capsem-app/Cargo.toml b/crates/capsem-app/Cargo.toml
index 102482dd3..5962ca945 100644
--- a/crates/capsem-app/Cargo.toml
+++ b/crates/capsem-app/Cargo.toml
@@ -15,6 +15,9 @@ path = "src/main.rs"
[dependencies]
tauri = { version = "2", features = ["custom-protocol"] }
+tauri-plugin-updater = "2"
+tauri-plugin-process = "2"
+tauri-plugin-dialog = "2"
tauri-plugin-opener = "2"
tauri-plugin-single-instance = "2"
serde = { workspace = true }
diff --git a/crates/capsem-app/capabilities/default.json b/crates/capsem-app/capabilities/default.json
index a68239a48..9a82a0418 100644
--- a/crates/capsem-app/capabilities/default.json
+++ b/crates/capsem-app/capabilities/default.json
@@ -8,6 +8,9 @@
"core:window:default",
"core:app:default",
"core:event:default",
+ "updater:default",
+ "process:allow-restart",
+ "dialog:default",
"opener:allow-open-url"
]
}
diff --git a/crates/capsem-app/src/main.rs b/crates/capsem-app/src/main.rs
index 9b1fdec5d..40041fce4 100644
--- a/crates/capsem-app/src/main.rs
+++ b/crates/capsem-app/src/main.rs
@@ -3,6 +3,7 @@
use std::path::{Path, PathBuf};
use std::time::SystemTime;
+use serde::Serialize;
use tauri::{Emitter, Manager};
use tracing::{info, warn};
use tracing_subscriber::prelude::*;
@@ -60,6 +61,28 @@ async fn open_url(url: String, app: tauri::AppHandle) -> Result<(), String> {
.map_err(|e| e.to_string())
}
+#[derive(Serialize)]
+struct UpdateInfo {
+ version: String,
+ current_version: String,
+}
+
+#[tauri::command]
+async fn check_for_app_update(app: tauri::AppHandle) -> Result