LISTEN.engine/engine.sock

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

.engine/engine.sockNDJSON · unix · fan-outinspect

▍ waiting on .engine/engine.sock

sqlite sessionsopenrouter8-turn tools

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 root

model --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

Orchestrator that does not patch filesNamed subagents: ask, linter, editor, reviewerConversationCompressor — 30+ turns → 1–5LSP / tree-sitter / mutating git — still on the bench

Worker trail · 34 messages

live
  1. thinkmaybe the timeout is in the client retry loop…
  2. toolgrep timeout auth.spec.ts session.ts
  3. resultsession.ts:88 timeout: 5_000
  4. think5s is tight under CI load. bump and retest.
  5. toolfile.write session.ts timeout 5s → 15s
  6. resultpatched +1 / −1
  7. thinkrun the flaky spec again, twice, then stop.
  8. toolpnpm test --filter=api auth.spec
  9. 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.