Skip to content
HomePagesHomePages template kit

Bind slot to fact

Fill a slot from a known property fact, no AI.

Fill a slot from a known property fact, no AI.

  • A section with a slot to rebind — Install scaffolds one.
  • Its fixtures.ts built from a scenario, so the fact resolves in preview — Pick a fixture scenario.
  • If you are swapping a slot off AI fill, the decision that fills it today — AI writes slot content adds a summary and the fill: that writes it.

Give the slot a source: fact.<container>.<field> and a writeback boolean. The pair is the whole declaration a fact-bound slot needs: the binding says where the value comes from, and writeback says whether a user’s edit propagates back to that fact.

Add fact to the section’s existing kit import — the scaffolded file takes only defineSchema, text and textBlock, so it is missing until you do.

For a worked example at full size, scaffold the example workspace (npm create @homepages/workspace@latest <name> -- --example spw-essential — the -- is required, or npm silently drops the flag) and read a fact-bound slot there.

// section.ts — the slot, bound to a fact instead of filled by AI
summary: text.long({
label: "Summary",
source: fact.property.address, writeback: false,
}),

Then delete that slot’s fill: (Sections and declarations). Both halves are the same declaration, so this is one edit: a slot declares exactly one of source: and fill:, and a bound slot that keeps its fill: is a compile error. The fact is baked in at fill time, and there is no decision left for it to disagree with.

The same pattern works for any slot type — pick a fact whose runtime shape matches, and the builder for the kind you want. For a numeric fact, number({ source: fact.unit.beds, writeback: true }); for a text one, text.long({ source: fact.property.address, writeback: false }) or any other text-shaped fact in the fact vocabulary. A fact that does not exist is a compile error on the fact.* path itself, before check ever runs. writeback: true makes the editor offer “Update everywhere” on the slot, and is legal only on a writable fact — on a read-only one (fact.property.address, fact.contact.headshot) only writeback: false compiles, so the declaration states what the catalog would otherwise decide silently. Omitting the boolean on a fact-bound slot is a compile error.

A binding names one fact. The pools the platform also holds — the property’s photos, videos, tours, floor plans, documents and their distilled notes — have no binding, because a pool is a whole candidate set and there is no single value for a slot to take from it. What a section wants from a pool is a count, a filter or a pick, which is a computation: read it off f in compute(), where every name you learned here reads identically — fact.unit.beds as f.unit.beds, fact.contact.website as f.contact.website.

The one fence under Steps is the whole edit to section.ts’s slots, plus fact on that file’s existing kit import and the deletion of the slot’s own fill:. Renderer.tsx and fixtures.ts are untouched.

Verify with the author loop.

  • typecheck — the slot carries its source binding and keeps its fill:, which is the one combination a slot may not declare.