Skip to content

Credentials/providers visibility: global runtime credential-status inventory + Settings surface #378

@markhayden

Description

@markhayden

Summary

Add a global, runtime-agnostic credential/provider status surface so the dashboard can show, at a glance, which providers and integrations are configured (and where the credential lives) — across all domains, not just image. Status only; never expose or store secret values from the runtime.

This generalizes the per-image work already shipped in the media-generation adapter architecture (see .claude/specs/media-generation-adapter-architecture.md).

Background — what exists today

The image generation work (Phase 1/2 of the media-generation spec) established:

  • A runtime-only plugin: image generation goes through ctx.runtime.images, with a shared @bakin/core/media direct-provider shim composed by the adapter for gap-fill.
  • A Bakin-owned provider secret store (~/.bakin/secrets.json, 0600, env → store resolution) for shim keys and for providers no runtime fronts.
  • A "serving path" diagnostic: generation results carry routeSource/credentialSource; readiness + recommend report a provider-level servedBy (runtime | shim | unconfigured).

So for image providers we can already answer "is this configured, and by whom (runtime vs Bakin)?" The gap: there's no equivalent view for the other credential domains a runtime holds (models/LLM, gateway, channels, skills/tools).

The idea

A Settings surface (a new Credentials tab — not a new nav item) that lists every provider/integration with:

  • Configured? yes/no
  • Owner / source: runtime-managed (e.g. OpenClaw) vs Bakin-managed (env / secret store)
  • Editability: runtime-managed rows are read-only status (point the user to configure them in the runtime); Bakin-managed rows are editable via the existing secret store.

Group by status (Configured / Not configured) to start; category grouping (image / models / channels / tools) can layer on once the real shape is known.

Proposed approach

  1. New boundary-safe runtime capability — e.g. runtime.providers.status() — returning a status-only inventory:
    { domain: 'models' | 'image' | 'gateway' | 'channels' | 'skills' | ...,
      id: string, owner: 'runtime' | 'bakin', configured: boolean }
    
    No secret values ever cross the boundary — only configured booleans. Surfacing the runtime's own configured self-report is not credential extraction.
  2. Adapter implements it by normalizing the runtime's config (for OpenClaw, the data config.get() already returns) + existing capability methods (images.providers()), then stripping everything but status. A future runtime (e.g. Hermes) maps its own shape onto the same contract.
  3. UI consumes the capability: the Credentials tab merges runtime-reported providers with Bakin-owned env/store entries; editing is limited to the Bakin secret store.

Coverage research (from the repo + mock)

The OpenClaw adapter already reaches these credential-bearing config sections (paths only — these are public config-schema locations, already in the open-source adapter):

Domain Config location Configured signal
Model/LLM + image providers models.providers.<id> (apiKey / env) key or env present; image also via images.providers().configured
Gateway gateway.auth (token) token present
Channels channels.<id> per-channel auth present (shape varies, untyped)
Skills / tools skills.entries.<id> (apiKey / env) key or env present (untyped)

Conclusions:

  • No new runtime CLI is required — the inventory is built by normalizing the config the adapter already reads. (The adapter only shells infer image providers, gateway restart, agents delete, cron run; there is no generic provider-listing command today.)
  • It is not image-only — models, gateway, channels, and skills/tools are all reachable.

Unverified / open

  • Dedicated TTS / browser / other tool token homes are not clearly located in the typed schema — needs confirmation against a real runtime config or upstream docs.
  • Whether a richer first-class provider/credential inventory exists upstream (vs. normalizing config).
  • Multi-runtime mapping (the capability must survive a second runtime with a different shape).
  • Tab axis: status (Configured/Not) vs owner (runtime/Bakin) vs category — owner is arguably the most actionable; decide with real data.

Constraints (non-negotiable)

  • Status only. The inventory returns configured booleans; it must never read, return, log, or persist runtime-owned secret values.
  • Runtime owns its keys. Bakin surfaces runtime status and points to where to configure it; it does not write runtime credentials.
  • Bakin only manages its own store. Editable rows map to ~/.bakin/secrets.json (already 0600, write-only/masked API to be added).

Near-term scope decision

Ship the image-scoped Provider Keys tab first, driven by the existing image providerReadiness() (runtime/env/store/none per image provider; edit = Bakin store). This issue tracks generalizing it into the runtime-agnostic inventory above.

References

  • .claude/specs/media-generation-adapter-architecture.md (four-layer model, secret store, serving-path diagnostics)
  • packages/core/src/media/ (shared shim + secret store)
  • packages/adapter-openclaw/src/config.ts, runtime.ts (config reader + image capability)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions