@cratis/cast 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +3 -1
  2. package/badges/RegistryMember.ts +2 -0
  3. package/badges/badgeSvg.ts +10 -1
  4. package/badges/registry.ts +5 -0
  5. package/cast-json.schema.json +1496 -0
  6. package/config/calendar.ts +34 -0
  7. package/config/castSchema.ts +3 -2
  8. package/github/gitHubSnapshotSchema.ts +58 -0
  9. package/machine/castJson.ts +17 -4
  10. package/machine/castJsonSchema.ts +35 -0
  11. package/machine/index.ts +6 -0
  12. package/machine/profileFromCastJson.ts +215 -0
  13. package/package.json +5 -1
  14. package/routes/404.astro +6 -4
  15. package/routes/cast.json.ts +7 -1
  16. package/routes/cv.astro +3 -365
  17. package/routes/index.astro +3 -55
  18. package/site/components/Activity.astro +9 -8
  19. package/site/components/Agentic.astro +11 -10
  20. package/site/components/CareerReplay.astro +11 -8
  21. package/site/components/CommandPalette.astro +10 -4
  22. package/site/components/Contact.astro +8 -5
  23. package/site/components/Cratis.astro +18 -16
  24. package/site/components/EventModel.astro +8 -5
  25. package/site/components/Footer.astro +9 -4
  26. package/site/components/Hero.astro +13 -10
  27. package/site/components/Inline.astro +45 -0
  28. package/site/components/Monogram.astro +4 -1
  29. package/site/components/Nav.astro +12 -9
  30. package/site/components/Now.astro +13 -10
  31. package/site/components/Projects.astro +11 -14
  32. package/site/components/PullRequestFeed.astro +6 -4
  33. package/site/components/SectionHeader.astro +6 -3
  34. package/site/components/Skills.astro +5 -2
  35. package/site/components/Stats.astro +9 -4
  36. package/site/components/Talks.astro +8 -5
  37. package/site/components/Terminal.astro +7 -2
  38. package/site/components/Writing.astro +9 -7
  39. package/site/data.ts +6 -43
  40. package/site/layouts/Base.astro +31 -19
  41. package/site/lib/blog.ts +42 -16
  42. package/site/lib/github.ts +56 -31
  43. package/site/lib/inline.ts +65 -9
  44. package/site/lib/nav.ts +14 -3
  45. package/site/pages/CvPage.astro +379 -0
  46. package/site/pages/ProfilePage.astro +78 -0
  47. package/site/profile/CastHost.ts +32 -0
  48. package/site/profile/CastView.ts +96 -0
  49. package/site/profile/assertRenderable.ts +151 -0
  50. package/site/profile/clientCast.ts +120 -0
  51. package/site/profile/index.ts +8 -0
  52. package/site/scripts/live.ts +21 -11
  53. package/site/scripts/palette.ts +30 -13
  54. package/site/scripts/replay.ts +2 -1
  55. package/site/scripts/terminal.ts +40 -29
  56. package/writing/fetchWriting.ts +17 -2
  57. package/writing/writingSnapshotSchema.ts +27 -0
@@ -0,0 +1,1496 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "$schema": {
6
+ "type": "string"
7
+ },
8
+ "castJsonVersion": {
9
+ "type": "number",
10
+ "const": 2
11
+ },
12
+ "handle": {
13
+ "type": "string",
14
+ "pattern": "^[A-Za-z0-9](?:[A-Za-z0-9]|-(?=[A-Za-z0-9])){0,38}$",
15
+ "description": "The GitHub login: the profile identity. Must equal profile.cast.person.handle."
16
+ },
17
+ "generator": {
18
+ "description": "What wrote the file, for example \"@cratis/cast 1.2.0\".",
19
+ "type": "string",
20
+ "maxLength": 200
21
+ },
22
+ "builtAt": {
23
+ "description": "When the file was written, ISO 8601.",
24
+ "type": "string",
25
+ "maxLength": 64
26
+ },
27
+ "profile": {
28
+ "type": "object",
29
+ "properties": {
30
+ "cast": {
31
+ "type": "object",
32
+ "properties": {
33
+ "$schema": {
34
+ "type": "string"
35
+ },
36
+ "site": {
37
+ "type": "object",
38
+ "properties": {
39
+ "url": {
40
+ "type": "string",
41
+ "format": "uri",
42
+ "description": "Public URL of the site, for example https://ada.dev."
43
+ },
44
+ "description": {
45
+ "description": "Meta description; defaults to the tagline and intro.",
46
+ "type": "string"
47
+ },
48
+ "source": {
49
+ "description": "Source repository, linked in the footer.",
50
+ "type": "string",
51
+ "format": "uri"
52
+ },
53
+ "language": {
54
+ "default": "en",
55
+ "type": "string"
56
+ }
57
+ },
58
+ "required": [
59
+ "url"
60
+ ]
61
+ },
62
+ "person": {
63
+ "type": "object",
64
+ "properties": {
65
+ "name": {
66
+ "type": "string",
67
+ "minLength": 1,
68
+ "description": "Display name, for example \"Ada Lovelace\"."
69
+ },
70
+ "fullName": {
71
+ "description": "Full legal name when it differs from the display name.",
72
+ "type": "string"
73
+ },
74
+ "handle": {
75
+ "type": "string",
76
+ "pattern": "^[A-Za-z0-9](?:[A-Za-z0-9]|-(?=[A-Za-z0-9])){0,38}$",
77
+ "description": "Your GitHub login: your one Cast identity. Tier, badge, /cast.json and the verification page all use it."
78
+ },
79
+ "title": {
80
+ "type": "string",
81
+ "minLength": 1,
82
+ "description": "Role line under your name."
83
+ },
84
+ "titleShort": {
85
+ "description": "Shorter role line for small screens.",
86
+ "type": "string"
87
+ },
88
+ "location": {
89
+ "type": "string"
90
+ },
91
+ "country": {
92
+ "description": "ISO 3166 two-letter country code, used in structured data.",
93
+ "type": "string",
94
+ "minLength": 2,
95
+ "maxLength": 2
96
+ },
97
+ "email": {
98
+ "type": "string",
99
+ "format": "email",
100
+ "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
101
+ },
102
+ "photo": {
103
+ "description": "Portrait: a path relative to cast.yaml (for example ./avatar.jpeg) or an https URL.",
104
+ "type": "string"
105
+ },
106
+ "links": {
107
+ "default": {},
108
+ "description": "Profile links by name: github, linkedin, mastodon, bluesky, website or anything else.",
109
+ "type": "object",
110
+ "propertyNames": {
111
+ "type": "string"
112
+ },
113
+ "additionalProperties": {
114
+ "type": "string",
115
+ "format": "uri"
116
+ }
117
+ },
118
+ "tagline": {
119
+ "type": "string",
120
+ "minLength": 1,
121
+ "description": "The hero headline. Wrap the words to accent in *asterisks*."
122
+ },
123
+ "intro": {
124
+ "type": "string",
125
+ "minLength": 1,
126
+ "description": "One paragraph under the headline."
127
+ },
128
+ "about": {
129
+ "default": [],
130
+ "type": "array",
131
+ "items": {
132
+ "type": "string",
133
+ "minLength": 1
134
+ }
135
+ },
136
+ "interests": {
137
+ "default": [],
138
+ "type": "array",
139
+ "items": {
140
+ "type": "string"
141
+ }
142
+ },
143
+ "languages": {
144
+ "default": [],
145
+ "type": "array",
146
+ "items": {
147
+ "type": "string"
148
+ }
149
+ }
150
+ },
151
+ "required": [
152
+ "name",
153
+ "handle",
154
+ "title",
155
+ "tagline",
156
+ "intro"
157
+ ]
158
+ },
159
+ "now": {
160
+ "default": {},
161
+ "description": "The \"now\" read model: ordered key/value rows. YYYY-MM values are shown as months.",
162
+ "type": "object",
163
+ "propertyNames": {
164
+ "type": "string"
165
+ },
166
+ "additionalProperties": {
167
+ "anyOf": [
168
+ {
169
+ "type": "string"
170
+ },
171
+ {
172
+ "type": "array",
173
+ "items": {
174
+ "type": "string"
175
+ }
176
+ }
177
+ ]
178
+ }
179
+ },
180
+ "stats": {
181
+ "default": [],
182
+ "type": "array",
183
+ "items": {
184
+ "type": "object",
185
+ "properties": {
186
+ "value": {
187
+ "type": "number"
188
+ },
189
+ "prefix": {
190
+ "default": "",
191
+ "type": "string"
192
+ },
193
+ "suffix": {
194
+ "default": "",
195
+ "type": "string"
196
+ },
197
+ "label": {
198
+ "type": "string",
199
+ "minLength": 1
200
+ },
201
+ "live": {
202
+ "description": "Replace the value with a build-time number.",
203
+ "type": "string",
204
+ "enum": [
205
+ "contributionsLastYear",
206
+ "mergedPullRequests",
207
+ "rankOneRepositories",
208
+ "clientLanguages"
209
+ ]
210
+ },
211
+ "plain": {
212
+ "default": false,
213
+ "description": "Show the value without counting up or thousands separators.",
214
+ "type": "boolean"
215
+ }
216
+ },
217
+ "required": [
218
+ "value",
219
+ "label"
220
+ ]
221
+ }
222
+ },
223
+ "career": {
224
+ "default": {
225
+ "events": []
226
+ },
227
+ "type": "object",
228
+ "properties": {
229
+ "events": {
230
+ "default": [],
231
+ "type": "array",
232
+ "items": {
233
+ "type": "object",
234
+ "properties": {
235
+ "seq": {
236
+ "description": "Stream position. Assigned in file order when omitted.",
237
+ "type": "integer",
238
+ "exclusiveMinimum": 0,
239
+ "maximum": 9007199254740991
240
+ },
241
+ "date": {
242
+ "type": "string",
243
+ "pattern": "^\\d{4}(-\\d{2})?$"
244
+ },
245
+ "endDate": {
246
+ "description": "End of an engagement that does not set a role.",
247
+ "type": "string",
248
+ "pattern": "^\\d{4}(-\\d{2})?$"
249
+ },
250
+ "type": {
251
+ "type": "string",
252
+ "pattern": "^[A-Z][A-Za-z]+$",
253
+ "description": "Past-tense event name."
254
+ },
255
+ "title": {
256
+ "type": "string",
257
+ "minLength": 1
258
+ },
259
+ "org": {
260
+ "type": "string"
261
+ },
262
+ "orgUrl": {
263
+ "type": "string",
264
+ "format": "uri"
265
+ },
266
+ "location": {
267
+ "type": "string"
268
+ },
269
+ "summary": {
270
+ "type": "string",
271
+ "minLength": 1
272
+ },
273
+ "skills": {
274
+ "type": "array",
275
+ "items": {
276
+ "type": "string"
277
+ }
278
+ },
279
+ "role": {
280
+ "description": "Sets the current role in the projection.",
281
+ "type": "string"
282
+ },
283
+ "endsRole": {
284
+ "description": "Organization whose open role this event ends.",
285
+ "type": "string"
286
+ }
287
+ },
288
+ "required": [
289
+ "date",
290
+ "type",
291
+ "title",
292
+ "summary"
293
+ ]
294
+ }
295
+ }
296
+ }
297
+ },
298
+ "cratis": {
299
+ "type": "object",
300
+ "properties": {
301
+ "title": {
302
+ "default": "What I lead at Cratis.",
303
+ "type": "string"
304
+ },
305
+ "label": {
306
+ "default": "Cratis",
307
+ "type": "string"
308
+ },
309
+ "pitch": {
310
+ "type": "string",
311
+ "minLength": 1
312
+ },
313
+ "role": {
314
+ "type": "string",
315
+ "minLength": 1,
316
+ "description": "What you do at Cratis, in your own words."
317
+ },
318
+ "links": {
319
+ "default": {
320
+ "cratis.io": "https://cratis.io",
321
+ "github.com/Cratis": "https://github.com/Cratis"
322
+ },
323
+ "type": "object",
324
+ "propertyNames": {
325
+ "type": "string"
326
+ },
327
+ "additionalProperties": {
328
+ "type": "string",
329
+ "format": "uri"
330
+ }
331
+ },
332
+ "pipeline": {
333
+ "default": [],
334
+ "description": "Repository names shown as the model-to-running-app pipeline, left to right.",
335
+ "type": "array",
336
+ "items": {
337
+ "type": "string"
338
+ }
339
+ },
340
+ "clientLanguages": {
341
+ "default": [],
342
+ "type": "array",
343
+ "items": {
344
+ "type": "string"
345
+ }
346
+ },
347
+ "repos": {
348
+ "default": [],
349
+ "type": "array",
350
+ "items": {
351
+ "type": "object",
352
+ "properties": {
353
+ "name": {
354
+ "type": "string",
355
+ "minLength": 1,
356
+ "description": "Repository name in the Cratis organization."
357
+ },
358
+ "url": {
359
+ "description": "Omit for repositories that are not public; they are then never fetched.",
360
+ "type": "string",
361
+ "format": "uri"
362
+ },
363
+ "kind": {
364
+ "type": "string",
365
+ "minLength": 1
366
+ },
367
+ "group": {
368
+ "default": "tooling",
369
+ "type": "string",
370
+ "enum": [
371
+ "pipeline",
372
+ "tooling",
373
+ "client"
374
+ ]
375
+ },
376
+ "step": {
377
+ "type": "string"
378
+ },
379
+ "note": {
380
+ "type": "string"
381
+ },
382
+ "role": {
383
+ "description": "Fallback role text; replaced by the live rank when GitHub data is available.",
384
+ "type": "string"
385
+ },
386
+ "rank": {
387
+ "default": 0,
388
+ "type": "integer",
389
+ "minimum": 0,
390
+ "maximum": 9007199254740991
391
+ },
392
+ "founded": {
393
+ "default": false,
394
+ "type": "boolean"
395
+ },
396
+ "commits": {
397
+ "default": 0,
398
+ "type": "integer",
399
+ "minimum": 0,
400
+ "maximum": 9007199254740991
401
+ },
402
+ "prs": {
403
+ "default": 0,
404
+ "type": "integer",
405
+ "minimum": 0,
406
+ "maximum": 9007199254740991
407
+ },
408
+ "desc": {
409
+ "type": "string",
410
+ "minLength": 1
411
+ }
412
+ },
413
+ "required": [
414
+ "name",
415
+ "kind",
416
+ "desc"
417
+ ]
418
+ }
419
+ },
420
+ "highlights": {
421
+ "default": [],
422
+ "type": "array",
423
+ "items": {
424
+ "type": "string"
425
+ }
426
+ }
427
+ },
428
+ "required": [
429
+ "role"
430
+ ]
431
+ },
432
+ "projects": {
433
+ "default": [],
434
+ "type": "array",
435
+ "items": {
436
+ "type": "object",
437
+ "properties": {
438
+ "name": {
439
+ "type": "string",
440
+ "minLength": 1
441
+ },
442
+ "url": {
443
+ "type": "string",
444
+ "format": "uri"
445
+ },
446
+ "pitch": {
447
+ "type": "string",
448
+ "minLength": 1
449
+ },
450
+ "features": {
451
+ "default": [],
452
+ "type": "array",
453
+ "items": {
454
+ "type": "string"
455
+ }
456
+ },
457
+ "stack": {
458
+ "default": [],
459
+ "type": "array",
460
+ "items": {
461
+ "type": "string"
462
+ }
463
+ },
464
+ "install": {
465
+ "description": "Install command with a copy button.",
466
+ "type": "string"
467
+ },
468
+ "version": {
469
+ "description": "Fallback version; replaced by the latest GitHub release when tracked.",
470
+ "type": "string"
471
+ },
472
+ "category": {
473
+ "default": "project",
474
+ "type": "string"
475
+ },
476
+ "featured": {
477
+ "default": false,
478
+ "description": "Show the card at double width.",
479
+ "type": "boolean"
480
+ }
481
+ },
482
+ "required": [
483
+ "name",
484
+ "url",
485
+ "pitch"
486
+ ]
487
+ }
488
+ },
489
+ "projectCategories": {
490
+ "default": [],
491
+ "type": "array",
492
+ "items": {
493
+ "type": "object",
494
+ "properties": {
495
+ "id": {
496
+ "type": "string",
497
+ "minLength": 1
498
+ },
499
+ "label": {
500
+ "type": "string",
501
+ "minLength": 1
502
+ },
503
+ "filter": {
504
+ "description": "Filter chip label; defaults to label.",
505
+ "type": "string"
506
+ }
507
+ },
508
+ "required": [
509
+ "id",
510
+ "label"
511
+ ]
512
+ }
513
+ },
514
+ "talks": {
515
+ "default": [],
516
+ "type": "array",
517
+ "items": {
518
+ "type": "object",
519
+ "properties": {
520
+ "title": {
521
+ "type": "string",
522
+ "minLength": 1
523
+ },
524
+ "lang": {
525
+ "default": "en",
526
+ "description": "BCP 47 language of the talk, for example \"en\" or \"no\".",
527
+ "type": "string"
528
+ },
529
+ "host": {
530
+ "type": "string",
531
+ "minLength": 1
532
+ },
533
+ "with": {
534
+ "type": "string"
535
+ },
536
+ "date": {
537
+ "type": "string",
538
+ "pattern": "^\\d{4}(-\\d{2}(-\\d{2})?)?$"
539
+ },
540
+ "url": {
541
+ "type": "string",
542
+ "format": "uri"
543
+ },
544
+ "summary": {
545
+ "type": "string",
546
+ "minLength": 1
547
+ }
548
+ },
549
+ "required": [
550
+ "title",
551
+ "host",
552
+ "date",
553
+ "summary"
554
+ ]
555
+ }
556
+ },
557
+ "community": {
558
+ "default": [],
559
+ "type": "array",
560
+ "items": {
561
+ "type": "object",
562
+ "properties": {
563
+ "title": {
564
+ "type": "string",
565
+ "minLength": 1
566
+ },
567
+ "detail": {
568
+ "default": "",
569
+ "type": "string"
570
+ },
571
+ "date": {
572
+ "type": "string",
573
+ "pattern": "^\\d{4}(-\\d{2}(-\\d{2})?)?$"
574
+ }
575
+ },
576
+ "required": [
577
+ "title",
578
+ "date"
579
+ ]
580
+ }
581
+ },
582
+ "writing": {
583
+ "default": {
584
+ "sources": [],
585
+ "themes": []
586
+ },
587
+ "type": "object",
588
+ "properties": {
589
+ "sources": {
590
+ "default": [],
591
+ "type": "array",
592
+ "items": {
593
+ "anyOf": [
594
+ {
595
+ "type": "object",
596
+ "properties": {
597
+ "rss": {
598
+ "type": "string",
599
+ "format": "uri",
600
+ "description": "RSS or Atom feed URL."
601
+ },
602
+ "author": {
603
+ "description": "Only include entries by this author name.",
604
+ "type": "string"
605
+ }
606
+ },
607
+ "required": [
608
+ "rss"
609
+ ]
610
+ },
611
+ {
612
+ "type": "object",
613
+ "properties": {
614
+ "starlightBlogAuthor": {
615
+ "type": "string",
616
+ "format": "uri",
617
+ "description": "Author page of a Starlight Blog site, for example https://blog.cratis.io/authors/your-name/."
618
+ }
619
+ },
620
+ "required": [
621
+ "starlightBlogAuthor"
622
+ ]
623
+ }
624
+ ]
625
+ }
626
+ },
627
+ "themes": {
628
+ "default": [],
629
+ "description": "Filter chips, each a set of post tags.",
630
+ "type": "array",
631
+ "items": {
632
+ "type": "object",
633
+ "properties": {
634
+ "id": {
635
+ "type": "string",
636
+ "pattern": "^[a-z0-9-]+$"
637
+ },
638
+ "label": {
639
+ "type": "string",
640
+ "minLength": 1
641
+ },
642
+ "tags": {
643
+ "minItems": 1,
644
+ "type": "array",
645
+ "items": {
646
+ "type": "string"
647
+ }
648
+ }
649
+ },
650
+ "required": [
651
+ "id",
652
+ "label",
653
+ "tags"
654
+ ]
655
+ }
656
+ },
657
+ "agenticTheme": {
658
+ "description": "Theme id whose posts the agentic section lists.",
659
+ "type": "string"
660
+ }
661
+ }
662
+ },
663
+ "agentic": {
664
+ "type": "object",
665
+ "properties": {
666
+ "title": {
667
+ "default": "I build the harness.",
668
+ "type": "string"
669
+ },
670
+ "pitch": {
671
+ "type": "string",
672
+ "minLength": 1
673
+ },
674
+ "label": {
675
+ "default": "Agentic engineering",
676
+ "type": "string"
677
+ },
678
+ "workflowLabel": {
679
+ "default": "every change in my setup",
680
+ "type": "string"
681
+ },
682
+ "workflow": {
683
+ "default": [],
684
+ "type": "array",
685
+ "items": {
686
+ "type": "object",
687
+ "properties": {
688
+ "step": {
689
+ "type": "string",
690
+ "minLength": 1
691
+ },
692
+ "event": {
693
+ "type": "string",
694
+ "pattern": "^[A-Z][A-Za-z]+$"
695
+ },
696
+ "who": {
697
+ "type": "string",
698
+ "minLength": 1
699
+ },
700
+ "text": {
701
+ "type": "string",
702
+ "minLength": 1
703
+ },
704
+ "loop": {
705
+ "description": "A loop-back note shown on the step, for example \"blocker → Implement\".",
706
+ "type": "string"
707
+ }
708
+ },
709
+ "required": [
710
+ "step",
711
+ "event",
712
+ "who",
713
+ "text"
714
+ ]
715
+ }
716
+ },
717
+ "items": {
718
+ "default": [],
719
+ "type": "array",
720
+ "items": {
721
+ "type": "object",
722
+ "properties": {
723
+ "name": {
724
+ "type": "string",
725
+ "minLength": 1
726
+ },
727
+ "url": {
728
+ "type": "string",
729
+ "format": "uri"
730
+ },
731
+ "kind": {
732
+ "type": "string",
733
+ "minLength": 1
734
+ },
735
+ "text": {
736
+ "type": "string",
737
+ "minLength": 1
738
+ },
739
+ "list": {
740
+ "type": "array",
741
+ "items": {
742
+ "type": "string"
743
+ }
744
+ },
745
+ "listLabel": {
746
+ "type": "string"
747
+ }
748
+ },
749
+ "required": [
750
+ "name",
751
+ "kind",
752
+ "text"
753
+ ]
754
+ }
755
+ }
756
+ },
757
+ "required": [
758
+ "pitch"
759
+ ]
760
+ },
761
+ "eventModel": {
762
+ "type": "object",
763
+ "properties": {
764
+ "title": {
765
+ "default": "Start with the *event model.*",
766
+ "type": "string"
767
+ },
768
+ "label": {
769
+ "default": "How I think",
770
+ "type": "string"
771
+ },
772
+ "intro": {
773
+ "description": "Paragraph under the title. Defaults to a short explanation of the board.",
774
+ "type": "string",
775
+ "minLength": 1
776
+ },
777
+ "summary": {
778
+ "description": "Line under the board before a card is selected.",
779
+ "type": "string"
780
+ },
781
+ "name": {
782
+ "type": "string",
783
+ "minLength": 1
784
+ },
785
+ "repo": {
786
+ "type": "string",
787
+ "format": "uri"
788
+ },
789
+ "sourceRoot": {
790
+ "default": "",
791
+ "type": "string"
792
+ },
793
+ "branch": {
794
+ "default": "main",
795
+ "type": "string"
796
+ },
797
+ "columns": {
798
+ "type": "integer",
799
+ "exclusiveMinimum": 0,
800
+ "maximum": 9007199254740991
801
+ },
802
+ "lanes": {
803
+ "minItems": 1,
804
+ "type": "array",
805
+ "items": {
806
+ "type": "object",
807
+ "properties": {
808
+ "id": {
809
+ "type": "string",
810
+ "minLength": 1
811
+ },
812
+ "label": {
813
+ "type": "string",
814
+ "minLength": 1
815
+ }
816
+ },
817
+ "required": [
818
+ "id",
819
+ "label"
820
+ ]
821
+ }
822
+ },
823
+ "cards": {
824
+ "minItems": 1,
825
+ "type": "array",
826
+ "items": {
827
+ "type": "object",
828
+ "properties": {
829
+ "id": {
830
+ "type": "string",
831
+ "minLength": 1
832
+ },
833
+ "kind": {
834
+ "type": "string",
835
+ "enum": [
836
+ "ui",
837
+ "command",
838
+ "event",
839
+ "view"
840
+ ]
841
+ },
842
+ "name": {
843
+ "type": "string",
844
+ "minLength": 1
845
+ },
846
+ "lane": {
847
+ "type": "string",
848
+ "minLength": 1
849
+ },
850
+ "col": {
851
+ "type": "integer",
852
+ "minimum": 0,
853
+ "maximum": 9007199254740991
854
+ },
855
+ "source": {
856
+ "type": "string",
857
+ "minLength": 1
858
+ },
859
+ "note": {
860
+ "type": "string",
861
+ "minLength": 1
862
+ }
863
+ },
864
+ "required": [
865
+ "id",
866
+ "kind",
867
+ "name",
868
+ "lane",
869
+ "col",
870
+ "source",
871
+ "note"
872
+ ]
873
+ }
874
+ },
875
+ "edges": {
876
+ "default": [],
877
+ "type": "array",
878
+ "items": {
879
+ "type": "array",
880
+ "prefixItems": [
881
+ {
882
+ "type": "string"
883
+ },
884
+ {
885
+ "type": "string"
886
+ }
887
+ ],
888
+ "items": false,
889
+ "minItems": 2,
890
+ "maxItems": 2
891
+ }
892
+ },
893
+ "steps": {
894
+ "default": [],
895
+ "type": "array",
896
+ "items": {
897
+ "type": "object",
898
+ "properties": {
899
+ "title": {
900
+ "type": "string",
901
+ "minLength": 1
902
+ },
903
+ "text": {
904
+ "type": "string",
905
+ "minLength": 1
906
+ },
907
+ "cards": {
908
+ "type": "array",
909
+ "items": {
910
+ "type": "string"
911
+ }
912
+ }
913
+ },
914
+ "required": [
915
+ "title",
916
+ "text",
917
+ "cards"
918
+ ]
919
+ }
920
+ }
921
+ },
922
+ "required": [
923
+ "name",
924
+ "repo",
925
+ "columns",
926
+ "lanes",
927
+ "cards"
928
+ ]
929
+ },
930
+ "skills": {
931
+ "default": {},
932
+ "type": "object",
933
+ "propertyNames": {
934
+ "type": "string"
935
+ },
936
+ "additionalProperties": {
937
+ "type": "array",
938
+ "items": {
939
+ "type": "string"
940
+ }
941
+ }
942
+ },
943
+ "education": {
944
+ "default": [],
945
+ "type": "array",
946
+ "items": {
947
+ "type": "object",
948
+ "properties": {
949
+ "degree": {
950
+ "type": "string",
951
+ "minLength": 1
952
+ },
953
+ "school": {
954
+ "type": "string",
955
+ "minLength": 1
956
+ },
957
+ "from": {
958
+ "type": "string",
959
+ "minLength": 1
960
+ },
961
+ "to": {
962
+ "type": "string"
963
+ }
964
+ },
965
+ "required": [
966
+ "degree",
967
+ "school",
968
+ "from"
969
+ ]
970
+ }
971
+ },
972
+ "certifications": {
973
+ "default": [],
974
+ "type": "array",
975
+ "items": {
976
+ "type": "object",
977
+ "properties": {
978
+ "title": {
979
+ "type": "string",
980
+ "minLength": 1
981
+ },
982
+ "issuer": {
983
+ "type": "string",
984
+ "minLength": 1
985
+ },
986
+ "year": {
987
+ "type": "string",
988
+ "minLength": 1
989
+ },
990
+ "url": {
991
+ "type": "string",
992
+ "format": "uri"
993
+ }
994
+ },
995
+ "required": [
996
+ "title",
997
+ "issuer",
998
+ "year"
999
+ ]
1000
+ }
1001
+ },
1002
+ "github": {
1003
+ "default": {
1004
+ "orgs": [
1005
+ "Cratis"
1006
+ ],
1007
+ "releases": [],
1008
+ "stars": []
1009
+ },
1010
+ "type": "object",
1011
+ "properties": {
1012
+ "login": {
1013
+ "description": "Must equal person.handle (case-insensitive) when given; your GitHub login is your one identity.",
1014
+ "type": "string"
1015
+ },
1016
+ "orgs": {
1017
+ "default": [
1018
+ "Cratis"
1019
+ ],
1020
+ "description": "Organizations whose merged public pull requests are counted. The first one feeds the live pull request feed.",
1021
+ "type": "array",
1022
+ "items": {
1023
+ "type": "string"
1024
+ }
1025
+ },
1026
+ "releases": {
1027
+ "default": [],
1028
+ "description": "owner/name repositories whose latest release versions your projects.",
1029
+ "type": "array",
1030
+ "items": {
1031
+ "type": "string",
1032
+ "pattern": "^[\\w.-]+\\/[\\w.-]+$"
1033
+ }
1034
+ },
1035
+ "stars": {
1036
+ "default": [],
1037
+ "description": "owner/name repositories whose star count is shown.",
1038
+ "type": "array",
1039
+ "items": {
1040
+ "type": "string",
1041
+ "pattern": "^[\\w.-]+\\/[\\w.-]+$"
1042
+ }
1043
+ }
1044
+ }
1045
+ },
1046
+ "theme": {
1047
+ "default": {
1048
+ "accent": "#8b5cf6",
1049
+ "mode": "dark"
1050
+ },
1051
+ "type": "object",
1052
+ "properties": {
1053
+ "accent": {
1054
+ "default": "#8b5cf6",
1055
+ "description": "Your accent color. Defaults to Cratis violet.",
1056
+ "type": "string",
1057
+ "pattern": "^#[0-9a-fA-F]{6}$"
1058
+ },
1059
+ "mode": {
1060
+ "default": "dark",
1061
+ "type": "string",
1062
+ "enum": [
1063
+ "dark",
1064
+ "light",
1065
+ "system"
1066
+ ]
1067
+ }
1068
+ }
1069
+ },
1070
+ "sections": {
1071
+ "description": "Section order. Listed sections render in this order; omitted ones are hidden. Omit the key to show every section that has data.",
1072
+ "type": "array",
1073
+ "items": {
1074
+ "anyOf": [
1075
+ {
1076
+ "type": "string",
1077
+ "enum": [
1078
+ "hero",
1079
+ "now",
1080
+ "stats",
1081
+ "career",
1082
+ "model",
1083
+ "cratis",
1084
+ "activity",
1085
+ "agentic",
1086
+ "projects",
1087
+ "writing",
1088
+ "talks",
1089
+ "skills",
1090
+ "contact"
1091
+ ]
1092
+ },
1093
+ {
1094
+ "type": "object",
1095
+ "properties": {
1096
+ "id": {
1097
+ "type": "string",
1098
+ "enum": [
1099
+ "hero",
1100
+ "now",
1101
+ "stats",
1102
+ "career",
1103
+ "model",
1104
+ "cratis",
1105
+ "activity",
1106
+ "agentic",
1107
+ "projects",
1108
+ "writing",
1109
+ "talks",
1110
+ "skills",
1111
+ "contact"
1112
+ ]
1113
+ },
1114
+ "title": {
1115
+ "type": "string"
1116
+ },
1117
+ "label": {
1118
+ "type": "string"
1119
+ },
1120
+ "intro": {
1121
+ "type": "string",
1122
+ "minLength": 1
1123
+ }
1124
+ },
1125
+ "required": [
1126
+ "id"
1127
+ ]
1128
+ }
1129
+ ]
1130
+ }
1131
+ }
1132
+ },
1133
+ "required": [
1134
+ "site",
1135
+ "person"
1136
+ ],
1137
+ "additionalProperties": false,
1138
+ "description": "cast.yaml as JSON. See https://github.com/Cratis/Cast/blob/main/Documentation/cast-yaml.md"
1139
+ },
1140
+ "github": {
1141
+ "description": "Public GitHub data captured at build time. Without it the directory uses its own.",
1142
+ "type": "object",
1143
+ "properties": {
1144
+ "fetchedAt": {
1145
+ "type": "string",
1146
+ "maxLength": 40
1147
+ },
1148
+ "login": {
1149
+ "type": "string",
1150
+ "minLength": 1,
1151
+ "maxLength": 39,
1152
+ "description": "GitHub login the data was captured for. Must be the profile handle."
1153
+ },
1154
+ "orgs": {
1155
+ "default": [],
1156
+ "maxItems": 20,
1157
+ "type": "array",
1158
+ "items": {
1159
+ "type": "string",
1160
+ "minLength": 1,
1161
+ "maxLength": 100
1162
+ }
1163
+ },
1164
+ "profile": {
1165
+ "type": "object",
1166
+ "properties": {
1167
+ "login": {
1168
+ "type": "string",
1169
+ "minLength": 1,
1170
+ "maxLength": 39
1171
+ },
1172
+ "name": {
1173
+ "type": "string",
1174
+ "maxLength": 200
1175
+ },
1176
+ "bio": {
1177
+ "type": "string",
1178
+ "maxLength": 500
1179
+ },
1180
+ "location": {
1181
+ "type": "string",
1182
+ "maxLength": 200
1183
+ },
1184
+ "blog": {
1185
+ "type": "string",
1186
+ "maxLength": 500
1187
+ },
1188
+ "avatarUrl": {
1189
+ "type": "string",
1190
+ "format": "uri"
1191
+ },
1192
+ "followers": {
1193
+ "type": "integer",
1194
+ "minimum": 0,
1195
+ "maximum": 9007199254740991
1196
+ },
1197
+ "publicRepositories": {
1198
+ "type": "integer",
1199
+ "minimum": 0,
1200
+ "maximum": 9007199254740991
1201
+ }
1202
+ },
1203
+ "required": [
1204
+ "login"
1205
+ ]
1206
+ },
1207
+ "contributions": {
1208
+ "default": {
1209
+ "total": 0,
1210
+ "weeks": []
1211
+ },
1212
+ "description": "The contribution calendar of the last year, one entry per week starting on Sunday.",
1213
+ "type": "object",
1214
+ "properties": {
1215
+ "total": {
1216
+ "type": "integer",
1217
+ "minimum": 0,
1218
+ "maximum": 9007199254740991
1219
+ },
1220
+ "commits": {
1221
+ "type": "integer",
1222
+ "minimum": 0,
1223
+ "maximum": 9007199254740991
1224
+ },
1225
+ "weeks": {
1226
+ "default": [],
1227
+ "maxItems": 60,
1228
+ "type": "array",
1229
+ "items": {
1230
+ "type": "object",
1231
+ "properties": {
1232
+ "start": {
1233
+ "type": "string",
1234
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
1235
+ },
1236
+ "counts": {
1237
+ "maxItems": 7,
1238
+ "type": "array",
1239
+ "items": {
1240
+ "type": "integer",
1241
+ "minimum": 0,
1242
+ "maximum": 9007199254740991
1243
+ }
1244
+ }
1245
+ },
1246
+ "required": [
1247
+ "start",
1248
+ "counts"
1249
+ ]
1250
+ }
1251
+ }
1252
+ },
1253
+ "required": [
1254
+ "total"
1255
+ ]
1256
+ },
1257
+ "mergedPullRequests": {
1258
+ "default": {
1259
+ "total": 0,
1260
+ "byOrg": {},
1261
+ "latest": []
1262
+ },
1263
+ "type": "object",
1264
+ "properties": {
1265
+ "total": {
1266
+ "type": "integer",
1267
+ "minimum": 0,
1268
+ "maximum": 9007199254740991
1269
+ },
1270
+ "byOrg": {
1271
+ "default": {},
1272
+ "type": "object",
1273
+ "propertyNames": {
1274
+ "type": "string",
1275
+ "maxLength": 100
1276
+ },
1277
+ "additionalProperties": {
1278
+ "type": "integer",
1279
+ "minimum": 0,
1280
+ "maximum": 9007199254740991
1281
+ }
1282
+ },
1283
+ "latest": {
1284
+ "default": [],
1285
+ "maxItems": 30,
1286
+ "type": "array",
1287
+ "items": {
1288
+ "type": "object",
1289
+ "properties": {
1290
+ "title": {
1291
+ "type": "string",
1292
+ "minLength": 1,
1293
+ "maxLength": 300
1294
+ },
1295
+ "repository": {
1296
+ "type": "string",
1297
+ "maxLength": 200,
1298
+ "pattern": "^[\\w.-]+\\/[\\w.-]+$"
1299
+ },
1300
+ "number": {
1301
+ "type": "integer",
1302
+ "exclusiveMinimum": 0,
1303
+ "maximum": 9007199254740991
1304
+ },
1305
+ "url": {
1306
+ "type": "string",
1307
+ "format": "uri"
1308
+ },
1309
+ "mergedAt": {
1310
+ "type": "string",
1311
+ "maxLength": 40
1312
+ }
1313
+ },
1314
+ "required": [
1315
+ "title",
1316
+ "repository",
1317
+ "number",
1318
+ "url",
1319
+ "mergedAt"
1320
+ ]
1321
+ }
1322
+ }
1323
+ },
1324
+ "required": [
1325
+ "total"
1326
+ ]
1327
+ },
1328
+ "repositories": {
1329
+ "default": {},
1330
+ "description": "Standing in each tracked repository, by owner/name.",
1331
+ "type": "object",
1332
+ "propertyNames": {
1333
+ "type": "string",
1334
+ "maxLength": 200,
1335
+ "pattern": "^[\\w.-]+\\/[\\w.-]+$"
1336
+ },
1337
+ "additionalProperties": {
1338
+ "type": "object",
1339
+ "properties": {
1340
+ "commits": {
1341
+ "type": "integer",
1342
+ "minimum": 0,
1343
+ "maximum": 9007199254740991
1344
+ },
1345
+ "rank": {
1346
+ "type": "integer",
1347
+ "minimum": 0,
1348
+ "maximum": 9007199254740991
1349
+ },
1350
+ "prs": {
1351
+ "type": "integer",
1352
+ "minimum": 0,
1353
+ "maximum": 9007199254740991
1354
+ }
1355
+ },
1356
+ "required": [
1357
+ "commits",
1358
+ "rank",
1359
+ "prs"
1360
+ ]
1361
+ }
1362
+ },
1363
+ "releases": {
1364
+ "default": {},
1365
+ "type": "object",
1366
+ "propertyNames": {
1367
+ "type": "string",
1368
+ "maxLength": 200,
1369
+ "pattern": "^[\\w.-]+\\/[\\w.-]+$"
1370
+ },
1371
+ "additionalProperties": {
1372
+ "type": "object",
1373
+ "properties": {
1374
+ "tag": {
1375
+ "type": "string",
1376
+ "minLength": 1,
1377
+ "maxLength": 100
1378
+ },
1379
+ "publishedAt": {
1380
+ "type": "string",
1381
+ "maxLength": 40
1382
+ },
1383
+ "url": {
1384
+ "type": "string",
1385
+ "format": "uri"
1386
+ }
1387
+ },
1388
+ "required": [
1389
+ "tag",
1390
+ "publishedAt",
1391
+ "url"
1392
+ ]
1393
+ }
1394
+ },
1395
+ "stars": {
1396
+ "default": {},
1397
+ "type": "object",
1398
+ "propertyNames": {
1399
+ "type": "string",
1400
+ "maxLength": 200,
1401
+ "pattern": "^[\\w.-]+\\/[\\w.-]+$"
1402
+ },
1403
+ "additionalProperties": {
1404
+ "type": "integer",
1405
+ "minimum": 0,
1406
+ "maximum": 9007199254740991
1407
+ }
1408
+ }
1409
+ },
1410
+ "required": [
1411
+ "login"
1412
+ ]
1413
+ },
1414
+ "writing": {
1415
+ "description": "Posts captured from the writing sources.",
1416
+ "type": "object",
1417
+ "properties": {
1418
+ "fetchedAt": {
1419
+ "type": "string",
1420
+ "maxLength": 64
1421
+ },
1422
+ "sources": {
1423
+ "default": [],
1424
+ "maxItems": 20,
1425
+ "type": "array",
1426
+ "items": {
1427
+ "type": "string",
1428
+ "format": "uri"
1429
+ }
1430
+ },
1431
+ "posts": {
1432
+ "default": [],
1433
+ "maxItems": 300,
1434
+ "type": "array",
1435
+ "items": {
1436
+ "type": "object",
1437
+ "properties": {
1438
+ "title": {
1439
+ "type": "string",
1440
+ "minLength": 1,
1441
+ "maxLength": 300
1442
+ },
1443
+ "url": {
1444
+ "type": "string",
1445
+ "format": "uri"
1446
+ },
1447
+ "date": {
1448
+ "type": "string",
1449
+ "maxLength": 64,
1450
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}"
1451
+ },
1452
+ "minutes": {
1453
+ "type": "number",
1454
+ "minimum": 0,
1455
+ "maximum": 10000
1456
+ },
1457
+ "description": {
1458
+ "default": "",
1459
+ "type": "string",
1460
+ "maxLength": 2000
1461
+ },
1462
+ "tags": {
1463
+ "default": [],
1464
+ "maxItems": 30,
1465
+ "type": "array",
1466
+ "items": {
1467
+ "type": "string",
1468
+ "maxLength": 100
1469
+ }
1470
+ }
1471
+ },
1472
+ "required": [
1473
+ "title",
1474
+ "url",
1475
+ "date"
1476
+ ]
1477
+ }
1478
+ }
1479
+ }
1480
+ }
1481
+ },
1482
+ "required": [
1483
+ "cast"
1484
+ ]
1485
+ }
1486
+ },
1487
+ "required": [
1488
+ "castJsonVersion",
1489
+ "handle",
1490
+ "profile"
1491
+ ],
1492
+ "additionalProperties": {},
1493
+ "$id": "https://unpkg.com/@cratis/cast/cast-json.schema.json",
1494
+ "title": "Cratis Cast: cast.json, version 2",
1495
+ "description": "The complete, render-ready Cast profile a site publishes at /cast.json. The Cast directory renders member profiles from it. See https://github.com/Cratis/Cast/blob/main/Documentation/cast-json.md"
1496
+ }