[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71ER6YVF8R7KYDM97DAHECE":3,"skill-same:01M71ER6YVF8R7KYDM97DAHECE":66},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":44,"commitSha":45,"skillDirectory":46,"forksCount":14,"repositoryHtmlUrl":47,"repositoryHomepageUrl":6,"ownerHtmlUrl":48,"ownerBlogUrl":49,"ownerDescription":50,"updatedAt":51,"install":52,"resources":65},"01M71ER6YVF8R7KYDM97DAHECE","linear-inbox-cleanup",null,"Mark as read every unread Linear inbox notification that needs no action, archive every read one that needs no action, and leave the rest unchanged. Use when the user asks to clean up their Linear inbox, or on a schedule. Changes read and archive state, so answer read-only questions about the inbox directly instead.","patinaproject\u002Fskills","patinaproject","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F229996889?v=4","01M71E58JKTDNY1138WYZK44TR","Patina Project","01M71E58K5GH4K16MV6A8BQ6NZ",1,"MIT","https:\u002F\u002Fgithub.com\u002Fpatinaproject\u002Fskills\u002Fblob\u002Fmain\u002Fplugins\u002Fwork\u002Fskills\u002Flinear-inbox-cleanup\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"cleanup","linear inbox cleanup","linear","inbox","notification","changes","mark","REST","state","schedule","one","when","use","only","clean","up","archive","answer","read-only","as","2026-11-10 10:12:30",false,"---\nname: linear-inbox-cleanup\ndescription: Mark as read every unread Linear inbox notification that needs no action, archive every read one that needs no action, and leave the rest unchanged. Use when the user asks to clean up their Linear inbox, or on a schedule. Changes read and archive state, so answer read-only questions about the inbox directly instead.\n---\n\n# Linear Inbox Cleanup\n\nA notification **needs no action** when it is **done**, **status noise**,\n**triage-assigned**, **superseded**, or **idle**. **Clear** every unread\nnotification that needs no action. **Archive** every read notification that\nneeds no action, whatever its age. **Keep** every other notification. When in\ndoubt about a notification, keep it.\n\nA notification is read when its `readAt` is non-null. When the response omits\n`readAt`, treat the notification as unread.\n\nClear means `mark_notification` with `id` set to the notification ID and\n`read: true`. Archive means the GraphQL `notificationArchive` mutation, sent as\nin [Archive](#archive). Keep means leave the notification unchanged: an unread\none stays unread, and a read one stays read and in the inbox.\n\nIn [Categories](#categories) and [Superseded](#superseded), \"clear\" means the\nnotification needs no action. [Run](#run) step 8 decides whether it is\ncleared or archived.\n\n## Scope\n\nUse only these Linear MCP tools: `get_user`, `get_notifications`, `get_issue`,\n`get_diff`, `list_comments`, and `mark_notification`. Do not use a browser.\n\nThe only non-MCP actions are two shell commands: the key check in\n[Run](#run) step 3, which reaches no service, and the `curl` call in\n[Archive](#archive). The `curl` call sends `notificationArchive`, the only\nGraphQL operation this skill may send. Send no other GraphQL query or\nmutation.\n\nThe only writes are clear, through `mark_notification`, and archive, through\n`notificationArchive`. Never snooze, delete, or unarchive a notification, and\nnever comment on or change an issue, project, document, comment, or pull\nrequest.\n\n## Categories\n\n- **Done.** The notification's issue has status type `completed` or\n  `canceled`, or its pull request has status `merged`. A Duplicate status is\n  type `canceled`. Any other issue status type, and an open pull request or\n  one closed without merging, is not done. Nothing is left to act on, so clear\n  a done notification whatever its type, mentions included.\n- **Status noise.** `category` is `statusChanges`. That covers\n  `issueStatusChanged`, `issueRestored`, `issueUnblocked`, and every other\n  status-change type. Clear it whatever the issue's status.\n- **Triage-assigned.** `type` is `issueAssignedToYou` and `subtitle` is\n  `Assigned by Triage Rule`. An assignment by a person or a bot is not\n  triage-assigned.\n- **Superseded.** A later event shows the user already acted, or the work\n  moved on. See [Superseded](#superseded).\n- **Idle.** A new-comment notification where the user is not @-mentioned and\n  has not commented in that thread.\n\nIssue URLs below use `\u003CKEY>-\u003CN>`, the issue identifier with its team key, such\nas `ENG-123`.\n\n## Notifying comment\n\nFind a notification's notifying comment and thread this way:\n\n1. Find the parent from the `url`. `\u002Fissue\u002F\u003CKEY>-\u003CN>\u002F...` gives\n   `issueId: \"\u003CKEY>-\u003CN>\"`, `\u002Fdocument\u002F\u003Cslug>` gives `documentId`, and\n   `\u002Fproject\u002F\u003Cslug>` gives `projectId`. The comment ID prefix is the eight hex\n   characters after `#comment-`.\n2. Call `list_comments` for the parent with `limit: 250`, following `cursor`.\n3. The notifying comment is the one whose `id` starts with the prefix.\n4. The thread root is the comment's `parentId` when set, or else the comment's\n   own `id`. The thread is the root plus every comment whose `parentId` is the\n   root.\n\n## Superseded\n\nCheck each condition in this order, and record the first that matches as the\nreason. A condition matches only the notification types listed for it. A\ncondition that does not apply to a notification is a silent non-match. When a\ncondition applies but a lookup it needs fails, or a field it needs is missing,\nkeep the notification and, when it is unread, list it under Unresolved. No\nlater check runs on it, Idle included. A field is missing when the response\nomits it. A field the response returns as `null` is present and empty.\n\nCompare timestamps as instants and dates in UTC.\n\n- **Answered.** Types: `issueNewComment`, `issueCommentMention`,\n  `documentNewComment`, `documentCommentMention`, `projectNewComment`, and\n  `projectCommentMention`, with a `url` that has `#comment-\u003Cprefix>`. A\n  comment in the thread has `author.id` equal to the user's `id` and\n  `createdAt` later than the notifying comment's `createdAt`. A comment with\n  only `onBehalfOf.id` equal to the user's `id` does not count.\n- **Reviewed.** Types: `pullRequestReviewRequested` and\n  `pullRequestReviewRerequested`, plus `pullRequestCommented`,\n  `pullRequestCommentMention`, and `pullRequestMention` when `subtitle`\n  contains \"ready for review\", case-insensitive. The `url` is a `\u002Freview\u002F`\n  URL. Read `viewerReviewState` from `get_diff`. A null `lastSubmittedAt` or\n  `lastSubmittedDecision` matches neither bullet. Clear when either holds:\n  - `lastSubmittedAt` is later than the notification's `updatedAt` and\n    `createdAt`, and `isAskedToReviewAgain` is false. Any decision counts,\n    changes requested included.\n  - For the two request types only: `lastSubmittedDecision` is `approved`,\n    and `isReviewRequested` and `isAskedToReviewAgain` are both false.\n- **Advanced.** Type: `issueNewComment`. The notifying comment's body begins\n  with `> *This was generated by AI during triage.*` and does not @-mention the\n  user. The issue's `statusType` is `unstarted` or `started`.\n- **Reassigned.** Type: `issueAssignedToYou`. The issue's `assigneeId` is not\n  the user's `id`. An unassigned issue counts.\n- **Rescheduled.** Type: `issueDue`. The notice is overdue when its `subtitle`\n  contains \"overdue\", case-insensitive, and due soon otherwise. Clear either\n  kind when the issue's `dueDate` is empty. Also clear an overdue notice when\n  `dueDate` is later than the date of the notification's `createdAt` and is\n  today or later.\n- **Restated.** Types: the Answered types. Check this condition last, after\n  the others have run over every notification. Clear this notification when\n  another one with the same `type` and a later `createdAt` is still pending,\n  and its notifying comment is in the same thread as this one's, with the same\n  `author.id`. For an unread notification, the later one is pending when it is\n  still unread after every earlier clear in this run. For a read notification,\n  the later one is pending when it is unread, or when it is read and no\n  earlier check matched it. When either comment or its author cannot be\n  resolved, this condition does not match.\n\n## Run\n\nKeep one cache for the whole run, keyed by issue identifier, review URL, and\ncomment parent. Every step reads from it, so each is fetched at most once.\n\n1. **Identify the user.** Call `get_user` with `query: \"me\"`. Keep the user's\n   `id` and `name`. `get_user` returns no profile URL, so build it as\n   `https:\u002F\u002Flinear.app\u002F\u003Cworkspace>\u002Fprofiles\u002F\u003CdisplayName>`, taking\n   `\u003Cworkspace>` from any notification `url` in step 2. A comment body\n   @-mentions the user only when it contains that profile URL or a mention\n   link to it. The user's name or `@\u003CdisplayName>` as plain text, without the\n   profile link, is not a mention, because Linear does not notify it as one.\n\n2. **Fetch every notification.** Call `get_notifications` with `limit: 250`\n   and without `unreadOnly`. Follow `cursor` until `hasNextPage` is false.\n   Split the result into unread and read notifications.\n\n3. **Set read notifications aside.** Check whether the key is set with\n   `[ -n \"$LINEAR_API_KEY\" ] && echo set || echo unset`, which never prints\n   the key. When it is unset, keep every read notification without lookups and\n   skip archiving for the run. Otherwise, keep without lookups each read\n   notification whose `snoozedUntilAt` is later than now. Steps 4 to 8 cover\n   the unread notifications and the remaining read ones.\n\n4. **Clear status noise and triage-assigned.** Neither needs a lookup.\n\n5. **Clear the done ones** among the rest. Look up each notification's status\n   from its `url`:\n\n   - `\u002Fissue\u002F\u003CKEY>-\u003CN>\u002F...`: call `get_issue` for `\u003CKEY>-\u003CN>` with `fields`\n     `statusType`, `assigneeId`, and `dueDate`, and read its status type.\n   - `\u002Freview\u002F\u003Cslug>`: call `get_diff` with the review URL, without its\n     `#comment-` fragment, and read its status.\n\n   A notification whose lookup fails, or shows no status type, is not done.\n\n6. **Clear the superseded ones** among the rest, by [Superseded](#superseded).\n\n7. **Find the idle candidates** among the notifications not yet cleared or\n   kept as unresolved. A candidate reports a new comment or reply:\n   `category` is `commentsAndReplies`, or `type` is a new-comment or reply\n   type, such as `issueNewComment`, `projectUpdateNewComment`, or a document or\n   project comment type. Keep every other notification without further checks,\n   including:\n\n   - any `type` containing `Mention`, such as `issueMention` or\n     `issueCommentMention`, or `category` `mentions`\n   - reactions, meaning any `type` containing `Reaction`\n   - review requests, re-requests, approvals, and all other pull-request or\n     `reviews` activity\n   - assignments not made by the Triage Rule, document content changes,\n     project updates, and anything else that is not a comment\n\n   Then check each candidate:\n\n   1. Find the notifying comment and thread by\n      [Notifying comment](#notifying-comment). Keep the notification when the\n      parent, the prefix, or a matching comment cannot be found.\n   2. Keep the notification when any comment in the thread has `author.id` or\n      `onBehalfOf.id` equal to the user's `id`.\n   3. Keep the notification when the notifying comment's body @-mentions the\n      user.\n   4. Otherwise, clear it.\n\n8. **Write.** Steps 4 to 7 only decide. Write after every decision is made.\n   Clear each unread notification that needs no action with\n   `mark_notification`. Archive each read notification that needs no action,\n   one at a time, by [Archive](#archive). A notification cleared in this run is\n   never archived in this run. A later run archives it once it is read.\n\n## Archive\n\nArchive one notification with this shell command, replacing `\u003Cid>` with the\nnotification `id`. It reads the key from the environment and prints the\nresponse, which holds only `success` or `errors`, and the HTTP status. It never\nprints the key.\n\n```sh\ncase \"$LINEAR_API_KEY\" in lin_api_*) auth=\"$LINEAR_API_KEY\" ;; *) auth=\"Bearer $LINEAR_API_KEY\" ;; esac\ncurl -sS https:\u002F\u002Fapi.linear.app\u002Fgraphql \\\n  -H \"Authorization: $auth\" -H 'Content-Type: application\u002Fjson' \\\n  -w '\\nHTTP %{http_code}\\n' \\\n  -d '{\"query\":\"mutation($id: String!) { notificationArchive(id: $id) { success } }\",\"variables\":{\"id\":\"\u003Cid>\"}}'\n```\n\nAn archive fails on a curl error, an HTTP status other than 200, an `errors`\nentry in the response, or `success` other than `true`. On the first failure,\nsend no further `notificationArchive` in this run. Count the failed\nnotification and every one not yet sent as kept read. A wrong key, a key\nfor another user, and a rate limit all fail this way.\n\n## Report\n\nEnd with a short summary.\n\n- **Counts.** Unread scanned, read scanned, cleared per reason, archived per\n  reason, idle candidates, kept unread, and kept read. Unread scanned equals\n  cleared plus kept unread. Read scanned equals archived plus kept read. So\n  scanned equals cleared plus archived plus kept.\n- **Archiving skipped.** When `LINEAR_API_KEY` is unset, one line saying\n  archiving was skipped because `LINEAR_API_KEY` is not set.\n- **Cleared.** One line per cleared notification, in this form:\n  `[\u003CKEY>-\u003CN>](issue url) — \u003Ctitle> — \u003Cauthor or notification type> (reason: \u003Creason>)`.\n  The reason is one of `issue completed`, `issue canceled`, `PR merged`,\n  `status change`, `assigned by Triage Rule`, `superseded: answered`,\n  `superseded: reviewed`, `superseded: advanced`, `superseded: reassigned`,\n  `superseded: rescheduled`, `superseded: restated`, or\n  `not mentioned, not in thread`. For a pull request, use the pull request's\n  title as the link text and link its Linear review page. For a document or\n  project, use its title as the link text and link its Linear page. Never\n  invent an issue identifier.\n- **Archived.** One line per archived notification, in the Cleared form and\n  reason vocabulary, followed by the notification `id`.\n- **Unresolved.** Every unread notification kept because something could not\n  be resolved, with the reason: a failed lookup, no status type, a missing field\n  a Superseded condition needs, no parent or comment prefix, or no matching\n  comment. After an archive failure, add one line with the error message and\n  the count of the failed notification plus those not yet sent. A read\n  notification that cannot be resolved is counted as kept read and is not\n  listed here.\n\nRender every Linear issue identifier as a Markdown link to its Linear URL.\n","# Linear Inbox Cleanup\n\nA notification **needs no action** when it is **done**, **status noise**,\n**triage-assigned**, **superseded**, or **idle**. **Clear** every unread\nnotification that needs no action. **Archive** every read notification that\nneeds no action, whatever its age. **Keep** every other notification. When in\ndoubt about a notification, keep it.\n\nA notification is read when its `readAt` is non-null. When the response omits\n`readAt`, treat the notification as unread.\n\nClear means `mark_notification` with `id` set to the notification ID and\n`read: true`. Archive means the GraphQL `notificationArchive` mutation, sent as\nin [Archive](#archive). Keep means leave the notification unchanged: an unread\none stays unread, and a read one stays read and in the inbox.\n\nIn [Categories](#categories) and [Superseded](#superseded), \"clear\" means the\nnotification needs no action. [Run](#run) step 8 decides whether it is\ncleared or archived.\n\n## Scope\n\nUse only these Linear MCP tools: `get_user`, `get_notifications`, `get_issue`,\n`get_diff`, `list_comments`, and `mark_notification`. Do not use a browser.\n\nThe only non-MCP actions are two shell commands: the key check in\n[Run](#run) step 3, which reaches no service, and the `curl` call in\n[Archive](#archive). The `curl` call sends `notificationArchive`, the only\nGraphQL operation this skill may send. Send no other GraphQL query or\nmutation.\n\nThe only writes are clear, through `mark_notification`, and archive, through\n`notificationArchive`. Never snooze, delete, or unarchive a notification, and\nnever comment on or change an issue, project, document, comment, or pull\nrequest.\n\n## Categories\n\n- **Done.** The notification's issue has status type `completed` or\n  `canceled`, or its pull request has status `merged`. A Duplicate status is\n  type `canceled`. Any other issue status type, and an open pull request or\n  one closed without merging, is not done. Nothing is left to act on, so clear\n  a done notification whatever its type, mentions included.\n- **Status noise.** `category` is `statusChanges`. That covers\n  `issueStatusChanged`, `issueRestored`, `issueUnblocked`, and every other\n  status-change type. Clear it whatever the issue's status.\n- **Triage-assigned.** `type` is `issueAssignedToYou` and `subtitle` is\n  `Assigned by Triage Rule`. An assignment by a person or a bot is not\n  triage-assigned.\n- **Superseded.** A later event shows the user already acted, or the work\n  moved on. See [Superseded](#superseded).\n- **Idle.** A new-comment notification where the user is not @-mentioned and\n  has not commented in that thread.\n\nIssue URLs below use `\u003CKEY>-\u003CN>`, the issue identifier with its team key, such\nas `ENG-123`.\n\n## Notifying comment\n\nFind a notification's notifying comment and thread this way:\n\n1. Find the parent from the `url`. `\u002Fissue\u002F\u003CKEY>-\u003CN>\u002F...` gives\n   `issueId: \"\u003CKEY>-\u003CN>\"`, `\u002Fdocument\u002F\u003Cslug>` gives `documentId`, and\n   `\u002Fproject\u002F\u003Cslug>` gives `projectId`. The comment ID prefix is the eight hex\n   characters after `#comment-`.\n2. Call `list_comments` for the parent with `limit: 250`, following `cursor`.\n3. The notifying comment is the one whose `id` starts with the prefix.\n4. The thread root is the comment's `parentId` when set, or else the comment's\n   own `id`. The thread is the root plus every comment whose `parentId` is the\n   root.\n\n## Superseded\n\nCheck each condition in this order, and record the first that matches as the\nreason. A condition matches only the notification types listed for it. A\ncondition that does not apply to a notification is a silent non-match. When a\ncondition applies but a lookup it needs fails, or a field it needs is missing,\nkeep the notification and, when it is unread, list it under Unresolved. No\nlater check runs on it, Idle included. A field is missing when the response\nomits it. A field the response returns as `null` is present and empty.\n\nCompare timestamps as instants and dates in UTC.\n\n- **Answered.** Types: `issueNewComment`, `issueCommentMention`,\n  `documentNewComment`, `documentCommentMention`, `projectNewComment`, and\n  `projectCommentMention`, with a `url` that has `#comment-\u003Cprefix>`. A\n  comment in the thread has `author.id` equal to the user's `id` and\n  `createdAt` later than the notifying comment's `createdAt`. A comment with\n  only `onBehalfOf.id` equal to the user's `id` does not count.\n- **Reviewed.** Types: `pullRequestReviewRequested` and\n  `pullRequestReviewRerequested`, plus `pullRequestCommented`,\n  `pullRequestCommentMention`, and `pullRequestMention` when `subtitle`\n  contains \"ready for review\", case-insensitive. The `url` is a `\u002Freview\u002F`\n  URL. Read `viewerReviewState` from `get_diff`. A null `lastSubmittedAt` or\n  `lastSubmittedDecision` matches neither bullet. Clear when either holds:\n  - `lastSubmittedAt` is later than the notification's `updatedAt` and\n    `createdAt`, and `isAskedToReviewAgain` is false. Any decision counts,\n    changes requested included.\n  - For the two request types only: `lastSubmittedDecision` is `approved`,\n    and `isReviewRequested` and `isAskedToReviewAgain` are both false.\n- **Advanced.** Type: `issueNewComment`. The notifying comment's body begins\n  with `> *This was generated by AI during triage.*` and does not @-mention the\n  user. The issue's `statusType` is `unstarted` or `started`.\n- **Reassigned.** Type: `issueAssignedToYou`. The issue's `assigneeId` is not\n  the user's `id`. An unassigned issue counts.\n- **Rescheduled.** Type: `issueDue`. The notice is overdue when its `subtitle`\n  contains \"overdue\", case-insensitive, and due soon otherwise. Clear either\n  kind when the issue's `dueDate` is empty. Also clear an overdue notice when\n  `dueDate` is later than the date of the notification's `createdAt` and is\n  today or later.\n- **Restated.** Types: the Answered types. Check this condition last, after\n  the others have run over every notification. Clear this notification when\n  another one with the same `type` and a later `createdAt` is still pending,\n  and its notifying comment is in the same thread as this one's, with the same\n  `author.id`. For an unread notification, the later one is pending when it is\n  still unread after every earlier clear in this run. For a read notification,\n  the later one is pending when it is unread, or when it is read and no\n  earlier check matched it. When either comment or its author cannot be\n  resolved, this condition does not match.\n\n## Run\n\nKeep one cache for the whole run, keyed by issue identifier, review URL, and\ncomment parent. Every step reads from it, so each is fetched at most once.\n\n1. **Identify the user.** Call `get_user` with `query: \"me\"`. Keep the user's\n   `id` and `name`. `get_user` returns no profile URL, so build it as\n   `https:\u002F\u002Flinear.app\u002F\u003Cworkspace>\u002Fprofiles\u002F\u003CdisplayName>`, taking\n   `\u003Cworkspace>` from any notification `url` in step 2. A comment body\n   @-mentions the user only when it contains that profile URL or a mention\n   link to it. The user's name or `@\u003CdisplayName>` as plain text, without the\n   profile link, is not a mention, because Linear does not notify it as one.\n\n2. **Fetch every notification.** Call `get_notifications` with `limit: 250`\n   and without `unreadOnly`. Follow `cursor` until `hasNextPage` is false.\n   Split the result into unread and read notifications.\n\n3. **Set read notifications aside.** Check whether the key is set with\n   `[ -n \"$LINEAR_API_KEY\" ] && echo set || echo unset`, which never prints\n   the key. When it is unset, keep every read notification without lookups and\n   skip archiving for the run. Otherwise, keep without lookups each read\n   notification whose `snoozedUntilAt` is later than now. Steps 4 to 8 cover\n   the unread notifications and the remaining read ones.\n\n4. **Clear status noise and triage-assigned.** Neither needs a lookup.\n\n5. **Clear the done ones** among the rest. Look up each notification's status\n   from its `url`:\n\n   - `\u002Fissue\u002F\u003CKEY>-\u003CN>\u002F...`: call `get_issue` for `\u003CKEY>-\u003CN>` with `fields`\n     `statusType`, `assigneeId`, and `dueDate`, and read its status type.\n   - `\u002Freview\u002F\u003Cslug>`: call `get_diff` with the review URL, without its\n     `#comment-` fragment, and read its status.\n\n   A notification whose lookup fails, or shows no status type, is not done.\n\n6. **Clear the superseded ones** among the rest, by [Superseded](#superseded).\n\n7. **Find the idle candidates** among the notifications not yet cleared or\n   kept as unresolved. A candidate reports a new comment or reply:\n   `category` is `commentsAndReplies`, or `type` is a new-comment or reply\n   type, such as `issueNewComment`, `projectUpdateNewComment`, or a document or\n   project comment type. Keep every other notification without further checks,\n   including:\n\n   - any `type` containing `Mention`, such as `issueMention` or\n     `issueCommentMention`, or `category` `mentions`\n   - reactions, meaning any `type` containing `Reaction`\n   - review requests, re-requests, approvals, and all other pull-request or\n     `reviews` activity\n   - assignments not made by the Triage Rule, document content changes,\n     project updates, and anything else that is not a comment\n\n   Then check each candidate:\n\n   1. Find the notifying comment and thread by\n      [Notifying comment](#notifying-comment). Keep the notification when the\n      parent, the prefix, or a matching comment cannot be found.\n   2. Keep the notification when any comment in the thread has `author.id` or\n      `onBehalfOf.id` equal to the user's `id`.\n   3. Keep the notification when the notifying comment's body @-mentions the\n      user.\n   4. Otherwise, clear it.\n\n8. **Write.** Steps 4 to 7 only decide. Write after every decision is made.\n   Clear each unread notification that needs no action with\n   `mark_notification`. Archive each read notification that needs no action,\n   one at a time, by [Archive](#archive). A notification cleared in this run is\n   never archived in this run. A later run archives it once it is read.\n\n## Archive\n\nArchive one notification with this shell command, replacing `\u003Cid>` with the\nnotification `id`. It reads the key from the environment and prints the\nresponse, which holds only `success` or `errors`, and the HTTP status. It never\nprints the key.\n\n```sh\ncase \"$LINEAR_API_KEY\" in lin_api_*) auth=\"$LINEAR_API_KEY\" ;; *) auth=\"Bearer $LINEAR_API_KEY\" ;; esac\ncurl -sS https:\u002F\u002Fapi.linear.app\u002Fgraphql \\\n  -H \"Authorization: $auth\" -H 'Content-Type: application\u002Fjson' \\\n  -w '\\nHTTP %{http_code}\\n' \\\n  -d '{\"query\":\"mutation($id: String!) { notificationArchive(id: $id) { success } }\",\"variables\":{\"id\":\"\u003Cid>\"}}'\n```\n\nAn archive fails on a curl error, an HTTP status other than 200, an `errors`\nentry in the response, or `success` other than `true`. On the first failure,\nsend no further `notificationArchive` in this run. Count the failed\nnotification and every one not yet sent as kept read. A wrong key, a key\nfor another user, and a rate limit all fail this way.\n\n## Report\n\nEnd with a short summary.\n\n- **Counts.** Unread scanned, read scanned, cleared per reason, archived per\n  reason, idle candidates, kept unread, and kept read. Unread scanned equals\n  cleared plus kept unread. Read scanned equals archived plus kept read. So\n  scanned equals cleared plus archived plus kept.\n- **Archiving skipped.** When `LINEAR_API_KEY` is unset, one line saying\n  archiving was skipped because `LINEAR_API_KEY` is not set.\n- **Cleared.** One line per cleared notification, in this form:\n  `[\u003CKEY>-\u003CN>](issue url) — \u003Ctitle> — \u003Cauthor or notification type> (reason: \u003Creason>)`.\n  The reason is one of `issue completed`, `issue canceled`, `PR merged`,\n  `status change`, `assigned by Triage Rule`, `superseded: answered`,\n  `superseded: reviewed`, `superseded: advanced`, `superseded: reassigned`,\n  `superseded: rescheduled`, `superseded: restated`, or\n  `not mentioned, not in thread`. For a pull request, use the pull request's\n  title as the link text and link its Linear review page. For a document or\n  project, use its title as the link text and link its Linear page. Never\n  invent an issue identifier.\n- **Archived.** One line per archived notification, in the Cleared form and\n  reason vocabulary, followed by the notification `id`.\n- **Unresolved.** Every unread notification kept because something could not\n  be resolved, with the reason: a failed lookup, no status type, a missing field\n  a Superseded condition needs, no parent or comment prefix, or no matching\n  comment. After an archive failure, add one line with the error message and\n  the count of the failed notification plus those not yet sent. A read\n  notification that cannot be resolved is counted as kept read and is not\n  listed here.\n\nRender every Linear issue identifier as a Markdown link to its Linear URL.\n",{"name":5,"description":7},"main","e6ee720f466a8344a52abd87679191fadde3b63f","plugins\u002Fwork\u002Fskills\u002Flinear-inbox-cleanup","https:\u002F\u002Fgithub.com\u002Fpatinaproject\u002Fskills","https:\u002F\u002Fgithub.com\u002Fpatinaproject","https:\u002F\u002Fwww.patinaproject.com","The best way to pick your next pair of boots or shoes.","2026-11-11 10:34:42",{"source":8,"skillName":5,"commands":53,"prompt":63,"zipAvailable":64},[54,57,60],{"tool":55,"command":56},"npx","npx skills add patinaproject\u002Fskills --skill linear-inbox-cleanup",{"tool":58,"command":59},"bunx","bunx skills add patinaproject\u002Fskills --skill linear-inbox-cleanup",{"tool":61,"command":62},"pnpm","pnpm dlx skills add patinaproject\u002Fskills --skill linear-inbox-cleanup","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fpatinaproject\u002Fskills\u002Fblob\u002Fmain\u002Fplugins\u002Fwork\u002Fskills\u002Flinear-inbox-cleanup\u002FSKILL.md",true,[],[67,96,108,128,151,167],{"skillNo":68,"name":69,"nameZh":6,"description":70,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":71,"categories":72,"keywords":83,"publishedAt":39},"01M71ESEDVHD9EXN6787XHP7HD","writing-for-pstack","Write or tighten an operator prompt for a patina-mode run. Use when the operator asks to write, revise, or review a prompt that will be passed to patina-mode.","https:\u002F\u002Fgithub.com\u002Fpatinaproject\u002Fskills\u002Fblob\u002Fmain\u002Fplugins\u002Fwork\u002Fskills\u002Fwriting-for-pstack\u002FSKILL.md",[73,78],{"categoryNo":74,"categoryName":75,"taxonomyType":76,"taxonomyTypeDesc":77},"01JBSEEDCAT000000000000018","写作与文案","SCENARIO","使用场景",{"categoryNo":79,"categoryName":80,"taxonomyType":81,"taxonomyTypeDesc":82},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[84,85,86,87,30,88,89,90,91,31,92,93,94,95],"writing for pstack","writing","for","pstack","run","review","prompt","write","revise","tighten","mode","operator",{"skillNo":97,"name":98,"nameZh":6,"description":99,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":100,"categories":101,"keywords":104,"publishedAt":39},"01M71ESCJ0SSJFFENF8HYDKBTJ","writing-for-agents","Writing documents for agents. Use when creating or editing skills, or modifying AGENTS.md or CLAUDE.md.","https:\u002F\u002Fgithub.com\u002Fpatinaproject\u002Fskills\u002Fblob\u002Fmain\u002Fplugins\u002Fwork\u002Fskills\u002Fwriting-for-agents\u002FSKILL.md",[102,103],{"categoryNo":74,"categoryName":75,"taxonomyType":76,"taxonomyTypeDesc":77},{"categoryNo":79,"categoryName":80,"taxonomyType":81,"taxonomyTypeDesc":82},[85,105,86,106,30,31,107],"writing for agents","editing","documents",{"skillNo":109,"name":110,"nameZh":6,"description":111,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":112,"categories":113,"keywords":114,"publishedAt":39},"01M71ESA1NN9WVMD2HA5Z1RRDY","wizard","Generate an interactive bash wizard that walks a human through steps only they can perform. Use when provisioning infrastructure, setting up credentials or CI secrets, walking an unfamiliar third-party dashboard, or running a one-off migration or cutover. Don't invoke this for steps the agent can perform itself.","https:\u002F\u002Fgithub.com\u002Fpatinaproject\u002Fskills\u002Fblob\u002Fmain\u002Fplugins\u002Fwork\u002Fskills\u002Fwizard\u002FSKILL.md",[],[110,115,86,116,117,118,34,32,31,30,119,120,121,122,123,124,125,29,126,127],"interactive","can","human","provisioning infrastructure","Bash","secrets","credentials","ci","generate","dashboard","invoke","setting","running",{"skillNo":129,"name":130,"nameZh":6,"description":131,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":132,"categories":133,"keywords":134,"publishedAt":39},"01M71ES8FAN567N3JEPG8W6AS1","wayfinder","Plan a huge chunk of work (more than one agent session can hold) as a shared map of decision tickets on your issue tracker, and resolve them one at a time until the way to the destination is clear.","https:\u002F\u002Fgithub.com\u002Fpatinaproject\u002Fskills\u002Fblob\u002Fmain\u002Fplugins\u002Fwork\u002Fskills\u002Fwayfinder\u002FSKILL.md",[],[130,135,136,137,138,116,139,140,141,38,142,143,144,29,145,146,147,148,149,150],"at","tracker","destination","agent session","true","more","tickets","shared","time","map","session","one at a time","work","decision","plan","chunk",{"skillNo":152,"name":153,"nameZh":6,"description":154,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":155,"categories":156,"keywords":157,"publishedAt":39},"01M71ES6PWJPKBW8R24YFH4PY6","wait-what","Stop. That last message did not land: re-pitch it.","https:\u002F\u002Fgithub.com\u002Fpatinaproject\u002Fskills\u002Fblob\u002Fmain\u002Fplugins\u002Fwork\u002Fskills\u002Fwait-what\u002FSKILL.md",[],[158,159,160,161,162,163,164,139,165,166],"wait","wait what","pitch","message","stop","land","it","last","re",{"skillNo":168,"name":169,"nameZh":6,"description":170,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":171,"categories":172,"keywords":173,"publishedAt":39},"01M71ES4ZXKEGMMYS0NFPEBQ80","using-github","Work with repository settings, pull requests, reviews, checks, and releases on GitHub. Use for GitHub operations other than issue tracking.","https:\u002F\u002Fgithub.com\u002Fpatinaproject\u002Fskills\u002Fblob\u002Fmain\u002Fplugins\u002Fwork\u002Fskills\u002Fusing-github\u002FSKILL.md",[],[174,175,176,86,177,178,179,180,181,182,31,183,184,185,147,186,187,188],"github","using github","issue","issue tracking","github operations","requests","reviews","with","releases","operations","tracking","settings","repository","pull","pull requests"]