> ## Documentation Index
> Fetch the complete documentation index at: https://docs.beta.b3os.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Linear

The io.b3os/linear pack: 11 actions with call snippets, fixture outputs, connection setup and error codes, generated from version 1.0.0.

`io.b3os/linear` 1.0.0 · `issue-tracking`, `project-management` · MIT

Track work in Linear with your own API key: search and list issues, read an issue with its comments, create issues, move them between workflow states, assign them, comment, and list teams, workflow states and projects. Uses Linear's GraphQL API. A personal API key (Settings, Security & access) or an OAuth access token for your own Linear app works.

Every call's result carries `upstream_status` and `timing`: `validate_ms`, `inject_ms`, `render_ms`, `upstream_ms`, `map_ms` and `total_ms`. `upstream` is the service's time; the others are B3OS's own ([call actions](/actions/call)). The snippets below show no timing values, because a fixture records none.

## Connection

`api_key`, type `api_key`: Linear API key.

A personal API key, sent as the Authorization header as is. An OAuth access token from your own Linear app works too when you store it with the Bearer prefix.

How to get one: [linear.app](https://linear.app/developers/graphql#authentication).

The credential is sent only to `api.linear.app`.

Store the credential once as a [vault connection](/vault) for this pack and key, then name its id in a call's `connections`. Leave the key out and B3OS uses the project's newest connection for the pack and key without a `subject` ([connections](/actions/call#connections)).

Hosts it reaches: `api.linear.app`.

## Actions

| Action | Effect | MCP tool | Title |
|---|---|---|---|
| [`get-viewer`](/actions/catalog/linear#linear-get-viewer) | read | `linear__get-viewer` | Get current user |
| [`list-teams`](/actions/catalog/linear#linear-list-teams) | read | `linear__list-teams` | List teams |
| [`list-workflow-states`](/actions/catalog/linear#linear-list-workflow-states) | read | `linear__list-workflow-states` | List workflow states |
| [`search-issues`](/actions/catalog/linear#linear-search-issues) | read | `linear__search-issues` | Search issues |
| [`list-issues`](/actions/catalog/linear#linear-list-issues) | read | `linear__list-issues` | List team issues |
| [`get-issue`](/actions/catalog/linear#linear-get-issue) | read | `linear__get-issue` | Get issue |
| [`create-issue`](/actions/catalog/linear#linear-create-issue) | write | `linear__create-issue` | Create issue |
| [`move-issue`](/actions/catalog/linear#linear-move-issue) | write | `linear__move-issue` | Move issue to a state |
| [`assign-issue`](/actions/catalog/linear#linear-assign-issue) | write | `linear__assign-issue` | Assign issue |
| [`add-comment`](/actions/catalog/linear#linear-add-comment) | write | `linear__add-comment` | Comment on issue |
| [`list-projects`](/actions/catalog/linear#linear-list-projects) | read | `linear__list-projects` | List projects |

get-viewer

**Get current user.** Who the API key belongs to: user id, name, email and organization (name and URL key). A cheap way to check a connection.

Ref `io.b3os/linear/get-viewer@1.0.0` · effect `read` · connection `api_key` · MCP tool `linear__get-viewer`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/linear/get-viewer@1",
          "input": {},
          "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/linear/get-viewer@1",
      input: {},
      connections: { api_key: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    });
    console.log(result.output);
    ```
  **Python**

```python
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/linear/get-viewer@1",
        "input": {},
        "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    })
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {"name": "linear__get-viewer", "arguments": {}}
    }
    ```

    Expose the pack as tools with `--packs linear` on the local server or `?packs=linear` on the remote URL, and the agent calls `linear__get-viewer` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: Get current user (documented response shape, example values). From the bundle's `fixtures/get-viewer.json`, not a live call.

```json
{
  "id": "8f3a9b2e-1c4d-4e5f-9a6b-7c8d9e0f1a2b",
  "name": "Mona Example",
  "email": "mona@acme.example",
  "organization": "Acme",
  "organization_url_key": "acme"
}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `connection_unauthorized` | 401 | no | Linear rejected the API key or token. |
| `forbidden` | matched on the response body | no | built from the service's response |
| `rate_limited` | 429 | yes | Linear rate limit reached; retry shortly. |
| `not_found` | matched on the response body | no | built from the service's response |
| `invalid_request` | matched on the response body | no | built from the service's response |

list-teams

**List teams.** Teams in the workspace with id, key (the issue prefix) and name. create-issue needs a team id.

Ref `io.b3os/linear/list-teams@1.0.0` · effect `read` · connection `api_key` · MCP tool `linear__list-teams`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/linear/list-teams@1",
          "input": {},
          "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/linear/list-teams@1",
      input: {},
      connections: { api_key: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    });
    console.log(result.output);
    ```
  **Python**

```python
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/linear/list-teams@1",
        "input": {},
        "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    })
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {"name": "linear__list-teams", "arguments": {}}
    }
    ```

    Expose the pack as tools with `--packs linear` on the local server or `?packs=linear` on the remote URL, and the agent calls `linear__list-teams` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: List teams (documented response shape, example values). From the bundle's `fixtures/list-teams.json`, not a live call.

```json
{
  "teams": [
    {
      "id": "4e1d2c3b-5a6f-4b7c-8d9e-0f1a2b3c4d5e",
      "key": "ENG",
      "name": "Engineering"
    },
    {
      "id": "9a8b7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d",
      "key": "DES",
      "name": "Design"
    }
  ]
}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `connection_unauthorized` | 401 | no | Linear rejected the API key or token. |
| `forbidden` | matched on the response body | no | built from the service's response |
| `rate_limited` | 429 | yes | Linear rate limit reached; retry shortly. |
| `not_found` | matched on the response body | no | built from the service's response |
| `invalid_request` | matched on the response body | no | built from the service's response |

list-workflow-states

**List workflow states.** A team's workflow states (Todo, In Progress, Done, ...) with id, name and type. move-issue needs a state id.

Ref `io.b3os/linear/list-workflow-states@1.0.0` · effect `read` · connection `api_key` · MCP tool `linear__list-workflow-states`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/linear/list-workflow-states@1",
          "input": {"team": "ENG"},
          "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/linear/list-workflow-states@1",
      input: { team: "ENG" },
      connections: { api_key: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    });
    console.log(result.output);
    ```
  **Python**

```python
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/linear/list-workflow-states@1",
        "input": {"team": "ENG"},
        "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    })
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {
        "name": "linear__list-workflow-states",
        "arguments": {"team": "ENG"}
      }
    }
    ```

    Expose the pack as tools with `--packs linear` on the local server or `?packs=linear` on the remote URL, and the agent calls `linear__list-workflow-states` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: List workflow states (documented response shape, example values). From the bundle's `fixtures/list-workflow-states.json`, not a live call.

```json
{
  "states": [
    {
      "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
      "name": "Todo",
      "type": "unstarted",
      "position": 0
    },
    {
      "id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
      "name": "In Progress",
      "type": "started",
      "position": 1
    },
    {
      "id": "c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f",
      "name": "Done",
      "type": "completed",
      "position": 2
    }
  ]
}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `connection_unauthorized` | 401 | no | Linear rejected the API key or token. |
| `forbidden` | matched on the response body | no | built from the service's response |
| `rate_limited` | 429 | yes | Linear rate limit reached; retry shortly. |
| `not_found` | matched on the response body | no | built from the service's response |
| `invalid_request` | matched on the response body | no | built from the service's response |

search-issues

**Search issues.** Full-text search over issue titles, descriptions and identifiers in the workspace, best match first: identifier, title, state, priority, assignee, team, labels and URL. Use list-issues to filter one team by state instead.

Ref `io.b3os/linear/search-issues@1.0.0` · effect `read` · connection `api_key` · MCP tool `linear__search-issues`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/linear/search-issues@1",
          "input": {"query": "checkout overflow", "first": 1},
          "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/linear/search-issues@1",
      input: { query: "checkout overflow", first: 1 },
      connections: { api_key: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    });
    console.log(result.output);
    ```
  **Python**

```python
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/linear/search-issues@1",
        "input": {"query": "checkout overflow", "first": 1},
        "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    })
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {
        "name": "linear__search-issues",
        "arguments": {"query": "checkout overflow", "first": 1}
      }
    }
    ```

    Expose the pack as tools with `--packs linear` on the local server or `?packs=linear` on the remote URL, and the agent calls `linear__search-issues` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: Search issues (documented response shape, example values). From the bundle's `fixtures/search-issues.json`, not a live call.

```json
{
  "issues": [
    {
      "id": "5f6e7d8c-9b0a-4c1d-8e2f-3a4b5c6d7e8f",
      "identifier": "ENG-123",
      "title": "Cart overflows on narrow screens",
      "url": "https://linear.app/acme/issue/eng-123",
      "priority": 2,
      "priority_label": "High",
      "estimate": 3,
      "due_date": null,
      "state": "In Progress",
      "state_type": "started",
      "assignee": "Mona Example",
      "assignee_email": "mona@acme.example",
      "team": "ENG",
      "labels": ["Bug"],
      "created_at": "2026-10-24T17:11:20.000Z",
      "updated_at": "2026-10-25T09:02:41.000Z",
      "completed_at": null
    }
  ]
}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `connection_unauthorized` | 401 | no | Linear rejected the API key or token. |
| `forbidden` | matched on the response body | no | built from the service's response |
| `rate_limited` | 429 | yes | Linear rate limit reached; retry shortly. |
| `not_found` | matched on the response body | no | built from the service's response |
| `invalid_request` | matched on the response body | no | built from the service's response |

list-issues

**List team issues.** A team's issues, most recently updated first, limited to workflow state types you choose (default: everything not completed or canceled). Page with after = the previous end_cursor while has_next_page is true.

Ref `io.b3os/linear/list-issues@1.0.0` · effect `read` · connection `api_key` · MCP tool `linear__list-issues`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/linear/list-issues@1",
          "input": {"team": "ENG", "first": 1},
          "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/linear/list-issues@1",
      input: { team: "ENG", first: 1 },
      connections: { api_key: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    });
    console.log(result.output);
    ```
  **Python**

```python
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/linear/list-issues@1",
        "input": {"team": "ENG", "first": 1},
        "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    })
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {
        "name": "linear__list-issues",
        "arguments": {"team": "ENG", "first": 1}
      }
    }
    ```

    Expose the pack as tools with `--packs linear` on the local server or `?packs=linear` on the remote URL, and the agent calls `linear__list-issues` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: List team issues (documented response shape, example values). From the bundle's `fixtures/list-issues.json`, not a live call.

```json
{
  "issues": [
    {
      "id": "5f6e7d8c-9b0a-4c1d-8e2f-3a4b5c6d7e8f",
      "identifier": "ENG-123",
      "title": "Cart overflows on narrow screens",
      "url": "https://linear.app/acme/issue/eng-123",
      "priority": 2,
      "priority_label": "High",
      "estimate": 3,
      "due_date": null,
      "state": "In Progress",
      "state_type": "started",
      "assignee": "Mona Example",
      "assignee_email": "mona@acme.example",
      "team": "ENG",
      "labels": ["Bug"],
      "created_at": "2026-10-24T17:11:20.000Z",
      "updated_at": "2026-10-25T09:02:41.000Z",
      "completed_at": null
    }
  ],
  "has_next_page": true,
  "end_cursor": "5f6e7d8c-9b0a-4c1d-8e2f-3a4b5c6d7e8f"
}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `connection_unauthorized` | 401 | no | Linear rejected the API key or token. |
| `forbidden` | matched on the response body | no | built from the service's response |
| `rate_limited` | 429 | yes | Linear rate limit reached; retry shortly. |
| `not_found` | matched on the response body | no | built from the service's response |
| `invalid_request` | matched on the response body | no | built from the service's response |

get-issue

**Get issue.** One issue by identifier (ENG-123) or id, with its Markdown description, state, assignee, labels, project, parent and the latest 20 comments.

Ref `io.b3os/linear/get-issue@1.0.0` · effect `read` · connection `api_key` · MCP tool `linear__get-issue`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/linear/get-issue@1",
          "input": {"id": "ENG-123"},
          "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/linear/get-issue@1",
      input: { id: "ENG-123" },
      connections: { api_key: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    });
    console.log(result.output);
    ```
  **Python**

```python
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/linear/get-issue@1",
        "input": {"id": "ENG-123"},
        "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    })
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {"name": "linear__get-issue", "arguments": {"id": "ENG-123"}}
    }
    ```

    Expose the pack as tools with `--packs linear` on the local server or `?packs=linear` on the remote URL, and the agent calls `linear__get-issue` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: Get issue (documented response shape, example values). From the bundle's `fixtures/get-issue.json`, not a live call.

```json
{
  "id": "5f6e7d8c-9b0a-4c1d-8e2f-3a4b5c6d7e8f",
  "identifier": "ENG-123",
  "title": "Cart overflows on narrow screens",
  "url": "https://linear.app/acme/issue/eng-123",
  "priority": 2,
  "priority_label": "High",
  "estimate": 3,
  "due_date": null,
  "state": "In Progress",
  "state_type": "started",
  "assignee": "Mona Example",
  "assignee_email": "mona@acme.example",
  "team": "ENG",
  "labels": ["Bug"],
  "created_at": "2026-10-24T17:11:20.000Z",
  "updated_at": "2026-10-25T09:02:41.000Z",
  "completed_at": null,
  "description": "Steps:\n\n1. Open the cart\n2. Resize to 375px",
  "project": "Checkout v2",
  "parent": null,
  "comments": [
    {
      "author": "Hubot Example",
      "body": "Reproduced on Safari 18.",
      "created_at": "2026-10-25T10:00:00.000Z"
    }
  ]
}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `connection_unauthorized` | 401 | no | Linear rejected the API key or token. |
| `forbidden` | matched on the response body | no | built from the service's response |
| `rate_limited` | 429 | yes | Linear rate limit reached; retry shortly. |
| `not_found` | matched on the response body | no | built from the service's response |
| `invalid_request` | matched on the response body | no | built from the service's response |

create-issue

**Create issue.** Create an issue in a team (team_id from list-teams) with a title and optional Markdown description, priority (0 none to 4 low), assignee, labels and initial state. Returns its identifier and URL. Not idempotent.

Ref `io.b3os/linear/create-issue@1.0.0` · effect `write` · connection `api_key` · MCP tool `linear__create-issue`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/linear/create-issue@1",
          "input": {
            "team_id": "4e1d2c3b-5a6f-4b7c-8d9e-0f1a2b3c4d5e",
            "title": "Flaky checkout test",
            "description": "Seen three times this week.",
            "priority": 2
          },
          "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/linear/create-issue@1",
      input: {
        team_id: "4e1d2c3b-5a6f-4b7c-8d9e-0f1a2b3c4d5e",
        title: "Flaky checkout test",
        description: "Seen three times this week.",
        priority: 2,
      },
      connections: { api_key: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    }, { idempotencyKey: crypto.randomUUID() });
    console.log(result.output);
    ```
  **Python**

```python
    import uuid
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/linear/create-issue@1",
        "input": {
            "team_id": "4e1d2c3b-5a6f-4b7c-8d9e-0f1a2b3c4d5e",
            "title": "Flaky checkout test",
            "description": "Seen three times this week.",
            "priority": 2,
        },
        "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    }, idempotency_key=str(uuid.uuid4()))
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {
        "name": "linear__create-issue",
        "arguments": {
          "team_id": "4e1d2c3b-5a6f-4b7c-8d9e-0f1a2b3c4d5e",
          "title": "Flaky checkout test",
          "description": "Seen three times this week.",
          "priority": 2
        }
      }
    }
    ```

    Expose the pack as tools with `--packs linear` on the local server or `?packs=linear` on the remote URL, and the agent calls `linear__create-issue` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: Create issue (documented response shape, example values). From the bundle's `fixtures/create-issue.json`, not a live call.

```json
{
  "id": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
  "identifier": "ENG-124",
  "title": "Flaky checkout test",
  "url": "https://linear.app/acme/issue/eng-124"
}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `connection_unauthorized` | 401 | no | Linear rejected the API key or token. |
| `forbidden` | matched on the response body | no | built from the service's response |
| `rate_limited` | 429 | yes | Linear rate limit reached; retry shortly. |
| `not_found` | matched on the response body | no | built from the service's response |
| `invalid_request` | matched on the response body | no | built from the service's response |

move-issue

**Move issue to a state.** Change an issue's workflow state, for example to In Progress or Done (state ids from list-workflow-states). Returns the issue's new state.

Ref `io.b3os/linear/move-issue@1.0.0` · effect `write` · connection `api_key` · MCP tool `linear__move-issue`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/linear/move-issue@1",
          "input": {
            "id": "ENG-123",
            "state_id": "c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f"
          },
          "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/linear/move-issue@1",
      input: { id: "ENG-123", state_id: "c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f" },
      connections: { api_key: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    }, { idempotencyKey: crypto.randomUUID() });
    console.log(result.output);
    ```
  **Python**

```python
    import uuid
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/linear/move-issue@1",
        "input": {
            "id": "ENG-123",
            "state_id": "c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f",
        },
        "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    }, idempotency_key=str(uuid.uuid4()))
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {
        "name": "linear__move-issue",
        "arguments": {
          "id": "ENG-123",
          "state_id": "c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f"
        }
      }
    }
    ```

    Expose the pack as tools with `--packs linear` on the local server or `?packs=linear` on the remote URL, and the agent calls `linear__move-issue` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: Move issue to a state (documented response shape, example values). From the bundle's `fixtures/move-issue.json`, not a live call.

```json
{"identifier": "ENG-123", "state": "Done", "state_type": "completed"}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `connection_unauthorized` | 401 | no | Linear rejected the API key or token. |
| `forbidden` | matched on the response body | no | built from the service's response |
| `rate_limited` | 429 | yes | Linear rate limit reached; retry shortly. |
| `not_found` | matched on the response body | no | built from the service's response |
| `invalid_request` | matched on the response body | no | built from the service's response |

assign-issue

**Assign issue.** Assign an issue to a user (user id, from get-issue or the Linear app), or unassign it when assignee_id is omitted.

Ref `io.b3os/linear/assign-issue@1.0.0` · effect `write` · connection `api_key` · MCP tool `linear__assign-issue`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/linear/assign-issue@1",
          "input": {
            "id": "ENG-123",
            "assignee_id": "8f3a9b2e-1c4d-4e5f-9a6b-7c8d9e0f1a2b"
          },
          "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/linear/assign-issue@1",
      input: {
        id: "ENG-123",
        assignee_id: "8f3a9b2e-1c4d-4e5f-9a6b-7c8d9e0f1a2b",
      },
      connections: { api_key: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    }, { idempotencyKey: crypto.randomUUID() });
    console.log(result.output);
    ```
  **Python**

```python
    import uuid
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/linear/assign-issue@1",
        "input": {
            "id": "ENG-123",
            "assignee_id": "8f3a9b2e-1c4d-4e5f-9a6b-7c8d9e0f1a2b",
        },
        "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    }, idempotency_key=str(uuid.uuid4()))
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {
        "name": "linear__assign-issue",
        "arguments": {
          "id": "ENG-123",
          "assignee_id": "8f3a9b2e-1c4d-4e5f-9a6b-7c8d9e0f1a2b"
        }
      }
    }
    ```

    Expose the pack as tools with `--packs linear` on the local server or `?packs=linear` on the remote URL, and the agent calls `linear__assign-issue` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: Assign issue (documented response shape, example values). From the bundle's `fixtures/assign-issue.json`, not a live call.

```json
{"identifier": "ENG-123", "assignee": "Mona Example"}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `connection_unauthorized` | 401 | no | Linear rejected the API key or token. |
| `forbidden` | matched on the response body | no | built from the service's response |
| `rate_limited` | 429 | yes | Linear rate limit reached; retry shortly. |
| `not_found` | matched on the response body | no | built from the service's response |
| `invalid_request` | matched on the response body | no | built from the service's response |

add-comment

**Comment on issue.** Add a Markdown comment to an issue. Returns the comment id and URL. Not idempotent.

Ref `io.b3os/linear/add-comment@1.0.0` · effect `write` · connection `api_key` · MCP tool `linear__add-comment`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/linear/add-comment@1",
          "input": {"id": "ENG-123", "body": "Fixed in #43."},
          "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/linear/add-comment@1",
      input: { id: "ENG-123", body: "Fixed in #43." },
      connections: { api_key: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    }, { idempotencyKey: crypto.randomUUID() });
    console.log(result.output);
    ```
  **Python**

```python
    import uuid
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/linear/add-comment@1",
        "input": {"id": "ENG-123", "body": "Fixed in #43."},
        "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    }, idempotency_key=str(uuid.uuid4()))
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {
        "name": "linear__add-comment",
        "arguments": {"id": "ENG-123", "body": "Fixed in #43."}
      }
    }
    ```

    Expose the pack as tools with `--packs linear` on the local server or `?packs=linear` on the remote URL, and the agent calls `linear__add-comment` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: Comment on issue (documented response shape, example values). From the bundle's `fixtures/add-comment.json`, not a live call.

```json
{
  "id": "1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
  "url": "https://linear.app/acme/issue/eng-123#comment-1b2c3d4e",
  "created_at": "2026-10-26T08:00:00.000Z"
}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `connection_unauthorized` | 401 | no | Linear rejected the API key or token. |
| `forbidden` | matched on the response body | no | built from the service's response |
| `rate_limited` | 429 | yes | Linear rate limit reached; retry shortly. |
| `not_found` | matched on the response body | no | built from the service's response |
| `invalid_request` | matched on the response body | no | built from the service's response |

list-projects

**List projects.** Projects in the workspace, most recently updated first: name, state (planned, started, completed, ...), progress from 0 to 1, lead, start and target dates, and URL.

Ref `io.b3os/linear/list-projects@1.0.0` · effect `read` · connection `api_key` · MCP tool `linear__list-projects`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/linear/list-projects@1",
          "input": {"first": 1},
          "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/linear/list-projects@1",
      input: { first: 1 },
      connections: { api_key: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    });
    console.log(result.output);
    ```
  **Python**

```python
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/linear/list-projects@1",
        "input": {"first": 1},
        "connections": {"api_key": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    })
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {"name": "linear__list-projects", "arguments": {"first": 1}}
    }
    ```

    Expose the pack as tools with `--packs linear` on the local server or `?packs=linear` on the remote URL, and the agent calls `linear__list-projects` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: List projects (documented response shape, example values). From the bundle's `fixtures/list-projects.json`, not a live call.

```json
{
  "projects": [
    {
      "id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
      "name": "Checkout v2",
      "state": "started",
      "progress": 0.42,
      "lead": "Mona Example",
      "start_date": "2026-09-01",
      "target_date": "2026-11-15",
      "url": "https://linear.app/acme/project/checkout-v2-2c3d4e5f"
    }
  ]
}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `connection_unauthorized` | 401 | no | Linear rejected the API key or token. |
| `forbidden` | matched on the response body | no | built from the service's response |
| `rate_limited` | 429 | yes | Linear rate limit reached; retry shortly. |
| `not_found` | matched on the response body | no | built from the service's response |
| `invalid_request` | matched on the response body | no | built from the service's response |