公司给了一套 Claude Code,我还留着自己订阅的那份:cooconscc 双入口实践

4 阅读6分钟

公司统一配了 Claude Code,走集采 API 通道,模型、token、白名单都有人管着。按理说够用了,但我自己又掏钱订阅了一份 Claude.ai。这篇讲实际的双配置方案——不是网上那种"两个 profile 目录 + 复杂切换工具"的正经答案,而是我真正在用的一个别名 + 一个 IP 卫兵。

为什么要两份

公司那套的好处不用多讲:稳定、免费、合规。但对我来说有几个挠痒痒的地方:

  • 模型和额度被统一锁定。公司通道用团队选定的模型,额度按项目分。我周末想用 Opus 跑个玩具项目,不好意思占额度。
  • 计费模式不同。公司是 API 计费(按 token),个人订阅是按月固定(Pro/Max)。同样一个任务,个人订阅跑上下文填得越满越"划算",API 通道反而要省着用。两套通道对应两种心态,硬要混在一起算账很累。
  • 日志归属。工作代码走公司通道合情合理。但我写个人项目、副业草稿、给朋友 debug,不想让这些内容进公司网关日志池。

所以结论是:两条通道,默认公司,按需切个人,而不是一套打天下。

实际方案:一个别名叫 cooconscc

核心实现就是 ~/.zshrc 里的一段,脱敏后长这样:

# 默认:公司 API 通道
export ANTHROPIC_BASE_URL="<公司 Claude 转发网关>"
export ANTHROPIC_AUTH_TOKEN="<company-api-key>"

# cooconscc: 切回官方订阅(需要 JP 出口 IP)
cooconscc() {
  export https_proxy=http://127.0.0.1:7897
  export http_proxy=http://127.0.0.1:7897
  export all_proxy=socks5://127.0.0.1:7897
  echo "proxy on -> 127.0.0.1:7897"

  local country
  country=$(curl -s --max-time 5 ipinfo.io | grep '"country"' | awk -F'"' '{print $4}')
  if [[ "$country" == "JP" ]]; then
    echo "IP check passed: $country (subscription mode)"
    unset ANTHROPIC_BASE_URL
    unset ANTHROPIC_AUTH_TOKEN
    claude "$@"
    # 退出后恢复 API 配置
    export ANTHROPIC_BASE_URL="<公司 Claude 转发网关>"
    export ANTHROPIC_AUTH_TOKEN="<company-api-key>"
  else
    echo "IP check failed: country=$country (need JP), claude not started"
    return 1
  fi
}

就这么多。没有并列的 ~/.claude-work/ 目录,没有 wrapper CLI,没有 profile 管理器。三个设计点值得展开:

1. 环境变量 set/unset 做开关,不做目录隔离

Claude Code 启动时读 ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN。两个都有 → 走 API 通道(公司转发网关);两个都没 → 走官方订阅的 OAuth 登录。

所以"切通道"本质上是一个变量开关,不需要任何 profile 目录。默认留给公司(高频),切换动作显式(低频)——这个默认选择匹配我实际的使用比例(工作日 9:周末 1)。

2. IP 卫兵是这套方案最值的一环

订阅账号最怕的事是风控。Claude.ai 对出口 IP 的地区和稳定度是有判定的,从国内直连或者从代理节点频繁跳就可能被标记。所以我在 unset 变量之前强校验出口国家:

  • 先 export 好三个代理变量(http/https/socks5 都同一个代理端口)。
  • 用 curl -s --max-time 5 ipinfo.io 拿到 country,必须是 JP(我稳定的日本节点)才继续。
  • 不是 JP,直接 return 1,连 claude 都不启动。

--max-time 5 是为了防 ipinfo.io 自己卡住把终端挂住。

代价:代理没开或抽风时 cooconscc 直接开不起来。我认为这是好事——宁可开不起来,不愿意无意识裸跑。一次误启动导致账号被风控的代价,远大于偶尔启动失败的麻烦。

3. 退出后自动恢复公司 env

claude "$@" 是 foreground 命令,正常退出后才会跑下面两行 export。所以同一个 shell session 里cooconscc 结束后直接敲 claude 会自动回到公司通道,不用手动重开 terminal。

破绽:如果 kill -9 或 terminal crash,env 会停留在 unset 状态。没处理,几乎遇不到,遇到就新开一个 shell。

skill 怎么分?答案是不分

这可能是跟常见"企业 AI 最佳实践"最拧巴的一点:我的 ~/.claude/skills/ 里公司 skill 和个人 skill 完全混在一起。数仓查表的 skill 和 Figma 设计稿 skill 躺在同一个目录,两边通道都能召唤。

刻意的。理由:

  • Skill 的知识是累加的。查数仓表结构那类能力,周末写个人工具时偶尔也用得上(复用一段 SQL pattern、学个字段命名)。反过来,工作项目做前端时想用 Figma skill 直接拉 token 列表。强隔离就是在制造二次搬运。
  • Skill 文件里不写秘密。token、内网地址一律走环境变量。skill 本身只是"知识+流程",跟谁跑无所谓。
  • Claude Code 的 skill 按需加载。没触发就不进 context,也不会泄到 API provider。

所以"双入口 + 单 skill 池"在我这里是特性不是 bug。前提是你的公司 skill 不把内网地址或 token 写死在 skill 文件里(不应该这么写,但现实里真有)。真要隔离的场景我会开新的目录用 CLAUDE_CONFIG_DIR 切,但到目前为止没遇到值得这么做的。

direnv:装着但没让它管 Claude Code

zshrc 里 eval "$(direnv hook zsh)" 是装了的。想过给公司项目目录加 .envrc 强制保留 API 模式,防止在公司仓库里误敲 cooconscc。最后没配,因为:

  • 我的习惯是进公司仓库默认 claude,进个人仓库默认 cooconscc。肌肉记忆够用。
  • direnv 会污染"env 从哪来"的心智模型,以后调试会烦。

direnv 留着管 nodejs 版本和项目级 env,不让它管 Claude Code。

好处

  • 低认知负担。没有 profile 目录,没有配置文件切换,就是一个别名。几乎零学习成本转给团队里愿意自己订阅的同事。
  • IP 卫兵是保险。我到目前为止没碰过任何订阅风控,大概率归功于这一步。
  • skill / memory 共享带来的复利。工作里 debug 出来的一个思路,周末直接能被个人 session 召回。
  • default 优先级匹配现实。工作日 90% 时间用 claude(默认),切 cooconscc 是周末/夜里的动作。这个比例决定了默认应该留给公司。

代价和踩过的坑

  • skill 混用的心智税。对话一开始偶尔蹦出一个"你要查哪张数仓表"的 skill 建议,个人项目完全不需要。目前靠 skill description 写得足够精准来缓解,没到痛的地步。
  • 代理挂掉就开不了 cooconscc。Clash/Mihomo 偶尔抽风,得先修代理再启 claude。可以接受。
  • env 恢复不原子。正常退出没问题,异常死亡会留 unset 状态。新开 terminal 解决。
  • key 写在 zshrc 里。这是最该改的一环。短期靠 zshrc 只在本地 + chmod 600,长期应该挪到 macOS Keychain,用 security find-generic-password -w 按需取。列在待办里,没改。

值不值

值。两条通道的心智边界很清楚——想用 Opus、想写跟公司无关的代码、想做不留公司日志的草稿,就敲 cooconscc;其它时候就 claude。认知成本等于记住一个别名的肌肉记忆。

比 profile 切换、目录隔离、wrapper CLI 都简单,又比"全部走公司通道"多出了我需要的那点自主权。一个周末搞定,往后每天无感。

附:让 Claude Code 自己生成这套配置

如果你也想要双入口但懒得手写,把下面这段 prompt 丢给你自己的 Claude Code,它会按你的几个参数生成一份合适的 shell 片段:

我要在本机配置两条 Claude Code 通道:
  (A) 默认 `claude`:走公司/API 转发通道,依赖 ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN。
  (B) 自定义别名 <我的别名>:走官方 Claude.ai 订阅(OAuth,无 API key),启动前必须满足:
      1. 本地代理已开启(http / https / socks5 都走同一个端口)。
      2. 出口 IP 国家命中白名单(例如 JP / US / SG 之一),否则拒绝启动。

请先一次性反问我以下 5 个问题,等我回答完再生成最终脚本:
  1. 别名叫什么?
  2. 本地代理端口是多少?socks 和 http 是同一个端口吗?
  3. 白名单国家码(ISO 两位码,可多选)?
  4. 我的 shell 是 zsh 还是 bash?
  5. 公司 API 凭据希望明文写进 rc 文件,还是从 macOS Keychain / pass / gpg 取?

生成脚本时请遵守:
  - 追加到 rc 文件而不是覆盖,给出 `cat >> ~/.zshrc <<'EOF' ... EOF` 这种安全写法。
  - 默认部分:export 公司通道所需的两个环境变量,值用 `<placeholder>` 让我自己填;若我选了 Keychain 模式,用 `$(security find-generic-password -s <service> -w)` 这种按需取的形式。
  - 别名部分:用 shell function 而非 alias(需要多行逻辑 + 传参)。function 内部逻辑:
      a) 设置代理环境变量;
      b) 用 `curl -s --max-time 5 ipinfo.io` 拿 country;
      c) 命中白名单才 unset 公司通道的两个变量并执行 `claude "$@"`;
      d) claude 正常退出后再把公司变量 export 回来;
      e) IP 不过关时打印中文提示并 return 1。
  - 不要写任何真实 token 或真实网关地址,全部 placeholder。
  - 最后附一段 3-5 行的验证命令清单:env 检查 ANTHROPIC_* 是否存在、`which claude`、启动别名观察 IP 校验输出。

最后提醒我把 rc 文件权限设为 `chmod 600`(如果我选了明文模式)。

照这段 prompt 走,Claude Code 会先问你 5 个问题,再生成可直接追加到 rc 文件的片段。替换 placeholder 即可使用。