Composer des grid canvases
Un grid canvas est une composition, non une app : une grille de placements, chacun rendant un component canvas (un widget réutilisable avec sa propre source, build et contrat de placement). Le home canvas de l'utilisateur est un grid canvas ordinaire dans son canal personnel. La layout est une donnée — publier ou patcher une layout est immédiat et en direct, sans build.
Trois types de canvas partagent un même lifecycle :
freeform— une app standalone (le skillbuilding-canvasesles possède).component— un widget réutilisable. Même pipeline source/build qu'un freeform, plus un contrat de placement. La visibilité suit son canal : canal personnel = privé, canal d'équipe = partagé.grid— une layout de placements référençant des components. Aucune source fichier ; layout uniquement.
L'échelle de résolution : configurer, forker, builder
Quand un placement de grid a besoin de contenu (« un widget météo ici », « un kanban de mes tâches »), résous dans cet ordre — placer un component existant surpasse l'authoring d'un doublon :
- Chercher le store :
canvas-listaveckind=componentetsearch=<ce que le widget affiche>. Un component est placeable quandcomponent_metaetpublished_build_idsont définis. Si sonconfigSchemapeut exprimer la demande (« météo pour Lisbonne » → component météo existant avecconfig: {"location": "Lisbonne"}), place et configure — n'écris pas de code. - Fork quand un component est proche mais son config ne peut pas exprimer la demande : lis sa source (
canvas-source-retrieve), crée un nouveau component (canvas-createaveckind=component), adapte, publie. Nomme la différence dans la description du nouveau component. - Builder nouveau quand rien ne convient — voir « Building a component » ci-dessous.
Les nouveaux components arrivent dans le canal où tu les crées. Crée-les dans le même canal que le grid qu'ils servent sauf si l'utilisateur demande à les partager plus largement.
Building a component
Un component s'authors exactement comme un freeform canvas — charge building-react-quill-canvases (ou building-html-canvases) plus querying-canvas-data et validating-and-publishing-canvases — avec trois additions. Un component affichant des données PostHog suit la même règle de vérifiabilité que tout canvas : une figure adossée à un insight lie son insight sauvegardé, une query ad-hoc expose la query exacte qui s'est exécutée (voir « Verifiability » dans querying-canvas-data).
Démarre du projet complet et buildable dans references/component-example.md ; son envelope, son contrat de placement, ses déclarations de capability et son accès défensif à ph.state sont les parts qui cassent quand c'est improvisé.
-
Crée avec
kind=componentet unedescriptionécrite pour la recherche en store : dis ce que le widget affiche et ce que son config contrôle. Les placements futurs sont trouvés par ce texte. -
Déclare le contrat de placement dans la clé
componentde top-level du projet :{ "component": { "size": { "defaultW": 2, "defaultH": 1, "minW": 1, "minH": 1, "maxW": 4 }, "configSchema": { "type": "object", "properties": { "location": { "type": "string", "description": "Ville pour afficher la météo" } } } } }La taille est en unités de grid (largeurs 1–12, hauteurs 1–40) ;
minW <= defaultW <= maxW. La plage est informelle : les utilisateurs peuvent redimensionner un placement à n'importe quelle taille, elle informe les defaults et les avertissements, jamais les rejets. Le vocabulaire du config schema est un allowlist —type,title,description,default,properties,required,additionalProperties,items,enum,const,minimum,maximum,minLength,maxLength,minItems,maxItems,format. Pas de$ref, pas depattern— la validation les rejette. -
Designs responsively. Donne au root du component
h-screenpour qu'il remplisse la viewport de l'iframe du placement, et adapte la layout à n'importe quelle taille que l'utilisateur drag : un placement 2×1 est une tile jetable ; un 6×4 est une surface d'app complète. N'utilise pash-fullsur le root : la shell artifact d'un component publié ne donne à ses élémentshtml,bodyet#rootaucune hauteur explicite, doncheight: 100%s'effondre à la hauteur du contenu. Rends utilement àminW×minH, et traiteconfigcomme le seul input par-placement.
Publie et attends le build comme tout canvas — un component sans build prêt ne peut pas aller en direct sur un grid.
Composing a whole canvas
Un whole-canvas ask (« un home canvas qui résume mon work in progress ») signifie habituellement plusieurs widgets, pas un. Planifie l'ensemble complet d'abord — un placement par concern — puis résous chacun avec l'échelle ci-dessus. Mets-les en layout ensemble : pas de chevauchements, tailles matchées à ce que chaque widget affiche, la grid remplie délibérément plutôt que des tiles disséminées dans un coin. Batch les écritures de layout (une publish pour une layout initiale, des patches chirurgicales après) au lieu d'une write par widget, et termine avec chaque placement en direct ou échoué — ne generant jamais.
Canvas comments
Les utilisateurs laissent du feedback sous forme de comment threads sur le canvas, ancrés à sa task de conversation.
Liste-les avec les task comment tools (tasks-comments-list, tasks-comments-retrieve) sur ta task avant et après changer le canvas, et adresse les ouverts — un comment nommant un widget cassé est ton brief pour le fixer.
Editing a grid
La boucle est read → patch, gardée exactement comme validating-and-publishing-canvases le décrit pour les source publishes — avec canvas-layout-get à la place de canvas-source-retrieve, et canvas-layout-patch (ops chirurgicales, guard requis) ou canvas-layout-publish (document complet, pour une layout initiale ou full restructure) comme la write. Sur un 409, relis la layout, réapplique ton changement, et patch à nouveau.
Operations :
add_placement— une nouvelle box :{id, status, x, y, w, h, ...}. Les placements ne doivent pas se chevaucher ou dépassergrid.columns.update_placement— mergechangesdans le placement avecid. Remplir une box dessinée est{"op": "update_placement", "id": "p1", "changes": {"status": "live", "component": "<component canvas id>", "config": {...}}}.remove_placement,set_grid.
The placement lifecycle
Le status d'un placement dit au renderer ce qu'il faut afficher :
pending— l'utilisateur a dessiné une box mais ne l'a pas décrite (ou le prompt attend dispatch).generating— une agent task la remplit ;generationTaskIdlie la task etpromptenregistre l'ask. Définis ceci quand tu commences à travailler sur un placement depuis une task.live— rend soncomponentàversion("latest"par défaut ; un pinned version id est permis). Requiert que le component soit publié et visible pour l'acting user.failed— la generation a échoué ; garde lepromptpour que l'utilisateur puisse retry ou re-décrire.
Quand une task te demande de remplir un placement, son prompt et la taille de la box sont ton brief : honore le w×h dessiné et garde le prompt du placement intact pour la provenance.
Validation you will hit
Les layout publishes valident atomiquement ; chaque error nomme son placement. Les courantes :
component_not_found— l'id est mauvais, supprimé, pas un component, ou pas visible pour l'acting user (un component dans le canal personnel de quelqu'un d'autre n'est pas placeable).component_not_published— le component n'a jamais publié un contrat de placement.placement_config_invalid—configne matche pas leconfigSchemadu component.placement_size_out_of_contract— un warning, pas une error : lew/hde la box est en dehors de la plage suggérée du component. La publish réussit quand même ; le component doit rendre responsively.placements_overlap/invalid_placement— géométrie ; fixe les coordonnées plutôt que de retirer l'autre widget.
Termine ta réponse en linquant le grid canvas avec le champ url que les canvas tools retournent — ne construis jamais une canvas URL toi-même.