Skip to content

Ta ​

A coding agent based on Cell and pi. ta is pi renamed to Ta: the interactive interface, -p, --mode json|rpc, slash commands, the session tree, extensions, skills and pi packages all work as in pi. On top of that:

  • Codemode by default: the model writes JavaScript scripts that call all tools through codemode, which can call them in parallel and filter large output within the script; only the script's output enters the context (see "pi Patches" below).
  • Session lock: only one Ta process can write to a single session file at any time; pi has no lock, so two processes would interleave writes.
  • Ta's appearance and identity: the terminal startup displays Cell's pixel dinosaur, version, and common keys (press the expand key to see all keys; set quietStartup: true to hide them); the system prompt, hint text, and MCP client name all refer to Ta. The /bug command opens Ta's GitHub issue page in the browser, including version, model, and platform information. The /share command, which depends on pi's official service (Radius), has been removed; /changelog displays Ta's release notes instead. Pi's version check and installation statistics for pi.dev are disabled by default (TA_SKIP_VERSION_CHECK=0 or TA_TELEMETRY=1 to enable). Pi's environment variables in Ta are named TA_OFFLINE, TA_SELF_UPDATE_COMMAND, and TA_TELEMETRY, though the original PI_* names still work.
  • ta serve: provides pi agent sessions over WebSocket to any number of clients (Web, desktop, mobile) and includes a built-in Web client; see @celljs/ta-host and @celljs/ta-web for details.

Install ​

bash
npm i -g @celljs/ta     # Node.js >= 22.19
ta                      # Interactive mode
ta -p "Summarize this repository"     # One-off run

Correspondence with pi ​

piTa
Global directory~/.pi/agent/~/.ta/agent/ (auth.json, models.json, settings.json, sessions/, extensions/ …, content format same)
Project directory.pi/.ta/; project description is still AGENTS.md
Environment variablePI_CODING_AGENT_DIRTA_CODING_AGENT_DIR, TA_CODING_AGENT_SESSION_DIR
Subcommandinstall remove update list mcpSame, plus serve, exec-server, pair, relay

Pi's extensions and pi packages work directly in Ta. Install them with ta install npm:<package-name>. To reuse existing .pi/skills from your project, add "skills": ["../.pi/skills"] to .ta/settings.json.

When Cua Driver is installed, Ta can use desktop applications on this machine in the background; see the built-in extension @celljs/ta-computer-use for details.

When a reply changes files, the web client shows them above the message box with the lines added and removed; a click on a file shows its diff in the workbench, and one button takes the changes of that reply back. See the built-in extension @celljs/ta-changes.

Ta works on a schedule too: /loop 30m <prompt>, /remind in 45m <prompt>, or just say "sum up yesterday's commits every day at 9". The Ta service runs each one in a new conversation at its time, and the Scheduled page of the web client lists the tasks and the summary of each run. See the built-in extension @celljs/ta-cron.

Like pi, Ta does not request approval before tool calls by default; to enable approval requests, install the optional package @celljs/ta-permission-gate.

ta serve ​

bash
ta serve                      # 127.0.0.1, last port (switches to free port if occupied)
ta serve --host 0.0.0.0 --port 4100
ta serve --web                # Start and open Web client in browser (token already included)
ta serve --exec ws://box:4200/exec   # Tools execute on ta exec-server on another machine (TA_EXEC_TOKEN)
ta exec-server --host 0.0.0.0 --port 4200 --cwd /workspace
ta pair                       # Pair phone or other device, connect back via Relay (default https://relay.cellbang.com)
ta relay --port 8080          # Run your own Relay

After startup, Ta writes the address and access token to ~/.ta/agent/serve.json (mode 0600). The Web client is available at the same address at /: the page file contains no data and requires no token; all API calls under /api require the token. The --web flag places the token in the URL's # fragment (not sent to the server or included in the Referer header); the page reads it and stores it in localStorage, then removes it from the address bar. The port and token persist across restarts (stored in serve-state.json in the same directory, mode 0600; delete it to get a new token and port), allowing a Web client installed as a PWA to reconnect to ta serve and auto-login on the next visit. When --port is specified, that port is used instead. The TA_SERVE_TOKEN environment variable can set the token (for example, generated by a desktop shell), in which case it is not recorded. Clients connect using @celljs/ta-client.

When the client does not specify a directory, conversations open in ta serve's working directory. The default is the directory where ta serve started; the Web client and desktop app can change it using "Open working directory…", and the selection is stored in ta.json in the agent directory. Model services can be signed in through the Web client (gear menu → "Model accounts…"), which writes credentials to the same auth.json file as the terminal's /login command. Conversations can also run on another machine, like VS Code's Remote SSH: in the directory picker, select a host (a Host from ~/.ssh/config or user@host), and the directory becomes ssh://<host>/<path>. The agent and model credentials stay on the ta serve machine; commands, files, terminals, and git run on that remote host. Ta serve uses the system ssh to connect (keys, ssh-agent, ProxyJump all work as usual, and the page prompts for passwords or host confirmation when needed). On the first connection, it places a small server (and Node.js 22 if missing) in ~/.ta/server on that host. Dev servers on that remote host open localhost addresses in the built-in browser, and ports are automatically forwarded. See ta-remote-ssh.md.

Devices paired with ta pair connect to ta serve through Relay with end-to-end encryption; the Web client's "Use on your phone…" feature does the same and displays a QR code for scanning.

Build ​

bun run build first builds ta serve's server using cell build --root serve, outputting to dist/serve/index.mjs, and builds the Web client to dist/public/ (the serve application loads @celljs/ta-web to build the frontend, and @celljs/serve-static hosts it). Then scripts/assemble.ts builds the ta command (from ta-harness's TaCli) to dist/cli.mjs and generates dist/pi/, which contains a package.json that renames pi to Ta (piConfig), along with pi's themes, HTML export template, documentation, and examples. When ta starts, it lets pi read branding information from this directory (PI_PACKAGE_DIR), using the same directory layout as pi's official binary. Built-in pi packages (defined in Ta's TaPackages.BUILTIN) are copied to dist/pi/packages/<name> after the build without source code or tests; they can be disabled in the Web client's Settings → Packages.

Everything ta needs at runtime is in dist/, so the published package has no dependencies, and installing ta does not install Cell or pi; the build places all dependencies in devDependencies. Ta serve's server is a separate Cell application under serve/ (private, not included in workspaces). Cell collects components only from dependencies; its serve/package.json lists which components to include. The @celljs/ta package itself does not need dependencies. When adding a component to ta serve, add it to both files: components in serve/package.json's dependencies determine the output content, and entries in package.json's devDependencies determine the turbo build order.

The ta command itself does not load Cell; its startup time and memory usage match pi. Only ta serve loads Cell.

pi Patches ​

The following hardcoded brand text in pi, the /bug and /share built-in commands, and the codemode default are patched:

  • Patches are stored as patches/@earendil-works%2Fpi-coding-agent@<version>.patch in the repo root. They are generated by bun run pi-patch (see scripts/pi-patch.ts below), registered in the root package.json's patchedDependencies, and automatically applied by bun install. Patches only modify pi's bundled output dist/bundle (what Ta runs).
  • Package manager patches only work in this repository. During the build, scripts/assemble.ts copies the patched dist/bundle to dist/pi/dist/bundle for release (~9 MB). The ta command sets PI_PACKAGE_DIR to dist/pi, and PiBundleUtil loads that copy. There is only one pi instance per process; extensions access it through its built-in module table. The build fails directly if the patch is not applied.
  • The bundle loads the following modules from node_modules at runtime: jiti (for loading extensions), @silvia-odwyer/photon-node (for image resizing), and quickjs-wasi (for codemode's WebAssembly). scripts/assemble.ts also copies these from pi's side to dist/pi/node_modules, using the same versions as pi. Extensions use typebox and pi's packages through the bundle's built-in module table. The build scans the bundle for packages loaded by name and fails if any are missing from the required or optional list. When upgrading pi, the script tells you which packages to add.

The following table shows what is changed, as defined by scripts/pi-patch.ts's REPLACEMENTS (original and replacement per group):

GroupChange
codemode by defaultThe default tools include codemode with codemode.mode set to only, so the model sees only the codemode tool. The tools read, bash, edit, write, extension tools, and MCP tools are called in the script using tools.<name>(). Pi has no host default setting layer; this change is only applied here. To revert to pi's behavior, write "codemode": { "mode": "on" } in settings.json (to provide other tools directly) or "defaultTools": ["-codemode"] (to disable codemode), or use --tools -codemode for a single run.
built-in commandsThe /share command (which uploads to Radius) and pi's /bug command (for pi developers) are removed. The /bug command is provided by Ta's extension instead, and the crash-after /bug hint is rewritten.
system promptThe opening is changed to Ta, and the pi docs section explains how pi's ~/.pi/agent, .pi/, and pi command correspond to Ta.
help of taIn ta -h, ta update -h, and ta auth -h, "pi" is changed to "Ta". Environment variables are listed as TA_* (converted to pi's PI_* by TaBrand.activate). The PI_PACKAGE_DIR variable set by Ta and PI_SHARE_VIEWER_URL (removed with /share) are excluded. MCP service examples change from radius to github. The commands ta update ta and ta update self are now equivalent.
update of tata update (for self and ta) queries npm for the latest @celljs/ta, not pi.dev (which would return the pi package name and replace Ta with pi). It does not prompt to run pi's install script because Ta is a single-file package with no fixed dependencies.
messagesIn tmux setup hints, project trust hints, and ChatGPT login port occupied hints, "pi" is changed to "Ta". The MCP client name changes from pi to ta.

Changes are only made where pi has no setting, parameter, or extension point. If a change can be made using piConfig, environment variables (TaBrand.activate), or a Ta extension, it is not done in the patch. Do not edit patches manually: pi's bundle is chunked by hash and compressed into long lines, so manual edits will fail after a pi upgrade.

To upgrade pi, first change the pi version in ai-packages/ai-coding-agent and other places, then run bun install. Next, run bun run pi-patch in apps/ta. The script takes the unpatched pi from the Bun cache and applies replacements line by line according to REPLACEMENTS (ignoring filenames; each original must appear the specified number of times in the entire dist/bundle). It then generates a new version patch with bun patch --commit, removes the .bun-tag-* chunk, and deletes the old patch. Finally, remove the old version line from the root package.json's patchedDependencies and run bun run test. If the original text has changed in the new pi, the script lists the find count and stops; update that line's from value and run the script again. Use bun run pi-patch --check to verify without generating a patch. test/pi-patch.spec.ts also checks the currently installed pi.

The following are not changed: pi's documentation body (the system prompt already tells the model how to map it), the Radius login option description (which belongs to pi's official service and is accurate), the settings page's "Pi's drawn cursor" option, and one error message in the package manager (which is buried in a tens of KB long line, so the patch cost exceeds the benefit).

Performance Benchmarks ​

bash
bun run bench               # All except long scenarios, ~3 min, outputs Markdown table
bun run bench streaming     # Specify scenario; --help lists all scenarios

The benchmarks use the locally built product (run bun run build first). The model runs as a standalone process with a fake OpenAI-compatible service (bench/fake-model.ts): the rate scenario has a first token latency of 200 ms and generates 100 tokens/sec; the burst scenario outputs 5000 tokens quickly. The baseline is pi --mode rpc: pi serving multiple sessions requires one process per session. Memory and CPU are sampled outside the process using ps (on Linux, this reads /proc), which does not interfere with the measured process.

Reference results from an Apple M4 Pro with Node.js 24:

ScenariopiTa
--version / -p0.12 s 112 MB / 0.18 s 127 MB0.12 s 114 MB / 0.19 s 128 MB
ta serve idle—66 MB, idle CPU 0
32 sessionsOne process per session, ~127 MB × 32181 MB (per session ~1.6 MB)
Single session stream (rate) first token / CPU209 ms / 5%209 ms / 5–6%
10 sessions concurrent stream1693 MB, 4.57 s CPU191 MB, 1.92 s CPU
50 clients viewing same session—Per client ~35 µs per delta

The endurance scenario (a long scenario that must be specified explicitly) runs 60 bursts on a 64 MB heap limit and checks that memory converges.

Tests ​

bun run test is an integration test that uses the real built product and a local fake OpenAI-compatible model service. It covers print and JSON modes, session locking, installation of pi packages and the permission gate, ta serve's multi-client broadcast, reconnect with resend, approval with first-come-first-served semantics, idempotent acknowledgments, session locking, idle session reclamation, and rate limiting.