Upgrade the Claude ACP adapter (upstream sync)
SkillCommunicationThis skill is a runbook for syncing a fork of the claude-agent-acp adapter with a newer upstream release. It guides an AI agent through reading UPSTREAM.md, triaging upstream commits, bumping the claude-agent-sdk and @agentclientprotocol/sdk, porting bug fixes and new SDK message handling, and preserving the fork's intentional divergences.
Use Upgrade the Claude ACP adapter (upstream sync) in Claude, ChatGPT or Ahel Desktop
Free. Sign in, add Upgrade the Claude ACP adapter (upstream sync) and connect your AI. About a minute.
Also: Claude Code · Cursor · Codex
Then ask your AI: use the Upgrade the Claude ACP adapter (upstream sync) skill
Details
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; ahel provides instructions and does not run this skill.
No other account needed.
Have a local git clone of the upstream claude-agent-acp repository available and note its path.
What your AI can do with it
- Read UPSTREAM.md to find the fork point, last sync, file mapping, and divergences
- Triage upstream commits into ports, dependency bumps, and skips
- Bump claude-agent-sdk and @agentclientprotocol/sdk to target versions
Getting started
- Have a local git clone of the upstream claude-agent-acp repository available and note its path.
- Have the fork repository checked out with the claude adapter under packages/agent/src/adapters/claude/.
- Read UPSTREAM.md in that adapter directory to learn the last sync commit, pinned SDK versions, file mapping, and intentional divergences.
- Tell the agent to follow the upgrade skill in the claude adapter directory, or move the skill file to .claude/skills/<name>/SKILL.md to run it as a slash command.
- Provide the upstream checkout path if the agent asks for it, then let the agent triage commits, port changes, bump SDKs, verify with typechecking, and update UPSTREAM.md.
What this skill tells your AI
The instructions your AI receives, as published by posthog/posthog in packages/agent/packages/agent/src/adapters/claude/SKILL.md and read by ahel’s review.
This is a runbook for syncing our fork of @anthropic-ai/claude-agent-acp (the upstream
Zed/agentclientprotocol ACP agent) that lives in packages/agent/src/adapters/claude/ with a newer
upstream release. The fork is heavily diverged. The job is to port the valuable upstream changes
(SDK bumps, bug fixes, new SDK-message handling) while preserving every intentional divergence — not
to make the fork identical to upstream.
UPSTREAM.md (this directory) is the source of truth for the fork point, last-synced
version/commit, the file mapping, the PostHog-only code, and the intentional
divergences. Read it first, update it last.
This file is a runbook, not an auto-registered slash command. Invoke it by telling Claude to "follow the upgrade skill in the claude adapter dir." Move it to
.claude/skills/<name>/SKILL.mdif you ever want it runnable as/<name>.
Inputs you need before starting
- Upstream source checkout — a local git clone of
github.com/agentclientprotocol/claude-agent-acp. You need its history to diff. If the user hasn't given the path, ask for it (it's usually somewhere like~/Cloud/claude-agent-acp). Do not guess. - This repo — the fork under
packages/agent/.
Process
0. Orient (read, don't write)
- Read
UPSTREAM.md. Note Last sync (commit + version), the pinned SDK versions, the File Mapping, PostHog-Only Code (Do Not Sync), and Intentional Divergences. - In the upstream checkout, list the change set since the last sync and skim the changelog:
git -C <upstream> log --oneline <last-sync-sha>..HEADgit -C <upstream> show <upstream>/CHANGELOG.md:CHANGELOG.md(or just readCHANGELOG.md)
- Confirm the new target version + HEAD sha and the target SDK versions from the upstream
package.json.
1. Triage every commit
Bucket each commit since the last sync:
- Port — bug fixes and new feature / SDK-message handling that are not in the PostHog-only list and don't fight a divergence.
- Dep bump — record the target SDK versions; the diff tells you if code changes ride along.
- Skip —
chore(main): release …,actions/*CI bumps, pure dependabot dev-dep bumps, and anything matching the PostHog-only / divergence lists.
Read intent from source diffs (exclude tests + JSON first):
git -C <upstream> show <sha> -- src/ ':(exclude)src/tests/*' ':(exclude)*.json'
A dependabot SDK-bump commit often also carries real code (new message handling). Don't assume "deps" == "no code".
2. Map upstream → fork
Upstream is one large src/acp-agent.ts; our fork is split. Use the File Mapping in UPSTREAM.md.
Rough guide:
| Upstream | Fork |
|---|---|
acp-agent.ts prompt loop, lifecycle, cancel | claude-agent.ts |
| inline message/stream/result/system conversion | conversion/sdk-to-acp.ts |
| inline prompt→SDK conversion | conversion/acp-to-sdk.ts |
tools.ts (tool_use→ACP, PostToolUse hook) | conversion/tool-use-to-acp.ts, hooks.ts |
| model alias resolution | session/models.ts, session/model-config.ts |
| options / system prompt | session/options.ts |
| permissions | permissions/* |
For each upstream change, rg the fork for the touched symbol first — the fork usually already has a
diverged version of it, so you're editing, not adding.
3. Bump dependencies
In packages/agent/package.json, set @anthropic-ai/claude-agent-sdk, @agentclientprotocol/sdk,
and @anthropic-ai/sdk to the upstream package.json versions, then pnpm install from the repo
root. (packages/shared pins its own older @agentclientprotocol/sdk; leave it unless a
cross-package type error forces a bump.)
4. Find the breaking-change surface
Run pnpm --filter agent typecheck. The errors are your ACP/SDK breaking-change list. Gotchas seen
in past syncs:
- The ACP SDK ships name-mangled generated types.
dist/schema/*.gen.d.tsshows enum literals asn(e.g.StopReason = "…" | "n" | "cancelled"). Don't trust grep there. Read the hand-writtendist/acp.d.ts, or download the exact target to inspect cleanly:cd /tmp && npm pack @agentclientprotocol/sdk@<ver> && tar xzf *.tgz rg -n "type StopReason|deleteSession|SessionModelState" package/dist/schema/types.gen.d.ts package/dist/acp.d.ts node -e "require('<pkg>/package.json')"may fail on the SDKs (exports map blocks the subpath). Readnode_modules/<pkg>/package.jsondirectly for the installed version.- An ACP SDK bump can break code outside the claude adapter. The whole
packages/agentpackage must typecheck — expect to also fixadapters/codex/*andserver/agent-server.ts. Keep those fixes minimal and behavior-preserving (e.g. when ACP removed themodelsresponse field, the codex adapter derived the model id fromconfigOptionsinstead).
5. Port in phases — bug fixes first, then features
For each ported change:
- Preserve divergences (see
UPSTREAM.md→ Intentional Divergences + PostHog-only). The big ones: single-sessionthis.session(notthis.sessions[id]);interruptReasonon cancel; gateway models viafetchGatewayModels(notinitializationResult.models);_posthog/*ext notifications; the "Unsupported slash command" gate onknownSlashCommands;SYSTEM_REMINDERstripping; plan / questions / MCP-metadata machinery. - New SDK
systemsubtypes are safe by default.handleSystemMessageends indefault: break, and the prompt-loop top-levelswitch (message.type)onlyunreachable()s unknown top-level types. So a new subtype won't crash the loop — port real handling only where there's user value (e.g.permission_denied→ failed tool_call,tool_progress→ in_progress,commands_changed→ available_commands_update,mirror_error→ log). - When upstream reads new fields (
stop_details,getContextUsage,thinking), confirm the installed SDK.d.tsactually has them before porting. Skip ports the fork can't use (e.g. the fork doesn't readMAX_THINKING_TOKENS, so upstream'sresolveThinkingConfigwas N/A). - Typecheck after each logical group, not just at the end.
6. Verify (all of it)
pnpm --filter agent typecheck
pnpm --filter agent build
npx biome check --write <changed files> # biome is the formatter/linter, not prettier/eslint
pnpm typecheck # whole repo: confirms apps/code compiles vs the new ACP SDK
pnpm --filter agent test
pnpm --filter code test
- The
apps/coderenderer unit testsanalytics.test.tsandpanelLayoutStore.test.tsare flaky — they sometimes throw ingetElectronTRPC/ electron-trpcipcLinkdepending on test ordering. If they fail, re-run; a clean rerun (orgit stash+ run on the clean tree) passing confirms it's the known flake, not your change.
7. Update UPSTREAM.md (do this last)
- Bump Last sync (version + HEAD sha + date) and the pinned SDK versions.
- Add
## Changes Ported in v<X> Sync(one bullet per change, with PR # and short sha) and## Skipped in v<X> Sync(with the reason for each skip). - If a port made a former divergence match upstream, move it out of the Intentional Divergences table.
Fork facts worth remembering
- Single session. The agent owns one
this.session(fromBaseAcpAgent), not asessionsmap. Upstream's per-session refactors usually collapse to "just usethis.session". - Prompt loop is a persistent consumer (since the v0.54.1 sync, upstream #780):
prompt()enqueues aTurndeferred;runConsumerdrains the query stream for the session's life, settles turns at their terminalresult, and capturesquery+session.queryGenerationso the fork-onlyrefreshSession()can retire it (bump generation → abort wake-up → end input). Steer mode,interruptReason, per-turn broadcast-at-activation and the unsupported-slash-command gate all live inside it — port upstream prompt-loop changes into the consumer, not a per-prompt loop. - ACP connection classes are the deprecated ones on purpose. The fork stays on
AgentSideConnection/ClientSideConnection(still shipped in ACP 1.x) because they carry theextMethod/extNotificationsurface_posthog/*uses; permission requests reach the client via the class's genericrequest(..., { cancellationSignal }). Don't port theagent()builder without a plan for the extension surface. - Renderer uses config options only. Model/mode/effort selection is
SessionConfigOptionend to end; the renderer never reads the legacymodelsresponse field or callsunstable_setSessionModel. That's why upstream's ACP-0.24/0.25 model-state removals are safe to follow. toolUseCacheis never cleared in the fork (created once in the constructor), so long sessions accumulate — keep the prune-at-tool_result behavior, and make any PostToolUse hook close over the data it needs rather than re-reading the cache.- Conversion is split out.
claude-agent.tscallshandleSystemMessage/handleStreamEvent/handleResultMessage/handleUserAssistantMessagefromconversion/sdk-to-acp.ts. Upstream inlines all of this inacp-agent.ts. - Don't commit or push unless the user explicitly asks. Leave the work on the current branch.
Signals
- GitHub stars
- 40k
- Forks
- 3k
- Last commit
- Sep 2026
Others that do the same job
Questions
- What is the source of truth for the fork point and divergences?
- UPSTREAM.md in the claude adapter directory. It records the fork point, last-synced version and commit, file mapping, PostHog-only code, and intentional divergences. Read it first and update it last.
- Does this skill make the fork identical to upstream?
- No. The job is to port valuable upstream changes such as SDK bumps, bug fixes, and new SDK message handling while preserving every intentional divergence.
Advanced
- Item type
- skill
- Key
upgrade-claude-adapter- Source
- github.com/posthog/posthog
Related picks
Skill · mattpocock
The pick for TypeScripttypescript-pro
Skill · jeffallan
The pick for TypeScriptnodejs-backend-patterns
Skill · wshobson
The pick for Noderun-node-tests
Skill · hiroro-work
The pick for Nodeslack-gif-creator
Skill · anthropics
More in Communicationerror-handling
Skill · affaan-m
More in Communication