Actions Developer Guide
Declarative Module Actions (The “Act” Phase)
The Actions engine in rescile provides a standardized, secure execution environment for infrastructure changes and business logic. Actions natively expose Write/Execute APIs to both the Frontend UI and AI Agents via the Model Context Protocol (MCP).
Actions use a trigger-based execution model. Instead of handling raw script files directly, clients interact with standardized Action APIs. The rescile engine manages the action definitions, securely sandboxes the execution, and seamlessly binds contextual data from the graph, such as Vault secrets and generated artifacts.
Directory Structure
Actions are defined within your module’s ecosystem. While models mutate the graph and outputs generate files, actions define executable logic.
Action definitions are placed in the actions/ directory, while the actual execution binaries or scripts live in the runtimes/ directory.
my-module/
├── module.toml
├── models/
├── output/
├── actions/ <-- Declarative action definitions (.toml)
│ ├── remediate.toml
│ └── deploy_aws_hub.toml
└── runtimes/ <-- Executable scripts or binaries (WASM, JS, Py, Nix)
└── flake.nix <-- Reproducible environment definition
Defining an Action
An action TOML file binds a specific runtime to an input schema, a graph context, and secure credentials.
Below is an example of an action that uses the reproducible Nix runtime to execute Python deployment scripts (e.g., AWS Network Hub).
# actions/deploy_aws_hub.toml
name = "deploy_aws_hub"
description = "Orchestrates the deployment of the AWS Zurich Transit VPC and Ingress Filters"
exec = [
["sh", "-c", "if [ '{{ input.dry_run }}' = 'true' ]; then python3 orchestrator.py --dry-run; else python3 orchestrator.py; fi"]
]
[[input]]
name = "dry_run"
description = "Check state and log intended actions without calling AWS"
type = "boolean" # default string
[[input]]
name = "region"
description = "AWS Region"
type = "string"
[[input]]
name = "server_name"
description = "Name of the target server"
type = "string"
resource_link = "server.name" # Optional: UI will render a dropdown fetched from the graph and validation if the resource and property exists in the graph
[runtime]
engine = "nix"
# The path is relative to the `runtimes/` directory of your module.
# Do NOT include "runtimes/" in the path here.
flake = "./flake.nix"
files = ["./orchestrator.py", "./state_manager.py"]
# Mount the expected Python module files from the graph context.
[[mount]]
resource_type = "python_module"
origin_resource = "aws_hub"
filename = "zurich_transit_vpc.py"
# Note: Variables like `origin_resource.name` are NOT available during action bundling.
# Use `{{ input.my_var }}` to dynamically select specific artifacts based on action inputs.
filename = "zurich_transit_vpc_{{ input.region }}.py"
Pluggable, Secure Runtimes
To maintain system security, rescile requires execution isolation using specific runtimes. The engine parameter dictates the isolation boundary:
wasi(WebAssembly): Modules compile logic to.wasm. Executed usingwasmtimewith zero external dependencies, providing strong isolation and high performance.nix(Nix Flakes): Spawns an execution boundary wrapped in anix developshell for highly reproducible environments without polluting the host OS or requiring pre-installed tooling.container(Docker/Podman): Spawns an ephemeral container, mounts required outputs, streams logs, and destroys the container when finished. Ideal for legacy tooling like Terraform or Ansible.http(Webhook): Securely triggers existing CI/CD pipelines (e.g., GitHub Actions) using signed payloads.api(Declarative API Chaining): Executes REST/GraphQL API calls directly from the Rust core. Extremely lightweight for interacting with cloud APIs.
Platform Constraints: Some runtimes depend on the underlying architecture and operating system. The runtime block evaluates declarative platform constraints against the host system, emitting a warning if the action cannot be executed locally.
Execution via rescile-runner
The rescile-runner component is responsible for securely executing the generated action bundles. It is compiled as a standalone binary designed to reduce the blast radius, operating in two modes:
- Oneshot / Ephemeral Mode: Acts as a short-lived executor in target environments (e.g., CI/CD pipelines or Kubernetes Jobs). It fetches the deployment instruction bundle directly from the Controller via a temporary URL, retrieves secrets in-memory, executes the sandbox, and streams logs back before terminating.
- Daemon Mode: Runs continuously as a persistent worker node, securely accepting and processing execution requests.
Intelligent MCP Integration (The AI DevOps Agent)
Because each action block strictly defines an input schema and a description, the Rescile MCP Server automatically parses all loaded actions and exposes them as MCP Tools to Large Language Models (LLMs)
The AI Workflow:
- An LLM uses
listResourcesand identifies a database failing compliance. - The LLM queries the MCP server for available tools.
- The MCP Server dynamically presents available actions (e.g.,
terraform_apply) along with their required JSON schema. - The LLM constructs a JSON payload (e.g.,
{ "application_name": "db-main" }) and calls the tool. - Rescile securely bundles the instruction, executes the action via
rescile-runner, and streams the aggregated execution logs back to the LLM.
Automated API & UI Triggering
When Rescile loads a module, it dynamically generates REST endpoints for each action:
POST /api/actions/:module_name/:action_name
The Rescile core automatically validates incoming JSON payloads against the defined input_schema.
Frontend Integration: The Managed Services Portal UI (or any custom app) can trigger actions simply by making a POST request to the endpoint with the necessary context JSON. Execution streams stdout and stderr directly to a dedicated Server-Sent Events (SSE) endpoint (/api/actions/stream/:execution_id), enabling real-time observability in the browser.