Skip to main content
connic
Build

File Tools

Let agents keep files between runs. Save reports and downloads into folders, find them again by metadata, and pass them to the browser or to other agents.

Last updated

Quick start

Add the file tools to an agent. Agents choose the path when they save a file, and folders appear as soon as a file lands in them. See Files for the data model and limits.

agents/invoice-collector.yaml
version: "1.0"

name: invoice-collector
model: connic/gpt-5.6-luna
description: "Downloads invoices from supplier portals and files them"
system_prompt: |
  Download this month's invoice from the supplier portal and save it
  under invoices/<supplier>/. Mark new invoices with status "new".

tools:
  - web_browser_open
  - web_browser_observe
  - web_browser_act
  - web_browser_download
  - file_list
  - file_update

files:
  folders: [invoices]
  prevent_delete: true

Access control

The files block limits what an agent can see and change. Without it, the agent can use the whole file tree.

  • folders covers each folder and everything below it: invoices includes invoices/2026/acme.pdf. With folders set, files outside them are invisible to the agent.
  • prevent_write blocks file_write and file_update. Moving a file needs write access to both folders.
  • prevent_delete blocks file_delete.
  • session_only shows the agent only files written in its current session, which keeps one end user's files away from another's. It requires session.
  • A folder setting overrides the top-level setting, and the most specific folder wins.
agents/support.yaml
session:
  key: context.customer_id

files:
  session_only: true          # each customer sees only their own uploads
  prevent_delete: true
  folders:
    uploads: {}
    templates:
      session_only: false     # shared by every session
      prevent_write: true

A file an agent cannot see is never replaced. If its path is taken, the new file is saved under a numbered name instead.

Use in custom tools

Custom tools import the same functions from connic.tools. The agent's access control applies to these calls too.

tools/invoices.py
from connic.tools import file_list, file_read, file_update

async def next_pending_invoice() -> dict:
    """Return the oldest invoice that still needs processing."""
    result = await file_list(
        "invoices",
        recursive=True,
        filter={"status": "new", "_mime_type": "application/pdf"},
        sort={"_created_at": 1},
        limit=1,
    )
    if not result["files"]:
        return {"done": True}
    invoice = result["files"][0]
    await file_update(invoice["_path"], metadata={"status": "processing"})
    return invoice

Browser downloads and uploads

The browser tools move files to and from project files. A save_to ending in / is a folder that keeps the downloaded name.

browser.py
# Save a download straight into files (up to 100 MiB)
await web_browser_download("e12", include_content=False, save_to="invoices/acme/")

# Put a stored file into an upload field
await web_browser_upload("e7", path="contracts/signed/acme.pdf")

Tool reference

file_list

List the files and subfolders in a folder, or every file below it. Filters use the database filter operators on custom metadata and on the system fields _name, _path, _folder, _mime_type, _size, _source, _agent, _run_id, _session_id, _created_at, and _updated_at.

list.py
result = await file_list("invoices/2026")
# {"folder": "invoices/2026", "folders": ["acme"], "files": [...], "count": 3, "total": 3}

# Everything this session wrote, anywhere in the tree
result = await file_list(recursive=True, scope="session")
ParameterTypeDefaultDescription
folderstr""Folder to list. Empty for the root.
recursiveboolFalseReturn every file below the folder instead of listing subfolders.
filterdictNoneMetadata filter.
scopestr"all""session" or "run" keeps only files written in the current session or run.
sortdict{"_name": 1}Sort order. 1 ascending, -1 descending.
limitint100Maximum files to return, up to 1000.
skipint0Files to skip for pagination.

file_read

Read a file. The model gets the full text of text files, and PDFs and images as an attachment it can read, for files up to 20 MiB. Other formats and larger files return the metadata and an error; pass their path to the browser or a custom tool instead. In custom tools, file_read returns the raw bytes of any file as content.

read.py
# In a custom tool
result = await file_read("reports/summary.md")
# {"file": {"_path": "reports/summary.md", ...}, "content": b"# Summary ..."}
text = result["content"].decode("utf-8")
ParameterTypeDefaultDescription
pathstrrequiredFile path.

file_write

Write a text file. Missing folders are created. Returns the stored file, including its final _path. In custom tools, content can also be bytes, for binary files such as PDFs or images.

write.py
result = await file_write(
    "reports/2026-10/summary.md",
    "# October summary\n...",
    metadata={"status": "draft", "customer": "acme"},
)
# result["_path"] is the stored path, e.g. "reports/2026-10/summary (2).md" if the name was taken
ParameterTypeDefaultDescription
pathstrrequiredFile path.
contentstr | bytesrequiredText content. Bytes only in custom tools.
mime_typestrNoneContent type. Guessed from the file name if omitted.
metadatadictNoneCustom fields. Keys must not start with an underscore.
overwriteboolFalseReplace an existing file at the path. Otherwise the new file gets a numbered name.

file_update

Move or rename a file or a folder, or merge metadata into a file. A None value removes a metadata field. Moving onto a path that is taken fails.

update.py
# Rename a file and mark it processed
await file_update("inbox/acme.pdf", new_path="done/acme.pdf", metadata={"status": "processed"})

# Move a whole folder
await file_update("inbox/2026-09", new_path="archive/2026-09")
ParameterTypeDefaultDescription
pathstrrequiredPath of the file or folder.
new_pathstrNoneNew path. Moving a folder moves everything in it.
metadatadictNoneFields to merge into a file's metadata.

file_delete

Delete a file, or a folder and everything in it. Returns the number of deleted files.

delete.py
await file_delete("tmp/scratch.txt")
await file_delete("tmp", recursive=True)
ParameterTypeDefaultDescription
pathstrrequiredPath of the file or folder.
recursiveboolFalseRequired to delete a folder.