feat: Phase 3a — public release readiness (license, packaging fix, CLI fix, MCP registry, release pipeline) - #9
Conversation
…ap design Audits the current codebase (343 tests passing, 89.5% coverage, zero ruff/ pyright issues) and identifies concrete gaps across four themes requested by the maintainer: maintainability, quality of life, power/optimization, and public release readiness. Recommends a decomposed roadmap (Phase 3a-3d) and fully specs Phase 3a (Public Release Readiness) as the first implementable unit: missing LICENSE/SECURITY.md/CONTRIBUTING.md/CHANGELOG.md, ruff/pyright missing from runtime dependencies, a hanging --version/--help CLI entrypoint, missing MCP schema descriptions, and no PyPI/MCP-registry publishing pipeline. Phases 3b-3d (LSP module split, dead code removal, parallel validator execution, optional HTTP transport) are scoped as backlog outlines pending direction on Phase 3a. No source code changes; this is a brainstorming/design deliverable only. Co-authored-by: Qkal <qkal@users.noreply.github.com>
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (24)
📝 WalkthroughWait, I made an XML error. Let me restate correctly without errors. WalkthroughThis PR prepares the project for public release: adds LICENSE, CODE_OF_CONDUCT, CONTRIBUTING, SECURITY, CHANGELOG, GitHub issue/PR templates; moves ruff/pyright into runtime dependencies; adds Field descriptions for MCP schemas; fixes CLI --version/--help hang; adds a tag-driven release workflow publishing to PyPI and the MCP registry with server.json; overhauls README; and adds design/plan documentation plus tests. ChangesPublic release readiness
Sequence Diagram(s)sequenceDiagram
participant Tag as Git Tag Push
participant CI as ci.yml
participant Build as build job
participant PyPI as PyPI
participant Registry as MCP Registry
Tag->>CI: workflow_call verify
CI->>Build: trigger build (uv build)
Build->>PyPI: publish-pypi (OIDC)
Build->>Registry: publish-mcp-registry (server.json sync)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Resolves the 4 open questions from the design doc per maintainer feedback: bundle ruff+pyright as core deps, delete (don't finish wiring) the dead validators.py wrapper code in Phase 3b, use the GitHub repo name (techne) for the MCP Registry namespace while keeping the PyPI distribution name (agent-quality-mcp) unchanged, and defer the Dockerfile out of Phase 3a. Adds docs/superpowers/plans/2026-06-30-agent-quality-mcp-public-release-readiness.md, a task-by-task implementation plan for Phase 3a following this repo's existing plan conventions. Co-authored-by: Qkal <qkal@users.noreply.github.com>
Adds LICENSE (MIT, matching existing pyproject.toml metadata), SECURITY.md (private vulnerability reporting + recap of existing safety guarantees), CONTRIBUTING.md (dev setup, PR conventions, SemVer policy, one-time release setup notes), CHANGELOG.md (Keep a Changelog format, Unreleased section), CODE_OF_CONDUCT.md (Contributor Covenant v2.1), and GitHub issue/PR templates. Part of Phase 3a (Public Release Readiness), Task 1. See docs/superpowers/plans/2026-06-30-agent-quality-mcp-public-release-readiness.md Co-authored-by: Qkal <qkal@users.noreply.github.com>
The original .gitignore (first commit: 'initialize local-only docs ignore') ignored all of docs/, intended for local-only notes. Every spec/plan under docs/superpowers/ since then has only been tracked because someone manually force-added it with 'git add -f' -- a normal 'git add .' would silently drop a newly added design doc. Narrow the rule to 'docs/* + !docs/superpowers/' so docs/superpowers/ specs and plans are tracked normally while anything else directly under docs/ stays ignored, preserving the original local-only-notes intent. Verified: a new file under docs/superpowers/specs/ is no longer reported by 'git check-ignore', while a new file directly under docs/ still is. Part of Phase 3a (Public Release Readiness), Task 2. Co-authored-by: Qkal <qkal@users.noreply.github.com>
Moves ruff and pyright from [project.optional-dependencies].dev into core [project].dependencies, so a default 'pip install agent-quality-mcp' (no extras) produces a server that can actually run two of the three quality tools it exists to orchestrate, instead of reporting them as unavailable. Verified with a clean 'uv pip install' into a throwaway venv (no dev extra): ruff and pyright both resolve and run. Also adds keywords/classifiers/urls to pyproject.toml for PyPI discoverability, with a regression test asserting both. Part of Phase 3a (Public Release Readiness), Task 3. Co-authored-by: Qkal <qkal@users.noreply.github.com>
validate_patch and inspect_workspace previously had one-line docstrings and zero per-field descriptions anywhere in their Pydantic request models. An agent calling either tool cold, without having read the README, had no way to learn from the tool schema alone what mode, safety_mode, or config_overrides do, or which values are valid. Adds Field(description=...) to every ValidatePatchRequest and InspectWorkspaceRequest field, and expands both tool docstrings to state what each tool does, that it never mutates the real workspace, and which response field to act on. New regression test asserts every property in both models' model_json_schema() has a non-empty description, so this cannot silently regress. Part of Phase 3a (Public Release Readiness), Task 4. Co-authored-by: Qkal <qkal@users.noreply.github.com>
main() previously called create_app().run() unconditionally and never inspected sys.argv. Verified before this fix: 'agent-quality-mcp --version' and '--help' hung for the full duration of 'timeout 3 ...' (exit 124) because the process moved straight into the blocking stdio read loop instead of printing anything. Adds parse_args(), using argparse so --version/-V prints the version and exits 0, --help/-h prints usage and exits 0, and unrecognized arguments fail fast with a usage message on stderr and a non-zero exit -- all before the server starts. The existing test_main_closes_pyright_lsp_manager test now pins sys.argv to simulate the no-argument invocation it always intended to test, since main() now genuinely reads sys.argv. Manually re-verified with the same 'timeout 3 ...; echo 0' check used to find the bug: --version and --help now exit 0 immediately with output; an unrecognized flag exits 2 with a stderr message. Part of Phase 3a (Public Release Readiness), Task 5. Co-authored-by: Qkal <qkal@users.noreply.github.com>
Adds .github/workflows/release.yml, triggered on 'v*' tag push: 1. verify: reuses ci.yml (lint, type check, test, whitespace) as a required gate before anything publishes. 2. build: 'uv build' the sdist/wheel and upload as an artifact. 3. publish-pypi: pypa/gh-action-pypi-publish with Trusted Publishing (OIDC, no stored token) -- requires a one-time PyPI-side Trusted Publisher binding documented in CONTRIBUTING.md. 4. publish-mcp-registry: syncs server.json's version to the tag, then publishes via mcp-publisher with GitHub OIDC (no secret needed). Makes ci.yml callable as a reusable workflow (adds workflow_call to its triggers) so the release pipeline can require its checks instead of duplicating them. Both workflow files validated with yaml.safe_load. Part of Phase 3a (Public Release Readiness), Task 6. Co-authored-by: Qkal <qkal@users.noreply.github.com>
Adds server.json at the repo root, validated against the live official schema (https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json) with jsonschema.validate -- confirmed passing. Per the design's Resolved Decisions: 'name' uses the GitHub repository name (io.github.qkal/techne) while packages[0].identifier stays the real published PyPI distribution name (agent-quality-mcp) -- the registry verifies package ownership against the latter, so these are deliberately different fields, not a naming inconsistency. Adds the matching 'mcp-name: io.github.qkal/techne' HTML comment as the first line of README.md, which the registry uses to verify README/package ownership. Part of Phase 3a (Public Release Readiness), Task 7. Co-authored-by: Qkal <qkal@users.noreply.github.com>
- Adds CI/PyPI/license/Python-version badges below the title. - Adds a 'Use With An MCP Client' section with a copy-paste claude_desktop_config.json/.cursor/mcp.json snippet using 'uvx agent-quality-mcp'. - Updates Setup to lead with 'uv tool install agent-quality-mcp' (now that ruff/pyright are bundled dependencies) and moves 'uv sync --extra dev' to a clearly labeled local-development path. - Notes in MVP Limitations that ruff/pyright are bundled runtime dependencies, not external prerequisites, and documents the --version/--help/--help CLI behavior. - Adds a 'Contributing And Community' section linking CONTRIBUTING.md, SECURITY.md, CHANGELOG.md, and LICENSE. Part of Phase 3a (Public Release Readiness), Task 8. Co-authored-by: Qkal <qkal@users.noreply.github.com>
| set -euo pipefail | ||
| VERSION="${GITHUB_REF#refs/tags/v}" | ||
| jq --arg v "$VERSION" '.version = $v | .packages[0].version = $v' server.json > server.json.tmp | ||
| mv server.json.tmp server.json |
There was a problem hiding this comment.
🟡 Manual workflow dispatch publishes garbled version to the MCP Registry
The version extraction silently produces a raw git ref instead of a semver string (VERSION="${GITHUB_REF#refs/tags/v}" at .github/workflows/release.yml:81) when the workflow is not triggered by a tag push, so a manual dispatch could publish a broken entry like refs/heads/master as the version to the MCP Registry.
Impact: A manual workflow dispatch could publish a broken, non-semver version string to the MCP Registry.
Version extraction has no guard against non-tag refs
The release workflow is triggered by both push: tags: ["v*"] and workflow_dispatch: {} (.github/workflows/release.yml:4-7). The publish-mcp-registry job extracts the version with VERSION="${GITHUB_REF#refs/tags/v}" at line 81. This shell parameter expansion only strips the refs/tags/v prefix if present.
When triggered via workflow_dispatch from a branch, GITHUB_REF is e.g. refs/heads/master. The expansion ${GITHUB_REF#refs/tags/v} doesn't match and returns the unchanged full string refs/heads/master. The set -euo pipefail on line 80 does not catch this: GITHUB_REF is set (no -u violation), the expansion doesn't error (no -e violation), and jq happily writes the garbled string into server.json. The subsequent ./mcp-publisher publish at line 89 then publishes this broken version.
A guard like [[ "$GITHUB_REF" == refs/tags/v* ]] || { echo "Error: not a tag ref"; exit 1; } before the extraction would prevent this.
| set -euo pipefail | |
| VERSION="${GITHUB_REF#refs/tags/v}" | |
| jq --arg v "$VERSION" '.version = $v | .packages[0].version = $v' server.json > server.json.tmp | |
| mv server.json.tmp server.json | |
| set -euo pipefail | |
| if [[ "$GITHUB_REF" != refs/tags/v* ]]; then | |
| echo "::error::publish-mcp-registry requires a tag ref (got $GITHUB_REF)" | |
| exit 1 | |
| fi | |
| VERSION="${GITHUB_REF#refs/tags/v}" | |
| jq --arg v "$VERSION" '.version = $v | .packages[0].version = $v' server.json > server.json.tmp | |
| mv server.json.tmp server.json |
Was this helpful? React with 👍 or 👎 to provide feedback.
| id-token: write | ||
| steps: | ||
| - name: Download distribution artifact | ||
| uses: actions/download-artifact@v5 |
There was a problem hiding this comment.
🚩 Artifact action version mismatch between upload and download steps
The release workflow uploads artifacts with actions/upload-artifact@v4 (.github/workflows/release.yml:39) but downloads them with actions/download-artifact@v5 (.github/workflows/release.yml:55). These are different major versions. While v5 of download-artifact is generally documented as backward-compatible with v4 uploads for same-workflow usage, mixing major versions is unusual and could break if GitHub changes the artifact backend. Matching versions (both v4 or both v5) would be more conventional and less fragile.
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Brainstormed, designed, and now implements Phase 3a: Public Release Readiness — closing the gap between "code is well-tested" and "an external person can actually find, install, and legally use this." No changes to the validation/decision pipeline (
decision.py,grouping.py,actions.py,risk.py,response.py, LSP/session code) — only release-engineering, packaging, and discoverability.See the full audit and design rationale in:
docs/superpowers/specs/2026-06-30-agent-quality-mcp-public-release-readiness-design.mddocs/superpowers/plans/2026-06-30-agent-quality-mcp-public-release-readiness.mdMaintainer-confirmed decisions baked into this PR
ruff+pyrightas core runtime dependencies (no separatetoolsextra).wrap_uv_result/wrap_ruff_resultrather than finish wiring them.io.github.qkal/techne. The PyPI distribution name (agent-quality-mcp) is unchanged and is whatserver.json'spackages[0].identifiercorrectly points at — these are deliberately different fields.Dockerfilein this phase (deferred).Changes
LICENSE(MIT),SECURITY.md,CONTRIBUTING.md,CHANGELOG.md,CODE_OF_CONDUCT.md, GitHub issue/PR templates..gitignorefix: narrowed the blanketdocs/rule (docs/*+!docs/superpowers/) so new design docs are no longer silently dropped by a plaingit add .— verified withgit check-ignorebefore/after.ruff/pyrightfromdev-only extras into coredependencies. Verified with a cleanuv pip installinto a throwaway venv (nodevextra) that both tools resolve and run. Addedclassifiers/urls/keywordstopyproject.toml. Regression tests added.ValidatePatchRequest/InspectWorkspaceRequestfield now has aField(description=...); both tool docstrings expanded. New test asserts every property in both JSON schemas has a non-empty description.agent-quality-mcp --version/--helppreviously hung indefinitely (verified:timeout 3 ...→ exit124) becausemain()never inspectedsys.argv. Now usesargparse;--version/-Vand--help/-hexit0immediately, unrecognized arguments exit non-zero with a usage message. Re-verified with the sametimeoutcheck..github/workflows/release.yml— tag-driven (v*), reusesci.ymlas a required gate (workflow_call), builds withuv build, publishes to PyPI via Trusted Publishing (OIDC, no stored token), then publishes/updatesserver.jsonto the official MCP Registry viamcp-publisherwith GitHub OIDC.server.jsonadded and validated against the live official schema (jsonschema.validateagainsthttps://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json— passes). Matchingmcp-nameownership marker added toREADME.md.uv tool install agent-quality-mcp, updated MVP Limitations, and a Contributing/Security/Changelog/License pointer section.Test Plan
uv sync --extra dev && .venv/bin/python -m pytest --cov=agent_quality_mcp --cov-report=term-missing -v— 352 passed, 1 skipped, 89.5% coverage (gate 78%).venv/bin/ruff check .— zero issues.venv/bin/pyright --pythonpath .venv/bin/python— zero errors/warningsgit diff --check— no whitespace issues.venv/bin/python -m pytest tests/integration/test_validate_patch_demo.py -v— passesuv pip install(nodevextra) into a throwaway venv confirmsruff/pyrightare runnabletimeout 3 .venv/bin/agent-quality-mcp --version/--helpexit0immediately (previously exit124);--not-a-real-flagexits2server.jsonvalidated against the live MCP Registry schema withjsonschema.validate.githubfiles confirmed ingit ls-files(not just present on disk)Not In This PR (by design)
Dockerfile— explicitly deferred per maintainer decision.CONTRIBUTING.md): register a Trusted Publisher binding foragent-quality-mcp/qkal/techne/release.yml/ environmentpypi. Also recommended: enable "Private vulnerability reporting" in repo Settings → Security.Summary by CodeRabbit
New Features
Bug Fixes
Documentation