Skip to main content
Glama
README.md
# tasq

A local-first task manager, exposed as a **CLI**, an interactive **TUI**, and a
local **MCP server**, backed by a single SQLite file. Built with Python, uv,
Typer, Textual, and the MCP SDK.

See [`spec.md`](./spec.md) for the original design and rationale.

## What it does

tasq keeps your work in one SQLite file on your machine — no account, no server,
no sync — and lets you drive it three ways over the **same** engine: type commands
(`tasq …`), scroll an interactive board (`tasq ui`), or let an AI assistant manage
tasks through the built-in MCP server. Anything you do one way is immediately
visible in the others.

**The mental model.** A **task** has a title, a status, a priority (P1–P5), an
optional t-shirt **size** (XS–XL, used for effort estimates), optional
**scheduled** (start) and **due** dates, a markdown **description**, and any number
of **labels**. Tasks can be grouped under a **project** and broken into one level
of **sub-tasks**. Every status change is recorded as an **auditable history** —
you can always see when and why a task moved, not just where it is now.

**What you can do with it:**

- **Capture & organise** — add tasks with priority, size, dates, labels, and
  rich descriptions; group them by project; break them into sub-tasks.
- **Track a lifecycle** — move tasks through *waiting → in-progress → blocked →
  done/cancelled*, each transition logged with an optional comment.
- **See what's next** — an **agenda** (overdue + today + upcoming) with effort
  estimates, and a proposed day-by-day **plan** that packs open work into your
  daily focus budget over working days (weekends skipped) — a suggestion, never
  written back to a task. Export the plan as an HTML report.
- **Find things** — fuzzy search across titles/descriptions (typos are fine), and
  a **references** view that pulls URLs (PRs, JIRAs, docs) out of descriptions so
  you can jump straight to them.
- **Work interactively** — a full-screen board (`tasq ui`) to scroll, quick-edit
  priority/size/status, create/schedule/delete tasks, open references, and view
  the plan — all with the keyboard.
- **Hand off to (and resume) AI agents** — link a task to the AI coding session
  you worked on it in (agent, directory, session id, launcher/profile), then
  **resume** or **start** that session in a new iTerm2 tab — a fresh session is
  primed with a task briefing so the agent self-manages via tasq. Configurable
  launchers and project directories make this a one-key action.
- **Be legible to an AI** — the MCP server exposes every capability as a tool, and
  labels carry human-written descriptions so an assistant acts on intent, not
  guesswork.

Nothing leaves your machine: it's a single local SQLite file (WAL + FTS5), and the
CLI, TUI, and MCP server are thin adapters over one shared core.

## Quickstart

Install with [uv](https://docs.astral.sh/uv/):

```bash
uv sync
uv run tasq --help            # or symlink the ./tasq wrapper onto your PATH
```

**See it populated in seconds** — seed a throwaway demo database (it never touches
your real tasks) and open the board:

```bash
uv run tasq demo --ui         # seeds a demo.db and opens `tasq ui`
# …or explore piece by piece:
tasq demo                     # prints the exact commands to try (agenda, plan, …)
```

**Start using it for real:**

```bash
tasq add "Write the launch post" -p blog --priority 2 --due 2026-08-20
tasq ui                       # your board (1-5 = priority · n = new · ! = flag · a = agent)
```

**Wire it into your AI assistant** — register the MCP server (see
[Claude Code](#claude-code) / [GitHub Copilot](#github-copilot-vs-code) below) and your
agent can capture, plan, and flag tasks just like you do. Then follow the
**[AI workflow walkthrough](docs/ai-workflow.md)** for the full loop: start a task in an
agent → it links its session and pings you when it needs a decision → you answer →
resume where it left off.

## Install / run

```bash
uv sync                       # install dependencies
uv run tasq --help               # the `tasq` (and short `tq`) command
```

The database lives at `$XDG_DATA_HOME/tasq/tasks.db` by default. Override with
`--db PATH` or the `TASQ_DB` environment variable.

## CLI tour

```bash
# Capture
tasq add "Write the spec" -p acme --priority 2 --size M --due 2026-07-25 \
    -l writing --desc "See [design](https://figma.com/f/abc) and https://github.com/acme/repo"

# Missing dates are guessed: start = next working day, due = a few business days later
tasq add "Follow up with infra"   # e.g. start 2026-07-31 · due 2026-08-07
tasq add "Someday idea" --no-guess-dates   # leave both dates unset

# See what's next
tasq agenda --days 5              # overdue + today + upcoming, with effort estimates
tasq today
tasq overdue

# Get a proposed day-by-day schedule — a suggestion, never written back to tasks
tasq plan                        # packs open tasks into 5h/day over 5 working days
tasq plan --days 10 --hours 6    # 10 working days at 6 focus-hours/day
tasq plan --weekends             # include Sat/Sun (excluded by default)
tasq plan -o html --browser      # write an HTML report and open it in the browser
tasq plan -o html --out plan.html  # …or just write it to a specific file
tasq plan -p Work -p IGM         # limit planning to certain projects
tasq plan -L personal            # keep private (labelled) tasks out of the plan

# Interactive board: scroll the task list and quick-edit with the keyboard
tasq ui                          # 1-5 = priority · shift+←/→ = size · s/b/d = start/block/done
                                 # n = new task · t = set start date · o = open refs in browser
                                 # / = fuzzy find · ! = flag for attention · p = project filter · v = plan view
                                 # a = start in an AI agent · x = delete
                                 # L = references view (u = unique · / = search · b = open as HTML)
                                 # r = reload · R = resume in iTerm
                                 # enter = edit (shows clickable refs + AI session, has Delete)
                                 # ⟳ = linked AI session (resumable) · ⚠ = needs attention (rings a bell)
                                 # auto-refreshes every 5s (configurable), so agent/CLI changes just appear

# Open a task's reference URLs (PRs, JIRAs, …) in the browser
tasq open 2                      # opens every URL extracted from task #2's description
tasq refs open 5                 # …or open a single extracted reference by its ref-id

# Link a task to the AI session you're working in, so it can be resumed later
tasq link 2 -a claude-code -d . -s <session-id> -c claude-work
                                 # -c is the command/alias you launched with (selects a profile)
tasq unlink 2                    # drop the session link

# Start a task in an AI agent — new iTerm2 tab, primed with a task briefing (macOS)
tasq work 2                      # prompts for a project dir + launcher, opens a briefed session
tasq work 2 -D igm               # start in the 'igm' project dir (its default launcher)
tasq work 2 -D igm -l claude-work    # …and pick one of that dir's allowed launchers
tasq work 2 --resume             # resume a session instead of a new briefed one
tasq work 2 -D igm --print       # print the launch command instead of opening iTerm

# Resume a linked session — opens a new iTerm2 tab, cds in, and runs the agent (macOS)
tasq resume 2                    # e.g. `cd <dir> && claude-work --resume <session-id>`
tasq resume 2 --print            # just print the command (no iTerm), for other terminals

# Break a task into sub-tasks (one level deep; they show in list/agenda too)
tasq add "Write migration" --parent 1 --priority 1
tasq subtasks 1                  # list a task's sub-tasks
tasq edit 3 --no-parent          # promote a sub-task back to top-level
tasq list --top-level            # hide sub-tasks from the flat list

# Flag a task as awaiting your attention (an AI agent can do this via MCP)
tasq flag 3 -m "which auth provider — okta or auth0?"   # stands out + rings a bell in the UI
tasq list --attention            # everything currently flagged
tasq unflag 3                    # clear it once you've answered

# Move it through its lifecycle (comment optional, recorded either way)
tasq start 1 -m "picking this up"
tasq block 1 -m "waiting on backend"
tasq done  1
tasq history 1

# Find things (fuzzy — typos are fine)
tasq search "lgin bug"
tasq refs                        # every extracted URL (PRs, JIRAs), newest first
tasq refs --unique               # collapse duplicate URLs → one row per link + task count
tasq refs -o html --browser      # write an HTML report of the references and open it
tasq refs github                 # …or fuzzy-search them
tasq refs open 2                 # open a matched URL

# Projects & labels (labels carry AI-facing descriptions)
tasq project add acme -l globex-corp
tasq label describe deep-work --desc "Requires 2h+ focus; schedule in the morning"
tasq label list

# Pull work in from external sources (PRs to review, JIRAs, emails), deduplicated
tasq fetch reviews --org acme        # PRs awaiting your review (via `gh`) → tasks, deduped
tasq fetch reviews --user octocat --print   # …or just print the ingest JSON
your-fetcher | tasq ingest --source jira     # any fetcher: upsert JSON by (source, external_id)
tasq list --source github-reviews            # what's been synced
# re-running never duplicates; see docs/ingestion.md for the item schema + example fetchers

# Machine-readable output for any query command
tasq list --status waiting,blocked --json
```

## Configuration

Planning and effort estimates are tunable via an optional TOML file at
`$XDG_CONFIG_HOME/tasq/config.toml` (override with `TASQ_CONFIG`). Everything has a
default, so the file is optional. `TASQ_DAILY_HOURS` overrides the daily budget for
a single run, and `tasq plan --hours N` overrides it per-invocation.

```toml
[planning]
daily_hours = 5          # focus hours/day for `plan`; the rest is meetings/overhead
include_weekends = false # plan Mon–Fri only (override per-run with --weekends)
projects = []            # only plan these projects (empty = all); overridable with -p
labels = []              # only plan tasks carrying one of these labels
exclude_labels = ["personal"]  # keep private work out of the plan (override with -L)

[effort]
unsized_hours = 2        # assumed effort for a task with no size

[effort.size_hours]      # hours per t-shirt size (drives estimates and `plan`)
XS = 0.5
S = 1
M = 2
L = 4
XL = 8

[add]
guess_dates = true       # fill missing start/due when adding (override with --no-guess-dates)
due_business_days = 5    # due lands this many working days after the start date

[ui]
refresh_seconds = 5      # how often `tasq ui` polls for changes (0 disables auto-refresh)

[agents.launchers]       # commands/aliases for `tasq work` (each alias can be a profile)
claude = "claude-code"
claude-work = "claude-code"
copilot = "github-copilot-cli"

# Big-project directories agents can be started in (one table per project).
# `launchers` (defaults to all) restricts what's allowed there; `default` (defaults
# to the first) is preselected. `name` defaults to the path's basename.
[[agents.project_dirs]]
name = "igm"
path = "/Users/me/IGT/Azure/repos/igm"
launchers = ["copilot", "claude-work"]
default = "copilot"

# Customise the briefing that primes a fresh `tasq work` session. Placeholders
# $id, $title, $description are filled in (use ${id} next to letters). Optional —
# omit to use the built-in briefing.
[agents]
prompt_template = """
Work on tasq task #$id: $title.
$description

Link this session to task #$id in tasq, mark it in_progress, ask me for context,
and record any relevant PR / JIRA / repo URLs as you go.
"""
```

## MCP server

Run the server over stdio:

```bash
tasq serve
```

Register it with an MCP client (e.g. Claude Desktop):

```json
{
  "mcpServers": {
    "tasq": { "command": "uvx", "args": ["tasq", "serve"] }
  }
}
```

> The examples below use `uvx tasq serve`, which works once the package is
> published. To run from a local checkout instead, use
> `uv` with `--directory`, e.g.
> `"command": "uv", "args": ["run", "--directory", "/path/to/tasq", "tasq", "serve"]`.
> Point at a specific database with the `TASQ_DB` env var if you don't want the default.

### Claude Code

Add it from the terminal (project-scoped):

```bash
claude mcp add tasq -- uvx tasq serve
```

…or commit a `.mcp.json` at the repository root so the whole team gets it:

```json
{
  "mcpServers": {
    "tasq": {
      "command": "uvx",
      "args": ["tasq", "serve"],
      "env": { "TASQ_DB": "${HOME}/.local/share/tasq/tasks.db" }
    }
  }
}
```

### GitHub Copilot (VS Code)

Copilot's agent mode reads MCP servers from `.vscode/mcp.json` (note the
top-level `servers` key and the `type` field):

```json
{
  "servers": {
    "tasq": {
      "type": "stdio",
      "command": "uvx",
      "args": ["tasq", "serve"],
      "env": { "TASQ_DB": "${env:HOME}/.local/share/tasq/tasks.db" }
    }
  }
}
```

Then open the Copilot Chat **Agent** view and enable the `tasq` tools. (User-level
config lives under `"mcp": { "servers": { … } }` in VS Code `settings.json`.)

It exposes tools (`add_task`, `edit_task`, `get_task`, `list_tasks`,
`search_tasks`, `search_references`, `transition_task`, `flag_attention`,
`clear_attention`, `link_session`, `unlink_session`, `ingest`, `agenda`, `plan`,
project/label management) and resources
(`task://{id}`, `agenda://today`, `agenda://upcoming`, `labels://`). Labels are
surfaced **with their descriptions**, so an assistant knows what each means and
when to apply it. The agent has full read/write access.

**Linking a session:** `link_session(task_id, agent, directory, session_id, launcher)`
records which AI CLI worked on a task, where, under which session id, and with
which command/alias (so a resume can pick the right profile). Ask the agent to
"link this session to task #N" and it stores the details for later resumption.

**Asking for your attention:** when an agent needs a decision or input, it calls
`flag_attention(task_id, note)`. The task then stands out (a `⚠` row) and rings a
bell in your open board — which auto-refreshes — so you notice without watching the
terminal. `clear_attention(task_id)` removes the flag once you've responded.

## Documentation

- **[AI workflow walkthrough](docs/ai-workflow.md)** — the full loop: start a task in
  an agent, get pinged when it needs a decision, and resume where it left off.
- **[Ingesting external tasks](docs/ingestion.md)** — pull in PRs/JIRAs/emails as
  deduplicated tasks (the item schema, upsert semantics, and example fetchers).
- **[spec.md](./spec.md)** — the original design and rationale (historical: it predates
  the TUI and the AI-session features, which have since shipped).
- Try `tasq demo` for a populated database to explore hands-on.

## Architecture

The CLI and MCP server are thin adapters over a shared core:

```
tasq.cli  ─┐
           ├─▶ tasq.services.Core ─▶ tasq.repository ─▶ SQLite
tasq.mcp  ─┘        (use cases)         (typed rows)
```

- `models.py` — enums + frozen, fully-typed dataclasses (the domain objects).
- `repository.py` — the only place that touches `sqlite3` rows.
- `services.py` — use cases, transactions, and domain rules.
- `references.py` / `search.py` — URL extraction and fuzzy (FTS5 + rapidfuzz) search.
- `serialize.py` — one shared dict shape for CLI `--json` and MCP output.

## Development

```bash
uv run pytest        # tests
uv run mypy          # strict type checking
uv run ruff check .  # lint
uv run ruff format . # format
```

TDQS

B3.4/5.0

Scored across 19 tools

Disambiguation5/5

Each tool targets a distinct resource and action: tasks, projects, labels, sessions, attention flags, and bulk ingestion. Overlap is minimal, and descriptions clearly distinguish search_tasks from search_references and agenda from plan.

Naming Consistency4/5

Most tools follow a clear verb_noun pattern (add_task, list_tasks, edit_task, link_session). A few exceptions like 'ingest', 'agenda', and 'plan' deviate from this pattern but remain readable and predictable.

Tool Count5/5

With 19 tools covering task CRUD, status transitions, projects, labels, sessions, and planning, the count is well-scoped for the server's purpose. It is neither overly sparse nor bloated.

Completeness4/5

The surface covers most lifecycle needs: create/read/update/transition tasks, manage projects and labels, link sessions, and flag attention. Minor gaps exist, such as no hard delete for tasks and no session listing, but these are workable.