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

# Python SDK

> Use ticket-rs from Python with native bindings

The `ticket-py` package provides native Python bindings to ticket-rs, giving you full access to issue management and graph analytics from Python code.

Every visible `tk` subcommand has a typed Python wrapper, generated from the same `clap::Command` tree the binary parses against — so the Python surface stays in lockstep with the CLI by construction. Calls go through an in-process PyO3 FFI; no subprocess is spawned.

***

## Installation

<Tabs>
  <Tab title="Installer Script (Recommended)">
    The official installer downloads pre-built wheels for your platform:

    ```bash theme={null}
    curl -fsSL https://ticket-rs.io/install.sh | sh -s -- --pkgs=py
    ```

    This creates an isolated virtual environment at `~/.ticket/.venv` with:

    * Auto-detected Python version (3.9-3.13)
    * Pre-built wheel for your platform (no compilation needed)
    * Managed by [uv](https://docs.astral.sh/uv/) for fast installs

    <Tip>
      Install both Python bindings and MCP server together:

      ```bash theme={null}
      curl -fsSL https://ticket-rs.io/install.sh | sh -s -- --pkgs=py,mcp
      ```
    </Tip>
  </Tab>

  <Tab title="uv">
    ```bash theme={null}
    uv pip install ticket-py
    ```

    <Note>
      Requires building from source. For pre-built wheels, use the installer script.
    </Note>
  </Tab>

  <Tab title="pip">
    ```bash theme={null}
    pip install ticket-py
    ```

    <Note>
      Requires building from source. For pre-built wheels, use the installer script.
    </Note>
  </Tab>
</Tabs>

### Activating the Environment

If you used the installer script, activate the environment:

```bash theme={null}
source ~/.ticket/.venv/bin/activate
```

Or run directly without activation:

```bash theme={null}
~/.ticket/.venv/bin/python -c "import ticket_py; print(ticket_py.dispatch(['--version']).strip())"
```

***

## Quick Start

```python theme={null}
import ticket_py

# Every visible `tk` subcommand is a top-level function.
# Pass kwargs the same way you'd pass flags on the CLI.

# Initialise a tickets directory
ticket_py.init(dir="/path/to/your/project")

# Get issues ready to work on (no open blockers)
ready = ticket_py.ready(dir="/path/to/your/project", format="json")
for issue in ready:
    print(f"{issue['id']}: {issue['title']}")

# Get repository statistics
stats = ticket_py.stats(dir="/path/to/your/project", format="json")
print(f"Open: {stats['open']}  Closed: {stats['closed']}  Ready: {stats['ready']}")
```

***

## API Reference

`ticket_py` exposes three categories of API:

1. **76 typed wrappers** — one per visible `tk` subcommand. Type hints come from `clap`.
2. **`dispatch(argv)`** — raw escape hatch for any command, including hidden ones.
3. **`command_spec()`** — introspect the CLI surface as a nested dict.

### Typed wrappers

Each wrapper takes the command's flags as keyword arguments (kebab-case becomes snake\_case: `--dry-run` → `dry_run`), plus the global flags `dir`, `format`, `json`, and `strict`.

Return value depends on `format`:

* `format="json"` → parsed JSON (`list` / `dict`)
* omitted or any other value → the raw stdout string

```python theme={null}
import ticket_py

# Core issue management
ticket_py.create(title="Fix the bug", priority=1, format="json")
issue = ticket_py.show(id="tk-abc123", format="json")
ticket_py.update(id="tk-abc123", status="in_progress")
ticket_py.close(id="tk-abc123", reason="fixed")
issues = ticket_py.list(format="json")

# Dependencies (nested commands become snake_case)
ticket_py.dep_add(blocked="tk-1", blocker="tk-2")
ticket_py.dep_tree(id="tk-1")

# AI/analytics
triage = ticket_py.triage(format="json")
priority = ticket_py.priority(format="json")
plan = ticket_py.plan(format="json")
next_pick = ticket_py.next(format="json")

# Reserved word `type` becomes `type_`
ticket_py.create(title="Fix bug", type_="bug", priority=1)
```

The full surface includes every visible `tk` command — `linear_sync`, `github_sync`, `claude_sync`, `worktree`, `stacks`, `insights`, `search`, `similar`, `validate`, `lint`, and more. Discover them at runtime:

```python theme={null}
import ticket_py
print(sorted(ticket_py.typed_api.__all__))
```

### `dispatch(argv)`

Raw escape hatch for any command. Same in-process PyO3 path; you build the argv yourself.

```python theme={null}
import ticket_py
import json

# Equivalent to `tk list --format json -C /path/to/repo`
out = ticket_py.dispatch(["list", "--format", "json", "-C", "/path/to/repo"])

# Returns the raw stdout string. Parse it yourself.
issues = json.loads(out)
```

### `command_spec()`

Introspect the CLI surface as a nested dict — useful for building meta-tools, generating other typed bindings, or discovering commands and their flags programmatically.

```python theme={null}
import ticket_py

spec = ticket_py.command_spec()
# spec = { "name": "tk", "subcommands": [...], "global_args": [...] }

# List every visible top-level command
for cmd in spec["subcommands"]:
    if not cmd["hidden"]:
        print(cmd["name"], "—", cmd.get("about", ""))
```

***

## Error handling

Errors split into two distinct classes:

| Exception      | Cause                                                                                                    |
| -------------- | -------------------------------------------------------------------------------------------------------- |
| `ValueError`   | argv didn't parse (unknown subcommand, bad flag, missing required positional). Fix the call.             |
| `RuntimeError` | argv parsed fine but the command itself failed (issue not found, parse error, etc.). The system refused. |

```python theme={null}
import ticket_py

try:
    ticket_py.show(id="tk-doesnotexist")
except RuntimeError as e:
    # The command ran but failed — issue doesn't exist
    print(f"command failed: {e}")
except ValueError as e:
    # You mis-typed the call — bad flag, missing arg, etc.
    print(f"bad call: {e}")
```

***

## Return shapes

When you pass `format="json"`, wrappers return parsed JSON. The shape mirrors what `tk <command> --format json` emits on the CLI:

```python theme={null}
# list(format="json") → list of dicts
[
    {"id": "tk-abc", "title": "Fix bug", "status": "open", "priority": 1},
]

# triage(format="json") → dict with nested structure
{
    "quick_ref": {"total": 42, "open": 18, "ready": 5},
    "recommendations": [{"id": "tk-abc", "score": 87.5, "reason": "..."}],
    "quick_wins": [],
    "blockers_to_clear": [],
}

# stats(format="json") → flat counts
{"total": 42, "open": 18, "in_progress": 3, "blocked": 2, "closed": 19, "ready": 5}
```

For the exact shape of each command's JSON, run `tk <command> --format json` once and inspect.

***

## Examples

### Find high-priority ready issues

```python theme={null}
import ticket_py

ready = ticket_py.ready(format="json")
high_priority = [i for i in ready if i["priority"] <= 1]

for issue in high_priority:
    print(f"[P{issue['priority']}] {issue['id']}: {issue['title']}")
```

### Batch create issues

```python theme={null}
import ticket_py

tasks = [
    ("Set up CI/CD", "task", 1),
    ("Write documentation", "task", 2),
    ("Add unit tests", "task", 2),
]

for title, type_, priority in tasks:
    out = ticket_py.create(
        title=title,
        type_=type_,
        priority=priority,
        format="json",
    )
    print(f"Created: {out['id']}")
```

### Export issues to JSON

```python theme={null}
import json
import ticket_py

issues = ticket_py.list(format="json")
data = [
    {
        "id": i["id"],
        "title": i["title"],
        "status": i["status"],
        "priority": i["priority"],
    }
    for i in issues
]

with open("issues.json", "w") as f:
    json.dump(data, f, indent=2)
```

### Integration with pandas

```python theme={null}
import pandas as pd
import ticket_py

issues = ticket_py.list(format="json")
df = pd.DataFrame(issues)

# Analyse by status
print(df.groupby("status").size())

# Find issues with most dependencies
df["deps_count"] = df["deps"].apply(len)
print(df.nlargest(5, "deps_count")[["id", "title", "deps_count"]])
```

***

## Platform Support

Pre-built wheels are available for:

| Platform | Architectures                          | Python Versions |
| -------- | -------------------------------------- | --------------- |
| Linux    | x86\_64, aarch64                       | 3.9 - 3.13      |
| macOS    | x86\_64 (Intel), arm64 (Apple Silicon) | 3.9 - 3.13      |
| Windows  | x86\_64                                | 3.9 - 3.13      |

<Note>
  If no pre-built wheel exists for your platform/Python version, installation will build from source (requires Rust toolchain).
</Note>

***

## Environment Variables

| Variable           | Description                       | Default     |
| ------------------ | --------------------------------- | ----------- |
| `TICKET_HOME`      | Location for the installer's venv | `~/.ticket` |
| `TK_WHEEL_VERSION` | Wheel version to install          | `0.0.1`     |

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="ImportError: No module named 'ticket_py'">
    Make sure you've activated the virtual environment:

    ```bash theme={null}
    source ~/.ticket/.venv/bin/activate
    ```

    Or reinstall:

    ```bash theme={null}
    curl -fsSL https://ticket-rs.io/install.sh | sh -s -- --pkgs=py
    ```
  </Accordion>

  <Accordion title="ImportError: cannot import name 'Ticket' / 'list_issues' / ...">
    In recent releases, the hand-written `Ticket` pyclass and the
    nine hand-written wrapper functions (`list_issues`, `ready_issues`,
    `show_issue`, `create_issue`, `update_issue`, `search_issues`,
    `find_similar_issues`, `version`) were replaced with a typed\_api
    generated from the CLI's `clap` surface.

    ```python theme={null}
    # Before (removed)
    ticket_py.list_issues()
    ticket_py.create_issue(title="Fix bug", priority=1)

    # After
    ticket_py.list(format="json")
    ticket_py.create(title="Fix bug", priority=1, format="json")
    ```

    See the API Reference above; or `ticket_py.dispatch(["list", "-f", "json"])` for the raw escape hatch.
  </Accordion>

  <Accordion title="Build fails during pip install">
    The package contains native Rust code. If no pre-built wheel exists for your platform, you'll need:

    1. Rust toolchain: `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`
    2. Python development headers

    Or use the installer script which downloads pre-built wheels.
  </Accordion>

  <Accordion title="Wrong Python version">
    The installer auto-detects your Python version. To use a specific version:

    ```bash theme={null}
    # Set Python version before running installer
    export PATH="/path/to/python3.12/bin:$PATH"
    curl -fsSL https://ticket-rs.io/install.sh | sh -s -- --pkgs=py
    ```
  </Accordion>
</AccordionGroup>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="MCP Server" icon="plug" href="/integrations/mcp">
    Use ticket-mcp for AI agent integration.
  </Card>

  <Card title="CLI Reference" icon="terminal" href="/cli-reference/commands">
    Full command documentation.
  </Card>
</CardGroup>
