Takopi transport backend for Linear Agent SDK
Project description
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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file takopi_linear-0.1.0.tar.gz.
File metadata
- Download URL: takopi_linear-0.1.0.tar.gz
- Upload date:
- Size: 106.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e4e5a1ab86391414b7331335aa2e8d6ace598668462451d5ef8dd6532ce634e3
|
|
| MD5 |
801f21a8f35706ef79b3ef02deaa0f98
|
|
| BLAKE2b-256 |
1364d8dae1c55aec504edba0f0fedbf939d2bc921de754910d00e3bd33bb0dee
|
Provenance
The following attestation bundles were made for takopi_linear-0.1.0.tar.gz:
Publisher:
release.yml on asianviking/takopi-linear
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
takopi_linear-0.1.0.tar.gz -
Subject digest:
e4e5a1ab86391414b7331335aa2e8d6ace598668462451d5ef8dd6532ce634e3 - Sigstore transparency entry: 992186272
- Sigstore integration time:
-
Permalink:
asianviking/takopi-linear@2523744e52f127b34250618ead9cde7f32d4dd4a -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/asianviking
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2523744e52f127b34250618ead9cde7f32d4dd4a -
Trigger Event:
push
-
Statement type:
File details
Details for the file takopi_linear-0.1.0-py3-none-any.whl.
File metadata
- Download URL: takopi_linear-0.1.0-py3-none-any.whl
- Upload date:
- Size: 50.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bd39988458adabe198c7c0e5caf0ae0ece62b106ba67c23dc11d38d4f755af9a
|
|
| MD5 |
a5df202a1caf9cf7b1294d96b00e6b54
|
|
| BLAKE2b-256 |
916b564d8a6786ce9a250489dd8d0ac8572793394a0448b6319afeb9371ce47d
|
Provenance
The following attestation bundles were made for takopi_linear-0.1.0-py3-none-any.whl:
Publisher:
release.yml on asianviking/takopi-linear
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
takopi_linear-0.1.0-py3-none-any.whl -
Subject digest:
bd39988458adabe198c7c0e5caf0ae0ece62b106ba67c23dc11d38d4f755af9a - Sigstore transparency entry: 992186298
- Sigstore integration time:
-
Permalink:
asianviking/takopi-linear@2523744e52f127b34250618ead9cde7f32d4dd4a -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/asianviking
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2523744e52f127b34250618ead9cde7f32d4dd4a -
Trigger Event:
push
-
Statement type: