Cali: a role-oriented CLI that wraps an LLM agent around React Native QA, review and perf runs
AI agent for building React Native apps
At a glance
- What is it?
- Cali v2 splits a mobile agent workflow into four fixed roles, a shared cali-context.json contract and an explicit tool pack per command. The design is opinionated in a useful way, but the review, perf-review and dev commands are still marked experimental and the whole thing depends on external CLIs and skills being present.
- Who is it for?
- Adopt Cali if you already run React Native or Expo builds in GitHub Actions or EAS and want a repeatable QA pass that writes a report instead of a chat transcript; the qa command is the only one that is not flagged experimental. Skip it if your team needs a general-purpose coding agent, if you cannot install agent-device and agent-react-devtools on the runner, or if you want the tool to install its own shell dependencies, which it deliberately refuses to do.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 76 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem Cali targets: mobile QA that nobody can reproduce twice
Most agent tooling for mobile work is a chat loop with a shell. You describe a task, the model picks commands, and the result is a transcript that nobody can rerun on the next pull request. Cali takes the opposite position: the deterministic parts (which artifact, which platform, which app id, which output directory, which provider) live in the CLI and in a JSON file, and the model only gets the tools its role needs. The README states the intent directly: it keeps deterministic setup in the CLI, gives the agent only the tools it needs, and writes a structured report that works locally or in CI. The audience is React Native and Expo teams who already have build artifacts and want a QA or review pass that produces the same shape of output every time. That is a narrower audience than the description (an AI agent for building React Native apps) suggests.
Four commands, four tool packs, one shared context file
Cali exposes four role entrypoints. `cali qa` runs a mobile QA pass with the agent-device tool pack. `cali review` does findings-first PR or repository review and is marked experimental. `cali perf-review` combines agent-device with react-devtools and is also experimental. `cali dev` is a repository-backed implementation flow, experimental as well. The mechanism that holds these together is the tool pack: a bounded set of tools exposed to the role, named in the README as agent-device, react-devtools, repo-read and repo-write. A QA run cannot reach a write tool because the pack does not include one. Every command reads the same cali-context.json contract but only requires the sections it actually uses, so a PR review does not need a mobile block and a QA run does not need pullRequest. Output goes through publishers, which the README describes as output targets that enrich or write the report, such as local files or blob-hosted screenshots. The practical consequence is that the agent's blast radius is set by configuration rather than by prompt discipline.
Getting a local QA run to start
The README gives this example for local iOS: `cali qa --local ios --artifact ./artifacts/MyApp.app --prompt "verify the onboarding copy on Screen B"`. Flags win over the context file, so `--platform`, `--artifact`, `--app-id`, `--output-dir`, `--pr-number` and `--task-id` all override JSON values. Platform can be inferred from common artifact extensions (.apk, .aab, .app, .app.tar.gz, .ipa), and for local runs `--app-id` is optional when Cali can infer it from the artifact. On Android, that inference reads AndroidManifest.xml directly from the archive and falls back to SDK aapt when the manifest is not readable. Credentials come from either `AI_GATEWAY_API_KEY` with `QA_MODEL` set to a gateway-routed model, or `ANTHROPIC_API_KEY` with a direct Anthropic model; the CLI loads .env automatically from the current workspace. Cali defaults to openai/gpt-5.4-mini, routed through AI Gateway when gateway credentials are present, and the README notes that direct provider support in this package is Anthropic only. Optional blob screenshot uploads need `BLOB_READ_WRITE_TOKEN`.
The external binaries Cali will not install for you
Each command shells out to local tooling. `qa` requires agent-device. `perf-review` requires agent-device and agent-react-devtools. `review` requires git and rg. `dev` requires git, rg and zsh. The README is explicit that if one of these is missing, Cali stops with an actionable error instead of trying to install it automatically, which is the right call for a CI tool but does mean a fresh runner needs `npm i -g agent-device` and `npm i -g agent-react-devtools` before the first run. Skills are handled differently: Cali discovers them from `~/.cali/skills`, `./.cali/skills`, `./.agents/skills` and `~/.agents/skills`, requires the agent-device skill for qa and both agent-device and react-devtools for perf-review, and auto-installs missing required skills with `npx skills` into `~/.cali/skills`. So the split is: binaries are your problem, skills are the CLI's problem. Note the zsh requirement on `dev`, which makes that command awkward on a slim Linux container.
Local device handling is where a run usually breaks
The README documents the local mobile behaviour in some detail, and it is worth reading before the first attempt. Each run gets a unique agent-device session name such as `ios-a1b2c`. Local Android reuses the single booted emulator when exactly one is available, otherwise you must pass `--device`; local iOS behaves the same way with a single booted simulator. Local runs try `open --relaunch` before reinstalling the app. The line that catches people out is the note that debug artifacts usually need Metro running for the duration of the QA run, and that Metro must be started and stopped outside Cali. A CI job that builds a debug artifact and then calls `cali qa` without a Metro process will fail somewhere inside the agent loop rather than at startup. Release artifacts sidestep this, but the README does not say so outright; it only warns about debug builds.
Context sanitisation and what report.json actually contains
Context can arrive from three places: provider detection (GitHub Actions or EAS), explicit `--local android|ios` flags, or an explicit JSON file passed with `--context`. Cali sanitizes credential-bearing repository URLs when loading context and publishes a reduced safe context in report.json by default. That is a sensible default for a report that gets uploaded as a CI artifact, but it is a one-way door: anything scrubbed on the way in will not be visible to a downstream job that parses report.json. If your pipeline reads the repository webUrl or a token-bearing clone URL out of the report, that field may not be there. The README does not enumerate which fields survive sanitisation, so this is something to confirm empirically on a throwaway branch before wiring a downstream consumer to the file. CI mode is detected implicitly from the environment, with `--ci github-actions|eas` available only as an override. The retro banner is suppressed by `--quiet` or automatically when CI=true.
Where Cali is the wrong tool, and what to use instead
Three of the four commands carry an experimental label in the README, so a team that needs a dependable PR reviewer today is buying into unfinished surface area. The `dev` command also requires zsh, which rules it out on many minimal CI images. The more interesting comparison is with a general-purpose coding agent such as Claude Code or a similar terminal agent. Those give the model a broad shell and let it decide what to run; Cali inverts that by fixing the role, the tool pack and the context contract up front. The difference shows in the failure mode. A general agent can improvise a workaround when a device is missing; Cali stops with an actionable error. A general agent can also edit files during a QA pass; Cali's qa tool pack does not include repo-write, so it cannot. If your work is exploratory, or the task does not fit one of the four roles, the fixed-role model is a constraint rather than a feature, and a general agent is the better fit. If your work is a repeatable pass that runs on every PR, the constraint is the point.
Licence and the cost of keeping up
Cali is MIT-licensed TypeScript, so forking and vendoring are permitted under the usual terms; this is not legal advice and you should read the licence text yourself. The maintenance question is less about the licence than about the dependency chain. Cali sits on top of agent-device, agent-react-devtools, git, rg and zsh, and its skills are pulled with `npx skills` at run time. Any of those can move independently of Cali. The release history in the repository shows v0.1.0 in November 2024 and v0.3.1 in December 2024, so the version line is still early and the experimental labels on review, perf-review and dev are consistent with that. The context contract is the piece most likely to churn, because it is shared across all four commands; a field rename there touches every role at once. Pinning the CLI version in CI and treating cali-context.json as a reviewed file rather than a generated one is the cheapest way to keep an upgrade from silently changing what the agent can see.
Editorial conclusion
Adopt Cali if you already run React Native or Expo builds in GitHub Actions or EAS and want a repeatable QA pass that writes a report instead of a chat transcript; the qa command is the only one that is not flagged experimental. Skip it if your team needs a general-purpose coding agent, if you cannot install agent-device and agent-react-devtools on the runner, or if you want the tool to install its own shell dependencies, which it deliberately refuses to do. Before committing, verify three things: that `cali qa --local ios --artifact ./artifacts/MyApp.app` can see a booted simulator, that your model credentials resolve through AI_GATEWAY_API_KEY or ANTHROPIC_API_KEY, and that the safe context written into report.json does not strip a field your downstream CI job reads.
Community notes