TeXRA CLI
The TeXRA CLI brings TeXRA's theorist agents to the terminal: a local texra command for chatting with an agent, running long autonomous attempts at a problem, launching specialist teams, and running document workflows over your project. It is published to npm as @texra-ai/cli.
Install
Install the CLI globally from npm (requires Node.js 22.19.0 or later in 22.x, or Node.js 24 or later):
npm install -g @texra-ai/cliOr with Homebrew on macOS and Linux, which installs Node.js for you if needed:
brew install texra-ai/tap/texraVerify the command:
texra --help
texra version
texra agents list
texra configRun texra with no model connected and the chat still opens, with a Connect a model panel in front: sign in with a ChatGPT or Grok subscription, or add a provider API key. A message typed before you connect is sent as soon as you do. On your first run TeXRA then hands the chat to the setup assistant and opens /agent, where you pick an agent or a team (a preset such as Lean Project, led by its orchestrator); /agent stays available until your first message in any new chat.
For a guided first run, use texra setup. It walks you through sign-in (a ChatGPT or Grok subscription, or an API key), checks your environment, shows your agents, and starts your first task:
texra setupWorking from an Overleaf or ShareLaTeX project? Clone it into a directory first, by URL, git URL, or 24-character project id:
texra clone <project> --cwd ./projectRunning agents
Run an agent's document task from a project directory:
texra run polish --input paper.tex --output paper.polished.tex --print- Revision 1: draft
- Revision 2: critique and revise
Command in, revisions stream as progress, and the printed path is the success signal: the copied --output destination, or the generated file in run storage when no copy was requested.
Document tasks that take an instruction, such as polish, accept it with --instruction <text> or --instruction-file <file>. When both are set, the file contents are passed first:
texra run polish --input paper.tex --instruction "Tighten the proof of Lemma 2"
texra run polish --input paper.tex --instruction-file notes.mdPass read-only context files with repeated --context flags. The agent can read these files through {{ ALL_CONTEXTS }}, but it only emits revised documents for the selected inputs:
texra run correct --input appendices.tex --context Draft0.tex --context refs.bibPass multiple inputs with repeated --input flags, a directory, or a glob. Directory inputs expand recursively to .tex files. Multi-input runs can copy their generated artifacts to a directory with --output-dir; relative document paths are preserved under that directory:
texra run polish --input Draft0.tex --input appendices.tex --output-dir polished
texra run correct --input 'sections/**/*.tex' --output-dir correctedAdd --reflect to have the bundled critic agent review each revision but the last; the next revision reads its critique. The revision count is unchanged:
texra run polish --input paper.tex --output paper.polished.tex --reflectDocument tasks always write generated files into the run's run-storage directory first. In text mode, TeXRA prints a filesystem path: the copied path when --output or --output-dir is used, otherwise the final generated file in run storage.
With --output, TeXRA also copies the final artifact to the requested filesystem destination. JSON and NDJSON output keep outputs[] as the run-storage source of truth (relativePath, absolutePath, and location), include runDirectory, include copiedOutput or copiedOutputs when a filesystem copy was written, and report the completed run's canonical outcome.
Final run result objects report their terminal state through outcome and name the run through runId. A texra run result also records the plugins it ran with: plugins lists the installed plugins that loaded when it started or resumed, enabled and trusted (name, source, and for a fetched plugin its ref and pinned commit). The tools a run offered can change between its model requests when a plugin is switched on or off; the run records each change in its history.
NDJSON contract, version 2
Every --output-format ndjson line is one JSON object whose first key is kind, followed by the record's own fields, a ts timestamp, and contract: 2, the version of this contract. Version 2 is the 1.0 contract:
kind: "progress"records carry a session event verbatim.eventis the event'stype(run.start,status,run.end,usage,stage.start,tool.start,run.description,run.removed, and so on), andpayloadis the rest of the event under its own field names. Ausageevent is one priced model turn, so a run's spend is the sum of itsusageevents. A run's events name it throughpayload.aggregateId, the JSON array["run", "<run id>"]; a parent edge ispayload.parentonrun.start; the terminal fact isrun.endwith itsoutcome. One record with no session event behind it,event: "run.children", reports a parent run's live children as{ runId, children }, each child carrying itschildRunId,identity,agentName, andstatus— the run phase, orreadybefore the child's first activation. A child that reached a terminal outcome leaves the list; itsrun.endrecord carries the outcome.kind: "agent-result",kind: "result", andkind: "team-result"carry the run result described above underresult, withrunId.- History records (
history-entry,history-detail) spell a terminal outcome ascompleted,interrupted, orerror;resumableandunknownpass through unchanged.
Authentication
Model calls run on your own provider API keys, or on a provider subscription you already pay for. There is no TeXRA account: every agent ships bundled.
Bring your own provider keys. Set the environment variable for the provider you want to use (ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_API_KEY, …), then run the CLI normally:
export ANTHROPIC_API_KEY=sk-…
texra run polish --input paper.texA project's .env file is read by every task of that project. A key set only in this terminal does not reach a task that runs in the TeXRA service; the CLI says so, and TEXRA_NO_SERVICE=1 keeps the task in this terminal.
Use a provider subscription. ChatGPT, Grok (xAI), Kimi Code, and the GLM Coding Plan can serve model calls in place of an API key:
texra auth chatgpt login # Codex models through your ChatGPT plan
texra auth grok login # Grok models through an xAI subscriptionInside a chat, /login manages the same preferences: its form signs you in or out and sets which subscription serves each provider's models, and /login status prints how each model will be paid for.
CI pipelines. Headless pipelines can't sign in interactively. Store the provider API key as a CI secret and export it in the pipeline environment. With a provider key set, texra run … needs no other credentials.
Subscriptions sign in through texra auth <provider> login:
texra auth chatgpt login # browser sign-in
texra auth chatgpt login --no-browser # print the loopback sign-in URL
texra auth chatgpt login --device # device code: approve from a browser on any device
texra auth chatgpt status
texra auth chatgpt logoutgrok takes the same verbs. --no-browser still uses a local callback server. Open the printed URL in a browser that can reach the terminal session; SSH and container sessions may need callback port forwarding. --device needs no callback at all: the CLI prints a short code and a verification URL. Open the URL in a browser on any device, including your phone, and approve the code. This is the recommended path on SSH, WSL2, and containers.
Run texra doctor at any time to see which dependencies are detected and which models the CLI can reach with the current credentials.
Interactive chat
texra chat opens an interactive chat in the terminal. It streams reasoning, tool calls, and diffs, and writes to the same run history as the VS Code extension. Running bare texra in a terminal opens this same session.
Reading the section, then tightening the opener.
- ●read_file(sections/intro.tex)⎿In this paper we present a novel approach to… +41 lines (ctrl + t to view transcript)
- ●edit_file(sections/intro.tex)
A texra chat session streams reasoning and tool calls inline, shows diffs as the agent edits, and lists its slash commands at the bottom.
texra chat # default chat agent and model
texra chat --agent research # pick the agent for the session
texra chat --model deepseek/deepseek-flash@high # override the session model and effort
# headless chat run for scripts and CI
texra run review --input main.tex --instruction "Check the proof." --printSlash commands inside the session: /login signs in and sets which provider subscriptions serve their models, /approval sets the approval policy and turns off a grant you gave with a on an approval card (/status lists them), /config holds settings and integrations, /model switches to another model from the same provider mid-session (the change applies immediately and persists on resume), /skills lists available skills and applies one to your next request, and /resume restores a stored execution. Chat requires an interactive terminal. For scripted, non-TTY runs use texra run <agent> with --print or --output-format json|ndjson. One command serves every agent: an agent without a document task accepts workspace --input and --context files plus a required instruction (--instruction, --instruction-file, or both); an agent with a document task runs that task over the --input files, takes --output/--output-dir, and produces document-oriented outputs. List the agents that have a document task with texra agents list --tasks. A bare name picks the highest-priority agent of that name (custom, then built-in, then plugin); pass a source-qualified key such as texra run builtIn:assistant to pick another.
/tasks lists the tasks the background service runs, across every project (see Background service). Choosing one attaches to it inside the chat: its transcript streams live, Enter sends it a follow-up, and a command, edit or question it asks appears as the usual approval card. Esc detaches; the task keeps running in the service.
Teams
The CLI can list, show, and run the same built-in teams as the extension's Teams settings tab: Lean Project, Physicist, Mathematician, Computer Scientist, and Software Engineer.
texra team list
texra team show software-engineer
texra team run software-engineer --instruction "Profile and speed up scripts/simulate.py"run starts the team's orchestrator, which plans the work and delegates to its specialists. For example, the Software Engineer team's engineer lead delegates to coder, codeReviewer, testEngineer, and codeSimplifier. Pass --input and --context files as with texra run; read-only context files are included in the instruction the team receives. When the work splits cleanly, the lead can fan it out as a scripted multi-agent workflow.
run is the way to start a team from a terminal. For an interactive session, open a chat and use /agent to pick the team's lead by name, such as engineer or orchestrator; team scoping applies to team run and to resumed team sessions.
- 1●codercompleted48soptimized the inner loop in scripts/simulate.py
- 2●testEngineerrunning21spytest -q · 17 passed, 3 to go
The lead delegates while child agents stream below it as numbered subagent rows. Each one is a focusable stream with its own scoped transcript.
In an interactive team session, focusing a subagent shows only its own transcript. Scroll back through its earlier output with normal terminal scrolling and search. Each subagent keeps its own scoped history that persists across sessions, and resuming a subagent continues it where it left off.
Skills
Skills are reusable instruction folders the agent can apply to a request. List what's available, and pull in extra skill folders for any agent run:
texra skills list
texra run polish --input paper.tex --source ~/my-skills
texra chat --include-interop--source (alias -s) adds an additional skill root and may be repeated; --include-interop also includes .agents, .claude, .codex, and .gemini skill folders from the workspace and home directory. When skills share a name, project and user skills take precedence over bundled ones. In chat, pick a skill with /skills to apply it to your next request.
Plugins
TeXRA installs plugins published for Claude Code and Codex. It reads the plugin's own manifest, .claude-plugin/plugin.json or .codex-plugin/plugin.json, and the folders beside it: skills from skills/, commands from commands/, agents from agents/, MCP servers from .mcp.json, plus any of these paths the manifest declares.
texra plugin install github.com/LionSR/AgenticPublicationProtocol
texra plugin install github.com/<owner>/<repo>@v1.0.0
texra plugin install https://example.org/plugins.git --ref main
texra plugin install ./my-plugin
texra plugin enable paper-protocol
texra plugin list
texra plugin update
texra plugin disable paper-protocol
texra plugin remove paper-protocolAn installed plugin stays off until you enable it. texra plugin enable shows what the plugin declares (its skills, commands, agents, and each MCP server's command line) and asks you to trust it. The trust covers that version, every file in the plugin folder, and the MCP servers' commands, arguments and environment values. If any of those change, the plugin loads nothing until you enable it again and trust it anew. A program or file outside the plugin that a server runs, such as node, is listed as external and trusted by its path, size and date, not by its content. A plugin cannot be named custom, builtIn or plugin. A plugin with LSP servers runs code of its own and cannot be enabled yet; output styles and apps are not loaded. A plugin's Claude Code hooks run as processes in the workspace. A Stop hook that blocks (decision: "block", or exit code 2) keeps the run going once with its reason as the next instruction, even under texra run. The stop after that turn tells the hook stop_hook_active: true and cannot block again.
An enabled, trusted plugin loads under its own name: its skills and commands are skills named <plugin>:<name>, its agents are agents named <plugin>:<name>, and every top-level chat run is offered its MCP servers' tools, named mcp__plugin_<plugin>_<server>__<tool>. A plugin agent that lists tools gets only those; one that lists none inherits them: a subagent gets every tool its parent was offered, and a top-level run the file, shell and web tools plus the installed plugins' tools. A subagent never gets more than its parent was offered. Each server runs as its own process in the plugin folder, and its tool calls are approved like shell commands. Enabling, disabling or changing a plugin reaches a running conversation at its next model request, which records the change; a call to a tool that has since gone is refused. What a plugin took part in stays in the history after you disable or remove it.
A fetched plugin lives in ~/.texra/v1/global-storage/plugins/<name>/, pinned to the commit its branch or tag resolved to. texra plugin update fetches the same branch or tag again and pins the new commit. If removing a plugin could not delete its folder, texra plugin remove again finishes the job. A local folder is used in place and is not copied, so edits to it show up at once; removing it only forgets it.
A repository with a marketplace file (.claude-plugin/marketplace.json or .agents/plugins/marketplace.json) and no plugin manifest of its own installs the plugin it lists. When it lists several, name the ones you want with --plugin <name>, which may be repeated.
The CLI, the VS Code extension and the desktop app share one install record and one set of trust decisions. The Skills section of the Agents settings page in the extension and the desktop lists installed plugins and installs, enables, disables, updates and removes them; enabling there asks for trust in a dialog.
Shell completion
TeXRA can print completion scripts for Bash, Zsh, and Fish:
texra completion bash >> ~/.bashrc
texra completion zsh > "${fpath[1]}/_texra"
texra completion fish > ~/.config/fish/completions/texra.fishRestart the shell, or source the file you updated. Completion includes subcommands, flags, enum values such as --output-format text|json|ndjson, agent names for texra run <TAB>, and model names for --model <TAB>.
Agent and model completion call back into texra agents list and texra models list. Disable those dynamic lookups in slow shells with:
export TEXRA_COMPLETION_DYNAMIC=0Execution history
TeXRA stores completed executions in the workspace run store. List recent runs:
texra history list
texra history list --limit 10 # only the most recent runs (alias: -n)
texra history list --output-format ndjsonText output prints one tab-separated row per run:
<id> <timestamp> <agent> <status> <primary input>The NDJSON form is stable for scripts under the version-2 contract above. Each line has kind history-entry and contains the same run entry object used by JSON output, with the terminal outcome spelled as completed, interrupted, or error.
Inspect or delete one run:
texra history show <id>
texra history delete <id>Continue a stored session, on the saved agent and model:
texra resume <id>
texra --resume <id>A chat reopens in the interactive chat and waits for your next message, so without a terminal it exits with a usage error that points scripting at texra run. A document task run resumes headless under its original execution id and honors the headless globals (--print, --output-format, --no-input). The interactive chat also accepts /resume: with no id it lists recent tasks by title, with an id it continues that task, and /resume all continues every interrupted one. /rename <title> gives the focused task your own title. A missing or malformed id exits with code 2.
Fork, reset or hand off a conversation as you continue it:
texra resume <id> --fork # a new task holding the conversation
texra resume <id> --fork --at <n> # the same, cut at the end of an earlier turn
texra resume <id> --reset # clear what the model sees, then continue
texra resume <id> --handoff "<text>" # clear it and continue from this textInside the chat, /fork continues a new task holding the conversation (the original stays in /resume), /handoff <text> continues the task in a fresh context that starts from your text, and /reset clears that context so the model answers your next message alone.
A fork leaves the original task unchanged, and it can be cut only at the end of a turn: a position inside one is refused. A reset or a handoff takes effect when the task is next waiting for you, after any message already queued for it, and the handoff's text is the message the model answers next.
When texra chat opens without a task to resume, it looks for tasks a closed or crashed TeXRA stopped mid-way. With "texra.resumeOnOpen": "auto" in ~/.texra/v1/global-storage/config.json it continues them; the default, ask, lists them above the input, where /resume all continues them and anything else you send hides the list. A task whose agent is missing, or comes from a plugin that is off or not trusted, waits until that is fixed and then continues by itself. texra run never resumes anything on its own.
A run another TeXRA process still holds is refused, and the message names that process's pid and host. A holder that cannot be reached (it ran on another machine, or its liveness cannot be proven) counts as holding the run; when you are sure it is gone, delete the run from history and start a new one.
Background service
One TeXRA service per user and machine runs tasks for every terminal. It starts on its own the first time a chat or a texra tasks command needs it, keeps running the tasks it started when the terminal that started them closes, and exits after ten minutes with no client connected and no task running.
A task in the service asks a window of its own project for what only a window has, and the window focused last answers. A chat shows its project's task notices (a refused resume, an error). When the asked window closes or does not answer in time, the tool says so instead of waiting; with no window of the project open, the task runs as a headless run does.
texra chat (and a bare texra) is a client of the service: the conversation's runs run there, so /tasks in another terminal lists it and can attach to it while it works. texra resume <id> of a conversation the service is running continues it there. When the service cannot start, or TEXRA_NO_SERVICE=1 is set, the chat runs in its own process and says so once; other terminals then do not see it. texra run, -p and --output-format ndjson always run in their own process.
texra tasks list # every project's tasks, newest first
texra tasks start <agent> --instruction "<text>" # start an agent in the service; prints its id
texra tasks attach <id> # follow it live until it ends
texra tasks send <id> "<text>" # send it a follow-up
texra tasks stop <id> # stop it; it can be resumed laterlist marks the tasks the service is running now with *. Any number of terminals can attach to the same task at once and all of them print the same transcript; Ctrl-C detaches one terminal and leaves the task running. An id may be shortened to any prefix only one task has. tasks start runs the task under the project's approval policy; an approval policy it asks for (--approval-policy, --no-input, TEXRA_APPROVAL_POLICY) applies to that task alone: it narrows the project's, and yolo auto-approves the task. It never changes the project's policy. A service task that asks for approval waits for an answer: texra tasks attach only watches, so answer it from the chat with /tasks. With --output-format ndjson, attach writes the task's own rows (not its agents') as progress records, in the shape texra run uses.
Manage the service itself:
texra service status # pid, version, socket, clients, tasks running
texra service stop # stop it; its running tasks stop and can be resumed
texra service restart
texra serve # run it in the foreground, logging to stderrThe service listens on a socket in ~/.texra/run/ that only your user can open, and writes its log to ~/.texra/run/serve.log. A newer TeXRA that finds an older service asks it to finish its running tasks and exit, and starts its own beside it. The service takes its environment (PATH, provider keys) from your login shell, not from the terminal or window that happened to start it, so latexmk and git are found the same way from every window; it logs the PATH it uses. It reads that environment and your settings when it starts: after you export or remove a key in your shell profile, or edit config.json, run texra service restart. The service does not run on Windows yet; there, chats run in their own process.
Tools and integrations
The CLI can inspect the same external agent integrations shown in the extension settings:
texra tools list
texra tools status codex
texra tools disable codex
texra tools enable codex
texra tools install codex
texra tools auth codextools list reports each integration id, name, category, enabled state, and detection result.
tools list reports six columns per integration: a status dot marks the enabled state, a check or cross marks whether the backing tool was detected on this machine, and the note carries the registered install command when something is missing.
Use --output-format json or --output-format ndjson for scripts. tools install <id> prints the install guide and registered command; it only runs the command when passed --run. In the interactive TUI, /plugins lists the same plugins, with installed plugins and MCP servers beside them, and switches the ones that can be switched on or off.
Models and memories
List the models TeXRA knows about, and manage which ones appear in the /model picker and the lead-model picker:
texra models list
texra models show deepseek/deepseek-v4-pro
texra models enabled
texra models enable xai/grok-4.7
texra models disable xai/grok-4.7Inspect the notes agents have stored for this workspace (see Memory):
texra memory list
texra memory show memories/<file>Workspace defaults
Run texra config in a terminal, or /config in a chat, to open the same configuration view. Its Agents section has three distinct choices:
- Workspace agents controls which agents are available in the current folder. It may inherit the user default, show all agents, use a named team, or store an exact custom selection.
- Default team is a user-level choice used only by workspaces whose agents are set to inherit. With no default team, an inherited workspace shows all agents.
- Default chat agent is the root agent selected for new chats in this workspace. It is stored under
texra.chatin.texra/config.jsonand does not change which agents are visible.
The corresponding non-interactive interface is texra config agents:
texra config agents # inspect the effective agents
texra config agents --all # make every agent visible in this folder
texra config agents --team lean-project # use a named team
texra config agents --inherit # follow the user default
texra config agents --default-team physicist
texra config agents --agents correct,polish,assistant,review
texra config agents --default-agent builtIn:assistanttexra agents list and texra team list|show|run keep narrower responsibilities: they inspect or run agents and teams, but do not alter the workspace agents. texra init writes initial command defaults and likewise does not change agent visibility.
The CLI reads optional, non-secret defaults from .texra/config.json in the current workspace. Scaffold one with texra init (add --yes to accept defaults non-interactively, or --gitignore to add .texra/ to .gitignore). Command-line flags override environment variables, environment variables override the workspace file, and the workspace file overrides built-in defaults.
- 1CLI flagshighest priority--model deepseek/deepseek-flashwins
- 2Environment variablesshell exportsTEXRA_MODELTEXRA_AGENTTEXRA_OUTPUT_FORMATTEXRA_APPROVAL_POLICY
- 3Workspace file.texra/config.json"model": …
- 4Built-in defaultlowest prioritydeepseek/deepseek-v4-pro
Resolution order, highest priority on top: a CLI flag beats its TEXRA_* env var, which beats the .texra/config.json key, which beats the built-in default (deepseek/deepseek-v4-pro).
{
"texra.model": "deepseek/deepseek-v4-pro",
"texra.outputFormat": "text",
"texra.chat": {
"agent": "assistant",
"model": "deepseek/deepseek-v4-pro"
},
"texra.run": {
"model": "deepseek/deepseek-v4-pro"
}
}Supported top-level keys are texra.agent, texra.model, and texra.outputFormat; texra.chat and texra.run may set command-specific agent and model defaults. Shared TeXRA settings the CLI honors, such as texra.telemetry.enabled, are also accepted. The built-in CLI model default is deepseek/deepseek-v4-pro.
The approval policy (texra.approvalPolicy) and the two approval switches (texra.toolUse.requireEditApproval, texra.toolUse.requireBashApproval) are never read from .texra/config.json, because a repository you clone can carry that file. Set them with /config or the settings view: they are kept in your own storage for the current workspace, and a value in your user configuration file is the default for every workspace. A project file that sets one is ignored and texra doctor reports the key.
The corresponding environment variables are TEXRA_AGENT, TEXRA_MODEL, TEXRA_OUTPUT_FORMAT, and TEXRA_APPROVAL_POLICY. Run texra doctor to see which workspace config file was loaded and whether any keys were ignored.
Two more switches live in the environment:
| Variable | Effect |
|---|---|
TEXRA_NO_TELEMETRY / DO_NOT_TRACK | Turn off usage logging (Usage logging) |
TEXRA_NO_UPDATE_CHECK | Skip the daily check for a newer texra release (environment-only) |
Usage logging can also be turned off with "texra.telemetry.enabled": false in your user configuration file, ~/.texra/v1/global-storage/config.json (texra doctor prints this hint). The environment variables override a stored true, but not the reverse: they can only switch logging off.
Both take 1, true, or any other value; 0, false, no, off, empty, and unset mean "leave it on".