Skip to content

Inheritance ​

A pika config file can pull values from elsewhere and merge them into the resolved output that consumers see. The merging happens at read time, so the source is always the live remote value — no caching, no copy-paste.

Sources fall into two categories:

  1. Internal files — another pika config (or a specific variant of it).
  2. External resources — Vault, Kubernetes Secrets, Consul, etcd, AWS Secrets Manager / SSM, GCP Secret Manager, GCP Parameter Manager, Azure Key Vault, or plain HTTP.

External resources are configured once under Settings → External Resources and then referenced by name from any file's inheritance chain.

Inheritance entry shape ​

Each entry on a file is a small JSON object. Pick one of source (internal) or resource (external) per entry:

json
{
  "resource": "my-vault",
  "path": "myapp/database",
  "paths": ["password", "host"],
  "inject": "database.auth"
}
FieldRequiredDescription
source(one of 2)Path to another pika config file. Append @variant to inherit from a specific variant.
resource(one of 2)Name of an external resource defined under Settings. Use this for Vault, Kubernetes, Consul, etc.
pathyes for resourceThe resource-specific path: a Vault secret path, an etcd key, an S3 object key, etc.
pathsnoPick only specific keys out of the loaded data. Supports dot-notation (database.host) and wildcards (logging.*).
injectnoNest the inherited data under this key path in the resolved output (e.g. database.auth). Supports dot-notation.
formatnoWhen the resource returns an opaque string wrapped as {"value": "..."} (Consul / etcd / GCP / HTTP), set json, yaml, or toml to decode the inner payload before merge. Ignored for source entries — internal files carry their own meta.format.

You manage inheritance entries from the Inherits section of a file in the UI. Order matters — later entries override earlier ones, and the file's own content overrides everything.

INFO

The mount field used to point at a raw filesystem mount; that feature was extracted out of pika. Legacy rows with "mount": "..." decode but the field is ignored at resolution time.

External resources ​

Each external resource has a name that you choose. That name is what resource: references. Pika supports the following backends — each has its own page with auth, configuration, and inheritance examples:

Resource permissions ​

Every external resource carries its own permission switches, edited in the same form as its connection settings:

SwitchOff means
Read valuesNo single-entry reads, no version history, and no inheritance — a file that inherits from the resource fails to resolve.
ListThe inventory stays hidden; callers can still work with paths they already know.
Add new entriesWrites to paths that don't exist yet are rejected.
Change existing entriesWrites to paths that already exist are rejected.
DeleteDeletes are rejected.

These are a ceiling, not a grant. A denied operation is refused before pika contacts the backend, for every caller — superadmin sessions, API tokens, MCP clients, and public endpoints alike. User capabilities (external.read / external.write) and token scopes can only narrow it further. A resource with everything switched off is effectively parked: the credentials stay configured, and Test connection still works so you can verify them.

Splitting add from change needs the backend to answer "does this path already exist" before writing. GitLab does; the others do not, so for them set both switches the same way — a mismatched pair rejects every write instead of guessing. The browser hides the actions a resource forbids, so New entry and Edit disappear rather than failing on submit.

Resources saved before these switches existed stay unrestricted.

Examples ​

Pull a database password out of Vault ​

Define an external resource named vault pointing at your Vault server, then on myapp/config add an inheritance entry:

json
{
  "resource": "vault",
  "path": "myapp/db",
  "paths": ["password"],
  "inject": "database.password"
}

If the Vault secret returns { "password": "hunter2", "host": "..." }, the resolved config is merged with { "database": { "password": "hunter2" } }.

Inherit from another pika file ​

A prod variant that starts from the base config and only overrides a few fields:

json
{ "source": "myapp/config" }

Or inherit from a specific variant:

json
{ "source": "myapp/config@staging" }

Decode a string-wrapped Consul value ​

When a Consul KV value contains a JSON document but Consul returned it as a plain string, set format: json so pika decodes the inner payload before merging:

json
{
  "resource": "consul",
  "path": "config/myapp",
  "format": "json",
  "inject": "remote"
}

Combine sources ​

json
[
  { "source":   "shared/common" },
  { "resource": "k8s", "path": "default/secret/myapp", "inject": "secrets" }
]

The base config's hand-edited fields override both inherited sources, so you can drop a single key into the file to change behaviour without touching either source.

Preview before saving ​

The Render panel in the UI shows the fully resolved output of a file with all inheritance applied. Use it to verify the chain produces the expected merged document before consumers fetch it.

The same data is available programmatically via:

sh
curl -X POST -H "Authorization: Bearer $TOKEN" \
  https://localhost:8080/api/v1/render/myapp/config

Released under the MIT License.