diff --git a/.gqlgen.yml b/.gqlgen.yml
index 521a6cf..06e5f7c 100644
--- a/.gqlgen.yml
+++ b/.gqlgen.yml
@@ -27,11 +27,11 @@ models:
   Torrent:
     extraFields:
       T:
-        type: "*git.kmsign.ru/royalcat/tstor/src/daemons/torrent.Controller"
+        type: "*git.kmsign.ru/royalcat/tstor/daemons/torrent.Controller"
   TorrentFile:
     extraFields:
       F:
-        type: "*git.kmsign.ru/royalcat/tstor/src/daemons/torrent.FileController"
+        type: "*git.kmsign.ru/royalcat/tstor/daemons/torrent.FileController"
   TorrentPeer:
     extraFields:
       F:
@@ -45,7 +45,7 @@ models:
   TorrentFS:
     extraFields:
       FS:
-        type: "*git.kmsign.ru/royalcat/tstor/src/daemons/torrent.TorrentFS"
+        type: "*git.kmsign.ru/royalcat/tstor/daemons/torrent.TorrentFS"
   ResolverFS:
     extraFields:
       FS:
diff --git a/Dockerfile b/Dockerfile
index 054e197..707f524 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -6,6 +6,7 @@ COPY go.mod ./
 COPY go.sum ./
 RUN --mount=type=cache,mode=0777,target=/go/pkg/mod go mod download all
 
+COPY ./daemons ./daemons
 COPY ./pkg ./pkg
 COPY ./src ./src
 COPY ./cmd ./cmd
diff --git a/cmd/tstor/main.go b/cmd/tstor/main.go
index 58fec83..5d6ff4a 100644
--- a/cmd/tstor/main.go
+++ b/cmd/tstor/main.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"errors"
 	"fmt"
+	"io/fs"
 	"log/slog"
 
 	"net"
@@ -13,13 +14,13 @@ import (
 	"os/signal"
 	"syscall"
 
+	"git.kmsign.ru/royalcat/tstor/daemons/qbittorrent"
+	"git.kmsign.ru/royalcat/tstor/daemons/ytdlp"
 	"git.kmsign.ru/royalcat/tstor/pkg/ctxbilly"
 	wnfs "git.kmsign.ru/royalcat/tstor/pkg/go-nfs"
 	"git.kmsign.ru/royalcat/tstor/pkg/rlog"
 	"git.kmsign.ru/royalcat/tstor/src/config"
 	"git.kmsign.ru/royalcat/tstor/src/daemons"
-	"git.kmsign.ru/royalcat/tstor/src/daemons/qbittorrent"
-	"git.kmsign.ru/royalcat/tstor/src/daemons/ytdlp"
 	"git.kmsign.ru/royalcat/tstor/src/delivery"
 	"git.kmsign.ru/royalcat/tstor/src/telemetry"
 	"git.kmsign.ru/royalcat/tstor/src/vfs"
@@ -118,6 +119,10 @@ func run(configPath string) error {
 		return err
 	}
 
+	vfs.Walk(ctx, sfs, "/", func(path string, info fs.FileInfo, err error) error {
+		return nil
+	})
+
 	if conf.Mounts.Fuse.Enabled {
 		mh := fuse.NewHandler(conf.Mounts.Fuse.AllowOther, conf.Mounts.Fuse.Path)
 		err := mh.Mount(sfs)
diff --git a/src/daemons/qbittorrent/api.go b/daemons/qbittorrent/api.go
similarity index 100%
rename from src/daemons/qbittorrent/api.go
rename to daemons/qbittorrent/api.go
diff --git a/src/daemons/qbittorrent/cleanup.go b/daemons/qbittorrent/cleanup.go
similarity index 95%
rename from src/daemons/qbittorrent/cleanup.go
rename to daemons/qbittorrent/cleanup.go
index 21a32d4..c8b08c9 100644
--- a/src/daemons/qbittorrent/cleanup.go
+++ b/daemons/qbittorrent/cleanup.go
@@ -12,7 +12,7 @@ import (
 	"git.kmsign.ru/royalcat/tstor/pkg/rlog"
 )
 
-func (d *Daemon) Cleanup(ctx context.Context, dryRun bool) ([]string, error) {
+func (d *Daemon) Cleanup(ctx context.Context, run bool) ([]string, error) {
 	d.log.Info(ctx, "cleanup started")
 
 	torrentInfos, err := d.client.qb.Torrent().GetTorrents(ctx, &qbittorrent.TorrentOption{})
@@ -37,7 +37,7 @@ func (d *Daemon) Cleanup(ctx context.Context, dryRun bool) ([]string, error) {
 		slog.Any("infohashes", torrentToDelete),
 	)
 
-	if dryRun {
+	if !run {
 		d.log.Info(ctx, "dry run, skipping deletion")
 		return torrentToDelete, nil
 	}
diff --git a/src/daemons/qbittorrent/client.go b/daemons/qbittorrent/client.go
similarity index 100%
rename from src/daemons/qbittorrent/client.go
rename to daemons/qbittorrent/client.go
diff --git a/src/daemons/qbittorrent/daemon.go b/daemons/qbittorrent/daemon.go
similarity index 97%
rename from src/daemons/qbittorrent/daemon.go
rename to daemons/qbittorrent/daemon.go
index 143752c..cd53747 100644
--- a/src/daemons/qbittorrent/daemon.go
+++ b/daemons/qbittorrent/daemon.go
@@ -26,7 +26,7 @@ import (
 	"go.opentelemetry.io/otel"
 )
 
-var trace = otel.Tracer("git.kmsign.ru/royalcat/tstor/src/daemons/qbittorrent")
+var trace = otel.Tracer("git.kmsign.ru/royalcat/tstor/daemons/qbittorrent")
 
 type Daemon struct {
 	proc   *os.Process
@@ -231,6 +231,9 @@ func (d *Daemon) syncTorrentState(ctx context.Context, file vfs.File, ih metainf
 			if err == nil {
 				break
 			}
+			if errors.Is(err, context.DeadlineExceeded) {
+				return err
+			}
 			log.Error(ctx, "waiting for torrent to be added", rlog.Error(err))
 			time.Sleep(time.Millisecond * 15)
 		}
diff --git a/src/daemons/qbittorrent/fs.go b/daemons/qbittorrent/fs.go
similarity index 100%
rename from src/daemons/qbittorrent/fs.go
rename to daemons/qbittorrent/fs.go
diff --git a/src/daemons/qbittorrent/install.go b/daemons/qbittorrent/install.go
similarity index 100%
rename from src/daemons/qbittorrent/install.go
rename to daemons/qbittorrent/install.go
diff --git a/src/daemons/qbittorrent/install_test.go b/daemons/qbittorrent/install_test.go
similarity index 100%
rename from src/daemons/qbittorrent/install_test.go
rename to daemons/qbittorrent/install_test.go
diff --git a/src/daemons/torrent/client.go b/daemons/torrent/client.go
similarity index 100%
rename from src/daemons/torrent/client.go
rename to daemons/torrent/client.go
diff --git a/src/daemons/torrent/controller.go b/daemons/torrent/controller.go
similarity index 100%
rename from src/daemons/torrent/controller.go
rename to daemons/torrent/controller.go
diff --git a/src/daemons/torrent/daemon.go b/daemons/torrent/daemon.go
similarity index 100%
rename from src/daemons/torrent/daemon.go
rename to daemons/torrent/daemon.go
diff --git a/src/daemons/torrent/daemon_load.go b/daemons/torrent/daemon_load.go
similarity index 100%
rename from src/daemons/torrent/daemon_load.go
rename to daemons/torrent/daemon_load.go
diff --git a/src/daemons/torrent/daemon_stats.go b/daemons/torrent/daemon_stats.go
similarity index 100%
rename from src/daemons/torrent/daemon_stats.go
rename to daemons/torrent/daemon_stats.go
diff --git a/src/daemons/torrent/dht_fileitem_store.go b/daemons/torrent/dht_fileitem_store.go
similarity index 100%
rename from src/daemons/torrent/dht_fileitem_store.go
rename to daemons/torrent/dht_fileitem_store.go
diff --git a/src/daemons/torrent/dup_cache.go b/daemons/torrent/dup_cache.go
similarity index 100%
rename from src/daemons/torrent/dup_cache.go
rename to daemons/torrent/dup_cache.go
diff --git a/src/daemons/torrent/file_controller.go b/daemons/torrent/file_controller.go
similarity index 100%
rename from src/daemons/torrent/file_controller.go
rename to daemons/torrent/file_controller.go
diff --git a/src/daemons/torrent/fs.go b/daemons/torrent/fs.go
similarity index 100%
rename from src/daemons/torrent/fs.go
rename to daemons/torrent/fs.go
diff --git a/src/daemons/torrent/fs_test.go b/daemons/torrent/fs_test.go
similarity index 100%
rename from src/daemons/torrent/fs_test.go
rename to daemons/torrent/fs_test.go
diff --git a/src/daemons/torrent/infobytes.go b/daemons/torrent/infobytes.go
similarity index 100%
rename from src/daemons/torrent/infobytes.go
rename to daemons/torrent/infobytes.go
diff --git a/src/daemons/torrent/metrics.go b/daemons/torrent/metrics.go
similarity index 100%
rename from src/daemons/torrent/metrics.go
rename to daemons/torrent/metrics.go
diff --git a/src/daemons/torrent/peer_store.go b/daemons/torrent/peer_store.go
similarity index 100%
rename from src/daemons/torrent/peer_store.go
rename to daemons/torrent/peer_store.go
diff --git a/src/daemons/torrent/piece_completion.go b/daemons/torrent/piece_completion.go
similarity index 100%
rename from src/daemons/torrent/piece_completion.go
rename to daemons/torrent/piece_completion.go
diff --git a/src/daemons/torrent/piece_completion_test.go b/daemons/torrent/piece_completion_test.go
similarity index 100%
rename from src/daemons/torrent/piece_completion_test.go
rename to daemons/torrent/piece_completion_test.go
diff --git a/src/daemons/torrent/queue.go b/daemons/torrent/queue.go
similarity index 100%
rename from src/daemons/torrent/queue.go
rename to daemons/torrent/queue.go
diff --git a/src/daemons/torrent/setup.go b/daemons/torrent/setup.go
similarity index 100%
rename from src/daemons/torrent/setup.go
rename to daemons/torrent/setup.go
diff --git a/src/daemons/torrent/stats.go b/daemons/torrent/stats.go
similarity index 100%
rename from src/daemons/torrent/stats.go
rename to daemons/torrent/stats.go
diff --git a/src/daemons/torrent/storage.go b/daemons/torrent/storage.go
similarity index 100%
rename from src/daemons/torrent/storage.go
rename to daemons/torrent/storage.go
diff --git a/src/daemons/torrent/storage_dedupe.go b/daemons/torrent/storage_dedupe.go
similarity index 100%
rename from src/daemons/torrent/storage_dedupe.go
rename to daemons/torrent/storage_dedupe.go
diff --git a/src/daemons/torrent/storage_open.go b/daemons/torrent/storage_open.go
similarity index 100%
rename from src/daemons/torrent/storage_open.go
rename to daemons/torrent/storage_open.go
diff --git a/src/daemons/ytdlp/controller.go b/daemons/ytdlp/controller.go
similarity index 100%
rename from src/daemons/ytdlp/controller.go
rename to daemons/ytdlp/controller.go
diff --git a/src/daemons/ytdlp/daemon.go b/daemons/ytdlp/daemon.go
similarity index 100%
rename from src/daemons/ytdlp/daemon.go
rename to daemons/ytdlp/daemon.go
diff --git a/src/daemons/ytdlp/fs.go b/daemons/ytdlp/fs.go
similarity index 100%
rename from src/daemons/ytdlp/fs.go
rename to daemons/ytdlp/fs.go
diff --git a/src/daemons/ytdlp/tasks.go b/daemons/ytdlp/tasks.go
similarity index 100%
rename from src/daemons/ytdlp/tasks.go
rename to daemons/ytdlp/tasks.go
diff --git a/src/daemons/ytdlp/ytdlp.go b/daemons/ytdlp/ytdlp.go
similarity index 100%
rename from src/daemons/ytdlp/ytdlp.go
rename to daemons/ytdlp/ytdlp.go
diff --git a/graphql/sources/qbittorrent_mutation.graphql b/graphql/sources/qbittorrent_mutation.graphql
index c5d5809..aba4408 100644
--- a/graphql/sources/qbittorrent_mutation.graphql
+++ b/graphql/sources/qbittorrent_mutation.graphql
@@ -1,5 +1,5 @@
 type QBitTorrentDaemonMutation {
-  cleanup(dryRun: Boolean!): QBitCleanupResponse! @resolver
+  cleanup(run: Boolean!): QBitCleanupResponse! @resolver
 }
 
 type QBitCleanupResponse {
diff --git a/src/daemons/storage.go b/src/daemons/storage.go
index df121f8..b67dc7f 100644
--- a/src/daemons/storage.go
+++ b/src/daemons/storage.go
@@ -3,8 +3,8 @@ package daemons
 import (
 	"context"
 
-	"git.kmsign.ru/royalcat/tstor/src/daemons/qbittorrent"
-	"git.kmsign.ru/royalcat/tstor/src/daemons/ytdlp"
+	"git.kmsign.ru/royalcat/tstor/daemons/qbittorrent"
+	"git.kmsign.ru/royalcat/tstor/daemons/ytdlp"
 	"git.kmsign.ru/royalcat/tstor/src/vfs"
 )
 
diff --git a/src/delivery/graphql/generated.go b/src/delivery/graphql/generated.go
index 501cf2b..fc48e02 100644
--- a/src/delivery/graphql/generated.go
+++ b/src/delivery/graphql/generated.go
@@ -92,7 +92,7 @@ type ComplexityRoot struct {
 	}
 
 	QBitTorrentDaemonMutation struct {
-		Cleanup func(childComplexity int, dryRun bool) int
+		Cleanup func(childComplexity int, run bool) int
 	}
 
 	QBitTorrentDaemonQuery struct {
@@ -233,7 +233,7 @@ type MutationResolver interface {
 	DedupeStorage(ctx context.Context) (int64, error)
 }
 type QBitTorrentDaemonMutationResolver interface {
-	Cleanup(ctx context.Context, obj *model.QBitTorrentDaemonMutation, dryRun bool) (*model.QBitCleanupResponse, error)
+	Cleanup(ctx context.Context, obj *model.QBitTorrentDaemonMutation, run bool) (*model.QBitCleanupResponse, error)
 }
 type QBitTorrentDaemonQueryResolver interface {
 	Torrents(ctx context.Context, obj *model.QBitTorrentDaemonQuery) ([]*model.QTorrent, error)
@@ -398,7 +398,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 			return 0, false
 		}
 
-		return e.complexity.QBitTorrentDaemonMutation.Cleanup(childComplexity, args["dryRun"].(bool)), true
+		return e.complexity.QBitTorrentDaemonMutation.Cleanup(childComplexity, args["run"].(bool)), true
 
 	case "QBitTorrentDaemonQuery.torrents":
 		if e.complexity.QBitTorrentDaemonQuery.Torrents == nil {
@@ -1105,7 +1105,7 @@ interface Progress {
     total: Int!
 }`, BuiltIn: false},
 	{Name: "../../../graphql/sources/qbittorrent_mutation.graphql", Input: `type QBitTorrentDaemonMutation {
-  cleanup(dryRun: Boolean!): QBitCleanupResponse! @resolver
+  cleanup(run: Boolean!): QBitCleanupResponse! @resolver
 }
 
 type QBitCleanupResponse {
@@ -1384,28 +1384,28 @@ func (ec *executionContext) field_Mutation_uploadFile_argsFile(
 func (ec *executionContext) field_QBitTorrentDaemonMutation_cleanup_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
 	var err error
 	args := map[string]interface{}{}
-	arg0, err := ec.field_QBitTorrentDaemonMutation_cleanup_argsDryRun(ctx, rawArgs)
+	arg0, err := ec.field_QBitTorrentDaemonMutation_cleanup_argsRun(ctx, rawArgs)
 	if err != nil {
 		return nil, err
 	}
-	args["dryRun"] = arg0
+	args["run"] = arg0
 	return args, nil
 }
-func (ec *executionContext) field_QBitTorrentDaemonMutation_cleanup_argsDryRun(
+func (ec *executionContext) field_QBitTorrentDaemonMutation_cleanup_argsRun(
 	ctx context.Context,
 	rawArgs map[string]interface{},
 ) (bool, error) {
 	// We won't call the directive if the argument is null.
 	// Set call_argument_directives_with_null to true to call directives
 	// even if the argument is null.
-	_, ok := rawArgs["dryRun"]
+	_, ok := rawArgs["run"]
 	if !ok {
 		var zeroVal bool
 		return zeroVal, nil
 	}
 
-	ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("dryRun"))
-	if tmp, ok := rawArgs["dryRun"]; ok {
+	ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("run"))
+	if tmp, ok := rawArgs["run"]; ok {
 		return ec.unmarshalNBoolean2bool(ctx, tmp)
 	}
 
@@ -2476,7 +2476,7 @@ func (ec *executionContext) _QBitTorrentDaemonMutation_cleanup(ctx context.Conte
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		directive0 := func(rctx context.Context) (interface{}, error) {
 			ctx = rctx // use context from middleware stack in children
-			return ec.resolvers.QBitTorrentDaemonMutation().Cleanup(rctx, obj, fc.Args["dryRun"].(bool))
+			return ec.resolvers.QBitTorrentDaemonMutation().Cleanup(rctx, obj, fc.Args["run"].(bool))
 		}
 
 		directive1 := func(ctx context.Context) (interface{}, error) {
diff --git a/src/delivery/graphql/model/entry.go b/src/delivery/graphql/model/entry.go
index e5f01ee..ef3ffb7 100644
--- a/src/delivery/graphql/model/entry.go
+++ b/src/delivery/graphql/model/entry.go
@@ -3,7 +3,7 @@ package model
 import (
 	"context"
 
-	"git.kmsign.ru/royalcat/tstor/src/daemons/torrent"
+	"git.kmsign.ru/royalcat/tstor/daemons/torrent"
 	"git.kmsign.ru/royalcat/tstor/src/vfs"
 )
 
diff --git a/src/delivery/graphql/model/mappers.go b/src/delivery/graphql/model/mappers.go
index 31de5f9..3152f67 100644
--- a/src/delivery/graphql/model/mappers.go
+++ b/src/delivery/graphql/model/mappers.go
@@ -3,7 +3,7 @@ package model
 import (
 	"context"
 
-	"git.kmsign.ru/royalcat/tstor/src/daemons/torrent"
+	"git.kmsign.ru/royalcat/tstor/daemons/torrent"
 	atorrent "github.com/anacrolix/torrent"
 )
 
diff --git a/src/delivery/graphql/model/models_gen.go b/src/delivery/graphql/model/models_gen.go
index 46b5533..2a5396a 100644
--- a/src/delivery/graphql/model/models_gen.go
+++ b/src/delivery/graphql/model/models_gen.go
@@ -5,7 +5,7 @@ package model
 import (
 	"time"
 
-	"git.kmsign.ru/royalcat/tstor/src/daemons/torrent"
+	"git.kmsign.ru/royalcat/tstor/daemons/torrent"
 	"git.kmsign.ru/royalcat/tstor/src/vfs"
 	torrent1 "github.com/anacrolix/torrent"
 	"github.com/anacrolix/torrent/types"
diff --git a/src/delivery/graphql/resolver/qbittorrent_mutation.resolvers.go b/src/delivery/graphql/resolver/qbittorrent_mutation.resolvers.go
index b80a5a6..bd5efb2 100644
--- a/src/delivery/graphql/resolver/qbittorrent_mutation.resolvers.go
+++ b/src/delivery/graphql/resolver/qbittorrent_mutation.resolvers.go
@@ -12,8 +12,8 @@ import (
 )
 
 // Cleanup is the resolver for the cleanup field.
-func (r *qBitTorrentDaemonMutationResolver) Cleanup(ctx context.Context, obj *model.QBitTorrentDaemonMutation, dryRun bool) (*model.QBitCleanupResponse, error) {
-	hahses, err := r.QBitTorrentDaemon.Cleanup(ctx, dryRun)
+func (r *qBitTorrentDaemonMutationResolver) Cleanup(ctx context.Context, obj *model.QBitTorrentDaemonMutation, run bool) (*model.QBitCleanupResponse, error) {
+	hahses, err := r.QBitTorrentDaemon.Cleanup(ctx, run)
 	if err != nil {
 		return nil, err
 	}
diff --git a/src/delivery/graphql/resolver/resolver.go b/src/delivery/graphql/resolver/resolver.go
index c443a86..d0be310 100644
--- a/src/delivery/graphql/resolver/resolver.go
+++ b/src/delivery/graphql/resolver/resolver.go
@@ -1,8 +1,8 @@
 package resolver
 
 import (
-	"git.kmsign.ru/royalcat/tstor/src/daemons/qbittorrent"
-	"git.kmsign.ru/royalcat/tstor/src/daemons/torrent"
+	"git.kmsign.ru/royalcat/tstor/daemons/qbittorrent"
+	"git.kmsign.ru/royalcat/tstor/daemons/torrent"
 	"git.kmsign.ru/royalcat/tstor/src/vfs"
 	"github.com/go-git/go-billy/v5"
 )
diff --git a/src/delivery/graphql/resolver/torrent_query.resolvers.go b/src/delivery/graphql/resolver/torrent_query.resolvers.go
index 906fefb..084919c 100644
--- a/src/delivery/graphql/resolver/torrent_query.resolvers.go
+++ b/src/delivery/graphql/resolver/torrent_query.resolvers.go
@@ -10,7 +10,7 @@ import (
 	"strings"
 	"time"
 
-	"git.kmsign.ru/royalcat/tstor/src/daemons/torrent"
+	"git.kmsign.ru/royalcat/tstor/daemons/torrent"
 	graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
 	"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
 	tinfohash "github.com/anacrolix/torrent/types/infohash"
diff --git a/src/delivery/http.go b/src/delivery/http.go
index 90cbd08..fc55353 100644
--- a/src/delivery/http.go
+++ b/src/delivery/http.go
@@ -5,10 +5,10 @@ import (
 	"log/slog"
 	"net/http"
 
+	"git.kmsign.ru/royalcat/tstor/daemons/qbittorrent"
+	"git.kmsign.ru/royalcat/tstor/daemons/torrent"
 	"git.kmsign.ru/royalcat/tstor/pkg/rlog"
 	"git.kmsign.ru/royalcat/tstor/src/config"
-	"git.kmsign.ru/royalcat/tstor/src/daemons/qbittorrent"
-	"git.kmsign.ru/royalcat/tstor/src/daemons/torrent"
 	"git.kmsign.ru/royalcat/tstor/src/vfs"
 	echopprof "github.com/labstack/echo-contrib/pprof"
 	"github.com/labstack/echo/v4"
diff --git a/src/delivery/router.go b/src/delivery/router.go
index d274c0f..c03a50e 100644
--- a/src/delivery/router.go
+++ b/src/delivery/router.go
@@ -4,8 +4,8 @@ import (
 	"context"
 	"net/http"
 
-	"git.kmsign.ru/royalcat/tstor/src/daemons/qbittorrent"
-	"git.kmsign.ru/royalcat/tstor/src/daemons/torrent"
+	"git.kmsign.ru/royalcat/tstor/daemons/qbittorrent"
+	"git.kmsign.ru/royalcat/tstor/daemons/torrent"
 	graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
 	"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/resolver"
 	"git.kmsign.ru/royalcat/tstor/src/vfs"
diff --git a/src/vfs/utils.go b/src/vfs/utils.go
index 10c16f4..1b592c6 100644
--- a/src/vfs/utils.go
+++ b/src/vfs/utils.go
@@ -143,8 +143,12 @@ func readdirnames(ctx context.Context, vfs Filesystem, dir string) ([]string, er
 		return nil, err
 	}
 
-	var names []string
+	names := make([]string, 0, len(files))
 	for _, file := range files {
+		if file == nil {
+			continue
+		}
+
 		names = append(names, file.Name())
 	}
 
diff --git a/ui/lib/api/schema.graphql b/ui/lib/api/schema.graphql
index 96c0726..0070d3c 100644
--- a/ui/lib/api/schema.graphql
+++ b/ui/lib/api/schema.graphql
@@ -57,8 +57,12 @@ interface Progress {
 	current: Int!
 	total: Int!
 }
+type QBitCleanupResponse {
+	count: Int!
+	hashes: [String!]!
+}
 type QBitTorrentDaemonMutation {
-	cleanup(dryRun: Boolean!): Int! @resolver
+	cleanup(run: Boolean!): QBitCleanupResponse! @resolver
 }
 type QBitTorrentDaemonQuery {
 	torrents: [QTorrent!]! @resolver