Switch Claude Code to the z.ai GLM Coding Plan in one command

By Yassine El Haddad, updated . The code is on GitHub under the MIT license. Not affiliated with Anthropic or Z.ai.

Keep using Claude Code, but run it on the z.ai GLM Coding Plan instead of your Claude subscription, or next to it. One installer adds a claude-z command that uses GLM-5.3 with its full 1M-token context. It also wires up z.ai's web search and image tools, and puts your 5-hour and weekly quota in the status line. Your normal claude keeps working exactly as before.

Get 10% off the GLM Coding Plan Install claude-z

The discount applies to your first subscription if you're new to z.ai. It's a referral link (disclosure); the plain link is z.ai/subscribe.

glm-5.3[1m] · ctx 12% · 5h 8% · wk 41%

Switching from a Claude subscription

You don't have to choose up front. claude keeps your Claude Pro or Max subscription, and claude-z runs the same Claude Code on z.ai, with its own settings and history. Give both the same tasks, then decide which subscription you need.

claude on a Claude subscriptionclaude-z on the GLM Coding Plan
ModelsClaude (Opus, Sonnet, Haiku)GLM-5.3 and GLM-5.3-Flash
Context in Claude CodeDepends on model and plan1M tokens with glm-5.3[1m]
Usage limitsSession and weekly limits5-hour and weekly credit limits, shown in the status line
Web searchBuilt-in WebSearchz.ai web search and web reader MCP (1.2 credits per call)
ImagesBuilt-inz.ai vision MCP
Other appsClaude on web, desktop and mobileClaude Code, Cline and other supported coding tools
Who processes your codeAnthropicZ.ai: read their terms and privacy policy first

How to switch

  1. Subscribe to the GLM Coding Plan (referral link, 10% off your first subscription) and create an API key in your z.ai account.
  2. Run the one-line installer below and paste the key when asked.
  3. Open a new terminal and run claude-z in your project.

GLM-5.3 is a different model from Claude, so results will differ. Run your usual tasks through both before you cancel anything. z.ai's FAQ says Coding Plan subscriptions are non-refundable once purchased.

Quick start

You need a GLM Coding Plan API key (subscribe here, referral link), Claude Code, and jq on Linux and macOS. Node.js 22 or newer is only needed for the vision tool.

Linux and macOS:

curl -fsSL https://raw.githubusercontent.com/yel-hadd/claude-code-zai/v1.1.0/install.sh | bash

Windows (PowerShell):

irm https://raw.githubusercontent.com/yel-hadd/claude-code-zai/v1.1.0/install.ps1 | iex

The installer asks for your key with hidden input. Then open a new terminal and run claude-z. To let an AI agent do the setup, paste the setup prompt into Claude Code, Cursor or any coding agent.

Re-running the installer is safe: it updates files and never duplicates anything. install.sh --uninstall or install.ps1 -Uninstall removes it, keeping your key unless you add --purge / -Purge.

What you get

PieceWhat it does
claude-zStarts Claude Code against z.ai with GLM-5.3 and a separate config folder, ~/.claude-z
1M contextUses the glm-5.3[1m] model names, so Claude Code knows the real context size
Web search and readerz.ai's MCP servers replace Claude Code's built-in web search, which can't run through z.ai
Visionz.ai's image MCP server for screenshots and images
Quota status lineModel, context used, 5-hour and weekly quota, reset time in your local time zone
zai-usageFull quota report in your terminal, without starting Claude Code
/zai-usageThe same report inside a session; works even when the quota is used up

Your API key is stored in ~/.config/zai/api_key, readable only by you. Config files reference it as ${ZAI_API_KEY} and never contain the key itself.

The settings

These are the environment variables claude-z sets. They are the same on every OS.

VariableValueWhy
ANTHROPIC_BASE_URLhttps://api.z.ai/api/anthropicz.ai's Anthropic-compatible endpoint
ANTHROPIC_AUTH_TOKENyour z.ai API keyRead from the key file at launch
ANTHROPIC_MODELglm-5.3[1m]Main model
ANTHROPIC_DEFAULT_OPUS_MODELglm-5.3[1m]Used when you pick Opus in /model
ANTHROPIC_DEFAULT_SONNET_MODELglm-5.3[1m]Used when you pick Sonnet in /model
ANTHROPIC_DEFAULT_HAIKU_MODELglm-5.3-flash[1m]Fast model for background jobs
CLAUDE_CODE_SUBAGENT_MODELglm-5.3[1m]Model for subagents
CLAUDE_CODE_AUTO_COMPACT_WINDOW1000000Compact near 1M tokens, not 200k
API_TIMEOUT_MS300000050-minute timeout for long responses
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC1No telemetry or update checks to Anthropic
CLAUDE_CONFIG_DIR~/.claude-zSeparate settings, history and MCP list

The base URL, timeout, model names and auto-compact window come from z.ai's Claude Code guide.

Manual setup

Everything the installers put in ~/.claude-z, if you'd rather set it up by hand. Make the .sh files executable with chmod +x, and on Linux and macOS install jq.

Linux and macOS

~/.claude-z/claude-z.sh: the command. Add . ~/.claude-z/claude-z.sh to ~/.bashrc or ~/.zshrc.
# claude-z: Claude Code on the z.ai GLM Coding Plan (bash and zsh).
# Sourced from ~/.bashrc or ~/.zshrc. Key lives in ~/.config/zai/api_key (chmod 600).
# https://github.com/yel-hadd/claude-code-zai
# No GLM Coding Plan yet? https://z.ai/subscribe?ic=BY27XR8RLD (referral link, 10% off your first subscription)

unalias claude-z zai-usage 2>/dev/null

function claude-z {
  local key_file="$HOME/.config/zai/api_key"
  if [ ! -s "$key_file" ]; then
    echo "claude-z: missing z.ai key in $key_file" >&2
    echo "No GLM Coding Plan yet? https://z.ai/subscribe?ic=BY27XR8RLD (referral link, 10% off your first subscription)" >&2
    return 1
  fi
  local key; key="$(cat "$key_file")"
  CLAUDE_CONFIG_DIR="$HOME/.claude-z" \
  ANTHROPIC_BASE_URL="https://api.z.ai/api/anthropic" \
  ANTHROPIC_AUTH_TOKEN="$key" \
  ZAI_API_KEY="$key" \
  API_TIMEOUT_MS=3000000 \
  ANTHROPIC_MODEL='glm-5.3[1m]' \
  ANTHROPIC_DEFAULT_OPUS_MODEL='glm-5.3[1m]' \
  ANTHROPIC_DEFAULT_SONNET_MODEL='glm-5.3[1m]' \
  ANTHROPIC_DEFAULT_HAIKU_MODEL='glm-5.3-flash[1m]' \
  CLAUDE_CODE_SUBAGENT_MODEL='glm-5.3[1m]' \
  CLAUDE_CODE_AUTO_COMPACT_WINDOW=1000000 \
  CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 \
    claude "$@"
}

# z.ai quota without starting Claude Code (works even when a limit is exhausted)
function zai-usage {
  "$HOME/.claude-z/zai-quota.sh" --full
}
~/.claude-z/zai-quota.sh: reads the quota, cached for 60 seconds
#!/usr/bin/env bash
# z.ai GLM Coding Plan quota, from https://api.z.ai/api/monitor/usage/quota/limit
# Usage: zai-quota.sh [--short|--full|--json]   (cached 60s in ~/.cache/zai-quota.json)
# https://github.com/yel-hadd/claude-code-zai
mode="${1:---short}"
cache="${XDG_CACHE_HOME:-$HOME/.cache}/zai-quota.json"
key="${ZAI_API_KEY:-$(cat "$HOME/.config/zai/api_key" 2>/dev/null)}"
[ -n "$key" ] || { echo "z.ai: no key"; exit 0; }

mkdir -p "$(dirname "$cache")"
if [ ! -s "$cache" ] || [ $(( $(date +%s) - $(stat -c %Y "$cache" 2>/dev/null || stat -f %m "$cache") )) -ge 60 ]; then
  tmp="$cache.$$"
  if curl -s -m 5 https://api.z.ai/api/monitor/usage/quota/limit \
       -H "Authorization: Bearer $key" -H "Accept-Language: en-US,en" -o "$tmp" \
     && jq -e '.success == true' "$tmp" >/dev/null 2>&1; then
    mv "$tmp" "$cache"
  else
    rm -f "$tmp"
  fi
fi
[ -s "$cache" ] || { echo "z.ai: quota unavailable"; exit 0; }

case "$mode" in
  --json) cat "$cache" ;;
  --short)
    # unit 3 = hours, 6 = weeks, 5 = months; nextResetTime is epoch ms
    jq -r '
      def win: if .unit == 3 then "\(.number)h" elif .unit == 6 then "wk" elif .unit == 5 then "mo" else "u\(.unit)" end;
      def reset: if .nextResetTime then " ↻" + ((.nextResetTime / 1000) | strflocaltime("%a %H:%M")) else "" end;
      [.data.limits[] | select(.type != "TIME_LIMIT") | "\(win) \(.percentage)%" + (if .percentage >= 80 then reset else "" end)]
      | join(" · ")' "$cache" ;;
  --full)
    jq -r '
      def win: if .unit == 3 then "\(.number)-hour window" elif .unit == 6 then "Weekly" elif .unit == 5 then "Monthly" else "unit \(.unit) x\(.number)" end;
      "z.ai plan: \(.data.level)",
      (.data.limits[] |
        "\(win) (\(.type)): \(.percentage)% used, \(.currentValue // 0) of \(.usage // "?"), \(.remaining // "?") left" +
        (if .nextResetTime then ", resets \((.nextResetTime / 1000) | strflocaltime("%a %b %d %H:%M %Z"))" else "" end))' "$cache" ;;
esac
~/.claude-z/statusline.sh: the status line
#!/usr/bin/env bash
# claude-z status line: model · context used · z.ai quota
# https://github.com/yel-hadd/claude-code-zai
input="$(cat)"
model="$(jq -r '.model.display_name // .model.id // "GLM"' <<<"$input")"
ctx="$(jq -r '.context_window.used_percentage // empty | floor' <<<"$input" 2>/dev/null)"
quota="$("$(dirname "$0")/zai-quota.sh" --short)"
printf '%s' "$model"
[ -n "$ctx" ] && printf ' · ctx %s%%' "$ctx"
printf ' · %s\n' "$quota"
~/.claude-z/hooks/zai-usage-hook.sh: answers /zai-usage without calling the model
#!/usr/bin/env bash
# UserPromptSubmit hook: answer /zai-usage locally, without calling the model,
# so it still works when the z.ai quota is exhausted.
# https://github.com/yel-hadd/claude-code-zai
prompt="$(jq -r '.prompt // empty')"
case "$prompt" in
  /zai-usage|/zai-usage\ *)
    out="$("$(dirname "$0")/../zai-quota.sh" --full 2>&1)"
    jq -n --arg r "$out" '{decision: "block", reason: $r}'
    ;;
esac
exit 0
~/.claude-z/settings.json
{
  "permissions": {
    "deny": ["WebSearch"]
  },
  "statusLine": {
    "type": "command",
    "command": "~/.claude-z/statusline.sh",
    "padding": 0
  },
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          { "type": "command", "command": "~/.claude-z/hooks/zai-usage-hook.sh", "timeout": 15 }
        ]
      }
    ]
  }
}

Windows

Windows uses PowerShell versions of the same scripts. In settings.json, run them with a full forward-slash path, for example powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/YOU/.claude-z/statusline.ps1, which works whichever shell Claude Code uses.

~/.claude-z/claude-z.ps1: the command. Dot-source it from your PowerShell profile.
# claude-z: Claude Code on the z.ai GLM Coding Plan (PowerShell 5.1 and 7).
# Dot-sourced from $PROFILE. Key lives in ~/.config/zai/api_key (owner-only ACL).
# https://github.com/yel-hadd/claude-code-zai
# No GLM Coding Plan yet? https://z.ai/subscribe?ic=BY27XR8RLD (referral link, 10% off your first subscription)

function claude-z {
  $keyFile = Join-Path $HOME '.config\zai\api_key'
  if (-not (Test-Path $keyFile) -or -not "$(Get-Content $keyFile -Raw)".Trim()) {
    Write-Host "No GLM Coding Plan yet? https://z.ai/subscribe?ic=BY27XR8RLD (referral link, 10% off your first subscription)"
    Write-Error "claude-z: missing z.ai key in $keyFile"; return
  }
  $key = (Get-Content $keyFile -Raw).Trim()
  $vars = @{
    CLAUDE_CONFIG_DIR                        = Join-Path $HOME '.claude-z'
    ANTHROPIC_BASE_URL                       = 'https://api.z.ai/api/anthropic'
    ANTHROPIC_AUTH_TOKEN                     = $key
    ZAI_API_KEY                              = $key
    API_TIMEOUT_MS                           = '3000000'
    ANTHROPIC_MODEL                          = 'glm-5.3[1m]'
    ANTHROPIC_DEFAULT_OPUS_MODEL             = 'glm-5.3[1m]'
    ANTHROPIC_DEFAULT_SONNET_MODEL           = 'glm-5.3[1m]'
    ANTHROPIC_DEFAULT_HAIKU_MODEL            = 'glm-5.3-flash[1m]'
    CLAUDE_CODE_SUBAGENT_MODEL               = 'glm-5.3[1m]'
    CLAUDE_CODE_AUTO_COMPACT_WINDOW          = '1000000'
    CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = '1'
  }
  $saved = @{}
  foreach ($name in $vars.Keys) {
    $saved[$name] = [Environment]::GetEnvironmentVariable($name, 'Process')
    [Environment]::SetEnvironmentVariable($name, $vars[$name], 'Process')
  }
  try { claude @args }
  finally {
    foreach ($name in $saved.Keys) {
      [Environment]::SetEnvironmentVariable($name, $saved[$name], 'Process')
    }
  }
}

# z.ai quota without starting Claude Code (works even when a limit is exhausted)
function zai-usage {
  & (Join-Path $HOME '.claude-z\zai-quota.ps1') -Mode Full
}
~/.claude-z/zai-quota.ps1: reads the quota, cached for 60 seconds
# z.ai GLM Coding Plan quota, from https://api.z.ai/api/monitor/usage/quota/limit
# Usage: zai-quota.ps1 [-Mode Short|Full|Json]   (cached 60s in %TEMP%\zai-quota.json)
# https://github.com/yel-hadd/claude-code-zai
param([ValidateSet('Short', 'Full', 'Json')][string]$Mode = 'Short')

[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12

$key = $env:ZAI_API_KEY
$keyFile = Join-Path $HOME '.config/zai/api_key'
if (-not $key -and (Test-Path $keyFile)) { $key = "$(Get-Content $keyFile -Raw)".Trim() }
if (-not $key) { 'z.ai: no key'; return }

$tmpDir = if ($env:TEMP) { $env:TEMP } else { [IO.Path]::GetTempPath() }
$cache = Join-Path $tmpDir 'zai-quota.json'
if (-not (Test-Path $cache) -or ((Get-Date) - (Get-Item $cache).LastWriteTime).TotalSeconds -ge 60) {
  try {
    $r = Invoke-RestMethod -Uri 'https://api.z.ai/api/monitor/usage/quota/limit' -TimeoutSec 5 `
      -Headers @{ Authorization = "Bearer $key"; 'Accept-Language' = 'en-US,en' }
    if ($r.success) { $r | ConvertTo-Json -Depth 6 | Set-Content -Path $cache -Encoding UTF8 }
  } catch { }
}
if (-not (Test-Path $cache)) { 'z.ai: quota unavailable'; return }
if ($Mode -eq 'Json') { Get-Content $cache -Raw; return }

$q = Get-Content $cache -Raw | ConvertFrom-Json

# unit 3 = hours, 6 = weeks, 5 = months; nextResetTime is epoch ms
function Format-Reset($limit, $format) {
  [DateTimeOffset]::FromUnixTimeMilliseconds([int64]$limit.nextResetTime).ToLocalTime().ToString($format)
}

if ($Mode -eq 'Short') {
  $parts = foreach ($l in $q.data.limits) {
    if ($l.type -eq 'TIME_LIMIT') { continue }
    $w = switch ($l.unit) { 3 { "$($l.number)h" } 6 { 'wk' } 5 { 'mo' } default { "u$($l.unit)" } }
    $s = "$w $($l.percentage)%"
    if ($l.percentage -ge 80 -and $l.nextResetTime) { $s += ' resets ' + (Format-Reset $l 'ddd HH:mm') }
    $s
  }
  $parts -join ' | '
} else {
  "z.ai plan: $($q.data.level)"
  foreach ($l in $q.data.limits) {
    $w = switch ($l.unit) { 3 { "$($l.number)-hour window" } 6 { 'Weekly' } 5 { 'Monthly' } default { "unit $($l.unit) x$($l.number)" } }
    $used = if ($null -ne $l.currentValue) { $l.currentValue } else { 0 }
    $line = "$w ($($l.type)): $($l.percentage)% used, $used of $($l.usage), $($l.remaining) left"
    if ($l.nextResetTime) { $line += ', resets ' + (Format-Reset $l 'ddd MMM dd HH:mm zzz') }
    $line
  }
}
~/.claude-z/statusline.ps1: the status line
# claude-z status line (Windows): model | context used | z.ai quota
# https://github.com/yel-hadd/claude-code-zai
try { $in = [Console]::In.ReadToEnd() | ConvertFrom-Json } catch { $in = $null }
$parts = @(@($in.model.display_name) | Where-Object { $_ })
if ($null -ne $in.context_window.used_percentage) {
  $parts += "ctx $([math]::Floor($in.context_window.used_percentage))%"
}
$parts += & (Join-Path $PSScriptRoot 'zai-quota.ps1') -Mode Short
$parts -join ' | '
~/.claude-z/hooks/zai-usage-hook.ps1: answers /zai-usage without calling the model
# UserPromptSubmit hook (Windows): answer /zai-usage locally, without calling the model,
# so it still works when the z.ai quota is exhausted.
# https://github.com/yel-hadd/claude-code-zai
try { $in = [Console]::In.ReadToEnd() | ConvertFrom-Json } catch { exit 0 }
if ("$($in.prompt)".Trim() -match '^/zai-usage(\s|$)') {
  $out = (& (Join-Path $PSScriptRoot '../zai-quota.ps1') -Mode Full) -join "`n"
  @{ decision = 'block'; reason = $out } | ConvertTo-Json -Compress
}
exit 0

z.ai tools (all platforms)

Keep the single quotes: they keep ${ZAI_API_KEY} as literal text, which Claude Code fills in at startup.

claude-z mcp add -s user -t http web-search-prime https://api.z.ai/api/mcp/web_search_prime/mcp --header 'Authorization: Bearer ${ZAI_API_KEY}'
claude-z mcp add -s user -t http web-reader https://api.z.ai/api/mcp/web_reader/mcp --header 'Authorization: Bearer ${ZAI_API_KEY}'
claude-z mcp add -s user zai-mcp-server -e 'Z_AI_API_KEY=${ZAI_API_KEY}' -e Z_AI_MODE=ZAI -- npx -y @z_ai/mcp-server@latest

In PowerShell, write the separator as '--' and use cmd /c npx for the last one. PowerShell silently drops a bare --.

Compare them on your own code. Give claude and claude-z the same task this week and see which one you'd pay for. Your Claude setup stays as it is, and install.sh --uninstall removes claude-z in one step.

FAQ

Should I switch from a Claude subscription to the z.ai GLM Coding Plan?

Try it before deciding. claude-z runs alongside your normal claude, so you can give both the same tasks and compare. The main differences are the model (GLM-5.3 instead of Claude), the usage limits, and who processes your code. Everything else in Claude Code works the same.

How do I get a GLM Coding Plan?

Subscribe on z.ai, then create an API key in your account. If you sign up through an invite link such as this referral link, z.ai's campaign rules (October 2026) give new subscribers 10% off their first GLM Coding Plan order.

Can I use Claude Code without a Claude subscription?

Yes. Claude Code can talk to any Anthropic-compatible endpoint, and z.ai runs one at https://api.z.ai/api/anthropic. With a GLM Coding Plan API key, claude-z runs Claude Code on GLM-5.3 instead of Claude. You still need Claude Code installed, but not an Anthropic account.

How do I use Claude Code with z.ai?

Point Claude Code at z.ai's Anthropic-compatible endpoint, https://api.z.ai/api/anthropic, and pass your GLM Coding Plan key as ANTHROPIC_AUTH_TOKEN. This repo wraps those settings in a claude-z command so they only apply when you want them, and your normal Claude Code login keeps working.

Why does Claude Code say "Model glm-5.3 isn't recognized · context assumed to be 200k tokens"?

Claude Code doesn't know GLM's context size. Use the model names with the [1m] suffix (glm-5.3[1m], glm-5.3-flash[1m]) and set CLAUDE_CODE_AUTO_COMPACT_WINDOW=1000000. Claude Code then reports a 1,000,000-token context window. If it says the [1m] model doesn't exist, run claude update.

Does GLM-5.3 get the full 1M context in Claude Code?

Yes, with the [1m] model names. Tested on Claude Code 2.1.301 and later, which report contextWindow: 1000000 for glm-5.3[1m]. Without the suffix, Claude Code assumes 200k and compacts the conversation far too early.

How do I check my z.ai GLM Coding Plan quota?

Three ways: the status line at the bottom of claude-z, the zai-usage command in any terminal, and /zai-usage inside a session. All three read z.ai's quota endpoint, https://api.z.ai/api/monitor/usage/quota/limit, and show the 5-hour and weekly credit limits with reset times in your local time zone. That endpoint isn't in z.ai's public docs. On my Pro plan in October 2026 it reported 12,000 credits per 5-hour window and 60,000 per week.

How do I check quota when the limit is already used up?

Use zai-usage in a terminal, or /zai-usage inside claude-z. A normal slash command would fail, because it sends its output to the model, and the model is what's blocked. This repo's /zai-usage is answered by a local UserPromptSubmit hook instead, so it never calls the API.

What does error 1310 "Weekly/Monthly Limit Exhausted" mean?

Your plan's weekly credit limit is used up, and z.ai returns HTTP 429 until it resets. Claude Code may retry for a while, which looks like a hang. The reset time in z.ai's message is China Standard Time (UTC+8). zai-usage shows the same reset time converted to your local time.

Does web search work in Claude Code with z.ai?

Not the built-in one: Claude Code's WebSearch tool runs on Anthropic's servers. This setup blocks it and adds z.ai's web-search-prime and web-reader MCP servers instead. z.ai charges 1.2 credits per search or page read, according to its plan overview.

Can I keep my Anthropic Claude subscription alongside z.ai?

Yes. claude keeps using your Anthropic login and ~/.claude. claude-z uses z.ai and its own ~/.claude-z folder, with separate settings, history and MCP servers. Nothing is shared between them.

Where is my z.ai API key stored?

In ~/.config/zai/api_key, with permissions limited to your user (chmod 600 on Linux/macOS, an owner-only ACL on Windows). claude-z reads it at launch and passes it to Claude Code and the z.ai tools as environment variables. The MCP config only contains the ${ZAI_API_KEY} placeholder.

Troubleshooting

SymptomLikely causeFix
Model "glm-5.3" isn't recognizedModel names lack [1m]Use the [1m] names; run claude update if they're rejected
zsh: no matches found: glm-5.3[1m]Unquoted square bracketsQuote the model name
401 or authentication errorWrong key, or ANTHROPIC_API_KEY also setRe-run the installer with the right key; unset ANTHROPIC_API_KEY
Seems to hang, or 429 [1310]Plan limit used upRun zai-usage to see when it resets
Web search failsBuilt-in search can't run through z.aiUse the z.ai MCP tools (the installer adds them)
MCP server Failed to connectStarted without claude-z, Node.js older than 22, or missing cmd /c on WindowsStart with claude-z; upgrade Node.js
Status line says quota unavailableNetwork, jq missing, or empty key fileRun ~/.claude-z/zai-quota.sh --json to see the raw reply
PowerShell: "running scripts is disabled"Execution policySet-ExecutionPolicy -Scope CurrentUser RemoteSigned

What has been tested

LinuxmacOSWindows
Installer: install, re-run, uninstallYes, by hand and in CIYes, in CI (built-in bash 3.2)Yes, in CI (PowerShell 5.1 and 7, including icacls)
claude-z, zai-usage, /zai-usage hook, status line scriptsYes, by hand and in CIYes, in CIYes, in CI
Live Claude Code session: status line, /zai-usage, MCP connectedYes (Fedora, bash)Not runYes (PowerShell 7, on Linux)
z.ai vision tool via cmd /c npxNot run

CI runs every installer on GitHub's Ubuntu, macOS and Windows machines with a dummy key and without Claude Code, so it covers the installers and scripts but not a live z.ai session. Live sessions were tested with Claude Code 2.1.301 to 2.1.305 and a GLM Coding Plan Pro account in October 2026. zsh hasn't been tested. Reports from real Macs and Windows machines are welcome in GitHub issues.

Referral disclosure

The GLM Coding Plan buttons and links on this page are the author's referral link. If you subscribe through it, z.ai gives you 10% off your first subscription and gives the author z.ai credits, according to z.ai's campaign rules as of October 2026. It costs you nothing extra. Plain link without referral: z.ai/subscribe.

Sources