/link-ticket-to-session
Link the current Claude Code session to a ticket (Linear, Jira, GitHub Issues, or GitHub Pull Requests) and cache its title/status in karma. Use when the user explicitly asks to link, attach, associate, or connect this session to a ticket, issue, or PR — e.g.
$ npx -y skills add JayantDevkar/claude-code-karma --skill link-ticket-to-session --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/link-ticket-to-session
Context preview
The summary Claude sees to decide when to auto-load this skill.
Link the current Claude Code session to a ticket (Linear, Jira, GitHub Issues, or GitHub Pull Requests) and cache its title/status in karma. Use when the user explicitly asks to link, attach, associate, or connect this session to a ticket, issue, or PR — e.g.
SKILL.md
link-ticket-to-session.SKILL.mdname: link-ticket-to-session
description: Link the current Claude Code session to a ticket (Linear, Jira, GitHub Issues, or GitHub Pull Requests) and cache its title/status in karma. Use when the user explicitly asks to link, attach, associate, or connect this session to a ticket, issue, or PR — e.g. "/link-ticket-to-session ABC-123", "link this session to LINEAR-42", "associate this work with issue #15", "attach session to PR octocat/repo#7". Do NOT auto-invoke from passing ticket-key mentions in normal conversation.
argument-hint: <ticket-ref-or-url>
allowed-tools: Bash, mcp__linear, mcp__claude_ai_Linear, mcp__plugin_github_github, mcp__atlassian
You are linking the current Claude Code session (`${CLAUDE_SESSION_ID}`) to: **$ARGUMENTS**
Karma is a read-only observer on the user's machine. It stores the link and caches title/status for display, but never writes back to the ticket provider. You fetch metadata via the user's already-configured MCP server.
Karma's API URL comes from `KARMA_API_URL` (set by users on non-default ports/hosts) with `http://localhost:8020` as fallback. Inline `${KARMA_API_URL:-http://localhost:8020}` in **every** curl below — bash variables don't persist across separate Bash tool calls, so a top-of-script assignment would be empty by the time the next curl runs.
Step 1 — Parse $ARGUMENTS
Recognized forms:
| Provider | Short ref | URL forms | |--------------------|---------------------|--------------------------------------------------------| | Linear | `LINEAR-123` | `https://linear.app/.../issue/ABC-123` | | Jira | `PROJ-45` | `https://*.atlassian.net/browse/PROJ-45` | | GitHub **Issue** | `owner/repo#42` | `https://github.com/owner/repo/issues/42` | | GitHub **PR** | `owner/repo#42` | `https://github.com/owner/repo/pull/42` |
GitHub issues and pull requests share a single numbering namespace — `owner/repo#42` could be either. **The URL kind (`/issues/` vs `/pull/`) is the only signal**, and karma's backend preserves it, so when you have a URL keep it intact when POSTing (Step 4). For a bare `owner/repo#N` with no URL, default to `/issues/N` — GitHub auto-redirects to `/pull/N` when N is actually a PR, so the link still resolves.
A bare `#N` (no owner/repo) is **not** accepted — always qualify with `owner/repo#N`.
Step 2 — Identify provider and (for GitHub) kind
Set two variables you'll use below:
- `<provider>` ∈ `linear` | `jira` | `github`
- For GitHub: `<kind>` ∈ `issue` | `pull_request` (derived from URL path)
For Linear and Jira this collapses to just `<provider>`.
Step 3 — Fetch metadata via MCP (when available)
Pick the right MCP tool for the provider and kind:
| Provider · Kind | MCP tool | |-----------------------------|---------------------------------------------------------| | `linear` | Linear MCP — search/fetch issue by key | | `jira` | Atlassian MCP — fetch by key | | `github` · `issue` | `mcp__plugin_github_github__issue_read`, method `get` | | `github` · `pull_request` | `mcp__plugin_github_github__pull_request_read`, method `get` |
Calling the wrong GitHub method silently returns the wrong thing because both shapes look superficially similar — so derive the kind first.
If the relevant MCP isn't installed, **skip this step** and proceed to Step 4 without title/status. Karma will create the link; the title/status fields stay NULL and can be refreshed later via Step 5.
Pull at minimum: `title`, `status` (or state), `url`. **Strip large fields** — karma caps `metadata_json` at 64 KB and a full PR payload easily exceeds that. Specifically drop:
- GitHub PR: `body`, `commits`, `files`, `reviewers`, `comments`, `labels`,
`requested_reviewers`, `head` / `base` blobs beyond `ref`
- GitHub issue: `body`, `comments`, `reactions`, `labels`
- Linear / Jira: `description`, `comments`, `subscribers`, `attachments`
Status semantics by kind
The `status` you cache should reflect *what the provider says now*, not a generic "open/closed". Karma's UI normalizes these to canonical buckets at render time, so faithful provider language is the right input:
- **Linear**: workflow state name verbatim — e.g. `Backlog`, `In Progress`,
`In Review`, `Done`, `Cancelled` (workspace-defined; don't normalize).
- **Jira**: workflow state name — e.g. `To Do`, `In Progress`, `In Review`,
`Done`.
- **GitHub issue**: `open` or `closed`.
- **GitHub PR**: derive from the flags the PR API returns:
| `state` | `draft` | `merged` | Cache as | |----------|---------|----------|--------------| | `open` | `true` | — | `draft` | | `open` | `false` | — | `open` | | `closed` | — | `true` | `MERGED` | | `closed` | — | `false` | `closed` |
Step 4 — POST the link
The `url` field should be the URL you actually have — `/pull/N` for PRs, `/issues/N` for issues. **Don't rewrite it.** Karma's parser preserves the path segment; the UI uses it to distinguish PRs from issues.
curl -s -X POST "${KARMA_API_URL:-http://localhost:8020}/sessions/${CLAUDE_SESSION_ID}/tickets" \
-H 'Content-Type: application/json' \
-d '{"ref":"<key>","provider":"<provider>","url":"<url>","source":"slash_command"}'For GitHub, `<key>` is always `owner/repo#N` regardless of kind — the URL field carries the issue/PR distinction.
Step 5 — PUT the metadata (only if Step 3 succeeded)
curl -s -X PUT "${KARMA_API_URL:-http://localhost:8020}/tickets/<provider>/<key>" \
-H 'Content-Type: application/json' \
-d '{"title":"<title>","status":"<status>"}'For GitHub keys with `/` and `#`, URL-encode the key in the path: `octocat/repo#
Read more
name: link-ticket-to-session description: Link the current Claude Code session to a ticket (Linear, Jira, GitHub Issues, or GitHub Pull Requests) and cache its title/status in karma. Use when the user explicitly asks to link, attach, associate, or connect this session to a ticket, issue, or PR — e.g. "/link-ticket-to-session ABC-123", "link this session to LINEAR-42", "associate this work with issue #15", "attach session to PR octocat/repo#7". Do NOT auto-invoke from passing ticket-key mentions in normal conversation. argument-hint: <ticket-ref-or-url> allowed-tools: Bash, mcp__linear, mcp__claude_ai_Linear, mcp__plugin_github_github, mcp__atlassian
You are linking the current Claude Code session (`${CLAUDE_SESSION_ID}`) to: **$ARGUMENTS**
Karma is a read-only observer on the user's machine. It stores the link and caches title/status for display, but never writes back to the ticket provider. You fetch metadata via the user's already-configured MCP server.
Karma's API URL comes from `KARMA_API_URL` (set by users on non-default ports/hosts) with `http://localhost:8020` as fallback. Inline `${KARMA_API_URL:-http://localhost:8020}` in **every** curl below — bash variables don't persist across separate Bash tool calls, so a top-of-script assignment would be empty by the time the next curl runs.
Step 1 — Parse $ARGUMENTS
Recognized forms:
| Provider | Short ref | URL forms | |--------------------|---------------------|--------------------------------------------------------| | Linear | `LINEAR-123` | `https://linear.app/.../issue/ABC-123` | | Jira | `PROJ-45` | `https://*.atlassian.net/browse/PROJ-45` | | GitHub **Issue** | `owner/repo#42` | `https://github.com/owner/repo/issues/42` | | GitHub **PR** | `owner/repo#42` | `https://github.com/owner/repo/pull/42` |
GitHub issues and pull requests share a single numbering namespace — `owner/repo#42` could be either. **The URL kind (`/issues/` vs `/pull/`) is the only signal**, and karma's backend preserves it, so when you have a URL keep it intact when POSTing (Step 4). For a bare `owner/repo#N` with no URL, default to `/issues/N` — GitHub auto-redirects to `/pull/N` when N is actually a PR, so the link still resolves.
A bare `#N` (no owner/repo) is **not** accepted — always qualify with `owner/repo#N`.
Step 2 — Identify provider and (for GitHub) kind
Set two variables you'll use below:
- `<provider>` ∈ `linear` | `jira` | `github`
- For GitHub: `<kind>` ∈ `issue` | `pull_request` (derived from URL path)
For Linear and Jira this collapses to just `<provider>`.
Step 3 — Fetch metadata via MCP (when available)
Pick the right MCP tool for the provider and kind:
| Provider · Kind | MCP tool | |-----------------------------|---------------------------------------------------------| | `linear` | Linear MCP — search/fetch issue by key | | `jira` | Atlassian MCP — fetch by key | | `github` · `issue` | `mcp__plugin_github_github__issue_read`, method `get` | | `github` · `pull_request` | `mcp__plugin_github_github__pull_request_read`, method `get` |
Calling the wrong GitHub method silently returns the wrong thing because both shapes look superficially similar — so derive the kind first.
If the relevant MCP isn't installed, **skip this step** and proceed to Step 4 without title/status. Karma will create the link; the title/status fields stay NULL and can be refreshed later via Step 5.
Pull at minimum: `title`, `status` (or state), `url`. **Strip large fields** — karma caps `metadata_json` at 64 KB and a full PR payload easily exceeds that. Specifically drop:
- GitHub PR: `body`, `commits`, `files`, `reviewers`, `comments`, `labels`,
`requested_reviewers`, `head` / `base` blobs beyond `ref`
- GitHub issue: `body`, `comments`, `reactions`, `labels`
- Linear / Jira: `description`, `comments`, `subscribers`, `attachments`
Status semantics by kind
The `status` you cache should reflect *what the provider says now*, not a generic "open/closed". Karma's UI normalizes these to canonical buckets at render time, so faithful provider language is the right input:
- **Linear**: workflow state name verbatim — e.g. `Backlog`, `In Progress`,
`In Review`, `Done`, `Cancelled` (workspace-defined; don't normalize).
- **Jira**: workflow state name — e.g. `To Do`, `In Progress`, `In Review`,
`Done`.
- **GitHub issue**: `open` or `closed`.
- **GitHub PR**: derive from the flags the PR API returns:
| `state` | `draft` | `merged` | Cache as | |----------|---------|----------|--------------| | `open` | `true` | — | `draft` | | `open` | `false` | — | `open` | | `closed` | — | `true` | `MERGED` | | `closed` | — | `false` | `closed` |
Step 4 — POST the link
The `url` field should be the URL you actually have — `/pull/N` for PRs, `/issues/N` for issues. **Don't rewrite it.** Karma's parser preserves the path segment; the UI uses it to distinguish PRs from issues.
curl -s -X POST "${KARMA_API_URL:-http://localhost:8020}/sessions/${CLAUDE_SESSION_ID}/tickets" \
-H 'Content-Type: application/json' \
-d '{"ref":"<key>","provider":"<provider>","url":"<url>","source":"slash_command"}'For GitHub, `<key>` is always `owner/repo#N` regardless of kind — the URL field carries the issue/PR distinction.
Step 5 — PUT the metadata (only if Step 3 succeeded)
curl -s -X PUT "${KARMA_API_URL:-http://localhost:8020}/tickets/<provider>/<key>" \
-H 'Content-Type: application/json' \
-d '{"title":"<title>","status":"<status>"}'For GitHub keys with `/` and `#`, URL-encode the key in the path: `octocat/repo#
Repo: JayantDevkar/claude-code-karma

