tail.surf (tsf)
tail.surf is a streaming gist for live work and agent conversations.
Each stream gets a stable URL that can be concurrently written to, read from anywhere, and tailed in real-time.
Free to start with no sign-up required.
Use it to stream sandbox output, build output, deploy logs, sandbox sessions, or agent-to-agent messages. For example:
- Share long-running command output without keeping an SSH session, sandbox, or terminal attached.
- Give agents a reliable async channel with durable catch-up.
- Turn build, test, deploy, and debugging output into a permalink that can be inspected in real-time or after the fact.
Open tail.surf for the scrubbable live transcript, or install the tsf CLI below. Rust SDK documentation and examples live in Rustdoc.
Install
Install the prebuilt CLI on macOS or Linux:
|
Install it from PowerShell on Windows:
irm https://tail.surf/install.ps1 | iex
The direct installer puts tsf in ~/.local/bin. It writes an installer receipt so tsf can update only the files that installer owns.
Cargo remains the Rust-native fallback:
Update a direct installation explicitly:
Check without installing:
Installer-owned binaries may contact GitHub Releases and print an update hint after a successful interactive command against https://tail.surf. The check runs at most once per day, waits at most 500 milliseconds, and never installs an update. Set TSF_NO_UPDATE_CHECK or DO_NOT_TRACK to disable hints. CI and non-interactive commands do not check.
Installations owned by a package manager do not check or print the hint. Cargo users rerun cargo install tailsurf-cli --locked. cargo-binstall users rerun cargo binstall tailsurf-cli.
CLI quickstart
Create a private stream:
Create a public stream:
Choose a shorter initial lifetime with a human duration:
|
Streams expire after 10 days by default. Their complete history remains readable until expiry.
tsf new prints the title, Stream ID, expiry, and initial links. Private streams get a read link and an owner link. Public streams get a public URL and an owner link. The title is optional.
Create custom links with --link LINK_ID=PERMISSION. Link IDs are short semantic names such as deploy-bot. Permissions are read, write, read-write, and owner. The short forms r, w, rw, and o are also accepted. A stream may have up to three initial links, including defaults. Links are shown once.
Stream command output into a new stream:
|
Bare tsf captures piped input in a new stream. With terminal input and no subcommand, it prints help.
Creation details and links go to stdout. Durability progress goes to stderr.
Use write to send input to an existing stream. It accepts a write-capable link and creates no links.
Run a command through tsf when you want tsf to propagate the command exit status:
By default, tsf makes line boundaries transcript record boundaries and marks records as transcript-oriented:
|
|
One logical line is limited to 16 MiB by default. This is the same default used by tail and replay. Set --max-logical-record-bytes on both the writer and reader only when a larger application-specific limit is required.
Use raw mode when you want to send stdin as byte records instead of line-framed transcript records. Raw mode flushes at the physical record size limit, after a short linger, and at EOF:
|
|
On Ctrl-C, tsf stops input, flushes accepted bytes, waits for durability acknowledgements, closes the writer, and exits with status 130.
Tail or replay a link or public stream URL:
--last or -n starts relative to the durable tail. --seq starts at an absolute sequence number. --since accepts a duration or RFC 3339 timestamp. --limit bounds the number of records.
tail follows new records unless --limit bounds it. replay snapshots the current durable tail and exits after printing that range.
--sse uses the resumable HTTP event-stream transport. The default binary WebSocket transport remains best for interactive CLI use.
Both commands preserve payload bytes. They exit successfully when a downstream pipe closes normally.
Inspect stream metadata:
Owner links contain #o= and can manage the stream:
Deletion asks for confirmation on a terminal. Scripts must pass --yes.
Renewal extends an active stream from the current time. Link expiry accepts durations such as 1h or 7d, or never by default.
A stream title contains 1 to 120 Unicode code points. Leading or trailing whitespace, control characters, and line breaks are rejected. Titles may be duplicated, changed, or cleared. The immutable Stream ID remains the stream identity and URL component.
Every link has a client-chosen immutable Link ID. Link IDs contain 1 to 64 lowercase ASCII letters, digits, or hyphens. They cannot start or end with a hyphen. Link IDs are unique within a stream.
Link file options write complete URLs. Any command that accepts a link also accepts @PATH to read one complete URL from a file. On Unix, tsf creates and tightens link files to mode 0600.
Commands with structured output accept --json.
Development
See Development for the workspace layout, local-service setup, checks, and diagnostics. Release maintainers should also read Release operations.
License
The Rust SDK and CLI are MIT licensed. See LICENSE.