Files
inkreach-teable-cli/.agents/skills/inkreach-teable/guides/tables-fields.md
T
yeuimu 5a984eb5f8 docs(skill): update inkreach-teable skill for fixed field routes + select-choice dependency
- cli-reference.md: field get/update/delete now <tableId> <fieldId>;
  new field visible-choices command; note --options goes via convert API
- tables-fields.md: correct update/delete signatures; options-rewrite
  semantics (convert API, whole-replace not merge); new section on
  select-choice visibilityFilter dependency (read/write/evaluate,
  backend 400 guards, write-time enforcement message)
2026-08-16 05:35:23 +00:00

16 KiB

Tables, Fields, Records & Views

Complete guide for building table structures and working with data via the inkreach-teable CLI.

Quick Start

Minimal walkthrough — create a table with fields in one shot, then insert a record:

# 1. Create a "Tasks" table with 4 fields
inkreach-teable table create --name "Tasks" --base-id bseXXX \
  --fields '[
    {"name":"Title","type":"singleLineText"},
    {"name":"Status","type":"singleSelect","options":{"choices":["Todo","Doing","Done"]}},
    {"name":"Due Date","type":"date"},
    {"name":"Est Hours","type":"number","options":{"formatting":{"precision":1}}}
  ]'

# 2. Insert a record
inkreach-teable record create --table-id tblXXX \
  --fields '{"Title":"Ship sign-up flow","Status":"Doing","Due Date":"2025-06-15","Est Hours":3.5}'

# 3. Verify
inkreach-teable record get --table-id tblXXX

Tip

: table create --fields creates the table AND all fields atomically. For existing tables, use field create.


Tables

Create

inkreach-teable table create --name "<name>" [--base-id <id>] \
  [--fields '<json>'] [--description <desc>]
Flag Required Description
--name yes Display name (unique within base)
--base-id no Defaults to stored config
--fields no Array of field objects (see below)
--description no Optional description

--fields format: JSON array of {name, type, [options], [description]} objects. Allowed types and aliases:

Shorthand Full type Shorthand Full type
text, str singleLineText long longText
num, int number check, bool checkbox
sel, select singleSelect multi, tags multipleSelect
date date rate, star rating
user, person user file, attach attachment
link, rel link rollup rollup
formula formula auto autoNumber
created createdTime modified lastModifiedTime
createdBy createdBy modifiedBy lastModifiedBy
button button condRollup conditionalRollup

Compact shorthand (in --fields only): "name:type" string format:

inkreach-teable table create --name "Projects" --fields '["Name:text","Budget:num","Active:check"]'

With select options: "Status:sel:Todo,Doing,Done", "Tags:mul:Bug,Feature,UI"

Update & Delete

inkreach-teable table update <tableId> --name "<newName>" [--description <d>]
inkreach-teable table delete <tableId>
Operation Idempotent? Notes
update yes Only changes name/description
delete DESTRUCTIVE Deletes all records + fields; irreversible

List & Get

inkreach-teable table list [--base-id <id>]
inkreach-teable table get <tableId>

table get returns dbTableName — the internal SQL table name used in sql queries (e.g., SELECT * FROM "bseXXX"."tbl_abc").


Fields

Create

inkreach-teable field create --table-id <tid> --name "<name>" \
  --type <type> [--options '<json>'] [--description <d>]
Flag Required Notes
--table-id yes Target table
--name yes Field display name
--type yes Full type name or alias (see field-types.md)
--options depends on type JSON object; see type-specific shapes below
--description no Optional

Type inference from name: when --type is omitted, the CLI infers from the field name:

Name pattern Inferred type Name pattern Inferred type
status, priority, stage, category, type, level singleSelect tag, label multipleSelect
description, notes, comment, content, body longText count, amount, price, quantity, total, age number
rating, score, stars rating is*, has*, active, enabled, done, completed checkbox
assignee, owner, user user attachment, file, image, photo, document attachment
email singleLineText url, link (without table context) singleLineText
created time / created createdTime last modified / updated lastModifiedTime
created by, author createdBy modified by, updated by lastModifiedBy

Options by type (most common):

Type Required options Shape
singleSelect / multipleSelect choices {"choices":["A","B","C"]} or {"choices":[{"name":"A","color":"blue"}]} — colors auto-assigned if omitted
number none (defaults integer) {"formatting":{"precision":2}} for decimal
rating none (defaults max=5, star, yellow) {"max":5,"icon":"star","color":"yellowBright"}
date none {"formatting":{"date":"YYYY-MM-DD","time":"None","timeZone":"UTC"}}
link foreignTableId / foreignTableName {"foreignTableId":"tblXXX","relationship":"manyOne"}
formula expression {"expression":"{fieldId}+{otherFieldId}"}
rollup via --lookup-options See field-types.md
button workflow {"label":"Click","color":"blue","workflow":{"id":"wflXXX"}}

Name resolution: for link fields, use foreignTableName instead of foreignTableId — the CLI resolves it automatically:

inkreach-teable field create --table-id tblXXX --name "Project" --type link \
  --options '{"foreignTableName":"Projects","relationship":"manyOne"}'

Update & Delete

inkreach-teable field update <tableId> <fieldId> [--name "<n>"] [--options '<json>']
inkreach-teable field delete <tableId> <fieldId>
Detail Rule
--name only Uses the PATCH update API (name/description only)
--options Rewrites options via the convert API (PUT …/field/:fid/convert) — the PATCH update API strips options by design. CLI auto-fetches the field's current type; omitted keys are replaced whole, not merged
--name + --options Both applied via one convert call
field delete Irreversible — all cell data in that field is lost

Select-choice dependency (visibilityFilter) — 2026-08

Single/multiple-select choices may carry a visibilityFilter making them visible only when another select field matches:

{"choices":[{"id":"choA","name":"墨盒","visibilityFilter":{
  "filterSet":[{"fieldId":"fldDeviceType","operator":"is","value":"choPrinter"}]}}]}
  • Read config: inkreach-teable field get <tableId> <fieldId> → options.choices[].visibilityFilter
  • Write config: field update --options (convert API). Backend rejects self-reference (Self-reference in visibilityFilter is not allowed) and dependency cycles (Dependency cycle detected…) with 400 — enforced on both V1 and V2 paths since fix 26ed1f732
  • Evaluate for a record: inkreach-teable field visible-choices <tableId> <recordId> <fieldId> → choices currently selectable
  • Write-time enforcement: writing a record value that fails its visibility condition → 400 Option "X" does not meet the current row conditions and cannot be selected.

Records

Get (read)

# All records (paginated)
inkreach-teable record get --table-id <tid> [--filter '<json>'] [--projection '<json>'] \
  [--page-size <n>] [--page <n>] [--search <kw>]

# Single record by ID
inkreach-teable record get-one <recordId>
Flag Description
--filter Filter expression: {"fieldId":{"operator":"value"}}
--projection JSON array of field IDs to return: '["fldXXX","fldYYY"]'
--page-size Records per page (default 100)
--search Keyword search: "keyword" (auto-wraps to {"value":"keyword"})
--view-id Fetch in view order with view's filter/sort/group applied

Filter operators by field type:

Field Type Supported Operators
singleLineText longText url email phone is isNot contains doesNotContain isEmpty isNotEmpty
number currency percent duration rating is isNot isGreater isGreaterEqual isLess isLessEqual isEmpty isNotEmpty
checkbox is
date createdTime lastModifiedTime is isNot isWithIn isBefore isAfter isOnOrBefore isOnOrAfter isEmpty isNotEmpty
singleSelect (single) is isNot isAnyOf isNoneOf isEmpty isNotEmpty
singleSelect (multi) hasAnyOf hasAllOf isExactly isNotExactly hasNoneOf isEmpty isNotEmpty
multipleSelect hasAnyOf hasAllOf isExactly isNotExactly hasNoneOf isEmpty isNotEmpty
user createdBy lastModifiedBy (single) is isNot isAnyOf isNoneOf isEmpty isNotEmpty
user createdBy lastModifiedBy (multi) hasAnyOf hasAllOf isExactly hasNoneOf isNotExactly isEmpty isNotEmpty
link (single) is isNot isAnyOf isNoneOf contains doesNotContain isEmpty isNotEmpty
link (multi) hasAnyOf hasAllOf isExactly hasNoneOf isNotExactly contains doesNotContain isEmpty isNotEmpty
attachment isEmpty isNotEmpty

⚠️ isAnyOf only works for select/link/user fields, NOT for text/number fields. For text fields with multiple values, use or conjunction with multiple is rules:

{"conjunction":"or","filterSet":[
  {"fieldId":"fldX","operator":"is","value":"val1"},
  {"fieldId":"fldX","operator":"is","value":"val2"}
]}

Date sub-operators (with is / isNot / isWithIn / isBefore etc.):

Operator Description
today tomorrow yesterday Relative day
currentWeek lastWeek nextWeekPeriod Relative week
currentMonth lastMonth nextMonthPeriod Relative month
currentYear lastYear nextYearPeriod Relative year
oneWeekAgo oneWeekFromNow ±1 week
oneMonthAgo oneMonthFromNow ±1 month
daysAgo daysFromNow ±N days (set value)
exactDate Specific date: "2025-06-15"
exactDateTime Specific datetime: "2025-06-15T09:00:00.000Z"
pastWeek pastMonth pastYear Last week/month/year (for isWithIn)
nextWeek nextMonth nextYear Next week/month/year (for isWithIn)
pastNumberOfDays nextNumberOfDays ±N days (for isWithIn, set value)

Conjunction: "and" (all must match) or "or" (any matches). Filter sets can nest for complex logic.

Create

# Single record
inkreach-teable record create --table-id <tid> --fields '<json>'

# Batch (up to 2000)
inkreach-teable record create --table-id <tid> --records '<json>'

--fields format (single): {"FieldName":"value","Another":"value"} — field names resolve automatically.

Value semantics:

Value Meaning
"string" Normal value
null Clear the cell
"" (empty string) Skip (no change; update only)

Important

: "" is skip, not clear. Use null to empty a cell. For checkbox: true = checked, null = unchecked (NOT false).

--typecast: auto-converts human-readable values to internal IDs. Essential for user and link fields:

# Without typecast — must use IDs
inkreach-teable record create --table-id tblXXX --fields '{"Assignee":{"id":"usrXXX","title":"Alice"}}'

# With typecast — use display names
inkreach-teable record create --table-id tblXXX --fields '{"Assignee":"Alice"}' --typecast

--records format (batch): {"header":["Field1","Field2"],"records":[["val1","val2"],["val3","val4"]]}

Update

inkreach-teable record update --table-id <tid> --records '<json>'

--records format: [{"id":"recXXX","fields":{"FieldName":"newValue"}}] — array of {id, fields} objects. Batch up to 2000.

Record reordering: pass --order with viewId, anchorId, position:

inkreach-teable record update --table-id tblXXX \
  --records '[{"id":"recXXX","fields":{}}]' \
  --order '{"viewId":"viwXXX","anchorId":"recYYY","position":"before"}'

Delete

inkreach-teable record delete --table-id <tid> --record-ids "recA,recB,recC"

Max 1000 IDs per call. Irreversible.


Views

List & Get

inkreach-teable view list <tableId>
inkreach-teable view get <viewId>

Create

inkreach-teable view create --table-id <tid> --name "<name>" [--type <t>]
--type Description
grid Default spreadsheet view
kanban Board (requires a singleSelect/link grouping field)
form Form input view
gallery Card gallery
calendar Calendar (requires a date field for grouping)

Update (configure filters, sorts, grouping)

inkreach-teable view update <viewId> \
  [--name "<n>"] \
  [--filter '<json>'] \
  [--sort '<json>'] \
  [--group '<json>'] \
  [--column-meta '<json>']

Filters: {"conjunction":"and","filterSet":[{"fieldId":"fldXXX","operator":"is","value":"Done"}]}

Sorts: [{"fieldId":"fldXXX","order":"asc"}]

Group: [{"fieldId":"fldXXX","order":"asc"}]

Column meta: controls visibility, width, order of fields in the view.

Delete

inkreach-teable view delete <viewId>

Deleting a view does NOT delete the table or its data — only the view configuration.


Value Formats Quick Reference

Field Type Value format Notes
singleLineText / longText "string"
number 42 or 3.14 Integer or float
checkbox true / null NOT false for unchecked
date "2025-06-15" or "2025-06-15T09:00:00.000Z" ISO 8601; "now" maps to current time
singleSelect "Option Name" (string)
multipleSelect ["Tag A","Tag B"] (array of strings)
rating 3 Integer 1..max
attachment [{"name":"f.png","token":"xxx"}] Always array of objects; update replaces all
user {"id":"usrXXX","title":"Alice"} With --typecast: just "Alice" or "alice@example.com"
link [{"id":"recXXX"}] With --typecast: just "Linked Record Name"
formula / rollup / lookup Read-only Cannot be set via record create/update
autoNumber / createdBy / createdTime / lastModifiedTime / lastModifiedBy Auto-populated Cannot be set manually
button {"count":0} Read-only; incremented by button clicks

Common Patterns

User intent Correct approach Wrong approach
Create a table with fields table create --fields '[...]' — one call Multiple field create calls (slower, more error-prone)
Use display names for linked records record create --fields '{"Project":"Acme"}' --typecast Manually looking up recXXX IDs
Use email to assign user record create --typecast --fields '{"Assignee":"alice@co.com"}' Looking up usrXXX IDs
Clear a cell null in the fields object "" (which means skip!)
Update one field, leave others --records '[{"id":"recXXX","fields":{"Status":"Done"}}]' Re-sending all fields (unnecessary, slower)
Fetch only 2 columns record get --projection '["fldXXX","fldYYY"]' Fetching all fields (wastes bandwidth)
Find records by keyword record get --search "keyword" record get then filtering manually
Add a select field with colored options --options '{"choices":["A","B"]}' — colors auto Manually specifying color for every choice
Make a link field to another table --type link --options '{"foreignTableName":"Target","relationship":"manyOne"}' Using IDs + manual lookup
Reorder records in a view record update --order '{"viewId":...,"anchorId":...,"position":"before"}' Deleting and re-creating records
View data in kanban board view create --type kanban then view update --group Creating special columns
Set datetime in a date field "2025-06-15T14:30:00.000Z" "2025-06-15 14:30" (non-ISO; may be rejected)
Update attachments Always pass the full array (replaces all) Trying to add/remove individual attachments
Batch insert 500 records One record create --records call 500 separate record create calls