Skip to Content
Next — You're reading the unreleased preview docs. APIs and pages may change before the next release.Switch to the current docs →
How-To GuidesMoonBitAdding Secrets to a MoonBit Agent

Adding Secrets to a MoonBit Agent

Overview

Secrets are sensitive configuration values (API keys, passwords, tokens) stored per-environment and accessed at runtime via @config.Secret[T] from the Golem MoonBit SDK. Unlike regular config fields, the config value carries an opaque secret handle and plaintext is revealed only when agent code calls .get(). Manage secrets via the CLI. Use secretDefaults in golem.yaml only for development placeholders; never commit real credentials.

Declaring Secrets in a Config Struct

Use @config.Secret[T] for secret fields inside a #derive.config struct:

#derive.config pub(all) struct MyAgentConfig { name : String api_key : @config.Secret[String] db : DbConfig } #derive.config pub(all) struct DbConfig { host : String port : UInt password : @config.Secret[String] }

Wiring Secrets Into The Agent Constructor

Secrets use the same typed config mechanism as regular agent config. Receive the config via @config.Config[T] in the constructor:

#derive.config pub(all) struct MyAgentConfig { api_key : @config.Secret[String] } #derive.agent struct MyAgent { config : @config.Config[MyAgentConfig] } fn MyAgent::new(config : @config.Config[MyAgentConfig]) -> MyAgent { { config, } } pub fn MyAgent::connect(self : Self) -> String raise @common.AgentError { let _api_key = self.config.value.api_key.get() // Pass the credential only to the private provider adapter, never to a response or log. "Credential available" }
  • The @config.Config[T] parameter in the constructor is detected automatically by the SDK tooling to embed config and secret declarations into the component metadata.

Reading Secrets at Runtime

Call .get() on a Secret[T] to explicitly reveal the value. It raises @common.AgentError; declare that error on synchronous callers or catch it. Import "golemcloud/golem_sdk/interface/golem/agent/common" @common and "golemcloud/golem_sdk/config" @config in moon.pkg. Secrets are lazily loaded, so a fresh .get() call can observe updated values after the update is visible:

pub fn MyAgent::connect(self : Self) -> String raise @common.AgentError { let config = self.config.value let _api_key = config.api_key.get() let _db_password = config.db.password.get() "Credentials available" }

Managing Secrets via CLI

Secrets are environment-scoped — each deployment environment has its own set of secret values.

# Create secrets in the current environment golem secret create apiKey --type String --value "sk-abc123" golem secret create db.password --type String --value "s3cret" # Without a value option the value is prompted for (hidden input); or pipe it in printenv DB_PASSWORD | golem secret create db.password --type String --value-stdin # Create, or update the value if the secret already exists golem secret create apiKey --type String --value "sk-abc123" --update-existing # List all secrets golem secret list # Update a secret value golem secret update apiKey --value "new-value" # Remove a secret value golem secret update apiKey --unset # Delete a secret (asks for confirmation; --yes skips it) golem secret delete apiKey

Note: For update and delete, you can also use --id <uuid> instead of the positional path.

Secret Defaults in golem.yaml

For local development convenience, set placeholder defaults under secretDefaults.<environment>. The CLI selects defaults by environment name, with no production exclusion. Keep defaults development-only and never commit real credentials. Use the CLI for production secret values:

secretDefaults: local: apiKey: "dev-key-123" db: password: "dev-password"

Key Points

  • Secrets use the same @config.Config[T] constructor injection mechanism as regular typed config
  • If the agent also needs non-secret typed config guidance, use golem-add-config-moonbit alongside this guide
  • Secret paths are normalized to camelCase by the platform — MoonBit snake_case field names like api_key become apiKey in the CLI and manifest (e.g., golem secret create apiKey ...)
  • The --type argument accepts type names using the project’s language syntax (e.g., String, UInt, Bool); if parsing as MoonBit fails, the other supported languages’ type syntax is tried
  • Secrets are stored per-environment, not per-agent-instance
  • Missing required secrets cause agent creation to fail, not deployment
  • Secrets are revealed on .get(), and each reveal pins the resolved secret revision for deterministic retries and replay
  • Fresh .get() calls can observe runtime updates without restarting the agent
  • .get() raises @common.AgentError — declare raise @common.AgentError or catch the error without logging the credential
  • Never edit generated files — golem_reexports.mbt, golem_agents.mbt, and golem_derive.mbt are auto-generated by golem build