Metadata-Version: 2.4
Name: tasksmind
Version: 0.2.0
Summary: TasksMind Python SDK — The AI Engineer for Developers on Call.
Project-URL: Homepage, https://tasksmind.com
Project-URL: Documentation, https://docs.tasksmind.com
Project-URL: Repository, https://github.com/tasksmind/tasksmind-python
Project-URL: Bug Tracker, https://github.com/tasksmind/tasksmind-python/issues
Author-email: TasksMind <support@tasksmind.com>
License: MIT
Keywords: ai,automation,devops,oncall,tasksmind
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Requires-Dist: httpx>=0.24.0
Description-Content-Type: text/markdown

# TasksMind Python SDK

The official Python client for [TasksMind](https://tasksmind.com) — the AI Engineer for developers on call.

TasksMind reviews pull requests, fixes CI failures, implements features, and analyzes bugs — triggered with a single API call from your terminal or code.

---

## Table of contents

- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Authentication](#authentication)
- [CLI quickstart](#cli-quickstart)
- [Python quickstart](#python-quickstart)
- [Intents — what TasksMind can do](#intents)
- [API reference](#api-reference)
- [Error handling](#error-handling)
- [Tips](#tips)

---

## Prerequisites

- Python 3.9 or later
- A TasksMind API key — sign up at [tasksmind.com](https://tasksmind.com) to get one

---

## Installation

```bash
pip install tasksmind
```

---

## Authentication

Every request requires an API key. The recommended way is an environment variable:

```bash
export TASKSMIND_API_KEY="tm_..."
```

The client picks it up automatically:

```python
from tasksmind import TasksMind

client = TasksMind()  # reads TASKSMIND_API_KEY
```

You can also pass it explicitly:

```python
client = TasksMind(api_key="tm_...")
```

---

## CLI quickstart

After installation the `tasksmind` command is available in your shell.

**Implement a feature**
```bash
tasksmind run "add a /health endpoint" \
  --repo https://github.com/my-org/my-repo
```

**Review a pull request**
```bash
tasksmind run "review this PR" \
  --repo https://github.com/my-org/my-repo \
  --intent review_pr \
  --pr 42
```

**Fix CI on a PR**
```bash
tasksmind run "fix the failing tests" \
  --repo https://github.com/my-org/my-repo \
  --intent fix_ci \
  --pr 42
```

**Root-cause an incident**
```bash
tasksmind run "why is the API returning 500s on /checkout" \
  --repo https://github.com/my-org/my-repo \
  --intent root_cause
```

**Fire-and-forget (don't wait for result)**
```bash
tasksmind run "summarize the codebase" \
  --repo https://github.com/my-org/my-repo \
  --intent summarize_repo \
  --no-wait
```

**Check on a run later**
```bash
tasksmind status <run-id>
tasksmind logs   <run-id>
```

**Skip `--repo` every time** — set it once as an env var:
```bash
export TASKSMIND_REPO="https://github.com/my-org/my-repo"
tasksmind run "add pagination to the /users endpoint"
```

Full flag reference:
```
tasksmind run --help
```

---

## Python quickstart

```python
import os
from tasksmind import TasksMind, AuthError, TimeoutError, APIError

client = TasksMind()  # reads TASKSMIND_API_KEY from environment

# 1. Start a run
run = client.runs.create(
    repo_url="https://github.com/my-org/my-repo",
    repo_ref="main",                              # branch, tag, or SHA
    payload={
        "intent": "review_pr",
        "target": {"pr_number": 42},
    },
)
print(f"Started: {run.id}  status={run.status}")

# 2. Wait for it to finish (polls every 2 s, times out after 10 min)
result = client.runs.wait(run.id, timeout_s=600)

# 3. Use the result
if result.is_success():
    print(result.output)          # full text output
    if result.pr_url:
        print(f"PR: {result.pr_url}")
else:
    print(f"Failed: {result.error}")
```

---

## Intents

Pass `intent` inside the `payload` dict when calling `runs.create`.

### `implement_feature` — write code and open a PR

```python
run = client.runs.create(
    repo_url="https://github.com/my-org/my-repo",
    payload={
        "intent": "implement_feature",
        "raw_text": "add rate limiting middleware to all API routes",
        "target":   {"feature": "add rate limiting middleware to all API routes"},
    },
)
result = client.runs.wait(run.id)
print(result.pr_url)   # e.g. https://github.com/my-org/my-repo/pull/99
```

### `review_pr` — code-review a pull request

```python
run = client.runs.create(
    repo_url="https://github.com/my-org/my-repo",
    payload={
        "intent": "review_pr",
        "target": {"pr_number": 42},
    },
)
result = client.runs.wait(run.id)
print(result.output)   # full review text
```

### `fix_ci` — analyse and explain CI failures on a PR

```python
run = client.runs.create(
    repo_url="https://github.com/my-org/my-repo",
    payload={
        "intent": "fix_ci",
        "target": {"pr_number": 42},
    },
)
result = client.runs.wait(run.id)
print(result.output)   # root-cause analysis + suggested fix
```

### `fix_bug` — investigate and fix a described bug

```python
run = client.runs.create(
    repo_url="https://github.com/my-org/my-repo",
    payload={
        "intent":   "fix_bug",
        "raw_text": "users can't log in after the latest deploy — JWT validation always fails",
    },
)
result = client.runs.wait(run.id)
print(result.output)
```

### `root_cause` — root-cause analysis for an incident

```python
run = client.runs.create(
    repo_url="https://github.com/my-org/my-repo",
    payload={
        "intent":   "root_cause",
        "raw_text": "payment service started throwing NullPointerException at checkout",
    },
)
result = client.runs.wait(run.id)
print(result.output)
```

### `summarize_repo` — explain a codebase

```python
run = client.runs.create(
    repo_url="https://github.com/my-org/my-repo",
    payload={"intent": "summarize_repo"},
)
result = client.runs.wait(run.id)
print(result.output)
```

### `status_pr` — PR status and CI check summary

```python
run = client.runs.create(
    repo_url="https://github.com/my-org/my-repo",
    payload={
        "intent": "status_pr",
        "target": {"pr_number": 42},
    },
)
result = client.runs.wait(run.id)
print(result.output)
```

### `changes_pr` — plain-English description of what a PR changes

```python
run = client.runs.create(
    repo_url="https://github.com/my-org/my-repo",
    payload={
        "intent": "changes_pr",
        "target": {"pr_number": 42},
    },
)
result = client.runs.wait(run.id)
print(result.output)
```

---

## API reference

### `TasksMind(api_key, *, base_url, timeout)`

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `api_key` | `str` | `$TASKSMIND_API_KEY` | Your API key (required) |
| `base_url` | `str` | `https://api.tasksmind.com` | Override API base URL |
| `timeout` | `float` | `60.0` | HTTP request timeout in seconds |

---

### `client.runs.create(repo_url, repo_ref, payload)`

Start a new run. Returns immediately with a `Run` object.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `repo_url` | `str` | — | Full GitHub repo URL |
| `repo_ref` | `str` | `"main"` | Branch, tag, or commit SHA |
| `payload`  | `dict` | `{}` | Intent and target (see [Intents](#intents)) |

**`payload` fields**

| Field | Type | Description |
|-------|------|-------------|
| `intent` | `str` | One of the intent names above (default: `"implement_feature"`) |
| `raw_text` | `str` | Free-text description of the task |
| `target` | `dict` | Intent-specific context, e.g. `{"pr_number": 42}` |

---

### `client.runs.get(run_id)`

Fetch the latest state of a run by its ID.

```python
run = client.runs.get("550e8400-e29b-41d4-a716-446655440000")
print(run.status, run.output)
```

---

### `client.runs.list(limit, offset, status)`

List runs for your account.

```python
runs = client.runs.list(limit=10)
for r in runs:
    print(r.id, r.status)

# filter by status
completed = client.runs.list(status="completed")
```

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `limit`  | `int` | `20` | Max results (1–100) |
| `offset` | `int` | `0`  | Pagination offset |
| `status` | `str` | `None` | Filter by status string |

---

### `client.runs.wait(run_id, *, timeout_s, poll_s)`

Poll until the run reaches a terminal status, then return it.

```python
result = client.runs.wait(run.id, timeout_s=300, poll_s=3)
```

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `timeout_s` | `float` | `600.0` | Max seconds to wait before raising `TimeoutError` |
| `poll_s`    | `float` | `2.0`   | Seconds between poll requests |

---

### `Run` object

| Attribute | Type | Description |
|-----------|------|-------------|
| `.id` | `str` | Run UUID |
| `.status` | `str` | `queued` · `running` · `completed` · `failed` · `error` · `cancelled` |
| `.output` | `str` | Full text output from the run |
| `.summary` | `str \| None` | Short AI-generated summary |
| `.pr_url` | `str \| None` | Pull request URL (when a PR was created) |
| `.pr_number` | `int \| None` | Pull request number |
| `.error` | `str \| None` | Error message when status is `failed` or `error` |
| `.is_success()` | `bool` | `True` when status is `completed` or `succeeded` |

---

## Error handling

```python
from tasksmind import (
    TasksMind,
    AuthError,       # 401 / 403 — bad or missing API key
    NotFoundError,   # 404 — run ID doesn't exist
    RateLimitError,  # 429 — slow down
    APIError,        # any other 4xx / 5xx
    TimeoutError,    # runs.wait() exceeded timeout_s
)

client = TasksMind()

try:
    run = client.runs.create(
        repo_url="https://github.com/my-org/my-repo",
        payload={"intent": "review_pr", "target": {"pr_number": 42}},
    )
    result = client.runs.wait(run.id, timeout_s=300)

    if result.is_success():
        print(result.output)
    else:
        print(f"Run failed: {result.error}")

except AuthError:
    print("Invalid API key — check TASKSMIND_API_KEY")
except NotFoundError:
    print("Run not found")
except RateLimitError:
    print("Rate limited — back off and retry")
except TimeoutError:
    print("Timed out waiting for result")
except APIError as e:
    print(f"API error {e.status_code}: {e.body}")
```

All exceptions inherit from `TasksMindError`:

```
TasksMindError
├── AuthError
├── NotFoundError
├── RateLimitError
├── APIError
└── TimeoutError
```

---

## Tips

**Use a context manager** to ensure the HTTP connection is closed:
```python
with TasksMind() as client:
    result = client.runs.wait(
        client.runs.create(
            repo_url="https://github.com/my-org/my-repo",
            payload={"intent": "summarize_repo"},
        ).id
    )
    print(result.output)
```

**Set a default repo** so you don't repeat `--repo` on every CLI call:
```bash
export TASKSMIND_REPO="https://github.com/my-org/my-repo"
tasksmind run "add a /metrics endpoint"
```

**Fire-and-forget** then check back later:
```python
run = client.runs.create(
    repo_url="https://github.com/my-org/my-repo",
    payload={"intent": "implement_feature", "raw_text": "add dark mode"},
)
print(f"Queued: {run.id}")
# ... later ...
result = client.runs.get(run.id)
print(result.status)
```

**Target a specific branch or commit**:
```python
run = client.runs.create(
    repo_url="https://github.com/my-org/my-repo",
    repo_ref="feat/my-branch",   # or a full commit SHA
    payload={"intent": "review_pr", "target": {"pr_number": 55}},
)
```

---

## Requirements

- Python ≥ 3.9
- [`httpx`](https://www.python-httpx.org/) ≥ 0.24 (installed automatically)

---

## Links

- [Website](https://tasksmind.com)
- [PyPI](https://pypi.org/project/tasksmind/)
- [Report an issue](https://github.com/tasksmind/tasksmind-python/issues)
