Repository navigation
emrg: an Agent is the directory a session runs in #2519
Description
An Agent is the directory a session runs in
What is wrong today
There is no entity for "the directory a session runs in". A session takes a bare path
(Session(session_id, cwd)), keeps it as a plain attribute, and every module that needs
the state layout beside that directory spells the layout out again:
emrg/session.py—generate_session_id,session_dir,list_sessionsemrg/sessions_index.py— the walk that rebuilds the global indexemrg/memory.py—ProjectMemoryStoreemrg/server/daemon.py— the collector that reads a session's project memory, and the
subject list in the memory-reflection prompt
The copies agree, which is exactly what makes them invisible: the layout can change in one
of them and every test still passes, because the answers stay equal until the day one copy
is edited alone. session_dir's own docstring asks for "an edit in one place rather than a
search for every copy of the expression", and four of the sites above bypass it.
What this change does
A new emrg/agent.py holds Agent: the one directory a session runs in, carrying
base_dir and the three derived paths emrg_dir, sessions_dir, memory_dir. It carries
no behaviour — no model, no history, no sandbox knowledge — because those belong to the
session that runs in it and to the daemon that schedules it, and a field here would be a
second place to keep a fact that already has an owner.
base_dir is stored exactly as given: no resolve(), no expanduser(), no
trailing-slash normalisation, and a str stays a str. The value is compared for equality
downstream against strings that are already recorded elsewhere (what a client sent, what
meta.json stored), so normalising it on one side only is how two spellings of one
directory start disagreeing.
Session holds an Agent. Session(session_id, agent) still accepts a path and wraps it
on the spot, so no existing caller changes; cwd becomes a read-only property answering
agent.base_dir, which leaves every reader of session.cwd untouched. It is a property
rather than a field because a second assignment could move a session's files and its cwd
apart with nothing recording which one is right.
The sites above ask the Agent instead of spelling the layout. session_dir,
generate_session_id and list_sessions keep their signatures and delegate, so no caller
changes and no second convention is introduced.
Acceptance
Agentstores what it was given: a trailing slash, a..and a~survive unchanged,
and astrstays astrwhile aPathstays aPath.Session(sid, path)andSession(sid, Agent(path))produce the identical session
directory and the identicalcwd;session.cwdcannot be assigned.- No module builds a
<dir>/.emrg/{sessions,memory}path — the layout exists inAgent
and nowhere else — and a prompt that merely names the layout is not a producer. - The existing session, index, memory and prompt-template suites pass, the only edit being
a stand-in that models what a session now holds. - Mutation arms, each watched red:
resolve()onbase_dir;expanduser()on
base_dir; a second spelling of the sessions path; a re-introduced copy of the layout
in the daemon. - The three-platform CI matrix is green.
Not in this change
Registering directories, the projects.yml → agents.yml migration, renaming project to
agent across configuration, records, protocol and both clients, and the daemon split are
not here. Each is separately verifiable, and each follows in its own issue opened
together with the pull request that does it.
Activity
[-]emrg: project disappears — an Agent is the directory a session runs in[/-][+]emrg: an Agent is the directory a session runs in[/+]argszero commentedon Oct 23, 2026
Handled by #2520