Blog Post 26 — PR #68: pipx/pip Packaging (v0.9.8 prep)

Series: Building synlynk — The Coordination OS for Multi-Agent Development
PR: #68 — feat/pipx-install
Date: 2026-06-27


Where We Were After PR #67

PR #67 fixed a critical concurrency bug (story-5b86c353): concurrent dispatch_agent calls were clobbering each other's context snapshot by writing to a shared .synlynk/context.md. The fix gave each dispatched job its own isolated context file at .synlynk/contexts/<job_id>.md. With that debt cleared, the working plan was to finish the packaging story as the next zero-debt prerequisite before the v0.10.0 Developer Preview launch.

The Strategic Shift

The v0.10.0 milestone was redefined this session from a version bump into a full Named Release — meaning HN post, README overhaul, synlynk doctor, and a one-sentence pitch. For that to land credibly, pipx install git+https://github.com/nikhilsoman/synlynk needs to work on the first try. That made pyproject.toml packaging a prerequisite for the dev preview, not a nice-to-have.

What This PR Ships

pyproject.toml — standard setuptools.build_meta backend with:

  • Entry point synlynk = "synlynk:main" so pipx install drops a synlynk binary directly in PATH
  • requires-python = ">=3.9", MIT license, PyPI classifiers, project URLs
  • [tool.setuptools.packages.find] scoped to include = ["synlynk*"] — no accidental inclusion of tests/, bin/, etc.

synlynk/__main__.py — three-line file enabling python -m synlynk as a canonical invocation path:

from synlynk import main

if __name__ == "__main__":
    main()

install.sh — header updated to surface pipx as the recommended install path while preserving the curl-based script install as a fallback for environments without pipx.

Two new tests — both guarding against the silent version drift that would break a future PyPI publish:

  • test_pyproject_version_matches_module — reads pyproject.toml with tomllib/tomli and asserts version == synlynk.VERSION
  • test_main_entrypoint_importableimportlib.import_module("synlynk.__main__") verifies the entrypoint is importable cleanly

Verified install paths before committing:

pipx install . --force  # → synlynk 0.9.7
python -m synlynk --version  # → synlynk 0.9.7

493 tests passing.

One Build Stumble Worth Noting

First attempt used build-backend = "setuptools.backends.legacy:build" — a path that doesn't exist in the setuptools module namespace. pip install -e . failed with ModuleNotFoundError: No module named 'setuptools.backends'. The correct backend is setuptools.build_meta (the string that has shipped in every setuptools >= 40.8). Documentation for the wrong string is unfortunately easy to find in older blog posts.

Progress Toward Developer Preview

The dev preview checklist now has its packaging box checked. Remaining before v0.10.0:

Item Status
Dispatch context isolation (story-5b86c353) ✅ PR #67
pipx/pip packaging ✅ This PR
synlynk doctor health command Queued — v0.9.8
README overhaul Sunday — chore/readme-overhaul
BS-5 website brainstorm Saturday PM
BS-6 OKF + visualization Sunday AM
BS-7 skill pack interop + benchmarks Sunday AM/PM
HN launch post draft Sunday PM

New Goalpost

v0.9.8 closes with the synlynk doctor health command (story-048f5fe5). After that, the README overhaul and brainstorm sessions (BS-5, BS-6, BS-7) feed directly into the v0.10.0 Named Release — the first public artifact of synlynk as a packaging-installable coordination layer for multi-agent development.