linear
$
npx mdskill add openai/symphony/linearExecute raw Linear GraphQL operations for comment editing and upload flows during Symphony app-server sessions.
- Enables agents to perform custom GraphQL queries and mutations for Linear tasks like issue management.
- Integrates with Symphony's linear_graphql client tool, leveraging configured Linear authentication.
- Uses targeted introspection queries to discover unfamiliar mutations or input types as needed.
- Sends GraphQL operations directly and treats top-level errors as failures for precise execution.
SKILL.md
.github/skills/linearView on GitHub ↗
---
name: linear
description: |
Use Symphony's `linear_graphql` client tool for raw Linear GraphQL
operations such as comment editing and upload flows.
---
# 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:
```json
{
"query": "query or mutation document",
"variables": {
"optional": "graphql variables object"
}
}
```
Tool behavior:
- Send one GraphQL operation per tool call.
- Treat a top-level `errors` array 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:
```graphql
query ListMutations {
__type(name: "Mutation") {
fields {
name
}
}
}
```
Inspect a specific input object:
```graphql
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: $key)` when you have a ticket key such as `MT-686`.
- Fall back to `issues(filter: ...)` when you need identifier search semantics.
- Once you have the internal issue id, prefer `issue(id: $id)` for narrower reads.
Lookup by issue key:
```graphql
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:
```graphql
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:
```graphql
query IssueByIdOrKey($id: String!) {
issue(id: $id) {
id
identifier
title
}
}
```
Read the issue once the internal id is known:
```graphql
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`:
```graphql
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`:
```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`:
```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`:
```graphql
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:
```graphql
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:
```graphql
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:
```graphql
query QueryFields {
__type(name: "Query") {
fields {
name
}
}
}
```
```graphql
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:
1. Call `linear_graphql` with `fileUpload` to get `uploadUrl`, `assetUrl`, and
any required upload headers.
2. Upload the local file bytes to `uploadUrl` with `curl -X PUT` and the exact
headers returned by `fileUpload`.
3. Call `linear_graphql` again with `commentCreate` (or `commentUpdate`) and
include the resulting `assetUrl` in the comment body.
Useful mutations:
```graphql
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_graphql` for comment edits, uploads, and ad-hoc Linear API
queries.
- 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 `stateId`
instead of hardcoding names inside mutations.
- Prefer `attachmentLinkGitHubPR` over 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.
More from openai/symphony
- commit- Produce a commit that reflects the actual code changes and the session context. - Follow common git conventions (type prefix, short subject, wrapped body). - Include both summary and rationale in the body.
- debug- Find why a run is stuck, retrying, or failing. - Correlate Linear issue identity to a Codex session quickly. - Read the right logs in the right order to isolate root cause.
- land- Ensure the PR is conflict-free with main. - Keep CI green and fix failures when they occur. - Squash-merge the PR once checks pass. - Do not yield to the user until the PR is merged; keep the watcher loop running unless blocked. - No need to delete remote branches after merge; the repo auto-deletes head branches.
- pull1. Verify git status is clean or commit/stash changes before merging. 2. Ensure rerere is enabled locally: - `git config rerere.enabled true` - `git config rerere.autoupdate true` 3. Confirm remotes and branches: - Ensure the `origin` remote exists. - Ensure the current branch is the one to receive the merge. 4. Fetch latest refs: - `git fetch origin` 5. Sync the remote feature branch first: - `git pull --ff-only origin $(git branch --show-current)` - This pulls branch updates made remotely (for example, a GitHub auto-commit) before merging `origin/main`. 6. Merge in order: - Prefer `git -c merge.conflictstyle=zdiff3 merge origin/main` for clearer conflict context. 7. If conflicts appear, resolve them (see conflict guidance below), then: - `git add <files>` - `git commit` (or `git merge --continue` if the merge is paused) 8. Verify with project checks (follow repo policy in `AGENTS.md`). 9. Summarize the merge: - Call out the most challenging conflicts/files and how they were resolved. - Note any assumptions or follow-ups.
- push- `gh` CLI is installed and available in `PATH`. - `gh auth status` succeeds for GitHub operations in this repo.