This was generated by AI during triage.
Summary
Kanban task completion can delete a real user source directory when a board or task workspace points at an existing project folder but the task uses workspace_kind = scratch.
The worker documentation says scratch is disposable and gets garbage-collected. That behavior is expected. The safety problem is that Hermes currently allows a user-provided/default workdir outside Hermes-managed scratch space to be treated as scratch without warning or blocking, so a misconfiguration can turn normal task completion into data loss.
Impact
- Real source checkouts can be deleted if they are configured as a scratch workspace.
- Sibling workers spawned in the same workspace then fail with
FileNotFoundError / os.getcwd() because their cwd has been removed.
- Task logs may not show an explicit
rm -rf, making the root cause hard to diagnose.
Relevant Code Path
In hermes_cli/kanban_db.py, successful task completion calls workspace cleanup:
# complete_task(...)
_cleanup_workspace(conn, task_id)
Cleanup removes scratch workspaces:
if kind != "scratch" or not path:
return
wp = Path(path)
if wp.is_dir():
shutil.rmtree(wp, ignore_errors=True)
The task schema defaults to scratch:
workspace_kind TEXT NOT NULL DEFAULT 'scratch'
Reproduction Shape
- Create or use a board whose default workdir points at an existing real source directory, for example:
hermes kanban boards set-default-workdir my-board /path/to/real/source
- Create a kanban task without explicitly setting a persistent workspace kind such as
dir:/path/to/real/source or worktree.
- Dispatch and complete the task.
- Completion cleanup treats
/path/to/real/source as disposable scratch and may remove it.
Expected Behavior
Hermes should never silently delete a user source directory because it was assigned as a task workspace.
For non-Hermes-managed paths, Hermes should either:
- reject
workspace_kind = scratch, or
- require explicit confirmation, or
- coerce/direct users to
dir:<absolute-path> or worktree.
Scratch cleanup should only delete directories Hermes itself created under a known Hermes scratch root, such as:
~/.hermes/kanban/workspaces/...
Actual Behavior
If a task has:
workspace_kind = scratch
workspace_path = /path/to/real/source
then successful task completion can call:
shutil.rmtree("/path/to/real/source", ignore_errors=True)
Suggested Fix
Add guardrails before shutil.rmtree():
- Only delete scratch workspaces under the configured Hermes kanban workspaces root.
- Refuse to delete paths containing
.git or obvious source-control metadata.
- Refuse to delete paths outside
~/.hermes/kanban/workspaces unless they carry a Hermes-owned marker file.
- Log a warning/error when scratch cleanup is rejected.
- Consider making board
default_workdir imply persistent dir:<path> semantics rather than scratch semantics.
- Consider warning in
boards set-default-workdir if the target exists and is outside Hermes-managed workspace storage.
Regression Tests
Please add tests for:
- Hermes-created scratch workspace under kanban workspaces root is cleaned up.
- Existing user source directory outside the scratch root is not removed.
- Any path containing
.git is not removed by scratch cleanup.
- Board
default_workdir cannot accidentally become destructively cleanup-eligible by default.
Severity
P0 / critical because the failure mode is data loss. There is a workaround (dir:<path> or worktree), but the current configuration path is too easy to misuse and the result is severe.
Summary
Kanban task completion can delete a real user source directory when a board or task workspace points at an existing project folder but the task uses
workspace_kind = scratch.The worker documentation says
scratchis disposable and gets garbage-collected. That behavior is expected. The safety problem is that Hermes currently allows a user-provided/default workdir outside Hermes-managed scratch space to be treated asscratchwithout warning or blocking, so a misconfiguration can turn normal task completion into data loss.Impact
FileNotFoundError/os.getcwd()because their cwd has been removed.rm -rf, making the root cause hard to diagnose.Relevant Code Path
In
hermes_cli/kanban_db.py, successful task completion calls workspace cleanup:Cleanup removes scratch workspaces:
The task schema defaults to scratch:
Reproduction Shape
dir:/path/to/real/sourceorworktree./path/to/real/sourceas disposable scratch and may remove it.Expected Behavior
Hermes should never silently delete a user source directory because it was assigned as a task workspace.
For non-Hermes-managed paths, Hermes should either:
workspace_kind = scratch, ordir:<absolute-path>orworktree.Scratch cleanup should only delete directories Hermes itself created under a known Hermes scratch root, such as:
Actual Behavior
If a task has:
then successful task completion can call:
Suggested Fix
Add guardrails before
shutil.rmtree():.gitor obvious source-control metadata.~/.hermes/kanban/workspacesunless they carry a Hermes-owned marker file.default_workdirimply persistentdir:<path>semantics rather than scratch semantics.boards set-default-workdirif the target exists and is outside Hermes-managed workspace storage.Regression Tests
Please add tests for:
.gitis not removed by scratch cleanup.default_workdircannot accidentally become destructively cleanup-eligible by default.Severity
P0 / critical because the failure mode is data loss. There is a workaround (
dir:<path>orworktree), but the current configuration path is too easy to misuse and the result is severe.