Changelog
What changed in each release, newest first. These are the release notes published with each version on GitHub, where the downloads are.
v0.11.0
things-cli v0.11.0 — smaller JSON for agents
JSON listings are now sized for agents, and there is a new things doctor for checking database access. Most of the rest is a refactor of the write and import code, with no change in behaviour, plus a set of fixes to how --when times are sent and checked.
Behaviour changes
-jlistings print a default set of fields.listviews,searchandprojectsused to print every field of every row. They now print the fields an agent needs to pick an item and act on it: uuid, title, type, status, start, startBucket, dates, reminder, project, area and heading titles, tags, repeating and checklist progress. Notes, parent uuids, sort indexes and the creation date are left out. On a 94-task list the output drops from 90 KB to 29 KB.--fields allprints the full record exactly as before, andthings show <uuid> -jis unchanged. (#454)--fields(-f) picks the keys yourself.things anytime -j --fields uuid,title,deadlineprints only those keys, in that order. Unknown names are refused with theunknown fieldtoken and the list of valid names. (#451, #459)- Weekdays and evening times are sent and checked.
fridayandfriday@9pmare sent as the date Things gives them (the next such day after today, sosaturday@9pmon a Saturday is next week) and read back.evening@6pmis sent asevening@18:00and checked to be in This Evening today.importaccepts and resolves them too. (#458) - A
--whenthe CLI cannot check is reported as not confirmed. An abbreviation such asfrior a phrase such asnext fridaythat Things understood used to print the item as if confirmed.add,project add,editandimportnow report it asnot confirmed (when not checked)(JSONconfirmed: false, reason: when), exit 0. (#453, #458) - Dated
--whentimes are sent as a date.today@6pm,tomorrow@9amand<date>@<time>are sent to Things asYYYY-MM-DD@HH:MMand read back, inadd,editand nowimport, so a time Things misfiles is caught. A bare 12-hour time such as9:30pmis sent as21:30. (#443, #446, #449) - Project refs say “project not found”.
open --projectandproject editrefuse a ref that names a to-do, and every kind of miss (title, row number, uuid) now reports the project kind. (#448, #444, #445)
New
things doctorchecks that the Things database can be found and opened, and reports a permission denial (Full Disk Access) as such. (#447)
Also
- A padded
--list,--areaor--headingname is sent trimmed when only the trimmed name matches. A title that really has the spaces still matches as typed.importsends names as given. (#456) - The missing-area and “–heading needs a list” warnings use one wording across
add,editandimport, and a list given by uuid is named by its title. (#450) - Large refactors of the import, edit and database code, each checked against the previous binary with a comparison runner now in
tools/compare/. (#431–#455) - The README puts Install first. (#457)
- The bundled skill and the docs at things.rlew.io are updated. Run
things skill installafter upgrading.
Requirements
macOS with Things3 installed. Binaries for Apple Silicon (darwin_arm64) and Intel (darwin_amd64).
What’s Changed
Other Changes
- refactor: let each error type fill its own –json error payload by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/431
- refactor: share small helpers and the –when read-back verdict by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/433
- fix(add): check every field before –create-tags creates a tag by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/434
- refactor(db): build alias-specific SQL with functions and share the row loop by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/432
- test(db): add shared test helpers and move raw TMTask inserts onto the fixture by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/436
- fix: check every edit field before –create-tags creates a tag by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/435
- test: keep import creation-dates in step with the pinned clock by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/437
- refactor: split importcheck.go and share the –when rules with import by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/438
- fix(edit): check the auth token before –create-tags creates a tag by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/439
- refactor: build the target warnings in one place by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/440
- test: add days to Things dates with AddDays, not the day bits by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/441
- refactor: simplify code churned through 0.10.0 by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/442
- fix(when): send a bare 12-hour –when time as HH:MM and read it back by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/443
- fix(open): refuse a –project ref that is not a project by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/444
- fix(project): match only projects by title for project edit by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/445
- fix(when): send a dated –when time as YYYY-MM-DD@HH:MM and read it back by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/446
- fix(db): report permission denial in database discovery; add things doctor by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/447
- fix(lookup): report a project not found for every ref shape in a project lookup by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/448
- fix(import): send a dated when time as YYYY-MM-DD@HH:MM and read it back as sent by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/449
- feat(output): add –fields to limit JSON listings to named keys by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/451
- chore(warnings): one wording for the missing-area and heading-needs-a-list warnings by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/450
- refactor(edit): decide whether an edit is sent in one place by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/452
- fix(when): report a –when the read-back cannot place as not confirmed by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/453
- test: tidy date helpers and rows.Err, rename the unlogged rule, add the binary comparison runner by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/455
- feat(output)!: print a default field set on -j listings, with –fields all for the full record by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/454
- fix: send a padded list, area or heading name trimmed when only that form matches by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/456
- docs(readme): move Install up and mention the import read-back of created items by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/457
- fix(when): send weekday names as their date and check evening@time, in add, edit and import by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/458
- feat(list): add -f as the short form of –fields by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/459
- docs(release): add v0.11.0 release notes header by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/460
Full Changelog: https://github.com/ryanlewis/things-cli/compare/v0.10.0...v0.11.0
v0.10.0
things-cli v0.10.0 — the CLI shows what Things shows
A big release, this one: three headline changes and a long list of fixes. Everything since v0.9.0, over a hundred PRs.
The CLI shows what Things shows. Every view was compared against the app row by row. today, anytime, upcoming, someday and the project, area and tag pages now list the same rows in the same order as the app: a deadline that has arrived pulls an item into Today, a scheduled Someday item appears in Upcoming, This Evening sits last, and a to-do you completed stays where it was until Things moves it to the Logbook. That last one changes the default output, so --open-only and the open_only config key give the old lists back.
Writes behave the same way every time. A lot of this release went on validating that each command does one thing and says what it did. Every write reads its result back from Things, and the refusals and --json error tokens are shared across add, edit and import. Behaviour changed in a few places, mainly so that an agent driving the CLI gets a deterministic answer rather than a silent miss: an item that landed somewhere else, a --when Things ignored, or a title that happened to match a different task.
Listings fit the terminal. Rows adapt to the width they are printed at. Long titles are cut before any column is dropped, dates switch to a compact form (due:Tue, 21 Oct) when the full date will not fit, tags shorten to the first plus a count, and checklist progress and start dates appear on rows when there is room. Piped output is byte-identical to before, so scripts and agents see no change. (#298–#319) Here is things today at 80 columns on v0.9.0:

and on v0.10.0:

Behaviour changes
- Default views include closed items Things still shows.
inbox,today,anytime,upcoming,someday, barethings, bare--project/--arealistings andshow --agenton a project now list to-dos completed or cancelled but not yet moved to the Logbook, as the app does.--open-onlygives the old output, and the newopen_onlyconfig key makes that the default.--include-completedis accepted but does nothing. (#384, #389) addandproject addprint the created item, in the same form asthings show, after reading it back. They exit non-zero if the item never appears, or appears somewhere other than where it was sent. Under--jsona misfiled item is reported as one error object with the tokenmisfiled, itsuuidand where itlanded. (#332, #381, #393)- Refs that look like a number but are not a row are refused.
+5,#5,# 12,(#12),No. 12,12.and an all-digit ref that is not a row in the last list now match only an exact title or a uuid. They used to match any title containing them, sothings complete '#12'could close the wrong task. Dates, times, amounts and version numbers still match part of a title. (#378, #392, #395) importrefuses payloads Things would reject. Acreation-dateorcompletion-datewithout a full date, time and offset, or a non-textlist,list-id,heading,heading-id,areaorarea-id, makes Things reject the whole payload with an error sheet. The CLI now refuses it before sending anything, asimport refusedwith areasonper item. (#391, #394, #397)--jsonno longer escapes&,<and>. (#286)- Plain
showprintsCreated:in local time. JSON timestamps are unchanged (UTC, RFC 3339). (#283) complete,cancelandeditrefuse an item that is in the Trash. A row number or uuid that now points at a trashed item used to be completed, cancelled or edited silently with exit 0. It is now refused with exit 1 and the--jsontokentrashed;showstill opens it and saysStatus: Open (in Trash).completeandcancelnow print the item they closed, likeedit --complete. Switching a closed item between completed and cancelled returns the tokenalready closed. (#407, #406)- Reminder times are shown. Task JSON gains
reminderTime(HH:MM, omitted when unset);showandshow --agentput it on the start line, and list rows show it before the title, as the app does. (#405) importrefuses more of what Things rejects, and never drops an item from the read-back. Malformed items (invalid-item), blank titles (blank-title), wrong JSON kinds for any attribute (invalid-type), impossible calendar dates such as month 13 (invalid-date), and payloads that create more than 200 items (too-many-items, since Things shows a confirmation dialog above that) are refused before sending. Two date forms Things accepts (+01:00:00, trailing space) are accepted. A same-titled dated/undated pair no longer fails when both landed. (#412)importrefuses what Things would silently mangle. Duplicate keys, titles and notes over Things’ length limits,itemson a to-do, creation or completion dates in the future, and awhenordeadlineThings would misread are all refused before anything is sent, each with its ownreason. The full list is on the commands page. (#418)- A title that belongs only to a closed or trashed to-do no longer reaches a different open one.
complete "Pay rent"with “Pay rent” completed and “Re: Pay rent deposit” open used to close the deposit task via the substring fallback; it now fails withalready closedortrashed, lists thematches, and touches nothing. Refs are stricter in the same way: a leading zero or a bare0is never a row number, a uuid-shaped ref never matches part of a title, and an empty ref is refused. (#422) edit --heading ""clears the heading andedit --list ""unfiles the to-do, and both are read back; they used to print the old location while Things moved the item. Blank titles are refused everywhere, and a--whenthat cannot be a real date or time is refused before anything is sent, while a free phrase Things ignored is reported as such instead of waiting five seconds. (#423)- Deadlines promote items the way the app does. Any undated open to-do or project whose deadline has arrived is in
todayandanytimeand leavessomeday, and one with a later deadline is inupcoming; Inbox items stay in the Inbox.--tagandprojectslist closed-but-unlogged rows like the other views,projects --open-onlyhides them, andsearchskips to-dos inside a trashed project. (#421) - Row order matches the app.
todayputs This Evening last under its own header and orders project groups by schedule;anytime,someday,--areaand--taglist projects before loose to-dos and follow heading order inside a project;trashis most-recently-trashed first; plainlogbookhas a date header per day. (#420) - Docs match the binary.
--deadlinetakes English phrases (nottoday/tomorrow),--when 9:30PMworks, RFC 3339 offsets are ignored in favour of the wall clock,openandlogprint nothing on success,~in--db/--config/thedbkey follows$HOME. (#417) importreads back where each to-do landed. AwhenThings did not apply (a keyword or date that landed elsewhere, such astodaywith a past deadline, which Things files in the Inbox) is reportedconfirmed: false, reason: misfiledwithlanded, and the import exits non-zero; a free phrase Things ignored isreason: when, exit 0, asadddoes. (#428)
Listings match the app
todayorders rows by the day they were placed in Today, newest first, then by their position that day. It also lists undated to-dos whose deadline has come. (#342, #385)inbox,anytimeandupcomingfollow the app’s rules for deadlines, Someday and scheduled projects, and rows Things has not moved into Today yet. (#288, #347, #349, #354, #356, #366, #370)logbookfollows the “Move completed items to Logbook” setting and holds back everything Things has not logged. (#357, #362)- A
--projectlisting is in the order of the project’s page in the app. (#351) - To-dos of a project with no area sit in the no-area group at the top of Today, Anytime and Someday, not after every area. The Logbook no longer hides the logged to-dos of a project that is completed but not yet logged. (#410)
- Names match the way Things matches them: exact case first, then full Unicode case folding, normalisation, and compatibility forms for project and area titles. (#284, #287, #327, #341, #358, #361, #368, #371)
Writes are checked
add --project/--listandproject add --areaaccept a uuid. When several projects or areas share a title, the CLI picks the one Things files into (the smallest uuid; a project beats an area) and says so on stderr. It also notes when the target is completed, cancelled or in the Trash. (#343, #344, #390)add,editandproject add/editwarn when a list, heading or area will not resolve, using Things’ own title rules. (#352, #359, #367, #372)- The read-back checks the When bucket (Today, This Evening, Anytime, Someday or a date) as well as the list and heading. A
--whenor move Things ignores, or a reminder the item already has, returns at once instead of waiting. (#372, #382, #393, #398, #399) complete,cancel,edit --completeandedit --cancelon an item that is already in that state do nothing and exit 0. Switching an item between completed and cancelled is refused. (#384, #388)importreads back every item it creates, checks it landed where Things files it (following Things’ measured rules forlist,list-id,heading,heading-id,areaand nested items), checks acompletion-datewas kept, and exits non-zero naming each item that did not. (#355, #374, #391, #394, #397)- Checklist-only edits confirm. (#334)
addconfirms a to-do whose title had a newline (Things stores it as a space), and the search hint it prints on failure is safe to paste. (#404)edit --tags/--add-tagsnaming a tag Things does not have treats that tag as no change, so an edit that would otherwise be a no-op returns at once instead of waiting out the read-back and failing. (#330)- A row number from a listing of another database (
--db <backup>thencomplete 2) is refused, and the re-run command printed with a stale-row error keeps--config. (#337, #350) - To-dos inside a repeating project template count as repeating, so the writes Things drops silently on them are refused before anything is sent. (#340)
- The read-back accepts a new item in any open project or area sharing the requested title, instead of failing a correct
addorimportwhen titles collide. (#383) - A missing row during a status check is retried until the deadline rather than reported at once, and a second prompt in one command no longer loses the input the first one read ahead. (#333)
edit --when todayon an item still in Today from an earlier day is a no-op that returns at once, and--when <today's date>on it is no longer reported as misfiled. Things keeps such an item’s original start date; the docs now say so. A dropped write on one of these rows that still has its reminder is reported as not applied. (#408)
things update
- New command that updates the CLI the way it was installed (Homebrew,
go installor the release binary). It installs only the release it checked and stops if that check fails. It usesGH_TOKENorGITHUB_TOKENwhen set, and falls back to the github.com releases redirect when the API check fails. (#306, #308, #373, #380, #386)
Also
- “Today” is read once per query from one clock, so a listing that runs across midnight judges every row by the same day, and the day’s bounds are right in zones where midnight is skipped or repeated. (#396)
- Docs:
--include-completedis documented only where it is accepted; the config template’s exampledbpath now has theThingsData-XXXXX/segment; the database lookup is derived from$HOMEand--db/dbis the only override. (#406) - The docs site has a Changelog page built from the GitHub release notes, linked from the version on the home page. (#315)
- Go toolchain 1.26.9 (GO-2026-6617). (#411)
- The bundled skill and the docs at things.rlew.io are updated for all of the above. Run
things skill installafter upgrading.
Requirements
macOS with Things3 installed. Binaries for Apple Silicon (darwin_arm64) and Intel (darwin_amd64).
What’s Changed
🐛 Bug Fixes
- fix: render task timestamps in local time by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/283
- fix(output): stop escaping &, < and > in –json output by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/286
- fix(open): match –tag and –area names case-insensitively by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/284
- fix(db): ignore case beyond ASCII in name and title filters by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/287
- fix(list): list anytime tasks due later in upcoming, as the app does by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/288
Other Changes
- fix(output): fit task rows to narrow terminals by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/298
- fix(output): wrap things show detail values with a hanging indent by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/299
- feat(output): show a task’s start date beside its deadline by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/300
- fix(output): fit the project list and hint line to a narrow terminal by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/301
- fix(output): keep the project marker when a title is cut, fit group headers by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/302
- refactor(hint): let one terminal check decide the hint and its width by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/303
- test(output): pin the terminal check so no test reads the real stdout by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/304
- feat(output): cut over-long titles before dropping a column by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/305
- feat: add
things updateto update the CLI the way it was installed by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/306 - fix(output): end each row at its last filled cell by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/307
- fix(update): never downgrade, and run install.sh from the release tag by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/308
- feat(list): show checklist progress on task rows by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/309
- fix(output): wrap tabbed and list-like note lines under their text by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/310
- fix(output): drop checklist and start columns before cutting a title by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/311
- feat(output): switch dates to a compact form before dropping them by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/312
- feat(output): shorten tags to the first and a count before dropping them by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/313
- test(output): pin piped, wide-rune, dim-cut and tab/newline title rendering by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/314
- docs: add a changelog page built from the GitHub release notes by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/315
- refactor(output): measure table cells once and fit columns in one flat pass by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/316
- refactor(output): pass one layout to every printer, split task rows from headers by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/317
- fix(output): print tab and line-break titles on one line in listings by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/318
- feat(output): offer common next actions in the listing hint by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/319
- refactor(cmd): share the auth token read and warn on its errors by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/320
- refactor(db): finish the view table by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/321
- refactor(output): replace Print with typed printers and drop go-isatty by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/322
- refactor(things): share update params and URL building in UpdateCommon by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/323
- refactor(cmd): route prompts and warnings through Deps by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/324
- refactor(cmd): share complete/cancel in runStatusChange and the read-back loop in pollUntil by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/326
- test: export the db fixture via dbtest by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/325
- fix(db): trim surrounding spaces in list and projects name filters by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/327
- refactor(cmd): use one shell-quoting rule for printed commands by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/328
- refactor(cmd): share edit and project edit flags and Run in runEdit by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/329
- fix(edit): treat tags Things does not have as no change in the no-op check by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/330
- refactor(cmd): print show and confirmed edit output through printItem by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/331
- feat(add): read back the created item and print it as show does by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/332
- fix: retry a missing row in verifyStatuses, and keep stdin between prompts by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/333
- fix(edit): confirm a checklist-only edit by the checklist itself by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/334
- fix(list): show to-dos closed today in a named project under –include-completed by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/335
- fix(upcoming): show to-dos closed today under –include-completed by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/336
- fix(lookup): refuse a numeric ref from a listing of another database by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/337
- fix(add): tighten the read-back’s unreadable, hint and warning messages by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/339
- fix(repeating): treat to-dos inside a repeating project template as repeating by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/340
- fix(list): prefer an exact-case –project title over case variants by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/341
- fix(today): list undated to-dos whose deadline has come by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/342
- fix(add): warn when –list or –heading will not resolve, accept a uuid, read tags once by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/343
- fix: read import’s stdin and terminal check through Deps, update the no_verify comment, send area uuids as area-id by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/344
- fix(inbox): leave out undated to-dos whose deadline has come by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/347
- ci: pin govulncheck and let Renovate bump it by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/348
- fix(anytime): leave out to-dos of projects in Someday or scheduled later by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/349
- fix(cache): carry –config in a listing’s re-run command by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/350
- fix(project): order a project listing the way its page in the app does by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/351
- fix(project): warn when project add –area names no area by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/352
- fix(anytime): list undated Inbox to-dos whose deadline has come by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/354
- feat(list): allow –include-completed on a bare –area listing by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/353
- fix(inbox): keep a to-do closed out of the Inbox there until it is logged by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/356
- fix(import): read back the items an import creates by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/355
- fix(logbook): follow the app’s “Move completed items to Logbook” setting by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/357
- fix(list): prefer the exact-case name for –area and –tag by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/358
- fix(add): match –list and –heading titles untrimmed, as Things does by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/359
- chore(hooks): judge the main-branch guard by the repository each git command targets by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/360
- feat(db): fold names with full Unicode case folding by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/361
- fix(logbook): withhold every row Things has not logged yet by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/362
- fix(views): list a scheduled row Things has not moved yet under today by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/366
- fix(edit): warn when –list, –heading or –area will not match in Things by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/367
- fix(db): match names that differ only in Unicode normalisation by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/368
- chore(hooks): read the docs reminder’s staged files from the repository the commit targets by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/369
- fix(json): report a scheduled row Things has not moved yet as anytime by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/370
- fix(db): match project and area titles across Unicode compatibility forms by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/371
- fix(edit): treat a no-op move as applied and warn on unknown ids by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/372
- fix(update): never install blind when the release check fails by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/373
- fix(import): do not confirm an item with a dated item’s row by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/374
- fix(lookup): refuse an all-digit ref that is not a row in the last list by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/378
- test(today): record that a deadline move clears its suppression by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/379
- fix: pin or stop on odd release tags, run update script under bash, NFC read-back key by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/380
- fix(add): check a created item’s destination in the read-back by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/381
- fix(edit): treat a –when or empty notes append Things ignores as applied by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/382
- fix(add): accept any list sharing the requested title in the read-back by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/383
- feat(list)!: show closed items Things still shows by default by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/384
- fix(today): order rows by reference date, then todayIndex, as the app does by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/385
- fix(hooks): ignore git commands inside quotes and heredoc bodies by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/387
- feat(config): add open_only to make –open-only the default for listings by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/389
- fix(update): send a GitHub token and fall back to the releases redirect by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/386
- fix(edit): guard –complete and –cancel on closed items like complete and cancel by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/388
- fix(lookup): refuse +N and #N refs instead of matching title fragments by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/392
- fix(import): refuse dates Things rejects, name shares-dated-title candidates, decode once by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/391
- fix(add): check the list Things picks when titles fold together by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/390
- fix(edit): check the –when bucket in the read-back, and tell case-twin headings apart by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/393
- fix(import): check destinations the way Things files them by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/394
- fix(lookup): refuse any number-like ref that is not a row or an exact title by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/395
- test(edit): pin –when today on a row Things has not moved past midnight by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/398
- fix(import): follow-ups to the destination and date checks by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/397
- fix(edit): leave a row Things has not moved into today where it is for –when today by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/399
- fix(db): read today once per query from one clock by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/396
- fix(add): confirm a to-do whose title had a newline by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/404
- feat(output): show a to-do’s reminder time by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/405
- chore(go): bump toolchain to go1.26.9 for GO-2026-6617 by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/411
- fix: refuse writes to trashed items and print what complete/cancel closed by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/407
- fix(db): group area-less projects first and wait for the logbook fold by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/410
- fix: bring docs, skill and config template in line with the binary by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/406
- fix(edit): count a row in Today from an earlier day as filed today by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/408
- fix(import): refuse payloads Things rejects before sending by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/412
- test(import): pin the shares-dated-title clock by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/414
- fix(edit): refuse writes to a to-do whose project is in the Trash by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/416
- docs: fix drift between the docs, the skill, –help and the binary by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/417
- fix(import): refuse payloads Things saves differently from what they say by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/418
- fix(list): match the app’s rows in today, upcoming, –tag, search and projects by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/421
- fix(list): match Things.app row order in today, anytime, someday, trash, logbook and –area/–tag by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/420
- fix(refs): stop task refs resolving to an item the user did not name by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/422
- fix: make write commands report what Things does by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/423
- fix(import): read back each created item’s when as add does by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/428
- docs: add before/after screenshots of today for the v0.10.0 release notes by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/429
- docs(release): add v0.10.0 release notes header by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/430
Full Changelog: https://github.com/ryanlewis/things-cli/compare/v0.9.0...v0.10.0
v0.9.0
things-cli v0.9.0 — edits confirm what happened
things edit and things project edit used to exit 0 with no output, so an agent had to run things show to learn whether the change had landed. They now wait for Things to record the write and print the item, in the same form as things show, so one call does both. How long the CLI waits for that confirmation can now be configured. Two behaviour changes, below.
Behaviour changes
editandproject editprint the edited item. The output is the same asthings showfor that item, plain or--json. Anything that expected these commands to print nothing needs updating. (#280)- An edit Things drops now fails. The CLI waits for the item’s modification date to change and exits non-zero with
edit did not apply: …if it never does. Before, a dropped edit reported success. An edit that only re-sets values the item already has is caught before the wait when it uses--title,--notes,--tags,--add-tagsor a--deadlinedate. Any other flag,--whenincluded, still waits and reports the same error, because Things does not record a no-op as a change. The error says to check withthings show <uuid>before retrying. (#280)
Also
--no-verifyand--duplicateedits print a line saying the edit was sent but not confirmed, with"confirmed": falseand areasonunder--json, rather than printing nothing. (#280)- The read-back wait is configurable, with
--verify-timeoutor theverify_timeoutconfig key, and defaults to 5s. It applies to every write that is read back:complete,cancel,edit,project edit,importandtag add. In v0.8.0,complete,cancel,importandtag addwaited 10s before reporting a change as not applied; they now give up after 5s unless configured otherwise. (#281) - The bundled skill tells agents that exit 0 with the item printed means the edit is confirmed, and to put several changes to one item in a single
edit. Runthings skill installafter upgrading. (#280, #281)
Requirements
macOS with Things3 installed. Binaries for Apple Silicon (darwin_arm64) and Intel (darwin_amd64).
What’s Changed
Other Changes
- chore: add CODEOWNERS by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/279
- feat(edit): read the item back after an edit and print it by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/280
- feat: cut the write read-back wait to 5s and make it configurable by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/281
- docs(release): add v0.9.0 release notes header by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/282
Full Changelog: https://github.com/ryanlewis/things-cli/compare/v0.8.0...v0.9.0
v0.8.0
things-cli v0.8.0 — parity with the app’s lists
Every list in Things.app now has a CLI view that returns the same rows in the same order, projects included. Until now a project scheduled for Today was visible in the app and absent from things today, so an agent driving the CLI never saw it. Every view was measured against the app’s own lists by uuid, and every one of them now matches. Two JSON fields became words, listings are deterministic, agents are steered to UUIDs, and the code behind the views was reorganised so the next parity fix is one table entry. Two breaking changes, below.
Breaking changes: type and start are strings
type and start on task rows in every --json output were Things’ internal integers. They are now words, so a caller can tell a project from a task, or a deferred item from a scheduled one, without a lookup table. Anything matching on type == 1 or start == 2 must change. On input, the legacy integers are still accepted. start also appears on things projects -j rows. (#208, #214, #218, #223, #241, #251)
| Before | After |
|---|---|
"type": 0 | "type": "task" |
"type": 1 | "type": "project" |
"type": 2 | "type": "heading" (never returned by any command) |
"start": 0 | "start": "inbox" |
"start": 1 | "start": "anytime" (Today when it carries a date) |
"start": 2 | "start": "someday" (Upcoming when it carries a date) |
The word for a to-do is task everywhere the CLI speaks, in JSON values, error payloads, the agent brief and the docs. The one exception is the things import payload, which keeps Things’ own spelling to-do. Run things skill install after upgrading so agents pick up the new skill, which documents all of this.
Projects appear where the app shows them
- today, upcoming, someday, logbook, trash and deadlines include projects. A project scheduled, deferred, closed, trashed or due is a row with
"type": "project"in JSON and a(project)marker in plain text. anytime is the exception, as in the app: it lists a project’s tasks under the project as a group header rather than as a row. The bare--areaand--taglistings include projects too;--project Xnever matches a project itself. (#201, #205, #206, #209, #212, #216, #213, #220, #217, #236, #222, #232) - logbook includes cancelled items, with
statustelling them apart. (#210, #225) - logbook and trash fold a closed or trashed project’s tasks into the project’s row, as the app does; the same fold applies under
--include-completed. Ask for the project instead:things --project <uuid>on a closed project returns its tasks whatever their status, andthings show <uuid> --agentlists them with their real status marks instead of claiming the project has no open tasks. Logbook went from 1334 rows to the app’s 910 on the author’s data, row for row. (#229, #235, #249, #252, #253, #260) - Closed items file by calendar day. An item you close stays in Today and Anytime, struck through in the app, until midnight, then moves to the logbook.
things today --include-completedand the newthings anytime --include-completedshow them until then;--include-completedused to keep everything closed since the last “Log Completed Now”. (#230, #233, #238, #247) - someday no longer surfaces tasks that live inside a project. The app keeps a deferred task inside its project, whichever list the project is in; measured with a probe project created and deleted through the app.
things someday --project Xis now rejected like the other impossible filters. (#211, #228) - Naming a trashed project with
--project <uuid>reaches its contents in every view. The app returns a trashed project’s untrashed children when asked for them directly, and so does the CLI now, in today, anytime, logbook and the rest, not only in the barethings --projectform. Trash keeps its fold, so a task trashed on its own account inside a later-trashed project stays where the app keeps it. (#263, #273) - Repeating templates, headings and trashed items stay excluded from these views exactly as before.
Listings are ordered as the app orders them, and deterministically
- today, anytime and someday arrange rows as the app does: unfiled items first, then areas in area order, and inside an area its own tasks before those of its projects. upcoming is ordered by start date. Closed items shown under
--include-completedstay where they were rather than sinking to the end. (#217, #236, #237, #239) - Every view, search and lookup ordering ends in a total tiebreak, so the same list run twice numbers the same items the same way and
things complete 3acts on the row you read. Deadlines and logbook had no tiebreak at all. Numbers still move as items are added, closed or rescheduled. (#221, #226)
Agents: use UUIDs, and --json no longer touches the row cache
- A
--jsonlisting no longer writes the numbered-row cache. JSON output never showed row numbers, so a JSON listing could only move the numbers a person had just read, and two agents on one machine could race each other into completing the wrong task. Numeric references keep resolving against the last plain-text listing. The bundled skill and https://things.rlew.io/agents/ now tell agents to use--jsonand act onuuid, never on row numbers, with every example resolving a UUID first. Thanks to @davidolrik for the report. (#246, #261) things skill installhonours each agent’s config-directory variable:$CLAUDE_CONFIG_DIRfor Claude Code (thanks to @davidolrik for the fix),$CODEX_HOMEfor Codex and$PI_CODING_AGENT_DIRfor Pi, each with that tool’s own rule for tilde expansion. (#227, #234, #250, #254)things projects -jreportsstart,startDateanddeadline, and itstaskCountandopenCountare documented, with a recipe for finding projects with no open tasks and the caveats that go with it. (#202, #204, #203, #207)- References and filters match literally. A task reference, a search query and the
--project,--areaand--tagfilters used to be SQL LIKE patterns, sothings complete '20_30 review'could resolve to and complete20:30 review, andthings search '50%'matched everything.%and_are now characters to find. (#262, #266, #267, #268) - Row numbers expire after four hours. The numbered-row cache now records when the listing ran and which command printed it, and a bare number against a listing older than four hours is refused with an error that names the listing to re-run, or the UUID to use instead, under the stable token
stale list cache. A cache written by an older release counts as stale, so the first numeric reference after upgrading asks for a fresh listing. (#265, #271) - A title shared by a project and a task is an ambiguity, not a coin toss.
things project edit Choresused to resolve the first row with that title, land on the task and recommend a retry that edited the wrong item. An exact title that matches more than one open item now returns the existingambiguous taskerror listing each candidate with its type and UUID, so the caller picks by UUID. (#194, #270) - The jq
selectexamples in the agent docs were missing.[] |and failed against the JSON array; all are fixed. (#225)
Under the hood
Each list view is now described once, in one table, with a golden test that pins the exact SQL for every view, filter and flag combination; the four copies of the column renderer became one; main.go was split by command group; the status, type and start codecs share one implementation. None of this changes output: it was verified byte for byte against the previous binary across hundreds of live invocations. (#240, #242, #243, #248, #258, #259, #264)
Also
editandproject editrefuse the wrong kind of reference with the same structured error instead of opening athings:///updateURL for the wrong kind of item. (#190, #193, #219, #231)- An empty listing that names a repeating project template says so.
things --project <template>prints a one-line note on stderr that the template’s tasks are not listed, instead of an unexplained empty result. (#174, #272) - The reference site at https://things.rlew.io moved to Hugo with a new landing page, an agents page, a social preview image and analytics, and rebuilds on each release. Local builds stamp version, commit and date. (#183, #185, #186, #188, #192, #195, #198)
Requirements
macOS with Things3 installed. Binaries for Apple Silicon (darwin_arm64) and Intel (darwin_amd64).
What’s Changed
Other Changes
- build: stamp version, commit and date into local builds by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/183
- docs: add an animated demo to the README by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/184
- docs: add a Working with agents page and make the site the reference by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/185
- ci(pages): build the site with Hugo by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/186
- ci(pages): let workflow_dispatch deploy again by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/187
- feat(site): replace Jekyll with a Hugo site and new landing page by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/188
- fix(edit): refuse a project reference instead of opening things:///update by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/190
- ci(site): derive the site version from tags and rebuild on release by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/192
- fix(project edit): refuse a to-do with the same structured error as edit by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/193
- feat(site): add Umami analytics by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/195
- chore(claude): remind agents to keep the site docs in step with the CLI by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/196
- ci(site): ignore pre-release tags for the site version by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/197
- feat(site): add a social preview image and structured data by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/198
- chore(og): render the social image with Go instead of Python by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/199
- build: pin the Go toolchain with a toolchain directive by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/200
- fix(projects): report start, startBucket, startDate and deadline by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/204
- fix(list): include scheduled projects in today, upcoming and anytime by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/205
- docs(projects): document taskCount and openCount by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/207
- fix(list): include projects in someday and logbook by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/209
- feat(output)!: render type as a string in JSON by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/214
- fix(list): include projects in trash by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/216
- fix(list): include projects in deadlines by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/220
- feat(output)!: spell the to-do type value task, not todo by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/223
- fix(list): include cancelled items in logbook by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/225
- fix(list): make view ordering deterministic by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/226
- fix(list): keep project to-dos out of someday by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/228
- chore(output): say task, not to-do, in the –json error kind by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/231
- fix(list): carry projects in the bare-filter catch-all view by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/232
- fix(list): file closed items by the calendar day, not manualLogDate by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/233
- fix(list): fold a closed or trashed project’s to-dos into its row by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/235
- fix(list): match the app’s anytime and upcoming arrangement by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/236
- fix(list): arrange today and someday the way the app does by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/239
- feat(list): show items closed today in anytime under –include-completed by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/247
- chore(cli): split main.go by command group by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/248
- feat(model)!: render start as a string and share one enum codec by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/251
- fix: Honour $CLAUDE_CONFIG_DIR by @davidolrik in https://github.com/ryanlewis/things-cli/pull/234
- fix(list): fold closed-project to-dos out of the –include-completed views by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/252
- fix(skill): honour $CODEX_HOME and $PI_CODING_AGENT_DIR by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/254
- docs: state the project rule once, and call a task a task by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/255
- docs: say task for the CLI’s concept across the site and README by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/257
- refactor(db): describe each list view in one table by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/258
- refactor(db): move the flag-validation maps into the view table by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/259
- fix(list): let a named project lift the closed-project fold by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/260
- fix(list): do not write the row cache under –json by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/261
- refactor(output): one column renderer, one kind word, one status text by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/264
- fix(list): match –project, –area and –tag values literally by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/266
- fix(lookup): match a task reference and a search query literally by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/268
- test(db): one fixture builder instead of fourteen per-view seeds by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/269
- fix(lookup): report an exact title that matches more than one row by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/270
- feat(cache): expire the numbered rows after four hours by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/271
- fix(list): reach a trashed project’s children by naming it in any view by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/273
- feat(list): say why a repeating project template lists nothing by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/272
- docs(release): add v0.8.0 release notes header by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/275
- build(goreleaser): drop the deprecated homebrew_casks url.verified key by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/276
- docs(release): keep the v0.8.0 projects section as one list by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/277
New Contributors
- @davidolrik made their first contribution in https://github.com/ryanlewis/things-cli/pull/234
Full Changelog: https://github.com/ryanlewis/things-cli/compare/v0.7.0...v0.8.0
v0.7.0
things-cli v0.7.0 — a config file, tag creation, and output an agent can trust
A TOML config file for persistent defaults, tag creation from the CLI, a things show --agent hand-off format, a repeating view, machine-readable --json errors, and fixes to what lookups and views return.
Settings live in a file now
~/.config/things-cli/config.tomlsupplies defaults forjson,color,db,no_verify,strict_tags,create_tags,assume_yesandhints. Flags still win per run.--config PATHorTHINGS_CLI_CONFIGpoint at another file,$XDG_CONFIG_HOMEis honoured, and the file is optional: without one,thingsruns on its built-in defaults.things config path,config showandconfig init(writes a commented template) round it out. Unknown keys and malformed TOML fail with one line naming the file. Full reference at https://things.rlew.io/configuration/. (#159, #160)assume_yesis scoped tocompleteandcancel; it cannot reachskill uninstall, whose--yesmeans delete. (#158, #169)
Tags can be created from the CLI
things tag add <name>...creates tags over AppleScript, skipping names that already exist (case-insensitive) and reading the tag list back to confirm.--create-tagsonadd,edit,project add,project editandimportcreates the unknown tags before the write instead of warning.--create-tagswith--strict-tagsis rejected. Tag names are escaped for AppleScript. (#144, #150)
Handing a to-do to an agent
things show <ref> --agentprints a self-contained Markdown brief: the to-do, its notes and checklist, and the exact UUID-based commands to close it out, ready forthings show 3 --agent | claude -p "action this". Plainlistandsearchoutput on a terminal ends with a one-line hint;--no-hintsorhints = falseturns it off. Notes are fenced and labelled as content so a to-do cannot forge the closing-out section. (#153, #172)--jsonis now non-interactive and its errors are JSON. An ambiguous or missing ref no longer opens the picker or prints help text to stdout; you get one object with a stableerrortoken (ambiguous task,not found,import refused,import partially applied, orerror), the message, the query and the candidates or per-item details. Exit codes match the plain path. (#152, #157, #161, #166, #164, #168)--yes/-yoncompleteandcancelskips the project confirmation, sothings --json complete <project> --yesworks from a script. (#158, #169)
Lookups and views return what they claim
- Project headings never come back as tasks from
show,edit,complete,cancel,open,searchor the numeric index cache. A heading with the same title as a to-do no longer makes the lookup ambiguous. (#146, #149) - Repeating templates have their own view.
things repeatinglists to-do and project templates (projects marked(project)), and they are gone fromsomeday, the catch-all project view andthings projects. Generated instances were never affected and still list in today and upcoming. (#147, #154, #165, #170) - A title shared by a template and its generated to-do resolves to the to-do, so
things complete "Water plants"no longer hits the repeating refusal while an actionable instance exists. The template is still reachable by UUID or fromthings repeating. (#156, #163) - To-dos under a trashed project are hidden in inbox, today, upcoming, anytime, someday and deadlines, not just the filtered views.
trashandlogbookstill show them. (#155, #162) - To-dos inside a repeating project template are hidden from the same views, since the app only shows the generated copies. (#171, #173)
importwithoperation: updategoes through the repeating check and the read-back. A payload that sets when, deadline, completed or canceled on a repeating item is refused whole, with the path of each offending item, before anything is sent. Status changes are read back after the write with one shared timeout.completed: falseandcanceled: falsecount as status changes, andcanceledtakes priority overcompleted, as the Things docs specify. (#145, #151)- The
things tag addsuggestion printed for unknown tags is now shell-quoted, and--json=1,-jvand other flag spellings render parse errors as JSON. (#164, #168)
Also
- Import checks resolve every item in one query per round instead of one per item. (#167, #175)
- The bundled agent skill was reorganised and audited against every
--help;openis no longer described as a write, and theskill,configandtagcommands are covered. Runthings skill installagain to pick it up. (#176)
Requirements
macOS with Things3 installed. Binaries for Apple Silicon (darwin_arm64) and Intel (darwin_amd64).
What’s Changed
Other Changes
- fix(db): exclude project headings from task lookups by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/149
- fix(views): keep repeating templates out of someday, add repeating view by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/154
- feat(tags): create tags from the CLI by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/150
- fix(cli): make –json non-interactive and emit errors as JSON by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/157
- fix(import): apply the repeating check and status read-back to update items by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/151
- feat(config): add a TOML config file for persistent flag defaults by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/160
- fix(views): hide to-dos whose project is in the trash by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/162
- fix(db): resolve a shared title to the to-do, not the repeating template by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/163
- feat(json): add per-item details to import failures under –json by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/166
- fix(views): list repeating project templates, hide them from things projects by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/170
- fix(cli): correct –json parse-failure handling and the tag hint’s quoting by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/168
- feat(complete): add –yes to complete and cancel so projects work non-interactively by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/169
- fix(views): hide the to-dos inside a repeating project template by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/173
- feat(show): hand a to-do to an agent with
things show <ref> --agentby @ryanlewis in https://github.com/ryanlewis/things-cli/pull/172 - perf(db): batch the per-item uuid lookups in the import checks by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/175
- docs(skill): reorder the bundled skill around what an agent needs first by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/176
- docs: give configuration its own page on the docs site by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/178
- fix(config): keep the config diagnostics working when the file is unusable by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/180
- docs(site): add configuration tab to locale by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/181
- docs(config): describe the config file as optional by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/182
- docs(release): add v0.7.0 release notes header by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/177
Full Changelog: https://github.com/ryanlewis/things-cli/compare/v0.6.0...v0.7.0
v0.6.0
things-cli v0.6.0 — filters that tell the truth, writes that fail loudly
Four fixes from recent use, three of them about the CLI quietly reporting the wrong thing. Two new flags.
Filters no longer under-report
--project,--areaand--tagnow search all open tasks by default instead of the Today view. Naming a project previously returned only its Today slice while the header just printed the project name; one project showed 8 tasks where there were 59. An explicit view still wins and is now labelled in the header when combined with a filter. (#140, #142)- Tasks nested under a project heading are included in project and area filters, and
showreports their project and area. They were invisible before because Things stores the project on the heading row, not the task. (#139, #142) - Tasks left open under a trashed project no longer leak into filtered output.
- Behaviour change:
things today "Chores"now means today within Chores. It used to silently switch to the whole-project view.
Complete and cancel now verify the write landed
- Repeating to-dos and projects are refused up front. Things silently drops status, when and deadline changes on repeating items through both the URL scheme and AppleScript, so
cancelused to exit 0 and change nothing. The CLI now checks for a recurrence rule and refuses with a message naming the blocked attributes.showprints aRepeats:line and JSON carries"repeating": true. (#129, #143) - Every complete and cancel reads the status back from the database and exits non-zero if it did not change. A new global
--no-verifyskips the check.edit --complete --canceltogether is now rejected. (#143)
Unknown tags are no longer dropped silently
- Things ignores tags that do not already exist.
add,edit,project add,project editandimportnow warn on stderr for each unknown tag, and--strict-tagsrefuses to write at all. Matching is case-insensitive, as Things treats tag names. Creating tags from the CLI is still open as #144. (#102, #141)
Also
- Dependency bumps: modernc sqlite v1.57, kong v1.16.1, lipgloss v2.0.6. (#118)
- Release pipeline egress allowlist narrowed to the Apple notary bucket. (#138)
Requirements
macOS with Things3 installed. Binaries for Apple Silicon (darwin_arm64) and Intel (darwin_amd64).
What’s Changed
📦 Dependencies
- fix(deps): update all non-major dependencies by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/118
Other Changes
- docs(release): unwrap v0.5.3 header prose for GitHub rendering by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/136
- docs(release): unwrap older release header prose by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/137
- fix(release): narrow S3 egress wildcards to Apple notary bucket by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/138
- fix: project, area, and tag filters under-report by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/142
- fix: refuse writes Things drops on repeating items, and verify status changes landed by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/143
- feat(tags): warn on unknown tags and add –strict-tags by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/141
- docs(release): add v0.6.0 release notes header by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/148
Full Changelog: https://github.com/ryanlewis/things-cli/compare/v0.5.3...v0.6.0
v0.5.3
things-cli v0.5.3 — signed and notarized binaries
Infra release: no CLI changes. The binaries themselves are the feature.
Release pipeline
- Darwin binaries are now Developer ID–signed and notarized by Apple. Both architectures are signed and notarized before archiving, so the tarballs, checksums, and provenance attestations all cover the signed Mach-O. Gatekeeper accepts the binary without any quarantine workaround — the cask’s
xattr -d com.apple.quarantinehack is gone. (#130) - Release job egress is now blocked by default with an explicit endpoint allowlist (previously audit-only), limiting what a compromised dependency or action could exfiltrate — the job holds signing keys now. (#130)
One caveat: bare Mach-O binaries can’t have the notarization ticket stapled, so Gatekeeper does an online check on first run. Fine for normal installs; only bites a fully-offline first run.
Requirements
macOS with Things3 installed. Binaries for Apple Silicon (darwin_arm64) and Intel (darwin_amd64).
What’s Changed
Other Changes
- feat(release): sign + notarize darwin binaries, lock down release egress by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/130
- docs(release): add v0.5.3 release notes header by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/131
- fix(release): allow goreleaser.com in egress allowlist by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/132
- fix(release): cap notarize timeout at 20m by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/133
- fix(release): allow timestamp.apple.com:80 in egress allowlist by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/134
- fix(release): allow Sigstore public-good endpoints for attestation by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/135
Full Changelog: https://github.com/ryanlewis/things-cli/compare/v0.5.2...v0.5.3
v0.5.2
things-cli v0.5.2 — timestamps back from 2057
Patch release: one bug fix.
Fixes
creationDateandstopDateare no longer 31 years in the future. Things stores its absolute timestamps (task creation, task and checklist completion) as Unix-epoch seconds, but they were decoded against Apple’s Core Data reference date (2001-01-01) — so a task created on 2026-08-09 reported"creationDate": "2057-08-09T…"in--jsonoutput. Anything sorting or filtering on those fields downstream would misbehave. Scheduling fields (startDate,deadline) use a different encoding and were always correct. (#127)
No CLI surface changes — if you parse creationDate/stopDate from --json output, the values are simply right now.
Requirements
macOS with Things3 installed. Binaries for Apple Silicon (darwin_arm64) and Intel (darwin_amd64).
What’s Changed
Other Changes
- fix(db): decode creationDate/stopDate as Unix epoch, not Core Data by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/127
- docs(release): add v0.5.2 release notes header by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/128
Full Changelog: https://github.com/ryanlewis/things-cli/compare/v0.5.1...v0.5.2
v0.5.1
things-cli v0.5.1 — cancel projects, honest empty JSON
Patch release: two bug fixes with a supply-chain hardening pass riding underneath.
Fixes
things cancelnow works on projects. It previously routed every reference through the task-only AppleScript path, so cancelling a project failed with a raw osascript error. Projects now cancel properly, behind the same interactive confirmationcompleteuses — cancelling a project cascades to its tasks. (#125)- Empty
--jsonresults emit[], notnull. All list-shaped commands (list,search,projects,areas,tags) returnednullfor an empty result, which breaksjq '.[]'pipelines — including the ones documented in the bundled agent skill. (#124) - Date filters on
somedayare rejected instead of silently matching nothing. Someday items have no start date, so--on/--from/--tocould never match; the CLI now says so instead of returning empty output, and the README no longer advertises the impossible combination. (#124)
Small improvements
show,complete, andcancelhelp text now documents the numeric-index reference form (things list today; things complete 3) — it always worked, but onlyeditadmitted it. (#125)things projectsgains the-ashort flag for--area, matchinglistandopen. (#125)
Supply chain
- Release artifacts now carry build provenance attestations.
install.shverifies them automatically when the GitHub CLI is present (and refuses to install on a failed verification); check any artifact yourself withgh attestation verify things_<version>_darwin_arm64.tar.gz -R ryanlewis/things-cli. (#122, #123) - CI hardening: govulncheck (gating + weekly Security-tab scan), CodeQL, dependency review, and a locked-down release pipeline. (#122)
Requirements
macOS with Things3 installed. Binaries for Apple Silicon (darwin_arm64) and Intel (darwin_amd64).
What’s Changed
📦 Dependencies
- fix(deps): update all non-major dependencies by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/113
- chore(deps): update actions/setup-go action to v7 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/117
- chore(deps): update actions/checkout digest to 3d3c42e by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/116
- chore(deps): update golangci/golangci-lint-action digest to ba0d7d2 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/114
- chore(deps): update goreleaser/goreleaser-action digest to f06c13b by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/115
Other Changes
- docs: fix staleness in README and GitHub Pages site by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/111
- chore: adopt the shared Renovate config by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/119
- chore: pin actions to SHAs, default token to read-only by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/120
- chore(ci): harden-runner egress audit on the release job by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/121
- ci(security): hardening — provenance, scanning, workflow lockdown by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/122
- feat(install): verify build provenance via gh attestation by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/123
- fix(output): emit [] instead of null for empty –json results by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/124
- fix(cancel): route projects through project-capable AppleScript by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/125
- docs(release): add v0.5.1 release notes header by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/126
Full Changelog: https://github.com/ryanlewis/things-cli/compare/v0.5.0...v0.5.1
v0.5.0
things-cli v0.5.0 — clearer JSON status, leaner today
Minor release. Two behaviour changes worth a look before you upgrade any automation, plus dependency maintenance.
Behaviour changes
- JSON
statusis now a string.Task,Project, andChecklistItemstatusfields render as"open"/"cancelled"/"completed"in JSON instead of the raw Things integers (0/2/3). The bare ints were an implementation detail that read like a rank. Plain-text output is unchanged. The decoder still accepts both the string name and the legacy integer, and any unrecognised code round-trips as its number — but consumers that parse our JSONstatusas a number will need to read it as a string. (#107, closes #105) things todayexcludes completed tasks by default. It now returns only open tasks; completed/cancelled items Things still shows in Today are available behind a new--include-completedflag (UI-parity). For automation, “in today” now means “still to do”. (#109, closes #106)
Maintenance
- Bumped
lipgloss,golang.org/x/term,golang.org/x/sys, andmodernc.org/sqlite;actions/checkout→ v7 in CI. (#100, #108)
Requirements
macOS with Things3 installed. Binaries for Apple Silicon (darwin_arm64) and Intel (darwin_amd64).
What’s Changed
📦 Dependencies
- chore(deps): update actions/checkout action to v7 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/108
- fix(deps): update all non-major dependencies by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/100
Other Changes
- feat(output): emit human-readable status string in JSON by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/107
- fix(today): exclude completed tasks by default, add –include-completed by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/109
- docs(release): add v0.5.0 release notes header by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/110
Full Changelog: https://github.com/ryanlewis/things-cli/compare/v0.4.2...v0.5.0
v0.4.2
things-cli v0.4.2 — fix --when rejecting weekday names
Patch release. things add --when monday was incorrectly rejected with “did you mean today?”. The --when typo detector flags any value within Levenshtein distance 2 of a keyword, and monday is exactly distance 2 from today — so it was mistaken for a typo despite being a valid natural-language date Things accepts.
Fix
- Weekday names and their abbreviations (
monday…sunday, plusmon,tue,wed,thu,fri,sat,sunand common variants) now bypass the typo detector and pass through to Things verbatim. Verified against Things3 that each resolves to the correct upcoming scheduled date. - Genuine typos (
tommorrow,evning, …) are still rejected as before.
Requirements
macOS with Things3 installed. Binaries for Apple Silicon (darwin_arm64) and Intel (darwin_amd64).
What’s Changed
Other Changes
- fix(when): stop rejecting weekday names like “monday” by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/103
- docs(release): add v0.4.2 release notes header by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/104
Full Changelog: https://github.com/ryanlewis/things-cli/compare/v0.4.1...v0.4.2
v0.4.1
things-cli v0.4.1 — fix Homebrew completion install
Patch release. v0.4.0 added shell completions, but the Homebrew cask passed the shell name as --shell=bash (Homebrew’s :arg format) while things completions takes the shell as a positional argument. The mismatch made brew install print “Failed to generate … completions” warnings and write no completion files.
Fix
- The cask now calls
things completions bash|zsh|fishwith the shell as a bare positional argument (Homebrew’s default whenshell_parameter_formatis omitted), matching the CLI.brew install/brew upgradenow generates the bash, zsh, and fish completion files as intended.
If you installed v0.4.0 from Homebrew, run brew update && brew reinstall ryanlewis/tap/things to pick up working completions.
Requirements
macOS with Things3 installed. Binaries for Apple Silicon (darwin_arm64) and Intel (darwin_amd64).
What’s Changed
Other Changes
- fix(release): use positional shell arg for cask completions by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/97
Full Changelog: https://github.com/ryanlewis/things-cli/compare/v0.4.0...v0.4.1
v0.4.0
things-cli v0.4.0 — shell completions
things <TAB> now completes subcommands, flags, and enum values in bash, zsh, and fish. Homebrew sets it up for you; everyone else runs one line.
Headline
- Shell completions for bash, zsh, and fish (#94, #95). The Homebrew cask generates them on install, so
brew install ryanlewis/tap/thingsgives youthings <TAB>with no extra steps. On other install paths, load them yourself —source <(things completions bash),source <(things completions zsh), orthings completions fish | source. Completions are driven from the live command tree, so they never drift from the CLI: subcommand names, flag names, and enum values like--color auto|always|never.
Under the hood
- Migrated styling to lipgloss v2 (
charm.land/lipgloss/v2) (#93). No visible change tolist/showoutput; JSON (-j) stays script-stable. - Routine dependency updates (#83, #91, #92).
Docs
- The bundled agent skill (
things skill show/ installedSKILL.md) now spells out everythings openflag (-p/-a/-t/-q/--filter/--background) and theedit/project editprepend/append/checklist/*-idflags instead of trailing...(#89). Reinstall it (things skill install claude,…codex,…pi) to pick up the new text.
Requirements
macOS with Things3 installed. Binaries for Apple Silicon (darwin_arm64) and Intel (darwin_amd64).
What’s Changed
📦 Dependencies
- chore(deps): update dependency golangci/golangci-lint to v2.12.1 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/83
- fix(deps): update all non-major dependencies by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/91
- chore(deps): update golangci/golangci-lint-action digest to 82606bf by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/92
- chore(deps): update goreleaser/goreleaser-action digest to 5daf1e9 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/11
Other Changes
- docs(skill): document things open flags and edit prepend/append by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/89
- docs(release): add v0.3.2 release notes header by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/90
- fix(deps): migrate to lipgloss v2 (charm.land/lipgloss/v2) by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/93
- feat(cli): generate shell completions by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/94
- feat(release): ship shell completions in the cask by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/95
- docs(release): add v0.4.0 release notes header by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/96
Full Changelog: https://github.com/ryanlewis/things-cli/compare/v0.3.1...v0.4.0
v0.3.1
things-cli v0.3.1 — clean uninstall
Patch release: the Homebrew cask now ships a zap stanza so a full uninstall cleans up after itself.
Change
- Cask
zap trash:now lists~/Library/Caches/things-cli(the last-list cache that backsthings complete 1-style indices), sobrew uninstall --zap thingsleaves no orphan state behind (#86)
Plain brew uninstall things still leaves the cache alone — zap only fires with --zap (or brew zap things separately), so a routine uninstall + reinstall keeps your indices intact.
Requirements
macOS with Things3 installed. Binaries for Apple Silicon (darwin_arm64) and Intel (darwin_amd64).
What’s Changed
Other Changes
- feat(release): zap things-cli cache on cask uninstall by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/86
- docs(release): add v0.3.1 release notes header by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/87
Full Changelog: https://github.com/ryanlewis/things-cli/compare/v0.3.0...v0.3.1
v0.3.0
things-cli v0.3.0 — Homebrew tap, date filters, polished output
Install with brew install ryanlewis/tap/things and start slicing your lists by date — plus a fresh coat of lipgloss styling on list and show.
Headline
- Homebrew cask —
brew install ryanlewis/tap/things(auto-published from each release intoryanlewis/homebrew-tap) - Date-range list filters — narrow any list with
--on,--from, and--to(#81) - Styled output —
listandshownow render with lipgloss; JSON output (-j) is unaffected and remains script-stable
Fixes
things todaykeeps completed items visible until youlogthem, matching the Things app (#74)ThingsDatemarshals asYYYY-MM-DDin JSON output (was a packed integer) (#79)
Docs
- Install page surfaces Homebrew as the recommended option
- Skill docs cover bulk reschedule, the auth-token flow, and weekday
--whenparsing (#80)
Requirements
macOS with Things3 installed. Binaries for Apple Silicon (darwin_arm64) and Intel (darwin_amd64).
What’s Changed
📦 Dependencies
- chore(deps): update dependency ruby to v4 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/66
- chore(deps): update dependency golangci/golangci-lint to v2.12.0 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/75
Other Changes
- fix(release): blank line before changelog separator by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/67
- docs(site): add prominent GitHub CTA on home page by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/68
- fix(pages): pin Ruby to 3.4.9 for Chirpy compatibility by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/69
- feat(docs): replace bird favicon with checkbox avatar by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/71
- docs(site): swap GitHub CTA for shields.io badges by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/70
- feat(output): style list/show output with lipgloss by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/72
- fix(today): keep completed items visible until logged by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/74
- fix(model): marshal ThingsDate as YYYY-MM-DD in JSON output by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/79
- docs(skill): document bulk reschedule, auth-token, weekday –when by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/80
- feat(list): filter by –on / –from / –to date ranges by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/81
- feat(release): publish Homebrew cask to ryanlewis/homebrew-tap by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/84
- docs(release): add v0.3.0 release notes header by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/85
Full Changelog: https://github.com/ryanlewis/things-cli/compare/v0.2.0...v0.3.0
v0.2.0
things-cli v0.2.0 — more writes, safer writes
A bigger surface area for writing back to Things3, plus client-side validation so the URL scheme can’t silently swallow bad input. The docs now live at things.rlew.io.
New commands
things edit— update existing tasks (title, notes, when, deadline, tags, checklist, project, area) via the URL schemethings open— reveal a task, project, or area in the Things3 appthings import— batch-create items from a JSON payload using thethings:///add-jsonschemethings project add/things project edit— create and update projectsthings skill— install the bundled Claude Code skill (also supports Codex and Pi agents) so an AI assistant can drivethings-clicorrectly
Quality of life
--whenand--deadlineare validated and normalized before being sent to Things- URL-scheme size and field limits are checked client-side, with clear errors instead of a silently truncated task
things todayordering now matches the Things app (projects and area-only items grouped by area index)--todos/--checklistcorrectly expand literal\nin arguments
Docs
- Project site published at things.rlew.io — install guide, command reference, about page
- README rewritten with grouped command tables and capabilities above the fold
Requirements
macOS with Things3 installed. Binaries for Apple Silicon (darwin_arm64) and Intel (darwin_amd64).
What’s Changed
📦 Dependencies
- fix(deps): update all non-major dependencies by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/51
- chore(deps): update actions/checkout action to v6 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/58
- chore(deps): update actions/configure-pages action to v6 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/59
- chore(deps): update actions/deploy-pages action to v5 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/62
- chore(deps): update actions/upload-pages-artifact action to v5 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/63
- chore(deps): update dependency ruby to v3.4.9 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/55
Other Changes
- docs(claude): add workflow rules to CLAUDE.md by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/16
- feat: add
things project addto create projects via URL scheme by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/21 - feat: add
things editto update tasks via URL scheme by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/26 - chore: block commits to main via hook; strengthen workflow docs by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/27
- feat: add
things opento reveal items in Things3 by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/28 - feat: add
things skillcommand group with bundled Claude Code skill by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/29 - docs: document
things skillcommand in README by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/32 - feat: add
things project editto update projects via URL scheme by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/35 - feat: add
things importfor batch JSON URL scheme by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/36 - feat(things): validate URL scheme limits client-side by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/37
- feat: validate and normalize –when / –deadline values by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/38
- fix(skill): emit valid SKILL.md from bare
skill showby @ryanlewis in https://github.com/ryanlewis/things-cli/pull/40 - refactor(add): stop sending auth-token to things:///add by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/41
- refactor: simplify validators, URL-scheme setters, and runOpen resolution by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/42
- fix(today): align CLI Today view with the Things app by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/43
- refactor: dispatch kong subcommands via Run methods by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/44
- docs(readme): convert command docs to grouped tables by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/45
- feat(skill): add Codex and Pi agents to bundled skill installer by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/48
- docs: add github pages site (chirpy) under /docs by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/53
- fix(docs): add locale entries for install/commands tabs by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/56
- docs: serve site at things.rlew.io by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/57
- fix(docs): drop duplicate site name from home page by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/60
- docs: drop home-page badges and credit Cultured Code by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/61
- fix(today): order projects and area-only items by area index by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/52
- docs: credit Cultured Code on install + about pages by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/64
- docs(readme): spell out capabilities above the fold by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/49
- docs(release): add v0.2.0 release notes header by @ryanlewis in https://github.com/ryanlewis/things-cli/pull/65
New Contributors
- @ryanlewis made their first contribution in https://github.com/ryanlewis/things-cli/pull/16
Full Changelog: https://github.com/ryanlewis/things-cli/compare/v0.1.0...v0.2.0
v0.1.0
🎉 First release — things-cli v0.1.0
A command-line interface for Things3 on macOS. Reads tasks, projects, areas and tags directly from the Things3 SQLite database (read-only) and writes via the official things:/// URL scheme and AppleScript — so Things stays the source of truth and your data never leaves the machine.
Highlights
- Read anything —
things today,things inbox,things upcoming, project/area/tag filters, full-textthings search, andthings showwith numeric references into the last list - Write safely —
things addcreates tasks via the Things URL scheme;things complete/things cancel/things logdrive Things via AppleScript - JSON everywhere —
-jon any command emits structured output for piping intojq - Pure Go — single static binary, no cgo, no external SQLite dependency (
modernc.org/sqlite) - Installable three ways
curl -fsSL https://raw.githubusercontent.com/ryanlewis/things-cli/main/install.sh | sh(verifies checksums)go install github.com/ryanlewis/things-cli/cmd/things@latest- Download a tarball from this release and drop the binary onto your
PATH
Requirements
macOS with Things3 installed. Binaries for Apple Silicon (darwin_arm64) and Intel (darwin_amd64).
What’s Changed
📦 Dependencies
- chore: Configure Renovate by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/1
- fix(deps): update module github.com/mattn/go-isatty to v0.0.21 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/2
- fix(deps): update module modernc.org/sqlite to v1.49.1 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/3
- chore(deps): update actions/checkout action to v6 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/7
- chore(deps): update actions/setup-go action to v6 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/8
- chore(deps): update golangci/golangci-lint-action action to v9 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/9
- chore(deps): update goreleaser/goreleaser-action action to v7 by @renovate[bot] in https://github.com/ryanlewis/things-cli/pull/10
New Contributors
- @renovate[bot] made their first contribution in https://github.com/ryanlewis/things-cli/pull/1
Full Changelog: https://github.com/ryanlewis/things-cli/commits/v0.1.0