Linear manager
A curated collection of agent skills — reusable, self-contained modules that extend AI coding assistants with specialized capabilities and domain knowledge.
npx -y skills add snvtac/skills --skill linear-managerAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Manage Linear tickets/comments via direct HTTP GraphQL with `python3 scripts/linear_manager.py` and token env vars only (no Linear MCP). Supports create/read/update/delete tickets and sub-tickets, issue templates, discovery commands (whoami, teams, projects), creating/moving tickets under a project, workflow status changes, team reassignment, cycle/label updates, and comment read/create/thread reply.
SKILL.md
13.4 KB, as published. Nobody here has run it
Linear Manager
Overview
Use this skill for Linear operations through https://api.linear.app/graphql only.
Execution entrypoint is python3 scripts/linear_manager.py.
Capability Scope
- Read:
list,get,templates,states,children,comments - Discovery (for an unfamiliar/multi workspace):
workspaces(all token env vars → workspace names),whoami(current user + workspace),teams(id/key/name),projects(id/name + teams) - Write:
create,update,delete,comment - Sub-ticket:
create --parent <ISSUE_REF> - Template:
templates,create [--template-id|--template-name|--use-default-template] - Project:
projects [--team-key <KEY>|--team-id <UUID>] [--name <SUBSTR>]create --project-id <UUID>orcreate --project-name <NAME>update --project-id <UUID>orupdate --project-name <NAME> - Team management:
update --team-key <KEY>orupdate --team-id <UUID> - Status management:
update --state <name>orupdate --state-id <uuid> - Cycle/label management:
update --cycle-id|--cycle-name|--cycle-numberupdate --set-labels|--add-labels|--remove-labelsupdate --set-label-ids|--add-label-ids|--remove-label-ids
Hard Constraints
- Always operate via HTTP script:
python3 scripts/linear_manager.py. - Never use Linear MCP tools (
mcp__linear__*) in this skill. - If token is missing or HTTP fails, return an error with short suggestions only.
- Do not fallback to Linear MCP under any failure mode.
Token Policy
Default env var is LINEAR_API_TOKEN. Select a non-default token with --token-env <ENV_NAME>.
Never print or echo a token value (do not run echo "$LINEAR_API_TOKEN"). To verify a token, resolve its workspace with whoami/workspaces instead — those never expose the token string.
If the chosen token env var is missing, stop and provide suggestions only:
export LINEAR_API_TOKEN='lin_api_xxx'
Multi-Workspace Policy (Pick One, Then Lock It)
The environment may define MORE THAN ONE Linear token, because the user works across multiple workspaces (e.g. two lin_api_* tokens in .bashrc). Treat the active workspace as explicit per-session state:
- Discover. Run
workspacesto list every Linear token env var and the workspace it maps to. Token values are never printed — only env var names, the viewer, andorganization.name/urlKey.python3 scripts/linear_manager.py --pretty workspaces - Ask the user to choose — by workspace name. If more than one workspace is available and the user has not already named one this session, STOP before any operation and present the choice as selectable options whose labels are the
organization.namevalues fromworkspaces(e.g. "Final Round AI", "Dark Legion"). Never guess or default silently. - Lock for the session, with a hard guard. Once the user picks (or only one token exists), record the corresponding
--token-envAND the chosen workspace name. On EVERY subsequent command this session, pass both--token-env <ENV>and--expect-workspace <NAME>. The guard runswhoamibefore the command and refuses to run (exit code3) if the token does not resolve to that workspace — so a forgotten or wrong--token-envcan never silently hit another workspace. Do not switch workspaces unless the user explicitly asks.python3 scripts/linear_manager.py \ --token-env PERSON_LINEAR_API_TOKEN \ --expect-workspace "Dark Legion" \ --show-workspace --pretty list --team-key ENG --limit 5 - Report the workspace on every operation. State which workspace each result ran against. Output is labeled with
_tokenEnv, and--show-workspaceadds the resolved_workspace(org name) so reports are never ambiguous.
If the user later names a different workspace explicitly, switch to its token env var (and matching --expect-workspace) and re-confirm by reporting the new workspace name.
Cross-session note: this lock lives only in the current session. A new
claudesession starts with no memory of the choice and MUST re-run step 1–2. The selection is intentionally never persisted, so workspaces cannot leak across sessions.
Write Safety Policy (Default Dry-Run)
create, update, delete, comment are dry-run by default.
To perform real write, caller must pass --execute.
Delete has an extra safety requirement:
- Run dry-run first to inspect the resolved target and expected confirmation value.
- Re-run with both
--executeand--confirm-delete <IDENTIFIER>after the user explicitly agrees.
Recommended two-step workflow:
- Run dry-run first and inspect payload.
- Run the same command with
--executeto apply.
Example:
python3 scripts/linear_manager.py --pretty update --id ENG-123 --state "In Progress"
python3 scripts/linear_manager.py --pretty update --id ENG-123 --state "In Progress" --execute
Command Reference
Run from skill folder:
python3 scripts/linear_manager.py --pretty list --limit 20
python3 scripts/linear_manager.py --pretty templates --team-key ENG
python3 scripts/linear_manager.py --pretty templates \
--team-key ENG \
--name "Issue Templates 2025"
python3 scripts/linear_manager.py --pretty workspaces
python3 scripts/linear_manager.py --pretty whoami
python3 scripts/linear_manager.py --pretty teams --limit 100
python3 scripts/linear_manager.py --pretty teams --name core
python3 scripts/linear_manager.py --pretty projects --limit 50
python3 scripts/linear_manager.py --pretty projects --team-key ENG --limit 50
python3 scripts/linear_manager.py --pretty projects --team-key ENG --name "platform"
python3 scripts/linear_manager.py --pretty get --id ENG-123 --include-children --comments-limit 20
python3 scripts/linear_manager.py --pretty create \
--team-key ENG \
--title "Issue title"
python3 scripts/linear_manager.py --pretty create \
--team-key ENG \
--title "Issue title" \
--description "Issue description" \
--execute
python3 scripts/linear_manager.py --pretty create \
--team-key ENG \
--title "Issue title" \
--template-name "Issue Templates 2025"
python3 scripts/linear_manager.py --pretty create \
--team-key ENG \
--title "Issue title" \
--template-id <TEMPLATE_UUID> \
--execute
python3 scripts/linear_manager.py --pretty create \
--team-key ENG \
--title "Issue title" \
--use-default-template
python3 scripts/linear_manager.py --pretty create \
--team-key ENG \
--title "Issue title" \
--project-name "Platform Foundation 2026"
python3 scripts/linear_manager.py --pretty create \
--team-key ENG \
--title "Issue title" \
--project-id <PROJECT_UUID> \
--execute
# --team-key/--team-id is optional when the project resolves to a single team; the team
# is derived (output then includes derivedTeam + a warning to verify it).
python3 scripts/linear_manager.py --pretty create \
--title "Issue title" \
--project-name "Platform Foundation 2026"
python3 scripts/linear_manager.py --pretty create \
--team-key ENG \
--title "Sub-ticket title" \
--parent ENG-123 \
--execute
python3 scripts/linear_manager.py --pretty update \
--id ENG-123 \
--cycle-name "Cycle 25" \
--add-labels "TEST,bug bash"
python3 scripts/linear_manager.py --pretty update \
--id ENG-123 \
--cycle-name "Cycle 25" \
--add-labels "TEST,bug bash" \
--execute
python3 scripts/linear_manager.py --pretty update \
--id ENG-123 \
--description-file /tmp/issue-desc.md \
--execute
python3 scripts/linear_manager.py --pretty update \
--id ENG-123 \
--team-key DEVOPS
python3 scripts/linear_manager.py --pretty update \
--id ENG-123 \
--team-key DEVOPS \
--execute
python3 scripts/linear_manager.py --pretty update \
--id ENG-123 \
--project-name "Platform Foundation 2026" \
--execute
python3 scripts/linear_manager.py --pretty states --team-key ENG
python3 scripts/linear_manager.py --pretty children --id ENG-123 --limit 50
python3 scripts/linear_manager.py --pretty comments --id ENG-123 --limit 20
python3 scripts/linear_manager.py --pretty comment \
--id ENG-123 \
--body "Progress update"
python3 scripts/linear_manager.py --pretty comment \
--id ENG-123 \
--body "Progress update" \
--execute
python3 scripts/linear_manager.py --pretty comment \
--id ENG-123 \
--parent-comment-id <COMMENT_UUID> \
--body "Thread reply" \
--execute
python3 scripts/linear_manager.py --pretty delete --id ENG-123
python3 scripts/linear_manager.py --pretty delete \
--id ENG-123 \
--confirm-delete ENG-123 \
--execute
Output And Exit Codes
- Exit code
0: success - Exit code
1: validation/API error - Exit code
2: missing token env var - Exit code
3:--expect-workspaceguard mismatch (token resolves to a different workspace)
Operational Notes
- Prefer
--prettyfor readable JSON. --idand--parentaccept both UUID and identifier (TEAM-123).templatesis read-only. It lists issue templates by default and can filter by team/name.- Template creation is optional. If no template flag is passed to
create, the command keeps the original custom-content behavior. create --template-nameuses a case-insensitive exact name match and must resolve to one available issue template.create --titleis still required, so template title values are always overridden by the CLI title.- CLI-provided create fields override matching template fields; fields not provided by the CLI are left for Linear to fill from the template.
- Form-field templates are not filled by this CLI version. Dry-run warns for explicit
--template-id/--template-nameselections whenhasFormFields=true. delete --executerequires--confirm-deleteto exactly match the resolved issue identifier.- For an unfamiliar or multi-token environment, start with
workspaces(pick the workspace), thenwhoami(confirm user + workspace), thenteams(find team keys), thenprojects(find project ids/names). workspacesscans all candidate token env vars and does not require--token-envto be set; it never prints token values. Detection is by token VALUE prefix (lin_api_/lin_oauth_) only — never by env var name — so an unrelated secret is never sent to Linear. If a real token uses an unrecognized format, select it explicitly with--token-env.- Output is labeled with
_tokenEnv; add--show-workspaceto also include_workspace(resolved org name) at one extra API call. --expect-workspace <name|urlKey>is a hard cross-workspace guard: it runswhoamifirst and refuses (exit3) unless the token resolves to that workspace. It applies to all commands exceptworkspaces, and reuses the samewhoamicall as--show-workspace. In a multi-token environment, pass it on every command alongside--token-env. An empty value (e.g.--expect-workspace "$UNSET") also refuses (exit3) rather than silently skipping.whoamiandteamsare read-only and need no arguments beyond optionalteams --name/--limit.projectslists workspace projects by default;--team-key|--team-idlists projects accessible to that team. It is read-only.projects --nameis a case-insensitive substring filter applied to the fetched page (--limit).--limitis capped at 250 (Linear's per-query complexity ceiling); to find a specific project, prefer--name, scope with--team-key/--team-id, or resolve it directly viacreate/update --project-name.create/updateaccept--project-id(UUID) or--project-name.--project-nameis a case-insensitive exact match scoped to the issue's team and must resolve to exactly one project.--project-idis validated to be accessible to the target team; a project scoped to other teams (or with no team) is rejected before the mutation.createaccepts a team via--team-key/--team-id, OR derives the team from--project-id/--project-namewhen that project belongs to exactly one team. If the project spans multiple teams (or none), pass--team-key/--team-idexplicitly. When the team is derived, the output includesderivedTeamand awarningsentry — verify it is the intended team before relying on a real create.update --team-key|--team-idmoves an issue to another team.- Do not combine a cross-team move with
--state,--cycle-*, or label mutation flags; move first, then apply destination-team workflow fields in a second command. - For large markdown, use
--description-fileor--body-file. - Use
--body-stdinfor piping comment content.
Validation
Ensure no MCP call is introduced in executable script:
rg -n "mcp__linear__" skills/linear-manager/scripts/linear_manager.py
Expected result: no matches (exit code 1).
Resources
- Script entrypoint:
scripts/linear_manager.py - Test cases:
scripts/linear_manager_test_cases.md - GraphQL reference:
references/graphql-operations.md