Included with IVYX Studio
IVYX in your terminal
The same gateway your workspace runs on, with no window open.
Every capability call in IVYX passes a policy gate, and until now that gate was only reachable with Studio in front of you. ivyx is the same gate on a command line, so an MCP client, a CI job and a script all meet the rule that lives in your repository.
$ ivyx init # write .punica/policy.yaml and .punica/serve.yaml$ ivyx capability list # what is installed, and what this project serves$ ivyx serve --stdio # speak MCP to any client$ ivyx runs tail # gate decisions as they happen
The first four commands, in the order you would run them. ivyx --help is the reference that ships with the binary.
Set it up once
Two commands stand between a fresh install and an agent calling your workspace from another window.
Getting it
It ships inside IVYX Studio on macOS and Linux, and one command in the palette puts it on your PATH. That command copies the CLI into your home directory rather than linking into the app, so updating Studio does not break it, and the launcher runs the app's own runtime, so the machine does not need a Node of its own.
$Install 'ivyx' command in PATHConnect it to an MCP client
serve prints what it exposes and where the policy came from, and then goes quiet so the stream belongs to the protocol.
$claude mcp add ivyx -- ivyx serve --stdioserve speaks stdio in this release. --print-config prints the connection line for Claude Code, Claude Desktop or Cursor, or the raw JSON if your client wants a config file.
A project says what it exposes in .punica/serve.yaml, so a capability nobody listed is refused rather than served.
Made for CI
policy explain runs the gate and executes nothing, so a rule can be asserted in a pipeline before anything is allowed to happen. It answers with what the gate will do rather than what the catalogue advertises, which is not always the same thing.
$ivyx policy explain mlops.model.promote --args '{"alias":"production"}'--json is on every command, so a refusal is a failing step rather than a line in a log.
Exit codes
- 0
- The call is allowed.
- 2
- Refused, or the input was invalid.
- 1
- Something went wrong.
Nine commands
The first wave, and ivyx --help is the reference that stays current.
Serve
ivyx serve --stdioServe capabilities to an MCP client.
ivyx statusWhether serve is running, what it serves, where policy is.
ivyx initWrite .punica/policy.yaml and .punica/serve.yaml.
Policy
ivyx policy lintSchema, unknown ids, unreachable rules.
ivyx policy explainRun the gate against a call. Nothing executes.
ivyx capability listEvery capability installed, or only the ones served.
Record
ivyx runs showEvery gated call in one run.
ivyx runs tailGate decisions as they happen.
ivyx evidence verifySignature and hashes of an evidence package.
Five things it does not do
It does not carry its own policy
The rule comes from the project, found by walking up from your directory the way git finds a repository. A second policy file would be a second definition of the policy.
It does not decide for a person
A call that needs a person is refused when nobody is there, and the record says it needed a person rather than that it failed. What counts as needing one is the gate’s answer, not the catalogue’s: an approval a capability declares is enforced, and one the catalogue synthesized for display is not.
It does not hold a signing key
There is no account and no cloud, and the CLI signs nothing. Studio’s key is sealed by the OS keychain inside its own process and is not readable from here, which status reports in those words rather than as “no key”. Verifying an evidence package still works, because a signature carries the public half a verifier needs.
It does not run where it cannot enforce
It probes the substrate for the guards it depends on rather than comparing version numbers, and on an older one it stops and names what is missing. It also reads the capability budget back after applying it and refuses to serve if it did not take effect, because a server that believes it serves four capabilities while serving five hundred is worse than one that does not start.
It does not overwrite what you wrote
init writes only the files that are missing, so running it in a project that already has a policy leaves that policy alone. runs tail marks a record as seen only after it has read it, so a file caught mid-write is retried rather than skipped.