Cowork cloud sessions cannot access any GitHub repository, and the git proxy instructs the agent to call a nonexistent add_repo tool
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Cowork cloud sessions cannot access any GitHub repository, and the git proxy's own error message instructs the agent to call a tool (add_repo) that does not exist in the session.
A Cowork cloud session started with no repository configured as a session source has three overlapping blockers, and no discoverable path around any of them. Notably, the failure is not limited to private repositories — the session-bound git proxy blocks all repository access, including public repos that require no credential at all.
This is a fresh report rather than a comment on #76248 because that issue is scoped to pushes failing with PAT pass-through. This report adds two distinct defects: (a) reads are blocked too, not just writes, and (b) the remediation instruction embedded in the proxy's error text points at a nonexistent tool. Also related: #64130, #74542 (OAuth-only connector, no App installation), and #18467 / #57161 / #79083 (personal-account repos invisible despite App install).
---
Defect 1 (primary) — Proxy error instructs the agent to call a tool that does not exist
Repository-scoped API calls from inside the sandbox return:
GitHub access to this repository is not enabled for this session. Use add_repo to request
access. If add_repo answers that read access is already available and you need GitHub API or
write access, call add_repo again with access:"push" to attach the repository with credentials.
There is no add_repo tool in the session. It is not in PATH, and it is not present in the session's tool registry — a ToolSearch query for add_repo returns only unrelated GitHub MCP tools (create_repository, fork_repository, list_repository_collaborators, …). The error text is written as an instruction to the agent, but the agent has no way to act on it, so the model is deterministically routed into a dead end. The linked documentation_url points at the GitHub Actions docs, which describe an unrelated feature.
Defect 2 — All repository access is blocked, including public repos
The user-level endpoint is blocked entirely:
$ curl -H "Authorization: Bearer $GH_TOKEN" "https://api.github.com/user/repos?visibility=private"
{"message":"This GitHub API path is not available: sessions are bound to their configured
repositories. Use repository-scoped endpoints (repos/{owner}/{repo}/...).",
"documentation_url":"https://docs.anthropic.com/en/docs/claude-code/github-actions"}
Repository-scoped endpoints return 403 for every repo tried, and git clone over HTTPS fails because credential.interactive is disabled and the proxy injects no credential:
$ curl -s -o /dev/null -w "%{http_code}" .../repos/<owner>/<repo> # → 403
$ git clone --depth 1 https://github.com/<owner>/<repo>.git
Cloning into '/tmp/...'...
fatal: could not read Username for 'https://github.com': terminal prompts disabled
This blocks reads of public repositories as well, which cannot be justified on credential-safety grounds — no credential is needed to clone a public repo. #76248 reports clones/fetches still working; that is no longer the case here, which suggests the enforcement has widened since that report.
Defect 3 — No way to add a repository as a session source from Cowork
Both the proxy error ("add the repository to the session's sources") and the API error ("Use add_repo") presuppose an affordance that does not exist in the Cowork surface. There is no repo picker, no session-source setting, and no slash command. The user cannot fix this from the product, and neither can the agent.
Contributing factor — connector is OAuth-only, private repos invisible
Separately from the proxy, the GitHub MCP connector in the session is authenticated (get_me → correct login, 93 public repos) but sees zero private repositories:
search_repositories("user:<login>")→ 75 results, all"private": falsesearch_repositories("user:<login> is:private")→total_count: 0get_teams()→null
This matches the OAuth-authorized-but-App-not-installed pattern in #64130 and #74542. The net effect is that a user who has authorized GitHub, sees "Connected" in settings, and has granted repository access still has no working path to their own private code from Cowork — the connector can't see it and the proxy won't clone it.
What Should Happen?
- The proxy error must not instruct the agent to call a tool that isn't registered in the session. Either expose
add_repoas a real tool in Cowork cloud sessions, or replace the text with an accurate, user-actionable instruction (and fix thedocumentation_url, which currently points at GitHub Actions docs). - Public repository reads should not require session binding. Cloning a public repo needs no credential and should not be gated by the credential-injection allowlist.
- Cowork should expose a discoverable way to add a repository to a session's authorized set, mirroring the repo picker in Claude Code on the web.
- Connecting GitHub should route through the GitHub App installation + repository-selection flow so the connector can actually see private repos (per #64130).
Steps to Reproduce
- Start a Cowork cloud session from the web app with no GitHub repository configured as a source.
- Ask Claude to read a private repository you own.
- Observe the MCP connector returns only public repos, with
is:privatesearches empty. - In the sandbox, run
curl -H "Authorization: Bearer $GH_TOKEN" https://api.github.com/user/repos→ blocked with the "sessions are bound to their configured repositories" message. - Run the same against
repos/{owner}/{repo}for any repo, public or private → 403 with theadd_repoinstruction. - Search the session's tool registry for
add_repo→ not found. git cloneany repo over HTTPS →fatal: could not read Username ... terminal prompts disabled.
Environment
- Product: Cowork cloud session (web client)
CLAUDE_CODE_REMOTE_SESSION_ID:cse_011Yr7B3YaJ9HcEuoNBnpvVtCLAUDE_CODE_REMOTE_ENVIRONMENT_TYPE:cloud_defaultCLAUDE_CODE_REMOTE_HERMETIC_MODE:0- Proxy flags observed:
CCR_TEST_GITPROXY=1,CCR_AGENT_PROXY_ENABLED=1,CCR_UPSTREAM_PROXY_ENABLED=1,CCR_EGRESS_GATEWAY_ENABLED=1 - Injected git config:
credential.interactive(disabled),url.https://github.com/.insteadOf ghCLI: not installed in the sandbox (gh: command not found), so the documentedghfallback is unavailable- Model:
claude-opus-5 - Date observed: 2026-08-06
Impact
For Cowork specifically this is the difference between "an agent that can work on my codebase" and "an agent that can only work on code I paste in." The security rationale for the proxy is understandable — an agent holding a broad-scope token is an exfiltration risk under prompt injection — but the replacement path was never surfaced in this client, so the practical result is no repository access at all, with an error message that sends the agent chasing a tool that doesn't exist. Competing products solve this with either a pasted PAT or an App install with repo selection at setup time; Cowork currently has neither working end to end.
12 Comments
Corroborating this from a separate Cowork cloud session (
claude-opus-5, desktop client, August 6). Sameadd_repodead end, samedocumentation_urlpointing at the GitHub Actions docs. Two corrections and two additions from testing it directly.Correction:
git cloneover HTTPS does work for public reposSame session, back to back:
So the git-protocol block isn't blanket. It's specifically that no credential is injected for private repos.
Addition: the REST API is 403 for everything, including public endpoints
That second one is the surprising case. Reading a public issue needs no credential and carries no access risk, but it's blocked the same as everything else. The security rationale that justifies the private-repo block doesn't extend to it.
Practical consequence:
ghis not installed in the session, and installing it doesn't help, because it speaks to the API that's 403ing. There is no CLI path to GitHub at all. The only working channel isWebFetchagainst public github.com HTML.Addition: the desktop-bridge workaround is a dead end, for a specific reason
Cowork can reach a locally-mounted git worktree through the remote-devices bridge, which is a real workaround for reading code. But that shell has no network:
The two shells each have exactly one of the two things needed, and there's no way to combine them:
| | network | repo access |
|---|---|---|
| cloud shell | yes | no credential |
| device shell | no | yes (mounted worktree) |
Neither can fetch, so the agent can't tell whether a branch it's reasoning about is current.
Where this actually costs something
This week I was evaluating moving our agent work-order briefs out of in-repo
.mdfiles and into GitHub Issues. It's otherwise the better design and removes a class of race condition. I declined it specifically because the agent can't read Issues on a private repo, so the corpus of prior decisions would go dark to it.That's a case where this limitation changed an architecture decision rather than just being an inconvenience.
---
Adding a repo picker plus routing auth through the GitHub App installation flow, as proposed above, would resolve all of it. Allowing unauthenticated reads of public API endpoints looks decoupled from that and shippable on its own, since there's no credential involved either way.
Also hitting this. DealRoomLabs, private org repo, Cowork cloud session,
claude-opus-5, 2026-08-25. Still reproduces three weeks after the original report.
Task was trivial: create a
skills/folder inDealRoomLabs/[MY_REPO]. Session hadGH_TOKEN and GITHUB_TOKEN set,
ghnot installed.git clone https://github.com/DealRoomLabs/[MY_REPO].git
fatal: could not read Username for 'https://github.com': terminal prompts disabled
curl -H "Authorization: Bearer $GH_TOKEN" https://api.github.com/repos/DealRoomLabs/[MY_REPO]
{"message":"GitHub access to this repository is not enabled for this session.
Use add_repo to request access..."}
add_repois not in the tool registry. ToolSearch returns no match for it either,so the error is pointing at something the agent has no way to call.
Workaround was to drive the GitHub web UI through the Claude in Chrome tools and
commit from the browser. Fine for one file, unusable past that.
Impact for us: Cowork is where our product and GTM work happens, and a lot of it
touches internal repos. That work now has to move to the Claude Code CLI or get
done by hand. A repo picker in Cowork session settings, matching what Claude Code
on the web already has, would close this.
Reproducing this on 2026-08-30. Adding a measured matrix.
<html><head></head><body><h1>Cowork cloud sessions: the <code>ccr-gitengine</code> proxy blocks GitHub App installation tokens and rewrites API identity</h1>
<p><strong>Reporter:</strong> Funos (funos.es) — 3 engineers-equivalent, Claude Max + Anthropic API customer
<strong>Surface:</strong> Claude Cowork (cloud sandbox), <code>CCR_AGENT_PROXY_ENABLED=1</code>, <code>CCR_TEST_GITPROXY=1</code>
<strong>First observed:</strong> 2026-08-27 · <strong>Still reproducing:</strong> 2026-08-30
<strong>Related open issues:</strong> anthropics/claude-code #76248 (opened 2026-07-10), #84581 (opened 2026-08-06) — both still open, no maintainer response.</p>
<hr>
<h2>1. Summary</h2>
<p>From inside a Cowork cloud session, three independent behaviours of the outbound proxy make it impossible for us to operate GitHub with a <strong>separate machine identity</strong>:</p>
<ol>
<li><strong><code>api.github.com</code> ignores the credential supplied by the process and answers with the session owner's identity.</strong> <code>GET /user</code> returns HTTP 200 and <code>"login":"marcfunos"</code> with <strong>no</strong> <code>Authorization</code> header at all, and again with a deliberately invalid Bearer token.</li>
<li><strong>The git transport rejects any credential whose prefix is exactly <code>ghs_</code></strong> — the prefix of <em>every</em> GitHub App installation token. One character of difference (<code>GHS_</code>, <code>ghsx_</code>, <code>xghs_</code>) reaches GitHub normally.</li>
<li><strong>Writes are blocked per-repository</strong>, and the error instructs the agent to call a tool named <code>add_repo</code> that <strong>does not exist</strong> in the session's tool list, and that has no corresponding UI control anywhere in Cowork.</li>
</ol>
<p>The same GitHub App installation token works normally from outside the sandbox (HTTP 200, correct HEAD SHA) at the same moment.</p>
<p>We are not asking you to accept our reading of your architecture. We are asking you to explain the observable matrix in §3.</p>
<hr>
<h2>2. Why this matters beyond connectivity</h2>
<p>We deliberately use a GitHub App (<code>funos-claude-techlead</code>) so that automated merges carry <strong>their own identity</strong>, distinct from any human's. That is our audit trail: a merge signed <code>funos-claude-techlead[bot]</code> is an automated action; a merge signed by a person is a human action.</p>
<p>Two consequences of the current behaviour:</p>
<ul>
<li><strong>Attribution.</strong> <code>api.github.com</code> answering with the session owner's login for an unauthenticated request means an agent in a Cowork session acts, at the API layer, <strong>as the human account</strong>. Any action taken that way is indistinguishable in GitHub's audit log from one the human performed.</li>
<li><strong>Governance.</strong> The only credential the proxy will carry is one bound to the session's human identity. Forcing us onto a human PAT collapses machine and human accountability into a single account. That is a compliance regression, not an inconvenience.</li>
</ul>
<hr>
<h2>3. Observable matrix</h2>
<p>All measurements below were taken from inside a Cowork cloud session. <strong>Every token used in the prefix table was fabricated and invalid</strong> — no real credential was needed to produce the behaviour.</p>
<h3>3a. <code>api.github.com</code> — credential is ignored</h3>
Request | Credential sent | Result
-- | -- | --
GET /user | none | HTTP 200, "login":"<session owner>"
GET /user | invalid Bearer | HTTP 200, same login
GET /repos/<org>/<repo> | none | HTTP 403 (see body below)
<p><strong>A meaningless string reaches GitHub. A well-formed GitHub App installation token does not.</strong> The match is case-sensitive, at position 0, on the exact four characters <code>ghs_</code>. A non-existent App ID produces the same result as a valid one, so the outcome does not depend on the token being valid.</p>
<p>Note: the <code>ccr-gitengine</code> 401 does carry a real <code>X-Github-Request-Id</code>, so we make <strong>no claim</strong> about whether GitHub sees the request. What we observe is that the response lacks <code>Server</code>, <code>Date</code> and <code>Content-Length</code>, and that the realm is named after your proxy.</p>
<h3>3c. Writes — blocked per repository, with no available remedy</h3>
<p>Push to a <strong>throwaway repository owned by the reporter</strong>, using a <strong>valid fine-grained PAT with write permission on that repository</strong>:</p>
<pre><code>access denied by the git proxy: <org>/<repo> is not in this session's authorized
repository set, so the proxy will not inject a credential for it. To fix, add the
repository to the session's sources.
</code></pre>
<p>There is no "session's sources" control in the Cowork interface.</p>
<p>Reads via git transport <strong>do</strong> work when a fine-grained read-only PAT is supplied in the URL (1,556 refs returned). Without a credential, <code>git ls-remote</code> fails with <code>could not read Username</code> — i.e. the proxy injects nothing for our repository.</p>
<h3>3d. External control — the same token works outside the sandbox</h3>
<p>At the same time, on the reporter's own machine, with an installation token freshly issued by the same App:</p>
<ul>
<li><code>GET /repos/<org>/<repo></code> → <strong>HTTP 200</strong></li>
<li><code>git ls-remote</code> → correct <code>HEAD</code> SHA, matching what the sandbox read with a PAT</li>
</ul>
<p>Independent control: a different cloud coding agent (running outside Anthropic's infrastructure) wrote to the <strong>same repository, same organization, same branch protection</strong> throughout the incident. Nothing on our side is broken.</p>
<h3>3e. Sandbox environment (redacted)</h3>
<pre><code>CCR_AGENT_PROXY_ENABLED=1
CCR_UPSTREAM_PROXY_ENABLED=1
CCR_TEST_GITPROXY=1
CCR_EGRESS_GATEWAY_ENABLED=1
https_proxy=http://127.0.0.1:<port>
GH_TOKEN=proxy-injected
GITHUB_TOKEN=proxy-injected
GIT_CONFIG_KEY_1=url.https://github.com/.insteadOf (value: git@github.com:)
GIT_SSL_CAINFO=/root/.ccr/ca-bundle.crt
</code></pre>
<hr>
<h2>4. Questions we would like answered</h2>
<ol>
<li>Is the <code>ghs_</code> prefix filter on the git transport <strong>intended</strong>? If so, what is the supported way for a Cowork session to act under a GitHub App identity?</li>
<li><code>GET /user</code> returning the session owner's login for an <strong>unauthenticated</strong> request: is that intended? What identity actually performs GitHub API calls originating from a Cowork session, and how is that recorded in the customer's GitHub audit log?</li>
<li><code>add_repo</code> is referenced in your own error message. Does it exist? If it exists on another surface, how does a <strong>Cowork</strong> user add a repository to the session's authorized set?</li>
<li>If a repository <em>is</em> attached, <strong>which identity signs the resulting commits and pushes</strong> — the session owner, or a bot/App identity we control?</li>
<li>Is there any supported configuration in which an automated action from a Cowork session is attributable to an identity other than the human who owns the session?</li>
</ol>
<hr>
<h2>5. What we are doing meanwhile</h2>
<p>Read-only auditing from the session with a human fine-grained read-only PAT, and every merge performed manually by a human. This removes the automation benefit but preserves the audit trail. We would prefer a supported path.</p>
<hr>
<h2>6. Reproduction, minimal</h2>
<p>Inside a Cowork cloud session, with <strong>no real credentials</strong>:</p>
<pre><code class="language-bash">curl -s https://api.github.com/user | head -3
curl -s -w '\n%{http_code}\n' https://api.github.com/repos/<any-org>/<any-private-repo>
for t in "ghs_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" \
"GHS_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" \
"ghsx_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" \
"hola-que-tal-1234567890"; do
echo "--- $t"
curl -s -D- -o /dev/null -u "x-access-token:$t" \
"https://github.com/<any-org>/<any-repo>.git/info/refs?service=git-upload-pack" \
| grep -Ei 'www-authenticate|^server|^HTTP'
done
</code></pre>
<p>Expect: the first two <code>curl</code>s show the identity substitution and the <code>add_repo</code> message; the loop shows <code>realm="ccr-gitengine"</code> for the <code>ghs_</code> case only, and <code>realm="GitHub"</code> with <code>Server: GitHub-Babel/3.0</code> for every other string, garbage included.</p>
<hr>
<p><em>No real token is reproduced anywhere in this report.</em></p></body></html>
Adding my own experience to this. It is frankly infuriating. I had such a good workflow going until they added this git proxy that blocks the PAT I have agents using. Now pushing code from a chat or cowork scenario is miserable. I don't like using code because I just get buried in approvals. I want an agent that codes in a VM and then has the ability to use a PAT I provide to push code.
This should be simple, but instead it has probably chewed up hundreds of dollars of tokens and made me strongly consider leaving anthropic tools entirely. I'm far from the biggest user, but I spend $500-1000/month and push claude as the best tool to use.
But to be honest, it's getting to the point where it's easier to run a small qwen in a local harness. At the end of the day it's not slower because I don't burn hours on nonsense like this.
cowork_github_push_support_request.md
Support Request: Cowork cloud session cannot push to GitHub (git proxy blocks all repos)
Product: Claude (Cowork mode)
Date: September 4, 2026
Session: https://claude.ai/code/session_01ECu3nvDnjhtSGhcAcDUogM
Account: dooziiinc@gmail.com
What I was trying to do
Set up a Cowork session to work independently on my private GitHub repository (
dooziiinc/openwater) in parallel with my own local development — cloning the repo into the session's cloud workspace, making commits there, and pushing branches/opening PRs, while I keep working on my local checkout at the same time.What happened
git clonethe repo directly — this worked fine, full read access.git push(even a--dry-run), it was rejected with:``
``remote: access denied by the git proxy: dooziiinc/openwater is not in this session's
authorized repository set, so the proxy will not inject a credential for it. To fix,
add the repository to the session's sources.
add_repotool, no repo-picker, nothing underListConnectors/SearchMcpRegistryfor GitHub push access).Root cause (as far as we could tell)
This appears to match a known, already-filed issue: anthropics/claude-code#84581 — "Cowork cloud sessions cannot access any GitHub repository, and the git proxy instructs the agent to call a nonexistent
add_repotool." That issue describes the same failure mode: the git proxy's error message references a tool and a "session sources" configuration step that doesn't actually exist anywhere in the current Cowork product, leaving no way for a user to authorize push access to their own repository.Impact
Read access (clone) works. Write access (push, and therefore PRs) is completely blocked for every private repository, with no self-serve fix available to the user or the agent. This blocks the core "work independently on my repo in the cloud" workflow.
Request
add_repotool) would help users and agents understand this isn't something they're doing wrong.Confirming this is still reproducible today (2026-09-04) on a Cowork cloud session, working against a private repo (
tron1982-gm/ppMT-Website).Model/session type:
claude-sonnet-5, Cowork cloud session.Private repo — blocked, matches the original report:
git ls-remote https://github.com/<org>/<private-repo>.git→fatal: could not read Username for 'https://github.com': terminal prompts disabledcurl https://api.github.com/repos/<org>/<private-repo>→``
json
``{"message":"GitHub access to this repository is not enabled for this session. Use add_repo to request access. If add_repo answers that read access is already available and you need GitHub API or write access, call add_repo again with access:\"push\" to attach the repository with credentials.","documentation_url":"https://docs.anthropic.com/en/docs/claude-code/github-actions"}
There is no
add_repotool available in this Cowork session's tool registry (checked via ToolSearch), so the instruction in the error message is a dead end.Public repo — confirming @afxjzs's split-behavior finding:
git ls-remoteagainst a public repo (anthropics/claude-codeitself) succeeds fine (returns the full ref list), butcurl https://api.github.com/repos/anthropics/claude-codeand even.../issues/84581both return a bare403, no credential involved either way. So the git-protocol block really is scoped to missing credentials for private repos, but the REST API block is blanket and doesn't distinguish public from private — same pattern already reported here and in #86828.On the GitHub side: the Claude GitHub App is fully installed with "All repositories" access selected (including private repos), all requested permissions accepted (including the newer "Read access to commit statuses" scope). Re-saving that configuration and starting a brand-new Cowork session made no difference — same error every time for the private repo. So this doesn't look like anything fixable from the user's GitHub App settings; it's the session-side git/API proxy not being authorized for the repo at all.
Workaround that does work reliably, same as @jmburke describes above: driving GitHub entirely through Claude's browser tools (in-app Browser pane or Claude-in-Chrome, already signed in to github.com) — both read (browsing files, PRs, Actions logs) and write (editing via the CodeMirror web editor, committing, opening/merging PRs) work fine that way. Slower and far more token-intensive than a real
git/ghworkflow, but it's the only path that isn't blocked, and it's enough to keep a project moving when there's no alternative.Happy to provide more repro details/session IDs if useful for debugging.
I setup my own proxy to literally forward requests to api.github.com. Workarounds exist, but not ideal...
Still reproducing on 2026-09-14,
claude-opus-5, Cowork cloud session. This onewas linked to a desktop, which turns out to matter rather a lot.
Two additional points to report first, then the part nobody has posted.
point 1 —
ghis missing on both sidesThe
ghCLI isn't installed in the sandbox. True, but incomplete.It isn't installed in the linked device's VM either, so the documented
ghfallback has nowhere at all to run:
point 2 — @afxjzs is right about git, and it isn't a credential problem
Git protocol works for public repositories from the cloud container. Confirmed
against a repo I own, flipped from private to public mid-session:
The REST API, however, does not care:
A public repository the same shell can clone, and a public endpoint on this very
repository, both refused. No credential is involved in either call, so there is
nothing here for the proxy to be protecting.
The new part — the session can reach the API, just not from the half that needs it
A Cowork session linked to a desktop has two shells: the cloud container, and a
Linux VM on the user's own machine, reached through
device_bash. Both egressthrough allowlisting proxies. They do not agree with one another.
That 200 is how the Claude Cowork session read this issue and its comments today. The agent could not
fetch its own bug report from the sandbox, so it fetched it from my Mac instead
and carried the JSON back over the bridge.
Two things follow. It is a usable workaround for anyone stuck — link a desktop
and route API reads through
device_bash— which I offer without enthusiasm,because tunnelling GitHub reads through a laptop to reach a cloud agent is not a
design anyone intended.
More usefully, it is evidence for defect 2. The block is not a boundary. It is one
misconfigured egress rule on one of two shells belonging to the same session,
carrying the same identity, and an agent that thinks to ask the other shell walks
straight round it. A control that is trivially bypassed from inside the trust
boundary it claims to draw is not buying the safety the sandbox is presumably
paying for — it is only buying the friction.
Environment
claude-opus-5, linked to a macOS desktopuvpresent,ghabsentadd_repostill absent from the tool registry;ToolSearchreturns no matchthe API behaviour
I'm not sure if this is related or not, but I work on a lot of public repos like https://github.com/apache/datafusion and I cannot use Claude Code cloud sessions on them:
I'm hitting this exact issue in a Cowork session, with a clean reproduction timeline that might help narrow it down.
What worked: A Cowork session pushed directly to my private repo (cos-control-plane) successfully for several hours on 2026-09-19–20, authoring and pushing 6+ commits to main under its own git identity (Claude <noreply@anthropic.com>), via the Claude GitHub App.
What broke: After the conversation was compacted/continued (a context-limit summarization event), every further push attempt from that same session started failing with:
remote: access denied by the git proxy: <owner>/<repo> is not in this session's authorized repository set, so the proxy will not inject a credential for it. To fix, add the repository to the session's sources.
What I tried, in order, none of which fixed it:
Reinstalled the Claude GitHub App, explicitly scoped to the one repo.
Started a completely new/fresh Cowork task (not a continuation) after the reinstall — identical error.
Fully disconnected the GitHub connector at claude.ai/customize/connectors, uninstalled the GitHub App entirely from github.com/settings/installations, then reinstalled from scratch and reconnected — identical error, in yet another fresh session.
Workaround confirmed: A separate, independently-authenticated Claude Code instance (not a Cowork session — a self-hosted container with its own GitHub credentials) can push to the same repo without any issue. So this isn't a GitHub-account-level permission problem — it's specific to how Cowork sessions get (or lose) their git-proxy credential injection for a given repo.
This matches issue #84581, where a maintainer confirmed the underlying block is intended behavior, but the self-service repo-authorization flow doesn't seem to work correctly for Cowork sessions specifically (unlike the separate claude.ai/code web interface, which apparently has a working repo picker). Happy to provide session IDs or further detail if useful.
Adding a measurement that I think narrows this, because it rules out
credentials entirely and points at one specific component.
In a Cowork cloud session, a non-repo GitHub endpoint succeeds with the same
token that every repo endpoint refuses — and public repos are refused too.
That third line is the one I have not seen stated on these threads. It is a
public repository, fetched with no Authorization header at all — an
unauthenticated request that GitHub itself would answer 200 for anyone. It is
refused with the same "not enabled for this session" body. So:
unauthenticated request to a public repo)
/usersucceeding proves the token is valid, the proxy is passing traffic,and GitHub is reachable
What is left is a per-repository allowlist applied to the
/repos/*pathinside the session, which is empty for this session and has no way to be
populated.
add_repo, which the error names as the remedy, is not in thesession's tool registry — I checked the loaded tools and the deferred-tool
list, and searched for it by name.
It can also be lost mid-session. Earlier in the same session I had
successfully created branches, commits and a PR through the Git Data API. Later
calls began returning the 403 above with nothing changed on my side. Between
those two points the session's MCP servers disconnected and reconnected several
times (I saw at least four cycles). I cannot show causation, only that it is
the sole state change I observed between working and not.
Things that did not fix it, for the record, so others can skip them:
this cannot affect it, and did not)
Happy to supply session ids or run any specific probe if that would help.