PYTHON ?= uv run python UV_CACHE_DIR ?= .uv-cache PYTEST_WORKERS ?= $(shell sh -c 'n=$$(getconf _NPROCESSORS_ONLN 2>/dev/null || nproc 2>/dev/null || echo 2); if [ "$$n" -gt 8 ]; then n=8; fi; if [ "$$n" -lt 2 ]; then echo 1; else echo $$n; fi') PYTEST_FLAGS ?= -n $(PYTEST_WORKERS) OLLAMA_BASE_URL ?= http://localhost:11434/v1 OLLAMA_MODEL ?= llama3.2:3b OLLAMA_DEMO_FLAGS ?= RUNTIME_PLATFORM ?= linux-x86_64 RUNTIME_SOURCE_DIR ?= runtime_sources RUNTIME_BUILD_DIR ?= build/runtime_bundle RUNTIME_BUNDLE_DIR ?= src/pyro_mcp/runtime_bundle RUNTIME_MATERIALIZED_DIR ?= build/runtime_sources RUNTIME_OCI_LAYOUT_DIR ?= build/oci_layouts RUNTIME_ENVIRONMENT ?= debian:12-base RUNTIME_ENVIRONMENTS ?= debian:12-base debian:12 debian:12-build PYPI_DIST_DIR ?= dist TWINE_USERNAME ?= __token__ PYPI_REPOSITORY_URL ?= USE_CASE_ENVIRONMENT ?= debian:12 USE_CASE_SMOKE_FLAGS ?= DAILY_LOOP_ENVIRONMENT ?= debian:12 .PHONY: help setup lint format typecheck test check dist-check pypi-publish demo network-demo doctor ollama ollama-demo run-server install-hooks smoke-daily-loop smoke-use-cases smoke-cold-start-validation smoke-repro-fix-loop smoke-parallel-workspaces smoke-untrusted-inspection smoke-review-eval runtime-bundle runtime-binaries runtime-kernel runtime-rootfs runtime-agent runtime-validate runtime-manifest runtime-sync runtime-clean runtime-fetch-binaries runtime-build-kernel-real runtime-build-rootfs-real runtime-materialize runtime-export-environment-oci runtime-export-official-environments-oci runtime-publish-environment-oci runtime-publish-official-environments-oci runtime-boot-check runtime-network-check help: @printf '%s\n' \ 'Available targets:' \ ' help Show this help message' \ ' setup Install project dependencies' \ ' lint Run Ruff lint checks' \ ' format Run Ruff formatter' \ ' typecheck Run mypy' \ ' test Run pytest in parallel when multiple cores are available' \ ' check Run lint, typecheck, and tests' \ ' dist-check Smoke-test the installed pyro CLI and environment UX' \ ' pypi-publish Build, validate, and upload the package to PyPI' \ ' demo Run the deterministic VM demo' \ ' network-demo Run the deterministic VM demo with guest networking enabled' \ ' doctor Show runtime and host diagnostics' \ ' smoke-daily-loop Run the real guest-backed prepare plus reset daily-loop smoke' \ ' smoke-use-cases Run all real guest-backed workspace use-case smokes' \ ' smoke-cold-start-validation Run the cold-start repo validation smoke' \ ' smoke-repro-fix-loop Run the repro-plus-fix loop smoke' \ ' smoke-parallel-workspaces Run the parallel isolated workspaces smoke' \ ' smoke-untrusted-inspection Run the unsafe or untrusted inspection smoke' \ ' smoke-review-eval Run the review and evaluation workflow smoke' \ ' ollama-demo Run the network-enabled Ollama lifecycle demo' \ ' run-server Run the MCP server' \ ' install-hooks Install pre-commit hooks' \ ' runtime-bundle Rebuild and sync the packaged runtime bundle' \ ' runtime-binaries Stage runtime binaries into the build bundle' \ ' runtime-kernel Stage kernel artifacts into the build bundle' \ ' runtime-rootfs Stage rootfs artifacts into the build bundle' \ ' runtime-agent Stage guest agent artifacts into the build bundle' \ ' runtime-validate Validate runtime sources against the lockfile' \ ' runtime-manifest Regenerate the runtime manifest in the build bundle' \ ' runtime-sync Sync the built runtime bundle into src/' \ ' runtime-fetch-binaries Materialize pinned upstream Firecracker binaries' \ ' runtime-build-kernel-real Materialize the real guest kernel' \ ' runtime-build-rootfs-real Materialize the real guest rootfs images' \ ' runtime-materialize Run all real-source materialization steps' \ ' runtime-export-environment-oci Export one environment as a local OCI layout' \ ' runtime-export-official-environments-oci Export all official environments as OCI layouts' \ ' runtime-publish-environment-oci Publish one exported OCI layout to its registry target' \ ' runtime-publish-official-environments-oci Publish all official environments to their registry targets' \ ' runtime-boot-check Validate direct Firecracker boot from the bundled runtime' \ ' runtime-network-check Validate outbound guest networking from the bundled runtime' \ ' runtime-clean Remove generated runtime build artifacts' setup: uv sync --dev lint: uv run ruff check . format: uv run ruff format . typecheck: uv run mypy test: uv run pytest $(PYTEST_FLAGS) check: lint typecheck test dist-check: uv run python -m pyro_mcp.cli --version uv run python -m pyro_mcp.cli --help >/dev/null uv run python -m pyro_mcp.cli prepare --help >/dev/null uv run python -m pyro_mcp.cli host --help >/dev/null uv run python -m pyro_mcp.cli host doctor >/dev/null uv run python -m pyro_mcp.cli mcp --help >/dev/null uv run python -m pyro_mcp.cli run --help >/dev/null uv run python -m pyro_mcp.cli env list >/dev/null uv run python -m pyro_mcp.cli env inspect debian:12 >/dev/null uv run python -m pyro_mcp.cli doctor --environment debian:12 >/dev/null pypi-publish: @if [ -z "$$TWINE_PASSWORD" ]; then \ printf '%s\n' 'TWINE_PASSWORD is required; use a PyPI API token.' >&2; \ exit 1; \ fi rm -rf "$(PYPI_DIST_DIR)" uv build --out-dir "$(PYPI_DIST_DIR)" uvx --from twine twine check "$(PYPI_DIST_DIR)"/* @if [ -n "$(PYPI_REPOSITORY_URL)" ]; then \ TWINE_USERNAME="$(TWINE_USERNAME)" uvx --from twine twine upload --repository-url "$(PYPI_REPOSITORY_URL)" "$(PYPI_DIST_DIR)"/*; \ else \ TWINE_USERNAME="$(TWINE_USERNAME)" uvx --from twine twine upload "$(PYPI_DIST_DIR)"/*; \ fi demo: uv run pyro demo network-demo: uv run pyro demo --network doctor: uv run pyro doctor smoke-daily-loop: uv run python scripts/daily_loop_smoke.py --environment "$(DAILY_LOOP_ENVIRONMENT)" smoke-use-cases: uv run python scripts/workspace_use_case_smoke.py --scenario all --environment "$(USE_CASE_ENVIRONMENT)" $(USE_CASE_SMOKE_FLAGS) smoke-cold-start-validation: uv run python scripts/workspace_use_case_smoke.py --scenario cold-start-validation --environment "$(USE_CASE_ENVIRONMENT)" $(USE_CASE_SMOKE_FLAGS) smoke-repro-fix-loop: uv run python scripts/workspace_use_case_smoke.py --scenario repro-fix-loop --environment "$(USE_CASE_ENVIRONMENT)" $(USE_CASE_SMOKE_FLAGS) smoke-parallel-workspaces: uv run python scripts/workspace_use_case_smoke.py --scenario parallel-workspaces --environment "$(USE_CASE_ENVIRONMENT)" $(USE_CASE_SMOKE_FLAGS) smoke-untrusted-inspection: uv run python scripts/workspace_use_case_smoke.py --scenario untrusted-inspection --environment "$(USE_CASE_ENVIRONMENT)" $(USE_CASE_SMOKE_FLAGS) smoke-review-eval: uv run python scripts/workspace_use_case_smoke.py --scenario review-eval --environment "$(USE_CASE_ENVIRONMENT)" $(USE_CASE_SMOKE_FLAGS) ollama: ollama-demo ollama-demo: uv run pyro demo ollama --base-url "$(OLLAMA_BASE_URL)" --model "$(OLLAMA_MODEL)" $(OLLAMA_DEMO_FLAGS) run-server: uv run pyro mcp serve install-hooks: uv run pre-commit install runtime-binaries: uv run python -m pyro_mcp.runtime_build stage-binaries --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)" runtime-kernel: uv run python -m pyro_mcp.runtime_build stage-kernel --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)" runtime-rootfs: uv run python -m pyro_mcp.runtime_build stage-rootfs --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)" runtime-agent: uv run python -m pyro_mcp.runtime_build stage-agent --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)" runtime-validate: uv run python -m pyro_mcp.runtime_build validate --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)" runtime-manifest: uv run python -m pyro_mcp.runtime_build manifest --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)" runtime-sync: uv run python -m pyro_mcp.runtime_build sync --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)" runtime-bundle: uv run python -m pyro_mcp.runtime_build bundle --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)" runtime-fetch-binaries: uv run python -m pyro_mcp.runtime_build fetch-binaries --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)" runtime-build-kernel-real: uv run python -m pyro_mcp.runtime_build build-kernel --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)" runtime-build-rootfs-real: uv run python -m pyro_mcp.runtime_build build-rootfs --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)" runtime-materialize: uv run python -m pyro_mcp.runtime_build materialize --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)" runtime-export-environment-oci: uv run python -m pyro_mcp.runtime_build export-environment-oci --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)" --environment "$(RUNTIME_ENVIRONMENT)" --output-dir "$(RUNTIME_OCI_LAYOUT_DIR)" runtime-export-official-environments-oci: @for environment in $(RUNTIME_ENVIRONMENTS); do \ $(MAKE) runtime-export-environment-oci RUNTIME_ENVIRONMENT="$$environment"; \ done runtime-publish-environment-oci: uv run python -m pyro_mcp.runtime_build publish-environment-oci --platform "$(RUNTIME_PLATFORM)" --source-dir "$(RUNTIME_SOURCE_DIR)" --build-dir "$(RUNTIME_BUILD_DIR)" --bundle-dir "$(RUNTIME_BUNDLE_DIR)" --materialized-dir "$(RUNTIME_MATERIALIZED_DIR)" --environment "$(RUNTIME_ENVIRONMENT)" --layout-root "$(RUNTIME_OCI_LAYOUT_DIR)" runtime-publish-official-environments-oci: @for environment in $(RUNTIME_ENVIRONMENTS); do \ $(MAKE) runtime-publish-environment-oci RUNTIME_ENVIRONMENT="$$environment"; \ done runtime-boot-check: uv run python -m pyro_mcp.runtime_boot_check runtime-network-check: uv run python -m pyro_mcp.runtime_network_check runtime-clean: rm -rf "$(RUNTIME_BUILD_DIR)" "$(RUNTIME_MATERIALIZED_DIR)"