oh-my-cli: a self-hosted code agent CLI with a safety plane you can read
A minimal autonomous code-agent CLI built with Qwen Code
At a glance
- What is it?
- oh-my-cli is a TypeScript code-agent CLI built on Qwen Code that reads files, edits them and runs shell commands under inspectable approval, trust and command policies. Its value is the permission model, not the model behind it.
- Who is it for?
- Adopt oh-my-cli if you want an agent whose permission surface you can audit before it touches a repository, and if you are comfortable running Node.js 22 with an OpenAI-compatible endpoint you control. Skip it if you need a published release channel: package.json pins version 0.1.0 and no releases are listed, so you install from source and track main.
- Can I use it commercially?
- Yes. Apache-2.0 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 37 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 17, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem oh-my-cli addresses: an agent that can edit files needs a permission model, not just a prompt
Most terminal coding agents arrive with a model choice and a warning. oh-my-cli inverts that. The README states the project's own framing directly: safety is the product. Everything else in the repository is arranged around that claim.
The target user is an engineer who already has an OpenAI-compatible endpoint, hosted or local, and wants an agent to read and edit files and run shell commands without handing it blanket authority over a machine. The README describes four mechanisms that make up the boundary: approval modes with a spoof-resistant approval preview, a folder-trust boundary, workspace path containment, and a deterministic command policy. Mutating tools fail closed by default, which means the default posture is refusal rather than execution.
That posture costs something. An agent that fails closed will stop and ask more often than one that does not, and the README does not claim otherwise. The trade is deliberate: the project assumes you would rather approve a write than discover one. If your work is exploratory and you do not care what the agent touches, this is the wrong shape of tool.
How oh-my-cli works: a CLI over an OpenAI-compatible endpoint, with sessions on disk
The architecture visible in the repository is small. package.json declares three runtime dependencies: commander for argument parsing, the openai client, and zod for schema validation. There is no agent framework underneath. The bin entry maps the oh-my-cli command to ./dist/index.js, main points at dist/desktop/main.js for the Electron shell, and the source lives in src/ with tests in tests/.
Model configuration resolves through a layered chain rather than a single source. Environment variables win over a workspace .env file, which wins over the user settings file, which wins over a built-in default for the base URL. The credential is the exception: the settings file never stores it, only the name of the environment variable that holds it, through a field called apiKeyEnv. Raw credential fields such as model.apiKey are rejected, according to the README.
Sessions are the other half of the mechanism. Every run is a JSONL session, and the README lists resume, continue, compact, export, undo and redo as operations on those sessions. That means state is a file you can read, not a process you have to keep alive. The headless side adds a versioned JSON event stream, run summaries, run scorecards, spend budgets, run caps and recovery from checkpoints. None of that is verified here; it is what the README documents.
Installing oh-my-cli and running a first task
The README gives three commands for install. There is no published package, so this is a from-source build. Node.js 22 or newer is required by the engines field in package.json.
npm install
npm run build
npm linknpm link puts the oh-my-cli command on your PATH so the examples in the documentation run as written. The README notes that npm unlink -g oh-my-cli removes it later, and that you can skip linking entirely by invoking the built entry directly with node dist/index.js.
Before running a task, the README points to a setup check called --doctor, described as part of the first-run path in docs/FIRST-RUN.md. A second diagnostic, --preflight, prints a redacted summary of the resolved model, endpoint host, settings source and credential variable name, marking which layer supplied each value as env, workspace-env, settings or default. The credential value itself is never printed.
The smallest useful configuration avoids exporting variables in every shell. The README shows a user settings file at ~/.oh-my-cli/settings.json, or an alternative path passed with --settings:
{
"model": {
"baseUrl": "https://dashscope.aliyuncs.com/compatible-mode/v1",
"name": "qwen-latest-series-invite-beta-v77",
"apiKeyEnv": "DASHSCOPE_API_KEY"
},
"mcpServers": {},
"extensions": {}
}The base URL and model name live in the file; the credential stays in the named environment variable. The README is explicit that a settings file inside a project is never auto-discovered, so an untrusted repository cannot redirect your endpoint or credential. If you prefer a project-local file, the workspace .env accepts OPENAI_API_KEY, OPENAI_BASE_URL and OPENAI_MODEL, but only when the workspace is trusted through --trust-workspace or --trust for the current run. An untrusted workspace's .env is never opened. The README also states that .env values are parsed for model-config resolution only and never mutate process.env, so spawned tools do not inherit them, and that .env.local, .env.production and nested .env files are not read.
Where the safety plane stops: trust, containment and the limits the README admits
Folder trust is a one-time decision with lasting weight. The README says a workspace becomes trusted through a user-owned trust store via --trust-workspace, or for a single run via --trust. Once trusted, its .env is read. The README does not document a rollback or a review step for that store, and it does not describe how to inspect which workspaces are already trusted. That is a gap worth knowing about before you run --trust-workspace broadly.
The command policy is described as deterministic, which is the right word for a rule set you can read, and also a limit: a deterministic policy cannot reason about a command it has never seen. Novel shell invocations are exactly the case where a rule list and an intent diverge. The approval preview is described as spoof-resistant, which addresses the display layer, not the decision layer.
The headless surface carries its own cost. Spend budgets and run caps exist because an agent loop can spend money unattended, and recovery from checkpoints exists because runs fail. Those features are acknowledgements of failure modes rather than guarantees against them. The README does not state what happens when a budget is exhausted mid-run, and it does not document how checkpoint recovery interacts with an already-modified working tree. Treat both as things to test on a throwaway repository first.
One more boundary: the project develops itself through an autonomous queue under a governance plane described in AUTONOMY.md. The README says the Bot may propose governance changes but cannot apply them, and that policy files, workflows and CODEOWNERS are protected and maintained by a named account. Whatever you think of that arrangement, it means the repository's own contribution path is not the ordinary pull-request flow.
oh-my-cli compared with running a general agent framework directly
The obvious alternative is to wire the openai client to your own tool loop, or to use a broader agent framework that ships many integrations and lets you assemble permissions yourself. The difference is where the safety logic lives.
In a general framework, approval and path containment are typically things you configure or implement, and the defaults tend to be permissive because the framework is meant to be extended. In oh-my-cli, those decisions are inside the product and the defaults fail closed. You get less surface area and fewer integrations, and in exchange the permission model is a thing you read rather than a thing you write.
That trade only pays off if you actually read it. A framework you configure gives you a written record of your own policy; oh-my-cli gives you the project's policy, which you either accept or fork. The README also notes the project ships an Electron desktop shell and a local web delivery board alongside the CLI, so the comparison is not purely CLI against CLI. If your requirement is a large plugin ecosystem, oh-my-cli's extensions and mcpServers fields are present but the README does not document a registry, so that ground is thin.
Maintenance, upgrade cost and the Apache-2.0 licence
The repository is not archived, and the last push was on 2026-08-12. That is recent, but no releases are listed, and package.json pins version 0.1.0. There is no published changelog to read, so upgrading means tracking the main branch and reading commits, or pinning a commit hash yourself.
The upgrade surface is narrow because the dependency list is short: commander, openai and zod at runtime, with electron, esbuild, tsx, typescript and vitest for development. A Node.js 22 floor is enforced through engines. The configuration schema is the part most likely to move under you, since it is validated with zod and covers the model, profiles, mcpServers and extensions sections. The README documents a selection precedence for profiles but the excerpt is truncated at that point, so check the full file before relying on profile switching.
The licence is Apache-2.0, declared in both LICENSE and package.json. That permits commercial and private use and requires attribution and notice retention. It also includes a patent grant and termination clause. This is a description of the licence text, not legal advice; if you redistribute oh-my-cli inside a product, have counsel read the NOTICE and modification requirements rather than taking this paragraph as clearance.
Editorial conclusion
Adopt oh-my-cli if you want an agent whose permission surface you can audit before it touches a repository, and if you are comfortable running Node.js 22 with an OpenAI-compatible endpoint you control. Skip it if you need a published release channel: package.json pins version 0.1.0 and no releases are listed, so you install from source and track main. Before trusting it on real work, run oh-my-cli --preflight to confirm which layer supplies the base URL, model and credential variable, then read the command policy and approval preview sections of the README against your own workflow.
Frequently asked questions
What is oh-my-cli?
It is a small self-hosted code-agent CLI built with Node.js 22, TypeScript and ESM, described in the README as a terminal tool that reads and edits files and runs shell commands against any OpenAI-compatible endpoint. Its distinguishing feature is a safety plane made of approval modes, folder trust, workspace path containment and a deterministic command policy, with mutating tools failing closed by default.
Is oh-my-cli open source?
Yes. The repository declares the Apache License 2.0 in both LICENSE and package.json, and the source lives in the src/ directory with tests under tests/.
How much does oh-my-cli cost?
The CLI itself is Apache-2.0 licensed, so there is no licence fee described in the README. Any cost comes from the model endpoint you point it at, and the README documents spend budgets and run caps for that reason. No provider prices are listed.
Which model versions does oh-my-cli support?
Any OpenAI-compatible endpoint, since the model name is configuration rather than a fixed choice. The README's own settings example uses qwen-latest-series-invite-beta-v77 against the DashScope compatible-mode base URL, and a local profile example points at llama3 on http://127.0.0.1:11434/v1.
Is the Qwen API free to use with oh-my-cli?
The README does not say. oh-my-cli only requires an OpenAI-compatible base URL, an API key and a model name; what that endpoint charges is outside the repository's documentation.
Community notes