Go Runtime
Go Runtime
CNOS now ships a first-party Go runtime client in packages/go.
The Go client reads the same runtime bootstrap contracts that the Node runtime already understands:
__CNOS_GRAPH____CNOS_PROJECTION__- explicit
.cnos-server.json - autodiscovered
.cnos-server.jsonnext to.cnosrc.yml
That means a Go service can consume CNOS values and secrets directly without dropping back to cnos build env -> .env.
When no projection is present, the Go runtime now falls back to native authoring-time resolution from .cnos/ or cnos/. That path understands:
.cnosrc.ymlanchor discoverygit+https://...#refandgit+ssh://...#refremote roots.cnos-workspace.yml- workspace inheritance and optional global roots
- profile activation and inheritance
- filesystem values and secrets
- dotenv layers
- process env mappings
- public promotion
- runtime-derived values
- manifest vault mappings for environment and local vault secrets
Build the projection
For deployment or local packaging:
cnos build server --profile prod --to .cnos-server.jsonFor process bootstrap during development:
cnos run -- ./your-go-serviceImport the runtime
Current module path:
import cnos "github.com/kitsyai/cnos/packages/go"Then load the runtime:
runtime, err := cnos.Load(cnos.Options{})if err != nil { panic(err)}Or use the package-level singleton for the closest Node-style runtime flow:
if err := cnos.Ready(); err != nil { panic(err)}
value, ok, err := cnos.Read("value.app.version")if err != nil { panic(err)}_ = value_ = okLoad() checks sources in this order:
ProjectionDatapassed throughLoadProjection- explicit path from
cnos.Options{ProjectionPath: ...} __CNOS_GRAPH____CNOS_PROJECTION__.cnos-server.jsonin the current working directory.cnos-server.jsonbeside a discovered.cnosrc.yml- native authoring-time resolution from
cnos.Options{Root: ...}or a discovered.cnosrc.yml
If the process already has __CNOS_GRAPH__, __CNOS_PROJECTION__, or a nearby .cnos-server.json, the package singleton bootstraps automatically and Ready() is optional.
Read values and secrets
port, _, err := runtime.Value("server.port")if err != nil { panic(err)}
token, _, err := runtime.Secret("app.token")if err != nil { panic(err)}The Go runtime reconstructs the same logical keys used in CNOS:
value.*secret.*public.*meta.profilemeta.workspacemeta.cnos_version
Inspect/provenance is also available directly in Go:
inspect, err := runtime.Inspect("value.app.version")if err != nil { panic(err)}_ = inspectDerived values stay live
Runtime-dependent derived formulas in the server projection are evaluated at read time, not frozen during build.
Example CNOS config:
app: origin: $derive: "https://${value.app.host}:${process.env.PORT}"In Go:
origin, _, err := runtime.Value("app.origin")if err != nil { panic(err)}If PORT changes in the host process, the next read re-evaluates the formula.
Custom runtime namespaces
Custom server-only runtime namespaces work the same way as in Node. Register a provider for any namespace that was declared in the CNOS manifest and carried into the server projection.
host := ""
if err := runtime.RegisterRuntimeProvider("request", func(path string) any { if path == "headers.host" && host != "" { return host } return nil}); err != nil { panic(err)}The built-in process.* namespace covers env.*, cwd, platform, arch, and pid. process.node.version is still Node-only.
Secret hydration
The Go runtime supports built-in secret-ref providers used by server projections:
environmentgithub-secretslocal
Remote providers such as GCP Secret Manager, AWS Secrets Manager, HashiCorp Vault, and Azure Key Vault are compiled into the Go binary by registering provider factories:
runtime, err := cnos.Load(cnos.Options{ SecretVaultProviders: []cnos.SecretVaultProviderFactory{gcpFactory},})The manifest remains the configuration source for which named vault uses which provider. Go does not dynamically load provider packages from .cnos.yml.
For local vaults, the Go client reuses the same CNOS auth conventions:
__CNOS_VAULT_KEY_<VAULT>__~/.cnos/secrets/sessions/<vault>.jsonkeychain:cnos/<vault>CNOS_SECRET_PASSPHRASE_<VAULT>CNOS_SECRET_PASSPHRASE
It also understands the encrypted secret payload generated by:
cnos run --auth -- ./your-go-serviceThat lets a Go process start with already-resolved secret values even when it is not re-authenticating to the local vault itself.
Current limits
The remaining Go-specific gaps are:
- browser/public runtime behavior
Use it as the server-runtime companion to cnos build server, cnos run, local .cnos/ authoring flows, and Git-backed shared config repos.