BIBLIOGRAPHY
History
Related-Notes
매뉴얼
그대로 가져왔다. 검토 필요. 동작이 잘 된다.
Org Todoist: What is it?
An Emacs package for bidirectional incremental sync of Org Mode elements with Todoist using org exactly how you normally would in Emacs Org Mode.
Key features
- CRUD1 tasks
- CRUD1 new sections
- CRUD1 new projects
- Refile tasks and sections to other sections and projects
Org Todoist also supports collaboration with other users via assigning tasks and notifications.
How it works
Commands are automatically detected and batched by diffing the current org-todoist-file
with the abstract syntax tree from a snapshot of the previous sync and nodes are updated in place using a single asynchronous request, meaning metadata (such as time tracking information and additional properties) is retained.
Syncing is done using the Todoist sync API, which sends a single request for both pulling and pushing. Local changes will overwrite remote changes!
Installation
Doom Emacs
(package! org-todoist
:recipe (:host github
:repo "lillenne/org-todoist"
:branch "main"
:files ("org-todoist.el")))
Usage
Bidirectional sync
;; Unless ARG, go to the Todoist buffer.
(org-todoist-sync &optional ARG)
Local changes will overwrite remote changes!
To automatically sync at a given interval, unless the org-todoist-file
is visited by the active buffer:
(run-at-time nil 180 #'org-todoist-background-sync)
Mapping org headlines to Todoist objects
Org | Todoist |
---|---|
Headline | Project, Section, or Task |
Plain-text under headline | Description |
Scheduled | Due |
Deadline | Deadline |
Effort | Duration |
Priority | Priority |
Todo-state + Todo-keyword | Checked, Deleted |
Tags (+inherited) | Labels |
org-archive-tag | Archive projects + sections |
Responsible UID property | Assignee |
See the next section to learn the mapping rules for projects, sections, and tasks.
Creating projects, subprojects, sections, tasks, and subtasks
Simply create org headlines! The corresponding Todoist types (projects, subprojects, sections, tasks, and subtasks) will be inferred from the org structure. Sections will be preferred over subprojects unless the TODOIST_TYPE
property is set to PROJECT
. A new subproject can be created quickly using the interactive function org-todoist-add-subproject
. If a TODO item does not fall under a project, it will be assigned to the default section of the Inbox project.
Level | Todoist Type |
---|---|
1 | Project |
2+ | Section or Subproject |
TODO | Task |
Updating projects, sections, and tasks
Updating items happens automatically when updating any headline, description, todo-state, todo-keyword4, priority, effort, tag, scheduled time, deadline time, or assignee OR when any project, section, or task is moved under another headline. This works with standard org commands (e.g., org-refile
).
Deleting items
When the org-todoist-delete-remote-items
variable is non-nil, removing items from the org-todoist-file
(via deletion or refiling) will cause them to be deleted from Todoist. Additionally, items can be deleted by changing their todo-keyword
to the org-todoist-deleted-keyword
.
Tags, labels, and archiving
Org tags are mapped directly to Todoist labels and support inherited tags. Note, inherited tags will also be applied directly to the child tasks on next sync.
Projects and sections can be archived in Todoist by applying the org-archive-tag
to the headline. Note, you cannot archive the default section and if you do locally on your org document it will not be synced.
Comments and notifications
Comments are done via org-add-note
and currently ( ) do not support editing or deletion from org mode. Within comments, other users can be notified via the org-todoist-tag-user
command, which will prompt for completion of the desired user, send a request to notify them in the comment’s note_add command, and input a special markdown syntax into the comment which will property display as @<User> in the Todoist app. If you prefer to use the org link syntax and have it look funny in the Todoist app, set org-todoist-comment-tag-user-pretty
to non-nil.
;; Inserts the special tag from the todoist app that formats to @User
;; & adds the user id to uids_to_notify in the request
(org-todoist-tag-user)
;; non-nil to format in org link syntax instead of markdown for better viewing in org but worse in the Todoist app
(setq org-todoist-comment-tag-user-pretty nil)
Assigning Tasks
(org-todoist-assign-task) ;; Prompts for user selection and changes the responsible uid property to the user's id
(org-todoist-unassign-task) ;; Removes the responsibile uid property
Ignoring subtrees
If you’d like to keep other notes or TODOs alongside your projects and not have them synced to Todoist, you can mark a subtree as ignored by setting the TODOIST_TYPE
property to IGNORED
using M-x org-todoist-ignore-subtree
. Any org element descendent from an ignored node will not have its changes pushed to Todoist.
Org capture to a Todoist project section
Captures will automatically sync by default via the org-capture-finalize-hook
. If you would like to change this behavior, run (remove-hook 'org-capture-after-finalize-hook #'org-todoist--sync-after-capture)
.
Sample capture templates:
(setq org-capture-templates `(
;; Capture a TODO directly to the inbox
("i" "Inbox" entry
(file+olp ,(org-todoist-file) "Inbox" ,org-todoist--default-section-name)
"* TODO %?")
;; Capture to a specific project, section, and parent task, creating them if needed.
;; Also prompts for tags, effort, task assignment, scheduled, and deadline times
;; Projects are determined by projectile if possible, otherwise via an interactive prompt
("p" "Select project, section, and parent task" entry (function org-todoist--find-project-and-section)
"* TODO %^{What is the task} %^G %^{EFFORT}p %(org-todoist-assign-task) %(progn (org-schedule nil) nil) %(progn (org-deadline nil) nil)\n%?")
;; Capture a note to an ignored subtree
("n" "Project Notes" entry (function org-todoist-project-notes) "* %?")))
(Currently) unsupported features
[X] = Implemented
[-] = WIP or implemented with caveats
[ ] = Not currently supported
- [-] Essential task items
- [-] Recurring tasks2
- Quick add
- [-] Comments
- [-] Item comments
- Add and pull (plain-text only)
- Sort by time added
- Update
- Delete
- [-] Notify other users
- Project comments
- Add
- Update
- Delete
- Notify other users
- [-] Item comments
Quirks
- Once a task has been permanently deleted in Todoist, changing the TODO state in org will be reset back to org-todoist-deleted-keyword on next sync. Todoist does not support reviving permanently deleted tasks.
- Comments on subtasks are added to both the root task and the subtask on Todoist, which is reflected here.
- The org element API does not properly parse property drawers if anything besides is put above them (e.g. adding your description above the property drawer), so don’t do that!
Configuration
NOTE: To match Todoist’s 4 priority structure, this package sets the user’s org-priority-highest
org-priority-lowest
and org-priority-default
values.
Required
Org Todoist requires a Todoist API token to function.
(setq org-todoist-api-token "<your-token>")
Additionally, Todoist markdown lists use 4 spaces vs the default 2 spaces for org plain lists. This is compenated for by using a file-local variable in the org-todoist-file
header to set org-list-indent-offset
to 2 (2 base + 2 offset = Todoist’s 4). However, this means that when accessing the file for the first time, you will be prompted to allow “potentially unsafe” file-local variables. You must accept this or manually set the value otherwise this may cause sync errors.
Optional
org-todoist-delete-remote-items
- If non-nil, delete items no longer present in the org todoist buffer after the last sync. This will also delete tasks refiled or archived to a separate file from Todoist.org-todoist-file
- The file to use for Todoist tasks.org-todoist-use-auto-reminder
- If newly created tasks should use Todoist’s default reminder. Defaultt
.org-todoist-show-n-levels
- The fold level of the org buffer after sync, with caveats. See docstring. Default show all.org-todoist-todo-keyword
- New tasks are given this keyword.org-todoist-done-keyword
- Completed tasks are given this keyword.org-todoist-deleted-keyword
- Tasks with this keyword are deleted remotely.org-todoist-storage-dir
- Directory for storing Todoist sync_tokens and the previous org file for detecting changes to push. If using multiple computers and a synced file solution, this directory must be accessible on all PCs.org-todoist-my-id
- (Currently unused) Your todoist ID. This will be inferred if your name is Todoist matchesuser-full-name
. Otherwise, you can set this property to the value of “tid” in the property drawer under “Todoist Metadata” > “Collaborators” > “<your-name>“.
Troubleshooting
For troubleshooting errors, you can use the following variables and methods:
org-todoist-log-last-request
- Set to non-nil to log the last outgoing request to theorg-todoist--last-request
variableorg-todoist-log-last-response
- Set to non-nil to log the last response json to theorg-todoist-sync-dir
and alist toorg-todoist--last-response
. Anyorg-todoist--push-test
- Returns the detected diff commands.
Why?
Org mode is an excellent planning and note-taking tool, but struggles in a few areas:
- Collaboration with others
- Mobile app features / availability (shoutout to Orgzly for their great android app)
- Sync between devices (I personally use Syncthing which works well, but will often have conflicts when adding from the widget)
Todoist fills these gaps and, more importantly, my wife uses it.
There is currently another great integration for org-mode and todoist, but it takes a fundamentally different approach (stateless on-demand regeneration using many requests with the REST API vs stateful syncing with a single request to the sync API that can be queried by Orgzly on mobile and buffer creation with org.el vs org-element-api).
Contributing, Issues, and Feature Request
Feel free to submit an issue or feature request! When submitting issues please see the troubleshooting section and attach the response json (or at least the error information). I’ll do my best to address issues timely and evaluate feature additions. I work full time and have two very young (0-3) boys, so if there is a feature you want to add please feel free to submit a PR yourself!
Todoist API Data
My personal test API call data is included in the repo to show the API return format and help my own development but is protected with sops. If you need data for any reason, please use your own.
To test interacting with the Todoist API using curl with your own data, you can use the following commands. Note, Todoist has many great examples using curl in their API documentation.
curl https://api.todoist.com/sync/v9/sync \
-H "Authorization: Bearer <token> " \
-d sync_token='sSK9OCkrXyWsUjMU0g6iuS05TwAKhmceWSiL7FCho_p2SRb23dpApCsv9u_P2jyidIDJqjE94dzOeB-1JnipI5wJRl01N8ZdaeTBdMUbxvWZavpF' \
-d resource_types='["all"]'
curl https://api.todoist.com/sync/v9/sync \
-H "Authorization: Bearer <token>" \
-d commands='[
{
"type": "item_complete",
"uuid": "a74bfb5c-5f1d-4d14-baea-b7415446a871",
"args": {
"id": "<task-id>"
}
}]'
Not on Roadmap
Things that I am not currently planning to implement (myself! you are welcome to!) due to time restrictions or it not being important to my workflow:
- File attachments
- Filters (use org agenda for this)
- Location notifications
- Updating or deleting comments
- Markdown support
- Activity log
- View options
- Templates (use org capture templates for this)
Footnotes
-
Recurring tasks only support a subset of Todoist scheduling features. e.g. Todoists “every mon, fri” is not easily recreatable using org mode. These tasks should still be pulled down correctly from Todoist on next sync. ↩ ↩2
-
Assignee is a Todoist-only idea, but is supported via the [BROKEN LINK: Collaboration] commands. ↩
-
Changing todo-keywords only triggers an update if the todo-state changes or the keyword is the
org-todoist-deleted-keyword
. ↩