Metadata-Version: 2.4
Name: flowtask-sdk
Version: 0.5.1
Summary: Python SDK for the FlowTask visual task manager API
License: MIT
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.28.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"

# FlowTask Python SDK

A Python client for the FlowTask API — programmatically create projects, tasks, and dependency graphs.

## Install

```bash
pip install -e sdk/python
```

Or from the SDK directory:

```bash
cd sdk/python
pip install -e .
```

## Quick Start

```python
from flowtask import FlowTask

# Connect with your API token (create one in the FlowTask UI → Key icon → API Tokens)
ft = FlowTask(token="ft_your_token_here", base_url="http://localhost:3000")

# Create a project
project = ft.create_project("Sprint 1", color="#6366F1")

# Create tasks
design = project.create_task("Design System", color="#8B5CF6")
build = project.create_task("Build Components", color="#3B82F6")
test = project.create_task("Write Tests", color="#10B981")
deploy = project.create_task("Deploy", color="#EF4444")

# Create dependencies (diamond-shaped DAG)
build.add_dependency(design)   # Design must be done before Build
test.add_dependency(design)    # Design must be done before Test
deploy.add_dependency(build)   # Build must be done before Deploy
deploy.add_dependency(test)    # Test must be done before Deploy

# See what's actionable right now
for task in ft.actual_tasks():
    print(f"→ {task.title}")
# → Design System (the only task with no blockers)

# Complete a task and see what unblocks
design.complete()
for task in ft.actual_tasks():
    print(f"→ {task.title}")
# → Build Components
# → Write Tests
```

## API Reference

### FlowTask Client

```python
ft = FlowTask(token="ft_...", base_url="https://your-app.railway.app")
```

### Projects

```python
# List all projects
projects = ft.list_projects()

# Create a project
project = ft.create_project("Name", description="...", color="#6366F1")

# Load full project (tasks + dependencies)
tasks, dependencies = project.load()

# Update
project.update(name="New Name", color="#EF4444")

# Delete
project.delete()
```

### Tasks

```python
# Create a task in a project
task = project.create_task(
    "Task Title",
    description="Details...",
    color="#3B82F6",
    due_date="2026-04-01T00:00:00Z",
    assignee="Alice",
)

# Update fields
task.update(title="New Title", description="Updated")

# Change status
task.set_status("in_progress")  # or "pending", "completed"
task.complete()                  # shorthand for completed

# Delete
task.delete()
```

### Dependencies

```python
# Make task_b depend on task_a (task_a must be done first)
task_b.add_dependency(task_a)

# Or use the client directly
dep = ft.create_dependency(
    enabling_task_id=task_a.id,
    dependent_task_id=task_b.id
)

# Remove a dependency
ft.delete_dependency(dep.id)
```

### Tags

```python
# Create a tag
tag = ft.create_tag("frontend", color="#3B82F6")

# Assign to a task
task.add_tag(tag.id)

# Remove from a task
task.remove_tag(tag.id)

# List all tags
tags = ft.list_tags()
```

### Smart Features

```python
# Get actionable tasks (all dependencies completed)
actionable = ft.actual_tasks()
for task in actionable:
    print(f"[{task.project_id}] {task.title} — {task.status}")
```

## Error Handling

```python
from flowtask import FlowTask, CycleDetectedError, ValidationError, NotFoundError

ft = FlowTask(token="ft_...")

try:
    ft.create_dependency(task_a.id, task_b.id)
except CycleDetectedError as e:
    print(f"Would create a cycle: {e.message}")
except ValidationError as e:
    print(f"Invalid input: {e.message}")
except NotFoundError as e:
    print(f"Not found: {e.message}")
```

## Example: Import Tasks from CSV

```python
import csv
from flowtask import FlowTask

ft = FlowTask(token="ft_...", base_url="http://localhost:3000")
project = ft.create_project("Imported Project")

with open("tasks.csv") as f:
    for row in csv.DictReader(f):
        project.create_task(
            title=row["title"],
            description=row.get("description", ""),
            color=row.get("color"),
            due_date=row.get("due_date"),
        )
```

## Example: Daily Standup Report

```python
from flowtask import FlowTask

ft = FlowTask(token="ft_...", base_url="http://localhost:3000")

print("📋 What I can work on today:")
for task in ft.actual_tasks():
    due = f" (due {task.due_date[:10]})" if task.due_date else ""
    print(f"  → {task.title}{due}")
```
