Skip to content

fix(edit): refuse a project reference instead of opening things:///update - #190

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

ryanlewis merged 2 commits into
mainfrom
fix/edit-project-guard

Conversation

@ryanlewis

Copy link
Copy Markdown
Owner

things edit <project> resolved the reference fine — resolveTask returns projects as well as to-dos — and then opened things:///update?id=<project uuid>. Things answers a project id there with a modal "Cannot update to-do with ID … because it does not exist", steals focus, and changes nothing.

edit now refuses a project before any URL is opened. Plain text on stderr:

Error: "Chores" is a project; use things project edit

Under --json it is a new stable token, not a task, carrying kind, query, uuid and title, so an agent can branch on it and retry against the right command.

I refused rather than routing to update-project. Routing would silently drop the task-only flags — --checklist, --list, --heading — so a caller could get a partial edit reported as a success.

Also here: a test that sends a project reference through edit and asserts nothing is opened and the token is right; the new token in internal/skill/SKILL.md and the README error list; and a line in the README and site command pages saying edit is for to-dos only, where someone reads about editing rather than only in the error section.

One thing left alone deliberately: the mirror case, things project edit <to-do>, still returns an unstructured not a project: …, so under --json it lands as the generic error token. Fixing that needs its own token and doc entries, so it belongs in its own change.

Closes #189

…date

resolveTask returns projects as well as to-dos, so `things edit <project>`
reached things.UpdateTask and opened things:///update with a project id.
Things answers that with a modal "Cannot update to-do with ID ... because it
does not exist", steals focus and changes nothing.

edit now refuses a project before any URL is opened, with `"<title>" is a
project; use things project edit` and, under --json, a new stable error token
`not a task` carrying kind, query, uuid and title. Refusing rather than
routing to update-project keeps the task-only flags (checklist, list, heading)
from being silently dropped.

Closes #189
…citly

Follow-up from review: the retry command in the refusal message was derived
from Kind, which only reads as a real command for "project"; it is now an
explicit field. The README and site command pages describe the refusal where
someone reads about editing, not only in the --json error section.
@ryanlewis
ryanlewis force-pushed the fix/edit-project-guard branch from c365212 to 323c819 Compare September 5, 2026 17:33
@ryanlewis
ryanlewis merged commit 4a8d83e into main Sep 5, 2026
10 checks passed
@ryanlewis
ryanlewis deleted the fix/edit-project-guard branch September 5, 2026 17:35
ryanlewis added a commit that referenced this pull request Sep 5, 2026
…dit (#193)

#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
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.

edit sends a project UUID to things:///update and Things shows a 'does not exist' dialog

1 participant