Development¶
This page covers local development, testing, documentation, and release preparation.
Repository Layout¶
.
├── src/nber_cli/ # Package source
├── tests/ # Pytest suite
├── docs/ # MkDocs documentation source
├── .github/workflows/ # CI, release, and docs workflows
├── pyproject.toml # Package metadata and dependency groups
└── uv.lock # Locked dependency graph
Local Setup¶
Run the CLI from the working tree:
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. - Publishing to PyPI when a GitHub release is published.
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. - Update Changelog. Keep the root
CHANGELOG.mdanddocs/en/changelog.md/docs/zh/changelog.mdconsistent. - Run
uv lockand commit the resultinguv.lock.
Static checks¶
- Run
uv run pytest -q. - Run
uv run ruff check .. - Run
uv run --group docs mkdocs build --strict.
Cross-surface consistency¶
- Package version matches the plugin manifests. The Claude plugin manifest (
plugins/nber-cli/.claude-plugin/plugin.json), the Codex plugin manifest (plugins/nber-cli/.codex-plugin/plugin.json), and the marketplace files (.claude-plugin/marketplace.json,.agents/plugins/marketplace.json) must all carry the sameversionfield aspyproject.toml. A small shell loop is enough: - Marketplace files and skill paths are tracked in Git. Run
git ls-files plugins/ .claude-plugin/ .agents/ | sortand confirm every path the docs reference is present. On a case-sensitive Linux checkout,plugins/nber-cli/skills/nber-cli/SKILL.md(lowercase) does not exist; the tracked 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 diff 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.py; review any change to that file againstdocs/en/mcp.mdanddocs/zh/mcp.md.
Build and smoke test¶
- Run
uv buildand confirm bothdist/*.whlanddist/*.tar.gzare produced. - Install the built wheel in a throwaway environment and run a smoke test. This catches packaging mistakes that do not show up in the dev install:
- Run
git diff --checkon the release branch. This catches trailing-whitespace and conflict-marker mistakes that the other checks can miss.
Publish¶
- Create and publish a GitHub release. The
publish.ymlworkflow builds the package and uploads it to PyPI; the version inpyproject.tomlat release time is what gets published, which is why step 1 is non-negotiable.
Optional but recommended¶
- Cross-check the docs index against the file system:
git ls-files docs/ | sortshould match the nav declared inmkdocs.yml. - 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.