Files
yatm/docs/operations/cli.md
T
Samuel CuiandClaude Opus 5.5 97faae0d78 Document tar Tape operation, architecture and research
Organize documentation by audience: packaged user guides in docs/operations
(including Devices, Tape scripts, Auto read order, Jobs, offline migration and
tar recovery), contributor procedures in docs/development, maintainer release
procedures in docs/release, current behavior in docs/architecture (now with
separate Tape and read-planning documents) and evidence in docs/research. Each
rule keeps one owner and other pages link to it; the document checker, the
packaged guide allowlist and their tests follow the new layout. The documents
land together because the new guides and index link to each other.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 15:16:41 +08:00

14 KiB

Command-Line Reference

The yatm-cli executable is the scripted and agent-facing surface. It calls the same gRPC and HTTP API the browser does, so a CLI request carries no separate server semantics; Interface contracts owns the rules shared with those surfaces.

Agents and Connection

The bundled Skill routes agent work to command domains and defines operating rules. It ships inside the release package beside the operations guides that own the workflows. Agents read the matching installed --help down to the selected command for its inventory, arguments and flags, and interpret its JSON output as the operational source of truth. The Skill's domain table does not duplicate the installed command inventory; this document owns the surface rules.

Connection settings are global flags or their YATM_* environment variables: --server, --timeout (0 removes the deadline), --basic-user and --basic-password-file. Registered Location paths, Volume mount points and Tape devices are paths on the server; --input, --output and --basic-password-file are paths on the machine running the agent.

Unary replies print protobuf JSON, and streaming operations print JSON Lines with one item result per line and a final summary. A Files listing is the one stream with no summary: it writes one message per batch as the server produces it, so a reader sees the first rows before the read finishes. Exit status distinguishes intent from execution: 0 succeeded, 1 failed at runtime, and 2 rejected the command as a usage or safety error. An executed stream that settles with failed, unprocessed or publication-pending items exits nonzero even when the request itself completed. A completed --dryrun plan succeeds even though its proposed entries remain UNPROCESSED; planning failures and pending Library publication still exit nonzero.

A read that returns a complete directory takes no page size and no cursor; those flags belong to the query form of the same command, which returns one bounded page and the cursor that continues it. Passing either for a complete read is a usage error rather than a silently ignored argument.

Long work belongs to a Job, and a waiting command always has a timeout. Physical decisions such as choosing a device, loading Media, formatting, or continuing writes stay explicit rather than implicit in another command. There is no file or Preview download command; full archived content is obtained through Restore. The CLI has no command for an operation the API does not expose.

Instant fields in JSON use decimal strings and names ending in _ns, following the shared time contract. Preserve them as signed 64-bit integers when processing output. Restore --before accepts a timestamp with its stated timezone and retains its nanosecond precision; dates outside the supported range are usage errors.

job wait succeeds for a durable COMPLETED Job whose phase is COMPLETED or UNSPECIFIED, including after a service restart. It keeps waiting while an attached runner reports QUEUED for an admitted attempt waiting for shared Media resources, or a finalizing phase. An idle READY Job reports UNSPECIFIED and requires an explicit Media choice; the Job lifecycle defines which failures return a Job to READY and which are terminal. Waiting returns nonzero with action_required for FAILED or idle READY, including the persisted error when present.

archive creation ID, restore creation ID and scan creation ID call their kind's read-only GetCreation method once and print its typed response. request contains the retained creation inputs; a nonempty unavailable_reason explains missing original inputs that require reselection. Reading does not create a Job or change the old Job. Review the selections and options, resolve missing inputs, and explicitly use the normal Create flow with its current validation and pre-submit checks to submit new work.

identical groups and identical members include a disposable result_id in their first reply. Later pages require --result ID with the returned cursor; an unavailable ID fails and requires a new Find instead of silently repeating the complete search. identical find returns the same kind of ID and both row counts for identical rows --result ID --offset N; identical positions locates File IDs within both hidden-file projections, and identical close releases the result. An idle result expires after 30 minutes and does not survive a service restart; run Find again if it is unavailable. Row pages default to 100 and accept at most 200 rows; group and member CLI pages default to 20. identical rows and identical positions accept the same --sort-key file-id|name|size and --order asc|desc. The default is File ID ascending; name starts ascending and size starts descending when selected. Row pages and position lookups use the same requested order under the Library sorting contract. These reads never scan or hash physical files.

job log reads a raw bounded byte page and returns JSON with text in logs and the next byte offset as a decimal string in offset. Follow that returned offset, not the text's character count; an empty logs ends the read. This CLI representation does not Base64-encode the log, although the underlying RPC uses a protobuf bytes field. JSON text can replace invalid UTF-8, including a character split by a byte-page boundary; preserve the original Job bundle's job.log when exact bytes are required. job log-lines reads a line page from the tail or a returned byte cursor, toward older or newer content, with optional exact --level and case-insensitive --query filters. The server owns page limits; the CLI supplies no limit. An empty filtered page can still advance its cursor, so use the returned has_older and has_newer flags to continue. Continuation fragments can appear as context when their line start lies outside the bounded read, even if that fragment does not establish a filter match.

library export retains streamed delivery. Reported HTTP or transport failures return nonzero; named-file output is published only after the response is received and the file is closed. The CLI does not validate the JSONL end record. In particular, close-delimited HTTP/1.0 can make an interrupted download appear complete; import still rejects the missing end record. Stdout may contain a partial stream on failure, so its exit status must be checked.

The separate standalone export tool opens the configured local Catalog and delegates to the same Library snapshot writer. Its default selection is file,media,position; related version groups follow Library selection rules. This selected export omits Location/original groups and Settings, so it is not a complete installation backup. Unknown or empty comma-separated type names fail before opening configuration, Catalog or output. Named regular-file output is staged in the same directory and replaces the resolved target only after export, resource cleanup, file synchronization and close succeed; failures retain the previous backup and remove the owned staging file. Existing permission bits and final symlink targets are preserved; replacement creates a new inode, so other hard links retain the old file. New files keep the normal creation mode and process umask. Stdout and explicitly named device/pipe outputs remain streaming and can contain partial data on failure. Interrupt and termination signals cancel the operation cooperatively. Signal interception is released after the first cancellation, so a later signal can terminate an operation blocked in an OS call. Cooperative cancellation runs normal cleanup; forced termination cannot guarantee it.

Directory paths

ls accepts one optional positional directory operand. A bare ls selects the Library root. /Photos/2026, Photos/2026, ./Photos/2026 and library:///Photos/2026 all select the same logical directory relative to that root. The CLI has no persistent working directory, never uses the client's PWD to resolve the operand, and never falls back from a failed lookup to filesystem paths. Positional path syntax applies only to ls; du, mv, mkdir, rm and other commands retain their existing arguments and flags.

location://NAS/DCIM selects DCIM relative to the registered root of the Location whose full, case-sensitive display name is exactly NAS. Both location://NAS and location://NAS/ select that Location's root. --server still selects the YATM server; the URI's Location name is not a network host. Missing or duplicate display names fail resolution. Use --location-id ID --path PATH to select an ambiguous name by ID. Lookup enumerates existing registrations in bounded pages and compares names exactly, including Unicode names, without a fuzzy text filter, aliases or a display-name uniqueness constraint.

The existing ID selectors remain available: --file-id selects a Library directory, and --location-id with optional --path selects a registered Location directory. A positional operand is mutually exclusive with either ID selector and with a nonempty --path. More than one directory operand is a usage error.

Plain paths are literal and are not percent-decoded; a colon alone does not select a URI, so library:2026 names an ordinary Library directory. URI components are percent-decoded once; encode literal %, ? and # as %25, %3F and %23. Quote operands containing spaces for the shell. A percent-encoded slash in a Location name is rejected. After URI decoding, or directly for a plain path, . and .. segments are normalized within the selected root; traversal above that root is rejected.

Library path resolution uses existing API reads and compares each candidate directory name by exact bytes; a fuzzy search match alone never establishes identity. Resolution and the final List or Search share one command context and the global --timeout deadline. No API, entity or storage changes are required for path lookup.

Ordinary ls still reads a complete directory, without --limit or --cursor. --query selects a paged Search within the resolved directory. --recursive also selects a paged Search over a Library subtree, even without a query expression. Both search forms accept --limit and --cursor. An unreadable child remains in List output with error and no actionable reference. The command drains the remaining rows, then returns the existing failure exit code with code: incomplete; directory or transport failures retain their own errors. Supported filenames are legal UTF-8, including literal backslashes, whitespace and control characters. Non-UTF-8 names are escaped for display only and are not usable path operands. Quote shell operands so the shell preserves their bytes. The Library guide shows usage.

Reports and mutations

The shared rule owns which commands report under --dryrun, what a report contains and which operations are excluded. This surface adds only where the CLI differs: archive write tape format keeps --confirm-format, because confirming the Tape barcode authorizes a write to a device rather than a dry-run decision, and a report needs no follow-up command — the same command without --dryrun performs the resolved work.

Tape Commands

  • settings devices reads the typed DEVICE group, and --device-json FILE replaces the user-owned Device settings without device access. Server-owned learned_read_parameters are preserved and incoming values for them are ignored. Device settings and Auto read order explain the fields and give JSON examples.
  • archive write tape format resolves the selected device's defaults at this Media operation. --format ltfs_v1|tar_pax_v1, --record-mode, --record-bytes and --hardware-compression true|false override them as Tar write options describe; LTFS rejects tar options. --barcode is normalized to six uppercase letters or digits and requires an exact --confirm-format. Registered Media and identity conflicts stop before writing, and FORMAT erases the cartridge even when its cartridge memory barcode is empty.
  • archive write tape append uses the registered profile and rejects conflicting explicit options.
  • restore run tape, Tape verify run and scan run take --device, an optional --media-id hint and --refresh-position-map (default false). Without a hint, the server identifies the Tape by its cartridge memory barcode; a hint never bypasses physical verification. Load Tape for Restore or Scan describes both options.
  • No command sets encryption: the configured encrypt script owns it, and Media output carries encryption_key_saved, never the key. The Device's read order applies to each read attempt, and the Job log records the requested and effective order with any fallback reason.

Tape Device Diagnostics

tape device list prints every configured Tape entry with its busy status and detail; listing sends no SCSI commands. tape device inspect --device DEVICE explicitly requests passive diagnostics as protobuf JSON. Absent facts stay absent, and inspection never loads, positions or modifies the cartridge. media inspect tape is the separate cartridge identification operation; it uses the configured LTFS adapter and can load the cartridge. Inspect a Device explains the reported fields.