bfev is intended to be shareable with colleagues who may not have your
exact setup. Two distribution layers:
Standard wheel via Hatchling:
uv build # produces dist/bfev-0.1.0-*.whl + sdist
uv pip install dist/bfev-0.1.0-*.whl
A colleague then needs only Python 3.11+ and the wheel:
pip install bfev-0.1.0-*.whl
bfev --version
bfev init my-first-client
This installs the CLI, contracts, logging, lockfile, audit, and the crosscheck-XLSX builder. It does not install Claude Code or any agent definitions — those come from the plugin.
The plugin (plugin/) ships:
plugin.json — plugin manifestagents/{orchestrator,collection,simulate,calculate,report}.md — agent
definitions with frontmatter declaring allowed tools and reading the
contract from bfev.contracts.for_agent("<name>")skills/ — the four pipeline skills, vendored from ~/.claude/skills/
with paths cleaned (no hardcoded /mnt/...)A colleague installs the plugin via:
/plugin add <repo-url-or-path>/plugin
Then their Claude Code sees agent:orchestrator etc.
For colleagues who can't install Quarto / openpyxl / fonts cleanly:
docker build -t bfev:0.1.0 .
docker run -v ~/bfev:/data -e BFEV_HOME=/data bfev:0.1.0 init my-client
The Dockerfile bundles Python, uv, Quarto, fonts, and the bfev package. It
mounts $BFEV_HOME so client data stays on the host filesystem.
Client data must never end up in the package. Two safeguards:
$BFEV_HOME defaults to ~/bfev, outside any git repo.bfev.toml into git must .gitignore the
clients/ directory. The repo's own .gitignore does this.The package ships only resources/ (the master taxonomy, regulatory
anchors, EF tables). IPCC volumes are fetched separately via
bfev fetch-ipcc — they're public but heavy.
bfev follows semver. Breaking changes to:
…bump the major version. Adding optional fields or new audit checks bumps the minor. Bug fixes bump the patch.
Every project's lockfile.yaml records the bfev version it was created with.
A project initialised under bfev 0.x won't run under bfev 1.x without an
explicit bfev upgrade.
Markdown is canonical. A single declarative manifest, docs/build.yaml, drives
one pilot that regenerates the whole site (HTML + PDF) in one command:
python docs/build_docs.py # → docs/_site/ (HTML + assets + PDF)
python docs/build_docs.py --format html # HTML only (no LaTeX needed)
python docs/build_docs.py --dry-run # enumerate the build plan, render nothing
HTML is rendered by a pure-Python markdown→HTML converter (no pandoc, no LaTeX),
output mirroring the Diátaxis tree under _site/. PDFs go through Quarto and
need a LaTeX toolchain (Windows MiKTeX with the Times/Arial fonts); without it
the pilot renders HTML, reports the PDF step as skipped, and never crashes.