-
-
Notifications
You must be signed in to change notification settings - Fork 70
Expand file tree
/
Copy pathdomain_map.yaml
More file actions
1003 lines (939 loc) · 40.2 KB
/
domain_map.yaml
File metadata and controls
1003 lines (939 loc) · 40.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# domain_map.yaml
# Generated by skill-domain-discovery
# Library: @tanstack/devtools
# Version: 0.10.12
# Date: 2026-03-11
# Status: reviewed
library:
name: '@tanstack/devtools'
version: '0.10.12'
repository: 'https://github.com/TanStack/devtools'
description: >
Framework-agnostic toolkit for building, composing, and debugging custom
devtools panels via a plugin system with typed event communication.
Supports React, Vue, Solid, and Preact.
primary_framework: 'framework-agnostic'
domains:
- name: 'Setting up devtools'
slug: 'setup'
description: >
Installing, configuring, and mounting TanStack Devtools in an application.
Covers framework adapter selection, plugin registration, shell configuration,
and Vite plugin integration.
- name: 'Building plugins'
slug: 'plugin-development'
description: >
Creating custom devtools plugins end-to-end: defining event clients,
building panel components, registering plugins, and publishing to
the marketplace.
- name: 'Event communication'
slug: 'event-communication'
description: >
The typed event system that plugins use to send and receive data.
Covers EventClient creation, event maps, connection lifecycle,
bidirectional patterns, and cross-tab synchronization.
- name: 'Framework adaptation'
slug: 'framework-adaptation'
description: >
Creating per-framework plugin adapters using devtools-utils factory
functions. Covers React, Vue, Solid, and Preact differences,
portal/teleport mechanisms, and NoOp variants for tree-shaking.
- name: 'Build and production'
slug: 'build-production'
description: >
Vite plugin features and production build concerns. Covers source
injection, console piping, production stripping, enhanced logging,
and conditional devtools inclusion.
- name: 'Library instrumentation'
slug: 'instrumentation'
description: >
Strategically adding event emissions to a library codebase at critical
architecture and debugging points without overdoing it.
skills:
- name: 'App setup'
slug: 'app-setup'
domain: 'setup'
description: >
End-app developer installs TanStack Devtools, picks the right framework
adapter, registers plugins, and configures the shell.
type: 'core'
packages:
- '@tanstack/react-devtools'
- '@tanstack/vue-devtools'
- '@tanstack/solid-devtools'
- '@tanstack/preact-devtools'
- '@tanstack/devtools'
- '@tanstack/devtools-vite'
covers:
- 'TanStackDevtools component'
- 'plugins prop'
- 'config prop (position, hotkeys, theme, hideUntilHover, requireUrlFlag)'
- 'eventBusConfig prop'
- 'Framework-specific plugin types'
- 'defaultOpen behavior'
- 'localStorage persistence'
tasks:
- 'Install devtools for my React/Vue/Solid/Preact app'
- 'Add TanStack Query and Router devtools to my app'
- 'Configure devtools position, hotkeys, and theme'
- 'Set up devtools with Vite plugin for enhanced features'
- 'Hide devtools trigger until hover'
- 'Require URL flag to enable devtools'
failure_modes:
- mistake: 'Vite plugin not placed first in plugins array'
mechanism: >
Source injection and other transforms must run before framework
plugins. Placing devtools() after other plugins causes source
inspector to not work.
wrong_pattern: |
export default {
plugins: [
react(),
devtools(),
],
}
correct_pattern: |
export default {
plugins: [
devtools(),
react(),
],
}
source: 'docs/quick-start.md, docs/vite-plugin.md'
priority: 'HIGH'
status: 'active'
- mistake: 'Vue plugin uses render instead of component'
mechanism: >
Vue adapter uses component reference + props pattern, not JSX render.
Using render field produces silent failure — no panel renders.
wrong_pattern: |
const plugins = [
{ name: 'My Plugin', render: <MyComponent /> }
]
correct_pattern: |
const plugins: TanStackDevtoolsVuePlugin[] = [
{ name: 'My Plugin', component: MyComponent }
]
source: 'docs/framework/vue/adapter.md, packages/vue-devtools/src/vue-devtools.vue'
priority: 'CRITICAL'
status: 'active'
skills: ['app-setup', 'framework-adapters']
- mistake: 'Installing as regular dependency for dev-only use'
mechanism: >
Devtools should be devDependencies when using Vite plugin stripping.
Installing as regular deps bloats production node_modules.
wrong_pattern: |
npm install @tanstack/react-devtools @tanstack/devtools-vite
correct_pattern: |
npm install -D @tanstack/react-devtools @tanstack/devtools-vite
source: 'docs/installation.md'
priority: 'MEDIUM'
status: 'active'
- mistake: 'Mounting TanStackDevtools in SSR without client guard'
mechanism: >
The core shell requires DOM APIs. Mounting during SSR causes errors.
React adapter has use client directive, but custom setups need guards.
wrong_pattern: |
// In an SSR-rendered component without client guard
function App() {
return <TanStackDevtools />
}
correct_pattern: |
// React adapter already has 'use client' directive
// For custom setups, guard with typeof document check
import { TanStackDevtools } from '@tanstack/react-devtools'
function App() {
return <TanStackDevtools />
}
source: 'packages/devtools/src/core.ts, packages/react-devtools/src/devtools.tsx'
priority: 'HIGH'
status: 'active'
- name: 'Vite plugin setup'
slug: 'vite-plugin'
domain: 'build-production'
description: >
Configure the Vite plugin for source inspection, console piping,
enhanced logging, server event bus, and production stripping.
type: 'core'
packages:
- '@tanstack/devtools-vite'
covers:
- 'devtools() function and options'
- 'Source injection (data-tsd-source attributes)'
- 'Source inspector activation and hotkeys'
- 'Console piping (client-to-server and server-to-client)'
- 'Enhanced console logs with source locations'
- 'Production build stripping'
- 'Server event bus configuration'
- 'Editor integration (launch-editor)'
- 'Plugin marketplace support'
- 'Connection injection placeholders'
tasks:
- 'Add Vite plugin to my project'
- 'Configure source inspector for click-to-open-in-editor'
- 'Set up console piping between browser and terminal'
- 'Configure custom editor for go-to-source'
- 'Disable specific Vite plugin features'
- 'Configure event bus port and host'
subsystems:
- name: 'Source injection'
package: '@tanstack/devtools-vite'
config_surface: 'injectSource.enabled, injectSource.ignore (files, components)'
- name: 'Console piping'
package: '@tanstack/devtools-vite'
config_surface: 'consolePiping.enabled, consolePiping.levels'
- name: 'Enhanced logging'
package: '@tanstack/devtools-vite'
config_surface: 'enhancedLogs.enabled'
- name: 'Production stripping'
package: '@tanstack/devtools-vite'
config_surface: 'removeDevtoolsOnBuild'
- name: 'Server event bus'
package: '@tanstack/devtools-vite'
config_surface: 'eventBusConfig.port, eventBusConfig.enabled, eventBusConfig.debug'
- name: 'Editor integration'
package: '@tanstack/devtools-vite'
config_surface: 'editor.name, editor.open'
failure_modes:
- mistake: 'Expecting Vite plugin features in production'
mechanism: >
Source injection, console piping, enhanced logging, and the server
event bus only work during development with Vite dev server.
Production builds strip all of this.
source: 'packages/devtools-vite/src/plugin.ts'
priority: 'MEDIUM'
status: 'active'
- mistake: 'Not placing devtools() first in Vite plugins'
mechanism: >
All devtools sub-plugins use enforce:pre. They must transform code
before framework plugins (React, Vue, etc.) process it.
wrong_pattern: |
plugins: [react(), devtools()]
correct_pattern: |
plugins: [devtools(), react()]
source: 'docs/vite-plugin.md'
priority: 'HIGH'
status: 'active'
skills: ['vite-plugin', 'app-setup']
- mistake: 'Source injection on spread props elements'
mechanism: >
The Oxc transform skips elements with {...props} spread to avoid
overwriting dynamic attributes. Agent might not realize source
inspector wont work on those elements.
source: 'packages/devtools-vite/src/inject-source.ts'
priority: 'MEDIUM'
status: 'active'
- mistake: 'Using devtools-vite with non-Vite bundlers'
mechanism: >
The package is Vite-specific (peer dep vite ^6 || ^7). It will not
work with webpack, rspack, or other bundlers. EventClient still works
without it for same-page communication.
source: 'packages/devtools-vite/package.json'
priority: 'HIGH'
status: 'active'
- mistake: 'Event bus port conflict in multi-project setups'
mechanism: >
Default port 4206 may conflict when running multiple Vite dev servers.
ServerEventBus falls back to OS-assigned port on EADDRINUSE, but
clients may not discover the new port without Vite injection.
source: 'packages/event-bus/src/server/server.ts lines 313-336'
priority: 'MEDIUM'
status: 'active'
- name: 'Event client creation'
slug: 'event-client-creation'
domain: 'event-communication'
description: >
Create a typed EventClient for a library, define event maps, understand
the connection lifecycle, event namespacing, and queuing behavior.
type: 'core'
packages:
- '@tanstack/devtools-event-client'
covers:
- 'EventClient class and constructor options'
- 'Event map type definitions'
- 'pluginId namespacing (auto-prepend)'
- 'emit() and event queuing'
- 'on(), onAll(), onAllPluginEvents() listeners'
- 'Connection lifecycle (5 retries, 300ms interval)'
- 'enabled/disabled state'
- 'SSR/non-web environment fallbacks'
- 'Internal EventTarget (withEventTarget option)'
tasks:
- 'Create a typed EventClient for my library'
- 'Define an event map with typed payloads'
- 'Emit events from my library code'
- 'Listen for events in my devtools panel'
- 'Handle connection failures gracefully'
failure_modes:
- mistake: 'Including pluginId prefix in event names'
mechanism: >
EventClient auto-prepends pluginId to event names. Writing
emit('my-plugin:state-update') produces the event name
'my-plugin:my-plugin:state-update' on the bus.
wrong_pattern: |
myClient.emit('my-plugin:state-update', data)
correct_pattern: |
myClient.emit('state-update', data)
source: 'packages/event-bus-client/src/plugin.ts lines 190-199'
priority: 'CRITICAL'
status: 'active'
- mistake: 'Creating multiple EventClient instances per plugin'
mechanism: >
EventClient should be a singleton per plugin. Multiple instances
with the same pluginId create duplicate event handlers and
multiple connection attempts to the bus.
wrong_pattern: |
function MyPanel() {
const client = new MyEventClient() // new instance per render
client.on('state', cb)
}
correct_pattern: |
// Module-level singleton
export const myClient = new MyEventClient()
function MyPanel() {
myClient.on('state', cb)
}
source: 'docs/building-custom-plugins.md, packages/event-bus-client/src/plugin.ts'
priority: 'CRITICAL'
status: 'active'
- mistake: 'Not realizing events drop after 5 failed retries'
mechanism: >
After 5 connection retries (1.5s total), failedToConnect is set
permanently. All subsequent emit() calls are silently dropped.
No error is thrown.
source: 'packages/event-bus-client/src/plugin.ts lines 44-56'
priority: 'HIGH'
status: 'active'
- mistake: 'Listening before emitting and expecting connection'
mechanism: >
Connection is lazily initiated on first emit(), not on construction
or on(). If you only call on() without ever emitting, the client
never connects to the bus.
source: 'packages/event-bus-client/src/plugin.ts'
priority: 'HIGH'
status: 'active'
- mistake: 'Using non-serializable payloads in events'
mechanism: >
Events are serialized via JSON when crossing process/tab boundaries
(WebSocket, SSE, BroadcastChannel). Functions, DOM nodes, and
circular references will fail silently or produce empty payloads.
wrong_pattern: |
client.emit('update', {
callback: () => {}, // function - not serializable
element: document.body, // DOM node
})
correct_pattern: |
client.emit('update', {
count: 42,
label: 'my-update',
timestamp: Date.now(),
})
source: 'packages/event-bus/src/utils/json.ts, docs/bidirectional-communication.md'
priority: 'HIGH'
status: 'active'
skills: ['event-client-creation', 'bidirectional-communication']
- mistake: 'Non-unique pluginId causing event collisions'
mechanism: >
If two plugins use the same pluginId, their events collide on
the bus. One plugin receives events intended for the other,
causing incorrect state and hard-to-debug behavior.
wrong_pattern: |
// Plugin A
class PluginA extends EventClient<AEvents> {
constructor() { super({ pluginId: 'my-plugin' }) }
}
// Plugin B — same pluginId!
class PluginB extends EventClient<BEvents> {
constructor() { super({ pluginId: 'my-plugin' }) }
}
correct_pattern: |
// Plugin A
class PluginA extends EventClient<AEvents> {
constructor() { super({ pluginId: 'query-inspector' }) }
}
// Plugin B — unique pluginId
class PluginB extends EventClient<BEvents> {
constructor() { super({ pluginId: 'router-inspector' }) }
}
source: 'maintainer interview'
priority: 'CRITICAL'
status: 'active'
- mistake: 'Not stripping EventClient emit calls for production'
mechanism: >
The Vite plugin strips framework adapter imports but NOT
@tanstack/devtools-event-client imports. Library authors must
decide whether to keep or guard emit() calls in production.
The enabled:false option or conditional guards are needed.
wrong_pattern: |
// Library code — emits in production with no guard
export function updateState(state) {
myClient.emit('state-changed', state)
}
correct_pattern: |
// Option 1: Use enabled flag
const myClient = new MyClient({
pluginId: 'my-lib',
enabled: process.env.NODE_ENV === 'development',
})
// Option 2: Conditional guard
export function updateState(state) {
if (__DEV__) myClient.emit('state-changed', state)
}
source: 'maintainer interview'
priority: 'HIGH'
status: 'active'
- name: 'Strategic instrumentation'
slug: 'strategic-instrumentation'
domain: 'instrumentation'
description: >
Analyze a library codebase to find critical architecture and debugging
points, then add strategic event emissions that provide maximum debugging
value with minimum noise.
type: 'core'
packages:
- '@tanstack/devtools-event-client'
covers:
- 'Identifying critical architecture points (middleware, state transitions, lifecycle hooks)'
- 'Choosing what to emit vs what to skip'
- 'Consolidating multiple events into single meaningful emissions'
- 'Performance-aware emission patterns'
- 'Middleware/interceptor integration patterns'
- 'Observer/subscription emission patterns'
tasks:
- 'Instrument my library with devtools events'
- 'Find the right places to emit events in my codebase'
- 'Emit one meaningful event instead of many noisy ones'
- 'Add devtools support to my state management library'
- 'Instrument middleware pipelines for debugging'
failure_modes:
- mistake: 'Emitting too many granular events'
mechanism: >
Emitting 15 events for what could be 1 consolidated event creates
noise in the devtools panel and performance overhead. Consolidate
related state changes into single emissions.
wrong_pattern: |
function processRequest(req) {
client.emit('request-start', { id: req.id })
client.emit('request-parsed', { body: req.body })
client.emit('request-validated', { valid: true })
client.emit('middleware-1-start', {})
client.emit('middleware-1-end', {})
// ... 10 more events
}
correct_pattern: |
function processRequest(req) {
const result = runPipeline(req)
client.emit('request-processed', {
id: req.id,
duration: result.duration,
middlewareChain: result.middlewareNames,
status: result.status,
})
}
source: 'maintainer interview'
priority: 'HIGH'
status: 'active'
- mistake: 'Emitting in hot loops without debouncing'
mechanism: >
Emitting events inside tight loops or rapid state updates causes
performance degradation. Events should be debounced or batched
for high-frequency operations.
source: 'docs/bidirectional-communication.md'
priority: 'HIGH'
status: 'active'
- mistake: 'Not emitting at architecture boundaries'
mechanism: >
The highest-value emission points are architecture boundaries:
before/after middleware, on state transitions, at lifecycle hooks.
Emitting inside implementation details misses the forest for trees.
source: 'maintainer interview'
priority: 'MEDIUM'
status: 'active'
- name: 'Plugin panel development'
slug: 'plugin-panel-development'
domain: 'plugin-development'
description: >
Build the devtools panel component that displays data emitted by
your library. Use devtools-ui components, handle theming, and
manage event listener lifecycle.
type: 'core'
packages:
- '@tanstack/devtools-ui'
- '@tanstack/devtools-event-client'
covers:
- 'Panel component structure'
- 'Listening to events via on()'
- 'Theme handling (light/dark)'
- 'devtools-ui components (JSONTree, buttons, inputs, sections)'
- 'Plugin registration (name, render, id, defaultOpen)'
- 'Plugin lifecycle (mount, activate, destroy)'
- 'Max 3 concurrent active plugins'
- 'localStorage state persistence'
- 'Two paths: Solid.js core with devtools-ui for multi-framework, or framework-specific panels directly'
- 'Transparent server/client event bridging (emit on server, receive on client and vice versa)'
tasks:
- 'Build a panel that displays my library state'
- 'Use devtools-ui JSON viewer to show data'
- 'Handle dark/light theme in my panel'
- 'Register my panel as a devtools plugin'
- 'Set my plugin to open by default'
failure_modes:
- mistake: 'Not cleaning up event listeners'
mechanism: >
Each on() call returns a cleanup function. Forgetting to call it
in useEffect cleanup (React), onCleanup (Solid), or onUnmounted
(Vue) causes memory leaks and duplicate handlers on re-render.
wrong_pattern: |
useEffect(() => {
client.on('state', (e) => setState(e.payload))
// Missing cleanup!
}, [])
correct_pattern: |
useEffect(() => {
const cleanup = client.on('state', (e) => setState(e.payload))
return cleanup
}, [])
source: 'docs/building-custom-plugins.md, docs/event-system.md'
priority: 'CRITICAL'
status: 'active'
- mistake: 'Ignoring theme prop in panel component'
mechanism: >
The render function receives theme as second argument. Panel
components should adapt their styling. Agents often hardcode
light or dark styles.
source: 'docs/plugin-lifecycle.md'
priority: 'MEDIUM'
status: 'active'
- mistake: 'Not knowing max 3 active plugins limit'
mechanism: >
At most 3 plugin panels can be displayed simultaneously
(MAX_ACTIVE_PLUGINS constant). Setting more than 3 plugins
to defaultOpen:true only opens the first 3.
source: 'packages/devtools/src/utils/get-default-active-plugins.ts'
priority: 'MEDIUM'
status: 'active'
- mistake: 'Using raw DOM manipulation instead of framework portals'
mechanism: >
Plugin render() receives a DOM element, but framework adapters
handle portaling automatically. Agents might try to manually
manipulate the DOM instead of using the adapter pattern.
source: 'docs/plugin-lifecycle.md'
priority: 'MEDIUM'
status: 'active'
- mistake: 'Oversubscribing to events in multiple places'
mechanism: >
AI agents subscribe to the same event in 5 different components
instead of subscribing once and sharing state. This creates
duplicate handlers, wasted memory, and inconsistent state.
wrong_pattern: |
// Component A subscribes
client.on('state', (e) => setStateA(e.payload))
// Component B also subscribes to same event
client.on('state', (e) => setStateB(e.payload))
// Component C also subscribes...
client.on('state', (e) => setStateC(e.payload))
correct_pattern: |
// Subscribe once in a shared store/context
const cleanup = client.on('state', (e) => {
sharedStore.setState(e.payload)
})
// Components read from the shared store
source: 'maintainer interview'
priority: 'HIGH'
status: 'active'
- mistake: 'Hardcoding repeated event payload fields'
mechanism: >
When multiple events share common fields (name, type, version),
agents hardcode each field separately instead of creating a shared
object and spreading it. Makes code harder to maintain.
wrong_pattern: |
client.emit('created', { name: lib.name, type: lib.type, version: lib.version, action: 'create' })
client.emit('updated', { name: lib.name, type: lib.type, version: lib.version, action: 'update' })
client.emit('deleted', { name: lib.name, type: lib.type, version: lib.version, action: 'delete' })
correct_pattern: |
const baseInfo = { name: lib.name, type: lib.type, version: lib.version }
client.emit('created', { ...baseInfo, action: 'create' })
client.emit('updated', { ...baseInfo, action: 'update' })
client.emit('deleted', { ...baseInfo, action: 'delete' })
source: 'maintainer interview'
priority: 'MEDIUM'
status: 'active'
skills: ['plugin-panel-development', 'strategic-instrumentation']
- mistake: 'Not keeping devtools packages at latest versions'
mechanism: >
Agents pin or use old versions of devtools packages. While exact
version sync is not required, using latest versions across all
devtools packages increases stability and compatibility.
source: 'maintainer interview'
priority: 'MEDIUM'
status: 'active'
skills: ['app-setup', 'plugin-panel-development']
- name: 'Framework adapters'
slug: 'framework-adapters'
domain: 'framework-adaptation'
description: >
Use devtools-utils factory functions to create per-framework plugin
adapters with NoOp variants for production tree-shaking.
type: 'framework'
packages:
- '@tanstack/devtools-utils'
covers:
- 'createReactPlugin() / createReactPanel()'
- 'createSolidPlugin() / createSolidPanel()'
- 'createVuePlugin() / createVuePanel()'
- 'createPreactPlugin() / createPreactPanel()'
- '[Plugin, NoOpPlugin] tuple pattern'
- 'DevtoolsPanelProps (theme prop)'
- 'Class-based panel factories'
- 'Framework-specific portal/teleport mechanisms'
tasks:
- 'Create React and Solid adapters for my plugin'
- 'Use factory functions to build framework adapters'
- 'Set up production tree-shaking with NoOp variants'
- 'Build a class-based devtools core with panel wrappers'
subsystems:
- name: 'React adapter'
package: '@tanstack/devtools-utils'
config_surface: 'createReactPlugin({name, id, defaultOpen, Component})'
- name: 'Solid adapter'
package: '@tanstack/devtools-utils'
config_surface: 'createSolidPlugin({name, id, defaultOpen, Component})'
- name: 'Vue adapter'
package: '@tanstack/devtools-utils'
config_surface: 'createVuePlugin(name, component)'
- name: 'Preact adapter'
package: '@tanstack/devtools-utils'
config_surface: 'createPreactPlugin({name, id, defaultOpen, Component})'
failure_modes:
- mistake: 'Using React JSX pattern in Vue adapter'
mechanism: >
Vue uses component reference + props, not JSX render elements.
createVuePlugin takes (name, component) not an options object.
wrong_pattern: |
const [Plugin] = createVuePlugin({
name: 'My Plugin',
Component: MyPanel,
})
correct_pattern: |
const [Plugin] = createVuePlugin('My Plugin', MyPanel)
source: 'packages/devtools-utils/src/vue/plugin.ts'
priority: 'CRITICAL'
status: 'active'
- mistake: 'Solid render prop not wrapped in function'
mechanism: >
Solid requires render to be a function returning JSX, not raw JSX.
Passing raw JSX causes it to evaluate immediately and not react
to signal changes.
wrong_pattern: |
<TanStackDevtools
plugins={[{
name: 'My Plugin',
render: <MyPanel />,
}]}
/>
correct_pattern: |
<TanStackDevtools
plugins={[{
name: 'My Plugin',
render: () => <MyPanel />,
}]}
/>
source: 'docs/framework/solid/adapter.md'
priority: 'CRITICAL'
status: 'active'
- mistake: 'Ignoring NoOp variant for production'
mechanism: >
Factory functions return [Plugin, NoOpPlugin] tuple. The NoOp
variant renders nothing and is meant for production builds.
Ignoring it means devtools code ships to production.
wrong_pattern: |
const [MyPlugin] = createReactPlugin({ ... })
// Always uses MyPlugin, even in production
correct_pattern: |
const [MyPlugin, NoOpPlugin] = createReactPlugin({ ... })
const ActivePlugin = process.env.NODE_ENV === 'development'
? MyPlugin
: NoOpPlugin
source: 'docs/devtools-utils.md'
priority: 'HIGH'
status: 'active'
- mistake: 'Not passing theme prop to panel component'
mechanism: >
Factory-created plugins receive DevtoolsPanelProps with theme.
Agent might destructure props but not use theme, resulting in
panel that doesnt match devtools dark/light mode.
source: 'packages/devtools-utils/src/react/plugin.tsx'
priority: 'MEDIUM'
status: 'active'
- name: 'Bidirectional communication'
slug: 'bidirectional-communication'
domain: 'event-communication'
description: >
Implement two-way event patterns between the devtools panel and
application: commands, state editing, and time-travel debugging.
type: 'core'
packages:
- '@tanstack/devtools-event-client'
covers:
- 'App-to-devtools observation pattern'
- 'Devtools-to-app command pattern'
- 'Time-travel debugging with snapshots and revert'
- 'Bidirectional event map design'
- 'structuredClone for snapshot safety'
- 'Debouncing frequent emissions'
tasks:
- 'Add a reset button to my devtools panel'
- 'Implement state editing from devtools'
- 'Build time-travel debugging for my state library'
- 'Send commands from devtools panel back to app'
failure_modes:
- mistake: 'Not using structuredClone for snapshots'
mechanism: >
Passing state object references directly means future mutations
corrupt historical snapshots. Must deep-clone before emitting.
wrong_pattern: |
client.emit('snapshot', { state, timestamp: Date.now() })
correct_pattern: |
client.emit('snapshot', {
state: structuredClone(state),
timestamp: Date.now(),
})
source: 'docs/bidirectional-communication.md'
priority: 'HIGH'
status: 'active'
- mistake: 'Not distinguishing observation from command events'
mechanism: >
Mixing observation and command events in the same namespace causes
confusion. Use distinct suffixes like state-update (observation)
vs set-state (command).
source: 'docs/bidirectional-communication.md'
priority: 'MEDIUM'
status: 'active'
- mistake: 'Non-serializable payloads in cross-tab scenarios'
mechanism: >
Events crossing tab/process boundaries are JSON-serialized.
Functions, DOM nodes, and circular references silently fail.
source: 'packages/event-bus/src/utils/json.ts'
priority: 'HIGH'
status: 'active'
skills: ['event-client-creation', 'bidirectional-communication']
- name: 'Production setup'
slug: 'production-setup'
domain: 'build-production'
description: >
Handle devtools in production vs development: tree-shaking,
conditional imports, Vite stripping, and dev-only dependencies.
type: 'lifecycle'
packages:
- '@tanstack/devtools-vite'
- '@tanstack/devtools'
covers:
- 'removeDevtoolsOnBuild option'
- 'Dev dependency vs regular dependency'
- '/production sub-export'
- 'Conditional imports with environment variables'
- 'NoOp plugin variants for tree-shaking'
- 'Non-Vite production exclusion patterns'
tasks:
- 'Strip devtools from production build'
- 'Keep devtools in production intentionally'
- 'Set up conditional devtools loading'
- 'Handle production builds without Vite'
failure_modes:
- mistake: 'Keeping devtools in production without disabling stripping'
mechanism: >
Setting removeDevtoolsOnBuild defaults to true. If you want
devtools in production, you must explicitly set it to false AND
install as regular dependency.
wrong_pattern: |
// vite.config.ts - devtools stripped silently
devtools()
// package.json - devDependency won't be available
"devDependencies": { "@tanstack/react-devtools": "..." }
correct_pattern: |
// vite.config.ts
devtools({ removeDevtoolsOnBuild: false })
// package.json - regular dependency
"dependencies": { "@tanstack/react-devtools": "..." }
source: 'docs/production.md'
priority: 'HIGH'
status: 'active'
- mistake: 'Not using /production sub-export for production builds'
mechanism: >
Production builds should use the /production sub-export which
includes only production-safe code without dev-only features.
source: 'docs/production.md'
priority: 'MEDIUM'
status: 'active'
- mistake: 'Non-Vite projects not excluding devtools manually'
mechanism: >
Without the Vite plugin, devtools are not automatically stripped.
Non-Vite projects must manually exclude via environment variables
or conditional imports.
wrong_pattern: |
// Always imports devtools regardless of environment
import { TanStackDevtools } from '@tanstack/react-devtools'
correct_pattern: |
const Devtools = process.env.NODE_ENV === 'development'
? await import('./devtools-setup')
: () => null
source: 'docs/production.md'
priority: 'HIGH'
status: 'active'
- name: 'Marketplace publishing'
slug: 'marketplace-publishing'
domain: 'plugin-development'
description: >
Publish a devtools plugin to npm and submit it to the TanStack
Devtools Marketplace registry for discovery and one-click install.
type: 'lifecycle'
packages:
- '@tanstack/devtools'
covers:
- 'PluginMetadata registry format'
- 'plugin-registry.ts submission'
- 'pluginImport configuration (importName, type)'
- 'requires field (packageName, minVersion, maxVersion)'
- 'Framework tagging'
- 'Multi-framework submissions'
- 'Featured plugins'
tasks:
- 'Submit my plugin to the TanStack Marketplace'
- 'Configure plugin metadata for auto-install'
- 'Submit plugins for multiple frameworks'
failure_modes:
- mistake: 'Missing pluginImport metadata for auto-install'
mechanism: >
Without pluginImport.importName and pluginImport.type, the
marketplace cant auto-inject the plugin into user code.
The install button will add the package but not wire it up.
source: 'docs/third-party-plugins.md, packages/devtools-vite/src/inject-plugin.ts'
priority: 'HIGH'
status: 'active'
- mistake: 'Not specifying requires.minVersion'
mechanism: >
If your plugin depends on a minimum version of another library,
omitting minVersion means users with older versions will get
runtime errors.
source: 'docs/third-party-plugins.md'
priority: 'MEDIUM'
status: 'active'
- mistake: 'Submitting without framework field'
mechanism: >
The framework field enables filtering in the marketplace UI.
Without it, users cant find framework-specific plugins.
source: 'docs/third-party-plugins.md'
priority: 'MEDIUM'
status: 'active'
tensions:
- name: 'Instrumentation completeness vs performance'
skills: ['strategic-instrumentation', 'event-client-creation']
description: >
Strategic instrumentation wants comprehensive debugging data, but
emitting too many events degrades application performance. Events
crossing WebSocket/SSE boundaries add latency.
implication: >
An agent optimizing for debugging coverage will emit events in hot
paths and tight loops. An agent optimizing for performance will skip
critical debugging points. The right balance is architecture-boundary
emissions with debouncing for high-frequency updates.
- name: 'Development convenience vs production safety'
skills: ['app-setup', 'production-setup']
description: >
Easy dev setup (devDependencies, auto-stripping) conflicts with
production usage where you need regular deps and explicit opt-in.
implication: >
An agent setting up devtools will install as devDependency and rely
on Vite stripping. If the user later wants production devtools, the
agent needs to undo those decisions — change to regular dep, disable
stripping, use production sub-export.
- name: 'Framework-agnostic core vs framework ergonomics'
skills: ['framework-adapters', 'plugin-panel-development']
description: >
The Solid.js core provides consistency but framework adapters have
different patterns. Vue uses component not render, Solid requires
function wrappers, React uses JSX directly.
implication: >
An agent trained on React patterns will use render/JSX everywhere.
Vue and Solid have fundamentally different plugin definitions that
agents consistently get wrong without framework-specific guidance.
cross_references:
- from: 'app-setup'
to: 'vite-plugin'
reason: >
After basic setup, Vite plugin adds enhanced features. Agent should
know Vite plugin is optional but recommended.
- from: 'event-client-creation'
to: 'strategic-instrumentation'
reason: >
After creating an EventClient, the next step is instrumenting code.
Understanding the event system informs where to emit.
- from: 'event-client-creation'
to: 'plugin-panel-development'
reason: >
The EventClient emits events that the panel listens to. Both sides
must use the same event map and understand the pluginId namespacing.
- from: 'plugin-panel-development'
to: 'framework-adapters'
reason: >
After building a panel, wrapping it in framework adapters makes it
usable across React, Vue, Solid, and Preact.
- from: 'framework-adapters'
to: 'production-setup'
reason: >
NoOp variants from factory functions are the primary mechanism for
production tree-shaking.
- from: 'bidirectional-communication'
to: 'event-client-creation'
reason: >
Bidirectional patterns extend the event client with command events.
Understanding the base event system is prerequisite.
- from: 'vite-plugin'
to: 'production-setup'
reason: >
The Vite plugin handles production stripping. Understanding its
defaults informs production configuration decisions.
- from: 'plugin-panel-development'
to: 'marketplace-publishing'
reason: >
After building a working plugin, publishing to the marketplace is
the distribution step. Plugin metadata must match the code.
- from: 'strategic-instrumentation'
to: 'bidirectional-communication'
reason: >
Strategic emission points often benefit from bidirectional patterns —
not just showing state but allowing developers to interact with it.
gaps:
- skill: 'strategic-instrumentation'
question: >
What are the specific telemetry/instrumentation patterns built into
TanStack Devtools that the maintainer mentioned are undocumented?
context: >
Maintainer said telemetry support details are missing from docs.
To be investigated from source code.
status: 'resolved'
- skill: 'plugin-panel-development'
question: >
How does the Picture-in-Picture (PiP) window mode affect plugin
rendering? Do plugins need to handle PiP-specific concerns?
context: >
PiP opens a new browser window and renders devtools there. Has zero
impact on plugin development — works seamlessly with no special handling.
status: 'resolved'
- skill: 'event-client-creation'
question: >
Are there recommended patterns for testing EventClient instances
and plugin panels in isolation (unit tests, integration tests)?
context: >
No recommended testing patterns exist currently. EventClient works
for same-page communication without the full devtools shell.
status: 'resolved'
- skill: 'strategic-instrumentation'
question: >
What are the performance benchmarks for event emission? How many
events per second can the bus handle before degradation?
context: >
No formal benchmarks exist. General guidance: prototype freely with