swarmops cat#
Print one file at a revision, or part of it: from a byte, or a range of lines.
- 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 PATH | Result |
|---|---|
| A file | Its bytes; kind: file. |
| An executable | Its bytes; kind: exec. |
| A symlink | The link's target as its content, not followed; kind: symlink. |
| A directory | E_IS_DIR (exit 1), hint swarmops ls REV:PATH. |
| Nothing, or a path below a file | E_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\rbelongs to its line. Only the lines of the range that exist come back:linesin the result says which, andoffsetwhere the first one starts. A range that starts past the last line gives empty content, nolines, andoffsetequal 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--parentbuilds onmain's head as it is when it runs, so a whole-file put made from an older read ofmainreverts what landed in between;landthen merges the change onto the ref's head. - Page a large file. Read with a
--max-bytesthe caller can hold, then repeat with--offsetset tonext_offsetuntiltruncatedisfalse. Pin the revision to a full id first:next_offsetdoes not pin it, so pages read atmaincan come from two revisions. - Read around a line.
--lines 120-160gives a window of a source file;offsetin the result maps it back to bytes. - Compare content by id. Two files with the same
blobid hold the same bytes;lsandshowgive blob ids without reading content. - Through MCP, the tool is
read_file, withrev,path,offset,lines(an object,{"first": A, "last": B}) andmax_bytes. Ask for 32,768 bytes or less a call: see Result size limits.
Caveats#
--max-bytes 0returns empty content withtruncated: trueandnext_offsetequal to the offset it started from, so a loop that reads on whiletruncatednever ends. Ask for at least one byte.catreads 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#
- Reading and repairing history: Read a file
- Reading and repairing history: When the path is not a file
- MCP integration: Result size limits
Return information#
result is a FileContent (swarmops schema FileContent prints its JSON Schema).
| Field | Type | Required | Description |
|---|---|---|---|
blob | string | yes | The blob's id. |
content | string | yes | The 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. |
encoding | ContentEncoding | yes | How content encodes the bytes it returns: utf8 when they are text, base64 when they are not (as when offset falls inside a character). |
kind | FileKind | yes | The file's kind. |
lines | LineRange or null | no | For 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_offset | integer or null | no | When 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. |
offset | integer or null | no | Where 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. |
size | integer | yes | The whole blob's size in bytes, also when content is part of it. |
truncated | boolean | yes | Whether 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).