Files is the workspace file store. Anything an agent reads or writes — uploaded documents, generated reports, sandbox-produced assets — lives here. One row per file in workspace_files; the bytes live in object storage and are served through /api/files/serve/... with workspace-scoped permissions.
What a file row stores
The workspace_files table:
| Column | Notes |
|---|---|
key | Object-storage key. Globally unique among non-deleted rows. |
originalName | The display name. Unique per workspace among context = 'workspace' rows. |
contentType | Mime type (used by the file picker + previews). |
size | Bytes. |
context | The bucket the file belongs to. See contexts below. |
chatId | Set when the file was uploaded into an Assistant chat. |
userId, workspaceId | Owner + scope. |
deletedAt | Soft-delete timestamp. |
uploadedAt | Insert time. |
Contexts
Each file is tagged with a context so different surfaces don't trample each other. The valid contexts:
| Context | Source |
|---|---|
workspace | The Files module — files explicitly placed in the workspace store. |
chat | Files attached to an Assistant chat (also tracked separately in assistantChatBagFiles). |
copilot | Legacy. The schema enum still includes the old copilot/mothership strings for backward compatibility but new uploads go through chat. See the Assistant page for naming history. |
knowledge-base | Files indexed by the (currently hidden) Knowledge Base module. |
execution | Files produced by a workflow run — workflow-bag and persistent-files writebacks. |
profile-pictures | User and workspace avatars. |
general | Catch-all for files that don't belong elsewhere. |
The context is set at upload time by the route that owns the upload — see Files › Uploads.
Lifecycle
Files are soft-deleted. deletedAt is set rather than the row being removed; storage objects can be reaped by a background job after a grace period. Two uniqueness rules are enforced only against active (non-deleted) rows:
- One active file per
keyglobally. - One active
originalNameper(workspaceId, context = 'workspace'). Re-uploading a name that already exists fails until the existing row is soft-deleted or renamed.
How blocks reach files
Workflow blocks pass files around as UserFile objects — a small JSON shape with name, key, context, optional path/url, plus metadata. The File block, Save File block, and any integration block that handles uploads accepts this shape. See Files › References.
Tables hold structured data; Files hold unstructured blobs. If you need to filter or query the contents, store metadata in a Table and reference the file via its key.
Source
packages/db/schema.ts—workspace_filesapps/actana/lib/uploads/utils/file-utils.ts—UserFileshape,inferContextFromKeyapps/actana/lib/uploads/utils/file-utils.server.ts—downloadFileFromStorageapps/actana/app/api/files/— upload, serve, presign routes