AI Agent Workspace Sync
CLI agents (Elyra, Claude Code, Codex, …) run in the agent panel, but on their own they only see files on disk — not what you're doing in the editor. The workspace sync closes that gap with a small local socket the agent (or any tool) can talk to.
When the editor starts it opens a per-process Unix socket and exports its path
to spawned agents as $E_EDITOR_SOCK. The protocol is one JSON object per
line, with one JSON response per line.
Reading editor state
printf '{"method":"context"}\n' | nc -U "$E_EDITOR_SOCK"
Returns the current file, cursor (1-based line/col), the selected text, the
language, the dirty flag, the list of open files, the workspace root, and all
diagnostics:
{
"ok": true,
"root": "/path/to/project",
"file": "/path/to/project/app/Models/User.php",
"line": 42, "col": 9,
"selection": "User::query()",
"language": "Php",
"dirty": true,
"open_files": ["…"],
"diagnostics": [
{"file": "…", "line": 12, "col": 5, "severity": "error", "message": "…"}
]
}
{"method":"diagnostics"} returns just the problems list.
Driving the editor
| Request | Effect |
|---|---|
{"method":"open","path":"…","line":45,"col":1} |
Open the file and jump to the position |
{"method":"focus","target":"terminal|editor|agent"} |
Focus a panel |
{"method":"notify","message":"…"} |
Post a system notification |
{"method":"review_summary","text":"…"} |
Hand the editor a written summary of this session's changes. It becomes the pull-request description when you ship from session review. |
Example — let the agent jump you to a definition it found:
printf '{"method":"open","path":"app/Models/User.php","line":58}\n' \
| nc -U "$E_EDITOR_SOCK"
Language-server co-op
The agent can reuse the editor's already-running language server — no re-indexing, exact type info:
| Request | Returns |
|---|---|
{"method":"lsp_definition","path":"…","line":12,"col":5} |
{uri, line, col} |
{"method":"lsp_references","path":"…","line":12,"col":5} |
{references:[…]} |
{"method":"lsp_hover","path":"…","line":12,"col":5} |
{hover} |
{"method":"lsp_symbols","query":"User"} |
workspace symbols with locations |
(The file should be open in the editor so its server is running.)
Database schema
printf '{"method":"db_schema"}\n' | nc -U "$E_EDITOR_SOCK"
Returns the tables and columns of a connected database (optionally
"connection":"<name>"), using the editor's existing, credential-safe
connection — the agent never sees the password.
The agent can also propose a query:
printf '{"method":"db_query","sql":"SELECT count(*) FROM users"}\n' | nc -U "$E_EDITOR_SOCK"
The editor shows a consent dialog with the SQL and the target connection. If you
Allow, the query runs and the response contains {columns, rows, rows_affected, elapsed_ms}; if you Deny, it returns an error. The agent
never gets direct database access.
Running commands
printf '{"method":"run","command":"php artisan test"}\n' | nc -U "$E_EDITOR_SOCK"
Runs a command in the workspace (or "cwd":"…") through the login shell and
returns {code, stdout, stderr}. This is the basis for an autonomous
test-fix-rerun loop.
Proposing edits (reviewed)
Instead of writing files blindly, an agent can propose a new version and let you review it hunk-by-hunk:
printf '{"method":"propose_edit","path":"app/Models/User.php","content":"<full new file>"}\n' \
| nc -U "$E_EDITOR_SOCK"
The editor diffs it against the current file and opens a review overlay where you Accept/Reject each hunk, then Apply (or Cancel). The reply reports how many hunks were applied. Accepted changes go into the open buffer (so they're undoable) or are written to disk.
Ghost marker & audit timeline
{"method":"mark","path":"…","line":42}(andopen/lsp_*) show where the agent is looking as a 🤖 marker in the status bar — click it to jump there.- Everything the agent does over the socket is recorded in the Agent Timeline (⌘⌥A): time, method and a short summary — so you can always answer "what did the agent just do?".
Who can talk to the socket
The socket path is the capability. Anything that can reach it can drive the
editor — including run, which executes shell commands. Three things guard it:
- The name carries 96 bits of randomness (
agent-<pid>-<random>.sock), so it can't be found by guessing. ~/.config/eis0700and the socket itself0600, so no other account on the machine can list or open it.- The path is handed out only through
$E_EDITOR_SOCK, which processes inherit from the editor that spawned them.
So an agent you started from e can use the socket, and a stray process that
merely knows ~/.config/e exists cannot.
What this does not protect against is code already running as you with
access to that environment variable — a malicious postinstall script in your own
project, say. Treat $E_EDITOR_SOCK the way you'd treat a shell: anything
holding it can run commands as you.
run and tinker deliberately execute without a per-call prompt; the
autonomous test-fix-rerun loop is built on that, and a dialog per command would
break it. db_query is the exception — it asks every time, because the risk
there is your data rather than your machine. Everything the agent does is
recorded in the Agent Timeline (⌘⌥A).
Notes
- The socket is local to your machine and per editor process; nothing is exposed over the network.
- Available on macOS/Linux (Unix sockets). The path lives under
~/.config/e/. - Sockets left behind by editors that are no longer running are cleaned up at startup.