Part of IVYX Studio
Every model you run, behind one switch
Local weights, a live Ollama daemon and a remote provider, in one list.
An LLM in IVYX is not an identity, it is an instruction set. A class fixes the role, the prompt, the response format, the token budget and the risk level, and the active core is the hardware it runs on. That split is what lets a small local model answer a routine class while a larger remote one stands behind it, and what lets an agent name the contract it needs instead of the model it hopes for.
- qwen3:4bollamarunning · 127.0.0.1:11434Active
- mistral-7b-instruct-q4_k_m.gguflocalweights on disk
- DeepSeek V4.1 FlashremoteOpenRouter · 1M context
The AI Cores pane: one list, whatever the core is.
Three kinds of core, one list
The list is built every time the panel renders, by merging what is actually on the machine rather than what was once configured.
Weights on disk
A model file this app was pointed at and runs itself, through whichever installed runtime handles that format. An unsupported format is refused with an error naming the runtimes that are registered.
A running Ollama daemon
Its models are listed live by the daemon. IVYX deliberately records nothing about them: a copy kept here would go stale the moment you run ollama rm, and a list that disagrees with the machine is worse than no list.
Somebody else's endpoint
A remote model, carrying the provider it came from and its context window, so the row reads as a fact rather than as a URL you have to recognise.
It also picks up a local server that is already up, including one a previous session left running, so the panel never offers to start something that is already answering.
The remote providers it already knows
Pick one and you get its endpoint, its authentication style and its model list without typing a URL. The catalogue is served by the IVYX registry rather than frozen into the app, so it can gain a provider without you updating anything.
- OpenRouteropenai wire
- OpenAIopenai wire
- Anthropic (Claude)anthropic wire
- Google (Gemini)openai wire
- DeepSeekopenai wire
- Mistral AIopenai wire
- xAI (Grok)openai wire
This is a shortcut, not a boundary. Six of the seven speak the OpenAI wire format, and a remote core is ultimately an endpoint and a token, so a provider that is not listed, a gateway of your own or a model running on another machine in your network all work the same way. When the registry cannot be reached the app falls back to a copy it ships with, and says that the copy is stale rather than presenting it as current.
One switch decides where work runs
Set Active is the only routing control in the product. There is no per-extension model setting and no provider field on a form somewhere else, so there is exactly one answer to the question of where your work runs.
llms.activeCore local:qwen3:4b
llm.local.endpoint http://127.0.0.1:11434
llm.local.model qwen3:4b
llm.remote.vendor openrouterWhat activating a core writes.
A backstop, not a swap
Activate a local core with a remote one configured and the chain resolves to both, in that order: the local model answers and the remote stands behind it for the attempts it cannot serve. Activate a remote core and it answers alone.
Right model, right endpoint
Each core carries its own endpoint, which matters more than it sounds. With an Ollama daemon and a llama.cpp server both up, a request carrying only a model name reached the server that ignores model names: right shape, wrong model, no error anywhere. Addressing cores individually is the fix.
An LLM is not an identity, it is an instruction set
An instruction class is a file in your workspace, versioned with the project rather than pasted into a feature. It is the contract a model is held to, and it is what an agent names when it needs work done.
- role, systemPrompt
- What this class is for, and the instructions it always carries.
- responseFormat, outputSchema
- text or json_object, with a schema the answer is checked against rather than hoped about.
- temperature, maxTokens
- The budget for one invocation. On a local server maxTokens caps thinking and answer together, so it is a contract term, not a ceiling you raise when results disappoint.
- reasoning
- Whether a thinking model may spend that budget on reasoning. Absent means it may not, which is what most classes want: a formatting job that declares 400 tokens against a reasoning core otherwise returns nothing at all.
- riskLevel
- low, medium or high. Declare it: leaving it out asks the kernel to work it out, which costs an extra model round trip on every single invocation.
- providerChain, fallbackPolicy
- Which cores answer this class, in order, and what kind of failure advances to the next one. Absent means the active core decides.
id: source-control.commit-message
role: commit-message-writer
riskLevel: low
temperature: 0.2
maxTokens: 3000
responseFormat: text
systemPrompt: |
You write the commit message for a set of staged
changes. You are given the diffstat, as much of the
patch as fits, and the subject lines of the
repository's recent commits.
...A shipped class, trimmed to its contract.
Classes are declared in an extension's own manifest, so installing an extension brings its classes with it and removing it takes them away again. Your own live beside them in the workspace.
Which class answers, and what happens when none does
An editor agent does not pick a model. It names a class, or names what it is building and lets the registry resolve the class, which is resolved in one fixed order.
- 01
The class it named
A turn can carry its instruction class outright, and that wins over everything below.
- 02
The product it is building for
An agent, a node or an MCP server resolves to that product's own generator class.
- 03
The artifact it is producing
A workflow resolves to the planner.
- 04
The default planner
What a turn gets when it asked for nothing in particular.
A missing class blocks the turn
A class that is not registered, or whose extension is not active, stops the turn with a reason that names what is missing. Nothing falls through to another model, because a generator answered under the wrong contract produces something that looks right and is not. It is the same instinct as the policy gate: refuse rather than guess.
The class is where you tune
One of the shipped classes records its own measurement in the file. At a 2,500 token budget it produced zero parseable answers in fifteen invocations on a small local model, because every one spent the whole budget on reasoning and came back empty. Raising it to 6,000 changed nothing but the bill. The answer itself is about 700 tokens, so the budget was never the lever. The model was.
Author it, test it, compare cores
Two panels, both reached from the hub.
Instruction Class Editor
Edit the class as the file it is, test it against a sample prompt, and get help writing the prompt. Registering a class declares file.write, because what it produces is a file in your workspace. It is also where one class is run across several cores at once, which is the next section.
Add AI Core
Search the Ollama library with real download sizes and a verdict on whether this machine can run the model, browse HuggingFace, or pick a file from disk and be told at pick time whether any installed runtime can run that format, rather than after the download.
One class, every core, the same prompt
Comparison is where a core stops being a preference and becomes a measurement. Choose a class, check the cores you want to hear from, write one prompt, and every checked core answers it through that class, several local models and a remote endpoint in the same run.
The whole class rides along, not just the prompt
Each core is sent the class's system prompt, temperature, token budget, reasoning mode and response format, rather than a bare question. That is what makes the result a comparison: the contract is held fixed and only the model changes. Each run registers a temporary clone of the class pinned to that one core, sends it through the gateway like any other call, and unregisters it whether the call succeeded or not.
What a row reports
- answeredBy
- Which model the endpoint said answered, read off the response rather than assumed from what was asked. A row that disagrees with the card you checked is exactly the failure this is here to catch.
- latencyMs
- How long it took, preferring the provider's own measurement over wall-clock time.
- text, error
- The answer, or the reason there was not one. An empty response is recorded as a failure rather than left as a blank row.
- scores
- A verdict per installed eval engine, for the classes one applies to.
It says which kind of nothing it got
Scoring is not built in. It needs an eval engine installed, and a class that no scorer applies to has nothing to report. Those two are distinguished from each other, and from a capability catalogue that could not be read at all, instead of collapsing into one empty column you would have to guess about.
And what the machine is doing while it runs
The results panel reads CPU count, CPU load and the RAM actually available, meaning free plus reclaimable rather than the bare free figure that misleads on unified-memory machines. Local cores carry their parameter size, quantization and size on disk, straight from the daemon. There is no GPU or VRAM readout, because the host exposes none, and no card claims to know which model is loaded in memory right now, because nothing asks it.
Every privileged step declares itself
Across this family the operations that matter are declared capabilities rather than private functions. Each one names the actions it performs and the risk it carries, so a rule in your policy file selects on them the way it selects on anything else.
- llms.instruction-classes.invoke
- Run a class through the kernel. Declares model.invoke at medium risk.
- llms.instruction-classes.test
- Run a class against a sample prompt, or through its linked eval suite. Declares model.invoke at medium risk.
- llms.ollama.server.start
- Start the daemon. Declares process.exec and net.request at high risk.
- llms.ollama.model.remove
- Delete a model from the daemon's store. Declares process.exec at high risk.
- llms-services.save-config
- Store a remote endpoint and its token. Declares secret.write at medium risk.
- llms-instruction-class-service.register-class
- Write an instruction class into the workspace. Declares file.write at medium risk.
Two kinds of approval
Starting a model server, installing the Ollama daemon, pulling a model and removing one all declare approval: step, so they stop for a person whatever your policy says. The class level operations declare approval: none, which leaves that decision to your rule. Either way the gate refuses a stopped call rather than holding it open, which is right for an agent, whose loop waits and resumes, and wrong for a button, whose call is long gone by the time the dialog is answered. So the panel does the waiting itself and sends the call once more after you grant it.
Where this stops being true
Listing the cores and choosing the active one are plain commands, not capabilities, so the switch itself is not what your policy gates. What the switch decides, which core answers an invocation, is.
The token is not in your repository
Saving a remote endpoint declares secret.write, and the value goes to the host Secret Manager rather than to .punica/settings.json, which is allowlisted back into git.
The family
One hub, and parts that each declare what they are allowed to do.
LLM Capabilities
The hub, and the only place the core list and the active core live. Five capabilities: opening the panel, tracking the classes an extension contributes, deleting one, testing one and invoking one. The last two carry model.invoke.
Instruction Class Editor
Authoring and comparison, and comparison is a declared capability of its own. Registering a class declares file.write, saving an endpoint's credentials declares secret.write, and testing a connection declares model.invoke and net.request.
LLM Services
Point Studio at a remote endpoint and hold its token. Saving the configuration declares secret.write, and testing it declares secret.write, model.invoke and net.request, so a rule can stop a token being written or an endpoint being reached.
AI Core (Service)
Owns the remote model records and the provider catalogue it fetches from the IVYX registry. Adding or updating a remote model declares secret.write, because a model record arrives with a token attached.
Ollama Runtime
Six capabilities over the daemon and its models. Starting it, installing it and removing a model are all high risk, all declare process.exec, and all ask for approval by declaration.
GGUF Runtime
Runs llama.cpp's llama-server against a GGUF file. Three capabilities, and starting the server is high risk with process.exec, the same shape every runtime here uses.
ONNX Runtime
An OpenAI compatible onnxruntime server covering chat, embeddings, rerank, speech and vision. The same three capabilities as the GGUF runtime, and you supply the server binary.
Ollama Library
The add a core panel: browse the Ollama library, browse HuggingFace, or add a model from disk. It declares no capabilities at all, only those three commands, because it finds models rather than running them.
LLM Capabilities Viewer
Read a class's whole contract as a card and test it in one shot. One capability, which is opening itself.
The three runtimes have no panel because they are not a place you go. Each registers itself as an engine and declares only its own server lifecycle, which is what leaves the hub free to be the one place the list and the choice live.
Local cores need the desktop app
Running weights on your own machine is a desktop feature, which for IVYX means macOS and Linux. A remote core needs no runtime installed at all.
In CI it is a file
Studio and the ivyx CLI are two hosts for the same seam, and each binds a model its own way. Do not expect them to share a setting: in Studio the binding is the active core you picked, and headless it is a file committed with the project.
- IVYX Studio
- The active core, set in the sidebar.
- ivyx CLI
- A model name committed to .punica/model.yaml.
$ivyx model use qwen3:4bBinding a local core headlessly. Nothing is bound until you say so.
A project file rather than a flag, because the capabilities that invoke a model are reached from a tool call, a command and a pipeline stage, and none of them takes a model argument. Nothing is bound by default and nothing is guessed.