Skip to content

lpjiang97/slingsync

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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 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.

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).

About

Pull Slack List items and create Things3 to-dos.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages