Skip to content
← Community packages

@kody/linear

Star @kody/linear
TrustedFeaturedInstall

Read and update Linear issues, projects, teams, comments, and workflow states through OAuth or an API key.

Browse files

License
MIT
Published
August 23, 2026
Pinned commit
c994644
Rating
No ratings yet
Forks
0
Stars
0
Adaptation effort

README

@kody/linear

Intent

Provide reusable, account-agnostic Linear helpers so Kody agents can read and update issues, projects, teams, comments, and workflow states through a saved linear / linear-* OAuth integration or a personal API key — without hand-rolling GraphQL. Mutations are previewable with dryRun: true and only run live after confirm: true.

This listing is meant to be forked. After you fork, connect your Linear workspace. Do not treat the live @kody/linear package storage as yours.

This official OAuth/API-key package is the preferred invoke path. Setup is harder: bring your own Linear OAuth app or personal API key. For a faster first win, connect Linear MCP in Get started and use @kody/linear-mcp.

When To Use

  • List or inspect teams, projects, issues, comments, and workflow states
  • Create or update issues, comments, and projects after explicit confirmation
  • Call an unwrapped Linear GraphQL operation through ./request
  • Connect more than one Linear workspace via integrationName / account

Auth

Linear has no built-in Kody OAuth app. Choose one lane:

LaneWhen to useCredential
OAuth (recommended)Multi-account, refresh tokens, shared helpersSaved integration linear or linear-<purpose>
Personal API keyFastest for a single workspace / personal scriptsUser secret linearApiKey (or linearApiKey-<purpose>)

OAuth access tokens use Authorization: Bearer …. Personal API keys must be sent as Authorization: <API_KEY> without the Bearer prefix — this package handles that.

Required API host: api.linear.app. Approve it in the account secrets UI.

Lane A — BYO OAuth

  1. Create an OAuth application at https://linear.app/settings/api/applications/new
  2. Set the redirect URI exactly to https://kody.codes/connect/oauth
  3. Request scopes read,write (comma-separated; read is always present). Narrower mutation-only scopes: issues:create, comments:create.
  4. Connect while signed in to Kody:

https://kody.codes/connect/oauth?provider=linear&authorizeUrl=https%3A%2F%2Flinear.app%2Foauth%2Fauthorize&tokenUrl=https%3A%2F%2Fapi.linear.app%2Foauth%2Ftoken&apiBaseUrl=https%3A%2F%2Fapi.linear.app&scopes=read%2Cwrite&scopeSeparator=%2C&flow=confidential&allowedHosts=api.linear.app&dashboardUrl=https%3A%2F%2Flinear.app%2Fsettings%2Fapi%2Fapplications%2Fnew

  1. Paste the Linear client id and client secret into the Kody wizard (never into chat). Approve host api.linear.app.
  2. Reconnect later with https://kody.codes/connect/oauth?provider=linear

OAuth token URL: https://api.linear.app/oauth/token. Authorize URL: https://linear.app/oauth/authorize. Flow: confidential (client secret). Linear scopes are comma-separated (scopeSeparator=,).

To connect a second workspace, change provider (for example provider=linear-work) and pass integrationName: 'linear-work' on every call. Add prompt=consent on Linear's authorize screen if you need to pick a different workspace for the same app.

Lane B — Personal API key

  1. Create a key at https://linear.app/settings/account/security
  2. Grant Read plus the write permissions you need (Write, or Create issues / Create comments).
  3. Save it (do not paste the value in chat):

https://kody.codes/account/secrets/new?name=linearApiKey&description=Linear%20personal%20API%20key&allowedHosts=api.linear.app&scope=user

For a second workspace/key, use a distinct secret name such as linearApiKey-work and pass secretName: 'linearApiKey-work' (or account: 'work', which resolves to linear-work / linearApiKey-work).

Scopes

ScopeNeeded for
readAll queries (viewer, teams, projects, issues, comments, workflow states)
issues:create./create-issue
comments:create./create-comment
write./update-issue, ./create-project, other mutations
adminDo not request unless a workflow truly needs admin endpoints

If Linear returns 401/403 or a GraphQL FORBIDDEN / insufficient-scope error, helpers throw a message that names the missing scope and the next setup URL (reconnect OAuth with that scope, or save an API key with the matching permission).

Multiple accounts

Every export accepts:

  • integrationName / integration — exact saved OAuth name (linear-work)
  • accountworklinear-work; linear-work used as-is; omitted → linear
  • secretName — API key secret override
  • auth'oauth' or 'api-key' when both exist

Do not hard-code a personal workspace slug or alias.

Safety

Mutating helpers require confirm: true. Pass dryRun: true to inspect the GraphQL payload without calling Linear. ./request treats query documents as read-only; mutation documents need confirmation.

Exports

ExportDescription
.Package overview, connect URLs, export map
./accountsResolve integration/secret names and report what is connected
./smoke-testLocal helper checks plus optional live viewer read (no email)
./viewerAuthenticated viewer id / name / organization id
./list-teamsList teams
./get-teamGet one team by UUID or key
./list-projectsList projects
./get-projectGet one project by UUID
./create-projectPreview or create a project (teamIds required)
./list-issuesList issues (teamId / teamKey, projectId, assigneeId, stateType, query)
./get-issueGet one issue by UUID or identifier (ENG-123)
./create-issuePreview or create an issue (title + teamId)
./update-issuePreview or update an issue
./list-commentsList comments on an issue
./create-commentPreview or create a comment
./list-workflow-statesList workflow states (teamId / teamKey, type)
./requestGeneric GraphQL escape hatch
./typesShared TypeScript types

Priority values: 0 none, 1 urgent, 2 high, 3 medium, 4 low. Workflow state types: triage, backlog, unstarted, started, completed, canceled.

Smoke test

import smokeTest from 'kody:@kody/linear/smoke-test'

export default async function main() {
	return await smokeTest()
}

Without credentials this returns { ok: true, live: false } plus the connect and API-key URLs. After OAuth or an API key is saved it reads viewer { id } and returns { live: true, hasViewerId, hasOrganizationId } without email.

Preview a mutation without credentials:

import createIssue from 'kody:@kody/linear/create-issue'

export default async function main() {
	return await createIssue({
		title: 'Follow up on onboarding',
		teamId: '00000000-0000-0000-0000-000000000000',
		dryRun: true,
	})
}

Examples

import listIssues from 'kody:@kody/linear/list-issues'
import listWorkflowStates from 'kody:@kody/linear/list-workflow-states'

export default async function main() {
	const states = await listWorkflowStates({ teamKey: 'ENG' })
	return await listIssues({
		teamKey: 'ENG',
		stateType: 'started',
		first: 20,
	})
}
import createIssue from 'kody:@kody/linear/create-issue'

export default async function main() {
	const preview = await createIssue({
		title: 'Investigate checkout timeout',
		teamId: 'team-uuid',
		priority: 2,
		dryRun: true,
	})
	// After the user confirms the exact team and title:
	return await createIssue({
		title: 'Investigate checkout timeout',
		teamId: 'team-uuid',
		priority: 2,
		confirm: true,
	})
}

Unwrapped GraphQL:

import request from 'kody:@kody/linear/request'

export default async function main() {
	return await request({
		query: `query ($key: String!) {
			team(id: $key) { id name key }
		}`,
		variables: { key: 'ENG' },
	})
}

Notes

  • GraphQL endpoint: https://api.linear.app/graphql
  • Helpers project slim objects. Use ./request when you need extra fields.
  • assigneeId: 'me' on ./list-issues filters to the authorizing user.
  • This package is not affiliated with or endorsed by Linear Orbit, Inc.

Branding

The community icon is Linear's official logomark as served by Linear (https://static.linear.app/client/assets/favicon-D8hcELd9.svg), scaled to a square. Paths are unmodified. Linear® is a trademark of Linear Orbit, Inc.

Docs

Report this listing

Log in to report this listing.