agentleFS
damslethdamsleth/SKILLS/cj-things/SKILL.md

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.

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
  1. Distinctive:

    Use the damsleth/things3-cli fork of ossianhempel/things3-cli: it adds field-clearing via empty flag values, which upstream silently drops.

    line 11
  2. Very specific:

    If things is missing, say so and stop.

    line 36
  3. Very specific:

    When another skill (or you) needs to *parse* the output rather than show it, add --json.

    line 73
  4. Very specific:

    Default table output uses columns UUID TITLE PROJECT AREA HEADING STATUS TRASHED.

    line 88
  5. Very specific:

    Never print the token. Pass it inline, and redact auth-token= from any echoed URLs (sed -E 's/auth-token=[^&" ]+/auth-token=REDACTED/g').

    line 155
  6. Very specific:

    If secret reports the name unknown, fall back to manual setup:

    line 158
  7. Very specific:

    UUIDs, not guesses: Always resolve a UUID via a read (tasks/search/show) before update/delete.

    line 176
  8. Distinctive:

    Keep responses tight: when listing, curate to what matters rather than dumping the whole backlog (a Things DB can have hundreds of tasks).

    line 178

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

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 today

General-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 containers

Useful 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> --json

Gotcha: 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 = notes

Common 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 complete

update 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 shape

Delete (needs Automation permission)

things delete --id=<UUID> --confirm=<UUID>   # non-interactive single delete
things delete --id=<UUID>                    # interactive, prompts for confirmation

Bulk 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> --completed

Never 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:

  1. Things 3 → Settings → General → Things URLs → enable/copy the token.
  2. export THINGS_AUTH_TOKEN=<token> (add to ~/.zshrc to persist).
  3. Re-run things auth to confirm.

Reads and add/delete don't need it.

Safety

  • Preview before bulk writes. --dry-run prints 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 (tasks with the same filters, or delete --dry-run) first.
  • Background by default. Writes open Things in the background; pass --foreground only if the user wants the app brought forward.
  • UUIDs, not guesses. Always resolve a UUID via a read (tasks/search/show) before update/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. now merges things all --json with repo .plans/ and ADO work items, so planning skills (cj-daily, cj-notes, a weekly review) call now --agent when it is installed, not things today/upcoming/deadlines. Come here for the rest: the logbook (things logtoday / logbook; now excludes completed work by design), tag/query filters, things areas --json for a --list-id, and every mutation. Deferred work is now --upcoming, not things 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.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.