Metadata-Version: 2.4
Name: cctodo
Version: 0.2.0
Summary: Command line tool and Python client for ccToDo (www.cctodo.com)
Author-email: CloudCircus <support@cctodo.com>
License-Expression: MIT
Project-URL: Homepage, https://www.cctodo.com/
Project-URL: Source, https://github.com/RubenNorgaard/cctodo_py
Keywords: todo,tasks,cli,cctodo
Classifier: Environment :: Console
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Office/Business :: Scheduling
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# cctodo

The command line tool and Python client for [ccToDo](https://www.cctodo.com/), made by CloudCircus.

```sh
pip install cctodo
cctodo login          # paste a token from Settings → API tokens
cctodo mytasks
cctodo new -group "work group" "my task"
cctodo done 123
```

It uses only the Python standard library and needs Python 3.9 or newer.

## Commands

Tasks are shown with their id (`#123`), and the commands take that id. Where a command takes a group,
you can give its id, its title, or the start of the title (case-insensitive). Without `-g`, commands
use your **My Tasks**.

A **milestone** is a goal with a target date that tasks in the same group can belong to (one milestone per task).
It's reached when it has no pending tasks and every milestone before it is reached. Give a milestone by its id, or
by its title (or the start of it) together with `-g GROUP`.

| Command | What it does |
|---|---|
| `cctodo mytasks` (`my`) | Your pending My Tasks. `-c` shows completed tasks instead. |
| `cctodo list [GROUP]` (`ls`) | A group's pending tasks. `--all` lists every group, `-c` shows completed tasks. |
| `cctodo assigned` | Pending tasks assigned to you, in all groups. |
| `cctodo groups` | Your groups, with their pending counts. |
| `cctodo new TITLE… [-g GROUP] [-a WHO] [-b BODY] [-e]` (`add`) | Adds a task at the bottom of the list. `-b -` reads the details from stdin; `-e` writes the title and details in `$EDITOR`. |
| `cctodo show ID` | A task with its details (markdown) and comments. |
| `cctodo done ID…` / `start ID…` / `reopen ID…` | Sets the state to done, in progress, or to do. |
| `cctodo edit ID [-t TITLE] [-b BODY]` | Edits a task. With no options it opens `$EDITOR`: the first line is the title and the rest is the details. It refuses to overwrite someone else's newer edit. |
| `cctodo assign ID WHO` | Assigns to `me`, a member's email, or `none`. |
| `cctodo mv ID -g GROUP` / `mv ID --before ID2` / `--after ID2` | Moves a task to another group, or reorders it. |
| `cctodo rm ID… [-y]` | Deletes tasks after asking you to confirm. |
| `cctodo comment ID TEXT… [-r COMMENT_ID]` | Adds a comment, or a reply with `-r`. |
| `cctodo milestones [GROUP]` (`ms`) | A group's milestones in order of target date: reached `[x]`, next `[>]`, overdue `[!]`, with task counts. |
| `cctodo milestone new TITLE… -d YYYY-MM-DD [-g GROUP] [-b DESCRIPTION]` | Adds a milestone. |
| `cctodo milestone show/edit/rm MILESTONE` | Shows a milestone with its tasks, changes it (`-t`, `-d`, `-b`, or `$EDITOR`), or deletes it (its tasks stay). |
| `cctodo milestone link MILESTONE TASK_ID…` / `unlink TASK_ID…` | Puts tasks in a milestone, or takes them out. `new -m MILESTONE` and `edit ID -m MILESTONE` (or `-m none`) do the same for one task. |
| `cctodo group new/rename/members/leave/rm` | Manages groups. |
| `cctodo invite GROUP EMAIL [-m MESSAGE]` | Invites someone. If you're a member rather than an owner, an owner approves the invite first. |
| `cctodo invites` / `accept ID` / `decline ID` | Lists and answers invites addressed to you. |
| `cctodo whoami` / `logout` | Shows the account you're logged in as, or forgets the saved token. |

Add `--json` to any command for the raw API output. `NO_COLOR` turns colours off.

**Exit codes:**
- `0`: the command succeeded.
- `1`: an error occurred.
- `3`: you're not logged in, or your token was revoked.

## Configuration

`cctodo login` saves the token in `~/.config/cctodo/config.json`, readable only by you
(`%APPDATA%\cctodo\config.json` on Windows). You can set these environment variables instead:

- `CCTODO_TOKEN`: the API token.
- `CCTODO_API_URL`: the API address. It defaults to `https://api.cctodo.com`.
- `CCTODO_CONFIG`: a different config file.

To revoke a token, go to Settings → API tokens on www.cctodo.com.

## Python

```python
from cctodo import Client, Conflict

todo = Client()                                  # the same token as the CLI (or Client(token="cct_..."))
work = todo.find_group("work group")
task = todo.create_task(work.id, "Write the report", body="Due **Friday**")
todo.assign(task.id, todo.me().id)
todo.start(task.id)

for t in todo.tasks(work.id):                    # pending tasks, in order
    print(t.id, t.state, t.title)                # attribute or t["title"] access

roof = todo.create_milestone(work.id, "Roof on", "2026-11-01", description="Tiles **and** gutters")
todo.set_milestone(task.id, roof.id)             # or None to take it out
for m in todo.milestones(work.id):               # in order of target date
    print(m.title, m.target_date, "reached" if m.reached else f"{m.pending_count} to go")

try:
    todo.update_task(task.id, body="…", expected_updated_at=task.updated_at)
except Conflict:
    print("Someone else changed it first")
```

**Return values:** results are the API's JSON as `Record` objects (dicts with attribute access).

**Errors:** errors raise `cctodo.NotFound` (404; this also covers groups you're not in), `NotAllowed` (403),
`Invalid` (400), `Conflict` (409), `RateLimited` (429) or `Unauthorized` (401). All of them subclass `cctodo.CctodoError`.

## Development

```sh
pip install -e .
python -m unittest discover -s . -t .
CCTODO_API_URL=http://api.localhost:8000 cctodo whoami      # against a local cctodo_web
```

## Licence

MIT. See [LICENSE](LICENSE).
