Configuration
All configuration options in Polycrate: restrictions on template substitution, workspace.poly structure and keys, block instances, secrets.poly, YAML anchors, container configuration and the global CLI configuration in ~/.polycrate/polycrate.yml.
Configuration
This page documents all configuration options in Polycrate – from workspace settings to block instances.
Important restrictions
What does NOT work
# ❌ WRONG: Jinja2 syntax does NOT work
blocks:
- name: cert-manager
from: cargo.ayedo.cloud/ayedo/k8s/cert-manager:0.4.0
config:
letsencrypt:
cloudflare:
api_token: "{{ secrets.cloudflare_api_token }}" # ❌ Is NOT substituted!
# ❌ WRONG: Bash variables do NOT work
blocks:
- name: my-app
config:
database_url: "${DATABASE_URL}" # ❌ Is NOT substituted!
home_dir: "$HOME/data" # ❌ Is NOT substituted!
# ❌ WRONG: environment references do NOT work
blocks:
- name: my-app
config:
environment: ${ENV:-production} # ❌ Is NOT substituted!
What works instead
1. Secrets in a separate file (secrets.poly):
# workspace.poly - non-sensitive configuration
blocks:
- name: cert-manager
from: cargo.ayedo.cloud/ayedo/k8s/cert-manager:0.4.0
config:
letsencrypt:
solver:
type: dns01
provider: cloudflare
# secrets.poly - sensitive configuration (gets encrypted)
blocks:
- name: cert-manager
config:
letsencrypt:
cloudflare:
api_token: "actual-secret-token-here" # ✅ Real value
2. Configuration is merged at runtime:
Polycrate merges workspace.poly and secrets.poly automatically at runtime. The values from secrets.poly override/extend the values from workspace.poly.
3. Templates in Ansible playbooks:
Jinja2 templating works in Ansible playbooks and templates, NOT in .poly files:
# deploy.yml - Jinja2 works here!
- name: Deploy with config
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: Secret
metadata:
name: "{{ block.name }}-secrets"
data:
api_token: "{{ block.config.letsencrypt.cloudflare.api_token | b64encode }}"
{# templates/config.yml.j2 - Jinja2 works here! #}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ block.name }}-config
data:
environment: {{ block.config.environment }}
Why this restriction?
- Security: no unintended code execution in configuration files
- Predictability: configuration is deterministic and reviewable
- Simplicity: YAML parsing without an additional template engine
- Separation of concerns: configuration (
.poly) vs. logic (Ansible/playbooks)
→ Secrets management | Ansible integration
Workspace configuration (workspace.poly)
The workspace configuration (default: workspace.poly) contains the settings for a workspace and must be located in the root directory of the workspace.
Custom configuration file
You can specify a custom configuration file for the workspace:
polycrate run my-block install --workspace-config path/to/workspace-config.yml
This can be particularly helpful when using Polycrate in CI/CD pipelines.
Complete workspace.poly structure
workspace.config is not an arbitrary key-value mapping: when the workspace is loaded, it is converted into the typed structure WorkspaceConfig (Polycrate CLI). Only the YAML keys listed below are allowed (in the file without underscores, e.g. blocksroot, artifactsroot). Additional keys under config: are not carried over when reading into this struct (e.g. no free environment: at workspace level – environment/app values belong in blocks[].config or in playbooks).
Under config: there is additionally the optional section release (same indentation as image, blocksroot, …). It is read by polycrate release finalize from the raw workspace.poly and is not part of WorkspaceConfig, but it drives release automation. → Release lifecycle, CLI reference: polycrate release
# workspace.poly (excerpt)
name: my-workspace
organization: my-org
version: 1.0.0
config:
image:
reference: cargo.ayedo.cloud/library/polycrate
version: "0.31.0"
blocksroot: blocks
logsroot: .logs
blocksconfig: block.poly
workspaceconfig: workspace.poly
workflowsroot: workflows
artifactsroot: artifacts
secretsroot: artifacts/secrets
containerroot: /workspace
sshprivatekey: artifacts/secrets/id_rsa
sshpublickey: artifacts/secrets/id_rsa.pub
sshkeysource: workspace
remoteroot: /polycrate
dockerfile: Dockerfile.poly
# Optional: global key-value map (advanced)
globals: {}
# Optional: pre/post actions for `polycrate release finalize` (not WorkspaceConfig fields)
release:
post_actions:
- block: app
action: deploy
blocks:
- name: my-app
from: cargo.ayedo.cloud/ayedo/k8s/my-app:1.0.0
config:
replicas: 3
workflows:
- name: deploy-all
steps:
- name: deploy-app
block: my-app
action: install
workspace.config keys (reference)
| YAML key | Content | Short description |
|---|---|---|
image |
reference, version |
Container base image for action runs |
blocksroot |
string | Directory for block instances (e.g. blocks) |
logsroot |
string | Directory for logs (e.g. .logs) |
blocksconfig |
string | File name of the block catalogue file (usually block.poly) |
workspaceconfig |
string | File name of this workspace file (usually workspace.poly) |
workflowsroot |
string | Directory for workflow definitions |
artifactsroot |
string | Artifact directory (e.g. artifacts) |
secretsroot |
string | Directory for secrets (default artifacts/secrets) |
containerroot |
string | Workspace root inside the container (default /workspace) |
sshprivatekey / sshpublickey |
string | Paths to SSH keys (context-dependent local vs. container) |
sshkeysource |
string | workspace or user |
sshusepassphrase |
bool | Passphrase for SSH keys |
remoteroot |
string | Default path for remote/special scenarios (default /polycrate) |
dockerfile |
string | File name of the custom Dockerfile (usually Dockerfile.poly) |
globals |
map | Optional global key-value map |
Workspace fields
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | ✅ | Unique workspace name |
organization |
string | ❌ | Organization/team |
version |
string | ❌ | Workspace version (e.g. for releases) |
config |
map | ❌ | Workspace-wide configuration (WorkspaceConfig + optional release) |
blocks |
list | ❌ | Block instances |
workflows |
list | ❌ | Workflow definitions |
Naming rules
Valid names for workspace, organization, blocks, actions and workflows are described centrally:
Block configuration (workspace.poly)
Blocks are instantiated in workspace.poly. Each block instance references a template block via from:.
Block from a registry
blocks:
- name: kubernetes-cluster
from: cargo.ayedo.cloud/ayedo/k8s/cluster:1.2.3
config:
node_count: 3
region: eu-central-1
Local template block
blocks:
- name: my-app
from: my-app-template # Block in blocks/my-app-template/
config:
port: 8080
Block with kubeconfig reference (legacy)
blocks:
- name: k8s
from: cargo.ayedo.cloud/ayedo/k8s/cluster:1.0.0
- name: my-app
from: cargo.ayedo.cloud/ayedo/k8s/my-app:1.0.0
kubeconfig:
from: k8s # Legacy: kubeconfig artifact from the k8s block
config:
namespace: production
Block instances and inventory
The Ansible inventory lives as inventory.yml in the workspace root and applies to all blocks of this workspace.
blocks:
- name: infrastructure
from: cargo.ayedo.cloud/ayedo/infra/servers:1.0.0
- name: my-service
from: cargo.ayedo.cloud/ayedo/services/my-service:1.0.0
Block instance fields
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | ✅ | Unique instance name in the workspace |
from |
string | ❌ | Template block (registry or local) |
config |
map | ❌ | Block-specific configuration |
kubeconfig.from |
string | ❌ | Legacy: reference to another block instance for the kubeconfig artifact. Best practice: one file artifacts/secrets/kubeconfig.yml without from. |
inventory.from |
string | ❌ | Legacy: reference to another block instance for the inventory artifact. Best practice: central inventory.yml in the workspace root without from. |
Secrets configuration (secrets.poly)
Sensitive configuration belongs in secrets.poly (same format as workspace.poly):
# secrets.poly
blocks:
- name: my-app
config:
database_password: secret
api_key: abc123
- name: cert-manager
config:
letsencrypt:
cloudflare:
api_token: "cloudflare-api-token-here"
After encryption, secrets.poly.age is created:
polycrate workspace encrypt
YAML anchors for reusable values
Recommended: set identical values literally multiple times
name: acme-production-1
organization: acme
blocks:
- name: keycloak
from: cargo.ayedo.cloud/ayedo/k8s/keycloak:0.4.1
config:
ingress:
host: https://id.acme-corp.com
class: nginx
tls:
issuer: letsencrypt-production
- name: mattermost
from: cargo.ayedo.cloud/ayedo/k8s/mattermost:0.1.0
config:
s3:
endpoint: https://s3.loopback.ayedo.cloud
ingress:
class: nginx
Basic principle of YAML anchors (language reference)
# Define an anchor with &name
my-value: &my-anchor "reusable-value"
# Use the anchor with *name
other-key: *my-anchor # → "reusable-value"
Example with anchors (only if you use them deliberately)
The following pattern works for pure parsing; after a write operation by Polycrate it may be written back in resolved form:
domain: &domain acme-corp.com
s3_endpoint: &s3_endpoint https://s3.loopback.ayedo.cloud
keycloak_base_url: &keycloak_base_url https://id.acme-corp.com
ingress_class: &ingress_class nginx
letsencrypt_issuer: &letsencrypt_issuer letsencrypt-production
name: acme-production-1
organization: acme
blocks:
- name: keycloak
from: cargo.ayedo.cloud/ayedo/k8s/keycloak:0.4.1
config:
ingress:
host: *keycloak_base_url
class: *ingress_class
tls:
issuer: *letsencrypt_issuer
- name: mattermost
from: cargo.ayedo.cloud/ayedo/k8s/mattermost:0.1.0
config:
s3:
endpoint: *s3_endpoint
ingress:
class: *ingress_class
Common anchor names (reference only)
| Anchor | Typical value | Typical use |
|---|---|---|
&domain |
example.com |
Base domain for all services |
&s3_endpoint |
https://s3.provider.com |
S3-compatible storage |
&keycloak_base_url |
https://id.example.com |
SSO provider URL |
&letsencrypt_issuer |
letsencrypt-production |
cert-manager issuer |
&ingress_class |
nginx |
Ingress controller class |
Further restrictions
- No sharing with
secrets.poly– YAML anchors are only valid within one file; they cannot be used betweenworkspace.polyandsecrets.poly. - Manual anchor definition – if you use anchors anyway, define them before the
blocks:section so the file stays readable for humans (the structure can still be changed by a Polycrate write operation).
→ Best practices · Production example (historically with anchors)
Container configuration
The Polycrate image can be customized per workspace.
→ The Polycrate container (concept, lifecycle, tooling in the container) · Dockerfile.poly (custom image, config.dockerfile, build with --build)
Pinning the image version
# workspace.poly
config:
image:
reference: cargo.ayedo.cloud/library/polycrate
version: "0.51.3" # Specific version instead of :latest
Custom Dockerfile
In detail: Dockerfile.poly (path config.dockerfile, FROM convention, build).
For additional tools, create a Dockerfile.poly:
# Dockerfile.poly
FROM cargo.ayedo.cloud/library/polycrate:latest
# Install additional tools (Ubuntu-based!)
RUN apt-get update && apt-get install -y --no-install-recommends \
postgresql-client \
redis-tools \
&& rm -rf /var/lib/apt/lists/*
# Build and use the image
polycrate run my-block install --build
Persistent system and community packages (apt)
Everything you write into the image via RUN apt-get install … is permanently available in every Polycrate container of this workspace – e.g. helper programs that your playbooks or roles expect (jq, additional Python modules via python3-pip, database clients):
RUN apt-get update && apt-get install -y --no-install-recommends \
jq \
python3-pip \
&& rm -rf /var/lib/apt/lists/*
Ansible Galaxy: installing collections and roles permanently
ansible-galaxy is included in the Polycrate image. Install collections and roles in the build of the custom image so that they do not have to be downloaded again for every action and are available identically everywhere (default paths under /root/.ansible/ or configurable via ansible.cfg in the workspace).
Single collection and role:
RUN ansible-galaxy collection install community.general && \
ansible-galaxy role install geerlingguy.nginx
Via requirements.yml (recommended for multiple entries):
Place e.g. ansible-galaxy-requirements.yml in the workspace and reference it in the Dockerfile:
# ansible-galaxy-requirements.yml (example)
---
collections:
- name: community.general
roles:
- name: geerlingguy.nginx
COPY ansible-galaxy-requirements.yml /tmp/ansible-galaxy-requirements.yml
RUN ansible-galaxy install -r /tmp/ansible-galaxy-requirements.yml
Note: COPY refers to the build context (workspace root during the image build). Paths to roles/collections in playbooks (roles: / collections:) must match the installed names – as with a normal Ansible project.
CLI configuration (~/.polycrate/polycrate.yml)
Global CLI settings are configured in ~/.polycrate/polycrate.yml:
# ~/.polycrate/polycrate.yml
api:
enabled: true
url: https://hub.polycrate.io
api_key: <your-api-key>
hub:
url: https://hub.polycrate.io
docs_url: https://docs.ayedo.de
Update and verification checks
After every action or workflow run the CLI optionally performs several checks. All checks are enabled by default and can be disabled globally in polycrate.yml or per invocation via a flag.
| Key | Flag | Default | Description |
|---|---|---|---|
check_updates |
--check-updates |
true |
Checks whether a newer version of the Polycrate CLI is available on the hub. |
check_block_updates |
--check-block-updates |
true |
Checks after an action run whether a newer version of the executed block is available on the hub. |
check_workspace_behind_remote |
--check-workspace-behind-remote |
true |
Warns before the run if the workspace Git state is behind the remote. |
check_maintenance_window |
--check-maintenance-window |
true |
Checks before the run whether the workspace is within the configured maintenance window. |
sync_loopback_kubeconfig |
--sync-loopback-kubeconfig |
true |
Historical name: reconcile the workspace-local kubeconfig with the API credential before the run (the implementation matches kind=loopback). General sync: polycrate k8s sync-kubeconfigs. |
All checks run non-blocking: errors or an available update do not abort the running command. In CI environments and non-interactive sessions the update checks are skipped automatically.
Global configuration (permanent):
# ~/.polycrate/polycrate.yml
check_updates: true
check_block_updates: true
check_workspace_behind_remote: true
check_maintenance_window: true
sync_loopback_kubeconfig: true
The pre-run reconciliation only applies to a workspace-local kubeconfig (e.g. artifacts/secrets/kubeconfig.yml) — not when falling back to ~/.kube/config. → Kubeconfig synchronization.
Disable per invocation:
# Skip the block update check for this run
polycrate run my-block install --check-block-updates=false
# Skip the workspace stale check and maintenance window
polycrate run my-block install \
--check-workspace-behind-remote=false \
--check-maintenance-window=false
# Skip the pre-run kubeconfig reconciliation
polycrate run my-block install --sync-loopback-kubeconfig=false
Runtime directory (CLI flag)
The global flag --runtime-dir is not part of polycrate.yml; it is set on the command line. It determines where Polycrate stores temporary files per transaction (default: ~/.polycrate/run). Together with --config-dir you can, in restricted environments (sandboxes, CI, remote editors), point both the configuration base and the runtime storage at writable paths without extending HOME.
→ In detail: CLI reference — runtime directory
SSH configuration (with sshkeysource: user)
If the workspace uses config.sshkeysource: user, the path to the personal SSH key can be set here:
ssh:
user_key_path: "~/.ssh/work_ed25519" # optional; default: ~/.ssh/id_rsa
user_key_path_by_workspace: # optional; workspace.name → key path
laser24: "~/.ssh/laser_ed25519"
archenemy: "~/.ssh/ayedo_work"
Recommendations (short)
- Explicit block tags (
:1.2.3), full registry paths - Secrets only in
secrets.poly; no templates/env substitution in.poly - Set recurring values literally (YAML anchors see above — not recommended)
- Maintain
CHANGELOG.polyfor workspace and blocks
See also
- Workspaces – workspace structure and organization
- Blocks – block definition and actions
- Naming conventions – regex and valid names
- Dependencies – managing block dependencies
- Inheritance –
from:inheritance; legacy:kubeconfig.from/inventory.from - CLI reference – all available commands