Skip to content
titah

Getting started

Account & sign-in

`titah login` signs a machine in through the browser. Titah works fully without it — an account only adds the web dashboard.

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

FlagEffect
--server <url>Sign in to a specific instance, overriding config and environment
--no-browserPrint 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:

  1. TITAH_ACCOUNT_SERVER in the environment
  2. account.server in titah.json
  3. 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.