Documentation
Connectors
Authenticating third-party accounts, personal and per project.
On this page
Three integration surfaces, not one
TDE has three separate places where "connect something external" happens, and confusing them is the single most common source of "why can't the agent see my database". They have different storage, different scope and different consumers.
| Surface | What it is | Who consumes it | Where |
|---|---|---|---|
| Connectors | Authentication to an information source — an issue tracker, a chat workspace, a payments account | Bots, TUI apps, TDE's own features | Control Center → Connectors, and Project → Integrations |
| Database | Named DSN profiles for a SQL or NoSQL server | The Database app, and agents through MCP | Control Center → Database |
| MCP | Tool servers you point your agent CLIs at | Claude, Codex, Cursor and OpenCode | Control Center → MCP |
A connector answers "which account am I acting as". A database profile answers "which server do I query". An MCP server answers "which tools does the agent have". See MCP and Data apps for the other two.
The connector kinds
Ten kinds exist. Six of them resolve per project, two are personal — once per account and device — and two are the ones described above that have a type but no live surface.
| Kind | Scope | How you authenticate | What uses it |
|---|---|---|---|
| GitHub | Personal | Paste a personal access token | PR open, status and merge; issue import via gh; the PR janitor bot |
| Telegram | Personal | Paste a BotFather token, then a chat id | Remote task intake, guard approvals, inbox mirror |
| Linear | Per project | Paste an API token | Issue import; the Linear sync bot, every 30 minutes |
| Jira | Per project | Paste site, account email and API token | Manual issue import |
| Todoist | Per project | Paste a token, then pick a Todoist project | Task import; the Todoist sync bot |
| Slack | Per project | OAuth through TDE's hosted broker | Slack triage bot, every 15 minutes |
| Stripe | Per project | stripe login on the CLI, or paste an API key | The daily subscriber report bot, 09:00 |
| Sentry | Per project | sentry-cli login in a browser | Unresolved issue listing. No bot |
| Postgres | — | — | Nothing today; use Database |
| — | — | Nothing today; use the Email app |
Personal connectors live in Control Center → Connectors and have exactly one credential each, so there is one GitHub identity and one Telegram bot per machine. Everything else is attached from Project → Integrations, whose subtitle states the rule plainly: "Accounts used only by tasks and Bots in this project."
How a project finds its account
Per-project connectors are named deterministically from the project. TDE slugifies the project name and prefixes it with the kind:
linear:cpfhub-api
jira:cpfhub-api
todoist:cpfhub-api
sentry:cpfhub-api
stripe:cpfhub-api
slack-triage:T01ABCDEF:U01ABCDEFSlack is the exception: its name carries the Slack team id and Slack user id instead of the project slug, because one person may be in several workspaces.
Linear, Slack, Stripe and Sentry also get a persisted row linking the project to
the connector name, and a connector name can be linked to only one project — a
second attempt fails with IntegrationAlreadyLinked. Jira and Todoist have no
such row by design: their per-project connector name is the link, so there
is nothing else to store.
Health is probed, not assumed
The dots next to each connector are live. Opening the Connectors tab re-probes
every configured account by making a real call — auth.test for Slack, getMe
for Telegram, an org lookup for Sentry — so a revoked token shows red rather than
staying green because the config file still exists.
Connecting
Token paste
GitHub, Linear, Jira and Todoist are a paste into a form. Jira asks for three fields (site URL, account email, API token) because its API needs all three. Todoist is two-phase: paste the token, then pick which Todoist project to import from, because importing everything is almost never what you want.
Telegram is also two-phase and validates aggressively, because the two values look similar and people paste the wrong one constantly:
- the bot token is shape-checked, then verified live with
getMe; - the chat id rejects a pasted bot token ("Isso é o token do bot (BotFather),
não o chat id"), rejects the bot's own id, and strips the
Your user ID:prefixes that@userinfobotadds.
On success the bot sends a test message and mirrors the last 20 inbox rows, so you know immediately whether it worked.
OAuth
Slack is the only OAuth connector. TDE never holds a Slack client secret: it
calls a hosted broker (https://www.tde.sh/api/oauth/slack by default,
overridable with TDE_SLACK_OAUTH_BROKER_URL or TDE_SITE_URL), gets back an
authorization URL, renders it as a QR code in TDE Browser, and polls for
completion. The broker URL is validated: no credentials in the URL, no query, no
fragment, and HTTPS unless the host is loopback.
Only a user token (xoxp-) may be stored on your machine. A bot token is
refused outright. See
Slack and Telegram for why that matters.
CLI login
Stripe and Sentry authenticate through their own CLIs, and TDE installs the CLI
for you on first Connect. If stripe or sentry-cli is not on your PATH,
TDE runs the matching Store manifest's install step in a
visible terminal window, then resumes the connect flow where it left off.
stripe login # opens a browser, writes Stripe's own credential
sentry-cli login # opens a browser, writes ~/.sentryclircThe two then diverge:
- Stripe keeps its credential in the CLI's own store. TDE holds nothing — a
Stripe connector in CLI mode has no secret at all. Project-scoped Stripe is
different: pasting an API key stores it in the vault as
STRIPE_API_KEY:<project>, and it is injected as an environment variable, never as a command-line argument, so it does not appear in a process list. - Sentry does not stop at the CLI. TDE reads
~/.sentryclircafter login and copies the token into the vault, keeping the org and project slugs as connector metadata.
What is stored where
~/.tde/connectors.json holds the shape of each connector: its kind, its name,
endpoints, org slugs, chat ids, whether it is enabled, and — for credentials —
only the name of a vault entry. The token itself is in ~/.tde/secrets.db,
encrypted. The in-memory field holding resolved secrets is marked
non-serializable, so there is no code path that could write one to the config
file.
| Connector | Vault entry |
|---|---|
| GitHub | GITHUB_TOKEN |
| Telegram | TELEGRAM_BOT_TOKEN |
| Linear | LINEAR_API_KEY or LINEAR_API_KEY:<project> |
| Jira | JIRA_API_TOKEN:<project> |
| Todoist | TODOIST_API_TOKEN:<project> |
| Stripe | STRIPE_API_KEY:<project> (absent in CLI mode) |
| Sentry | SENTRY_TOKEN:<project> |
| Slack | SLACK_TOKEN:triage:<team>:<user> |
Removing a connector
Disconnecting deletes the config entry and the vault entry in the same operation. That is not tidiness: the boot-time hydrate above would otherwise resurrect the connector from the orphaned secret on the next start, and Sync would replicate the resurrection to your other machines. An empty value is stored as a tombstone so the deletion itself replicates.
There is no connector CLI
Connectors are configured from the desktop's Control Center, from a project's
Integrations modal, or from the standalone tde-control TUI (whose add flow
covers GitHub and Linear only). The semantic CLI has no connector command —
tde verbs are tasks, projects, pipelines, agents, share, ask and chat. See the
CLI overview.