repo-scope: madt_adr and other MCP tools cannot target a nested repo, because they take no dir= #638

Open
opened 2026-09-25 16:33:29 +00:00 by hexajon · 1 comment
Owner

What happens

I am moving architecture decision records into ten repos. One is a workspace repo. The other nine are nested, gitignored clones inside its working tree. My MCP server starts in the workspace repo.

madt_adr has no dir=, so it acts only on the workspace repo. It cannot reach the nine nested repos. Other tools have the same kind of gap. The table lists the gaps in the default tool set.

Gaps

I read these gaps from the tool schemas that my MCP server serves today. I did not check the gated domains.

Tool Acts on dir= owner_repo= Gap
madt_adr (init, new, check) the local docs/decisions/ tree no no Launch repo only.
madt_prune local and remote branches no no Launch repo only.
madt_remote_add the remotes of a local repo no yes, but it names the forge repo No way to name the local repo.
madt_prs action=checkout a checkout into a local repo no yes Launch repo only.
madt_orchestrate batch merge the local checkout reconcile mode only reconcile mode only Batch merge runs in the launch repo only.
madt_open the web URL of the repo, an issue, or a PR no no Launch repo only.
madt_api_call, madt_server_info the launch forge no no Launch forge only (#485, #468).
madt_releases download files on disk yes, but it means the download directory yes Same parameter name as the repo selector, with a different meaning.
madt_issues forge issues create, comment, list, and get only yes The other actions need owner_repo=.

These tools take dir= today: madt_status, madt_pull, madt_fetch, madt_worktrees, madt_branch_create, madt_branch_delete, madt_add, madt_commit, madt_push, madt_finish, madt_log, madt_ref_inspect, madt_tag_list, madt_auth_use_ssh, madt_auth_whoami.

Ask

Confirm each row against main, and add rows for the gated domains. Then fix each gap, or record why it stays.

Relates to #485, #507, and #577.

## What happens I am moving architecture decision records into ten repos. One is a workspace repo. The other nine are nested, gitignored clones inside its working tree. My MCP server starts in the workspace repo. `madt_adr` has no `dir=`, so it acts only on the workspace repo. It cannot reach the nine nested repos. Other tools have the same kind of gap. The table lists the gaps in the default tool set. ## Gaps I read these gaps from the tool schemas that my MCP server serves today. I did not check the gated domains. | Tool | Acts on | `dir=` | `owner_repo=` | Gap | |---|---|---|---|---| | `madt_adr` (`init`, `new`, `check`) | the local `docs/decisions/` tree | no | no | Launch repo only. | | `madt_prune` | local and remote branches | no | no | Launch repo only. | | `madt_remote_add` | the remotes of a local repo | no | yes, but it names the forge repo | No way to name the local repo. | | `madt_prs` `action=checkout` | a checkout into a local repo | no | yes | Launch repo only. | | `madt_orchestrate` batch merge | the local checkout | reconcile mode only | reconcile mode only | Batch merge runs in the launch repo only. | | `madt_open` | the web URL of the repo, an issue, or a PR | no | no | Launch repo only. | | `madt_api_call`, `madt_server_info` | the launch forge | no | no | Launch forge only (#485, #468). | | `madt_releases` `download` | files on disk | yes, but it means the download directory | yes | Same parameter name as the repo selector, with a different meaning. | | `madt_issues` | forge issues | `create`, `comment`, `list`, and `get` only | yes | The other actions need `owner_repo=`. | These tools take `dir=` today: `madt_status`, `madt_pull`, `madt_fetch`, `madt_worktrees`, `madt_branch_create`, `madt_branch_delete`, `madt_add`, `madt_commit`, `madt_push`, `madt_finish`, `madt_log`, `madt_ref_inspect`, `madt_tag_list`, `madt_auth_use_ssh`, `madt_auth_whoami`. ## Ask Confirm each row against `main`, and add rows for the gated domains. Then fix each gap, or record why it stays. Relates to #485, #507, and #577.
Author
Owner

Deferred out of v0.20.0. #638 is not a mechanical change: every tool here
touches the forge even on its local path, so a correct dir= has to resolve the
dir's OWN forge identity through config.GetConfigForDir. That resolver has a
CLOSED call-site allowlist (internal/parity/getconfigfordir_drift.go,
getConfigForDirSites), pinned by TestNoUnpinnedGetConfigForDirCallSites: a new
site is an ADR 0027 credential-boundary carve-out, a recorded decision per tool,
not a drop-in. So #638 is a set of boundary rulings and gets its own pass.

Per row, confirmed against main:

  • madt_adr (init/new/check): init is local-only, but new numbering and check's
    issue verify resolve the LAUNCH forge (origin.go:52-60; adr.go:1512), so on a
    foreign dir they read the wrong origin. Needs a dir-scoped resolver (a new
    carve-out) or a refusal of the forge paths on a foreign dir. Reconcile-style
    precedent, and the real need behind this issue.
  • madt_prs action=checkout: the PR read resolves the launch forge and the
    checkout moves HEAD. Needs a dir-scoped PR read (a new carve-out) plus a
    foreign-primary clamp. Direct analogue of orchestrate reconcile.
  • madt_prune: cwd-scoped, hits the forge on dry-run and deletes remote branches
    when remote=true. A credential-boundary widening.
  • madt_remote_add: writes per-repo credential config into the target repo; which
    identity lands in a foreign repo's config is a credential decision.
  • madt_orchestrate batch-merge: the largest surface - merges PRs, bisects,
    writes revert branches, all credentialed and HEAD-moving.
  • madt_server_info: a dir= version probe crosses the boundary like
    madt_api_call; likely stays launch-forge-only.
  • madt_releases download: dir= already means the download destination (pinned
    non-DirScope, dirscope_drift.go:149). A repo selector collides; either rename
    the download param (breaking) or add a distinct selector.

Not gaps, by-design boundary: madt_api_call (ADR 0027 forbids foreign-cred
resolution), madt_issues (the dir= report carve-out is already built -
create/comment/list/get only), and the gated domains (forge-API tools selected
by owner_repo=, no local-repo gap).

When this is picked up, madt_adr and madt_prs checkout are the cleanest first
carve-outs: reconcile-style precedent and the actual multi-repo need. The rest
follow.

Deferred out of v0.20.0. #638 is not a mechanical change: every tool here touches the forge even on its local path, so a correct dir= has to resolve the dir's OWN forge identity through config.GetConfigForDir. That resolver has a CLOSED call-site allowlist (internal/parity/getconfigfordir_drift.go, getConfigForDirSites), pinned by TestNoUnpinnedGetConfigForDirCallSites: a new site is an ADR 0027 credential-boundary carve-out, a recorded decision per tool, not a drop-in. So #638 is a set of boundary rulings and gets its own pass. Per row, confirmed against main: - madt_adr (init/new/check): init is local-only, but new numbering and check's issue verify resolve the LAUNCH forge (origin.go:52-60; adr.go:1512), so on a foreign dir they read the wrong origin. Needs a dir-scoped resolver (a new carve-out) or a refusal of the forge paths on a foreign dir. Reconcile-style precedent, and the real need behind this issue. - madt_prs action=checkout: the PR read resolves the launch forge and the checkout moves HEAD. Needs a dir-scoped PR read (a new carve-out) plus a foreign-primary clamp. Direct analogue of orchestrate reconcile. - madt_prune: cwd-scoped, hits the forge on dry-run and deletes remote branches when remote=true. A credential-boundary widening. - madt_remote_add: writes per-repo credential config into the target repo; which identity lands in a foreign repo's config is a credential decision. - madt_orchestrate batch-merge: the largest surface - merges PRs, bisects, writes revert branches, all credentialed and HEAD-moving. - madt_server_info: a dir= version probe crosses the boundary like madt_api_call; likely stays launch-forge-only. - madt_releases download: dir= already means the download destination (pinned non-DirScope, dirscope_drift.go:149). A repo selector collides; either rename the download param (breaking) or add a distinct selector. Not gaps, by-design boundary: madt_api_call (ADR 0027 forbids foreign-cred resolution), madt_issues (the dir= report carve-out is already built - create/comment/list/get only), and the gated domains (forge-API tools selected by owner_repo=, no local-repo gap). When this is picked up, madt_adr and madt_prs checkout are the cleanest first carve-outs: reconcile-style precedent and the actual multi-repo need. The rest follow.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sixfold-space/madtea#638
No description provided.