#api-client #terminal #curl #tui

bin+lib churl

A fast terminal API client — craft, send, and inspect HTTP requests

14 releases (9 breaking)

Uses new Rust 2024

0.10.0 Jul 26, 2026
0.8.0 Jul 19, 2026

#416 in Command line utilities

40 downloads per month

MIT/Apache

3MB
52K SLoC

churl

A fast terminal API client — craft, send, and inspect HTTP requests from your terminal.

CI crates.io license


Install

curl | sh (macOS and Linux)

curl -fsSL https://github.com/AlsubaieAli/churl/releases/latest/download/install.sh | sh

The script detects your OS and architecture, downloads the matching binary, verifies its SHA-256 checksum, and installs to ~/.local/bin. To pass options through the pipe, use sh -s --:

curl -fsSL https://github.com/AlsubaieAli/churl/releases/latest/download/install.sh \
  | sh -s -- --to ~/bin --force
Option Effect
--to DIR Install to DIR instead of ~/.local/bin
--tag TAG Install a specific release, including betas (e.g. --tag v0.2.0-beta.1)
--force Overwrite an existing churl binary
--dry-run Print the resolved URL and target, download nothing

PowerShell (Windows)

irm https://github.com/AlsubaieAli/churl/releases/latest/download/install.ps1 | iex

The script downloads the Windows binary, verifies its SHA-256 checksum, and installs to %LOCALAPPDATA%\Programs\churl. To pass options, download and run it directly:

irm https://github.com/AlsubaieAli/churl/releases/latest/download/install.ps1 -OutFile install.ps1
pwsh install.ps1 -To C:\Tools\churl -Force
Option Effect
-To DIR Install to DIR instead of %LOCALAPPDATA%\Programs\churl
-Tag TAG Install a specific release, including betas (e.g. -Tag v0.2.0-beta.1)
-Force Overwrite an existing churl binary
-DryRun Print the resolved URL and target, download nothing

Prebuilt binaries

Download the archive for your platform from the latest release:

Platform Archive
macOS (Apple Silicon) churl-aarch64-apple-darwin.tar.gz
macOS (Intel) churl-x86_64-apple-darwin.tar.gz
Linux x86_64 (musl, static) churl-x86_64-unknown-linux-musl.tar.gz
Linux aarch64 (musl, static) churl-aarch64-unknown-linux-musl.tar.gz
Windows x86_64 churl-x86_64-pc-windows-msvc.zip

Each archive includes a churl binary and a .sha256 checksum file.

cargo install

Builds from source (needs a Rust toolchain):

cargo install churl

From git (bleeding edge)

Builds the tip of master — unreleased features, no stability promises:

cargo install --git https://github.com/AlsubaieAli/churl churl

Updating

The simplest way to update a binary install is the built-in self-updater:

churl update          # check the latest release, confirm, verify, and self-replace
churl update --check  # just report whether a newer version is available
churl update -y       # skip the confirmation prompt

churl update queries the latest GitHub release, and if you're already on it does nothing. Otherwise it downloads the asset for your platform, verifies its SHA-256, backs the current binary up to churl.bak beside itself, and atomically replaces the running binary — so a failed update always leaves a working churl in place.

For installs managed by another tool, use its own update path (check what you're running with churl --version):

Installed via Update with
curl | sh churl update, or re-run the installer with --force
Prebuilt binary churl update, or download the newer archive and replace the binary
cargo install churl cargo install churl — cargo rebuilds when a newer version is published
git cargo install --git … churl --force (--force reinstalls even if the version number hasn't changed)

Package-manager distribution (Homebrew / AUR) arrives at 1.0.

Uninstalling

churl uninstall           # removes the binary; prints the config + state paths left behind
churl uninstall --purge   # also deletes churl's config dir and state.sqlite (asks first; -y to skip)

Uninstall never touches your workspace files (churl.toml, collections, sequences/) — only the churl binary and, with --purge, churl's own config and local state database.

Pinning a churl version per workspace

Drop a .churl-version file at a workspace root naming a single version:

echo 0.2.0 > .churl-version

When you launch churl in that workspace with a different version, it prints a one-line warning and runs anyway — it never blocks you or switches versions (it's an advisory hint, nvmrc-style). Delete the file to remove the pin.

Beta releases

Pre-releases (tags like v0.2.0-beta.1) ship the same binaries as stable releases but are never picked up by releases/latest or a plain cargo install churl — you opt in explicitly:

# installer
curl -fsSL https://github.com/AlsubaieAli/churl/releases/latest/download/install.sh \
  | sh -s -- --tag v0.2.0-beta.1 --force

# or cargo
cargo install churl --version 0.2.0-beta.1

Quickstart

The fastest way to get started is churl init --demo, which scaffolds a demo workspace with example endpoints, a profile, and template variables:

mkdir my-api && cd my-api
churl init --demo       # scaffolds churl.toml + example endpoints in the cwd
churl                   # opens the TUI — select an endpoint and press Ctrl-S to send

Or scaffold directly to a new directory:

churl init --demo ~/my-api

The demo workspace targets httpbingo.org — a public HTTP echo service — so your first request works immediately without any sign-up.

Prefer no scaffold at all? churl init (without --demo) writes just a blank churl.toml — handy right before churl importing your first endpoint.

Headless / agent use

churl also runs without the TUI, for scripts, CI, and AI agents. churl send fires an ad-hoc request from inline flags (curl-mnemonic -X/-H/-d/--url or churl-native --method/--header/--body — no workspace required); churl run <endpoint> executes a saved endpoint by its collection/endpoint name path. Add --json to either for a single machine-readable envelope on stdout with a frozen schema and stable exit codes — see docs/CLI.md.

churl send https://httpbingo.org/get
churl --json run "examples/Get Anything" | jq .data.response.status

Feature matrix

Feature Notes
Collections + endpoints TOML files, one endpoint per file, comment-preserving edits
Profiles + template vars {{base_url}}, {{token}} placeholders; CLI --var, profiles, collection and workspace vars
Auth Basic, Bearer, API key (header or query); secrets via {{var}} placeholders
curl import / export churl import "curl …" converts a curl command; round-trip stable
Themes Dark (default) and light built-ins; per-slot [theme_colors] overrides
Keymaps Fully remappable via [keys] + per-pane [keys.response] etc.; churl keymaps prints the effective map
Vim navigation j/k, g/G, Ctrl-d/Ctrl-u, jump-mode (f), Space-leader
Response viewer Virtualised scroll; syntax highlighting (JSON, YAML, HTML, …)
Response search / incremental smart-case search, n/N navigation, auto-unfold
Response wrap W soft-wraps at pane width
Response headers h toggles between body and full headers
JSON folding o/O fold/unfold regions at the cursor
Structural nav J/K jump between collapsible JSON nodes (fold-aware; skips leaves)
Copy to clipboard y copies the view, Y copies the cursor line (OSC 52 — works over SSH/tmux)
Request history Every request written to SQLite; browse via the history picker

Configuration

~/.config/churl/config.toml — global settings:

theme = "dark"           # "dark" (default) or "light"
timeout_secs = 30        # request timeout in seconds
max_body_bytes = 10485760  # response body cap (10 MB default)
redirect = "strip"       # cross-origin redirect policy: "strip" (default),
                         # "strict", or "follow-all". "strip" follows redirects
                         # but drops standard and detected-secret auth headers
                         # when a hop crosses the origin (scheme+host+port);
                         # prefer "strict" when following untrusted redirects
                         # (it surfaces a cross-origin 3xx instead of following).

[theme_colors]
# Override individual theme slots with named ANSI colours or #rrggbb hex.
title = "cyan"
accent = "#ffcc00"

[keys]
# Remap any action globally.
"ctrl-p" = "open-palette"

[keys.response]
# Override keys in the response pane overlay.
"ctrl-f" = "open-body-search"

Print the effective keymap (defaults + your overrides) at any time:

churl keymaps

What's next

The road to 1.0, roughly in order — see docs/ROADMAP.md for the full roadmap:

  • CLI & headlesschurl send/run for scripting, CI, and AI agents, with structured JSON output and clean exit codes
  • Debugging & testing — a request inspector, plus status / header / body assertions that make churl a real testing tool
  • Settings, multipart & save-response-to-file
  • Saved reports & storage maintenance — persist and reload sequence and load runs
  • Interop — OpenAPI, Postman, and .http import/export
  • 1.0 — a final quality and security sweep, refreshed docs, and Homebrew / AUR

After 1.0: a plugin system (community auth schemes, body types, viewers, and import/export formats), streaming (Server-Sent Events, then WebSocket), and an MCP server so agents can drive churl as a tool.


Development

git clone https://github.com/AlsubaieAli/churl
cd churl
cargo test --all       # full suite
cargo run -p churl     # run the TUI from source

CI runs fmt, clippy (-D warnings), the test suite, and a security audit on every push and pull request. Releases are fully automated: PR titles follow Conventional Commits, and merging the bot-maintained release PR publishes to crates.io, tags, writes the changelog, and builds binaries for all five supported targets. The full workflow — conventions, release train, betas, dev builds — is in CONTRIBUTING.md.

Need a binary from an unreleased branch? Collaborators can comment /build on a pull request (or run the Dev build workflow from the Actions tab) to get macOS/Linux/Windows binaries as workflow artifacts.


License

Licensed under either of

at your option.

Dependencies

~72–99MB
~1.5M SLoC