Workflows
Generated automatically at build time from the madtea repository - do not edit here. Source: docs/reference/cli-workflows.md.
High-level git workflow commands for branch completion, orchestration, ADR management, and merged-branch pruning.
Destruction model for prune (content-verified, never force-delete) and branch delete: ADR 0029.
CLI Commands
madtea adr check
Verify ADR numbering, index bijection, and links (exit 1 on drift)
madtea adr new
Create the next ADR record and index row (number from origin)
| Flag | Type | Default | Description |
|---|---|---|---|
--offline | bool | false | Number from the local tree instead of the origin default branch |
--title | string | Record title (defaults to a title derived from the slug) | |
--tracking | string | Tracking reference recorded in the header (e.g. an issue or epic) |
madtea finish
Commit, push, create PR, merge, and return to default branch
| Flag | Type | Default | Description |
|---|---|---|---|
--branch | string | Finish a named branch instead of the current checkout (skips the commit step; the branch must exist locally and be ahead of the default) | |
--close | bool | false | Close linked issue (this is the default behavior — accepted for compatibility) |
--close-linked | bool | false | Force-close all branch-detected issues (skip dependency safety check) |
--closes | stringSlice | [] | Issue numbers to explicitly close (repeatable, comma-separated) |
--files | stringSlice | [] | Stage these paths before committing, in this same finish call (comma-separated or repeatable; mirrors madtea add). Mutually exclusive with –no-commit and –branch |
--no-close | bool | false | Reference branch-detected issues only, never close them |
--no-commit | bool | false | Skip commit step (use when changes are already committed) |
--owner-repo | string | Complete a branch that lives only on the forge (owner/repo), with no local checkout: opens the PR, merges, and deletes the remote branch. Requires –branch; mutually exclusive with –files/–no-commit | |
--summary | string | PR summary (use @file to read from file, @- for stdin) | |
--summary-file | string | Read PR summary from file (use - for stdin, avoids shell quoting issues) |
madtea orchestrate
Merge PRs in batch with verification and bisect failure isolation
| Flag | Type | Default | Description |
|---|---|---|---|
--max-failures | int | 2 | Stop after N culprits found and reverted (0 = unlimited, capped at 50 as a safety limit) |
--no-revert | bool | false | Skip bisection and revert on failure; just report pass/fail |
--strict-overlap | bool | false | Error and refuse to start if any PRs touch the same files |
--style | string | Merge strategy (merge, rebase, rebase-merge, squash, fast-forward-only); default honors the repo’s configured merge style | |
--verify | string | Shell command to run after each merge (executed via sh -c with full local shell access) | |
--verify-timeout | duration | 5m0s | Timeout for each verify command execution |
madtea orchestrate reconcile
Merge a moved base branch into an open PR’s head (no force-push)
| Flag | Type | Default | Description |
|---|---|---|---|
--abort | bool | false | Discard an in-progress reconcile merge (git merge –abort) |
--continue | bool | false | Complete an in-progress reconcile merge (after resolving + staging conflicts) and push |
--owner-repo | string | Forge repository (owner/repo) whose PR number is meant; default derives it from the checkout’s origin |
madtea prune
Clean up stale remote refs and merged branches
| Flag | Type | Default | Description |
|---|---|---|---|
--count | bool | false | Print the number of prunable branches (dry run; exits 0 regardless of count) |
--delete-branches | bool | false | Actually delete merged branches (default is dry run) |
--dry-run | bool | false | Show what would be deleted without deleting (this is the default) |
--remote | bool | false | Also delete remote branches via Gitea API |
madtea secret-exec
Execute a command with the Forgejo/Gitea token injected as an environment variable
MCP Tools
madt_adr
Create and consistency-check architecture decision records (ADRs) in any repo that carries a docs/adr/ tree.
Output schema: declared
One tool, action-dispatched. Set action to one of:
action="check"
Verify the ADR tree — unique numbers, file/index bijection, and resolvable links — and report every inconsistency; a clean tree returns OK. Returns an error when drift is found so it wires straight into a gate.
action="new"
Create the next ADR record and index row; the number is resolved from the origin default branch, NOT the local tree, so a diverged branch cannot reissue a landed number. Fails if origin is unreachable — pass offline=true to number from the local tree instead.
Required: slug
Optional: title, tracking, offline
Example:
madt_adr(action="new", slug="origin-first-forge-resolution")
madt_clone
Clone a Forgejo/Gitea repository - public repos need no credentials; private repos require madtea auth login first. Per-repo credentials are configured automatically. Never raw git clone a credentialed URL (leaks the token). Under ssh/ssh-only git-protocol it clones over SSH as git@host:owner/repo.git, no token on the git wire. The result names the forge host and warns on read-only mirrors.
Output schema: declared
| Parameter | Type | Required | Description |
|---|---|---|---|
branch | string | no | Clone specific branch |
depth | integer | no | Shallow clone depth |
directory | string | no | Target directory (default: repo name) |
repository | string | yes | Repository in owner/repo format or full URL |
madt_finish
Complete a feature branch: commit, push, create PR, merge, return to mainline. Must be run from a FEATURE branch (errors on the default branch). The commit step commits the staged changes, or stages files=[…] itself in THIS call (mirrors madt_add/madt_commit; mutually exclusive with no_commit/branch=). No blanket “stage everything” mode (the removed all=true/git add -A): declare paths in files=[…], or stage via madt_add first (check with madt_status), or set no_commit=true if already committed; mixed staged/unstaged trees silently drop unstaged edits from the PR. Merges to the DEFAULT branch - ONLY for branch completion, NOT for intermediate work (use madt_commit for mid-branch checkpoints; push with madt_push). It ALWAYS merges: for a review-only PR, use madt_push then madt_prs action=create draft=true - and do not call finish on a branch that already has an open PR. Branch-detected issues (e.g. ‘feat/issue-321-thing’) auto-close iff they have no open dependencies - parent epics (open deps) are referenced instead. Override with closes/close_linked/no_close. Set branch= to finish a branch by name without checking it out: the branch must exist and be ahead of the default; use this for a linked worktree’s branch (same repo, no dir=) without disturbing its checkout. Pass dir= to target another local git repo by path; a same-repo dir changes nothing. A FOREIGN dir requires branch= (no checkout-mode finish cross-repo) and defaults no_close=true (override via closes=/close_linked=). When the server’s cwd is NOT itself a git repo (a plain parent dir of clones), a repo whose toplevel is strictly UNDER that dir is in-scope, not foreign: finish it via branch= (no checkout to stage) with normal branch-detected auto-close (no forced no_close=true). Without dir, targets the server’s cwd; in a detected multi-repo workspace with no dir it fails closed regardless (set MADTEA_CALLER_REPO). Set owner_repo=owner/repo (no dir, no checkout) to complete a forge-only branch (e.g. one committed by madt_files new_branch=) via a pure API path: open the PR, merge (honoring default_merge_style), delete the remote branch. Requires branch=; mutually exclusive with dir=/files=/no_commit; defaults no_close=true (same overrides). For the parallel-agent worktree flow, see madt_help(topic="worktrees"). A failed finish returns the step ledger with a partial-progress line naming what completed - staging failures included (step ‘commit’ failed, not a bare error). Re-running the identical call converges without duplicating work: a commit-landed/push-failed state re-runs without re-committing (files= included). One exception: if the MERGE landed but the final return step failed, recover with madt_pull - a re-run cannot converge from that state. A provably-stale .git/index.lock self-heals with a stated confirmation; a held lock refuses with a teaching error naming the lock path.
Output schema: declared
| Parameter | Type | Required | Description |
|---|---|---|---|
branch | string | no | Name of a local branch to finish instead of the current checkout (e.g. ‘feat/issue-42-auth’). When set, the commit step is skipped and that branch is pushed, PR-opened, and merged by name — intended for branches checked out in a linked worktree so you can finish them without switching the worktree’s checkout. The branch must exist (in dir=, if set) and have commits ahead of the default, and must not itself be the default branch. Required — and the ONLY allowed form — when dir= names a FOREIGN repo: a foreign target never checks out or stages a stranger’s working tree. |
close_linked | boolean | no | Force-close every branch-detected issue, skipping the dependency safety check. Default behavior already auto-closes issues with no open dependencies — only set this to true to override that check. Also overrides the foreign-target no_close=true default when dir= names a repo outside the server’s working directory. |
closes | string | no | Comma-separated issue numbers to explicitly close on merge (e.g. ‘218,221’). These are closed without consulting the dependency API — use only when you are sure the work fully resolves them. Also overrides the foreign-target no_close=true default when dir= names a repo outside the server’s working directory. |
dir | string | no | Absolute path to a LOCAL git repo to finish, for a repo other than the server’s working directory (validated: resolved, must be an existing git repository; no workspace-roots confinement). A repo that turns out to be the SAME one (or one of its linked worktrees) changes nothing — finish behaves exactly as it would without dir=. A genuinely FOREIGN repo is allowed only in the no-checkout branch= form, and defaults no_close to true unless closes= or close_linked=true is also set. |
files | []string | string | no | Paths to stage before committing, in this SAME finish call (files or directories, e.g. [‘docs/’, ‘main.go’]) — mirrors madt_add/madt_commit’s files, so a caller need not round-trip through madt_add first. There is no blanket “stage everything” mode (the removed all/git add -A) — name the paths you mean. Mutually exclusive with no_commit and branch=. |
no_close | boolean | no | Reference branch-detected issues (Refs) but never close them. Use when the branch implements one slice of a parent epic and you don’t want any auto-close behavior. This is the DEFAULT automatically when dir= names a FOREIGN repo — a generic branch name must never auto-close a stranger’s tracker entry on a coincidental issue-number match; pass closes= or close_linked=true to still close in that repo. |
no_commit | boolean | no | Skip commit step if changes are already committed |
owner_repo | string | no | owner/repo naming a repository on the forge to complete a branch in with NO local checkout of any kind (e.g. ‘acme/widgets’) — the remote-only form for a branch that lives only on the forge, such as one committed by madt_files new_branch=. It resolves the default branch, opens the PR from the remote branch, merges honoring the repo’s default_merge_style, and deletes the remote branch, all via the API with no clone. Requires branch=; mutually exclusive with dir=/files=/no_commit; defaults no_close=true (override via closes=/close_linked=), like a foreign dir. |
raw_json | boolean | no | Return raw JSON (the {“kind”:“ledger”,…} step envelope) instead of the compact agent line. |
summary | string | yes | PR body summary describing the changes (use @file to read from file, @- for stdin) |
title | string | yes | Commit message subject and PR title — the one-line conventional-commit summary applied to both the commit and the PR (e.g. ‘feat: add auth’). |
madt_orchestrate
Merge PRs in batch with verification and bisect failure isolation, OR reconcile a conflicted PR whose base moved. BATCH-MERGE mode (prs + verify): merges all PRs first, runs verify once, then bisects to find and revert culprits on failure. Already-merged PRs are skipped (safe to re-run). Requires a local checkout that is ON the default branch with a CLEAN working tree — the run pulls the current branch after merging, checks out commits during bisection (fails on a dirty tree), and creates revert branches from HEAD. All listed PRs must be open and non-draft: a closed or draft PR aborts the entire run before any merge (only already-merged PRs are skipped). SECURITY: verify runs via sh -c with full local shell access (env vars, files, network) and may execute multiple times during bisection — only pass trusted commands, never untrusted or user-supplied strings. RECONCILE mode (reconcile=<pr>): the push-compatible, force-push-free recovery when madt_finish/merge fails because the base branch moved under an open PR — checks out the PR’s head and merges the latest base INTO it, so the follow-up push needs no force. A clean merge is pushed and steers you back to finish/merge; a conflict returns the conflicted-file work-list plus continue/abort rails: resolve, madt_add the files, then reconcile_continue=true or reconcile_abort=true. Reconcile also takes dir=/owner_repo= (see param docs) for foreign-repo PRs: reconciled in a linked worktree holding the head; a foreign PRIMARY checkout is refused.
Output schema: declared
| Parameter | Type | Required | Description |
|---|---|---|---|
dir | string | no | Reconcile mode only: absolute path to the LOCAL git repo/worktree to reconcile in (validated: an existing git repository). For a FOREIGN repo’s PR pass a LINKED WORKTREE holding the PR’s head branch; a foreign PRIMARY checkout is refused and never touched. Defaults to the working directory. |
max_failures | integer | no | Stop after N culprits found and reverted. Default: 2. Note: over MCP, 0 is indistinguishable from unset and is treated as the default (2) — it is NOT unlimited; pass 50 explicitly for the maximum allowed. |
merge_style | string | no | Merge strategy: merge, squash, rebase, rebase-merge, fast-forward-only |
no_revert | boolean | no | Skip bisection and revert on failure; just report pass/fail (leaves broken merges on main) |
owner_repo | string | no | Reconcile mode: owner/repo naming which repo’s PR number is meant — the fix for a same-numbered PR resolving in the wrong repo. Defaults to dir’s origin when omitted. |
prs | string | no | Comma-separated PR numbers to merge in order (e.g. ‘101,102,103’) |
reconcile | string | no | PR number whose base branch moved (e.g. ‘1956’): switches to reconcile mode and merges the latest base branch INTO that open PR’s head branch — the push-compatible, force-push-free recovery. Mutually exclusive with prs/verify. |
reconcile_abort | boolean | no | Discard an in-progress reconcile merge (git merge –abort), restoring the head branch to its pre-merge state (e.g. true). |
reconcile_continue | boolean | no | Complete an in-progress reconcile merge after you resolved and staged the conflicts with madt_add (git merge –continue + push) (e.g. true). |
strict_overlap | boolean | no | Error and refuse to start if any PRs touch the same files (default: warn but proceed) |
verify | string | no | Shell command to run for verification (executed via sh -c with full local shell access) |
verify_timeout | string | no | Timeout for each verify command (e.g. ‘5m’, ’30s’). Default: 5m |
madt_prune
Clean up stale remote refs and delete branches merged into the default branch. A dry run (default) previews the full set: merged local branches AND remote-only orphans (no remote=true needed to preview them). delete_branches=true deletes the local branches; remote=true also deletes the remote twins and orphans, then cleans the now-stale remote-tracking refs. Local branches squash/cherry-pick-merged (squash_merged, content already in the default branch) are ALSO deleted under delete_branches=true - their remote twins under remote=true. Branches held by a linked worktree are skipped and reported, never attempted-and-errored. To delete one specific (possibly unmerged) remote branch, use madt_branches_remote action=delete instead.
Output schema: declared
| Parameter | Type | Required | Description |
|---|---|---|---|
delete_branches | boolean | no | Actually delete merged branches (default: dry run showing what would be deleted without deleting) |
raw_json | boolean | no | Return raw JSON (the prune result: merged_branches, remote_orphans, deleted counts, dry_run), also incl. squash_merged, instead of the formatted text line. |
remote | boolean | no | Also delete remote branches via Gitea API |
Canonical source: docs/reference/cli-workflows.md in the madtea repo.