How the JSON Output Mode in witr Handles Multiple Input Sources

When using the --json flag with multiple inputs, witr aggregates all results into a single JSON array, including both successful process lookups and error entries for failed targets.

The pranshuparmar/witr CLI tool provides a machine-readable JSON output mode designed for scripting and integration workflows. Understanding how this mode behaves with multiple input sources requires examining the core aggregation logic in the application layer and the serialization utilities in the output package.

Single-Target vs. Multi-Target JSON Processing

witr distinguishes between single and multiple input sources to determine output formatting strategy.

Single-Target JSON Output

For a single input source, witr serializes the model.Result struct immediately using dedicated helper functions. The internal/output/json.go file defines multiple serialization formats:

  • ToJSON – Full process details including ancestry and children
  • ToShortJSON – Compact format with essential fields only
  • ToTreeJSON – Hierarchical tree representation
  • ToWarningsJSON – Warning-focused output
  • ToEnvJSON – Environment variable inspection

These helpers write directly to standard output without buffering.

Multi-Target JSON Aggregation

When multiple sources are provided, the behavior shifts fundamentally. In internal/app/app.go, witr accumulates results in a slice variable named jsonResults rather than emitting each result immediately.

The aggregation flow follows this pattern:

  1. Initialize empty jsonResults slice
  2. For each input target, perform lookup and serialization
  3. Append serialized JSON string to jsonResults
  4. After all targets processed, marshal complete slice as JSON array
  5. Write final array to standard output in single operation

This design ensures valid, parseable JSON output regardless of how many sources succeed or fail.

Error Handling in Multi-Target JSON Mode

Failed lookups do not terminate execution or corrupt the JSON structure. The jsonErrorEntry function in internal/app/app.go generates standardized error objects:

// Error entry format consistent with successful results
{"error": "descriptive message", "target": "input specification"}

These error entries interleave with successful results in the final array, preserving target order and enabling callers to correlate errors with specific inputs.

JSON Structure and Field Behavior

The underlying data model in internal/model defines the Result struct with omitempty JSON tags. Key characteristics include:

  • Consistent schema – All entries share the same top-level structure
  • Sparse fields – Empty arrays and zero values are omitted (e.g., Children field absent when no child processes exist)
  • Deterministic ordering – Array preserves input target sequence

Practical Usage Examples

Single Process Inspection

witr --json pid 1234

Output:

{"PID":1234,"Command":"nginx","Ancestry":[{"PID":1,"Command":"systemd"}],"Children":[]}

Multiple Port Inspection with Mixed Results

witr --json port 8080 port 5432 port 9999

Output:

[
  {"Port":8080,"PID":5678,"Command":"node","Ancestry":[...]},
  {"Port":5432,"PID":9012,"Command":"postgres","Ancestry":[...]},
  {"error":"no process listening on port 9999","target":"port 9999"}
]

Programmatic Processing with jq

witr --json pid $(pgrep -d',' -f "python") | jq '.[] | select(.Command | contains("worker"))'

Source Code Reference

File Purpose GitHub URL
internal/app/app.go CLI entry point, --json flag handling, jsonResults aggregation, jsonErrorEntry https://github.com/pranshuparmar/witr/blob/main/internal/app/app.go
internal/output/json.go JSON serialization helpers: ToJSON, ToShortJSON, ToTreeJSON, ToWarningsJSON, ToEnvJSON https://github.com/pranshuparmar/witr/blob/main/internal/output/json.go
internal/app/render_test.go Test coverage for JSON output formatting and multi-target accumulation https://github.com/pranshuparmar/witr/blob/main/internal/app/render_test.go
internal/app/collect_test.go Verification of error entry generation and inclusion in JSON arrays https://github.com/pranshuparmar/witr/blob/main/internal/app/collect_test.go
internal/model/result.go Result struct definition with JSON tags https://github.com/pranshuparmar/witr/blob/main/internal/model/result.go

Performance Characteristics

The multi-target JSON mode maintains O(n) memory complexity relative to input count, as all results are buffered in jsonResults before final output. For extremely large target lists (thousands of PIDs or ports), consider:

  • Piping through witr in batches
  • Using --short flag to reduce per-entry serialization overhead
  • Filtering targets at the shell level before passing to witr

Summary

  • Single targets serialize immediately via internal/output/json.go helpers
  • Multiple targets aggregate in jsonResults slice and emit as unified JSON array
  • Errors return as structured objects via jsonErrorEntry, maintaining parseable output
  • omitempty tags produce compact JSON by excluding empty fields
  • Source order preservation enables reliable result-to-input correlation

Frequently Asked Questions

What happens if one target fails when using JSON mode with multiple inputs?

witr continues processing remaining targets. The failure is recorded as a JSON error entry in the final array using jsonErrorEntry, allowing the complete output to parse successfully while indicating which specific input failed.

Does the JSON output mode support streaming for large target lists?

No. As implemented in internal/app/app.go, witr buffers all jsonResults in memory before the final write. The output is emitted as a single valid JSON array after all targets complete, trading memory usage for guaranteed structural validity.

How do I distinguish between different result types in the JSON array?

Each object contains identifying fields based on lookup type: PID for process ID lookups, Port for network port inspections, Label for container labels, or error for failed operations. The presence of these fields serves as implicit type discrimination.

Can I combine JSON output with other formatting flags like --short or --tree?

Yes. The --json flag accepts modifier flags that route to specific serializers: --short uses ToShortJSON, and --tree uses ToTreeJSON. These produce different JSON schemas optimized for specific use cases while maintaining the same multi-target aggregation behavior.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →