- 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
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:
.claude/tracker.json(preferred, generic name).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 trackertrackerselects.
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 bylinearMcp(defaultlinear-server; an example workspace useslinear-acme). Requiresorg+team. Tool calls use themcp__<linearMcp>__*prefix.gitea: issues live in the repo's own Gitea issue tracker — no Linear MCP involved. The repo (owner/repo) is derived fromgit remote get-url origin; the API usesremoteBaseUrl+$GITEA_TOKEN(load viasource ~/.env.claudeif needed), exactly like the/workGitea PR variant.org/team/projectare ignored.github: issues live in the repo's own GitHub issue tracker — no Linear MCP involved. The repo (owner/repo) is derived fromgit remote get-url origin; all issue and PR operations use theghCLI (must be authenticated —gh auth status).org/team/projectare ignored. GitHub has no workflow states, so WIP is signalled by assigning the issue to yourself (like gitea); the PR'sCloses #Ncloses the issue on merge.
First-time setup
If no tracker config exists:
- Ask the user which
tracker(linear,gitea, orgithub). Forlinear, also askorg,team, and optionallyproject; forgitea, askremoteBaseUrl. - Ask which optional fields they want. Show the table above.
- Write the file to
.claude/tracker.json(preferred). Suggest they commit it or gitignore it depending on preference. - 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): usesghforgh pr create,gh pr view, and the GitHub GraphQL review-thread API. No extra config needed. Requires an authenticatedgh(gh auth status).gitea: uses Gitea's REST API viacurl. RequiresremoteBaseUrl(e.g.https://git.naps.pt) and$GITEA_TOKENin 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)
- Fetch the issue via the configured Linear MCP (
get_issue). - Read the full description, acceptance criteria, and comments.
Ad-hoc task description provided (free text, not matching an issue ID pattern)
- Create a new Linear issue in the configured team (and project if set).
- Apply any configured default
labels. - 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)
- List issues in the configured team/project that are unstarted (Backlog, Todo, Ready, or equivalent).
- Pick the highest-priority unblocked issue.
- If none found, tell the user and stop.
Then:
- Move the issue to "In Progress" immediately.
- Note the issue ID, title, and
gitBranchNamefor later use. - Use
gitBranchNamefrom 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)
GET $BASE/api/v1/repos/$REPO/issues/23.- Read the title, body, and comments (
GET .../issues/23/comments).
Ad-hoc task description provided (free text, not a bare number)
- 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}')" - Apply any configured default
labels(resolve label names to IDs viaGET .../labels, passlabels:[ids]). - Title from the text (summarize if long; full text → body). Save the returned
number.
No argument (auto-pick)
GET $BASE/api/v1/repos/$REPO/issues?state=open&type=issues&limit=50(thetype=issuesfilter excludes PRs).- Prefer an unassigned issue; if priority labels exist (e.g.
priority/*), pick the highest, else the oldest open one. - If none found, tell the user and stop.
Then:
- Gitea has no workflow states — signal WIP by assigning the issue to yourself:
Optionally add a
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>"]}'status/in-progresslabel if one already exists in the repo. Don't invent label schemes. - Note the issue
numberand 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)
gh issue view 23 --json number,title,body,comments.- Read the title, body, and comments.
Ad-hoc task description provided (free text, not a bare number)
- Create the issue:
Apply any configured default
gh issue create --title "<title>" --body "<full text>" [--label <l1> --label <l2>]labels(each as a--labelflag; only labels that already exist in the repo). - Title from the text (summarize if long; full text → body). Save the returned issue
number(parse from the URLghprints).
No argument (auto-pick)
gh issue list --state open --limit 50 --json number,title,labels,assignees.- Prefer an unassigned issue; if priority labels exist (e.g.
priority/*), pick the highest, else the oldest open one. - If none found, tell the user and stop.
Then:
- GitHub has no workflow states — signal WIP by assigning the issue to yourself:
Optionally add a
gh issue edit $N --add-assignee @mestatus/in-progresslabel if one already exists in the repo. Don't invent label schemes. - Note the issue
numberand 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
- Create a worktree at
worktrees/<branch-name>relative to the repo root.- tracker: linear: use
gitBranchNamefrom 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.
- tracker: linear: use
cdinto the worktree.- Run each command in
setupCommandsfrom the config. - Set kitty tab title (silently skip if kitty isn't available):
kitty @ set-tab-title "<repo>/<branch>" 2>/dev/null || true
Gather context
- Read all
contextFilesfrom the config. - Re-read the tracking issue description (with project context you'll understand it better now).
- Read
CLAUDE.md/AGENTS.mdat the repo root or.claude/if they exist, for project conventions. - Check recent git history:
git log --oneline -20to understand current patterns. - 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-investigatorsubagent instead (Agent tool,subagent_type: caveman:cavecrew-investigator). It returns a compressedfile:linemap, 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
- Work methodically through the requirements.
- 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
- With scope if configured:
- Follow existing code patterns. Match the style of surrounding code.
- Write tests appropriate to the project (match existing test patterns and coverage level).
- Never amend commits — always create new ones.
- 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.