Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

sshx Contract Freeze Policy

Agent ecosystems punish interface drift. This document is the public commitment for what is frozen in the v1 schemas and when a change requires v2.

Frozen v1 surface

Within a major schema version, changes are additive-only. Removing, renaming, or changing the meaning of a field, flag, exit code, or error_kind is a breaking change.

SurfaceFrozen namesNotes
Request schemasshx.request.v1sshx run request envelope
Run result schemasshx.result.v1Single-target run; compatibility command JSON retains its legacy fields
Plan schemasshx.plan.v1Nested in existing previews; does not replace sshx.request.v1
Event schemasshx.event.v1JSONL run_started / target_started / target_finished / run_finished
Host inventorysshx.hosts.v1--host-list and host mutation/test JSON
Secretssshx.secrets.v1--password-check / --password-list / --password-set JSON
Audit eventssshx.audit.v1One JSONL object per non-dry-run invocation
Audit querysshx.audit.query.v1sshx audit query/export --json
Text dissectionsshx.text.v1sshx text --json; help document is sshx.text.help.v1
Exit codes0, 1..254, 255Remote status vs sshx-level failure
JSON sshx failureexit_code: -1Distinguishes a remote exit 255
error_kindtimeout, auth, host_key, connect, blocked, exit_missing, config, error, plus SQL/apply additions including unreproducible_select, full_table_backup_requires_opt_in, and parent_directory_not_writableBranch on this field, not prose
JSONL event typesrun_started, target_started, target_finished, run_finished

CLI flags listed in sshx --help for a released minor version remain valid for the rest of that major line. New flags may be added. Required flags must not be introduced for an existing invocation shape.

Compatibility policy

  • Additive fields may appear on v1 documents at any time. Agents must ignore unknown fields.
  • A breaking change requires a new schema (sshx.result.v2, …) and an N-1 support window: the previous schema remains emitted or accepted until the next major sshx release after the new schema ships.
  • --json stdout stays a machine document. Human logs belong on stderr, and sshx never writes human text to stdout, including on failure.
  • stderr carries human notices (deprecation warnings, narration, progress) and, outside --json, the diagnostic for a failed invocation. --quiet (--no-notices) suppresses the notices; with it, a caller that merges the streams (2>&1) under --json still reads exactly one document, in both the success and the failure path. Merging stderr without --quiet is not supported for parsing.
  • Per-verb discovery is part of the contract: every subcommand answers sshx <verb> --help, and sshx <verb> --help --json emits the same blocks as an sshx.help.v1 document (sshx text --help --json keeps its structured sshx.text.help.v1 document).
  • --help and --quiet are recognized in option position, in any order: sshx -h=<host> -p=22 --help prints the global usage without resolving a host, connecting, or touching the trust store. Once the remote command, SQL statement, or -- separator starts, a later --help/--quiet belongs to the payload.
  • MCP tools return the CLI JSON verbatim. MCP does not grow a parallel schema.

Additive execution hardening

Plans, Outcomes, and Safe Retries defines --expect-plan, scalar risk and effects, execution identity/fingerprint, nullable execution observation, verification, deadlines and safe retry decisions. These fields do not redefine legacy intent, changed, force, completion, or exit status. New plan_mismatch, plan_unresolved, cancelled, and verification_failed categories are additive; parse categories, not error prose.

Do not assume every historical JSON response had a schema tag or the same envelope. Run, apply, SQL, inspection, compatibility command and file operations retain their domain-specific payloads. Common metadata is additive, not a replacement JSON object. JSONL event names remain unchanged.

1.0 evidence gates

1.0 is not a date or a blanket checked box. Each gate needs evidence:

GateEvidence and remaining boundary
CLI/MCP contract parityinternal/app/mcp_test.go, tests/e2e/mcp_e2e_test.go; malformed streams and shutdown require their own tests
Windows correctnessNative CI jobs, not a cross-build; POSIX permissions, login and signals are not Windows guarantees
Secret backend lifecycleinternal/keyringstore plus isolated native-keyring runs; the e2e backend does not prove native integration
Frozen JSON/JSONL and exitsContract fixtures and compiled-binary tests; legacy envelopes must remain consumable
Mutation/recovery evidenceReal file/SQL state and backup checks; mocked SQL counts do not prove engine transactions

See the acceptance matrix for concrete test paths and named prerequisites. A test existing in the tree does not mean it ran on every platform.

Until 1.0, minor versions may still add first-level capabilities. They must not break the frozen names in this document.