Skip to main content
AI tutorials

Run Lossless Coding Agents in Shell Pipelines with UNCUT

This tutorial explains how to install and configure UNCUT, a small headless coding-agent harness for terminals, CI jobs, containers, and experiments. You will learn to run prompts, process piped input, use tools safely, resume JSONL sessions, consume NDJSON events, and handle provider limits without silent truncation.

Run Lossless Coding Agents in Shell Pipelines with UNCUT

What is UNCUT?

UNCUT is a headless coding-agent harness designed for shell pipelines, CI jobs, containers, and agent experiments. It is distributed as a small, statically linked Go binary and communicates through standard input and standard output. It has no terminal user interface, telemetry, plugin system, background agents, automatic retries, or hidden context compaction.

The defining behavior is its lossless transport contract. UNCUT sends the entire conversation on every model call and does not truncate, summarize, prune, or rewrite valid UTF-8 prompts, stored messages, file contents, or command output. If a provider stops a response because of an output limit, UNCUT reports an error instead of treating the partial response as a successful answer.

Important: Lossless transport does not extend a model's context window or control provider-side processing. A provider can still reject an oversized request. UNCUT makes that failure visible rather than silently removing content.

Key features

  • Complete context: Every stored message and tool result is sent on each model request.
  • Headless operation: Final text is written to stdout, while --json provides structured NDJSON events.
  • Portable binary: Releases are available for Linux, macOS, and Windows on amd64 and arm64.
  • Provider-neutral protocol: UNCUT works with OpenAI-compatible Chat Completions endpoints, including local servers.
  • Resumable sessions: Append-only JSONL files preserve complete messages and tool results.
  • Four focused tools: The agent can read files, write files, replace exact text, and run commands.
  • Explicit failures: Invalid UTF-8, malformed sessions, output truncation, and step-limit exhaustion produce errors rather than silent recovery.

Install UNCUT

Linux

Download the release binary that matches your architecture. Change amd64 to arm64 on an ARM64 system.

VERSION=0.1.1
ARCH=amd64
curl -fSLo uncut "https://github.com/Balanov/uncut/releases/download/v${VERSION}/uncut-linux-${ARCH}"
mkdir -p "$HOME/.local/bin"
install -m 0755 uncut "$HOME/.local/bin/uncut"
export PATH="$HOME/.local/bin:$PATH"
uncut --version

Add $HOME/.local/bin to your persistent PATH configuration if it is not already present.

macOS

Apple Silicon systems normally use arm64; Intel Macs use amd64.

VERSION=0.1.1
ARCH=arm64
curl -fSLo uncut "https://github.com/Balanov/uncut/releases/download/v${VERSION}/uncut-darwin-${ARCH}"
mkdir -p "$HOME/.local/bin"
install -m 0755 uncut "$HOME/.local/bin/uncut"
export PATH="$HOME/.local/bin:$PATH"
uncut --version

Windows PowerShell

$Version = "0.1.1"
$Arch = "amd64"
$Dest = "$env:LOCALAPPDATA\Programs\UNCUT"
New-Item -ItemType Directory -Force $Dest | Out-Null
Invoke-WebRequest -Uri "https://github.com/Balanov/uncut/releases/download/v$Version/uncut-windows-$Arch.exe" -OutFile "$Dest\uncut.exe"
$env:Path = "$Dest;$env:Path"
uncut --version

Use arm64 instead of amd64 on Windows ARM64. Add the destination directory to your user PATH to make the command available in future PowerShell sessions.

Install or build with Go

If Go 1.26 or later is installed, install the latest version directly:

go install github.com/Balanov/uncut/cmd/uncut@latest

Alternatively, build a repository checkout:

git clone https://github.com/Balanov/uncut.git
cd uncut
go build -trimpath -ldflags="-s -w" -o bin/uncut ./cmd/uncut

On Windows, use bin/uncut.exe as the output path.

Verify downloaded binaries

Every release includes a checksums.txt file. The following example verifies the Linux amd64 download:

VERSION=0.1.1
ARCH=amd64
curl -fSLO "https://github.com/Balanov/uncut/releases/download/v${VERSION}/checksums.txt"
grep "uncut-linux-${ARCH}$" checksums.txt | sha256sum -c -

The release binaries are not currently code-signed, so Gatekeeper or SmartScreen may display a warning. Verify the SHA-256 checksum before allowing the executable. After verification on macOS, quarantine can be removed from only the installed binary:

xattr -d com.apple.quarantine "$HOME/.local/bin/uncut"

Configure a model provider

UNCUT requires a model identifier. For a hosted service, it usually also needs an API key. Set both values and then run a prompt:

export UNCUT_API_KEY="your-api-key"
export UNCUT_MODEL="your-model-id"
uncut "Inspect this repository and fix the failing tests"

The default endpoint is https://api.openai.com/v1, unless UNCUT_BASE_URL or OPENAI_BASE_URL is set. To use another OpenAI-compatible endpoint, provide its base URL:

export UNCUT_BASE_URL="https://openrouter.ai/api/v1"

UNCUT also falls back from UNCUT_API_KEY to OPENAI_API_KEY. A key is not required by default for local endpoints.

Connect to local Ollama

The README's tested example uses an installed, tool-capable qwen3:8b model:

ollama pull qwen3:8b
export UNCUT_BASE_URL="http://localhost:11434/v1"
export UNCUT_MODEL="qwen3:8b"
uncut "Explain this repository"

Replace the example with a model installed on your machine. Tool-call quality and behavior depend on the selected model.

Run your first coding task

Start UNCUT from the repository you want the agent to inspect. By default, the current directory becomes the workspace for file tools and shell commands.

cd path/to/project
uncut "Inspect this repository, run the tests, and fix the failure"

During the task, the model can call four tools:

  • read_file reads an entire UTF-8 text file.
  • write_file writes complete contents and creates missing parent directories.
  • replace replaces exactly one occurrence. It fails if it finds zero or multiple matches.
  • run_command returns the exit code and complete combined stdout and stderr.

File-tool paths must remain inside the workspace. On Unix, commands run through /bin/sh -c. On Windows, they run through cmd.exe /D /S /C.

Use UNCUT in Unix pipelines

UNCUT appends piped input to the prompt verbatim. This makes it suitable for reviews and log analysis without creating temporary files.

git diff | uncut "Review this diff. Do not edit files."
cat failing-test.log | uncut "Find the likely cause"

Input must be valid UTF-8. UNCUT rejects invalid input rather than silently replacing bytes. It also rejects binary files. On Windows, configure utilities to emit UTF-8 where possible because some commands produce UTF-16 or code-page output.

Consume structured NDJSON events

Use --json when integrating UNCUT with scripts, CI systems, or other agent infrastructure:

uncut --json "Run the tests and fix the failure"

The event stream can contain the following record types:

  • user for user messages.
  • assistant for assistant messages and complete tool calls.
  • assistant_meta for usage information and finish reasons.
  • tool for complete tool results.
  • done when the run completes successfully.
  • error when the run fails.

UNCUT uses non-streaming Chat Completions. It supports text and tool calls, but not image input.

Create and resume sessions

A session is an append-only JSONL record containing the complete conversation and tool results. Start a task with a session file, then reuse the same file to continue:

uncut --session .uncut/work.jsonl "Start the refactor"
uncut --session .uncut/work.jsonl "Continue with the tests"

If the file already exists, UNCUT loads its complete history. New records are appended and synchronized after every step. Invalid or partial records cause an explicit error and are not discarded to force the session to load.

Session files may contain source code, command output, credentials, or other secrets. Protect them appropriately and avoid committing them to version control.

Control the workspace and agent loop

Use --cwd to run against a workspace other than the current directory:

uncut --cwd ./services/api "Run the API tests and explain any failures"

Several flags control request and loop behavior:

  • --max-steps <n> limits model calls. The default is 32.
  • --max-tokens <n> sets an explicit provider output limit instead of using the provider default.
  • --request-timeout <duration> changes the per-request timeout from its default of 10m. A value of 0 disables the timeout.
  • --no-agents prevents UNCUT from reading the workspace's AGENTS.md.

By default, UNCUT reads AGENTS.md in full from the workspace root and adds it to the system prompt. When resuming a session, it reuses the original stored system message rather than rebuilding it from the current file.

Understand exit codes

Reliable exit codes make UNCUT useful in automation:

  • 0 means the agent produced a successful final answer.
  • 1 indicates a provider, input/output, session, or execution error.
  • 2 indicates invalid command-line usage.
  • 3 means the provider returned finish_reason=length or max_tokens; UNCUT rejected the partial answer.
  • 4 means the maximum number of steps was reached before a final answer.

In CI, treat every nonzero code as a failed run and inspect either stderr or the final error event from --json.

Advanced tips

Choose limits deliberately

Because UNCUT does not compact context, long sessions and large tool results can eventually exceed a model's context window. Start a new session when appropriate, select a provider with enough context capacity, and set --max-tokens only when you understand the provider's response limit. UNCUT will not combine partial responses or retry automatically.

Keep automated runs machine-readable

Use --json for CI and integrations rather than parsing conversational final text. The separate metadata events let consumers inspect finish reasons and usage without mixing them into assistant content.

Use isolated environments for untrusted work

UNCUT is not a sandbox. Although file tools enforce workspace boundaries, run_command executes with the current operating-system user's permissions and is not confined by those file checks. Run untrusted prompts or repositories in a disposable container or another isolated environment. Review file changes and session records yourself.

There are no approval dialogs, automatic commits, automatic retries, or hidden recovery loops. This makes execution behavior direct, but it also means you are responsible for choosing an appropriately restricted environment.

Verify the lossless contract locally

The repository includes a deterministic proof script that uses the real binary and a local provider. It requires Python 3 but no API key, external model, or third-party Python package:

go build -o bin/uncut ./cmd/uncut
python bench/proof.py ./bin/uncut

The proof checks complete transport of large files and command output, exact session resume, editing behavior, explicit truncation failures, step limits, and invalid UTF-8 handling. These checks measure transport behavior rather than model quality. Recorded results and reproduction instructions are available in the UNCUT repository.

Run development checks

When modifying UNCUT itself, format, test, and vet the Go code:

gofmt -w cmd internal
go test -count=1 ./...
go vet ./...

Conclusion

UNCUT provides a deliberately small and transparent way to run coding agents from terminals, pipelines, containers, and CI systems. Its complete-message transport, explicit failure handling, resumable sessions, structured events, and four built-in tools make it useful when silent context reduction is unacceptable. Configure an OpenAI-compatible endpoint, start in an isolated workspace, and use sessions or NDJSON output when you need reproducible automation.