cj-things
Skill1 starsChanged 32 days agoMITView on GitHub
Manage Things 3 (Cultured Code) tasks, projects, and areas from the terminal via the `things` CLI, with full CRUD plus the standard read views (today, upcoming, inbox, deadlines, logbook) with JSON output. Use when the user wants to add / list / complete / update / delete a Things task or project, capture a todo into Things, or needs the Things-only detail (logbook, tags, queries) that the cross-surface view leaves out. For what's open across relevant task surfaces, use cj-now instead. Pairs with cj-notes to turn captured notes into real tasks.
In this repository19 other files it gives its agents.
- AGENTS.mdAGENTS.md
- cj-abSkill
- cj-ambitionSkill
- cj-automateSkill
- cj-cloudflare-workerSkill
- cj-code-reviewSkill
- cj-dailySkill
- cj-meetingsSkill
- cj-notesSkill
- cj-nowSkill
- cj-owa-toolsSkill
- cj-todoSkill
- cj-uxloopSkill
- cj-video-visionSkill
- cj-voice-dnaSkill
- repo-deepSkill
- repo-depsSkill
- repo-groomSkill
- repo-healthSkill
The file
We split this skill into the rules it gives an agent
8 rules. About 0 are common, 2 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 11
Use the damsleth/things3-cli fork of ossianhempel/things3-cli: it adds field-clearing via empty flag values, which upstream silently drops.
- Very specific: line 36
If things is missing, say so and stop.
- Very specific: line 73
When another skill (or you) needs to *parse* the output rather than show it, add --json.
- Very specific: line 88
Default table output uses columns UUID TITLE PROJECT AREA HEADING STATUS TRASHED.
- Very specific: line 155
Never print the token. Pass it inline, and redact auth-token= from any echoed URLs (sed -E 's/auth-token=[^&" ]+/auth-token=REDACTED/g').
- Very specific: line 158
If secret reports the name unknown, fall back to manual setup:
- Very specific: line 176
UUIDs, not guesses: Always resolve a UUID via a read (tasks/search/show) before update/delete.
- Distinctive: line 178
Keep responses tight: when listing, curate to what matters rather than dumping the whole backlog (a Things DB can have hundreds of tasks).
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
cj-things
Overview
things is a macOS CLI for Things 3 by Cultured Code.
Use the damsleth/things3-cli fork of
ossianhempel/things3-cli: it adds
field-clearing via empty flag values, which upstream silently drops.
It talks to the app three ways, which is what decides whether a command needs setup:
- Reads (
today,tasks,search,show, …) query the local SQLite database. The DB lives in the Things app sandbox, so the terminal needs Full Disk Access to read it. - Adds (
add,add-project,add-area) go through the Things URL scheme. No token. - Updates (
update,update-project,update-area) also use the URL scheme but require an auth token (THINGS_AUTH_TOKEN). See Auth. - Deletes (
delete,delete-project,delete-area) use AppleScript, so they need Automation permission and a confirmation, but no token.
macOS only. Run things help <command> for the authoritative flag list, or read
references/commands.md for the full surface.
Boot
command -v things # the fork, installed from damsleth/things3-cli
things --version # CLI + detected Things.app version
things auth # token status, required only for `update*`If things is missing, say so and stop. Do not fabricate task data. If a read errors with a
database/permission message, the terminal likely lacks Full Disk Access; tell the user to
grant it in System Settings → Privacy & Security → Full Disk Access.
Reading tasks
Predefined views (each is read-only and accepts the same filter flags as tasks):
things today # what Things would show in Today (incl. predicted/repeating)
things upcoming # scheduled for the future
things inbox # unsorted inbox
things deadlines # everything with a hard deadline
things anytime # the Anytime backlog
things someday # the Someday backlog
things logbook # completed/canceled history
things logtoday # completed todayGeneral-purpose list + lookup:
things tasks # all incomplete, non-trashed todos
things tasks --project="Work" --tag=urgent # filter by project / area / tag
things tasks --search="invoice" # substring match on title or notes
things tasks --query='title:/deploy/ AND tag:work' # rich query: boolean + regex + fields
things search "standup" # search todos & projects by substring
things show --id=<UUID> # one item, exact; --recursive for checklists
things projects # things areas # things tags # list the containersUseful flags on every read command: --status=incomplete|completed|canceled|any,
--limit=N / --offset=N, date filters (--due-before, --created-after, --modified-after, …),
and --no-header to drop the column header.
JSON for programmatic use
When another skill (or you) needs to parse the output rather than show it, add --json.
This is the integration backbone. Prefer it over scraping the table:
things today --json
things tasks --project="Work" --json
things show --id=<UUID> --jsonGotcha: show --json returns a sparse object: unset and most non-core fields
are omitted entirely, so jq '.deadline' yields null whether the field was cleared
or never serialized. Fine for existence/title lookup; to verify a field update,
read back via things tasks --search/--query --json or the matching view
(deadlines, upcoming, …), which emit the full task shape.
Default table output uses columns UUID TITLE PROJECT AREA HEADING STATUS TRASHED.
The UUID is the stable handle. Capture it from a read, then pass it to update/delete
via --id=. Never guess a UUID.
Writing tasks
Add (no token needed)
things add "Call the dentist"
things add "Draft Q3 report" --notes="Pull numbers from the dashboard first" \
--when=today --deadline=2026-06-20 --tags=work,writing --list="Work"
printf 'Title line\nNote line one\nNote line two\n' | things add - # first line = title, rest = notesCommon add flags: --notes, --when=DATE|DATETIME (e.g. today, tomorrow, 2026-06-10,
or someday), --deadline=DATE, --tags=a,b, --list="Project or Area" (or --list-id=ID),
--heading, --checklist-item="…" (repeatable), and repeat flags (--repeat=day|week|month|year,
--repeat-every=N, …). add-project / add-area create containers.
Update & complete (needs token)
Completing a todo is an update, and there is no separate complete command:
things update --id=<UUID> --completed # mark done
things update --id=<UUID> --when=tomorrow --tags=work # reschedule / retag
things update --id=<UUID> --canceled # cancel instead of completeupdate mirrors add's mutation flags (--notes, --when, --deadline, --tags,
--add-tags, --completed, --canceled, --list, --heading) and is identified by --id.
Bulk update via query filters (same as tasks) is possible but requires --yes.
Clearing a field: pass an empty value (a fork feature; upstream drops empty flags from the URL, making this a silent no-op there):
things update --id=<UUID> --deadline="" # remove the deadline
things tasks --search="<title>" --json # verify via the tasks shapeDelete (needs Automation permission)
things delete --id=<UUID> --confirm=<UUID> # non-interactive single delete
things delete --id=<UUID> # interactive, prompts for confirmationBulk delete via query filters needs --confirm=delete --yes.
Auth (only for updates)
update* commands need a Things URL-scheme token in THINGS_AUTH_TOKEN.
On this machine the token lives in 1Password and resolves via the secret helper
(~/.config/zsh/secrets.zsh), so there is no need to touch the Things UI:
source ~/.config/zsh/secrets.zsh 2>/dev/null # required in harness/non-interactive shells:
# the snapshot has a stale `secret` fn and loses
# OP_SECRETS. Trailing compdef error is harmless;
# don't `&&` directly after source.
tok=$(secret THINGS_AUTH_TOKEN -p)
THINGS_AUTH_TOKEN="$tok" things update --id=<UUID> --completedNever print the token. Pass it inline, and redact auth-token= from any echoed
URLs (sed -E 's/auth-token=[^&" ]+/auth-token=REDACTED/g').
If secret reports the name unknown, fall back to manual setup:
- Things 3 → Settings → General → Things URLs → enable/copy the token.
export THINGS_AUTH_TOKEN=<token>(add to~/.zshrcto persist).- Re-run
things authto confirm.
Reads and add/delete don't need it.
Safety
- Preview before bulk writes.
--dry-runprints the URL (writes) or the matched set (bulk update/delete) without touching anything. Use it whenever a query could match more than one todo. - Confirm destructive ops. Deletes are real. Confirm with the user before
delete, and never run a bulk query-delete without showing the matches (taskswith the same filters, ordelete --dry-run) first. - Background by default. Writes open Things in the background; pass
--foregroundonly if the user wants the app brought forward. - UUIDs, not guesses. Always resolve a UUID via a read (
tasks/search/show) beforeupdate/delete. Don't act on a stale or assumed ID. - Keep responses tight: when listing, curate to what matters rather than dumping the whole backlog (a Things DB can have hundreds of tasks).
Integration with other skills
This skill is the single front door to Things writes for the rest of the suite, and to
the Things-only reads now doesn't carry.
- cj-now is where the planning skills read from.
nowmergesthings all --jsonwith repo.plans/and ADO work items, so planning skills (cj-daily, cj-notes, a weekly review) callnow --agentwhen it is installed, notthings today/upcoming/deadlines. Come here for the rest: the logbook (things logtoday/logbook;nowexcludes completed work by design), tag/query filters,things areas --jsonfor a--list-id, and every mutation. Deferred work isnow --upcoming, notthings upcoming. - cj-notes captures human-facing notes. When a note contains a concrete, actionable
next step ("send X", "follow up with Y"), offer to push it to Things with
things add "<task>" --notes="<context / link back to the note>"so the action doesn't get lost in prose. Keep the note as the record; Things holds the do. - Capture flow generally: anything the user says like "add that to my tasks", "put it in
Things", "remind me to…" →
things add. Confirm the title (and project/when if obvious) in one line; don't over-ask.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

