Sigil CLI JSON Contract
Sigil CLI commands are machine-first. JSON is the default output mode for:
sigilc lexsigilc parsesigilc compilesigilc inspect typessigilc inspect validatesigilc inspect codegensigilc inspect worldsigilc debug runsigilc debug testsigilc testsigilcusage/unknown-command failures
sigilc run is split:
- plain
sigil runstreams raw program stdout/stderr on success - plain
sigil runemits structured JSON on failure sigil run --jsonemits the structured JSON envelope on both success and failuresigil run --json --traceadds a bounded inline execution trace to that envelopesigil run --json --trace --trace-expradds expression enter/return/throw events to that tracesigil run --json --break-fnadds machine-readable breakpoint snapshotssigil run --json --recordadds replay recording metadata and writes a replay artifactsigil run --json --replayreplays a prior artifact and reports replay consumption metadata
Canonical Schema
The normative machine contract is:
language/spec/cli-json.schema.json
Consumers should validate against that schema, not this Markdown file. For the user-facing debugging workflow, examples, and command selection guide, see language/docs/DEBUGGING.md.
Versioning
formatVersionis the payload format version- current version:
1 - backward-incompatible output changes require incrementing
formatVersion
Common Envelope Pattern
Most commands emit:
{
"formatVersion": 1,
"command": "sigilc compile",
"ok": true,
"phase": "codegen",
"data": { "...": "..." }
}
Failures emit:
{
"formatVersion": 1,
"command": "sigilc compile",
"ok": false,
"phase": "parser",
"error": {
"code": "SIGIL-PARSE-NS-SEP",
"phase": "parser",
"message": "invalid namespace separator"
}
}
sigilc test keeps a specialized top-level summary / results envelope. sigilc inspect types, sigilc inspect validate, sigilc inspect codegen, and sigilc inspect world use inspect-specific envelopes. sigilc run uses the runEnvelope schema in --json mode and for failure payloads. sigilc debug run and sigilc debug test use replay-backed debug envelopes with data.session and data.snapshot.
Debug Surface Index
Use the current surfaces like this:
sigil inspect validate: canonical source and validation resultsigil inspect types: solved top-level declaration types plus named type inventorysigil inspect world: normalized runtime world for one project envsigil inspect codegen: generated TypeScript plus span-map summarysigil run --json: one structured run success/failure envelopesigil run --json --trace [--trace-expr]: bounded runtime tracesigil run --json --break...: inline breakpoint snapshotssigil run --json --record|--replay: record/replay summary plus standalone replay artifactssigil test: suite-level JSON results with optional per-test debug blockssigil debug runandsigil debug test: replay-backed stepping sessions with snapshots and watches
Diagnostics
Diagnostics are structured and machine-oriented:
codephasemessagelocationwhen availablefound/expectedwhen usefuldetailsfixitssuggestions
Inspect Types
sigil inspect types now reports two complementary views per analyzed file:
declarations: solved top-levelfunction | const | testsignaturestypes: named source-declared types in that module
Each types[] entry includes:
typeIdnamemoduleIdkindtypeParamsdefinitionSourcedefinitionAstconstrainedconstraintSourceconstraintAstequalityModespanIdlocation
definitionAst and constraintAst are normalized semantic nodes with a required kind field and command-specific properties.
Focused debug value payloads may also include typeId when the value has a statically known named Sigil type. In v1 this is surfaced on breakpoint locals, watch results, and expression value/error payloads rather than every generic trace value summary. Breakpoint and debug locals also expose an optional root typeId when the local itself is statically known to be a named Sigil type.
Run Failure Details
When sigil run fails after compilation and runner launch, the failure envelope keeps the usual top-level diagnostic shape and may enrich error.details with:
compile
- input - output - runnerFile - spanMapFile
runtime
- engine - exitCode - durationMs - stdout - stderr
- optional
trace
- enabled - truncated - totalEvents - returnedEvents - droppedEvents - events
- optional
breakpoints
- enabled - mode - stopped - truncated - totalHits - returnedHits - droppedHits - maxHits - hits
- optional
replay
- mode - file - recordedEvents - consumedEvents - remainingEvents - partial
exceptionfor uncaught runtime exceptions
- name - message - rawStack - optional generatedFrame - optional sigilFrame - optional sigilExpression
Run Trace Details
sigil run --trace currently requires --json. sigil run --trace-expr currently requires both --trace and --json.
When enabled, sigil run includes a bounded rolling trace window:
- only the most recent
256events are returned inline - older events are dropped and reflected through:
- truncated - totalEvents - returnedEvents - droppedEvents
Current trace event kinds:
callreturnbranch_ifbranch_matcheffect_calleffect_result
When --trace-expr is enabled, trace may also include:
expr_enterexpr_returnexpr_throw
Every trace event includes:
seqkinddepthmoduleIdsourceFilespanId
Events may also include:
- declaration context such as
declarationKind/declarationLabel spanKindfunctionNameargsresultvalueerror- branch selection details such as
taken,armSpanId,armIndex,hasGuard - effect details such as
effectFamilyandoperation
sigilFrame remains declaration-level context:
- it identifies the owning top-level Sigil declaration using the generated
.span.jsonsidecar - it may include a tiny declaration-header excerpt
sigilExpression is the exact failing expression when runtime capture can resolve it:
- it identifies the concrete expression span that threw or was active at failure time
- it may include compact
valueorerrorsummaries - it may include current-frame
localsand stack summaries when that state is available
Run Breakpoint Details
Breakpoint selectors currently require --json.
Supported selectors:
--break--break-fn--break-span
Supported controls:
--break-mode stop|collect--break-max-hits
The inline breakpoints block reports:
enabledmodestoppedtruncatedtotalHitsreturnedHitsdroppedHitsmaxHitshits
Each hit currently includes:
- matched selector summaries
moduleIdsourceFilespanIdspanKind- optional declaration context such as
declarationKind/declarationLabel - resolved Sigil
locationwhen the span map can provide it - current-frame
locals - stack-frame summaries
- a bounded
recentTracewindow using the same event schema asdata.trace
Stop mode is a successful early stop:
- the top-level envelope still uses
ok: true data.breakpoints.stoppedistrueruntime.stdout/runtime.stderrcontain only output produced before the stop
Collect mode keeps running:
stoppedremainsfalse- only the most recent
maxHitssnapshots are returned - older hits are reflected through
truncated,totalHits,returnedHits, anddroppedHits
Run Replay Details
sigil run now supports first-class record/replay:
--recordwrites a standalone replay artifact file--replayreuses that artifact as the runtime world/effect source--recordand--replayare mutually exclusive--replaycannot be combined with--env; the artifact owns replay-world resolution
The inline replay block in the run envelope is intentionally small:
modefilerecordedEventsconsumedEventsremainingEventspartial
Current replay coverage:
randomtimer/time.nowprocesshttptcpfile
Replay artifacts are strict:
- bound to the original entry file
- bound to the original argv
- bound to a source-graph fingerprint
- consumed in exact recorded sequence
Standalone replay artifact schema:
language/spec/run-replay.schema.json
Test Debug Details
sigil test remains JSON-first and now supports the same debugging surface as sigil run:
--trace--trace-exprrequiring--trace--break,--break-fn,--break-span--break-mode stop|collect--break-max-hits--record--replay
Per-test results may now include:
tracebreakpointsreplayexception
status may now be:
passfailerrorstopped
Stop-mode breakpoints are test-scoped:
- the current test becomes
status: "stopped" - the suite continues with later selected tests
- top-level
okbecomesfalse summary.stoppedcounts stopped tests
sigil test --replay is artifact-owned like sigil run --replay:
- it cannot be combined with
--env - per-test replay uses the recorded resolved test world after local
world { ... }overlays
Standalone test replay artifact schema:
language/spec/test-replay.schema.json
Debug Session Details
sigil debug is JSON-only in v1 and replay-backed:
sigil debug run start --replay[--watch ...] sigil debug run snapshotsigil debug run step-intosigil debug run step-oversigil debug run step-outsigil debug run continuesigil debug run closesigil debug test start --replay--test [--watch ...] sigil debug test ...for the same control verbs
Successful debug commands return:
data.session
- id - file - targetKind - state - replayFile - programPath or testPath - optional testId - watches
data.snapshot
- state - pauseReason - eventKind - seq - current source/span/declaration context when available - current-frame locals - watches - stack summaries - bounded recentTrace - stdoutSoFar - stderrSoFar - replay progress - optional lastCompleted - optional exception
Current step events are source-shaped:
function_enterfunction_returntest_entertest_returnexpr_enterexpr_returnexpr_throwbreakpointprogram_exittest_exituncaught_exception
Standalone debug-session schema:
language/spec/debug-session.schema.json
Current watch selector shape:
locallocal.field.subfield
Watch roots must match current-frame locals, params, or pattern-bound names. Nested segments only traverse record/object fields. Each watch result reports:
status: "ok"with a compact summarizedvaluestatus: "not_in_scope"when the root binding is absentstatus: "path_missing"when a nested field is missing or traversal leaves a record value
Inspect World Details
sigil inspect world is project-env scoped.
Successful output reports:
inputprojectprojectRootenvironmenttopology
- present - declaredEnvs - httpDependencies - tcpDependencies
summary
- singleton entry kinds plus HTTP/TCP binding counts
normalizedWorld
normalizedWorld is the runtime-normalized template Sigil will use for that environment, not the raw exported Sigil world value.
Inspect Codegen Details
sigil inspect codegen mirrors the real compile pipeline but keeps the results in memory.
Successful single-file output reports:
inputmoduleIdsourceFileprojectsummary
- modules - lineCount - spans - generatedRanges - topLevelAnchors
codegen
- outputFile - spanMapFile - source - lineCount - spanMapSummary
modules
- per-module inventory for the resolved compile graph
Directory mode reports:
inputsummary
- discovered - inspected - groups - modules - durationMs
files
- one single-file-style result per requested file
Only the requested file gets inline generated TypeScript in v1. Imported modules appear in modules inventory only.
inspect codegen does not write the derived .ts or .span.json files to disk. The reported outputFile and spanMapFile values are the same derived paths that sigil compile would use.
Current Notes
The current implementation uses:
"sigilc ..."strings in JSONcommandfields- successful
compileoutput reports.span.jsonsidecars viarootSpanMapand per-modulespanMapFile - successful
run --jsonoutput reports the entry module.span.jsonsidecar viadata.compile.spanMapFile - successful
run --json --traceoutput reports inline bounded trace events viadata.trace - breakpoint-enabled
run --jsonoutput may report inline snapshots viadata.breakpoints - successful
run --json --recordandrun --json --replayoutput may report inline replay summary data viadata.replay - runtime
runfailures may include declaration-levelsigilFrameand generated TypeScriptgeneratedFramecontext when an uncaught exception stack is available - traced
runfailures may include bounded inline trace events viaerror.details.trace - breakpoint-enabled
runfailures may include bounded snapshot data viaerror.details.breakpoints - recorded or replayed
runfailures may include replay summary data viaerror.details.replay inspect typesis top-level declaration-focused in v1; it does not report nested expression types yetinspect typesnow includes named type metadata, constraints, and equality mode for source-declared types; it still does not report nested expression types in v1inspect validatereturns canonical printer output even whenvalidation.okisfalse, as long as lexing and parsing succeededinspect codegenreturns generated TypeScript inline for the requested file and only inventories imported modulesinspect worldis project-level in v1; it does not batch over directories or include test-localworld { ... }overlayssigil testnow has a specialized result shape withlocation: {line,column}, optional per-test debug blocks, and astoppedstatus for stop-mode breakpoint hits
If prose and runtime output disagree, the implementation and cli-json.schema.json are the current source of truth.