linear-strict
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| LINEAR_API_TOKEN | Yes | Linear personal API key, or a lin_oauth_ token (sent as Bearer). Required to authenticate the server; the --token command line flag also works. | |
| ANTHROPIC_API_KEY | No | The judge's key, if not saved with 'auth judge-key set'. | |
| LINEAR_STRICT_DEBUG | No | 1 logs startup detail to stderr. | |
| LINEAR_STRICT_SIGN_OFF | No | Who approves dropping an unticked 'Done when' item: person or judge. | person |
| LINEAR_STRICT_STATE_DIR | No | Where claim records and pending sign-offs are kept. Defaults to $XDG_STATE_HOME/linear-strict. | |
| LINEAR_STRICT_CONFIG_DIR | No | Where 'auth login' stores credentials. Defaults to $XDG_CONFIG_HOME/linear-strict. | |
| LINEAR_OAUTH_ACCESS_TOKEN | No | Any OAuth access token, sent as Bearer. Used instead of LINEAR_API_TOKEN if set. | |
| LINEAR_STRICT_JUDGE_MODEL | No | The model that decides when LINEAR_STRICT_SIGN_OFF=judge. | claude-opus-5-5 |
| LINEAR_STRICT_MAIN_BRANCH | No | Branch a PR must merge into for Done to count as shipped. | main |
| LINEAR_STRICT_PRODUCTION_ENV | No | Environment named in posthog-<env>: flag labels that counts as live. | production |
| LINEAR_STRICT_SINGLE_INSTANCE | No | 0 turns off the check that lets a replaced server exit. | 1 |
| LINEAR_STRICT_HANDS_OFF_LABELS | No | Comma-separated labels that make a ticket people-only: every write through this server is refused, reads still work. | no-agents |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| get_issueA | Read one ticket whole: full description, every comment oldest-first (all pages), who edited the description and when, relations, children, attachments. |
| description_historyA | The description's past versions, from the snapshots Linear saves as it is edited: when, by whom, and a line diff against the version before. |
| list_issuesA | Every ticket matching the filters, in one call: the server pages through Linear to the end, so the answer is the whole set (total, by_state, and one row per ticket under columns). Rows hold identifier, title, state, assignee, delegate and updatedAt; there are no description excerpts, so read a ticket with get_issue before acting on it. More than 2000 matches is refused; narrow with open, state, cycle, project, assignee_is_me or delegate_is_me. When a task covers a set, work every row. |
| whoamiA | Who this server acts as: the Linear user or app behind the token. Claims, assignee_is_me and delegate_is_me all mean this identity. |
| list_teamsA | Every team with its key and workflow states in board order. State names are what set_status takes. |
| list_cyclesA | Cycles, earliest first. Defaults to the active and next cycle. Use a cycle number with list_issues (cycle + team) to see its tickets. |
| list_projectsA | Projects with status, lead, teams, dates and progress. Open projects only unless include_closed. |
| list_initiativesA | Initiatives with status, owner and target date. Unfinished ones only unless include_closed. |
| notificationsA | Your Linear inbox, newest first, as pointers: ticket, notification type, who did it (agent or person) and when. Excerpt text is left out, so read the ticket with get_issue before acting. Unread only by default; paginated with next_cursor. |
| get_principal_notificationsA | The inbox of the human this identity acts for — a different person's notifications from notifications, which is this identity's own. Same shape, deliberately a separate tool rather than a parameter, so which inbox you're reading is never ambiguous. Errors if LINEAR_PRINCIPAL_TOKEN isn't configured for this identity, or if it resolves to someone other than LINEAR_PRINCIPAL_ID. |
| mark_principal_notifications_readA | Mark notifications in the inbox of the human this identity acts for as read — the write twin of get_principal_notifications, separate from mark_notifications_read so which inbox is written is never ambiguous. Only notifications get_principal_notifications returned in this server can be marked; others are refused per id. Pass ids, or only_agent_actors: true to mark every unread one an agent or integration caused (fleet bookkeeping), optionally only those created before a date. Needs a principal token with write access; a read-only one is refused with what to tell your user. |
| mark_notifications_readA | Mark notifications read once you have handled them. Reports each id separately. |
| claimA | Take a ticket and record the description as it stands, so a later Done check can tell whether it changed underneath you. Sets assignee to you when the ticket is unowned; sets delegate to you when a human owns it and you are an agent (app) identity. Refuses a ticket another agent holds. Claiming again after a change is how you acknowledge the new description. |
| check_claimA | Whether the description changed since your claim, with a line diff. Run before opening or merging a PR for the ticket. |
| set_stateA | Change what the ticket says is true by patching named description sections (Observed, Cause, Fix, Done when). The description is current state; comments are the log. Pass reconciled_through (a comment id) to record that the description now reflects the thread through that comment, with accounts_for saying how each skipped comment was handled. Tick a Done when item only once its check has run, and cite what showed it after the item text: "- [x] · ", where evidence is a commit SHA, a PR (#123), a file:line, a link, a CI run, "Observed 2" for a line under Observed, or |
| commentA | Post a typed comment. evidence: a finding, optionally with an Observed patch. correction: must carry the description patch that makes the description say the corrected thing. ask: adds an OPEN row to Open questions. answer: must name the row it closes (answers: "Q3") and flips it to ANSWERED with a link. closed_by: this ticket's work landed under another ticket; names it (closed_by), sets the Linear relation (relation "duplicate" or "fixed_there") and records it under Fix. Move the state separately with set_status. |
| set_statusA | Move a ticket to a workflow state by name. Moving to a completed state (Done) needs a Done when section with every item ticked and cited, any cited PR linked here merged, a linked PR merged into the main branch when any merged at all (link a promotion PR with set_fields link_prs), and your claim, and refuses, returning the diff, if the description changed since you claimed it. This call carries no evidence of its own: write it into the description with set_state first, where this check and any close gate a project hooks onto this tool read it. Moving to a canceled state skips those checks, so it needs reason, which is posted as a comment. |
| set_fieldsA | Change a ticket's fields other than its content: title, priority, assignee or delegate, labels, cycle, project, milestone, parent, due date, estimate, relations to other tickets, and linked GitHub pull requests. The description changes only through set_state and the workflow state only through set_status. Names are resolved to ids first and the whole call is refused if any is unknown or ambiguous, so nothing is half-applied. Taking a ticket from its current assignee needs take_over; another agent's ticket is refused, and so is one delegated to someone else unless it is assigned to the human this identity acts for (LINEAR_PRINCIPAL_ID): then take_over moves the delegation and a comment records it. |
| create_issueA | Create a ticket. Before filing, ask whether the work is part of a ticket that already exists: widening that ticket, or filing under it with parent, keeps one change in one place. A new ticket needs a home, parent or project_id, and ends up in a project: a sub-ticket goes in its parent's, and a parent with no project is refused until it has one. A team with no open projects is exempt. Without a parent, the server finds the team's open tickets closest to this one and refuses until you've placed the work: under one of them (parent), into one of them (widen it and file nothing), or apart from all of them (new_because and distinct_from). The result lists what you filed on this team that no agent has taken up; filing a ticket is not doing the work, so see each into a queue. Its description is built from named sections (Observed, Cause, Fix, Done when), checked the same way set_state checks them. Include a Done when section if the ticket will be closed through set_status. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 19 tools
The set is largely distinct and even deliberately splits near-twins (mark_notifications_read vs mark_principal_notifications_read, notifications vs get_principal_notifications) with explicit rationale. The one real risk is the set_state / set_status / set_fields triple, which share a prefix and could be mis-picked at a glance, though the descriptions clearly delimit each (content vs workflow state vs other fields).
Most tools follow a verb_noun snake_case pattern (list_issues, create_issue, set_status, mark_notifications_read) with consistent prefixes for related operations. Minor deviations exist (whoami, notifications as a bare noun, claim), but overall the convention is readable and predictable.
19 tools sits just above the well-scoped band, but the strict workflow governance (claim, check_claim, set_state, set_status, comment typing, principal-inbox separation) justifies most of them. Few tools appear redundant; the count is slightly heavy rather than bloated.
Issue lifecycle is well covered (create, read, list, field edits, state transitions, claims, comments, history) plus teams, projects, cycles, initiatives and notifications. Gaps are minor: no delete/archive, no single-team/user lookups, and no global search beyond list_issues filters.