add-block-preview
GitHub管理 Sim 平台中 Block 的可见性门控,支持通过配置、环境变量或代码将未发布模块设为预览隐藏状态,并向特定用户或组织逐步开放,最终完成 GA 上线。
Trigger Scenarios
Install
npx skills add simstudioai/sim --skill add-block-preview -g -y
SKILL.md
Frontmatter
{
"name": "add-block-preview",
"description": "Gate a block's visibility — ship an unreleased block as a preview (hidden until revealed via AppConfig\/env), reveal it to admins\/orgs, GA it, or kill-switch a shipped block",
"argument-hint": "<block-type>"
}
Add Block Preview Skill
You manage block visibility gating in Sim — hiding blocks from every discovery surface (toolbar, cmd+K search, copilot @-mentions, agent tool picker, mothership VFS/metadata/tools, Access Control list, public docs/catalog) while never gating execution of already-placed instances.
The model
Three levers, evaluated in apps/sim/lib/core/config/block-visibility.ts and folded into the registry accessors (apps/sim/blocks/registry.ts):
-
preview: trueon theBlockConfig(static, in code) — the block is default-hidden EVERYWHERE (hosted, self-hosted, dev, SSR) until revealed. Fail-closed. -
The hosted
block-visibilityAppConfig document — per-block rule keyed by the existing block type:{ "<block-type>": { "enabled": false, // required. true = GA (visible to everyone) "orgIds": ["org_..."], // optional allowlist clauses (any match reveals) "userIds": ["user_..."], "adminEnabled": true // platform admins (user.role === 'admin') } } -
PREVIEW_BLOCKSenv (comma-separated block types) — the off-AppConfig reveal path for self-hosters and local dev.
A revealed block that is not globally GA (enabled !== true, or env-revealed) renders with a " (Preview)" name suffix on discovery surfaces. getBlock() stays pure, so placed instances keep their canonical name and always execute.
Lifecycle of a preview block
-
Author the block normally (
/add-blocketc.) and setpreview: trueon itsBlockConfig. Ship noBlockMetaand no docs until GA —check-block-registrydeliberately skips preview blocks in meta coverage, andgenerate-docsskips them at every gate. -
Local dev: set
PREVIEW_BLOCKS=<block-type>in your env to see it (with the suffix). -
Merge/deploy. The block's code is live everywhere but visible nowhere — no AppConfig rule exists and self-hosters have no env entry.
-
Hosted preview: add a rule to the
block-visibilityAppConfig document and start a deployment (no code deploy):- Admins only:
{ "enabled": false, "adminEnabled": true } - Design-partner org:
{ "enabled": false, "orgIds": ["org_123"] } - GA via config (code cleanup pending):
{ "enabled": true }— suffix disappears everywhere within ~30s (AppConfig TTL) + client refetch.
Same runbook as
feature-flags: edit the hosted document,aws appconfig start-deploymentwith thesim-<env>-faststrategy (see the infra README). - Admins only:
-
GA cleanup: delete
preview: truefrom the block (now visible to self-hosters on their next upgrade), add itsBlockMeta+ regen docs, and drop the AppConfig entry. For a v2 upgrade, this is also when v1 getshideFromToolbar: true(the superseded-version paradigm).
Kill switch (shipped blocks)
To pull an already-GA block from discovery surfaces on hosted (incident, deprecation): add { "<block-type>": { "enabled": false } } to the document. Allowlist clauses can carve out exceptions. Execution is NOT stopped — workflows already using the block keep running; the kill switch only prevents new placement/discovery.
Invariants (do not violate)
- Execution is never gated. The executor, serializer, drop-naming, and
isBlockTypeAccessControlExemptresolve via puregetBlock. Do not add visibility checks to execution paths. - Clone-not-remove: gated blocks stay in
getAllBlocks()output as clones withhideFromToolbar: true—.find-by-type consumers rely on this. Never filter them out. - Keys are registry block types. Never
custom_block_*(parse drops them — custom blocks have their own enabled/disabled lifecycle). - The shared hidden-predicate is
isHiddenUnder(apps/sim/blocks/visibility/context.ts). Never restate the preview/disabled rule inline at a new consumer. - Process-global caches stay ungated.
getStaticComponentFiles(VFS) andgetExposedIntegrationToolsbuild the ungated universe; per-viewer filtering happens at stamp/consumer time. Never move gating into a shared builder. - Gating is surface hiding, not secrecy — the full config ships in the client JS bundle. Anything truly secret cannot be a registered block.
Tests
Evaluation semantics: apps/sim/lib/core/config/block-visibility.test.ts. Registry projection: apps/sim/blocks/visibility/visibility.test.ts. When gating behavior changes, extend those — mock isPlatformAdmin for the admin clause; use the local withAppConfig harness.
Version History
- ceda457 Current 2026-08-20 15:28


