Actions

Actions are the executable units of a Polycrate block: action schema, playbook vs. script, prompts, interactive mode, labels, action config, runtime overrides with --set and data persistence.

Actions

Actions are the executable units of a block. They define what a block can actually do – e.g. install, uninstall, status or backup.

Action schema

An action is defined in block.poly under the actions: list:

# block.poly
actions:
  - name: install              # Required: unique name
    description: "Installs the application"  # Optional: description
    playbook: install.yml           # Either playbook OR script
    # script:                  # Alternative to playbook
    #   - echo "Hello"
    prompt:                    # Optional: user confirmation
      message: "Do you want to start the installation?"
    interactive: false         # Optional: TTY mode
    labels:                    # Optional: metadata
      category: deployment
      risk: low
    config:                    # Optional: action-specific config
      timeout: 300

Fields in detail

Field Type Required Description
name string ✅ Unique identifier; the CLI validates action names as a slug (see Naming conventions)
description string ❌ Human-readable description of the action
playbook string ⚠️ Path to the Ansible playbook (relative to block.poly)
script list ⚠️ List of shell commands
prompt object ❌ User confirmation before execution
interactive bool ❌ TTY mode for interactive commands (default: false)
labels map ❌ Key-value pairs for metadata
config map ❌ Action-specific configuration

⚠️ = playbook and script are mutually exclusive. One of the two is required.

Playbook vs. script

Playbook (recommended)

Ansible playbooks offer the best integration with Polycrate:

actions:
  - name: install
    playbook: install.yml

Advantages:

  • Access to the workspace, block, action variables via Jinja2
  • Idempotent execution
  • Structured error handling
  • Extensive modules for cloud, K8s, etc.

→ Ansible integration

Script (not recommended)

For trivial commands without variable access:

actions:
  - name: status
    script:
      - kubectl get pods
      - echo "Status check complete"

Limitations:

  • No structured error handling
  • No idempotent execution
  • Only suitable for commands without configuration dependencies

Prompt (user confirmation)

Actions can request a confirmation from the user:

actions:
  - name: destroy
    playbook: destroy.yml
    prompt:
      message: "⚠️ This action irrevocably deletes all resources. Continue?"

Behavior:

  • Polycrate shows the message and waits for y/n
  • On n the action is aborted
  • On y the action is executed

Skipping the prompt

# Auto-confirm a single action
polycrate run my-block destroy --force

# Globally for all actions
polycrate --force run my-block destroy

Interactive mode

For actions that need TTY interaction (e.g. password input, vim):

actions:
  - name: shell
    interactive: true
    playbook: shell.yml
actions:
  - name: edit-config
    interactive: true
    playbook: edit-config.yml

Use cases:

  • Debug shells
  • Interactive editors
  • Password prompts in playbooks

Labels

Metadata for categorization and filtering:

actions:
  - name: backup
    labels:
      category: maintenance
      risk: low
      duration: long
    playbook: backup.yml

  - name: destroy
    labels:
      category: cleanup
      risk: high
      requires-confirmation: "true"
    playbook: destroy.yml

Labels can be used in workflows or external tools for filtering.

Action-specific config

Actions can have their own configuration parameters:

actions:
  - name: backup
    config:
      retention_days: 30
      compress: true
    playbook: backup.yml

Available in the playbook as {{ action.config.retention_days }}.

Complete example

# blocks/my-app/block.poly
name: my-app
kind: k8sapp
version: 1.0.0

config:
  namespace: production
  replicas: 3

actions:
  - name: install
    description: "Installs the application in the Kubernetes cluster"
    playbook: install.yml
    labels:
      category: deployment

  - name: uninstall
    description: "Removes the application from the cluster"
    playbook: uninstall.yml
    prompt:
      message: "Do you really want to uninstall the application?"
    labels:
      category: cleanup
      risk: medium

  - name: status
    description: "Shows the current status of the application"
    playbook: status.yml

  - name: shell
    description: "Opens a shell in the first pod"
    interactive: true
    playbook: shell.yml

  - name: logs
    description: "Shows the application logs"
    config:
      tail: 100
      follow: false
    playbook: logs.yml

Running actions

# Default
polycrate run my-block install

# With workspace path
polycrate run my-block install -w /path/to/workspace

# With force (skips prompts)
polycrate run my-block destroy --force

# With increased log level
polycrate run my-block install --loglevel 2

# Interactive
polycrate run my-block shell

Runtime config overrides (--set)

The --set flag lets you override action.config values at runtime without changing workspace.poly or block.poly. The syntax follows the Helm standard.

# Simple value
polycrate run my-block migrate --set database.host=prod-db.internal

# Multiple overrides
polycrate run my-block deploy \
  --set replicas=5 \
  --set namespace=production \
  --set image.tag=v2.1.0

# Array values
polycrate run my-block backup \
  --set targets[0]=cluster-a \
  --set targets[1]=cluster-b

Priority (from low to high)

  1. block.poly – defaults in the block definition
  2. workspace.poly – partial overrides in the workspace
  3. --set flag – runtime overrides at execution (highest priority)

Notes

  • All values are strings (as with Helm): --set replicas=3 → "3" in the playbook. Type conversion in Ansible via | int, | bool etc.
  • Maps are deep-merged: --set db.host=x overrides only db.host; other keys under db are preserved.
  • Lists are replaced completely: --set items[0]=x replaces the whole list with ["x"].
  • Escape dots in keys: --set 'key\.name=value'
  • --set writes exclusively to action.config – block.config is not affected.
# Playbook access
- name: Deploy
  ansible.builtin.debug:
    msg: "Host: {{ action.config.database.host }}, Replicas: {{ action.config.replicas | int }}"

Naming rules

In the CLI, action names follow the slug pattern (lowercase letters, digits, single hyphens). Details, regex and examples: Naming conventions – slug.

Data persistence

Data is not automatically persisted between action runs, except for:

  1. Workspace directory: changes in /workspace (mounted)
  2. Artifacts: the recommended way for persistent data
# Example: store data as an artifact
# block.artifacts.path automatically selects local_path or container_path (depending on --local / container)
- name: Generate state in Ansible
  copy:
    content: "{{ state_data | to_nice_yaml }}"
    dest: "{{ block.artifacts.path }}/state.yml"

Relation to other concepts