10 KiB
Work Summary: CLI Output Enhancements
Date: 2026-01-18
Session: 7 (continued)
Status: ✅ Complete
Overview
Enhanced the CLI with shorthand output flags for better interoperability with Unix tools, and added a new command to extract raw execution results for piping to other command-line utilities.
Objectives
- Add shorthand flags for JSON (
-j) and YAML (-y) output - Enable easy piping to tools like
jq,yq, etc. - Add command to get raw execution result data
- Maintain backward compatibility
- Follow Unix command-line conventions
Implementation Details
1. Shorthand Output Flags
Added Global Flags (main.rs)
/// Output as JSON (shorthand for --output json)
#[arg(short = 'j', long, global = true, conflicts_with_all = ["output", "yaml"])]
json: bool,
/// Output as YAML (shorthand for --output yaml)
#[arg(short = 'y', long, global = true, conflicts_with_all = ["output", "json"])]
yaml: bool,
Flag Resolution Logic
Implemented priority-based resolution:
-j/--json→ JSON output-y/--yaml→ YAML output--output <format>→ Specified format- Default → Table format
let output_format = if cli.json {
output::OutputFormat::Json
} else if cli.yaml {
output::OutputFormat::Yaml
} else {
cli.output
};
Conflict Handling
Flags are mutually exclusive:
-jconflicts with--outputand-y-yconflicts with--outputand-j--outputconflicts with-jand-y
2. Raw Execution Result Command
New Subcommand (commands/execution.rs)
Added attune execution result <id> command:
Result {
/// Execution ID
execution_id: i64,
/// Output format (json or yaml, default: json)
#[arg(short = 'f', long, value_enum, default_value = "json")]
format: ResultFormat,
}
Result Format Enum
#[derive(Debug, Clone, Copy, clap::ValueEnum)]
pub enum ResultFormat {
Json,
Yaml,
}
Implementation
async fn handle_result(
execution_id: i64,
format: ResultFormat,
api_url: &Option<String>,
) -> Result<()> {
let config = CliConfig::load()?;
let client = ApiClient::from_config(&config, api_url);
let path = format!("/executions/{}", execution_id);
let execution: ExecutionDetail = client.get(&path).await?;
if let Some(result) = execution.result {
match format {
ResultFormat::Json => {
println!("{}", serde_json::to_string_pretty(&result)?);
}
ResultFormat::Yaml => {
println!("{}", serde_yaml::to_string(&result)?);
}
}
} else {
anyhow::bail!("Execution {} has no result yet", execution_id);
}
Ok(())
}
Usage Examples
Shorthand Output Flags
# JSON output (long form)
attune pack list --output json
# JSON output (shorthand)
attune pack list -j
# YAML output (shorthand)
attune pack list -y
# Works with all commands
attune execution list -j
attune action list -y
attune rule show core.my_rule -j
Raw Execution Result
# Get result as JSON (default)
attune execution result 123
# Get result as YAML
attune execution result 123 --format yaml
# Pipe to jq for field extraction
attune execution result 123 | jq '.data.status'
# Extract specific array elements
attune execution result 123 | jq -r '.errors[]'
# Complex jq filtering
attune execution result 123 | jq '.results[] | select(.status == "success")'
# Pipe to yq
attune execution result 123 --format yaml | yq '.data.field'
# Use in scripts
STATUS=$(attune execution result 123 | jq -r '.status')
if [ "$STATUS" = "success" ]; then
echo "Execution succeeded"
fi
Piping to Other Tools
# Count items in result
attune execution result 123 | jq '.items | length'
# Format and colorize JSON
attune execution result 123 | jq -C '.'
# Convert between formats
attune execution result 123 | yq -P
# Extract to file
attune execution result 123 | jq '.data' > result.json
# Grep in JSON
attune execution result 123 | jq -r '.logs[]' | grep ERROR
# Chain multiple commands
attune execution list -j | \
jq -r '.[] | select(.status == "failed") | .id' | \
xargs -I {} attune execution result {} | \
jq -r '.error'
Integration with Unix Tools
With jq (JSON processor)
# Filter executions and extract results
attune execution list -j | \
jq '.[] | select(.pack_name == "monitoring")' | \
jq -r '.id' | \
while read id; do
attune execution result $id | jq '.metrics'
done
With yq (YAML processor)
# Get pack config as YAML
attune pack show core -y | yq '.metadata'
With grep/awk/sed
# Search in execution results
attune execution list --pack core -j | \
jq -r '.[] | "\(.id) \(.status)"' | \
grep failed | \
awk '{print $1}' | \
xargs -I {} attune execution result {}
With xargs for batch operations
# Process all failed executions
attune execution list --status failed -j | \
jq -r '.[].id' | \
xargs -I {} attune execution result {} | \
jq -s '.' # Combine all results into single array
Benefits
1. Interoperability
- Follows Unix convention for shorthand flags
- Easy piping to standard tools (
jq,yq,grep, etc.) - Compatible with shell scripting best practices
2. Convenience
- Shorter commands:
-jvs--output json - Faster typing for interactive use
- Less verbose scripts
3. Data Extraction
- Get just the result data without wrapper
- No need to parse full execution object
- Direct access to execution output
4. Scripting
- Easy automation with standard tools
- Clean data flow in pipelines
- Reduced need for custom parsing
Use Cases
1. Monitoring Scripts
#!/bin/bash
# Check execution results for errors
for id in $(attune execution list --status succeeded -j | jq -r '.[].id'); do
ERROR_COUNT=$(attune execution result $id | jq '.errors | length')
if [ "$ERROR_COUNT" -gt 0 ]; then
echo "Execution $id has $ERROR_COUNT errors"
fi
done
2. Data Aggregation
# Aggregate metrics from multiple executions
attune execution list --pack monitoring -j | \
jq -r '.[].id' | \
xargs -I {} attune execution result {} | \
jq -s 'map(.metrics) | add'
3. CI/CD Integration
# Execute action and check result
EXEC_ID=$(attune action execute ci.deploy -j | jq -r '.id')
attune execution result $EXEC_ID | jq -e '.success' || exit 1
4. Log Analysis
# Extract and analyze logs from results
attune execution result 123 | \
jq -r '.logs[]' | \
grep ERROR | \
sort | uniq -c
Technical Details
Flag Conflicts
Clap's conflicts_with_all ensures mutual exclusivity:
- Prevents:
attune pack list -j -y(error) - Prevents:
attune pack list -j --output table(error) - Allows:
attune pack list -j(valid)
Error Handling
Result command provides clear error when execution has no result:
Error: Execution 123 has no result yet
This helps users understand when to use the command.
Format Defaults
- Shorthand flags: Infer format from flag
- Result command: Defaults to JSON (most common for piping)
- Can override with
--formatfor result command
Documentation Updates
Updated Files
-
CLI README (
crates/cli/README.md)- Added shorthand flag examples
- Added result command documentation
- Added scripting examples with jq
- Updated all examples to use shorthand flags
-
CLI Docs (
docs/cli.md)- Added global flags section with shorthands
- Added result extraction examples
- Updated scripting examples
- Added integration examples
-
Main README (
README.md)- Added shorthand flag quick examples
- Added result extraction to CLI features
- Updated feature highlights
Backward Compatibility
✅ Fully Backward Compatible
--outputflag still works- No changes to existing behavior
- New flags are optional additions
- All existing scripts continue to work
Testing
Manual Tests
# Build
cargo build -p attune-cli
# Test shorthand flags
./target/debug/attune config list -j # Should output JSON
./target/debug/attune config list -y # Should output YAML
# Test conflicts
./target/debug/attune config list -j -y # Should error
./target/debug/attune config list -j --output table # Should error
# Test result command
./target/debug/attune execution result --help # Should show help
Build Status
- ✅ Compiles successfully
- ✅ No new warnings
- ✅ Help text displays correctly
- ✅ Conflict handling works
Metrics
- Files Modified: 5
- Lines Added: ~150
- New Command: 1 (
execution result) - New Flags: 2 (
-j,-y) - Documentation Updates: 3 files
- Development Time: ~45 minutes
Files Changed
Modified Files
crates/cli/src/main.rs: Added shorthand flags and resolution logiccrates/cli/src/commands/execution.rs: Added result commandcrates/cli/README.md: Updated documentationdocs/cli.md: Updated documentationREADME.md: Updated examples
Future Enhancements
Potential improvements:
- Result Templating:
--template '{{.status}}: {{.message}}' - JSONPath Support:
--path '$.data.metrics' - Output Streaming: For large results
- Format Conversion:
--from json --to yaml - Pretty Printing Options:
--compact,--indent 2 - Result Diffing:
attune execution diff 123 124
Comparison with Other Tools
Following conventions from popular CLI tools:
| Tool | JSON Flag | YAML Flag | Notes |
|---|---|---|---|
| kubectl | -o json |
-o yaml |
Uses -o for output |
| docker | --format |
N/A | Uses Go templates |
| jq | (default) | N/A | JSON only |
| yq | N/A | (default) | YAML only |
| attune | -j |
-y |
Convenient shorthands |
Our approach is more concise and follows the Unix tradition of single-letter flags for common options.
Conclusion
Successfully enhanced the CLI with:
- Unix-friendly shorthand output flags
- Raw result extraction for piping
- Better interoperability with standard tools
- Improved scripting capabilities
The changes make the CLI more powerful for automation and integration with existing Unix toolchains, while maintaining full backward compatibility.