Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Contributing

Thanks for taking a look. Posel is pre-1.0 and moving quickly — issues and PRs are welcome.

## Build & run

Requires a current stable Rust toolchain. GPUI uses recently-stabilized std features; if a build
fails with `E0658`, run `rustup update stable`.

```bash
cargo run -p posel-app # the desktop app (binary: posel)
cargo run -p posel-cli -- <url> # headless engine driver
cargo test --workspace
cargo clippy --workspace --all-targets -- --deny warnings
cargo fmt --all --check # CI enforces this
```

A workspace can be opened by passing a path as the first argument to the app, or via the
`POSEL_WORKSPACE` environment variable:

```bash
cargo run -p posel-app -- examples/github-api
```

### Linux build prerequisites

GPUI links against system libraries that need their development packages present. Without them the
build fails inside `yeslogic-fontconfig-sys` with *"The pkg-config command could not be found"*,
which reads like a toolchain problem but isn't:

```bash
# Debian / Ubuntu
sudo apt install -y pkg-config libfontconfig-dev libfreetype-dev \
libxkbcommon-dev libxkbcommon-x11-dev libwayland-dev libxcb1-dev libx11-dev
```

## Layout

The domain logic is headless and unit-tested; GPUI is confined to the edge (`ui`/`app` only).

| Crate | Responsibility |
|-------|----------------|
| `core` | Protocol-tagged request/collection model (the source of truth) |
| `template` | Variable / secret / dynamic-value resolution |
| `engine` | tokio runtime, the `Transport` trait + HTTP transport, request resolution |
| `schema` | GraphQL brains: introspection → queryable schema, completion, formatting, validation |
| `storage` | git-friendly `.toml` format, secret backends, history, file-watching |
| `ui` | GPUI widgets: editors, viewers, sidebar, palette (protocol-aware via enum dispatch) |
| `app` | `posel` desktop binary |
| `cli` | `posel-cli` headless engine driver |

`core`, `template`, `engine`, `schema`, and `storage` carry no UI dependency and are tested in
isolation. A new protocol is a new `Transport` impl plus a registered editor/viewer; the UI stays
protocol-agnostic. See [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md).

## A note on the GPUI dependency

GPUI ships only as a git dependency (no crates.io release), and Posel carries a handful of small,
upstreamable editor enhancements to `gpui-component` — a completion trigger, bracket-aware
auto-indent, and bracket/quote auto-pairing among them. Those live on a public fork,
[`starvy/gpui-component`](https://github.com/starvy/gpui-component), pinned here to an immutable tag
so the whole graph resolves to a single, reproducible `gpui`. No local checkout is needed —
`cargo build` fetches everything.

Because the fork pins `gpui` itself, the two must move in lockstep: bumping one without the other
gives you two incompatible copies of `gpui` in the graph.

## Conventions

- **Conventional Commits** — `type(scope): subject`, scope is the crate (`ui`, `engine`, `storage`, …).
- **GPUI at the edge.** Only `ui` and `app` may depend on `gpui`/`gpui-component`.
- **Never block the GPUI thread.** IO runs on the engine's tokio runtime and is marshaled back
via channels.
- `thiserror` in libraries, `anyhow` at binary edges. No `unwrap`/`expect` on fallible library paths.
- Tests track behavior, not lines — cover engine/storage/template logic and tricky edge cases.

Before pushing, run the same gate CI does: `cargo fmt --all --check`, `cargo clippy --workspace
--all-targets -- --deny warnings`, `cargo test --workspace`.
229 changes: 85 additions & 144 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,186 +1,127 @@
# Posel

A fast, **native** API client for developers — REST and GraphQL first, multi-protocol by
design. No webview, no account, no cloud. Your collections are plain files on disk you can
commit to git.
**A native API client for REST, GraphQL, and tRPC. Your requests are files.**

Built in Rust on [GPUI](https://www.gpui.rs/) (the framework behind the Zed editor) and the
[gpui-component](https://github.com/longbridge/gpui-component) widget library.
[![CI](https://github.com/starvy/posel/actions/workflows/ci.yml/badge.svg)](https://github.com/starvy/posel/actions/workflows/ci.yml)
[![Release](https://img.shields.io/github/v/release/starvy/posel)](https://github.com/starvy/posel/releases/latest)
[![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue)](#license)
[![Built with Rust](https://img.shields.io/badge/built%20with-Rust-dea584?logo=rust&logoColor=white)](https://www.rust-lang.org)

![Posel — sending REST and GraphQL requests, switching environments, and inspecting response timing](docs/assets/posel-demo.gif)
Posel stores your requests as plain `.toml` files in a folder you own.

Diff them, review them, branch them — collaboration is just git.

<sub>Opening a saved request, sending it with <kbd>Ctrl</kbd>+<kbd>Enter</kbd>, resolving
`{{variables}}` against an environment, inspecting headers and the timing waterfall, running a
GraphQL query, and the command palette. ([higher-quality MP4](docs/assets/posel-demo.mp4))</sub>
No account, no sync server, no telemetry. Not now, not later.

## Why another API client?
![Posel — sending REST and GraphQL requests, switching environments, and inspecting response timing](docs/assets/posel-demo.gif)

Existing clients are mostly either cloud-first and heavy, or built on a web runtime. Posel's bet
is the opposite corner of the design space:
[Download](https://github.com/starvy/posel/releases) · [Docs](./docs) · [Architecture](./docs/ARCHITECTURE.md) · [Contributing](./CONTRIBUTING.md)

- **Native speed & huge payloads** — responses stream on a tokio runtime and render
incrementally; no webview to choke on large bodies.
- **Multi-protocol depth** — REST + GraphQL today, behind a clean *Protocol vs Transport*
boundary so gRPC and WebSocket/SSE slot in additively rather than as bolt-ons.
- **Git-native & local-first** — collections are human-readable `.toml`; collaboration is just
git. Secrets stay out of the repo — in your OS keychain by default, or another backend you
pick ([Secrets](#secrets)).
- **Keyboard-driven / Zed-like** — command palette, quick-open, env switcher, multi-tab; a
keyboard-first flow with minimal chrome.
## Your requests are files

## Status
This is a whole request — variables, and tests that run on every send:

```toml
name = "Get a user"
method = "GET"
url = "{{base_url}}/users/{{username}}"

[[assertions]]
target = "status"
op = "equals"
value = "200"

[[assertions]]
target = "json"
path = "login"
op = "equals"
value = "{{username}}"
```

Working, in active development. Runs on **macOS, Linux, and Windows**.
Commit it. Review it in a PR. Run it in CI with `posel-cli test`.

- **REST** — request editor (method, query/headers/body), streaming response panel,
environments + variables, pluggable secret storage, request history.
- **GraphQL** — schema introspection from the endpoint, schema-aware autocomplete, query
formatting, inline validation, and a dedicated data/errors viewer.
- **Workspace** — git-friendly `.toml` collections, live reflection of external file edits,
full collection CRUD, multi-tab requests, command palette.
- **Headless CLI** — `posel-cli` drives the same engine without the UI (REST send, GraphQL
introspect/query).
## Features

See [docs/PLAN.md](./docs/PLAN.md) for the phased roadmap and what's next.
- **REST, GraphQL, and tRPC** — GraphQL gets schema introspection, schema-aware autocomplete,
formatting, and inline validation.
- **Native, not a webview** — responses stream on a tokio runtime and render incrementally, so a
100 MB body opens and scrolls without jank.
- **Environments & variables** — `{{base_url}}` per environment, with a switcher.
- **Secrets stay out of the repo** — only the `{{secret:name}}` reference is written to disk.
- **Assertions & a headless CLI** — `posel-cli test` runs the same requests in CI.
- **Import & export** — bring in OpenAPI 3.x specs or a `curl` command; copy any request back out
as curl or JS fetch.
- **Keyboard-first** — command palette, quick-open, env switcher, multi-tab. <kbd>Ctrl</kbd>+<kbd>Enter</kbd> sends.

## Install

Grab the latest build for your platform from the
[Releases](https://github.com/starvy/posel/releases) page:
Grab a build from the [Releases](https://github.com/starvy/posel/releases) page:

- **macOS** — `.dmg` (universal: Apple Silicon + Intel)
- **Linux** — `.AppImage` (portable) or `.deb` (Debian/Ubuntu)
- **Windows** — `.msi` installer
| Platform | Download |
|----------|----------|
| macOS | `.dmg` (universal — Apple Silicon + Intel) |
| Linux | `.AppImage` (portable) or `.deb` |
| Windows | `.msi` |

> **Unsigned builds.** Releases aren't code-signed yet, so the OS warns on first launch:
> - **macOS** — right-click the app → **Open**, or `xattr -dr com.apple.quarantine /Applications/Posel.app`.
> - **Windows** — SmartScreen → **More info** → **Run anyway**.
>
> This goes away once signing/notarization is set up.
<details>
<summary>First launch on macOS or Windows</summary>

## Architecture
Releases aren't code-signed yet, so the OS warns the first time:

The domain logic is headless and unit-tested; GPUI is confined to the edge (`ui`/`app` only).
- **macOS** — right-click the app → **Open**, or
`xattr -dr com.apple.quarantine /Applications/Posel.app`
- **Windows** — SmartScreen → **More info** → **Run anyway**

| Crate | Responsibility |
|-------|----------------|
| `core` | Protocol-tagged request/collection model (the source of truth) |
| `template` | Variable / secret / dynamic-value resolution |
| `engine` | tokio runtime, the `Transport` trait + HTTP transport, REST & GraphQL resolution |
| `schema` | GraphQL brains: introspection → queryable schema, completion, formatting, validation |
| `storage` | git-friendly `.toml` format, pluggable secret backends, history, file-watching |
| `ui` | GPUI widgets: editors, viewers, sidebar, palette (protocol-aware via enum dispatch) |
| `app` | `posel` desktop binary |
| `cli` | `posel-cli` headless engine driver |
This goes away once signing and notarization are set up.

`core`, `template`, `engine`, `schema`, and `storage` carry no UI dependency and are tested in
isolation. New protocols are a new `Transport` impl plus a registered editor/viewer; the UI
stays protocol-agnostic. See [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md).
</details>

## Build & run
Or build it yourself — see [CONTRIBUTING.md](./CONTRIBUTING.md).

Requires a current stable Rust toolchain (GPUI uses recently-stabilized std features; run
`rustup update stable` if a build fails with `E0658`). Builds on macOS, Linux, and Windows;
secrets default to the platform keychain (macOS Keychain, Windows Credential Manager, Linux
Secret Service) and can be pointed elsewhere — see [Secrets](#secrets).
## Quick start

On **Linux**, GPUI links against system libraries that need their development packages present,
or the build fails in `yeslogic-fontconfig-sys` with *"The pkg-config command could not be
found"*:
There's a ready-made workspace in [`examples/github-api`](./examples/github-api): 36 requests across
seven collections, REST and GraphQL, two environments — and a `Meta` collection that needs no token.

```bash
# Debian / Ubuntu
sudo apt install -y pkg-config libfontconfig-dev libfreetype-dev \
libxkbcommon-dev libxkbcommon-x11-dev libwayland-dev libxcb1-dev libx11-dev
cargo run -p posel-app -- examples/github-api # or File ▸ Open Workspace…
```

Pick **Meta ▸ Get zen** and hit <kbd>Ctrl</kbd>+<kbd>Enter</kbd>. Same thing headless:

```bash
cargo run -p posel-app # the desktop app (binary: posel)
cargo run -p posel-cli -- <url> # headless engine driver
cargo test --workspace
cargo clippy --workspace -- --deny warnings
posel-cli send examples/github-api Meta/get-zen.toml
posel-cli test examples/github-api Meta/get-zen.toml # run its assertions
```

A workspace can be opened by passing a path as the first argument to the app, or via the
`POSEL_WORKSPACE` environment variable.

## Secrets

A `{{secret:name}}` reference is resolved at send time; the workspace `.toml` only ever holds the
*reference*, never the value, so collections stay safe to commit. Where the value comes from is
your choice:

| Backend | Writable from Posel | Where values live |
|---------|---------------------|-------------------|
| `keychain` *(default)* | yes | macOS Keychain, Windows Credential Manager, Linux Secret Service |
| `file` | yes | a `0600` TOML file in your user data directory |
| `env` | no | the process environment (`{{secret:github_token}}` → `$POSEL_SECRET_GITHUB_TOKEN`) |
| `command` | no | stdout of a helper command you configure (`pass`, `op`, `gh`, …) |
| `none` | — | nowhere; every `{{secret:…}}` fails |

The keychain is the default and the recommended choice — but not every machine has one. A headless
Linux box, a container, or a CI runner has no Secret Service, which is where
`org.freedesktop.DBus.Error.ServiceUnknown: The name org.freedesktop.secrets was not provided by
any .service files` comes from. Pick one of the other backends there.

Configure it under `[secrets]` in `settings.toml` in your user data directory
(`~/.local/share/posel` on Linux, `~/Library/Application Support/posel` on macOS,
`%LOCALAPPDATA%\posel\data` on Windows):

```toml
[secrets]
backend = "file" # keychain | file | env | command | none
Secret *values* never enter your workspace — only the `{{secret:name}}` reference does, so the
folder stays safe to commit. Values come from your OS keychain by default; a local file,
environment variables, or a shell command (`pass`, `1Password`, `gh auth token`) all work too.
See [docs/SECRETS.md](./docs/SECRETS.md).

env_prefix = "POSEL_SECRET_" # env backend: name → $POSEL_SECRET_<NAME>
command = ["pass", "show", "posel/{name}"] # command backend: stdout is the value
```
## Why shouldn't I use Posel?

`command` runs the given argv once per lookup and takes its stdout (trailing newline trimmed) as
the value; `{name}` is substituted with the secret name in every argument — e.g.
`["op", "read", "op://vault/{name}/token"]` or `["gh", "auth", "token"]`. A non-zero exit surfaces
the helper's stderr.
- **It's pre-1.0.** It works and it's a usable daily driver, but expect breaking changes.
- **Builds aren't signed yet**, so first launch takes an extra click on macOS and Windows.
- **No Postman/Insomnia collection import yet** — OpenAPI and curl are supported, those aren't.
- **If you want cloud sync or a team workspace server, this isn't it** — and won't be.

**About the `file` backend.** It stores values in plaintext at rest — the same posture as
`~/.aws/credentials`, `~/.docker/config.json`, or `gh`'s `hosts.yml`. On Unix the file is *created*
`0600` (owner-only) before any value is written to it, never chmod'ed afterwards, so the plaintext
is not readable by anyone else even momentarily; on Windows it inherits the user-scoped ACL of
`%LOCALAPPDATA%`. Updates go through a temp file and an atomic rename, entries are namespaced per
workspace, and it lives in your user data directory — **never inside a workspace**, so it can't be
committed by accident. Use the keychain where you have one; use this where you don't.
## Docs

Either way can be overridden for a single run with `POSEL_SECRET_BACKEND`, which wins over
`settings.toml` (an unrecognized value is ignored and the configured backend stands):
- [SPEC.md](./docs/SPEC.md) — what Posel is and the product decisions behind it
- [ARCHITECTURE.md](./docs/ARCHITECTURE.md) — how it's put together
- [SECRETS.md](./docs/SECRETS.md) — secret backends and how to pick one
- [PLAN.md](./docs/PLAN.md) — the phased roadmap
- [CONTRIBUTING.md](./CONTRIBUTING.md) — build it, run the tests, send a PR

```bash
POSEL_SECRET_BACKEND=env cargo run -p posel-app
```

`posel-cli` takes the same choice as a flag on `send`, `login`, `test`, and `codegen`:

```bash
posel-cli send ./ws users/list.toml --secret-backend env # this run only
posel-cli send ./ws users/list.toml --secret token=abc # inline; no store is read
posel-cli send ./ws users/list.toml --keychain # pin the OS keychain
```

Given none of those, the CLI resolves through whatever `settings.toml` configures. If several are
given, `--keychain` wins, then `--secret`, then `--secret-backend`. `--secret-backend` swaps only
the backend — the configured `env_prefix` and `command` still apply.

## A note on the GPUI dependency
## Status

GPUI ships only as a git dependency (no crates.io release), and Posel carries three small,
upstreamable editor enhancements to `gpui-component` (a completion trigger, bracket-aware
auto-indent, and bracket/quote auto-pairing). Those live on a public fork,
[`starvy/gpui-component`](https://github.com/starvy/gpui-component), pinned here to an immutable
tag so the whole graph resolves to a single, reproducible `gpui`. No local checkout is needed —
`cargo build` fetches everything.
Public beta on macOS, Linux, and Windows. Built in Rust on [GPUI](https://www.gpui.rs/), the
framework behind the [Zed](https://zed.dev) editor.

## License

Dual-licensed under either of

- Apache License, Version 2.0 ([LICENSE-APACHE](./LICENSE-APACHE))
- MIT license ([LICENSE-MIT](./LICENSE-MIT))

at your option.
Dual-licensed under either of [Apache-2.0](./LICENSE-APACHE) or [MIT](./LICENSE-MIT), at your
option.
Loading
Loading