softr-vibe-coding 2.9.1 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +12 -3
- package/SKILL.md +31 -12
- package/datasources/multi-datasource.md +1 -1
- package/datasources/softr-database.md +2 -2
- package/datasources/writing.md +7 -5
- package/package.json +1 -1
- package/references/anti-patterns.md +9 -1
- package/references/editable-settings.md +1 -1
- package/references/printing.md +533 -0
- package/references/softr-mcp.md +365 -128
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,13 @@ All notable changes to this skill are documented here. Versions follow [Semantic
|
|
|
4
4
|
|
|
5
5
|
Entries from 1.3.1 onward are generated automatically from git commit subjects between version bumps (see `.github/workflows/publish.yml`). Entries before 1.3.1 were backfilled by hand from the existing commit history.
|
|
6
6
|
|
|
7
|
+
## [2.11.0] - 2026-10-01
|
|
8
|
+
- Track Softr's 2026-10-01 MCP release: renamed tools, sourceSha256 push checks, stub-tool root cause
|
|
9
|
+
|
|
10
|
+
## [2.10.0] - 2026-09-30
|
|
11
|
+
- Add the print-in-a-new-window rule and references/printing.md (verified live 2026-09-30)
|
|
12
|
+
- Add right-edge placement and the schema-less workspace-tool correction (2026-09-30)
|
|
13
|
+
|
|
7
14
|
## [2.9.1] - 2026-09-30
|
|
8
15
|
- Add right-edge placement and the schema-less workspace-tool correction (2026-09-30)
|
|
9
16
|
- Document dropdown clipping by overflow ancestors (verified live 2026-09-30)
|
package/README.md
CHANGED
|
@@ -169,7 +169,7 @@ Create a contact form that creates records in our Airtable Contacts table
|
|
|
169
169
|
softr-vibe-coding/
|
|
170
170
|
├── SKILL.md # Main skill
|
|
171
171
|
│ # Workflow, code structure, visual baseline,
|
|
172
|
-
│ # components, settings,
|
|
172
|
+
│ # components, settings, 28 hard constraints
|
|
173
173
|
│
|
|
174
174
|
├── ui-ux-guidelines.md # Design reference
|
|
175
175
|
│ # 26 sections: hierarchy, color, typography,
|
|
@@ -194,7 +194,9 @@ softr-vibe-coding/
|
|
|
194
194
|
│ │ # MCP servers, auth, permissions; what the server
|
|
195
195
|
│ │ # enforces on block data endpoints, "Preview as"
|
|
196
196
|
│ │ # role testing, search-replace on 100KB+ blocks
|
|
197
|
-
│ │ # (Sep 18 2026)
|
|
197
|
+
│ │ # (Sep 18 2026); Oct 1 2026: tool rename map,
|
|
198
|
+
│ │ # push verification by sourceSha256, stub-tool
|
|
199
|
+
│ │ # root cause, update_field/update_table fixes
|
|
198
200
|
│ ├── advanced-integrations.md # Shadow DOM CSS isolation
|
|
199
201
|
│ │ # Leaflet, Mapbox, TinyMCE, Quill, FullCalendar
|
|
200
202
|
│ ├── native-chrome-styling.md # Restyle Softr's native shell (header, footer,
|
|
@@ -223,6 +225,13 @@ softr-vibe-coding/
|
|
|
223
225
|
│ │ # MCP/CLI install (@latest npx + browser step),
|
|
224
226
|
│ │ # extract → poll → findings → generate → write
|
|
225
227
|
│ │ # flow, DESIGN.md anatomy, drift QA
|
|
228
|
+
│ ├── printing.md # Printing from a block: ALWAYS a new window
|
|
229
|
+
│ │ # with its own document (never window.print()
|
|
230
|
+
│ │ # on the page, never an in-page print view) —
|
|
231
|
+
│ │ # escaped HTML builder, pop-up-safe open from
|
|
232
|
+
│ │ # the click, print once stylesheets, fonts and
|
|
233
|
+
│ │ # images load, ?print=1 deep link, paper layout
|
|
234
|
+
│ │ # (Sep 30 2026)
|
|
226
235
|
│ ├── quick-reference.md # Syntax cheat sheet
|
|
227
236
|
│ │ # Imports, hook signatures, mutation shapes,
|
|
228
237
|
│ │ # field mapping, component skeleton
|
|
@@ -309,7 +318,7 @@ The skill enforces these automatically, but good to know (verified live against
|
|
|
309
318
|
- Create payloads are **flat**; update payloads are `{ recordId, fields: {...} }` — asymmetric by design
|
|
310
319
|
- `mutateAsync` is fully supported — it's the tool for sequential multi-row saves
|
|
311
320
|
- SELECT fields write by option **label string**; linked records write as arrays of record-id strings
|
|
312
|
-
- Every code recompile resets the block's auto-registered Actions to default permissions — tighten permissions after the last redeploy, and note there is **no cosmetic-edit exemption**: an edit that changes only a comment resets them too. **Always read the permissions back to confirm** — the
|
|
321
|
+
- Every code recompile resets the block's auto-registered Actions to default permissions — tighten permissions after the last redeploy, and note there is **no cosmetic-edit exemption**: an edit that changes only a comment resets them too. **Always read the permissions back to confirm** — a create action defaults to the block's own visibility, so on a block everyone can see it comes back publicly writable, and the MCP call that re-tightens it can fail with no fallback
|
|
313
322
|
- **Blocks cannot import each other**, so two blocks that must look alike will drift — each one looks correct in isolation while the set does not. Repeated page chrome (back button, title, primary action) must sit at the same offset on every page, and a loading skeleton must track the REST state of whatever it stands in for
|
|
314
323
|
- No `import React from 'react'` — use named imports (`import { useState } from "react"`)
|
|
315
324
|
- Must use `export default function Block()`
|
package/SKILL.md
CHANGED
|
@@ -20,7 +20,7 @@ allowed-tools: Read Write Glob Grep Bash
|
|
|
20
20
|
|
|
21
21
|
# Softr Vibe Coding Block Generator
|
|
22
22
|
|
|
23
|
-
You generate complete, production-ready Softr Vibe Coding blocks as TypeScript React files. A Vibe Coding block is a single file with a default-exported React component, compiled by Softr's server and run in the browser inside a Softr app. The current platform compiles TypeScript with modern syntax — optional chaining (`?.`), nullish coalescing (`??`), arrow functions, `const`, generics — plus shadcn/ui from `@/components/ui/*`, lucide-react, sonner, and date-fns (verified live against the builder MCP's `
|
|
23
|
+
You generate complete, production-ready Softr Vibe Coding blocks as TypeScript React files. A Vibe Coding block is a single file with a default-exported React component, compiled by Softr's server and run in the browser inside a Softr app. The current platform compiles TypeScript with modern syntax — optional chaining (`?.`), nullish coalescing (`??`), arrow functions, `const`, generics — plus shadcn/ui from `@/components/ui/*`, lucide-react, sonner, and date-fns (verified live against the builder MCP's `vibe_coding_block_get_docs` and a 15-block production deployment, 2026-08-25).
|
|
24
24
|
|
|
25
25
|
> **Scope note — blocks vs. native chrome.** A block is page *content*, rendered inside a shadow DOM. Softr's global **header / top bar / nav / dropdown menus** are native chrome (configured in Studio, rendered in the main document) — you **cannot** build or replace them as a block. To restyle them, add CSS to Settings → Custom Code → Code inside header. See [references/native-chrome-styling.md](references/native-chrome-styling.md). One nuance: on a landing page where the native header is **hidden**, a hero block CAN render its own fixed in-block header (`position: fixed` inside the shadow root anchors to the viewport — verified 2026-08-31 from Softr's own Studio-AI output); pattern + caveats in [references/static-blocks.md](references/static-blocks.md#block-owned-landing-page-header).
|
|
26
26
|
|
|
@@ -65,7 +65,7 @@ You generate complete, production-ready Softr Vibe Coding blocks as TypeScript R
|
|
|
65
65
|
|
|
66
66
|
5. **Write the complete block file** (`.tsx` preferred; `.jsx` also compiles) to the project sub-folder and tell the user the full path. Create the sub-folder if it doesn't exist yet. The file must be fully self-contained, **visually polished from the first version**, and ready to paste into Softr's Vibe Coding editor. Styling is not an afterthought -- it ships in v1. **Never deliver code inline in chat.** Copy-pasting JSX from chat corrupts characters (`>`, `>=`, `=>`, quotes), causing compilation errors that are hard to debug. Always write to a file.
|
|
67
67
|
|
|
68
|
-
**Delivery path:** if the official Softr MCP server is connected with Applications & Forms full access, offer to deploy the block directly after writing the file — `
|
|
68
|
+
**Delivery path:** if the official Softr MCP server is connected with Applications & Forms full access, offer to deploy the block directly after writing the file — `vibe_coding_block_create` (or `vibe_coding_block_update_code` for edits) plus `vibe_coding_block_connect_data_source` to wire the data. The local `.tsx` file stays the source of truth. Remember: every code push resets the block's Action permissions to defaults (Hard Constraint 21), and a block whose data source isn't connected saves fine but errors at page load. Details in [references/softr-mcp.md](references/softr-mcp.md).
|
|
69
69
|
|
|
70
70
|
6. **Self-validate before delivering.** Before presenting the code as complete, verify. (Data-hook items apply only to data-connected blocks; static marketing blocks swap in the checklist deltas from [references/static-blocks.md](references/static-blocks.md#workflow-deltas).)
|
|
71
71
|
- Every data hook is called with an **inline options object literal** — `useRecords({ ... })` written through a variable or wrapper function fails to compile (verified live 2026-08-25). Share `q.select` mappings between hooks, never whole options objects
|
|
@@ -91,10 +91,11 @@ You generate complete, production-ready Softr Vibe Coding blocks as TypeScript R
|
|
|
91
91
|
- No hardcoded domains in links -- use relative paths (`/page?recordId=...`); same-page anchors written relative too (`/#section`)
|
|
92
92
|
- **No `<select>` and no shadcn `<Select>`** — both break inside a block's shadow DOM (native hands the list to the OS; shadcn portals outside the shadow root and arrives unstyled). Use the `Combo` pattern in [references/searchable-dropdown.md](references/searchable-dropdown.md) — **searchable by default** for every framed filter or form field whatever the option count; `bare` inline editors are click-only; `searchable={false}` only on a short fixed enum the user is setting (a status, a location, a group-by)
|
|
93
93
|
- No clipping class (`overflow-hidden`, `overflow-*-auto`, `truncate`, `line-clamp-*`) on any element that contains a `Combo` — its panel is absolutely positioned in local DOM, so a clipping `<td>` cuts the menu to the row's height; bound an over-wide chip at the chip (`min-w-0 truncate`), and never `scrollIntoView` inside the panel. See [references/searchable-dropdown.md](references/searchable-dropdown.md#the-four-things-that-will-bite-you), item 4
|
|
94
|
+
- Any **Print** control opens a **new window with its own document** — `window.open` straight from the click, an escaped standalone HTML printout written into it, `print()` once its stylesheets, fonts and images are in, the button disabled until the data has fully loaded. No `window.print()` on the Softr page, no in-page print view (Hard Constraint 28). See [references/printing.md](references/printing.md)
|
|
94
95
|
- Static block: no hardcoded user-visible copy — every string/image/link is an editable setting (see [references/editable-settings.md](references/editable-settings.md#granularity-doctrine-settings-first-static-blocks))
|
|
95
96
|
- Array-setting rows keyed by **index**, never by a builder-editable field value
|
|
96
97
|
- Media settings that may start empty (`src: ""`) gated with a conditional render or placeholder — never an unconditional `<img src={setting.src}>`
|
|
97
|
-
- **Deploying through the MCP:** `errors: null` on a push is not proof —
|
|
98
|
+
- **Deploying through the MCP:** `errors: null` on a push is not proof — compare the push result's `sourceSha256` with `shasum -a 256` of the file you sent, every byte counted, trailing newline included (Softr stores exactly what it receives; the one-byte drift we once blamed on it was a chunked read on our side). Prove deployed == disk *before* editing the same way, with `vibe_coding_block_get_code` and `includeCode: false`, so a Studio-side change is never overwritten. Fetch the full `sourceCode` only when a digest is missing or the hashes differ. Protocol in [references/softr-mcp.md → Verifying a push](references/softr-mcp.md#verifying-a-push--the-deployed-source-is-the-only-proof)
|
|
98
99
|
|
|
99
100
|
## What to Clarify
|
|
100
101
|
|
|
@@ -102,7 +103,7 @@ When the user describes their block, figure out which of these areas apply and a
|
|
|
102
103
|
|
|
103
104
|
- **Data source type**: Is it Airtable, Softr Database, REST API, or another source? This determines the data fetching approach. **Load the relevant data source guide** from the [datasources/](datasources/) directory before writing code.
|
|
104
105
|
- **Data source fields**: For Airtable/Softr Database, you need actual field IDs. For REST APIs, you access the raw API response directly. If the user doesn't know field IDs:
|
|
105
|
-
- For **Softr Database**, the cleanest path is the official **Softr MCP server** — ask whether they have it installed (`claude mcp list` shows it as `softr` or similar). If yes, query schema directly with the MCP tools instead of asking for paste-ins. The same server also browses connected **Airtable, Google Sheets, Notion, and
|
|
106
|
+
- For **Softr Database**, the cleanest path is the official **Softr MCP server** — ask whether they have it installed (`claude mcp list` shows it as `softr` or similar). If yes, query schema directly with the MCP tools instead of asking for paste-ins. The same server also browses connected integrations down to field level — **Airtable, Google Sheets, Notion, Supabase**, and per its tool descriptions (2026-10-01) many more, from Excel and monday to HubSpot and SQL databases (`integration_list` → ... → `integration_list_table_fields`) — so prefer it for those sources too when available — see [references/softr-mcp.md](references/softr-mcp.md). If no MCP, the next-best option for Softr DB is the bundled **`get-softr-database` CLI script** — tell the user to run `python3 ~/.claude/skills/softr-vibe-coding/tools/get-softr-database.py <database_id>` (it prompts for their Softr API key and exports the full schema to `~/Desktop/softr-database-<id>-<timestamp>.json` — Python stdlib only, nothing to install) and paste the resulting JSON into chat. As a final fallback, ask them to paste the `tablespace-with-tables` network response (DevTools -> Network -> filter that string while on Studio's Data tab) — same JSON content, different acquisition path. Optionally tell them they can install the MCP once with `claude mcp add --transport http softr https://mcp.softr.io/mcp` for future sessions. Full MCP details in [references/softr-mcp.md](references/softr-mcp.md); CLI script details in [datasources/softr-database.md](datasources/softr-database.md#bundled-cli-script-get-softr-database); fallback paste-in workflows in [datasources/fields.md](datasources/fields.md#field-inspector-block).
|
|
106
107
|
- For **Airtable**, the most thorough path is the bundled **`get-airtable-base` shell script** — `bash ~/.claude/skills/softr-vibe-coding/tools/get-airtable-base` (requires `jq` — `brew install jq` on macOS). It prompts for Base ID + PAT, then exports the full schema (every table, every field with both `fld...` IDs and column names, relationships, webhooks, interfaces) to a timestamped Desktop folder. The user pastes `02-schema.json` or the combined `00-bundle.json` into chat. For lighter inspection (just a few fields, runtime-only), suggest the Field Inspector block — empty `q.select({})` works for Airtable. CLI script details in [datasources/airtable.md](datasources/airtable.md#bundled-cli-script-get-airtable-base).
|
|
107
108
|
- For other non-Softr-DB sources where empty `q.select({})` works, suggest the Field Inspector block.
|
|
108
109
|
- **Brand colors**: Already resolved in Step 1 (Detect the brand source). Don't re-ask. The brand source is one of:
|
|
@@ -175,9 +176,10 @@ For advanced patterns beyond data fetching, load the relevant reference when the
|
|
|
175
176
|
| Debugging a broken block, checking patterns before delivery, full violation catalog | [references/anti-patterns.md](references/anti-patterns.md) |
|
|
176
177
|
| Quick syntax check — import paths, hook signatures, mutation call shapes, field mapping | [references/quick-reference.md](references/quick-reference.md) |
|
|
177
178
|
| Any **dropdown / picker / combobox** in a block — why shadcn `<Select>` and native `<select>` both fail inside the shadow DOM, the `composedPath()` click-outside, sorting A→Z inside the component, multi-token filtering, **searchable by default** regardless of option count (`bare` inline editors click-only; `searchable={false}` only for a short fixed enum being set), the `bare` inline-editor variant | [references/searchable-dropdown.md](references/searchable-dropdown.md) |
|
|
179
|
+
| **Printing** anything from a block — always a new window/tab holding its own document, never `window.print()` on the page or an in-page print view: the escaped HTML builder, pop-up-safe opening from the click, print-when-ready (stylesheets, fonts and images, capped), Print disabled until the data has loaded, the `?print=1` deep link from another page, paper layout (shared `<colgroup>`, `vertical-align: middle`, tick boxes) | [references/printing.md](references/printing.md) |
|
|
178
180
|
| Small reusable patterns — `localStorage` cross-page state, clipboard copy button | [references/common-patterns.md](references/common-patterns.md) |
|
|
179
181
|
| Writing Airtable Automation Scripts / Scripting Extension scripts / Airtable formulas — companion to Softr blocks for cross-table cascades and computed values | [references/airtable-automations.md](references/airtable-automations.md) |
|
|
180
|
-
| The official **Softr MCP server** — Softr DB schema + full record/table/field/database CRUD (deletes included), field-level browsing of connected Airtable / Google Sheets / Notion / Supabase
|
|
182
|
+
| The official **Softr MCP server** — Softr DB schema + full record/table/field/database CRUD (deletes included), field-level browsing of connected integrations (Airtable / Google Sheets / Notion / Supabase and more), **creating, editing, versioning, and deploying Vibe Coding blocks directly** (`vibe_coding_block_get_docs`, `vibe_coding_block_create`, ...), push verification by `sourceSha256`, app management/scaffolding, the **Softr Workflows** suite (28 tools, 418-node catalog), and **per-application MCP servers**. Tool names changed on 2026-10-01; the file carries the old → new map | [references/softr-mcp.md](references/softr-mcp.md) |
|
|
181
183
|
| Restyling Softr's **native shell — header / footer / nav / dropdowns / page background** (not a block; it's Softr chrome, done with global Custom Code CSS): stable selectors vs. hashed classes, floating "island" header+footer, the dropdown blank-space grid fix, the multi-layer page-background stacking, restyle-vs-replace | [references/native-chrome-styling.md](references/native-chrome-styling.md) |
|
|
182
184
|
| Adding a **dynamic date filter or custom filter control to a native List/Grid block** (via a Custom Code Static block, not a Vibe block): drive the block's conditional filter with `{URL_PARAM:…}`, the empty-param "match nothing" wide-range sentinel, inject the control into the filter row and keep it alive across Softr's re-renders | [references/native-block-filters.md](references/native-block-filters.md) |
|
|
183
185
|
| **Editable settings deep-dive** — full hook catalog (incl. verified-undocumented `useLongTextSetting` and the `navigation` array-schema type), settings-first granularity doctrine, heading-line-split and `-text`/`-link` pairing patterns, naming conventions, rename-resets-value gotcha, empty-media gating, key-by-index rule | [references/editable-settings.md](references/editable-settings.md) |
|
|
@@ -207,7 +209,7 @@ export default function Block() {
|
|
|
207
209
|
}
|
|
208
210
|
```
|
|
209
211
|
|
|
210
|
-
Wrap the outermost layout in `container` and `content` divs by default — these constrain width to match the Softr app's max width settings so the block aligns with neighboring native blocks. Note this is a **house convention, not platform-enforced**: per the official developer guide the platform default is full width, and the classes are merely "available" to constrain it (verified 2026-08-31 against `
|
|
212
|
+
Wrap the outermost layout in `container` and `content` divs by default — these constrain width to match the Softr app's max width settings so the block aligns with neighboring native blocks. Note this is a **house convention, not platform-enforced**: per the official developer guide the platform default is full width, and the classes are merely "available" to constrain it (verified 2026-08-31 against `vibe_coding_block_get_docs` and a rendering wrapper-free Studio-AI hero).
|
|
211
213
|
|
|
212
214
|
**Exceptions (omit the wrappers deliberately):**
|
|
213
215
|
- Blocks inside Softr column containers — Softr controls layout.
|
|
@@ -557,14 +559,23 @@ Non-negotiable rules. Most are enforced by the Softr platform (compiler, validat
|
|
|
557
559
|
**Any save counts, including one whose only change is a comment** -- there is no "cosmetic edit"
|
|
558
560
|
exemption; a `search_replace` that rewrites nothing but a code comment rebuilds the Actions exactly
|
|
559
561
|
like a full rewrite does (verified live 2026-09-09, on two blocks at once).
|
|
562
|
+
The same rebuild runs on a Save in Studio's code editor, an AI-assistant edit and a version restore
|
|
563
|
+
(per Softr, 2026-10-01), and only `OPEN_CHAT` / `TRIGGER_CUSTOM_WORKFLOW` actions survive it.
|
|
564
|
+
**Record before, re-apply after, read back** -- before the push, note every action with
|
|
565
|
+
`isDefaultVisibility: false` (`vibe_coding_block_get_settings` lists them); after it, re-apply each
|
|
566
|
+
by `actionType` (+ `dataSourceId`), never by action id, which every compile regenerates. Each
|
|
567
|
+
update replaces that action's whole permission, so send the complete state.
|
|
560
568
|
**Re-read the permissions after EVERY push and confirm they actually changed** -- do not assume the
|
|
561
|
-
restore worked.
|
|
562
|
-
|
|
563
|
-
|
|
569
|
+
restore worked. The default for ADD_RECORD follows the block's own visibility, so on a block
|
|
570
|
+
everyone can see it comes back `ALL_USERS`, i.e. writable by logged-OUT visitors (UPDATE/DELETE
|
|
571
|
+
reset to logged-in users). The MCP call that re-tightens it (`vibe_coding_block_set_action_visibility`)
|
|
572
|
+
can itself fail with no fallback. It fails when the client holds only a stub of the tool
|
|
573
|
+
(name-only description, no properties), which happens after a session resume, so check the
|
|
574
|
+
loaded definition and start a fresh session if it is a stub (see
|
|
564
575
|
[references/softr-mcp.md](references/softr-mcp.md#the-array-argument-rejection-and-why-it-is-a-security-issue)).
|
|
565
576
|
A push that returns `errors: null` can still have left public write access on the block.
|
|
566
|
-
**If any action is still
|
|
567
|
-
Check the page's own VIEW permission first (`
|
|
577
|
+
**If any action is still broader than intended, report it WITH its severity and let the builder decide.**
|
|
578
|
+
Check the page's own VIEW permission first (`application_page_get_permissions`): a page gated to logged-in
|
|
568
579
|
users makes an open action housekeeping, a public page makes it a real hole. Surface the list
|
|
569
580
|
either way -- page, block, action type, data source -- and note that a human sets them on the
|
|
570
581
|
block's Actions tab. Do not unilaterally block a publish; it is not your app.
|
|
@@ -604,10 +615,18 @@ Non-negotiable rules. Most are enforced by the Softr platform (compiler, validat
|
|
|
604
615
|
one table merge into ONE UPDATE_RECORD action (field list = the union), filed under the table's
|
|
605
616
|
FIRST connection even when a hook points at a second one. Point writes at the first connection.
|
|
606
617
|
Verified live 2026-09-18. See [datasources/writing.md](datasources/writing.md#actions-register-per-table-not-per-hook-or-connection).
|
|
618
|
+
28. **Print in a new window, never on the page [house]** -- A Print control opens a new window
|
|
619
|
+
(`window.open("", "_blank", …)`, synchronously in the click handler; a toast if it returns
|
|
620
|
+
`null`) and writes a standalone, escaped HTML printout into it, printed once its stylesheets,
|
|
621
|
+
fonts and images are in. Never `window.print()` on the Softr page: a block is page content in
|
|
622
|
+
a shadow root, so the page prints Softr's header, footer and every sibling block, and hiding
|
|
623
|
+
them takes global CSS across Softr's page structure as well as print CSS in the block. Never
|
|
624
|
+
an in-page "print view" either (Leo rejected it by name). Verified live 2026-09-30. See
|
|
625
|
+
[references/printing.md](references/printing.md).
|
|
607
626
|
|
|
608
627
|
## Style Conventions
|
|
609
628
|
|
|
610
|
-
**The current platform compiles TypeScript with modern syntax** — optional chaining (`?.`), nullish coalescing (`??`), arrow functions, `const`/`let`, generics — verified live against `
|
|
629
|
+
**The current platform compiles TypeScript with modern syntax** — optional chaining (`?.`), nullish coalescing (`??`), arrow functions, `const`/`let`, generics — verified live against `vibe_coding_block_get_docs` and a 15-block production deployment on 2026-08-25. Write new blocks in modern TS (`.tsx`); it matches what Softr's own Studio AI emits.
|
|
611
630
|
|
|
612
631
|
History, kept so old guidance elsewhere is recognizable as superseded: until mid-2026 this skill mandated `var` + `function(){}` and banned `?.` / `??` because the then-current bundler failed on them (verified April 2026; a Studio-scaffolded block already contradicted it by July 2026). That platform behavior is gone. Existing var-style blocks remain valid — the compiler accepts both styles — so don't churn a working block just to modernize its syntax, and don't "fix" modern syntax back to var-style when editing.
|
|
613
632
|
|
|
@@ -152,7 +152,7 @@ The second connection above is for **reads**. Actions are filed per table:
|
|
|
152
152
|
under the **first** connection's `dataSourceId`.
|
|
153
153
|
|
|
154
154
|
So **point every write at the table's first connection**, and expect one action per table and
|
|
155
|
-
operation in `
|
|
155
|
+
operation in `vibe_coding_block_get_settings` / the Actions tab — that is the row you re-tighten
|
|
156
156
|
after each push. Details in [writing.md](writing.md#actions-register-per-table-not-per-hook-or-connection).
|
|
157
157
|
|
|
158
158
|
## Getting the datasource ids — ask for CODE, never for a value
|
|
@@ -93,14 +93,14 @@ After `source ~/.zshrc`, just run `get-softr-database <database_id>` from anywhe
|
|
|
93
93
|
| Relationship | Yes | Linked records to other Softr Database tables. Write as an **array of record-id strings**, e.g. `[recordId]` (verified 2026-08-25) |
|
|
94
94
|
| Formula | Read-only | Booleans return as strings: use `=== "1"` for true, `=== "0"` for false |
|
|
95
95
|
|
|
96
|
-
This table is the coarse block-side view. The full current catalog is larger — Rating, Duration, Currency, Percent, plus computed Lookup/Rollup/Count and system fields — and is best fetched live
|
|
96
|
+
This table is the coarse block-side view. The full current catalog is larger — Rating, Duration, Currency, Percent, plus computed Lookup/Rollup/Count and system fields — and is best fetched live from the MCP, authoritative **for the server you're calling** (`database_get_field_reference` on the workspace server, `get_schema` on a per-app server): the per-app servers document a fuller catalog than the workspace server (adding Address, Progress, Time, Date range, Button, and display options like Percent's progress-bar/ring — still missing from the workspace reference on 2026-10-01), and the two have also differed on operator names — see [../references/softr-mcp.md](../references/softr-mcp.md#softr-database-tools).
|
|
97
97
|
|
|
98
98
|
## Rate Limits
|
|
99
99
|
No API rate limits. Softr Database queries run internally without external API calls, making it the best choice for high-traffic applications.
|
|
100
100
|
|
|
101
101
|
## Gotchas
|
|
102
102
|
- **Formula boolean values are strings.** A formula that evaluates to true returns `"1"`, not `true`. Always compare with `=== "1"` or `=== "0"`.
|
|
103
|
-
- **Field IDs are opaque codes.** You cannot guess them from column names. Look them up via the ranked list above (MCP `
|
|
103
|
+
- **Field IDs are opaque codes.** You cannot guess them from column names. Look them up via the ranked list above (MCP `database_list_fields` / bundled CLI / network inspector / Studio field drawer) — the generic Field Inspector block does NOT work for Softr Database.
|
|
104
104
|
- **Relationships** work similarly to linked records in Airtable but use Softr's internal record IDs.
|
|
105
105
|
|
|
106
106
|
## Best For
|
package/datasources/writing.md
CHANGED
|
@@ -377,10 +377,12 @@ and schema work, and **none of them raises an error**.
|
|
|
377
377
|
enforcement only fires on the next write. If one side must hold many links, both sides
|
|
378
378
|
must allow multiple entries; enforce any one-parent rule in the UI, not the schema.
|
|
379
379
|
|
|
380
|
-
2.
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
380
|
+
2. **In a Tables API field PUT, `allowMultipleEntries` is a TOP-LEVEL field property, not part
|
|
381
|
+
of `options`.** A `PUT /fields/{id}` with the property at top level works. Do not reach for the
|
|
382
|
+
MCP's old `update_field` here: per Softr, until 2026-10-01 it wrote `allowMultipleEntries: false`
|
|
383
|
+
on every call whatever it was sent, which is what looked like "ignored" when we tested it. Since
|
|
384
|
+
then `database_update_field` takes the setting **inside `options`** and keeps it when you leave
|
|
385
|
+
it out (per Softr; not yet re-tested by us).
|
|
384
386
|
|
|
385
387
|
3. **A Tables API field PUT that omits `options.inverseLinkFieldId` SEVERS the inverse
|
|
386
388
|
pairing** — it comes back `null` and the two sides stop mirroring each other. Always
|
|
@@ -547,7 +549,7 @@ Details that matter in practice:
|
|
|
547
549
|
- A bulk import of images from another system (Airtable, a vendor CDN, a CSV of image links) is therefore
|
|
548
550
|
a plain loop of record writes with no download-and-re-upload stage.
|
|
549
551
|
|
|
550
|
-
_Write shape verified live 2026-08-26 on Softr Database via the MCP `update_record
|
|
552
|
+
_Write shape verified live 2026-08-26 on Softr Database via the workspace MCP's `update_record` (now `database_update_record`): a 20,990-byte
|
|
551
553
|
`image/jpeg` behind an extensionless ImageKit URL came back as a Softr-hosted S3 object of identical size
|
|
552
554
|
and type, with small/medium/large thumbnails generated. Copy-not-link confirmed. The in-block
|
|
553
555
|
`useRecordUpdate` / `createRecord` path takes the same shape, but external-URL ingestion was not separately
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "softr-vibe-coding",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"description": "Claude Code skill for generating production-ready Softr Vibe Coding blocks (JSX). Installs into ~/.claude/skills/ and auto-updates on each Claude Code session.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"softr-vibe-coding": "./bin/cli.js"
|
|
@@ -43,7 +43,9 @@ Run through this catalog before delivering any block. Every row is a violation o
|
|
|
43
43
|
| Passing a data hook's options through a variable or wrapper function: `useRecords(buildOpts())` | **Fails to compile** — the options object must be an inline literal at the call site (verified live 2026-08-25; hit in production, fixed by making the wrapper take the hook's *result* instead). Share `q.select` mappings between hooks, never whole options objects |
|
|
44
44
|
| Tightening Actions-tab permissions before the block's final redeploy | Every code recompile **resets the auto-registered Actions to default permissions** (verified live 2026-08-25). Tighten permissions after the LAST redeploy, and re-check after any future one |
|
|
45
45
|
| Assuming a comment-only edit is "safe" and leaves Action permissions alone | There is no cosmetic-edit exemption. Any save recompiles, and every recompile rebuilds the Actions at default visibility — a `search_replace` changing nothing but a code comment resets them exactly like a rewrite (verified live 2026-09-09, on two blocks at once). Re-check after EVERY push, including cosmetic ones |
|
|
46
|
-
| Treating the permission-restore call as done because you issued it | Read the permissions back with `
|
|
46
|
+
| Treating the permission-restore call as done because you issued it | Read the permissions back with `vibe_coding_block_get_settings` and confirm each one changed. `vibe_coding_block_set_action_visibility` can fail outright on the array-argument rejection (the client holding only a stub of the tool, typically after a session resume), and it has **no fallback** — the default for ADD_RECORD follows the block's own visibility, so on a block everyone can see, a routine push silently leaves it publicly writable while returning `errors: null`. Verified live 2026-09-09: four ADD_RECORD actions left open across two blocks. Report the list with its severity — check the page's VIEW permission with `application_page_get_permissions`, since a logged-in-gated page makes this housekeeping while a public page makes it a real hole — and let the builder decide whether it holds their release. A human sets them on the block's Actions tab |
|
|
47
|
+
| Calling an array-argument MCP tool (`vibe_coding_block_set_action_visibility`, `vibe_coding_block_update_code_search_replace`) when its loaded definition is a stub — description identical to the tool name, schema `{"type":"object"}` with no properties | A stub declares no types, so the array is sent as a JSON string and rejected (since 2026-10-01 the error reads "Parameter '…' must be an array of objects, but a string was sent"). Stubs appear after a session resume. Start a fresh session, which reloads the real definitions, then call. Root cause established 2026-10-01 — see [softr-mcp.md](softr-mcp.md#the-array-argument-rejection-and-why-it-is-a-security-issue) |
|
|
48
|
+
| Verifying a push by pulling the whole block source back into the model's context | Compare `sourceSha256` from the push result (or from `vibe_coding_block_get_code` with `includeCode: false`) with `shasum -a 256` of the file you sent; fetch the full source only when the digest is missing or differs. Available since 2026-10-01 — see [softr-mcp.md](softr-mcp.md#verifying-a-push--the-deployed-source-is-the-only-proof) |
|
|
47
49
|
| Splitting one table's writes across several `useRecordUpdate` hooks (or across two connections of the same table) to get separately-permissioned Actions | Actions register per **TABLE**: the hooks merge into ONE UPDATE_RECORD action whose field list is the union, and a hook pointed at a second connection of the table is still filed under the FIRST connection's dataSourceId (verified live 2026-09-18). Point writes at the table's first connection; expect one action per table + operation when re-tightening permissions. See [datasources/writing.md](../datasources/writing.md#actions-register-per-table-not-per-hook-or-connection) |
|
|
48
50
|
| Treating Studio's Actions tab as a separately-managed configuration to keep in sync with code | Actions auto-derive from your `useRecordCreate`/`useRecordUpdate`/`useRecordDelete` + `q.select` on every save. The Actions tab is a read-only inspector; there is no manual delete control. To change an Action, change the code |
|
|
49
51
|
| One alias in a write-side `q.select` referencing a renamed / non-existent Airtable column | Softr's Action parser silently rejects the **entire** create/update Action — not just the bad alias. Symptoms: Studio's Actions tab shows "No actions used in this block yet", `createRecord.enabled` / `updateRecord.enabled` stays `false`, `.mutate()` calls dispatch but resolve immediately to "not yet ready". Every OTHER field in the same `q.select()` is also lost, even the ones that map cleanly. Diagnostic: bisect the `q.select` — strip down to a known-good minimal set, confirm the Action appears in Studio, then add fields back in halves until it drops out. The culprit is in the last half added. Once narrowed to a single field, grep its name against the freshest Airtable schema export to catch the rename / trailing-space / case-mismatch. Verified 2026-05-21: a `"Photos"` column on Wigs was renamed to `"Before Photos"`, the helper that wrote `photos: "Photos"` had its entire Action disabled even though 11 other fields in the same `q.select` were fine. See [datasources/airtable.md](../datasources/airtable.md#maintainability-gotcha) |
|
|
@@ -91,6 +93,12 @@ Run through this catalog before delivering any block. Every row is a violation o
|
|
|
91
93
|
| Softr nav dropdown panel shows a tall blank gap below the items, and `height: auto` won't shrink it | The items sit in a CSS grid Softr sets to `grid-auto-flow: column` with pre-sized empty row tracks (`grid-template-rows: 60px 60px…`). Override the flow on `.softr-topbar [role="menu"] [role="group"]`: `grid-auto-flow: row !important; grid-template-rows: none !important; grid-auto-rows: auto !important` (leave `grid-template-columns` to preserve the menu width). Verified June 2026. See [native-chrome-styling.md](native-chrome-styling.md). |
|
|
92
94
|
| Setting the page background on `body` (or any single element) — it appears to do nothing | Softr paints the SAME page fill on `html`, `body`, `#page-content`, AND a deeper class-less wrapper div, stacked — so styling one gets covered. Paint your backdrop on `html`, then clear the duplicates above it: `body`, `#page-content`, and `#page-content div` — but EXCLUDE the header subtree with `:not(.softr-topbar):not(.softr-topbar *)` (it renders inside `#page-content`, and `#page-content`'s id specificity would otherwise flatten the dropdown panel). Verified June 2026. See [native-chrome-styling.md](native-chrome-styling.md). |
|
|
93
95
|
|
|
96
|
+
## Printing
|
|
97
|
+
|
|
98
|
+
| Anti-Pattern | Correct Approach |
|
|
99
|
+
|---|---|
|
|
100
|
+
| Printing the Softr page — `window.print()` from a block, with or without `@media print` CSS to hide the rest — or an in-page "print view": the block switches itself to a print layout under the app chrome, with "Print again" / "Exit print view" buttons | **Symptom:** the paper carries Softr's header and footer, every sibling block and the block's own controls; or the user lands in a second screen of the block that they have to find their way out of — "a weird UI", which Leo rejected by name on 2026-09-30. **Cause:** a block is page content in a shadow root. The app chrome and the sibling blocks are outside it, so the block's own print CSS cannot hide them; that takes global Custom Code CSS aimed at Softr's page structure, which you do not control. A print view changes nothing about that: it still ends in `window.print()` on the same page. **Fix:** Print opens a new window holding its own document — `window.open("", "_blank", …)` synchronously in the click (a toast if it returns `null`), a standalone, escaped HTML printout written into it, `print()` once its stylesheets, fonts and images are in. From another page, the linking page opens the target with `?print=1` in a window of its own, and the target block replaces its own document with the printout. Verified live 2026-09-30. See [printing.md](printing.md) |
|
|
101
|
+
|
|
94
102
|
## Permissions
|
|
95
103
|
|
|
96
104
|
| Anti-Pattern | Correct Approach |
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Editable settings are the hooks from `@/lib/editable-settings` that surface a block's content in Studio's **Content → Settings** pane, so builders (and clients) edit text, images, links, and lists **without re-prompting or touching code**. Softr's own pitch: "make simple text and image edits directly without re-prompting." This file is the deep-dive; SKILL.md keeps the compact signatures.
|
|
4
4
|
|
|
5
|
-
**Provenance discipline.** Every behavior below is tagged either **[official]** (in Softr's Vibe Coding Developer Guide, re-fetchable via the MCP's `
|
|
5
|
+
**Provenance discipline.** Every behavior below is tagged either **[official]** (in Softr's Vibe Coding Developer Guide, re-fetchable via the MCP's `vibe_coding_block_get_docs`) or **[verified-undocumented]** (absent from the official guide but proven working — source and date given). Keep the tags when editing this file: they're what stops a future docs-based review from false-positiving working code (the same failure class as the useRecord-via-Studio-binding incident), and what tells you which behaviors could silently change under you since Softr never promised them.
|
|
6
6
|
|
|
7
7
|
## Contents
|
|
8
8
|
|