Thalix VaultDocumentation
Browse documentation
Users
publishedimplementedEdit this page

Automation and JSON output

Every tv command that supports --json writes one newline-delimited JSON document (two, for tv login --browser's pending/authenticated pair) to standard output per invocation, and reports failure as a non-zero exit code with a JSON error object on standard error. Human-readable output is the default; nothing below changes when --json is omitted except formatting.

The envelope

Every success document carries the shared schemaVersion field:

{ "schemaVersion": 1, "command": "version", "...": "..." }

schemaVersion is 1 for every implemented command today; automation should check it before trusting the rest of the shape, since it is the compatibility signal for future breaking changes. Every failure document carries the shared error shape instead:

{
  "schemaVersion": 1,
  "error": { "code": "AUTHENTICATION_REQUIRED", "message": "...", "correlationId": "..." }
}

error.code is one of the stable machine codes in the table below — never a free-text string. error.message is safe to print but not safe to pattern-match; match on error.code instead. error.correlationId is present on every JSON error (and is null only for IDENTITY_NOT_ALLOWED before the safe-correlation boundary in the device-authorization login path is reached).

Exit codes

Exit codeMeaning
0Success.
1Unexpected local/internal failure without a mapped CliError.
2Usage or INVALID_REQUEST error: missing/conflicting flags or malformed local input.
3Authentication and mapped backend/domain errors. Branch on error.code, not the numeric exit code alone.
130The interactive tv login prompt (email or password) was cancelled (Ctrl-C) before completion.

Verified from this build (tv nonsense, a usage error, and tv whoami with no session, an authentication error):

$ tv nonsense; echo "exit=$?"
Error: Unknown command: nonsense
Run tv help for commands.
Correlation ID: 80d3fc27-2f01-420c-8d43-7b01f83ec1c7
exit=2

$ tv whoami --json; echo "exit=$?"
{"schemaVersion":1,"error":{"code":"AUTHENTICATION_REQUIRED","message":"Run tv login before using tv whoami.","correlationId":"9ec9dec8-90a9-4741-946a-bdd7f6ade22f"}}
exit=3

Correlation IDs

A correlation ID connects one operation across every boundary it actually reaches: CLI output, service-boundary evidence, and a database audit event, when those records exist. Local-only failures (a usage error, a pre-network failure) still return a safe, generated correlation ID, but imply no server or database record — a correlation ID supports lookup, it does not promise every layer produced one. See Incident investigation for a worked example reconstructing an operation end-to-end from its correlation ID, and Audit and observability for the full boundary contract.

Login JSON streams

Password sign-in (--user <email> --password-stdin --json) writes exactly one JSON document on success:

{"schemaVersion":1,"command":"login","status":"authenticated","expiresAt":"...","scopes":["account:read"],"tokenPrefix":"tv_...","correlationId":"..."}

The password itself is never accepted as a command-line argument and never appears in any output; pipe it on standard input as exactly one line. --json without --user/--password-stdin is a usage error (exit 2).

The fallback browser flow (tv login --browser --json) is the one invocation that writes more than one JSON line:

{"schemaVersion":1,"command":"login","status":"authorization_pending","userCode":"...","verificationUriComplete":"...","expiresAt":"...","correlationId":"..."}
{"schemaVersion":1,"command":"login","status":"authenticated","expiresAt":"...","scopes":["account:read"],"tokenPrefix":"tv_...","correlationId":"..."}

Neither line contains the device code or the issued token. Consumers must parse stdout one line at a time and wait for status: "authenticated" before treating login as complete.

Confirmation boundaries

Automation may pass --yes only on commands that document it (currently tv file move). A script should log its own intent and retain the returned correlationId for every access-reducing, update, or administrative call, so a human can look it up later in tv admin audit list.

Stable error codes

Every code below is a literal error.code value from packages/contracts/src, grouped by the command family that returns it. INVALID_REQUEST and INTERNAL_ERROR are common to every family and are not repeated in each row.

Session (tv login / tv whoami / tv logout)

CodeMeaning
AUTHENTICATION_REQUIREDNo valid session on disk.
INVALID_CREDENTIALSUnknown email, wrong password, or an account without a password — deliberately identical for all three so sign-in cannot enumerate accounts.
AUTHENTICATION_FAILEDThe device/browser handshake did not produce a valid session.
IDENTITY_NOT_ALLOWEDThe signed-in identity is not permitted to use tv.
ACCOUNT_DEACTIVATEDThe account or organization membership is deactivated.
RATE_LIMITEDToo many attempts for this email, or too many organization-wide (per-email and global counters); wait and retry later.
SESSION_STORE_UNAVAILABLEThe local credential file could not be read, written, or verified.
AUTHORIZATION_PENDING(device flow) Waiting on browser approval; keep polling.
SLOW_DOWN(device flow) Poll less frequently.
AUTHORIZATION_DENIEDThe browser approval was explicitly denied.
DEVICE_CODE_EXPIREDThe one-time device code expired before approval.
INVALID_DEVICE_CODEThe device code is unknown or already consumed.
SCOPE_DENIEDThe token's scope does not permit the requested operation.
INVALID_BACKEND_RESPONSEThe backend returned a shape the CLI does not recognize.

Update (tv update [--rollback])

See Command reference and Install and update from a private Git checkout for the full per-path refusal-code table (UPDATE_* for a checkout install, RELEASE_* for a standalone install).

Files (tv file *)

CodeMeaning
FORBIDDENAuthenticated, but not permitted to act on this Root Folder/organization scope.
ACCOUNT_DEACTIVATEDThe acting account is deactivated.
NOT_FOUNDNo file with sufficient access exists at this ID (anti-enumeration: identical for "doesn't exist" and "exists but you can't see it").
FOLDER_NOT_FOUNDThe named Root Folder does not exist.
FOLDER_INACTIVEThe named Root Folder is deactivated.
FILE_NAME_INVALIDThe uploaded filename failed validation.
FILE_MIME_TYPE_INVALID--mime-type is not a well-formed MIME type.
FILE_DESCRIPTION_INVALID--description failed validation.
FILE_METADATA_INVALIDA --meta/--set value does not match its field's type or choices.
FILE_VERIFICATION_INVALIDThe backend's own re-measurement of an uploaded object did not match.
FILE_ARCHIVEDThe command is refused because the file is archived (metadata updates and new content versions are rejected on an archived file; restore it first).
FILE_COMMIT_CONFLICTA concurrent commit already advanced this file's version.
FILE_UPLOAD_FAILEDThe upload to object storage failed.
FILE_CHECKSUM_MISMATCHThe downloaded or uploaded bytes' SHA-256 did not match the declared value.
FILE_SIZE_MISMATCHThe downloaded or uploaded byte count did not match the declared value.
FILE_SEARCH_FILTER_INVALIDA tv file find filter is malformed or self-contradictory.
FILE_UPDATE_REASON_REQUIREDtv file update/archive/restore requires --reason/--set/--unset.
FILE_METADATA_REQUIREDA required metadata field was not supplied.
FILE_METADATA_INCOMPATIBLEA metadata value is incompatible with a field that changed since it was set.

Access (tv file access * / tv folder access *)

CodeMeaning
FORBIDDENNot permitted to grant/revoke/list at the requested scope.
NOT_FOUNDAnti-enumeration not_found for a file you cannot manage.
USER_ROLE_INVALIDtv admin user role given a role other than admin/user.
FOLDER_NOT_FOUNDNamed Root Folder does not exist.
FOLDER_INACTIVENamed Root Folder is deactivated.
GRANT_LEVEL_INVALID--level is not read/write/manage.
GRANT_SUBJECT_NOT_FOUNDThe --user/--group grant subject does not exist.

Groups (tv group *)

CodeMeaning
GROUP_NAME_INVALIDGroup name failed validation.
GROUP_NAME_CONFLICTThe caller already owns a group with that name (names are unique per owner, not organization-wide).
GROUP_NAME_AMBIGUOUSThe caller belongs to more than one group with that name (different owners); a unique identifier is required.
GROUP_NOT_FOUNDAnti-enumeration: no group by that name is visible to the caller, or it genuinely does not exist.
GROUP_MEMBER_NOT_FOUNDThe target email is not a member of the group.
GROUP_ROLE_INVALIDThe role is not owner/manager/member, or the caller cannot assign it (a manager promoting to owner).
GROUP_ALREADY_MEMBERThe invited email already belongs to an active member of the group.
GROUP_INVITATION_NOT_FOUNDAnti-enumeration: the invitation ID does not resolve to a real, still-pending invitation the caller may act on.
GROUP_INVITATION_ALREADY_RESOLVEDThe invitation was already accepted, declined, revoked, or has expired.
GROUP_LAST_OWNERThe action would leave the group with zero active owners.
GROUP_TRANSFER_TARGET_NOT_MEMBERtv group transfer named someone who is not already an active member.

Group administration (tv admin group *)

CodeMeaning
FORBIDDENNot an administrator.
NOT_FOUNDThe group does not exist.
GROUP_MEMBER_NOT_FOUNDThe target email is not a member of the group.
GROUP_TRANSFER_TARGET_NOT_MEMBERtv admin group transfer named someone who is not already an active member.
GROUP_OWNER_DEACTIVATION_BLOCKEDtv admin user deactivate was refused because the subject solely owns a group that still has other active members; transfer ownership first.

Root Folders and metadata (tv folder * / tv metadata * / tv admin folder * / tv admin metadata *)

CodeMeaning
FORBIDDENNot an administrator.
ACCOUNT_DEACTIVATEDThe acting account is deactivated.
NOT_FOUNDNamed Root Folder/definition does not exist.
FOLDER_NAME_INVALIDRoot Folder name failed validation.
FOLDER_NAME_CONFLICTA Root Folder or subfolder with that name already exists in the same location (owner for a root, parent for a subfolder), including a deactivated one — retired names stay reserved.
FOLDER_PARENT_NOT_FOUND--parent names a folder that does not exist, is in a different organization/root, or that the caller lacks live manage access to — deliberately indistinguishable from a nonexistent parent.
FOLDER_DEPTH_EXCEEDEDThe parent is already at the maximum nesting depth (32); the child would exceed it (on create or move).
DEFAULT_FOLDER_PROTECTEDThe default Root Folder ("My Files") cannot be deactivated or archived.
FOLDER_ROOT_IMMOVABLEtv folder move was given a root -- only a subfolder may move; a root may only be renamed.
FOLDER_CROSS_ROOT_MOVEtv folder move --parent names a folder in a different root tree; a subfolder may move only within its own root.
FOLDER_CYCLE_DETECTEDtv folder move --parent would self-parent the folder or make it a child of its own descendant.
FOLDER_NOT_EMPTYtv folder archive was given a folder that still contains a file or a child folder, active or archived.
FOLDER_PARENT_INACTIVEtv folder restore was refused because a folder in its parent chain is not active.
FOLDER_REASON_INVALID--reason on a rename/move/archive/restore is empty, over 500 characters, or contains a control character.
METADATA_KEY_INVALIDkey failed validation.
METADATA_KEY_CONFLICTA definition with that key already exists.
METADATA_LABEL_INVALID--label failed validation.
METADATA_TYPE_INVALID--type is not text/number/boolean/date/choice.
METADATA_CHOICES_INVALID--choice values failed validation.
METADATA_CHOICE_MUTATION_INVALID--add-choice/--remove-choice given for a non-choice field, or would remove a choice in use.
METADATA_INACTIVEThe definition is deactivated.

Audit (tv admin audit list)

CodeMeaning
FORBIDDENNot an administrator.
ACCOUNT_DEACTIVATEDThe acting account is deactivated.
AUDIT_FILTER_INVALIDA filter combination is malformed (bad --limit, --cursor, date, or enum value).

Agent Skill (tv skill *)

CodeMeaning
SKILL_BUNDLE_NOT_FOUNDNeither a linked Git checkout's disk payload nor a standalone binary's embedded payload could be located (a compiled release binary embeds its own skill bundle, see Agent Skill).
SKILL_NO_REPOSITORY--scope project requested outside a Git repository.
SKILL_NOT_INSTALLEDtv skill update found no prior install for this target/scope.
SKILL_MODIFIED_FILESInstall/update would overwrite files changed outside tv; retry with --backup-and-replace.
SKILL_MANIFEST_CORRUPTThe install's manifest file is not valid JSON matching the expected schema.

Compatibility

Every implemented command's JSON documents are schema version 1 today. Production backend-compatibility negotiation (comparing tv version --json against an authenticated backend response) remains planned.