# How Version Synchronization Works Across pyproject.toml, __init__.py, and test_cli.py in Agent-Reach

> Learn how Agent-Reach synchronizes versions across pyproject.toml, __init__.py, and test_cli.py using pyproject.toml as the single source of truth via automated testing.

- Repository: [Pnant/Agent-Reach](https://github.com/Panniantong/Agent-Reach)
- Tags: internals
- Published: 2026-07-16

---

**Agent-Reach maintains version consistency by treating [`pyproject.toml`](https://github.com/Panniantong/Agent-Reach/blob/main/pyproject.toml) as the single source of truth, mirroring the value in [`agent_reach/__init__.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/__init__.py) as `__version__`, and enforcing alignment through a test in [`tests/test_cli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/tests/test_cli.py) that fails the build if the values diverge.**

Agent-Reach is a Python CLI tool that requires strict version consistency between its build configuration, runtime package metadata, and test suite. Understanding how version synchronization works across [`pyproject.toml`](https://github.com/Panniantong/Agent-Reach/blob/main/pyproject.toml), [`__init__.py`](https://github.com/Panniantong/Agent-Reach/blob/main/__init__.py), and [`test_cli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/test_cli.py) ensures reliable releases and prevents version drift that can confuse users and break automated workflows.

## Canonical Version in pyproject.toml

The [`pyproject.toml`](https://github.com/Panniantong/Agent-Reach/blob/main/pyproject.toml) file serves as the single source of truth for the package version. This is the only location that requires manual editing when cutting a new release, as it is the version that **pip** and build tools read when constructing the wheel distribution.

```toml

# pyproject.toml

[project]
name = "agent-reach"
version = "1.5.0"

```

## Runtime Version in __init__.py

The package exposes the version through a module-level constant in [`agent_reach/__init__.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/__init__.py). This allows the CLI and other library code to access the version string programmatically via `agent_reach.__version__` without parsing TOML files at runtime.

```python

# agent_reach/__init__.py

__version__: str = "1.5.0"

```

## Automated Verification in test_cli.py

The test suite validates that the runtime version matches the build configuration. In [`tests/test_cli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/tests/test_cli.py), the `test_version_matches_pyproject` function imports `__version__` from the package and compares it against the version declared in [`pyproject.toml`](https://github.com/Panniantong/Agent-Reach/blob/main/pyproject.toml) using `tomllib`.

```python

# tests/test_cli.py

from agent_reach import __version__
import tomllib
import pathlib

def test_version_matches_pyproject():
    pyproject_path = pathlib.Path(__file__).parents[2] / "pyproject.toml"
    data = tomllib.loads(pyproject_path.read_text())
    assert __version__ == data["project"]["version"]

```

## The Synchronization Workflow

Maintainers follow a deliberate three-step workflow to keep these three locations aligned.

### Step 1: Update the Source

Edit the `version` field in [`pyproject.toml`](https://github.com/Panniantong/Agent-Reach/blob/main/pyproject.toml) to the new release number. This is the only manual change required.

### Step 2: Propagate to __init__.py

Run the helper script [`scripts/sync-upstream.sh`](https://github.com/Panniantong/Agent-Reach/blob/main/scripts/sync-upstream.sh) or manually copy the version string to [`agent_reach/__init__.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/__init__.py), updating the `__version__` constant to match the value in [`pyproject.toml`](https://github.com/Panniantong/Agent-Reach/blob/main/pyproject.toml).

### Step 3: Verify via CI

The continuous integration pipeline executes `pytest tests/test_cli.py`. If the assertion fails because the strings differ, the build blocks the release, forcing immediate correction before the package can be deployed to PyPI.

## Summary

- **[`pyproject.toml`](https://github.com/Panniantong/Agent-Reach/blob/main/pyproject.toml)** contains the canonical version string read by pip and build tools.
- **[`agent_reach/__init__.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/__init__.py)** mirrors this value as `__version__` for runtime access by the CLI and library code.
- **[`tests/test_cli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/tests/test_cli.py)** enforces parity by asserting equality between the TOML declaration and the Python constant.
- **CI integration** ensures any mismatch fails the build before deployment, preventing version drift.

## Frequently Asked Questions

### What happens if the versions in __init__.py and pyproject.toml don't match?

The test in [`tests/test_cli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/tests/test_cli.py) will fail with an `AssertionError`, blocking the CI pipeline and preventing a broken release from being published to PyPI.

### Why not use importlib.metadata instead of hardcoding __version__?

While `importlib.metadata` can read version from installed package metadata, Agent-Reach uses a hardcoded `__version__` to ensure the value is available during development and testing before the package is installed, and to avoid import overhead in CLI startup.

### How does the sync script update the files?

The [`scripts/sync-upstream.sh`](https://github.com/Panniantong/Agent-Reach/blob/main/scripts/sync-upstream.sh) helper extracts the version from [`pyproject.toml`](https://github.com/Panniantong/Agent-Reach/blob/main/pyproject.toml) using a TOML parser, then writes that value to [`agent_reach/__init__.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/__init__.py), ensuring the two files stay synchronized without manual copy-pasting errors.

### Can I automate this further with dynamic versioning?

Yes, you could configure `hatch-vcs` or `setuptools-scm` to generate `__version__` dynamically from Git tags, but Agent-Reach deliberately uses explicit strings to maintain simplicity and avoid build-time dependencies.