Skip to content

feat: Claude subscription support through a Claude Agent provider - #1706

Draft
sahrizvi wants to merge 3 commits into
mainfrom
feat/claude-subscription
Draft

sahrizvi wants to merge 3 commits into
mainfrom
feat/claude-subscription

Conversation

@sahrizvi

@sahrizvi sahrizvi commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Issue for this PR

No issue. Ports upstream opencode PR 58782, "feat(core): add Claude Agent provider".

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Lets a user chat with Claude models on their Claude Pro/Max subscription. The CLI starts the user's installed claude through Anthropic's Claude Agent SDK, so the login stays with Claude Code. The CLI never reads or stores its token. Setup is claude auth login, then /connect → Claude Agent.

The existing opencode-anthropic-auth plugin sends subscription OAuth tokens straight to the Anthropic API, which Anthropic now restricts for third-party apps. Upstream replaced that approach with this provider.

Why this is a port, not a cherry-pick. Upstream built the provider in packages/core on its v2 plugin context (ctx.provider, ctx.aisdk.hook, ctx.session.hook). Our shipped CLI does not run that runtime: providers resolve in provider/provider.ts and requests are built in session/llm.ts.

  • src/altimate/provider/claude-agent/{claude,sync,tools,language-model}/ are upstream's modules, copied with import paths adjusted. They manage the claude process, keep the CLI's history in sync with Claude's saved session, and hold Claude's tool calls until the CLI runs them.
  • index.ts, catalog.ts, storage.ts and plugin.ts replace upstream's plugin-context wiring.
  • Marked hooks in provider.ts, transform.ts, llm.ts, plugin/index.ts and the TUI provider list connect it.
  • The folder's README.md lists every difference from upstream for the next bridge merge.

Behaviour. Claude uses Altimate's tools, permissions, agent prompt, skills and AGENTS.md. Claude Code's own tools, settings files, CLAUDE.md, hooks, MCP servers, memory and auto compaction are turned off. The per-turn environment block is not sent, because upstream found that forwarding it made subscriptions reject chats as a third-party app. A subscription shows $0 cost; an API key or cloud login is priced from that provider's catalog.

One fix on top of upstream. Our session processor only records a tool call whose part a tool-input-start opened. Upstream sends a bare tool-call, so the first live chat looped on empty steps. The stream converter now emits tool-input-start/delta/end before each call.

Known gaps, documented in the README:

  • Titles, summaries and compaction run as standalone calls. Upstream copies the chat's Claude session so they reuse its prompt cache; our runtime has no hook for that.
  • headerTimeout and chunkTimeout never reach Claude Code, because the provider loader removes them first.
  • A model list that changes mid-session shows after the next reload.

Dependency. @anthropic-ai/claude-agent-sdk@0.3.301, upstream's version. Installing it also downloads a ~270 MB per-platform copy of claude that is never run.

How did you verify your code works?

Live runs with a real Claude Max login and claude 2.1.322, in an isolated data directory:

  • TUI (tmux): /connect → Claude Agent saved only the marker, not a token. Models listed: Opus 5.5, Fable 5.2, Sonnet 5.5, Haiku 5.5, with effort variants.
  • Sonnet 5.5 at medium effort: called glob and two reads and answered correctly. The follow-up ran sql_analyze and reused the same Claude session and process. Cost was $0, ~58K prompt tokens came from cache, and Haiku generated the title.
  • Switching providers: an Altimate LLM Gateway turn, then back to Claude. Claude caught up on the turn it had not seen.
  • altimate run -m claude-agent/haiku and the build:local binary: both answered correctly with tool calls, so the SDK survives bundling.

Not covered yet:

  • Permission prompts (YOLO was on), interrupting mid-tool, and the 5-minute idle stop and resume.
  • Compaction, subagents and attachments.
  • The logged-out and missing-claude paths, and Linux/Windows.

Checks:

  • bun turbo typecheck passes.
  • Marker guard, branding audit and tracker-leak scan are clean.
  • 105 Claude Agent tests pass: upstream's replay tests through the real SDK, plus integration.test.ts.
  • Full packages/opencode main pass: 20,934 pass, 6 fail. The 6 failures (mcp.headers and mcp HttpApi) fail the same way on a clean checkout of main on this machine.
  • CI's subprocess pass: 40/40.

Codex review fixes (second commit):

  • Generate calls work. agent create with a Claude model ran live and wrote an agent file.
  • Stopped tools now interrupt the waiting Claude turn.
  • Connection settings, login status and the session registry are kept per project.
  • A plugin's explicit maxOutputTokens is kept.
  • Covered by review-fixes.test.ts. After these fixes, I re-ran the Claude Agent tests and the message-conversion suite, not the full suite.

Cost side effects

None that grow with user data. Each chat runs on the user's own Claude login. The /connect login check starts claude without sending a prompt, so it uses no tokens.

Screenshots / recordings

Not included yet.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR
  • I checked for cost side effects (model calls, queries or cloud resources that grow with user data) and described them, or wrote "none"

🤖 Generated with Claude Code

Port upstream opencode PR 58782 ("feat(core): add Claude Agent provider") to the
shipped runtime. Claude models run through the user's own Claude Code login via
`@anthropic-ai/claude-agent-sdk`, so a Claude Pro/Max subscription covers usage.
The CLI never reads or stores the Claude Code token.

- Copy upstream's process, sync, tools and language-model modules into
  `src/altimate/provider/claude-agent/` with import paths adjusted, and their
  replay tests and recordings into `test/altimate/provider/claude-agent/`
- Replace upstream's core plugin-context wiring with Altimate-owned modules:
  per-instance session registry and AI SDK factory (`index.ts`), saved model
  list and login-based pricing (`catalog.ts`), JSON storage (`storage.ts`), and
  an internal plugin for the `/connect` login check and idle release (`plugin.ts`)
- Marked hooks in `provider.ts` (bundled factory, provider entry, `haiku` small
  model), `transform.ts` (effort variants), `llm.ts` (request kind and session
  headers, agent role and instructions, no default output cap), `plugin/index.ts`
  and the TUI provider list
- Emit `tool-input-start/delta/end` before each `tool-call`, because the session
  processor drops a tool call no `tool-input-start` opened
- Build the MCP tool server on the bundled `@modelcontextprotocol/sdk` 1.x
- Add `@anthropic-ai/claude-agent-sdk@0.3.301` and document the provider

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

…per-project state

- Implement `doGenerate` by collecting the streamed reply, so `generateObject`
  and `generateText` callers (`agent create`, learning reflection) work; JSON
  requests are asked for in the prompt and a markdown fence is removed
- Flag stopped Claude Agent tool calls with `toolAborted` in `message-v2.ts`
  history conversion, so the waiting Claude turn is interrupted as upstream does
- Keep connection settings, login status and the session registry per project,
  so one project's config or open instance no longer affects another's
- Drop only the default output cap before `chat.params`, so a plugin's explicit
  `maxOutputTokens` still applies

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
- - - - - - - - - - - - - - - - - - - - - - - - -
                    AIRECEIPTS                    
             1 session behind this PR             

  CODEX HELPERS (1) — no commits
  (unattributed usage) · 7m.......3,420,771 tokens
--------------------------------------------------
TOTAL unpriced..................≥ 3,420,771 tokens
  counted: 1 session
  cache served 96% of input tokens

1 candidate session not attributed
(in repo + branch window, no branch commit)

1 session made git writes that could not be anchored
(see docs/trust.md)
  full receipts + session ids: section below
- - - - - - - - - - - - - - - - - - - - - - - - -
                npx aireceipts-cli                
         github.com/anandgupta42/receipts         
- - - - - - - - - - - - - - - - - - - - - - - - -
full receipts (1 session)
session id scope turns time tokens in / out cached
codex 437143ce no commits 1 7m 145k / 15k 96%

codex · 437143ce

- - - - - - - - - - - - - - - - - - - - - - - - -
                    AIRECEIPTS                    
    Codex · Nov 10 2026 20:48:24 UTC · 7m 34s     
            (unattributed usage) 100%             
         cache served 96% of input tokens         

(unattributed usage)......3,420,771 tok  (0 calls)
exec.............................0 tok  (29 calls)

caveat: Codex request envelopes did not reconcile — request-level pricing disabled
--------------------------------------------------
TOTAL................................3,420,771 tok
no price table matched
- - - - - - - - - - - - - - - - - - - - - - - - -
                npx aireceipts-cli                
         github.com/anandgupta42/receipts         
- - - - - - - - - - - - - - - - - - - - - - - - -

Generated by aireceipts

`authorize()` ran the full Claude Code probe, including context-window discovery
for every model, before returning, so `/connect` sat on the previous dialog for
about 9 seconds and then jumped to the model list. It now returns at once, the
dialog shows its waiting screen, and the check (with retries) runs in the callback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sahrizvi

sahrizvi commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator Author

Draft Walkthrough video (for SA review → public changelog, doesnt have voice)

pr1706-claude-agent.mp4
f24 f27 sheet

Terminal recording of Claude subscription support (Claude Agent provider), recorded with this branch on macOS against a Claude Max login, starting from a fresh install (≈53s, no narration):

  • Run /connect, search all providers for Claude Agent, and see the Claude Code login screen while Altimate Code checks the claude login
  • Once connected, the Claude Code models (Opus, Sonnet, Haiku, Fable) appear as ready; pick Sonnet 5.5 and the medium effort level
  • Ask which source tables each model in a small dbt project reads from: Claude uses Altimate Code's Glob, Grep and Read tools and answers with a table, including that the staging models hardcode raw.* instead of source()

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant