Skip to content

fix(project edit): refuse a to-do with the same structured error as edit - #193

Merged
ryanlewis merged 2 commits into
mainfrom
fix/project-edit-todo-token
Sep 5, 2026
Merged

ryanlewis merged 2 commits into
mainfrom
fix/project-edit-todo-token

Conversation

@ryanlewis

Copy link
Copy Markdown
Owner

#190 gave things edit <project> a stable not a task token under --json. The opposite mistake did not get the same treatment: things project edit <to-do> returned a bare not a project: <title>, which lands under --json as the generic {"error": "error"} with no kind, uuid or title. An agent branching on tokens handled one direction and had to string-match the other.

Both guards now return the same error type, carrying the token it renders as — not a task one way, not a project the other — with kind, query, uuid and title in each. The plain-text message mirrors its opposite:

Error: "Post letter" is a to-do; use things edit

The guard sits before checkRepeating, tag verification and any URL open, so nothing is written. A test mirrors the one from #190: a to-do reference through project edit, nothing opened, the whole payload asserted.

Docs: the new token in internal/skill/SKILL.md, the README error section and the site commands page, next to the not a task entries. The site's agents page listed tokens too and had never gained not a task — it now names both.

One thing found and left alone: title resolution has no type preference, so with both a project and a to-do called "Chores", things project edit Chores resolves the to-do and points at things edit, which is not the item the user meant. That is in resolveTask/GetTask and predates this change — worth its own issue.

Closes #191

`things project edit <to-do>` returned a bare "not a project: <title>", so
under --json it landed as the generic `error` token with no kind, uuid or
title. An agent branching on tokens handled a project sent to `edit` but not
a to-do sent to `project edit`.

Both guards now return the same error type, which carries the token it should
render as: `not a task` one way, `not a project` the other, with kind, query,
uuid and title in each. The plain-text message mirrors its opposite —
`"Post letter" is a to-do; use things edit`.

Closes #191
Follow-up from review: the site's token list predates `not a task` and did
not gain `not a project` either, so an agent author reading the reference
docs would meet a token the CLI emits but the list does not mention. Also
fall back to the generic `error` token if a wrongKindError is ever built
without one, rather than shipping an empty string a consumer cannot match.
@ryanlewis
ryanlewis merged commit 73f87ed into main Sep 5, 2026
10 checks passed
@ryanlewis
ryanlewis deleted the fix/project-edit-todo-token branch September 5, 2026 17:44
ryanlewis added a commit that referenced this pull request Sep 10, 2026
Closes #219

The `--json` error payload spelled one concept two ways. `kind` was
`"task"` everywhere except the `not a project` failure, where it was
`"to-do"`, while `type` on a task row has said `"task"` since #214. One
word wins, and that word is `task`.

## What changed

`ProjectEditCmd.Run` now builds its `wrongKindError` with `Kind:
"task"`. That field feeds both the JSON `kind` and the rendered message,
so the message moves with it: `"Post letter" is a task; use things
edit`. Every other producer already said `task`, `project`, `area` or
`tag`.

The docs that print or explain the payload follow: the error-payload
example in the bundled skill, the token paragraph on the agents page,
and the README paragraph explaining what `kind` carries. The skill gains
a one-line note in its `--json` section saying a to-do is a `task` in
every JSON value the CLI emits, naming `import` payloads as the one
exception.

`commands.md` and `configuration.md` are untouched. Neither documents
the error payload, and no command or flag changed.

## Not a breaking change

`kind: "to-do"` was introduced in #193, which is not an ancestor of
`v0.7.0`. The value has never appeared in a release, so no published
contract moves and there is nothing for the 0.8.0 notes to warn about.
That is the same reasoning #223 applied to the `type` rename. The
`error` token is untouched either way: it stays `not a project`.

## Out of scope, deliberately

`import` payloads still spell a to-do `"to-do"`. That is Things' own
JSON URL scheme format and it stays documented as the exception.

Three other `kind` variables hold `"to-do"` and were left alone, because
none of them reaches JSON. They only compose English prose: the
repeating-item refusal in `verify.go`, the per-item refusal line in
`importcheck.go`, and the agent brief's opening sentence in
`internal/output/agent.go`. The issue scopes itself to JSON values, and
renaming these would rewrite prose and its tests well outside that. The
new comment on the `Kind` field says so explicitly, so the next reader
does not take the rule as wider than it is.

## How tested

`make test` and `make lint` both green.
`TestRunProjectEditRefusesTodoReference` asserts the new `kind` and
message and carries a comment saying why. The built binary was run
against the live Things database to confirm the payload it prints.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

project edit on a to-do returns an unstructured error, so --json has no token for it

1 participant