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.
Returns environment variables shell commands should use for this changeset.
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.
Discards one changed file from the changeset view.
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.
Validates the merge plan back to the real project without applying it.
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.
Returns environment variables shell commands should use for this changeset.
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.
Discards one changed file from the changeset view.
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
{:conflict, details} listing what couldn't be auto-merged. Stops the
GenServer only on success; conflict results keep the changeset alive for review.
Returns modified and deleted file lists.
Returns the overlay directory path.
Validates the merge plan back to the real project without applying it.
This performs the same path validation and conflict planning as merge/1
but does not write, delete, or clean up anything. It is useful when a caller
needs to know whether a merge would succeed before mutating other state.
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}.
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.