Repository navigation
Bind agent tool calls to the run's repositories - #2087
Merged
Merged
Conversation
ppXD
force-pushed
the
fix/delete-a-merged-branch-only-in-its-own-repository
branch
from
October 7, 2026 19:18
59fb645 to
ad1a095
Compare
ppXD
changed the base branch from
fix/delete-a-merged-branch-only-in-its-own-repository
to
main
October 7, 2026 19:19
ppXD
force-pushed
the
fix/bind-agent-tool-calls-to-the-runs-repositories
branch
from
October 7, 2026 19:19
22031af to
86c9a1b
Compare
agent.run_command and the git.* pull-request tools resolved a model-supplied repositoryId by id and team only, so an agent could clone, read, merge or comment on any repository of its team at any ref it named, including repositories its run was never bound to and unmerged branches, using that repository's connection credential. Network Off and a read-only write scope did not stop it. The run's bound repositories (its admitted task's workspace, with each repository's access and ref) are now stamped server-side onto the posture every tool call carries. NodeAgentTool holds every node that declares a repository input (NodeManifest.RepositoryInput) to that set: any other id gets the same "not found" a missing or foreign one gets. Read-only context is the run's to read, not to write: an agent opens, merges, reviews and comments on none of its pull requests, and a command checks it out only at its bound or default branch. The pin covers what a command checks out; the repository's pull requests stay readable through the git read tools. A patch-only repository refuses agent pull-request writes through the guard chain an agent's pushed branch meets. Each of these refusals is answered before a call is parked for approval (IAgentTool.RefusalAsync), so a Standard or Trusted run never asks a human to approve a call that could only be refused; the tool checks again when the call runs, since a repository can change while a card waits. RunCommandService keeps its own ref pin for a caller that reaches it directly. A supervisor-spawned child's related repositories carry the operator's bound ref, not one the supervisor model authored: that ref is what the child clones and what its read-only binding pins commands to. A run whose write scope is read-only (an agent.run with readOnly, or a Confined tier) is served a NonDestructive catalog: every tool that does not write, so it can still ask a human through decision.request. The fabric opt-out's ReadOnly slice is unchanged. Workflow-node calls carry no calling run and are unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
agent.run_command,git.fetch_pr_diff,git.list_prs,git.fetch_pr_checks,git.open_pr,git.merge_pr,git.pr_reviewandgit.post_pr_comment.AgentRunExecutor.OpenMcpEndpointstamps the bound set (id, access, ref) server-side ontoAgentRunPosture.NodeAgentToolenforces it once for every node that declaresNodeManifest.RepositoryInput.Repository {id} not found.that a missing or foreign id gets.agent.run_commandchecks it out only at its bound or default branch (AgentRepositoryBinding).IAgentRepositoryPolicy).IAgentTool.RefusalAsync, consulted byMcpRequestHandlerafter the gate's deny check and input validation). Standard and Trusted runs therefore never post a card or claim a ledger row for a call that could only be refused. The tool checks again when the call runs.SupervisorRepoClamp.IntersectWithBoundRepos).readOnlyonagent.run, or a Confined tier) is servedMcpCatalogMode.NonDestructive. It gets no tool that writes, but can still ask a human throughdecision.request.ReadOnlyslice.Test plan
NodeAgentToolagainst the production PR write nodes (Read, Write and unknown access); handler refusals before park/claim at every tier; supervisor clamp ref; full unit suite (12,417 passed, 1 skipped)readOnlyruns listdecision.requestand can reach it, whileagent.run_command,git.open_prandgit.merge_prare absentHeadlineFlowE2ETests(readOnlyfan-out) 3/3