Linear for you and your agents. Single-file Python CLI that drives Linear from the shell or a subagent. Zero deps, MIT.
linear-cli
以下摘录自该仓库的 README(片段) · 在 GitHub 读完整 README →
> Linear for you and your agents. Same queue, same CLI.
Linear for human-owned work and agent-executed handoff. Keep the human as assignee, delegate the issue to an agent with --delegate, and require proof before --done closes the loop.
Use the same shell contract whether you're typing or a subagent is: query the queue, delegate the work, ship progress notes, and close only with evidence. Single-file Python (stdlib only) keeps install and audit overhead low, but the moat is the delegation workflow.
Watch with audio (MP4, 1.4 MB)
Install
Preferred (pinned tag + SHA-256 verify via install.sh):
Manual pin (same tag; no checksum — prefer install.sh above):
Setup
Create a Linear API key with Full access at linear.app/settings/account/security, then:
Config is written to ~/.linear-cli/config.json. If you already have ~/.agents/linear.json from an earlier setup, linear-cli auto-migrates it on first run.
> **Security:** treat the API key like a password. **Do not paste it into chat with an LLM in plaintext.** Pass it from your shell env (linear setup --api-key "$LINEAR_API_KEY"), or let linear-cli read it from the macOS Keychain. Resolution order is: config file → LINEAR_API_KEY env → Keychain service linear-api-key.
Fleet setup for agents
For a shared agent fleet, mint the Full-access key once with agents browser so the browser session drives linear.app/settings/account/security instead of exposing the key in chat. Store it in agents secrets / the OS keychain, then let each session run with LINEAR_API_KEY populated from that secret.
No code change is required for this path: linear-cli already resolves credentials from its config file, then LINEAR_API_KEY, then the macOS Keychain service linear-api-key.
Usage
--pickup (claim, In Progress) -> --comment (progress) -> --done --proof (close with evidence). JSON on every read." width="100%" />
> Every list is fully paginated — no silent truncation at Linear's 50-issue
> page cap, so linear tasks and --query see the *whole* cycle/team before
> you create a duplicate.
Full help: linear --help.
Search
--query is a server-side substring match on title and description. --similar
is the check-before-create step: it ranks the whole team's tickets (every cycle,
done and canceled included) by relevance to a title or paragraph, fusing Linear's
own semantic search with a local token-overlap ranker.
Before you create
linear tasks --similar " " is the check: run it, and if a
close ticket already exists, enrich that one instead of filing a twin. linear
create repeats the same ranking automatically (top 3, printed to stderr) and
then creates anyway — advisory, never a deny. --from-file bulk create skips
the lookup because searchIssues is rate-limited to 30/min.
Optional: embeddings
A third ranker scores candidates by cosine similarity over text embeddings. It
is off until you configure a backend:
Ollama is read from $OLLAMA_HOST (default http://localhost:11434);
--embeddings-model NAME picks another model (embeddinggemma, all-minilm,
…). The Gemini key comes from the environment only and is never written to
config.json. Vectors are cached in ~/.linear-cli/cache.sqlite keyed by
issue and model, so only new or edited issues are re-embedded. A hit is marked
E; if the backend is unreachable the ranker prints one embeddings: …
skipped line and --similar answers from the other two.
For humans and agents
The same CLI works whether you're typing or a subagent is. Driving Linear from either shouldn't require shelling out to @linear/sdk, hand-rolling GraphQL, or parsing HTML.
- **Assignee-as-queue.** linear tasks returns what *you* own in the active cycle. Widen with --cycle all (whole team) or --cycle none (backlog), or filter by --assignee me|none| . No dashboards, no saved views.
- **Directory-aware scope.** When agents projects binds the current directory to a Linear project, linear tasks (and --board) auto-scope to that project — so an agent launched inside a project folder works that project's queue, not the whole workspace. --all shows every project, --project X overrides, and autoScope: false in ~/.linear-cli/config.json disables it. Fail-open: with no agents CLI or no binding for the cwd, nothing changes. The --json output carries project: {id, name, auto} (null when unscoped).
- **Milestones as deliverables.** --milestone scopes to one deliverable across all cycles; --by-milestone groups a project's issues by milestone (with a *No milestone* bucket for unmatched work), each row annotated with its cycle so you see which iteration a deliverable's work is scheduled in. linear projects / milestones list roll up per-milestone % done, so a deliverable's progress sits next to its target date. Scoping to --project/--milestone widens to all cycles by default (the whole deliverable, not just this cycle's slice).