Skip to Content
SpikesS1 · Claude Agent SDK Skills

Spike S1 · Claude Agent SDK 集成验证(skills + 鉴权)

状态:✅ 通过(2026-05-18)

本文档原本只覆盖”skills 加载”,spike 过程中追加了 SDK OAuth fallback 调研——两组发现一起记下。

验证目标

@anthropic-ai/claude-agent-sdk 在容器内的预期使用方式(cwd 指向 git clone 后的仓库 + settingSources + skills:"all")能否识别本仓库的 4 个 .claude/skills/openspec-*

验证策略 · 零成本

关键发现:SDKSystemMessageinit 子类型携带 skills: string[] 字段——SDK spawn Claude Code 子进程时就枚举所有 discovered skills 并通过 init message 返回。

拿到 init 立即 process.exit()

  • 不进 turn → 不调 Anthropic API → 零 token 消耗
  • 不需要 ANTHROPIC_API_KEYapiKeySource: 'none' 也能拿到 init)

验证脚本

/tmp/openspec-spike-s1/spike.mjs(独立 npm 隔离环境,未污染主仓库依赖):

import { query } from '@anthropic-ai/claude-agent-sdk'; const REPO = '/Users/tanghehui/ExploreProject/openspec-agent-platform'; for await (const msg of query({ prompt: 'unused', options: { cwd: REPO, settingSources: ['project'], skills: 'all', allowedTools: [], permissionMode: 'bypassPermissions', maxTurns: 0, }, })) { if (msg.type === 'system' && msg.subtype === 'init') { const openspec = (msg.skills ?? []).filter((s) => s.startsWith('openspec-')); console.log(`匹配 openspec-* 的 skill 数: ${openspec.length}`); process.exit(openspec.length === 4 ? 0 : 1); } }

实际输出

=== INIT MESSAGE === apiKeySource: none model: claude-opus-4-7[1m] claude_code_version: 2.1.143 cwd: /Users/tanghehui/ExploreProject/openspec-agent-platform --- skills 字段 --- total: 12 list: - openspec-apply-change ← project skill - openspec-explore ← project skill - openspec-archive-change ← project skill - openspec-propose ← project skill - update-config ← user-level - debug - simplify - batch - fewer-permission-prompts - loop - schedule - claude-api 匹配 openspec-* 的 skill 数: 4 ✓ S1 通过

结论

验证项结果
SDK 在 cwd: <repo> + settingSources: ['project'] + skills: 'all' 配置下能加载仓库 skills
4 个 .claude/skills/openspec-* 全部被识别
SKILL.md frontmatter 格式(已离线验证 + 现已运行时验证)符合 SDK 期望
整个 spike 零成本

下一阶段(运行时实际触发 skill)

POC 实施期跑通真实容器任务时(§7 任务 12 / 16)会进入 turn,那时才能验证 Claude 实际能不能在 propose 这个 skill 已加载的前提下,按需触发 /opsx:propose ...。但根据 SDK 文档:skill 加载机制 = 描述匹配 + on-demand,frontmatter description 字段已离线验证齐全,运行时触发风险极低。

走偏的 attempt(仅作记录)

2026-05-18 第一次尝试用 claude --print --output-format stream-json --max-budget-usd 0.05 跑 spike——方向错了:

  • CLI 走 OAuth(Claude.ai 订阅),与 SDK 在容器内用 ANTHROPIC_API_KEY 鉴权路径不同
  • 没禁用 SessionStart hooks,注入 ~40K Vercel context tokens,cache_creation 触发 $0.27 实际计费(在 $0.05 budget cap 检查前)

教训:涉及真实费用的 spike,必须先确认”零成本路径”(如 init 拿了就退)再跑。


追加调研 · SDK 鉴权 fallback 链路(2026-05-18)

触发问题

hi minimal turn 跑通后,result.total_cost_usd: 0.10 引发疑问:

  • env 没设 ANTHROPIC_API_KEY(已显式 delete
  • init message 报告 apiKeySource: 'none'
  • 但 turn 跑通了 → SDK 走了某条 fallback 鉴权

需要弄清:$0.10 是真实 API token 计费、还是 Max 订阅额度池吸收。

SDK 源码层面的事实

@anthropic-ai/claude-agent-sdk@0.3.143 内嵌的鉴权 endpoint:

Endpoint用途
https://platform.claude.com/oauth/authorizeOAuth 授权流程入口
https://platform.claude.com/v1/oauth/tokenOAuth refresh
https://api.anthropic.com/api/oauth/claude_cli/create_api_key关键 · OAuth → 临时 API key 换取
https://api.anthropic.com/api/oauth/claude_cli/roles角色查询

SDK 内嵌字符串:"find-generic-password" + "security" → SDK 用 security find-generic-password -s "Claude Code-credentials" 命令读 macOS keychain。

完整鉴权 fallback 链路

SDK query() 启动 1. 检查 process.env.ANTHROPIC_API_KEY ↓ (未设) 2. 调 `security find-generic-password` 读 macOS keychain service: "Claude Code-credentials" ↓ (找到 claudeAiOauth.accessToken) 3. 用 OAuth access token POST /api/oauth/claude_cli/create_api_key ↓ (拿到临时 API key) 4. 用临时 API key 调 /v1/messages 真正做 inference init message 报告 apiKeySource: 'none' ← 是"user 没显式传",不是"无鉴权"

”apiKeySource: ‘none’” 实测含义

ApiKeySource TypeScript 类型声明:'user' | 'project' | 'org' | 'temporary' | 'oauth' —— 不含 'none'

但 SDK 实际运行时返回 'none' —— 类型声明与实现脱节。 正确理解:“none 表示 user 没显式提供 API key,SDK 内部用 OAuth fallback 链路自动换取了临时 key”。

$0.10 实际走哪条账户

结论:Max 订阅额度池吸收,不另扣信用卡

实测验证(用户在 console.anthropic.com/settings/usage  查看):

  • spike 前后今天 API spend 不增加
  • 即便 SDK 用了临时 API key 调 inference,Anthropic 后端识别这是”OAuth 派生的 key” → reimburse 到订阅额度池

result.total_cost_usd: 0.10 是 SDK 计算的”等价 API 价格”,对订阅用户来说是参考数字,不进信用卡账单。

对 POC 架构的实际影响

场景鉴权方式合规性
本地 dev(开发者自己跑 spike / 调容器镜像)SDK 自动复用 keychain OAuth✅(自用)
POC 容器(生产 / 多用户)必须注入 ANTHROPIC_API_KEY
容器复用 OAuth token❌ Anthropic ToS 禁止 + user-level 凭据安全风险

Anthropic 官方表述(Agent SDK overview ):

“Unless previously approved, Anthropic does not allow third party developers to offer claude.ai login or rate limits for their products, including agents built on the Claude Agent SDK. Please use the API key authentication methods described in this document instead.”

对 design.md 的补充

D11 · 双轨鉴权策略(已写入 design.md):

  • 容器内:ANTHROPIC_API_KEY env 严格注入
  • 本地 dev:SDK 自动 fallback OAuth(无需配置)
  • 镜像构建禁止读 keychain / 打包 OAuth refresh token

对 specs/task-runner/spec.md 的补充

新增 Requirement: 容器内鉴权策略(已写入),定义 3 个 scenario:

  1. API key 注入(business 提供,sk-ant-api* 格式)
  2. 禁止 OAuth 复用(镜像不打包 keychain 读取逻辑)
  3. API key 缺失或无效时快速失败(退出码 2)