Workflows
Generated automatically at build time from the madtea repository - do not edit here. Source: docs/reference/cli-workflows.md.
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 init
Create a new repository and push initial commit
| Flag | Type | Default | Description |
|---|---|---|---|
--description | string | Repository description | |
--dir | string | Directory to initialize (default: ./ | |
--org | string | Create repository under an organization | |
--private | bool | false | Make repository private |
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 succeed without credentials; private repos require madtea auth login first. When credentials are configured, per-repo credentials are set up automatically. Use this instead of raw git clone with a credentialed URL (which would leak the token into git config/history). The result names the resolved forge host and warns when the repo is a read-only mirror.
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=), collapsing the separate madt_commit step. There is no blanket “stage everything” mode (the removed all=true/git add -A): declare the 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 without merging, use madt_push then madt_prs action=create draft=true instead — 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 in Forgejo/Gitea — issues that look like parent epics (have 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 branch in a linked worktree (same repo, no dir=) without disturbing its checkout. Pass dir= to target another local git repo by path (validated, any 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 working directory is itself NOT a git repo (a session launched in a plain parent dir that merely contains clones), a repo whose toplevel is strictly UNDER that dir is in-scope, not foreign: it is finished via branch= (there is no checkout to stage in a non-git cwd) but keeps normal branch-detected auto-close (no forced no_close=true). Without dir, targets the server’s working directory; 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 (override via closes=/close_linked=). For the parallel-agent worktree flow (commit in a linked worktree with madt_commit dir=, then finish it by name with branch= from the mainline checkout), see madt_help(topic=“worktrees”).
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_init
Bootstrap a new repository: create remote, init local, stage everything (git add -A), commit, push. Set org to create under an organization; omit org for a personal repo. Only for brand-new work: fails if the target directory already has commits — to publish an EXISTING local repo, create the remote with madt_repos action=create, then madt_remote_add, then push. Creates a README.md if the directory is empty.
Output schema: declared
| Parameter | Type | Required | Description |
|---|---|---|---|
description | string | no | Repository description |
dir | string | no | Directory to initialize (default: ./ |
name | string | yes | Repository name to create |
org | string | no | Organization to create the repo under (omit for personal repo) |
private | boolean | no | Make repository private |
raw_json | boolean | no | Return raw JSON (the {“kind”:“ledger”,…} step envelope) instead of the compact agent line. |
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=
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. Default is dry run; set delete_branches=true to delete. Set remote=true to also delete merged remote twins and merged remote-only branches (orphans), then remove the now-stale remote-tracking refs. Local branches whose content already landed in the default branch via a squash/cherry-pick merge (squash_merged) are content-verified, so they too ARE deleted under delete_branches=true - including their remote twins under remote=true - and listed as would-delete on a dry run. 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.