RFC: Universal Output Format Interfaces
This RFC proposes a fundamental architectural change to ensure all Conduit commands support multiple output formats consistently.
Motivation
Currently, commands have inconsistent output formatting. Some are decorative-only, making it difficult to:
- Process command output programmatically
- Export data for analysis
- Build integrations and pipelines
- Create consistent user experiences
Proposed Architecture
1. Abstract Command Class with Format Interfaces
<?php
namespace Conduit\Commands;
use LaravelZero\Framework\Commands\Command;
abstract class AbstractConduitCommand extends Command
{
protected $signature = '{command} {--format=terminal : Output format (terminal, json, table, markdown, csv)}';
public function handle(): int
{
$data = $this->getData();
$format = $this->option('format');
return match($format) {
'json' => $this->outputJson($data),
'table' => $this->outputTable($data),
'markdown' => $this->outputMarkdown($data),
'csv' => $this->outputCsv($data),
default => $this->outputTerminal($data)
};
}
/**
* Get the data to be formatted
*/
abstract protected function getData(): array;
/**
* Format output for terminal (decorative)
*/
abstract protected function outputTerminal(array $data): int;
/**
* Format output as JSON
*/
abstract protected function outputJson(array $data): int;
/**
* Format output as table
*/
abstract protected function outputTable(array $data): int;
/**
* Format output as markdown
*/
abstract protected function outputMarkdown(array $data): int;
/**
* Format output as CSV
*/
abstract protected function outputCsv(array $data): int;
}
2. Component Scaffolding with Stubs
When creating new commands:
conduit make:command spotify:analytics
Generates:
<?php
namespace ConduitSpotify\Commands;
use Conduit\Commands\AbstractConduitCommand;
class AnalyticsCommand extends AbstractConduitCommand
{
protected $signature = 'spotify:analytics {--format=terminal : Output format}';
protected function getData(): array
{
// TODO: Implement data collection
return [];
}
protected function outputTerminal(array $data): int
{
// TODO: Implement terminal formatting
$this->info('Analytics data in terminal format');
return self::SUCCESS;
}
protected function outputJson(array $data): int
{
// TODO: Implement JSON formatting
$this->line(json_encode($data, JSON_PRETTY_PRINT));
return self::SUCCESS;
}
protected function outputTable(array $data): int
{
// TODO: Implement table formatting
$this->table(['Metric', 'Value'], $data);
return self::SUCCESS;
}
protected function outputMarkdown(array $data): int
{
// TODO: Implement markdown formatting
$this->line('# Analytics Report');
return self::SUCCESS;
}
protected function outputCsv(array $data): int
{
// TODO: Implement CSV formatting
$this->line('metric,value');
return self::SUCCESS;
}
}
3. Helper Traits for Common Patterns
trait FormatsAsJson
{
protected function outputJson(array $data): int
{
$this->line(json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
return self::SUCCESS;
}
}
trait FormatsAsTable
{
protected function outputTable(array $data): int
{
if (empty($data)) {
$this->warn('No data to display');
return self::SUCCESS;
}
$headers = array_keys(reset($data));
$rows = array_map('array_values', $data);
$this->table($headers, $rows);
return self::SUCCESS;
}
}
4. Global Options in Conduit Core
// In AppServiceProvider
$this->app->beforeResolving(AbstractConduitCommand::class, function ($command) {
// Add global format validation
// Set default formats based on config
// Handle piping detection
});
Benefits
- Consistency: Every command supports the same output formats
- Enforced Implementation: Abstract methods ensure formats aren't forgotten
- Developer Experience: Stubs with TODOs guide implementation
- User Experience: Users know --format works everywhere
- Composability: Easy to pipe and chain commands
- Future-Proof: New formats can be added to abstract class
Migration Path
- Create AbstractConduitCommand in core
- Update existing commands gradually
- New commands must extend AbstractConduitCommand
- Deprecation warnings for old-style commands
- Full migration in next major version
Example Usage
# Human-readable
conduit spotify:current
# For scripts
conduit spotify:current --format=json | jq '.artist'
# For documentation
conduit knowledge:search "error" --format=markdown > errors.md
# For spreadsheets
conduit analytics:report --format=csv > report.csv
# For dashboards
conduit status:all --format=table
Additional Considerations
- Detect when output is piped and default to json/plain
- Add --fields option to select specific fields
- Support --output=file.json for direct file writing
- Consider --jq option for built-in JSON filtering
- Add format to config for user preferences
This would make Conduit the most integration-friendly CLI framework!
RFC: Universal Output Format Interfaces
This RFC proposes a fundamental architectural change to ensure all Conduit commands support multiple output formats consistently.
Motivation
Currently, commands have inconsistent output formatting. Some are decorative-only, making it difficult to:
Proposed Architecture
1. Abstract Command Class with Format Interfaces
2. Component Scaffolding with Stubs
When creating new commands:
Generates:
3. Helper Traits for Common Patterns
4. Global Options in Conduit Core
Benefits
Migration Path
Example Usage
Additional Considerations
This would make Conduit the most integration-friendly CLI framework!