feat(llm): run keyless on Claude Code login — claude-code provider + chat floor#186
Merged
Conversation
…chat floor Adds a `claude-code` provider (`ClaudeCodeChatModel` over the Claude Agent SDK) so metalworks runs on the user's existing Claude Code login with NO API key, and makes it the keyless chat floor: when no key/ref/METALWORKS_MODEL is configured and the SDK + `claude` CLI are present, resolve_chat() falls back to it instead of raising MissingKeyError (the chat analogue of the embeddings local-model floor). Any explicit key/ref still wins. - llm/adapters/claude_code.py: non-agentic completion (allowed_tools=[], max_turns=1, bypassPermissions); native structured via the SDK output_format json_schema → ResultMessage.structured_output, with the schema-in-prompt ladder as fallback; an async→sync bridge (one shared daemon event loop + run_coroutine_threadsafe) so the sync, thread-pooled protocol drives the async-only SDK; SDK errors mapped to actionable MetalworksError. - config.py: claude-code in _NATIVE_PROVIDERS; resolve_chat dispatch; _claude_code_available() (find_spec + shutil.which, no subprocess) gates the floor before the final MissingKeyError; the raise now also names the extra. - pyproject: claude-code = ["claude-agent-sdk>=0.2.110"] (+ in all). - tests: offline (fake SDK module) — text, native structured, prompt fallback, is_error, non-agentic options, alias strip, MissingExtraError, concurrent bridge; floor resolution (engages / key-wins / unavailable-raises / ref). - docs + CHANGELOG. Verified live: keyless complete_text/structured + floor. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
pgsharma
pushed a commit
that referenced
this pull request
Jun 26, 2026
Cut 0.4.0: the keyless Claude Code path (chat floor #186, web-search floor #187, caveat fix #188) plus the 0.3.1–0.3.3 reliability run, with a full docs/metadata pass and a positioning refresh. - Version → 0.4.0 (pyproject + __init__ + plugin.json) + CHANGELOG [Unreleased] → [0.4.0]. - Docs audit: surface the keyless `claude-code` path across README, docs/ (installation, index, quickstart, cli, claude-code, configuration, extending, demand-research, ai-agents, custom-chatmodel, internals), plugin docs + skills, CONTRIBUTING; add the `claude-code` extra everywhere it's listed; fix the stale "submissions come from the HF Parquet mirror" claim (the live Arctic Shift API has been the default since 0.1.1). - Positioning: drop "marketing research" (markety) and de-narrow the whole-product framing from Reddit-only to "real conversations across the web (Reddit, HN, forums, …)"; refresh keywords (out: marketing; in: validation, startups, founders). Reddit kept where it's a genuine feature. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
pgsharma
added a commit
that referenced
this pull request
Jun 26, 2026
Cut 0.4.0: the keyless Claude Code path (chat floor #186, web-search floor #187, caveat fix #188) plus the 0.3.1–0.3.3 reliability run, with a full docs/metadata pass and a positioning refresh. - Version → 0.4.0 (pyproject + __init__ + plugin.json) + CHANGELOG [Unreleased] → [0.4.0]. - Docs audit: surface the keyless `claude-code` path across README, docs/ (installation, index, quickstart, cli, claude-code, configuration, extending, demand-research, ai-agents, custom-chatmodel, internals), plugin docs + skills, CONTRIBUTING; add the `claude-code` extra everywhere it's listed; fix the stale "submissions come from the HF Parquet mirror" claim (the live Arctic Shift API has been the default since 0.1.1). - Positioning: drop "marketing research" (markety) and de-narrow the whole-product framing from Reddit-only to "real conversations across the web (Reddit, HN, forums, …)"; refresh keywords (out: marketing; in: validation, startups, founders). Reddit kept where it's a genuine feature. Co-authored-by: Zpoof <praguns0726@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
What
You asked to use Claude Code as metalworks' model — no API key, as the default. This adds a
claude-codeprovider (ClaudeCodeChatModelover the Claude Agent SDK) that runs completions through the bundledclaudeCLI using your existing Claude Code login, and makes it the keyless chat floor: when no key / ref /METALWORKS_MODELis configured and the SDK + CLI are present,resolve_chat()falls back to it instead of raisingMissingKeyError— the chat analogue of how embeddings already fall back to the local model. Any explicit key/ref still wins.Verified live (keyless, no API key):
complete_text→ "Tokyo.",complete_structured→{city, country}(native), and the floor viaresolve_chat()→ClaudeCodeChatModel→ "Paris."Why not MCP sampling
The cleaner "host does the inference" path (MCP
sampling) is not supported by Claude Code — tracked in #1785 and closed "not planned" in #31893. The Agent SDK (subprocess) is the only viable keyless path.Changes
llm/adapters/claude_code.py(new) — non-agentic completion (allowed_tools=[],max_turns=1,permission_mode="bypassPermissions"); native structured via the SDK'soutput_formatjson_schema →ResultMessage.structured_output, with the schema-in-prompt ladder as fallback; an async→sync bridge (one shared daemon event loop +run_coroutine_threadsafe) so the sync, thread-pooledChatModelprotocol drives the async-only SDK; SDK errors mapped to actionableMetalworksError.config.py—claude-codein_NATIVE_PROVIDERS;resolve_chatdispatch;_claude_code_available()(find_spec+shutil.which, no subprocess, no env read) gates the floor right before the finalMissingKeyError, which now also names themetalworks[claude-code]option.pyproject.toml—claude-code = ["claude-agent-sdk>=0.2.110"](+ inall).test_claude_code_adapter.py, new) — fully offline via a fake SDK module: text, native structured, prompt fallback,is_error, non-agentic options, alias strip,MissingExtraError, and the concurrent bridge (12 calls through a thread pool); plus floor resolution (engages / key-wins / unavailable-raises /claude-code/opusref).Honest trade-offs (in the docs)
claudeCLI per call (~5–7s/call) — the keyless convenience path, not the fast one. A key is faster for a many-call research run.Gate
ruff check·ruff format --check·pyright(0 errors) ·gen_ts_types.py --checkPASSED ·import metalworksstays free (SDK lazy-imported). Full suite 1188 passed clean-room (the 1 local failure is the pre-existing wedged-~/.metalworks/store.dbdisk I/O errorfrom stale MCP servers — unrelated; touches nothing inllm//config). No version bump — tagging left to you.🤖 Generated with Claude Code