Titah does not need an account
This is worth saying first, because it is the part most tools get wrong. The agent loop, the tools, delegation, consensus, sub-agents — none of it asks who you are. Your provider credentials are yours, your sessions are on your own disk, and nothing about your code goes to a Titah server because you signed in.
An account adds one thing: the web dashboard, and whatever is built behind it. That is why the first-run question offers “continue without an account” as a real answer rather than a way of postponing the real one.
The dashboard shows:
- Devices signed in with your account, each revocable individually
- Projects you have worked in — metadata only, and switchable off four different ways
- Analytics across all of them, with CSV and JSON export
- Sessions, if you switch sync on — off by default, and it needs both
tracking.syncin your config and the project’s toggle here - Artifacts — pages the agent published, each one private until you decide otherwise. Nothing arrives here on its own: every publish is a tool call you approved. See Artifacts
/dashboard/sessions/ and /dashboard/agents/ are still placeholders; synced
transcripts appear under their project. See
Project tracking.
The first-run question
The first time you open the TUI on a machine that has never run Titah:
Welcome to Titah 0.7.0.
1. Sign in to your Titah account
2. Continue without an account
Titah works fully either way — an account only adds the web dashboard.
Choose [1-2] ›
Whichever you pick is recorded, and you are never asked again. A question
that keeps asking is a question that stops being read. Change your mind at any
time with titah login, or /login inside the TUI.
Two deliberate details:
- A non-interactive run — a script, a Dockerfile, CI — is never asked and never has a choice recorded on your behalf. It simply proceeds without an account. The next time a human opens the TUI, the question appears as normal.
- A failed sign-in does not stop the session. You came to use the agent, not to log in; Titah records “no account”, says why the sign-in failed, and carries on.
Signing in
titah login
Signing in to Titah.
Server: https://titah.dev
Your code: KMTV-9RQD
A browser window should have opened. Confirm the code there.
If it did not: https://titah.dev/cli/activate/
Waiting for approval… (Ctrl+C to cancel)
Confirm the code in the browser and the terminal completes on its own.
Inside the TUI, /login does the same thing in a panel, and Esc cancels it.
Why a code instead of a redirect
Titah uses the Device Authorization Grant (RFC 8628) rather than the loopback redirect that browser-first tools use.
The reason is where coding agents actually run. Over SSH, inside a container, on
a build box — a redirect to 127.0.0.1 lands on the loopback interface of the
wrong machine, and the flow dead-ends with no useful error. A code you type
into any browser, on any machine, behaves identically everywhere. One code path,
no port to forward, no firewall rule, no callback URL to register.
The cost is honest: you type eight characters. That is the whole downside.
Options
| Flag | Effect |
|---|---|
--server <url> | Sign in to a specific instance, overriding config and environment |
--no-browser | Print the URL instead of opening a browser |
Pointing Titah at your own instance
titah-web is ordinary Django — plenty of people will run their own. The server is chosen from, in order:
TITAH_ACCOUNT_SERVERin the environmentaccount.serverintitah.json- the default,
https://titah.dev
{ "account": { "server": "https://titah.internal" } }
export TITAH_ACCOUNT_SERVER=http://localhost:8080 # your own instance
titah login
The environment wins over the config so one shell can be pointed elsewhere without editing a file other people share.
!!! warning “The token is bound to the server that issued it”
account.json records which server a session belongs to. Changing the
server does not silently reuse the old token — you are asked to sign in
again, because a token from one instance means nothing to another.
Checking and revoking
titah whoami
Email: [email protected]
Name: Ada Lovelace
Server: https://titah.dev
Device: ada@laptop (linux)
Since: 2026-08-13T04:10:22.000Z
Status: verified as [email protected]
That last line is the one that matters. The file on disk only says what was
once true; whoami asks the server whether the session is still valid. A
token you revoked from the dashboard shows up here as revoked, and titah doctor --probe reports the same thing in its Account section.
titah logout
Revokes the token on the server and deletes it locally. If the server cannot be reached, the local token is deleted anyway and Titah tells you the row may still be listed on your dashboard — a sign-out that fails silently and leaves the token on disk is a sign-out that lied.
From the web
Dashboard → Devices lists every signed-in machine with when it was added, when it was last used, and the IP it came from. Revoking takes effect the next time that machine talks to the server.
Tokens expire on their own after 90 days.
Where the token lives
~/.local/share/titah/account.json, mode 0600 — written to a temporary file
and renamed, with the mode set before the rename, so it is never briefly
world-readable.
It is deliberately not auth.json. That file holds your provider keys; this
one holds your identity. Mixing them would mean titah auth remove anthropic
could take your login with it — two things with no reason to share a file.
Neither file is ever written into titah.json, which is the file people paste
into GitHub issues.
Security notes
- The device code and the access token are stored on the server as SHA-256 hashes. A database dump does not yield a usable credential.
- A device code is good for one token and expires after ten minutes.
Replaying a consumed code returns
expired_token. - Polling faster than the advertised interval gets
slow_down, and the answer comes back before the window advances — so ignoring it does not help. - The approval page names the device and the IP that asked, and says plainly that a code somebody else sent you is an attempt to sign their machine in as you. Approve only a code your own terminal is showing.
- Revocation is idempotent and never reveals whether a token existed. Answering “no such token” would make the endpoint an oracle for testing stolen values.
Troubleshooting
“Cannot reach the account server” — the default is
https://titah.dev. If you run your own instance, set
TITAH_ACCOUNT_SERVER or account.server; the error message names both.
“That is not a valid code” — it is eight characters. Dashes, spaces and
lower case are all accepted; the alphabet deliberately excludes 0, O, 1,
I and L, so if you think you see one, it is something else.
The browser did not open — expected over SSH without X11, where Titah does not even try. The printed URL works from any machine.
“This machine is no longer signed in” — the token was revoked or expired.
Run titah login again.