# Core Pack Actions ## Overview All actions in the core pack are implemented as **pure POSIX shell scripts** with **zero external dependencies** (except `curl` for HTTP actions). This design ensures maximum portability and minimal runtime requirements. **Key Principles:** - **POSIX shell only** - No bash-specific features, works everywhere - **DOTENV parameter format** - Simple key=value format, no JSON parsing needed - **No jq/yq/Python/Node.js** - Core pack depends only on standard POSIX utilities - **Stdin parameter delivery** - Secure, never exposed in process list - **Explicit output formats** - text, json, or yaml ## Parameter Delivery Method **All actions use stdin with DOTENV format:** - Parameters read from **stdin** in `key=value` format - Use `parameter_delivery: stdin` and `parameter_format: dotenv` in YAML - Terminated with `---ATTUNE_PARAMS_END---` delimiter - **DO NOT** use environment variables for parameters **Example DOTENV input:** ``` message="Hello World" seconds=5 enabled=true ---ATTUNE_PARAMS_END--- ``` ## Output Format **All actions must specify an `output_format`:** - `text` - Plain text output (stored as-is, no parsing) - `json` - JSON structured data (parsed into JSONB field) - `yaml` - YAML structured data (parsed into JSONB field) **Output schema:** - Only applicable for `json` and `yaml` formats - Describes the structure of data written to stdout - **Should NOT include** stdout/stderr/exit_code (captured automatically) ## Environment Variables ### Standard Environment Variables (Provided by Worker) The worker automatically provides these environment variables to all action executions: | Variable | Description | Always Present | |----------|-------------|----------------| | `ATTUNE_ACTION` | Action ref (e.g., `core.http_request`) | ✅ Yes | | `ATTUNE_EXEC_ID` | Execution database ID | ✅ Yes | | `ATTUNE_API_TOKEN` | Execution-scoped API token | ✅ Yes | | `ATTUNE_RULE` | Rule ref that triggered execution | ❌ Only if from rule | | `ATTUNE_TRIGGER` | Trigger ref that caused enforcement | ❌ Only if from trigger | **Use cases:** - Logging with execution context - Calling Attune API (using `ATTUNE_API_TOKEN`) - Conditional logic based on rule/trigger - Creating child executions - Accessing secrets via API ### Custom Environment Variables (Optional) Custom environment variables can be set via `execution.env_vars` field for: - **Debug/logging controls** (e.g., `DEBUG=1`, `LOG_LEVEL=debug`) - **Runtime configuration** (e.g., custom paths, feature flags) Environment variables should **NEVER** be used for: - Action parameters (use stdin DOTENV instead) - Secrets or credentials (use `ATTUNE_API_TOKEN` to fetch from key vault) - User-provided data (use stdin parameters) ## Implementation Pattern ### POSIX Shell Actions (Standard Pattern) All core pack actions follow this pattern: ```sh #!/bin/sh # Action Name - Core Pack # Brief description # # This script uses pure POSIX shell without external dependencies like jq. # It reads parameters in DOTENV format from stdin until the delimiter. set -e # Initialize variables with defaults param1="" param2="default_value" # Read DOTENV-formatted parameters from stdin while IFS= read -r line; do case "$line" in *"---ATTUNE_PARAMS_END---"*) break ;; esac [ -z "$line" ] && continue key="${line%%=*}" value="${line#*=}" # Remove quotes if present case "$value" in \"*\") value="${value#\"}"; value="${value%\"}" ;; \'*\') value="${value#\'}"; value="${value%\'}" ;; esac # Process parameters case "$key" in param1) param1="$value" ;; param2) param2="$value" ;; esac done # Validate required parameters if [ -z "$param1" ]; then echo "ERROR: param1 is required" >&2 exit 1 fi # Action logic echo "Processing: $param1" exit 0 ``` ### Boolean Normalization ```sh case "$bool_param" in true|True|TRUE|yes|Yes|YES|1) bool_param="true" ;; *) bool_param="false" ;; esac ``` ### Numeric Validation ```sh case "$number" in ''|*[!0-9]*) echo "ERROR: must be a number" >&2 exit 1 ;; esac ``` ## Core Pack Actions ### Simple Actions 1. **echo.sh** - Outputs a message (reference implementation) 2. **sleep.sh** - Pauses execution for a specified duration 3. **noop.sh** - Does nothing (useful for testing and placeholder workflows) ### HTTP Action 4. **http_request.sh** - Makes HTTP requests with full feature support: - Multiple HTTP methods (GET, POST, PUT, PATCH, DELETE, etc.) - Custom headers and query parameters - Authentication (basic, bearer token) - SSL verification control - Redirect following - JSON output with parsed response ### Pack Management Actions (API Wrappers) These actions wrap Attune API endpoints for pack management: 5. **download_packs.sh** - Downloads packs from git/HTTP/registry 6. **build_pack_envs.sh** - Builds runtime environments for packs 7. **register_packs.sh** - Registers packs in the database 8. **get_pack_dependencies.sh** - Analyzes pack dependencies All API wrappers: - Accept parameters via DOTENV format - Build JSON request bodies manually (no jq) - Make authenticated API calls with curl - Extract response data using simple sed patterns - Return structured JSON output ## Testing Actions Locally Test actions by echoing DOTENV format to stdin: ```bash # Test echo action printf 'message="Hello World"\n---ATTUNE_PARAMS_END---\n' | ./echo.sh # Test with empty parameters printf '---ATTUNE_PARAMS_END---\n' | ./echo.sh # Test sleep action printf 'seconds=2\nmessage="Sleeping..."\n---ATTUNE_PARAMS_END---\n' | ./sleep.sh # Test http_request action printf 'url="https://api.github.com"\nmethod="GET"\n---ATTUNE_PARAMS_END---\n' | ./http_request.sh # Test with file input cat params.dotenv | ./echo.sh ``` ## YAML Configuration Example ```yaml ref: core.example_action label: "Example Action" description: "Example action demonstrating DOTENV format" enabled: true runner_type: shell entry_point: example.sh # IMPORTANT: Use DOTENV format for POSIX shell compatibility parameter_delivery: stdin parameter_format: dotenv # Output format: text, json, or yaml output_format: text parameters: type: object properties: message: type: string description: "Message to output" default: "" count: type: integer description: "Number of times to repeat" default: 1 required: - message ``` ## Dependencies **Core pack has ZERO runtime dependencies:** ✅ **Required (universally available):** - POSIX-compliant shell (`/bin/sh`) - `curl` (for HTTP actions only) - Standard POSIX utilities: `sed`, `mktemp`, `cat`, `printf`, `sleep` ❌ **NOT Required:** - `jq` - Eliminated (was used for JSON parsing) - `yq` - Never used - Python - Not used in core pack actions - Node.js - Not used in core pack actions - bash - Scripts are POSIX-compliant - Any other external tools or libraries This makes the core pack **maximally portable** and suitable for minimal containers (Alpine, distroless, etc.). ## Security Benefits 1. **No process exposure** - Parameters never appear in `ps`, `/proc//environ` 2. **Secure by default** - All actions use stdin, no special configuration needed 3. **Clear separation** - Action parameters vs. environment configuration 4. **Audit friendly** - All sensitive data flows through stdin, not environment 5. **Minimal attack surface** - No external dependencies to exploit ## Best Practices ### Parameters 1. **Always use stdin with DOTENV format** for action parameters 2. **Handle quoted values** - Remove both single and double quotes 3. **Provide sensible defaults** - Use empty string, 0, false as appropriate 4. **Validate required params** - Exit with error if truly required parameters missing 5. **Mark secrets** - Use `secret: true` in YAML for sensitive parameters 6. **Never use env vars for parameters** - Parameters come from stdin only ### Environment Variables 1. **Use standard ATTUNE_* variables** - Worker provides execution context 2. **Access API with ATTUNE_API_TOKEN** - Execution-scoped authentication 3. **Log with context** - Include `ATTUNE_ACTION` and `ATTUNE_EXEC_ID` in logs 4. **Never log ATTUNE_API_TOKEN** - Security sensitive 5. **Use env vars for runtime config only** - Not for user data or parameters ### Output Format 1. **Specify output_format** - Always set to "text", "json", or "yaml" 2. **Use text for simple output** - Messages, logs, unstructured data 3. **Use json for structured data** - API responses, complex results 4. **Define schema for structured output** - Only for json/yaml formats 5. **Use stderr for diagnostics** - Error messages go to stderr, not stdout 6. **Return proper exit codes** - 0 for success, non-zero for failure ### Shell Script Best Practices 1. **Use `#!/bin/sh`** - POSIX shell, not bash 2. **Use `set -e`** - Exit on error 3. **Quote all variables** - `"$var"` not `$var` 4. **Use `case` not `if`** - More portable for pattern matching 5. **Clean up temp files** - Use trap handlers 6. **Avoid bash-isms** - No `[[`, `${var^^}`, `=~`, arrays, etc. ## Execution Metadata (Automatic) The following are **automatically captured** by the worker and should **NOT** be included in output schemas: - `stdout` - Raw standard output (captured as-is) - `stderr` - Standard error output (written to log file) - `exit_code` - Process exit code (0 = success) - `duration_ms` - Execution duration in milliseconds These are execution system concerns, not action output concerns. ## Example: Complete Action ```sh #!/bin/sh # Example Action - Core Pack # Demonstrates DOTENV parameter parsing and environment variable usage # # This script uses pure POSIX shell without external dependencies like jq. set -e # Log execution start echo "[$ATTUNE_ACTION] [Exec: $ATTUNE_EXEC_ID] Starting" >&2 # Initialize variables url="" timeout="30" # Read DOTENV parameters while IFS= read -r line; do case "$line" in *"---ATTUNE_PARAMS_END---"*) break ;; esac [ -z "$line" ] && continue key="${line%%=*}" value="${line#*=}" case "$value" in \"*\") value="${value#\"}"; value="${value%\"}" ;; esac case "$key" in url) url="$value" ;; timeout) timeout="$value" ;; esac done # Validate if [ -z "$url" ]; then echo "ERROR: url is required" >&2 exit 1 fi # Execute echo "Fetching: $url" >&2 result=$(curl -s --max-time "$timeout" "$url") # Output echo "$result" echo "[$ATTUNE_ACTION] [Exec: $ATTUNE_EXEC_ID] Completed" >&2 exit 0 ``` ## Further Documentation - **Pattern Reference:** `docs/QUICKREF-dotenv-shell-actions.md` - **Pack Structure:** `docs/pack-structure.md` - **Example Actions:** - `echo.sh` - Simplest reference implementation - `http_request.sh` - Complex action with full HTTP client - `register_packs.sh` - API wrapper with JSON construction