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

API reference

Module functions syq.cp, syq.rm, and syq.map use a default Client. AsyncClient has the same arguments and result types; await its operations except map, which returns an async context manager.

Client and executable selection

Client(*, executable=None, cache_dir=None, process_cwd=None, env=None, timeout=None) and AsyncClient(...) accept:

ArgumentMeaning
executableCustom executable path, or name to find on PATH; default: managed syq
cache_dirManaged executable cache root
process_cwdLocal subprocess working directory; default: inherit
envSubprocess environment mapping; default: inherit
timeoutOperation timeout in seconds; default: no limit

client.version() returns the executable version as text. syq.version(executable=None) does the same without a client. syq.managed_executable(cache_dir=None) returns the verified executable path, downloading it if needed. See Compatibility for version selection and caching.

Arguments and validation

Options use CLI names with hyphens replaced by underscores. Python keywords get a trailing underscore: from_, as_. Paths accept str, bytes, or os.PathLike; selector keywords accept one path or an iterable of paths. Use src=["a", "b"] for CLI --srcs a b, and likewise src_non_dir and src_dir.

Shared by cp, rm, and mapMeaning
*sources, srcSelect named objects
srcs_inSelect a directory’s contents
src_non_dir, src_dirRequire non-directory objects or directories
cwdSource resolution base; may be remote for cp and rm
rootConfine source resolution beneath this directory; requires relative selectors; conflicts with cwd
follow, follow_srcFollow source symlinks; follow also enables destination following for cp
timeoutOmitted: use client default; None: no timeout; number: timeout in seconds

Boolean flags default to False; other optional arguments default to None, except check=True and timeout, whose omitted value inherits the client default. Invalid argument combinations raise SyqInvocationError; filesystem and remote checks happen in syq.

cp

cp(*sources, **options)CpResult copies files. Choose one placement option. In addition to the shared arguments above, it accepts:

OptionsValues / purpose
from_, toSSH endpoint strings; omitted endpoints are local
into, into_new, into_existingDestination directory paths
as_, as_new, as_existingExact destination paths
mappingMapping, MapStream, manifest path, or iterable of MappingEntry; replaces selectors; conflicts with as_* and prune. Async clients also accept AsyncMapping and async iterables
follow_dstBoolean: follow destination symlinks
prune, dry_run, hash, verify_onlyBoolean: mirror, preview, compare content, or verify without copying
only_new, only_existing, skip_newerBoolean: copy missing entries, copy existing entries, or skip newer destination files
ignorePattern string, IgnoreFrom(path), or ordered iterable of either
ignore_fromRule file path or iterable of paths; applied after ignore
preservePreservation string or iterable of strings
inplace, no_compressBoolean: update destination files in place or disable compression
bwlimit, min_size, max_sizeNative rate/size strings or integers
max_deleteNonnegative integer deletion limit; requires prune=True
connectionsPositive integer connection count
auth_from, viaCredential source string; aliases, so use only one
coordinate_at, rsh, peer_authCoordinator, SSH command, and peer authentication strings
pscopeExisting ephemeral scope path for forward SSH connection reuse
syq_pathRemote executable path
no_bootstrap, tcp_plain, no_tcpBoolean remote/transport controls
tcp_ports, tcp_congestionPort range and congestion-control strings
receiver_max_entries, receiver_max_bytesReceiver ceilings: integer entries, native size string or integer bytes
receiver_receipt"sizes" or "digests"
on_event, results, checkSee events and failures below

Option behavior is covered in Copy files and Remote copy details.

pscope selects an isolated scope for reusing SSH connections. For return copies or commands, use syq persist connect server and omit pscope. See persistence in scripts for setup and cleanup, and Compatibility for executable selection.

Typed remote-to-remote copies require an enrolled receiver or coordinate_at="local". With dry_run=True or verify_only=True, they require coordinate_at="local". Use run for detached commands and human output options.

IgnoreFrom(path) is a frozen dataclass holding a rule-file path (str, bytes, or os.PathLike). To interleave rule files and inline patterns: ignore=[syq.IgnoreFrom("rules"), "!keep.tmp"]. The last matching rule wins.

With only_new=True, directories already present when syq first checks them keep their metadata. Missing children are still added. Adding children may naturally change directory timestamps. Directories copied as new receive normal copy metadata. When several sources supply the same new directory, the last source supplies its metadata, just as without only_new=True. Adding children to those existing directories requires write access; permissions are not temporarily widened. Permission failures are reported in the result and raise SyqOperationError unless check=False. A dry run does not test write permission.

rm

on="server" selects the removal endpoint. A final selected symlink is always unlinked. Both follow_src=True and follow=True permit symlinks in cwd, root, and selector parent directories. Directory and contents selectors reject a final symlink even with following enabled.

rm(*sources, **options)RmResult removes selected entries. Besides the shared arguments, it accepts on, dry_run, connections, syq_path, no_bootstrap, pscope, on_event, results, and check with the types above. It supports local and ordinary SSH endpoints. Command-restricted receivers reject removal. See Remove files.

map

map(*sources, **options) → MapStream lists local mapping entries without copying. Besides the shared arguments, it accepts as_ to rename a selected object. srcs_in must be the sole selector when used.

MapStream is a Mapping and an iterable context manager; use with. AsyncMapStream is an AsyncMapping and an async context manager; use async with. Streams must be consumed inside their context and cannot be reused after completion or closure. Async streams capture the producer directory, environment, and timeout when created, even though execution starts later.

Mapping and AsyncMapping

A mapping combines entries with their local source context. Pass it directly to cp(mapping=...), even on a client with a different process_cwd.

Mapping(entries, *, cwd=None, root=None, follow_src=False) accepts an iterable of MappingEntry. AsyncMapping(...) accepts an async iterable. If both cwd and root are omitted, the source base is the current directory at construction. Otherwise exactly one may be supplied. Relative cwd and root paths resolve against the Python process directory at construction, not a client’s process_cwd. root confines source resolution.

MemberTypeMeaning
cwdpathlib.PathAbsolute source-base spelling, preserving symlinks and ..
rootpathlib.Path or NoneConfinement base, when created with root
follow_srcboolWhether the copy should follow source symlinks
transform(function)Mapping or AsyncMappingLazy transformation that keeps the source context

The context properties are read-only. A transform receives each MappingEntry and returns a replacement entry, or None to omit it. Transformations can be chained. Async transforms also accept awaitable callbacks and await them in entry order. Neither form caches entries; reuse depends on the supplied iterable.

A context-carrying mapping rejects from_, cwd, and root overrides on cp. It automatically enables the source-following policy used by map; enabling follow or follow_src on the copy is also permitted. The destination options remain independent. map(root=..., srcs_in=...) carries the selected directory as the consuming copy’s root. The copy resolves that root again; it does not inherit an open directory handle or a snapshot of the source tree.

MappingEntry

Frozen dataclass describing one source-to-destination mapping. Pass an iterable of these to cp(mapping=...); use dataclasses.replace to change an entry.

AttributeTypeMeaning
srcRelativePathPath relative to the copy’s source base
dstRelativePathPath relative to the destination container
kindEntryKind or NoneObject kind, when known; default None
sizeint or NoneInformational size in bytes; default None
mtimeint or NoneInformational modification time in Unix seconds; default None

MappingEntry(src, dst, kind=None, size=None, mtime=None) also accepts text or byte paths for src and dst and converts them to RelativePath. size and mtime do not impose preconditions on the copy.

RelativePath and PathValue

RelativePath(value) accepts text, bytes, or os.PathLike. It rejects empty paths, absolute paths, NUL bytes, and empty, . or .. components. Join paths with /, for example syq.RelativePath("archive") / entry.dst.

PathValue(raw: bytes) holds a path received in an event, which may be absolute. Both types are immutable and provide:

MemberTypeMeaning
rawbytesOriginal filename bytes; also returned by bytes(path)
textstrUTF-8 decoding; raises UnicodeDecodeError for invalid UTF-8
str(path)strFilesystem decoding with os.fsdecode
PathValue.displaystrSame as str(path)

RelativePath also implements os.PathLike, returning bytes.

Normal end of stream iteration checks the mapping process status. Leaving its context early stops the process. An exhausted or closed stream cannot be copied as an empty mapping.

For cp(mapping=iterable), the entire iterable is saved to a temporary manifest before copying starts. An iteration, transformation, or serialization failure starts no copy. Plain iterables and manifest paths have no source context; pass cwd, root, or from_ explicitly as needed. See mapping rules.

Events and terminal results

cp and rm return frozen dataclasses after validating the complete results stream and process exit status. A truncated stream raises even if the process exits successfully. Dry runs return the same types, with planned totals.

CpResult

Returned by cp(), or available as SyqOperationError.result after an unsuccessful copy. Read attributes directly, for example result.files_transferred. It includes the common result fields below plus:

AttributeTypeMeaning
files_transferredintRegular files transferred
files_unchangedintRegular files skipped as unchanged
files_excludedintFiles excluded from copying
directories_createdintDirectories created
symlinks_createdintSymbolic links created
specials_createdintSpecial filesystem objects created
bytes_transferredintFile-content bytes transferred, not compressed network traffic
bytes_unchangedintBytes in unchanged files
deletions_plannedint or NoneEntries selected for pruning
deletions_completedint or NoneEntries pruned
deletions_blockedint or NonePruning deletions blocked by a safety limit
receiptReceiptSummary or NoneVerified receiver receipt details; None for ordinary copies

With dry_run=True, mutation totals describe planned changes. With verify_only=True, matching files count as unchanged; transfer and creation totals are zero. A failed call reports work completed before it stopped.

Ordinary copies have all three deletion fields only with prune=True; otherwise they are None. Receiver-attested results have only deletions_completed, and their unchanged/excluded totals are always zero because the receiver cannot observe source-side skips. receipt is None for ordinary copies.

RmResult

Returned by rm(), or available as SyqOperationError.result after an unsuccessful removal. It includes the common result fields below plus:

AttributeTypeMeaning
selectors_totalintExplicit source selectors supplied
selectors_resolvedintSelectors that resolved to an object
selectors_missingintSelectors already missing; this is not an error
entries_plannedintEntries a dry run would remove; zero in live runs
entries_removedintEntries removed; zero in dry runs
entries_already_absentintEntries gone by removal time; zero in dry runs
entries_failedintRemoval or inspection failures, including during dry runs
modestrAlways "rm"

Selectors identify requests; entries count individual filesystem objects. One directory selector can account for many entries. Duplicate and overlapping selectors have separate indexes.

Common result fields

Both CpResult and RmResult include:

AttributeTypeMeaning
statusOperationStatusOutcome from the table below
exit_codeintsyq process exit code
dry_runboolWhether this was a preview
errorsintCounted errors
elapsed_msintRun duration in milliseconds
protocolProtocolMetadataAutomation envelope; also present on every event

ProtocolMetadata

Frozen dataclass accessed through result.protocol or event.protocol. The SDK checks these fields; applications normally only need them when recording or diagnosing a stream.

AttributeTypeMeaning
schemastr"syq.automation"
schema_versionint1
seqintRecord sequence number, starting at zero
typestrWire record type; "result" for terminal totals

ReceiptSummary

Frozen dataclass accessed through CpResult.receipt for receiver-attested copies.

AttributeTypeMeaning
statusReceiptStatusReceiver receipt outcome
operationsintAttested operation record count
final_statesintAttested final-state record count
recordsintTotal receipt record count
provenancestr"receiver_attested"

OperationStatus

String enum: compare with syq.OperationStatus.SUCCESS, or use .value for "success".

MemberValueExit codeMeaning
SUCCESS"success"0Requested operation succeeded
PARTIAL"partial"23Per-entry failures; independent work finished
REFUSED"refused"25A safety cap refused deletions; copy only
ABORTED"aborted"1Operation aborted; copy only
FAILED"failed"1Fatal failure

Event callbacks

on_event(event) receives an AutomationEvent in stream order. Events are not stored in the result. AsyncClient accepts synchronous or awaitable callbacks; awaitable callbacks count toward the timeout.

AutomationEvent is the union of the event classes below and CpResult and RmResult. Each event is a frozen dataclass. Its fields are listed below; all events also carry protocol: ProtocolMetadata, just like results. event.protocol.type identifies the wire record type. Optional fields use None when unavailable.

See Automation results for stream semantics. Python exposes class as class_ and paths as PathValue.

results= accepts a binary file-like object with write(bytes) returning a positive byte count for nonempty writes, and optional flush(). The client copies validated NDJSON records, flushes after completion, and leaves it open. It withholds the terminal record if stream validation, process completion, or a callback fails. Sink failures raise and abort the operation.

OperationResult.is_retryable identifies retryable failures; retry_entry() returns a MappingEntry when a complete mapping identity is available, otherwise None. Only use collected entries after the call returns a validated success or partial result. A terminal callback alone does not establish completion. The client does not retry automatically.

Event types

RunEvent

Invocation details. started_at is Unix seconds; mode is "cp" or "rm". prune and mapping are None for removal; verify_only defaults to False.

protocol.type = "run". Fields in addition to the common envelope:

run_id: str
started_at: int
syq_version: str
mode: str
prune: bool | None
mapping: bool | None
dry_run: bool
endpoints: tuple[Endpoint, ...]
verify_only: bool

ProgressEvent

Sampled progress for displays; use the terminal result for final totals. Byte fields measure file content (comparison work with verify_only=True), scanned counts scanned entries, and elapsed_ms is milliseconds.

protocol.type = "progress". Fields in addition to the common envelope:

bytes_done: int
bytes_total: int
bytes_unchanged: int
files_done: int
files_total: int
files_unchanged: int
files_excluded: int
scanned: int
scan_done: bool
elapsed_ms: int

TraceEvent

One planned copy change. dst is relative to the destination container; src is the mapping source when available. bytes is the planned file size, and reason describes why the change is needed.

protocol.type = "trace". Fields in addition to the common envelope:

action: OperationAction
dst: PathValue
src: PathValue | None
kind: EntryKind
bytes: int | None
reason: TraceReason

OperationResult

One copy outcome. dst is destination-relative, or relative to the signed destination scope for a receiver receipt. src is present for mapping entries when available. bytes and attempts give transfer information. Error details are present when known; message is display text. provenance, scope, and code apply to receiver-attested outcomes.

protocol.type = "operation_result". Fields in addition to the common envelope:

action: OperationAction
dst: PathValue
src: PathValue | None
kind: EntryKind | None
disposition: Disposition
bytes: int | None
attempts: int | None
retryable: Retryability | None
class_: ErrorClass | None
os_kind: OsKind | None
message: str | None
provenance: str | None
scope: int | None
code: ReceiptCode | None

SelectionResult

One removal selector, indexed from zero. path is the original selector; status says whether it resolved. kind is None for a missing selector.

protocol.type = "selection_result". Fields in addition to the common envelope:

selector: int
path: PathValue
status: SelectionStatus
kind: EntryKind | None

RemovalTrace

One entry a preview would remove. selector identifies its source selector; path identifies the entry. disposition is always WOULD_REMOVE.

protocol.type = "removal_trace". Fields in addition to the common envelope:

selector: int
path: PathValue
kind: EntryKind
disposition: RemovalDisposition

RemovalResult

One removal outcome or preview inspection failure. selector identifies its source selector; path identifies the entry. attempts counts attempts; retryable, class_, os_kind, and message describe failures when available.

protocol.type = "removal_result". Fields in addition to the common envelope:

selector: int
path: PathValue
kind: EntryKind | None
disposition: RemovalDisposition
attempts: int
retryable: Retryability | None
class_: ErrorClass | None
os_kind: OsKind | None
message: str | None

ErrorEvent

One counted error. message is display text; class_ and os_kind classify it when known. Receiver errors can also carry provenance and code.

protocol.type = "error". Fields in addition to the common envelope:

message: str
class_: ErrorClass | None
os_kind: OsKind | None
provenance: str | None
code: ReceiptCode | None

FinalStateEvent

Receiver-attested destination state. dst is relative to the signed scope. provenance is "receiver_attested". Present objects have kind and byte size; metadata, digest, and symlink_target are present where available. observation_error describes a partial observation. Absent objects have no object details; failed observations have code and optional message.

protocol.type = "final_state". Fields in addition to the common envelope:

provenance: str
scope: int
dst: PathValue
state: FinalObjectState
kind: FinalObjectKind | None
size: int | None
metadata: ObjectMetadata | None
digest: AttestedDigest | None
symlink_target: PathValue | None
observation_error: str | None
code: ReceiptCode | None
message: str | None

Endpoint, ObjectMetadata, and AttestedDigest

Nested frozen dataclasses used by events:

TypeFieldsMeaning
Endpointrole: EndpointRole, kind: EndpointKind, host: str | None, user: str | NoneSource/destination and local/SSH identity; host and user are optional
ObjectMetadatamode: int, uid: int, gid: int, mtime: int, mtime_nsec: int, rdev: intUnix mode, owner/group IDs, modification time (seconds plus nanoseconds), and device ID
AttestedDigestalgorithm: str, value: str"blake3" and its 64 lowercase hexadecimal digest characters

Enums

All enums are string enums exported by syq. Members use uppercase names; values use lowercase, for example EntryKind.FILE.value == "file". OperationStatus is defined with the result types above.

TypeMembers
EntryKindFILE, DIR, SYMLINK, SPECIAL
EndpointKindLOCAL, SSH
EndpointRoleSOURCE, DESTINATION
OperationActionTRANSFER_FILE, CREATE_DIRECTORY, CREATE_SYMLINK, CREATE_SPECIAL, DELETE, SET_METADATA, OBSERVE_HASH
DispositionSUCCEEDED, FAILED, BLOCKED, INCOMPLETE, OBSERVED
ReceiptCodeNONE, EXECUTION_FAILED, AUTHORIZATION_REFUSED, FILE_LIFECYCLE_INCOMPLETE, OBSERVATION_FAILED
FinalObjectStatePRESENT, ABSENT, OBSERVATION_FAILED
FinalObjectKindDIR, FILE, SYMLINK, FIFO, SOCKET, CHARACTER_DEVICE, BLOCK_DEVICE, OTHER
ReceiptStatusCLEAN, FAILED, INCOMPLETE
RetryabilityYES, NO, UNKNOWN
ErrorClassIO, TRANSPORT, CONFLICT, INTEGRITY, SAFETY_LIMIT, USAGE, INTERNAL
OsKindNOT_FOUND, PERMISSION_DENIED, ALREADY_EXISTS, INVALID_INPUT, NO_SPACE, QUOTA_EXCEEDED, READ_ONLY, OTHER
TraceReasonDESTINATION_MISSING, TYPE_DIFFERS, CONTENT_DIFFERS, METADATA_DIFFERS, DESTINATION_ONLY
SelectionStatusRESOLVED, MISSING
RemovalDispositionWOULD_REMOVE, REMOVED, ALREADY_ABSENT, FAILED

ReceiptStatus.CLEAN means a clean receipt, FAILED reports receiver failures, and INCOMPLETE reports an incomplete lifecycle. Retryability.YES, NO, and UNKNOWN state whether a failed entry can be retried.

Failure model

SyqError is the base class for every SDK-defined exception below. Specific subclasses retain their details so callers can distinguish an unsuccessful operation from a broken results stream.

ExceptionMeaning / useful attributes
SyqInstallErrorManaged executable installation or verification failed
SyqInvocationErrorInvalid Python arguments
SyqOperationErrorTyped operation was unsuccessful; .result and .stderr (last 8 KiB)
SyqProtocolErrorInvalid, unsupported, inconsistent, or incomplete results; .returncode, .stderr
SyqProcessErrorRaw run exited nonzero; .result contains complete output
SyqOutputErrorA helper such as version() received unexpected output

For cp and rm, check=False returns unsuccessful typed results; for run, it returns nonzero process results. It does not suppress other errors. Spawn failures, timeouts, and ordinary Python type/value errors use standard Python exceptions. Exceptions from application callbacks or mapping iterators are re-raised unchanged. Async cancellation remains asyncio.CancelledError. These exceptions are not wrapped in SyqError.

Timeout, cancellation, early mapping exit, and streaming failures stop the local process group, including SSH children. Filesystem changes already completed are not rolled back.

run

client.run(args, *, check=True, cwd=None, env=None, timeout=CLIENT_DEFAULT, input=None) returns Result. input accepts bytes. args is a sequence of arguments after the executable name, passed without a shell.

Here, cwd is the local subprocess directory. cwd and env use client defaults when omitted or None. timeout uses the client default only when omitted; explicit None disables it. Module-level syq.run takes the same arguments plus executable=None and defaults to no timeout.

Wrappers can forward syq.CLIENT_DEFAULT to preserve client inheritance. syq.Timeout is the type alias for a number, None, or that sentinel:

def copy_data(client: syq.Client, *, timeout: syq.Timeout = syq.CLIENT_DEFAULT):
    return client.cp("data", into="backup", timeout=timeout)

CLIENT_DEFAULT applies to client methods (including module-level cp, rm, and map); client constructors and module-level run have no client default to inherit.

Timeouts cover subprocess execution. Managed installation and mapping-input materialization happen before the copy process starts and are not covered by its timeout. Async cancellation still stops mapping-input preparation.

syq exec is also available through run; its command output and exit status are a process result:

result = syq.run(
    ["exec", "--on", "@mac", "--cwd", "work/project", "--", "cargo", "test"],
    executable="/path/to/syq",
)

For exec, pass --cwd in the argument list to select the receiving working directory. The SDK’s cwd= parameter selects the local working directory of the requesting syq process.

Result

Frozen dataclass returned by run() and held in SyqProcessError.result:

AttributeTypeMeaning
argvtuple[str | bytes, ...]Executed argument list, including the executable
returncodeintProcess exit status
stdoutbytesComplete captured standard output
stderrbytesComplete captured standard error

Compatibility

Python 3.10+ on Linux and macOS; no runtime Python dependencies. Each Python package uses the matching syq release. syq.__version__ and syq.PINNED_SYQ_VERSION report those versions. Pin the package in your dependency file to keep the pairing.

Managed executable

The default client downloads the matching executable on first use and verifies it against the package’s embedded release manifest. It checks the cached binary before every use and replaces missing or corrupt entries. It does not search PATH.

The default cache is $XDG_CACHE_HOME/syq/sdk/python/v<version>/ when XDG_CACHE_HOME is absolute, or ~/.cache/syq/sdk/python/v<version>/ otherwise. Use Client(cache_dir=...) to change the cache root, or syq.managed_executable() to download ahead of time and get the path.

Custom executable

Client(executable="/opt/bin/syq") uses that binary; Client(executable="syq") searches PATH. Overrides bypass managed download and verification, so you are responsible for compatibility and origin. Typed calls still validate automation output. A failed executable selection does not fall back to another binary.