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>
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 devicesreads the typed DEVICE group, and--device-json FILEreplaces the user-owned Device settings without device access. Server-ownedlearned_read_parametersare preserved and incoming values for them are ignored. Device settings and Auto read order explain the fields and give JSON examples.archive write tape formatresolves the selected device's defaults at this Media operation.--format ltfs_v1|tar_pax_v1,--record-mode,--record-bytesand--hardware-compression true|falseoverride them as Tar write options describe; LTFS rejects tar options.--barcodeis 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 appenduses the registered profile and rejects conflicting explicit options.restore run tape, Tapeverify runandscan runtake--device, an optional--media-idhint 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
encryptscript owns it, and Media output carriesencryption_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.