Integration details
Description
Anchor gives ChatGPT a shared drive where it can create files and organize them in folders. ChatGPT can read and write files in HTML, Markdown (MD), JSON, CSV, and other text formats, design typed tables, and query them with SQL. It can move files around, make copies, and keep everything organized. Every file, table, and folder it creates is shareable with your team, while Anchor handles storage, permissions, and versioning. Log in once, with no API keys and no setup, and ChatGPT only ever touches what you can access.
- Integration type
- Plugin
- Verification status
- Not applicable
- Platform
- ChatGPT
- Primary Subcategory
- Cloud File Storage
- Secondary Subcategories
- None listed
- Brand
- Anchor
- Access
- Account required
- First tracked
- 2026-08-25
- Tool count
- 15
- Geography
- US
The Primary Subcategory used for this profile’s headline score.
Other Subcategories where the Integration is listed.
ChatGPT Plugin Discovery Score
ChatGPT Plugin discovery is coming soon
ChatGPT can surface a Plugin when it matches a user's request.Your Plugin Discovery Score measures how often yours appears.
No spam. Unsubscribe any time.
What discovery looks like

Competing in ChatGPT Cloud File Storage
View Category15 tools agents can invoke
Add a new column to an existing Anchor table. This is the column-level counterpart to create_table — same column schema, but for a single column added after the table already exists. Example input: { "table_id": "a195e7a1-b0a0-7f00-a1b2-c3d4e5f60001", "column": { "identifier": "project_id", "display_name": "Project", "type": "INTEGER", "isUnique": false, "isRequired": false, "foreignKeyTableIdentifier": "a195e7a1-b0a0-7f00-a1b2-c3d4e5f60002", "foreignKeyOnDelete": "CASCADE" } } Example with required ENUM column and defaultValue: { "table_id": "a195e7a1-b0a0-7f00-a1b2-c3d4e5f60001", "column": { "identifier": "priority", "display_name": "Priority", "type": "ENUM", "isUnique": false, "isRequired": true, "possibleValues": ["P0", "P1", "P2"], "defaultValue": "P2" } } Under the hood this runs an ALTER TABLE … ADD COLUMN on the underlying PostgreSQL table: ALTER TABLE anchor_tables."<table_uuid>" ADD COLUMN <identifier> <PG_TYPE> [NOT NULL] [UNIQUE] [DEFAULT <value>::<PG_TYPE>] [CHECK (...)] [REFERENCES <fk_table>(record_id) ON DELETE CASCADE|SET NULL]; Type mapping: STRING → TEXT, NUMBER → DOUBLE PRECISION, INTEGER → BIGINT, BOOLEAN → BOOLEAN, ENUM → TEXT (with CHECK constraint), DATE → DATE, DATETIME → TIMESTAMPTZ, EMAIL / CREATED_BY_EMAIL → TEXT. RULES: - The column uses exactly one of three forms: standard, ENUM (requires possibleValues), or foreign key (requires foreignKeyTableIdentifier + foreignKeyOnDelete). - Cannot add a column whose identifier already exists in the table. - If the column is required (isRequired: true), defaultValue MUST be set — existing rows are backfilled with it via DEFAULT. The column will be rejected without it. - If the column is not required, defaultValue is optional — existing rows get NULL when omitted. - Unique columns: when isUnique is true, isRequired must be false and defaultValue must not be set — existing rows are filled with NULL (which satisfies uniqueness). - CREATED_BY_EMAIL columns: defaultValue must NOT be set (the enforcement trigger overrides it on every INSERT/UPDATE with the caller's email). New rows inserted after the column is added are always populated by the trigger. Existing rows cannot be backfilled — the trigger only fires on INSERT/UPDATE — so isRequired may only be true if the table currently has zero rows. On a non-empty table, isRequired must be false; existing rows will be NULL while new rows are auto-filled by the trigger.
add_table_column
Copy a file. Only files can be copied (not folders). The copy gets a new ID, the caller becomes the owner, and no existing access roles are carried over. For tables, the full PostgreSQL table (schema + data) is duplicated. Requires read access to the source file and write access to the destination folder. Only in-org copies are allowed.
cp
Create a new folder. Pass folder_id to create a subfolder inside an existing folder, or org_id to create a folder at the org root. Requires permission at the parent location.
mkdir
Create a new table in Anchor (File type: TABLE). Tables are structured data stores with typed columns. Under the hood, this creates a PostgreSQL table whose name is the returned UUID. The table is displayed to users without exposing database concepts, but all column configurations (types, constraints, foreign keys) map directly to PostgreSQL features — the Postgres type is noted next to each config option. Tables are designed to work together through normalization: - Master data entities (Customers, Products, Employees, Vendors, Locations, Categories, etc.) are the core reusable "nouns" of an organization. - Transactional tables (Orders, Invoices, Appointments, Transactions) reference master tables via foreign keys (foreignKeyTableIdentifier) rather than embedding fields like "customer_name" or "product_name" directly. - Existing tables in the organization can be inspected with ls and describe_table to identify foreign key targets and avoid duplicating master data. SCHEMA RULES: - Every table must include a "record_id" column (INTEGER, isUnique: true, isRequired: true). This column is auto-generated (GENERATED ALWAYS AS IDENTITY) — do NOT include record_id values in subsequent INSERT queries. - Each column has an identifier (snake_case, immutable, used in SQL) and a display_name (human-friendly, shown in UI). - Each column uses exactly one of three forms: standard, ENUM (requires possibleValues), or foreign key (requires foreignKeyTableIdentifier + foreignKeyOnDelete). - columns is an array of column definitions (preferred). A legacy map keyed by identifier is also accepted. - The full column schema is set at creation time. After creating, use describe_table to inspect the schema. Example input: { "folder_id": "0195e7a1-b0a0-7f00-a1b2-c3d4e5f60001", "name": "Tasks", "description": "Tracks work items and their status", "columns": [ { "identifier": "record_id", "display_name": "Record ID", "type": "INTEGER", "isUnique": true, "isRequired": true }, { "identifier": "name", "display_name": "Name", "type": "STRING", "isUnique": false, "isRequired": true, "defaultValue": "" }, { "identifier": "due_date", "display_name": "Due Date", "type": "DATE", "isUnique": false, "isRequired": false }, { "identifier": "priority", "display_name": "Priority", "type": "ENUM", "isUnique": false, "isRequired": true, "possibleValues": ["P0", "P1", "P2"], "defaultValue": "P2" } ] }
create_table
Permanently delete a table or other-file (HTML, Markdown, CSV, etc.). The deletion is immediate and irreversible — there is no trash or undo. For a TABLE, the underlying data is dropped along with the file; for an OTHER file, the stored content is removed. Only an owner of the file (or of a parent folder) can delete a file. This is a destructive action — confirm with the user before deleting files you did not create.
rm_file
Permanently delete a column from an existing Anchor table. The deletion is immediate and irreversible — all data in the column across every row is destroyed and cannot be recovered. This is a destructive action — confirm with the user before deleting a column. Under the hood this runs an ALTER TABLE … DROP COLUMN on the underlying PostgreSQL table: ALTER TABLE anchor_tables."<table_uuid>" DROP COLUMN <column_identifier>; The "record_id" column cannot be deleted — it is the primary key.
delete_table_column
Get a table's full schema, metadata, and row count. Use this to understand a table's structure before querying or modifying it with query_table, add_table_column, or delete_table_column. Does not return row data — use query_table for that. For tables with many rows, use query_table to peek at a sample or write aggregated SQL queries rather than fetching all rows. Example input: { "table_id": "a195e7a1-b0a0-7f00-a1b2-c3d4e5f60001" } Returns: - Row count: total number of rows in the table. For large tables, use query_table with LIMIT to peek at sample data, or write aggregated SQL queries (COUNT, SUM, AVG, GROUP BY, etc.) instead of selecting all rows. - Column definitions: each column has an identifier (snake_case, immutable — use this in SQL queries) and a display_name (human-friendly — use this when communicating with the user). Also includes types, constraints, allowed values, and foreign key references. - Timestamps: creation and last update times.
describe_table
Get links to view or download a file. The view link opens the file as a live, rendered page in the browser that a human can read and share. Files of type OTHER return both a view link and a download link; tables return a view link only (they have no downloadable file).
file_link
Get a deep link where the user can manually upload files to a folder in the Anchor UI. Supports only files of type OTHER; tables are created by their dedicated tool.
file_upload_link
Map of your orgs, folders, and files. A good starting point when the layout isn't already known. If you're not sure where to begin, omit `target` (or pass {by:"overview"}) — it lists every org you belong to plus "Shared with Me", each expanded breadth-first under number_of_items (default 20). To scope in, set `target` to exactly one tagged variant: - {by:"overview"} → every org + "Shared with Me" (the default). - {by:"org", org_id} → that org's root folders, expanded breadth-first. - {by:"folder", folder_id} → that folder, then its children, expanded breadth-first. - {by:"file", file_id} → one file's details (leaf — no recursion). - {by:"shared_with_me"} → folders and files shared with you from outside your orgs. Reading the output (indented text, not JSON): - Lines starting with "- " are items. Lines without "- " are properties of the nearest item above them. - Indentation is 2 spaces per level; a child sits one level deeper than its parent. - Folders end with "/". Files do not. Orgs are prefixed with "[Org] ". "Shared with Me" has no id. - Every item shows its uuid after " -- " (except "Shared with Me"). - "# items: N" under a folder/org is its total visible child count. If fewer rows appear beneath it, the rest were trimmed by number_of_items — call ls with target {by:"folder",folder_id} to drill in. - A trailing "... N more orgs not shown" line means the overview hit number_of_items before listing every org. "Shared with Me" is always shown; raise number_of_items or scope in with {by:"org",org_id}. Example: - [Org] Neural Bridge -- 019385a0-0000-0000-0000-000000000001 # items: 5 - Home/ -- 019385a0-0000-0000-0000-000000000002 # items: 2 - file1 -- 019385a0-0000-0000-0000-000000000010 - file2 -- 019385a0-0000-0000-0000-000000000011 Tunables (all optional): - number_of_items (default 20): global budget across orgs + folders + files. - show_org_details / show_folder_details / show_file_details / show_shared_with_me_details: add property blocks (timestamps, type, sizes, versions, …) per item type. - hide_orgs / hide_folders / hide_files / hide_shared_with_me: drop a whole category from the output and from the budget. IDs appear in Anchor URLs: - https://anchor.cc/org/$org_id - https://anchor.cc/folder/$folder_id - https://anchor.cc/file/$file_id — also /table/$file_id - https://anchor.cc/shared-with-me — target {by:"shared_with_me"}
ls
List the organizations the user belongs to. Returns each org's id, name, and creation timestamp.
list_orgs
Move or rename a file or folder. Source can be a file or folder. Destination can be an org (root level) or a folder — but files cannot be moved directly under an org, only into folders. Requires editor (or owner) access on the source and on a destination folder; moving a folder to an org root only requires membership in that org. Valid argument combinations (set exactly one source; unused fields must be omitted or null): • Move a file into a folder: { file_id, destination_folder_id, new_name? } • Rename a file in place: { file_id, new_name } • Move a folder into a folder: { folder_id, destination_folder_id, new_name? } • Move a folder to an org root: { folder_id, destination_org_id, new_name? } • Rename a folder in place: { folder_id, new_name } Constraints: set exactly one of file_id / folder_id. Provide at least one of destination_folder_id, destination_org_id, or new_name. destination_org_id is only valid for folder sources (files cannot live at the org root). destination_folder_id takes precedence over destination_org_id when both are set.
mv
Run a SQL query against Anchor tables. This executes real SQL against the underlying PostgreSQL database — every Anchor table is a Postgres table whose name is its UUID. ALLOWED STATEMENTS: SELECT, INSERT, UPDATE, DELETE (data operations only). BLOCKED STATEMENTS: CREATE, ALTER, DROP, TRUNCATE, triggers, indexes, and all other schema/DDL operations — these are rejected. Use create_table, add_table_column, or delete_table_column for schema changes. ONE STATEMENT PER CALL: - Exactly one SQL statement per call: no ";"-stacked statements, no BEGIN/COMMIT wrappers (each call already runs in its own transaction). - Bulk-insert with a single multi-row VALUES list. - For upserts use INSERT ... ON CONFLICT (MERGE is not allowed). - Inline literal values; bind parameters ($1) are not supported. ACCESS CONTROL: - Viewer access (read-only): SELECT queries only. - Editor access (read + write): SELECT, INSERT, UPDATE, and DELETE. If a user only has viewer access, write queries will be rejected with an access error. REFERENCING TABLES AND COLUMNS: - Tables are referenced by UUID as a double-quoted identifier: SELECT * FROM "a195e7a1-b0a0-7f00-a1b2-c3d4e5f60001" - Columns are referenced by their snake_case identifier (no quoting needed). - Always call describe_table first to discover column identifiers, types, and constraints before writing queries. - Every query must reference at least one Anchor table (a bare SELECT 1 is rejected). - System catalogs (pg_catalog, information_schema) are not queryable; use describe_table for schema discovery. CROSS-TABLE JOINS: You can JOIN multiple tables in a single query as long as all tables belong to the same organization. Cross-org queries are not allowed. RECORD_ID: The record_id column is auto-generated (GENERATED ALWAYS AS IDENTITY). Never include record_id in INSERT statements — it is assigned automatically. You can use record_id in WHERE clauses, JOINs, and SELECT lists. Add RETURNING record_id to an INSERT to get the generated ids back. CREATED_BY_EMAIL COLUMNS: Columns of type CREATED_BY_EMAIL are enforced server-side by a trigger that overrides the column with the calling user's email on every INSERT and UPDATE. You usually don't need to include these columns in writes — INSERT without them and the trigger will populate them automatically. If you do include a CREATED_BY_EMAIL column in an INSERT or UPDATE, you MUST set it to your own email (the email of the user making the request); any other value will be silently overwritten with your email by the trigger, so inserting or updating a peer's email will not work. DESTRUCTIVE OPERATIONS (UPDATE, DELETE): Before running UPDATE or DELETE queries, ALWAYS confirm with the user first. Describe what rows will be affected (e.g. "This will delete 3 rows where status = 'archived'") and wait for explicit approval. Data modifications cannot be undone. EXAMPLES: Select all rows: SELECT * FROM "a195e7a1-b0a0-7f00-a1b2-c3d4e5f60001" Select with filter: SELECT name, email FROM "a195e7a1-b0a0-7f00-a1b2-c3d4e5f60001" WHERE status = 'active' ORDER BY name Insert a single row (omit record_id): INSERT INTO "a195e7a1-b0a0-7f00-a1b2-c3d4e5f60001" (name, email, status) VALUES ('Alice', '[email protected]', 'active') RETURNING record_id Insert multiple rows: INSERT INTO "a195e7a1-b0a0-7f00-a1b2-c3d4e5f60001" (name, email, status) VALUES ('Alice', '[email protected]', 'active'), ('Bob', '[email protected]', 'pending') Join two tables (same org): SELECT o.order_date, c.name AS customer_name, o.total FROM "a195e7a1-b0a0-7f00-a1b2-c3d4e5f60001" o JOIN "a195e7a1-b0a0-7f00-a1b2-c3d4e5f60002" c ON o.customer_id = c.record_id WHERE o.total > 100 Aggregate query: SELECT status, COUNT(*) AS count FROM "a195e7a1-b0a0-7f00-a1b2-c3d4e5f60001" GROUP BY status Update rows (confirm with user first): UPDATE "a195e7a1-b0a0-7f00-a1b2-c3d4e5f60001" SET status = 'archived' WHERE last_login < '2024-01-01' Delete rows (confirm with user first): DELETE FROM "a195e7a1-b0a0-7f00-a1b2-c3d4e5f60001" WHERE status = 'archived'
query_table
Reads the parsed text content of an OTHER file (e.g. extracted text from PDFs, spreadsheets, documents, or text files written via write_file). Applies only to OTHER files where textable is true. Text-like formats (Markdown, HTML, JSON, CSV/TSV, XML/YAML, plain text, and source code) are returned as raw bytes verbatim — byte-for-byte identical to what write_file would round-trip, so oldString-based edits will match exactly. Binary document formats (PDF, DOC/DOCX, PPT/PPTX, XLS/XLSX, application/rtf) are returned as extracted plain text only — the original binary structure is lost and write_file cannot edit these formats. For TABLE files use describe_table or query_table.
read_file
Each file becomes a live, shareable page (its `view_link`), so prefer writing to Anchor whenever the user will want to view, keep, or share what you produce. Create or edit one or more textable OTHER files in a single call. Pass `writes`: an array where each entry independently creates a new file (folder_id + name) or edits an existing one (file_id). Malformed entries are rejected by schema validation before anything runs (the whole call fails — fix the entry and retry). Once the batch starts, entries are applied sequentially in array order; each gets its own per-item result so a single runtime failure (e.g. NO_ACCESS, EDIT_CONFLICT) does not halt the rest of the batch — the response array preserves the same length and order as the input. Writable mime types — text only. write_file accepts plain-text formats whose mime type is in the platform textable allowlist: Markdown (.md), plain text (.txt, .log, .ndjson), JSON (.json), HTML (.html), CSV/TSV (.csv, .tsv), XML (.xml), YAML (.yaml, .yml), TOML (.toml), SQL (.sql), and source code (.tsx, .ts, .js, .jsx, .css, .py, .go, .rs, .rb, .java, .c, .cpp, .cs, .php, .swift, .kt, .scala, .sh, .lua, .dockerfile, etc.). Binary document formats — PDF, DOC/DOCX, PPT/PPTX, XLS/XLSX, application/rtf — CANNOT be created or rewritten via write_file (they are read-only through read_file). Images, archives, and other binary content are likewise unsupported. The mime type is auto-detected from content + filename extension on every create and every full rewrite; if the detected type is not on the allowlist the entry is rejected with NOT_TEXTABLE. Per-entry shape — exactly one of the following three forms (enforced by the input schema; each form accepts only its listed fields): • Create new: { folder_id, name, text_content: { newString } }. • Edit existing — surgical: { file_id, text_content: { newString, oldString, replaceAll? } }. oldString must match exactly once unless replaceAll is true; include surrounding context to keep oldString unambiguous. • Edit existing — full rewrite: { file_id, text_content: { newString, rewrite: true } }. Replaces the entire file with newString. Picking a format for documents and presentations. Default to HTML (.html) for documents, write-ups, and slides — full layout control that Markdown's constrained renderer can't match. Use .md only when explicitly requested or for README/changelog-style source. Markdown contract (`.md` files). Markdown files are rendered with GitHub-Flavored Markdown (GFM): headings (`#`–`######`), lists, task lists (`- [ ]`), tables, fenced code blocks, blockquotes (`>`), autolinks, strikethrough (`~~`). A limited HTML subset is supported (the same allowlist GitHub uses: `<h1>`–`<h6>`, `<p>`, `<blockquote>`, `<details>`/`<summary>`, `<pre>`, `<code>`, `<kbd>`, `<sub>`/`<sup>`, `<table>` family, `<a>`, `<img>`, `<hr>`, `<br>`, `<em>`, `<strong>`, `<del>`, `<ins>`). The `style`, `class`, and `id` attributes are stripped, as are `<script>`, `<iframe>`, `<object>`, `<embed>`, and bare `<div>`/`<span>` wrappers — do NOT rely on inline CSS or layout HTML; it will be silently removed and the document will collapse to plain text. Write semantic Markdown (`## Heading`, `> blockquote`, `**bold**`, lists, tables) — the renderer applies consistent typography, spacing, and color tokens automatically. Designing a custom font/color/border per document is an anti-pattern: the doc will look broken in the Anchor preview and unportable everywhere else. HTML contract (`.html` files). HTML files are rendered inside a full-screen iframe with no surrounding chrome and no parent-supplied padding — the document IS the viewport. Author every .html as a complete, self-contained page: • Include `<!doctype html>`, `<html>`, `<head>`, and `<body>`, and a viewport meta tag: `<meta name="viewport" content="width=device-width, initial-scale=1">`. • Put padding/margin on `body` (or a single content wrapper) so text does not touch the iframe edges. Constrain a readable measure (e.g. `max-width: 72ch; margin: 0 auto;` for prose; full-bleed sections for slides) so long lines don't sprawl on wide screens. • Be mobile-first and responsive. Mobile viewports (≤ 480px wide) are common — use fluid units (`rem`, `%`, `vw`/`vh`, `clamp()`), media queries, and flex/grid that wraps. Never assume a desktop width; never produce horizontal scroll on a phone. • For slide-like presentations, build each slide as a full-viewport section (`min-height: 100vh`) and let the user scroll between them; keep titles, bullets, and imagery readable on a narrow viewport. • Inline `<style>` and `<script>` are allowed and encouraged — the iframe sandboxes the document, so there is no parent CSS to inherit or conflict with. Choose colors, fonts, and spacing deliberately; nothing is applied for you. • Always use relative hyperlinks for inter-document links — never hardcode absolute URLs (e.g. `https://anchor.cc/...`) for content that lives in the same folder. Use relative paths (`./other-file.html`) for sibling files. Absolute links break when the document is moved, copied, or shared, while relative paths stay portable. In-page navigation is not supported (the document is rendered inside an iframe), so do not rely on `href="#..."` fragment anchors for tables of contents or cross-references. • Links to a different page or external site MUST add `target="_blank" rel="noopener"` — the document lives in an iframe, so a plain link loads the destination inside that frame instead of as a full page. Constraints: ≤ 100 writes per call. Rewrites that produce non-textable content are rejected. Each resulting file must stay under the platform file-size ceiling, else the entry is rejected with FILE_TOO_LARGE. Inspect the returned `results` array: each entry is either a success object (file_id, name, mime_type, size_bytes, line_count, created_or_updated) or an error object ({ error, detail? }). The `summary` field reports per-status counts so the agent can see at a glance whether the batch fully succeeded.
write_file
How do I improve a ChatGPT Plugin's discoverability?
The levers are the listing surface agents actually read: names, descriptions, keywords, tool metadata, and registry health. Which lever matters depends on where discovery breaks, which is what continuous measurement shows.
What are Anchor alternatives on ChatGPT?
As of 2026-08-25, Anchor competes with Box, Dropbox, FileAssist, FilesAnywhere, firestorage.ai, IDrive e2, WeTransfer in ChatGPT Cloud File Storage, ranked by public Discoverability Score.
Where is this profile measured?
This profile uses the geography attached to the latest public registry snapshot: US. Locale tags are intentionally omitted.