Symphony linear
install
source · Clone the upstream repo
git clone https://github.com/openai/symphony
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/openai/symphony "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.codex/skills/linear" ~/.claude/skills/openai-symphony-linear && rm -rf "$T"
manifest:
.codex/skills/linear/SKILL.mdsource content
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
array as a failed GraphQL operation even if the tool call itself completed.errors - 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
when you have a ticket key such asissue(id: $key)
.MT-686 - Fall back to
when you need identifier search semantics.issues(filter: ...) - Once you have the internal issue id, prefer
for narrower reads.issue(id: $id)
Lookup by issue key:
query IssueByKey($key: String!) { issue(id: $key) { id identifier title state { id name type } project { id name } branchName url description updatedAt links { nodes { id url title } } } }
Lookup by identifier filter:
query IssueByIdentifier($identifier: String!) { issues(filter: { identifier: { eq: $identifier } }, first: 1) { nodes { id identifier title state { id name type } project { id name } branchName url description updatedAt } } }
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 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 } } } } }
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 } } }
Move an issue to a different state
Use
issueUpdate with the destination stateId:
mutation MoveIssueToState($id: String!, $stateId: String!) { issueUpdate(id: $id, input: { stateId: $stateId }) { success issue { id identifier state { id name } } } }
Attach a GitHub PR to 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 } } }
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
withlinear_graphql
to getfileUpload
,uploadUrl
, and any required upload headers.assetUrl - Upload the local file bytes to
withuploadUrl
and the exact headers returned bycurl -X PUT
.fileUpload - Call
again withlinear_graphql
(orcommentCreate
) and include the resultingcommentUpdate
in the comment body.assetUrl
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
for comment edits, uploads, and ad-hoc Linear API queries.linear_graphql - Prefer the narrowest issue lookup that matches what you already know: key -> identifier search -> internal id.
- For state transitions, fetch team states first and use the exact
instead of hardcoding names inside mutations.stateId - Prefer
over a generic URL attachment when linking a GitHub PR to a Linear issue.attachmentLinkGitHubPR - 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
; those URLs already carry the needed authorization.fileUpload