How to Debug Generated CLI Commands Using JSON Output and Trace Flags in CLI-Anything
CLI-Anything provides orthogonal debugging mechanisms through the --json flag for machine-readable output and trace flags (--trace, --debug) for targeted troubleshooting across all agent harnesses.
The HKUDS/CLI-Anything repository generates unified command-line interfaces for diverse applications like Zotero, Unreal Insights, and Zoom. When building or troubleshooting these generated CLIs, you need reliable ways to inspect command behavior, capture structured data, and trace execution paths. This guide explains the exact implementation patterns found in zotero_cli.py and unrealinsights_cli.py to debug generated CLI commands using JSON output and trace flags.
Understanding the Core Debugging Architecture
CLI-Anything implements two orthogonal systems for debugging: machine-readable JSON output for programmatic inspection, and trace-oriented flags for runtime behavior analysis. Both mechanisms rely on Click's context object (ctx.obj) to propagate settings across commands and sessions.
Machine-Readable Output with --json
The --json flag appears as a top-level option in every agent harness. In zotero/agent-harness/cli_anything/zotero/zotero_cli.py at line 183, the flag is defined using @click.option("--json", is_flag=True, help=""). Similarly, unrealinsights/agent-harness/cli_anything/unrealinsights/unrealinsights_cli.py defines this option at line 289 alongside other debugging flags.
When parsing occurs, the flag value is stored in the Click context object. The Zotero harness stores it at lines 189-199:
ctx.obj["json_output"] = json_output
The Unreal Insights harness stores it similarly at lines 17-19 within the cli() function. This context storage makes the setting reachable from any sub-command, including in REPL mode.
Output routing happens through helper functions. The emit() function in zotero_cli.py (lines 129-143) checks the flag and either prints JSON or a human-readable message:
def emit(ctx, payload, message):
if root_json_output(ctx):
print(json.dumps(payload))
else:
print(message)
Trace and Debug Flags for Targeted Troubleshooting
For tools operating on trace files, the Unreal Insights harness provides additional flags. The --trace option at line 289 allows you to specify an existing trace file path rather than letting the CLI discover one automatically.
The trace path is stored in a session object via session.set_trace(trace). Sub-commands retrieve it using _require_trace() at lines 92-100, which validates file existence and raises a ClickException if the trace is missing:
def _require_trace(ctx):
session = ctx.obj["session"]
trace = session.get_trace()
if not trace:
raise click.ClickException("No trace file specified")
return trace
The --debug flag, defined at line 291, toggles verbose error reporting. When enabled, the central error handler _handle_exc at lines 291-298 prints full tracebacks instead of concise error messages, making it invaluable for development and CI pipelines.
Context Propagation and Session Management
Debugging settings persist across command invocations through a shared session pattern. The Session object is attached to ctx.obj["session"] at lines 13-18 in unrealinsights_cli.py, ensuring that JSON, trace, and debug settings remain active in REPL mode.
This propagation mechanism means that once you enable --json or --debug in a command, subsequent commands in the same session inherit those settings. The context dictionary serves as the single source of truth for output formatting preferences throughout the application lifecycle.
Practical Implementation Examples
Below are minimal implementations demonstrating the debugging patterns used throughout the repository.
Basic JSON Output Routing
This pattern from zotero_cli.py shows how to route output based on the JSON flag:
@click.command()
@click.pass_context
def list_items(ctx):
# Simulated backend query
payload = {"items": ["a", "b", "c"], "count": 3}
# Route through emit helper
emit(ctx, payload, message="Found 3 items: a, b, c")
Trace File Handling with Debug Mode
This example from the Unreal Insights harness demonstrates trace validation and debug error handling:
@click.command()
@click.pass_context
def analyze_trace(ctx):
# Validates --trace was provided and file exists
trace_path = _require_trace(ctx)
try:
result = run_analysis(trace_path)
_output(ctx, result, _human_analyze_summary)
except Exception as exc:
# Respects --debug flag for traceback verbosity
_handle_exc(ctx, exc)
Running the Examples
Execute these commands to see the debugging flags in action:
# Human-readable output (default)
cli-anything-zotero collection list
# Machine-readable JSON for piping to jq
cli-anything-zotero collection list --json
# Trace-specific analysis with JSON output
cli-anything-unrealinsights analyze --trace mygame.utrace --json
# Full traceback on errors
cli-anything-unrealinsights analyze --debug
# CI pipeline combination: structured output with full error details
cli-anything-unrealinsights analyze --trace mygame.utrace --json --debug
Debugging Workflows by Use Case
Combine these flags to address specific debugging scenarios:
- Inspect command structure: Omit
--jsonto see the human-readable command string the CLI would execute. - Integrate with scripts: Add
--jsonto emit raw JSON suitable for downstream processing with tools likejq. - Force specific input: Use
--trace <path>to bypass automatic discovery and test against a known file. - Surface execution errors: Add
--debugto print full Python tracebacks instead of user-friendly error messages. - CI/CD debugging: Combine
--json --debugto get structured output alongside complete stack traces when exceptions occur.
Summary
--jsonflag: Defined in agent harnesses likezotero_cli.py(line 183), stored inctx.obj["json_output"], and processed byemit()helpers (lines 129-143) to toggle between human-readable and machine-readable output.- Trace flags: The
--traceoption inunrealinsights_cli.py(line 289) stores paths in session objects, validated by_require_trace()(lines 92-100) for commands requiring trace file inputs. - Debug mode: The
--debugflag controls traceback verbosity through_handle_exc(lines 291-298), showing full stack traces when enabled. - Context persistence: Settings propagate via
ctx.objand theSessionobject (lines 13-18), ensuring debugging flags persist across REPL commands and sub-command invocations.
Frequently Asked Questions
How do I capture machine-readable output from CLI-Anything commands?
Add the --json flag to any command. The flag is defined at the top level of each agent harness (e.g., line 183 in zotero_cli.py) and stored in ctx.obj["json_output"]. When enabled, helper functions like emit() print raw JSON via json.dumps() instead of formatted text, making it easy to pipe results to other tools or parse them programmatically.
What is the difference between the --trace and --debug flags?
The --trace flag specifies an input file path for tools that analyze trace data (like Unreal Insights), storing the value in session.set_trace() and validating it via _require_trace(). The --debug flag is a boolean toggle that modifies error handling behavior; when set, the _handle_exc() function prints full Python tracebacks rather than concise error messages, helping you diagnose code-level issues.
Where does the CLI store debugging configuration between commands?
Debugging settings persist in the Click context object (ctx.obj) and the Session object attached to it, as implemented in unrealinsights_cli.py lines 13-18. This architecture ensures that enabling --json, --debug, or --trace in one command maintains those settings for subsequent commands within the same REPL session or script execution.
Can I combine JSON output with full error tracebacks?
Yes. Combine --json and --debug flags in the same invocation. The --json flag ensures successful output is formatted as JSON, while --debug ensures that any exceptions trigger _handle_exc() to display the full traceback before exiting. This combination is particularly useful in CI pipelines where you need structured data alongside detailed failure diagnostics.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →