Coding agents — letting Claude Code, Codex and others edit your model#
A coding agent such as Claude Code, Codex, Gemini CLI or Cursor can change the model you have open in ICore Blocks. It edits the project's own files, in the project's own folder, and then tells the application to reload the project from its folder, so the change appears in the window you are working in. The project file is plain text, the same recipe statements the application uses everywhere (Recipes and templates — recording, replaying and reusing diagrams), so an agent edits it like any other source file.
The workflow an agent follows#
- The agent checks that the application has this project open (
icore status). - It edits the files in the project folder in place, mainly
<Project>.iproj(the model) andsolver.ini(the simulation settings). - It checks the folder (
icore check): a separate copy of ICore Blocks, with no window, loads the files and simulates them, and answers GREEN or RED. The agent fixes what a RED check names and checks again. - It pulls the reload trigger (
icore reload). The application checks the folder the same way itself, and only when that check is GREEN does it re-read the folder and replace what the window shows. - It reads the answer: the blocks and links now loaded, or, on a RED check, why nothing changed.
The agent never makes a new project or works on a copy: the change is always to the
project you have open. The instructions the agent reads, in AGENTS.md, say so.
You can pull the same trigger yourself: Reload from Project Folder in the project
menu, or reloadProject in the command window.
What keeps your work safe#
- Autosave waits for the reload. When the project file on disk changes outside the application, autosave pauses instead of writing the window's model over the change, and a notification says so. A reload, or a save you make yourself, ends the pause.
- Nothing on screen is lost. Before every reload the model on screen is written to
.icore/before-reload.iprojin the project folder, so an edit you made in the window while an agent was editing the file can still be recovered. - An agent's
icore saverefuses while an edit is waiting to be loaded, because saving would overwrite it with what the window shows. - A file that does not load in full is not loaded at all. The background check refuses it and lists the lines, and the window keeps the model it had.
- Undo history does not survive a reload, as it does not survive opening a project.
Background checks: a model an agent writes cannot crash your application#
A model can crash or hang the program that loads it — a block given a configuration it cannot handle, a feedback loop that never settles. When that program is the application you are working in, the crash takes your unsaved work with it. (The Terminal panel's shell, and an agent running in it, survive it on macOS and Linux: see "If the application crashes" below.)
So an agent's change is tried somewhere else first. Before a reload, a push, an apply, a
console line (eval) or a simulation touches the model you have open, the application
starts a separate copy of itself with no window, gives it a copy of the project, and
has it load the change and simulate the model from its start time to its stop time. Only
when that copy finishes without crashing, without hanging and without an error does the
change reach your window. If the copy crashes, only the copy is gone: your model stays as
it was, and the agent is told exactly what happened.
| The check is RED when | The agent is told |
|---|---|
| the model crashed the copy | the step it was in (opening the project, applying the change, simulating), the signal, and the stack of functions that were running |
| the copy hung | the step it was in when it was stopped (after 120 seconds unless the agent asks for longer) |
| a line of the project file did not apply | every such line and why |
| the simulation failed | the run's errors and its signals |
An agent can also run the check on its own, without changing anything in your window:
icore check in the project folder. Real output,
from a project whose model is a Step into a Gain, run on 2026-10-03 against a build of
commit 63287e25 with this feature applied:
$ icore check
GREEN -- the model loaded, and it simulated without an error in a separate process.
simulated 0 to 10 s, 101 steps; 4 signal(s):
Home/Src:out0 first 0 last 1 min 0 max 1 mean 0.90099
Home/G1:out0 first 0 last 4 min 0 max 4 mean 3.60396
Home/K9:out0 first 1 last 1 min 1 max 1 mean 1
Home/FromTheFolder:out0 first 1 last 1 min 1 max 1 mean 1
and after a line naming a block type that does not exist was added to the file:
$ icore check
RED -- 1 line(s) of the project file did not apply, first: z = block(NoSuchBlockType): unknown block type 'NoSuchBlockType'. Your open model was not changed.
did not apply: z = block(NoSuchBlockType): unknown block type 'NoSuchBlockType'
the copy that was checked: ~/Documents/ICore Blocks/Probe/.icore/check/job-1791048801840-75459-cli
(It exits with 0 for GREEN and 1 for RED.) A copy whose check was RED is kept in the
project's .icore/check/ folder so the agent can look at it; the five most recent are
kept.
- Every check echoes into your Command Window, labelled
agent >, like the agent's other commands, so you see each GREEN and RED as it happens. - Your window stays responsive while a check runs. Another agent command sent meanwhile is answered "busy", and the agent sends it again.
- A check usually takes a few seconds, plus however long the model takes to simulate. A model set to run forever is checked over its first 10 seconds of simulated time.
--no-simulatemakes a check only load the model, for a model that is not meant to run yet.--check-timeout SECONDSgives a long simulation more time.icore checkasks the running application to start the copy, so the copy runs under your licence. With no application running it starts the copy itself: then the copy needs a licence token in theICORE_LICENSE_TOKENenvironment variable, and says so if it has none. It finds the ICore Blocks program by itself (the one that ran last);--app PATHor theICORE_APPenvironment variable names another, and--localskips the running application.- The copy is licensed by the application that starts it, which hands it the licence it is already using. The copy removes it from its environment before it runs anything of the model's, so code a model runs never sees it.
The check protects your application from the agent's model. If the application crashes for any other reason, the Terminal panel's shell survives it on macOS and Linux; see the next section.
If the application crashes: the Terminal panel's shell carries on#
On macOS and Linux the Terminal panel's shell does not run inside ICore Blocks. It runs in a small helper process of its own, so when the application crashes — or is killed — the shell, and an agent running in it, keep running. The helper keeps the last megabyte of what the shell printed.
The next time you open the Terminal panel, it takes that shell over: what the shell
printed while no window was attached is shown again, a line says
[reattached: this shell outlived the app that started it], and you carry on in the
same shell, with the same directory, variables and running programs. An agent there can
reach the application you just started with icore as before; it finds the new
application by itself.
Closing the Terminal panel, or quitting ICore Blocks normally, still ends the shell, as it always did. Only a crash leaves it running.
Shells left behind by a crash that you do not want to take over can be listed and ended in the command window:
| Command | What it does |
|---|---|
terminalHosts | Lists the shells kept alive this way, and which are left behind (their application is gone) |
terminalHosts end left-behind | Ends every shell no running application holds |
terminalHosts end <host pid> | Ends one |
On Windows the shell is still part of the application and ends with it; there, start a long agent session in a terminal outside the application if a crash must not stop it.
Checking the result: simulate#
An agent can run the model without anyone pressing Run. icore simulate (or simulate in
the command window) runs it from its start time to its stop time with the project's solver
settings — when an agent asks, in the separate copy described above, never in your
window — and prints, for every sink block (Scope, Display, ...), the signal's first, last,
lowest, highest and mean value, flagging any that became NaN or infinite. It also lists
every error or warning the run logged, and fails with the reason when the model cannot run:
$ icore simulate
simulated 0 to 10 s, 101 steps; 1 signal(s):
Home/Scope:in0 first 0 last 0.999879 min 0 max 0.999879 mean 0.798693
icore simulate Home/Plant, Home/Controller watches those blocks' outputs instead, and
--csv results.csv also writes every sample to a file in the project folder.
icore eval modelConfig shows the solver settings the run uses.
Exporting code: Deploy to Hardware targets from a script#
The Deploy to Hardware targets can be created, configured and fired from the command window or a script, so an agent can export the model's code itself. They are the same targets the Deploy to Hardware panel shows, and they are saved with the project.
t = target(C++)
t.setConfig(Source, Home/Controller)
t.setConfig(Folder, code/controller_cpp)
t.setConfig(Verification, None)
t.fire()
target(Language)creates one: Python, MATLAB, Java, Rust, C++, C, System Verilog, Verilog, VHDL or PLC - ST. It starts out exporting Home intocode/<name>in the project folder.t.setConfig(Key, Value)setsName,Language,Source,Folder,Verification,Tolerance,Pulse Width,Amplitude Min,Amplitude Max,Seed,Compiler ScanorCompiler Path.t.listConfigshows them all with what each accepts.t.fire()exports now and lists the files written. It never opens a dialog: if export verification fails, the export stops and the reason is printed.getTarget(name)binds an existing target,targetslists them, andt.deleteremoves one. From outside the application,icore targetsandicore fire <name>do the same.
Export needs a fixed-step solver, as it does from the panel.
Seeing what an agent did#
Every command an agent runs appears in your Command Window as it happens, labelled
agent > in place of the prompt, with its output underneath, so you can follow along
and see exactly what was done to your model.
What you get in a new project#
Every new project folder, whether empty or made from a template, gets four files that tell an agent how to work in it:
| File | Read by | What it holds |
|---|---|---|
AGENTS.md | Codex, Cursor, GitHub Copilot, Amp, Jules and most others | The instructions: edit this folder in place and reload, never a new project; the .iproj format; how to ask the application for help |
CLAUDE.md | Claude Code | Imports AGENTS.md (@AGENTS.md), plus a note on the MCP tools |
GEMINI.md | Gemini CLI | Imports AGENTS.md, plus how to add the MCP tools |
.mcp.json | Claude Code | Registers the icore MCP server, so Claude Code gets icore_* tools |
These files are yours once they are written. ICore Blocks never overwrites a file you changed. To add them to a project made before this feature, or to turn them off for new projects, type one of these in the command window (The command window — the command engine for a user):
| Command | What it does |
|---|---|
agentGuide | Shows which of the four files the open project has, and whether new projects get them |
agentGuide write | Adds whichever of the four files are missing from the open project |
agentGuide refresh | Adds missing files and updates the generated ones to this version's text; a file whose first line you deleted, or that you wrote yourself, is left alone |
agentGuide off / agentGuide on | Stops, or restarts, writing them into new projects (on by default) |
Starting an agent#
The simplest way is the application's own Terminal panel. Its shell starts in the
project folder and already knows where the application is, so you type claude or
codex there and the agent can start working. The shell is given:
| Variable | Value |
|---|---|
PATH | Starts with the folder that holds the icore client, so icore works as a command |
ICORE_AGENT_SOCKET | Where the running application listens |
ICORE_PROJECT_DIR | The open project's folder |
ICORE_AGENT_CLI | The full path of the icore client |
An agent started in any other terminal works too. The client finds the running application on its own, and if more than one copy is running it picks the one whose project folder you are in.
The icore client#
The client is a single Python 3 file, icore.py, that the application writes into its
own data folder every time it starts, so it always matches the version you are running.
On macOS that is ~/Library/Application Support/ICore Blocks/agent/icore.py; on Windows it
is %LOCALAPPDATA%\ICore Blocks\agent\icore.py. The generated AGENTS.md names the exact
path for your machine, and the command that runs Python on it: python3 on macOS and
Linux, and on Windows whichever of py, python and python3 your PATH has. On Windows
the application also writes icore.cmd beside the client, which is what icore runs in
the Terminal panel's Command Prompt or PowerShell.
| Command | What it does |
|---|---|
icore status | Which application is running, which project it has open, whether an edit on disk is waiting to be loaded, and whether changes are checked first |
icore check [BLOCK, ...] | Loads and simulates the project folder in a separate copy of ICore Blocks with no window, and answers GREEN or RED. Changes nothing in the open application; works with none running when ICORE_LICENSE_TOKEN is set |
icore reload [--file] | Checks the project folder, then, if the check is GREEN, re-reads it into the open project. --file pulls the trigger through the project folder instead of the connection |
icore pull [LEVEL] [-o FILE] | The live diagram as recipe text. Without a level it is Home, which includes every subsystem, so it is the whole model |
icore push FILE [--level LEVEL] | Replaces the whole model with FILE, as one Undo step. With --level Home/Controller it replaces only that subsystem's contents and keeps its ports, so the links the level above has to it stay |
icore apply FILE [--level LEVEL] | Adds FILE's blocks and links to a level without clearing it, as one Undo step |
icore eval CODE | Runs console lines, from arguments, -f FILE, or standard input |
icore run NAME | Runs a saved script from the project's scripts/ folder |
icore simulate [--csv F] [BLOCK, ...] | Runs the model and summarises every sink block's signal (or the named blocks') |
icore targets | Lists the Deploy to Hardware targets |
icore fire NAME | Exports a target's code now |
icore save [--force] | Saves the project. Refuses while an edit on disk is waiting to be loaded, unless forced |
icore blocks [TEXT] | Lists the block types whose library path contains TEXT |
icore describe TYPE | A block's description, including its ports and parameters |
icore help [NAME] | The console's own help for a command or a recipe statement |
It exits with 0 on success, 1 when the application refused, a check was RED or a
line failed (the message says which), and 2 when no running application could be
reached. reload, push, apply and check take --no-simulate, and those and eval
and simulate take --check-timeout SECONDS, both for the background check.
A real session, run on 2026-09-25 against a build of commit 8ad88242 with this feature
applied. The project was made from the First-Order Lag template, and the gain was then
edited in the pulled file:
$ icore status
ICore Blocks 1.0.3 (pid 94647, protocol 1)
project: LagDemo
folder: ~/Documents/ICore Blocks/LagDemo
$ icore pull -o model.icore
wrote model.icore
$ icore push model.icore
model replaced (Undo reverts it): 4 block(s), 3 link(s)
$ icore eval 'getBlock(Home/Kp).getConfig(Gain Value)'
_ = block 'Kp' in ICore Blocks/Home
Gain Value = 2.5
$ icore eval 'getBlock(Home/Gain1)'
line 1: getBlock(Home/Gain1)
getBlock(): no block 'Gain1' in ICore Blocks/Home -- it holds: Kp, Out, Step, Transfer Function
The last command exits with status 1, and its message lists what the level holds so the agent can correct itself.
To edit a block that already exists, bind a handle to it by its path with getBlock:
icore eval 'getBlock(Home/Controller/Kp).setConfig(Gain Value, 2.5)'
MCP tools#
icore mcp runs the same client as an MCP server, the standard way agents take tools. It
offers icore_check, icore_reload, icore_simulate, icore_status, icore_pull, icore_push,
icore_apply, icore_eval, icore_blocks, icore_describe, icore_help and icore_save. icore_pull can write
straight to a file and icore_push can read from one, so an agent edits a real file
between the two.
- Claude Code reads
.mcp.jsonin the project folder and asks you once to approve theicoreserver. - Codex keeps its MCP servers in its own settings, so add it once:
codex mcp add icore -- python3 "<path to icore.py>" mcp(on Windows, the commandAGENTS.mdnames instead ofpython3), and approve the tool calls when Codex asks. - Gemini CLI: add the same command under
mcpServersin~/.gemini/settings.json.
If the agent cannot reach the application#
An agent that runs its shell commands in a sandbox may not be allowed to open the
application's local socket; Codex's default sandbox is one. The reload still works:
icore reload then pulls the trigger through the project folder instead. It creates
.icore/reload, the application (which watches the open project's folder for that file)
checks and reloads, and the answer appears in .icore/reload-result.json. icore check
can do without the connection too, by starting its own copy of ICore Blocks, when
ICORE_LICENSE_TOKEN is set. The other icore commands need the connection. For those, use the MCP tools, which Codex runs outside its
sandbox, or start Codex with local connections allowed:
codex -c sandbox_workspace_write.network_access=true
Claude Code runs icore without a sandbox unless you have turned one on.
What an agent can and cannot do#
- Edits reach the window by a reload. An agent edits the project's files and then reloads; until then the window shows the model as it was.
- A push replaces the whole model. Blocks, links, positions, parameters and solver settings come from the file. Scope traces and simulation results are cleared.
- An apply only adds. Use it to put new blocks into one subsystem without touching the rest.
- Edits wait for a running script. While a script in the ICore Script IDE is paused or running, and while code export is running, the application refuses edits and says why. Try again when it has finished.
- Scripts are ordinary files. An agent can edit
scripts/*.icoredirectly. The Script IDE reloads a changed script on its own, andicore run NAMEruns it.
Turning it off#
The switches are in Settings ▸ Project ▸ Coding Agents:
- Agent Instructions in New Projects decides whether a new project gets the four files. Existing projects are never changed by it.
- Let Coding Agents Reach This App closes or opens the connection at once. Off, the application stops listening and stops watching the project folder for the reload trigger, and it stays off in later sessions until you turn it back on.
- Check Agent Changes in the Background First is the check described above. It is on by default. Off, an agent's change is applied to your model directly, as typing it in the command window would be, and a model that crashes takes the application down.
agentGuide on|off, agentBridge on|off and agentBridge check on|off in the command
window do the same.
Reload from Project Folder in the project menu works either way. agentBridge on its own shows
whether it is on, where it listens, and where the client is. The connection point is a
local socket that only your own user account can open.
Without a window#
ICoreBlocks --console "agentServe 0 --project <folder>" opens a project with no window
and serves the same commands until a client asks it to stop, which is useful on a build
machine. A number instead of 0 stops it after that many seconds. The background check is
the console command agentCheck, which the application and icore check run; it is not
meant to be typed.