TwinDocs
Use your Twin

Add documents, sheets, files, and sessions

Create or reuse channel content in the app, CLI, API, SDK, or MCP without asking an agent to generate it.

You can write a document, build a sheet, or upload an ordinary file directly. An MLX agent does not need to generate it. The same content can be referenced from a Channel or a Data Set record.

Add content in a Channel

Open a Channel and choose Add:

  • Document creates an editable text artifact.
  • Sheet creates an editable CSV sheet.
  • Upload files uploads files from your computer.
  • Add existing… finds an accessible artifact, file, or session to attach.
  • Start session opens a new conversation with the Channel as its context.

Documents and sheets are artifacts with versions. Uploads retain their original file format. Use a sheet for an editable grid, or upload a spreadsheet when you want to preserve the original workbook.

Removing an existing item from a Channel removes that attachment. It does not delete the original content. Content belonging to the Channel itself, or shown through session activity, can have other reasons to remain visible.

Use content in a record field

Add a field to a Data Set and choose File, Artifact (document or sheet), or Session. The field stores the existing resource's ID and displays a link you can open. You can choose an existing item, or create content from the field picker. Clearing the field removes its value; it does not delete the resource.

A Session field points to a conversation. Selecting one does not start a run. A field reference does not grant access to its resource: people opening the record must also have access to the file, artifact, or session.

For records projected from a connected source, new content is placed in the known Channel and its ID is saved in the editable record field. The separate record attachment API accepts stored workspace record IDs; a source-system row ID alone does not identify a workspace attachment destination.

Use the CLI

Install and sign in to the CLI, then use the same commands from your terminal or a local coding assistant:

twin login

# Create a document or sheet directly from local content.
twin artifacts --kind markdown --title "Project brief" \
  --file brief.md --channel operations --allow-write
twin artifacts --kind csv --title "Delivery plan" \
  --file plan.csv --channel operations --allow-write

# Upload original bytes and place the file in the Channel.
twin files --upload proposal.pdf --channel operations --allow-write

# Find existing content and download an uploaded file.
twin files --q proposal --json
twin artifacts --channel operations --json
twin sessions --json
twin files --file FILE_ID --download proposal-copy.pdf

# Attach existing resources without copying them.
twin files --file FILE_ID --attach --channel operations --allow-write
twin artifacts --artifact ARTIFACT_ID --attach --channel operations --allow-write
twin sessions --session SESSION_ID --attach --channel operations --allow-write

# Remove one attachment without deleting the original.
twin files --file FILE_ID --detach --channel operations --allow-write
twin artifacts --artifact ARTIFACT_ID --detach --channel operations --allow-write
twin sessions --session SESSION_ID --detach --channel operations --allow-write

File attachment also accepts --session SESSION_ID or --record RECORD_ID in place of --channel. Artifact attachment accepts --record RECORD_ID. A Session field is set through the record API; session attachment targets Channels.

Use twin help files, twin help artifacts, or twin help sessions for all options. Writes require --allow-write. Downloading to an existing local path fails instead of overwriting it.

Use the HTTP API or TypeScript SDK

Public clients use the Twin gateway with their OAuth bearer token or signed MLX subject token. Reads require twin.read; changes require twin.write and the user's normal resource permissions.

The upload endpoint accepts real multipart file bytes, up to 50 MiB or the lower limit configured by your organisation. Let your HTTP client generate the multipart boundary:

curl "$TWIN_GATEWAY/api/twin/files" \
  -H "Authorization: Bearer $TWIN_ACCESS_TOKEN" \
  -F "file=@proposal.pdf" \
  -F "channelId=CHANNEL_ID"

The response contains file.id. Use that ID to retrieve metadata at GET /api/twin/files/FILE_ID, download bytes at GET /api/twin/files/FILE_ID/content, or attach it elsewhere:

POST /api/twin/files/FILE_ID/links
Content-Type: application/json
Authorization: Bearer <access-token>

{"targetType":"record","targetId":"RECORD_ID"}

Use DELETE at the same path with the same body to detach. Artifact references use /api/twin/artifacts/ARTIFACT_ID/links and accept channel or record. Session sharing uses /api/twin/sessions/SESSION_ID/channels with {"channelId":"CHANNEL_ID"}. Artifact and session attachment responses contain attached; their removal responses contain detached. false means the requested state already held. File attachment and removal return the updated file with its current links.

The handwritten TypeScript SDK exposes the same operations:

import { SDK } from "@mercury-labs/mlx-agent-sdk";

const sdk = new SDK({
  serverURL: process.env.TWIN_GATEWAY,
  bearerToken: process.env.TWIN_ACCESS_TOKEN,
});

const { file } = await sdk.twin.uploadTwinFile({
  file: new File(["Draft brief"], "brief.txt", { type: "text/plain" }),
  channelId: "CHANNEL_ID",
});
await sdk.twin.attachTwinFile({
  fileId: file.id, targetType: "record", targetId: "RECORD_ID",
});
await sdk.twin.attachTwinArtifact({
  artifactId: "ARTIFACT_ID", targetType: "channel", targetId: "CHANNEL_ID",
});
await sdk.twin.attachTwinSession({ sessionId: "SESSION_ID", channelId: "CHANNEL_ID" });

Create documents and sheets with sdk.twin.createTwinArtifact, using kind: "markdown" or kind: "csv", title, content, an idempotencyKey, and an optional channelId. Updating an artifact requires its expectedVersionId to avoid replacing someone else's newer version.

Use MCP

Connected MCP clients have the same resource operations:

ActionMCP tools
Find or inspect filestwin_files_list, twin_file_get
Upload a small filetwin_file_upload
Prepare a larger uploadtwin_file_upload_prepare
Read a filetwin_file_content
Attach or detach a filetwin_file_attach, twin_file_detach
Create or edit an artifacttwin_artifact_create, twin_artifact_update
Attach or detach an artifacttwin_artifact_attach, twin_artifact_detach
Share or unshare a sessiontwin_session_attach, twin_session_detach

twin_file_upload accepts a filename, content type, and base64 content with a maximum decoded size of 32 KiB. It performs the upload and returns the saved file. For example:

{"fileName":"note.txt","contentType":"text/plain","contentBase64":"SGVsbG8=","channelId":"CHANNEL_ID"}

For a larger file, call twin_file_upload_prepare with its placement, such as {"channelId":"CHANNEL_ID"}. It returns uploadUrl, method, fileField, fields, maxBytes, and authentication instructions. This response says uploaded: false: preparation has not uploaded a file. The client must then send the actual multipart request with the same authenticated authority and check the upload response. An MCP client that cannot send authenticated HTTP uploads needs the CLI or another HTTP client for files larger than 32 KiB.

Understand access when adding existing content

ResourceWhat adding it to a Channel does
FileGrants access through the destination. Only its creator or an organisation admin can change its attachments.
ArtifactAdds a reference to the same artifact and versions. Its original access rules remain in force.
SessionExplicitly grants current Channel readers access to the conversation. Only the session owner or an organisation admin can share it.

Session sharing does not transfer ownership, grant permission to send messages or start runs, or share its task, artifacts, or files. Those keep their own access rules. Removing the explicit session attachment revokes that grant; independent access and actual Channel activity remain. An agent merely reading or writing a Channel does not create a session sharing grant.

On this page