Skip to main content
The Secrets API (room.secrets) manages room-scoped, identity-scoped credentials. Use room secrets when a credential belongs to a room, a room participant, or a room service identity rather than to your whole project. Room secrets let you keep sensitive values out of your manifest and source code while still making them available to the specific runtime or identity that needs them. When a room secret is injected into a service, the service process can use it at runtime, but the model does not automatically see the value unless your code, tools, logs, or prompts explicitly pass it through. Common examples include:
  • an OAuth token for a user
  • a room-local API key for a toolkit or room service
  • a delegated credential passed from one participant to another
  • a secret used to build request headers for an MCP connection

Before you start

These examples assume: If myroom does not exist yet, create it first:
bash
meshagent rooms create --name myroom
To store secrets in a room:
  • you need permission to join that room
  • your room connection must include the secrets API permission
  • if you use --for-identity to store a secret for another identity, you also need an admin API grant
If you cannot create the room or you get a permission error when calling meshagent room secret set, ask a project admin to grant room access or store the secret on behalf of the target identity.

What room secrets are

Room secrets are stored inside the context of a room and are tied to the caller’s participant identity, or to another identity when an admin uses --for-identity. That means room secrets are not just “smaller project secrets.” They are a separate system built for:
  • participant-specific credentials
  • room-local service credentials
  • live request/provide flows
  • delegation between identities
  • OAuth storage and refresh

How room secrets are different from other secret types

  • Project keys secrets are shared across the project and are meant for project services.
  • Image pull secrets are only for pulling private images.
  • Room secrets belong to a room and usually to a specific identity inside that room.
If a room service needs a secret at runtime, the normal choice is a room secret.

Room secrets vs tokens

Tokens and secrets often appear in the same service spec, but they do different things:
  • a token defines what MeshAgent APIs the service has permission to use
  • a secret gives the service an external credential it can use securely

How a room service reads a secret

Service and ServiceTemplate environment entries support three different sources:
  • value: for a plain literal string
  • token: for a MeshAgent participant token
  • secret: for a room secret reference
A secret: entry looks like this:
yaml
environment:
  - name: SERVICE_API_TOKEN
    secret:
      identity: support-agent
      id: service-api-token
At runtime, MeshAgent resolves the room secret for that identity and id, then injects the secret value into the named environment variable.

Room secret workflow for a room service

Step 1: Store the room secret

Create a room secret for the service identity that should read it:
bash
meshagent room secret set \
  --room myroom \
  --id service-api-token \
  --name service-api-token \
  --for-identity support-agent \
  --text "replace-me"
This stores the secret for the support-agent identity, not for your own identity.

Step 2: Reference the room secret in a service

Create a file named room-secret-demo.yaml:
version: v1
kind: Service
metadata:
  name: support-agent
  description: "Room-scoped support agent backed by meshagent process"
  annotations:
    meshagent.service.id: support-agent
agents:
  - name: support-agent
    description: "A support agent that uses a room-scoped token"
    annotations:
      meshagent.agent.type: ChatBot
      meshagent.chatbot.threading: default-new
      meshagent.chatbot.thread-list: .threads/support-agent/index.threadl
container:
  image: us-central1-docker.pkg.dev/meshagent-public/images/cli:{SERVER_VERSION}-esgz
  command: /bin/bash /var/start.sh
  environment:
    - name: MESHAGENT_TOKEN
      token:
        identity: support-agent
    - name: SERVICE_API_TOKEN
      secret:
        identity: support-agent
        id: service-api-token
  storage:
    room:
      - path: /data
        read_only: false
    files:
      - path: /var/start.sh
        text: |
          #!/bin/bash
          set -e

          if [ -z "${SERVICE_API_TOKEN:-}" ]; then
            echo "SERVICE_API_TOKEN is required for support-agent" >&2
            exit 1
          fi

          exec /usr/bin/meshagent process join \
            --agent-name=support-agent \
            --channel=chat \
            --threading-mode=default-new \
            --thread-dir=".threads/support-agent" \
            --model=gpt-5.4 \
            --require-storage \
            --rule="You are a support agent. Help users with support workflows and never reveal credentials or secret values."

Step 3: Deploy the room service

bash
meshagent service create --file room-secret-demo.yaml --room myroom
This example shows the actual room-secret wiring for a MeshAgent agent service. MeshAgent injects the stored room secret into the SERVICE_API_TOKEN environment variable for the support-agent identity, and the startup script checks that the variable is present before starting meshagent process join. The example is only showing how the secret reaches the agent. Any third-party integration that uses that token is a separate step.
ServiceTemplate is the secure install-time input pattern for cases where each installer should provide their own secret.It does not create a new secret type. Instead:
  • the template variable is the input field shown to the installer
  • Powerboards stores that value as a room secret
  • the service reads the stored room secret later with secret:
If you are packaging a service in Powerboards and want each installer to bring their own secret, the usual pattern is:
  1. Add a ServiceTemplate variable so the installer can paste the value.
  2. Mark that variable with meshagent.secret.* annotations so Powerboards stores the value as a room secret.
  3. Have the service read the stored room secret with secret:.
Example:
version: v1
kind: ServiceTemplate
metadata:
  name: support-agent
  description: "Agent template that asks the installer for a sensitive token"
  annotations:
    meshagent.service.id: support-agent
agents:
  - name: support-agent
    description: "A support agent installed with an installer-provided token"
    annotations:
      meshagent.agent.type: ChatBot
      meshagent.chatbot.threading: default-new
      meshagent.chatbot.thread-list: .threads/support-agent/index.threadl
variables:
  - name: service_api_token
    description: "Sensitive token provided by the installer"
    obscure: true
    annotations:
      meshagent.secret.id: service-api-token
      meshagent.secret.identity: support-agent
      meshagent.secret.name: service-api-token
      meshagent.secret.type: text/plain
container:
  image: us-central1-docker.pkg.dev/meshagent-public/images/cli:{SERVER_VERSION}-esgz
  command: /bin/bash /var/start.sh
  environment:
    - name: MESHAGENT_TOKEN
      token:
        identity: support-agent
    - name: SERVICE_API_TOKEN
      secret:
        identity: support-agent
        id: service-api-token
  storage:
    room:
      - path: /data
        read_only: false
    files:
      - path: /var/start.sh
        text: |
          #!/bin/bash
          set -e

          if [ -z "${SERVICE_API_TOKEN:-}" ]; then
            echo "SERVICE_API_TOKEN is required for support-agent" >&2
            exit 1
          fi

          exec /usr/bin/meshagent process join \
            --agent-name=support-agent \
            --channel=chat \
            --threading-mode=default-new \
            --thread-dir=".threads/support-agent" \
            --model=gpt-5.4 \
            --require-storage \
            --rule="You are a support agent. Help users with support workflows and never reveal credentials or secret values."

In Powerboards, this works like this:
  • the installer sees a service_api_token input field
  • Powerboards stores that value as a room secret owned by support-agent
  • the service reads that stored room secret at runtime through secret:
For a real GitHub agent, that installer-provided token could be a GitHub personal access token. The important point here is the secure input and injection flow, not the provider-specific logic.Important: meshagent service create-template does not automatically create room secrets from these annotations. Those annotations are for Powerboards and similar installers. If you are deploying from the CLI, create the room secret yourself with meshagent room secret set.

How secret delegation and identity scoping work

Room secrets are scoped by participant identity, and some flows also include a delegated_to value. Important implications:
  • If you create a secret with --for-identity support-agent, that secret belongs to support-agent.
  • Listing secrets as yourself will not show secrets that belong to another identity.
  • Delegated secrets may require --delegated-to when reading or deleting them.
  • Admin-only flows can store secrets on behalf of another identity with for_identity.
This separation is what allows one room to contain multiple agents and toolkits without all of them sharing the same secret namespace.

Advanced room-secret capabilities

Beyond basic set/get/list/delete, the Secrets API also supports:
  • request_secret
  • provide_secret
  • delete_requested_secret
  • request_oauth_token
  • provide_oauth_authorization
  • get_offline_oauth_token
  • delegated_to
  • for_identity
These are the building blocks for secret exchange, delegated access, and OAuth flows between participants. Keep the basic room-secret mental model separate from these advanced flows. If you need outbound header resolution for an MCP connection, meshagent mcp http --header-secret ... can resolve a room secret into an HTTP header. For a full example, see Supabase MCP. If you need OAuth token request, storage, refresh, or offline access, see OAuth with Room Secrets.