Development¶
This page covers local development, testing, documentation, and release preparation.
For the detailed fixture and mocking layout, see Test Infrastructure. For runtime component relationships, see System Architecture.
Repository Layout¶
.
├── src/nber_cli/ # CLI, MCP, core logic, persistence, and migrations
├── src/nber_server/ # Optional local FastAPI service
├── desktop/ # React frontend and Tauri/Rust shell
├── scripts/ # Desktop build, signing, artifact, and smoke helpers
├── tests/ # Python and release-tooling tests
├── docs/ # MkDocs documentation source
├── .github/workflows/ # CI, release, Desktop, and docs workflows
└── pyproject.toml # Package metadata and dependency groups
uv.lock can be generated locally, but this repository currently ignores it and does not treat it as a release artifact.
Local Setup¶
Run the CLI from the working tree:
For Desktop development, also install Node dependencies and run the Tauri development shell:
Tests¶
Run a specific test file:
Linting¶
Documentation¶
Serve the docs locally:
Build the docs in strict mode:
The generated site is written to site/, which should not be committed.
GitHub Actions¶
The project uses separate workflows for:
- Linting with Ruff.
- Running Pytest.
- Building MkDocs documentation.
- Deploying documentation to GitHub Pages on pushes to
master. - Checking the React frontend on pull requests and pushes.
- Building macOS, Windows, and Linux Desktop installers on
v*tags or manual dispatch. - Publishing to PyPI when a GitHub release is published.
The normal pull-request Desktop check runs Python, TypeScript, frontend tests, the Vite build, and Rust unit tests. Full platform installer builds run only for tags or manual workflow dispatch.
Release Checklist¶
The following checks all need to pass before tagging a release. Each one catches a different class of release-time failure, and skipping any of them has historically let a regression ship.
Code and dependencies¶
- Bump the version in
pyproject.toml,desktop/package.json,desktop/package-lock.json,desktop/src-tauri/tauri.conf.json,desktop/src-tauri/Cargo.toml,desktop/src-tauri/Cargo.lock,tests/release/test_release_metadata.py, the Claude/Codex plugin manifests, and.claude-plugin/marketplace.json. - Update Changelog. Keep the root
CHANGELOG.mdanddocs/en/changelog.md/docs/zh/changelog.mdconsistent. - Run
uv run pytest tests/release/test_release_metadata.py -qand confirm all release versions are synchronized. Do not adduv.lock; it is intentionally ignored under the current repository policy.
Static checks¶
- Run
uv run pytest tests -q. - Run
uv run ruff check .. - Run
uv run --group docs mkdocs build --strict. - In
desktop/, runnpm ci,npm run lint,npm run test, andnpm run build; then runcargo checkindesktop/src-tauri/.
Cross-surface consistency¶
- Tracked plugin files and skill paths exist. Run
git ls-files plugins/ .claude-plugin/ | sort. On a case-sensitive checkout, the tracked skill path isplugins/nber-cli/skills/NBER-CLI/SKILL.md. - Top-level imports in docs are real. Every
from nber_cli import ...andimport nber_cli.x as ...example indocs/en/anddocs/zh/must point to a name listed innber_cli.__all__, or to a documented module-level helper. Run the snippet below and confirm the output is empty:uv run python -c "from nber_cli import __all__; import re, pathlib; missing=[]; [missing.append((p, m)) for p in pathlib.Path('docs').rglob('*.md') for m in re.findall(r'(?:from nber_cli import|import nber_cli\.)\s*([A-Za-z0-9_]+)', p.read_text()) if m not in __all__ and not m.startswith('nber_cli.')]; print(missing)" - Public
__all__symbols are documented. Every name innber_cli.__all__should appear indocs/en/python-api.mdanddocs/zh/python-api.md. A future sweep can use the snippet above in reverse to flag undocumented names. - CLI help text and MCP tool schemas are sane. Run
uv run nber-cli --helpand skim each subcommand's--help. The MCP tool schemas are derived from the Python type hints and docstrings ofsrc/nber_cli/mcp/mcp.py; review any change to that file againstdocs/en/mcp.mdanddocs/zh/mcp.md. - HTTP routes match the public contract. Run
uv run pytest tests/server/test_server.py -qand review route or schema changes againstdocs/en/http-api.mdanddocs/zh/http-api.md.
Build and smoke test¶
- Build from a clean checkout with
uv buildand confirm bothdist/*.whlanddist/*.tar.gzare produced. - Inspect the artifacts before installation. The wheel must contain both
nber_cli/andnber_server/, includingnber_cli/db/migrations/. The sdist must not contain local databases or logs,.dev,.agents,.conductor,.superpowers,tmp,output,node_modules, Rusttarget, or bundled sidecar binaries. Treat an unexpectedly large sdist as a release blocker. - Install the built wheel in a throwaway environment and test every console entry point. This catches missing packages that do not show up in the development install:
uv venv --seed /tmp/nber-cli-smoke /tmp/nber-cli-smoke/bin/pip install dist/*.whl /tmp/nber-cli-smoke/bin/nber-cli --version /tmp/nber-cli-smoke/bin/nber-cli info cache /tmp/nber-cli-smoke/bin/nber-cli mcp-server --help /tmp/nber-cli-smoke/bin/nber-server --help /tmp/nber-cli-smoke/bin/nber-sidecar --help - Run the Desktop package checker and native installer smoke test on every release platform, then confirm macOS arm64/x64, Windows x64, and Linux x64 artifacts were uploaded.
- Run
git diff --checkon the release branch. This catches trailing whitespace and conflict markers.
Publish¶
- Before creating the tag, verify that the intended tag is exactly
vplus thepyproject.tomlversion. The workflows currently accept anyv*tag, so this remains a manual release gate. - Push the matching tag and wait for the Desktop workflow to create or update the draft GitHub Release. Review every uploaded artifact before publishing it.
- Publish the GitHub Release only after the draft is complete. Publishing triggers
publish.yml, which rebuilds and uploads the Python wheel and sdist to PyPI.
Optional but recommended¶
- Cross-check the English and Chinese public docs against the nav declared in
mkdocs.yml. Internal files underdocs/desktop/are intentionally outside the public nav. - From a clean checkout on a case-sensitive filesystem (Linux CI is enough), run
uv sync --dev --group docsanduv run nber-cli --helpto make sure no path or import is sensitive to case.
Coding Style¶
- Python code targets Python 3.11 or newer.
- Variable names should follow PEP 8 and use clear English names.
- Code comments should be written in English.
- Keep CLI behavior script-friendly: stable exit codes, readable errors, and JSON output where automation needs it.