diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json new file mode 100644 index 00000000..747ddf8b --- /dev/null +++ b/.claude-plugin/marketplace.json @@ -0,0 +1,20 @@ +{ + "name": "ado-aw", + "metadata": { + "description": "Azure DevOps Agentic Workflows (ado-aw) marketplace", + "version": "0.38.0" + }, + "owner": { + "name": "GitHub Next", + "url": "https://github.com/githubnext/ado-aw" + }, + "plugins": [ + { + "name": "ado-aw", + "source": "./agency/plugins/ado-aw", + "version": "0.38.0", + "description": "Create, update, validate, operate, and debug Azure DevOps agentic workflows with ado-aw", + "keywords": ["azure-devops", "ado", "agentic", "pipelines", "ado-aw"] + } + ] +} diff --git a/.gitattributes b/.gitattributes index 0ff4ac97..0b0ef50a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,6 +3,12 @@ # Install scripts must always be LF (executed on Linux/macOS via curl|sh). scripts/install/*.sh text eol=lf scripts/install/*.ps1 text eol=lf +# Agency plugin is a Linux/macOS-consumed artifact (and release-please rewrites +# it on Linux CI) — keep every text file LF. +agency/plugins/** text eol=lf +# Generated marketplace catalogs (release-please rewrites on Linux CI). +.claude-plugin/marketplace.json text eol=lf +.github/plugin/marketplace.json text eol=lf # BEGIN ado-aw managed (do not edit) tests/fixtures/job-agent.lock.yml linguist-generated=true merge=ours text eol=lf tests/fixtures/runtime_imports_author_marker_job.lock.yml linguist-generated=true merge=ours text eol=lf diff --git a/.github/agents/ado-aw.agent.md b/.github/agents/ado-aw.agent.md index d194b89d..e6fd5f76 100644 --- a/.github/agents/ado-aw.agent.md +++ b/.github/agents/ado-aw.agent.md @@ -1,11 +1,11 @@ --- -description: Azure DevOps Agentic Pipelines (ado-aw) - Create, update, and debug AI-powered ADO pipelines +description: Azure DevOps Agentic Workflows (ado-aw) - Create, update, and debug AI-powered Azure DevOps agentic workflows disable-model-invocation: true --- -# ADO Agentic Pipelines Agent +# Azure DevOps Agentic Workflows Agent -This agent helps you create and manage Azure DevOps agentic pipelines using **ado-aw**. +This agent helps you create and manage Azure DevOps agentic workflows using **ado-aw**. ado-aw compiles human-friendly markdown files with YAML front matter into secure, multi-stage Azure DevOps pipelines that run AI agents in network-isolated sandboxes. @@ -37,39 +37,39 @@ Verify: `ado-aw --version` This is a **dispatcher agent** that routes your request to the appropriate specialized prompt: -- **Creating new agentic pipelines** → Routes to the create prompt -- **Updating existing pipelines** → Routes to the update prompt -- **Debugging failing pipelines** → Routes to the debug prompt +- **Creating new agentic workflows** → Routes to the create prompt +- **Updating existing workflows** → Routes to the update prompt +- **Debugging failing workflows** → Routes to the debug prompt ## Available Prompts -### Create New Agentic Pipeline -**Load when**: User wants to create a new agentic pipeline from scratch +### Create New Agentic Workflow +**Load when**: User wants to create a new agentic workflow from scratch -**Prompt file**: https://raw.githubusercontent.com/githubnext/ado-aw/v0.16.0/prompts/create-ado-agentic-workflow.md +**Prompt file**: https://raw.githubusercontent.com/githubnext/ado-aw/v0.38.0/prompts/create-ado-agentic-workflow.md **Use cases**: -- "Create an agentic pipeline that reviews PRs weekly" -- "I need a pipeline that triages work items daily" +- "Create an agentic workflow that reviews PRs weekly" +- "I need a workflow that triages work items daily" - "Design a scheduled dependency updater" -### Update Existing Pipeline +### Update Existing Workflow **Load when**: User wants to modify an existing agent workflow file -**Prompt file**: https://raw.githubusercontent.com/githubnext/ado-aw/v0.16.0/prompts/update-ado-agentic-workflow.md +**Prompt file**: https://raw.githubusercontent.com/githubnext/ado-aw/v0.38.0/prompts/update-ado-agentic-workflow.md **Use cases**: -- "Add the Azure DevOps MCP to my pipeline" +- "Add the Azure DevOps MCP to my workflow" - "Change the schedule from daily to weekly" - "Add work item creation as a safe output" -### Debug Failing Pipeline -**Load when**: User needs to troubleshoot a failing agentic pipeline +### Debug Failing Workflow +**Load when**: User needs to troubleshoot a failing agentic workflow -**Prompt file**: https://raw.githubusercontent.com/githubnext/ado-aw/v0.16.0/prompts/debug-ado-agentic-workflow.md +**Prompt file**: https://raw.githubusercontent.com/githubnext/ado-aw/v0.38.0/prompts/debug-ado-agentic-workflow.md **Use cases**: -- "Why is my agentic pipeline failing?" +- "Why is my agentic workflow failing?" - "The agent can't reach the MCP server" - "Safe outputs aren't being processed" @@ -92,12 +92,12 @@ ado-aw compile ado-aw compile # Verify pipeline matches source -ado-aw check +ado-aw check ``` ## Key Features -- **Natural language pipelines**: Write in markdown with YAML frontmatter +- **Natural language workflows**: Write in markdown with YAML frontmatter - **3-stage security**: Agent → Threat Analysis → Safe Output Execution - **Network isolation**: AWF (Agentic Workflow Firewall) with domain whitelisting - **MCP Gateway**: Tool routing for Azure DevOps, custom MCPs @@ -109,4 +109,4 @@ ado-aw check - Agent files must be compiled with `ado-aw compile` after YAML frontmatter changes - Markdown body (agent instructions) changes do NOT require recompilation - The agent never has direct write access — all mutations go through safe outputs -- Full reference: https://raw.githubusercontent.com/githubnext/ado-aw/v0.16.0/AGENTS.md +- Full reference: https://raw.githubusercontent.com/githubnext/ado-aw/v0.38.0/AGENTS.md diff --git a/.github/plugin/marketplace.json b/.github/plugin/marketplace.json new file mode 100644 index 00000000..747ddf8b --- /dev/null +++ b/.github/plugin/marketplace.json @@ -0,0 +1,20 @@ +{ + "name": "ado-aw", + "metadata": { + "description": "Azure DevOps Agentic Workflows (ado-aw) marketplace", + "version": "0.38.0" + }, + "owner": { + "name": "GitHub Next", + "url": "https://github.com/githubnext/ado-aw" + }, + "plugins": [ + { + "name": "ado-aw", + "source": "./agency/plugins/ado-aw", + "version": "0.38.0", + "description": "Create, update, validate, operate, and debug Azure DevOps agentic workflows with ado-aw", + "keywords": ["azure-devops", "ado", "agentic", "pipelines", "ado-aw"] + } + ] +} diff --git a/AGENTS.md b/AGENTS.md index 7841734d..e1882c30 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,4 +1,4 @@ -# Copilot Instructions for Azure DevOps Agentic Pipelines +# Copilot Instructions for Azure DevOps Agentic Workflows This repository contains a compiler for Azure DevOps pipelines that transforms natural language markdown files with YAML front matter into Azure DevOps @@ -102,8 +102,21 @@ Every compiled pipeline runs as three sequential jobs: │ │ │ ├── 0002_pool_object_form.rs # Legacy scalar pool → object form codemod │ │ │ └── helpers.rs # take_key, insert_no_overwrite, rename_key, ConflictPolicy │ │ ├── codemod_integration_test.rs # White-box rewrite-path tests (stub registry injection) -│ │ └── types.rs # Front matter grammar and types -│ ├── init.rs # Repository initialization for AI-first authoring +│ │ ├── types.rs # Front matter grammar and types +│ │ └── ir/ # Typed Azure DevOps pipeline IR (see docs/ir.md) +│ │ ├── mod.rs # Pipeline / PipelineBody / PipelineShape root types +│ │ ├── ids.rs # Typed StageId / JobId / StepId newtypes +│ │ ├── step.rs # Step variants (Bash, Task, Checkout, Download, Publish, RawYaml) +│ │ ├── job.rs # Job, Pool, TemplateContext, JobVariable +│ │ ├── stage.rs # Stage + external-params wrap +│ │ ├── env.rs # Typed EnvValue (Literal, AdoMacro, PipelineVar, Secret, StepOutput, Coalesce, Concat) +│ │ ├── condition.rs # Typed Condition / Expr AST + codegen to ADO condition syntax +│ │ ├── output.rs # OutputDecl / OutputRef + location-aware lowering +│ │ ├── graph.rs # Dependency graph: validation, edge derivation, isOutput promotion, cycle detection +│ │ ├── lower.rs # IR → serde_yaml::Value lowering +│ │ ├── emit.rs # Thin `lower() + serde_yaml::to_string()` wrapper +│ │ └── summary.rs # Public, serializable PipelineSummary / GraphSummary for agent-facing tooling (see docs/ir.md Public JSON summary) +│ ├── init.rs # Repository initialization for AI-first authoring (incl. `--agency` plugin scaffold, embeds agency/plugins/ado-aw/ via include_str!) │ ├── execute.rs # Stage 3 safe output execution │ ├── fuzzy_schedule.rs # Fuzzy schedule parsing │ ├── logging.rs # File-based logging infrastructure @@ -154,7 +167,7 @@ Every compiled pipeline runs as three sequential jobs: │ │ ├── whatif.rs # `ado-aw whatif`: static downstream skip classification for failures │ │ ├── lint.rs # `ado-aw lint`: structural workflow lint checks │ │ └── catalog.rs # `ado-aw catalog`: list in-tree registries (tools, runtimes, models, etc.) -│ ├── detect.rs # Agentic pipeline detection — discovers compiled pipelines; used by all lifecycle commands +│ ├── detect.rs # Agentic workflow detection — discovers compiled pipelines; used by all lifecycle commands │ ├── update_check.rs # Version update check — queries GitHub Releases and prints advisory when newer version is available │ ├── ndjson.rs # NDJSON parsing utilities │ ├── sanitize.rs # Input sanitization for safe outputs @@ -217,11 +230,21 @@ Every compiled pipeline runs as three sequential jobs: │ ├── extension.rs # CompilerExtension impl (compile-time) │ └── execute.rs # Stage 3 runtime (validate/copy) ├── ado-aw-derive/ # Proc-macro crate: #[derive(SanitizeConfig)], #[derive(SanitizeContent)] +├── .claude-plugin/ # Root Claude marketplace catalog (makes the repo installable via `/plugin marketplace add`); release-please-versioned +│ └── marketplace.json # Lists the ado-aw plugin with source ./agency/plugins/ado-aw +├── agency/ # Agency / Claude Code marketplace plugin (canonical source of truth) +│ └── plugins/ado-aw/ # Version-locked plugin (release-please bumps version + pinned prompt URLs); listed in Agency marketplace via external `source`; scaffolded into consumer repos by `ado-aw init --agency` +│ ├── .claude-plugin/ # plugin.json (manifest) +│ ├── .mcp.json # Wires read-only `ado-aw mcp-author` stdio server +│ ├── agency.json # Marketplace governance metadata + external source pointer +│ ├── agents/ado-aw.md # Dispatcher subagent +│ ├── skills/ # 6 SKILL.md playbooks (create/update/debug-workflow, compile-and-validate, manage-lifecycle, audit-build) +│ └── scripts/ # doctor.{sh,ps1} prerequisite checks ├── examples/ # Example agent definitions ├── prompts/ # AI agent prompt files for workflow authoring tasks -│ ├── create-ado-agentic-workflow.md # Step-by-step guide for creating a new agentic pipeline -│ ├── update-ado-agentic-workflow.md # Guide for modifying an existing agentic pipeline -│ └── debug-ado-agentic-workflow.md # Guide for troubleshooting a failing agentic pipeline +│ ├── create-ado-agentic-workflow.md # Step-by-step guide for creating a new agentic workflow +│ ├── update-ado-agentic-workflow.md # Guide for modifying an existing agentic workflow +│ └── debug-ado-agentic-workflow.md # Guide for troubleshooting a failing agentic workflow ├── scripts/ # Supporting scripts shipped as release artifacts │ └── ado-script/ # TypeScript workspace for bundled gate.js, import.js, exec-context-pr.js, exec-context-pr-synth.js │ └── src/ @@ -255,11 +278,11 @@ index to jump to the right page. ### Prompt files for workflow authoring - [`prompts/create-ado-agentic-workflow.md`](prompts/create-ado-agentic-workflow.md) — step-by-step - guide for creating a new agentic pipeline from scratch (interactive and non-interactive modes). + guide for creating a new agentic workflow from scratch (interactive and non-interactive modes). - [`prompts/update-ado-agentic-workflow.md`](prompts/update-ado-agentic-workflow.md) — guide for - modifying an existing agentic pipeline (read-then-update workflow with validation). + modifying an existing agentic workflow (read-then-update workflow with validation). - [`prompts/debug-ado-agentic-workflow.md`](prompts/debug-ado-agentic-workflow.md) — guide for - troubleshooting a failing agentic pipeline and filing a diagnostic report. + troubleshooting a failing agentic workflow and filing a diagnostic report. ### Authoring agent files @@ -311,6 +334,10 @@ index to jump to the right page. - [`docs/cli.md`](docs/cli.md) — `ado-aw` CLI commands (`init`, `compile`, `check`, `mcp`, `mcp-http`, `execute`, `secrets`, `enable`, `disable`, `remove`, `list`, `status`, `run`, `audit`; `configure` is a deprecated hidden alias). +- [`docs/agency-plugin.md`](docs/agency-plugin.md) — the Agency / Claude Code + plugin (`agency/plugins/ado-aw/`): canonical layout, six skills, `mcp-author` + wiring, the self-contained root marketplace catalogs, `init --agency` + scaffolding, release-please version-locking, and shared-marketplace listing. - [`docs/audit.md`](docs/audit.md) — `ado-aw audit`: accepted build-id / URL forms, artifact layout, cache behavior, rejection tracing, and `AuditData` report shape. @@ -449,10 +476,10 @@ the bash body — shellcheck honours the directive and it's inert at runtime. cargo run -- compile ./path/to/agent.md ``` -### Recompile all agentic pipelines in the current directory +### Recompile all agentic workflows in the current directory ```bash -# Auto-discovers and recompiles all detected agentic pipelines +# Auto-discovers and recompiles all detected agentic workflows cargo run -- compile ``` diff --git a/README.md b/README.md index 9186077b..302ee0de 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # ado-aw -An agentic pipeline compiler for Azure DevOps. Write pipeline definitions in -human-friendly markdown, compile them into secure, multi-stage Azure DevOps -pipelines that run AI agents in network-isolated sandboxes. +**Azure DevOps Agentic Workflows.** Write agentic workflows in human-friendly +markdown; ado-aw compiles each into a secure, multi-stage Azure DevOps pipeline +that runs an AI agent in a network-isolated sandbox. Inspired by [GitHub Agentic Workflows (gh-aw)](https://github.com/githubnext/gh-aw). @@ -71,7 +71,7 @@ If you see `The Process object must have the UseShellExecute property set to fal ado-aw init ``` -This creates a Copilot agent at `.github/agents/ado-aw.agent.md` that helps you create, update, and debug agentic pipelines. The agent automatically downloads the ado-aw compiler and handles compilation. +This creates a Copilot agent at `.github/agents/ado-aw.agent.md` that helps you create, update, and debug agentic workflows. The agent automatically downloads the ado-aw compiler and handles compilation. ### 3. Create an Agent with AI @@ -87,7 +87,7 @@ and open PRs to update them. Or if you've run `ado-aw init`, simply ask your AI agent: ``` -Create an agentic pipeline that checks for outdated dependencies and opens PRs +Create an agentic workflow that checks for outdated dependencies and opens PRs ``` The AI will generate a markdown file like: @@ -521,7 +521,7 @@ network: ado-aw [OPTIONS] Commands: - init Initialize a repository for AI-first agentic pipeline authoring + init Initialize a repository for AI-first agentic workflow authoring compile Compile markdown to pipeline definition check Verify a compiled pipeline matches its source mcp Run as an MCP server (safe outputs) @@ -567,9 +567,9 @@ ado-aw provides specialized prompt files that guide AI agents through common tas | Task | Prompt URL | Description | |------|-----------|-------------| -| Create a workflow | [create-ado-agentic-workflow.md](prompts/create-ado-agentic-workflow.md) | Step-by-step guide for creating a new agentic pipeline from scratch | +| Create a workflow | [create-ado-agentic-workflow.md](prompts/create-ado-agentic-workflow.md) | Step-by-step guide for creating a new agentic workflow from scratch | | Update a workflow | [update-ado-agentic-workflow.md](prompts/update-ado-agentic-workflow.md) | Guide for modifying existing agent workflows | -| Debug a pipeline | [debug-ado-agentic-workflow.md](prompts/debug-ado-agentic-workflow.md) | Troubleshoot failing agentic pipelines | +| Debug a workflow | [debug-ado-agentic-workflow.md](prompts/debug-ado-agentic-workflow.md) | Troubleshoot failing agentic workflows | ### Using Prompts with Your AI Agent diff --git a/agency/plugins/ado-aw/.claude-plugin/plugin.json b/agency/plugins/ado-aw/.claude-plugin/plugin.json new file mode 100644 index 00000000..77781a4b --- /dev/null +++ b/agency/plugins/ado-aw/.claude-plugin/plugin.json @@ -0,0 +1,23 @@ +{ + "name": "ado-aw", + "version": "0.38.0", + "description": "Azure DevOps Agentic Workflows (ado-aw) — create, update, validate, operate, and debug AI-powered Azure DevOps agentic workflows: Markdown agent specs compiled into secure, network-isolated ADO pipelines.", + "author": { + "name": "GitHub Next", + "url": "https://github.com/githubnext/ado-aw" + }, + "homepage": "https://github.com/githubnext/ado-aw", + "repository": "https://github.com/githubnext/ado-aw", + "license": "MIT", + "keywords": [ + "azure-devops", + "ado", + "agentic", + "pipelines", + "ado-aw", + "safe-outputs", + "compiler", + "automation" + ], + "mcpServers": "./.mcp.json" +} diff --git a/agency/plugins/ado-aw/.mcp.json b/agency/plugins/ado-aw/.mcp.json new file mode 100644 index 00000000..ef3ae5b1 --- /dev/null +++ b/agency/plugins/ado-aw/.mcp.json @@ -0,0 +1,10 @@ +{ + "mcpServers": { + "ado-aw": { + "command": "ado-aw", + "type": "local", + "args": ["mcp-author"], + "tools": ["*"] + } + } +} diff --git a/agency/plugins/ado-aw/README.md b/agency/plugins/ado-aw/README.md new file mode 100644 index 00000000..a84a82a6 --- /dev/null +++ b/agency/plugins/ado-aw/README.md @@ -0,0 +1,80 @@ +# ado-aw — Azure DevOps Agentic Workflows + +Author, compile, validate, operate, and debug **ado-aw** agentic workflows for +Azure DevOps from your agent (Claude Code or Copilot CLI). Each agentic workflow +compiles to a secure, multi-stage Azure DevOps pipeline. + +[ado-aw](https://github.com/githubnext/ado-aw) compiles human-friendly Markdown +agent specs (Markdown body + YAML front matter) into secure, multi-stage Azure +DevOps pipelines that run AI agents in network-isolated sandboxes. Every compiled +pipeline runs three sequential jobs: + +1. **Agent** — runs the AI agent in an AWF network-isolated sandbox with a + read-only ADO token, producing *safe-output proposals* (not direct actions). +2. **Detection** — a separate agent inspects the proposals for prompt injection, + secret leaks, and other threats. +3. **SafeOutputs** — a non-agent executor applies approved safe outputs with a + write-capable token the agent never sees. + +## What this plugin provides + +- A dispatcher **agent** (`agents/ado-aw.md`) that routes authoring/ops requests. +- A read-only **MCP server** wired via `.mcp.json` to `ado-aw mcp-author` + (inspect / graph / lint / whatif / trace / audit / catalog). +- Six **skills**: + - `create-workflow` — author a new pipeline from scratch (compile + lint). + - `update-workflow` — read-then-update an existing pipeline with validation. + - `debug-workflow` — diagnose a failing pipeline (`trace_failure`, `audit_build`). + - `compile-and-validate` — `ado-aw compile` + `lint_workflow` + IR/graph inspection. + - `manage-lifecycle` — enable / disable / remove / run / list / status / secrets. + - `audit-build` — download and analyze a finished build's artifacts. + +## Installing + +This repository is itself an installable plugin marketplace — the root +`.claude-plugin/marketplace.json` (Claude) and `.github/plugin/marketplace.json` +(Copilot) catalogs register the `ado-aw` plugin (whose files live under +`agency/plugins/ado-aw/`). From your agent: + +```text +/plugin marketplace add githubnext/ado-aw +/plugin install ado-aw@ado-aw +``` + +`ado-aw init --agency` scaffolds the same catalogs + plugin into a consumer repo, +so that repo becomes registerable the same way. + +## Prerequisites + +The `ado-aw` compiler must be on `PATH`. Run the bundled doctor check first: + +```bash +bash ./scripts/doctor.sh # macOS / Linux +``` +```powershell +.\scripts\doctor.ps1 # Windows +``` + +If `ado-aw` is missing, install it from the +[releases page](https://github.com/githubnext/ado-aw/releases/latest). ADO-facing +skills (`debug-workflow`, `audit-build`, `manage-lifecycle`) additionally rely on +`gh`/`az` auth or an ADO PAT, resolved through ado-aw's normal auth path. + +## Security model + +This plugin adds **no new write paths**. It only adds a read-only MCP server plus +`ado-aw` CLI invocations the user could already run. All mutation stays inside +ado-aw's three-stage safe-output model. No remote MCP endpoints are introduced +and no secrets are stored in the plugin tree. + +## Source of truth & versioning + +The canonical plugin lives in the ado-aw repository at +[`agency/plugins/ado-aw`](https://github.com/githubnext/ado-aw/tree/main/agency/plugins/ado-aw) +and is **version-locked to the compiler**: release automation bumps the plugin +version and the pinned prompt URLs in lock-step with each ado-aw release. The +Agency marketplace lists it via an external `source` pointer (`agency.json`). + +## License + +MIT — see the [ado-aw repository](https://github.com/githubnext/ado-aw). diff --git a/agency/plugins/ado-aw/agency.json b/agency/plugins/ado-aw/agency.json new file mode 100644 index 00000000..1c06c642 --- /dev/null +++ b/agency/plugins/ado-aw/agency.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://github.com/agency-microsoft/.github-private/agency.schema.json", + "engines": ["claude", "copilot"], + "category": "developer-tools", + "platforms": ["windows", "macos", "linux"], + "governance": { + "layer": 4, + "certification": "draft", + "organization": "github-next" + }, + "source": { + "source": "github", + "url": "https://github.com/githubnext/ado-aw.git", + "path": "agency/plugins/ado-aw" + }, + "permissions": { + "mcpServers": ["ado-aw"], + "tools": ["*"], + "fileAccess": "read-write" + }, + "requirements": { + "ado-aw": { + "description": "The ado-aw compiler binary must be on PATH. The local mcp-author stdio server (read-only inspect/graph/lint/whatif/trace/audit/catalog) is launched as `ado-aw mcp-author`. ADO-facing tools (trace, audit) reuse ado-aw's normal auth resolution (explicit PAT, environment, or Azure CLI)." + } + } +} diff --git a/agency/plugins/ado-aw/agents/ado-aw.md b/agency/plugins/ado-aw/agents/ado-aw.md new file mode 100644 index 00000000..ee465c49 --- /dev/null +++ b/agency/plugins/ado-aw/agents/ado-aw.md @@ -0,0 +1,85 @@ +--- +name: ado-aw +description: Create, update, validate, operate, and debug Azure DevOps agentic workflows using ado-aw. Use when the user wants to author, modify, compile, run, or troubleshoot AI-powered Azure DevOps agentic workflows written as Markdown agent files (each compiles to a secure, network-isolated ADO pipeline). +--- + +# Azure DevOps Agentic Workflows Agent + +This agent helps you author and manage Azure DevOps agentic workflows using +**ado-aw**. + +ado-aw compiles human-friendly Markdown files with YAML front matter into +secure, multi-stage Azure DevOps pipelines that run AI agents in +network-isolated sandboxes (Agent → Threat Detection → Safe-Output Execution). + +## Prerequisites + +Before doing anything else, make sure the ado-aw compiler is available — run the +**doctor** check (`bash scripts/doctor.sh` on macOS/Linux, `scripts/doctor.ps1` on +Windows). It verifies `ado-aw` is on `PATH` and that `gh`/`az` auth is present +where ADO calls are needed. If `ado-aw` is missing, install it: + +```bash +# Linux +curl -fsSL https://github.com/githubnext/ado-aw/releases/latest/download/install-linux.sh | sh +# macOS (Apple Silicon) +curl -fsSL https://github.com/githubnext/ado-aw/releases/latest/download/install-macos.sh | sh +# Windows (PowerShell) +powershell -ExecutionPolicy Bypass -NoProfile -Command "iwr https://github.com/githubnext/ado-aw/releases/latest/download/install-windows.ps1 -UseBasicParsing | iex" +``` + +Verify: `ado-aw --version` + +## Read-only MCP tools + +This plugin wires the local, read-only **`ado-aw mcp-author`** server (see +`.mcp.json`). Prefer these tools over shelling out when you only need to inspect: + +- `inspect_workflow`, `graph_summary`, `graph_dump`, `step_dependencies`, `step_outputs` +- `lint_workflow`, `whatif`, `catalog` +- `trace_failure`, `audit_build` (ADO read auth) + +Mutating actions are **not** in the MCP server. Use the `ado-aw` CLI (via Bash) +for `compile`, `enable`, `disable`, `remove`, `run`, `list`, `status`, +`secrets`, `init` — gated by the guardrails below. + +## Capability routing + +Route the user's request to the matching skill: + +| The user wants to… | Skill | +| --- | --- | +| Create a new workflow from scratch | `create-workflow` | +| Change an existing workflow | `update-workflow` | +| Understand why a pipeline failed | `debug-workflow` | +| Compile / confirm a workflow is valid | `compile-and-validate` | +| Enable / disable / run / check status | `manage-lifecycle` | +| Analyze a finished build | `audit-build` | + +## Authoritative prompts (version-pinned) + +The create/update/debug skills load these compiler-version-pinned playbooks: + +- Create: https://raw.githubusercontent.com/githubnext/ado-aw/v0.38.0/prompts/create-ado-agentic-workflow.md +- Update: https://raw.githubusercontent.com/githubnext/ado-aw/v0.38.0/prompts/update-ado-agentic-workflow.md +- Debug: https://raw.githubusercontent.com/githubnext/ado-aw/v0.38.0/prompts/debug-ado-agentic-workflow.md +- Full reference: https://raw.githubusercontent.com/githubnext/ado-aw/v0.38.0/AGENTS.md + +## Guardrails + +- Never bypass ado-aw's three-stage safe-output model or fabricate write tokens. + The agent never has direct write access — all mutations go through safe outputs. +- Always `ado-aw compile` **and** `lint_workflow` before declaring a workflow done. +- Agent files must be recompiled with `ado-aw compile` after YAML front-matter + changes; Markdown-body-only changes do not require recompilation. +- Never push directly to a protected branch — use ado-aw's own flow. +- Surface ADO auth/permission errors verbatim with the doc pointer + (`docs/safe-output-permissions.md`). + +## Quick reference + +```bash +ado-aw compile # compile one agent file to pipeline YAML +ado-aw compile # recompile all detected pipelines +ado-aw check # verify a pipeline matches its source +``` diff --git a/agency/plugins/ado-aw/scripts/doctor.ps1 b/agency/plugins/ado-aw/scripts/doctor.ps1 new file mode 100644 index 00000000..11c02184 --- /dev/null +++ b/agency/plugins/ado-aw/scripts/doctor.ps1 @@ -0,0 +1,56 @@ +#!/usr/bin/env pwsh +# doctor.ps1 - verify prerequisites for the ado-aw Agency plugin. +# +# Checks: +# 1. `ado-aw` is on PATH (else point to the install docs). +# 2. `gh` and `az` availability + auth (advisory - only needed for ADO-facing +# skills: debug-workflow, audit-build, manage-lifecycle). +# +# Exit code is non-zero only when a hard requirement (ado-aw) is missing. +$ErrorActionPreference = 'Stop' + +function Write-Ok($m) { Write-Host " [ok] $m" -ForegroundColor Green } +function Write-Warn($m) { Write-Host " [warn] $m" -ForegroundColor Yellow } +function Write-Err($m) { Write-Host " [fail] $m" -ForegroundColor Red } + +$hardFail = $false + +Write-Host "ado-aw plugin doctor" +Write-Host "" + +# 1. ado-aw (hard requirement) +if (Get-Command ado-aw -ErrorAction SilentlyContinue) { + $version = (ado-aw --version 2>$null) + if (-not $version) { $version = 'unknown' } + Write-Ok "ado-aw found: $version" +} else { + Write-Err "ado-aw not found on PATH" + Write-Host ' Install it (PowerShell):' + Write-Host ' powershell -ExecutionPolicy Bypass -NoProfile -Command "iwr https://github.com/githubnext/ado-aw/releases/latest/download/install-windows.ps1 -UseBasicParsing | iex"' + Write-Host ' Docs: https://github.com/githubnext/ado-aw/releases/latest' + $hardFail = $true +} + +# 2. ADO auth helpers (advisory) +if (Get-Command gh -ErrorAction SilentlyContinue) { + gh auth status *> $null + if ($LASTEXITCODE -eq 0) { Write-Ok "gh authenticated" } + else { Write-Warn "gh found but not authenticated (run 'gh auth login' for GitHub-backed flows)" } +} else { + Write-Warn "gh not found (optional; needed for some GitHub-backed flows)" +} + +if (Get-Command az -ErrorAction SilentlyContinue) { + az account show *> $null + if ($LASTEXITCODE -eq 0) { Write-Ok "az authenticated" } + else { Write-Warn "az found but not logged in (run 'az login' for ADO trace/audit/lifecycle skills)" } +} else { + Write-Warn "az not found (optional; ADO-facing skills can also use an explicit PAT)" +} + +Write-Host "" +if ($hardFail) { + Write-Err "Missing required tool(s). Install ado-aw before using this plugin." + exit 1 +} +Write-Ok "All required prerequisites satisfied." diff --git a/agency/plugins/ado-aw/scripts/doctor.sh b/agency/plugins/ado-aw/scripts/doctor.sh new file mode 100755 index 00000000..efd72f00 --- /dev/null +++ b/agency/plugins/ado-aw/scripts/doctor.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# doctor.sh - verify prerequisites for the ado-aw Agency plugin. +# +# Checks: +# 1. `ado-aw` is on PATH (else point to the install docs). +# 2. `gh` and `az` availability + auth (advisory - only needed for ADO-facing +# skills: debug-workflow, audit-build, manage-lifecycle). +# +# Exit code is non-zero only when a hard requirement (ado-aw) is missing. +set -euo pipefail + +ok() { printf ' \033[32m✓\033[0m %s\n' "$1"; } +warn() { printf ' \033[33m!\033[0m %s\n' "$1"; } +err() { printf ' \033[31m✗\033[0m %s\n' "$1"; } + +hard_fail=0 + +echo "ado-aw plugin doctor" +echo + +# 1. ado-aw (hard requirement) +if command -v ado-aw >/dev/null 2>&1; then + version="$(ado-aw --version 2>/dev/null || echo 'unknown')" + ok "ado-aw found: ${version}" +else + err "ado-aw not found on PATH" + echo " Install it:" + echo " Linux: curl -fsSL https://github.com/githubnext/ado-aw/releases/latest/download/install-linux.sh | sh" + echo " macOS: curl -fsSL https://github.com/githubnext/ado-aw/releases/latest/download/install-macos.sh | sh" + echo " Docs: https://github.com/githubnext/ado-aw/releases/latest" + hard_fail=1 +fi + +# 2. ADO auth helpers (advisory) +if command -v gh >/dev/null 2>&1; then + if gh auth status >/dev/null 2>&1; then + ok "gh authenticated" + else + warn "gh found but not authenticated (run 'gh auth login' for GitHub-backed flows)" + fi +else + warn "gh not found (optional; needed for some GitHub-backed flows)" +fi + +if command -v az >/dev/null 2>&1; then + if az account show >/dev/null 2>&1; then + ok "az authenticated" + else + warn "az found but not logged in (run 'az login' for ADO trace/audit/lifecycle skills)" + fi +else + warn "az not found (optional; ADO-facing skills can also use an explicit PAT)" +fi + +echo +if [ "${hard_fail}" -ne 0 ]; then + err "Missing required tool(s). Install ado-aw before using this plugin." + exit 1 +fi +ok "All required prerequisites satisfied." diff --git a/agency/plugins/ado-aw/skills/audit-build/SKILL.md b/agency/plugins/ado-aw/skills/audit-build/SKILL.md new file mode 100644 index 00000000..0a69c894 --- /dev/null +++ b/agency/plugins/ado-aw/skills/audit-build/SKILL.md @@ -0,0 +1,31 @@ +--- +name: audit-build +description: Download and analyze a finished ado-aw pipeline build. Use when the user wants a security/behavior report on a completed build — firewall/network activity, MCP tool calls, safe-output proposals, detection findings, token usage, or policy signals. +allowed-tools: Bash, Read, Glob, Grep, mcp__ado-aw__audit_build, mcp__ado-aw__trace_failure +--- + +# Audit a build + +Analyze a **finished** ado-aw pipeline build and render its findings. + +1. Confirm the `ado-aw` compiler is installed (`ado-aw --version`) and that ADO + read auth is available (`gh`/`az` or a PAT). + +2. Run the audit. Accepts a bare build id or a full Azure DevOps build URL: + - MCP: `audit_build` — same shape as `ado-aw audit --json`; returns the + structured `AuditData` report. + - CLI: `ado-aw audit ` (add `--json` for machine output). + - `trace_failure` — when the build failed, correlate the failed-job chain with + the local IR graph. + +3. The report's analyzers cover: detection-stage artifacts, AWF firewall/network + logs, build timeline / job-level data, MCP tool calls, missing-tool / + missing-data / noop safe outputs, OTel agent stats (token usage, duration, + turns), policy findings (safe-output integrity, prompt-injection signals), and + safe-output NDJSON. + +4. Summarize findings by severity and call out anything in the firewall, policy, + or safe-output sections explicitly. The audit cache is keyed on build id; + pass `--no-cache` (CLI) / `no_cache: true` (MCP) to force a fresh download. + +The user's request: $ARGUMENTS diff --git a/agency/plugins/ado-aw/skills/compile-and-validate/SKILL.md b/agency/plugins/ado-aw/skills/compile-and-validate/SKILL.md new file mode 100644 index 00000000..cc4d4d61 --- /dev/null +++ b/agency/plugins/ado-aw/skills/compile-and-validate/SKILL.md @@ -0,0 +1,31 @@ +--- +name: compile-and-validate +description: Compile an ado-aw agent file to Azure DevOps pipeline YAML and validate it. Use when the user asks to compile a workflow, check whether it is valid, verify a pipeline matches its source, or understand the compiled IR / dependency graph. +allowed-tools: Bash, Read, Glob, Grep, mcp__ado-aw__lint_workflow, mcp__ado-aw__inspect_workflow, mcp__ado-aw__graph_summary, mcp__ado-aw__graph_dump, mcp__ado-aw__step_dependencies, mcp__ado-aw__step_outputs +--- + +# Compile and validate + +Compile and validate an ado-aw agentic workflow. This skill is CLI- and +MCP-driven; it does not fetch a remote playbook. + +1. Confirm the `ado-aw` compiler is installed (`ado-aw --version`). + +2. **Compile** with the CLI (mutates the `.lock.yml` on disk): + - `ado-aw compile ` — compile one file. + - `ado-aw compile` — auto-discover and recompile all detected pipelines. + - `ado-aw check ` — verify a compiled pipeline still + matches its source Markdown (good for CI parity checks). + +3. **Validate and explain** with the read-only MCP tools (no mutation): + - `lint_workflow` — structural lint checks; resolve every finding. + - `inspect_workflow` — the public `PipelineSummary` (schema_version = 1). + - `graph_summary` / `graph_dump` — the resolved dependency graph + (text or Graphviz DOT). + - `step_dependencies` — upstream/downstream traversal for a step or job id. + - `step_outputs` — declared outputs and their consumers. + +4. Treat the workflow as "valid" only when `compile` succeeds **and** + `lint_workflow` is clean. Recompile after any YAML front-matter change. + +The user's request: $ARGUMENTS diff --git a/agency/plugins/ado-aw/skills/create-workflow/SKILL.md b/agency/plugins/ado-aw/skills/create-workflow/SKILL.md new file mode 100644 index 00000000..11ef17c3 --- /dev/null +++ b/agency/plugins/ado-aw/skills/create-workflow/SKILL.md @@ -0,0 +1,28 @@ +--- +name: create-workflow +description: Create a new ado-aw agentic Azure DevOps pipeline from scratch. Use when the user wants to author a brand-new AI-powered ADO pipeline as a Markdown agent file. Ends with a clean compile + lint. +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, mcp__ado-aw__catalog, mcp__ado-aw__lint_workflow, mcp__ado-aw__inspect_workflow, mcp__ado-aw__graph_summary +--- + +# Create an ado-aw workflow + +You are creating a **new** ado-aw agentic workflow. + +1. Confirm the `ado-aw` compiler is installed (`ado-aw --version`). If not, + install it using the platform installer scripts from the ado-aw releases page + (see the plugin README / `scripts/doctor.*`). + +2. Load the **entire** content of the authoritative, version-pinned playbook and + follow its instructions precisely: + + https://raw.githubusercontent.com/githubnext/ado-aw/v0.38.0/prompts/create-ado-agentic-workflow.md + +3. While authoring, use the read-only MCP tools to stay grounded: + - `catalog` — discover available safe-outputs, runtimes, tools, engines, models. + - `lint_workflow` — structural lint checks on the draft. + - `inspect_workflow` / `graph_summary` — confirm the compiled IR/graph shape. + +4. **Finish only when** `ado-aw compile .md` succeeds and `lint_workflow` + is clean. Recompile after any YAML front-matter change. + +The user's request: $ARGUMENTS diff --git a/agency/plugins/ado-aw/skills/debug-workflow/SKILL.md b/agency/plugins/ado-aw/skills/debug-workflow/SKILL.md new file mode 100644 index 00000000..266b5f3e --- /dev/null +++ b/agency/plugins/ado-aw/skills/debug-workflow/SKILL.md @@ -0,0 +1,33 @@ +--- +name: debug-workflow +description: Diagnose a failing ado-aw agentic Azure DevOps pipeline. Use when the user reports a pipeline failing, an agent unable to reach an MCP/network host, safe outputs not being applied, or wants to understand why a build behaved a certain way. +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, mcp__ado-aw__trace_failure, mcp__ado-aw__audit_build, mcp__ado-aw__whatif, mcp__ado-aw__inspect_workflow, mcp__ado-aw__graph_summary, mcp__ado-aw__lint_workflow +--- + +# Debug an ado-aw workflow + +You are troubleshooting a **failing** ado-aw agentic workflow. + +1. Confirm the `ado-aw` compiler is installed (`ado-aw --version`). + +2. Gather evidence before theorizing: + - `trace_failure` — trace the build's failed-job chain using audit data plus + the local IR graph (pass the build id or full ADO build URL). + - `audit_build` — download and analyze the build's artifacts (firewall/network + logs, MCP tool calls, safe-output NDJSON, detection findings, policy signals). + - `whatif` — classify which downstream jobs are skipped when a given step/job + fails, to confirm the blast radius. + +3. Load the **entire** content of the authoritative, version-pinned playbook and + follow its instructions precisely: + + https://raw.githubusercontent.com/githubnext/ado-aw/v0.38.0/prompts/debug-ado-agentic-workflow.md + +4. For Stage 3 (SafeOutputs) 401/403 failures, consult + `docs/safe-output-permissions.md` and surface the auth/permission error + verbatim with the doc pointer. + +5. If a fix requires a source change, validate it with `ado-aw compile` + + `lint_workflow` before proposing it. + +The user's request: $ARGUMENTS diff --git a/agency/plugins/ado-aw/skills/manage-lifecycle/SKILL.md b/agency/plugins/ado-aw/skills/manage-lifecycle/SKILL.md new file mode 100644 index 00000000..8a862816 --- /dev/null +++ b/agency/plugins/ado-aw/skills/manage-lifecycle/SKILL.md @@ -0,0 +1,36 @@ +--- +name: manage-lifecycle +description: Operate compiled ado-aw pipelines in Azure DevOps. Use when the user wants to register/enable/disable/remove build definitions, queue runs, set pipeline secrets, or report pipeline status. +allowed-tools: Bash, Read, Glob, Grep +--- + +# Manage pipeline lifecycle + +Operate compiled ado-aw pipelines against Azure DevOps. These are **mutating CLI +actions** — they are deliberately not exposed via the read-only MCP server. + +1. Confirm the `ado-aw` compiler is installed (`ado-aw --version`) and that ADO + auth is available (`gh`/`az` login or an ADO PAT, per ado-aw's auth resolution). + +2. Use the `ado-aw` CLI (via Bash): + - `ado-aw enable` — register ADO build definitions for compiled pipelines and + ensure they are enabled. + - `ado-aw disable` — set matched definitions to disabled (default) or paused. + - `ado-aw remove` — delete matched build definitions (honors `--yes` / tty prompt). + - `ado-aw run` — queue builds for matched definitions, optionally polling to + completion. + - `ado-aw list` — render matched definitions with their latest-run state + (text or JSON). + - `ado-aw status` — denser per-pipeline status block. + - `ado-aw secrets set/list/delete` — manage pipeline variables. `list` never + prints values; never echo secret values into the conversation. + +## Guardrails + +- These commands change real ADO state. Confirm scope (`--source` / `--all-repos` + and the matched set via `ado-aw list`) **before** running enable/disable/remove/run. +- Never fabricate or hardcode a PAT; rely on ado-aw's auth resolution. +- Surface ADO auth/permission errors verbatim; for Stage 3 401/403 see + `docs/safe-output-permissions.md`. + +The user's request: $ARGUMENTS diff --git a/agency/plugins/ado-aw/skills/update-workflow/SKILL.md b/agency/plugins/ado-aw/skills/update-workflow/SKILL.md new file mode 100644 index 00000000..36d00482 --- /dev/null +++ b/agency/plugins/ado-aw/skills/update-workflow/SKILL.md @@ -0,0 +1,29 @@ +--- +name: update-workflow +description: Update an existing ado-aw agentic Azure DevOps pipeline. Use when the user wants to modify an existing Markdown agent file — change schedule, add a tool/MCP, add a safe output, adjust runtimes, etc. Read-then-update with validation. +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, mcp__ado-aw__inspect_workflow, mcp__ado-aw__graph_summary, mcp__ado-aw__step_dependencies, mcp__ado-aw__whatif, mcp__ado-aw__lint_workflow, mcp__ado-aw__catalog +--- + +# Update an ado-aw workflow + +You are modifying an **existing** ado-aw agentic workflow. + +1. Confirm the `ado-aw` compiler is installed (`ado-aw --version`). + +2. **Read the existing agent file first**, and inspect its current shape before + changing anything: `inspect_workflow`, `graph_summary`, `step_dependencies`, + and `whatif` (to understand downstream impact of a change). + +3. Load the **entire** content of the authoritative, version-pinned playbook and + follow its instructions precisely: + + https://raw.githubusercontent.com/githubnext/ado-aw/v0.38.0/prompts/update-ado-agentic-workflow.md + +4. Use `catalog` to confirm any newly referenced safe-output / runtime / tool / + model identifiers are valid. + +5. **Recompile** with `ado-aw compile` after editing YAML front matter, then run + `lint_workflow` until clean. Markdown-body-only changes do not require + recompilation. + +The user's request: $ARGUMENTS diff --git a/docs/agency-plugin.md b/docs/agency-plugin.md new file mode 100644 index 00000000..85c04897 --- /dev/null +++ b/docs/agency-plugin.md @@ -0,0 +1,143 @@ +# Agency / Claude Code Plugin + +_Part of the [ado-aw documentation](../AGENTS.md)._ + +ado-aw ships a [Claude Code plugin](https://code.claude.com/docs/en/plugins-reference) +that helps engineers author, compile, validate, operate, and debug Azure DevOps +agentic workflows from their agent (Claude Code or Copilot CLI). It is also an +[Agency](https://github.com/agency-microsoft/playground) marketplace plugin. + +The plugin is mostly **packaging + wiring**, not new behavior: it surfaces +ado-aw's existing read-only [`mcp-author`](mcp-author.md) server and the +authoring playbooks in [`prompts/`](../prompts) as agent skills. + +## Source of truth + +The canonical, version-controlled plugin lives in this repository at +[`agency/plugins/ado-aw/`](../agency/plugins/ado-aw). It is the single source of +truth — `ado-aw init --agency` embeds these exact files via `include_str!` and +scaffolds them verbatim, so a consumer repo's plugin can never drift from the +canonical copy. A parity test (`tests/init_tests.rs`) asserts the two are +byte-for-byte identical. + +## Layout + +``` +agency/plugins/ado-aw/ +├── .claude-plugin/ +│ └── plugin.json # plugin manifest (name, version, mcpServers ref) +├── .mcp.json # wires the read-only `ado-aw mcp-author` server +├── agency.json # Agency marketplace governance + external source +├── README.md # plugin landing page +├── agents/ +│ └── ado-aw.md # dispatcher subagent (routes to skills) +├── skills/ +│ ├── create-workflow/SKILL.md +│ ├── update-workflow/SKILL.md +│ ├── debug-workflow/SKILL.md +│ ├── compile-and-validate/SKILL.md +│ ├── manage-lifecycle/SKILL.md +│ └── audit-build/SKILL.md +└── scripts/ + ├── doctor.sh # prerequisite check (POSIX) + └── doctor.ps1 # prerequisite check (Windows) +``` + +### Skills + +| Skill | Source of truth | What it does | +| --- | --- | --- | +| `create-workflow` | `prompts/create-ado-agentic-workflow.md` | Author a new agentic workflow; ends with compile + lint. | +| `update-workflow` | `prompts/update-ado-agentic-workflow.md` | Read-then-update an existing workflow with validation. | +| `debug-workflow` | `prompts/debug-ado-agentic-workflow.md` | Diagnose a failing run via `trace_failure` + `audit_build`. | +| `compile-and-validate` | [`docs/cli.md`](cli.md), [`docs/ir.md`](ir.md) | `ado-aw compile` + `lint_workflow` + IR/graph inspection. | +| `manage-lifecycle` | [`docs/cli.md`](cli.md) | `enable`/`disable`/`remove`/`run`/`list`/`status`/`secrets`. | +| `audit-build` | [`docs/audit.md`](audit.md) | Download + analyze a finished build's artifacts. | + +The `create`/`update`/`debug` skills load their authoritative playbook from a +**compiler-version-pinned** `raw.githubusercontent.com/.../v/prompts/...` +URL, so the instructions always match the installed binary. + +## MCP / tool surface + +`.mcp.json` wires the local, read-only [`ado-aw mcp-author`](mcp-author.md) stdio +server, exposing `inspect_workflow`, `graph_summary`, `graph_dump`, +`step_dependencies`, `step_outputs`, `lint_workflow`, `whatif`, `catalog`, +`trace_failure`, and `audit_build`. Mutating actions (`compile`, `enable`, +`disable`, `remove`, `run`, `secrets`, `init`) are **not** in the MCP server — the +skills invoke them via the agent's shell, so the read-only firebreak is preserved. + +## Self-contained marketplace + +The repository root carries two generated marketplace catalogs that make the repo +directly installable: + +| File | Engine | +| --- | --- | +| `.claude-plugin/marketplace.json` | Claude Code | +| `.github/plugin/marketplace.json` | GitHub Copilot | + +Each lists the `ado-aw` plugin via `source: "./agency/plugins/ado-aw"`. After +running `ado-aw init --agency` (or pointing at this repo), register and install: + +```text +/plugin marketplace add githubnext/ado-aw +/plugin install ado-aw@ado-aw +``` + +`ado-aw init --agency` writes the plugin under `agency/plugins/ado-aw/` **plus** +these root catalogs into the target repo, mirroring how the plugin is checked in +to ado-aw itself. + +## Versioning + +The plugin is **version-locked to the compiler**. `release-please` (via +`extra-files` in `release-please-config.json`) bumps, in lock-step on every +release: + +- `plugin.json` `version` and both root catalogs' `metadata.version` + + `plugins[0].version` (JSON updaters), and +- the version-pinned prompt URLs in `agents/ado-aw.md` and the + create/update/debug skills (generic updater, keyed on the + `` marker). + +> **Maintainer note — adding a version reference to a skill.** Only files that +> contain a version-pinned URL are listed in `release-please-config.json` +> `extra-files`. The `compile-and-validate`, `manage-lifecycle`, and +> `audit-build` skills are **intentionally omitted** because they are CLI/MCP- +> driven and carry no pinned version. If you add a `v/...` reference to +> any of them, you **must** add a `` marker on +> that line **and** add the file to `extra-files`, or the bump will silently be +> missed. + +## Identity & governance + +`agency.json` declares `engines: ["claude", "copilot"]`, `category: +developer-tools`, and `governance: { layer: 4, certification: draft, +organization: github-next }`. Following the Agency convention, it carries **no +personal alias or email** — identity is the organization name only. It also +declares an external `source` pointer to this repo, used when the plugin is +listed in the shared Agency marketplace. + +## Listing in the shared Agency marketplace + +Hosting the plugin here makes it installable directly, but it is separate from +being _listed in_ `agency-microsoft/playground`. To list it, add a one-line +external-source entry to that repo's `marketplace-config.json`: + +```json +"extPluginSources": { + "https://github.com/githubnext/ado-aw.git": ["agency/plugins/ado-aw"] +} +``` + +The playground's sync bot then generates the shared marketplace entry from this +repo's `agency.json` `source` block. + +## Related references + +- [`docs/cli.md`](cli.md) — the `init --agency` flag and CLI counterparts for the + skills' commands. +- [`docs/mcp-author.md`](mcp-author.md) — the read-only MCP server the plugin wires. +- [`prompts/`](../prompts) — the authoritative authoring playbooks the + create/update/debug skills load. diff --git a/docs/cli.md b/docs/cli.md index 2313cb4d..beea16b6 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -9,6 +9,7 @@ Global flags (apply to all subcommands): `--verbose, -v` (enable info-level logg - `init` - Initialize a repository for AI-first agentic pipeline authoring - `--path ` - Target directory (defaults to current directory) - `--force` - Bypass the GitHub-remote guard (use when running inside a GitHub-hosted repository like `githubnext/ado-aw` itself) + - `--agency` - **Additive.** Also generate an Agency / [Claude Code plugin](https://code.claude.com/docs/en/plugins-reference) and the marketplace catalogs that make the repo directly installable (in addition to the standard Copilot agent file). Writes the plugin under `agency/plugins/ado-aw` (mirroring how it is checked in to ado-aw itself) plus **repo-root** marketplace catalogs `.claude-plugin/marketplace.json` (Claude) and `.github/plugin/marketplace.json` (Copilot) that list the plugin via `source: "./agency/plugins/ado-aw"`. After scaffolding, register with `/plugin marketplace add ` then `/plugin install ado-aw@ado-aw`. The plugin tree is a verbatim copy of the canonical in-repo plugin at [`agency/plugins/ado-aw/`](../agency/plugins/ado-aw): `.claude-plugin/plugin.json`, `.mcp.json` (wires the read-only `ado-aw mcp-author` server), `agency.json` (marketplace governance + external `source` pointer), `README.md`, an `agents/ado-aw.md` dispatcher subagent, six `skills//SKILL.md` playbooks (`create-workflow`, `update-workflow`, `debug-workflow`, `compile-and-validate`, `manage-lifecycle`, `audit-build`), and `scripts/doctor.{sh,ps1}` prerequisite checks. The canonical plugin + catalogs are version-locked to the compiler (release-please bumps the plugin/catalog versions + pinned prompt URLs in lock-step). - Creates `.github/agents/ado-aw.agent.md` — a Copilot dispatcher agent that routes to specialized prompts for creating, updating, and debugging agentic pipelines - The agent auto-downloads the ado-aw compiler and handles the full lifecycle (create → compile → check) - `compile []` - Compile a markdown file to Azure DevOps pipeline YAML. If no path is given, auto-discovers and recompiles all detected agentic pipelines in the current directory. diff --git a/release-please-config.json b/release-please-config.json index 23a61c18..99e216d7 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -4,7 +4,39 @@ "packages": { ".": { "release-type": "rust", - "bump-minor-pre-major": true + "bump-minor-pre-major": true, + "extra-files": [ + { + "type": "json", + "path": "agency/plugins/ado-aw/.claude-plugin/plugin.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": ".claude-plugin/marketplace.json", + "jsonpath": "$.metadata.version" + }, + { + "type": "json", + "path": ".claude-plugin/marketplace.json", + "jsonpath": "$.plugins[0].version" + }, + { + "type": "json", + "path": ".github/plugin/marketplace.json", + "jsonpath": "$.metadata.version" + }, + { + "type": "json", + "path": ".github/plugin/marketplace.json", + "jsonpath": "$.plugins[0].version" + }, + "agency/plugins/ado-aw/agents/ado-aw.md", + "agency/plugins/ado-aw/skills/create-workflow/SKILL.md", + "agency/plugins/ado-aw/skills/update-workflow/SKILL.md", + "agency/plugins/ado-aw/skills/debug-workflow/SKILL.md", + ".github/agents/ado-aw.agent.md" + ] } } } diff --git a/src/data/init-agent.md b/src/data/init-agent.md index e548070e..7b52ec73 100644 --- a/src/data/init-agent.md +++ b/src/data/init-agent.md @@ -1,11 +1,11 @@ --- -description: Azure DevOps Agentic Pipelines (ado-aw) - Create, update, and debug AI-powered ADO pipelines +description: Azure DevOps Agentic Workflows (ado-aw) - Create, update, and debug AI-powered Azure DevOps agentic workflows disable-model-invocation: true --- -# ADO Agentic Pipelines Agent +# Azure DevOps Agentic Workflows Agent -This agent helps you create and manage Azure DevOps agentic pipelines using **ado-aw**. +This agent helps you create and manage Azure DevOps agentic workflows using **ado-aw**. ado-aw compiles human-friendly markdown files with YAML front matter into secure, multi-stage Azure DevOps pipelines that run AI agents in network-isolated sandboxes. @@ -37,39 +37,39 @@ Verify: `ado-aw --version` This is a **dispatcher agent** that routes your request to the appropriate specialized prompt: -- **Creating new agentic pipelines** → Routes to the create prompt -- **Updating existing pipelines** → Routes to the update prompt -- **Debugging failing pipelines** → Routes to the debug prompt +- **Creating new agentic workflows** → Routes to the create prompt +- **Updating existing workflows** → Routes to the update prompt +- **Debugging failing workflows** → Routes to the debug prompt ## Available Prompts -### Create New Agentic Pipeline -**Load when**: User wants to create a new agentic pipeline from scratch +### Create New Agentic Workflow +**Load when**: User wants to create a new agentic workflow from scratch -**Prompt file**: https://raw.githubusercontent.com/githubnext/ado-aw/v{{ compiler_version }}/prompts/create-ado-agentic-workflow.md +**Prompt file**: https://raw.githubusercontent.com/githubnext/ado-aw/v{{ compiler_version }}/prompts/create-ado-agentic-workflow.md **Use cases**: -- "Create an agentic pipeline that reviews PRs weekly" -- "I need a pipeline that triages work items daily" +- "Create an agentic workflow that reviews PRs weekly" +- "I need a workflow that triages work items daily" - "Design a scheduled dependency updater" -### Update Existing Pipeline +### Update Existing Workflow **Load when**: User wants to modify an existing agent workflow file -**Prompt file**: https://raw.githubusercontent.com/githubnext/ado-aw/v{{ compiler_version }}/prompts/update-ado-agentic-workflow.md +**Prompt file**: https://raw.githubusercontent.com/githubnext/ado-aw/v{{ compiler_version }}/prompts/update-ado-agentic-workflow.md **Use cases**: -- "Add the Azure DevOps MCP to my pipeline" +- "Add the Azure DevOps MCP to my workflow" - "Change the schedule from daily to weekly" - "Add work item creation as a safe output" -### Debug Failing Pipeline -**Load when**: User needs to troubleshoot a failing agentic pipeline +### Debug Failing Workflow +**Load when**: User needs to troubleshoot a failing agentic workflow -**Prompt file**: https://raw.githubusercontent.com/githubnext/ado-aw/v{{ compiler_version }}/prompts/debug-ado-agentic-workflow.md +**Prompt file**: https://raw.githubusercontent.com/githubnext/ado-aw/v{{ compiler_version }}/prompts/debug-ado-agentic-workflow.md **Use cases**: -- "Why is my agentic pipeline failing?" +- "Why is my agentic workflow failing?" - "The agent can't reach the MCP server" - "Safe outputs aren't being processed" @@ -97,7 +97,7 @@ ado-aw check ## Key Features -- **Natural language pipelines**: Write in markdown with YAML frontmatter +- **Natural language workflows**: Write in markdown with YAML frontmatter - **3-stage security**: Agent → Threat Analysis → Safe Output Execution - **Network isolation**: AWF (Agentic Workflow Firewall) with domain whitelisting - **MCP Gateway**: Tool routing for Azure DevOps, custom MCPs @@ -109,4 +109,4 @@ ado-aw check - Agent files must be compiled with `ado-aw compile` after YAML frontmatter changes - Markdown body (agent instructions) changes do NOT require recompilation - The agent never has direct write access — all mutations go through safe outputs -- Full reference: https://raw.githubusercontent.com/githubnext/ado-aw/v{{ compiler_version }}/AGENTS.md +- Full reference: https://raw.githubusercontent.com/githubnext/ado-aw/v{{ compiler_version }}/AGENTS.md diff --git a/src/init.rs b/src/init.rs index 8b64c86b..20411f2c 100644 --- a/src/init.rs +++ b/src/init.rs @@ -1,5 +1,5 @@ use anyhow::{Context, Result}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; // The agent template is embedded from src/data/init-agent.md const AGENT_TEMPLATE: &str = include_str!("data/init-agent.md"); @@ -7,7 +7,97 @@ const AGENT_TEMPLATE: &str = include_str!("data/init-agent.md"); const AGENT_DIR: &str = ".github/agents"; const AGENT_FILENAME: &str = "ado-aw.agent.md"; -pub async fn run(path: Option<&std::path::Path>) -> Result<()> { +/// Root directory (relative to the target repo) for the generated Agency / +/// Claude Code plugin. Mirrors the canonical in-repo layout (`agency/plugins/ +/// ado-aw/`) so a scaffolded consumer repo matches how the plugin is checked in +/// to ado-aw itself, keeping `--agency` output and the source of truth aligned. +const AGENCY_PLUGIN_DIR: &str = "agency/plugins/ado-aw"; + +/// Marketplace catalog files written at the **repo root** (not inside the plugin +/// dir). These are what make the repository itself an installable marketplace: +/// `/plugin marketplace add ` reads the root `.claude-plugin/marketplace +/// .json` (Claude) / `.github/plugin/marketplace.json` (Copilot), each of which +/// lists the `ado-aw` plugin with `source: "./agency/plugins/ado-aw"`. Written +/// verbatim from the canonical catalogs at the ado-aw repo root. +/// +/// Each entry is `(path relative to the repo root, embedded file)`. +const AGENCY_MARKETPLACE_FILES: &[(&str, &str)] = &[ + ( + ".claude-plugin/marketplace.json", + include_str!("../.claude-plugin/marketplace.json"), + ), + ( + ".github/plugin/marketplace.json", + include_str!("../.github/plugin/marketplace.json"), + ), +]; + +/// Files that make up the Agency / Claude Code plugin. The canonical, live copy +/// is checked in at `agency/plugins/ado-aw/` (the single source of truth, listed +/// in the Agency marketplace via an external `source` pointer and version-locked +/// to the compiler by release-please). `--agency` embeds that same tree and +/// scaffolds it into a consumer repo, so the two stay byte-for-byte identical. +/// +/// Each entry is `(relative path within the plugin dir, embedded file)`. The +/// embedded files already carry the literal release version (release-please +/// bumps the canonical files and `Cargo.toml` together), so they are written +/// verbatim — no placeholder substitution. +const AGENCY_PLUGIN_FILES: &[(&str, &str)] = &[ + ( + ".claude-plugin/plugin.json", + include_str!("../agency/plugins/ado-aw/.claude-plugin/plugin.json"), + ), + ( + ".mcp.json", + include_str!("../agency/plugins/ado-aw/.mcp.json"), + ), + ( + "agency.json", + include_str!("../agency/plugins/ado-aw/agency.json"), + ), + ( + "README.md", + include_str!("../agency/plugins/ado-aw/README.md"), + ), + ( + "agents/ado-aw.md", + include_str!("../agency/plugins/ado-aw/agents/ado-aw.md"), + ), + ( + "skills/create-workflow/SKILL.md", + include_str!("../agency/plugins/ado-aw/skills/create-workflow/SKILL.md"), + ), + ( + "skills/update-workflow/SKILL.md", + include_str!("../agency/plugins/ado-aw/skills/update-workflow/SKILL.md"), + ), + ( + "skills/debug-workflow/SKILL.md", + include_str!("../agency/plugins/ado-aw/skills/debug-workflow/SKILL.md"), + ), + ( + "skills/compile-and-validate/SKILL.md", + include_str!("../agency/plugins/ado-aw/skills/compile-and-validate/SKILL.md"), + ), + ( + "skills/manage-lifecycle/SKILL.md", + include_str!("../agency/plugins/ado-aw/skills/manage-lifecycle/SKILL.md"), + ), + ( + "skills/audit-build/SKILL.md", + include_str!("../agency/plugins/ado-aw/skills/audit-build/SKILL.md"), + ), + ( + "scripts/doctor.sh", + include_str!("../agency/plugins/ado-aw/scripts/doctor.sh"), + ), + ( + "scripts/doctor.ps1", + include_str!("../agency/plugins/ado-aw/scripts/doctor.ps1"), + ), +]; + +pub async fn run(path: Option<&std::path::Path>, agency: bool) -> Result<()> { let base = path .map(PathBuf::from) .unwrap_or_else(|| PathBuf::from(".")); @@ -33,8 +123,15 @@ pub async fn run(path: Option<&std::path::Path>) -> Result<()> { // Print success message println!("✓ Created {}", agent_path.display()); + + // `--agency` is additive: keep the standard agent file above and also emit + // the Agency / Claude Code plugin. + if agency { + write_agency_plugin(&base).await?; + } + println!(); - println!("This agent helps you create, update, and debug Azure DevOps agentic pipelines."); + println!("This agent helps you create, update, and debug Azure DevOps agentic workflows."); println!("It will automatically download the ado-aw compiler and handle compilation."); println!(); println!("To use it, ask your AI agent:"); @@ -47,3 +144,67 @@ pub async fn run(path: Option<&std::path::Path>) -> Result<()> { Ok(()) } + +/// Write the Agency / Claude Code plugin into `/agency/plugins/ado-aw`, +/// plus the repo-root marketplace catalogs that make `` an installable +/// marketplace. +/// +/// The plugin is additive to the standard agent file and follows the Claude +/// Code plugin conventions, written under `agency/plugins/ado-aw` so it mirrors +/// how the plugin is checked in to ado-aw itself. Files are copied verbatim from +/// the canonical in-repo plugin (`agency/plugins/ado-aw/`); they already carry +/// the correct release version, so no substitution is performed. +/// +/// The root catalogs (`.claude-plugin/marketplace.json`, +/// `.github/plugin/marketplace.json`) are what `/plugin marketplace add ` +/// reads, so the scaffolded repo is directly registerable as a marketplace. +async fn write_agency_plugin(base: &Path) -> Result<()> { + let plugin_root = base.join(AGENCY_PLUGIN_DIR); + + for (rel_path, contents) in AGENCY_PLUGIN_FILES { + let dest = plugin_root.join(rel_path); + let parent = dest + .parent() + .with_context(|| format!("Plugin file has no parent directory: {}", dest.display()))?; + tokio::fs::create_dir_all(parent) + .await + .with_context(|| format!("Failed to create directory: {}", parent.display()))?; + tokio::fs::write(&dest, contents) + .await + .with_context(|| format!("Failed to write plugin file: {}", dest.display()))?; + + // `tokio::fs::write` creates files mode 0644 (minus umask); shell scripts + // need the executable bit so the documented `./scripts/doctor.sh` works. + #[cfg(unix)] + if rel_path.ends_with(".sh") { + use std::os::unix::fs::PermissionsExt; + tokio::fs::set_permissions(&dest, std::fs::Permissions::from_mode(0o755)) + .await + .with_context(|| { + format!("Failed to set executable bit: {}", dest.display()) + })?; + } + } + + // Root marketplace catalogs (written relative to the repo root, not the + // plugin dir) so `/plugin marketplace add ` can detect the plugin. + for (rel_path, contents) in AGENCY_MARKETPLACE_FILES { + let dest = base.join(rel_path); + let parent = dest.parent().with_context(|| { + format!("Marketplace catalog has no parent directory: {}", dest.display()) + })?; + tokio::fs::create_dir_all(parent) + .await + .with_context(|| format!("Failed to create directory: {}", parent.display()))?; + tokio::fs::write(&dest, contents) + .await + .with_context(|| format!("Failed to write marketplace catalog: {}", dest.display()))?; + } + + println!("✓ Created Agency plugin in {}", plugin_root.display()); + println!( + "✓ Wrote marketplace catalogs (.claude-plugin/, .github/plugin/) — register with: /plugin marketplace add " + ); + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 05bf8058..5d591780 100644 --- a/src/main.rs +++ b/src/main.rs @@ -282,7 +282,7 @@ enum Commands { #[arg(long = "enabled-tools")] enabled_tools: Vec, }, - /// Initialize a repository for AI-first agentic pipeline authoring + /// Initialize a repository for AI-first agentic workflow authoring Init { /// Target directory (defaults to current directory) #[arg(long)] @@ -291,6 +291,11 @@ enum Commands { /// GitHub-hosted repository like `githubnext/ado-aw` itself) #[arg(long)] force: bool, + /// Additionally generate an Agency / Claude Code plugin under + /// `agency/plugins/ado-aw` plus repo-root marketplace catalogs + /// (additive to the standard agent file). + #[arg(long)] + agency: bool, }, /// (Deprecated) Set GITHUB_TOKEN on every matched ADO definition. /// Use `secrets set GITHUB_TOKEN ` instead. @@ -604,7 +609,7 @@ enum Commands { } #[derive(Parser, Debug)] -#[command(version, about = "Compiler for Azure DevOps agentic pipelines")] +#[command(version, about = "Compiler for Azure DevOps Agentic Workflows")] struct Args { /// Enable verbose logging (info level) #[arg(short, long, global = true)] @@ -1085,7 +1090,11 @@ async fn main() -> Result<()> { ) .await?; } - Commands::Init { path, force } => { + Commands::Init { + path, + force, + agency, + } => { let init_path = path.as_deref().unwrap_or(Path::new(".")); // `--force` bypasses the GitHub-remote guard so maintainers can // run `ado-aw init` inside this repository (or other GitHub-hosted @@ -1093,7 +1102,7 @@ async fn main() -> Result<()> { if !force { ensure_non_github_remote_for_ado_aw("init", init_path).await?; } - init::run(path.as_deref()).await?; + init::run(path.as_deref(), agency).await?; } Commands::Configure { token, diff --git a/tests/init_tests.rs b/tests/init_tests.rs index b3344fba..067eb39d 100644 --- a/tests/init_tests.rs +++ b/tests/init_tests.rs @@ -26,7 +26,7 @@ fn test_init_creates_agent_file() { let content = fs::read_to_string(&agent_path).expect("Should be able to read agent file"); assert!( - content.contains("ADO Agentic Pipelines Agent"), + content.contains("Azure DevOps Agentic Workflows Agent"), "Agent file should contain the expected title" ); // Verify version placeholder was substituted @@ -66,7 +66,7 @@ fn test_init_overwrites_by_default() { let content = fs::read_to_string(&agent_path).expect("Should read agent file"); assert!( - content.contains("ADO Agentic Pipelines Agent"), + content.contains("Azure DevOps Agentic Workflows Agent"), "Default init should restore the template content" ); assert!( @@ -75,6 +75,222 @@ fn test_init_overwrites_by_default() { ); } +/// Test that `init --agency` is additive: it produces the standard agent file +/// AND the Agency / Claude Code plugin under the `agency/plugins/ado-aw` directory. +#[test] +fn test_init_agency_generates_plugin() { + let temp_dir = tempfile::tempdir().expect("Failed to create temp directory"); + + let output = ado_aw_bin() + .args([ + "init", + "--agency", + "--path", + temp_dir.path().to_str().unwrap(), + ]) + .output() + .expect("Failed to run ado-aw init --agency"); + + assert!( + output.status.success(), + "init --agency should succeed: {}", + String::from_utf8_lossy(&output.stderr) + ); + + // Standard agent file is still produced (additive behavior). + let agent_path = temp_dir.path().join(".github/agents/ado-aw.agent.md"); + assert!( + agent_path.exists(), + "Standard agent file should still be created with --agency" + ); + + // Claude Code plugin manifest + MCP wiring under `agency/plugins/ado-aw`. + let plugin_root = temp_dir.path().join("agency/plugins/ado-aw"); + let plugin_json = plugin_root.join(".claude-plugin/plugin.json"); + assert!(plugin_json.exists(), "plugin.json should be created"); + assert!( + plugin_root.join(".mcp.json").exists(), + "MCP server wiring (.mcp.json) should be created" + ); + assert!( + plugin_root.join("agency.json").exists(), + "agency.json governance metadata should be created" + ); + assert!( + plugin_root.join("README.md").exists(), + "Plugin README.md should be created" + ); + + // Root marketplace catalogs make the repo registerable via + // `/plugin marketplace add ` — they live at the repo root, not in the + // plugin dir, and must list the ado-aw plugin via a relative `source`. + for catalog in [ + ".claude-plugin/marketplace.json", + ".github/plugin/marketplace.json", + ] { + let cat_path = temp_dir.path().join(catalog); + assert!( + cat_path.exists(), + "Root marketplace catalog {catalog} should be created" + ); + let cat: serde_json::Value = + serde_json::from_str(&fs::read_to_string(&cat_path).expect("catalog readable")) + .unwrap_or_else(|e| panic!("{catalog} should be valid JSON: {e}")); + assert_eq!( + cat["plugins"][0]["name"], "ado-aw", + "{catalog} should list the ado-aw plugin" + ); + assert_eq!( + cat["plugins"][0]["source"], "./agency/plugins/ado-aw", + "{catalog} plugin source should point at the plugin dir" + ); + } + + // Dispatcher subagent. + assert!( + plugin_root.join("agents/ado-aw.md").exists(), + "Agency subagent should be created" + ); + + // All six skills. + for skill in [ + "create-workflow", + "update-workflow", + "debug-workflow", + "compile-and-validate", + "manage-lifecycle", + "audit-build", + ] { + assert!( + plugin_root + .join("skills") + .join(skill) + .join("SKILL.md") + .exists(), + "Skill {skill}/SKILL.md should be created" + ); + } + + // Doctor prerequisite scripts (both platforms). + for script in ["doctor.sh", "doctor.ps1"] { + assert!( + plugin_root.join("scripts").join(script).exists(), + "scripts/{script} should be created" + ); + } + + // On Unix, the scaffolded doctor.sh must be executable so the documented + // `./scripts/doctor.sh` invocation works (not just `bash doctor.sh`). + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let mode = fs::metadata(plugin_root.join("scripts/doctor.sh")) + .expect("doctor.sh metadata") + .permissions() + .mode(); + assert!( + mode & 0o111 != 0, + "scaffolded doctor.sh should have the executable bit set, got mode {mode:o}" + ); + } + + // The manifest is a verbatim copy of the canonical plugin: it must carry a + // concrete version (no unresolved placeholder) and be valid JSON. + let manifest = fs::read_to_string(&plugin_json).expect("Should be able to read plugin.json"); + assert!( + !manifest.contains("{{ compiler_version }}"), + "Version placeholder should not appear in plugin.json" + ); + // plugin.json must be valid JSON with the expected plugin name. + let parsed: serde_json::Value = + serde_json::from_str(&manifest).expect("plugin.json should be valid JSON"); + assert_eq!(parsed["name"], "ado-aw", "plugin.json name should be ado-aw"); +} + +/// Test that `init --agency` scaffolds a byte-for-byte copy of the canonical +/// in-repo plugin (`agency/plugins/ado-aw/`). This guards the single-source-of- +/// truth invariant: the embedded files and the checked-in files must not drift. +#[test] +fn test_init_agency_matches_canonical_source() { + let temp_dir = tempfile::tempdir().expect("Failed to create temp directory"); + + let output = ado_aw_bin() + .args([ + "init", + "--agency", + "--path", + temp_dir.path().to_str().unwrap(), + ]) + .output() + .expect("Failed to run ado-aw init --agency"); + assert!(output.status.success(), "init --agency should succeed"); + + let repo_root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")); + let canonical = repo_root.join("agency/plugins/ado-aw"); + let scaffolded = temp_dir.path().join("agency/plugins/ado-aw"); + + for rel in [ + ".claude-plugin/plugin.json", + ".mcp.json", + "agency.json", + "README.md", + "agents/ado-aw.md", + "skills/create-workflow/SKILL.md", + "skills/update-workflow/SKILL.md", + "skills/debug-workflow/SKILL.md", + "skills/compile-and-validate/SKILL.md", + "skills/manage-lifecycle/SKILL.md", + "skills/audit-build/SKILL.md", + "scripts/doctor.sh", + "scripts/doctor.ps1", + ] { + let want = fs::read_to_string(canonical.join(rel)) + .unwrap_or_else(|e| panic!("canonical {rel} should be readable: {e}")); + let got = fs::read_to_string(scaffolded.join(rel)) + .unwrap_or_else(|e| panic!("scaffolded {rel} should be readable: {e}")); + assert_eq!( + got, want, + "scaffolded {rel} must match the canonical agency/plugins/ado-aw source" + ); + } + + // Root marketplace catalogs must also match the canonical repo-root copies. + for rel in [ + ".claude-plugin/marketplace.json", + ".github/plugin/marketplace.json", + ] { + let want = fs::read_to_string(repo_root.join(rel)) + .unwrap_or_else(|e| panic!("canonical {rel} should be readable: {e}")); + let got = fs::read_to_string(temp_dir.path().join(rel)) + .unwrap_or_else(|e| panic!("scaffolded {rel} should be readable: {e}")); + assert_eq!(got, want, "scaffolded {rel} must match the canonical repo-root catalog"); + } +} + +/// Test that `init` WITHOUT `--agency` does not create the plugin directory. +#[test] +fn test_init_without_agency_skips_plugin() { + let temp_dir = tempfile::tempdir().expect("Failed to create temp directory"); + + let output = ado_aw_bin() + .args(["init", "--path", temp_dir.path().to_str().unwrap()]) + .output() + .expect("Failed to run ado-aw init"); + assert!(output.status.success(), "init should succeed"); + + assert!( + !temp_dir.path().join("agency/plugins/ado-aw").exists(), + "Plugin directory should not be created without --agency" + ); + assert!( + !temp_dir.path().join(".claude-plugin/marketplace.json").exists(), + "Root Claude catalog should not be created without --agency" + ); + assert!( + !temp_dir.path().join(".github/plugin/marketplace.json").exists(), + "Root Copilot catalog should not be created without --agency" + ); +} /// Test that `--force` is advertised in `init --help` and describes its /// actual purpose: bypassing the GitHub-remote guard so maintainers can run /// `ado-aw init` inside a GitHub-hosted fork of `ado-aw` itself.