CLEO CLI Design Standard
Developer implementation guide for LLM-agent-first CLI design Version: 3.4 | Updated: 2026-02-10 Scope: CLI command development standards for agent automation
RFC 2119 Conformance
This specification uses RFC 2119 keywords to indicate requirement levels:| Keyword | Meaning |
|---|---|
| MUST | Absolute requirement. Non-compliance is a specification violation. |
| MUST NOT | Absolute prohibition. |
| SHALL | Equivalent to MUST. |
| SHOULD | Recommended but not mandatory. Valid reasons may exist to ignore. |
| SHOULD NOT | Discouraged but not prohibited. |
| MAY | Optional. Implementations can choose to include or omit. |
Related Specifications
| Document | Relationship |
|---|---|
| SPEC-BIBLE-GUIDELINES.md | AUTHORITATIVE for specification standards |
| LLM-TASK-ID-SYSTEM-DESIGN-SPEC.md | AUTHORITATIVE for task ID format, validation, error codes 10-22 |
| TASK-HIERARCHY-SPEC.md | Hierarchy features (type, parentId, size) affecting JSON output |
| RCSD-PIPELINE-SPEC.md | Uses: RCSD commands (consensus, spec, decompose) MUST follow this spec |
| LLM-TASK-ID-SYSTEM-DESIGN-IMPLEMENTATION-REPORT.md | Tracks implementation status against all LLM specs |
Executive Summary
Mission Statement
Design CLI tools with LLM-agent-first principles: JSON output by default, human output opt-in via--human flag, structured errors, and consistent behavior across all commands.
Core Principles
| Principle | Requirement |
|---|---|
| JSON by Default | All commands MUST default to JSON output |
| Human Opt-In | Human-readable output via explicit --human flag |
| Structured Errors | All errors MUST return JSON with error codes |
| Consistent Flags | All commands MUST support --format and --quiet |
| Documented Exit Codes | Every exit code MUST be a defined constant |
| Schema Validation | All JSON MUST include $schema field |
Reference Implementation
analyze.sh exemplifies the gold standard for LLM-agent-first design:
- JSON output is DEFAULT (human requires explicit
--humanflag) - Comprehensive
_metaenvelope with version, timestamp, algorithm - Structured recommendations with
action_order,recommendation.command - Exit codes documented (0=success, 1=error, 2=no tasks)
Part 1: Command Inventory
All Commands (34 total)
| # | Command | Script | Category | Requirements |
|---|---|---|---|---|
| 1 | add | add.sh | Write | JSON output, --format, --quiet |
| 2 | analyze | analyze.sh | Read | JSON default, --human opt-in |
| 3 | archive | archive.sh | Write | JSON output, --format, --quiet, --dry-run |
| 4 | backup | backup.sh | Maintenance | JSON output, --format, --quiet |
| 5 | blockers | blockers.sh | Read | JSON output, --format, --quiet |
| 6 | complete | complete.sh | Write | JSON output, --format, --quiet, --dry-run |
| 7 | commands | commands.sh | Read | JSON default, --human opt-in, filters |
| 8 | config | config.sh | Maintenance | JSON output, --format, --quiet |
| 9 | dash | dash.sh | Read | JSON output, --format, --quiet |
| 10 | deps | deps.sh | Read | JSON output, --format, --quiet |
| 11 | exists | exists.sh | Read | JSON output, --format, --quiet |
| 12 | export | export.sh | Read | Multi-format, --quiet |
| 13 | extract | extract.sh | Sync | JSON output, --format, --quiet, --dry-run |
| 14 | find | find.sh | Read | JSON output, --format, --quiet, fuzzy search |
| 15 | focus | focus.sh | Write | JSON output, --format, --quiet |
| 16 | history | history.sh | Read | JSON output, --format, --quiet |
| 17 | init | init.sh | Setup | JSON output, --format, --quiet |
| 18 | inject | inject.sh | Sync | JSON output, --format, --quiet, --dry-run |
| 19 | labels | labels.sh | Read | JSON output, --format, --quiet |
| 20 | list | list.sh | Read | JSON output, --format, --quiet |
| 21 | log | log.sh | Read | JSON output, --format, --quiet |
| 22 | migrate | migrate.sh | Maintenance | JSON output, --format, --quiet, --dry-run |
| 23 | migrate-backups | migrate-backups.sh | Maintenance | JSON output, --format, --quiet, --dry-run |
| 24 | next | next.sh | Read | JSON output, --format, --quiet |
| 25 | phase | phase.sh | Write | JSON output, --format, --quiet |
| 26 | phases | phases.sh | Read | JSON output, --format, --quiet |
| 27 | research | research.sh | Read | JSON output, --format, --quiet, Context7 integration |
| 28 | restore | restore.sh | Maintenance | JSON output, --format, --quiet, --dry-run |
| 29 | session | session.sh | Write | JSON output, --format, --quiet |
| 30 | show | show.sh | Read | JSON output, --format, --quiet |
| 31 | stats | stats.sh | Read | JSON output, --format, --quiet |
| 32 | sync | sync.sh | Sync | JSON output, --format, --quiet, --dry-run |
| 33 | update | update.sh | Write | JSON output, --format, --quiet, --dry-run |
| 34 | validate | validate.sh | Maintenance | JSON output, --format, --quiet |
Command Categories
| Category | Commands | Special Requirements |
|---|---|---|
| Write | add, archive, complete, focus, phase, session, update | MUST return created/updated object, MUST support --dry-run |
| Read | analyze, blockers, commands, dash, deps, exists, export, find, history, labels, list, log, next, phases, research, show, stats | MUST support filtering, MUST return structured data |
| Sync | extract, inject, sync | MUST support --dry-run, MUST report conflicts |
| Maintenance | backup, config, init, migrate, migrate-backups, restore, validate | MUST report status, SHOULD support --dry-run |
| Setup | init | MUST be idempotent |
Part 2: Gap Analysis
Gap 1: JSON Output Inconsistencies
Impact: Agents need consistent JSON envelope across all commands| Command | Current Output | Required Fix |
|---|---|---|
add | Has JSON but missing $schema | Add schema, standardize envelope |
update | Has JSON but inconsistent | Standardize envelope |
complete | Has JSON output | Standardize envelope |
archive | Has JSON output | Standardize envelope |
phase subcommands | Partial JSON | Complete JSON for all subcommands |
Gap 2: JSON Default Implementation
Location:lib/output-format.sh resolve_format()
Current Issue: Not all scripts call resolve_format() or respect its result.
Required Behavior (LLM-Agent-First):
--human when they need human-readable output.
MUST be implemented in ALL commands via resolve_format() call.
Gap 3: Standardized Error JSON Format
Current Status: Error JSON implemented inlib/error-json.sh
Error JSON Envelope (IMPLEMENTED):
Gap 4: Phase Commands Need Full JSON
phase.sh subcommands MUST output JSON when --format json is specified.
Required for each subcommand:
Gap 5: Flag Inconsistency Across Commands
Conflict Matrix:| Short Flag | Conflicting Uses | Resolution |
|---|---|---|
-f | --format (7 commands) vs --files (update) | Keep -f for --format, --files long-form only |
-n | --notes (3 commands) vs --count (next) | Keep -n for --notes, use -c for --count |
| Flag | Current Coverage | Target |
|---|---|---|
--format | 17/32 (53%) | 100% |
--quiet | 21/32 (66%) | 100% |
--verbose | 2/32 (6%) | All display commands |
--dry-run | 3/32 (9%) | All write operations |
Part 3: Standardized Systems
3.1 Exit Code Standard (AUTHORITATIVE)
File:lib/exit-codes.sh
Exit Code Ranges:
0: Success1-9: General errors10-19: Hierarchy errors (see LLM-TASK-ID-SYSTEM-DESIGN-SPEC)20-29: Concurrency errors30-39: Session errors (multi-session, scope, focus)100+: Special conditions (not errors)
Complete Exit Code Table
| Code | Constant | Meaning | Recoverable | Example |
|---|---|---|---|---|
| General (0-9) | ||||
| 0 | EXIT_SUCCESS | Operation completed successfully | N/A | Task created |
| 1 | EXIT_GENERAL_ERROR | Unspecified error | Yes | Unknown failure |
| 2 | EXIT_INVALID_INPUT | Invalid user input/arguments | Yes | Missing required arg |
| 3 | EXIT_FILE_ERROR | File system operation failed | No | Permission denied |
| 4 | EXIT_NOT_FOUND | Requested resource not found | Yes | Task ID not found |
| 5 | EXIT_DEPENDENCY_ERROR | Missing dependency | No | jq not installed |
| 6 | EXIT_VALIDATION_ERROR | Data validation failed | Yes | Schema violation |
| 7 | EXIT_LOCK_TIMEOUT | Failed to acquire lock | Yes | Concurrent write |
| 8 | EXIT_CONFIG_ERROR | Configuration error | Yes | Invalid config |
| Hierarchy (10-19) | ||||
| 10 | EXIT_PARENT_NOT_FOUND | parentId references non-existent task | Yes | —parent T999 invalid |
| 11 | EXIT_DEPTH_EXCEEDED | Max hierarchy depth (3) exceeded | Yes | Too deeply nested |
| 12 | EXIT_SIBLING_LIMIT | Max siblings exceeded (if configured) | Yes | Parent at configured limit |
| 13 | EXIT_INVALID_PARENT_TYPE | subtask cannot have children | Yes | subtask as parent |
| 14 | EXIT_CIRCULAR_REFERENCE | Task would be ancestor of itself | No | Cycle detected |
| 15 | EXIT_ORPHAN_DETECTED | Task has invalid parentId | Yes | Parent was deleted |
| Concurrency (20-29) | ||||
| 20 | EXIT_CHECKSUM_MISMATCH | File modified externally | Yes | Retry operation |
| 21 | EXIT_CONCURRENT_MODIFICATION | Multi-agent conflict | Yes | Retry with backoff |
| 22 | EXIT_ID_COLLISION | ID generation conflict | Yes | Regenerate ID |
| Session (30-39) | ||||
| 30 | EXIT_SESSION_EXISTS | Session already active for scope | Yes | Use existing session or end it first |
| 31 | EXIT_SESSION_NOT_FOUND | Session ID not found | Yes | List sessions, start new |
| 32 | EXIT_SCOPE_CONFLICT | Scope overlaps with existing session | Yes | Use different scope |
| 33 | EXIT_SCOPE_INVALID | Invalid scope format or empty | Yes | Check scope syntax |
| 34 | EXIT_TASK_NOT_IN_SCOPE | Task outside session scope | Yes | Focus task within scope |
| 35 | EXIT_TASK_CLAIMED | Task focused by another session | Yes | Choose different task |
| 36 | EXIT_SESSION_REQUIRED | Operation requires active session | Yes | Start session first |
| 37 | EXIT_SESSION_CLOSE_BLOCKED | Cannot close - tasks incomplete | Yes | Complete or remove tasks |
| 38 | EXIT_FOCUS_REQUIRED | Operation requires focused task | Yes | Set focus first |
| 39 | EXIT_NOTES_REQUIRED | Session notes required | Yes | Provide notes |
| Special (100+) | ||||
| 100 | EXIT_NO_DATA | No data to process (not error) | N/A | Empty query result |
| 101 | EXIT_ALREADY_EXISTS | Resource already exists | N/A | Task ID exists |
| 102 | EXIT_NO_CHANGE | No changes needed | N/A | Update was no-op |
Exit Code Semantics (AUTHORITATIVE)
Commands MUST use the following exit codes:| Scenario | Exit Code | Error Code |
|---|---|---|
| Task not found | 4 | E_TASK_NOT_FOUND |
| Invalid task ID format | 2 | E_TASK_INVALID_ID |
| File not readable | 3 | E_FILE_READ_ERROR |
| Missing required argument | 2 | E_INPUT_MISSING |
| JSON schema validation failed | 6 | E_VALIDATION_SCHEMA |
| Parent task not found (hierarchy) | 10 | E_PARENT_NOT_FOUND |
| Would create circular reference | 14 | E_CIRCULAR_REFERENCE |
| Lock acquisition timeout | 7 | N/A (no E_ code) |
| Empty query result | 100 | N/A (not an error) |
| Session not found | 31 | E_SESSION_NOT_FOUND |
| Scope conflicts with existing session | 32 | E_SCOPE_CONFLICT |
| Task outside session scope | 34 | E_TASK_NOT_IN_SCOPE |
| Task claimed by another session | 35 | E_TASK_CLAIMED |
| Session required for operation | 36 | E_SESSION_REQUIRED |
| Focus required for operation | 38 | E_FOCUS_REQUIRED |
3.2 Error Code Standard (AUTHORITATIVE)
File:lib/error-json.sh
Convention: All error codes use E_ prefix.
Complete Error Code Table (29 codes)
| Category | Code | Exit Code | Description |
|---|---|---|---|
| Task Errors | |||
E_TASK_NOT_FOUND | 4 | Task ID does not exist | |
E_TASK_ALREADY_EXISTS | 101 | Task ID already exists | |
E_TASK_INVALID_ID | 2 | Task ID format is invalid | |
E_TASK_INVALID_STATUS | 2 | Status value not in enum | |
| File Errors | |||
E_FILE_NOT_FOUND | 4 | File does not exist | |
E_FILE_READ_ERROR | 3 | Cannot read file | |
E_FILE_WRITE_ERROR | 3 | Cannot write file | |
E_FILE_PERMISSION | 3 | Permission denied | |
| Validation Errors | |||
E_VALIDATION_SCHEMA | 6 | JSON schema validation failed | |
E_VALIDATION_CHECKSUM | 6 | Checksum mismatch | |
E_VALIDATION_REQUIRED | 6 | Required field missing | |
| Input Errors | |||
E_INPUT_MISSING | 2 | Required argument missing | |
E_INPUT_INVALID | 2 | Argument value invalid | |
E_INPUT_FORMAT | 2 | Argument format incorrect | |
| Dependency Errors | |||
E_DEPENDENCY_MISSING | 5 | Required tool not installed | |
E_DEPENDENCY_VERSION | 5 | Tool version incompatible | |
| Phase Errors | |||
E_PHASE_NOT_FOUND | 4 | Phase slug does not exist | |
E_PHASE_INVALID | 2 | Phase definition invalid | |
| Session Errors | |||
E_SESSION_ACTIVE | 101 | Session already active (legacy) | |
E_SESSION_NOT_ACTIVE | 4 | No active session (legacy) | |
E_SESSION_EXISTS | 30 | Session already active for scope | |
E_SESSION_NOT_FOUND | 31 | Session ID not found | |
E_SCOPE_CONFLICT | 32 | Scope overlaps with existing session | |
E_SCOPE_INVALID | 33 | Invalid scope format or empty | |
E_TASK_NOT_IN_SCOPE | 34 | Task outside session scope | |
E_TASK_CLAIMED | 35 | Task focused by another session | |
E_SESSION_REQUIRED | 36 | Operation requires active session | |
E_SESSION_CLOSE_BLOCKED | 37 | Cannot close session - tasks incomplete | |
E_FOCUS_REQUIRED | 38 | Operation requires focused task | |
E_NOTES_REQUIRED | 39 | Session notes required | |
| General Errors | |||
E_UNKNOWN | 1 | Unknown/unspecified error | |
E_NOT_INITIALIZED | 4 | Project not initialized | |
| Hierarchy Errors | |||
E_PARENT_NOT_FOUND | 10 | Parent task does not exist | |
E_DEPTH_EXCEEDED | 11 | Hierarchy depth limit exceeded | |
E_SIBLING_LIMIT | 12 | Sibling limit exceeded | |
E_INVALID_PARENT_TYPE | 13 | Parent type cannot have children | |
E_CIRCULAR_REFERENCE | 14 | Would create cycle | |
E_ORPHAN_DETECTED | 15 | Task references invalid parent | |
| Concurrency Errors | |||
E_CHECKSUM_MISMATCH | 20 | File modified during operation | |
E_CONCURRENT_MODIFICATION | 21 | Multi-agent conflict detected | |
E_ID_COLLISION | 22 | Generated ID already exists |
3.3 JSON Schema Standard
Schema Files
| Schema | File | Status | Purpose |
|---|---|---|---|
| Task Data | schemas/todo.schema.json | EXISTS | Task/project data validation |
| Archive | schemas/archive.schema.json | EXISTS | Archived tasks validation |
| Log | schemas/log.schema.json | EXISTS | Audit log validation |
| Config | schemas/config.schema.json | EXISTS | Configuration validation |
| Response | schemas/output.schema.json | EXISTS | Success response envelope |
| Error | schemas/error.schema.json | EXISTS | Error response envelope |
| Critical Path | schemas/critical-path.schema.json | EXISTS | Critical path analysis response |
Response Schema (schemas/output.schema.json)
Error Schema (schemas/error.schema.json)
3.4 JSON Envelope Standard (AUTHORITATIVE)
All JSON outputs MUST follow this envelope:Required _meta Fields
| Field | Type | Required | Description |
|---|---|---|---|
format | string | MUST | Always "json" for JSON output |
version | string | MUST | cleo version (e.g., "0.17.0") |
command | string | MUST | Command name (e.g., "add", "list") |
timestamp | string | MUST | ISO-8601 UTC timestamp |
checksum | string | MAY | SHA256 of file for integrity |
execution_ms | integer | MAY | Execution time in milliseconds |
3.5 Universal Flag Standard (AUTHORITATIVE)
| Flag | Long Form | Purpose | Default | Commands |
|---|---|---|---|---|
-f | --format | Output format | json | ALL |
-q | --quiet | Suppress non-essential output | false | ALL |
-v | --verbose | Detailed output | false | ALL read commands |
--human | Force human-readable text | false | ALL | |
--json | Force JSON (shortcut for --format json) | N/A (already default) | ALL | |
--dry-run | Preview changes | false | ALL write commands | |
--force | Skip confirmations | false | Destructive commands |
--human to get human-readable text output. The --json flag exists for explicit clarity but is redundant since JSON is already the default.
Format Values
| Format | Description | Use Case |
|---|---|---|
text | Human-readable colored output | Interactive terminal |
json | Machine-readable JSON envelope | Agent automation |
jsonl | JSON Lines (one object per line) | Streaming/logging |
markdown | Markdown formatted | Documentation |
table | ASCII table | Terminal display |
Part 4: Required Libraries
Foundation Libraries
All commands MUST source these libraries:| Library | Purpose | Required By |
|---|---|---|
lib/exit-codes.sh | Standardized exit code constants | ALL commands |
lib/error-json.sh | Format-aware error output | ALL commands |
lib/output-format.sh | TTY-aware format resolution | ALL commands |
Library Integration Pattern
Part 5: Write Command Requirements
All Write Commands MUST:
- Return the created/updated object in JSON output
- Include
$schemafield pointing tooutput.schema.json - Include complete
_metaenvelope - Support
--dry-runto preview changes without executing - Use
output_error()for all error conditions
JSON Output Examples
add Command Output
update Command Output
complete Command Output
Subcommand Requirements (e.g., phase.sh)
Commands with subcommands MUST:
- Accept
--formatflag before the subcommand - Each subcommand MUST respect the FORMAT variable
- Each subcommand MUST output proper JSON envelope
Part 5.3: Input Validation Requirements
Write commands MUST validate all inputs before modifying state:Field Length Limits
| Field | Max Length | Error Code |
|---|---|---|
| title | 120 chars | E_INPUT_INVALID |
| description | 2000 chars | E_INPUT_INVALID |
| notes (each) | 5000 chars | E_INPUT_INVALID |
| blockedBy reason | 300 chars | E_INPUT_INVALID |
| sessionNote | 2500 chars | E_INPUT_INVALID |
| label name | 50 chars | E_INPUT_INVALID |
| phase slug | 30 chars | E_INPUT_INVALID |
Validation Order
Commands MUST validate in this order:- Required arguments present (
E_INPUT_MISSING) - Format/type validation (
E_INPUT_FORMAT) - Length validation (
E_INPUT_INVALID) - Semantic validation (
E_VALIDATION_*)
Validation Response
Failed validation MUST return immediately (fail-fast) with:- Specific error code
- Field name in error message
- Actual vs. allowed value info
Part 5.4: Dry-Run Semantics
Commands with--dry-run MUST follow these semantics:
| Behavior | With —dry-run | Without —dry-run |
|---|---|---|
| Validation | Full | Full |
| File locking | None | Full |
| State modification | None | Full |
| JSON output | Full (with dryRun: true) | Full |
| Exit code | Same as real | Same |
Dry-Run Output
Part 5.6: Idempotency Requirements
Write commands MUST be idempotent where feasible to support agent retries without side effects:| Command | Idempotency | Mechanism |
|---|---|---|
add | SHOULD | Detect duplicate title+phase within 60s window, return existing task |
update | MUST | Updating with identical values returns EXIT_NO_CHANGE (102) |
complete | MUST | Completing already-done task returns EXIT_NO_CHANGE (102) |
archive | MUST | Re-archiving already-archived tasks is a no-op |
restore | MUST | Restoring already-active task returns EXIT_NO_CHANGE (102) |
Duplicate Detection for add
When creating a new task, the CLI SHOULD check if an identical task (same title, same phase) was created within the last 60 seconds. If found:
- Return the existing task with
success: true - Include
"duplicate": truein response - Use exit code 0 (success, not error)
EXIT_NO_CHANGE Semantics
Exit code 102 (EXIT_NO_CHANGE) indicates:
- The command was valid
- No changes were made (state unchanged)
- Agents SHOULD treat this as success and not retry
Non-Idempotent Operations
The following operations are inherently non-idempotent and MUST be documented in help text:backup create- Creates new backup each timesession start- Only valid if no session activelogentries - Each invocation appends
Part 5.7: Retry Protocol for Recoverable Errors
Agents SHOULD implement retry logic for recoverable errors with exponential backoff:| Exit Code | Name | Max Retries | Initial Delay | Backoff Factor |
|---|---|---|---|---|
| 7 | EXIT_LOCK_TIMEOUT | 3 | 100ms | 2x |
| 20 | EXIT_CHECKSUM_MISMATCH | 5 | 50ms | 1.5x |
| 21 | EXIT_CONCURRENT_MODIFICATION | 5 | 100ms | 2x |
| 22 | EXIT_ID_COLLISION | 3 | 0ms | immediate regenerate |
Retry Algorithm
ID Collision Handling (Exit Code 22)
ForEXIT_ID_COLLISION, agents SHOULD:
- Extract the colliding ID from error JSON
- Regenerate a new ID (or let CLI auto-generate)
- Retry immediately without delay
Maximum Total Wait
Agents SHOULD cap total retry wait time at 5 seconds to avoid blocking workflows.Part 6: Testing Requirements (AUTHORITATIVE)
6.1 Exit Code Testing
All commands MUST have tests verifying:6.2 JSON Output Testing
All commands with JSON output MUST have tests verifying:6.3 TTY Detection Testing
6.4 Test Coverage Requirements
| Category | Minimum Coverage | Commands |
|---|---|---|
| Exit codes | 100% of defined codes | All |
| JSON envelope | All required fields | All JSON-enabled |
| Error JSON | All error codes used | All |
| Flag parsing | All flags | All |
| TTY detection | Auto-detect + overrides | All format-enabled |
Part 7: Agent Integration Guide
Environment Setup
Query Patterns (Work Today)
Write Patterns (v0.17.0)
Part 8: Compliance Metrics
Required Metrics for Full Compliance
| Metric | Required Value |
|---|---|
| Agent workflow steps per mutation | 1x (command returns result) |
Commands requiring explicit --format json | 0/32 (auto-detect via TTY) |
| Error handling method | JSON with E_ error codes |
| Write confirmation in response | YES (full object returned) |
| Exit code coverage | 100% (all codes are constants) |
$schema field presence | 100% of JSON outputs |
_meta envelope presence | 100% of JSON outputs |
Compliance Definition
A command is fully compliant when it:- Sources all required libraries (
exit-codes.sh,error-json.sh,output-format.sh) - Calls
resolve_format()after argument parsing - Supports
--format,--quiet,--json,--humanflags - Returns JSON with
$schemaand_metaenvelope - Uses
output_error()for all errors - Uses exit code constants (no magic numbers)
- (Write commands) Supports
--dry-run - (Write commands) Returns created/updated object
Part 9: Command Compliance Requirements
All commands MUST meet these requirements:| Command | JSON | Quiet | Format | Dry-Run | exit-codes | error-json | resolve_format |
|---|---|---|---|---|---|---|---|
| add | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| analyze | ✅ | N/A | ✅ | N/A | ✅ | ✅ | ✅ |
| archive | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| backup | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| blockers | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| complete | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| commands | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| config | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| dash | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| deps | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| exists | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| export | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| extract | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| find | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| focus | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| history | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| init | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| inject | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| labels | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| list | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| log | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| migrate | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| migrate-backups | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| next | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| phase | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| phases | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| research | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| restore | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| session | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| show | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| stats | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
| sync | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| update | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| validate | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ |
Part 10: Development Workflow (AUTHORITATIVE)
Adding a New Command
When adding a new command to cleo, MUST follow this checklist:1. Foundation
- Source
lib/exit-codes.shat script start - Source
lib/error-json.shat script start - Source
lib/output-format.shat script start - Set
COMMAND_NAMEvariable for error reporting
2. Flag Parsing
- Implement
--formatflag (text|json|jsonl|markdown|table) - Implement
--quietflag (suppress non-essential output) - Implement
--humanshortcut (sets format=text) - Implement
--jsonshortcut (sets format=json) - For write commands: implement
--dry-run - For destructive commands: implement
--force - Call
resolve_format()after parsing all arguments
3. JSON Output
- Include
$schemafield in all JSON outputs - Include complete
_metaenvelope (format, version, command, timestamp) - Include
successboolean field - For task operations: include full task object with hierarchy fields
- For errors: use
output_error()from error-json.sh
4. Exit Codes
- Use constants from
lib/exit-codes.sh(never magic numbers) - Document all possible exit codes in command help
- Return
EXIT_SUCCESS(0) on success - Return appropriate error code on failure
- Return special codes (100+) for non-error conditions
5. Testing
- Add unit tests for flag parsing
- Add unit tests for JSON output structure
- Add unit tests for all exit codes
- Add integration tests for TTY detection
- Verify JSON validates against schema
6. Documentation
- Update this spec’s command matrix
- Add command to
docs/commands/if user-facing - Document exit codes in help text
- Document JSON output format in help text
Code Template
Part 11: Backward Compatibility Policy
Breaking Change Policy
| Change Type | Policy | Deprecation Period |
|---|---|---|
| Exit code value changes | MUST NOT change within major version | 2 major versions |
| Error code string changes | MUST NOT change within major version | 2 major versions |
| JSON field removal | MUST NOT remove within major version | 2 major versions |
| Flag removal | MUST NOT remove within major version | 1 major version |
| JSON field rename | Add new, deprecate old | 2 major versions |
| Default behavior change | Document clearly, consider --legacy flag | 1 major version |
Deprecation Process
- Announce: Mark deprecated in next minor release
- Warn: Emit deprecation warning to stderr (unless
--quiet) - Document: Add to
CHANGELOG.mddeprecation section - Sunset: Remove after deprecation period
Deprecation Registry
Maintain a deprecation registry indocs/DEPRECATIONS.md tracking:
- Deprecated item (exit code, error code, flag, field)
- Version deprecated
- Replacement (if any)
- Sunset version
JSON Stability Guarantees
| Field | Stability |
|---|---|
$schema | Stable (version in URL) |
_meta.version | Stable |
_meta.command | Stable |
_meta.timestamp | Stable |
success | Stable |
error.code | Stable within major version |
error.exitCode | Stable within major version |
| Command-specific fields | See individual command docs |
Part 12: Compliance Validation Checklist
Per-Command Checklist
Use this checklist to validate each command’s compliance:Automated Compliance Check
A compliance check script SHOULD be created atdev/check-compliance.sh:
Part 13: Files Reference
Required Library Files
| File | Purpose |
|---|---|
lib/exit-codes.sh | Exit code constants (17 codes) |
lib/error-json.sh | Error JSON output (29 error codes) |
lib/output-format.sh | Format resolution with TTY detection |
lib/hierarchy.sh | Hierarchy validation functions |
Required Schema Files
| File | Purpose |
|---|---|
schemas/todo.schema.json | Task data schema |
schemas/archive.schema.json | Archive data schema |
schemas/log.schema.json | Audit log schema |
schemas/config.schema.json | Configuration schema |
schemas/output.schema.json | Success response envelope |
schemas/error.schema.json | Error response envelope |
schemas/critical-path.schema.json | Critical path analysis response |
Reference Implementations
These commands exemplify best practices:| File | Why Study It |
|---|---|
scripts/analyze.sh | Gold standard - JSON default, --human flag |
scripts/exists.sh | Perfect exit codes pattern |
scripts/list.sh | Comprehensive JSON envelope |
scripts/validate.sh | --fix and JSON patterns |
Appendix A: Quick Reference Card
Exit Code Quick Reference
Error Code Quick Reference
JSON Envelope Quick Reference
Part 14: Pagination Standards (v0.88.0+)
14.1 Pagination Envelope
Commands returning arrays SHOULD include apagination object in the JSON envelope when results are paginated:
pagination object conforms to mcp-server/schemas/common/pagination.schema.json. All four fields (total, limit, offset, hasMore) are REQUIRED when the pagination key is present.
14.2 Smart Default Limits
Each command type has a context-optimized default page size viaget_default_limit() in lib/json-output.sh:
| Command | Default | Override |
|---|---|---|
list / tasks | 50 | --limit N |
session list | 10 | --limit N |
find / search | 10 | --limit N |
log | 20 | --limit N |
archive | 25 | --limit N |
| Others | 50 | --limit N |
--limit 0 to disable pagination and retrieve all items.
14.3 Pagination Flags
| Flag | Type | Default | Description |
|---|---|---|---|
--limit N | integer | Smart default | Maximum items to return (0 = unlimited) |
--offset N | integer | 0 | Number of items to skip |
###CLEO header block.
14.4 Compact Output Mode
List commands SHOULD use compact representations to minimize token consumption:compact_task()stripsnotes,description,acceptance,files,verification,_archivecompact_session()stripsfocusHistory,stats,taskSnapshots,notes,events
ct show <id> when full detail is needed for a specific item.
14.5 Agent Pagination Pattern
Agents SHOULD follow this pattern for paginated data:14.6 Implementation Library
All pagination functionality is centralized inlib/json-output.sh:
| Function | Purpose |
|---|---|
output_success | Standard non-paginated success envelope |
output_error_envelope | Lightweight error envelope |
output_paginated | Paginated success envelope with metadata |
apply_pagination | Slice a JSON array by limit/offset |
get_pagination_meta | Generate pagination metadata object |
get_default_limit | Smart default limit by command type |
compact_task | Strip verbose fields from tasks |
compact_session | Strip verbose fields from sessions |
Specification v3.4 - Authoritative Standard for LLM-Agent-First CLI Design Applicable to: cleo and any LLM-agent-first CLI project Last updated: 2026-02-10
