Metadata-Version: 2.5
Name: quaestor-cli
Version: 0.10.0
Summary: Command-line client for the Quaestor API — built for humans and agents.
Project-URL: Homepage, https://quaestor.app
Project-URL: Repository, https://github.com/neuromaxer/quaestor-lite
Project-URL: Documentation, https://github.com/neuromaxer/quaestor-lite/blob/main/apps/cli/README.md
Project-URL: Issues, https://github.com/neuromaxer/quaestor-lite/issues
Keywords: agent,ai,cli,habit-tracker,quaestor
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Utilities
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: httpx>=0.27
Requires-Dist: typer>=0.16
Description-Content-Type: text/markdown

# quaestor-cli

`qst` — a command-line client for [Quaestor](https://quaestor.app), an agent-native
platform for diary-based life management. An evening diary becomes tracked habits,
quest progress, and a morning plan.

Built for two users at once: a person in a terminal, and an AI assistant acting on their
behalf. That second audience shapes most of the design — commands are task-shaped rather
than endpoint-shaped, streaks and quests are addressed by name, failures are
distinguishable by exit code, and the server's own error message is printed verbatim so
an agent can relay something true.

```bash
uv tool install quaestor-cli
```

## Setup

Create an API key in the Quaestor web app under **Profile → Developer Access**.
The CLI uses the hosted production API automatically. On macOS, copy the key and run:

```bash
pbpaste | qst auth login
qst doctor
```

On other systems, run `qst auth login`, paste the key, press Enter, then signal
end-of-input (Ctrl-D on Unix).

The key is stored at `~/.config/quaestor/credentials.json` with mode `0600`. The
CLI also supports `QUAESTOR_API_KEY`; an existing environment variable takes
precedence over the file, but it is not needed for this setup.

Logging in again replaces the key while preserving an existing server override.
`qst doctor` reports authentication as unknown when the server cannot verify it;
only an explicit authentication refusal means the key was rejected.

## The evening diary workflow

Spend 10–15 minutes writing or recording your day. Your agent uses `qst` to log
measured habits, record quest progress, and plan the work you want to do tomorrow.
It reports what changed and prepares a short morning plan with Main and Side Quests.

Keep the original diary with your agent or in a place you choose. The CLI stores
habit records and quest-specific notes in Quaestor, not a general diary entry.
Those original entries become a record of your progress and a story worth keeping.

## Commands

```
qst streaks                      List streaks with mode, unit and target
qst show <streak>                Full configuration plus per-day totals, including missed days
qst log <streak> <value>         Log a COUNT amount
qst log <streak> --minutes 45    Log a TIME block (45, 45m, 1h30m, 1.5h); --quest <q> links it to a quest
qst events <streak>              Individual entries, newest first, with the source of each
qst review                       Totals, active days and current streak per streak
qst timer start|stop|status      Control the single running timer
qst auth login|whoami|logout     Manage the stored credential
qst doctor                       Check URL, reachability, credential and granted scopes

qst agenda [--week|--days N]     Overdue, past deadline, unplanned, each day's Main and Side quests, daily quests
qst quests [words] [filters]     Find quests: --status, --overdue, --on, --from/--to,
                                 --deadline-by, --under <quest>, --archived, --sort, --limit
qst quest show <quest>           Status (and when it was done), type, dates, upcoming blocks, sub-quest progress, linked streaks and quests, its link, description, latest Quest Log
qst quest log <quest>            Quest Log entries, newest first (--date for one day)
qst quest add <title>            --under <quest> --on fri --due <date> --priority high --emoji 🚀 --streak <s> ...
qst quest edit <quest>           --title --emoji --priority --start/--due (or 'none') --streak <s>|none --under/--top-level
qst quest status <quest> <s>     backlog | todo | in-progress | done (checks days from today on) | archived
qst quest archive <quest>        Hide it and its sub-quests (there is no delete)
qst quest plan <quest> <day>...  Plan days as Main quests (--side: Side; on planned days --main/--side switch);
                                 a Backlog or Done quest becomes Todo
qst quest unplan <quest> <day>   Remove a planned day (never demotes)
qst quest reschedule <q> <from> [to]   Move one planned day (to today by default, keeping Main/Side); a skipped day moved to today or later is kept as history
qst quest schedule <quest> --at "<day> HH:MM"  A block on the calendar (--for 30m default, --streak <s>);
                                 the quest shows on that day; links the streak
qst quest check <quest>          Single: finish it (Done; that day and later ones checked), or mark the day --worked
                                 (progress, stays open) / --skipped (counts as not done). Recurring: log --value/--minutes
                                 on its streak (--date, --undo)
qst quest note <quest> <text>    Append to that day's Quest Log entry (--date, --replace)
qst quest link|unlink <quest> <streak>  Link a streak (navigation only: nothing is logged or checked)
qst quest link-quest|unlink-quest <quest> <other>  Link two related quests (both list each other)
qst quest mention <quest>        Markdown link for a note or description; the app shows it as a chip
```

Every command takes `--json` for machine-readable output on stdout. Every write takes
`--dry-run`, which prints the request and writes nothing. `log` uses a read-only
streak lookup to validate the name, mode and `--unit` before printing the resolved
payload. A COUNT/TIME mismatch or wrong unit exits `1` without posting an event.

### Windows

`events`, `show` and `review` share one set of window flags: `--today`, `--week`
(default), `--days N`, or an explicit `--from` / `--to`. The explicit and relative forms
cannot be combined. Dates accept `today`, `yesterday`, a weekday (`mon`..`sun`, meaning
the most recent past one), `YYYY-MM-DD`, or an offset like `-3d`.

### Streaks are named, never UUIDs

`<streak>` is a name. Resolution tries exact match, then unique prefix, then unique
substring. On zero or multiple matches it exits `3`, lists the candidates, and writes
nothing — it never guesses.

```
$ qst log r 1
Streak 'r' is ambiguous — candidates: Reading, Running. Nothing was written.
```

### Quests are named too — by title or path

`<quest>` is a title, or a path of titles that names the parents as well:
`"Launch > Backend > Schema"` (`›` works too). The server resolves it — exact, then unique
prefix, then unique substring; archived quests only when nothing live matches — and on
zero or several matches `qst` exits `3`, prints the candidates' full paths, and writes
nothing.

```
$ qst quest check "write migration"
Quest 'write migration' is ambiguous — 2 quests match: Launch › Backend › Write migration;
Blog › Write migration. Use a path such as 'Launch > Backend > Write migration' to pick one.
Nothing was written.
```

With `--json`, the failure is one JSON document on stdout: `{"error": {"exit_code": 3,
"message": ..., "candidates": [...]}}`.

### Which way date words point

Where you plan (`add --on/--due/--start`, `plan`, a reschedule target, `agenda`/`quests
--from/--to`), a weekday means the **coming** one: `fri` on a Wednesday is this Friday,
and today if it is Friday; `next fri` is a week later; `+1w` is a week from today.
Where you record (`check --date`, `note --date`, streak commands), a weekday is the most
recent one and `last fri` is strictly before today; `check` refuses future days.
Where you name a day the quest already has (`reschedule`'s first day, `unplan`), a
weekday picks the quest's own date on that weekday within a week of today, in either
direction — so `qst quest reschedule report tue thu` works whether Tuesday was yesterday
or is next week.

### Retrying writes safely

Dropped connections are retried automatically with the same idempotency key. If a write
still fails with exit 4, the message includes the key; re-run with
`qst --idempotency-key <key> ...` (or set `QUAESTOR_IDEMPOTENCY_KEY`) and the server
replays the original write instead of creating a duplicate.

Quest reads send your local date (`today=`), so overdue and "today" match the web app.
Writes that change a status automatically say so (`Status: Todo → Done.`).

### Planned vs scheduled

`plan` gives a quest a **day** (a todo date). `schedule` gives it a **block**: a start and end
time on the Timeblocks calendar, on a TIME streak. Either puts the quest **on that day**: the
agenda lists it there, with the block's time. No todo date is added for a block, so moving or
deleting the block moves or removes the day; checking the day off writes its todo date.

```
$ qst quest schedule "Launch > Backend" --at "mon 14:00" --for 1h --streak "deep work"
Scheduled Launch › Backend for Mon 2026-10-19 14:00-15:00 (on Deep work; streak linked).
It now shows on Mon 2026-10-19.

$ qst agenda --days 7
...
Mon 2026-10-19 — 0/1 done
  Main quests
    [ ] Launch › Backend  @ 14:00-15:00 (block only)
```

A block-only day counts as planned (not unplanned), and a skipped single block makes the quest
overdue (a repeating block's skipped occurrence never does).

`--at` reads the day like `plan` (a bare `HH:MM` is today). Without `--streak` the server
picks one (the quest's last block's streak, then its recurring or linked streaks, then its
parents') and says so in its error when there is none. It creates one block per call and
has no idempotency key, so it isn't retried automatically.

### Recurring quests

`--streak <name>` makes a quest recurring on that streak (it needs a day, week or month
target; one quest per streak). A daily quest shows in the agenda's daily list every day;
a weekly or monthly one is planned per week or month. It is checked off by events on the
streak: `qst quest check <quest> --value 20` (or `--minutes 30`) logs one and says whether
the target is met. `qst log` on that streak counts the same way.

`qst quest link <quest> <streak>` is separate: a navigation-only link (the app shows it
under Linked streaks). A quest can be recurring on one streak and linked to others.

### `--unit` is a safety check, not data

Units belong to the streak, not the event, so `--unit` is never sent to the API. It
asserts what you believe the streak measures and fails before writing if you are wrong —
which is what stops an assistant logging "5 miles" as 5 km.

```
$ qst log running 5 --unit miles
'Running' is measured in km, not miles.
```

## Exit codes

An agent's only reliable error channel, so they are stable:

| Code | Meaning |
| --- | --- |
| 0 | Success |
| 1 | Bad arguments or unparseable input |
| 2 | Authentication failed, or the key lacks the required scope |
| 3 | Unknown or ambiguous streak or quest |
| 4 | Server or network error |

On failure the server's `detail` message is printed verbatim to stderr.

## Scopes

A key only carries the permissions granted when it was created, and the server enforces
them. Insufficient scope returns a message naming what is missing, so it is clear whether
something is a bug or a deliberate restriction:

```
$ qst log reading 5
API key is missing required scope(s): events:write
```

Deleting a streak has no scope at all — it is web-app only, because it also destroys every
event, total and milestone beneath it. The same goes for deleting a quest or a Quest Log
entry: `qst` has no delete command, and a key can archive a quest instead.

Quest commands need `quests:read` (agenda, lists, show, log) and `quests:write`
(everything else, archive included). Both are pre-checked when a key is created; older
keys lack them, and `qst doctor` lists the scopes a key actually holds plus a hint naming
the quest commands that will fail. `qst quest schedule` also needs `timeblocks:write`,
which is not pre-checked; without `timeblocks:read`, `qst quest show` leaves out the
quest's blocks.

## Using this with an AI assistant

The repository ships an [Agent
Skill](https://github.com/neuromaxer/quaestor-lite/blob/main/skills/quaestor/SKILL.md)
that teaches an assistant when and how to use these commands, following the
[agentskills.io](https://agentskills.io) format. Copy it to `~/.agents/skills/` (OpenClaw)
or `~/.hermes/skills/` (Hermes Agent).

Design notes and the security model are in the [feature
documentation](https://github.com/neuromaxer/quaestor-lite/blob/main/docs/features/agent-connect/agent-connect.md).

## Requirements

Python 3.12+. Depends only on `httpx` and `typer` — it speaks HTTP and never imports the
Quaestor backend, so it installs in seconds and tolerates version skew against the server.

## Developer configuration

Use `qst --dev doctor` to target `http://localhost:8000` for that invocation.
The development flag is hidden from normal help and never persists a local URL.

Staging and self-hosted deployments can still use `QUAESTOR_URL` or an existing
`base_url` in the credential store. Resolution order is `--dev`, environment, stored
URL, then the hosted production default. Ordinary hosted setup needs no override.

Quest links (`qst quest mention`, `show`) point at the web app: `https://quaestor.app` by
default, `http://localhost:3000` with `--dev`, or `QUAESTOR_APP_URL` for other deployments.

`qst` refuses to send a key over plain HTTP except to loopback. Set
`QUAESTOR_ALLOW_INSECURE=1` only for deliberate plaintext development deployments.
