Skip to main content

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-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).
  • Slack token with lists:read.
  • For two-way completion sync, token also needs lists:write.

Setup (uv-managed venv)

cd /path/to/things3_syncer
uv venv
uv sync

Run commands either with activation:

source .venv/bin/activate
slingsync --help

Or directly with uv run:

uv run slingsync --help

Compatibility wrapper (same behavior):

python syncer.py --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 (Global Recommended)

Config lookup order:

  1. --config /path/to/config.json
  2. $SLINGSYNC_CONFIG
  3. ./.sync_config.json (current working directory)
  4. ~/.config/slingsync/config.json

Global config (recommended)

Create:

mkdir -p ~/.config/slingsync
cp .sync_config.example.json ~/.config/slingsync/config.json

Then edit ~/.config/slingsync/config.json.

Local config (project-specific)

Store your core Slack values in a local file:

  • ./.sync_config.json (auto-loaded by the script)
  • Ignored by git (.gitignore includes it)

Create it from the example:

cp .sync_config.example.json .sync_config.json

Then edit:

{
  "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 lookup order: ./.sync_config.json, then ~/.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:

  • If config is local (./.sync_config.json): ./.sync_state/slack_to_things_<LIST_ID>.json
  • Otherwise: ~/.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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

slingsync-0.1.0.tar.gz (15.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

slingsync-0.1.0-py3-none-any.whl (18.0 kB view details)

Uploaded Python 3

File details

Details for the file slingsync-0.1.0.tar.gz.

File metadata

  • Download URL: slingsync-0.1.0.tar.gz
  • Upload date:
  • Size: 15.0 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

Hashes for slingsync-0.1.0.tar.gz
Algorithm Hash digest
SHA256 8c13e43779133d14edc7a8400a13583d8231a8cc42193c80b836ef6354301294
MD5 200cb3cb29f230c6c7cc833e06b0b47f
BLAKE2b-256 6dd2aca07cc40a4747d185145001650ba04aab27d9f9087c87fa685bd8bc95b6

See more details on using hashes here.

File details

Details for the file slingsync-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: slingsync-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 18.0 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

Hashes for slingsync-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f2dc20339ad30f8a2d5373f4814769f453277b7cec275a7f9297155c43497e08
MD5 191243f9d0abef3ab319546d6887a02b
BLAKE2b-256 735e370467d0e93d57bb35a6b0c06f232d5bbb454f564d5f4788f1a0cd28d904

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page