Technical docs

Storage

Overview

Support reference for the org Storage page (`/storage`) and the org storage APIs behind it.

For the organization private API surface under `/api/private`, see `private-api.md`.

What users can do in `/storage`

  • Browse folders with URL-backed navigation via `?path=...`.
  • Switch between list and grid views.
  • Search the current folder, sort, hide/show columns, and filter by file type and modified date.
  • Select multiple items and bulk delete.
  • Create folders.
  • Upload by file picker, drag-and-drop, or folder upload.
  • Download files.
  • Copy file or folder paths.
  • Share folders with AI teammates.
  • Open non-folder items in the visible `Docs` workspace via `/docs?path=...`.

Current file actions in the UI

  • Files: `Download`, `Copy Path`, `Delete`.
  • Folders: `Share`, `Copy Path`, `Delete`.
  • The Storage UI does not currently expose rename, copy, or move actions, even though org APIs exist for them.
  • The code still contains an unused details panel, but `/storage` does not currently expose a working details action.

Upload rules

  • Current `/storage` UI validation allows: `png`, `jpg`, `jpeg`, `gif`, `webp`, `svg`, `pdf`, `doc`, `docx`, `xls`, `xlsx`, `pptx`, `txt`, `htm`, `html`, `md`, `csv`, `json`, `yaml`, `yml`.
  • Backend upload policy used by org/private storage APIs and storage-backed tool outputs also accepts those Office formats plus additional text and code formats: `tsv`, `ts`, `tsx`, `js`, `jsx`, `py`, `sql`, `css`, `scss`, `sh`, `log`, `xml`, `toml`, `ini`.
  • Max upload size: `10 MB` per file.
  • In the `/storage` UI, individual files cannot be uploaded to root (`/`).
  • The org and private upload APIs still allow root uploads when `path` is omitted.
  • Root-level folder uploads are allowed.
  • Duplicate handling offers `Skip existing` and `Replace`.
  • When a folder upload contains unreadable local file or folder entries, readable siblings can still upload. The unreadable entries remain in the upload queue as non-retryable error rows with an `Unable to read this file/folder...` message.
  • Upload UI supports pause, resume, retry, cancel, and persistent progress.

Sharing behavior

  • Only folders can be shared.
  • Root (`/`) cannot be shared.
  • Sharing uses a dedicated dialog with AI teammates in the org, but Ally is not presented as a normal editable row there.
  • The dialog always shows an `Ally` row with both `Read` and `Write` checked and disabled.
  • The dialog text for Ally says `Full storage access is automatic.`
  • Ally is the only special system-backed teammate in this share list.
  • Permissions are `read` and `write`.
  • In the current dialog, enabling `write` also enables `read`.
  • If `write` is removed, `read` remains checked unless it is inherited from a parent share.
  • `read` is disabled when it is inherited or when `write` is checked, so the dialog never allows write-only access.
  • Parent-folder permissions appear as inherited (`from_parent: true`) and cannot be toggled from the child folder.
  • When a shared folder is renamed or moved, direct share records for that folder follow the new path.
  • Share records for nested folders under the renamed or moved folder are updated to the matching nested path under the new location.
  • After a move, parent-folder shares at the destination also apply through normal inherited permissions.
  • Deleting a folder or file path removes matching share records for that path and nested paths.

Indexing and search

  • Storage rows can show indexing states: `Indexed`, `Queued for indexing`, `Indexing…`, `Indexing failed`, `Not indexable`.
  • Vector indexing currently supports `.txt`, `.md`, `.docx`, `.pdf`, and `.pptx`.
  • Exact storage search is broader and can extract text from formats such as `docx`, `xlsx`, `pptx`, and `pdf`.
  • Valid uploads can still show `Not indexable`.
  • Vector embeddings are generated through the configured embedding provider. Current backend code supports OpenAI by default and Polza when configured.

Spreadsheet extraction

  • CSV and XLSX attachments can be converted into bounded text previews and row-range results for chat and agent workflows.
  • XLSX sheet indexes are one-based. The first worksheet has `index: 1`, and index-based selection uses the same one-based values.
  • Row numbers are also absolute and one-based. Sparse worksheets keep their original positions, so a populated row at a high Excel row number is returned with that row number rather than being compacted.
  • XLSX preflight rejects invalid ZIP containers, missing workbook or worksheet XML, excessive entry counts, and XML content above configured extraction limits.
  • If a workbook from a third-party generator cannot be loaded directly, extraction retries after removing text-irrelevant drawing, comment, table, and data-validation parts and normalizing prefixed SpreadsheetML namespaces. Cell values, shared strings, styles, and worksheet row positions remain available to the parser.

Org API routes

  • `GET /api/organizations/{orgId}/storage?path=...`
  • `GET /api/organizations/{orgId}/storage/stats?path=...`
  • `POST /api/organizations/{orgId}/storage/upload`
  • `GET /api/organizations/{orgId}/storage/download?path=...`
  • `DELETE /api/organizations/{orgId}/storage/file?path=...`
  • `POST /api/organizations/{orgId}/storage/folder`
  • `POST /api/organizations/{orgId}/storage/folder/rename`
  • `POST /api/organizations/{orgId}/storage/folder/copy`
  • `POST /api/organizations/{orgId}/storage/folder/move`
  • `GET /api/organizations/{orgId}/storage/file/content?path=...`
  • `PUT /api/organizations/{orgId}/storage/file/content`
  • `GET /api/organizations/{orgId}/storage/folder/share?path=...`
  • `POST /api/organizations/{orgId}/storage/folder/share`
  • `DELETE /api/organizations/{orgId}/storage/folder/share`

Docs edit endpoints

  • `GET/PUT /storage/file/content` only allow existing `.txt` and `.md` files.
  • Upload is capped at `10 MB` by the API upload route. The Docs content route is existing-file only; current code does not show a separate content-endpoint size rule beyond file handling in the caller.

AI teammate storage permissions

  • Non-system AI teammates are still limited to folders explicitly shared with them.
  • `storage.list` returns only content inside shared folders for non-system AI teammates.
  • `storage.semantic_search` searches indexed documents inside readable shared folders for non-system AI teammates.
  • `storage.search`, `storage.read_file`, `storage.read_image`, and `storage.stat_file` require readable shared-folder access for non-system AI teammates.
  • `storage.read_file` currently supports `.txt`, `.md`, `.json`, `.yaml`, `.yml`, `.htm`, `.html`, `.csv`, `.tsv`, `.ts`, `.tsx`, `.js`, `.jsx`, `.py`, `.sql`, `.css`, `.scss`, `.sh`, `.log`, `.xml`, `.toml`, `.ini`, `.docx`, and text-layer `.pdf`.
  • `storage.get_temp_file_url` also requires readable shared-folder access for non-system AI teammates.
  • `storage.write_file` and `storage.edit_file` require writable shared-folder access for non-system AI teammates.
  • `storage.write_file` and `storage.edit_file` support `.txt`, `.md`, `.htm`, `.html`, `.csv`, `.tsv`, `.json`, `.yaml`, `.yml`, `.ts`, `.tsx`, `.js`, `.jsx`, `.py`, `.sql`, `.css`, `.scss`, `.sh`, `.log`, `.xml`, `.toml`, and `.ini`.
  • `storage.rename` requires the target path to be inside a writable shared folder for non-system AI teammates.
  • `storage.copy` requires readable source access and writable destination access for non-system AI teammates.
  • `storage.move` requires writable access to both source and destination for non-system AI teammates.
  • `storage.get_temp_file_url` returns a temporary HTTPS link for a readable file and is meant for downstream tool calls or external systems that need a URL instead of inline bytes.
  • Do not show temporary file URLs to end users; they are short-lived bearer-style links for tool-to-tool handoff.
  • Current temporary-link format is `{API_DOMAIN}/shared/files/{organization_id}/{run_id}/{document_id}`.
  • The temporary link only works while the workflow run that created it is still active; once the run completes or is aborted, the link expires.
  • Prefer `storage.read_file` when the agent only needs supported text, `storage.read_image` when the model should inspect an image, or `programming.run_code` with `storage_mounts` when the file should be processed inside a sandbox.
  • `storage.get_temp_file_url` currently returns `File not found` when the file does not yet have an `OrganizationDocument` record.
  • Ally uses system-level storage access.

Realtime behavior

  • The backend emits `storage_file.created`, `storage_file.updated`, `storage_file.deleted`, `storage_file.renamed`, `storage_file.copied`, and `storage_file.moved`.
  • The current Storage file-list hook auto-refreshes on all six events.
  • Docs document state also listens to rename and move events so an open document can follow its new path.

Private storage API (HTTPS)

  • The canonical private API reference now lives in `private-api.md`.
  • Private storage routes are under `{api_url}/api/private/storage`.
  • Current auth is `api-key: <TOKEN>` only.

Start building your AI team