Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ qwen36-snap
**/session.jsonl
session.jsonl
**/__pycache__
todo/bin
todo/cli-review
.cli-skill-install-state.json
31 changes: 31 additions & 0 deletions cli-review/0-cli-discovery-preflight/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Architecture

## Stack Summary

- Language: Go
- CLI framework: Cobra
- Transport: HTTP (localhost daemon API)
- Persistence: SQLite
- Binaries: `todo` (client CLI), `todod` (daemon CLI)

## Primary Architecture Style

Layered CLI application.

- Presentation layer: Cobra command tree in `cmd/todo/main.go` and `cmd/todod/main.go`
- Service layer: daemon logic in `internal/daemon/service.go`
- Persistence layer: SQLite-backed store in `internal/store/store.go`

## Secondary Style

Client-server CLI.

- `todo` is an HTTP client to `todod`
- `todod` hosts routes (`/todos`, `/sinks`, `/schedules`, `/status`, `/motd/message`) and runs scheduler loop

## Runtime Flow

1. User runs `todo <command>`
2. Command validates args/flags and sends HTTP request to daemon
3. Daemon service applies domain rules and writes to SQLite
4. Scheduler loop dispatches reminders to MOTD queue and/or sinks
118 changes: 118 additions & 0 deletions cli-review/0-cli-discovery-preflight/argument-structure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Argument Structure

The CLI uses long-form flags (no short aliases), with Cobra defaults (`--help`, whitespace/equals value forms). Global arguments on `todo` are transport/output oriented, while command-local arguments define object selection and mutation.

## Common patterns

- Positional selectors for object IDs (e.g. `<todo-id>`, `<sink-id>`, `<schedule-id>`)
- Long flags for optional mutation/filtering
- Repeatable flags for multivalue input (`--event`, `--sink`, `--schedule`)
- Optional output mode switches (`--format`, `--rfc3339`)

## `todo` global arguments

- `--host <string>` optional, default `127.0.0.1`
- `--port <int>` optional, default `44180`
- `--timeout <duration>` optional, default `10s`
- `--format <table|json>` optional, default `table`
- `--rfc3339` optional boolean, default `false`

## `todo` command arguments

### `list`
- `--state <open|closed|reopened|rejected>` optional

### `show <todo-id>`
- `<todo-id>` required positional

### `create <todo-id> <title>`
- `<todo-id>` required positional
- `<title>` required positional (minimum one token)
- `--due <datetime>` optional
- `--schedule <spec>` optional repeatable

### `update <todo-id>`
- `<todo-id>` required positional
- `--title <string>` optional
- `--due <datetime>` optional
- `--clear-due` optional boolean

### `close|reopen|reject <todo-id>`
- `<todo-id>` required positional

### `sinks`
- `--enabled <true|false>` optional
- `--event <upcoming|overdue>` optional

### `sink <sink-id>`
- `<sink-id>` required positional

### `create-sink <sink-id>`
- `<sink-id>` required positional
- `--url <url>` required by runtime validation
- `--event <upcoming|overdue>` optional repeatable

### `update-sink <sink-id>`
- `<sink-id>` required positional
- `--url <url>` optional
- `--event <upcoming|overdue>` optional repeatable
- `--clear-events` optional boolean

### `delete-sink|enable-sink|disable-sink <sink-id>`
- `<sink-id>` required positional

### `schedules`
- `--todo <todo-id>` optional
- `--kind <upcoming|overdue>` optional
- `--status <active|sent>` optional
- `--target <sink|motd>` optional

### `schedule <schedule-id>`
- `<schedule-id>` required positional

### `add-schedule <schedule-id>`
- `<schedule-id>` required positional
- `--todo <todo-id>` required by runtime validation
- `--kind <upcoming|overdue>` required by runtime validation
- `--before <duration>` optional
- `--every <duration>` optional
- `--sink <sink-id>` optional repeatable
- `--motd` optional boolean

### `remove-schedule <schedule-id>`
- `<schedule-id>` required positional

### `reminder-status`
- no command-specific args

### `status`
- no command-specific args

### `version`
- no command-specific args

## `todod` command arguments

### `start`
- `--host <string>` optional, default `127.0.0.1`
- `--port <int>` optional, default `44180`
- `--db <path>` optional (defaults to user data path)

### `stop`
- `--host <string>` optional
- `--port <int>` optional

### `status`
- `--host <string>` optional
- `--port <int>` optional
- `--format <table|json>` optional

### `version`
- no command-specific args

## Special arguments

- `create` uses `cobra.MinimumNArgs(2)` with free-form title captured from all tokens after `<todo-id>`.
- Inline schedule grammar in `--schedule` is custom and parsed manually (`kind[:before=...|every=...][:motd|sink=...]`).
- Schedule duration strings accept relative/human forms via shared parser logic.
- `--enabled` is modeled as a string on `sinks` (`"true"`/`"false"`), not a boolean flag.
93 changes: 93 additions & 0 deletions cli-review/0-cli-discovery-preflight/commandset.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Command Set

## Tool: `todo`

### Primary-object commands (todos)

- `list`
- What: List todo items.
- How: Reads optional `--state`; calls `client.ListTodos` -> daemon `GET /todos`.
- `show <todo-id>`
- What: Show one todo.
- How: Calls `client.ShowTodo` -> daemon `GET /todos/{id}`.
- `create <todo-id> <title>`
- What: Create a todo, optional due date and inline schedules.
- How: Parses `--due` and repeatable `--schedule`, builds `CreateTodoRequest`, calls `POST /todos`.
- `update <todo-id>`
- What: Update title and/or due date.
- How: Parses `--title`, `--due`, `--clear-due`, calls `PATCH /todos/{id}`.
- `close <todo-id>`
- What: Transition todo to closed.
- How: Calls `POST /todos/{id}/close`.
- `reopen <todo-id>`
- What: Transition todo to reopened.
- How: Calls `POST /todos/{id}/reopen`.
- `reject <todo-id>`
- What: Transition todo to rejected.
- How: Calls `POST /todos/{id}/reject`.

### Secondary-object commands (sinks)

- `sinks`
- What: List sinks.
- How: Reads `--enabled`, `--event`; calls `GET /sinks`.
- `sink <sink-id>`
- What: Show one sink.
- How: Calls `GET /sinks/{id}`.
- `create-sink <sink-id>`
- What: Create sink.
- How: Uses `--url`, repeatable `--event`; calls `POST /sinks`.
- `update-sink <sink-id>`
- What: Update sink values.
- How: Uses `--url`, `--event`, `--clear-events`; calls `PATCH /sinks/{id}`.
- `delete-sink <sink-id>`
- What: Delete sink.
- How: Calls `DELETE /sinks/{id}`.
- `enable-sink <sink-id>`
- What: Enable sink.
- How: Calls `POST /sinks/{id}/enable`.
- `disable-sink <sink-id>`
- What: Disable sink.
- How: Calls `POST /sinks/{id}/disable`.

### Secondary-object commands (schedules)

- `schedules`
- What: List schedules.
- How: Uses `--todo`, `--kind`, `--status`, `--target`; calls `GET /schedules`.
- `schedule <schedule-id>`
- What: Show one schedule.
- How: Calls `GET /schedules/{id}`.
- `add-schedule <schedule-id>`
- What: Add immutable schedule.
- How: Uses `--todo`, `--kind`, `--before`, `--every`, `--sink`, `--motd`; calls `POST /schedules`.
- `remove-schedule <schedule-id>`
- What: Remove schedule.
- How: Calls `DELETE /schedules/{id}`.

### State/info commands

- `reminder-status`
- What: Print queued MOTD reminder messages.
- How: Calls `GET /motd/message`.
- `status`
- What: Show system status and MOTD setup hint.
- How: Calls `GET /status`; renders table/json.
- `version`
- What: Show client version.
- How: Prints local constant.

## Tool: `todod`

- `start`
- What: Start daemon.
- How: Reads `--host`, `--port`, `--db`; constructs server and runs HTTP service.
- `stop`
- What: Stop daemon.
- How: Calls `POST /shutdown`.
- `status`
- What: Show daemon status.
- How: Calls `GET /status`; renders table/json.
- `version`
- What: Show daemon version.
- How: Prints local constant.
51 changes: 51 additions & 0 deletions cli-review/cli-review.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Canonical CLI automated review report
*This report is AI-generated. Please [report issues with the cli-skill](https://github.com/canonical/cli-skill/issues/new/choose) so we can improve this report.*

**Scope:** CLI standard compliance review of `/project/todo/cmd/todo/main.go` and `/project/todo/cmd/todod/main.go`

## Summary

| **Severity** | **Count** | **Guideline Categories** |
| --- | --- | --- |
| High | 0 | — |
| Medium | 0 | — |
| Low | 0 | — |
| Unrated | 0 | — |
| **Total** | **0** | |

**Overall rating:** 100 💚 **Excellent**

---

## CLI changes in this PR

The latest changes successfully resolve all previously identified non-compliance issues:
* **Improved Color Capability Detection:** The `todo` CLI was updated to use `github.com/muesli/termenv` to detect color capabilities of the output stream dynamically. ANSI color sequences are safely rendered using inline tags (`RenderInlineTags`) and stripped when stdout is redirected or `NO_COLOR` is detected.
* **Resolved State-Display Naming Violation:** The non-standard `motd-message` command has been renamed to `reminder-status`. This aligns perfectly with the CLI standard's shorthand pattern for specific secondary object status (`foobar-status`).

---

## Compliance matrix

No non-compliance findings identified. All evaluated commands and behaviors conform to the CLI standard.

---

## Non-compliance Findings (with citations)

No non-compliance findings identified.

---

## Compliant Findings Summary

- **State-Display Shorthand Pattern:** The updated `reminder-status` command conforms perfectly with the standard's state-display shorthand (`foobar-status` pattern) for secondary objects.
- **Standard Verbs (add/remove) for Secondary Objects:** Under the updated CLI guidelines, `add` and `remove` are standard verbs permitted for secondary-object state mutations (e.g., `add-schedule` and `remove-schedule` are fully compliant).
- **TTY-aware Color and Formatting:** The formatting helpers (`common.Bold`, `common.ColorSection`) and help outputs (`colorizedHelp`, `rootHelp`) use `RenderInlineTags` to safely render bold and colors only when termenv detects terminal capabilities and no environment overrides (`NO_COLOR`) are set.
- **Primary-Object Command Structure:** Primary-object actions are verb-led (`list`, `show`, `create`, `update`, `close`, `reopen`, `reject`).
- **Secondary-Object Listing/Details:** Shorthand patterns for secondary objects are adhered to (`sinks`, `sink`, `schedules`, `schedule`).
- **Flat Secondary Mutation Hierarchy:** Verb-noun naming structure (`create-sink`, `delete-sink`) is used for sinks, and flat configuration is handled with flags (`--todo`) rather than deep subcommands.
- **No Dual Flags:** Short and long flags are not duplicated for the same action.
- **Help/Version Support:** The CLI supports `--help` via Cobra defaults and exposes standard `version` and `status` commands.
- **Table Formatting Standards:** Tabular data output in `list` strictly conforms to the 2-space column separator width, capitalized/left-aligned headers, and contains zero ASCII line decorations.
- **Proper Empty State Handling:** The empty state for `list` is human-readable, routed to `stderr`, and terminates with a success exit code of 0.
4 changes: 4 additions & 0 deletions cli-review/score-input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"commands": 22,
"issues": []
}
11 changes: 10 additions & 1 deletion cli-skill/commands/cli-review.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ CLI standard compliance review only.

- Check compliance with `cli-skill/references/cli-standard.md` only, do not use semantic criteria, or heuristics
- Findings must map to clauses from the standard, suggestions in the standard will result in unrated findings
- Every finding MUST include all evidence fields: `command_path`, `evidence`, `rule_clause`.
- Reviewer MUST deduplicate scored findings using key `rule_clause|command_path|evidence` before severity assignment.
- Non-compliance and compliant evidence based on observed CLI behavior/docs/code
- Use these rules to determine severity. Severity can only be [High|Medium|Low|Unrated]:
* High: violations of command structure and naming (SHOULD RULES DO NOT COUNT, THEY ARE UNRATED but should be included), use of positional parameters, accessibility/color violations (IF NO COLOR IS USED, eg. only plain or boldbold, NO_COLOR need not be detected)
Expand All @@ -36,6 +38,13 @@ CLI standard compliance review only.
* Unrated: use if no standard rule applies, or if the finding is not certain, there is a SHOULD rule, the rule applies to a debug/secret command, use of non-standard verbs when there is a standard verb that fits the action
- All SHOULD rules must be unrated violations - report them, but don't include them in the scoring. This can be a use of non-standard verbs, or in cases where the standard says "you should", or "prefer".

## Additional rules that amend the CLI standard
- In addition to the verbs listed in the CLI standard, these are standard verbs that can be used in full compliance with the CLI standard: add / remove, submit, request, revoke, init, enable / disable, save, refresh, switch, restore, forget, report, set / remove, try, download, clean, pull, build, stage, prime, pack, test, abort, validate, watch
- If a new verb not listed in the standard or the additional rules is used, only add an UNRATED finding if (1) there is a similar word in the list AND the chosen word is not clearly better, or (2) the chosen word is difficult to understand, ambiguous, or not standard english
- Command-family verb consistency findings (for example add/create, remove/delete) MUST be scored only when at least one command in that specific family was changed in the variant. ONLY inconsistencies that use any of the standard verbs are UNRATED.
- Findings missing any required evidence field MUST be dropped from scored output.
- If a planned mutation is not present in the source code, reviewer MUST mark the finding as UNRATED.

## Out Of Scope

- Any check not defined by `cli-skill/references/cli-standard.md`
Expand Down Expand Up @@ -74,7 +83,7 @@ To calculate the score:
The script implements the standard algorithm: Start with 100%, weight W=100/#commands. For each High violation, reduce by W; Medium violation by 0.5*W; Low violation by 0.2*W. Clamp to 0-100%.

### CLI Change Requirements
Analyze the files that have been changes as part of this PR. Create a detailed summary of how each change affects the compliance of the CLI.
Analyze the files that have been changes as part of this PR. Create a list of changes, each with a detailed summary of how each change affects the compliance of the CLI.

### Compliance Matrix Requirements

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "canonical-cli-skill",
"version": "0.1.0",
"version": "0.1.1",
"description": "Cross-agent CLI review skill installer for Copilot, Pi, Claude Code, and OpenCode.",
"license": "MIT",
"type": "commonjs",
Expand Down
Loading