takopi-linear
Linear transport backend plugin for takopi. Turns Linear into a full project management interface for your AI coding agent — delegate issues, track progress through native Agent Activities, and get PRs back.
Status: pre-alpha / early development. Not recommended for production use yet.
How it works
┌─────────────┐ webhook ┌──────────────────┐ Neon DB ┌─────────────────┐
│ Linear │ ──────────────► │ kai-gateway │ ──────────────► │ takopi-linear │
│ (issues, │ │ (Vercel) │ events table │ (this plugin) │
│ comments, │ ◄────────────── │ │ │ │
│ agent UI) │ GraphQL API └──────────────────┘ ◄────────────── │ polls for new │
└─────────────┘ poll + claim │ events, runs │
│ takopi engine │
└─────────────────┘
- A user creates a Linear issue and delegates it to the bot (assigns as agent)
- Linear fires an
AgentSessionEventwebhook to kai-gateway - kai-gateway validates the signature, normalizes the event, and inserts it into a shared Neon (Postgres) database
- takopi-linear polls the database, claims the event, and starts a takopi session
- The AI engine (Claude Code, Codex, etc.) does the work — progress streams back to Linear as native Agent Activities (thoughts, plans, actions)
- When done, the bot creates a PR, transitions the issue to Done, and posts a final response
Setup guide
Prerequisites
- Python 3.14+
- A Neon Postgres database (free tier works)
- A Vercel account (for deploying kai-gateway)
- A Linear workspace with admin access
- takopi installed and configured with at least one engine backend
Step 1: Create the Neon database
- Sign up at neon.tech and create a new project
- Create a database called
kai_gateway - Run the schema to create the events table:
CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE TABLE events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
source TEXT NOT NULL,
event_type TEXT NOT NULL,
external_id TEXT,
payload JSONB NOT NULL,
status TEXT NOT NULL DEFAULT 'pending',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
processed_at TIMESTAMPTZ,
error TEXT
);
CREATE INDEX idx_events_status ON events (status) WHERE status = 'pending';
CREATE INDEX idx_events_source ON events (source, status);
CREATE UNIQUE INDEX idx_events_external_id ON events (source, external_id) WHERE external_id IS NOT NULL;
- Copy your connection string — you'll need it for both kai-gateway and takopi-linear:
postgresql://user:pass@host.neon.tech/kai_gateway?sslmode=require
Step 2: Deploy kai-gateway
kai-gateway is a lightweight Vercel serverless function that receives Linear webhooks and writes them to the shared Neon database.
-
Clone the repo:
git clone https://github.com/asianviking/kai-gateway.git cd kai-gateway
-
Deploy to Vercel:
npx vercel -
Set the environment variables in Vercel (Settings > Environment Variables):
Variable Description DATABASE_URLNeon connection string from Step 1 LINEAR_WEBHOOK_SECRETYou'll get this from Linear in Step 3 -
Note your deployment URL (e.g.
https://kai-gateway.vercel.app) — you'll need it when configuring the Linear webhook.
Step 3: Create the Linear bot application
- Go to Linear Settings > API > Applications and create a new application
- Configure the application:
- Name: Your bot's name (e.g. "Kai")
- Actor: Select
Application(this gives the bot its own identity) - OAuth scopes: Enable
app:assignable,app:mentionable,read,write
- Install the application to your workspace (requires admin)
- Copy the OAuth access token and Application ID — you'll need these for takopi-linear config
- Set up the webhook:
- Webhook URL:
https://your-kai-gateway.vercel.app/webhooks/linear - Signing secret: Generate one and save it — add this to kai-gateway's
LINEAR_WEBHOOK_SECRETenv var - Events: Enable
Issues,Comments, andAgent sessions
- Webhook URL:
Step 4: Install and configure takopi-linear
-
Install the plugin:
pip install takopi-linear
-
Add the Linear transport to your
takopi.toml:transport = "linear" [transports.linear] oauth_token = "lin_oauth_..." # from Step 3 app_id = "your-app-id" # from Step 3 gateway_database_url = "postgresql://...@...neon.tech/kai_gateway?sslmode=require" # from Step 1 poll_interval = 5.0 # Map Linear projects to local repos [plugins.linear] project_map = { "linear-project-uuid" = "my-project" }
-
Start takopi — it will begin polling the gateway database for new events:
takopi run
Step 5: Test the integration
- Create a new Linear issue in a mapped project
- Assign the bot as the agent (delegate to it)
- The bot should acknowledge within a few seconds with an initial plan
- Watch it work through the issue and deliver a PR
Configuration reference
Transport settings ([transports.linear])
[transports.linear]
# Required
oauth_token = "..." # Linear OAuth access token (actor=app)
app_id = "..." # Linear application ID
gateway_database_url = "postgresql://..." # Neon DB connection string
# Polling
poll_interval = 5.0 # seconds between polls (default: 5.0)
poll_batch_size = 10 # events per poll (default: 10)
# Message formatting
message_overflow = "split" # "split" or "trim" (default: "split")
max_body_chars = 10000 # split threshold (default: 10000)
plan_coalesce_s = 1.0 # debounce plan updates (default: 1.0)
ephemeral_activity_coalesce_s = 0.2 # debounce thought updates (default: 0.2)
# Attachments
download_attachments = true # download attached files from prompts
attachment_allowed_hosts = ["uploads.linear.app"]
attachment_max_bytes = 20000000 # 20 MB
attachment_dir = ".takopi-linear/attachments"
Direct webhook server (optional)
For lower latency, you can also run a direct webhook server alongside DB polling. Events are deduplicated across both paths.
[transports.linear]
webhook_enabled = true
webhook_host = "0.0.0.0"
webhook_port = 8080
webhook_path = "/webhooks/linear"
webhook_signing_secret = "..." # HMAC-SHA256 signing secret
Plugin settings ([plugins.linear])
[plugins.linear]
# Project mapping (required — maps Linear project IDs to takopi project aliases)
project_map = { "linear-project-id" = "backend" }
# Worktrees
worktree_strategy = "per_issue" # "per_issue" (default) or "shared"
branch_prefix = "kai/" # branch prefix (default: "kai/")
# Workflow transitions (optional)
success_state_name = "In Review" # case-insensitive; falls back to first type="completed"
# success_state_names = ["Ready for Review", "In Review"] # first match wins
# Auto-labels (opt-in)
auto_labels_enabled = false
auto_labels = { processed = "agent:processed", completed = "agent:completed", failed = "agent:failed" }
# Sub-issues (opt-in — create sub-issues from checklist items)
subissues_enabled = false
subissues_max = 5
# Comment follow-ups (treat new comments as continuation prompts)
comment_followups_enabled = true
comment_followups_debounce_seconds = 0.5
# Prioritization
event_prioritization_enabled = true # sort by issue priority + cycle
current_cycle_only = false # skip issues outside current cycle
# Metadata
estimate_updates_enabled = false # update issue estimates
# Engine/model overrides per project
project_models = { "backend" = "opus" } # default model per project
project_reasoning = { "backend" = "high" } # default reasoning level per project
project_engines = { "backend" = "claude" } # default engine per project
File transfer ([transports.linear.files])
[transports.linear.files]
enabled = true
auto_put = true
auto_put_mode = "prompt" # "upload" = save only, "prompt" = save + annotate prompt
uploads_dir = "incoming"
Usage
Delegating work
Create a Linear issue and assign the bot as the agent. The issue title becomes the prompt:
| Issue title | Branch | Prompt |
|---|---|---|
Add JWT authentication |
kai/AV-123 (auto) |
"Add JWT authentication" |
@feat/auth Add JWT authentication |
feat/auth (custom) |
"Add JWT authentication" |
Title directives
Override model, reasoning, or engine per issue using brackets in the title:
[model:sonnet] Fix the login bug
[reasoning:high] Refactor the auth module
[engine:codex] Scaffold the new API
Or use Linear labels: model > sonnet, engine > codex, reasoning > high.
Special commands
Use these in issue comments:
| Command | Effect |
|---|---|
stop, cancel |
Cancel the current run |
/new, /reset |
Clear session context and start fresh |
/help, help, ? |
Show help text |
/file put <path> |
Upload an attached file to the working directory |
/file get <path> |
Download a file (or zipped directory) back to Linear |
Worktrees / branching
By default (worktree_strategy = "per_issue"), each issue runs in its own git worktree with a branch derived from the issue identifier (e.g. kai/AV-123).
To override per issue, prefix the title with @branch/name (e.g. @fix/login Fix the login bug).
kai-gateway
kai-gateway is the webhook ingress layer that sits between Linear and takopi-linear. It's a simple Vercel serverless function that:
- Receives Linear webhook events at
POST /webhooks/linear - Verifies the HMAC-SHA256 signature
- Checks for replay attacks (rejects stale deliveries)
- Normalizes the event payload
- Inserts it into the shared Neon
eventstable with deduplication
takopi-linear then polls this table, atomically claims pending events using FOR UPDATE SKIP LOCKED, and processes them. This decoupled architecture means:
- No public endpoint needed on the takopi host — it only makes outbound connections
- Multiple consumers can safely poll the same table (events won't be double-processed)
- Events are durable — if takopi is down, events queue up and are processed when it comes back
Environment variables (kai-gateway)
| Variable | Description |
|---|---|
DATABASE_URL |
Neon Postgres connection string |
LINEAR_WEBHOOK_SECRET |
HMAC-SHA256 signing secret (must match Linear app webhook config) |
Development
# Clone and install
git clone https://github.com/asianviking/takopi-linear.git
cd takopi-linear
uv sync --extra test
# Run tests
uv run pytest
# Build
uv build
See RELEASING.md for the release process.
Metadata
Release files for takopi-linear 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| takopi_linear-0.1.0.tar.gz | 106.5 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| takopi_linear-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 157.1 kB
Release files / takopi_linear-0.1.0.tar.gz
| Download URL | takopi_linear-0.1.0.tar.gz |
|---|---|
| Size | 106.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e4e5a1ab86391414b7331335aa2e8d6ace598668462451d5ef8dd6532ce634e3
|
|
BLAKE2b-256 checksum How to use checksums |
1364d8dae1c55aec504edba0f0fedbf939d2bc921de754910d00e3bd33bb0dee
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 25, 2026.
Transparency logRelease files / takopi_linear-0.1.0-py3-none-any.whl
| Download URL | takopi_linear-0.1.0-py3-none-any.whl |
|---|---|
| Size | 50.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bd39988458adabe198c7c0e5caf0ae0ece62b106ba67c23dc11d38d4f755af9a
|
|
BLAKE2b-256 checksum How to use checksums |
916b564d8a6786ce9a250489dd8d0ac8572793394a0448b6319afeb9371ce47d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 25, 2026.
Transparency logSecurity for takopi-linear 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for takopi_linear-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 25, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.