Table mode
A typed, real-time spreadsheet for humans and agents. Every row is a JSON object; every column is a schema entry with a type. Edits land live across every open tab and every connected agent. (Looking for prose, briefs, or narrative bodies instead? See doc mode.)
content-pipeline
Column types
textlongtextnumberstatuspersondateurlcheckboxselectCell selection & range
Click any cell to select. Shift-click another cell to extend the selection into a rectangle. Hold Shift while pressing arrow keys to grow the range one cell at a time. ⌘A / Ctrl+A selects every visible cell. Selection is the unit that copy, paste, drag-fill, and Delete operate on.
Row selection & bulk actions
Separately from the cell range, you can select whole rows via the checkbox that appears when you hover a row number. Row selection uses the same conventions as Finder / File Explorer:
- Click a row checkbox to toggle that row. The clicked row becomes the new range anchor.
- Shift-click another row to select every row from the anchor to the clicked row, inclusive, the same gesture as "select 20 rows at once" in a spreadsheet.
- ⌘-click / Ctrl-click another row to add (or remove) it without moving the anchor, so you can build a disjoint multi-selection and still Shift-extend later.
- With rows checked, Delete / Backspace deletes those rows; the bulk-action bar in the toolbar also shows a Delete button. Without any rows checked, Delete falls back to clearing the cells in the current range.
- The header-row checkbox toggles Select all (visible rows only, filters and hidden rows are respected).
Copy, paste, cut, fill
- Copy (⌘C / Ctrl+C) writes the selected range to the clipboard as TSV, paste it into Excel, Google Sheets, Numbers, or any text editor and the rectangle preserves shape.
- Paste (⌘V / Ctrl+V) reads the clipboard, parses TSV (handles quoted cells, embedded tabs/newlines), and pastes into the range starting at the anchor. Pastes wider/longer than the current sheet are clipped to the available cells.
- Cut (⌘X / Ctrl+X) copies the selected range to the clipboard, then clears the same range in one atomic step.
- Drag-fill the small accent square at the bottom-right of the selection, drag down to fill. Numeric and date sequences (e.g. 1, 2, 3 → 4, 5, 6 or 2026-01-01, 2026-01-02 → 2026-01-03) extrapolate; everything else cycles the source values.
- Delete / Backspace clears every cell in the range (or deletes the checked rows if any are selected).
Creating & editing columns
Click the + icon on the rightmost column to add one. Right-click any column header (or use the ⋯ menu on hover) to Rename, Sort, Add description, Hide, or Delete. Drag the header to reorder; the new position persists. Hidden columns appear as a chip next to the rightmost header, click to unhide.
Column descriptions show as a tooltip on hover, so the column contract (e.g. "ISO date, in local timezone" or "status: one of drafted/queued/active") stays one keystroke away from anyone editing the cell.
Find & replace
Click Find in the toolbar to substring-match across every visible cell. Type a replacement and press Enter (or click All) to rewrite every match in a single bulk update. Only free-text columns (text, longtext, url) are touched, structured types (status, person, date, select) are left intact so a free-text replace can't corrupt them.
Export to CSV
Click Export to download every visible row as a UTF-8 CSV (BOM-prefixed so Excel reads it without re-encoding). With a range selected, the menu offers a Selection · CSV option that exports just the rectangle, handy for sharing a slice without leaking the whole sheet.
Programmatically:
curl -X PUT https://trydock.ai/api/workspaces/content-pipeline/columns \
-H "Authorization: Bearer dk_..." \
-H "Content-Type: application/json" \
-d '{
"columns": [
{ "key": "title", "label": "GTM task", "type": "text", "position": 0, "width": 320 },
{ "key": "channel", "label": "Channel", "type": "select", "position": 1,
"options": [
{ "value": "linkedin", "label": "LinkedIn", "color": "#0A66C2" },
{ "value": "blog", "label": "Blog", "color": "#34D399" }
] },
{ "key": "status", "label": "Status", "type": "status", "position": 2,
"options": [
{ "value": "drafted", "label": "Drafted", "color": "#7A8B9E" },
{ "value": "queued", "label": "Queued", "color": "#F5B842" },
{ "value": "active", "label": "Active", "color": "#34D399" },
{ "value": "blocked", "label": "Blocked", "color": "#F87171" },
{ "value": "sealed", "label": "Sealed", "color": "#06D6A0" }
] },
{ "key": "owner", "label": "Owner", "type": "person", "position": 3 },
{ "key": "notes", "label": "Notes", "type": "longtext", "position": 4, "hidden": true }
]
}'Column fields you can set per entry: key, label, type, position, width, hidden, description, and options (for status and select).
Row CRUD
Rows are keyed by a stable id. Data is partial-patch merge on update, so you only send the fields you want to change.
POST /api/workspaces/:slug/rows
{ "data": { "title": "New LinkedIn thesis", "status": "drafted" } }PATCH /api/workspaces/:slug/rows/:id
{ "data": { "status": "sealed" } }
// other fields untouchedPATCH /api/workspaces/:slug/rows/bulk
{
"updates": [
{ "id": "row_a1...", "data": { "status": "active" } },
{ "id": "row_b2...", "data": { "status": "active", "owner": "Argus" } },
{ "id": "row_c3...", "data": { "status": "blocked" } }
]
}
// All-or-nothing: if any id is unknown, no row is updated.
// Cap: 500 updates per call. Each row in the batch costs the
// principal one row.updated event for SSE subscribers.DELETE /api/workspaces/:slug/rows/:idSee the full REST API reference for list/paginate/sort options.
Concurrency model
- Different rows = no conflict. Any number of agents can write in parallel.
- Same row, different fields = merged by the server (PATCH is field-level).
- Same row, same field = last write wins.
- Edits made by other collaborators flash pink in your tab; your own edits flash blue. Both fade in 700 ms.
- Recommendation: use
statusas a soft lock. Agents check the status before claiming a row.
Keyboard
Formulas
Any text-shaped cell can hold a spreadsheet formula. Press = in a selected cell (or click the cell and start typing =) to open the formula bar with the equals sign already seeded. Type a formula like =SUM(B1:B10), =AVERAGE(B1:B10)*0.21, or =IF(C1>100, "ok", "low") and press Enter or Tab to commit. The cell renders the computed value; the bar shows the formula source whenever the cell is selected.
Don't remember the function name? Click the fx chip in the formula bar to browse all 39 functions grouped by category, Math, Logic, Text, Date, Lookup, Predicates.
Change a source cell and every dependent recomputes in the same tick. If a formula errors (=A1/0 or a reference to a deleted column), the cell shows the canonical code (#DIV/0!, #REF!) in soft red and the formula bar surfaces a plain-language fix when the cell is selected.
Full reference: Formulas guide (function catalog, A1 syntax, error treatment, persistence model).
What you don't get (yet)
- Per-column data validation rules.
- Row grouping and pivot views.
Frequently asked questions
- What is a table-mode workspace in Dock?
- A workspace where the primary surface is a typed-row table with structured columns. Best for records with shared shape: tasks, leads, ingest rows, cron output, content pipelines. Both humans and agents append + edit rows in real time.
- How do I add a column to a Dock table?
- Click the `+` at the right edge of the column header strip; pick a type (text, longtext, number, status, person, date, url, checkbox, select). Or, from an agent: `POST /api/workspaces/:slug/columns` with `{ key, label, type }`. The column auto-positions at the end. Learn more →
- How do I bulk-edit rows in a Dock table?
- Select multiple rows (shift-click or drag), then use the bulk-actions menu in the toolbar (set status, assign owner, delete). Programmatic bulk ops: `move_rows` (MCP) for cross-surface moves, or PATCH each row in a loop.
- Can I export a Dock table to CSV?
- Yes. Settings menu → Export → CSV downloads the current table view (respects active filters and column order). For programmatic export use `GET /api/workspaces/:slug/rows?format=csv`.
- How do I filter rows in a Dock table?
- Click a column header → Filter, or use the filter bar above the table. Filters compose (multiple columns AND together). Filter state lives in the URL so you can share a filtered view with a teammate; agents can pass equivalent query params on `GET /rows`.
- How do I find and replace text in a Dock table?
- Cmd-F (Ctrl-F on Windows) opens the find bar with replace toggle. Scoped to the current workspace. For multi-workspace search, use Cmd-K (semantic search) or `GET /api/search?q=…`.
- How does Dock handle simultaneous edits to the same row?
- Last-write-wins on cell-level updates. The activity feed shows both writes with full attribution; nothing silently overwrites without a record. For doc bodies (richer state), the same last-write-wins applies; both kinds emit events for downstream reaction.
- How do I make a column read-only for agents?
- Per-column read-only is on the roadmap. Today: scope the agent to a viewer or commenter role on the workspace, or use webhooks + dangerous-ops to gate writes. For a hard column lock, add a webhook that reverts changes to that column from the agent's principal id.
- Can my AI agent read row updates in real time?
- Yes, via SSE on `GET /api/workspaces/:slug/stream`, or via webhooks subscribed to `row.created` / `row.updated`. SSE is best for in-process agents that already have a long-lived connection; webhooks are best for cron + serverless agents. Learn more →
- How do I delete a row in a Dock table?
- Hover the row → kebab → Delete (UI), or `DELETE /api/workspaces/:slug/rows/:id` (REST), or MCP `delete_row` (agent). Hard-delete; not recoverable. For audit-trail-friendly deletion patterns, set a status column to `archived` instead.
Related
- Formulas: 39-function catalog, A1 cell references, ranges, error treatment, persistence model.
- Rows API: REST surface for the same cells (single row, bulk, move between surfaces, history).
- Surfaces API: manage the table tabs that hold rows.
- Cell comments: anchor a thread to a single cell.
- Keyboard shortcuts: sheet navigation, copy/paste, find & replace.