Skip to content

Setup walkthrough — Baron on Azure DevOps (from scratch)

A complete, copy-paste walkthrough to wire Baron to an Azure DevOps project and drive it from Claude Code, as a first-time user. End state: you ask Claude things like “list my backlog” or “start a task and open a PR” and it does them through Baron’s normalized tools.

This walkthrough runs Baron from a clone (pnpm baron …) and says so in its prerequisites — it was written and verified that way against a real Azure DevOps project.

You do not have to: Baron is on npm, so the CLI runs via npx -y @zanaat/baron-cli@latest and the MCP server via the Claude Code plugin (/plugin marketplace add zanaat-dev/baron) or npx @zanaat/baron-mcp-server@latest. Every pnpm baron <cmd> below has an npx -y @zanaat/baron-cli@latest <cmd> equivalent, and recipes now run by name (--recipe task-start), so nothing here needs the repository except the clone itself.


  • <your-project>/.baron/policy.json — committed config mapping Baron’s abstract roles/types onto your Azure DevOps process (you confirm the mapping once).
  • <your-project>/.baron/credentials — gitignored secrets (your PAT). Never committed.
  • <your-project>/.mcp.json — tells Claude Code to launch Baron’s MCP server for this project.

  • Node ≥ 20 and pnpm (npm i -g pnpm).
  • An Azure DevOps project you can access (org / project, and a repo if you want branches/PRs).
  • Claude Code (CLI, desktop, or IDE extension).
  • The Baron repo cloned locally — referred to below as <baron> (e.g. C:/Users/you/Development/baron).
Terminal window
cd <baron>
pnpm install
pnpm build # compiles every package; also confirms your toolchain is good
pnpm test # optional sanity check — should be green

The repo exposes two convenience scripts you’ll use: pnpm baron <cmd> (the CLI) and pnpm baron:mcp (the MCP server).


2. Create an Azure DevOps Personal Access Token (PAT)

Section titled “2. Create an Azure DevOps Personal Access Token (PAT)”

Azure DevOps → User settings → Personal access tokens → New Token. Pick the scopes for the ports you’ll use:

You want to… Port PAT scope
Read/create/transition work items issues Work Items → Read & Write
Branches + pull requests scm Code → Read & Write
List/trigger/cancel pipeline runs, read logs ci Build → Read & Execute
List environments + deployments deploy Environment → Read (or Build → Read)

For a quick first test, a token with Work Items (R&W) is enough; add the others as you go. (A “Full access” token works too but grant the narrow scopes for real use.)

Note your coordinates (these are not secrets — they’re in your repo URL): https://dev.azure.com/<ORG>/<PROJECT> and the repo name <REPO>.


3. Put your credentials in .baron/credentials

Section titled “3. Put your credentials in .baron/credentials”

Baron reads credentials from a gitignored file (or the environment) — never from the committed policy, and you should never paste your PAT into a chat.

Terminal window
cd <your-project>
mkdir -p .baron

Create <your-project>/.baron/credentials (org/project/repo are coordinates; only the token is secret):

AZURE_DEVOPS_ORG=your-org
AZURE_DEVOPS_PROJECT=Your Project
AZURE_DEVOPS_REPO=your-repo
AZURE_DEVOPS_TOKEN=<paste-your-PAT-here>

baron init, doctor, run, and the MCP server all read this file (and let real environment variables override it). Step 4 will also ensure .baron/credentials is gitignored.


4. baron init — introspect and confirm the mapping

Section titled “4. baron init — introspect and confirm the mapping”

This connects to your live project, reads its actual work-item states and types, and proposes a role/type map for you to confirm. (It introspects live, which is why the credentials in step 3 come first.)

Terminal window
cd <baron>
pnpm baron init --provider azure-devops --root <your-project>

You’ll see a proposal like:

Proposed mapping for issues provider 'azure-devops':
role backlog -> {"state":"New"}
role in_progress -> {"state":"Active"}
role in_review -> {"state":"Test"}
role done -> {"state":"Closed"}
type epic -> Epic
type story -> Product Backlog Item
type task -> Task
Notes (confirm these guesses):
- Mapped role 'in_review' to state 'Test' by name ...

Read the notes and confirm the mapping is right for your process — this is the one human step Baron’s design depends on. Common things to check:

  • Does each workflow role map to the state you actually use? (e.g. is your review state really Test, or is it Resolved / Code Review?)
  • Did story map to your story-level type (Scrum: Product Backlog Item; Agile: User Story) and not to Feature?
  • Blocking is not a role, so there is nothing to map: issue.block / issue.unblock set an orthogonal flag and leave the workflow role alone.

Confirm to write <your-project>/.baron/policy.json. init also scaffolds .baron/credentials.example and adds .baron/credentials to your .gitignore.

Redoing an existing project (e.g. BeeMaster already has a .baron/): to start clean, re-run with --force to overwrite the policy: pnpm baron init --provider azure-devops --root <project> --force. (Or move the existing .baron/ aside first.)


5. baron doctor — validate against the live project

Section titled “5. baron doctor — validate against the live project”
Terminal window
cd <baron>
pnpm baron doctor --root <your-project>

Expect: OK — N reference(s) checked for 'azure-devops', no drift. (exit 0). If it reports drift, a state/type/column in your policy no longer matches the live project — fix policy.json and re-run.


policy.json binds issues by default. To use more ports, add them under providers (they reuse the same Azure DevOps credentials — no extra baron init, since their status maps are built in):

{
"providers": {
"issues": "azure-devops",
"scm": "azure-devops", // branches + PRs (needs AZURE_DEVOPS_REPO + Code R&W on the PAT)
"ci": "azure-devops", // pipelines/runs/logs/trigger/cancel (Build R&E)
"deploy": "azure-devops" // environments + deployments
},
// ... roleMap / typeMap / gapPolicy from init stay as-is ...
}

Re-run baron doctor after editing. (A full reference policy lives in examples/azure-proof.)


Claude Code reads a project’s .mcp.json. Create <your-project>/.mcp.json:

{
"mcpServers": {
"baron": {
"command": "pnpm",
"args": ["--dir", "<baron>", "baron:mcp"],
"env": { "BARON_ROOT": "<your-project>" }
}
}
}
  • BARON_ROOT points the server at this project, so it reads <your-project>/.baron/policy.json + credentials no matter where it runs.
  • Sprints (optional): iterations are team-scoped. Baron defaults to Azure’s "<project> Team"; if your sprints live under a differently-named team, add AZURE_DEVOPS_TEAM=<team name> to .baron/credentials.
  • Prefer the plugin (/plugin marketplace add zanaat-dev/baron && /plugin install baron@baron) — it brings the MCP server and the skills, and no .mcp.json is needed. If you wire the server manually instead, use "command": "npx", "args": ["-y", "@zanaat/baron-mcp-server@latest"] (keep the BARON_ROOT env). The explicit @latest matters — a bare name makes npx reuse its cached install without re-checking the registry, silently pinning you to a stale version.
  • Restart Claude Code (or reload MCP servers) so it picks up the new server. Confirm it started: running pnpm baron:mcp (with BARON_ROOT set) prints baron mcp-server running on stdio (root: …) to stderr, then waits — Ctrl-C to stop.

Claude will now see the baron_* tools for the bound ports (e.g. baron_issue_*, and baron_scm_* / baron_ci_* / baron_deploy_* if you bound those), the always-on baron_learning_* / baron_followup_*, and the labeled baron_native_request escape hatch.


Ask in plain language; Claude picks the tools:

  • “Using Baron, list my backlog.” → baron_issue_read { op: "query", role: backlog }
  • “Create a Baron task ‘Try the issues port’ and move it to in progress.” → baron_issue_write { op: "create" } + baron_issue_move { op: "transition" }
  • “Start a task ‘X’: create it, branch for it, move it to in progress.” → run the task-start recipe (issues + scm)
  • “Show my pipelines and the latest run’s status.” → baron_ci_read { op: "pipelines" } + baron_ci_read { op: "runs" }
  • “Is PR 42 ready to merge?” → baron_scm_read { op: "pr_status" }

You can also run a packaged recipe directly:

Terminal window
pnpm baron run --recipe task-start --root <your-project>

Tip: to keep Claude using Baron (rather than a raw Azure DevOps MCP) for work-tracking, drop a short CLAUDE.md in your project saying “route work-tracking through the baron_* tools; use the raw azure-devops MCP only for research Baron doesn’t cover.”


Symptom Cause / fix
POLICY_NOT_FOUND No .baron/policy.json at the root — run baron init (step 4), or check BARON_ROOT.
401 / 403 from Azure PAT missing or lacking a scope (step 2). For PRs you need Code R&W; for trigger/cancel, Build R&E.
ROLE_MAPPING on a transition The target role (e.g. ready) isn’t mapped in policy.json — add it or pick a mapped role. Loud-by-design.
doctor reports drift A state/type/column in policy.json no longer exists in the project — update the map.
Claude doesn’t see baron_* tools .mcp.json not picked up — restart Claude Code; on Windows try pnpm.cmd; confirm the server starts (step 7).
baron_deploy_* returns nothing Your project uses pipeline stages, not Azure Environments — that’s correct-empty, not an error.
A query returns a huge result baron_issue_read { op: "query" } defaults to 50 and is project-scoped + lean; pass a larger limit only if you need it.

The Azure DevOps path (issues lifecycle, branches/PRs, ci read + trigger/cancel + stages, deploy reads, scm pr-status, the escape hatch) has been exercised against a real project. GitHub and Slack adapters are conformance-tested but not yet live-validated here. See trying-with-claude-code.md for a phased verification checklist you can run after setup.

Baron is open source under Apache-2.0, a zanaat project.