1. 从 Skills 目录混乱说起:为什么我要用 Claude Code 搓一个 macOS 原生应用
如果你同时用 Claude Code、Codex、Gemini CLI、Copilot CLI 这几个 AI coding agent,大概率会遇到和我一样的问题:Skills 散落在不同目录里,装一个要 clone、建 symlink、重复 N 遍,卸载还得手动清残留。装了哪些、哪些有更新、哪些该删,全靠脑子记。
我日常在四个 Agent 之间切换,Skills 目录分别是~/.claude/skills/、~/.agents/skills/、~/.gemini/skills/、~/.copilot/skills/。每次装一个新 Skill,流程是:找 GitHub 仓库、git clone到本地、手动创建 symlink 到对应目录。要装到多个 Agent,以上步骤重复 N 遍。卸载更烦,删目录、清 symlink,漏一步就留残留。
命令行工具能解决安装问题,比如npx skills add https://github.com/github/awesome-copilot --skill git-commit,但它解决不了统一可视化管理——装了哪些 Skill、哪些有更新、哪些该删掉,还是得自己记。
所以我决定用 Claude Code 全程手搓一个 macOS 原生桌面应用来解决这个问题,这就是 SkillDeck。它提供统一的发现、安装、更新、删除全生命周期管理。我自己的技术背景是 Java/Go/Python,Swift 一行没写过,SwiftUI 和 macOS 平台开发零经验。这篇文章会交付可复制的 Claude Code 项目配置、SwiftUI 视图拆分模板,以及把 API 通道改到 TaoToken 的 settings 配置与一次端到端验证动作,帮你复现同类原生应用开发流程。
SkillDeck 的核心功能包括:三栏布局的统一仪表盘(左边 Agent 列表和筛选,中间 Skill 列表,右边详情),支持按名称、描述、作者搜索,按 Agent 过滤和排序;symlink 去重设计,同一个 Skill 通过 symlink 安装到多个 Agent 时只显示一次;内置 skills.sh 排行榜浏览,支持 All Time、Trending、Hot 三种排序;从 GitHub 一键安装,自动 clone、扫描、创建 symlink、更新 lock 文件;更新检测对比本地和远程 tree hash,有变更显示橙色角标;SKILL.md 编辑器分栏设计,左边表单加 Markdown 编辑区,右边实时预览;Agent 分配用 toggle 开关控制 symlink 创建和删除;文件系统监听自动刷新 GUI。
这套东西听起来功能不少,但真正让我有动力写这篇文章的,是开发过程中踩过的坑和验证过的工程化路径。下面我会从 Claude Code 的项目配置讲起,一路走到 SwiftUI 视图拆分、TaoToken 接入和端到端验证。
2. TaoToken 前置准备:把 API 通道切到稳定入口
在开始写 SwiftUI 代码之前,先把 Claude Code 的 API 通道配置好。这一步很关键,因为后面所有的 AI coding 协作都依赖这个通道的稳定性。我试过在开发中途切换 API 入口,结果 session 上下文丢失,不得不重新开 context,浪费了不少 token。
TaoToken 的接入方式很简单,核心是三件套:Base URL、API Key、Model ID。你需要先到官网注册账号,然后在控制台创建 API Key。整个过程不需要任何特殊网络配置,直接访问即可。
官网地址:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=
注册完成后,进入控制台创建 API Key。控制台地址:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite
创建 Key 的时候注意几点:Key 只在创建时显示一次,复制保存好;可以给 Key 设置备注名,方便区分不同项目;如果团队协作,建议每个成员单独创建 Key,方便追踪用量。
API Key 管理页面:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite
拿到 Key 之后,你需要确认要使用的 Model ID。TaoToken 支持多种模型,具体列表可以在模型对话页面查看。模型对话地址:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite
对于 Claude Code 这类 coding agent,建议选择支持长上下文和代码理解能力强的模型。我实测下来,在 SkillDeck 开发过程中,处理 SwiftUI 视图拆分和文件系统监听这类复杂逻辑时,模型的选择直接影响代码质量和调试效率。
API 的基础地址是:https://taotoken.net/api
注意这个地址不加任何 UTM 参数,直接用于配置。如果你需要查看详细的接入文档,包括不同语言和工具的配置示例,可以访问文档页面:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
对于长期编码和 Agent 开发场景,可以考虑 Coding Plan,它提供了更稳定的配额和优先级支持。Coding Plan 地址:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite
如果你使用 Claude Code 的 Anthropic 兼容接口,可以参考专门的配置说明:https://taotoken.net/doc/claudecode-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claudecode-anthropic&utm_campaign=rewrite
前置准备就这些,核心就是拿到 Base URL、API Key、Model ID 三件套。下面进入实际的 Claude Code 项目配置。
3. 可复制配置:Claude Code 项目设置与 SwiftUI 工程结构
这一节是全文的技术核心,我会给出完整的配置文件片段和 SwiftUI 视图拆分模板。所有配置都可以直接复制使用,路径和原文一致。
3.1 Claude Code 的 settings.json 配置
Claude Code 的全局配置在~/.claude/settings.json,项目级配置在项目根目录的.claude/settings.json。我建议把 API 通道相关的配置放在全局,把项目规范放在项目级。
全局~/.claude/settings.json的配置如下:
{ "cleanupPeriodDays": 90, "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-your-taoToken-api-key", "ANTHROPIC_MODEL": "claude-sonnet-4-20250514" } }这里有几个关键点:ANTHROPIC_BASE_URL填 TaoToken 的 API 地址,注意不要加末尾斜杠;ANTHROPIC_API_KEY填你在控制台创建的 Key;ANTHROPIC_MODEL填你要使用的 Model ID。cleanupPeriodDays设为 90 天,比默认的 30 天更长,方便用--resume恢复历史会话。
项目级.claude/settings.json配置如下:
{ "permissions": { "allow": [ "Bash(git:*)", "Bash(swift:*)", "Bash(xcodebuild:*)", "Read", "Write", "Edit" ], "deny": [ "Bash(rm -rf:*)", "Bash(git push:*)" ] } }这个配置允许 Claude Code 执行 git、swift、xcodebuild 等命令,但禁止自动 push 和危险的删除操作。实测下来,这个权限边界能有效防止 AI 误操作。
3.2 CLAUDE.md 开发规范
项目根目录的CLAUDE.md是约束 AI 开发规范的核心文件。我在这份文件里定了这些规则:
# SkillDeck 开发规范 ## Git 工作流 - 代码改动必须新建分支,禁止直接提交到 main - 分支命名格式:feature/功能名 或 fix/问题描述 ## 测试要求 - 每次代码修改都应包含对应的单元测试 - 新增 SwiftUI 视图必须有 Preview ## 提交确认 - AI 不能自动 commit/push,必须等人工确认 - 提交信息格式:type(scope): description ## PR 规范 - 每个 PR 必须包含 Manual Verification Required 清单 - 每个 PR 必须包含 Regression Checklist全局~/.claude/CLAUDE.md放通用规则,比如分支策略、测试要求,所有项目自动生效。项目特有的规范才放到项目根目录的CLAUDE.md里。这个区分很关键,能避免每个项目重复写同样的规则。
3.3 SwiftUI 视图拆分模板
SkillDeck 的界面是三栏布局,我把它拆成了独立的 SwiftUI 视图文件。下面是核心的视图拆分模板:
// SkillDeckApp.swift import SwiftUI @main struct SkillDeckApp: App { @StateObject private var appState = AppState() var body: some Scene { WindowGroup { ContentView() .environmentObject(appState) .frame(minWidth: 1000, minHeight: 600) } } }// ContentView.swift import SwiftUI struct ContentView: View { @EnvironmentObject var appState: AppState var body: some View { NavigationSplitView { AgentSidebarView() .navigationSplitViewColumnWidth(min: 180, ideal: 220) } content: { SkillListView() .navigationSplitViewColumnWidth(min: 280, ideal: 350) } detail: { SkillDetailView() } } }// AgentSidebarView.swift import SwiftUI struct AgentSidebarView: View { @EnvironmentObject var appState: AppState var body: some View { List(selection: $appState.selectedAgent) { Section("Agents") { ForEach(appState.agents) { agent in AgentRowView(agent: agent) .tag(agent) } } } .listStyle(.sidebar) } }// SkillListView.swift import SwiftUI struct SkillListView: View { @EnvironmentObject var appState: AppState @State private var searchText = "" var filteredSkills: [Skill] { appState.skills.filter { skill in searchText.isEmpty || skill.name.localizedCaseInsensitiveContains(searchText) } } var body: some View { List(filteredSkills) { skill in SkillRowView(skill: skill) } .searchable(text: $searchText, prompt: "搜索 Skill") } }// SkillDetailView.swift import SwiftUI struct SkillDetailView: View { @EnvironmentObject var appState: AppState var body: some View { if let skill = appState.selectedSkill { ScrollView { VStack(alignment: .leading, spacing: 16) { SkillHeaderView(skill: skill) AgentToggleView(skill: skill) SkillMarkdownView(skill: skill) } .padding() } } else { Text("选择一个 Skill 查看详情") .foregroundStyle(.secondary) } } }这套拆分模板的核心思路是:每个视图只负责自己的渲染逻辑,状态通过@EnvironmentObject共享。AppState作为单一数据源,管理 agents、skills、selectedAgent、selectedSkill 等状态。
3.4 文件系统监听配置
SkillDeck 需要监听 Skills 目录的变化,我用的是DispatchSource文件系统事件:
// FileSystemWatcher.swift import Foundation class FileSystemWatcher { private var sources: [DispatchSourceFileSystemObject] = [] private let queue = DispatchQueue(label: "com.skilldeck.watcher") var onChange: (() -> Void)? func watch(paths: [String]) { for path in paths { let fd = open(path, O_EVTONLY) guard fd >= 0 else { continue } let source = DispatchSource.makeFileSystemObjectSource( fileDescriptor: fd, eventMask: [.write, .delete, .rename], queue: queue ) source.setEventHandler { [weak self] in self?.onChange?() } source.setCancelHandler { close(fd) } source.resume() sources.append(source) } } func stop() { sources.forEach { $0.cancel() } sources.removeAll() } }这个监听器会在 Skills 目录发生变化时触发onChange回调,GUI 自动刷新。如果你从 CLI 侧用claude skills add安装了新 Skill,GUI 这边会自动更新,不需要手动点刷新。
4. 验证请求:一次端到端成功结果
配置写完了,接下来做一次端到端验证。这一步的目的是确认 Claude Code 能正常通过 TaoToken 的 API 通道工作,并且 SwiftUI 工程能正常编译运行。
4.1 验证 Claude Code 的 API 通道
打开终端,进入 SkillDeck 项目目录,启动 Claude Code:
cd ~/Projects/SkillDeck claude启动后,Claude Code 会自动加载~/.claude/settings.json里的环境变量。你可以用/status命令查看当前配置:
> /status API Base URL: https://taotoken.net/api Model: claude-sonnet-4-20250514 Session cleanup: 90 days如果 Base URL 显示的是 TaoToken 的地址,说明配置生效了。接下来发一个测试请求:
> 帮我检查 ContentView.swift 里的 NavigationSplitView 用法是否正确Claude Code 会读取文件并返回分析结果。如果能看到正常的代码分析输出,说明 API 通道工作正常。
4.2 验证 SwiftUI 工程编译
在终端执行编译命令:
xcodebuild -project SkillDeck.xcodeproj \ -scheme SkillDeck \ -configuration Debug \ -destination 'platform=macOS' \ build如果编译成功,你会看到BUILD SUCCEEDED的输出。然后运行应用:
open ./build/Debug/SkillDeck.app应用启动后,你应该能看到三栏布局的界面:左边是 Agent 列表,中间是 Skill 列表,右边是详情。如果 Skills 目录里有已安装的 Skill,列表会自动加载。
4.3 验证文件系统监听
在终端手动创建一个测试 Skill:
mkdir -p ~/.claude/skills/test-skill echo "# Test Skill" > ~/.claude/skills/test-skill/SKILL.md如果文件系统监听正常工作,SkillDeck 的 GUI 会自动刷新,列表里会出现test-skill。不需要手动点刷新按钮。
4.4 验证 Agent 分配功能
在 SkillDeck 里选中一个 Skill,右侧详情页会显示 Agent toggle 开关。打开 Claude Code 的开关,应用会自动创建 symlink:
ls -la ~/.claude/skills/ | grep test-skill你应该能看到 symlink 指向实际的 Skill 目录。关掉开关,symlink 自动删除。
这一套验证流程走下来,说明 Claude Code 的 API 通道、SwiftUI 工程编译、文件系统监听、Agent 分配功能都正常。如果某一步失败,下一节会讲常见错误的排查方法。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
开发过程中我踩过不少坑,这里整理几个最常见的报错和排查方法。
5.1 401 Unauthorized
这是最常见的错误,通常是 API Key 配置有问题。报错信息类似:
Error: 401 Unauthorized {"error":{"type":"authentication_error","message":"invalid api key"}}排查步骤:检查~/.claude/settings.json里的ANTHROPIC_API_KEY是否正确复制,注意不要有多余空格;确认 Key 没有过期或被删除,可以到控制台重新生成;确认ANTHROPIC_BASE_URL填的是https://taotoken.net/api,不要加末尾斜杠。
如果 Key 确认没问题但还是 401,可以尝试用 curl 直接测试:
curl -X POST https://taotoken.net/api/v1/messages \ -H "x-api-key: sk-your-key" \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -d '{"model":"claude-sonnet-4-20250514","max_tokens":100,"messages":[{"role":"user","content":"test"}]}'如果 curl 返回正常,说明 Key 没问题,问题出在 Claude Code 的配置加载上。
5.2 local proxy failed
这个错误通常出现在网络配置有问题的时候:
Error: local proxy failed: connection refused排查步骤:确认没有配置额外的代理环境变量,检查HTTP_PROXY、HTTPS_PROXY、ALL_PROXY是否被设置;如果设置了,用unset清除;确认 TaoToken 的 API 地址可以直接访问,不需要任何特殊网络配置。
5.3 reading choices 报错
这个错误通常出现在流式响应解析的时候:
Error: reading choices: unexpected end of JSON input排查步骤:检查 Model ID 是否正确,有些模型不支持流式输出;确认请求的max_tokens没有超过模型限制;如果用的是自定义模型,确认模型名称拼写正确。
在 Claude Code 里,可以用/model命令切换模型测试:
> /model claude-sonnet-4-202505145.4 OAuth 相关错误
如果你之前用过 Claude Code 的 OAuth 登录,可能会遇到配置冲突:
Error: OAuth token expired, please re-authenticate排查步骤:确认~/.claude/settings.json里没有残留的 OAuth 配置;如果有oauth相关字段,删除它们;重新启动 Claude Code,让它加载新的 API Key 配置。
如果问题依旧,可以尝试清除 Claude Code 的缓存:
rm -rf ~/.claude/cache5.5 Codex auth.json 配置
如果你同时用 Codex,它的配置在~/.codex/auth.json。接入 TaoToken 的配置如下:
{ "base_url": "https://taotoken.net/api", "api_key": "sk-your-taoToken-api-key", "model": "claude-sonnet-4-20250514" }注意 Codex 的配置字段名和 Claude Code 不同,不要混用。Base URL、API Key、Model ID 三件套要完整填写。
5.6 Cline MCP 配置
如果你用 Cline 的 MCP 功能,配置在 VS Code 的settings.json里:
{ "cline.mcpServers": { "taotoken": { "command": "npx", "args": ["-y", "@taotoken/mcp-server"], "env": { "TAOTOKEN_BASE_URL": "https://taotoken.net/api", "TAOTOKEN_API_KEY": "sk-your-taoToken-api-key", "TAOTOKEN_MODEL": "claude-sonnet-4-20250514" } } } }同样注意三件套完整:Base URL、API Key、Model ID。
5.7 CC Switch 配置
如果你用 CC Switch 管理多个 Claude Code 配置,可以在它的配置文件里添加 TaoToken 的配置:
[[profiles]] name = "taotoken" base_url = "https://taotoken.net/api" api_key = "sk-your-taoToken-api-key" model = "claude-sonnet-4-20250514"CC Switch 的配置文件路径通常在~/.cc-switch/config.toml。配置完成后,用 CC Switch 切换到 taotoken profile 即可。
6. 继续深入:Coding Plan 与长期开发建议
SkillDeck 从第一行代码到现在,全程用 Claude Code 开发。我自己的技术背景是 Java/Go/Python,Swift 之前一行没写过,SwiftUI 和 macOS 平台开发零经验。但这次的体验让我感触很深——AI Coding 真的把跨语言开发的门槛拉低了很多。
开发节奏基本上就是一个循环:提需求、AI 实现、我测试、发现问题、AI 修复、再测试。跟之前用 AI 搓 Skills 的流程差不多,但复杂度高了不少,毕竟是一个完整的 macOS 桌面应用,涉及 UI 布局、文件系统操作、网络请求、并发处理。
我不需要先花几周系统学习 Swift 和 SwiftUI,遇到不懂的语法或 API 直接问 AI 就行。但这不代表可以完全当甩手掌柜——你得能看懂代码逻辑、能写清楚需求、能有效测试和反馈问题,AI 才能帮你持续推进。说白了就是:你不需要会写 Swift,但你得会验收 Swift 代码。能跑起来、功能正确、边界情况覆盖到,这些判断能力还是需要你自己具备。
如果你打算长期用 Claude Code 做类似的原生应用开发,我建议考虑 Coding Plan。它提供了更稳定的配额和优先级支持,适合长期编码和 Agent 开发场景。Coding Plan 地址:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite
另外几个实用技巧:每个功能新开一个 context,不要在一个超长对话里做所有事情;完成一个功能后记得 commit,这样如果 AI 后续改错了什么,可以方便地回滚;大量 token 总结的内容保存成文档,放到项目的 memory 目录,下次开新 context 直接加载;用claude --resume恢复历史会话,但注意搜索不是百分百精准,有时候需要换几个关键词;Session 保留策略可以在~/.claude/settings.json里修改cleanupPeriodDays,但长期需要保留的内容还是整理成文档更靠谱。
SkillDeck 解决的核心痛点就一个:让多个 AI Agent 的 Skills 管理更直观易用。从安装、更新、分配到删除,全部在一个 GUI 里搞定。如果你也在用多个 AI coding agent,被 Skills 管理困扰,可以试试这套工程化路径。API 接入文档和更多配置示例可以在这里查看:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite