Parley 🏴‍☠️

GR
Gianluca Rea

parley

Jack Sparrow GIF

A git-friendly TUI HTTP client. Collections are plain TOML files — diff them, commit them, review them.


Why I built Parley

Most HTTP clients are great for sending requests, but not great for collaboration. In many teams, request collections end up buried in proprietary formats or huge JSON exports that are hard to review in pull requests.

Parley is my attempt to solve that friction with a simple rule: collections should be text-first.

Every collection is a plain .toml file, easy to read, version, diff, and discuss in Git. No hidden state, no binary blobs, and no lock-in around how request definitions are stored.

Repository: github.com/gianlucarea/parley

Demo GIF

Project overview

Parley is a terminal-first HTTP client written in Go, designed around developer workflows that already live in the shell and in Git.

At a high level, the app does four things:

  1. Loads request collections from TOML files.
  2. Resolves variables from .parley.env and shell environment values.
  3. Executes HTTP requests with auth support.
  4. Renders everything inside a three-pane TUI for fast iteration.

Architecture and components

Collection parser (internal/collection)

  • Loads .toml collection files from a file path or an entire directory
  • Supports multiple requests per file, each with a name, method, URL, headers, body, and auth
  • Collection name is derived from the filename (no extension)

Environment & variable substitution (internal/env)

  • Parses a .parley.env file (key=value, optional quotes, # comments)
  • Replaces {{VAR}} placeholders in URLs, headers, bodies, and auth fields
  • Substitution precedence: shell environment > .parley.env > literal value

HTTP executor (internal/http)

  • Executes GET, POST, PUT, PATCH, DELETE requests
  • Injects Authorization: Bearer <token> for bearer auth
  • Injects Authorization: Basic <b64> for basic auth
  • Auth field values also support {{VAR}} substitution
  • Returns status code, status text, response headers, body, and elapsed time

TUI (internal/tui)

Built with Bubbletea, Bubbles, and Lipgloss.

The interface uses a three-pane layout:

PaneDescription
SidebarLists all collections and their requests. Method badges are color-coded (GET green, POST yellow, PUT blue, PATCH cyan, DELETE red). Built-in filter with /.
EditorShows the selected request's method, URL, headers, body, and auth. Press Enter to execute.
ViewerDisplays the response: status code, elapsed time, and a syntax-highlighted scrollable body (powered by Chroma).

Keyboard shortcuts

KeyAction
TabCycle focus between panes
/ Navigate requests in sidebar
EnterSelect request (sidebar) / Run request (editor)
/Filter requests
EscClear filter
?Toggle help overlay
q / Ctrl+CQuit

Quickstart (from source)

# 1. Build from source
git clone https://github.com/gianlucarea/parley
cd parley
go build -o parley ./cmd/parley

# 2. Create a collection file
cat > api.toml << 'EOF'
[[requests]]
name   = "List Users"
method = "GET"
url    = "{{BASE_URL}}/users"

[requests.headers]
Accept = "application/json"

[[requests]]
name   = "Create User"
method = "POST"
url    = "{{BASE_URL}}/users"
body   = '{"name":"Alice"}'

[requests.auth]
type  = "bearer"
token = "{{API_TOKEN}}"
EOF

# 3. Create a .parley.env (keep this gitignored)
cat > .parley.env << 'EOF'
BASE_URL=https://api.example.com
API_TOKEN=my-secret-token
EOF

# 4. Launch
./parley .

Collection model

Parley uses one .toml file per logical collection. You can place multiple files in the same folder and load them together.

[[requests]]
name   = "Get User"
method = "GET"
url    = "{{BASE_URL}}/users/{{USER_ID}}"

[requests.headers]
Accept = "application/json"

[requests.auth]
type  = "bearer"
token = "{{API_TOKEN}}"

[[requests]]
name   = "Create Post"
method = "POST"
url    = "{{BASE_URL}}/posts"
body   = '{"title":"hello"}'

[requests.auth]
type     = "basic"
username = "{{USER}}"
password = "{{PASS}}"

Supported methods: GET POST PUT PATCH DELETE

Auth types:

typerequired fields
bearertoken
basicusername, password

Environment variables and precedence

# Lines starting with # are comments
BASE_URL=https://api.example.com
API_TOKEN=super-secret
USER=alice
PASS=hunter2

Parley resolves variables with this order:

shell environment > .parley.env > literal value

That means you can safely override values per run without touching committed files:

API_TOKEN=other-token ./parley .

What this enables in practice

  • Request definitions become reviewable artifacts in pull requests.
  • Teams can standardize API exploration workflows without coupling to a GUI state file.
  • Local secrets stay local by keeping .parley.env out of version control.

Future developments

  • Multiple named environments — switch between dev, staging, and prod profiles without editing files
  • Request history — persist and browse previous responses per request
  • Export to curl — copy the selected request as a ready-to-paste curl command
  • Import from OpenAPI / Swagger — generate a collection from an API spec file or URL
  • Response assertions — define expected status codes or body patterns and highlight failures
  • Request chaining — extract values from a response (e.g. a token) and inject them into subsequent requests
  • Pre-built binaries & releases — goreleaser pipeline for Linux / macOS / Windows (amd64 + arm64)
  • WebSocket / SSE support — stream responses in the viewer pane
  • gRPC support — proto-based collections alongside HTTP ones
  • Response diffing — compare two runs of the same request side by side