Skip to content

Repository files navigation

Slack Archive Toolkit

A local Python CLI (./slackbackup) that backs up Slack channel history via slackdump, then exports it into two LLM-ready documents for newsletter generation — a cross-workspace digest (messages, activity counts, inferred leadership) and a user profile report (full membership roster with titles and Slack roles) — plus per-month channel archives and a live search. No Slack admin access, no app install, no cloud infrastructure. See docs/DESIGN.md for the full architecture and a data-flow diagram of what this app does versus what slackdump does.

Status: Active development


Getting Started

Everything below runs locally via the ./slackbackup CLI — no Slack workspace admin access required. Secrets (the xoxc- token and xoxd- cookie) stay on your machine in ~/.slackdump-tokens.json and slackdump's own local session store — never in this repo (see .gitignore's "Secrets" section).

Prerequisites

  • slackdump binary installed — scripts/install-slackdump.sh downloads and checksum-verifies a pinned release to ~/bin
  • Python ≥3.10; pip install -e ".[test]" from the repo root

1. Get a token + cookie for each workspace

  1. Log into each Slack workspace in your browser (the web app, not just the login page).

  2. Open DevTools Console (F12 → Console). If Chrome blocks pasting, type allow pasting and press Enter first, then paste:

    Object.fromEntries(
      Object.values(JSON.parse(localStorage.localConfig_v2).teams)
        .map(t => [(t.domain || t.name).toLowerCase(), t.token])
    )

    This lists every workspace you're logged into in that browser at once — run it once per browser session, not once per workspace.

  3. Merge the resulting {workspace: xoxc-token} object into ~/.slackdump-tokens.json (create it if it doesn't exist), e.g.:

    { "f3pugetsound": "xoxc-...", "f3kirkland": "xoxc-..." }
  4. Get the cookie — one cookie works for every workspace under the same account, so this is a one-time step, not once per workspace: DevTools → Application/Storage → Cookies → https://<any-workspace>.slack.com → cookie named d → copy its Value (starts with xoxd-).

2. Register a workspace

./slackbackup workspace register <workspace> <xoxd-cookie>
./slackbackup workspace list   # shows known vs. registered status

<workspace> is matched against the tokens file keys after lowercasing and stripping a leading https:// and trailing .slack.comf3kirkland, f3kirkland.slack.com, and https://f3kirkland.slack.com all resolve the same way. Registration calls slackdump workspace import under the hood, which needs both the token (from the file) and the cookie (passed fresh — slackdump doesn't persist cookies, since they expire) every time you register or re-register.

Sessions expire. When they do, backups fail with authentication details expired. The full re-auth workflow — detecting which workspaces are stale, the one-command scripts/auth-refresh helper for interactive re-login, and scripts/auth-refresh/keepalive.sh for headless nightly session refresh (already wired into scripts/nightly-backup-digest.sh) — is documented in docs/OPERATIONS.md §Authorization / Session Lifecycle.

3. Register channels to track

./slackbackup channel list <workspace>                       # see what's available
./slackbackup channel register <workspace> <#channel-or-id>  # adds it to channels.json
./slackbackup channel validate channels.json

4. Back up

./slackbackup backup run channels.json ~/slack-backups

Per-channel-month exports (a different, narrower artifact than the digest below) are also available: ./slackbackup export monthly --from ... --to ... --workspace ... --channel ... --archive-root ~/slack-backups --out ~/slack-exports.

5. Generate the digest

./slackbackup export digest --archive-root ~/slack-backups --workspace 'f3*'
# -> ~/slack-exports/f3-digest-<today>.json
# Defaults: trailing 180 days. --workspace is required unless --jobs is given.
# Override with --days, --as-of, --out.

One merged JSON document: all in-range messages with thread nesting, per-channel and per-workspace activity counts, inferred leadership roles (from display names and profile titles), and non-image file/Canvas content.

For repeatable, per-recipient runs, drive the digest from job files instead of flags: ./slackbackup export digest --jobs 'jobs/*.json'. Each gitignored jobs/*.json fully specifies its own archive root, channels file, workspaces, day window, output path ({as_of}-templated), optional companion user roster, and leadership handler — one digest per job. This is what the nightly script runs after the blanket digest. See docs/DESIGN-export.md §Report jobs.

6. Generate the user profile report

./slackbackup export users --archive-root ~/slack-backups --workspace 'f3*'
# -> ~/slack-exports/f3-user-profiles-<today>.json
# --workspace is required.
# Override with --out.

The full per-workspace user roster — display names, profile titles, Slack account roles (admin/owner/bot/etc.) — for every workspace matching the glob, not just recent posters. This is a separate document from the digest and covers the complete cross-region membership picture, including people who haven't posted in the digest window.

7. Generate the newsletter

Feed both the digest JSON and the user profile JSON, plus docs/newsletter-prompt.md, to an LLM (e.g. paste all three into Claude, or use the Claude CLI/API with the files as attachments) to produce the actual newsletter. The prompt defines the regional structure, event/leadership handling, and sourcing rules — it expects the digest's messages/channels/leadership.by_region schema and the user profiles' per-workspace profiles list as-is, so don't reshape the JSON first.

8. Generate a new-member "Start Here" guide (optional)

Feed the digest JSON plus docs/fng-getting-started-prompt.md to an LLM to produce a "Slack: Start Here / FAQ" guide for new members, sourced only from the digest's actual channels/roles/events — same pattern as the newsletter above.

Browse the archive locally (optional)

To read a backed-up channel interactively, point slackdump's built-in viewer at that channel's archive directory (<archive-root>/<workspace>/<channel>):

slackdump view ~/slack-backups/f3puget/general

This starts a local, read-only web viewer — threads in a side panel, downloaded images and files inline, no Slack token or network needed (it reads only the local slackdump.sqlite). Add DEBUG=1 before the command if a message fails to render. Nothing is modified.

Recovering content from untracked channels (optional)

./slackbackup channel-digest run <workspace> '<glob>' <out_dir> archives every channel matching an fnmatch glob (e.g. 'shuttered-*') and writes a single merge-aware JSON digest of surviving messages, files, and orphaned Canvases — for pulling content out of channels that aren't in channels.json (e.g. Canvases stranded by a region migration). On-demand, not part of the nightly run. See docs/DESIGN-files.md §Channel digest.

Run ./slackbackup help for the full command list.


Documentation

Document Purpose
CONTEXT.md Purpose, capabilities, use cases
DESIGN.md Per-channel backup architecture, modules, key decisions
DESIGN-export.md Export pipeline: monthly per-channel JSON, cross-workspace LLM digest, user-profile roster, report jobs, pluggable leadership handlers
DESIGN-files.md Channel catalog + untracked-channel digest (implemented) + canvas/file harvesting (designed, not yet ported to Python)
references/slackdump-cli-notes.md slackdump CLI behavior, costs, and gotchas learned the hard way — check before re-deriving
ADRs Architecture decision records

License

MIT — see LICENSE for details.

About

Local CLI for backing up, archiving, and generating LLM-ready digests/newsletters from Slack workspaces

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages