CLI
The jpipe-cli module is the public entry point for jPipe. It exposes a
PicoCLI command hierarchy and assembles pipelines via CompilerFactory.
Command hierarchy
Commands
process (default)
Compiles a .jd source file and exports the selected model in the requested
format. This is the default subcommand: invoking jpipe without a subcommand
name is equivalent to jpipe process.
jpipe process -i <file> -m <model> [-f <format>] [-o <output>]
| Option | Short | Required | Default | Description |
|---|---|---|---|---|
--input |
-i |
No | stdin | Input .jd source file |
--output |
-o |
No | stdout | Output file |
--model |
-m |
Yes | — | Name of the model to export |
--format |
-f |
No | JPIPE |
Output format (see table below) |
Delegates to CompilerFactory.build(config, out). Returns exit code 0 on
success, 1 if any ERROR or FATAL diagnostic was reported.
Output formats
| Value | Description | Requires Graphviz |
|---|---|---|
JPIPE |
Canonical jPipe source (round-trip) | No |
DOT |
Graphviz DOT source | No |
PNG |
Rendered PNG image | Yes |
JPEG |
Rendered JPEG image | Yes |
SVG |
Rendered SVG image | Yes |
JSON |
JSON model dump | No |
PYTHON |
Python object model | No |
diagnostic
Parses and validates a .jd source file and reports on it without exporting
any model. Useful for checking a file for errors, inspecting the symbol table,
or feeding an IDE.
jpipe diagnostic -i <file> [-o <output>] [-f <format>]
| Option | Values | Default |
|---|---|---|
-f, --format |
TEXT, JSON (case-insensitive) |
TEXT |
The report has five sections:
- Diagnostics — all ERROR and FATAL messages, with source locations and their diagnostic code.
- Action Statistics — total command count, macro count, and deferral
count from the
ExecutionEngine. - Model Summary — for each model: kind (justification/template), parent template (if any), element counts, and which justifications implement it.
- Symbol Table — all element ids with their source locations, plus alias mappings from composition operators.
- Executed Actions — the ordered model-construction command trace.
Sections whose data is absent (no statistics recorded, no actions executed) are omitted rather than printed empty.
Both formats are produced from the same DiagnosticSnapshot, collected once by
CollectDiagnostics and then rendered by either DiagnosticReport (text) or
JsonDiagnosticReport (JSON), so the two can never describe different
compilations. Delegates to
CompilerFactory.buildDiagnosticCompiler(format, out).
JSON report
{
"schemaVersion": 1,
"source": "examples/foo.jd",
"status": "ok", // "ok" | "errors"
"diagnostics": [
{ "severity": "error", // "error" | "fatal"
"code": "unknown-model", // omitted when the diagnostic has no code
"source": "foo.jd",
"line": 12, "column": 4, // both omitted when the location is unknown
"message": "unknown model 'bar'" }
],
"stats": { "commands": { "total": 42, "macros": 3 }, "deferrals": 1 },
"models": [
{ "name": "m", "kind": "justification",
"implements": "t", // omitted when the model implements nothing
"location": { "source": "foo.jd", "line": 3, "column": 0 },
"elements": { "conclusion": 1, "subConclusion": 2, "strategy": 1,
"evidence": 3, "abstractSupport": 0 },
"usedBy": [ { "name": "j", "location": { … } } ], // templates only
"symbols": [ { "id": "e1", "kind": "evidence",
"synthesized": false, "location": { … } } ],
"aliases": [ { "from": "a", "to": "b" } ] }
],
"actions": [ { "index": 1, "depth": 0, "macro": false, "description": "…" } ]
}
Optional keys are omitted rather than emitted as null. Arrays preserve order;
object key order is not significant. schemaVersion is incremented whenever the
set of members changes, additions included — the schema is strict, so no change
is invisible to a consumer validating against it.
The document is described by a published JSON Schema
that acts as the contract with consumers; it ships on the classpath at
/schema/diagnostic-report-v1.schema.json and every report the test suite
produces is validated against it.
The ASCII logo is suppressed automatically when the JSON report goes to
standard output, so jpipe diagnostic -f json | jq . works without
--headless. Writing to a file with -o keeps the banner on stdout.
Reporting on a compilation that aborted. A fatal error — a syntax error,
an unresolvable load — stops the pipeline, but the report is still written in
both formats: the diagnostics describe the failure, models is empty and the
symbol table reads (empty), because nothing could be built. The exit code is
1. Consumers detect the case by finding a diagnostic with severity: "fatal",
and need no separate path for it.
A source file that cannot be read at all is reported the same way, as a fatal
diagnostic with exit code 1, rather than as the system error (42) it remains
under process.
This is why diagnostic has its own compiler rather than assembling the report
as the tail of the analysis chain — a report produced as a pipeline step could
never describe the failures that stopped that pipeline. process deliberately
keeps the old behaviour: its output stream carries a model export, so a report
poured into it would corrupt the artefact. A fatal there still reaches standard
error with exit code 1 and no output.
doctor
Checks that external tools required by jPipe are available on PATH and
prints a status line for each. Also prints the jPipe version number.
jpipe doctor
dot (Graphviz): OK (version 12.2.1)
Currently checks: dot (Graphviz). A tool is considered available if the OS
can launch the executable; the exit code of the probe is ignored. The probe
output is scanned for a version number, which is reported next to the status —
several operating systems ship an outdated Graphviz, and that shows up as
rendering bugs. When no version can be read out of the banner, the status line
reads OK (version unknown). Returns exit code 0 if all tools are found, 1
otherwise.
Shared infrastructure
InputOutputCommand
Abstract base for ProcessCommand and DiagnosticCommand. Handles:
- Logo display — calls
Logo.sout()unless--headlessis set. - Output stream resolution — opens a
FileOutputStreamwhen--outputis a file path; falls back toSystem.outfor stdout. - Error reporting — catches
CompilationExceptionandUnsupportedOperationExceptionand prints a cleanerror: …message to stderr; any other exception producesunexpected error: …and returns exit code42.
Subclasses implement doCall(OutputStream) and receive the resolved output
stream.
Doctor
Package-private utility that probes each required external tool by attempting
ProcessBuilder launch. Tools are configured in a static LinkedHashMap so
that new dependencies can be added without changing DoctorCommand.
Default subcommand
PicoCLI 4.x has no built-in default-subcommand API. Main.withDefaultSubcommand()
pre-processes the argument array: if no subcommand name (and no short-circuit
flag like --help or --version) is found, it inserts "process" at the
correct position — after any parent-level flags with their arguments. Subcommand
names and parent flag arities are derived from the live CommandLine object at
call time, so the method stays correct when the command tree changes.
Exit codes
| Code | Constant | Meaning |
|---|---|---|
0 |
EXIT_OK |
Success |
1 |
EXIT_JPIPE_ERROR |
Compilation error or missing tool |
42 |
EXIT_SYSTEM_ERROR |
Unexpected exception |