13 KiB
Core Pack Actions: Stdin Parameter Migration & Output Format Standardization
Date: 2026-02-07
Status: ✅ Complete
Scope: Core pack action scripts (bash and Python) and YAML definitions
Overview
Successfully migrated all core pack actions to follow Attune's secure-by-design architecture:
- Parameter delivery: Migrated from environment variables to stdin-based JSON parameter delivery
- Output format: Added explicit
output_formatfield to all actions (text, json, or yaml) - Output schema: Corrected schemas to describe structured data shape, not execution metadata
This ensures action parameters are never exposed in process listings and establishes clear patterns for action input/output handling.
Changes Made
Actions Updated (8 total)
Simple Actions
- echo.sh - Message output
- sleep.sh - Execution pause with configurable duration
- noop.sh - No-operation placeholder action
HTTP Action
- http_request.sh - HTTP requests with auth (curl-based, no runtime dependencies)
Pack Management Actions (API Wrappers)
- download_packs.sh - Pack download from git/HTTP/registry
- build_pack_envs.sh - Runtime environment building
- register_packs.sh - Pack database registration
- get_pack_dependencies.sh - Pack dependency analysis
Implementation Changes
Bash Actions (Before)
# Old: Reading from environment variables
MESSAGE="${ATTUNE_ACTION_MESSAGE:-}"
Bash Actions (After)
# New: Reading from stdin as JSON
INPUT=$(cat)
MESSAGE=$(echo "$INPUT" | jq -r '.message // ""')
# Outputs empty string if message not provided
Python Actions (Before)
# Old: Reading from environment variables
def get_env_param(name: str, default: Any = None, required: bool = False) -> Any:
env_key = f"ATTUNE_ACTION_{name.upper()}"
value = os.environ.get(env_key, default)
# ...
Python Actions (After)
# New: Reading from stdin as JSON
def read_parameters() -> Dict[str, Any]:
try:
input_data = sys.stdin.read()
if not input_data:
return {}
return json.loads(input_data)
except json.JSONDecodeError as e:
print(f"ERROR: Invalid JSON input: {e}", file=sys.stderr)
sys.exit(1)
YAML Configuration Updates
All action YAML files updated to explicitly declare parameter delivery:
# Parameter delivery: stdin for secure parameter passing (no env vars)
parameter_delivery: stdin
parameter_format: json
Key Implementation Details
- Bash scripts: Use
jqfor JSON parsing with// "default"operator for defaults - Python scripts: Use standard library
jsonmodule (no external dependencies) - Null handling: Check for both empty strings and "null" from jq output
- Error handling: Added
set -o pipefailto bash scripts for better error propagation - API token handling: Conditional inclusion only when token is non-null and non-empty
Testing
All actions tested successfully with stdin parameter delivery:
# Echo action with message
echo '{"message": "Test from stdin"}' | bash echo.sh
# Output: Test from stdin
# Echo with no message (outputs empty line)
echo '{}' | bash echo.sh
# Output: (empty line)
# Sleep action with message
echo '{"seconds": 1, "message": "Quick nap"}' | bash sleep.sh
# Output: Quick nap\nSlept for 1 seconds
# Noop action
echo '{"message": "Test noop", "exit_code": 0}' | bash noop.sh
# Output: [NOOP] Test noop\nNo operation completed successfully
# HTTP request action
echo '{"url": "https://httpbin.org/get", "method": "GET"}' | python3 http_request.py
# Output: {JSON response with status 200...}
Documentation
Created comprehensive documentation:
- attune/packs/core/actions/README.md - Complete guide covering:
- Parameter delivery method
- Environment variable usage policy
- Implementation patterns (bash and Python)
- Core pack action catalog
- Local testing instructions
- Migration examples
- Security benefits
- Best practices
Security Benefits
- No process exposure - Parameters never appear in
ps,/proc/<pid>/environ, or process listings - Secure by default - All actions use stdin without requiring special configuration
- Clear separation - Action parameters (stdin) vs. environment configuration (env vars)
- Audit friendly - All sensitive data flows through stdin, not environment
- Credential safety - API tokens, passwords, and secrets never exposed to system
Environment Variable Policy
Environment variables should ONLY be used for:
- Debug/logging controls (e.g.,
DEBUG=1,LOG_LEVEL=debug) - System configuration (e.g.,
PATH,HOME) - Runtime context (set via
execution.env_varsfield in database)
Environment variables should NEVER be used for:
- Action parameters
- Secrets or credentials
- User-provided data
Files Modified
Action Scripts
attune/packs/core/actions/echo.shattune/packs/core/actions/sleep.shattune/packs/core/actions/noop.shattune/packs/core/actions/http_request.pyattune/packs/core/actions/download_packs.shattune/packs/core/actions/build_pack_envs.shattune/packs/core/actions/register_packs.shattune/packs/core/actions/get_pack_dependencies.sh
Action YAML Definitions
attune/packs/core/actions/echo.yamlattune/packs/core/actions/sleep.yamlattune/packs/core/actions/noop.yamlattune/packs/core/actions/http_request.yamlattune/packs/core/actions/download_packs.yamlattune/packs/core/actions/build_pack_envs.yamlattune/packs/core/actions/register_packs.yamlattune/packs/core/actions/get_pack_dependencies.yaml
New Documentation
attune/packs/core/actions/README.md(created)
Dependencies
- Bash actions: Require
jq(already available in worker containers) - Python actions: Standard library only (
json,sys)
Backward Compatibility
Breaking change: Actions no longer read from ATTUNE_ACTION_* environment variables. This is intentional and part of the security-by-design migration. Since the project is pre-production with no live deployments, this change is appropriate and encouraged per project guidelines.
Next Steps
For Other Packs
When creating new packs or updating existing ones:
- Always use
parameter_delivery: stdinandparameter_format: json - Follow the patterns in core pack actions
- Reference
attune/packs/core/actions/README.mdfor implementation examples - Mark sensitive parameters with
secret: truein YAML
Future Enhancements
- Consider creating a bash library for common parameter parsing patterns
- Add parameter validation helpers
- Create action templates for different languages (bash, Python, Node.js)
Impact
- ✅ Security: Eliminated parameter exposure via environment variables
- ✅ Consistency: All core pack actions use the same parameter delivery method
- ✅ Documentation: Clear guidelines for pack developers
- ✅ Testing: All actions verified with manual tests
- ✅ Standards: Established best practices for the platform
Post-Migration Updates
Date: 2026-02-07 (same day)
Echo Action Simplification
Removed the uppercase parameter from echo.sh action and made it purely pass-through:
- Rationale: Any formatting should be done before parameters reach the action script
- Change 1: Removed uppercase conversion logic and parameter from YAML
- Change 2: Message parameter is optional - outputs empty string if not provided
- Impact: Simplified action to pure pass-through output (echo only), no transformations
Files updated:
attune/packs/core/actions/echo.sh- Removed uppercase conversion logic, simplified to output message or empty stringattune/packs/core/actions/echo.yaml- Removeduppercaseparameter definition, mademessageoptional with no default
The echo action now accepts an optional message parameter and outputs it as-is. If no message is provided, it outputs an empty string (empty line). Any text transformations (uppercase, lowercase, formatting) should be handled upstream by the caller or workflow engine.
Output Format Standardization
Added output_format field and corrected output schemas across all actions:
- Rationale: Clarify how action output should be parsed and stored by the worker
- Change: Added
output_formatfield (text/json/yaml) to all action YAMLs - Change: Removed execution metadata (stdout/stderr/exit_code) from output schemas
- Impact: Output schemas now describe actual data structure, not execution metadata
Text format actions (no structured parsing):
echo.sh- Outputs plain text, no schema neededsleep.sh- Outputs plain text, no schema needednoop.sh- Outputs plain text, no schema needed
JSON format actions (structured parsing enabled):
http_request.sh- Outputs JSON, schema describes response structure (curl-based)download_packs.sh- Outputs JSON, schema describes download resultsbuild_pack_envs.sh- Outputs JSON, schema describes environment build resultsregister_packs.sh- Outputs JSON, schema describes registration resultsget_pack_dependencies.sh- Outputs JSON, schema describes dependency analysis
Key principles:
- The worker automatically captures stdout/stderr/exit_code/duration_ms for every execution. These are execution metadata, not action output, and should never appear in output schemas.
- Actions should not include generic "status" or "result" wrapper fields in their output schemas unless those fields have domain-specific meaning (e.g., HTTP status_code, test result status).
- Output schemas should describe the actual data structure the action produces, not add layers of abstraction.
HTTP Request Migration to Bash/Curl
Migrated http_request from Python to bash/curl to eliminate runtime dependencies:
- Rationale: Core pack should have zero runtime dependencies beyond standard utilities
- Change: Rewrote action as bash script using
curlinstead of Pythonrequestslibrary - Impact: No Python runtime required, faster startup, simpler deployment
Migration details:
- Replaced
http_request.pywithhttp_request.sh - All functionality preserved: methods, headers, auth (basic/bearer), JSON bodies, query params, timeouts
- Error handling includes curl exit code translation to user-friendly messages
- Response parsing handles JSON detection, header extraction, and status code validation
- Output format remains identical (JSON with status_code, headers, body, json, elapsed_ms, url, success)
Dependencies:
curl- HTTP client (standard utility)jq- JSON processing (already required for parameter parsing)
Testing verified:
- GET/POST requests with JSON bodies
- Custom headers and authentication
- Query parameters
- Timeout handling
- Non-2xx status codes
- Error scenarios
New Documentation Created
attune/docs/QUICKREF-action-output-format.md- Comprehensive guide to output formats and schemas:- Output format field (text/json/yaml)
- Output schema patterns and best practices
- Worker parsing behavior
- Execution metadata handling
- Migration examples
- Common pitfalls and solutions
Standard Environment Variables
Added documentation for standard ATTUNE_* environment variables provided by worker to all executions:
- Purpose: Provide execution context and enable API interaction
- Variables:
ATTUNE_ACTION- Action ref (always present)ATTUNE_EXEC_ID- Execution database ID (always present)ATTUNE_API_TOKEN- Execution-scoped API token (always present)ATTUNE_RULE- Rule ref (if triggered by rule)ATTUNE_TRIGGER- Trigger ref (if triggered by event)
Use cases:
- Logging with execution context
- Calling Attune API with scoped token
- Conditional behavior based on rule/trigger
- Creating child executions
- Accessing secrets from key vault
Documentation created:
attune/docs/QUICKREF-execution-environment.md- Comprehensive guide covering all standard environment variables, usage patterns, security considerations, and examples
Key distinction: Environment variables provide execution context (system-provided), while action parameters provide user data (stdin-delivered). Never mix the two.
Conclusion
This migration establishes a secure-by-design foundation for action input/output handling across the Attune platform:
- Input (parameters): Always via stdin as JSON - never environment variables
- Output (format): Explicitly declared as text, json, or yaml
- Output (schema): Describes structured data shape, not execution metadata
- Execution metadata: Automatically captured by worker (stdout/stderr/exit_code/duration_ms)
- Execution context: Standard
ATTUNE_*environment variables provide execution identity and API access
All core pack actions now follow these best practices, providing a reference implementation for future pack development. The patterns established here ensure:
- Security: No parameter exposure via process listings, scoped API tokens for each execution
- Clarity: Explicit output format declarations, clear separation of parameters vs environment
- Separation of concerns: Action output vs execution metadata, user data vs system context
- Consistency: Uniform patterns across all actions
- Zero dependencies: No Python, Node.js, or runtime dependencies required for core pack
- API access: Actions can interact with Attune API using execution-scoped tokens