Ibm Bob
OpenCode plugin that registers IBM Bob / IBM-approved enterprise model endpoints as an OpenCode provider.
2
近 30 天 +1
261
近 7 天 190
40.9
生态多维模型
4 天前
2026-09-30
快速安装与配置
opencode.json写入当前项目的 opencode.json,只对这个仓库生效。
opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-ibm-bob@0.6.0"]
}写入 ~/.config/opencode/opencode.json,对所有项目生效。
~/.config/opencode/opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-ibm-bob@0.6.0"]
}若你要在本地改造这个插件,先装到项目里再从本地路径引用。
shell
pnpm add -D opencode-ibm-bobOpenCode 启动时会通过内嵌运行时自动加载 npm 依赖并缓存至本地目录,无需手动在全局环境执行安装。
Use IBM Bob's models inside OpenCode. Browser SSO, automatic model discovery, real dollar costs in the cost column, and a Bobcoin budget widget in the TUI sidebar.
It is the OpenCode counterpart of the Pi extension
pi-bob: it registers Bob as the
ibm-bob provider, discovers the model catalog Bob exposes to your account, and
adds Bob's browser SSO to opencode auth login.
The plugin does not scrape Bob, does not read Bob Shell's stored SSO secrets, and does not bypass IBM-approved access paths. SSO tokens are obtained through Bob's own browser login endpoints and stored in OpenCode's auth store.
Contents
- Setup in 3 steps — the fastest path
- The complete configuration — every file and every variable, in one place
- Troubleshooting
- What it does
- Model discovery
- Usage cost (Bobcoins)
- Sidebar Bobcoins widget
- Instance and team routing
- Environment variable reference
- Development · Validation performed
Setup in 3 steps
1. Declare the plugin
OpenCode reads two config files, and each one feeds a different process:
| File | Read by | Gives you |
|---|---|---|
opencode.json (project) or ~/.config/opencode/opencode.json (global) |
the OpenCode server | the ibm-bob provider, models, auth, the bob_usage tool |
.opencode/tui.json (project) or ~/.config/opencode/tui.json (global) |
the OpenCode TUI | the Bobcoin sidebar widget |
Listing the plugin only in opencode.json is enough to use Bob's models — the
second file just adds the sidebar widget. Both name the same package (there is
no /tui suffix: OpenCode resolves the TUI half from the package's own
exports["./tui"]).
opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-ibm-bob"]
}
.opencode/tui.json (optional — sidebar widget):
{
"$schema": "https://opencode.ai/tui.json",
"plugin": ["opencode-ibm-bob"]
}
Working from a checkout instead of npm? Put the repository's absolute path in place of the package name, in both files — no linking or installing needed:
{ "plugin": ["/absolute/path/to/opencode-ibm-bob"] }
2. Log in
Pick one of the two credentials. SSO is the recommended path.
Bob SSO (browser)
opencode auth login # pick "IBM Bob", then "IBM Bob SSO (browser)"
Your browser opens Bob's login page with a callback_uri pointing at a local
one-shot listener; the returned code is exchanged at
POST /authn/v1/auth/token, and OpenCode stores the access/refresh pair in its
own auth store (~/.local/share/opencode/auth.json). Expired tokens are
refreshed at POST /authn/v1/auth/refresh and written back through OpenCode's
auth API.
Do not copy a token out of Bob's local credential store unless IBM policy explicitly permits it — use the SSO login.
Approved API key
export IBM_BOB_API_KEY="..." # IBM_BOB_KEY is also accepted; do not commit either
Or store it in the auth store instead of the environment with
opencode auth login → IBM Bob API key.
Credential resolution order: what OpenCode stored for the provider (SSO or API
key), then IBM_BOB_API_KEY, then IBM_BOB_KEY. Run opencode auth logout for
ibm-bob before switching from SSO back to an environment key.
3. Use it
opencode models | grep ibm-bob
opencode run -m ibm-bob/premium "say hi"
After an SSO login the discovered catalog only lands at the next OpenCode
start (see Model discovery); until then you get the fallback
model, premium.
The complete configuration
Everything the plugin understands, in one place. Nothing below is required: the values shown are the ones the plugin already uses by default, so Setup in 3 steps is all you need to get running — come back here to change something.
opencode.example.json in this package is a ready-to-copy starting point for the
first block.
opencode.json — provider, models, overrides
Anything you declare under provider.ibm-bob wins over what the plugin
generates, so a corporate endpoint or a pinned model list stays in place. Both
blocks below are optional — plugin alone is a complete config:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-ibm-bob"],
"provider": {
"ibm-bob": {
"options": {
"baseURL": "https://api.us-east.bob.ibm.com/inference/v1"
},
"models": {
"premium": { "limit": { "context": 150000, "output": 8192 } }
}
}
}
}
.opencode/tui.json — the sidebar widget
{
"$schema": "https://opencode.ai/tui.json",
"plugin": ["opencode-ibm-bob"]
}
Environment — every variable with its default
Copy what you need into your shell profile, .env, or your OpenCode config's
environment. Only IBM_BOB_API_KEY ever holds a secret — keep it out of repo
files. Each variable is described in the
reference below.
# --- Credential (pick one, or use `opencode auth login` instead) ------------
export IBM_BOB_API_KEY="" # approved API key/token
export IBM_BOB_KEY="" # alias, matching Bob Shell
# --- Core -------------------------------------------------------------------
export IBM_BOB_ENABLED=true # false leaves the provider unregistered
export IBM_BOB_BASE_URL="https://api.us-east.bob.ibm.com/inference/v1"
export IBM_BOB_MODELS="premium" # fallback models when no catalog is available
export IBM_BOB_DEBUG=false # log discovery, token and login steps
# --- Model discovery --------------------------------------------------------
export IBM_BOB_DISCOVER_MODELS=true
export IBM_BOB_MODEL_DISCOVERY_TIMEOUT_MS=5000
export IBM_BOB_CATALOG_CACHE="${XDG_CACHE_HOME:-$HOME/.cache}/opencode/ibm-bob/catalog.json"
export IBM_BOB_CATALOG_TTL_MS=86400000 # 24h
# --- Instance / team routing ------------------------------------------------
export IBM_BOB_DISCOVER_PROFILE=true
export IBM_BOB_PROFILE_DISCOVERY_TIMEOUT_MS=5000
export IBM_BOB_PROFILE_CACHE="${XDG_CACHE_HOME:-$HOME/.cache}/opencode/ibm-bob/profile.json"
export IBM_BOB_PROFILE_TTL_MS=86400000 # 24h
export IBM_BOB_READ_BOBSHELL_SETTINGS=true # ~/.bob/settings.json, Bob Shell 1.x only
export IBM_BOB_INSTANCE_ID="" # override x-instance-id
export IBM_BOB_TEAM_ID="" # override x-team-id
export IBM_BOB_USER_AGENT="opencode-ibm-bob/<version>"
export IBM_BOB_HEADERS_JSON="" # extra headers, e.g. '{"x-trace":"1"}'
# --- Authentication ---------------------------------------------------------
export IBM_BOB_AUTH_SCHEME="Apikey" # non-JWT credentials; SSO always uses Bearer
export IBM_BOB_AUTH_BASE_URL="" # defaults to the origin of IBM_BOB_BASE_URL
export IBM_BOB_WEB_LOGIN_URL="https://bob.ibm.com/login"
export IBM_BOB_TOKEN_REQUEST_TIMEOUT_MS=10000
export IBM_BOB_LOGIN_TIMEOUT_MS=180000 # how long the SSO callback listener waits
export IBM_BOB_SSO_PORT="" # default: a random free port
# --- Cost and budget --------------------------------------------------------
export IBM_BOB_RATES="" # e.g. "premium=2:2,fast=0.8:0.84" (Bobcoins)
export IBM_BOB_BUDGET_TIMEOUT_MS=5000
export IBM_BOB_BUDGET_TTL_MS=300000 # 5min, budget cache used by the sidebar
export IBM_BOB_BUDGET_CACHE="${XDG_CACHE_HOME:-$HOME/.cache}/opencode/ibm-bob/budget.json"
# --- Adapter ----------------------------------------------------------------
export IBM_BOB_API="openai-completions" # or openai-responses / anthropic-messages
export IBM_BOB_NPM="" # override the AI SDK package
# --- Model metadata (only used when discovery cannot supply it) -------------
export IBM_BOB_CONTEXT_WINDOW=200000
export IBM_BOB_MAX_TOKENS=8192
export IBM_BOB_INPUT="text" # or "text,image"
export IBM_BOB_REASONING=false
export IBM_BOB_REASONING_MODELS="" # comma-separated model IDs
Troubleshooting
| Symptom | Cause and fix |
|---|---|
402 team user not found or has been deleted |
Bob rejects an SSO token with no x-team-id. The plugin normally resolves it from /admin/v1/profile; if that call cannot be reached, set IBM_BOB_TEAM_ID (and IBM_BOB_INSTANCE_ID) yourself. See Instance and team routing. |
opencode models shows only ibm-bob/premium |
The catalog has not been discovered yet. After an SSO login it is applied at the next OpenCode start. With an API key it is fetched immediately — check IBM_BOB_DEBUG=true output. |
| Models are stale after a plan change | Delete the catalog cache (${XDG_CACHE_HOME:-~/.cache}/opencode/ibm-bob/catalog.json) or lower IBM_BOB_CATALOG_TTL_MS. |
| The sidebar widget never appears | It is loaded from tui.json, not opencode.json. See step 1. |
| The sidebar says "usage unavailable" | The budget cache has not been written yet (it is refreshed once per session start), or no team could be resolved for the credential. |
401/403 from Bob with a valid key |
Your endpoint may expect a different auth scheme; set IBM_BOB_AUTH_SCHEME (Bob's own is Apikey). |
| Switching from SSO back to an env key does nothing | The stored credential wins. Run opencode auth logout for ibm-bob first. |
The cost column shows $0.00 |
The model is missing from the rate table; supply its rate with IBM_BOB_RATES. See Pricing the models. |
IBM_BOB_DEBUG=true logs discovery, token and login steps and is the first
thing to turn on for anything else.
What it does
| Hook | Effect |
|---|---|
config |
Registers the ibm-bob provider (name, adapter package, base URL, models, routing headers) so Bob models show up in /models, opencode models and --model ibm-bob/premium. |
tool |
Adds bob_usage, reporting the Bobcoins spent this session and the team's usage against its budget. See Usage cost. |
auth |
Adds IBM Bob SSO (browser) and IBM Bob API key to opencode auth login, refreshes expired SSO tokens, and attaches the credential, Bob's auth scheme and the instance/team routing headers to every request. |
Bob requires an x-instance-id header and, for SSO tokens, a matching
x-team-id; without the team it answers 402 team user not found or has been deleted. Neither the SSO callback nor the JWT carries a team, so the plugin
resolves the pair from Bob's own GET /admin/v1/profile, exactly as Bob Shell
does. See Instance and team routing.
Bob authenticates approved API keys with Authorization: Apikey <key> (Bob
Shell's own scheme) and SSO tokens with Authorization: Bearer <jwt>, while the
AI SDK adapters send Bearer or x-api-key for whatever credential they are
given. The plugin therefore rewrites that header per request; use
IBM_BOB_AUTH_SCHEME if your endpoint expects a different scheme.
Model discovery
Discovery is on by default and reads Bob's authenticated
GET /inference/v1/model/info:
- With
IBM_BOB_API_KEY/IBM_BOB_KEYset, the catalog is fetched while the config is built, so the models are registered for the current session. - After an SSO login, the catalog is fetched once the token is exchanged and cached on disk. OpenCode has already registered the provider's models by the time the auth loader runs, so an SSO-discovered catalog is applied at the next OpenCode start; until then the fallback models are used.
- The cache is refreshed in the background (once per session) when it is older
than
IBM_BOB_CATALOG_TTL_MS.
Only model_name and model_info are required, because Bob's API-key view of
the endpoint reports just those; other views also carry litellm_params.model
(the backend route behind the alias) and an exposed flag. Routes marked
exposed: false or completion_only: true are dropped, everything else is
kept, and Bob still enforces route access during inference. Failures, timeouts,
malformed payloads and empty catalogs fall back to the cached catalog, then to
IBM_BOB_MODELS.
Discovered context limits, output limits, vision support, reasoning support, backend identifiers and token prices are mapped into OpenCode model entries. Bob reports prices per token; OpenCode displays them per million tokens, and the plugin performs that conversion.
The cache lives in ${XDG_CACHE_HOME:-~/.cache}/opencode/ibm-bob/catalog.json,
is scoped to the base URL that produced it, and holds no credentials.
Usage cost (Bobcoins)
Bob does not price per token — /model/info reports a zero token price. It bills
in Bobcoins instead, reporting the amount spent as usage.credits on each
inference response, which is the field Bob Shell reads. One Bobcoin is worth
$0.50, the trial plan's 40 Bobcoins being priced at $20.
Pricing the models
Bob publishes no rate: every entry in /model/info reports
input_cost_per_token: 0, and the only figure Bob returns is the Bobcoin amount
charged on each response. The plugin therefore carries a table of rates measured
against the live us-east endpoint, converted to dollars at the plan's rate of
40 Bobcoins for $20:
| Models | Bobcoins / 1M | Dollars / 1M in | Dollars / 1M out |
|---|---|---|---|
premium, premium-ide, premium-shell, sonnet-4.5, wxO-model |
2.0 in / 2.0 out | $1.00 | $1.00 |
ultra |
2.5 / 2.5 | $1.25 | $1.25 |
fast, explorer |
0.8 / 0.84 | $0.40 | $0.42 |
granite-8b-code-instruct, gpt-oss-20b, openai/gpt-oss-20b, rnj-1-test, rnj-1-nextedit-v1-0 |
0 | free | free |
Those dollar figures fill each model's cost, so OpenCode's cost column shows
real money instead of the flat zero Bob's catalog implies. Cache tokens are
charged at the input rate, a route Bob does price in the catalog keeps its
declared price, and a model missing from the table stays at zero rather than
being guessed at.
The rates come from one trial account. If your plan is priced differently,
override them with IBM_BOB_RATES, which takes model=input:output pairs in
Bobcoins and is converted the same way:
export IBM_BOB_RATES="premium=2:2,fast=0.8:0.84"
Reading the current usage
The plugin registers a bob_usage tool that reports both figures:
This session so far: 0.000040 Bobcoins ($0.000020) over 1 billed response(s).
Team default: 0.384/40.00 BOBcoin used ($0.19 of $20.00), 39.62 left.
- Session — the credits Bob charged for the responses this OpenCode process
has already received. The turn that calls the tool has not been billed yet, so
its own cost only shows on a later call; in one-shot
opencode runthe figure is therefore usually zero, while a TUI session accumulates. - Team — read live from
GET /admin/v1/teams/{team}/users/{member}, the same call Bob Shell makes, falling back to the usage figure the profile already carries when that route is unreachable.
Amounts use Bob Shell's precision ladder, with one finer step: a single request
can cost less than 0.0001 Bobcoin, which Bob Shell's last rung prints as a
flat 0.0000.
Sidebar Bobcoins widget
OpenCode's TUI shows a "Context" widget in the session sidebar with the
tokens used and the percentage of the context window they fill. This plugin
ships an optional TUI-side counterpart that disables OpenCode's own
internal:sidebar-context widget and adds the team's Bobcoin usage against
its plan total underneath. OpenTUI has no image component at all (checked
its compiled component catalogue: text, box, and a handful of other
text-only primitives, no image/Sixel/Kitty support), so bob.ibm.com/pricing's
coin icon is approximated with the Unicode draughts-piece glyphs ⛀⛁ —
two overlapping discs, without depending on an emoji font being installed:
Context 12,480 tokens 34% used
⛀⛁ 0.38 / 40.00 Bobcoins
When Bob's admin API reports no budget_limit for the member — which is
what the trial account this was built against returns — there is no plan
total to show, and the line degrades to the usage alone:
Context 0 tokens 0% used
⛀⛁ 0.402 Bobcoins used
Reading the plan total needs a live IBM Bob credential, and the TUI process
never has one — it only talks to the local OpenCode server over HTTP, which
exposes no way to read back a stored secret. So the server half of the
plugin (src/index.ts) resolves the team budget the same way the bob_usage
tool does (see Reading the current usage) once
per session start, and caches it to
$XDG_CACHE_HOME/opencode/ibm-bob/budget.json (~/.cache/... by default,
override with IBM_BOB_BUDGET_CACHE); the sidebar widget polls that file
every 15 seconds. Until the first fetch lands, or if it fails (offline, no
team resolved, member API key with no team), it shows "usage unavailable"
rather than a stale or wrong figure.
TUI plugins are configured in a different file from server plugins —
.opencode/tui.json, not opencode.json. See
step 1 for both files; listing the plugin only in
opencode.json loads the provider but silently never loads this widget.
This half of the plugin only runs in the OpenCode TUI process — it has no
effect on opencode run, opencode serve, or the provider/auth behavior
described above.
Instance and team routing
Bob routes every request with an instance and, for SSO credentials, a team. The plugin resolves them in this order:
IBM_BOB_INSTANCE_ID/IBM_BOB_TEAM_ID- Bob Shell's non-secret
ibm.instanceId/ibm.teamIdin~/.bob/settings.json - Bob's authenticated
GET /admin/v1/profile, cached on disk - the first instance in the SSO token, as a last resort for
x-instance-id
Step 3 is what makes an SSO login work on its own. /admin/v1/profile returns
the instances the account belongs to and the teams inside each one; the plugin
flattens that into (instance, team) pairs and picks the pair matching whatever
is configured, or the first one — the same selection Bob Shell performs. An
instance with no team still yields a usable entry, because API keys route
without a team.
Bob Shell 2.x no longer writes ibm.instanceId / ibm.teamId anywhere: it
resolves them from the same endpoint on every start, so step 2 only applies to
Bob Shell 1.x installations.
The cache lives in ${XDG_CACHE_HOME:-~/.cache}/opencode/ibm-bob/profile.json,
is scoped to the origin that produced it, and holds no credentials.
Environment variable reference
Every variable is optional; see the complete configuration for a copy-paste block of the whole set.
Core
| Variable | Default | Description |
|---|---|---|
IBM_BOB_ENABLED |
true |
Set to false to leave the provider unregistered. |
IBM_BOB_BASE_URL |
https://api.us-east.bob.ibm.com/inference/v1 |
Approved Bob/IBM endpoint. The AI SDK adapters append their own route (/chat/completions, /responses, /messages). |
IBM_BOB_API_KEY |
unset | Approved API key/token. Keep it out of repo files. |
IBM_BOB_KEY |
unset | Alias for IBM_BOB_API_KEY, matching Bob Shell configuration. |
IBM_BOB_MODELS |
premium |
Comma-separated fallback model IDs used when no catalog is available. |
IBM_BOB_DISCOVER_MODELS |
true |
Discover visible models from /model/info. |
IBM_BOB_MODEL_DISCOVERY_TIMEOUT_MS |
5000 |
Discovery timeout. |
IBM_BOB_TOKEN_REQUEST_TIMEOUT_MS |
10000 |
SSO token exchange/refresh timeout. |
IBM_BOB_LOGIN_TIMEOUT_MS |
180000 |
How long the SSO callback listener waits. |
IBM_BOB_SSO_PORT |
random free port | Fixed port for the local SSO callback listener. |
IBM_BOB_CATALOG_CACHE |
${XDG_CACHE_HOME:-~/.cache}/opencode/ibm-bob/catalog.json |
Catalog cache file. |
IBM_BOB_CATALOG_TTL_MS |
86400000 |
Age after which the cached catalog is refreshed in the background. |
IBM_BOB_DISCOVER_PROFILE |
true |
Resolve the instance/team pair from /admin/v1/profile. |
IBM_BOB_PROFILE_DISCOVERY_TIMEOUT_MS |
5000 |
Profile discovery timeout. |
IBM_BOB_PROFILE_CACHE |
${XDG_CACHE_HOME:-~/.cache}/opencode/ibm-bob/profile.json |
Profile cache file. |
IBM_BOB_PROFILE_TTL_MS |
86400000 |
Age after which the cached profile is refetched. |
IBM_BOB_BUDGET_TIMEOUT_MS |
5000 |
Timeout for the Bobcoin budget lookup. |
IBM_BOB_BUDGET_TTL_MS |
300000 |
Age after which the cached team budget is refreshed at session start. |
IBM_BOB_BUDGET_CACHE |
${XDG_CACHE_HOME:-~/.cache}/opencode/ibm-bob/budget.json |
Budget cache file the sidebar widget reads. |
IBM_BOB_RATES |
measured table | Override the Bobcoin rates, as model=input:output pairs. |
IBM_BOB_DEBUG |
false |
Log discovery, token and login steps. |
Adapter
| Variable | Default | Description |
|---|---|---|
IBM_BOB_API |
openai-completions |
openai-completions (@ai-sdk/openai-compatible), openai-responses (@ai-sdk/openai) or anthropic-messages (@ai-sdk/anthropic). |
IBM_BOB_NPM |
adapter default | Override the AI SDK package used for the provider. |
Bob's documented route is the OpenAI-compatible one; the other two are for IBM-approved endpoints that expose those APIs.
Bob routing headers
| Variable | Default | Description |
|---|---|---|
IBM_BOB_READ_BOBSHELL_SETTINGS |
true |
Read the non-secret ibm.instanceId / ibm.teamId from ~/.bob/settings.json (Bob Shell 1.x only). Stored SSO secrets in that file are never read. |
IBM_BOB_INSTANCE_ID |
Bob Shell setting, else the discovered profile, else the SSO token's first instance | Override x-instance-id. |
IBM_BOB_TEAM_ID |
Bob Shell setting, else the discovered profile | Override x-team-id. |
IBM_BOB_USER_AGENT |
opencode-ibm-bob/<version> |
User-Agent sent to Bob. |
IBM_BOB_HEADERS_JSON |
unset | JSON object of extra headers, e.g. {"x-trace":"1"}. |
Auth header
| Variable | Default | Description |
|---|---|---|
IBM_BOB_AUTH_SCHEME |
Apikey |
Scheme used for non-JWT credentials. SSO tokens always use Bearer. |
IBM_BOB_AUTH_BASE_URL |
origin of IBM_BOB_BASE_URL |
Origin used for the /authn/v1/auth/* endpoints. |
IBM_BOB_WEB_LOGIN_URL |
https://bob.ibm.com/login (public-dev / qa hosts are mapped automatically) |
Bob web login page used for SSO. |
Model metadata
| Variable | Default | Description |
|---|---|---|
IBM_BOB_CONTEXT_WINDOW |
discovered; fallback 200000 |
Context window for every Bob model. Keep it at or below the backend limit so OpenCode compacts before Bob rejects the request. |
IBM_BOB_MAX_TOKENS |
discovered; fallback 8192 |
Maximum output tokens. |
IBM_BOB_INPUT |
discovered; fallback text |
text or text,image. |
IBM_BOB_REASONING |
discovered; fallback false |
Force reasoning support on or off. |
IBM_BOB_REASONING_MODELS |
empty | Comma-separated model IDs to mark as reasoning-capable. |
Development
bun install
bun test # 121 tests
bun run typecheck
Validation performed
Against the live https://api.us-east.bob.ibm.com endpoint with an approved API
key:
GET /inference/v1/model/inforeturns200; the plugin registered the 13 routes the account exposes (premium,premium-ide,premium-shell,sonnet-4.5,fast,ultra,explorer,wxO-model,granite-8b-code-instruct,gpt-oss-20b, …) and cached them.opencode run -m ibm-bob/premium "Reply with exactly: bob-ok"→bob-ok.opencode run -m ibm-bob/fast …→ answered, so non-default aliases route too.- A prompt requiring a tool call went through: the model invoked OpenCode's read tool and answered from its result.
Also verified locally:
bun test— 121 tests covering catalog parsing (including the API-key payload shape, theexposedandcompletion_onlyfilters), per-million price conversion, catalog cache round-trip and base-URL scoping, fallback and override model building, theApikey/Bearerheader rules, credential resolution order, SSO expiry/refresh/persistence, profile parsing and selection, profile cache round-trip and origin scoping, the routing-header precedence, Bobcoin parsing from both JSON and streamed responses, the Bobcoin and dollar formatting ladders, the budget lookup, the rate table with its Bobcoin-to-dollar conversion and itsIBM_BOB_RATESoverride, and theconfig/authhooks.tsc --noEmit— clean.- Against a local stub of the Bob API, OpenCode issued
GET /inference/v1/model/infoand thenPOST /inference/v1/chat/completionswithAuthorization: Apikey <key>,x-instance-id,x-team-idand the plugin's User-Agent, and nox-api-keyheader.
The browser SSO round-trip was then verified end to end against the same live
endpoint, with no IBM_BOB_* variable set and no ~/.bob/settings.json:
opencode auth login→ IBM Bob SSO (browser) stored an access/refresh pair, andPOST /authn/v1/auth/refreshreturned a rotated pair.- Before profile discovery existed, inference failed with
402 team user not found or has been deleted: Bob rejects an SSO token that carries nox-team-id, and neither the callback nor the JWT provides one. GET /admin/v1/profilereturns200with the account's instance and its teams; the plugin now resolves the pair from it and caches it.opencode run -m ibm-bob/premium "Reply with exactly: bob-ok"→bob-ok,-m ibm-bob/fastanswered, and a tool-calling prompt went through — all over SSO alone.
Bobcoin reporting was verified against the same live endpoint: a completion
reported usage.credits of 0.00004, the session accumulator picked it up
without disturbing the response OpenCode consumes, and bob_usage returned the
team's live figure from /admin/v1/teams/{team}/users/{member}.
Every rate in the table was measured against the live endpoint, two requests per
model with different output lengths so the input and output rates could be
separated; each pair reproduces the credits Bob reported. opencode stats then
moved from $0.00 to a populated figure.
Not verified: the 40 Bobcoins = $20 conversion, which was supplied rather than observed — Bob exposes no rate of its own.
Not verified: multi-instance and multi-team accounts, which were exercised only against parsed payloads and not a live account exposing more than one pair; and Bobcoin accounting on a streamed response, which was covered by tests but not observed against live Bob, since the adapter used here returned a single JSON body.
License
MIT
同类生态推荐
Cache Compact
opencode-cache-compact
Cache-friendly context compaction for OpenCode (V1 and V2): append a summary in place, then cut what the model sees down to it.
Kimi Code Statusline
opencode-kimi-code-statusline
OpenCode TUI plugin: display Kimi For Coding (Kimi Code) subscription quota (rolling 5h / weekly) in the footer statusline. V2-native, zero-config, no cookies.
Elicify Vertex
@elicify-ai/elicify-vertex
OpenCode plugin that makes any coding model behave like a mythos-class engineer: a behavioural contract, live in-loop detection and correction, and an independent verifier that verifies the work against your repo. Self-validating, evidence-driven agent lo