Sync Slack Lists into Things3 with two-way completion sync
Project description
Slack List -> Things3 Sync
slingsync pulls Slack List items and creates Things3 to-dos.
What It Does
- Reads Slack List items using
slackLists.items.list. - Creates Things3 to-dos via AppleScript.
- Avoids duplicates using a persisted state file.
- By default, deletes previously synced Things3 to-dos if the Slack item is gone or marked completed (
--delete-missingenabled by default). - By default, runs two-way completion sync: marks Slack items completed when mapped Things to-dos are completed (
--two-way-syncenabled by default).
Requirements
- macOS with Things3 installed.
- Python 3.9+.
uvinstalled (docs) only if you useuv tool,uvx, oruv run.- Slack token with
lists:read. - For two-way completion sync, token also needs
lists:write.
Install from PyPI
pip
pip install slingsync
slingsync --help
uv tool
uv tool install slingsync
slingsync --help
Slack Setup
- Create app: api.slack.com/apps
- Add scope
lists:read - Install/reinstall app to workspace
- Copy token (
xoxb-...or user token)
IDs You Need
How to find List ID and Team ID
- Open the Slack List in your browser.
- Copy the URL. It looks like:
https://XXX.slack.com/lists/TXXX/FXXX
- Extract:
- Team ID: the
T...segment (workspace/team) - List ID: the
F...segment (the list itself)
- Team ID: the
Use in config:
- Required: set
list_idin your config JSON. - Recommended: set
team_idin your config JSON.
Config File
No repo clone is required for the global config flow.
Config lookup order:
--config /path/to/config.json$SLINGSYNC_CONFIG~/.config/slingsync/config.json
Global config
First run bootstrap:
slingsync --dry-run
If ~/.config/slingsync/config.json does not exist, the command auto-creates it with empty keys.
Then edit ~/.config/slingsync/config.json.
Then set values:
{
"slack_token": "xoxb-XXX",
"list_id": "FXXX",
"team_id": "TXXX",
"assigned_user_id": "UXXX"
}
Look up your Slack member ID (for assigned_user_id):
curl -sS -G https://slack.com/api/users.lookupByEmail \
-H "Authorization: Bearer xoxb-XXX" \
--data-urlencode "email=you@XXX.com"
Read user.id from the response and put it in your config file.
If you get missing_scope, add users:read.email (and usually users:read) then reinstall the app.
assigned_user_id is used when you pass --filter-assigned-user-id.
Common Runs
Minimal run
uv run slingsync \
--dry-run
Dry run + open items + configured assignee filter + deadline mapping
uv run slingsync \
--filter-completed false \
--filter-assigned-user-id \
--deadline-column "todo_due_date" \
--dry-run
Default behavior includes deletion reconcile (preview first)
uv run slingsync \
--filter-completed false \
--filter-assigned-user-id \
--dry-run
Remove --dry-run to apply.
Disable Two-way completion sync
uv run slingsync \
--no-two-way-sync \
--dry-run
Disable deletion reconcile
uv run slingsync \
--no-delete-missing
Argument Reference
Slack
--config: explicit config JSON path (highest priority).$SLINGSYNC_CONFIG: config JSON path env override.- Default config path:
~/.config/slingsync/config.json. - Config values:
slack_token,list_id, optionalteam_id, optionalassigned_user_id. --include-archived: Include archived Slack items.--lookup-user-id: Lookup Slack member ID by email and exit.--lookup-email: Email for--lookup-user-id.
Field Mapping And Filters
--title-column: Column key/id used as Things title.--notes-column: Column key/id used as Things notes.--deadline-column: Column key/id used for Things deadline.--completed-column: Column key/id for completion state.--assigned-column: Column key/id for assignee.--status-column: Column key/id for status.--filter-completed {true|false|open|completed|...}: include only matching completion state.--filter-assigned-user: match assignee by name substring (case-insensitive).--filter-assigned-user-id/--no-filter-assigned-user-id: enable/disable assignee filter by configured Slack member ID. If enabled and noassigned_user_idis set in the resolved config file, the script exits with an error.--filter-status: include only status value.--exclude-status: exclude status value.--debug-filter-fields: print parsed status/assignee/completed fields per item.
Things Target
--target-list: Things list destination (defaultInbox).--target-project: Destination project (mutually exclusive with area).--target-area: Destination area (mutually exclusive with project).
Execution
--dry-run: Preview only, no writes.--state-file: Custom state file path.--max-items: Process only first N fetched items.--two-way-sync/--no-two-way-sync: enable/disable pushing Things completion back to Slack (default: enabled).--delete-missing/--no-delete-missing: enable/disable deletion reconcile (default: enabled).- Reconcile deletes when a previously synced Slack item is either missing from the list or marked completed.
Safety rule:
--delete-missing(default on) cannot be used with--max-items.- If you need
--max-items, add--no-delete-missing.
State File
Default:
~/.config/slingsync/state/slack_to_things_<LIST_ID>.json
Use --state-file to override.
Quick API check:
curl -sS -X POST https://slack.com/api/slackLists.items.list \
-H "Authorization: Bearer xoxb-XXX" \
-H "Content-Type: application/json; charset=utf-8" \
-d '{"list_id":"FXXX","team_id":"TXXX","limit":1}'
Automation Permission
First run may prompt macOS automation permission to control Things3. If denied accidentally, reset and retry:
tccutil reset AppleEvents com.apple.Terminal
(or reset iTerm2 bundle id if you use iTerm).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file slingsync-0.2.tar.gz.
File metadata
- Download URL: slingsync-0.2.tar.gz
- Upload date:
- Size: 14.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
60acf647e218273ce55b3b46dc4d0f7c448734f78b6d17ff4a86d2dfcdb61bb5
|
|
| MD5 |
8b962a63d2d14a07a192deb6aad4b11f
|
|
| BLAKE2b-256 |
fef9c054da6a3d1867dca78334ec7365902eb7f8e044a1a66d41aa97d0e1f52d
|
File details
Details for the file slingsync-0.2-py3-none-any.whl.
File metadata
- Download URL: slingsync-0.2-py3-none-any.whl
- Upload date:
- Size: 17.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0fb3462936314c1caf6988159fcd9224df122cd81b7760c2ed6e9f7afc675fda
|
|
| MD5 |
13725907d38a78bab530ea19e026fdb8
|
|
| BLAKE2b-256 |
008653269530e08655da429d3f1cb7ce4fbcc54f8ea44dcccec393682fbb2ae9
|