Gap
workspace has read, write, edit, clone, plus the git and worktree op groups, but no file/directory delete primitive. Agents that need to remove tracked files have to drop out of the workspace API and run git rm or rm -rf directly on disk, which defeats the point of the workspace abstraction (containment checks, sensitive-path filter, allowlist enforcement, primary-mutation gating).
This came up in a homeboy scope-reduction PR (Extra-Chill/homeboy, branch scope-reduction-cut-synthesis) that needs to delete five files and one directory tree (~5,500 LOC of synthesis code). Per the host site's three-step rule, fixing the upstream gap before papering over it.
Proposed shape
New ability datamachine/workspace-delete mirroring workspace-write conventions, plus a wp datamachine-code workspace delete <repo> <path> CLI subcommand.
Ability input schema
{
repo: string, // <repo> | <repo>@<branch-slug>
path: string, // relative path within the repo (file OR directory)
recursive?: bool = false, // required when target is a directory
allow_primary_mutation?: bool = false
}
Behaviour
- Resolve repo path via
Workspace::resolve_repo_path.
- Reject path traversal (
has_traversal), sensitive paths (is_sensitive_path), and allowlist violations (get_repo_allowed_paths / is_path_allowed) — same checks as git_add.
- Gate primary-mutation via
Workspace::ensure_primary_mutation_allowed (consistent with git_add/git_commit).
- If the path is tracked by git:
git rm [-r] -- <path> so the deletion is staged. Use --cached? No — full removal from working tree + index, matching what callers actually want.
- If the path is untracked: filesystem
unlink (file) or recursive rmdir (directory) — only when recursive=true for directories.
- Containment check after the operation: confirm
realpath(parent) is still inside repo_path (defensive against symlink shenanigans, even though git rm shouldn't create new paths).
Ability output schema
{
success: bool,
path: string,
deleted: string[], // for recursive deletes: every removed path (relative)
was_tracked: bool // git rm vs filesystem path
}
CLI
wp datamachine-code workspace delete <repo> <path> [--recursive] [--allow-primary-mutation]
Same argument parsing pattern as workspace edit / workspace write.
Why a single primitive (not two)
Splitting into delete-file + delete-directory doubles the surface for no gain. recursive flag covers the directory case and makes accidental recursive deletes opt-in (rejecting directories without recursive=true matches POSIX rm semantics).
Out of scope
- No glob/pattern support — agents enumerate paths themselves. Consistent with
git_add taking explicit paths.
- No "soft delete" / trash semantics — git history is the undo path.
- No batch ability
workspace-delete-many — agents can call once per path. If batch becomes a real need, add later.
Testing
- Unit-equivalent smoke tests via
wp datamachine-code workspace delete against a throwaway worktree (the Playwright-style "real workspace, real disk" approach DMC already uses).
- Verify primary-mutation gate:
delete <repo> (bare, no @) without --allow-primary-mutation returns the same error as git_add does today.
- Verify allowlist enforcement: configure
datamachine_workspace_allowed_paths and confirm out-of-allowlist deletes return path_not_allowed.
- Verify sensitive-path rejection: deleting
.env / wp-config.php returns sensitive_path.
- Verify tracked vs untracked paths produce correct
was_tracked output.
AI assistance
- AI assistance: Yes
- Tool(s): Claude Code (Sonnet 4.5)
- Used for: Drafting the issue from a homeboy scope-reduction call-graph audit. Chris reviewed the gap and authorized the upstream-first fix.
Gap
workspacehasread,write,edit,clone, plus thegitandworktreeop groups, but no file/directory delete primitive. Agents that need to remove tracked files have to drop out of the workspace API and rungit rmorrm -rfdirectly on disk, which defeats the point of the workspace abstraction (containment checks, sensitive-path filter, allowlist enforcement, primary-mutation gating).This came up in a homeboy scope-reduction PR (Extra-Chill/homeboy, branch
scope-reduction-cut-synthesis) that needs to delete five files and one directory tree (~5,500 LOC of synthesis code). Per the host site's three-step rule, fixing the upstream gap before papering over it.Proposed shape
New ability
datamachine/workspace-deletemirroringworkspace-writeconventions, plus awp datamachine-code workspace delete <repo> <path>CLI subcommand.Ability input schema
Behaviour
Workspace::resolve_repo_path.has_traversal), sensitive paths (is_sensitive_path), and allowlist violations (get_repo_allowed_paths/is_path_allowed) — same checks asgit_add.Workspace::ensure_primary_mutation_allowed(consistent withgit_add/git_commit).git rm [-r] -- <path>so the deletion is staged. Use--cached? No — full removal from working tree + index, matching what callers actually want.unlink(file) or recursivermdir(directory) — only whenrecursive=truefor directories.realpath(parent)is still insiderepo_path(defensive against symlink shenanigans, even though git rm shouldn't create new paths).Ability output schema
CLI
Same argument parsing pattern as
workspace edit/workspace write.Why a single primitive (not two)
Splitting into
delete-file+delete-directorydoubles the surface for no gain.recursiveflag covers the directory case and makes accidental recursive deletes opt-in (rejecting directories withoutrecursive=truematches POSIXrmsemantics).Out of scope
git_addtaking explicit paths.workspace-delete-many— agents can call once per path. If batch becomes a real need, add later.Testing
wp datamachine-code workspace deleteagainst a throwaway worktree (the Playwright-style "real workspace, real disk" approach DMC already uses).delete <repo>(bare, no@) without--allow-primary-mutationreturns the same error asgit_adddoes today.datamachine_workspace_allowed_pathsand confirm out-of-allowlist deletes returnpath_not_allowed..env/wp-config.phpreturnssensitive_path.was_trackedoutput.AI assistance