{"id":50389366,"url":"https://github.com/illegalstudio/linear-graphql","last_synced_at":"2026-05-30T17:04:09.173Z","repository":{"id":354238120,"uuid":"1222761555","full_name":"illegalstudio/linear-graphql","owner":"illegalstudio","description":null,"archived":false,"fork":false,"pushed_at":"2026-04-27T17:36:44.000Z","size":49,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-27T19:27:30.908Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/illegalstudio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-27T17:23:11.000Z","updated_at":"2026-04-27T17:36:48.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/illegalstudio/linear-graphql","commit_stats":null,"previous_names":["illegalstudio/linear-graphql"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/illegalstudio/linear-graphql","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/illegalstudio%2Flinear-graphql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/illegalstudio%2Flinear-graphql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/illegalstudio%2Flinear-graphql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/illegalstudio%2Flinear-graphql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/illegalstudio","download_url":"https://codeload.github.com/illegalstudio/linear-graphql/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/illegalstudio%2Flinear-graphql/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33700914,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-30T02:00:06.278Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-30T17:04:08.149Z","updated_at":"2026-05-30T17:04:09.167Z","avatar_url":"https://github.com/illegalstudio.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# linear-graphql-tool\n\nNode.js + TypeScript toolkit for Linear's GraphQL API. It can run as:\n\n- local CLI: `linear-tool ...`\n- local HTTP API: `linear-tool serve`\n- Linear webhook receiver with a persistent local inbox\n- importable tool surface for self-hosted agents, MCP bridges, or future OpenClaw plugins\n\nThe implementation uses direct GraphQL calls to `https://api.linear.app/graphql`, API-key auth via the `Authorization` header, and Linear webhook HMAC verification via `Linear-Signature`.\n\n## Install\n\n```bash\nnpm install\nnpm run build\n```\n\nDuring development:\n\n```bash\nnpm run cli -- --help\nnpm run serve\n```\n\nAfter `npm link` or package install:\n\n```bash\nlinear-tool --help\n```\n\n## Configure\n\nCreate `.env` from `.env.example`:\n\n```bash\ncp .env.example .env\n```\n\nRequired for Linear API commands:\n\n```bash\nLINEAR_API_KEY=lin_api_xxx\n```\n\nUseful optional values:\n\n```bash\nLINEAR_DEFAULT_TEAM=ENG\nLINEAR_DEFAULT_PROJECT=Roadmap\nLINEAR_WEBHOOK_SECRET=whsec_xxx\nLINEAR_LOCAL_BEARER_TOKEN=local-secret\nLINEAR_QUEUE_FILE=.linear-tool/queue.jsonl\n```\n\nValidate config:\n\n```bash\nnpm run cli -- config check\nnpm run cli -- config debug\n```\n\n## CLI Examples\n\nSearch and view issues:\n\n```bash\nnpm run cli -- issue search \"login\" --team ENG --status \"In Progress\" --limit 10\nnpm run cli -- issue view ENG-123\n```\n\nCreate and update:\n\n```bash\nnpm run cli -- issue create --title \"Fix webhook retry path\" --team ENG --label Bug --priority 2\nnpm run cli -- issue update ENG-123 --status Done --assignee alice@example.com\nnpm run cli -- issue label add ENG-123 Backend\nnpm run cli -- issue project ENG-123 \"Q2 Roadmap\"\nnpm run cli -- issue parent ENG-124 ENG-123\n```\n\nComments:\n\n```bash\nnpm run cli -- comment add ENG-123 --body \"Investigated by local agent.\"\nnpm run cli -- comment list ENG-123\n```\n\nTeams, projects, workflow states:\n\n```bash\nnpm run cli -- team list\nnpm run cli -- team members ENG\nnpm run cli -- project list\nnpm run cli -- project create --name \"Agent Inbox\" --team ENG --description \"Automation intake\"\nnpm run cli -- workflow list --team ENG\n```\n\nAgent-friendly JSON:\n\n```bash\nnpm run cli -- --json issue search \"webhook\" --team ENG\nnpm run cli -- --json queue pop\n```\n\nQueue:\n\n```bash\nnpm run cli -- queue peek\nnpm run cli -- queue pop --lease-ms 300000\nnpm run cli -- queue complete \u003cqueue-item-id\u003e --claim-token \u003ctoken\u003e\nnpm run cli -- queue fail \u003cqueue-item-id\u003e --error \"temporary failure\"\n```\n\n## HTTP API\n\nStart the local server:\n\n```bash\nnpm run serve\n```\n\nDefault bind is `127.0.0.1:8787`.\n\nEndpoints:\n\n- `GET /health`\n- `POST /issue/search`\n- `POST /issue/view`\n- `POST /issue/create`\n- `POST /issue/update`\n- `POST /comment/add`\n- `POST /comment/list`\n- `GET /queue`\n- `POST /queue/pop`\n- `POST /queue/complete`\n- `POST /hooks/linear`\n\nIf `LINEAR_LOCAL_BEARER_TOKEN` is set, local API routes require:\n\n```http\nAuthorization: Bearer \u003ctoken\u003e\n```\n\n`/health` and `/hooks/linear` do not use the local bearer token. Webhooks are authenticated with Linear's HMAC signature.\n\nExample:\n\n```bash\ncurl -s http://127.0.0.1:8787/issue/search \\\n  -H 'content-type: application/json' \\\n  -H 'authorization: Bearer local-secret' \\\n  -d '{\"query\":\"login\",\"team\":\"ENG\",\"limit\":5}'\n```\n\n## Webhooks\n\nSet `LINEAR_WEBHOOK_SECRET` to the secret Linear shows when creating the webhook. Configure Linear to call:\n\n```text\nPOST http://your-host:8787/hooks/linear\n```\n\nThe server verifies `Linear-Signature` against the raw request body using HMAC-SHA256. Valid events are routed into the local queue with deduplication.\n\nRecognized routes include:\n\n- `linear.issue.created`\n- `linear.issue.updated`\n- `linear.issue.assignee_changed`\n- `linear.issue.state_changed`\n- `linear.comment.created`\n- `linear.comment.mention`\n\nUnknown Linear webhook types are still persisted as `linear.\u003ctype\u003e.\u003caction\u003e` so agents can inspect them.\n\n## Local Queue\n\nThe queue is an append-only JSONL log. It supports:\n\n- `enqueue`\n- `peek`\n- `pop` / claim with lease\n- `complete`\n- `fail` with retry delay\n- dedup keys\n- priority ordering\n- crash recovery for expired claims\n\nThis is intentionally simple and self-host friendly. If you later need multi-process high-throughput consumers, replace `FileQueue` with a sqlite-backed implementation behind the same interface.\n\n## Agent Tool Surface\n\nImport from `src/index.ts` or the built package:\n\n```ts\nimport { createRuntime, loadConfig } from \"linear-graphql-tool\";\n\nconst runtime = createRuntime(loadConfig({ requireApiKey: true }));\n\nawait runtime.tools.searchIssues({ query: \"webhook\", team: \"ENG\", limit: 10 });\nawait runtime.tools.getIssue({ id: \"ENG-123\" });\nawait runtime.tools.createIssue({ title: \"Agent-created task\", team: \"ENG\", labels: [] });\nawait runtime.tools.addComment({ issue: \"ENG-123\", body: \"Done by local agent.\" });\nawait runtime.tools.peekQueue({ limit: 5 });\n```\n\nThe tool methods return clean structured JSON and avoid noisy GraphQL response shapes.\n\n## Project Structure\n\n```text\nsrc/\n  cli/          Commander CLI\n  client/       raw GraphQL client and Linear operation wrapper\n  config/       dotenv loading and zod validation\n  domain/       service layer, schemas, identifier resolution\n  http/         local HTTP API\n  queue/        persistent JSONL queue\n  tools/        agent-oriented tool functions\n  utils/        logging and typed errors\n  webhook/      Linear signature verification and event routing\ntests/          vitest coverage for critical behavior\n```\n\n## Reliability Notes\n\n- GraphQL calls retry transient network, timeout, and server errors with exponential backoff.\n- Linear GraphQL errors are surfaced explicitly, including rate-limit headers where available.\n- Config, user input, auth, Linear API, not-found, and runtime errors use distinct error classes.\n- Name-to-ID resolution caches teams, users, states, labels, and projects for `LINEAR_CACHE_TTL_MS`.\n- CLI exits with separate codes for config, auth, user input, Linear API, and runtime failures.\n\n## Tests\n\n```bash\nnpm run typecheck\nnpm test\n```\n\nCurrent coverage includes:\n\n- config validation\n- identifier resolution\n- webhook signature verification and routing\n- queue claim/recovery behavior\n- core issue service behavior with a mocked Linear API\n\n## Future OpenClaw / MCP Integration\n\nThe intended bridge point is `createLinearTools`. An OpenClaw plugin or MCP server can wrap these functions directly:\n\n- expose each method as one MCP tool\n- keep `FileQueue` for local webhook inbox state\n- add a sqlite queue adapter if multiple agent workers need concurrent claims\n- map OpenClaw agent identity to Linear comments or labels\n- add policy checks before write operations such as state changes or project moves\n\nThe current HTTP API can also act as a stable local bridge while a native plugin is developed.\n\n## References\n\n- Linear GraphQL getting started: https://linear.app/developers/graphql\n- Linear webhooks: https://linear.app/developers/webhooks\n- Linear rate limits: https://linear.app/developers/rate-limiting\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fillegalstudio%2Flinear-graphql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fillegalstudio%2Flinear-graphql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fillegalstudio%2Flinear-graphql/lists"}