pyro-mcp/Makefile
Thales Maciel 663241d5d2 Add daily-loop prepare and readiness checks
Make the local chat-host loop explicit and cheap so users can warm the machine once instead of rediscovering environment and guest setup on every session.

Add cache-backed daily-loop manifests plus the new `pyro prepare` flow, extend `pyro doctor --environment` with warm/cold/stale readiness reporting, and add `make smoke-daily-loop` to prove the warmed repro-fix reset path end to end.

Also fix `python -m pyro_mcp.cli` to invoke `main()` so the new smoke and `dist-check` actually exercise the CLI module, and update the docs/roadmap to present `doctor -> prepare -> connect host -> reset` as the recommended daily path.

Validation: `uv lock`, `UV_OFFLINE=1 UV_CACHE_DIR=.uv-cache make check`, `UV_OFFLINE=1 UV_CACHE_DIR=.uv-cache make dist-check`, and `UV_OFFLINE=1 UV_CACHE_DIR=.uv-cache make smoke-daily-loop`.
2026-03-13 21:17:59 -03:00

213 lines
12 KiB
Makefile

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)"