slingsync pulls Slack List items and creates Things3 to-dos.
- 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).
- 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.
pip install slingsync
slingsync --helpuv tool install slingsync
slingsync --help- Create app: api.slack.com/apps
- Add scope
lists:read - Install/reinstall app to workspace
- Copy token (
xoxb-...or user token)
- 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.
No repo clone is required for the global config flow.
Config lookup order:
--config /path/to/config.json$SLINGSYNC_CONFIG~/.config/slingsync/config.json
First run bootstrap:
slingsync --dry-runIf ~/.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 protected]"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.
uv run slingsync \
--dry-runuv run slingsync \
--filter-completed false \
--filter-assigned-user-id \
--deadline-column "todo_due_date" \
--dry-runuv run slingsync \
--filter-completed false \
--filter-assigned-user-id \
--dry-runRemove --dry-run to apply.
uv run slingsync \
--no-two-way-sync \
--dry-runuv run slingsync \
--no-delete-missing--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.
--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.
--target-list: Things list destination (defaultInbox).--target-project: Destination project (mutually exclusive with area).--target-area: Destination area (mutually exclusive with project).
--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.
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}'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).