Skip to content

Configure a repository workflow

Available in the development checkout; not yet part of published 0.3.0. Use --project to share readiness and exposure settings in a versioned apizr.toml. Apizr never searches for or loads this file automatically. Existing commands without --project and the historical pipeline's YAML --configuration option retain their behavior.

Complete example

The checkout contains a small, runnable example in examples/project-config:

project-config/
  apizr.toml
  policies/readiness.json
  policies/exposure.json
  src/calculator.py

src/calculator.py defines add(a: int, b: int = 1) -> int. The project file contains:

schema_version = "apizr.project/v1"
root = "."
readiness_policy = "policies/readiness.json"
exposure_policy = "policies/exposure.json"

[scan]
source_roots = ["src"]
excluded_directories = ["ignored"]
max_file_bytes = 4096

[graph]
max_ast_nodes = 10000

policies/readiness.json selects the existing direct readiness contract:

{"execution": {"modes": ["direct"]}}

policies/exposure.json explicitly selects one capability and both interfaces:

{
  "selection": {"include": ["python:calculator:add"]},
  "interfaces": ["rest", "mcp"],
  "execution": {"allowed": ["direct"]}
}

From the checkout, run:

apizr readiness --project examples/project-config/apizr.toml --report
apizr expose plan --project examples/project-config/apizr.toml --plan
mkdir -p build
apizr expose build rest --project examples/project-config/apizr.toml --output-dir build/rest
apizr expose build mcp --project examples/project-config/apizr.toml --output-dir build/mcp

The output directories must be absent or empty. Generating these bundles needs only the base installation; running them requires their transport dependencies. The installed-wheel test copies this exact example outside the checkout and compares all four commands with their explicit-argument equivalents.

Paths and precedence

root, readiness_policy and exposure_policy are relative to the directory of the file named by --project, including when invoked from another directory. Absolute local paths are also accepted. No environment-variable or ~ expansion is performed, and URI paths are rejected. scan.source_roots retains its existing meaning: paths inside the repository identified by root.

Setting Resolution
Repository root Explicit positional root overrides the file; the file defaults to . relative to its directory
Scan and graph bounds Explicit CLI values override the file, even when equal to the usual parser default; omitted values retain existing model defaults
Source roots Repeated CLI --source-root values replace the file's scan.source_roots
Directory exclusions Standard exclusions, file excluded_directories, and repeated CLI --exclude-dir values are combined, preserving additive exclusion behavior
Readiness policy readiness --policy or expose --readiness-policy replaces the file's readiness_policy
Exposure policy expose --policy replaces the file's exposure_policy as a whole
Output and execution Always explicit CLI options; they cannot be configured in the project file

CLI paths, including a positional root, policy overrides and --output-dir, remain relative to the current working directory. Overridden policy paths from the project file are not opened. The project file itself must still be valid.

A selected exposure policy file remains incompatible with inline exposure choices (--select, --exclude, --all-ready, --interface, --execution-mode, --require-control, --allow-conditional). This also applies when the policy path comes from apizr.toml: conflicting choices are refused, never merged. To use inline choices, use a project file without exposure_policy. Readiness, exposure and execution policies remain independent; no selection, execution mode or permission is implicitly widened.

Supported settings

schema_version is required and must equal apizr.project/v1. root defaults to .; the two policy paths are optional. The [scan] and [graph] tables reuse ScanPolicy and GraphPolicy, including their existing validation and bounds. Scan settings include source roots, excluded directories, file/total byte limits, source-file count, entry count and depth. Graph settings include AST-node, relationship, call and import limits. Existing fixed schema versions, Python-only suffixes and skipped symlinks remain unchanged.

The UTF-8 TOML file is limited to 64 KiB. Unknown fields or versions, invalid TOML, wrong types and invalid bounds are rejected. Strings, booleans and floats are not converted into integer bounds. The CLI reports these as invalid input with exit code 2, preserving its existing error presentation.

There are no plugin, execution, output or publication settings in this format. It loads local configuration only: it cannot install plugins, execute analyzed code, download repositories or publish services.

Load from Python

The loader is independent of the CLI and returns typed settings with resolved paths. It reads only the named TOML file; callers select and load JSON policies using the existing policy models before invoking the compiler API.

from apizr.compiler import assess_readiness
from apizr.project import load_project
from apizr.repository_readiness import RepositoryReadinessPolicy

settings = load_project("examples/project-config/apizr.toml")
assert settings.readiness_policy is not None  # Present in this example.
policy = RepositoryReadinessPolicy.model_validate_json(
    settings.readiness_policy.read_bytes()
)
report = assess_readiness(
    settings.root,
    scan_policy=settings.scan,
    graph_policy=settings.graph,
    readiness_policy=policy,
)
assert report.exit_code == 0

This exact Python example is also tested from the minimal installed wheel. Loader errors are ordinary validation, decoding or filesystem exceptions; the loader never prints results or terminates the process.