Skip to content

Re-engineer the maister-copilot generator into a runnable Copilot CLI plugin - #10

Open
robmar-net wants to merge 9 commits into
SkillPanel:masterfrom
robmar-net:copilot-generator-remediation
Open

Re-engineer the maister-copilot generator into a runnable Copilot CLI plugin#10
robmar-net wants to merge 9 commits into
SkillPanel:masterfrom
robmar-net:copilot-generator-remediation

Conversation

@robmar-net

Copy link
Copy Markdown

Summary

Re-engineers the maister-copilot generator (platforms/copilot-cli/build.sh + Makefile + CI) so the generated plugin is a runnable, coherent GitHub Copilot CLI plugin — not just an installable one. All changes are generator-side; the Claude plugins/maister/ source is 100% untouched.

Why

An initial documentation-based analysis (see #8) concluded the port "was not faithfully runnable and needed re-engineering of the orchestration layer." Live testing against a real GitHub Copilot CLI 1.0.73 overturned that: maister-copilot is runnable, and maister's orchestration maps onto Copilot's primitives almost 1:1:

maister (Claude) Copilot CLI Verified live
Task(subagent_type: "maister:X") task(agent_type: "maister-copilot:X")
Skill("X") skill("X")
parallel waves task mode:"background" + read_agent/list_agents
AskUserQuestion ask_user
hooks/hooks.json (${CLAUDE_PLUGIN_ROOT}) plugin hooks.json, same format
.mcp.json, agents/*.md, skills/*/SKILL.md same (agents namespaced maister-copilot:<name>)

So the real defects were narrow and all generator-side: wrong reference naming and the generator deleting hooks/.

What changed

  • Reference naming (core): the flat s/maister:/maister-/g — which mangled every reference — is replaced by a registry-driven, kind-aware rewrite: agent refs → maister-copilot:<name> (plugin-id namespaced), skill/command refs → bare <name>. Name-set registries are built from the source tree with a pairwise-disjointness assertion, and the pass fails loud on any unknown token. Illustrative compound tokens (maister:x:y, e.g. product-design's /maister:feature:new "does-not-exist" example) are handled in-generator, so the Claude source needs no edit.
  • Keep hooks: removed rm -rf "$OUT/hooks". The Claude-format hooks.json (incl. ${CLAUDE_PLUGIN_ROOT}, SessionStart + PreToolUse) fires unchanged on Copilot — dropping it was a needless functional + safety regression (it includes the destructive-command guard).
  • Manifest & branding: plugin.json description → "…for GitHub Copilot CLI" (targeted string edit, no JSON round-trip); fixed the "Use ask_user instead of ask_user" ordering tautology; hardened the .claude/CLAUDE.md path rewrite; scrubbed "Claude Code" branding/URLs.
  • make validate hardening: new static checks (no wrong maister-<word> refs, string argument-hint, hooks/ present, no Claude-Code residue) + a check-deterministic target (byte-identical rebuild).
  • WS7 compatibility harness (platforms/copilot-cli/compat-tests/, make test-copilot): loads the freshly-built plugin into a live Copilot CLI and asserts 7 runtime contracts (plugin/skills/agents register, task+skill delegation, hooks fire, MCP loads); emits a version-stamped report; side-effect-free; supports an auth-free subset.
  • CI: a compat job runs the harness when a Copilot seat is provisioned (fails on any red contract), else skips with build+validate still gating. Purely additive — the existing build job is unchanged.

How it was tested

On GitHub Copilot CLI 1.0.73:

  • make build ✅ · make validate ✅ (existing 6 + new checks) · make check-deterministic ✅ (byte-identical rebuild) · provenance: only build.sh / Makefile / build-copilot.yml + new compat-tests/ are source edits.
  • make test-copilotGREEN, 7 PASS · 0 FAIL (plugin loads; 17 skills register, 0 failures; 25 agents resolve as maister-copilot:<name>; task(agent_type) delegation executes; skill(<name>) executes; SessionStart+PreToolUse hooks fire with ${CLAUDE_PLUGIN_ROOT}; .mcp.json loads).

Notes

  • Generator-only & deterministic: plugins/maister/ (the Claude plugin) has zero changes; rebuilds are byte-identical, so the existing CI auto-commit stays a no-op.
  • Regenerated plugins/maister-copilot/** is included so the branch is self-consistent (matches the repo's "Rebuild Copilot CLI variant" convention).
  • Copilot delegation is model-driven (it decides when to call task/skill); capability and addressability are proven, determinism is inherently softer than Claude's Task tool.

Refs #8, #9

🤖 Generated with Claude Code

robmar and others added 5 commits July 23, 2026 13:53
…est/branding

Replace the flat s/maister:/maister-/g with a registry-driven, kind-aware
reference rewrite: agent refs -> maister-copilot:<name> (plugin-id namespaced),
skill/command refs -> bare <name>. Fail-loud on unknown tokens; compound
illustrative tokens (maister:x:y) handled in-generator so the Claude source
stays 100% untouched. Stop deleting hooks/ (Claude-format hooks.json fires
as-is on Copilot). Fix plugin.json description, the ask_user ordering tautology,
the .claude/CLAUDE.md path garble, and Claude-Code branding residue.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extend validate with checks for wrong maister-<word> refs, string argument-hint,
hooks/ presence, and Claude-Code residue. Add check-deterministic (byte-identical
rebuild) and test-copilot (runs the WS7 harness) targets.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Load the freshly-built plugin into a live Copilot CLI and assert 7 runtime
contracts (plugin/skills/agents register, task+skill delegation, hooks fire,
mcp loads). Emits a version-stamped report; supports an auth-free subset.
Side-effect-free (isolation trap restores the operator config).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a compat job that runs the harness when a Copilot seat is provisioned
(fails on any red contract, uploads the report), else skips with build+validate
still gating. Purely additive; the build job is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
robmar and others added 4 commits July 23, 2026 15:15
…residual in validate

The committed maister-copilot output carried un-converted AskUserQuestion in 8
skill files (a non-existent tool on Copilot) — the regenerate commit captured a
stale tree. A clean rebuild converts them to ask_user. Add a validate check
(WS5.9) forbidding AskUserQuestion residual in skills/commands/agents so this
class of staleness fails the build instead of shipping.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot's PreToolUse hook payload carries no agent identifier (verified live on
1.0.73 — not in stdin, not in any Copilot env var), so the Claude guard's
subagent-scoped agent_type gating is a silent no-op there. Ship a Copilot-specific
override that asks the user to confirm any destructive command (permissionDecision
"ask") — Copilot honors it and does NOT bypass it under --allow-all-tools (held
in headless = fail-closed). Better than the no-op (no protection) and than a
blanket deny (which would block the main agent's legitimate destructive commands).

build.sh (WS2b) overlays platforms/copilot-cli/hooks-overrides/ over the output
hook; the Claude source hook stays untouched. make validate WS5.10 guards it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
L0 proves the three maister hooks fire; L1 verifies each hook's EFFECT and
honestly reports no-ops. Findings on Copilot CLI 1.0.73:
- skill-invocation-reminder: PASS (additionalContext injected).
- post-compact-reminder: env dep satisfied — Copilot sets $CLAUDE_PROJECT_DIR
  in the hook env (verified under a sanitized env); compact matcher unverified.
- block-destructive-commands: LIMITATION — Copilot's PreToolUse payload omits
  any agent identifier, so the subagent-scoped guard never triggers (deny IS
  honored and tool_input.command matches; only the agent gating is inert).

Detection only — hooks unchanged. Side-effect-free; --no-live subset for CI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uirement)

Pin actions/upload-artifact@v4 -> @ea165f8d65b6e75b540449e92b4886f43607fa02
(v4.6.2) so the repo can enforce sha_pinning_required in Actions settings
without breaking this workflow. Supply-chain hardening: a moved/compromised
v4 tag can no longer silently change what runs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhRYoDBTTtWoKG1h7sH5t
@robmar-net

Copy link
Copy Markdown
Author

Update — three commits added to this PR (all still Copilot-only; the Claude plugins/maister/ source stays untouched, and rebuilds remain byte-identical):

  1. feat(copilot-gen): adapt destructive-command guard to 'ask' — live hook testing found the destructive-command guard is a silent no-op on Copilot: it keys on an agent_type that Copilot's PreToolUse payload never carries (verified on 1.0.73 — not in stdin, not in any env var). A generator override (build.sh WS2b) replaces only the output guard with a variant that asks the user to confirm any destructive command (permissionDecision: "ask"), which Copilot honors and does not bypass under --allow-all-tools (held in headless = fail-closed). Rationale is documented in the hook's header comment; make validate WS5.10 guards it.
  2. test(copilot-gen): L1 hook-effect checks (make test-hooks) — a committed harness that verifies each hook's effect (not just that it fires) on a live Copilot CLI: skill-invocation reminder reaches the model; post-compact reminder's env dep is satisfied (Copilot sets $CLAUDE_PROJECT_DIR); and the destructive guard now gates (a subagent's rm -rf is held). make test-hooks → 5 PASS · 0 FAIL. See compat-tests/L1-FINDINGS.md.
  3. ci: pin actions/upload-artifact to a commit SHA — supply-chain hardening so the workflow survives sha_pinning_required.

All verified against Copilot CLI 1.0.73: make build · make validate (incl. the new WS5.9/WS5.10 checks) · make check-deterministic (byte-identical) · make test-copilot (7 runtime contracts) · make test-hooks (hook effects).

Refs #8, #9

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