SwarmOps
ReferenceCommandsswarmops cat
View as Markdown

swarmops cat#

Print one file at a revision, or part of it: from a byte, or a range of lines.

Metadata
Group
read
Since
0.1.0
Mutates
no
Identity required
no
MCP tool
read_file
Envelope op
read_file
Exit codes
0126

Syntax#

swarmops cat [OPTIONS] <REV:PATH>

Required arguments#

Syntax: <REV:PATH>.

The revision and the file's path, split at the first ':'.

Optional arguments#

The command also takes the global options.

Syntax: --offset <N>. Default: 0.

Start at byte N of the file; a truncated result's next_offset reads on from there.

Syntax: --lines <A-B>.

Print lines A to B only, numbered from 1, both included, such as 10-20.

Syntax: --max-bytes <N>. Default: 1048576.

The most content bytes to print.

Examples#

swarmops --repo [tmp]/store cat main:README.md
{
  "ok": true,
  "op": "read_file",
  "api": 1,
  "result": {
    "blob": "[id1]",
    "size": 18,
    "kind": "file",
    "encoding": "utf8",
    "content": "# acme\n\nversion 2\n",
    "truncated": false
  },
  "meta": {
    "repo": "[tmp]/store",
    "elapsed_ms": "[elapsed_ms]",
    "resolved": {
      "main": "[c2]"
    },
    "auth": "trust"
  }
}

Exit code 0. Recorded by the CLI tests. A name in square brackets, such as [tmp] or [c1], stands for what differs from run to run: the test's temporary directory, an id, a time.

No recorded example yet.

Details#

cat reads one file at any revision without a checkout: the whole file, the bytes from an offset, or a range of lines, always within --max-bytes. It is the read an agent makes before it edits a file, and the one it pages through a large file with.

What the target names#

REV:PATH splits at the first :, so a path may hold : itself (main:a:b is path a:b). PATH is a repository path: UTF-8, relative to the root, /-separated, with no leading or trailing /, no empty, . or .. component, and no NUL. main:/src/lib.rs, main:src/ and main:./README.md are E_INVALID_ARG; ls, history, log --path and diff --path take one trailing /, but cat does not.

The entry at PATH decides the result:

At PATHResult
A fileIts bytes; kind: file.
An executableIts bytes; kind: exec.
A symlinkThe link's target as its content, not followed; kind: symlink.
A directoryE_IS_DIR (exit 1), hint swarmops ls REV:PATH.
Nothing, or a path below a fileE_PATH_NOT_FOUND (exit 6), hint the ls of the directory PATH would be in.

blob is the content's id and size the whole file's size, whatever part of it came back.

The three ways to read#

  • Whole file (no option): the bytes from the start, at most --max-bytes (1 MiB).
  • --offset N: the bytes from byte N to the end of the file, at most --max-bytes. An offset at or past the end gives empty content, truncated: false.
  • --lines A-B: lines A to B, numbered from 1, both included. A line ends after its \n; a last line without one is a line too, and a \r belongs to its line. Only the lines of the range that exist come back: lines in the result says which, and offset where the first one starts. A range that starts past the last line gives empty content, no lines, and offset equal to the file's size.

--offset and --lines do not go together (E_INVALID_ARG, from the command line, or from the operation when an MCP call sends both). --lines takes exactly A-B: --lines 2 and --lines 0-2 are refused, and so is a range whose end comes before its start.

Encoding and cuts#

content is text when the bytes returned are UTF-8 (encoding: utf8), and standard padded base64 otherwise (encoding: base64). A cut by --max-bytes keeps text as text: it moves back to the start of the character it would split, so text can stop up to 3 bytes short of --max-bytes, while bytes that are not text stop at exactly --max-bytes. An --offset that falls inside a character makes the result base64, because those bytes are not text on their own.

truncated: true means the content stops before the end of what was asked for, and next_offset says where it stops. The read on goes by bytes: --offset <next_offset> reads to the end of the file, not to the end of a --lines range, so a paged line read must stop on its own at the range's last line.

Patterns#

  • Read before you edit. Read the file at a full id, and give that id to commit --parent. A commit without --parent builds on main's head as it is when it runs, so a whole-file put made from an older read of main reverts what landed in between; land then merges the change onto the ref's head.
  • Page a large file. Read with a --max-bytes the caller can hold, then repeat with --offset set to next_offset until truncated is false. Pin the revision to a full id first: next_offset does not pin it, so pages read at main can come from two revisions.
  • Read around a line. --lines 120-160 gives a window of a source file; offset in the result maps it back to bytes.
  • Compare content by id. Two files with the same blob id hold the same bytes; ls and show give blob ids without reading content.
  • Through MCP, the tool is read_file, with rev, path, offset, lines (an object, {"first": A, "last": B}) and max_bytes. Ask for 32,768 bytes or less a call: see Result size limits.

Caveats#

  • --max-bytes 0 returns empty content with truncated: true and next_offset equal to the offset it started from, so a loop that reads on while truncated never ends. Ask for at least one byte.
  • cat reads the blob's object file whole, and verifies all of it, however little it returns: a large file costs its size in memory on every read.
  • A file of control characters prints at about six times its size through the CLI, since JSON spells most of them in six bytes each, and at about thirteen times through MCP.
  • These three are listed in known limitations.

Guides#

Return information#

result is a FileContent (swarmops schema FileContent prints its JSON Schema).

FieldTypeRequiredDescription
blobstringyesThe blob's id.
contentstringyesThe bytes returned: those from offset, or the requested lines, at most max_bytes of them. A cut keeps text as text: it falls where a character starts, so text may stop up to 3 bytes short of max_bytes, while bytes that are not text stop at exactly max_bytes.
encodingContentEncodingyesHow content encodes the bytes it returns: utf8 when they are text, base64 when they are not (as when offset falls inside a character).
kindFileKindyesThe file's kind.
linesLineRange or nullnoFor a request by lines: the lines of its range that exist, which content holds (the start of them when truncated); omitted when none does.
next_offsetinteger or nullnoWhen truncated: where content stops, the offset that reads on from there. A cut text holds whole characters, so a max_bytes under 4 can stop before a longer character at the offset it started from.
offsetinteger or nullnoWhere content starts in the file, in bytes: the request's offset, or where the first of its lines that exists starts (the file's size when none does); omitted when that is the file's start.
sizeintegeryesThe whole blob's size in bytes, also when content is part of it.
truncatedbooleanyesWhether content stops before the end of what was asked for: the file, from offset; or the requested lines that exist.

Envelope op: read_file.

Exit codes:

  • 0: Success.
  • 1: The operation failed.
  • 2: The request or the command line is malformed.
  • 6: Something the request names does not exist.

Errors#

  • E_NOT_A_REPO (exit 6): No store at the given path, or no store was named.
  • E_PATH_NOT_FOUND (exit 6): The path does not exist at that revision.
  • E_IS_DIR (exit 1): A file operation named a directory.
  • E_INVALID_ARG (exit 2): A malformed argument or request, including a command-line usage error.

Any command that opens a store may also fail with a store error, such as E_NOT_A_REPO, E_IO or E_STORE_CORRUPT; a command line the grammar refuses is E_INVALID_ARG (exit 2).

See also#

Edit on GitHub

On this page