14 KiB
Pack Structure Documentation
Last Updated: 2024-01-20
Status: Reference Documentation
Overview
Attune packs are bundles of automation components (actions, sensors, triggers, rules, workflows) organized in a standardized directory structure. This document defines the canonical pack structure and file formats.
Pack Directory Structure
packs/<pack_name>/
├── pack.yaml # Pack manifest (required)
├── README.md # Pack documentation (recommended)
├── CHANGELOG.md # Version history (recommended)
├── LICENSE # License file (recommended)
├── requirements.txt # Python dependencies (optional)
├── package.json # Node.js dependencies (optional)
├── actions/ # Action definitions
│ ├── <action_name>.yaml # Action metadata
│ ├── <action_name>.sh # Shell action implementation
│ ├── <action_name>.py # Python action implementation
│ └── <action_name>.js # Node.js action implementation
├── sensors/ # Sensor definitions
│ ├── <sensor_name>.yaml # Sensor metadata
│ ├── <sensor_name>.py # Python sensor implementation
│ └── <sensor_name>.js # Node.js sensor implementation
├── triggers/ # Trigger type definitions
│ └── <trigger_name>.yaml # Trigger metadata
├── rules/ # Rule definitions (optional)
│ └── <rule_name>.yaml # Rule metadata
├── workflows/ # Workflow definitions (optional)
│ └── <workflow_name>.yaml # Workflow metadata
├── policies/ # Policy definitions (optional)
│ └── <policy_name>.yaml # Policy metadata
├── config.schema.yaml # Pack configuration schema (optional)
├── icon.png # Pack icon (optional)
└── tests/ # Tests (optional)
├── test_actions.py
└── test_sensors.py
File Formats
Pack Manifest (pack.yaml)
The pack manifest is the main metadata file for a pack. It defines the pack's identity, version, dependencies, and configuration.
Required Fields:
ref(string): Unique pack reference/identifier (lowercase, alphanumeric, hyphens, underscores)label(string): Human-readable pack namedescription(string): Brief description of the packversion(string): Semantic version (e.g., "1.0.0")
Optional Fields:
author(string): Pack author nameemail(string): Author emailsystem(boolean): Whether this is a system pack (default: false)enabled(boolean): Whether pack is enabled by default (default: true)conf_schema(object): JSON Schema for pack configurationconfig(object): Default pack configurationmeta(object): Additional metadatatags(array): Tags for categorizationruntime_deps(array): Runtime dependencies (e.g., "python3", "nodejs", "shell")
Example:
ref: core
label: "Core Pack"
description: "Built-in core functionality including timer triggers and basic actions"
version: "1.0.0"
author: "Attune Team"
email: "core@attune.io"
system: true
enabled: true
conf_schema:
type: object
properties:
max_action_timeout:
type: integer
description: "Maximum timeout for action execution in seconds"
default: 300
minimum: 1
maximum: 3600
required: []
config:
max_action_timeout: 300
meta:
category: "system"
keywords:
- "core"
- "utilities"
python_dependencies:
- "requests>=2.28.0"
documentation_url: "https://docs.attune.io/packs/core"
repository_url: "https://github.com/attune-io/attune"
tags:
- core
- system
- utilities
runtime_deps:
- shell
- python3
Action Metadata (actions/<action_name>.yaml)
Action metadata files define the parameters, output schema, and execution details for actions.
Required Fields:
name(string): Action name (matches filename)ref(string): Full action reference (e.g., "core.echo")description(string): Action descriptionrunner_type(string): Execution runtime (shell, python, nodejs, docker)entry_point(string): Script filename to execute
Optional Fields:
enabled(boolean): Whether action is enabled (default: true)parameters(object): Parameter definitions (JSON Schema style)output_schema(object): Output schema definitiontags(array): Tags for categorizationtimeout(integer): Default timeout in secondsexamples(array): Usage examples
Example:
name: echo
ref: core.echo
description: "Echo a message to stdout"
enabled: true
runner_type: shell
entry_point: echo.sh
parameters:
message:
type: string
description: "Message to echo"
required: true
default: "Hello, World!"
uppercase:
type: boolean
description: "Convert message to uppercase"
required: false
default: false
output_schema:
type: object
properties:
stdout:
type: string
description: "Standard output from the command"
exit_code:
type: integer
description: "Exit code (0 = success)"
tags:
- utility
- testing
Action Implementation
Action implementations receive parameters as environment variables prefixed with ATTUNE_ACTION_.
Shell Example (actions/echo.sh):
#!/bin/bash
set -e
# Parse parameters from environment variables
MESSAGE="${ATTUNE_ACTION_MESSAGE:-Hello, World!}"
UPPERCASE="${ATTUNE_ACTION_UPPERCASE:-false}"
# Convert to uppercase if requested
if [ "$UPPERCASE" = "true" ]; then
MESSAGE=$(echo "$MESSAGE" | tr '[:lower:]' '[:upper:]')
fi
# Echo the message
echo "$MESSAGE"
# Exit successfully
exit 0
Python Example (actions/http_request.py):
#!/usr/bin/env python3
import json
import os
import sys
def get_env_param(name: str, default=None):
"""Get action parameter from environment variable."""
env_key = f"ATTUNE_ACTION_{name.upper()}"
return os.environ.get(env_key, default)
def main():
url = get_env_param("url", required=True)
method = get_env_param("method", "GET")
# Perform action logic
result = {
"url": url,
"method": method,
"success": True
}
# Output result as JSON
print(json.dumps(result, indent=2))
sys.exit(0)
if __name__ == "__main__":
main()
Sensor Metadata (sensors/<sensor_name>.yaml)
Sensor metadata files define sensors that monitor for events and fire triggers.
Required Fields:
name(string): Sensor nameref(string): Full sensor reference (e.g., "core.interval_timer_sensor")description(string): Sensor descriptionrunner_type(string): Execution runtime (python, nodejs)entry_point(string): Script filename to executetrigger_types(array): List of trigger types this sensor monitors
Optional Fields:
enabled(boolean): Whether sensor is enabled (default: true)parameters(object): Sensor configuration parameterspoll_interval(integer): Poll interval in secondstags(array): Tags for categorizationmeta(object): Additional metadata
Example:
name: interval_timer_sensor
ref: core.interval_timer_sensor
description: "Monitors time and fires interval timer triggers"
enabled: true
runner_type: python
entry_point: interval_timer_sensor.py
trigger_types:
- core.intervaltimer
parameters:
check_interval_seconds:
type: integer
description: "How often to check if triggers should fire"
default: 1
minimum: 1
maximum: 60
poll_interval: 1
tags:
- timer
- system
- builtin
meta:
builtin: true
system: true
Sensor Implementation
Sensors run continuously and emit events to stdout as JSON, one per line.
Python Example (sensors/interval_timer_sensor.py):
#!/usr/bin/env python3
import json
import time
from datetime import datetime
def check_triggers():
"""Check configured triggers and return events to fire."""
# Load trigger instances from environment
# Check if any should fire
# Return list of events
return []
def main():
while True:
events = check_triggers()
# Output events as JSON (one per line)
for event in events:
print(json.dumps(event))
sys.stdout.flush()
# Sleep until next check
time.sleep(1)
if __name__ == "__main__":
main()
Trigger Metadata (triggers/<trigger_name>.yaml)
Trigger metadata files define event types that sensors can fire.
Required Fields:
name(string): Trigger nameref(string): Full trigger reference (e.g., "core.intervaltimer")description(string): Trigger descriptiontype(string): Trigger type (interval, cron, one_shot, webhook, custom)
Optional Fields:
enabled(boolean): Whether trigger is enabled (default: true)parameters_schema(object): Schema for trigger instance configurationpayload_schema(object): Schema for event payloadtags(array): Tags for categorizationexamples(array): Configuration examples
Example:
name: intervaltimer
ref: core.intervaltimer
description: "Fires at regular intervals"
enabled: true
type: interval
parameters_schema:
type: object
properties:
unit:
type: string
enum: [seconds, minutes, hours]
description: "Time unit for the interval"
interval:
type: integer
minimum: 1
description: "Number of time units between triggers"
required: [unit, interval]
payload_schema:
type: object
properties:
type:
type: string
const: interval
interval_seconds:
type: integer
fired_at:
type: string
format: date-time
required: [type, interval_seconds, fired_at]
tags:
- timer
- interval
examples:
- description: "Fire every 10 seconds"
parameters:
unit: "seconds"
interval: 10
Pack Loading Process
When a pack is loaded, Attune performs the following steps:
- Parse Pack Manifest: Read and validate
pack.yaml - Register Pack: Insert pack metadata into database
- Load Actions: Parse all
actions/*.yamlfiles and register actions - Load Sensors: Parse all
sensors/*.yamlfiles and register sensors - Load Triggers: Parse all
triggers/*.yamlfiles and register triggers - Load Rules (optional): Parse all
rules/*.yamlfiles - Load Workflows (optional): Parse all
workflows/*.yamlfiles - Validate Dependencies: Check that all dependencies are available
- Apply Configuration: Apply default configuration from pack manifest
Pack Types
System Packs
System packs are built-in packs that ship with Attune.
system: truein pack manifest- Installed automatically
- Cannot be uninstalled
- Examples:
core,system,utils
Community Packs
Community packs are third-party packs installed from repositories.
system: falsein pack manifest- Installed via CLI or API
- Can be updated and uninstalled
- Examples:
slack,aws,github,datadog
Ad-Hoc Packs
Ad-hoc packs are user-created packs without code-based components.
system: falsein pack manifest- Created via Web UI
- May only contain triggers (no actions/sensors)
- Used for custom webhook integrations
Best Practices
Naming Conventions
- Pack refs: lowercase, alphanumeric, hyphens/underscores (e.g.,
my-pack,aws_ec2) - Component refs:
<pack_ref>.<component_name>(e.g.,core.echo,slack.send_message) - File names: Match component names (e.g.,
echo.yaml,echo.sh)
Versioning
- Use semantic versioning (MAJOR.MINOR.PATCH)
- Update
CHANGELOG.mdwith each release - Increment version in
pack.yamlwhen releasing
Documentation
- Include comprehensive
README.mdwith usage examples - Document all parameters and output schemas
- Provide example configurations
Testing
- Include unit tests in
tests/directory - Test actions/sensors independently
- Validate parameter schemas
Dependencies
- Specify all runtime dependencies in pack manifest
- Pin dependency versions in
requirements.txtorpackage.json - Test with minimum required versions
Security
- Use
secret: truefor sensitive parameters (passwords, tokens, API keys) - Validate all user inputs
- Sanitize command-line arguments to prevent injection
- Use HTTPS for API calls with SSL verification enabled
Example Packs
Minimal Pack
my-pack/
├── pack.yaml
├── README.md
└── actions/
├── hello.yaml
└── hello.sh
Full-Featured Pack
slack-pack/
├── pack.yaml
├── README.md
├── CHANGELOG.md
├── LICENSE
├── requirements.txt
├── icon.png
├── actions/
│ ├── send_message.yaml
│ ├── send_message.py
│ ├── upload_file.yaml
│ └── upload_file.py
├── sensors/
│ ├── message_sensor.yaml
│ └── message_sensor.py
├── triggers/
│ ├── message_received.yaml
│ └── reaction_added.yaml
├── config.schema.yaml
└── tests/
├── test_actions.py
└── test_sensors.py