| name | cordmine |
| description | Discord archive CLI: search, sync freshness, DMs, summaries, repo/release work. |
Cordmine (CLI)
Use local Discord archive data first for Discord questions. Hit Discord APIs
only when the archive is stale, missing the requested scope, or the user asks
for current external context. Drive everything through the cordmine CLI —
it is the agent-facing interface.
Sources
- Package: npm
cordmine (Bun-first, zero runtime deps) — run via bunx cordmine
- Repo: local checkout (Bun/TypeScript, Bun-first, zero runtime deps)
- DB: SQLite (WAL + FTS5) at
<dataDir>/cordmine/cordmine.db (override via
CORDMINE_DB env or --db); on Windows
%LOCALAPPDATA%\cordmine\cordmine.db
- Credentials: bot token via env only (
DISCORD_BOT_TOKEN), never in files
Commands
bunx cordmine sync --guild <guild_id>
bunx cordmine search "query" --limit 20 --json
bunx cordmine sql "select count(*) from messages" --json
bunx cordmine status --json
bunx cordmine coverage --json
bunx cordmine messages --channel general --limit 50
bunx cordmine channels --json
bunx cordmine members search alice
bunx cordmine digest --json
bunx cordmine embed
bunx cordmine version
Token & config
- Archive path:
CORDMINE_DB env or --db <path>
- Guild scope:
CORDMINE_GUILDS env (comma-separated) or --guild / --guilds
- Bot token resolution:
--token > --token-env NAME > DISCORD_BOT_TOKEN
(shell env or .env, which Bun auto-loads)
- All commands support
--json for machine parsing
- Exit codes: 0 ok / 2 usage / 4 auth / 5 db
Sync flags:
bunx cordmine sync --full --guild <guild_id> \
--exclude-channel <id> \
--exclude-kind forum,announcement \
--ignore-bots
--with-embeddings
Freshness
For recent/current questions, check freshness before analysis:
bunx cordmine status --json
bunx cordmine coverage --json
Precise freshness from the default database:
bunx cordmine sql "select coalesce(max(created_at),'') as newest from messages;"
Use --full only for deliberate historical backfills:
bunx cordmine sync --full --guild <guild_id>.
If SQLite reports busy/locked, check for stray bun processes holding the WAL
before retrying.
Query Workflow
- Resolve scope: guild, channel, DM, author, keyword, date range.
- Check freshness for recent/current requests.
- Prefer
search / messages for slices; use sql for exact counts.
- Report absolute date spans, counts, channel/DM names, and known gaps.
Useful SQL:
bunx cordmine sql "select count(*) as messages from messages;" --json
bunx cordmine sql "select coalesce(nullif(c.name,''), m.channel_id) as channel, count(*) as messages from messages m left join channels c on c.id = m.channel_id group by m.channel_id order by messages desc limit 20;" --json
bunx cordmine sql "select coalesce(nullif(mm.display_name,''), nullif(mm.global_name,''), nullif(mm.username,''), m.author_id) as author, count(*) as messages from messages m left join members mm on mm.guild_id = m.guild_id and mm.user_id = m.author_id group by m.guild_id, m.author_id order by messages desc limit 20;" --json
sql is read-only: only select / pragma / with queries are allowed.
Search internals: FTS5 (unicode61) over normalized content; query terms are
quoted and AND-joined; a plain LIKE '%x%' scan is ~10,000x slower than the
index (17 s vs <1 ms on 120k messages). Semantic ranking requires
bunx cordmine embed to have run; search --mode hybrid or
--mode semantic selects embedding-based ranking.
Discord Boundaries
Bot-backed sync requires configured Discord bot credentials; do not invent
token availability. The CLI never uses user tokens or calls Discord as the
user. Archives are local-only; never include secrets if you publish snapshots.
Verification
For repo edits, prefer the existing Bun gates:
bun test
bunx tsc --noEmit
Then run a targeted CLI smoke for the touched surface:
CORDMINE_DB=<db> bunx cordmine status --json
CORDMINE_DB=<db> bunx cordmine search "test" --limit 5 --json
CORDMINE_DB=<db> bunx cordmine sql "select count(*) from messages;" --json