Skip to content

Secret & Environment Management

Scion’s hosted architecture provides a centralized way to manage configuration and sensitive data across your team. Instead of sharing .env files or hardcoding credentials, you can use the Scion Hub to store and inject environment variables and secrets into your agents.

Scion distinguishes between regular environment variables and secure secrets:

Feature Environment Variables (env) Secrets (secret)
Visibility Read/Write (via API and CLI) Write-only (cannot be read back)
Storage Plaintext in database Encrypted at rest / Externally stored
Use Case API URLs, log levels, feature flags API keys, passwords, private keys
Injection Environment variables only Environment, files, or JSON variables

Both variables and secrets can be scoped to different levels. Scion resolves these hierarchically when an agent starts:

  1. User Scope: Personal secrets for a specific user. Applied to all agents owned by that user.
  2. Project Scope: Project-level secrets. Available to all agents running in a specific Project.
  3. Broker Scope: Infrastructure-level secrets. Available only to agents running on a specific Runtime Broker (e.g., for hardware-specific config).

Resolution Priority: When multiple scopes define the same secret key, the more specific scope wins. Broker scope has the highest priority, followed by Project, then User, then Hub. Template env blocks and CLI --env flags are layered on top of resolved secrets.


Both environment variables and secrets support Injection Modes, which control how they are delivered to the agent container:

  • As Needed (Default): The variable or secret is only injected if it is explicitly requested in the agent’s template (scion-agent.yaml) or harness configuration. This is the recommended mode for most credentials to minimize the attack surface.
  • Always: The variable or secret is injected into every agent started within that scope, regardless of whether it is explicitly requested.

You can set the injection mode via the CLI using the --always flag:

Terminal window
# Set a variable to be always injected in a project
scion hub env set --project --always LOG_LEVEL=debug
# Set a secret to be always injected for a user
scion hub secret set --always MY_GLOBAL_TOKEN secret-value

Use the scion hub env command suite to manage non-sensitive configuration.

Terminal window
# Set a user-scoped variable
scion hub env set API_URL=https://api.example.com
# Set a project-scoped variable (inferred from current directory)
scion hub env set --project LOG_LEVEL=debug
# Set a variable only for a specific broker
scion hub env set --broker=my-gpu-node CUDA_VISIBLE_DEVICES=0

Secrets are write-only from host-level CLI commands and the Web Dashboard. Once set, their values cannot be read back by users. However, authorized agents running inside their containers can securely retrieve project-scoped secrets at runtime via the Hub API or the sciontool utility.

Secrets can be set manually via the CLI or Web Dashboard, or gathered interactively during agent creation.

Terminal window
# Set a user-scoped secret
scion hub secret set ANTHROPIC_API_KEY sk-ant-api01-...
# Set a project-scoped secret
scion hub secret set --project DB_PASSWORD my-secure-password

Streamlined Project Secrets via scion secret

Section titled “Streamlined Project Secrets via scion secret”

While scion hub secret manages secrets at any scope (user, project, broker, hub), you can use the streamlined, top-level scion secret command group on your host to manage project-scoped secrets directly within your current project context:

Terminal window
# Set a project-scoped secret (inferred from current directory context)
scion secret set ANTHROPIC_API_KEY sk-ant-api01-...
# List all project secrets (metadata only)
scion secret list
# Get metadata for a specific project secret
scion secret get ANTHROPIC_API_KEY

Interactive Secrets-Gather: If a template requires specific secrets (defined in scion-agent.yaml), Scion utilizes an interactive secrets-gather pipeline during agent creation. It will automatically prompt you to securely input any missing values and store them in the backend, ensuring sensitive credentials are never written to plain text configuration files.

Secrets can be projected into the agent container in three ways:

  1. Environment (Default): Injected as a standard environment variable.
  2. File: Written to a specific path on the agent’s filesystem.
  3. Variable: Added to a JSON file at ~/.scion/secrets.json for programmatic access by the harness.

You can use the @ prefix to read a secret’s value from a local file. This is particularly useful for SSH keys or service account JSONs.

Terminal window
# Upload an SSH private key and mount it to the standard location in the agent
scion hub secret set --type file --target ~/.ssh/id_rsa SSH_KEY @~/.ssh/id_rsa

Scion recognizes certain secret names and uses them for built-in platform features. Using the correct name causes the broker to perform additional setup automatically.

Secret Name Type Target Path Effect
scion-telemetry-gcp-credentials file ~/.scion/telemetry-gcp-credentials.json Sets SCION_OTEL_GCP_CREDENTIALS, auto-enables GCP-native telemetry export, and reads project_id from the file if SCION_GCP_PROJECT_ID is not set.

Example — provisioning GCP telemetry credentials:

Terminal window
scion hub secret set \
--type file \
--target ~/.scion/telemetry-gcp-credentials.json \
scion-telemetry-gcp-credentials @/path/to/sa-key.json

Once set, every agent that starts will have the credential file mounted at ~/.scion/telemetry-gcp-credentials.json and GCP-native telemetry will be enabled automatically — no additional environment variable configuration required. See Metrics & OpenTelemetry for the full setup guide.


While environment and file-based injection deliver secrets at agent startup, Scion also supports dynamic runtime secret retrieval from inside the agent container. This enables harnesses or scripts to request project-scoped secrets programmatically as-needed, reducing initial environment exposure.

This runtime retrieval is accessible either via the sciontool helper utility or directly through the Hub API.

From inside an agent container, use the sciontool secret command suite:

  • List Available Secrets: Lists metadata (keys, types, and injection targets) for all secrets in the agent’s project. Sensitive values are omitted.

    Terminal window
    sciontool secret list

    Output:

    KEY TYPE TARGET
    --- ---- ------
    MY_API_KEY environment MY_API_KEY
    CLAUDE_AUTH file ~/.claude/.credentials.json
  • Retrieve a Secret Value: Decodes and outputs the raw bytes of a specific secret to stdout (ideal for piping or scripting).

    Terminal window
    sciontool secret get MY_API_KEY

    Example script usage:

    Terminal window
    export API_KEY=$(sciontool secret get MY_API_KEY)
  • Set a Project Secret: You can also write/update secrets from inside the container to persist credentials discovered or generated at runtime:

    Terminal window
    sciontool secret set NEW_TOKEN "secret-value"

Under the hood, sciontool interacts with the Hub’s agent-specific secrets API:

  • GET /api/v1/agents/{agentID}/secrets: Lists available secret metadata in the agent’s project.
  • GET /api/v1/agents/{agentID}/secrets/{key}: Retrieves a single secret’s metadata and its base64-encoded value.
  • PUT /api/v1/agents/{agentID}/secrets/{key}: Stores or updates a secret.
  • Authentication: API access is restricted to the running agent container. The agent must include its unique Hub-issued JWT (loaded from SCION_HUB_TOKEN) in the Authorization: Bearer <token> header of every request.
  • Authorization: Agents are strictly bounded to their own project’s secrets. They cannot access secrets in other projects, user-scoped secrets, or global Hub secrets unless explicitly shared via progeny policies (descendant access).
  • Audit Trail: To ensure accountability, every runtime read and write operation is fully audited on the Hub. Successful and failed retrieval attempts log an audit event (agent_secret_read) identifying the calling agent, requested key, and status.

When Scion resolves gh:// URIs in template skill lists, it authenticates with the default GITHUB_TOKEN — typically a GitHub App installation token scoped to the project’s own repository. This works for skills in public repos and the workspace repo itself, but fails with 404 when a gh:// URI references a skill in a different private repository.

To solve this, Scion supports convention-based project secrets that automatically provide the right credential for each gh:// URI based on the GitHub owner and repository name. No template changes are needed — the resolver derives a secret name from the URI and looks it up in your project secrets.

Create a project secret with one of these naming patterns:

Pattern Scope Example
GH_{OWNER}__{REPO} One specific repo GH_ACME_CORP__PRIVATE_SKILLS
GH_{OWNER} All repos under an owner/org GH_ACME_CORP

Normalization rules: uppercase the name, replace hyphens (-) and dots (.) with underscores (_). The double underscore (__) separates owner from repo. Note: Because of this normalization, names that differ only by hyphens, dots, or underscores (e.g., acme-corp and acme_corp) will resolve to the same secret name.

Examples:

GitHub Repository Secret Name
acme-corp/private-skills GH_ACME_CORP__PRIVATE_SKILLS
my-org/my.special.repo GH_MY_ORG__MY_SPECIAL_REPO
All repos under acme-corp GH_ACME_CORP
Terminal window
# Repo-specific credential (fine-grained PAT or classic PAT with repo access)
scion hub secret set --project GH_ACME_CORP__PRIVATE_SKILLS github_pat_...
# Or cover all repos under an owner with one token
scion hub secret set --project GH_ACME_CORP github_pat_...

Once set, template URIs resolve automatically — no ?token= annotation needed:

skills:
- uri: "gh://acme-corp/private-skills/my-skill" # auto-uses GH_ACME_CORP__PRIVATE_SKILLS

An explicit ?token=SECRET_NAME parameter on the URI still works as an override when disambiguation is needed.

When resolving a gh://owner/repo/... URI, Scion checks credentials in this order:

Priority Source Description
1 ?token=SECRET_NAME on the URI Explicit override — bypasses convention lookup
2 GH_{OWNER}__{REPO} Repo-specific convention secret
3 GH_{OWNER} Owner-level convention secret
4 Default GITHUB_TOKEN App token, environment, or provision secret cascade
5 Unauthenticated No credential found; works for public repos only

The first match wins. If no convention secret exists, behavior is identical to the default single-token resolution.

Note: Credentials resolved for private gh:// URIs are preserved end-to-end through the entire download sequence, preventing unauthenticated fallback or 404 errors during multi-file resolution.

Convention-keyed GitHub secrets support the standard injection modes:

  • As Needed (recommended): The credential is used at provision time to fetch skills and templates but is not exposed inside the agent container. This is the minimum-privilege posture.

    Terminal window
    scion hub secret set --project GH_ACME_CORP__PRIVATE_SKILLS github_pat_...
  • Always: The credential is also injected into the agent container as an environment variable (GH_ACME_CORP__PRIVATE_SKILLS). Use this when agents need runtime access to the same private repo.

    Terminal window
    scion hub secret set --project --always GH_ACME_CORP__PRIVATE_SKILLS github_pat_...

For more on injection modes, see Injection Modes above.


To use secrets in production, the Hub must be configured with a production-grade secrets backend.

Scion requires a secrets backend to store secret values. The recommended backend is GCP Secret Manager.

Set the backend in your settings.yaml:

server:
secrets:
backend: gcpsm
gcp_project_id: "my-gcp-project"
gcp_credentials: "/path/to/service-account.json" # Optional if using ADC

Or via environment variables:

Terminal window
export SCION_SERVER_SECRETS_BACKEND=gcpsm
export SCION_SERVER_SECRETS_GCP_PROJECT_ID=my-gcp-project
export SCION_SERVER_SECRETS_GCP_CREDENTIALS=/path/to/service-account.json

When GCP Secret Manager is configured, Scion uses a hybrid storage model:

  • Metadata (name, type, scope) is stored in the Hub database.
  • Secret values are stored in GCP Secret Manager with automatic versioning.

Automatic Plugin Secret Migration & Safety (Hub Integrations)

Section titled “Automatic Plugin Secret Migration & Safety (Hub Integrations)”

For external messaging integrations (such as Discord, Telegram, or Google Chat) that run as Hub-level message broker plugins, Scion implements an automatic, secure secret migration and stripping pipeline to keep sensitive bot tokens and API keys out of plaintext configuration files:

  • Automatic One-Shot Migration: When starting up or activating a plugin (e.g., via the runtime activation path in activateInstalledIntegration), the Hub automatically scans the integration’s configuration—including per-plugin external configuration files and inline config blocks. Any discovered secret keys are automatically migrated into the configured secure Secrets Backend (such as GCP Secret Manager).
  • Copy-Before-Strip Safety: After migrating the secrets, Scion strips the raw values in-place from the integration’s file-based and inline configurations (stripSecretKeysInPlace) using a secure copy-before-strip helper to avoid any risk of partial writes or configuration corruption, while deduplicating warning logs.
  • Boot and Activation Consistency: This migration-and-strip sequence runs consistently during both the Hub’s boot-up routine and dynamic runtime integration activation, ensuring that secrets are never stored or exposed in plaintext configs.

When an agent starts, the Runtime Broker requests a “Resolved Environment” from the Hub. The Hub merges secret values in this order (last one wins for the same key):

  1. Hub Secrets (global defaults)
  2. User Secrets
  3. Project Secrets
  4. Broker Secrets
  5. Template env block
  6. CLI --env flags

Secrets are transmitted over TLS between the Hub and Runtime Brokers. They are only decrypted by the Hub during the dispatch process and sent over an encrypted channel to the Runtime Broker. The Broker then injects them directly into the container’s memory space. Brokers never persist agent secrets to disk.

For a detailed overview of the security architecture, see the Security Architecture Reference.