# Adding Pieces To add a new piece to the space's piece list, use the `addPiece` handler exported by the default app pattern. **Never** push to `allPieces` directly. ## Why - **Type safety** — no `as any` casts needed - **Deduplication** — `addPiece` checks for duplicates before adding - **Transaction semantics** — proper commit/retry via the handler system - **Encapsulation** — patterns don't depend on the internal shape of the default app's state ## Usage in an `action()` The most common case — creating a piece in response to a user interaction: ```tsx // Shown for illustration only. import { action, pattern, wish, Stream, UI } from "commonfabric"; import { MentionablePiece } from "@commonfabric/piece"; // Wish for the addPiece handler at pattern body level const defaultApp = wish<{ addPiece: Stream<{ piece: MentionablePiece }> }>({ query: "#default", }); const createNote = action(() => { const note = Note({ title: "New Note", content: "", noteId: generateId() }); defaultApp.result.addPiece.send({ piece: note }); return navigateTo(note); }); return { [UI]: New Note, }; ``` ## Usage in a `handler()` When you need reusable logic that can be bound to different state: ```tsx // Shown for illustration only. import { handler, Stream } from "commonfabric"; import { MentionablePiece } from "@commonfabric/piece"; // Define at module scope const createNoteHandler = handler< { title: string; content: string }, { addPiece: Stream<{ piece: MentionablePiece }> } >(({ title, content }, { addPiece }) => { const note = Note({ title, content, noteId: generateId() }); addPiece.send({ piece: note }); return note; }); // Inside pattern body — bind with the wished stream const defaultApp = wish<{ addPiece: Stream<{ piece: MentionablePiece }> }>({ query: "#default", }); return { createNote: createNoteHandler({ addPiece: defaultApp.result.addPiece }), }; ``` ## Anti-patterns ### Direct mutation ```tsx // Shown for illustration only. // BAD — direct mutation, no deduplication const { allPieces } = wish<{ allPieces: Writable }>({ query: "#default" }).result; allPieces.push(newNote); ``` ### Type hack ```tsx // Shown inside a pattern body. // WORSE — hides type errors behind `as any` allPieces.push(note as any); (allPieces as any).push(note); ``` ### Wishing for `allPieces` as Writable ```tsx // Shown inside a pattern body. // BAD — exposes internal implementation of default-app wish<{ allPieces: Writable }>({ query: "#default" }); ``` Instead, wish only for the `addPiece` stream: ```tsx // Shown at module scope. // GOOD — depends on the handler contract, not internal state wish<{ addPiece: Stream<{ piece: MentionablePiece }> }>({ query: "#default", }); ``` ## How it works The `addPiece` handler is defined in `default-app.tsx` and exported as a `Stream<{ piece: MentionablePiece }>`. Internally it checks for duplicates and pushes to the owned `allPieces` Writable. The runtime infrastructure (`PieceManager.add()`) also uses this handler — patterns should follow the same approach. See [handler()](../concepts/handler.md) for handler mechanics and [wish()](wish.md) for wish usage.