quaestor-cli 0.2.0__tar.gz → 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. quaestor_cli-0.2.1/PKG-INFO +148 -0
  2. quaestor_cli-0.2.1/README.md +126 -0
  3. quaestor_cli-0.2.1/pyproject.toml +69 -0
  4. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/uv.lock +2 -2
  5. quaestor_cli-0.2.0/PKG-INFO +0 -7
  6. quaestor_cli-0.2.0/pyproject.toml +0 -45
  7. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/.gitignore +0 -0
  8. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/__init__.py +0 -0
  9. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/api.py +0 -0
  10. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/client.py +0 -0
  11. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/commands/__init__.py +0 -0
  12. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/commands/auth.py +0 -0
  13. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/commands/doctor.py +0 -0
  14. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/commands/events.py +0 -0
  15. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/commands/log.py +0 -0
  16. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/commands/review.py +0 -0
  17. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/commands/show.py +0 -0
  18. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/commands/streaks.py +0 -0
  19. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/commands/timer.py +0 -0
  20. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/config.py +0 -0
  21. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/errors.py +0 -0
  22. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/main.py +0 -0
  23. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/models.py +0 -0
  24. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/output.py +0 -0
  25. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/parse.py +0 -0
  26. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/resolve.py +0 -0
  27. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/runtime.py +0 -0
  28. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/src/quaestor_cli/window.py +0 -0
  29. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/tests/conftest.py +0 -0
  30. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/tests/factories.py +0 -0
  31. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/tests/test_cli_auth.py +0 -0
  32. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/tests/test_cli_errors.py +0 -0
  33. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/tests/test_cli_events.py +0 -0
  34. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/tests/test_cli_log.py +0 -0
  35. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/tests/test_cli_show.py +0 -0
  36. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/tests/test_cli_timer_review_doctor.py +0 -0
  37. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/tests/test_parse.py +0 -0
  38. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/tests/test_resolve.py +0 -0
  39. {quaestor_cli-0.2.0 → quaestor_cli-0.2.1}/tests/test_window.py +0 -0
@@ -0,0 +1,148 @@
1
+ Metadata-Version: 2.5
2
+ Name: quaestor-cli
3
+ Version: 0.2.1
4
+ Summary: Command-line client for the Quaestor API — built for humans and agents.
5
+ Project-URL: Homepage, https://quaestor.app
6
+ Project-URL: Repository, https://github.com/neuromaxer/quaestor-lite
7
+ Project-URL: Documentation, https://github.com/neuromaxer/quaestor-lite/blob/main/apps/cli/README.md
8
+ Project-URL: Issues, https://github.com/neuromaxer/quaestor-lite/issues
9
+ Keywords: agent,ai,cli,habit-tracker,quaestor
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Utilities
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: >=3.12
19
+ Requires-Dist: httpx>=0.27
20
+ Requires-Dist: typer>=0.16
21
+ Description-Content-Type: text/markdown
22
+
23
+ # quaestor-cli
24
+
25
+ `qst` — a command-line client for [Quaestor](https://quaestor.app), a habit tracker.
26
+
27
+ Built for two users at once: a person in a terminal, and an AI assistant acting on their
28
+ behalf. That second audience shapes most of the design — commands are task-shaped rather
29
+ than endpoint-shaped, streaks are addressed by name, failures are distinguishable by exit
30
+ code, and the server's own error message is printed verbatim so an agent can relay
31
+ something true.
32
+
33
+ ```bash
34
+ uv tool install quaestor-cli
35
+ ```
36
+
37
+ ## Setup
38
+
39
+ Create an API key in the Quaestor web app under **Profile → Developer Access**, then:
40
+
41
+ ```bash
42
+ export QUAESTOR_API_KEY="qst_live_..."
43
+ export QUAESTOR_URL="https://your-quaestor-backend" # defaults to http://localhost:8000
44
+ qst doctor
45
+ ```
46
+
47
+ Or store it instead of exporting it — read from stdin, so it never lands in shell history:
48
+
49
+ ```bash
50
+ pbpaste | qst auth login
51
+ ```
52
+
53
+ The key is stored at `~/.config/quaestor/credentials.json` with mode `0600`. The
54
+ environment variable wins if both are present.
55
+
56
+ `qst` refuses to send a key over plain HTTP to anything but a loopback host. Set
57
+ `QUAESTOR_ALLOW_INSECURE=1` only if you are knowingly running a plaintext self-hosted
58
+ backend.
59
+
60
+ ## Commands
61
+
62
+ ```
63
+ qst streaks List streaks with mode, unit and target
64
+ qst show <streak> Full configuration plus per-day totals, including missed days
65
+ qst log <streak> <value> Log a COUNT amount
66
+ qst log <streak> --minutes 45 Log a TIME block (45, 45m, 1h30m, 1.5h)
67
+ qst events <streak> Individual entries, newest first, with the source of each
68
+ qst review Totals, active days and current streak per streak
69
+ qst timer start|stop|status Control the single running timer
70
+ qst auth login|whoami|logout Manage the stored credential
71
+ qst doctor Check URL, reachability, credential and granted scopes
72
+ ```
73
+
74
+ Every command takes `--json` for machine-readable output on stdout. Every write takes
75
+ `--dry-run`, which prints the request and sends nothing.
76
+
77
+ ### Windows
78
+
79
+ `events`, `show` and `review` share one set of window flags: `--today`, `--week`
80
+ (default), `--days N`, or an explicit `--from` / `--to`. The explicit and relative forms
81
+ cannot be combined. Dates accept `today`, `yesterday`, a weekday (`mon`..`sun`, meaning
82
+ the most recent past one), `YYYY-MM-DD`, or an offset like `-3d`.
83
+
84
+ ### Streaks are named, never UUIDs
85
+
86
+ `<streak>` is a name. Resolution tries exact match, then unique prefix, then unique
87
+ substring. On zero or multiple matches it exits `3`, lists the candidates, and writes
88
+ nothing — it never guesses.
89
+
90
+ ```
91
+ $ qst log r 1
92
+ Streak 'r' is ambiguous — candidates: Reading, Running. Nothing was written.
93
+ ```
94
+
95
+ ### `--unit` is a safety check, not data
96
+
97
+ Units belong to the streak, not the event, so `--unit` is never sent to the API. It
98
+ asserts what you believe the streak measures and fails before writing if you are wrong —
99
+ which is what stops an assistant logging "5 miles" as 5 km.
100
+
101
+ ```
102
+ $ qst log running 5 --unit miles
103
+ 'Running' is measured in km, not miles.
104
+ ```
105
+
106
+ ## Exit codes
107
+
108
+ An agent's only reliable error channel, so they are stable:
109
+
110
+ | Code | Meaning |
111
+ | --- | --- |
112
+ | 0 | Success |
113
+ | 1 | Bad arguments or unparseable input |
114
+ | 2 | Authentication failed, or the key lacks the required scope |
115
+ | 3 | Unknown or ambiguous streak |
116
+ | 4 | Server or network error |
117
+
118
+ On failure the server's `detail` message is printed verbatim to stderr.
119
+
120
+ ## Scopes
121
+
122
+ A key only carries the permissions granted when it was created, and the server enforces
123
+ them. Insufficient scope returns a message naming what is missing, so it is clear whether
124
+ something is a bug or a deliberate restriction:
125
+
126
+ ```
127
+ $ qst log reading 5
128
+ API key is missing required scope(s): events:write
129
+ ```
130
+
131
+ Deleting a streak has no scope at all — it is web-app only, because it also destroys every
132
+ event, total and milestone beneath it. `qst doctor` lists the scopes a key actually holds.
133
+
134
+ ## Using this with an AI assistant
135
+
136
+ The repository ships an [Agent
137
+ Skill](https://github.com/neuromaxer/quaestor-lite/blob/main/skills/quaestor/SKILL.md)
138
+ that teaches an assistant when and how to use these commands, following the
139
+ [agentskills.io](https://agentskills.io) format. Copy it to `~/.agents/skills/` (OpenClaw)
140
+ or `~/.hermes/skills/` (Hermes Agent).
141
+
142
+ Design notes and the security model are in the [feature
143
+ documentation](https://github.com/neuromaxer/quaestor-lite/blob/main/docs/features/agent-connect/agent-connect.md).
144
+
145
+ ## Requirements
146
+
147
+ Python 3.12+. Depends only on `httpx` and `typer` — it speaks HTTP and never imports the
148
+ Quaestor backend, so it installs in seconds and tolerates version skew against the server.
@@ -0,0 +1,126 @@
1
+ # quaestor-cli
2
+
3
+ `qst` — a command-line client for [Quaestor](https://quaestor.app), a habit tracker.
4
+
5
+ Built for two users at once: a person in a terminal, and an AI assistant acting on their
6
+ behalf. That second audience shapes most of the design — commands are task-shaped rather
7
+ than endpoint-shaped, streaks are addressed by name, failures are distinguishable by exit
8
+ code, and the server's own error message is printed verbatim so an agent can relay
9
+ something true.
10
+
11
+ ```bash
12
+ uv tool install quaestor-cli
13
+ ```
14
+
15
+ ## Setup
16
+
17
+ Create an API key in the Quaestor web app under **Profile → Developer Access**, then:
18
+
19
+ ```bash
20
+ export QUAESTOR_API_KEY="qst_live_..."
21
+ export QUAESTOR_URL="https://your-quaestor-backend" # defaults to http://localhost:8000
22
+ qst doctor
23
+ ```
24
+
25
+ Or store it instead of exporting it — read from stdin, so it never lands in shell history:
26
+
27
+ ```bash
28
+ pbpaste | qst auth login
29
+ ```
30
+
31
+ The key is stored at `~/.config/quaestor/credentials.json` with mode `0600`. The
32
+ environment variable wins if both are present.
33
+
34
+ `qst` refuses to send a key over plain HTTP to anything but a loopback host. Set
35
+ `QUAESTOR_ALLOW_INSECURE=1` only if you are knowingly running a plaintext self-hosted
36
+ backend.
37
+
38
+ ## Commands
39
+
40
+ ```
41
+ qst streaks List streaks with mode, unit and target
42
+ qst show <streak> Full configuration plus per-day totals, including missed days
43
+ qst log <streak> <value> Log a COUNT amount
44
+ qst log <streak> --minutes 45 Log a TIME block (45, 45m, 1h30m, 1.5h)
45
+ qst events <streak> Individual entries, newest first, with the source of each
46
+ qst review Totals, active days and current streak per streak
47
+ qst timer start|stop|status Control the single running timer
48
+ qst auth login|whoami|logout Manage the stored credential
49
+ qst doctor Check URL, reachability, credential and granted scopes
50
+ ```
51
+
52
+ Every command takes `--json` for machine-readable output on stdout. Every write takes
53
+ `--dry-run`, which prints the request and sends nothing.
54
+
55
+ ### Windows
56
+
57
+ `events`, `show` and `review` share one set of window flags: `--today`, `--week`
58
+ (default), `--days N`, or an explicit `--from` / `--to`. The explicit and relative forms
59
+ cannot be combined. Dates accept `today`, `yesterday`, a weekday (`mon`..`sun`, meaning
60
+ the most recent past one), `YYYY-MM-DD`, or an offset like `-3d`.
61
+
62
+ ### Streaks are named, never UUIDs
63
+
64
+ `<streak>` is a name. Resolution tries exact match, then unique prefix, then unique
65
+ substring. On zero or multiple matches it exits `3`, lists the candidates, and writes
66
+ nothing — it never guesses.
67
+
68
+ ```
69
+ $ qst log r 1
70
+ Streak 'r' is ambiguous — candidates: Reading, Running. Nothing was written.
71
+ ```
72
+
73
+ ### `--unit` is a safety check, not data
74
+
75
+ Units belong to the streak, not the event, so `--unit` is never sent to the API. It
76
+ asserts what you believe the streak measures and fails before writing if you are wrong —
77
+ which is what stops an assistant logging "5 miles" as 5 km.
78
+
79
+ ```
80
+ $ qst log running 5 --unit miles
81
+ 'Running' is measured in km, not miles.
82
+ ```
83
+
84
+ ## Exit codes
85
+
86
+ An agent's only reliable error channel, so they are stable:
87
+
88
+ | Code | Meaning |
89
+ | --- | --- |
90
+ | 0 | Success |
91
+ | 1 | Bad arguments or unparseable input |
92
+ | 2 | Authentication failed, or the key lacks the required scope |
93
+ | 3 | Unknown or ambiguous streak |
94
+ | 4 | Server or network error |
95
+
96
+ On failure the server's `detail` message is printed verbatim to stderr.
97
+
98
+ ## Scopes
99
+
100
+ A key only carries the permissions granted when it was created, and the server enforces
101
+ them. Insufficient scope returns a message naming what is missing, so it is clear whether
102
+ something is a bug or a deliberate restriction:
103
+
104
+ ```
105
+ $ qst log reading 5
106
+ API key is missing required scope(s): events:write
107
+ ```
108
+
109
+ Deleting a streak has no scope at all — it is web-app only, because it also destroys every
110
+ event, total and milestone beneath it. `qst doctor` lists the scopes a key actually holds.
111
+
112
+ ## Using this with an AI assistant
113
+
114
+ The repository ships an [Agent
115
+ Skill](https://github.com/neuromaxer/quaestor-lite/blob/main/skills/quaestor/SKILL.md)
116
+ that teaches an assistant when and how to use these commands, following the
117
+ [agentskills.io](https://agentskills.io) format. Copy it to `~/.agents/skills/` (OpenClaw)
118
+ or `~/.hermes/skills/` (Hermes Agent).
119
+
120
+ Design notes and the security model are in the [feature
121
+ documentation](https://github.com/neuromaxer/quaestor-lite/blob/main/docs/features/agent-connect/agent-connect.md).
122
+
123
+ ## Requirements
124
+
125
+ Python 3.12+. Depends only on `httpx` and `typer` — it speaks HTTP and never imports the
126
+ Quaestor backend, so it installs in seconds and tolerates version skew against the server.
@@ -0,0 +1,69 @@
1
+ [project]
2
+ name = "quaestor-cli"
3
+ version = "0.2.1"
4
+ description = "Command-line client for the Quaestor API — built for humans and agents."
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ # NOTE: no `license` yet — the repository has no LICENSE file, so publishing one here
8
+ # would be inventing a licensing decision. Until one is chosen, PyPI shows no license,
9
+ # which legally means all rights reserved.
10
+ keywords = ["quaestor", "habit-tracker", "cli", "agent", "ai"]
11
+ classifiers = [
12
+ "Development Status :: 4 - Beta",
13
+ "Environment :: Console",
14
+ "Intended Audience :: End Users/Desktop",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.12",
17
+ "Programming Language :: Python :: 3.13",
18
+ "Topic :: Utilities",
19
+ "Typing :: Typed",
20
+ ]
21
+ dependencies = [
22
+ "httpx>=0.27",
23
+ # 0.16 is the first release that defaults pretty_exceptions_show_locals to False.
24
+ # Older versions render local variables — including the API key — into a crash
25
+ # traceback. main.py also sets the flag explicitly; this floor is belt and braces.
26
+ "typer>=0.16",
27
+ ]
28
+
29
+ [project.urls]
30
+ Homepage = "https://quaestor.app"
31
+ Repository = "https://github.com/neuromaxer/quaestor-lite"
32
+ Documentation = "https://github.com/neuromaxer/quaestor-lite/blob/main/apps/cli/README.md"
33
+ Issues = "https://github.com/neuromaxer/quaestor-lite/issues"
34
+
35
+ [project.scripts]
36
+ qst = "quaestor_cli.main:app"
37
+
38
+ [dependency-groups]
39
+ dev = [
40
+ "pytest>=8.0",
41
+ "pytest-asyncio>=0.23",
42
+ "respx>=0.21",
43
+ "ruff>=0.6",
44
+ "mypy>=1.11",
45
+ ]
46
+
47
+ [build-system]
48
+ requires = ["hatchling"]
49
+ build-backend = "hatchling.build"
50
+
51
+ [tool.hatch.build.targets.wheel]
52
+ packages = ["src/quaestor_cli"]
53
+
54
+ [tool.pytest.ini_options]
55
+ testpaths = ["tests"]
56
+ asyncio_mode = "auto"
57
+
58
+ [tool.ruff]
59
+ line-length = 110
60
+ target-version = "py312"
61
+ src = ["src", "tests"]
62
+
63
+ [tool.ruff.lint]
64
+ select = ["E", "F", "I", "UP", "B", "SIM"]
65
+
66
+ [tool.mypy]
67
+ python_version = "3.12"
68
+ strict = true
69
+ warn_unreachable = true
@@ -416,7 +416,7 @@ wheels = [
416
416
 
417
417
  [[package]]
418
418
  name = "quaestor-cli"
419
- version = "0.2.0"
419
+ version = "0.2.1"
420
420
  source = { editable = "." }
421
421
  dependencies = [
422
422
  { name = "httpx" },
@@ -435,7 +435,7 @@ dev = [
435
435
  [package.metadata]
436
436
  requires-dist = [
437
437
  { name = "httpx", specifier = ">=0.27" },
438
- { name = "typer", specifier = ">=0.12" },
438
+ { name = "typer", specifier = ">=0.16" },
439
439
  ]
440
440
 
441
441
  [package.metadata.requires-dev]
@@ -1,7 +0,0 @@
1
- Metadata-Version: 2.5
2
- Name: quaestor-cli
3
- Version: 0.2.0
4
- Summary: Command-line client for the Quaestor API — built for humans and agents.
5
- Requires-Python: >=3.12
6
- Requires-Dist: httpx>=0.27
7
- Requires-Dist: typer>=0.12
@@ -1,45 +0,0 @@
1
- [project]
2
- name = "quaestor-cli"
3
- version = "0.2.0"
4
- description = "Command-line client for the Quaestor API — built for humans and agents."
5
- requires-python = ">=3.12"
6
- dependencies = [
7
- "httpx>=0.27",
8
- "typer>=0.12",
9
- ]
10
-
11
- [project.scripts]
12
- qst = "quaestor_cli.main:app"
13
-
14
- [dependency-groups]
15
- dev = [
16
- "pytest>=8.0",
17
- "pytest-asyncio>=0.23",
18
- "respx>=0.21",
19
- "ruff>=0.6",
20
- "mypy>=1.11",
21
- ]
22
-
23
- [build-system]
24
- requires = ["hatchling"]
25
- build-backend = "hatchling.build"
26
-
27
- [tool.hatch.build.targets.wheel]
28
- packages = ["src/quaestor_cli"]
29
-
30
- [tool.pytest.ini_options]
31
- testpaths = ["tests"]
32
- asyncio_mode = "auto"
33
-
34
- [tool.ruff]
35
- line-length = 110
36
- target-version = "py312"
37
- src = ["src", "tests"]
38
-
39
- [tool.ruff.lint]
40
- select = ["E", "F", "I", "UP", "B", "SIM"]
41
-
42
- [tool.mypy]
43
- python_version = "3.12"
44
- strict = true
45
- warn_unreachable = true
File without changes