-
Notifications
You must be signed in to change notification settings - Fork 1
Agent Integration
The emulator exposes a control surface for AI agents over the Model Context Protocol (MCP) and the AG-UI event protocol. An agent such as Claude Code can insert disks, type BASIC, assemble 6502, read the screen, inspect memory and reconfigure slots -- everything a person can do through the UI.
Two coordinated pieces:
| Piece | Where | Role |
|---|---|---|
| MCP server |
../appleii-agent/ (separate Node package) |
Provides MCP tools over stdio, plus an HTTP/HTTPS server on port 3033 implementing AG-UI over SSE |
| Agent manager | src/js/agent/agent-manager.js |
Browser-side AG-UI client: connects, receives tool calls over SSE, executes them, posts results back |
The browser is the client. The server never reaches into the page; it publishes tool calls that a connected emulator picks up.
Several browser tabs can connect at once. Each is assigned a name from a pool, stored in sessionStorage so it survives a server restart within the same tab.
Tools take an optional emulator parameter:
| Value | Behaviour |
|---|---|
"Name" |
Target that emulator |
"all" |
Broadcast to every connected emulator, where the tool supports it |
| omitted, one connected | Use it |
| omitted, several connected | Use the one marked default |
| omitted, several, no default | The agent is asked to choose |
The first tab to connect becomes the default; set_default_emulator changes it and list_connections shows the current state. Double-clicking the emulator name on the sparkle button renames it inline (Unicode letters, hyphens and underscores -- no digits or spaces).
.mcp.json at the repo root configures the client:
-
Recommended:
bunx -y @retrotech71/appleii-agent -
Development:
node /path/to/appleii-agent/src/index.js
Environment variables: PORT (default 3033), HTTPS=true for TLS, and APPLEII_AGENT_SANDBOX pointing at a sandbox config.
Every file operation is gated by a sandbox config. Without one the agent starts but all file access is blocked -- that is the intended default, not a misconfiguration.
~/.appleii/sandbox.config:
# Comments start with #
[demos]@~/AppleII/demos
[work]@/Users/me/projects/apple
Keys are alphanumeric with underscores and hyphens; paths are absolute or ~-relative. Wire it up with:
"env": { "APPLEII_AGENT_SANDBOX": "/path/to/sandbox.config" }Tool calls then use [key]/relative/path/file. Path traversal (../) and paths outside every configured directory are rejected, and save tools default to overwrite: false. reload_sandbox picks up edits without restarting the client.
Server and connection
| Tool | Description |
|---|---|
server_control |
Start, stop or restart the agent server |
set_https |
Toggle HTTPS mode |
set_debug |
Set debug logging level |
get_state |
Current server and emulator state |
get_version |
Agent version |
reload_sandbox |
Reload sandbox.config
|
disconnect_clients |
Disconnect all SSE clients |
shutdown_remote_server |
Shut down another instance on the same port |
list_connections |
List connected emulators |
set_default_emulator |
Choose the default target |
Files into the emulator
| Tool | Description |
|---|---|
load_disk_image |
Read a .dsk/.do/.po/.nib/.woz from the sandbox as base64 |
load_smartport_image |
Read a .hdv/.po/.2mg as base64 |
load_file |
Read any file as base64 or text |
Files out of the emulator
| Tool | Description |
|---|---|
get_screenshot |
Capture the screen as MCP image content the model can actually see |
save_to |
Save from an emulator source to a sandbox path |
save_to sources: basic-editor, asm-editor, basic-memory, file-explorer, memory-range, screen, raw.
Generic
emma_command delegates to any frontend tool over AG-UI. Window management (showWindow, hideWindow, focusWindow) is a frontend tool, so it goes through emma_command rather than being an MCP tool of its own.
Registered in src/js/agent/agent-tools.js, grouped by area:
| Group | File | Examples |
|---|---|---|
| Emulator control | main-tools.js |
emulatorPower, emulatorCtrlReset, emulatorReboot, directLoadBinaryAt, directSaveBinaryRangeTo, captureScreenshot, captureScreenText
|
| BASIC | basic-program-tools.js |
directReadBasic, directWriteBasic, directRunBasic, basicProgramRun, basicProgramRenumber, basicProgramFormat, basicProgramLoadFile
|
| Assembler | assembler-tools.js |
asmAssemble, asmWrite, asmGet/asmSet, asmGetStatus, asmLoadFile, directExecuteAssemblyAt
|
| Disks | disk-tools.js |
driveInsertDisc, driveRecentsList, driveInsertRecent, drivesClearRecent
|
| SmartPort | smartport-tools.js |
smartportInsertImage, smartportRecentsList, smartportInsertRecent
|
| File explorer | file-explorer-tools.js |
listDiskFiles, getDiskFileContent
|
| Windows | window-tools.js |
showWindow, hideWindow, focusWindow
|
| Slots | slot-tools.js |
slotsListAll, slotsInstallCard, slotsRemoveCard, slotsMoveCard
|
basicProgramLoadFile and asmLoadFile are worth knowing about: they load a sandbox file into the editor server-side, so a long source file never passes through the model's context. Paired with save_to, an agent can round-trip a program it never had to read.
- The agent calls an MCP tool (say
load_disk_image). The server reads the file and returns base64. - The agent calls a frontend tool (
driveInsertDisc) viaemma_command; AG-UI delivers the call to the browser over SSE. - The frontend decodes the data and drives the disk manager and WASM exports.
- The result is posted back to
/tool-result.
Frontend tools reach the emulator through WasmProxy, so they are subject to the same rules as any other main-thread code -- see Worker-Architecture. Changes to the WASM exports these tools depend on (_readMemory, _setSlotCard, _getProDOSCatalog and friends) need the tools updated to match.
- Architecture-Overview -- where the agent layer sits
- Worker-Architecture -- how tools reach the emulator
- Debugger -- the same capabilities from the UI