Skip to content

emrg: the agent registry is agents.yml, migrated in place from projects.yml #2521

Closed

Description

@argszero

What is observed

~/.emrg/projects.yml is the installation's register of the directories a session runs in. Four modules build its path themselves, each spelling the directory out again:

  • emrg/server/daemon.py — self._projects_log = runtime_dir / "projects.yml", read by the project-touch path, the picker's list_projects and remove_project
  • emrg/server/scheduler.py — config_dir() / "projects.yml" in _resolve_project_path, _load_project_config and the emrg-entry self-heal
  • emrg/tools/submit_rant_tool.py — self._rants_log().parent / "projects.yml" in the candidate-name reader
  • scripts/check-memory-rotation.py — DEFAULT_PROJECTS = "~/.emrg/projects.yml"

emrg/tools/file_policy.py names the same file in its protected-files list, and tests/conftest.py names it as one of the host's real config files, so a test that writes it fails loudly.

Since #2520 the record of a directory a session runs in is an Agent (emrg/agent.py) — a base_dir and the three paths derived from it. The registry file still carries the name of the concept it no longer represents.

What is expected

The registry is ~/.emrg/agents.yml. Every reader and writer asks one producer for that path instead of building it, and the host's existing registry arrives at the new name with nothing lost — no entry dropped, no field dropped, last_active intact.

What the fix must satisfy

  • One producer, in emrg/config.py beside config_dir() and logs_dir() — the same "one derivation of that directory" treatment logs_dir() already has. Every site listed above asks it; config_dir() / "projects.yml" disappears from the package. The producer takes its base directory as an optional argument so a caller holding its own data directory (the rant tool, whose tests point it at a temp dir) still goes through the one function.
  • One-shot and atomic. When agents.yml is absent and projects.yml is present, the old name is moved into the new one by a single rename inside the same directory, so the move either happened or it did not: there is no window in which both names hold different halves of the register.
  • A registry already at the new name is never touched, and one that never existed is not created — a reader keeps its current "no registry ⇒ no entries" behaviour rather than materialising an empty file.
  • A failed move degrades, it does not raise. A read-only home or a permission boundary leaves the legacy file exactly where it is, and the caller proceeds as it already does for a missing registry; nothing new escapes into the daemon's startup path.
  • agents.yml inherits the protection. Its read and write semantics under every sandbox tier are the ones projects.yml had; the hermeticity guard in tests/conftest.py watches the new name, so a test writing the host's real registry still fails loudly.
  • Two concurrent callers are safe: the second rename finds the legacy name gone and is treated as the first one's success.
  • Guards to leave behind: a migration test (an entry and its last_active survive; the new file exists and the old one is gone), a "never moves what is already renamed" test, and a "a move that cannot happen leaves the legacy name readable" test.

Out of scope

The 9 task records, the 92 rant records, the project → agent vocabulary across the protocol and both clients, and the automatic registration of an arbitrary directory each stay for their own issue and their own change.

Activity

  1. argszero commented on Oct 23, 2026

    @argszero
    OwnerAuthor

    Handled by #2522

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions