typed CLI
The first-party coding agent CLI for typed.cloud. It runs the agent loop -- read, search, edit, run, verify -- in your terminal, against your own codebase, on your typed subscription.
The native protocol is the Anthropic Messages API, so the CLI works against
typed.cloud by default and against any Anthropic-API-compatible endpoint if you point
ANTHROPIC_BASE_URL elsewhere. It honors the same configuration surfaces as the
reference CLI (Claude Code) -- CLAUDE.md, settings.json permission rules, skills,
hooks, .mcp.json -- so an existing setup carries over without rewriting anything.
The typed CLI is the default client for new installs (apps/api/src/routes/launcher-version.ts advertises rollout.default_client = 'typed-cli' and the installer's setup_typed_cli writes ~/.config/typed/client = typed-cli on a successful install). Claude Code against typed.cloud remains fully supported; you can switch between the two clients at any time (see Install below).
Install
One curl installs the typed launcher with your API key wired in (the dashboard at
app.typed.cloud pre-fills the command with your key):
curl -fsSL https://app.typed.cloud/install.sh | bash -s <your-typed-key>
By default typed and t launch the first-party CLI pointed at typed.cloud. Switch back to the reference client (or print the current state) with:
typed cli on # default -- the launcher starts the first-party CLI
typed cli off # back to the reference client
typed cli # print the current state
(typed tui on|off is an interchangeable alias for typed cli on|off and still works. typed beta on|off is a deprecated alias for the same thing, still working for now.)
The opt-in is a one-line file at ~/.config/typed/client; nothing else about your
setup changes, and typed cli off reverts it completely.
Quickstart
typed login # browser device-auth; writes ~/.config/typed/api-key
t # start a session in the current project directory
Once you are in a session:
- Type a task and press Enter.
- Press
?on an empty input line (or run/help) for the one-screen help overlay: built-in commands, your discovered skills, key bindings, and how the permission gates work. Ctrl+Cinterrupts the current run (twice within 1.5s exits);Ctrl+Dexits;Tabcompletes/commands;Up/Downwalk input history.
The status line at the bottom shows the model tier, the run state, live session spend in dollars (real spend reported by the server, not an estimate), token counts, and the prompt-cache hit rate.
The everyday surface
Tools
Read (text and images), Write, Edit, Grep, Glob, Bash, PowerShell (Windows),
WebFetch, WebSearch, Agent (subagents for self-contained delegated tasks), and a
model-driven progress list rendered in the footer. MCP servers from .mcp.json
(stdio) register their tools as mcp__<server>__<tool>.
Permission gates
Tool calls that can mutate state are gated before they run. The engine is fully deterministic -- rules only, no model in the loop -- so a denial is reproducible and names the exact rule that produced it.
At a gate: y allows once, n denies, and a (when offered) allows always --
writing a CC-syntax allow rule (for example Bash(git status*)) to
.claude/settings.local.json so that shape never gates again in this project.
Destructive-class gates require Enter rather than a single key. Rules use the same
allow / deny / ask arrays and Tool(prefix*) syntax as the reference CLI.
Auto mode
For unattended or long-running sessions, auto mode skips the per-prompt gate
for mutating tools and fires the same a path the interactive a key does --
deriving a CC-syntax allow rule from the call, evaluating it, and running the
tool. Each auto-fired decision is committed to the scrollback as
+ auto: <ToolName> (<rule>) so the session log shows exactly which rules
the model self-allowed against.
Opt in three ways:
| Surface | Shape | Effect |
|---|---|---|
| Startup flag | typed --auto |
session-scoped auto mode; rules live only in memory and are lost on exit |
| Startup flag | typed --auto --auto-persist |
session-scoped auto + write each new allow rule to .claude/settings.local.json as it fires |
| In-session | /auto |
toggle auto mode on or off in the current session |
| In-session | /auto persist |
turn the current session's auto mode into the persisting variant (sticky) |
The status line shows an [auto] chip when auto is on, so it is visible at a
glance. Auto mode does not bypass deny rules -- the engine still rejects any
call that matches an explicit deny. Headless runs pick it up via
--permission-mode auto; the headless default behavior (deny gated calls) is
unchanged for default / accept-edits / readonly.
Built-in commands
| Command | What it does |
|---|---|
/help (or ? on an empty line) |
one-screen help overlay |
/undo |
restore every file the session has written, from per-session shadow snapshots taken before the first write to each file (works on dirty trees; no git required) |
/compact |
summarize older history to free context (auto-compaction also triggers at a threshold) |
/show <id> |
print the full output of a truncated tool result |
/status |
session state: model, spend, config sources |
/auto [on|off|persist] |
toggle auto mode (or set the persisting variant); see Permission gates above |
/exit |
leave the session |
Resuming work
typed --continue # resume the most recent session for this directory
typed --resume <id> # resume a specific session (id prefix ok)
typed --resume # list available sessions for this directory and pick one
Sessions are JSONL transcripts stored per project directory (see Env vars below).
Subcommands
typed login | logout # device-auth key management
typed use <tier> [--global] # pin a model tier (.typed file, or ~/.config/typed/model)
typed status # offline: resolved config + key source
typed doctor # probe the backend, key, and config for the common traps
typed ultracode [on|off] # multi-agent orchestration mode (Pro tier and up)
typed update # self-update: re-runs the installer; ~/.config/typed is preserved
typed codebase <verb> # hosted codebase indexing (Team tier); see below
typed doctor is the first thing to run when something is off: it checks the key
source, the model pin, the well-known env traps, and probes the service, printing
[ok] / [warn] / [FAIL] lines with a one-line fix for each failure.
Hosted codebase indexing
Team / Team Max only. typed indexes an uploaded snapshot of your repository and retrieves from it on every turn, so the model can cite files that were never in the conversation. On any other plan these commands return the API's own upgrade payload, including the link.
typed codebase push [path] # pack, upload, index; defaults to the cwd
typed codebase list # every codebase in your org
typed codebase status <id> # one codebase, with its failure reason
typed codebase rm <id> [--yes] # delete it (indexed chunks and archive too)
push packs the tree with .gitignore (and .typedignore, same syntax)
honored and .git excluded, then drives create -> upload -> finalize and polls
until the index is ready or failed, printing each step. It refuses before
uploading if the archive is over the server's size limit, naming the limit and
the actual size. On success it prints the codebase id and the line that attaches
it:
typed --codebase <id>
That flag is a session flag: every turn of the session carries the codebase, and a startup note names the one it is attached to. When the backend answers that a turn could not use the index -- still indexing, indexing failed, or retrieval briefly unavailable -- the CLI says so rather than letting the answer look codebase-informed. The flag has no effect on the free local tier, where inference never leaves your machine; the session says that at startup instead of sending a header nothing will read.
What is never uploaded
Your ignore files are advisory, and the archive is retained in storage after
indexing -- so push refuses credential-shaped files outright, whether or not
you remembered to ignore them:
- Credential filenames, by exact name, family prefix, or suffix:
.envand every.env.*,.npmrc/.yarnrc(registry auth),.netrc,.pgpass,credentials,credentials.json,service-account.json,secrets.*,id_rsaand siblings, and*.pem/*.key/*.p12/*.jks/*.gpg. Public certificates (*.crt,*.pub) are not treated as secrets. - Dotfiles you have not opted in, allowlisted down to declarative config
(
.gitignore,.editorconfig,.nvmrc,.tool-versions, the.eslintrc/.prettierrcfamilies,.typedignore)..env.exampleis not on that list. - Any file whose contents look secret-bearing regardless of its name -- an api key, an AWS access key id, a JWT, a PEM private-key block, or a password-style assignment with a key-like value. The whole file is skipped; nothing is redacted and re-packed.
push names every file it withheld and why, before it uploads. Paths are
printed so you know what is missing from the index; contents never are.
This cannot be overridden. An ignore file only excludes, it cannot re-include, and the server applies the same rules again after unpacking. If you genuinely need one of these files indexed, take the credential out of it first.
rm is irreversible (it wipes the indexed chunks and the uploaded archive), so
it asks you to type the id back unless you pass --yes.
The full endpoint contract, the status lifecycle, and the retention policy are documented for Team customers in the dashboard.
Headless mode
For scripts and CI:
typed-cli -p "fix the failing test in src/foo.test.ts" --output-format json
--output-format text prints the final answer; json prints a single result
envelope on stdout:
| Field | Meaning |
|---|---|
type, subtype |
"result", "success" or "error" |
is_error |
boolean |
result |
final assistant text (or the error message) |
num_turns |
turns used |
duration_ms, duration_api_ms |
wall time and time spent in API calls |
total_cost_usd |
real spend on typed backends; null when unknown |
usage |
input_tokens, output_tokens, cache_read_input_tokens, cache_creation_input_tokens |
api_error_status |
HTTP status when an API error ended the run (optional) |
session_id |
id of the session transcript |
Other flags: --model, --effort (maps to a typed tier when no explicit model is
set), --max-budget-usd (stop when estimated spend exceeds the budget),
--append-system-prompt-file,
--permission-mode default|accept-edits|readonly|bypass|auto (alias --auto;
add --auto-persist to write each new allow rule to
.claude/settings.local.json as it fires),
--tools <list>, --cwd <dir>,
--codebase <id> (attach a hosted codebase index -- Team tier; see
Subcommands above).
Headless runs never prompt: gated tool calls are denied (the model is told why)
unless you pass --permission-mode bypass. Hooks run headless only when the project
already has a trust record granting them, or TYPED_CLI_TRUST_HOOKS=1 is set.
Configuration surfaces
The CLI reads the same project configuration the reference CLI does:
| Surface | Support |
|---|---|
CLAUDE.md (user, project, .claude/, CLAUDE.local.md) |
full, including @import lines |
AGENTS.md (the client-neutral convention: root and ancestor directories) |
full; loaded alongside CLAUDE.md, identical copies deduped. Files below the start directory are not read |
settings.json permissions (allow / deny / ask) |
full, same rule syntax; project settings.json + settings.local.json + user settings merge additively |
.claude/skills/<name>/SKILL.md and .claude/commands/<name>.md |
full; discovered skills appear in / autocomplete and the ? overlay |
.agents/skills/**/SKILL.md (project and ~/.agents/skills, the Agent Skills standard) |
full; grouping folders scanned 4 levels deep, linked skill dirs followed, spec frontmatter (license, compatibility, metadata, allowed-tools, disable-model-invocation) read, spec violations warned about and loaded anyway |
.claude/agents/*.md |
full (name, description, tools, model frontmatter) |
hooks (PreToolUse, PostToolUse, UserPromptSubmit, Stop, SessionStart, PreCompact, SubagentStop, SessionEnd, Notification) |
full for these nine events; same stdin-JSON and exit-code semantics |
.mcp.json (stdio servers) |
full; project-scope servers are trust-gated |
CLAUDE_CONFIG_DIR |
honored everywhere ~/.claude would be used |
Skills the model can pick itself. Every skill with a description is listed
for the model at session start as an Agent Skills catalog (name, description,
and the absolute SKILL.md path), and the model loads one by reading the
file when a task matches. The catalog is budgeted like CLAUDE.md (5% of the
window, 4,096 chars, project skills kept first when it has to cut) and is left
out entirely on windows of 16K tokens or less, when the session has no Read
tool on the wire (the free local tier before its server proves tool calls),
and for project skills in a headless run without an explicit trust grant
(TYPED_CLI_TRUST_PROJECT=1 or a saved decision). Every omission is a startup
note, and the catalog notes are also written to stderr in headless runs. A
skill the model or you activated is named again after /compact,
with an instruction to re-read it. disable-model-invocation: true keeps a
skill slash-only; a skill whose name shadows a built-in command stays in the
catalog but loses its slash command.
First-run trust: the first time you run the CLI in a project that ships any of this config, it shows what it found and asks before using it. Hooks are opt-in -- they execute arbitrary commands, so they never run silently. Decisions are remembered per project.
Env vars
| Variable | Effect |
|---|---|
ANTHROPIC_BASE_URL |
backend endpoint (default https://api.typed.cloud) |
ANTHROPIC_AUTH_TOKEN / ANTHROPIC_API_KEY / TYPED_API_KEY |
API key; falls back to ~/.config/typed/api-key |
ANTHROPIC_MODEL |
model / tier (default typed, the free local tier -- pick a typed++ id to reach the hosted tiers) |
CLAUDE_CONFIG_DIR |
overrides ~/.claude for config discovery |
TYPED_VERIFY_CYCLE_CAP |
verification-cycle cap: how many times the loop allows the model to repeat an identical check (same command, same file read) without making a change before steering it onward. Default 2; 0 disables |
TYPED_NO_UPDATE_CHECK=1 |
disable the background version check entirely |
TYPED_CLI_STATUS_FD |
file descriptor number; when set, the CLI emits one JSON status event per line on that fd (session, turn, state, tool, usage, error, done) for host integrations such as terminal UIs |
TYPED_CLI_SESSIONS_DIR |
session transcript root (default ~/.config/typed/sessions); transcripts live under a per-project subdirectory |
TYPED_CLI_MEMORY_DIR |
persistent per-project memory root (default ~/.config/typed/memory) |
TYPED_CLI_TRUST_HOOKS=1 |
headless only: run hooks without an interactive trust grant |
TYPED_CLI_TRUST_PROJECT=1 |
headless only: treat the project as trusted for project-scope MCP servers and the model's skill catalog |
TYPED_CLI_SKILL_ALLOWED_TOOLS=1 |
opt-in: /name on a skill in a trusted project arms its allowed-tools frontmatter as session allow rules when the run starts (a queued invocation arms nothing until it runs; in an untrusted project a line says the rules were not armed) the permission engine consults last (after your deny, allow and ask rules; ignored in readonly and plan). Each armed rule is committed to the scrollback as + allow for this session (skill <name>): <rule>; an entry the engine cannot evaluate is refused with a ! line, never armed dead. Nothing is written to disk |
TYPED_CLI_COMPACT_THRESHOLD |
auto-compaction threshold in estimated tokens |
TYPED_CODEBASE_POLL_MS |
typed codebase push poll interval while the index builds (default 3000) |
TYPED_CODEBASE_POLL_TIMEOUT_MS |
how long typed codebase push waits before handing back (default 900000); the indexer keeps going either way |
TYPED_INSTALL_URL |
installer URL used by typed update |
TYPED_CLIENT |
one-shot launcher override (typed-cli or the reference client) without touching the typed cli state |
Resilience details worth knowing
- Stall watchdog: every streamed response runs under two timers -- a byte-idle timer and a content-progress timer (keepalive pings do not count as progress). A content-silent stall is aborted and retried once before surfacing an error.
- Quota: when a request exceeds your monthly quota, the error rendered in the CLI includes the remediation path (one-click top-up, or enable auto-top-up in the dashboard) instead of a dead error string.
- Verification cap: repeated identical verification commands within one edit
cycle are short-circuited with guidance rather than executed again -- this is the
measured fix for verify-loop runaway and is on by default (see
TYPED_VERIFY_CYCLE_CAP). - Comments while a run is in flight: a comment typed while the model is
streaming redirects it immediately -- the partial answer is kept, the comment
is appended, and the same turn is re-sent (up to 10 redirects per model turn;
after that the remaining comments start a fresh prompt). A comment typed during
tool calls interrupts read-only and idempotent calls and subagents, lets a
mutating call finish, skips the rest of that batch with a "not run" result, and
lands right after the tool results -- the footer chip shows
(after <tool>)while it waits. The chip counts only comments the model has not received yet. Every delivered comment gets a/rewindcheckpoint.Ctrl+Cparks the queue; the next submit merges the backlog in the order you typed it. - Hook-blocked prompts stay visible: a
UserPromptSubmithook that blocks a comment does NOT drop it. A! prompt blocked by hook: <reason>line commits under the blocked item, the footer swap-in shows it as[blocked: <reason>]with red text, and the drain continues to the next pending item. Blocked items persist for the rest of the session -- remove them with/queue-cancel <n>or let them die with/exit. The queue cap is 100; the 101st submit is dropped with a! queue full (N) -- submission droppedline. Use/queueto see the visible queue at any time.
Support
Run typed doctor first; it diagnoses the common setup traps with a fix line per
failure. If you are still stuck, email support@typed.cloud with your account
email, the doctor output, and the approximate UTC timestamp of the failed request.