OpenOv AI

Install

One line installs the openovai command. One more creates an instance: a directory of its own, signed in to its own account, served on one port. Node.js and Claude Code are fetched for you, pinned per release. Nothing global, no sudo.

From nothing to a Leader answering

  1. Get the openovai command

    curl -fsSL https://raw.githubusercontent.com/nilcaream/openovai/main/openovai | sh

    It is one shell script. Read from a pipe, it installs itself: a copy under ~/.local/share/openovai/ and a link at ~/.local/bin/openovai, and it says so. If ~/.local/bin is not on your PATH it prints the one line to add to your shell profile and asks you to open a new terminal — it never edits a profile itself. Once per user; every instance after that starts from it.

    With Node.js 24 or newer there is another way in, and it does this step and the next at once:

    npx @openovai/ovai@latest

    The package is the release. It asks the same questions as the next step and takes the same options, needs no download for the release itself, and leaves no openovai command behind. Node.js and Claude Code are fetched at the first ovai start, which needs sh, curl or wget, tar, sha256sum or shasum and uname, as the other way does. @latest is written out because npx reuses a copy it has cached for a name given with no version; @openovai/ovai@<version> names a release. ovai update takes later releases from GitHub, signed, whichever way the instance was made.

  2. Create the first instance

    ~/.local/bin/openovai

    With no arguments the release's installer asks its questions: where the instance lives, who it works for, the Leader's name, the models, the port, how it signs in. Before anything else openovai says which version it resolved — openovai <version> (latest) — downloads that release once, fetches the Node.js and Claude Code it pins, and hands over to its installer. The directory has to be empty or new.

    [media 5]
    recording, 20–30 s: from the one-liner to the page opening — the version resolved, the runtimes fetched, ovai start printing the one-time link
  3. Sign in, and start

    # if the instance signs itself in (--auth login): opens a browser once,
    # and the credential stays inside the instance
    ~/workspace/bin/ovai login
    # start the server in the background: it prints a one-time link to the page and returns
    ~/workspace/bin/ovai start
    # a new link, for another browser or once the first has run out
    ~/workspace/bin/ovai url

    Open the link it prints. It works once, for ten minutes, and signs that browser in: it stays signed in across restarts and updates, and nothing else on the machine that reaches the port gets the page. ovai url prints a new link, for each further browser. The Leader's panel is in the middle; type what you want and the Leader starts. ovai status says whether the server is running and where, ovai stop stops it.

  4. A second instance, on one line

    ~/.local/bin/openovai --root ~/second --user Ana --leader Max \
                          --leader-model opus --worker-model sonnet --port 7800 --auth login
    ~/second/bin/ovai login
    ~/second/bin/ovai start

    Every argument after the version is the release installer's own, passed through as it is: give them all and nothing is asked, so one command line describes a whole instance and can be read back, repeated and tested. Two instances on one machine share the runtimes and nothing else — not the account, not the transcripts, not the port. A later instance simply gets the newest release, said out loud; the older one catches up with ovai update.

The options

Each one is the installer's; openovai passes them through and knows only one of its own, the version.

openovai [version]
openovai <version> … or openovai --version <version> … takes that release; absent, the newest release on GitHub at that moment, printed before anything is done. Asked interactively, the choice offers latest and the versions already downloaded.
--root
Where the instance lives. It has to be empty or new. With --force an install over an instance already in place is an update of it: the payload is replaced whole and every file of yours is kept.
--user
The person the team works for.
--leader
The name of the session that leads the team.
--leader-model, --worker-model
The models those sessions run on, offered as opus for the Leader and sonnet for the Workers; opus/high names an effort too. A Worker can be hired onto another one later, and its desk keeps that one from then on.
--port
The port the page listens on, on 127.0.0.1 only. 0 means whatever is free, and ovai start prints the address it actually got; pick a number when you want the same one every time — a bookmark, or the page installed as a web app.
--auth
How the instance gets an account: login or inherit. Below.

What it needs

Linux or macOS, x86_64 or arm64, with sh, curl or wget, tar, sha256sum (or shasum, as a Mac has it), ssh-keygen from OpenSSH 8.1 or later, and uname. macOS is built for and checked with stand-ins on Linux, but ovai has not yet been run on a Mac. WSL 2 has not been tried, and native Windows is not supported. To try WSL 2, keep the instance in the Linux file system and off /mnt/c. Nothing else: no Node.js, no npm, no Claude Code on the machine — but for the npx way in, which runs its installer on a Node.js 24 or newer you already have, is refused by npm on Windows, and still needs sh, curl or wget, tar, sha256sum or shasum and uname at the first ovai start, where the instance fetches what it runs on. The rest the installer brings: the Node.js and Claude Code an instance runs on are pinned, exactly, per release — chosen and tested when the release is cut — fetched from a fixed address and checked against a checksum, and kept under ~/.local/share/openovai/, per user, outside every instance. Instances on one machine share those runtimes and reuse what is already there; an instance runs them by absolute path and never touches, nor uses, a Node.js or Claude Code the system already has. Nothing lands on your PATH but the openovai command.

Signing in

An instance needs an Anthropic account before it can answer anything. --auth picks how it gets one.

--auth login
The instance signs itself in. A freshly installed one has an empty Claude Code home, so ovai login opens a browser once and the credential is kept inside that instance. Use this when two instances on one machine should be two different accounts. The server looks once a day at when that sign-in runs out, and five days before it the Leader's panel gets one row with the date and the hour: run ovai login before then. Once it has run out and cannot be renewed, a panel whose turn failed on it, a turn started by an event of the server's or by a restart included, says, once, to run ovai login in a terminal and type again.
--auth inherit
The instance takes CLAUDE_CODE_OAUTH_TOKEN from the environment it is started in. Mint that token once on the machine with claude setup-token, export it wherever instances are started from, and every one of them is signed in from its first message, with no browser in the way. The token is long-lived but not forever and cannot refresh itself: when it expires every instance stops at once with the same message, and a new token fixes them all. ovai login refuses under this option and says so.

Either way the instance's Claude Code home is its own, so transcripts and settings stay separate. ovai configuration reports whether the instance has a credential and says plainly that it has not checked it against Anthropic: finding out costs a request, so the first message is where a dead credential shows up. ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN are removed from what an instance runs with, under both options.

ovai configuration: the version, the seats and their models, the port, how it signs in

From a clone

The same installer, run from the repository instead of a downloaded release:

git clone https://github.com/nilcaream/openovai.git
cd openovai
./install.sh --root ~/workspace --source . --user Ana --leader Max \
             --leader-model opus --worker-model sonnet --port 7799 --auth login

--source is where to install from: a clone, or an unpacked release. The instance copies bin/ and lib/ in, so it never reaches back to where it was installed from. A clone with nothing git status --porcelain lists, on any branch, puts the instance on the commit it was installed from: its version is the first 8 characters of that commit's hash. A clone with changes, or a directory that is not a clone, is installed on the lib/VERSION it carries.

Taking a newer version

An instance carries its own copy of the toolkit and does not follow it along on its own. ovai update is how it catches up:

~/workspace/bin/ovai update

It asks GitHub for the latest release, and if that is newer than the version this instance is on it takes it, once it has checked it: the release's signature against the keys in the instance's own lib/RELEASE_KEYS, the package against the SHA256SUMS that signature covers, and the lib/VERSION inside against the tag, all before anything is replaced. A release without them is not taken, and GitHub's own archive of a tag never is. The openovai command checks the same before it unpacks anything. Then the payload — bin/ and lib/ — is replaced whole, and the rest is done by the version it brought in: it runs bin/ovai update --finish from the payload it just put in place, which fetches the new runtime, takes away what the new version retires, seeds once a file of yours that a fresh install of this version would have seeded and this instance has not got, and wires the hook it runs. On the version the instance is already on, ovai update runs that same finish. Taking 0.21.0 is itself done the old way, by the version before it and unchecked; from there on every release is checked. Get the openovai command again with the curl … | sh line above so it pins the key too, since a copy installed earlier never checks. The signature proves a release was made by the repository's release workflow, not that anybody reviewed it. When the new release pins a newer Node.js or Claude Code, those are fetched beside the ones already there, and an instance still on the older release keeps using the older ones. Desks, conversations, knowledge/, customization/, plugins/, openovai.json and the Claude Code home are left alone. The settings are left alone but for two things: the subagent hook is wired into a settings file that lacks it, an older command for it replaced, the shell hook versions before 0.26.0 ran taken out and any hook of your own kept, and commit attribution is turned off in one that says nothing about it; no rule is added. A rule a fresh instance of the new version starts with and yours lacks is instead asked for on the Leader's panel, one permission popup per rule at every start of the server, with what ovai recommends and Ignore; nothing is added without a press, and Ignore is remembered in .claude/ignored-defaults.json. There is no rollback: taking the release again is the fix.

It refuses while the server is running, and while any session of this instance is running — found on the machine and named with the kill that ends it. It refuses to go backwards by name; --downgrade takes an older release anyway, and --from <url or directory> takes one from somewhere other than GitHub: only an http or https address is fetched, and anything else is a directory, named when it does not exist, cannot be read or is not a directory. A directory is not checked for a signature.

--from a clone takes a build of main, named by its commit. The clone must be on main with nothing git status --porcelain lists, or the update refuses in one line that says which. The instance is then on the first 8 characters of that commit's hash, and that is its version wherever ovai shows one: ovai configuration, the page, the server's health. A hash has no order, so a release is always taken onto a build, with no --downgrade; another commit is always taken; the same commit replaces nothing and runs the finish. Going back with --downgrade to a version before 0.20.0 leaves the hook in .claude/settings.json naming lib/hooks/run.sh, which the older version does not have: the downgrade says so, and it is rewired by hand. An instance on 0.19.0 reads a clone as the release its lib/VERSION names, so its first build is taken with the clone's own updater: node <clone>/lib/ovai.mjs --root <instance> update --from <clone>.

ovai update refusing while a session runs, then taking the release

A persona is rendered once, when a seat's process starts, from the templates the instance has at that moment. So an update changes nothing for a process already running; every process started after it is rendered from the new templates. What each release changed is in the release notes, written for whoever runs the workspace that takes it.

The ovai command

Each instance has one, at <instance>/bin/ovai. With no command it prints the help.

commandwhat
ovai startstarts the server in the background and prints a one-time link to the page, good for ten minutes, and one line per Claude Code variable saying what the sessions get of it (values masked); a port already taken names the process that holds it. Typed in a session's own shell, it hands that session on to nothing: the server and its seats start without the session's own variables
ovai urla new one-time link to the running page, for another browser; the link before it no longer opens anything. not running (exit 3) when there is no server
ovai statusnot running (exit 3), or running at <url> (pid, since) — found out by asking the address, not by trusting a file
ovai stopparks the room — every Worker is closed and the Leader writes its desk and stops, by a deadline — then closes the server; not running is not a failure
ovai restartthe two in a row, and prints the new address
ovai configurationwhat this instance is: version, who works here, on which models, the port, how it signs in, whether it has a credential, every desk with what it runs on, and last what the sessions get of the shell's Claude Code variables, as the server last started with them
ovai loginsigns the instance in, once, under --auth login
ovai claudeopens Claude Code on this instance, to reach its own commands — its configuration is the instance's rather than yours. A permission rule changed there applies at each seat's next call; the rest is not live when it quits: a seat reads its configuration when it starts, so ovai restart is what picks it up, and that interrupts whatever the seats are doing. The Leader is told that admin mode ran — within seconds when the server is running, else at its next start — and which of the instance's configuration files changed, by name
ovai plugin <name>writes plugins/<name>.mjs from a scaffold — see plugins
ovai updatetakes the latest release, as above
Next

The page is open and the Leader is in the middle. The Leader and the Workers says what to type and what happens then.