# plane-cli A lightweight **zsh + curl** CLI for [Plane](https://plane.so) (works with self-hosted instances). No build step, no dependencies to install beyond what you already have — it's a single sourced shell file that wraps the Plane REST API with `fzf` pickers. > Personal tool, built for a self-hosted Plane instance. Inspired by > [`cpatrickalves/plane-cli`](https://github.com/cpatrickalves/plane-cli), but deliberately > tiny: just functions in your shell. ## Requirements - `zsh` - `curl` - `python3` (used for JSON shaping — stdlib only) - `fzf` (interactive pickers) ## Install ```sh git clone https://forgejo.ludique.dev/theo/plane-cli.git ~/Developer/plane-cli ``` Add to your `~/.zshrc`: ```sh export PLANE_API_KEY="plane_api_xxxxxxxxxxxxxxxx" # keep this out of version control export PLANE_BASE="https://your-plane.example.com/api/v1/workspaces/your-workspace" source ~/Developer/plane-cli/plane.zsh ``` Reload (`source ~/.zshrc`), then pick your project once: ```sh pluse # fzf-pick a project — remembered across shells ``` ### Configuration Nothing instance-specific is hard-coded. The CLI reads everything from the environment and fetches each project's workflow states live, so it works against any Plane instance. | Env var | Required | Purpose | |-----------------------------|----------|---------------------------------------------------------------------| | `PLANE_API_KEY` | **yes** | Your API token (Plane → *Settings → API tokens*). | | `PLANE_BASE` | **yes** | `https:///api/v1/workspaces/`. | | `PLANE_PROJECT` | no | Pin the active project (UUID). Otherwise use `pluse`. | | `PLANE_PROJECT_NAME` | no | Display name for a pinned project (auto-resolved if omitted). | | `PLANE_EVERYTHING_PROJECT` | no | Target project UUID for `plsync` (see below). | | `PLANE_EVERYTHING_NAME` | no | Name `plsync` looks up if the UUID isn't set (default `Everything`).| | `PLANE_CLI_HOME` | no | Config dir (default `${XDG_CONFIG_HOME:-~/.config}/plane-cli`). | **Active project** — `pluse` (no args) opens an `fzf` picker, fetches that project's states, and persists the choice to `$PLANE_CLI_HOME/active`, so every new shell remembers it. You can also pass `pluse `. State keys (`backlog/todo/progress/done/cancelled`) are derived from Plane's state *groups*, so they map correctly on any project. ## Commands ``` pl list open issues (shows labels) pl -a list ALL issues (incl. done/cancelled) pl -s backlog|todo|... filter by state pl -p urgent|high|... filter by priority pl /text search titles containing 'text' pl -j raw JSON output (pipe to jq); honours filters pl -h full help pladd create an issue (interactive wizard) pladd "title" [opts] create inline -p priority urgent|high|medium|low (default: none) -s state backlog|todo|progress (default: backlog) -d YYYY-MM-DD due date -l a,b,c attach labels (must already exist) plstate [#] change state — fzf picker if no id pldone [#] mark done — fzf picker if no id plshow fzf-pick and inspect an issue (shows labels) pledit [#] edit title/priority/due/labels plrm [# ...] delete — fzf multi-select if no ids plcomment [#] [text] list comments on an issue, or add one pllabels [add "n" [#hex]] list project labels, or create one plprojects list all projects pluse [name|id] switch active project (fzf if no arg) plsync [--dry-run] mirror open issues from all projects into an "Everything" project ``` ### Examples ```sh pl -s todo # only todo issues pl -p high # only high priority pl /login # titles containing "login" pl -j | jq -r '.[].name' # scriptable JSON pladd "Fix export button" -p high -s todo -l bug,urgent plcomment 7 "fixed in latest deploy" pllabels add "bug" "#FF0000" ``` ## Notes - `pl -j` emits the filtered issue list as JSON for piping to `jq`. - Comments are created via Plane's `comment_html` field (the API stores HTML). - `plsync` mirrors every project's open issues into one "Everything" project. It resolves the target from `PLANE_EVERYTHING_PROJECT`, or a project named `Everything` (override the name with `PLANE_EVERYTHING_NAME`). It's idempotent — items are keyed by `[IDENTIFIER] title` and ones closed at the source are removed. Run `plsync --dry-run` first to preview. ## License MIT