@mcp-s/git
v1.0.1
Published
Willow Git Proxy — GitHub access for background coding agents, with no GitHub token in the sandbox
Downloads
717
Readme
@mcp-s/git (willow-git)
Willow Git Proxy CLI: point git at the Willow run gateway so background
coding agents can clone, fetch, pull, and push GitHub repositories. Willow
attaches the GitHub App token on the server side — no PAT, no App private key,
and no GitHub token of any kind inside the agent's environment.
Admin guide: https://docs.withwillow.ai/docs/admin/background-agents/git-proxy
Spec: docs/handoff/willow-git-proxy-technical-spec.md
Install (local)
npm install
npm run build
npm run test:vitest
npm link # optional: willow-git on PATHCLI
export WILLOW_GATEWAY_URL=https://run.example.com
export WILLOW_AGENT_TOKEN=ba_xxx:secret
export WILLOW_AGENT_SLUG=payments-bot
willow-git setup # ~/.willow/git/config + git URL rewrite
willow-git repos
git clone https://github.com/acme/payments.git
# SSH remotes are rewritten too
git clone [email protected]:acme/payments.git
# Open a pull request from the current branch (push it first)
willow-git pr create --title "Fix title" --body "Why"pr create posts to /agent-api/:slug/git/pulls; Willow checks write access
and calls the GitHub API itself. Repo comes from origin, head from the
current branch, and base from the allowlist default branch unless --repo,
--head, or --base is passed.
What setup writes
url.<gateway>/agent-api/<slug>/git/github.com/.insteadOf
https://github.com/ , [email protected]: , ssh://[email protected]/
http.<gateway>/agent-api/<slug>/git/.extraheader
Authorization: Bearer <WILLOW_AGENT_TOKEN>
credential.<gateway>/agent-api/<slug>/git/.helper
!f() { echo quit=1; }; f
<first writable PATH dir ahead of git>/git
wrapper that re-sends the current WILLOW_AGENT_TOKEN, then execs real gitA raw Authorization header rather than a credential helper: on managed
platforms WILLOW_AGENT_TOKEN is a placeholder the sandbox egress substitutes
on the way out, and HTTP Basic would base64-encode it beyond recognition.
That placeholder changes between turns, so the header saved in ~/.gitconfig
goes stale. The wrapper replaces it on every call with the value currently in
the environment, via GIT_CONFIG_COUNT so it never appears in a process
listing. Setup never overwrites a git it did not write; when it cannot
install the wrapper it warns, and setup must be re-run each turn. The quit
helper makes a 401 fail immediately instead of waiting on a username prompt.
Setup also unsets the credential.https://github.com.* keys written by
@mcp-s/git 0.x, which minted a GitHub token inside the sandbox.
To undo the rewrite on a shared machine:
git config --global --remove-section "url.<gateway>/agent-api/<slug>/git/github.com/"
git config --global --remove-section "http.<gateway>/agent-api/<slug>/git/"PATH shim (optional)
export PATH="$(npm root -g)/@mcp-s/git/git-shim:$PATH"git-shim/git execs willow-git git "$@", which checks the allowlist before
spawning real git so a disallowed repo or a push to a read-only repo fails with
a clear message. Plain git works without the shim; the gateway enforces the
same rules either way.
Layout
src/cli.ts argv router
src/model/gitProxy.ts wire + domain interfaces
src/consts/git.consts.ts constants
src/utils/config.utils.ts env + ~/.willow/git/config
src/utils/parse-repo.utils.ts github.com → owner/name; SSH→HTTPS
src/utils/repos.utils.ts GET /agent-api/:slug/git/repos
src/utils/pull-request.utils.ts POST /agent-api/:slug/git/pulls
src/utils/wrap-git.utils.ts allowlist pre-flight + spawn real git
src/utils/setup.utils.ts persist WILLOW_* + git URL rewrite
src/utils/git-shim.utils.ts live-token git wrapper
src/utils/secret-redaction.utils.ts registerSecret / redact stderr
git-shim/git PATH drop-in
tests/<domain>/*.spec.ts Vitest (PR-blocking)Security
The only credential this CLI handles is the agent's own Willow token, scoped to that agent's repository allowlist. GitHub credentials are minted and attached inside Willow and never cross into the agent's environment, so there is nothing here to cache, redact, or leak.
