Ethernity exposes a machine-readable CLI surface for GUI and automation clients under
ethernity api.
Current commands:
ethernity api backupethernity api compactethernity api config getethernity api config setethernity api extendethernity api inspect mintethernity api inspect extendethernity api inspect recoverethernity api mintethernity api recover
These commands write newline-delimited JSON (NDJSON) to stdout. In API mode, treat stdout as
reserved for event records only.
When --config is omitted in API mode, command behavior depends on the surface:
api backup,api compact,api extend,api mint, andapi recoverload defaults from the existing user config when it already exists, otherwise they fall back to the packaged config without creating user config files.api config getuses the user config when it exists; otherwise it reports the packaged config path withsource = "default"and does not initialize user config just to read settings.api config settargets the user config path by default and will initialize it if needed.
ethernity api recover does not implicitly read stdin. To recover from stdin, pass
--fallback-file - for fallback text or --payloads-file - for QR payload lines.
- Schema version:
1 - JSON Schema file:
docs/cli_api.schema.json - Transport: one JSON object per line on
stdout - Encoding: UTF-8 text
- Files and large artifacts: written to disk, then referenced by path in emitted events
- Inspect commands do not write files and never emit
artifactevents - Exit code
0: success - Exit code
2: validation, input, configuration, or runtime failure - Exit code
130: cancelled by user
Emitted once at command start.
Fields:
type:startedschema_version: integercommand:backup,compact,config,extend,mint, orrecoverargs: sanitized argument summary
For backup, args.passphrase_generate reflects whether the command will generate a passphrase,
not only whether --generate-passphrase was explicitly provided.
The args payload is command-specific and schema-validated in docs/cli_api.schema.json.
For config, args.operation is get or set.
For api inspect recover, api inspect extend, and api inspect mint, args.operation is
inspect while command remains recover, extend, or mint.
Emitted when the command enters a new stage.
Fields:
type:phaseid: stable phase idlabel: human-readable stage label
Current phases:
- Backup:
plan,input,backup,prepare,encrypt,shard,render - Compact:
compact - Config:
load,validate,write - Extend:
plan,render,validate,publish - Extend inspect:
plan - Mint:
plan,mint,render - Recover:
plan,decrypt,write
Emitted for countable or completed work inside a phase.
Fields:
type:progressphase: owning phase idcurrent: completed unitstotal: total units when known, otherwisenullunit: unit label such asfiles,documents, orsteplabel: progress label ornulldetails: structured metadata object, possibly empty
Emitted for non-fatal conditions.
Fields:
type:warningcode: stable warning codemessage: human-readable warningdetails: structured metadata object, possibly empty
Emitted for each output file produced by the command after the command completes successfully.
Fields:
type:artifactkind: stable artifact kindpath: normalized filesystem path for the emitted artifactdetails: structured metadata object, possibly empty
Emitted once on success.
Fields:
type:resultok:true- command-specific payload
Backup results expose generated_passphrase only when Ethernity generated the passphrase for the
run. Caller-supplied passphrases are not echoed back into NDJSON output.
Result path fields use the same normalized path form as the corresponding artifact events.
Recover results include output_path_kind so clients can distinguish a single recovered file from
an output directory path. When --output points to an existing directory, single-file recovery is
written inside that directory using the manifest filename.
For api backup, if --output-dir points to an existing directory, it is treated as a parent
directory and Ethernity creates backup-<doc_id> inside it. If the path does not exist, Ethernity
creates that exact directory.
For api mint, if --output-dir points to an existing directory, it is treated as a parent
directory and Ethernity creates mint-<doc_id> inside it. If the path does not exist, Ethernity
creates that exact directory.
Mint results include doc_hash, selected_extension_index, selected_extension_doc_hash,
expected_head_doc_hash, validated_head_index, validated_head_doc_hash, freshness_scope,
signing_key_source, and a stable artifacts object for minted shard paths.
Minting from an imported root-plus-extension recovery set requires either
--expected-head-doc-hash or --allow-stale-head because the supplied carriers prove only the
freshest head among the supplied inputs.
Compact results include expected_head_doc_hash, validated_head_index,
validated_head_doc_hash, and freshness_scope for the source head that was flattened into the
new standalone backup. Scan-mode compact requires either --expected-head-doc-hash or
--allow-stale-head because scanned carriers prove only the freshest head among supplied inputs.
Extend results include index, doc_id, doc_hash, root_doc_id, root_doc_hash, chain_id,
parent_head_index, parent_head_doc_hash, expected_head_doc_hash, freshness_scope, the
promoted extension_dir, a stable artifacts object for generated PDFs, and execution summaries
for selected_scope, diff_summary, resolved_policy, chunk_reuse, and extension_bytes.
Successful extend results always include non-null root lineage (root_doc_id, root_doc_hash,
chain_id), selected-scope metadata, diff metadata, and chunk-reuse statistics. Missing readiness
metadata is reported as an error before publishing instead of being represented as a partial success.
Extend selected_scope uses a stable scope summary with files, directories, base_dir,
file_count, total_bytes, input_origin, and input_roots. Extend diff_summary includes
new_paths, changed_paths, unchanged_paths, missing_paths, and matching *_count fields.
chunk_reuse includes reused_chunks and new_chunks when a publishable extension can be
previewed. Extension shard thresholds and share counts are bounded to 1..255 when enabled.
For api inspect extend, resolved_policy, chunk_reuse, and estimated_extension_bytes are
execution-grade preview values for the pending extension when unlock/auth requirements are satisfied
and the selected scope contains changes. Inspect also render-validates the pending artifacts in a
temporary no-publish workspace before reporting the extension as ready. resolved_policy is null
when runtime policy cannot be evaluated yet.
Compact results include the source root_dir or source_scan, the emitted standalone output_dir,
a fresh standalone doc_id, and a stable artifacts object for generated PDFs.
Inspect results include operation: "inspect", never include artifacts, and report readiness as a
success-shaped payload: ok: true plus any blocking_issues.
Decrypt-dependent source_summary fields may be null until auth or unlock requirements are
satisfied.
Config results include the resolved config path, normalized editable values, supported option lists, onboarding metadata, and a config validity status so a GUI can build its own onboarding flow and repair invalid config files.
Emitted once on failure.
Fields:
type:errorok:falsecode: stable error codemessage: human-readable errordetails: structured metadata object, possibly empty
Current command-specific error codes:
INPUT_REQUIRED:ethernity api backupwas invoked without--input,--input-dir, or--input -;ethernity api compactwas invoked without--root-diror--scan;ethernity api extendorethernity api inspect extendwas invoked without--root-dirOUTPUT_REQUIRED:ethernity api recoverwas invoked without--output, orethernity api compactwas invoked without--output-dirCONFIG_INPUT_REQUIRED:ethernity api config setwas invoked without--input-jsonCONFIG_JSON_INVALID: the JSON patch passed toapi config setwas malformed, not a JSON object, or not valid UTF-8CONFIG_UNKNOWN_FIELD: the patch referenced an unsupported config or onboarding fieldCONFIG_INVALID_VALUE: the patch supplied a value with the wrong type or enum valueCONFIG_CONFLICT: the patch supplied conflicting settings (for example mismatched shard counts)SHARD_DIR_NOT_FOUND:--shard-dirpath does not existSHARD_DIR_INVALID:--shard-dirpath is not a directorySHARD_DIR_EMPTY:--shard-dircontains no.txtfilesSIGNING_KEY_SHARD_DIR_NOT_FOUND:--signing-key-shard-dirpath does not existSIGNING_KEY_SHARD_DIR_INVALID:--signing-key-shard-dirpath is not a directorySIGNING_KEY_SHARD_DIR_EMPTY:--signing-key-shard-dircontains no.txtfilesEXTENSION_INPUT_REQUIRED:ethernity api extendwas invoked without--input,--input-dir, or--input -;ethernity api inspect extendhas no explicit selected scopeEXTENSION_INVALID_POLICY:ethernity api extendreceived an unsupported or inconsistent shard / unlock-policy combinationEXTENSION_NO_CHANGES:ethernity api extendfound no changed or new paths in the selected scope;api inspect extendreports a no-op preview instead of raising this codeEXTENSION_MAIN_CARRIER_INVALID: staged extension MAIN carriers failed ciphertext / AUTH validationEXTENSION_SHARD_CARRIER_INVALID: staged extension shard carriers failed payload validationEXTENSION_TOO_LARGE: the encrypted extension ciphertext exceeds the release size limitEXTENSION_PUBLISH_TARGET_INVALID: the extension publish target cannot be validated before writingCOMPACT_INVALID_POLICY:ethernity api compactcould not preserve the source or root shard policyRECOVERY_HEAD_UNTRUSTED: recover or compact could not authenticate or reconstruct the requested recovery head, or the latest supplied recovery head when no explicit head was requested
For api extend, every documented Stable Blocking Issue Code may also appear as command
error.code when a readiness blocker is promoted during publish-plan preparation. Those promoted
codes are part of the stable command error contract.
Current generic error codes:
CANCELLEDNOT_FOUNDPERMISSION_DENIEDINVALID_INPUTRUNTIME_ERRORIO_ERROR
Current warning codes emitted by backup/recover flows:
AUTH_PAYLOAD_MISSINGAUTH_PAYLOAD_INVALIDAUTH_DOC_HASH_MISMATCHAUTH_SIGNATURE_INVALIDAUTH_FALLBACK_INVALIDFALLBACK_SECTION_INVALIDRECOVERY_SHARD_PAYLOADS_IGNOREDBACKUP_SIGNING_KEY_SHARDING_DISABLEDBACKUP_QR_CHUNK_SIZE_REDUCED
Additional warning and error codes may be added in a backwards-compatible way. Existing codes will remain stable once documented here.
Current inspect blocking_issues[].code values:
AUTH_PAYLOAD_MISSINGAUTH_PAYLOAD_MULTIPLEAUTH_PAYLOAD_DOC_ID_MISMATCHAUTH_PAYLOAD_FRAME_INVALIDAUTH_PAYLOAD_INVALIDAUTH_DOC_HASH_MISMATCHAUTH_SIGNATURE_INVALIDPASSPHRASE_SHARDS_UNDER_QUORUMPASSPHRASE_SHARDS_INVALIDPASSPHRASE_INVALIDPASSPHRASE_REQUIREDAUTH_REQUIREDUNLOCK_FAILEDSIGNING_KEY_SHARDS_REQUIREDSIGNING_KEY_SHARDS_UNDER_QUORUMSIGNING_KEY_SHARDS_INVALIDPASSPHRASE_REPLACEMENT_NOT_READYSIGNING_KEY_REPLACEMENT_NOT_READYROOT_AUTHORITY_MISMATCHROOT_SHARD_POLICY_INVALIDEXTENSION_INPUT_REQUIREDRECOVERY_HEAD_UNTRUSTEDEXTENSION_LAYOUT_INVALIDEXTENSION_PUBLISH_TARGET_INVALIDEXTENSION_INVALID_POLICYEXTENSION_NO_CHANGESEXTENSION_TOO_LARGESEALED_ROOT_NOT_EXTENDABLECHAIN_INVALIDDELETE_NOT_SUPPORTED
Additional blocking issue codes may be added in a backwards-compatible way. Existing documented codes remain stable once listed here.
Current artifact kinds:
- Backup:
qr_document,recovery_document,recovery_kit_index,shard_document,signing_key_shard_document,layout_debug_json - Compact:
qr_document,recovery_document,recovery_kit_index,shard_document,signing_key_shard_document,layout_debug_json - Extend:
qr_document,recovery_document,recovery_kit_index,shard_document,signing_key_shard_document,layout_debug_json - Mint:
shard_document,signing_key_shard_document,layout_debug_json - Recover:
recovered_file
Inspect commands never emit artifact events.
Stable phase ids currently emitted by the API:
- Backup:
plan,input,backup,prepare,encrypt,shard,render - Compact:
compact - Config:
load,validate,write - Extend:
plan,render,validate,publish - Extend inspect:
plan - Mint:
plan,mint,render - Recover:
plan,decrypt,write
Stable recover result.auth_status values:
verifiedskippedmissinginvalidignored
ethernity api inspect recover reports:
doc_id,selected_extension_index,selected_extension_doc_hash,expected_head_doc_hash,validated_head_index,validated_head_doc_hash,freshness_scope,input_label,input_detail,auth_statussource_summarywhen decryption is possible, otherwisenullframe_counts.main|auth|shardunlock.mode|passphrase_provided|validated_shard_count|required_shard_threshold|shard_share_count|satisfiedblocking_issuesandwarnings
When recovery input contains multiple MAIN documents, such as a root backup plus extension
documents, api inspect recover remains readiness-oriented. If the root cannot yet be selected
because unlock material is missing or wrong, it still emits a result event with
source_summary: null, aggregate frame counts, and an unlock/root-selection blocking issue.
When scanning a backup root directory, recovery imports extension carriers by content. Directory
names, filenames, and redundant carrier copies are not required for extension chain recovery.
Extension recovery documents are human-readable fallback artifacts and are not treated as
machine-readable extension carriers.
ethernity api inspect mint reports:
doc_id,selected_extension_index,selected_extension_doc_hash,expected_head_doc_hash,validated_head_index,validated_head_doc_hash,freshness_scope,input_label,input_detail,auth_statussource_summarywhen decryption is possible, otherwisenullframe_counts.main|auth|shard|signing_key_shardunlock.validated_passphrase_shard_count|required_passphrase_threshold|satisfiedsigning_key.validated_shard_count|required_threshold|satisfied|sourcemint_capabilities.can_mint_passphrase_shards|can_mint_signing_key_shardsblocking_issuesandwarnings
ethernity api inspect extend reports:
doc_id,input_label,input_detail,input_kindsource_summary,frame_counts,root_doc_id,root_doc_hash,chain_idauth_status,discovered_extension_dirs,validated_head_index,validated_head_doc_hash,expected_head_doc_hash,freshness_scopeunlock.mode|passphrase_provided|validated_shard_count|required_shard_threshold|shard_share_count|satisfiedvalidated_head_auth_status,validated_head_root_authority_verifiedavailable_extensions,ancestry_valid,signing_authorityselected_scope,diff_summary,resolved_policy,chunk_reuse,estimated_extension_bytesblocking_issuesandwarnings
For mint inspect, frame_counts.signing_key_shard reports decoded signing-key shard input frames.
Signing-key readiness comes from signing_key.satisfied; validated_shard_count is informational
and can be 0 when the backup already embeds a signing seed.
For extend inspect, unlock.satisfied only describes root decryption readiness. Use
blocking_issues, signing_authority.satisfied, and the validated-head fields to decide whether
the write-producing extend action is ready. A selected scope with no changed or new paths reports
EXTENSION_NO_CHANGES as a blocking issue. A missing explicit scope reports
EXTENSION_INPUT_REQUIRED as a blocking issue.
mint_capabilities is per output type and reflects both readiness and the currently enabled
output toggles. A replacement-shard blocker can disable one capability while leaving the other
available.
When ethernity api backup --layout-debug-dir <dir> is used, each generated layout sidecar is
emitted as an artifact event with kind layout_debug_json.
api config get and api config set expose a structured editable config model with these sections:
templates.default_nametemplates.template_name,templates.recovery_template_name,templates.shard_template_name,templates.signing_key_shard_template_name,templates.kit_template_namepage.sizeqr.error,qr.chunk_sizeextension.chunking.target_size,extension.chunking.min_size,extension.chunking.max_sizedefaults.backup.*defaults.recover.outputdefaults.extend.*ui.*debug.max_bytesruntime.render_jobs
Config results also expose onboarding metadata:
onboarding.neededonboarding.configured_fieldsonboarding.available_fields
api config set accepts a partial JSON patch with this shape:
{
"values": {
"page": {"size": "LETTER"},
"defaults": {"backup": {"output_dir": "/tmp/backups"}}
},
"onboarding": {
"mark_complete": true,
"configured_fields": ["page_size", "backup_output_dir"]
}
}Unknown patch fields are rejected. defaults.recover.output remains an editable config value even
though ethernity api recover still requires explicit --output. When onboarding is supplied,
onboarding.mark_complete must be set explicitly.
Config results also include:
status:valid,invalid_toml, orinvalid_valueserrors: structured load problems for the current config snapshotsource:user,default, orexplicit
When status is not valid, values still contain a schema-valid snapshot derived from defaults
and any parseable settings so the GUI can offer repair UX.
The GUI should build its own onboarding flow on top of api config get and api config set.
Ethernity does not expose a separate API wizard.
Recommended procedure:
- Call
ethernity api config get. - Read
result.onboarding.needed,result.onboarding.configured_fields,result.options, and the currentresult.valuessnapshot. - Render the GUI's own onboarding steps and prefill any existing values you want to preserve.
- Submit a partial patch with
ethernity api config set --input-json <file>. - Include
onboarding.mark_complete = trueand setonboarding.configured_fieldsto the fields your GUI actually collected during onboarding. - Optionally call
ethernity api config getagain to confirm the saved state.
If the GUI reads an explicit config file with --config, onboarding metadata is not considered
applicable to that file. The result will report onboarding.needed = false and an empty
onboarding.configured_fields list.
Current onboarding field identifiers map to config values like this:
template_design->templates.default_namepage_size->page.sizebackup_output_dir->defaults.backup.output_dirqr_chunk_size->qr.chunk_sizeqr_error_correction->qr.errorpayload_codec->defaults.backup.payload_codecqr_payload_codec->defaults.backup.qr_payload_codecsharding->defaults.backup.shard_threshold,defaults.backup.shard_count,defaults.backup.signing_key_mode,defaults.backup.signing_key_shard_threshold, anddefaults.backup.signing_key_shard_count
The onboarding marker is separate from the TOML config file. onboarding.configured_fields
describes what the GUI asked the user during onboarding, not every value present in the config.
When onboarding is marked complete again, the stored configured_fields set is replaced with the
new list from the patch.
Example onboarding patch:
{
"values": {
"templates": {"default_name": "forge"},
"page": {"size": "LETTER"},
"qr": {"error": "Q", "chunk_size": 384},
"extension": {"chunking": {"target_size": 16384, "min_size": 4096, "max_size": 65536}},
"defaults": {
"backup": {
"output_dir": "/tmp/backups",
"payload_codec": "auto",
"qr_payload_codec": "raw",
"shard_threshold": 2,
"shard_count": 3,
"signing_key_mode": "sharded",
"signing_key_shard_threshold": 2,
"signing_key_shard_count": 3
}
}
},
"onboarding": {
"mark_complete": true,
"configured_fields": [
"template_design",
"page_size",
"backup_output_dir",
"qr_chunk_size",
"qr_error_correction",
"payload_codec",
"qr_payload_codec",
"sharding"
]
}
}{"type":"started","schema_version":1,"command":"recover","args":{"config":null,"paper":null,"fallback_file":null,"payloads_file":"main_payloads.txt","scan":[],"has_passphrase":true,"shard_fallback_file":[],"shard_payloads_file":[],"shard_scan":[],"auth_fallback_file":null,"auth_payloads_file":null,"extension_index":null,"extension_doc_hash":null,"expected_head_doc_hash":null,"output":"/tmp/out/secret.txt","quiet":true,"debug":false}}
{"type":"phase","id":"plan","label":"Resolving recovery inputs"}
{"type":"progress","phase":"plan","current":1,"total":1,"unit":"step","details":{"main_frame_count":2,"auth_frame_count":1,"shard_frame_count":0}}
{"type":"phase","id":"decrypt","label":"Decrypting and inspecting payload"}
{"type":"artifact","kind":"recovered_file","path":"/tmp/out/secret.txt","details":{"manifest_path":"secret.txt","size":42}}
{"type":"result","ok":true,"command":"recover","output_path":"/tmp/out/secret.txt","output_path_kind":"file","doc_id":"0123456789abcdef","selected_extension_index":null,"selected_extension_doc_hash":null,"expected_head_doc_hash":null,"validated_head_index":0,"validated_head_doc_hash":"89abcdef0123456789abcdef0123456789abcdef0123456789abcdef01234567","freshness_scope":null,"auth_status":"verified","input_label":"QR payloads","input_detail":"main_payloads.txt","manifest":{"format_version":1,"input_origin":"file","input_roots":[],"sealed":true,"file_count":1,"payload_codec":"raw","payload_raw_len":null},"files":[{"manifest_path":"secret.txt","output_path":"/tmp/out/secret.txt","size":42,"sha256":"0123","mtime":0}]}{"type":"started","schema_version":1,"command":"recover","args":{"operation":"inspect","config":null,"paper":null,"fallback_file":null,"payloads_file":"main_payloads.txt","scan":[],"has_passphrase":true,"shard_fallback_file":[],"shard_payloads_file":[],"shard_scan":[],"auth_fallback_file":null,"auth_payloads_file":null,"extension_index":null,"extension_doc_hash":null,"expected_head_doc_hash":null,"quiet":true,"debug":false}}
{"type":"phase","id":"plan","label":"Resolving recovery inputs"}
{"type":"progress","phase":"plan","current":1,"total":1,"unit":"step","details":{"main_frame_count":2,"auth_frame_count":1,"shard_frame_count":0}}
{"type":"phase","id":"decrypt","label":"Decrypting and inspecting payload"}
{"type":"progress","phase":"decrypt","current":1,"total":1,"unit":"step","details":{"file_count":1,"manifest_file_count":1}}
{"type":"result","ok":true,"command":"recover","operation":"inspect","doc_id":"0123456789abcdef","selected_extension_index":null,"selected_extension_doc_hash":null,"expected_head_doc_hash":null,"validated_head_index":0,"validated_head_doc_hash":"89abcdef0123456789abcdef0123456789abcdef0123456789abcdef01234567","freshness_scope":null,"auth_status":"verified","input_label":"QR payloads","input_detail":"main_payloads.txt","source_summary":{"format_version":1,"input_origin":"file","input_roots":[],"sealed":true,"file_count":1,"payload_codec":"raw","payload_raw_len":null},"frame_counts":{"main":2,"auth":1,"shard":0},"unlock":{"mode":"passphrase","passphrase_provided":true,"validated_shard_count":0,"required_shard_threshold":null,"shard_share_count":null,"satisfied":true},"blocking_issues":[],"warnings":[]}{"type":"started","schema_version":1,"command":"compact","args":{"config":null,"paper":null,"design":null,"root_dir":null,"scan":["root.pdf","extension-01.pdf"],"output_dir":"compacted","shard_fallback_file":[],"shard_payloads_file":[],"shard_scan":[],"auth_fallback_file":null,"auth_payloads_file":null,"expected_head_doc_hash":null,"allow_stale_head":true,"layout_debug_dir":null,"qr_chunk_size":null,"has_passphrase":true,"quiet":true,"debug":false}}
{"type":"phase","id":"compact","label":"Replaying source chain and preparing checkpoint"}
{"type":"progress","phase":"compact","current":0,"total":1,"unit":"step","details":{"root_dir":null,"scan":["root.pdf","extension-01.pdf"],"output_dir":"compacted"}}
{"type":"progress","phase":"compact","current":1,"total":1,"unit":"step","details":{"root_dir":null,"scan":["root.pdf","extension-01.pdf"],"output_dir":"compacted"}}
{"type":"artifact","kind":"qr_document","path":"compacted/qr_document.pdf","details":{"filename":"qr_document.pdf","size":1234}}
{"type":"artifact","kind":"recovery_document","path":"compacted/recovery_document.pdf","details":{"filename":"recovery_document.pdf","size":2345}}
{"type":"result","ok":true,"command":"compact","doc_id":"0123456789abcdef","root_dir":null,"source_scan":["root.pdf","extension-01.pdf"],"output_dir":"compacted","artifacts":{"qr_document":"compacted/qr_document.pdf","recovery_document":"compacted/recovery_document.pdf","recovery_kit_index":null,"shard_documents":[],"signing_key_shard_documents":[]},"expected_head_doc_hash":null,"validated_head_index":1,"validated_head_doc_hash":"89abcdef0123456789abcdef0123456789abcdef0123456789abcdef01234567","freshness_scope":"supplied_carriers_only"}{"type":"started","schema_version":1,"command":"config","args":{"operation":"get","config":null,"input_json":null}}
{"type":"phase","id":"load","label":"Loading config"}
{"type":"result","ok":true,"command":"config","operation":"get","path":"/home/user/.config/ethernity/config.toml","source":"user","status":"valid","errors":[],"values":{"templates":{"default_name":"sentinel","template_name":null,"recovery_template_name":null,"shard_template_name":null,"signing_key_shard_template_name":null,"kit_template_name":null},"page":{"size":"A4"},"qr":{"error":"M","chunk_size":512},"extension":{"chunking":{"target_size":16384,"min_size":4096,"max_size":65536}},"defaults":{"backup":{"base_dir":null,"output_dir":null,"shard_threshold":null,"shard_count":null,"signing_key_mode":null,"signing_key_shard_threshold":null,"signing_key_shard_count":null,"payload_codec":"auto","qr_payload_codec":"raw"},"recover":{"output":null},"extend":{"base_dir":null,"unlock_policy":null,"shard_threshold":null,"shard_count":null,"signing_key_mode":null,"signing_key_shard_threshold":null,"signing_key_shard_count":null,"qr_payload_codec":"raw"}},"ui":{"quiet":false,"no_color":false,"no_animations":false},"debug":{"max_bytes":1024},"runtime":{"render_jobs":"auto"}},"options":{"template_designs":["archive","forge","ledger","maritime","sentinel"],"page_sizes":["A4","LETTER"],"qr_error_correction":["L","M","Q","H"],"payload_codecs":["auto","raw","gzip"],"qr_payload_codecs":["raw","base64"],"signing_key_modes":["embedded","sharded"],"extension_unlock_policies":["self-contained","reuse-root"],"extension_signing_key_modes":["not-stored","sharded"],"onboarding_fields":["template_design","page_size","backup_output_dir","qr_chunk_size","qr_error_correction","sharding","payload_codec","qr_payload_codec"]},"onboarding":{"needed":true,"configured_fields":[],"available_fields":["template_design","page_size","backup_output_dir","qr_chunk_size","qr_error_correction","sharding","payload_codec","qr_payload_codec"]}}Recover can also scan QR payloads directly from PDFs, images, or directories by using --scan:
ethernity api recover --scan "/path/to/qr_document.pdf" --passphrase "correct horse battery staple" --output "/tmp/recovered.bin"--scan may be combined with either --payloads-file or --fallback-file when a recovery set
spans QR-readable artifacts and typed/transcribed text. --fallback-file and --payloads-file
remain mutually exclusive with each other.
Passphrase shard PDFs/images can be scanned separately with --shard-scan:
ethernity api recover --scan "/path/to/qr_document.pdf" --shard-scan "/path/to/shard-01.pdf" --shard-scan "/path/to/shard-02.pdf" --output "/tmp/recovered.bin"For extended backup roots, --extension-index <n> selects a specific authenticated replay target.
Use --extension-index 0 for intentional root-only recovery when the supplied extension head is not
trusted or the UI needs the original backup state. Recursive backup-root scans ignore published
extension carriers after an explicitly selected numeric index, so rollback to an earlier index is not
blocked by later carrier damage.
Use --expected-head-doc-hash <hash> with recover, inspect recover, extend, inspect extend,
or compact when the client already knows the trusted head. Commands fail closed if the validated
supplied head does not match. freshness_scope: "supplied_carriers_only" means the validated head is
the freshest authenticated head among the supplied carriers, not proof that no later carrier exists
elsewhere.
- Parse events line-by-line as they arrive
- Ignore unknown fields for forward compatibility
- Handle unknown event codes as non-fatal unless the event type is
error - Treat artifact events as success-only notifications; a failed command may still have written files
- Use artifact paths rather than assuming output filenames
- Use
output_path_kindto distinguish file outputs from directory outputs - Treat inspect
blocking_issuesas readiness guidance, not command failure - Use
api config get/setfor GUI settings management and onboarding state - Expect
api backup/api compact/api extend/api mint/api recoverto use the existing user config when present - Expect
api inspect recover/api inspect mintto avoid file writes and artifact events - Expect
api inspect extendto avoid persistent user-output writes and artifact events; successful extension readiness previews render into a temporary workspace that is cleaned up before the command returns - Prefer
codevalues for logic andmessagevalues for display - Treat stdin as opt-in for
api recover; pass--fallback-file -for typed fallback text or--payloads-file -for QR payload lines - Do not extract fallback text from PDF or image files; PDF/image recovery inputs are QR scan inputs only
extendalso accepts--unlock-policy self-contained|reuse-root.reuse-rootdisables extension-local passphrase shard emission and rejects explicit extension passphrase shard overrides for the new extension. It requires a recoverable root passphrase shard quorum, either from the shard set supplied to unlock the root backup or from authenticated root-level shard documents discovered in the backup root. Operators then unlock the extension through that root shard set. Signing authority recovery remains independent:reuse-rootemits no extension-local signing-key shards by default, but explicit--signing-key-mode shardedor signing-key shard-count options request root/chain signing authority shard documents for future extension minting. If no root or extension shard policy is available,api extendfails closed instead of emitting a plaintext passphrase recovery document by default; pass--shard-count 0only when plaintext passphrase output is intentional.
api extend and api inspect extend can also take repeatable --scan inputs containing the
root backup and extension QR-document PDFs/images. In scan mode, --root-dir is the writable
publish target for the next extension, not the source of truth for the existing chain; it may be a
fresh missing directory when its parent is writable, or an existing empty directory. To avoid mixing
scanned source material with a stale digital layout, scan-mode publishing writes a loose
extension-<index>-<doc_id> bundle directly under that target and does not create canonical
extensions/<index> output. Inspect/result payloads can report input_kind: "scanned_chain", and
started events include the scan array in schema version 1.
Because scan-mode extend can only authenticate the supplied carriers, it cannot prove that no later
extension exists elsewhere. Provide --expected-head-doc-hash <hash> to pin the trusted latest
head. If no trusted marker exists and the operator explicitly accepts the stale-head risk, pass
--allow-stale-head; otherwise inspect reports RECOVERY_HEAD_UNTRUSTED and api extend fails
closed before publishing.
api extend and api inspect extend can unlock the selected backup with passphrase shard inputs
by using --shard-fallback-file, --shard-payloads-file, or --shard-scan.
When those shard inputs appear to target published extension state but cannot be matched to the
current root chain, inspect reports PASSPHRASE_SHARDS_INVALID with
details.stage: "extension_shard_unlock" instead of treating the shard inputs as absent.
Both commands require --root-dir; without --scan, the inspect form stays read-only and targets
an existing non-symlink backup root directory.
Both commands also accept --input - for stdin-backed file content when selecting an explicit
scope.
api inspect extend accepts the same extension-policy preview knobs as api extend:
--qr-chunk-size, --layout-debug-dir, --unlock-policy, --shard-threshold,
--shard-count, --signing-key-mode not-stored|sharded, --signing-key-shard-threshold, and
--signing-key-shard-count. The inspect form validates --layout-debug-dir, preflights the
extension publish target, and render-validates pending artifacts in a temporary no-publish
workspace without creating persistent files under the publish target.
When the active design provides a compatible recovery_kit_index template, api extend emits an
extension-local recovery kit index. The index records the required root backup documents as external
dependencies because extension recovery is not self-contained. api inspect extend does not emit
artifact paths, but its readiness preview reflects the same policy by estimating the extension
payload and surfacing blocking issues when runtime preparation would fail. Designs without a
compatible template omit that optional index document.
If api extend encounters an inspect-time blocking issue while preparing the publish plan, it emits
that stable blocking_issues[].code as the command error.code. Clients should therefore handle
documented blocking issue codes on api extend error events as well as inspect result events.
For api inspect extend, result events also surface authenticated-head status:
validated_head_auth_statusvalidated_head_root_authority_verified
For a root-only head, validated_head_root_authority_verified is true only when the root AUTH
status is verified and the root-derived signing authority is present. Clients should pair this
field with validated_head_auth_status and blocking_issues before treating a head as trusted.
Recovery-valid and append-valid are intentionally different. api recover may restore content from
the available authenticated machine-readable carriers, including a degraded extension directory
whose redundant recovery_document-* PDF is missing. api extend and api inspect extend require
the published head to remain append-valid before creating another extension, so a degraded directory
can still produce a blocking issue such as EXTENSION_LAYOUT_INVALID or
RECOVERY_HEAD_UNTRUSTED. Append-valid inspection validates the required recovery_document-* PDF
as a human fallback artifact by checking that its visible AUTH and MAIN fallback sections bind to
the QR-derived extension identity; the PDF is still not used as a machine replay source.
available_extensions lists only extension entries that were authenticated and replayed as part of
the validated chain head. Layout-only discoveries remain in discovered_extension_dirs and must not
be treated as available for replay. Entries always include the numeric index alongside dir_name,
doc_id, and non-null doc_hash, plus:
auth_statusroot_authority_verified