You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Tracking the change proposed in #128 (by @haramiya).
We're moving this from a code PR to a tracked issue under CONTRIBUTING.md: feature ideas belong in adrs/ as a short human-written note and bugs as an issue, and we implement the underlying code from our side. Capturing the original proposal here so it isn't lost.
Running HARNESS=claude on a Claude subscription (CLAUDE_CODE_OAUTH_TOKEN from claude setup-token, no ANTHROPIC_API_KEY) serves turns fine, but the deployment tells everyone it isn't set up:
The admin onboarding view says Needs a key / "claude-opus-5 cannot run until its Anthropic key is configured" — while the assistant answers happily underneath.
Root cause: both read only the model credential store, which counts anthropic/openai/openrouter API keys (env or admin-managed) and knows nothing about auth the harness carries itself. #67 and #109 both hit this and proposed fixes at different layers.
Fix
harnessCarriedModelAuth(config) in src/config.ts names the provider a harness authenticates on its own:
claude → anthropic when CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_AUTH_TOKEN is in claudeProcessEnv
codex → openai when CODEX_ACCESS_TOKEN is in codexProcessEnv
otherwise undefined (env API keys are already counted through the credential store's fallback, so they aren't double-counted here)
Wired as an optional ServerDeps.harnessCarriedModelAuth and surfaced at the two places that were lying:
Surface gate: getSurfaceConfig ORs it into modelProviderConfigured. Unlike making modelProviderAvailabilityFor unconditionally report claude as available (adr: smaller fix for the keyless-harness model gate #109's noted downside), a claude deployment with no token anywhere still reports unconfigured and keeps the onboarding gate.
Admin API: GET /v1/admin/model-providers gains a sibling harnessAuth: { harnessId, provider } field. The credential-store providers statuses are deliberately untouched — anthropic keeps reporting absent when no key is stored, because those keys feed pi-transport calls and adding/deleting them is independent of harness OAuth. Old admin UI against new core ignores the extra field; new UI against old core sees no harnessAuth and behaves exactly as before (blue-green safe).
Admin onboarding view: the model-provider step shows Ready when the base model's provider is store-configured or harness-authenticated, with the summary "claude-opus-5 · authenticated by the claude harness — no API key needed." Stored-key summaries keep precedence; the key form stays usable for feeding pi-transport.
Screenshots
Admin → Onboarding, HARNESS=claude with only CLAUDE_CODE_OAUTH_TOKEN:
Before
After
Rendered against the admin page served with realistic stubbed API fixtures (the machine's only dev-instance Slack slot was held by another live instance, so this wasn't exercised on a booted stack; the same states are covered by the tests below).
Tests
test/model-credential-route.test.ts: claude harness + OAuth token → modelProviderConfigured: true, harnessAuth: { harnessId: "claude", provider: "anthropic" }, and the anthropic status still { configured: false, source: "absent" }; claude harness with no token → still unconfigured, no harnessAuth field. start() now derives the dep from the test config the same way src/index.ts does.
plugins/admin/test/onboarding-view.test.ts: runs the real loadOnboarding() (vm-extracted from index.html) against stubbed endpoints — harness auth alone → Ready badge + harness summary; no harness auth → Needs a key; stored admin key + harness auth → Ready with the stored-key summary.
Verification
test/model-credential-route.test.ts 13/13, test/external-slack-participants.test.ts + test/admin-resources.test.ts 20/20, plugins/admin onboarding suite 7/7
tsc --noEmit (root and plugins/admin), eslint ., prettier --check — clean (lint:ox has a pre-existing missing-native-binding failure locally; CI covers it)
Independent fresh-context adversarial review of the diff — findings resolved before merge
Tracking the change proposed in #128 (by @haramiya).
We're moving this from a code PR to a tracked issue under
CONTRIBUTING.md: feature ideas belong inadrs/as a short human-written note and bugs as an issue, and we implement the underlying code from our side. Capturing the original proposal here so it isn't lost.Original PR: #128
Reported by: @haramiya
If we ship a fix or feature from this, credit @haramiya as co-author.