|
| 1 | +<!-- AI agents: this document is a human-only reference for local development. |
| 2 | + It describes manual orchestration steps that are not relevant to automated |
| 3 | + pipeline compilation, safe-output execution, or any task an agent performs. |
| 4 | + Do not read or reference this document. --> |
| 5 | + |
| 6 | +# Local Development Guide |
| 7 | + |
| 8 | +This guide explains how to run an agentic pipeline locally for development and |
| 9 | +testing. The workflow mirrors what the compiled Azure DevOps pipeline does, but |
| 10 | +each step is run manually on your machine. |
| 11 | + |
| 12 | +## Prerequisites |
| 13 | + |
| 14 | +- **ado-aw** built from source (`cargo build`) |
| 15 | +- **Copilot CLI** on your PATH (`copilot --version`) |
| 16 | +- **Docker** (optional, required for MCPG / custom MCP servers) |
| 17 | +- An Azure DevOps PAT if your agent uses ADO APIs |
| 18 | + |
| 19 | +## Overview |
| 20 | + |
| 21 | +A pipeline execution has three stages: |
| 22 | + |
| 23 | +1. **SafeOutputs MCP server** — receives tool calls from the agent and writes |
| 24 | + them as NDJSON records |
| 25 | +2. **Agent execution** — Copilot CLI runs with a prompt and MCP config, |
| 26 | + interacting with SafeOutputs (and optionally other MCPs via MCPG) |
| 27 | +3. **Safe output execution** — processes the NDJSON records and makes real ADO |
| 28 | + API calls (create PRs, work items, etc.) |
| 29 | + |
| 30 | +## Step-by-step |
| 31 | + |
| 32 | +### 1. Create a working directory |
| 33 | + |
| 34 | +```bash |
| 35 | +export WORK_DIR=$(mktemp -d) |
| 36 | +echo "Working directory: $WORK_DIR" |
| 37 | +``` |
| 38 | + |
| 39 | +### 2. Start the SafeOutputs HTTP server |
| 40 | + |
| 41 | +```bash |
| 42 | +# Pick a port and generate an API key |
| 43 | +export SO_PORT=8100 |
| 44 | +export SO_API_KEY=$(openssl rand -hex 32) |
| 45 | + |
| 46 | +# Start in the background |
| 47 | +cargo run -- mcp-http \ |
| 48 | + --port "$SO_PORT" \ |
| 49 | + --api-key "$SO_API_KEY" \ |
| 50 | + "$WORK_DIR" \ |
| 51 | + "$(pwd)" \ |
| 52 | + > "$WORK_DIR/safeoutputs.log" 2>&1 & |
| 53 | +export SO_PID=$! |
| 54 | +echo "SafeOutputs PID: $SO_PID" |
| 55 | + |
| 56 | +# Wait for health check |
| 57 | +until curl -sf "http://127.0.0.1:$SO_PORT/health" > /dev/null 2>&1; do |
| 58 | + sleep 1 |
| 59 | +done |
| 60 | +echo "SafeOutputs ready" |
| 61 | +``` |
| 62 | + |
| 63 | +### 3. (Optional) Start MCPG for custom MCP servers |
| 64 | + |
| 65 | +Skip this step if your agent only uses SafeOutputs (no `mcp-servers:` or |
| 66 | +`tools: azure-devops:` in front matter). |
| 67 | + |
| 68 | +```bash |
| 69 | +export MCPG_PORT=8080 |
| 70 | +export MCPG_API_KEY=$(openssl rand -hex 32) |
| 71 | + |
| 72 | +# Generate MCPG config — adapt the JSON to your agent's mcp-servers front matter. |
| 73 | +# See the compiled pipeline's mcpg-config.json for the expected format. |
| 74 | +cat > "$WORK_DIR/mcpg-config.json" <<EOF |
| 75 | +{ |
| 76 | + "mcpServers": { |
| 77 | + "safeoutputs": { |
| 78 | + "type": "http", |
| 79 | + "url": "http://host.docker.internal:$SO_PORT/mcp", |
| 80 | + "headers": { |
| 81 | + "Authorization": "Bearer $SO_API_KEY" |
| 82 | + } |
| 83 | + } |
| 84 | + }, |
| 85 | + "gateway": { |
| 86 | + "port": $MCPG_PORT, |
| 87 | + "domain": "127.0.0.1", |
| 88 | + "apiKey": "$MCPG_API_KEY" |
| 89 | + } |
| 90 | +} |
| 91 | +EOF |
| 92 | + |
| 93 | +# Start MCPG container (macOS/Windows — use host.docker.internal) |
| 94 | +docker run -i --rm --name ado-aw-mcpg \ |
| 95 | + -p "$MCPG_PORT:$MCPG_PORT" \ |
| 96 | + -v /var/run/docker.sock:/var/run/docker.sock \ |
| 97 | + --entrypoint /app/awmg \ |
| 98 | + ghcr.io/github/gh-aw-mcpg:v0.3.0 \ |
| 99 | + --routed --listen "0.0.0.0:$MCPG_PORT" --config-stdin \ |
| 100 | + < "$WORK_DIR/mcpg-config.json" \ |
| 101 | + > "$WORK_DIR/gateway-output.json" 2>"$WORK_DIR/mcpg-stderr.log" & |
| 102 | +export MCPG_PID=$! |
| 103 | + |
| 104 | +# Wait for MCPG health check |
| 105 | +until curl -sf "http://127.0.0.1:$MCPG_PORT/health" > /dev/null 2>&1; do |
| 106 | + sleep 1 |
| 107 | +done |
| 108 | +echo "MCPG ready" |
| 109 | +``` |
| 110 | + |
| 111 | +### 4. Generate the MCP client config for Copilot |
| 112 | + |
| 113 | +**Without MCPG** (SafeOutputs only): |
| 114 | + |
| 115 | +```bash |
| 116 | +cat > "$WORK_DIR/mcp-config.json" <<EOF |
| 117 | +{ |
| 118 | + "mcpServers": { |
| 119 | + "safeoutputs": { |
| 120 | + "type": "http", |
| 121 | + "url": "http://127.0.0.1:$SO_PORT/mcp", |
| 122 | + "headers": { |
| 123 | + "Authorization": "Bearer $SO_API_KEY" |
| 124 | + }, |
| 125 | + "tools": ["*"] |
| 126 | + } |
| 127 | + } |
| 128 | +} |
| 129 | +EOF |
| 130 | +``` |
| 131 | + |
| 132 | +**With MCPG** — transform the gateway output: |
| 133 | + |
| 134 | +```bash |
| 135 | +# Wait for gateway-output.json to contain valid JSON, then rewrite for copilot |
| 136 | +python3 -c " |
| 137 | +import json, sys |
| 138 | +with open('$WORK_DIR/gateway-output.json') as f: |
| 139 | + config = json.load(f) |
| 140 | +for name, server in config.get('mcpServers', {}).items(): |
| 141 | + server['tools'] = ['*'] |
| 142 | +with open('$WORK_DIR/mcp-config.json', 'w') as f: |
| 143 | + json.dump(config, f, indent=2) |
| 144 | +" |
| 145 | +``` |
| 146 | + |
| 147 | +### 5. Write the agent prompt |
| 148 | + |
| 149 | +Extract the markdown body (everything after the YAML front matter) from your |
| 150 | +agent file: |
| 151 | + |
| 152 | +```bash |
| 153 | +AGENT_FILE=path/to/your-agent.md |
| 154 | + |
| 155 | +# Extract body after front matter (after second ---) |
| 156 | +awk '/^---$/{n++; next} n>=2' "$AGENT_FILE" > "$WORK_DIR/agent-prompt.md" |
| 157 | +``` |
| 158 | + |
| 159 | +### 6. Run the Copilot CLI |
| 160 | + |
| 161 | +```bash |
| 162 | +copilot \ |
| 163 | + --prompt "@$WORK_DIR/agent-prompt.md" \ |
| 164 | + --additional-mcp-config "@$WORK_DIR/mcp-config.json" \ |
| 165 | + --model claude-opus-4.5 \ |
| 166 | + --no-ask-user \ |
| 167 | + --disable-builtin-mcps \ |
| 168 | + --allow-all-tools |
| 169 | +``` |
| 170 | + |
| 171 | +Adjust flags based on your agent's front matter (model, allowed tools, etc.). |
| 172 | + |
| 173 | +### 7. Execute safe outputs |
| 174 | + |
| 175 | +```bash |
| 176 | +cargo run -- execute \ |
| 177 | + --source "$AGENT_FILE" \ |
| 178 | + --safe-output-dir "$WORK_DIR" \ |
| 179 | + --dry-run # Remove --dry-run to make real ADO API calls |
| 180 | +``` |
| 181 | + |
| 182 | +### 8. Cleanup |
| 183 | + |
| 184 | +```bash |
| 185 | +# Stop SafeOutputs |
| 186 | +kill "$SO_PID" 2>/dev/null |
| 187 | + |
| 188 | +# Stop MCPG (if started) |
| 189 | +docker stop ado-aw-mcpg 2>/dev/null |
| 190 | + |
| 191 | +echo "Done. Output files in: $WORK_DIR" |
| 192 | +``` |
| 193 | + |
| 194 | +## Tips |
| 195 | + |
| 196 | +- Use `--dry-run` on the execute step to validate safe outputs without making |
| 197 | + real ADO API calls |
| 198 | +- Set `AZURE_DEVOPS_EXT_PAT` for agents that need ADO API access |
| 199 | +- Check `$WORK_DIR/safeoutputs.log` and `$WORK_DIR/mcpg-stderr.log` for |
| 200 | + debugging |
| 201 | +- The compiled pipeline YAML shows the exact flags and config used in CI — use |
| 202 | + `ado-aw compile your-agent.md` and inspect the output for reference |
0 commit comments