Files
agent-skills/skills/linear-common/COMMON.md
T
naps62 f83a247de3 init: centralized agent skills for Claude Code + Codex
- skills/ shared by both tools (open Agent Skills standard)
- portable cross-skill refs (root-relative, no ~/.claude hardcode)
- bin/link.sh bootstrap for non-Nix machines
- nix/home.nix + flake.nix for home-manager

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SK5Lo7LQfwLRVdCv1A8uF
2026-07-24 17:59:44 +00:00

13 KiB

Linear Common - Shared Config & Setup

This document is referenced by the /work and /yolo skills. Do not invoke it directly.

Project config

Look for the tracker config in the current git repo root (git rev-parse --show-toplevel), trying these paths in order and using the first that exists:

  1. .claude/tracker.json (preferred, generic name)
  2. .claude/linear.json (legacy name, still supported)

If none exists, run First-time setup below, then continue. When creating the file in setup, prefer the generic .claude/tracker.json name.

Schema

Linear example (tracker: linear):

{
  "tracker": "linear",
  "org": "ern",
  "team": "Ern",
  "project": "Contracts v2",
  "defaultBranch": "main",
  "commitScope": "platform",
  "buildCommand": "forge test",
  "setupCommands": ["bun install"],
  "contextFiles": ["docs/README.md"],
  "prReviewers": [],
  "labels": []
}

Gitea-issues example (tracker: gitea):

{
  "tracker": "gitea",
  "defaultBranch": "main",
  "commitScope": "maestro",
  "remoteHost": "gitea",
  "remoteBaseUrl": "https://git.naps.pt",
  "buildCommand": "cargo test",
  "contextFiles": ["CLAUDE.md"],
  "prReviewers": [],
  "labels": []
}

GitHub-issues example (tracker: github):

{
  "tracker": "github",
  "defaultBranch": "main",
  "commitScope": "contracts",
  "buildCommand": "pnpm test",
  "contextFiles": ["AGENTS.md"],
  "prReviewers": [],
  "labels": []
}
Field Required Description
tracker no Where issues live: linear (default), gitea, or github. See Tracker backend below.
linearMcp no MCP server name when tracker: linear. Default linear-server. Use linear-acme for the example workspace.
org linear only Linear organization slug
team linear only Linear team name (for listing/creating issues)
project no Linear project name (narrows issue search). Ignored when tracker: gitea.
defaultBranch no Base branch, default main
commitScope no Conventional commit scope, e.g. platform -> feat(platform): ...
buildCommand no Command to verify the build. Run after implementation.
setupCommands no Commands to run inside a new worktree (install deps, etc.)
contextFiles no Files to read before coding (specs, architecture docs)
prReviewers no Reviewer usernames to request reviews from (/work only)
labels no Default issue labels for ad-hoc issues
remoteHost no github (default) or gitea. Selects which API /work uses for PR creation and review polling. /yolo is unaffected. Implied gitea when tracker: gitea, github when tracker: github.
remoteBaseUrl no Required when remoteHost: gitea or tracker: gitea. Base URL of the Gitea instance (e.g. https://git.naps.pt).

The config file is named .claude/tracker.json (preferred) or .claude/linear.json (legacy); either configures whichever tracker tracker selects.

Tracker backend

tracker selects where issues live. Every instruction below that refers to "the issue" applies to the configured backend; where the two differ (selection, status changes, branch naming) the gitea-specific steps are called out explicitly.

  • linear (default): issues live in Linear, accessed via the MCP server named by linearMcp (default linear-server; an example workspace uses linear-acme). Requires org + team. Tool calls use the mcp__<linearMcp>__* prefix.
  • gitea: issues live in the repo's own Gitea issue tracker — no Linear MCP involved. The repo (owner/repo) is derived from git remote get-url origin; the API uses remoteBaseUrl + $GITEA_TOKEN (load via source ~/.env.claude if needed), exactly like the /work Gitea PR variant. org/team/project are ignored.
  • github: issues live in the repo's own GitHub issue tracker — no Linear MCP involved. The repo (owner/repo) is derived from git remote get-url origin; all issue and PR operations use the gh CLI (must be authenticated — gh auth status). org/team/project are ignored. GitHub has no workflow states, so WIP is signalled by assigning the issue to yourself (like gitea); the PR's Closes #N closes the issue on merge.

First-time setup

If no tracker config exists:

  1. Ask the user which tracker (linear, gitea, or github). For linear, also ask org, team, and optionally project; for gitea, ask remoteBaseUrl.
  2. Ask which optional fields they want. Show the table above.
  3. Write the file to .claude/tracker.json (preferred). Suggest they commit it or gitignore it depending on preference.
  4. Continue with the task.

Remote host (/work only)

/work opens PRs and iterates on reviews. The forge it talks to is selected by remoteHost:

  • github (default): uses gh for gh pr create, gh pr view, and the GitHub GraphQL review-thread API. No extra config needed. Requires an authenticated gh (gh auth status).
  • gitea: uses Gitea's REST API via curl. Requires remoteBaseUrl (e.g. https://git.naps.pt) and $GITEA_TOKEN in the environment (typically loaded from ~/.env.claude). See /work's "Gitea variant" section for the specific endpoints.

/yolo doesn't care about remoteHost — push and merge are plain git, which works against any remote.

Linear MCP auth (tracker: linear only)

Skip this section entirely when tracker: gitea.

The Linear MCP server (named by linearMcp, default linear-server) supports one org at a time. Before making Linear API calls, verify the current auth matches the configured org. If it doesn't (or if auth fails), tell the user to re-authenticate via mcp__<linearMcp>__authenticate and stop. Don't try to work around auth issues silently.

Task selection

Based on $ARGUMENTS. The steps differ by tracker.

tracker: linear

Linear issue ID provided (e.g. ERN-347)

  1. Fetch the issue via the configured Linear MCP (get_issue).
  2. Read the full description, acceptance criteria, and comments.

Ad-hoc task description provided (free text, not matching an issue ID pattern)

  1. Create a new Linear issue in the configured team (and project if set).
  2. Apply any configured default labels.
  3. Use the provided text as the issue title. If it's long, summarize for the title and use the full text as description.

No argument (auto-pick)

  1. List issues in the configured team/project that are unstarted (Backlog, Todo, Ready, or equivalent).
  2. Pick the highest-priority unblocked issue.
  3. If none found, tell the user and stop.

Then:

  • Move the issue to "In Progress" immediately.
  • Note the issue ID, title, and gitBranchName for later use.
  • Use gitBranchName from the Linear response for branch naming (auto-links in Linear).

tracker: gitea

Set BASE=$remoteBaseUrl, REPO=<owner>/<repo> (from git remote get-url origin), and send Authorization: token $GITEA_TOKEN on every call.

Issue number provided (e.g. 23 or #23)

  1. GET $BASE/api/v1/repos/$REPO/issues/23.
  2. Read the title, body, and comments (GET .../issues/23/comments).

Ad-hoc task description provided (free text, not a bare number)

  1. Create the issue:
    curl -sS -X POST -H "Authorization: token $GITEA_TOKEN" -H "Content-Type: application/json" \
      "$BASE/api/v1/repos/$REPO/issues" \
      -d "$(jq -nc --arg title "<title>" --arg body "<full text>" '{title:$title, body:$body}')"
    
  2. Apply any configured default labels (resolve label names to IDs via GET .../labels, pass labels:[ids]).
  3. Title from the text (summarize if long; full text → body). Save the returned number.

No argument (auto-pick)

  1. GET $BASE/api/v1/repos/$REPO/issues?state=open&type=issues&limit=50 (the type=issues filter excludes PRs).
  2. Prefer an unassigned issue; if priority labels exist (e.g. priority/*), pick the highest, else the oldest open one.
  3. If none found, tell the user and stop.

Then:

  • Gitea has no workflow states — signal WIP by assigning the issue to yourself:
    curl -sS -X PATCH -H "Authorization: token $GITEA_TOKEN" -H "Content-Type: application/json" \
      "$BASE/api/v1/repos/$REPO/issues/$N" -d '{"assignees":["<your-gitea-username>"]}'
    
    Optionally add a status/in-progress label if one already exists in the repo. Don't invent label schemes.
  • Note the issue number and title; derive the branch name (see Worktree setup).

tracker: github

Uses the gh CLI against the origin repo (REPO=<owner>/<repo> from git remote get-url origin). Requires an authenticated gh — run gh auth status first; if it fails, tell the user to run gh auth login -h github.com and stop.

Issue number provided (e.g. 23 or #23)

  1. gh issue view 23 --json number,title,body,comments.
  2. Read the title, body, and comments.

Ad-hoc task description provided (free text, not a bare number)

  1. Create the issue:
    gh issue create --title "<title>" --body "<full text>" [--label <l1> --label <l2>]
    
    Apply any configured default labels (each as a --label flag; only labels that already exist in the repo).
  2. Title from the text (summarize if long; full text → body). Save the returned issue number (parse from the URL gh prints).

No argument (auto-pick)

  1. gh issue list --state open --limit 50 --json number,title,labels,assignees.
  2. Prefer an unassigned issue; if priority labels exist (e.g. priority/*), pick the highest, else the oldest open one.
  3. If none found, tell the user and stop.

Then:

  • GitHub has no workflow states — signal WIP by assigning the issue to yourself:
    gh issue edit $N --add-assignee @me
    
    Optionally add a status/in-progress label if one already exists in the repo. Don't invent label schemes.
  • Note the issue number and title; derive the branch name (see Worktree setup).

Worktree setup

Already in a worktree

Detect by checking git worktree list — if the current working directory is not the main worktree, you're already in one.

If already in a worktree: stay here. Check out the issue branch if the current branch doesn't match.

Not in a worktree

  1. Create a worktree at worktrees/<branch-name> relative to the repo root.
    • tracker: linear: use gitBranchName from Linear (auto-links in Linear). If unavailable, derive a concise name from the issue title.
    • tracker: gitea: derive <issue-number>-<slug> from the issue title (lowercase, hyphenated, ~5 words), e.g. 8-daemon-activity-state.
    • tracker: github: derive <issue-number>-<slug> from the issue title (lowercase, hyphenated, ~5 words), e.g. 12-onchainid-erc3643-fixture.
    • Do NOT include "claude" in branch names.
  2. cd into the worktree.
  3. Run each command in setupCommands from the config.
  4. Set kitty tab title (silently skip if kitty isn't available):
    kitty @ set-tab-title "<repo>/<branch>" 2>/dev/null || true
    

Gather context

  1. Read all contextFiles from the config.
  2. Re-read the tracking issue description (with project context you'll understand it better now).
  3. Read CLAUDE.md / AGENTS.md at the repo root or .claude/ if they exist, for project conventions.
  4. Check recent git history: git log --oneline -20 to understand current patterns.
  5. Locating the code to change — delegate when the area is unfamiliar or spread out. If the issue clearly points at one or two known files, just read them inline. But if you'd otherwise open many files to answer "where does X live / what calls Y / where are the similar cases", spawn the cavecrew-investigator subagent instead (Agent tool, subagent_type: caveman:cavecrew-investigator). It returns a compressed file:line map, keeping the main thread's context lean for the implementation and review that follow. Skip it for small, obvious, single-file tasks — the spawn overhead isn't worth it there.

Implementation guidelines

  1. Work methodically through the requirements.
  2. Commit after each logical step using conventional commits:
    • With scope if configured: feat(scope): description
    • Without: feat: description
    • Prefixes: feat, fix, refactor, test, docs, chore
  3. Follow existing code patterns. Match the style of surrounding code.
  4. Write tests appropriate to the project (match existing test patterns and coverage level).
  5. Never amend commits — always create new ones.
  6. Keep the tracking issue updated (Linear, Gitea, or GitHub, per tracker) if scope changes significantly.

Rules

  • Never ask the user during autonomous work unless you hit a genuine blocker (architectural contradiction, missing credentials, ambiguous requirements that could go very wrong).
  • If the build fails, fix it before pushing.
  • Respect existing project conventions from CLAUDE.md, AGENTS.md, etc.