DeltaGit should provide one provider-neutral command runtime for coding agents:
CoW workspace
+ process supervision
+ operation delta capture
+ rollback
This is a command runtime, not yet a container. It does not promise complete absolute-path virtualization without a virtual filesystem backend.
The runtime is the execution backend for per-operation workspace mode. The
agent still invokes its native Bash or exec_command tool, but that tool runs
only the small deltagit-run launcher. The original command is executed by the
runtime inside the operation workspace.
Agent integrations only prepare an operation and rewrite the tool input. The runtime owns the actual operation lifecycle.
Codex / Claude Code / other agent
│
▼
PreToolUse adapter
│
├── allocate operation
├── create CoW workspace
└── rewrite command
│
▼
deltagit-run --operation <id>
│
├── load the original command
├── start the requested shell in view_root
├── create process group / Job Object
├── inherit stdin/stdout/stderr
├── wait for root and descendants
├── capture the final delta
└── seal, cancel, or rollback
The provider's session ID or task ID is transport-correlation metadata: it may route later input or output to the operation, but it must not determine when the DeltaGit operation ends.
The smallest useful operation record contains:
operation_id
parent_version
base_root
view_root
original_command
original_cwd
environment
shell
owner_agent
tool_call_id
provider_session_id / task_id
deadline_ms
background
process_group_id / job_id
status
The original command is stored in the operation record. The hook should pass
only the operation ID to deltagit-run; this avoids fragile shell quoting.
The runner should not expose provider-specific flags such as
--yield-time-ms or --run-in-background. Those belong to the agent adapter
and the native tool transport.
The adapters preserve the provider's input shape and rewrite only the command
field. deltagit-run loads the rest from the operation record.
| Input | Owner | DeltaGit behavior |
|---|---|---|
command |
Agent adapter | Store the exact original; replace with deltagit-run --operation <id> |
workdir / effective cwd |
Adapter and runtime | Store it and resolve the corresponding path inside the view |
Claude timeout |
Provider and runtime | Record as an operation deadline; enforce process-group cleanup |
Claude run_in_background |
Provider transport | Preserve it; the operation stays open after the tool returns |
Codex yield_time_ms |
Provider transport | Preserve it; it only controls how long the call waits |
Codex max_output_tokens |
Provider output layer | Preserve it; it does not affect the filesystem lifecycle |
shell / tty |
Provider transport and runtime | Preserve the requested shell and stream mode |
write_stdin / task output |
Provider transport | Continue or observe the existing operation; never create a new one |
| cancellation / task stop | Provider and runtime | Terminate the process group, drain children, then seal as cancelled |
Keep these concepts separate:
hook timeout → how long the PreToolUse adapter may run
command timeout → how long the command may execute
poll/wait timeout → how long the caller waits for output
In particular, yield_time_ms is never an operation deadline. A command that
outlives the initial wait remains running and can continue through the
provider's existing session or background-task mechanism.
Do not split this into a second repository yet. Keep the first implementation inside DeltaGit so the operation protocol and workspace APIs can evolve together:
deltagit/
├── cmd/deltagit-run/
├── runtime/supervisor/
├── runtime/protocol/
└── runtime/adapters/
├── codex/
└── claude/
The supervisor should be shell-neutral even if the first implementation only
launches Bash. Later it can launch sh, zsh, PowerShell, or cmd without
changing the agent adapters.
Split this into a separate deltagit-runtime repository only when it needs an
independent release cycle or is consumed by another product. The repository
should not be named bash-adapter: the adapters understand coding-agent hook
protocols, while the supervisor understands processes and shells.
The ownership boundary is:
Agent adapter → Claude/Codex hook payloads and tool IDs
Supervisor → shells, stdio, deadlines, process trees, cancellation
DeltaGit → views, deltas, checkpoints, rollback, sealing, branches
prepared
│
▼
running
│
▼
draining
│
▼
quiescing
│
├── sealed
├── cancelled
├── failed
└── escaped
PostToolUse is optional telemetry. It is not the lifecycle authority. A
command is complete only after its process group or Job Object has drained and
the workspace has reached a short filesystem-quiescence window.
This handles commands such as:
long-running-command &
exit 0The shell may exit first, but the operation remains active until the child processes finish.
PreToolUse(Bash)
└── rewrite command to deltagit-run
The adapter stores the complete original exec_command input, including
workdir, yield_time_ms, output limits, and terminal mode. It returns the
same input with only command changed. Codex continues to own
exec_command, session_id, write_stdin, and output streaming.
write_stdin does not create another operation and does not need a separate
DeltaGit adapter.
PreToolUse(Bash)
└── rewrite command to deltagit-run
Claude Code's hook can replace the Bash input through updatedInput. Preserve
the original timeout, run_in_background, and other tool fields. Claude Code
continues to own its task IDs, output retrieval, and task cancellation. The
operation remains open until the supervisor observes process-group completion,
not merely until the hook or tool call returns.
The same operation allocator and deltagit-run binary should serve both
providers. Only the hook configuration and provider-specific event parsing
belong in the adapters.
References:
Do not perform general string replacement on arbitrary Bash commands.
The supervisor changes the process working directory:
base_root = /Users/yifanxu/project
view_root = /tmp/deltagit/op-123/workspace
This makes ordinary relative paths resolve inside the operation workspace:
./src/index.tsFor Read, Edit, and Write, an adapter can safely map structured paths:
/Users/yifanxu/project/src/a.ts
│
▼
/tmp/deltagit/op-123/workspace/src/a.ts
An opaque Bash string may contain paths inside variables, substitutions, here-documents, nested scripts, or binaries. Reliable translation requires a virtual filesystem layer such as FUSE, FSKit, OverlayFS, or an equivalent OS mechanism.
Therefore the first version guarantees:
CoW + changed cwd → relative-path isolation
structured path mapping → direct file-tool isolation
virtual filesystem → full absolute-path transparency
Keep the first version simple:
Edit / Write → atomic operation on the current persistent workspace
Bash → ephemeral CoW operation supervised by deltagit-run
An Edit or Write should not automatically join a currently running Bash operation. Joining live operations would require a shared virtual view and a more complex concurrency model. Add structured path routing later if that behavior becomes necessary.
Use native CoW or the simplest available fallback:
macOS → APFS clone/reflink backend
Linux → reflink backend, then copy fallback
Windows → native CoW backend where available, then copy fallback
FUSE and FSKit are optional materialization backends, not requirements of the operation model or the command supervisor.
Write the operation record before starting the child process. A recovery command should later be able to inspect orphaned operations and determine whether to:
reattach
finalize
mark cancelled
mark abandoned
retain for manual recovery
Recovery is more important than adding an early UI layer.
- Implement
deltagit-runwith the operation state machine. - Add the macOS native CoW workspace backend.
- Capture created, modified, and removed files.
- Verify long-running commands and
write_stdin. - Verify background children, cancellation, and rollback.
- Add the Codex
PreToolUse(Bash)adapter. - Add the Claude Code
PreToolUse(Bash)adapter. - Add structured path mapping for
Read,Edit, andWrite. - Add Linux and Windows workspace backends.
- Convert sealed operations into persistent branch commits and Git-compatible history.
short Bash command
file creation
file modification
file deletion
long-running Bash
write_stdin input
background child process
cancellation
rollback
two parallel operations
npm install
absolute-path bypass demonstration
general Bash string rewriting
FUSE/FSKit as a mandatory dependency
provider-specific session managers
PostToolUse-based sealing
automatic merging of Edit/Write into a live Bash operation
full absolute-path transparency
The first milestone is complete when two agents can run independent Bash operations in cheap CoW workspaces, receive normal command I/O, and safely seal or rollback their operation without DeltaGit knowing which provider owns the surrounding tool session.