Agent skill
sym-linear
Use Symphony's `linear_graphql` client tool for raw Linear GraphQL operations such as comment editing and upload flows.
Install this agent skill to your Project
npx add-skill https://github.com/gannonh/kata/tree/main/.agents/skills/sym-linear
SKILL.md
Linear GraphQL
Use this skill for raw Linear GraphQL work during Symphony app-server sessions.
Primary tool
Use the linear_graphql client tool exposed by Symphony's app-server session.
It reuses Symphony's configured Linear auth for the session.
Tool input:
{
"query": "query or mutation document",
"variables": {
"optional": "graphql variables object"
}
}
Tool behavior:
- Send one GraphQL operation per tool call.
- Treat a top-level
errorsarray as a failed GraphQL operation even if the tool call itself completed. - Keep queries/mutations narrowly scoped; ask only for the fields you need.
Discovering unfamiliar operations
When you need an unfamiliar mutation, input type, or object field, use targeted
introspection through linear_graphql.
List mutation names:
query ListMutations {
__type(name: "Mutation") {
fields {
name
}
}
}
Inspect a specific input object:
query CommentCreateInputShape {
__type(name: "CommentCreateInput") {
inputFields {
name
type {
kind
name
ofType {
kind
name
}
}
}
}
}
Common workflows
Query an issue by key, identifier, or id
Use these progressively:
- Start with
issue(id: $identifier)when you have a ticket key such asMT-686orKAT-857. - If you must use
issues(filter: ...), splitTEAM-NUMBERand filter withteam.key+number(do not useIssueFilter.identifier; it does not exist). - Once you have the internal issue id, prefer
issue(id: $id)for narrower reads.
Lookup by issue key/identifier:
query IssueByIdentifier($identifier: String!) {
issue(id: $identifier) {
id
identifier
title
state {
id
name
type
}
project {
id
name
}
branchName
url
description
updatedAt
}
}
Lookup by identifier with issues(filter: ...) (valid syntax):
query IssueByTeamKeyAndNumber($teamKey: String!, $number: Float!) {
issues(
filter: { team: { key: { eq: $teamKey } }, number: { eq: $number } }
first: 1
) {
nodes {
id
identifier
title
state {
id
name
type
}
project {
id
name
}
branchName
url
description
updatedAt
}
}
}
Given KAT-857, use teamKey = "KAT" and number = 857.
Resolve a key to an internal id:
query IssueByIdOrKey($id: String!) {
issue(id: $id) {
id
identifier
title
}
}
Read the issue once the internal id is known:
query IssueDetails($id: String!) {
issue(id: $id) {
id
identifier
title
url
description
state {
id
name
type
}
project {
id
name
}
attachments {
nodes {
id
title
url
sourceType
}
}
}
}
Query slice hierarchy and planning documents
Use these when an issue represents a parent slice with child tasks and attached plan docs.
Get child issues of a slice:
query SliceChildren($id: String!) {
issue(id: $id) {
children {
nodes {
id
identifier
title
state {
name
type
}
}
}
}
}
Get documents attached to an issue:
query IssueDocuments($id: String!) {
issue(id: $id) {
documents {
nodes {
id
title
content
}
}
}
}
Get project documents:
query ProjectDocuments($id: String!) {
project(id: $id) {
documents {
nodes {
id
title
content
}
}
}
}
Get milestone from issue:
query IssueMilestone($id: String!) {
issue(id: $id) {
projectMilestone {
id
name
}
}
}
Get milestone documents:
query MilestoneDocuments($id: String!) {
projectMilestone(id: $id) {
documents {
nodes {
id
title
content
}
}
}
}
Query team workflow states for an issue
Use this before changing issue state when you need the exact stateId:
query IssueTeamStates($id: String!) {
issue(id: $id) {
id
team {
id
key
name
states {
nodes {
id
name
type
}
}
}
}
}
Move an issue to a named state (resolve stateId first)
Use a two-step flow:
- Query
issue(id: ...) { team { states { nodes { id name type } } } }. - Pick the state whose
nameexactly matches your target and pass thatstateIdtoissueUpdate.
mutation MoveIssueToState($id: String!, $stateId: String!) {
issueUpdate(id: $id, input: { stateId: $stateId }) {
success
issue {
id
identifier
state {
id
name
}
}
}
}
Edit an existing comment
Use commentUpdate through linear_graphql:
mutation UpdateComment($id: String!, $body: String!) {
commentUpdate(id: $id, input: { body: $body }) {
success
comment {
id
body
}
}
}
Create a comment
Use commentCreate through linear_graphql:
mutation CreateComment($issueId: String!, $body: String!) {
commentCreate(input: { issueId: $issueId, body: $body }) {
success
comment {
id
url
}
}
}
Create an attachment/link on an issue
Use the GitHub-specific attachment mutation when linking a PR:
mutation AttachGitHubPR($issueId: String!, $url: String!, $title: String) {
attachmentLinkGitHubPR(
issueId: $issueId
url: $url
title: $title
linkKind: links
) {
success
attachment {
id
title
url
}
}
}
If you only need a plain URL attachment and do not care about GitHub-specific link metadata, use:
mutation AttachURL($issueId: String!, $url: String!, $title: String) {
attachmentLinkURL(issueId: $issueId, url: $url, title: $title) {
success
attachment {
id
title
url
}
}
}
Query issue attachments and relations
query IssueAttachmentsAndRelations($id: String!) {
issue(id: $id) {
id
identifier
attachments(first: 20) {
nodes {
id
title
url
sourceType
}
}
relations(first: 20) {
nodes {
id
type
relatedIssue {
id
identifier
title
state {
name
type
}
}
}
}
inverseRelations(first: 20) {
nodes {
id
type
issue {
id
identifier
title
state {
name
type
}
}
}
}
}
}
Common valid IssueFilter fields
Use these common fields inside issues(filter: ...):
idnumber(pair withteam.keyfor identifier-style lookups)teamstateprojectassigneetitlesearchableContentcreatedAtupdatedAtand/or
IssueFilter.identifier is invalid.
Introspection patterns used during schema discovery
Use these when the exact field or mutation shape is unclear:
query QueryFields {
__type(name: "Query") {
fields {
name
}
}
}
query IssueFieldArgs {
__type(name: "Query") {
fields {
name
args {
name
type {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}
}
}
}
Upload a video to a comment
Do this in three steps:
- Call
linear_graphqlwithfileUploadto getuploadUrl,assetUrl, and any required upload headers. - Upload the local file bytes to
uploadUrlwithcurl -X PUTand the exact headers returned byfileUpload. - Call
linear_graphqlagain withcommentCreate(orcommentUpdate) and include the resultingassetUrlin the comment body.
Useful mutations:
mutation FileUpload(
$filename: String!
$contentType: String!
$size: Int!
$makePublic: Boolean
) {
fileUpload(
filename: $filename
contentType: $contentType
size: $size
makePublic: $makePublic
) {
success
uploadFile {
uploadUrl
assetUrl
headers {
key
value
}
}
}
}
Usage rules
- Use
linear_graphqlfor comment edits, uploads, and ad-hoc Linear API queries. - Prefer the narrowest issue lookup that matches what you already know:
issue(id: TEAM-NUMBER)->issues(filter: { team.key + number })-> internal id. - Do not query
Issue.links; useIssue.attachments,Issue.relations, andIssue.inverseRelationsinstead. - Do not use
IssueFilter.identifier; useIssueFilter.numberwithIssueFilter.team.keywhen you need identifier-style filtering. - For state transitions, fetch team states first and use the exact
stateIdinstead of hardcoding names inside mutations. - Prefer
attachmentLinkGitHubPRover a generic URL attachment when linking a GitHub PR to a Linear issue. - Do not introduce new raw-token shell helpers for GraphQL access.
- If you need shell work for uploads, only use it for signed upload URLs
returned by
fileUpload; those URLs already carry the needed authorization.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
kata-context
Structural and semantic codebase intelligence with persistent memory — index TypeScript and Python repos into a knowledge graph with vector embeddings, query symbol dependencies, run semantic search by intent, search code patterns, fuzzy-find symbols, and persist/recall agent memories with git audit trail. Use when you need to understand code structure, find what depends on a symbol, trace dependencies, search by meaning, search for code patterns, find symbols by name, or remember/recall project decisions, patterns, and learnings.
claude-md-improver
Audit and improve CLAUDE.md files in repositories. Use when user asks to check, audit, update, improve, or fix CLAUDE.md files. Scans for all CLAUDE.md files, evaluates quality against templates, outputs quality report, then makes targeted updates. Also use when the user mentions "CLAUDE.md maintenance" or "project memory optimization".
frontend-design
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML/CSS layouts, or when styling/beautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.
debug-like-expert
Deep analysis debugging mode for complex issues. Activates methodical investigation protocol with evidence gathering, hypothesis testing, and rigorous verification. Use when standard troubleshooting fails or when issues require systematic root cause analysis.
swiftui
SwiftUI apps from scratch through App Store. Full lifecycle - create, debug, test, optimize, ship.
sym-address-comments
Help address review/issue comments on the open GitHub PR for the current branch using gh CLI; verify gh auth first and prompt the user to authenticate if not logged in.
Didn't find tool you were looking for?