Skill: dbalve/fast-io (version 1.233.0)

--- name: fast-io description: >- Workspaces for agentic teams. Complete agent guide with all 19 consolidated tools using action-based routing — parameters, workflows, ID formats, and constraints. Use this skill when agents need shared workspaces to collaborate with other agents and humans, create branded shares (Send/Receive/Exchange), or query documents using built-in AI. Supports ownership transfer to humans, workspace management, workflow primitives (tasks, worklogs, approvals, todos), and real-time collaboration. Free agent plan with 50 GB storage and 5,000 monthly credits. license: Proprietary compatibility: >- Requires network access. Connects to the Fast.io MCP server at mcp.fast.io via Streamable HTTP (/mcp) or SSE (/sse). metadata: author: fast-io version: "1.223.0" homepage: "https://fast.io" --- # Fast.io MCP Server -- AI Agent Guide **Version:** 1.223 **Last Updated:** 2026-05-22 The definitive guide for AI agents using the Fast.io MCP server. Covers why and how to use the platform: product capabilities, the free agent plan, authentication, core concepts (workspaces, shares, intelligence, previews, comments, URL import, metadata, workflow, ownership transfer), 12 end-to-end workflows, interactive MCP App widgets, and all 19 consolidated tools with action-based routing. > **Versioned guide.** This guide is versioned and updated with each server release. The version number at the top of this document tracks tool parameters, ID formats, and API behavior changes. If you encounter unexpected errors, the guide version may have changed since you last read it. > **Recent parameter changes (v2026.05.22 → v2026.05.23):** > - **`event` tool:** the `created-min` / `created-max` filter names were renamed to `created_min` / `created_max` (snake_case). The old hyphenated names are silently migrated to the new names by the server — existing agents continue to work. New agents should use snake_case directly. > - **`apps.extra_params`, `approval.properties`, `execute.body`, `execute.params`:** these free-form JSON parameters are now published as `{type: "string"}` in the tool schema (to satisfy strict-mode validators in OpenAI Apps SDK / Gemini API). The server still accepts either a native JSON object/array (auto-stringified) OR a pre-stringified JSON string at runtime — you can keep sending native objects from Claude Desktop and they will be auto-converted. > - **`/file/workspace|share` pass-through:** now accepts either `Mcp-Session-Id` (existing path) OR `Authorization: Bearer` (new — unblocks OAuth-only clients streaming large files without first establishing an MCP tool-auth session). Fresh Bearer tokens are used even when the DO session has a stale or expired session-stored token. > - **New `resource://status` MCP resource (v2026.05.24):** lightweight server-status resource alongside the existing `session://status` and `skill://guide` resources. Returns `{name, version, environment, transports, mcp_protocol_versions_supported, time, documentation}` — no auth, no session state. Added so MCP host UIs (ChatGPT Apps SDK in particular) that probe a well-known status URI can display server health without spending a tool call. For session-bound state continue using `session://status` (the resource) or `auth action=status` (the tool). > **Platform reference.** For a comprehensive overview of Fast.io's capabilities, the agent plan, key workflows, and upgrade paths, see [references/REFERENCE.md](references/REFERENCE.md). > **ID parameter taxonomy.** Four canonical ID parameter names appear across tools — they are intentionally distinct, not interchangeable. Pick the one that matches the operation's domain: > > - **`workspace_id`** — workspace opaque ID. Use when only workspaces are valid (not shares or other contexts). Example: `events action workspace-stream workspace_id="..."`. > - **`profile_id`** — polymorphic context ID. Pair with `profile_type` = `workspace` | `share` | `org`. Use instead of `workspace_id` when the operation also accepts shares. Example: `storage action list profile_type="share" profile_id="..." node_id="root"`. > - **`entity_id`** — opaque ID of a specific object (file, comment, worklog entry, etc.). Pair with `entity_type` to disambiguate. Example: `worklog action list entity_type="task" entity_id="..."`. > - **`node_id`** — storage tree node opaque ID. Both files and folders are nodes — use this name regardless of which. Example: `storage action details profile_type="workspace" profile_id="..." node_id="..."`. --- ## 1. Overview **Workspaces for Agentic Teams. Collaborate, share, and query with AI -- all through one API, free.** Fast.io provides workspaces for agentic teams -- where agents collaborate with other agents and with humans. Upload outputs, create branded shares, ask questions about documents using built-in AI, and hand everything off to a human when the job is done. No infrastructure to manage, no subscriptions to set up, no credit card required. ### The Problem Fast.io Solves Agentic teams -- groups of agents working together and with humans -- need a shared place to work. Today, agents cobble together S3 buckets, presigned URLs, email attachments, and custom download pages. Every agent reinvents collaboration, and there is no shared workspace where agents and humans can see the same files, track activity, and hand off work. When agents need to *understand* documents -- not just store them -- they have to download files, parse dozens of formats, build search indexes, and manage their own RAG pipeline. That is a lot of infrastructure for what should be a simple question: "What does this document say?" | Problem | Fast.io Solution | |---------|-----------------| | No shared workspace for agentic teams | Workspaces where agents and humans collaborate with file preview, versioning, and AI | | Agent-to-agent coordination lacks structure | Shared workspaces with activity feeds, comments, and real-time sync across team members | | Sharing outputs with humans is awkward | Purpose-built shares (Send, Receive, Exchange) with link sharing, passwords, expiration | | Collecting files from humans is harder | Receive shares let humans upload directly to your workspace -- no email attachments | | Understanding document contents | Built-in AI reads, summarizes, and answers questions about your files | | Building a RAG pipeline from scratch | Enable intelligence on a workspace and documents are automatically indexed, summarized, and queryable | | Finding the right file in a large collection | Storage search finds documents by keyword or meaning (semantic search when intelligence is enabled) | | Handing a project off to a human | One-click ownership transfer -- human gets the org, agent keeps admin access | | Tracking what happened | Full audit trail with AI-powered activity summaries | | Cost | Free. 50 GB storage, 5,000 monthly credits, no credit card | ### MCP Server This MCP server exposes 19 consolidated tools that cover the full Fast.io REST API surface. Every authenticated API endpoint has a corresponding tool action, and the server handles session management automatically. **All API access goes through the MCP tools.** Do not make direct HTTP calls to `api.fast.io` or the MCP server -- the tools handle authentication, session management, error recovery, and response formatting automatically. The only exceptions are binary transfers: `POST /blob` on the MCP server for uploads (the tool provides the curl command), download URLs returned by tools (which are pre-authenticated), and `GET /file/` pass-through endpoints on the MCP server for large file streaming. Everything else must use the tools. Once a user authenticates, the auth token is stored in the server session and automatically attached to all subsequent API calls. There is no need to pass tokens between tool invocations. ### Server Endpoints - **Production:** `mcp.fast.io` - **Development:** `mcp.fastdev1.com` Two transports are available on each: - **Streamable HTTP at `/mcp`** -- the preferred transport for new integrations. - **SSE at `/sse`** -- a legacy transport maintained for backward compatibility. ### MCP Resources The server exposes static MCP resources, widget resources, and file download resource templates. Clients can read them via `resources/list` and `resources/read`: | URI | Name | Description | MIME Type | |-----|------|-------------|-----------| | `skill://guide` | skill-guide | Full agent guide (this document) with all 19 tools, workflows, and platform documentation | `text/markdown` | | `session://status` | session-status | Current authentication state: `authenticated` boolean, `user_id`, `user_email`, `auth_method` (`"api_key"`, `"jwt"`, or `"oauth"` -- how the session was authenticated), `token_expires_at` (Unix epoch), `token_expires_at_iso` (ISO 8601), `scopes` (raw scope string or null), `scopes_detail` (array of hydrated scope objects with entity names/domains/parents, or null), `agent_name` (string or null) | `application/json` | | `resource://status` | server-status | Lightweight server health: `name`, `version`, `status`, `environment`, `transports` (`/mcp`, `/sse`), `mcp_protocol_versions_supported`, `time` (ISO 8601), `documentation` (skill guide + API + platform links). No auth required, no session state — for host UIs that probe a well-known status URI. For session-bound state use `session://status` or `auth` action `status`. | `application/json` | | `ui://fastio/*` | Widget HTML | Interactive HTML5 widgets (6 total) -- use the `apps` tool to discover and launch | `text/html` | **File download resource templates** -- read file content directly through MCP without needing external HTTP access: | URI Template | Name | Auth | Dynamic Listing | Description | |---|---|---|---|---| | `download://workspace/{workspace_id}/{node_id}` | download-workspace-file | Session token | Yes | Download a file from a workspace | | `download://share/{share_id}/{node_id}` | download-share-file | Session token | Yes | Download a file from a share | | `download://quickshare/{quickshare_id}` | download-quickshare-file | None (public) | No | Download a quickshare file | Files up to 50 MB are returned inline as base64-encoded blob content. Larger files return a text fallback with a URL to the HTTP pass-through endpoint (see below). The `download` tool responses include a `resource_uri` field with the appropriate URI for each file. **Dynamic resource listing:** When authenticated, workspace and share file resources are dynamically listed via `resources/list`. MCP clients (such as Claude Desktop's `@` mention picker) can discover available files without any tool calls. Up to 10 workspaces and 10 shares are enumerated, with up to 25 most recently updated root-level files from each. Resources appear as "WorkspaceName / filename.ext" or "ShareTitle / filename.ext". Results are cached for 1 minute per session. Only root-level files are listed -- subdirectories are not recursively enumerated. Use the `storage` tool with action `list` to browse deeper. The quickshare template remains template-only and is not dynamically enumerable. ### MCP Prompts The server registers MCP prompts that appear in the client's "Add From" / "+" menu as user-clickable app launchers. These are primarily for desktop MCP clients (e.g., Claude Desktop); code-mode clients (Claude Code, Cursor) do not surface prompts. | Prompt Name | Description | |---|---| | `App: Choose Workspace or Org` | Launch the Workspace Picker to browse orgs, select workspaces, and manage shares | | `App: Pick a File` | Launch the File Picker with built-in workspace navigator for browsing, searching, and selecting files | | `App: Open Workflow` | Launch the Workflow Manager (auto-selects workspace if only one, otherwise opens Workspace Picker first) | | `App: Upload Files` | Launch the Uploader to upload files with drag-and-drop, progress tracking, and text file creation | | `App: Available Apps` | List all available MCP App widgets with descriptions and launch instructions | ### HTTP File Pass-Through For files larger than 50 MB or when raw binary streaming is needed, the server provides an HTTP pass-through endpoint that streams file content directly from the API: | Endpoint | Auth | Description | |---|---|---| | `GET /file/workspace/{workspace_id}/{node_id}` | `Mcp-Session-Id` header | Stream a workspace file | | `GET /file/share/{share_id}/{node_id}` | `Mcp-Session-Id` header | Stream a share file | | `GET /file/quickshare/{quickshare_id}` | None (public) | Stream a quickshare file | The response includes proper `Content-Type`, `Content-Length`, and `Content-Disposition` headers from the upstream API. Errors are returned as HTML pages. The `Mcp-Session-Id` header is the same session identifier used for MCP protocol communication. ### Workflow Overview The server includes workflow features for project tracking: **tasks** (structured work items with priorities and assignees), **worklogs** (append-only activity logs), **approvals** (formal sign-off requests — see **Workflow Approvals -- Quick Start** below), and **todos** (simple checklists). Enable workflow on a workspace with `workspace` action `enable-workflow` before using these tools. See the **Full Agent Workflow** recipe in section 6 for the complete pattern. **Best practice (IMPORTANT):** After state-changing actions (uploading files, creating shares, changing task status, member changes, file moves/deletes), append a worklog entry describing what you did and why. Without worklog entries, agent work is invisible to humans reviewing the workspace. For multiple related actions (e.g., uploading several files), you may log once after the batch completes rather than after each individual action. Worklog entries are append-only and permanent. ### Additional References - **Agent guide (this file):** `/skill.md` on the MCP server -- tool documentation, workflows, and constraints. - **REST API reference:** `https://api.fast.io/llms.txt` -- endpoint documentation for the underlying REST API (reference only -- use the MCP tools, not direct HTTP calls). - **Platform guide:** [references/REFERENCE.md](references/REFERENCE.md) -- capabilities, agent plan details, key workflows, and upgrade paths. --- ## 2. Authentication (Critical First Step) Authentication is required before calling any tool except these unauthenticated tools: - `auth` with actions: `signin`, `signup`, `set-api-key`, `pkce-login`, `email-check`, `password-reset-request`, `password-reset` - `download` with action: `quickshare-details` ### Choosing the Right Approach There are three ways to use Fast.io as an agent, depending on whether you are operating autonomously or assisting an existing human user. **Option 1: Autonomous Agent -- Create an Agent Account** If you are operating independently (storing files, running workflows, building workspaces for users), create your own agent account with `auth` action `signup`. Agent accounts get the free agent plan (50 GB, 5,000 monthly credits) and can transfer orgs to humans when ready. This is the recommended path for autonomous agents. See **Agent Account Creation** below for steps. **Option 2: Assisting a Human -- Use Their API Key** If a human already has a Fast.io account and wants your help managing their files, workspaces, or shares, they can create an API key for you to use. No separate agent account is needed -- you operate as the human user. The human creates a key at Settings -> Devices & Agents -> API Keys (direct link: `https://go.fast.io/settings/api-keys`). Call `auth` with action `set-api-key` and the key to authenticate -- the key is validated and stored in the MCP session automatically. All subsequent tool calls use it. By default, API keys have the same permissions as the account owner. Keys can optionally be **scoped** to specific organizations, workspaces, or shares (using the same scope system as OAuth tokens) -- scoped keys can only access the granted entities, and operations outside the scope return 403. Keys can also be tagged with an `agent_name` for tracking and given an expiration date. Unscoped keys do not expire unless revoked. Agents can also manage API keys programmatically with `auth` actions `api-key-create`, `api-key-update`, `api-key-list`, `api-key-get`, and `api-key-delete`. **Option 3: Agent Account Invited to a Human's Org** If you want your own agent identity but need to work within a human's existing organization, create an agent account with `auth` action `signup`, then have the human invite you to their org with `member` action `add` (entity_type `org`) or to a workspace with `member` action `add` (entity_type `workspace`). Alternatively the human can invite via the UI: Settings -> Your Organization -> Manage People. This gives you access to their workspaces and shares while keeping your own account separate. After accepting invitations with `user` action `accept-all-invitations`, use `auth` action `signin` to authenticate normally. **Note:** If the human only invites you to a workspace (not the org), the org will appear as external -- see **Internal vs External Orgs** in the Organizations section. **Option 4: Browser Login (PKCE)** **Not for headless agents:** PKCE requires a human with a browser present in the conversation. Headless agents, CLI tools, and automated pipelines cannot complete this flow — use Option 1 (signup) or Option 2 (API key) instead. If you prefer not to send a password through the agent, use browser-based PKCE login. Call `auth` action `pkce-login` (optionally with an `email` hint) to get a login URL. The user opens the URL in a browser, signs in (email/password or SSO like Google/Microsoft), and approves access. The browser displays an authorization code which the user copies back to the agent. Call `auth` action `pkce-complete` with the code to finish signing in. This is the most secure option -- no credentials pass through the agent. PKCE login supports optional **scoped access** via the `scope_type` parameter. By default, `scope_type` is `"user"` (full account access). Other scope types restrict the token to specific entity types: | scope_type | Access granted | |------------|---------------| | `user` | Full account access (default) | | `org` | User selects specific organizations | | `workspace` | User selects specific workspaces | | `all_orgs` | All organizations the user belongs to | | `all_workspaces` | All workspaces the user has access to | | `all_shares` | All shares the user is a member of (`share:*:<mode>`) | **Scope inheritance:** Broader scopes include access to child entities automatically: - `all_orgs` includes all orgs + all workspaces + all shares within those orgs - `all_workspaces` includes all workspaces + all shares within those workspaces - `org` scope on a specific org includes access to all workspaces and shares within that org - `workspace` scope on a specific workspace includes access to shares within that workspace - `all_shares` grants direct access to all shares the user has membership in, bypassing workspace/org inheritance The `agent_name` parameter controls what the user sees on the approval screen -- the screen displays "**[agent_name]** will act on your behalf". If omitted, only the client name is shown. Use a descriptive name so the user knows which agent is requesting access. **Approval flow by scope_type:** - **`user`** (default): Full account access. The user sees a simple approve/decline prompt with no entity picker. - **`org`**, **`workspace`**: The user sees an entity selection screen listing their accessible entities with checkboxes, plus a read-only / read-write toggle. The user picks which entities to grant, then approves or declines. - **`all_orgs`**, **`all_workspaces`**, **`all_shares`**: The user sees a summary of the wildcard access being requested (no entity picker), then approves or declines. The MCP server defaults to `scope_type="user"` for backward compatibility. | Scenario | Recommended Approach | |----------|---------------------| | Operating autonomously, storing files, building for users | Create an agent account with your own org (Option 1) | | Helping a human manage their existing account | Ask the human to create an API key for you (Option 2) | | Working within a human's org with your own identity | Create an agent account, have the human invite you (Option 3) | | Building something to hand off to a human | Create an agent account, build it, then transfer the org (Option 1) | | Signing in without sending a password through the agent | Browser-based PKCE login (Option 4) | | Running headless / no browser available | Create an agent account (Option 1) or use an API key (Option 2) — do NOT use PKCE | **Credit limits by account type:** Agent accounts (Options 1, 3) can transfer orgs to humans when credits run out -- see Ownership Transfer in section 3. Human accounts (Option 2) cannot use the transfer/claim API; direct the human to upgrade their plan at `https://go.fast.io/settings/billing` or via `org` action `billing-create`. ### Standard Sign-In Flow 1. Call `auth` with action `signin`, `email` and `password`. 2. The server returns a JWT `auth_token` and stores it in the session automatically. 3. All subsequent tool calls use this token without any manual passing. ### Agent Account Creation When creating a new account (Options 1 and 3 above), agents **MUST** use `auth` action `signup` which automatically registers with `agent=true`. Never sign up as a human account. Agent accounts provide: - `account_type` set to `"agent"` - Free agent plan assigned automatically - Transfer/claim workflow enabled for handing orgs off to humans **Steps:** 1. (Optional) `auth` action `email-check` -- advisory hint only; do NOT gate on the result. Always attempt `signup`; see Section 9 for why. 2. Call `auth` action `signup` with `first_name`, `last_name`, `email`, and `password`. The `agent=true` flag is sent automatically by the MCP server. 3. The account is created and a session is established automatically -- the agent is signed in immediately. 4. **Verify your email** (required before using most endpoints): Call `auth` action `email-verify` with `email` to send a verification code, then call `auth` action `email-verify` again with `email` and `email_token` to validate the code. 5. No credit card is required. No trial period. No expiration. The account persists indefinitely. ### Two-Factor Authentication Flow 1. Call `auth` action `signin` with `email` and `password`. 2. If the response includes `two_factor_required: true`, the returned token has limited scope. 3. Call `auth` action `2fa-verify` with the 2FA `code` (TOTP, SMS, or WhatsApp). 4. The server replaces the limited-scope token with a full-scope token automatically. ### Inline 2FA for Sensitive Operations Some API endpoints require per-request 2FA verification when the account has 2FA enabled. These operations require a valid 2FA `token` parameter (6-digit TOTP or SMS/call/WhatsApp code) in addition to normal authentication: - **`api-key-create`** — creating a new API key - **`api-key-delete`** — revoking an API key If the account does not have 2FA enabled, these operations work normally without a token. If 2FA is enabled and the token is missing or invalid, the request fails. **Workflow:** 1. Check 2FA status: `auth` action `2fa-status` — if `state` is `"enabled"`, inline 2FA is required. 2. Prompt the user for a TOTP code from their authenticator app, or send a code via `auth` action `2fa-send`. 3. Pass the code as the `token` parameter to `api-key-create` or `api-key-delete`. **Tip:** API key authentication (`auth` action `set-api-key`) bypasses inline 2FA checks entirely. If the agent is already authenticated via API key, no token is needed for these operations. ### Browser Login (PKCE) Flow 1. Call `auth` action `pkce-login` (optionally with `email` to pre-fill the sign-in form, `scope_type` to request scoped access, and `agent_name` to identify the agent). 2. The tool returns a `login_url` -- present it to the user to open in a browser. 3. The user signs in (email/password or SSO). 4. The user sees the approval screen showing the `agent_name` (or client name if not provided). Depending on `scope_type`: for `user` they simply approve; for `org`/`workspace` they select specific entities and read-only/read-write access; for `all_orgs`/`all_workspaces`/`all_shares` they review the wildcard access summary. 5. The user clicks Approve. The browser displays an authorization code. The user copies it. 6. Call `auth` action `pkce-complete` with the `code` to exchange it for an access token. 7. The session is established automatically -- all subsequent tool calls are authenticated. If scoped access was granted, `scopes` and `agent_name` are included in the response and stored in the session. ### Checking Session Status - `auth` action `status` -- checks the local Durable Object session. No API call is made. Returns authentication state, user ID, email, auth_method, token expiry, scopes, and agent_name. If the session has expired, returns `session_expired: true` with `expired_reason` (`"token_expired"` or `"refresh_expired"`) and `expired_at` timestamp. - `auth` action `check` -- validates the token against the Fast.io API. Returns the user ID if the token is still valid. ### Session Expiry and Auto-Refresh **OAuth/PKCE sessions** (the default) have 1-hour access tokens and 30-day refresh tokens. The MCP server **proactively refreshes** OAuth access tokens before they expire -- an internal alarm fires ~5 minutes before expiry and silently obtains a new token using the stored refresh token. This creates a self-sustaining cycle: sessions stay alive indefinitely without user interaction, until the 30-day refresh token chain expires or is revoked. If proactive refresh fails, a reactive safety net retries on the next tool call (401 → refresh → retry). **Basic JWT sessions** (from `auth` action `signin`) last 30 days and have no refresh token. When the token expires, the session is cleaned up and re-authentication is required. **API keys** do not expire by default, but can optionally have an expiration set via `api-key-create` or `api-key-update` with the `key_expires` parameter. API key expiration is enforced server-side by the backend. The MCP server tracks how each session was authenticated (`auth_method`: `"api_key"`, `"jwt"`, or `"oauth"`) and skips client-side expiration checks for API key sessions. **Error differentiation:** When a session expires, tool calls return `"Session expired. Please re-authenticate..."` -- distinct from `"Not authenticated..."` which indicates no prior session existed. This helps distinguish reconnection issues from first-time setup. ### Signing Out Call `auth` action `signout` to clear the stored session from the Durable Object. --- ## 3. Core Concepts ### Organizations Organizations are top-level containers that collect workspaces. An organization can represent a company, a business unit, a team, or simply your own personal collection. Every user belongs to one or more organizations. Organizations have: - **Workspaces** — the file storage containers that belong to the organization. - **Members** with roles: owner, admin, member, guest, view. - **Billing and subscriptions** managed through Stripe integration. - **Plan limits** that govern storage, transfer, AI tokens, and member counts. Organizations are identified by a 19-digit numeric profile ID or a domain string. **IMPORTANT:** When creating orgs, agents MUST use `org` action `create` which automatically assigns `billing_plan: "agent"`. This ensures the org gets the free agent plan (50 GB, 5,000 credits/month). Do not use any other billing plan for agent-created organizations. #### Custom Domains Organizations on Pro or Business plans can configure a custom domain (e.g. `files.acme.com`) that serves the org's content. One custom domain per org. **Setup flow:** 1. `org` action `custom-domain-create` with `org_id` and `hostname` (a valid FQDN, e.g. `files.acme.com`). Returns `hostname`, `status: "pending"`, and `cname_target`. 2. The customer adds a DNS CNAME record: `files.acme.com CNAME custom.fast.io` (production) or `custom.fastdev1.com` (dev). 3. On the first request through the CNAME, a TLS certificate is automatically provisioned via Let's Encrypt (2-5 seconds). The domain status changes from `pending` to `active`. **Checking status:** `org` action `custom-domain-get` with `org_id`. Returns the domain info or `{ hostname: null }` if no custom domain is configured. **Validating DNS:** `org` action `custom-domain-validate` with `org_id`. Performs a live DNS lookup and returns whether the CNAME is correct. If valid and status is pending, the domain is automatically activated. **Removing:** `org` action `custom-domain-delete` with `org_id`. The existing TLS certificate expires naturally (up to 90 days); there is no immediate effect on traffic. No plan gate -- orgs that downgrade can still remove their domain. **Plan requirement:** Custom domains require a Pro or Business plan for creation. The agent plan does not include this feature. If the org is on a plan that does not support custom domains, creation returns a subscription upgrade error. #### Org Discovery (IMPORTANT) To discover all available orgs, agents **must call both actions**: 1. `org` action `list` -- returns internal orgs where you are a direct member (`member: true`) 2. `org` action `discover-external` -- returns external orgs you access via workspace membership only (`member: false`) **An agent that only checks `org` action `list` will miss external orgs entirely and won't discover the workspaces it's been invited to.** External orgs are the most common pattern when a human invites an agent to help with a specific project -- they add the agent to a workspace but not to the org itself. #### Internal vs External Orgs **Internal orgs** (`member: true`) -- orgs you created or were invited to join as a member. You have org-level access: you can see all workspaces (subject to permissions), manage settings if you're an admin, and appear in the org's member list. **External orgs** (`member: false`) -- orgs you can access only through workspace membership. You can see the org's name and basic public info, but you cannot manage org settings, see other workspaces, or add members at the org level. Your access is limited to the specific workspaces you were explicitly invited to. **Example:** A human invites your agent to their "Q4 Reports" workspace. You can upload files, run AI queries, and collaborate in that workspace. But you cannot create new workspaces in their org, view their billing, or access their other workspaces. The org shows up via `org` action `discover-external` -- not `org` action `list`. If the human later invites you to the org itself, the org moves from external to internal. ### Workspaces Workspaces are file storage containers within organizations. Each workspace has: - Its own set of **members** with roles (owner, admin, member, guest). Members have a `status` of `active` or `pending`. Pending members are invited users who haven't signed up yet — they appear in member lists immediately and can be assigned tasks, approvals, and todos. Notifications for pending members are suppressed until they sign up. When they sign up, their status becomes `active` and all assignments are preserved. - A **storage tree** of files and folders (storage nodes). - Optional **AI features** for RAG-powered chat. - **Shares** that can be created within the workspace. - **Archive/unarchive** lifecycle management. - **50 GB included storage** on the free agent plan, with files up to 1 GB per upload. - **File versioning** -- every edit creates a new version, old versions are recoverable. - **Keyword and semantic search** -- find files by name or content; with intelligence enabled, search by meaning. Workspaces are identified by a 19-digit numeric profile ID. #### Intelligence: On or Off Workspaces have an **intelligence** toggle that controls whether AI features are active. > **⚠️ COST WARNING:** Intelligence incurs significant ingestion costs (10 credits per page for every uploaded document). For a workspace with hundreds or thousands of pages, this adds up quickly. **Do NOT enable intelligence unless the user specifically needs RAG chat queries or semantic search via storage search.** Most workflows (file storage, sharing, collaboration, one-off file analysis) work perfectly without it. **Intelligence OFF (recommended default)** -- the workspace is pure file storage. You can still attach files directly to an AI chat conversation (up to 20 files, 200 MB total) and ask questions about them -- no ingestion cost. This is the right choice for most use cases: file storage, sharing, collaboration, project coordination, and analyzing a small number of specific files. **Intelligence ON (only when needed)** -- the workspace becomes an AI-powered knowledge base. Every document and code file uploaded is automatically ingested, summarized, and indexed. **Only enable this when the user needs one of these two capabilities:** 1. **RAG queries across many documents** -- scope AI chat to entire folders or the full workspace and ask questions across all indexed content. The AI retrieves relevant passages and answers with citations. This is useful when you have a large volume of documents and need to search across all of them. 2. **Semantic search via storage search** -- find files by meaning, not just keywords. Use `storage` action `search` to find documents semantically. "Show me contracts with indemnity clauses" works even if those exact words do not appear in the filename. Intelligence also enables auto-summarization and automatic metadata extraction, but these alone do not justify the ingestion cost. > **Coming soon:** RAG indexing support for images, video, and audio files. Currently only documents and code are indexed. **Default behavior:** The MCP server defaults intelligence to OFF when creating workspaces and shares. To enable intelligence, you must explicitly pass `intelligence: "true"`. **Do NOT enable intelligence unless the user specifically requests RAG chat queries or semantic search via storage search.** Do not enable it speculatively "just in case" -- it can always be enabled later, but ingestion costs (10 credits/page) are incurred immediately and are non-refundable. **Agent use case:** Create a workspace per project or client. Keep intelligence OFF for storage and collaboration. Only enable it when users need to query across a large document set. Upload reports, datasets, and deliverables. Invite other agents and human stakeholders. Everything is organized, searchable, and versioned. For full details on AI chat types, file context modes, AI state, and how intelligence affects them, see the **AI Chat** section below. ### Shares Shares are purpose-built spaces for exchanging files with people outside your workspace. They can exist within workspaces and have three types: | Mode | What It Does | Agent Use Case | |------|-------------|----------------| | **Send** | Recipients can download files | Deliver reports, exports, generated content | | **Receive** | Recipients can upload files | Collect documents, datasets, user submissions | | **Exchange** | Both upload and download | Collaborative workflows, review cycles | #### Portals A **Portal** is a Send share created from a workspace folder (`storage_mode=workspace_folder`). Portals are always Send-only -- recipients can view and download files but cannot upload. The portal displays the live contents of the linked workspace folder, so any changes to the folder are immediately reflected. Portals are ideal for publishing a folder's contents externally (e.g., a client deliverables folder) without duplicating files. To create a portal: use `share` action `create` with `share_type: "send"`, `storage_mode: "workspace_folder"`, and `folder_node_id` (or `create_folder: true`). #### Share Features - **Password protection** -- require a password for link access - **Expiration dates** -- shares auto-expire after a set period - **Download controls** -- three security levels: `off` (no restrictions, default), `medium` (guests can preview files inline but cannot download), `high` (all guest downloads blocked). Set via `download_security` on create/update. - **Access levels** -- Members Only, Org Members, Registered Users, or Public (anyone with the link) - **Custom branding** -- background images, gradient colors, accent colors, logos - **Post-download messaging** -- show custom messages and links after download - **Up to 3 custom links** per share for context or calls-to-action - **Anonymous file drops** -- allow guests to upload files to Receive/Exchange shares without registration (enable `anonymous_uploads_enabled` with "Anyone" access) - **Guest chat** -- let share recipients ask questions in real-time - **AI-powered auto-titling** -- shares automatically generate smart titles from their contents - **Activity notifications** -- get notified when files are sent or received - **Comment controls** -- configure who can see and post comments (owners, guests, or both) #### Two Storage Modes When creating a share with `share` action `create`, the `storage_mode` parameter determines how files are stored: - **`independent`** (independent storage, default) -- The share has its own isolated storage. Files are added directly to the share and are independent of any workspace. This creates a self-contained share -- changes to workspace files do not affect the share, and vice versa. Use for final deliverables, compliance packages, archived reports, or any scenario where you want an immutable snapshot. - **`workspace_folder`** (workspace-backed) -- The share is backed by a specific folder in a workspace. The share displays the live contents of that folder -- any files added, updated, or removed in the workspace folder are immediately reflected in the share. No file duplication, so no extra storage cost. To create a workspace folder share, pass `storage_mode=workspace_folder` and `folder_node_id={folder_opaque_id}` when creating the share. **Note:** Expiration dates are not allowed on workspace folder shares since the content is live. **Note:** Intelligence is not supported on workspace folder shares -- `intelligence` is always set to `false` regardless of the value passed. To use AI features on these files, use the parent workspace's AI endpoints instead. Both modes look the same to share recipients -- a branded share with file preview, download controls, and all share features. The difference is whether the content is a snapshot (independent) or a live view (workspace folder). **Response fields:** API responses include both `storage_mode` (`independent` or `workspace_folder`) and `share_category` (`portal` or `shared_folder`). Use `storage_mode` when creating shares; `share_category` is a read-only classification in responses. Shares are identified by a 19-digit numeric profile ID. **Agent use case:** Generate a quarterly report, create a Send share with your client's branding, set a 30-day expiration, and share the link. The client sees a professional, branded page with instant file preview -- not a raw download link. ### Storage Nodes Files and folders are represented as storage nodes. Each node has an opaque ID (a 30-character alphanumeric string, displayed with hyphens, e.g. [REDACTED_SECRET]). The special value `root` refers to the root folder of a workspace or share, and `trash` refers to the trash folder. Key operations on storage nodes: list, create-folder, move, copy, rename, delete (moves to trash), purge (permanently deletes), restore (recovers from trash), search, add-file (link an upload), and add-link (create a share reference). Nodes have versions. Each file modification creates a new version. Version history can be listed and files can be restored to previous versions. #### Overwriting files (REPLACE by default, versioned in place) **Do NOT delete and re-upload to "update" a file.** Same-name uploads to the same parent folder **overwrite the existing node in place, preserving the `node_id`**. The prior content is kept as a version and is recoverable at any time. Deleting the old node first is wasted work, breaks any `node_id` references held by other entities (comments, tasks, approvals, metadata, links), and can leak the file into trash — it is never the right pattern for editing a file's bytes. **The correct update-a-file pattern:** 1. `upload` action `create-session` with the **same** `parent_node_id` and the **same** `filename` as the existing file (plus `profile_type`, `profile_id`, `filesize`). The server resolves the collision to the existing node. 2. `POST /blob` with the new bytes (see Upload section below). 3. `upload` action `chunk` with `blob_id`, then `upload` action `finalize` (or use `stream` mode for single-shot streamed uploads). 4. The `node_id` is unchanged. The previous content becomes a version entry. 5. Inspect history with `storage` action `version-list` (returns all versions for the node). Roll back to any earlier version with `storage` action `version-restore`. Deterministic overwrite by node_id: if the filename may have drifted (e.g., a previous rename), or you want to guarantee the overwrite hits a specific `node_id` without re-resolving the parent folder, pass `target_node_id` on `create-session`. This pins the update target explicitly — the server uses `action=update` + `file_id=<target_node_id>`; `parent_node_id` is ignored and `filename` is optional (omit to keep the current name, or pass a new one to rename-on-replace). When `filename` is omitted, the tool performs one extra `storage` `details` lookup to fetch the current name (the Fast.io API still requires `name` in update mode); pass `filename` explicitly if you want to skip that call. See the `target_node_id` documentation in the Upload section below. **Worked example — edit a file's content and recover the prior version:** ``` # Initial upload upload create-session profile_type=workspace, profile_id=<ws_id>, parent_node_id=<folder_id>, filename="state.json", filesize=1024 POST /blob <bytes> upload chunk upload_id=<id> chunk_number=1 blob_id=<blob> upload finalize upload_id=<id> # → new_file_id = f3jm5-zqzfx-... (this is the stable node_id) # Later, "edit" the file by re-uploading with the same name+parent upload create-session profile_type=workspace, profile_id=<ws_id>, parent_node_id=<folder_id>, filename="state.json", filesize=2048 POST /blob <new_bytes> upload chunk upload_id=<id2> chunk_number=1 blob_id=<blob2> upload finalize upload_id=<id2> # → new_file_id = f3jm5-zqzfx-... (SAME node_id — overwritten in place) # Inspect version history storage version-list profile_type=workspace profile_id=<ws_id> node_id=f3jm5-zqzfx-... # → [{version_id: v2, current: true}, {version_id: v1, ...}] # Roll back if needed storage version-restore profile_type=workspace profile_id=<ws_id> node_id=f3jm5-zqzfx-... version_id=v1 ``` **What overwriting covers (REPLACE is the default behavior for all name collisions):** - **Upload (addfile)** -- silently overwrites the existing file. The previous content is preserved as a version entry, recoverable via `storage` action `version-list` / `version-restore`. Node ID is stable. - **Move / Copy** -- trashes the existing conflicting file, then completes the operation. The old file is recoverable from trash. - **Restore from trash** -- trashes the existing conflicting file, then restores. - **Folder conflicts and type mismatches** (file vs folder) still fall back to rename (e.g. `folder (2)`). Uploading a file with the same name as an existing file will **overwrite it**, not create a renamed copy like `report (2).pdf`. If you specifically need multiple files with the same name to coexist, rename them before uploading. ### Notes Notes are a storage node type (alongside files and folders) that store markdown content directly on the server. They live in the same folder hierarchy as files, are versioned like any other node, and appear in storage listings with `type: "note"`. #### Creating and Updating Notes Create notes with `workspace` action `create-note`, read with `workspace` action `read-note`, and update with `workspace` action `update-note`. > **Files and Notes are not interchangeable, even when both hold markdown.** A `.md` uploaded via the file-upload flow is a **File** (`type: "file"`), not a **Note** (`type: "note"`). Reading a markdown File returns text and "looks like" a note, but note-specific APIs (`update-note`, `read-note`) reject it with `Node is not a note` (error 153548). Choose the right creation path up front: > > - **If you will edit the content incrementally from an agent** → use `create-note`. Pass markdown as `content` directly. Do NOT upload it as a file first. > - **If it is a static artifact** (report, export, attachment) → use the upload flow. Accept that `update-note` will not work later; to change the content, upload a new version by calling `upload` action `create-session` with the **same** `parent_node_id` and **same** `filename` as the existing File, then `chunk`/`finalize` (or `stream`). Same-name uploads overwrite the File in place and preserve the previous content as a version (recover via `storage` action `version-list` / `version-restore`). > > When `update-note` fails with `Node is not a note`, the node is almost always a File. You have two valid recovery paths — pick based on what the node should be going forward: > > - **(a) Keep it as a File** and just change its bytes → use the upload flow described above (same `parent_node_id` + `filename` = in-place overwrite with a version entry). The node ID does NOT change; the node stays a File. > - **(b) Convert to a Note** (because you want to edit it incrementally via `update-note` from now on) → delete the File via `storage` action `delete`, then call `create-note` with the markdown content in the desired `parent_id`. This produces a NEW node with `type: "note"`. Future edits use `update-note` with the new `node_id`. > > Do NOT use delete-and-re-upload (via the upload flow) as a fix — that just creates another File and you will hit the same `Node is not a note` error on the next `update-note` call. To verify a node's type before calling, use `storage` action `details` and inspect the `type` field (`"file"` vs `"note"` vs `"folder"` vs `"link"`). **Creating:** Provide `workspace_id`, `parent_id` (folder opaque ID or `"root"`), `name` (must end in `.md`, max 100 characters), and exactly one of `content` (inline markdown, max 100 KB) or `blob_id` (see below). **Reading:** Provide `workspace_id` and `node_id`. Returns the note's markdown content and metadata. **Updating:** Provide `workspace_id`, `node_id`, and at least one of `name` (must end in `.md`), `content` (max 100 KB), or `blob_id`. When `content` and `blob_id` are both passed, the call errors — provide exactly one. #### Passing note content via `blob_id` (preferred for large notes) Both `create-note` and `update-note` accept an optional `blob_id` as an alternative to inline `content`: > `blob_id`: optional string. Blob ID from `POST /blob` response. Recommended for large note content — avoids base64 overhead and MCP transport limits. Consumed after use. Bytes are decoded as UTF-8 and passed as note content. (used by: `create-note`, `update-note` as one of `content`/`blob_id`) **Why this exists.** MCP transports tool parameters as inline JSON strings over the JSON-RPC pipe. Sending more than a few KB of note content through the `content` parameter is measurably slow — the full string has to be serialized into the tool call, travel through the transport, and be parsed again on the server. The `POST /blob` sidecar is a separate raw-HTTP path that bypasses MCP transport entirely: you POST the raw bytes (up to 100 MB, single-use, 5-minute TTL), get back a `blob_id`, and hand the `blob_id` to the tool. The server consumes the blob, UTF-8 decodes it, sanitizes it, and uses it as note content. Same pattern as `upload` action `chunk`/`stream`. **When to use which:** | Note size | Recommended path | |---|---| | Small edits (< ~10 KB — a few paragraphs, bullets, small sections) | Inline `content` | | Large notes (> ~10 KB — rich project context, transcripts, long markdown documents) | `POST /blob` → `blob_id` | Notes are capped at **100 KB** per node. Writes at or above **80 KB** return a non-fatal warning in `_warnings` (or via `withHints` on `create-note`) recommending rollover before you hit the ceiling. The warning is advisory — the write still succeeds. A typical rollover pattern is dated archive files: when a growing note crosses ~80 KB, create a new note named something like `archive-2026-04-14.md` or `notes-2026-W15.md`, move the older material there, and keep the "live" note small. | Constraint | Limit | |------------|-------| | Content encoding | Valid UTF-8 (UTF8MB4). Invalid byte sequences and control characters (`\p{C}` except `\t`, `\n`, `\r`) are stripped. | | Content size | 100 KB max | | Filename | 1-100 characters, must end in `.md` | | Markdown validation | Code blocks and emphasis markers must be balanced | | Rate limit | 2 per 10s, 5 per 60s | #### Notes as Long-Term Knowledge Grounding In an intelligent workspace, notes are automatically ingested and indexed just like uploaded documents. This makes notes a way to bank knowledge over time -- any facts, context, or decisions stored in notes become grounding material for future AI queries. When an AI chat uses folder scope (or defaults to the entire workspace), notes within that scope are searched alongside files. The AI retrieves relevant passages from notes and cites them in answers. Key behaviors: - Notes are ingested for RAG when workspace intelligence is enabled - Notes within a folder scope are included in scoped queries - Notes with `ai_state: indexed` are searchable via RAG - Notes can also be attached directly to a chat via `files_attach` (check `ai.attach` is `true` in storage details) **Use cases:** - Store project context, decisions, and rationale. Months later, ask "Why did we choose vendor X?" and the AI retrieves the note. - Save research findings in a note. Future AI chats automatically use those findings as grounding. - Create reference documents (style guides, naming conventions) that inform all future AI queries in the workspace. #### Other Note Operations Notes support the same storage operations as files and folders: move (via `storage` action `move`), copy (`storage` action `copy`), delete/trash (`storage` action `delete`), restore (`storage` action `restore`), version history (`storage` action `version-list`), and details (`storage` action `details`). #### Linking Users to Notes - **Note in workspace context** (opens workspace with note panel): `https://{domain}.fast.io/workspace/{folder_name}/storage/root?note={note_id}` - **Note preview** (standalone view): `https://{domain}.fast.io/workspace/{folder_name}/preview/{note_id}` ### AI Chat AI chat lets agents ask questions about files stored in workspaces and shares. Two chat types are available, each with different file context options. **AI chat is read-only.** It can read, analyze, search, and answer questions about file contents, but it cannot modify files, change workspace settings, manage members, or access events. Any action beyond reading file content — uploading, deleting, moving files, changing settings, managing shares, reading events — must be done through the MCP tools directly. Do not attempt to use AI chat as a general-purpose tool for workspace management. #### Two Chat Types - **`chat`** — Basic AI conversation with no file context from the workspace index. Use for general questions only. - **`chat_with_files`** — AI grounded in your files. Two mutually exclusive modes for providing file context: **Auto-promotion:** If you create a chat with `type=chat` but include `files_scope`, `folders_scope`, or `files_attach`, the system automatically promotes the type to `chat_with_files`. You don't need to worry about setting the type exactly right — the intent is unambiguous when file parameters are present. - **Folder/file scope (RAG)** — limits the retrieval search space. Requires intelligence enabled; files must be in `indexed` AI state. - **File attachments** — files read directly by the AI. No intelligence required; files must have `ai.attach: true` in storage details (the file must be a supported type for AI analysis). Max 20 files, 200 MB total. Both types augment answers with web knowledge when relevant. #### File Context: Scope vs Attachments For `chat_with_files`, choose one of these mutually exclusive approaches: | Feature | Folder/File Scope (RAG) | File Attachments | |---------|------------------------|------------------| | How it works | Limits RAG search space | Files read directly by AI | | Requires intelligence | Yes | No | | File readiness requirement | `ai_state: indexed` | `ai.attach: true` | | Best for | Many files, knowledge retrieval | Specific files, direct analysis | | Max references | 100 folder refs (subfolder tree expansion) or 100 file refs | 20 files / 200 MB | | Default (no scope given) | Entire workspace | N/A | **Scope parameters** (REQUIRES intelligence — will error if intelligence is off): - `folders_scope` — comma-separated `nodeId:depth` pairs (depth 1-10, max 100 subfolder refs). Defines a search boundary — the RAG backend finds documents within scoped folders automatically. Just pass folder IDs with depth; do not enumerate individual files. A folder with thousands of files and few subfolders works fine. - `files_scope` — comma-separated `nodeId:versionId` pairs (max 100). Limits RAG to specific indexed files. nodeId is required; versionId is required in the pair format but will be **auto-resolved to the node's current version** if left empty (e.g., `nodeId:` with nothing after the colon). Get `versionId` from the file's `version` field via `storage` action `details` (returned by default at `detail: "full"`); on `storage` action `list`, `version` is omitted at the default `detail: "terse"` — pass `detail: "standard"` or higher to surface it inline. - **If neither is specified, the default scope is the entire workspace (all indexed documents).** This is the recommended default — omit scope parameters unless you specifically need to narrow the search. **Attachment parameter** (no intelligence required): - `files_attach` — comma-separated `nodeId:versionId` pairs (max 20, 200 MB total). nodeId is required; versionId will be **auto-resolved to the current version** if left empty. Files are read directly, not via RAG. **FILES ONLY: passing a folder nodeId returns a 406 error.** To include folder contents in AI context, use `folders_scope` instead (requires intelligence). **Only files with `ai.attach: true` in storage details can be attached** — check before using. **Do not** list folder contents and pass individual file IDs as `files_scope` when you mean to search a folder — use `folders_scope` with the folder's nodeId instead. `files_scope` is only for targeting specific known file versions. **Scope vs attach:** `files_scope` and `folders_scope` narrow the RAG search boundary and **require workspace intelligence to be enabled** — they will error on non-intelligent workspaces. `files_attach` sends files directly to the AI without indexing and works regardless of intelligence setting, but accepts only file nodeIds (not folders). `files_scope`/`folders_scope` and `files_attach` are mutually exclusive — sending both will error. **Citations behavior:** the response `citations` array is populated only in RAG modes (`files_scope` / `folders_scope`) — when the AI selects passages from a corpus and cites which it used. In `files_attach` mode the file is force-attached, so `citations` is always an empty array; the answer text itself is the only source attribution. #### Intelligence and AI State The workspace intelligence toggle (see Workspaces above) controls whether uploaded documents and code files are auto-ingested, summarized, and indexed for RAG. Each file has an `ai_state` indicating its readiness: | State | Meaning | |-------|---------| | `disabled` | No AI processing done (file type not supported, or AI completely off) | | `pending` | Queued for AI processing | | `in_progress` | Currently being processed | | `ready` | Summary exists, file is attachable for AI chat, but NOT vector-indexed (intelligence OFF) | | `indexed` | Summary + vector indexed — file is searchable via RAG/semantic search (intelligence ON) | | `failed` | Processing failed | Only files with `ai_state: indexed` are included in folder/file scope (RAG) searches. Files with `ai_state: ready` or `indexed` are both attachable for AI chat — check the `ai.attach` field. Check file state via `storage` action `details` with `profile_type: "workspace"`. When polling for AI processing completion: if intelligence is ON, wait for `indexed`; if intelligence is OFF (but AI summaries are enabled), wait for `ready`. Check `capabilities.can_use_intelligence` on the workspace to know which terminal state to expect. #### Attachability — the `ai.attach` Flag File nodes returned by `storage` action `details` (default `detail: "full"`) include an `ai` object with three fields. The `ai.attach` flag specifically requires `detail: "full"` — list/recent/search at the default `detail: "terse"` omit the `ai` object entirely, and `standard` exposes only `ai.state` (not `ai.attach`). Always preflight via `storage` action `details` (full by default) before calling `files_attach`. | Field | Type | Meaning | |-------|------|---------| | `ai.state` | string | AI processing state (`disabled`, `pending`, `inprogress`, `ready`, `indexed`, `failed`) | | `ai.attach` | boolean | Whether the file can be used with `files_attach` | | `ai.summary` | boolean | Whether the file already has an AI-generated summary | **Before using `files_attach`, check that `ai.attach` is `true`.** A file is attachable when its type supports AI analysis (documents, code, images, PDFs, spreadsheets, etc.) or when it already has a summary from prior processing. Files with `ai.attach: false` (unsupported formats, corrupt files, or files still processing) will be rejected by the API. This flag is independent of the workspace intelligence setting — a file can have `ai.attach: true` even when intelligence is off. **When to enable intelligence:** You need RAG chat queries across many documents (scoped to folders or the full workspace) or semantic search via `storage` action `search`. Do NOT enable just for auto-summarization or metadata extraction alone -- the ingestion cost (10 credits/page) is significant. **When to disable intelligence (recommended default):** The workspace is for storage, sharing, collaboration, or you only need to analyze specific files via attachments. This covers most use cases. Saves significant credits. Intelligence can always be enabled later if needed. Even with intelligence off, `chat_with_files` with file attachments still works for files with `ai.attach: true`. #### How to Phrase Questions **With folder/file scope (RAG):** Write questions likely to match content in indexed files. The AI searches the scope, retrieves passages, and cites them. - Good: "What are the payment terms in the vendor contracts?" - Good: "Summarize the key findings from the Q3 analysis reports" - Bad: "Tell me about these files" — too vague, no specific content to match - Bad: "What's in this workspace?" — cannot meaningfully search for "everything" **With file attachments:** Be direct — the AI reads the full file content. No retrieval step. - "Describe this image in detail" - "Extract all dates and amounts from this invoice" - "Convert this CSV data into a summary table" **Personality:** The `personality` parameter controls the tone and length of AI responses. Pass it when creating a chat or sending a message: - `concise` — short, brief answers - `detailed` — comprehensive answers with context and evidence (default) Use `concise` when you need a quick fact, a yes/no answer, or a brief summary. Use `detailed` (or omit the parameter) when you need thorough analysis with supporting evidence and citations. The personality can also be overridden per follow-up message. **Controlling verbosity in questions:** You can also guide verbosity through how you phrase the question itself: - "In one sentence, what is the main conclusion of this report?" - "List only the file names that mention GDPR compliance, no explanations" - "Give me a brief summary — 2-3 bullet points max" Combining `personality: "concise"` with a direct question produces the shortest answers and uses the fewest AI credits. #### Chat Parameters Create a chat with `ai` action `chat-create` (with `profile_type: "workspace"`) or `ai` action `chat-create` (with `profile_type: "share"`): - `type` (required) — `chat` or `chat_with_files` - `query_text` (required for workspace, optional for share) — initial message, 2-12,768 characters - `personality` (optional) — `concise` or `detailed` (default: `detailed`) - `privacy` (optional) — `private` or `public` (default: `public`) - `files_scope` (optional) — `nodeId:versionId,...` (max 100, requires `chat_with_files` + intelligence). nodeId required; versionId auto-resolved if empty. **Omit to search all indexed documents (recommended default).** - `folders_scope` (optional) — `nodeId:depth,...` (depth 1-10, max 100 subfolder refs, requires `chat_with_files` + intelligence). Folder scope = search boundary, not file enumeration. **Omit to search all indexed documents (recommended default).** - `files_attach` (optional) — `nodeId:versionId,...` (max 20 / 200 MB, nodeId required, versionId auto-resolved if empty, mutually exclusive with scope params) #### Follow-up Messages Send follow-ups with `ai` action `message-send` (with `profile_type: "workspace"` or `"share"`). The chat type is inherited from the parent chat. Each follow-up can update the scope, attachment, and personality parameters. #### Waiting for AI Responses After creating a chat or sending a message, the AI response is asynchronous. Message states progress: `ready` → `in_progress` → `complete` (or `errored`). **Recommended:** Call `ai` action `message-read` (with `profile_type: "workspace"` or `"share"`) with the returned `message_id`. The tool polls automatically (up to 15 attempts, 2-second intervals, ~30 seconds). If the response is still processing after that window, use `event` action `activity-poll` with the workspace/share ID instead of calling the read action in a loop — see Activity Polling in section 7. #### Response Citations Completed AI responses include citations pointing to source files: - `nodeId` — storage node opaque ID - `versionId` — file version opaque ID - `entries[].page` — page number - `entries[].snippet` — text excerpt - `entries[].timestamp` — audio/video timestamp #### Linking Users to AI Chats Append `?chat={chat_opaque_id}` to the workspace storage URL: `https://{domain}.fast.io/workspace/{folder_name}/storage/root?chat={chat_id}` #### Share AI Chats Shares support AI chat with identical capabilities. All workspace AI endpoints have share equivalents accessible via `ai` actions with `profile_type: "share"`. ### AI Share / Export Generate temporary markdown-formatted download URLs for files that can be pasted into external AI tools (ChatGPT, Claude, etc.). Use `ai` action `share-generate` (with `profile_type: "workspace"` or `"share"`). URLs expire after 5 minutes. Limits: 25 files maximum, 50 MB per file, 100 MB total. ### Profile IDs Organizations, workspaces, and shares are all identified by 19-digit numeric profile IDs. These appear throughout the tool parameters as `workspace_id`, `share_id`, `org_id`, `profile_id`, and `member_id`. Most endpoints also accept custom names as identifiers: | Profile Type | Numeric ID | Custom Name | |-------------|-----------|-------------| | Workspace | 19-digit ID | Folder name (e.g., `my-project`) | | Share | 19-digit ID | URL name (e.g., `q4-financials`) | | Organization | 19-digit ID | Domain name (e.g., `acme`) | | User | 19-digit ID | Email address (e.g., `[REDACTED_SECRET]`) | ### QuickShares QuickShares are temporary public download links for individual files in workspaces (not available for shares). They can be accessed without authentication. Expires in seconds from creation (default 10,800 = 3 hours, max 604,800 = 7 days) or as an ISO 8601 datetime via `expires_at`. Max file size: 1 GB. Each quickshare has an opaque identifier used to retrieve metadata and download the file. ### File Preview Files uploaded to Fast.io get automatic preview generation. When humans open a share or workspace, they see the content immediately -- no "download and open in another app" friction. Supported preview formats: - **Images** -- full-resolution with auto-rotation and zoom - **Video** -- HLS adaptive streaming (50--60% faster load than raw video) - **Audio** -- interactive waveform visualization - **PDF** -- page navigation, zoom, text selection - **Spreadsheets** -- grid navigation with multi-sheet support - **Code and text** -- syntax highlighting, markdown rendering Use `storage` action `preview-url` (with `profile_type: "workspace"` or `"share"`) to generate preview URLs. Use `storage` action `preview-transform` (with `profile_type: "workspace"` or `"share"`) for image resize, crop, and format conversion. **Agent use case:** Your generated PDF report does not just appear as a download link. The human sees it rendered inline, can flip through pages, zoom in, and comment on specific sections -- all without leaving the browser. ### Comments and Annotations Humans and agents can leave feedback directly on files, anchored to specific content using the `reference` parameter: - **Image comments** -- anchored to spatial regions (normalized x/y/width/height coordinates) - **Video comments** -- anchored to timestamps with spatial region selection - **Audio comments** -- anchored to timestamps or time ranges - **PDF comments** -- anchored to specific pages with optional text snippet selection - **Text-anchored comments** -- anchored to selected text in markdown/notes using `exact`, `prefix`, `suffix`, `start_offset`, and `end_offset` fields (use `type: "document"` or `type: "text"`) - **Threaded replies** -- single-level threading only; replies to replies are auto-flattened to the parent - **Emoji reactions** -- one reaction per user per comment; adding a new reaction replaces the previous one - **Mention tags** -- reference users and files inline using bracket syntax: `@[profile:id]`, `@[user:opaqueId:Display Name]`, `@[file:fileId:filename.ext]`. Get IDs from member lists, user details, or storage listings. The display name segment is optional for profile tags but recommended for user and file tags Comments use JSON request bodies (`Content-Type: application/json`), unlike most other endpoints which use form-encoded data. **Listing comments:** Use `comment` action `list` for per-file comments and `comment` action `list-all` for all comments across a workspace or share. Both support `sort`, `limit` (2-200), `offset`, `include_deleted`, `reference_type` filter, and `include_total`. **Adding comments:** Use `comment` action `add` with `profile_type`, `profile_id`, `node_id`, and `text`. Optionally include `parent_comment_id` for replies and `reference` to anchor to a specific position. Supports mention tags in the body. Two character limits apply: total body including tags max 8,192 chars, display text (body with `@[...]` tags stripped) max 500 chars. Optionally include `linked_entity_type` and `linked_entity_id` to link the comment to a task or approval at creation time. **Deleting comments:** `comment` action `delete` is recursive -- deleting a parent also removes all replies. `comment` action `bulk-delete` is NOT recursive -- replies to deleted comments are preserved. **Comment Linking:** Comments can be linked to workflow entities (tasks or approvals). Each comment supports one link at a time (nullable). Use `comment` action `link` to associate an existing comment with a task or approval, `comment` action `unlink` to remove the association, and `comment` action `linked` to reverse-lookup all comments linked to a given entity. You can also link at creation time by passing `linked_entity_type` and `linked_entity_id` to the `add` action. Comment responses include `linked_entity_type` and `linked_entity_id` fields (null when unlinked). **Linking users to comments:** The preview URL opens the comments sidebar automatically. Deep link query parameters let you target a specific comment or position: | Parameter | Format | Purpose | |-----------|--------|---------| | `?comment={id}` | Comment opaque ID | Scrolls to and highlights a specific comment for 2 seconds | | `?t={seconds}` | e.g. `?t=45.5` | Seeks to timestamp for audio/video comments | | `?p={pageNum}` | e.g. `?p=3` | Navigates to page for PDF comments | Workspace: `https://{org.domain}.fast.io/workspace/{folder_name}/preview/{file_opaque_id}?comment={comment_id}` Share: `https://go.fast.io/shared/{custom_name}/{title-slug}/preview/{file_opaque_id}?comment={comment_id}` Parameters can be combined -- e.g. `?comment={id}&t=45.5` to deep link to a video comment at a specific timestamp. In shares, the comments sidebar only opens if the share has comments enabled. **Agent use case:** You generate a design mockup. The human comments "Change the header color" on a specific region of the image. You read the comment, see exactly what region they are referring to via the `reference.region` coordinates, and regenerate. **Text-anchored comments (markdown/notes):** To anchor a comment to specific text in a markdown or notes file, use the `reference` parameter with `type: "document"` (or `"text"`, which is an alias) and the text selection fields: - `exact` (string, max 500 chars) -- the selected text verbatim - `prefix` (string, max 100 chars) -- ~30-50 characters of context before the selection for disambiguation - `suffix` (string, max 100 chars) -- ~30-50 characters of context after the selection for disambiguation - `start_offset` (integer) -- character offset from document start (hint for resolving ambiguous matches) - `end_offset` (integer) -- character offset for end of selection (hint for resolving ambiguous matches) At minimum, provide `exact`. The `prefix`/`suffix` fields help locate the selection when the same text appears multiple times. The `start_offset`/`end_offset` fields are optional hints that may not survive document edits. Example -- text-anchored comment on a markdown file: ```json { "action": "add", "profile_type": "workspace", "profile_id": "1234567890123456789", "node_id": "abc123-def456-ghi789", "text": "This section needs a citation", "reference": { "type": "document", "exact": "Studies show a 40% improvement", "prefix": "In the results section, ", "suffix": " compared to the baseline.", "start_offset": 1250, "end_offset": 1280 } } ``` ### URL Import Agents can import files directly from URLs without downloading them locally first. Fast.io's server fetches the file, processes it, and adds it to your workspace or share. - Supports any HTTP/HTTPS URL - Supports OAuth-protected sources: **Google Drive, OneDrive, Dropbox** - Files go through the same processing pipeline (preview generation, AI indexing if intelligence is enabled, virus scanning) Use `upload` action `web-import` with the source URL, target profile, and parent node ID. Use `upload` action `web-status` to check progress and `upload` action `web-list` to list active import jobs. **Agent use case:** A user says "Add this Google Doc to the project." You call `upload` action `web-import` with the URL. Fast.io downloads it server-side, generates previews, indexes it for AI, and it appears in the workspace. No local I/O. ### Metadata Metadata enables structured data annotation on files within workspaces. The system uses a template-based approach (called "views" in the UI): administrators create templates that define the fields (name, type, constraints), then assign a template to the workspace. Files can then have metadata values set against the template fields. Key points: - **Available on all plans** -- metadata templates are no longer Pro/Business-gated. Free and Agent users can create their first template. - **Per-plan caps** -- each plan limits both how many templates a workspace can have and how many files (nodes) each template can hold: | Plan | Templates per workspace | Nodes per template | |----------|-------------------------|--------------------| | Agent | 1 | 10 | | Free | 1 | 10 | | Pro | 2 | 10 | | Business | 10 | 1,000 | Caps are enforced across automatch, manual add, and listings. On downgrade, overflow rows are preserved in storage but hidden by listings. - **Truncation signaling on `metadata-template-preview-match`** -- the response includes `plan_node_limit` (`-1` = unlimited) and `would_truncate_at` (= `min(total_matched, plan_node_limit)` when the cap applies, otherwise = `total_matched`). Doc-recommended frontend heuristic: warn the user when `would_truncate_at < total_matched` — the plan cap is clipping the sampled match count. The MCP `metadata-template-preview-match` handler emits this warning automatically in `_warnings`. Treat `plan_node_limit = -1` as "no cap" in UI. - **Truncation signaling on `metadata-template-list` and `metadata-template-details`** -- the live AI category overview states: *"Listing, details, and preview endpoints return `plan_node_limit`, `is_truncated`, and an unfiltered count alongside the visible (capped) count, so consumers can render upsell messaging."* The current response examples in the live reference don't show these fields explicitly, so verify the exact field names at runtime. The unfiltered count field is named `total_count_unfiltered` on the per-template `nodes/` listing endpoint; the field name on `list`/`details` is not pinned in the docs and may differ. Show an upsell prompt whenever `is_truncated` is true on either endpoint. - **[REDACTED_SECRET] concurrency** -- the server rate-limits concurrent calls per user+workspace and returns **409 Conflict** when another suggest-fields call is in flight. Wait a few seconds and retry. (Earlier internal notes incorrectly said 406; live docs are authoritative — it is 409.) - **`nodes/add/` cap-exceeded** (REST endpoint, not exposed as an MCP action) -- returns **400 (Fast.io error code 1605, "Invalid Input")** with a structured "would exceed cap" message. Concurrent calls cannot collectively exceed the cap. To pre-flight, read the per-template nodes listing endpoint and compute remaining slots from `plan_node_limit - total_count_unfiltered`. - **Auto-match silently caps** -- the server-side `auto-match` endpoint (not currently exposed as an MCP action) caps at `plan_node_limit` even when more files are matchable (saves credits and LLM cost). Because neither `auto-match` nor the per-template `nodes/` listing is currently driveable from the MCP tool, agents needing to know exactly how many files were mapped after auto-match must call those REST endpoints directly or surface the gap to the user. - **MCP tool coverage** -- the `workspace` MCP tool exposes template CRUD (`metadata-template-{create,delete,list,details,update,clone}`), workspace assignment (`metadata-template-{assign,unassign,resolve,assignments}`), the view-creation flow (`metadata-template-{preview-match,suggest-fields}`), per-user saved views (`metadata-view-{get,save,delete}`, `metadata-views-list`), saved-view TSV export (`metadata-view-export`), keyword search across metadata values (`metadata-search`), and file-level metadata (`metadata-{get,set,delete,extract}`, `metadata-list-files`, `metadata-list-templates-in-use`, `metadata-versions`). It does **not** currently expose `nodes/add`, `nodes/remove`, the per-template `nodes/` listing, `auto-match`, `extract-all`, or `/metadata/eligible/`. Agents needing those workflows must surface the gap to the user. - **Template categories** -- legal, financial, business, medical, technical, engineering, insurance, educational, multimedia, hr. - **Field types** -- string, int, float, bool, json, url, datetime -- each with optional constraints (min, max, default, fixed_list, can_be_null). - **Two metadata types** -- template metadata conforms to template field definitions; custom metadata is freeform key-value pairs not tied to any template. - **System templates** -- pre-built templates that are automatically cloned when assigned to a workspace, so customizations do not affect the global definition. - **AI extraction** -- the `extract` action uses AI to analyze file content and automatically populate metadata fields. Extracted values are flagged with `is_auto: true`. Consumes AI credits. - **Version history** -- metadata changes are tracked with version snapshots, accessible via the `versions` action. - **Template IDs** are alphanumeric strings prefixed with `mt_` (e.g. `mt_abc123def456`). ### Ownership Transfer The primary way agents deliver value: build something, then give it to a human. Also the recommended action when the agent plan runs out of credits and API calls start returning 402 Payment Required -- transfer the org to a human who can upgrade to a paid plan. **IMPORTANT: Account type restriction.** The transfer/claim workflow (`org` actions `transfer-token-create`, `transfer-token-list`, `transfer-token-delete`, `transfer-claim`) is only available when the agent created an **agent account** (via `auth` action `signup`) and that agent account owns the org. If the agent is signed in with a **human account** (via `auth` action `signin`), the transfer/claim API cannot be used. Human-owned orgs must be upgraded directly by the human through the Fast.io dashboard. **The flow:** 1. Agent creates an agent account with `auth` action `signup` and an org with `org` action `create`, sets up workspaces with `org` action `create-workspace`, uploads files, configures shares 2. Agent generates a transfer token (valid 72 hours) with `org` action `transfer-token-create` 3. Agent sends the claim URL to the human: `https://go.fast.io/claim?[REDACTED_SECRET]` 4. Human clicks the link and claims the org with their account **When to transfer:** - The org is ready for human use (workspaces configured, files uploaded, shares set up) - The agent plan runs out of credits (402 Payment Required) -- transfer so the human can upgrade - The human explicitly asks to take over the org **Managing transfer tokens:** - `org` action `transfer-token-list` -- check for existing pending tokens before creating new ones - `org` action `transfer-token-delete` -- revoke a token if the transfer is no longer needed - `org` action `transfer-claim` -- claim an org using a token (used by the receiving human's agent) **What happens after transfer:** - Human becomes the owner of the org and all workspaces - Agent retains admin access (can still manage files and shares) - Human gets a free plan (credit-based, no trial period) - Human can upgrade to Pro or Business at any time **Agent use case:** A user says "Set up a project workspace for my team." You create the org, build out the workspace structure, upload templates, configure shares for client deliverables, invite team members -- then transfer ownership. The human walks into a fully configured platform. You stay on as admin to keep managing things. **402 Payment Required use case (agent account):** While working, the agent hits credit limits. Call `org` action `transfer-token-create`, send the claim URL to the human, and explain they can upgrade to continue. The agent keeps admin access and resumes work once the human upgrades. **402 Payment Required use case (human account):** The agent cannot transfer the org. Instead, inform the user that their org has run out of credits and they need to upgrade their billing plan. Direct them to the Fast.io dashboard or use `org` action `billing-create` to update to a paid plan. ### Workflow (Tasks, Worklogs, Approvals, Todos) Workspaces and shares support an optional workflow layer that adds structured task management, activity logging, approval gates, and simple checklists. Workflow features are controlled by a toggle -- they must be explicitly enabled before use. On shares, workflow access requires admin or named member role -- guests and view-only users cannot access workflow features. #### Enabling Workflow - **Workspaces:** `workspace` action `enable-workflow` with `workspace_id` - **Shares:** `share` action `enable-workflow` with `share_id` Check whether workflow is enabled via `workspace` action `details` or `share` action `details` -- look for `workflow: true` in the response. Disabling workflow (`workspace` action `disable-workflow` or `share` action `disable-workflow`) makes all workflow data inaccessible but preserves it. Re-enabling restores access. #### Task Lists and Tasks Tasks are organized into lists. Each workspace or share can have multiple task lists, and each list contains individual tasks. - **Task lists** have a name and optional description. Create with `task` action `create-list`, list with `task` action `list-lists`. - **Tasks** have a title, description, status, priority, assignee, dependencies, and optional node link. Create with `task` action `create-task`, list with `task` action `list-tasks`. - **Statuses:** `pending`, `in_progress`, `complete`, `blocked` - **Priorities:** 0 = none, 1 = low, 2 = medium, 3 = high, 4 = critical - **Assignees** are profile IDs (workspace or share members, including pending members). Use `task` action `assign-task` to assign or unassign. Pending members (invited but not yet registered) can be assigned tasks — their assignments are preserved when they sign up. - **Bulk operations:** `task` action `bulk-status` changes status on up to 100 tasks at once. - **Moving tasks:** `task` action `move-task` moves a task from one list to another within the same profile. Requires the source `list_id`, `task_id`, and `target_task_list_id`. Optionally set `sort_order` to control position in the target list (default: 0). - **Reordering:** `task` action `reorder-tasks` sets the display order of tasks within a list. `task` action `reorder-lists` sets the display order of task lists within a profile. Pass arrays of IDs in the desired order; the server converts them to `{id, sort_order}` objects for the API. - **Creator tracking:** Tasks and task lists include a `created_by` field (profile ID of the creator). - **Filtered lists:** `task` action `filtered-list` returns tasks filtered by category -- "assigned" (assigned to me), "created" (created by me), or "status" (by status, requires `status` param). Scoped to a workspace or share. - **Summary:** `task` action `summary` returns lightweight counts -- total tasks, breakdown by status, assigned-to-me, and created-by-me. - **Markdown output:** Pass `format: "md"` to get human-readable markdown instead of JSON. #### Worklogs Worklogs are append-only chronological activity logs scoped to tasks, task lists, or profiles (workspaces and shares). Entries cannot be edited or deleted after creation. - **Entries:** Regular log entries appended with `worklog` action `append`. Use for progress updates, decisions, reasoning, and status changes. - **Interjections:** Priority corrections created with `worklog` action `interject`. Interjections are always urgent and require acknowledgement from other participants. - **Acknowledgement:** `worklog` action `acknowledge` marks an interjection as seen. `worklog` action `unacknowledged` lists interjections that still need acknowledgement. Entries include an `acknowledgable` boolean -- when `true`, the entry is an unacknowledged interjection that can be acknowledged. - **Response fields:** Entries include `acknowledged` (boolean), `acknowledgable` (boolean), `updated` (`YYYY-MM-DD HH:MM:SS UTC` timestamp), and `created` (`YYYY-MM-DD HH:MM:SS UTC` timestamp). - **Profile-level listing:** `worklog` action `profile-list` lists all worklog entries at the workspace or share level (different from `list` which is entity-scoped). - **Filtered lists:** `worklog` action `filtered-list` returns worklogs filtered by category -- "authored" (worklogs authored by me) or "interjections" (interjections targeted at me). Optional `type` sub-filter ("info" or "interjection"). - **Summary:** `worklog` action `summary` returns lightweight counts -- total entries, breakdown by entry type, authored-by-me, and pending interjections. - **Markdown output:** Pass `format: "md"` for human-readable output. ### Comments & Discussions -- Quick Start **When to use:** leave feedback on a file, start a container-level discussion, or attach a note to a workflow approval/task. **Comments are JSON** -- always use JSON request bodies (`Content-Type: application/json`). This is the #1 source of 406 errors on the comment API. **Three relationship modes -- pick one before you call:** **1. Node-attached (thread on a specific file/folder):** - `comment` action `add` with `profile_type`, `profile_id`, `node_id`, `text` (and optional `reference` for anchoring, `parent_comment_id` for replies). - Wraps `POST /comments/{entity_type}/{parent_id}/{node_id}/`. List with action `list`. **2. Workspace/share-attached (top-level container thread):** - Not exposed by `comment` action `add` (which requires `node_id`). For container-level comments, call the underlying endpoint via `execute`: `POST /comments/{entity_type}/{parent_id}/` with JSON body `{body, parent_id?}`. List via `comment` action `list-all`. **3. Workflow-linked (attach existing comment to an approval or task):** - Step A: create a comment via mode 1 or 2. - Step B: `comment` action `link` with `comment_id`, `linked_entity_type: "task" | "approval"`, `linked_entity_id`. - Reverse-lookup with `comment` action `linked`. Detach with `comment` action `unlink`. A comment can have at most one workflow link at a time. **Valid `entity_type` / `profile_type` values:** - Create/list endpoints: `"workspace"` or `"share"` ONLY. - Link/unlink/linked endpoints: `"task"` or `"approval"` ONLY (not `worklog_entry`, not `node`, not `share`). **Threading:** single-level only. Set `parent_comment_id` (body field: `parent_id`) to the top-level comment id. Replies to replies auto-flatten as siblings. **Reactions:** `comment` action `reaction-add` with `comment_id` + `emoji`. One reaction per user per comment -- new ones replace the previous. **Anti-patterns:** - Don't pass `entity_type: "approval"` (or `"task"`) to a create endpoint -- they only accept `"workspace"` or `"share"`. To comment on an approval, create on the parent workspace/share first, then LINK. - Don't hand-roll `/approvals/{id}/comments/` or `/tasks/{id}/comments/` -- no such paths exist. - Don't use form-encoded bodies -- comments are JSON everywhere. In code-mode, that's `fastio.postJson()`, not `fastio.post()`. - Don't mix a `node_id` with a `parent_id` from a different workspace/share -- the node must live under the parent you name. 404 usually means wrong parent. - Don't try to link to `worklog_entry` -- only `task` and `approval` are link targets. ### Workflow Approvals -- Quick Start **When to use:** a file, folder, or task needs formal sign-off from one or more reviewers. **Approvals attach to entities directly** -- not to shares. Common mistake: creating a share to hold approvals. Don't. Shares are for distribution (Send/Receive/Exchange); approvals are review gates that live on the entity itself. **Step 1 -- Enable workflow on the workspace (one time, per workspace):** - `workspace` action `enable-workflow` with `workspace_id`. **Step 2 -- Create one approval per reviewer on the target node:** - `approval` action `create` with: - `profile_type: "workspace"` (or `"share"`), `profile_id: <workspace_id_or_share_id>` - `entity_type: "node"` (for a file or folder) - `entity_id: <node_id>` - `description` (the review request, 1-65535 chars) - `approver_id: <user_id>` -- the reviewer (must be a member of the profile; pending members are fine) - For multiple reviewers, repeat this call N times with different `approver_id` values. (A share-scoped `bulk-create` exists for "approve every file in this share" — see the **Approvals** tool reference below. There is no bulk-create for the "one node, many reviewers" pattern.) **Valid `entity_type` values:** `node` (file/folder), `task`, `worklog_entry`, `share`. Use `node` for file/folder reviews. **Resolve:** `approval` action `resolve` with `approval_id` and `resolve_action: "approve" | "reject"` (optional `comment`). **Anti-patterns to avoid:** - Don't create a share of the file -- approvals go on the node directly. - Don't create a task just to hold an approval on a file -- use `entity_type: "node"`. - Don't create todos -- todos are checklists, not review gates. - `approver_id` is a single user, not a group. For 3 reviewers, make 3 calls. #### Approvals Formal approval requests scoped to tasks, storage nodes, worklog entries, or shares. Use when a decision requires explicit sign-off. - **Create:** `approval` action `create` with `profile_type`, `profile_id`, `entity_type` ("task", "node", "worklog_entry", or "share"), `entity_id`, `description` (1-65535 chars), and optionally `approver_id` (a single profile ID, must be an entity member — can be a pending member). - **Resolve:** `approval` action `resolve` with `profile_type`, `profile_id`, `approval_id`, and `resolve_action: "approve"` or `"reject"` plus an optional comment. Only designated approvers can resolve. - **Bulk operations:** `approval` action `bulk-create` creates approval requests for every file and note in a share (max 50 nodes). `approval` action `bulk-approve` resolves all pending approvals in a share (skips stale approvals where version_match=false). `approval` action `bulk-reject` rejects all pending approvals in a share. - **Version tracking:** Approvals track `version_id` and `version_match`. If a node is modified after an approval is created, `version_match` becomes false (stale). Bulk operations skip stale approvals to prevent resolving outdated content. - **Filtered lists:** `approval` action `filtered-list` returns approvals filtered by category -- "pending", "created", "assigned", or "resolved". Scope to a workspace or share with `profile_type`/`profile_id`, or omit both for a cross-profile user-level view. - **Summary:** `approval` action `summary` returns lightweight counts -- created-by-me and assigned-to-me breakdowns with pending/approved/rejected counts. - **Update:** `approval` action `update` with `profile_type`, `profile_id`, and `approval_id` modifies a pending approval -- change description, approver, deadline, node reference, or metadata. Only pending approvals can be updated. - **Delete:** `approval` action `delete` with `profile_type`, `profile_id`, and `approval_id` permanently removes an approval (any status). `approval` action `bulk-delete` permanently removes all approvals in a share (up to 500). - **Statuses:** `pending`, `approved`, `rejected` - **Markdown output:** Pass `format: "md"` for human-readable output. #### Todos Simple flat checklists scoped to workspaces and shares. No nesting -- just a list of items that can be checked off. - **Create:** `todo` action `create` with a title. Optional `assignee_id` — can be a pending member. - **Toggle:** `todo` action `toggle` flips the done state of a single todo. `todo` action `bulk-toggle` sets done state on up to 100 todos at once. - **Update/Delete:** `todo` action `update` changes title or assignee. `todo` action `delete` soft-deletes a todo. - **Creator tracking:** Todos include a `created_by` field (profile ID of the creator). - **Filtered lists:** `todo` action `filtered-list` returns todos filtered by category -- "assigned" (assigned to me), "created" (created by me), "done" (completed), or "pending" (incomplete). - **Summary:** `todo` action `summary` returns lightweight counts -- total, done, pending, assigned-to-me, and created-by-me. - **Markdown output:** Pass `format: "md"` for human-readable output. #### Notes as Agent Knowledge Layer Notes (`type: "note"`) are markdown files stored in workspace storage (see **Notes** above). When combined with workflow features, notes become a knowledge layer: - **Automatic AI indexing:** When workspace intelligence is enabled, notes are ingested and indexed for RAG just like uploaded files. - **Link tasks to notes:** Tasks can reference storage nodes, including notes. Create context notes for project background, requirements, or reference material, then create tasks that link to those notes for full context. - **Worklogs for reasoning:** Use worklog entries to record decisions, progress, and reasoning over time. The chronological log builds a narrative that complements the structured task list. - **AI can search all context:** With intelligence enabled, AI chat can search across notes, worklogs, task descriptions, and uploaded files -- giving comprehensive answers grounded in the project's full history. **Recommended pattern:** Create notes for project context and requirements. Create task lists for work phases. Link tasks to relevant notes. Log progress with worklogs. Request approvals for decisions. The AI can then answer questions like "Why did we choose this approach?" by searching across all of these artifacts. ### Permission Parameter Values Several tools use permission parameters with specific allowed values. Use these exact strings when calling the tools. #### Organization Creation (`org` action `create`) | Parameter | Allowed Values | Default | |-----------|----------------|---------| | `perm_member_manage` | `Owner only`, `Admin or above`, `Member or above` | `Member or above` | | `industry` | `unspecified`, `technology`, `healthcare`, `financial`, `education`, `manufacturing`, `construction`, `professional`, `media`, `retail`, `real_estate`, `logistics`, `energy`, `automotive`, `agriculture`, `pharmaceutical`, `legal`, `government`, `non_profit`, `insurance`, `telecommunications`, `research`, `entertainment`, `architecture`, `consulting`, `marketing` | `unspecified` | | `background_mode` | `stretched`, `fixed` | `stretched` | #### Workspace Creation (`org` action `create-workspace`) and Update (`workspace` action `update`) | Parameter | Allowed Values | Default | |-----------|----------------|---------| | `perm_join` | `Only Org Owners`, `Admin or above`, `Member or above` | `Member or above` | | `perm_member_manage` | `Admin or above`, `Member or above` | `Member or above` | #### Share Creation (`share` action `create`) | Parameter | Allowed Values | Default | |-----------|----------------|---------| | `share_type` | `send`, `receive`, `exchange` | `exchange` | | `storage_mode` | `independent`, `workspace_folder` | `independent` | | `access_options` | `Only members of the Share or Workspace`, `Members of the Share, Workspace or Org`, `Anyone with a registered account`, `Anyone with the link` | `Only members of the Share or Workspace` | | `invite` | `owners`, `guests` | `owners` | | `notify` | `never`, `notify_on_file_received`, `notify_on_file_sent_or_received` | `never` | | `display_type` | `list`, `grid` | `grid` | | `intelligence` | `true`, `false` | `false` (always `false` for `workspace_folder` shares) | | `comments_enabled` | `true`, `false` | `true` | | `download_security` | `off`, `medium`, `high` | `off` | | `guest_chat_enabled` | `true`, `false` | `false` | | `anonymous_uploads_enabled` | `true`, `false` | `false` | | `workspace_style` | `true`, `false` | `true` | | `background_image` | `0`-`128` | `0` | **Share constraints:** - Receive and Exchange shares cannot use `Anyone with the link` access -- this option is only available for Send shares. - Password protection (`password` parameter) is only allowed when `access_options` is `Anyone with the link`. - Expiration (`expires` parameter in MySQL format `YYYY-MM-DD HH:MM:SS`) is not allowed on `workspace_folder` shares. - Intelligence is not supported on `workspace_folder` shares. Creating a workspace folder share always sets `intelligence=false` regardless of the value passed. Updating a workspace folder share with `intelligence=true` returns an error. AI chat with file/folder scope and semantic search are not available on workspace folder shares — use the parent workspace's AI endpoints instead. Basic chat and `files_attach` (direct file attachment) still work. - Field length and format constraints for `custom_name`, `title`, and `description` are documented in the **Profile Field Constraints** table below. - Color parameters (`accent_color`, `background_color1`, `background_color2`) accept JSON strings. - `create_folder` creates a new workspace folder for the share when used with `storage_mode='workspace_folder'`. - `anonymous_uploads_enabled` allows guests to upload files to Receive/Exchange shares without creating an account. Requires an "Anyone" access level. Not applicable to Send shares or Portals. ### Profile Field Constraints All profile fields are validated server-side. Requests that violate these constraints are rejected with a 400 error. | Entity | Field | API Key | Min | Max | Pattern | Required | Nullable | |--------|-------|---------|-----|-----|---------|----------|----------| | Org | domain | `domain` | 2 | 63 | `^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?$` | Yes (create) | No | | Org | name | `name` | 3 | 100 | No control chars | Yes | No | | Org | description | `description` | 10 | 1000 | No control chars | No | Yes | | Workspace | folder_name | `folder_name` | 4 | 80 | `^[\p{L}\p{N}-]+$` (letters, digits, hyphens) | Yes (create) | No | | Workspace | name | `name` | 2 | 100 | No control chars | Yes | No | | Workspace | description | `description` | 10 | 1000 | No control chars | No | Yes | | Share | custom_name | `custom_name` | 4 | 80 | `^[\p{L}\p{N}]+$` (letters, digits only) | Yes (create) | No | | Share | custom_url | `custom_url` | 10 | 100 | — | Yes | Yes | | Share | title | `title` | 2 | 80 | No control chars | Yes | Yes | | Share | description | `description` | 10 | 500 | No control chars | No | Yes | - **"No control chars"** = rejects Unicode control characters (`\p{C}`) - **Org domain**: lowercase ASCII alphanumeric + hyphens; cannot start/end with hyphen - **Workspace folder_name**: Unicode letters, digits, and hyphens. **Globally unique** -- not scoped to an org. Recommend `{org_id}-{name}` convention to avoid collisions (auto-applied by `create-workspace` when name is taken) - **Share custom_name**: Unicode letters and digits only (no hyphens or special chars) - **Share description** max is 500 (org/workspace is 1000) --- ## 4. Agent Plan -- Free Tier The agent plan is a free tier designed for AI agents. No credit card, no trial period, no expiration. Enough resources to build and demonstrate value, with room to grow when the org transfers to a human on a paid plan. ### Resource Limits | Resource | Included | |----------|----------| | **Price** | $0 -- no credit card, no trial period, no expiration | | **Storage** | 50 GB | | **Max file size** | 1 GB | | **Monthly credits** | 5,000 (resets every 30 days) | | **Workspaces** | 5 | | **Shares** | 50 | | **Members per workspace** | 5 | | **Share invitations** | 10 per share | | **Account auto-deletion** | Never | ### Credit Costs All platform activity consumes credits from the monthly 5,000 allowance: | Resource | Cost | |----------|------| | Storage | 100 credits/GB | | Bandwidth | 212 credits/GB | | AI chat tokens | 1 credit per 100 tokens | | Document pages ingested | 10 credits/page | | Video ingested | 5 credits/second | | Audio ingested | 0.5 credits/second | | Images ingested | 5 credits/image | | File conversions | 25 credits/conversion | When credits run out, the org enters a reduced-capability state and API calls return 402 Payment Required. The org is never deleted. Use `org` action `limits` to check current credit usage and remaining balance. **When you hit 402 or run low on credits:** - **Agent account (created via `auth` action `signup`):** Transfer the org to the human. Call `org` action `transfer-token-create` to generate a transfer token, then send the human the claim URL: `https://go.fast.io/claim?[REDACTED_SECRET]`. Once they claim the org they can upgrade to a paid plan with unlimited credits. You retain admin access and can resume work immediately after the upgrade. This is the expected workflow -- agents build on the free plan, then hand off to humans who pay when they are ready. - **Human account (signed in via `auth` action `signin`):** You cannot use the transfer/claim API. Tell the user they need to upgrade the org's billing plan directly. They can do this from the Fast.io dashboard or by calling `org` action `billing-create` to update their subscription to a paid plan. ### After Transfer -- Human Plan Options Once an agent transfers an org to a human, the human gets a free plan (credit-based, no trial period) and can upgrade: | Feature | Agent (Free) | Free (Human) | Pro | Business | |---------|-------------|--------------|-----|----------| | Monthly credits | 5,000 | 5,000 | Unlimited | Unlimited | | Storage | 50 GB | 50 GB | 1 TB | 5 TB | | Max file size | 1 GB | 1 GB | 25 GB | 50 GB | | Workspaces | 5 | 5 | 10 | 1,000 | | Shares | 50 | 50 | 1,000 | 50,000 | The transfer flow is the primary way agents deliver value: set everything up on the free agent plan, then hand it off. The human upgrades when they are ready, and the agent retains admin access to keep managing things. --- ## 5. Tool Categories The 19 tools use action-based routing. Each tool covers a specific area of the Fast.io platform and exposes multiple actions. ### auth Authentication, sign-in/sign-up, two-factor authentication, API key management, and OAuth session management. This is always the starting point for any agent interaction. **Actions:** signin, signout, signup, check, session, status, set-api-key, email-check, email-verify, password-reset-request, password-reset, 2fa-verify, 2fa-status, 2fa-enable, 2fa-disable, 2fa-send, 2fa-verify-setup, pkce-login, pkce-complete, api-key-create, api-key-update, api-key-list, api-key-get, api-key-delete, oauth-list, oauth-details, oauth-revoke, oauth-revoke-all ### user Retrieve and update the current user profile, search your contacts, manage invitations, upload and delete user assets (profile photos), check account eligibility, list shares the user belongs to, and manage personal AI instructions (markdown guidance the platform applies to AI features). **Actions:** me, update, search-contacts, close, details-by-id, profiles, allowed, org-limits, list-shares, invitation-list, invitation-details, accept-all-invitations, asset-upload, asset-delete, asset-types, asset-list, instructions-get, instructions-set, instructions-clear > `search-contacts` searches your personal contact list (prior interactions) and returns `{email: name}` only — no user_id, no context scope. To find members of a specific workspace/share/org, use `org action=members`, `workspace action=members`, or `share action=members`. > AI instructions: `instructions-get` / `instructions-set` / `instructions-clear` manage a single self-scoped markdown slot at `/user/me/instructions/` (max 65536 bytes UTF-8, full replace on set, soft-clear preserves audit row). The user profile has no `me` scope variant — it's already self-only. First read returns `content: ""` with null timestamps, not a 404. ### org Organization CRUD, member management, billing and subscription operations, workspace creation, invitation workflows, asset management (upload, delete), organization discovery, ownership transfer, custom domain management, and AI instructions (org-wide and per-user slots). **Actions:** list, details, create, update, close, public-details, limits, list-workspaces, list-shares, create-workspace, billing-plans, billing-create, billing-cancel, billing-details, billing-activate, billing-reset, billing-members, billing-meters, members, invite-member, remove-member, update-member-role, member-details, leave, transfer-ownership, join, invitations-list, invitation-update, invitation-delete, transfer-token-create, transfer-token-list, transfer-token-delete, transfer-claim, discover-all, discover-available, discover-check-domain, discover-external, asset-upload, asset-delete, asset-types, asset-list, custom-domain-get, custom-domain-create, custom-domain-delete, custom-domain-validate, instructions-get, instructions-set, instructions-clear > **Per-entity verbosity:** `list`, `discover-all`, `discover-available`, `discover-external`, `members`, `list-workspaces` accept a `detail` parameter (`terse` | `standard` | `full`) and default to `terse` (terse fields per the API spec: `id`, `domain`, `name`, `logo`). `details` defaults to `full` (drill-down adds `subscriber_trial_credits`, `billing_email`, social URLs, `encryption_key`, `perm_*` blocks, `dmca`, `owner_defined`, `platform`, `storage` on top of the standard surface — `description`, `plan`, `user_permission`, `user_status`, `member`, `closed`/`locked`/`suspended`, `created`/`updated`, `parent`, `capabilities`, `custom_domain`, `accent_color`, background and homepage, subscriber/billing flags). Pass an explicit `detail` to override. Per the API spec, the orgs spec enumerates `output=` for org-object endpoints — `details`, `list` (`/orgs/list/`), `discover-all`, `discover-available`, `discover-external` all fall under that scope. `list-workspaces` returns workspace objects so it falls under the workspaces spec (also enumerated). `members` returns member rows and is NOT enumerated for `output=` in any per-category spec, so passing `detail` there may be a silent no-op until the platform's compact-response coverage extends. Wiring is preserved end-to-end. `discover-check-domain` is a boolean availability check and does not accept `detail`. > AI instructions: `instructions-get`/`instructions-set`/`instructions-clear` accept an optional `scope` param: `profile` (default, org-wide slot — owner/admin only, 403 code 1680 for non-admins) or `me` (per-user slot — any member). The two scopes are independent and do NOT merge server-side; concat client-side if you want a combined view. content max 65536 bytes UTF-8, full replace on set, soft-clear preserves the audit row. ### workspace Workspace-level settings, lifecycle operations (update, delete, archive, unarchive), listing and importing shares, managing workspace assets, workspace discovery, notes (create, read, update), quickshare management, metadata operations (template CRUD, assignment, file metadata get/set/delete, AI extraction), workflow toggle (enable/disable tasks, worklogs, approvals, and todos), and AI instructions (workspace-wide and per-user slots). **Actions:** list, details, update, delete, archive, unarchive, members, list-shares, import-share, available, check-name, create-note, read-note, update-note, quickshare-get, quickshare-delete, quickshares-list, metadata-template-create, metadata-template-delete, metadata-template-list, metadata-template-details, metadata-template-update, metadata-template-clone, metadata-template-preview-match, metadata-template-suggest-fields, metadata-template-assign, metadata-template-unassign, metadata-template-resolve, metadata-template-assignments, metadata-view-get, metadata-view-save, metadata-view-delete, metadata-views-list, metadata-view-export, metadata-search, metadata-get, metadata-set, metadata-delete, metadata-extract, jobs-status, metadata-list-files, metadata-list-templates-in-use, metadata-versions, enable-workflow, disable-workflow, enable-import, disable-import, instructions-get, instructions-set, instructions-clear > **Per-entity verbosity:** `list`, `available`, `members`, `list-shares` accept a `detail` parameter (`terse` | `standard` | `full`) and default to `terse` (terse fields per the API spec: `id`, `name`, `folder_name`, `org_domain`, `user_status`). `details` defaults to `full` (drill-down adds `cloud_import`, `comments`, `chat`, `search`, `assets`, `workflow_permissions`, remaining branding, `perm_*` blocks, `platform`, `suspended`, `owner_defined`, `parents` on top of the standard surface — `description`, `workspace_level`, `closed`/`archived`/`locked`, `storage`, `created`/`updated`, `logo`, `accent_color`, `org_custom_hostname`, `intelligence`, `workflow`, `capabilities`). Pass an explicit `detail` to override. Per the API spec, the workspaces spec enumerates `output=` for workspace-object endpoints — `list`, `available`, `details`. `list-shares` returns share objects so it falls under the shares spec (also enumerated). `members` returns member rows and is NOT enumerated for `output=` in any per-category spec, so passing `detail` there may be a silent no-op until the platform's compact-response coverage extends. Wiring is preserved end-to-end. Metadata sub-actions and other workspace operations do not currently accept `detail`. > AI instructions: `instructions-get`/`instructions-set`/`instructions-clear` accept an optional `scope` param: `profile` (default, workspace-wide slot — owner/admin only, 403 code 1680 for non-admins) or `me` (per-user slot — any member, no guests). The two scopes are independent and do NOT merge server-side; concat client-side if you want a combined view. content max 65536 bytes UTF-8, full replace on set, soft-clear preserves the audit row. ### share Share CRUD, public details, archiving, password authentication, asset management, share name availability checks, workflow toggle (enable/disable tasks, worklogs, approvals, and todos), and AI instructions (share-wide and per-user slots). **Actions:** list, details, create, update, delete, public-details, archive, unarchive, password-auth, members, available, check-name, quickshare-create, enable-workflow, disable-workflow, instructions-get, instructions-set, instructions-clear > **Per-entity verbosity:** `list`, `available`, `members` accept a `detail` parameter (`terse` | `standard` | `full`) and default to `terse` (terse fields per the API spec: `id`, `title`, `share_type`, `share_level`, `share_root_id` (members-only), `creator` scalar user id). `public-details` defaults to `standard` (adds `share_category`, `storage_mode`, `folder_node_id`, `share_link` object, parent linkage, lifecycle flags incl. `locked`, `custom_name`, `custom_url`, `description`, `download_security`, `expires`, `created`/`updated`, `guest_chat_enabled`/`anonymous_uploads_enabled`, `user_status`, `intelligence`, `workflow` — no member roster, no owner-defined data). `details` defaults to `full` (member-facing surface: `capabilities`, `perm_*` blocks, activity tracking, `comments`, `event_flow`, `filesystem`, `invite`, `member_visibility`, `multiplayer`, `chat`, `search`, `assets`, `workflow_permissions`, `access_options`, `display_type`, full branding (accent color, logo, background), `password`, `platform`, `notify`, custom links, `owner_defined`, `deleted`, `storage`, `suspended`, `parents`). Pass an explicit `detail` to override. Per the API spec, the shares spec enumerates `output=` for share-object endpoints — `details`, `public-details`, `list` (`/shares/all/`), `available`. `members` returns member rows and is NOT enumerated for `output=` in any per-category spec, so passing `detail` there may be a silent no-op until the platform's compact-response coverage extends. Wiring is preserved end-to-end so callers can opt in once the server respects it. > AI instructions: `instructions-get`/`instructions-set`/`instructions-clear` accept an optional `scope` param: `profile` (default, share-wide slot — owner/admin only, 403 code 166463 for non-admins) or `me` (per-user slot — registered members only, 403 code 185733 for anonymous/link guests). The two scopes are independent and do NOT merge server-side; concat client-side if you want a combined view. content max 65536 bytes UTF-8, full replace on set, soft-clear preserves the audit row. ### storage File and folder operations within workspaces and shares. List, list recently modified files across all folders, create folders, move, copy, delete, rename, purge, restore, search (keyword or semantic when intelligence is enabled), add files from uploads, add share links, transfer nodes, manage trash, version operations, file locking, and preview/transform URL generation. Requires `profile_type` parameter (also accepted as `context_type`) (`workspace` or `share`). > **Per-node verbosity:** `list`, `recent`, `search`, `trash-list`, and `details` accept a `detail` parameter (`terse` | `standard` | `full`). Defaults: `list`/`recent`/`search`/`trash-list` → `terse` (compact rows: id, type, name, parent, mimetype, size, modified). `details` → `full` (drill-down — keeps ai.attach, virus, hashes, file_attributes, lock_info, long-form summaries available without an extra round-trip). Search bumps default to `full` automatically when the legacy `details: "true"` flag is also set, honoring the explicit hydration intent. **Search-specific:** semantic-search hits include `content_snippet` (the matching text chunk). The platform caps the snippet per detail level — `terse` → ~200 bytes, `standard` → ~600 bytes, `full` → untruncated. UTF-8 safe (won't split multi-byte sequences); a trailing `…` indicates truncation, so a hit with `snippet.endsWith('…')` has more content available — bump `detail` to retrieve more. Pass an explicit `detail` to override any default. Not to be confused with `details` (search-only `"true"|"false"` flag). > **REPLACE-by-default on copy/move:** If a file with the same name already exists in the destination folder, the existing target is silently sent to trash for rollback. The MCP response includes a `_warnings` block flagging this on every copy/move call (whether or not a collision actually happened — the API doesn't return a `replaced` indicator). Rename the source first if you want to avoid overwriting. > **Search at terse cannot distinguish trashed nodes from live ones.** Keyword search may return trashed nodes; the terse projection from the API does not include `deleted`/`parent: trash` fields. Bump `detail` to `standard` or higher to see trash status, or check the runtime `_next` hint in the search response. **Actions:** list, recent, details, search, trash-list, create-folder, copy, move, delete, rename, purge, restore, add-file, add-link, transfer, version-list, version-restore, lock-acquire, lock-status, lock-release, preview-url, preview-transform ### upload File upload operations. Chunked upload lifecycle (create session, upload chunks as plain text, base64-encoded binary, or blob reference, finalize, check status, cancel), single-call streaming uploads (`stream-upload` creates a stream session, streams the bytes, and auto-finalizes in one call), bulk uploads of many small files in one round-trip (`batch`), web imports from external URLs, upload limits and file extension restrictions, and session management. Large binary data flows through the `POST /blob` sidecar (100 MB cap per blob); for small binaries when the agent cannot reach `/blob` (sandboxed environments), use `content_base64` instead — the server decodes it server-side, capped only by MCP transport message size. > **`folder_id` alias for `parent_node_id`:** On `create-session`, `stream-upload`, and `web-import`, `folder_id` is accepted as an alias for `parent_node_id` — the canonical API-internal field name surfaces in finalize/status responses, so agents that read those responses and try to pass `folder_id` back will get the same behavior. Pass either name; they're equivalent. If both are passed with different values, `parent_node_id` wins. Note: `batch` action uses `folder_id` as its canonical name (target folder for the batch), NOT as an alias for `parent_node_id`. **Actions:** create-session, stream-upload, batch, chunk, stream, finalize, status, cancel, list-sessions, cancel-all, chunk-status, chunk-delete, web-import, web-list, web-cancel, web-status, limits, extensions, blob-info ### download Generate download URLs and ZIP archive URLs for workspace files, share files, and quickshare links. MCP tools cannot stream binary data -- these actions return URLs that can be opened in a browser or passed to download utilities. Requires `profile_type` parameter (also accepted as `context_type`) (`workspace` or `share`) for file-url and zip-url actions. Responses include a `resource_uri` field (e.g. `download://workspace/{id}/{node_id}`) that MCP clients can use to read file content directly via MCP resources. Direct download URLs include `?error=html` so errors render as human-readable HTML in browsers. **Actions:** file-url, zip-url, quickshare-details ### ai AI-powered RAG chat, document analysis, and shareable summaries in workspaces and shares. Create chats, send messages, read AI responses (with polling), list and manage chats, publish private chats, generate AI share markdown, track AI token usage, and auto-title generation. Requires `profile_type` parameter (also accepted as `context_type`) (`workspace` or `share`). **Actions:** chat-create, chat-list, chat-details, chat-update, chat-delete, chat-publish, chat-cancel, message-send, message-list, message-details, message-read, share-generate, transactions, autotitle > **Per-entity verbosity:** `chat-list`, `message-list` accept a `detail` parameter (`terse` | `standard` | `full`) and default to `terse` (id, title/excerpt, created, last activity, message count). `chat-details`, `message-details` default to `full` (full chat metadata: participants, attached/scoped files, publish state; message details add full response text, citations, token usage, files_attach payload). Pass an explicit `detail` to override. Mutation actions (chat-create, chat-update, chat-delete, chat-publish, chat-cancel, message-send, share-generate, autotitle), `transactions` (account usage), and the `message-read` polling loop do not accept `detail`. **Verification gap:** the AI API per-category spec only enumerates `output=` on metadata sub-endpoints; chat and message endpoints don't enumerate it, so passing `detail` here may currently be a silent no-op until the platform's compact-response coverage extends. Wiring is preserved end-to-end so callers can opt in once the server respects it. ### comment Comments are scoped to `{entity_type}/{parent_id}/{node_id}` where entity_type is `workspace` or `share`, parent_id is the 19-digit profile ID, and node_id is the storage node opaque ID. List comments on files (per-node and profile-wide with sort/limit/offset/filter params), add comments with optional reference anchoring (image regions, video/audio timestamps, PDF pages with text selection, text selections in markdown/notes), single-level threaded replies, recursive single delete, non-recursive bulk delete, get comment details, emoji reactions (one per user per comment), and workflow linking (link/unlink comments to tasks or approvals, reverse lookup). Comments use JSON request bodies. **Actions:** list, list-all, add, delete, bulk-delete, details, reaction-add, reaction-remove, link, unlink, linked > **Per-comment verbosity:** `list`, `list-all`, `linked` accept a `detail` parameter (`terse` | `standard` | `full`) and default to `terse` (id, body excerpt, author handle, created, parent_id, node_id). `details` defaults to `full` (long-form thread context, mention expansions, linked workflow entity details, full reaction roster, extended audit metadata). Pass an explicit `detail` to override. **Verification gap:** the comments API per-category spec does not currently enumerate an `output=` section, so passing `detail` may be a silent no-op until the platform's compact-response coverage extends to comments. Wiring is preserved end-to-end so callers can opt...


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal:  | SkillSpector: clean (LOW)