Python · json-ipc · incomplete · MIT
The agent is a client.This is the server.
CodeLoom Engine is a Python JSON-IPC core for a coding-agent workplace. It owns the workspace. A TUI, an IDE pane, or a REPL connects to .engine/engine.sock and speaks newline-delimited commands and events. Clients never import the loop.
Shipping today: SQLite sessions, OpenRouter, sandboxed reads, git status, drop-in @tool files, and a cataloged command/event wire. Designed, not built: orchestrator, named subagents, context folding. Still early.
engine.codeloom.iresharma.com · github.com/iresharma/codeloom.engine · Iresh Sharma
▍ waiting on .engine/engine.sock
01 bind
python app.py . listens on {workspace}/.engine/engine.sock. One process owns the workspace. Clients never import the loop.
02 command
NDJSON in: StartSession, OpenFile, SubmitUserMessage, RequestGit. Typed dataclasses, language-agnostic. A TUI, a web UI, or dummy_client.py.
03 event
NDJSON out: SnapshotReady, FileContent, ChatMessageAdded, GitStateUpdated. Multiple clients subscribe to the same fan-out.
Protocol
Commands in. Events out.
Commands live in protocol/commands.py, events in protocol/events.py. @command / @event fill the registries; @handles lands on EngineSession. A TUI in any language has to know the JSON type names, so they stay in those two files. The client renders. It does not walk the tree.
StartSession
Bind a workspace. Pass session_id to resume from SQLite at .engine/session.db.
SubmitUserMessage
One user turn. AgentLoop may run @tool calls and call the model again, capped at 8 turns.
RequestSnapshot
Reconnect payload: messages, open files, rebuilt file tree, live git. Tree and git are not stored.
OpenFile / CloseFile
Drive the file panel. Engine reads UTF-8 inside the workspace; the client never walks the repo.
RequestGit
Branch, dirty, staged / unstaged / untracked, diffs. Rebuilt on request.
ListSessions
Catalog of persisted sessions. Shutdown writes; the Unix server stays up.
Extend
Two surfaces. Do not mix them.
Tools are for the model — drop a file, the loop discovers it. Commands and events are the client wire contract. If the agent should read git, add a tool. If the UI should show git without asking the LLM, add a command and an event.
tools/echo.py
Drop a module under tools/. Decorate the function. Restart the session — the engine imports the package tree and registers anything with @tool. No catalog list to edit. AgentLoop sends those schemas on each model call and, if the model returns tool_calls, runs them and calls again (capped at 8 turns).
If the agent should read git, add a tool.
from tools.base import ToolContext, tool
@tool(description="Echo text back.")
def echo(ctx: ToolContext, text: str) -> str:
return text
# name = function name
# schema from type hints, or parameters=
# ctx.workspace is the project rootmodel --tool calls--> tools/*.py
client --JSON cmd----> protocol/commands.py --> @handles
engine --JSON event--> protocol/events.py
Designed · not implemented
An orchestrator that does not act. Workers that fold.
The bet the protocol is built for: a main agent that never writes the patch. It spawns named subagents — ask, linter, editor, reviewer — then a ConversationCompressor folds each trail from 30+ messages (thinking, tool calls, the mess) into 1–5. AgentLoop today already runs @tool calls in a loop (capped at 8 turns). The orch and the compressor are still ahead.
0+
Raw worker trail
the compressor target
0
After a fold
typically 1–5 messages
0
Work the orch should do
spawn, read, write_context
Worker trail · 34 messages
live- thinkmaybe the timeout is in the client retry loop…
- toolgrep timeout auth.spec.ts session.ts
- resultsession.ts:88 timeout: 5_000
- think5s is tight under CI load. bump and retest.
- toolfile.write session.ts timeout 5s → 15s
- resultpatched +1 / −1
- thinkrun the flaky spec again, twice, then stop.
- toolpnpm test --filter=api auth.spec
- resultok 2 passed 0 flaky
+25 more · thinking · tool_call · tool_result
Folded into orchestrator · 3 messages
waiting for compressor…
Click fold to replay the compressor. This is the roadmap, not a live trace.
Clients
You build the skin. Engine does the workplace.
Point dummy_client.py, a TUI, or something weirder at the socket. Sessions persist. File tree and git are rebuilt on snapshot so the client stays a renderer. New UI verbs go in the command catalog — the dummy client already looks up type names. New model verbs go under tools/. Don't fork the loop.
python app.py .
# listening on .engine/engine.sock
python dummy_client.py .
engine> start
engine> open src/auth.ts
engine> fix the flaky auth test
{"type":"ChatMessageAdded","role":"assistant",...}
engine> git
{"type":"GitStateUpdated","git":{"branch":"main","dirty":true}}Status
Still in development. Missing a lot — orchestrator, named subagents, compressor, LSP, tree-sitter, mutating git. What you can clone today: the socket, the two catalogs, @tool discovery, SQLite sessions, reads, git status, and an OpenRouter loop that will actually run the tools the model calls.
Adjacent surfaces
codeloom.iresharma.com
CodeLoom
An autonomous coding agent that plans, writes, and ships.
Open Agentide.codeloom.iresharma.com
CodeLoom IDE
An AI-native editor. Cursor energy, built from a VS Code fork.
Open IDEtui.codeloom.iresharma.com
CodeLoom TUI
A coding agent in the terminal, with a Neovim-like workspace.
Open TUIcli.codeloom.iresharma.com
CodeLoom CLI
A coding agent you invoke like any other Unix tool.
Open CLI