Skip to content

Deleting a project leaves its run directories orphaned under .od/runs/ #6117

Description

@kobbyDaUXer

What happens

Deleting a project leaves its runs' state behind under .od/runs/<runId>/. The directories are never reclaimed, so they accumulate for the lifetime of the install.

Reproduced on 0.16.1:

$ od project create --name "smoke test"
$ od run start --project <projectId> --agent antigravity --message "Design a login screen."
{ "runId": "ac829957-3f2c-4695-9f41-85143789dc4d", … }

$ od project delete <projectId>
[project] deleted <projectId>

$ ls .od/runs/ac829957-3f2c-4695-9f41-85143789dc4d
events.jsonl   state.json

The project is gone from od project list, but the run directory remains.

Why

app.delete('/api/projects/:id') in apps/daemon/src/routes/project/index.ts:2273 does three things:

await cancelRunsOwnedBy(design.runs, { projectId: req.params.id });
dbDeleteProject(db, req.params.id);
await removeProjectDir(PROJECTS_DIR, req.params.id).catch(() => {});

Live runs are cancelled (#5468) and the project directory is removed, but nothing removes the per-run directories under the runs root. They are keyed by run id rather than nested under the project, so removing the project directory doesn't reach them, and I couldn't find a retention/prune job that would collect them later.

Impact

Small but unbounded. Each orphaned run keeps an events.jsonl (the full agent event stream — a few KB for a short run, considerably more for a long agentic session) plus state.json, with no project row left to reach them from. Anyone who creates and deletes throwaway projects — which is the natural way to try things out — accumulates them silently.

There is also a privacy angle worth weighing: events.jsonl contains the prompts and the agent's output. A user who deletes a project reasonably expects that content to be gone, and it isn't.

Suggested fix

Extend the delete handler to remove run directories owned by the project. cancelRunsOwnedBy already enumerates runs by projectId, so the ownership lookup exists — the same set could be swept after cancellation. A retention sweep on startup for runs whose project no longer exists would also catch directories orphaned by earlier versions.

Happy to send a PR if the approach sounds right — I'd want a maintainer's call on whether deletion should be immediate or left to a retention window, since there's an argument for keeping run diagnostics around briefly after a project goes.

Environment

  • Open Design 0.16.1, daemon running via pnpm tools-dev
  • macOS 15.5, Node 24.18.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions