Repository navigation
feat: publish Konductor as a Claude Code plugin marketplace - #28
Merged
Merged
Conversation
knihit
requested review from
georgebearden,
ihmaws,
shsenior and
simonkrol
as code owners
September 30, 2026 02:50
…ADME; harden token handling
…w docs and script headers CHANGELOG.md's [Unreleased] entry is now crisp bullets in final-state form, matching the [1.1.0] entry's style. generated/claude-plugin/README.md, install-claude-plugin-marketplace.md, README.md's Optional Integrations section, and the six new scripts' header comments/docstrings no longer use em dashes or "--" as a prose separator.
…ease
A final compliance pass over the whole committed tree (not just this PR's
diff hunks) found several internal-only references left over from earlier
scrub rounds, all in files this PR ships:
- CHANGELOG.md and README.md's Project Structure diagram named the
internal package ("ASDLC Core AI Capabilities") and a phantom
internal-tooling config file ("aim.json") that doesn't exist in this repo.
- cli.rs cited an internal "Engineering Design" doc section with no public
equivalent.
- synth/claude.rs had four comments/test strings grounding behavior against
"AIM" (an internal build tool) or an internal-only "aim-agent-authoring"
skill; rewritten to cite Claude Code's own public hooks schema and this
package's own installed output instead.
- synth/mod.rs and install.rs test fixtures used "asdlc-plan"/"asdlc-verify"
SOP names; renamed to "k-plan"/"k-verify", matching this repo's own
public SOP naming convention.
- BUILD_USER_GUIDE_PROMPT.md spelled out the internal package name in a
forbidden-pattern warning; genericized to the same effect.
No functional behavior changes; verified with pytest, cargo test --release,
and make claude-plugin-check.
7475ba9 fixed 10 internal Amazon-tool references found in a compliance sweep, but did so against the whole committed tree rather than this PR's own feature diff (origin/main...787f4e4). A pre-existing internal reference is only this PR's job to fix if the PR's own changes made it stale or inaccurate; otherwise it belongs to the separate, dedicated repo-wide cleanup already flagged for a future PR. Re-reverted 6 of the 10 fixes whose surrounding content the PR's own diff never touches, keeping the 4 that were already fixed for good reason: - CHANGELOG.md's file header ("All notable changes to X will be documented here.") is a one-time line unrelated to the PR's own [Unreleased] entries added a few lines below it. Reverted. - README.md's Project Structure tree is byte-identical between origin/main and 787f4e4; the PR never edits that list. Reverted the aim.json line removal. - cli.rs's exit-code contract comment sits nowhere near the PR's one hunk (new synth CLI args, ~460 lines away). Reverted the "(Engineering Design paragraph 6)" removal. - synth/claude.rs: the module-level doc comment is substantially extended by this PR with new paragraphs documenting the very mcpServers/mcpRegistry behavior being added, so removing "AIM's own" from that same continuous doc block is defensible -- kept. The other three claude.rs locations (a doc comment for a function the PR never touches, and two test assertions where the PR's only nearby change is an unrelated `&BTreeMap::new()` parameter added for an unrelated signature change) are reverted; the PR's edits there have no bearing on what those comments describe. - synth/mod.rs and install.rs: asdlc-plan/asdlc-verify test fixture names are pre-existing tests with no PR hunk anywhere near them. Reverted both. - BUILD_USER_GUIDE_PROMPT.md's naming-convention warning is ~60 lines from the PR's one hunk (a page-alias table row) and covers an unrelated topic. Reverted. Verified with pytest, cargo test --release (cli/mcp/shared workspaces), and make claude-plugin-check.
ihmaws
requested changes
Oct 1, 2026
…n on PRs instead release.yml's workflow_dispatch trigger let any branch run the full release pipeline. check-version, build, and publish had no branch guard and never consulted the dry-run flag, so a branch with an unreleased VERSION bump could trigger a real `gh release create`, and by default, publish-claude-plugin would then force-push that branch's build to the public claude-plugin branch every marketplace install pulls from. release.yml now triggers only on push to main, with no manual-dispatch path to the publish/release logic anywhere in the workflow. validate-pr.yml installs the claude CLI so its existing `make claude-plugin-check` step runs the real `claude plugin validate --strict` check against the assembled plugin tree on every PR, matching what release.yml's publish-claude-plugin job validates before publishing. This is read-only: validate-pr.yml has no publish, release, or push step anywhere in its job graph.
…rketplace # Conflicts: # CHANGELOG.md # cli/konductor-rs/src/cli/install.rs
install.rs's format_install_summary doc comment still called its SOP clause the "SOP-skip note" after sop_clause gained a "converted ..." wording for harnesses that render SOPs as skills -- the comment half described the Kiro case and missed the Claude one. release.yml's publish-claude-plugin job carried a comment that just restated the if: condition on the next line; removed it.
9 of 10 tasks
9 tasks done
Pin the credential-bearing AWS proxy, reject missing bundled MCP configuration, and publish the plugin branch with its immutable tag in one atomic push. Require the plugin branch to be provisioned before release.\n\nAlso shorten the affected public setup and generated-output documentation, and add regression coverage for exact proxy pinning and missing bundled configuration.
Keep user docs focused on installation, updates, and security boundaries. Move implementation detail out of public guides, remove duplicated rationale from generator scripts, and eliminate stale version claims and long comments that repeated code behavior.
Keep the generated plugin README concise, but retain the generated-tree layout, MCP namespacing, publication, rollback, and Kiro configuration guidance needed to maintain the release path.
Keep comments for plugin runtime constraints, compatibility behavior, release atomicity, and schema validation. Remove narration that duplicates commands, argument help, or maintainer documentation.\n\nAlso make Rust synthesis reject bundled MCP configuration that omits the required bundled object, matching the plugin renderer.
ihmaws
previously approved these changes
Oct 6, 2026
Pin the AWS MCP proxy directly in k-architect's and k-developer's own dependencies.mcpRegistry entries instead of routing it through a separate --claude-bundled-mcp-config override file and CLI flag. Remove that flag, its parsing, and the config-driven override path from konductor synth; scripts/claude-plugin-mcp-servers.json now only lists bundled server names for the allowlist. Drop the repo-root plugin.json/.mcp.json generation path. The flat release tree assembled by scripts/assemble-claude-plugin-branch.sh is the only Claude Code plugin layout this repository ships; make claude-plugin-check validates marketplace.json and that flat tree only. Restore the plugin-scoped MCP tool-name rewrite in that assembly script, which the repo-root removal had dropped, re-introducing a bare mcp__aws-mcp__* grant in released output. Document the session-wide MCP credential boundary and the plugin-scoped permission glob (mcp__plugin_<name>_aws-mcp__*) needed to configure Claude Code permissions for this install path. Add an end-to-end regression test asserting the assembled tree's rewritten grants, replace the config-override unit tests with coverage for the direct-pin behavior, and update Makefile/README comments to match the simplified pipeline.
release.yml's publish-claude-plugin job no longer force-pushes the assembled plugin tree directly to a public branch. It now pushes a fresh, collision-resistant candidate branch (release version plus workflow run identifier) and opens a draft pull request into the protected release/plugins branch, using GITHUB_TOKEN scoped to contents: write and pull-requests: write only. The plugins branch ruleset blocks creation, update, deletion, and non-fast-forward on release/plugins with no bypass actors, and the org-wide ruleset requires two approvals before any merge -- so the actual publish is a human-reviewed action, not something this workflow can push through on its own. tag-claude-plugin-release.yml creates the immutable claude-plugin-vX.Y.Z tag only after that PR merges, driven by compute-plugin-release-tag.sh's merged/base-ref/ head-ref guards. validate-plugin-publish-preconditions.sh gates the push itself: confirms the checkout matches the expected release ref by commit SHA, and that neither the derived candidate branch nor the release tag already exists on the remote, failing closed on any inconclusive remote lookup. A new opt-in rehearsal workflow, plugin-publish-dry-run.yml, exercises the same push-candidate-branch/open-draft-PR path under a distinct branch prefix so it can never produce a real tag, gated behind a typed confirmation input. marketplace.json's source ref moves from the old claude-plugin branch to release/plugins to match. Adds unit tests for all three new scripts (28 cases): tag-computation guards, candidate-branch derivation, and the four publish-precondition checks (ref match, protected-name refusal, branch collision, tag collision), with the collision checks run against a disposable local bare repo rather than the real remote.
Updates CHANGELOG.md, the plugin README, and the two install guides to describe the candidate-branch-plus-draft-PR publish path instead of the old force-push-to-claude-plugin description, including the dry-run rehearsal workflow and the recovery guidance for a bad release.
ihmaws
reviewed
Oct 7, 2026
ihmaws
left a comment
Member
There was a problem hiding this comment.
Final questions about the workflow. Should the plugins branches be orphaned from the main trunk?
Also, should their be harness specific variants (claude-code, kiro, etc)?
Both the release and dry-run publish jobs built their candidate commit with `git init` in a throwaway directory, so the candidate shared no history with release/plugins and `gh pr create` had no common ancestor to diff against. scripts/build-plugin-candidate-commit.sh replaces that: it checks out the candidate branch directly on top of origin/<base-branch>, clears every previously tracked path, and overlays the already-assembled flat artifact before committing. The resulting commit's parent is release/plugins' own tip, giving GitHub a real merge base. Both workflows now call this one script instead of each inlining their own git init.
7 of 9 tasks
Bind confirm_dry_run through a step-scoped env: block instead of interpolating the raw input into the shell script body, closing a shell-injection vector on a free-form workflow_dispatch string. Scope GH_TOKEN to only the two steps that call the GitHub API (precondition validation, draft PR creation) instead of job-wide, so unrelated steps (checkout, build, npm install) never see it. Run the cleanup-identifiers step unconditionally (if: always()) and report the candidate branch independently of PR outputs, so a run that fails after pushing a branch but before opening a PR still prints something a reviewer can act on. Add regression tests asserting these properties against the parsed workflow YAML.
…t.closed release/plugins is artifact-only, so a pull_request-triggered workflow on that branch never finds a copy of itself to run. Switch tag-claude-plugin-release.yml to a workflow_dispatch that takes a merged PR number, verifies it live via the GitHub API (merged, correct base, head prefix, merge commit SHA), and fails closed on a non-main dispatch ref before trusting any helper script. Read the release version from the published .claude-plugin/plugin.json instead of a VERSION file, which release/plugins never carries. Scope GH_TOKEN to only the steps that call the GitHub API or push the tag.
ihmaws
approved these changes
Oct 13, 2026
ihmaws
previously approved these changes
Oct 13, 2026
validate-pr.yml already builds and strictly validates the Claude Code plugin on every PR, making the manual dry-run rehearsal redundant. It also pushed a real branch and opened a real draft PR into release/plugins with contents:write and pull-requests:write, which is unnecessary exposure for a rehearsal step. Removes the workflow and the scaffolding that existed only to support it: the dry-run-only --prefix option on derive-plugin-candidate-branch.sh and its tests, the workflow's own regression test file, and the test asserting both workflows called the shared candidate-commit script. Rewords comments and docstrings in validate-plugin-publish-preconditions.sh, compute-plugin-release-tag.sh, build-plugin-candidate-commit.sh, and the remaining tests that referenced the removed workflow, without changing their guard logic. Trims the CHANGELOG entry to match. The real publish path (candidate branch + draft PR into release/plugins, tagged via tag-claude-plugin-release.yml) is unchanged.
Point the .gitignore and validate-pr.yml comments at the current publish path (release/plugins via a candidate branch and draft PR) instead of the old claude-plugin branch, and drop the now-false "both shapes" claim since the repo-root plugin layout was removed. Also corrects the k-architect MCP row in agents.md: the five-tool allowedTools grant only applies on Kiro CLI. On Claude Code the agent's frontmatter grants the whole aws-mcp server via mcp__aws-mcp__*, which includes three additional AWS-API-acting tools.
build-plugin-candidate-commit.sh now reports committed=true|false (via GITHUB_OUTPUT and stdout), and release.yml's publish-claude-plugin job gates the branch push and draft-PR steps on it, with a new step that prints a clear notice and ends the job green when the assembled plugin tree already matches release/plugins' tip exactly. Before, those steps ran unconditionally and gh pr create failed with "No commits between", leaving a dangling pushed branch. Also binds every step output used in that job's run bodies through env instead of interpolating raw steps.*.outputs.* expressions directly, matching tag-claude-plugin-release.yml's existing convention.
…entials The manually built AUTHORIZATION header on the tag push was dead: the merge-commit checkout step already persists write-scoped credentials (actions/checkout's default persist-credentials behavior, enabled by this job's contents: write permission), so the header was ignored in favor of that persisted credential. Drops it and the now-unused GH_TOKEN binding on that step. Also adds a concurrency group to the job so two operator-triggered dispatches can't both pass "tag does not already exist" and then race to push the same immutable tag ref.
claude-plugin-check printed its success line even when both claude plugin validate calls were skipped because the CLI isn't on PATH. It now tracks whether validation actually ran and prints a distinct "validation skipped" notice instead of a false success claim. CI is unaffected: validate-pr.yml and release.yml both install the claude CLI first, so this only changes the message a developer sees locally without the CLI installed.
Adds the same [ -d "$d" ] || continue guard that copy-skills-with-collision-guard.sh already uses, so an unmatched sop-*/ glob doesn't get treated as a literal directory name.
simonkrol
previously approved these changes
Oct 13, 2026
ihmaws
previously approved these changes
Oct 13, 2026
Add the flag to reference.md's per-command flags table and link to it from the plugin marketplace install guide's AWS MCP section, where the plugin build already relies on it to select which dependencies.mcpRegistry entries get merged into rendered Claude Code agent frontmatter.
derive-plugin-candidate-branch.sh, build-plugin-candidate-commit.sh, and validate-plugin-publish-preconditions.sh each had their own copy of the main|mainline|release/plugins case statement. Extract it to a shared is_protected_branch helper in scripts/lib/protected-branches.sh that each script sources; each caller keeps its own error message, exit code, and the point in its flow where the check runs. Add test_protected_branches_lib.py for the helper itself.
ihmaws
approved these changes
Oct 14, 2026
simonkrol
approved these changes
Oct 14, 2026
3 tasks done
knihit
added a commit
that referenced
this pull request
Oct 16, 2026
doctor/power-cli ordering, harness-scoped uninstall cleanup, malformed- tag rejection, and binary --version validation all fix konductor-setup code that is part of this same unreleased [1.1.0] Power and never shipped on its own. Remove the entries instead of describing a fix to something nobody ever saw broken. PR #28's Claude plugin entries are unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Plugin marketplace:
.claude-plugin/marketplace.json, pointing thekonductorplugin entry at therelease/pluginsbranch (ref: "release/plugins"), notmain.docs/user-guide/tasks/install-claude-plugin-marketplace.md, covering/plugin marketplace add aws-solutions/konductorthen/plugin install konductor@konductor, plus theaws:ViaAWSMCPService/aws:CalledViaAWSMCPIAM condition keys for scoping AWS MCP access.generated/claude-plugin/README.mdand the generation scripts underscripts/(generate-claude-plugin.sh,assemble-claude-plugin-branch.sh,copy-skills-with-collision-guard.sh,render-claude-plugin-json.py,rewrite-claude-plugin-mcp-tool-names.py,read-bundled-mcp-servers.sh,claude-plugin.template.json). The plugin layout is a single flat tree undergenerated/claude-plugin/and the assembled candidate branch; there's no separate repo-rootplugin.json/.mcp.json.Makefiletargets:claude-pluginregenerates the flat tree,claude-plugin-checkregenerates and validates it (claude plugin validate --strict) with no commits or pushes. If theclaudeCLI isn't on PATH, it skips validation and reports that instead of a false pass. All generated output is gitignored.Release and publish flow (
release.yml):publish-claude-pluginjob runs afterpublishsucceeds on a push tomain. It assembles the flat plugin tree, builds a candidate commit on top ofrelease/plugins' current tip (scripts/build-plugin-candidate-commit.sh), pushes it to a freshplugin-candidate/...branch (scripts/derive-plugin-candidate-branch.sh), and opens a draft pull request into the protectedrelease/pluginsbranch.release/plugins' tip exactly (for example, a re-release of unchanged plugin content), the job skips the push and draft-PR steps and ends green with a notice instead of pushing an empty branch.release/pluginsitself is protected (branch ruleset blocks creation/update/deletion/non-fast-forward, zero bypass actors) and the org-wide ruleset requires two approvals, so a human has to merge the candidate PR.tag-claude-plugin-release.ymlcreates the immutableclaude-plugin-vX.Y.Ztag. It's manualworkflow_dispatch, run frommainwith the merged PR's number as input. It verifies the PR is actually merged, checks out the merge commit, confirms the published artifacts are present, and tags that commit. A concurrency group serializes dispatches so two runs can't race the same tag.build-plugin-candidate-commit.sh,derive-plugin-candidate-branch.sh, andvalidate-plugin-publish-preconditions.shnow share one protected-branch check,is_protected_branchinscripts/lib/protected-branches.sh, instead of each keeping its own copy of the case statement.plugin-publish-dry-run.ymlwas removed;validate-pr.ymlnow runsmake claude-plugin-check(built with the same pinnedclaudeCLI versionrelease.ymluses) on every PR, giving strict manifest validation without ever pushing a branch or opening a PR.AWS MCP bundling:
konductor synthtakes a new--claude-bundled-mcp-serversflag: a comma-separated allowlist ofdependencies.mcpRegistryserver names the Claude Code transformer may merge into an agent's renderedmcpServers:frontmatter. Omitted, the allowlist is empty and nothing gets merged; this is opt-in by design.scripts/claude-plugin-mcp-servers.jsonis this repo's own choice:aws-mcponly (notplaywright-mcp).k-architectandk-developer's agent specs now pinmcp-proxy-for-aws-cli==1.7.0directly independencies.mcpRegistry, replacing the earlier moving-version launch command. Both agents still grant the full AWS MCP tool surface.Docs:
docs/user-guide/README.md,docs/user-guide/agents.md,docs/user-guide/reference.md,docs/user-guide/tasks/README.md,docs/user-guide/tasks/install-claude-code.md: updated for the pinned MCP proxy and the plugin marketplace path.agents.mdnow spells out the Kiro CLI vs. Claude Code split fork-architect/k-developer's AWS MCP grant: Kiro CLI'sallowedToolsgrants five tools (doc search, doc read, skill retrieval, region list, regional availability), while Claude Code grants the whole server viamcp__aws-mcp__*(8 tools, including the three AWS-API-acting ones).reference.mdalso gains a flags-table row for the newsynth --claude-bundled-mcp-serversflag, linked from the marketplace install guide's AWS MCP section.README.md's "Optional integrations" section was restructured: AWS MCP gets its own subsection describing the pinned proxy and the IAM condition keys; Playwright, Slack, and Asana integrations are listed separately as user-configured.docs/user-guide/tasks/install-claude-plugin-marketplace.mdis new, as noted above.Other:
disable-model-invocation: true) on Claude Code rather than being skipped.Type of Change
cli/) change, Rustmcp-proxy-for-aws-clipin independencies.mcpRegistry)Testing
python3 -m pytest tests/ -q: 140 tests, 136 passed, 4 skipped.cargo test --release -- --test-threads=1(incli/konductor-rs, summed across every test binary): 1776 passed, 0 failed.make claude-plugin-check: both the marketplace manifest and the assembled flat plugin tree passclaude plugin validate --strict.actionlintagainst.github/workflows/*.yml: 0 findings.cd cli && make lint(clippy + fmt): clean.Checklist
cd cli && make lintpassesAgents Affected
Note: Names below are the post-Konductor-rebrand agent identifiers.
dependencies.mcpRegistrynow pinsmcp-proxy-for-aws-cli==1.7.0foraws-mcpNotes for Reviewers
release/pluginscurrently mirrorsmain's tree. The first candidate PR opened against it will replace that entire tree with the assembled plugin files (agents, skills, README, license, rendered.claude-plugin/plugin.json/.mcp.json), so its diff will show the source tree being deleted. That's expected, not a mistake in the candidate-build step.VERSIONbump in this PR;CHANGELOG.mdentries stay under[Unreleased].