In-memory changesets with filesystem overlays for agent editing.
A changeset tracks file edits without modifying the original project. Edits are held in memory and materialized into a hardlink overlay where external tools (compilers, test runners, linters) see a coherent view of the project with changes applied.
Lifecycle
{:ok, cs} = MingaAgent.Changeset.create("/path/to/project")
:ok = MingaAgent.Changeset.write_file(cs, "lib/math.ex", new_content)
:ok = MingaAgent.Changeset.edit_file(cs, "lib/util.ex", "old", "new")
# External tools see changes through the overlay
{output, 0} = MingaAgent.Changeset.run(cs, "mix compile")
# Session ends: merge back with three-way merge
:ok = MingaAgent.Changeset.merge(cs)Budget system
{:ok, cs} = MingaAgent.Changeset.create("/path/to/project", budget: 3)
{:ok, 1} = MingaAgent.Changeset.record_attempt(cs)
{:budget_exhausted, 4, 3} = MingaAgent.Changeset.record_attempt(cs)
Summary
Functions
Returns the current attempt count and budget.
Creates a new changeset against project_root.
Deletes a file from the changeset's view.
Discards all changes, cleans up the overlay, and stops the GenServer.
Edits a file by replacing old_text with new_text.
Merges changes back to the real project with three-way merge.
Returns modified and deleted file lists.
Returns the overlay directory path.
Returns the project root this changeset was created against.
Reads a file (changeset version if modified, otherwise from project).
Records a verification attempt (e.g., after running tests).
Resets the entire changeset, restoring all files to their original state.
Runs a shell command in the overlay directory.
Returns a summary of all changes.
Undoes the last edit to a specific file.
Writes content to relative_path within the changeset.
Types
@type changeset() :: pid()
Functions
@spec attempt_info(changeset()) :: %{ attempts: non_neg_integer(), budget: pos_integer() | :unlimited }
Returns the current attempt count and budget.
Creates a new changeset against project_root.
Starts a Changeset.Server GenServer under MingaAgent.Supervisor.
The server creates a filesystem overlay mirroring the project.
Options
:budget- max verification attempts before exhaustion (default::unlimited)
Deletes a file from the changeset's view.
@spec discard(changeset()) :: :ok
Discards all changes, cleans up the overlay, and stops the GenServer.
Edits a file by replacing old_text with new_text.
Merges changes back to the real project with three-way merge.
If someone edited the same files since the changeset was created,
a three-way merge is attempted. Returns :ok for clean merges, or
{:ok, :merged_with_conflicts, details} listing what couldn't be
auto-merged. Stops the GenServer on success.
Returns modified and deleted file lists.
Returns the overlay directory path.
Returns the project root this changeset was created against.
Reads a file (changeset version if modified, otherwise from project).
@spec record_attempt(changeset()) :: {:ok, pos_integer()} | {:budget_exhausted, pos_integer(), pos_integer()}
Records a verification attempt (e.g., after running tests).
Returns {:ok, attempt_number} or {:budget_exhausted, attempts, budget}.
@spec reset(changeset()) :: :ok
Resets the entire changeset, restoring all files to their original state.
@spec run(changeset(), String.t(), keyword()) :: {String.t(), non_neg_integer()}
Runs a shell command in the overlay directory.
Sets MIX_BUILD_PATH to an isolated build directory so compilation
doesn't contaminate the real project's _build.
Returns a summary of all changes.
Undoes the last edit to a specific file.
Writes content to relative_path within the changeset.