Skip to content

Setup

This walkthrough assumes you already have a runner CLI installed and logged in (Claude Code is the default; Codex, OpenCode, Antigravity, and Hermes also work — see Runners).

  • Node 22+ (uses the experimental SQLite module).
  • A Linear workspace you can administer (you’ll create a webhook).
  • A runner CLI logged in: claude (default), or one of codex / opencode / agy / hermes.
  • Webhook ingress — Cloudflare Tunnel is recommended; ngrok and Tailscale Funnel work too.
Terminal window
git clone https://github.com/juneclaw/june.git
cd june
npm install

In Linear: Settings → API → Personal API keys → Create key. Copy the value; you can’t retrieve it later. June reads it from JUNE_LINEAR_API_KEY (or LINEAR_CLAUDE_LINEAR_API_KEY as a legacy alias).

Terminal window
export JUNE_LINEAR_API_KEY=lin_api_

The token needs read + write on issues and comments in the team you’ll point it at. A personal key with full scope is fine for self-hosting.

The orchestrator listens on :8787 (override with PORT). Linear needs to reach it over HTTPS.

Stable URL, free, no rotating token. From a machine with cloudflared installed and authenticated:

Terminal window
cloudflared tunnel create june
cloudflared tunnel route dns june june.<your-domain>
cloudflared tunnel run --url http://localhost:8787 june
Terminal window
ngrok http 8787

The free tier URL rotates every restart — fine for development, painful for long-running setups.

If your Linear team has Tailscale ACLs, expose :8787 via Funnel and use the *.ts.net URL.

In Linear: Settings → API → Webhooks → New webhook. Point it at https://<your-ingress>/webhook/linear. Subscribe to Issue and Comment events. Copy the signing secret.

Terminal window
export JUNE_LINEAR_WEBHOOK_SECRET=lws_

(LINEAR_CLAUDE_WEBHOOK_SECRET is honored as a legacy alias.)

If you’d rather have June register the webhook for you, set LINEAR_CLAUDE_PUBLIC_WEBHOOK_URL=https://<your-ingress>/webhook/linear and npm run setup will create or update the webhook via the API.

June expects a small set of Linear labels and workflow states. Run:

Terminal window
npm run ensure-labels # creates: codex, opencode, gemini, hermes, xhigh, fast, goal
npm run ensure-states # ensures: Todo, In Progress, Ready for Review, Blocked, Waiting

Both are idempotent. Re-run after any Linear UI change without worry.

Terminal window
npm start

The service runs with Node’s experimental SQLite module under the hood:

Terminal window
node --experimental-sqlite src/server.mjs

Health checks live at GET /health. Logs stream to logs/agent.log and stdout.

Create a fresh Linear issue in the team you configured, in any active state (Todo, In Progress, etc.). Within a few seconds the orchestrator should:

  1. Receive the webhook.
  2. Move the issue to In Progress.
  3. Post the agent’s first reply as a comment.
  4. Land in Ready for Review on a clean exit, or Blocked with a triage summary on failure.

Add a comment to the same issue — the agent resumes the same session and replies.