Skip to main content

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-missing enabled by default).
  • By default, runs two-way completion sync: marks Slack items completed when mapped Things to-dos are completed (--two-way-sync enabled by default).

Requirements

  • macOS with Things3 installed.
  • Python 3.9+.
  • uv installed (docs) only if you use uv tool, uvx, or uv 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

  1. Create app: api.slack.com/apps
  2. Add scope lists:read
  3. Install/reinstall app to workspace
  4. Copy token (xoxb-... or user token)

IDs You Need

How to find List ID and Team ID

  1. Open the Slack List in your browser.
  2. Copy the URL. It looks like:
    • https://XXX.slack.com/lists/TXXX/FXXX
  3. Extract:
    • Team ID: the T... segment (workspace/team)
    • List ID: the F... segment (the list itself)

Use in config:

  • Required: set list_id in your config JSON.
  • Recommended: set team_id in your config JSON.

Config File

No repo clone is required for the global config flow.

Config lookup order:

  1. --config /path/to/config.json
  2. $SLINGSYNC_CONFIG
  3. ~/.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, optional team_id, optional assigned_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 no assigned_user_id is 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 (default Inbox).
  • --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).

Metadata

Release files for slingsync 0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for slingsync 0.2
File Size Uploaded
slingsync-0.2.tar.gz 14.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for slingsync 0.2
File Interpreter ABI Platform
slingsync-0.2-py3-none-any.whl Python 3 none any Details

Total release size: 32.8 kB

Release files / slingsync-0.2.tar.gz

Download URL slingsync-0.2.tar.gz
Size 14.9 kB
Tags Source
SHA-256 checksum
How to use checksums
60acf647e218273ce55b3b46dc4d0f7c448734f78b6d17ff4a86d2dfcdb61bb5
BLAKE2b-256 checksum
How to use checksums
fef9c054da6a3d1867dca78334ec7365902eb7f8e044a1a66d41aa97d0e1f52d
Upload date
Uploaded using Trusted Publishing?
What is 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}

Release files / slingsync-0.2-py3-none-any.whl

Download URL slingsync-0.2-py3-none-any.whl
Size 17.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0fb3462936314c1caf6988159fcd9224df122cd81b7760c2ed6e9f7afc675fda
BLAKE2b-256 checksum
How to use checksums
008653269530e08655da429d3f1cb7ce4fbcc54f8ea44dcccec393682fbb2ae9
Upload date
Uploaded using Trusted Publishing?
What is 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}

Release history Release notifications | RSS feed

This release

0.2 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page