Skip to content

Make the CLI reachable without PATH: python -m control_plane - #14

Merged
susheem-k merged 1 commit into
mainfrom
docs/module-invocation
Sep 13, 2026
Merged

susheem-k merged 1 commit into
mainfrom
docs/module-invocation

Conversation

@susheem-k

Copy link
Copy Markdown
Contributor

Context

pip install agentplane-control-plane succeeds, then control-plane is not found.

This is not a bug we can fix in the package. pip writes the console script into the
interpreter's scripts directory and cannot add that directory to PATH — wheels have
no install-time hooks, and setup.py's hooks don't run for wheel installs. It is the
default outcome on Windows with the Python Install Manager,
which puts only its python.exe shim on PATH and leaves each interpreter's
Scripts\ off it. pip's warning about this is easy to miss in install output.

Hit while setting up the plane for the mini-SWE-agent governance work.

What this changes

python -m control_plane now works. There was no __main__.py, so the documented
fallback for "not on PATH" didn't exist — only python -m control_plane.cli, which is
an internal path no one would guess.

Hints follow the invocation. prog is derived from argv[0], so --help and the
ui subcommand name whichever form you used. Previously control-plane ui printed
Run: control-plane serve --port 8800 — telling a user to run the exact command they
had just failed to run.

README gains two subsections under Install:

  • If control-plane isn't foundpipx / uv tool (which own a bin directory
    already on PATH), the module form, and a sysconfig one-liner that prints the
    directory to add by hand.
  • After upgrading Python — installs belong to one interpreter, so both forms
    break after an upgrade; a hand-added scripts directory is usually version-scoped
    (...\pythoncore-3.14-64\Scripts) and needs updating too.

Quick start still leads with control-plane. The equivalence is stated once near the
top rather than doubling every example — the console script is the better UX when it
works, and the fallback only needs to be findable.

Tests

tests/test_cli_entrypoints.py (5 cases): the module form runs, names itself in usage,
emits hints in its own form, and _prog() is checked against both argv[0] shapes.

Suite 42 → 47, all passing. ruff format clean on touched files. The one pre-existing
ruff check error (ui/store_client.py:9, unused os) is on main already and left
alone.

Non-scope

No packaging or entry-point changes — [project.scripts] is untouched and the console
script behaves exactly as before. Nothing here affects the Docker image, whose
entrypoint stays control-plane serve.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EMQxc7WjBTqdUJu18LAskK

pip installs the console script into the interpreter's scripts directory and
cannot put that directory on PATH -- no wheel can, since wheels have no
install-time hooks. On Windows with the Python Install Manager this is the
default outcome: only the python.exe shim is on PATH, so `control-plane`
installs successfully and is then not found.

Add __main__.py so `python -m control_plane` works as a documented fallback,
and derive argparse's prog from argv[0] so a user who cannot reach the console
script is not told to run it -- `control-plane ui` previously printed a hint
naming the very command that was missing.

README gains two subsections under Install: what to do when `control-plane`
isn't found (pipx / uv / module form / the sysconfig one-liner that prints the
directory to add), and what to expect after a Python upgrade -- both forms stop
working, since installs belong to one interpreter, and a hand-added scripts
directory is usually version-scoped.

Quick start keeps the console script as the primary form; the equivalence is
stated once at the top rather than doubling every example.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMQxc7WjBTqdUJu18LAskK
@susheem-k
susheem-k merged commit 074af3a into main Sep 13, 2026
3 checks passed
@susheem-k
susheem-k deleted the docs/module-invocation branch September 13, 2026 07:28
susheem-k added a commit that referenced this pull request Sep 13, 2026
0.2.0 is the version people actually install, and it has neither the
__main__.py nor the README guidance from #14. Both exist for someone who has
just run `pip install` and found no `control-plane` command -- and that person
gets the PyPI wheel and the PyPI project page, so until this ships the fix
reaches only people installing from a clone, who never had the problem.

Patch, not minor: purely additive. [project.scripts] is untouched and the
console script's output is byte-identical -- prog only differs for the module
form, which is new in this release.

RELEASING.md described required reviewers on the `pypi` environment as
optional. They are now configured on all three AgentPlane repos, so the upload
pauses for approval; say so, and say why it matters (PyPI versions are
immutable, so that prompt is the last point a bad build can be stopped).

Verified against the built artifacts, not just the source tree: wheel and sdist
pass `twine check` (which also confirms the edited README renders on PyPI),
__main__.py is packaged, entry_points.txt is unchanged, and a clean venv
installed from the wheel reports 0.2.1 and runs `python -m control_plane`.


Claude-Session: https://claude.ai/code/session_01EMQxc7WjBTqdUJu18LAskK

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant