Things3's feature design follows the GTD (Getting Things Done) methodology. Understanding these concepts helps us build the right CLI tool.
Area
├── Project
│ ├── Heading (grouping header, not a task)
│ │ ├── To-Do
│ │ │ └── Checklist Item
│ │ └── To-Do
│ └── To-Do
└── To-Do (belongs directly to Area, not inside a project)
Tag (can be attached to To-Do, Project, Area)
The most basic unit. Attributes:
- Title + Notes (notes support Markdown formatting, including links, bold, italic, lists, etc.)
- When (scheduled date): determines which list it appears in. Supports natural language input such as "tomorrow", "in 3 days", "next tuesday"
- Deadline: independent of when
- Reminder: reminder time (triggers on the start date). Can only be set via Shortcuts; URL Scheme does not support this
- Tags: multiple tags (supports inheritance — a project's tags are automatically applied to its sub-tasks)
- Checklist: up to 100 sub-items
- Status: incomplete / completed / canceled
A completable collection of tasks with a defined endpoint. Can be grouped internally using Headings. A project itself also has when/deadline/tags/notes.
Completing or canceling a project requires all its to-dos to be completed or canceled first.
An ongoing area of responsibility (e.g., "Work", "Home") with no completion state. Used to organize projects and standalone to-dos.
A grouping header inside a project; it is not a task itself. In the database type = 2. Can have an archived state.
A tag system with hierarchical structure (via TMTag.parent self-reference). For example, "Places" can have child tags "Home" and "Office". Keyboard shortcuts can be assigned to tags. Tags must be created before they can be used in URL Scheme (URL Scheme cannot create tags; only AppleScript and manual operations can).
A sub-item inside a to-do, with its own completion state. Maximum 100 per to-do.
Things' lists are not storage locations — they are views that are dynamically computed based on rules.
| List | Content | DB Equivalent |
|---|---|---|
| Inbox | Uncategorized new tasks | start = 0 |
| Today | Tasks to do today + overdue tasks | startDate = today or deadline <= today, dynamically computed |
| Upcoming | Tasks with a future startDate | startDate > today |
| Anytime | Tasks that can be done at any time | start = 1 |
| Someday | Tasks to maybe do later | start = 2 |
| Logbook | Completed/canceled tasks | status IN (2, 3) |
| Trash | Deleted tasks | trashed = 1 |
Today is not a simple database query — it is dynamically composed of three parts:
- Normal Today tasks: incomplete tasks with
start=Anytimeand astartDatevalue - Unacknowledged scheduled tasks (indicated by a yellow dot): tasks with
start=Somedayand astartDatein the past — the user previously scheduled them but they were moved to Someday, and Things prompts the user to confirm - Unacknowledged overdue tasks: tasks without a
startDatebut with an expireddeadline, that have not been dismissed by the user (deadlineSuppressionDateis empty or has expired)
Ordering uses a separate todayIndex field.
When an overdue task appears in Today, the user can dismiss it. Things sets deadlineSuppressionDate to the current day, removing it from Today until the date changes and it is re-evaluated. This concept is critical for correctly implementing the Today list.
when=evening is a sub-state of Today — the task is in the Today list but marked as "evening".
things:///show?id=tomorrow can be used to view tasks with a startDate of tomorrow.
This is the most important design distinction in Things:
- When (scheduled date): "When do I plan to start working on this?"
- Determines which list the task appears in (Today/Upcoming/Someday)
- Can be vague (today/evening/someday)
- Deadline: "What is the latest this must be completed by?"
- Independent of when
- When the deadline is reached, the task automatically appears in Today
A task can have both a when and a deadline. For example:
- When: next Monday (planning to start next Monday)
- Deadline: next Friday (must be done by Friday)
Things supports recurring tasks, but with special limitations:
- Identified in the database via
rt1_recurrenceRule - URL Scheme cannot modify the when/deadline/completed fields of recurring tasks
- Recurring tasks cannot be duplicated via URL Scheme
- Most queries should filter out the template rows of recurring tasks
Things uses 22-character base32-encoded UUIDs (e.g., TryhwrjdiHEXfjgNtw81yt). These can be obtained by:
- Reading the
uuidfield from the database - In Things, Control-click → Share → Copy Link (the link contains the UUID)
- The
x-things-idreturned by URL Scheme
Things internally supports a contact/delegation feature (TMContact table, linked via TMTask.contact), but this is not a core feature exposed in the user interface. The field exists in the database but has limited practical use.
- Capture: Quickly drop into Inbox (URL Scheme
addwithout specifying a list) - Organize: Assign from Inbox to a Project/Area, set when/deadline/tags
- Execute: Check the Today list and complete tasks
- Area: "Work", "Personal", "Health" — persist indefinitely
- Project: "Finish the report", "Renovate the kitchen" — have a defined endpoint
- By location: "Office", "Home", "On the go"
- By tool: "Computer", "Phone"
- By energy: "High energy", "Low energy"
- By priority: "Important"
Someday is a parking lot for "things I might do later" — it should be reviewed regularly, not forgotten.
Based on the concepts above, the CLI tool should:
- Read commands corresponding to built-in lists:
inbox,today,upcoming,anytime,someday,logbook - Browse commands:
projects,areas,tags, filter by project/area/tag - Search: full-text search of title + notes
- Create: via URL Scheme add/add-project
- Modify: via URL Scheme update (requires auth-token and UUID)
- Navigate: via URL Scheme show to open Things and jump to a specific item
Key principle: reads go through the database, writes go through URL Scheme. More complex operations (Heading management, Reminder setting, individual Checklist Item operations) require Shortcuts. Area and Tag management requires AppleScript.