Core concepts
@cosyte/cli is a thin, honest skin over the @cosyte/* parsers. Understanding its three
load-bearing disciplines (the wrapper boundary, the exit-code contract, and the PHI posture) tells
you exactly what to trust it for.
The wrapper boundary
The CLI's correctness surface is narrow by design, because most correctness lives one layer down.
The CLI owns: format autodetection routing, the exit-code contract, the value-free PHI posture, argument/stdin handling, output shaping, and faithful pass-through of the wrapped library's warnings.
The CLI does not re-do: any wire-format parsing, tolerance, or warning semantics. That is the
wrapped parser's job, graded by its own conformance gate. cosyte parse equals the library's
programmatic parse; a bug in a value is the library's, while a mis-route, a wrong exit code, or a
leaked value is the CLI's.
Fail-safe autodetection
Detection sniffs content, never the file extension, and is conservative: a single confident
signature match parses; zero or more than one match is a typed data error asking for --format,
never a guess. A wrong sniff would route bytes to the wrong parser and yield confident garbage,
so the CLI refuses to guess at the routing layer.
The exit-code contract
Exit codes are a designed surface CI depends on: 0 success, 1 an operation-level failure (an
invalid validate verdict, a redact the de-identifier could not complete), 2 usage error, 65
data error (unparseable / undetected), 66 no input, 69 a capability not wired for this input,
70 internal error, 74 an output error (the stream the CLI was writing to closed before the
output was delivered, the shape a downstream consumer that exits early produces). The codes from
65 up are the values the Unix sysexits.h header assigns to the conditions they name; 1 and 2
are this CLI's own values, because that header defines no constant for either. The load-bearing
rule: the CLI never prints a reassuring line and exits 0 on input it could not handle, or on
output that never reached its consumer.
The PHI posture
A CLI operates on real files a developer points at: the moment Cosyte code touches un-synthetic PHI. So the channels are split:
- stdout is the data channel.
parseemits the parsed model there because that is your explicit request, going to the sink you chose (a pipe, a redirect, your screen). - Every other surface is value-free. stderr, errors, and diagnostics carry only positional context (a segment/field index, a byte offset, a file path, a stable code), never a name, DOB, MRN, or result value. An error never echoes the offending bytes.
Diagnostic codes are stable (CLI_CODES): scripts branch on them, so renaming one is a breaking
change.
--unsafe-show-values: the single door to a value
Value-free-by-default has one explicit escape hatch: --unsafe-show-values. With it set, a
CLI_PARSE_FAILED diagnostic appends a bounded excerpt of the offending input to aid local debugging.
It is off by default, PHI-exposing by design (the flag name carries the warning), and it is the
only configuration under which a value reaches a secondary surface: resolved once, globally, and
funnelled through a single chokepoint so the "a value appears on stderr iff the flag is set"
property is provable in one place. A successful parse never puts values on stderr regardless of the
flag.
redact / deid: delegated, never approximated
The one command whose job is to strip identifiers owns no policy. De-identification belongs to
@cosyte/deid: the CLI locates nothing, transforms nothing, and never falls back to a partial
Safe-Harbor scrub, which would leave PHI behind while looking de-identified (a false-safety
impression). It delegates for the formats that library covers and this CLI can serialize, which are
ccda, fhir, hl7, x12, and refuses everything else with a typed, value-free code: astm,
mllp, and ncpdp have no adapter there (CLI_NOT_IMPLEMENTED, 69), and dicom is covered but its
de-identified form is a binary stream this text stdout cannot carry (CLI_FORMAT_UNSUPPORTED, 65,
the CLI's own limit rather than the library's).
The fail-closed half is the point: if the library reports any locus it could not handle, the run
exits 1 and emits nothing, because a partial pass offered as a de-identified copy is the exact
hazard this command exists to avoid. What reaches stderr is the library's own value-free manifest and
its own published label and version; the CLI asserts no de-identification standard of its own. Same
discipline as the wrapper boundary everywhere else: the CLI never invents a capability its ground
layer lacks, and never claims one it cannot back.