devlanes 0.0.1 → 0.2.0

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.
package/schema.json ADDED
@@ -0,0 +1,3172 @@
1
+ {
2
+ "$comment": "Generated by bins/devlanes/build.rs from crates/config; do not edit.",
3
+ "$defs": {
4
+ "ComposeFiles": {
5
+ "anyOf": [
6
+ {
7
+ "description": "One Compose file relative to the project.",
8
+ "examples": [
9
+ "docker-compose.yml"
10
+ ],
11
+ "type": "string"
12
+ },
13
+ {
14
+ "description": "Ordered Compose files, merged in the same order as repeated -f arguments.",
15
+ "examples": [
16
+ [
17
+ "docker-compose.yml",
18
+ "docker-compose.dev.yml"
19
+ ]
20
+ ],
21
+ "items": {
22
+ "description": "Ordered Compose files, merged in the same order as repeated -f arguments.",
23
+ "examples": [
24
+ "docker-compose.yml",
25
+ "docker-compose.dev.yml"
26
+ ],
27
+ "type": "string"
28
+ },
29
+ "type": "array"
30
+ }
31
+ ],
32
+ "description": "Compose files used to resolve and start infrastructure.",
33
+ "examples": [
34
+ "docker-compose.yml",
35
+ [
36
+ "docker-compose.yml",
37
+ "docker-compose.dev.yml"
38
+ ]
39
+ ]
40
+ },
41
+ "ConfigDuration": {
42
+ "description": "A duration written with `ms`, `s`, `m`, `h`, or `d` units.",
43
+ "examples": [
44
+ "15s",
45
+ "10m"
46
+ ],
47
+ "pattern": "^[0-9]+(ms|s|m|h|d)$",
48
+ "type": "string"
49
+ },
50
+ "ContainerConfig": {
51
+ "additionalProperties": false,
52
+ "description": "Plain Docker container managed alongside Compose services.",
53
+ "examples": [
54
+ {
55
+ "image": "ghcr.io/cerbos/cerbos:0.40.0",
56
+ "per_lane": true,
57
+ "ports": {
58
+ "grpc": 3593,
59
+ "http": 3592
60
+ }
61
+ }
62
+ ],
63
+ "properties": {
64
+ "command": {
65
+ "anyOf": [
66
+ {
67
+ "$ref": "#/$defs/Run"
68
+ },
69
+ {
70
+ "type": "null"
71
+ }
72
+ ],
73
+ "description": "Command replacing the image's default command.",
74
+ "examples": [
75
+ [
76
+ "server",
77
+ "--config=/policies/config.yaml"
78
+ ]
79
+ ]
80
+ },
81
+ "env": {
82
+ "additionalProperties": {
83
+ "$ref": "#/$defs/Templated_Scalar",
84
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
85
+ "examples": [
86
+ "${{ lane.index }}"
87
+ ]
88
+ },
89
+ "default": {},
90
+ "description": "Environment variables passed to this container.",
91
+ "examples": [
92
+ {
93
+ "LOG_LEVEL": "debug"
94
+ }
95
+ ],
96
+ "type": "object"
97
+ },
98
+ "image": {
99
+ "anyOf": [
100
+ {
101
+ "$ref": "#/$defs/Templated_string"
102
+ },
103
+ {
104
+ "type": "null"
105
+ }
106
+ ],
107
+ "description": "Docker image to run; required after local overrides are merged.",
108
+ "examples": [
109
+ "ghcr.io/cerbos/cerbos:0.40.0"
110
+ ]
111
+ },
112
+ "per_lane": {
113
+ "anyOf": [
114
+ {
115
+ "$ref": "#/$defs/Templated_boolean"
116
+ },
117
+ {
118
+ "type": "null"
119
+ }
120
+ ],
121
+ "description": "Create one container per lane; defaults to a shared project container.",
122
+ "examples": [
123
+ true,
124
+ false
125
+ ]
126
+ },
127
+ "ports": {
128
+ "additionalProperties": {
129
+ "$ref": "#/$defs/Templated_uint16",
130
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
131
+ "examples": [
132
+ "${{ lane.index }}"
133
+ ]
134
+ },
135
+ "default": {},
136
+ "description": "Named container ports; host ports are allocated by devlanes.",
137
+ "examples": [
138
+ {
139
+ "grpc": 3593,
140
+ "http": 3592
141
+ }
142
+ ],
143
+ "type": "object"
144
+ },
145
+ "ready": {
146
+ "anyOf": [
147
+ {
148
+ "$ref": "#/$defs/ReadyConfig"
149
+ },
150
+ {
151
+ "type": "null"
152
+ }
153
+ ],
154
+ "description": "Readiness check for the container.",
155
+ "examples": [
156
+ "started",
157
+ {
158
+ "http": {
159
+ "path": "/healthz"
160
+ }
161
+ },
162
+ {
163
+ "tcp": true
164
+ }
165
+ ]
166
+ },
167
+ "volumes": {
168
+ "description": "Docker source:destination[:mode] mounts; relative sources use the owning worktree.",
169
+ "examples": [
170
+ [
171
+ "./infra/cerbos:/policies:ro"
172
+ ]
173
+ ],
174
+ "items": {
175
+ "$ref": "#/$defs/Templated_string",
176
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
177
+ "examples": [
178
+ "${{ lane.index }}"
179
+ ]
180
+ },
181
+ "type": [
182
+ "array",
183
+ "null"
184
+ ]
185
+ }
186
+ },
187
+ "type": "object"
188
+ },
189
+ "FnoxConfig": {
190
+ "additionalProperties": false,
191
+ "description": "Secrets profile selection for the project or a single unit.",
192
+ "examples": [
193
+ {
194
+ "profile": "dev"
195
+ }
196
+ ],
197
+ "properties": {
198
+ "profile": {
199
+ "anyOf": [
200
+ {
201
+ "$ref": "#/$defs/Templated_string"
202
+ },
203
+ {
204
+ "type": "null"
205
+ }
206
+ ],
207
+ "description": "Secrets profile passed to fnox; uses fnox's default profile when omitted.",
208
+ "examples": [
209
+ "dev",
210
+ "admin-api"
211
+ ]
212
+ }
213
+ },
214
+ "type": "object"
215
+ },
216
+ "HostConfig": {
217
+ "anyOf": [
218
+ {
219
+ "$ref": "#/$defs/Templated_string",
220
+ "description": "Hostname routed to the service's primary port. Dot-separated labels of letters,\ndigits and inner hyphens, with an optional leading `*.` wildcard; case and a\ntrailing dot are ignored.",
221
+ "examples": [
222
+ "api.${{ lane.domain }}"
223
+ ]
224
+ },
225
+ {
226
+ "$ref": "#/$defs/HostRoute",
227
+ "description": "Hostname with optional named port, fallback, and Host-header policy.",
228
+ "examples": [
229
+ {
230
+ "fallback": true,
231
+ "host": "*.${{ lane.domain }}"
232
+ }
233
+ ]
234
+ }
235
+ ],
236
+ "description": "Hostname routed by the HTTP proxy, optionally with route settings.",
237
+ "examples": [
238
+ "api.${{ lane.domain }}",
239
+ {
240
+ "fallback": true,
241
+ "host": "*.${{ lane.domain }}"
242
+ }
243
+ ]
244
+ },
245
+ "HostHeader": {
246
+ "description": "Host header sent to the upstream HTTP server.",
247
+ "examples": [
248
+ "preserve",
249
+ "upstream"
250
+ ],
251
+ "oneOf": [
252
+ {
253
+ "const": "preserve",
254
+ "description": "Keep the Host header supplied by the client.",
255
+ "examples": [
256
+ "preserve"
257
+ ],
258
+ "type": "string"
259
+ },
260
+ {
261
+ "const": "upstream",
262
+ "description": "Send the upstream address and port as the Host header.",
263
+ "examples": [
264
+ "upstream"
265
+ ],
266
+ "type": "string"
267
+ }
268
+ ]
269
+ },
270
+ "HostRoute": {
271
+ "additionalProperties": false,
272
+ "description": "HTTP proxy route to a service or container port.",
273
+ "examples": [
274
+ {
275
+ "host": "inspect.${{ lane.domain }}",
276
+ "port": "inspector"
277
+ },
278
+ {
279
+ "fallback": true,
280
+ "host": "*.${{ lane.domain }}"
281
+ }
282
+ ],
283
+ "properties": {
284
+ "fallback": {
285
+ "anyOf": [
286
+ {
287
+ "$ref": "#/$defs/Templated_boolean"
288
+ },
289
+ {
290
+ "type": "null"
291
+ }
292
+ ],
293
+ "description": "Use this route only when no other hostname matches; defaults to false.",
294
+ "examples": [
295
+ true,
296
+ false
297
+ ]
298
+ },
299
+ "host": {
300
+ "$ref": "#/$defs/Templated_string",
301
+ "description": "Exact hostname or `*.` wildcard pattern, evaluated for the current lane. Labels\nhold letters, digits and inner hyphens; case and a trailing dot are ignored.",
302
+ "examples": [
303
+ "api.${{ lane.domain }}",
304
+ "*.${{ lane.domain }}"
305
+ ]
306
+ },
307
+ "host_header": {
308
+ "anyOf": [
309
+ {
310
+ "$ref": "#/$defs/HostHeader"
311
+ },
312
+ {
313
+ "type": "null"
314
+ }
315
+ ],
316
+ "description": "Preserve the browser's Host header by default, or rewrite it for the upstream.",
317
+ "examples": [
318
+ "preserve",
319
+ "upstream"
320
+ ]
321
+ },
322
+ "port": {
323
+ "description": "Named port to route to; uses the unit's primary port when omitted.",
324
+ "examples": [
325
+ "inspector"
326
+ ],
327
+ "type": [
328
+ "string",
329
+ "null"
330
+ ]
331
+ }
332
+ },
333
+ "required": [
334
+ "host"
335
+ ],
336
+ "type": "object"
337
+ },
338
+ "HostsFile": {
339
+ "description": "Whether project hostnames are also written to the system hosts file.",
340
+ "examples": [
341
+ "auto",
342
+ "never",
343
+ "always"
344
+ ],
345
+ "oneOf": [
346
+ {
347
+ "const": "auto",
348
+ "description": "Write entries when the system cannot resolve the configured hostnames.",
349
+ "examples": [
350
+ "auto"
351
+ ],
352
+ "type": "string"
353
+ },
354
+ {
355
+ "const": "never",
356
+ "description": "Do not write hosts entries.",
357
+ "examples": [
358
+ "never"
359
+ ],
360
+ "type": "string"
361
+ },
362
+ {
363
+ "const": "always",
364
+ "description": "Always write exact hostnames, including for runtimes without localhost subdomain support.",
365
+ "examples": [
366
+ "always"
367
+ ],
368
+ "type": "string"
369
+ }
370
+ ]
371
+ },
372
+ "HttpReady": {
373
+ "additionalProperties": false,
374
+ "description": "HTTP readiness probe against the unit's local server.",
375
+ "examples": [
376
+ {
377
+ "path": "/healthz",
378
+ "status": 200,
379
+ "timeout": "60s"
380
+ }
381
+ ],
382
+ "properties": {
383
+ "path": {
384
+ "anyOf": [
385
+ {
386
+ "$ref": "#/$defs/Templated_string"
387
+ },
388
+ {
389
+ "type": "null"
390
+ }
391
+ ],
392
+ "description": "Request path, such as /healthz.",
393
+ "examples": [
394
+ "/healthz",
395
+ "/-/health"
396
+ ]
397
+ },
398
+ "status": {
399
+ "anyOf": [
400
+ {
401
+ "$ref": "#/$defs/Templated_uint16"
402
+ },
403
+ {
404
+ "type": "null"
405
+ }
406
+ ],
407
+ "description": "HTTP response status required for readiness, between 100 and 599.",
408
+ "examples": [
409
+ 200
410
+ ]
411
+ },
412
+ "timeout": {
413
+ "anyOf": [
414
+ {
415
+ "$ref": "#/$defs/Templated_ConfigDuration"
416
+ },
417
+ {
418
+ "type": "null"
419
+ }
420
+ ],
421
+ "description": "Maximum time to wait for the HTTP probe to succeed.",
422
+ "examples": [
423
+ "15s",
424
+ "10m"
425
+ ]
426
+ }
427
+ },
428
+ "type": "object"
429
+ },
430
+ "InfraCommand": {
431
+ "anyOf": [
432
+ {
433
+ "$ref": "#/$defs/InfraCommandOptions",
434
+ "description": "Command or script with lifecycle and failure-handling settings.",
435
+ "examples": [
436
+ {
437
+ "ignore_errors": true,
438
+ "run": "docker compose exec -T rabbitmq rabbitmqctl add_vhost ${{ lane.vhost }}"
439
+ }
440
+ ]
441
+ },
442
+ {
443
+ "$ref": "#/$defs/Run",
444
+ "description": "Shell command or argv without extra options.",
445
+ "examples": [
446
+ "docker compose exec -T postgres createdb acme_${{ lane.name }}"
447
+ ]
448
+ }
449
+ ],
450
+ "description": "Named infrastructure command in shorthand or object form.",
451
+ "examples": [
452
+ "docker compose exec -T postgres createdb acme_${{ lane.name }}",
453
+ {
454
+ "ignore_errors": true,
455
+ "run": [
456
+ "aws",
457
+ "s3",
458
+ "mb",
459
+ "s3://${{ lane.bucket }}"
460
+ ]
461
+ }
462
+ ]
463
+ },
464
+ "InfraCommandOptions": {
465
+ "additionalProperties": false,
466
+ "description": "Setup or teardown command with optional container restart tracking.",
467
+ "examples": [
468
+ {
469
+ "container": "rabbitmq",
470
+ "ignore_errors": true,
471
+ "run": "docker compose exec -T rabbitmq rabbitmqctl add_vhost ${{ lane.vhost }}"
472
+ }
473
+ ],
474
+ "properties": {
475
+ "container": {
476
+ "description": "Container whose restart invalidates this setup entry's completion record, so it runs again.",
477
+ "examples": [
478
+ "rabbitmq"
479
+ ],
480
+ "type": [
481
+ "string",
482
+ "null"
483
+ ]
484
+ },
485
+ "cwd": {
486
+ "anyOf": [
487
+ {
488
+ "$ref": "#/$defs/Templated_string"
489
+ },
490
+ {
491
+ "type": "null"
492
+ }
493
+ ],
494
+ "description": "Working directory relative to the lane's worktree.",
495
+ "examples": [
496
+ "infra"
497
+ ]
498
+ },
499
+ "env": {
500
+ "additionalProperties": {
501
+ "$ref": "#/$defs/Templated_Scalar",
502
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
503
+ "examples": [
504
+ "${{ lane.index }}"
505
+ ]
506
+ },
507
+ "default": {},
508
+ "description": "Environment overrides for this command.",
509
+ "examples": [
510
+ {
511
+ "AWS_DEFAULT_REGION": "us-east-1"
512
+ }
513
+ ],
514
+ "type": "object"
515
+ },
516
+ "ignore_errors": {
517
+ "anyOf": [
518
+ {
519
+ "$ref": "#/$defs/Templated_boolean"
520
+ },
521
+ {
522
+ "type": "null"
523
+ }
524
+ ],
525
+ "description": "Continue when the command fails; defaults to false.",
526
+ "examples": [
527
+ true,
528
+ false
529
+ ]
530
+ },
531
+ "run": {
532
+ "anyOf": [
533
+ {
534
+ "$ref": "#/$defs/Run"
535
+ },
536
+ {
537
+ "type": "null"
538
+ }
539
+ ],
540
+ "description": "Shell text or argv; mutually exclusive with run_script.",
541
+ "examples": [
542
+ "pnpm dev",
543
+ [
544
+ "node",
545
+ "server.mjs",
546
+ "--port",
547
+ "${{ self.port }}"
548
+ ]
549
+ ]
550
+ },
551
+ "run_script": {
552
+ "anyOf": [
553
+ {
554
+ "$ref": "#/$defs/RunScript"
555
+ },
556
+ {
557
+ "type": "null"
558
+ }
559
+ ],
560
+ "description": "Script source and name; mutually exclusive with run.",
561
+ "examples": [
562
+ "apps/api/package.json#dev",
563
+ {
564
+ "name": "fixtures",
565
+ "source": "justfile"
566
+ }
567
+ ]
568
+ },
569
+ "timeout": {
570
+ "anyOf": [
571
+ {
572
+ "$ref": "#/$defs/Templated_ConfigDuration"
573
+ },
574
+ {
575
+ "type": "null"
576
+ }
577
+ ],
578
+ "description": "Maximum run duration for this command.",
579
+ "examples": [
580
+ "15s",
581
+ "10m"
582
+ ]
583
+ }
584
+ },
585
+ "type": "object"
586
+ },
587
+ "InfraConfig": {
588
+ "additionalProperties": false,
589
+ "description": "Containers and per-lane setup/teardown commands started before application services.",
590
+ "examples": [
591
+ {
592
+ "compose": "docker-compose.yml",
593
+ "hidden": [
594
+ "postgres"
595
+ ]
596
+ }
597
+ ],
598
+ "properties": {
599
+ "compose": {
600
+ "anyOf": [
601
+ {
602
+ "$ref": "#/$defs/ComposeFiles"
603
+ },
604
+ {
605
+ "type": "null"
606
+ }
607
+ ],
608
+ "description": "Compose file or ordered list of Compose files.",
609
+ "examples": [
610
+ "docker-compose.yml",
611
+ [
612
+ "docker-compose.yml",
613
+ "docker-compose.dev.yml"
614
+ ]
615
+ ]
616
+ },
617
+ "containers": {
618
+ "additionalProperties": {
619
+ "$ref": "#/$defs/ContainerConfig",
620
+ "description": "Plain Docker container managed alongside Compose services.",
621
+ "examples": [
622
+ {
623
+ "image": "ghcr.io/cerbos/cerbos:0.40.0",
624
+ "per_lane": true,
625
+ "ports": {
626
+ "grpc": 3593,
627
+ "http": 3592
628
+ }
629
+ }
630
+ ]
631
+ },
632
+ "default": {},
633
+ "description": "Plain Docker containers managed alongside Compose services.",
634
+ "examples": [
635
+ {
636
+ "cerbos": {
637
+ "image": "ghcr.io/cerbos/cerbos:0.40.0",
638
+ "per_lane": true,
639
+ "ports": {
640
+ "http": 3592
641
+ }
642
+ }
643
+ }
644
+ ],
645
+ "type": "object"
646
+ },
647
+ "env": {
648
+ "additionalProperties": {
649
+ "$ref": "#/$defs/Templated_Scalar",
650
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
651
+ "examples": [
652
+ "${{ lane.index }}"
653
+ ]
654
+ },
655
+ "default": {},
656
+ "description": "Variables for Compose interpolation, separate from process global_env.",
657
+ "examples": [
658
+ {
659
+ "ACME_DB_PORT": 15432
660
+ }
661
+ ],
662
+ "type": "object"
663
+ },
664
+ "exclude": {
665
+ "description": "Compose services never started by devlanes.",
666
+ "examples": [
667
+ [
668
+ "caddy"
669
+ ]
670
+ ],
671
+ "items": {
672
+ "description": "Compose services never started by devlanes.",
673
+ "examples": [
674
+ "caddy"
675
+ ],
676
+ "type": "string"
677
+ },
678
+ "type": [
679
+ "array",
680
+ "null"
681
+ ]
682
+ },
683
+ "hidden": {
684
+ "description": "Containers whose ports must not be mirrored to remote clients.",
685
+ "examples": [
686
+ [
687
+ "postgres"
688
+ ]
689
+ ],
690
+ "items": {
691
+ "description": "Containers whose ports must not be mirrored to remote clients.",
692
+ "examples": [
693
+ "postgres"
694
+ ],
695
+ "type": "string"
696
+ },
697
+ "type": [
698
+ "array",
699
+ "null"
700
+ ]
701
+ },
702
+ "hosts": {
703
+ "additionalProperties": {
704
+ "description": "Container name to HTTP proxy route declarations.",
705
+ "examples": [
706
+ [
707
+ "s3.${{ lane.domain }}"
708
+ ]
709
+ ],
710
+ "items": {
711
+ "$ref": "#/$defs/HostConfig",
712
+ "description": "Hostname routed by the HTTP proxy, optionally with route settings.",
713
+ "examples": [
714
+ "api.${{ lane.domain }}",
715
+ {
716
+ "fallback": true,
717
+ "host": "*.${{ lane.domain }}"
718
+ }
719
+ ]
720
+ },
721
+ "type": "array"
722
+ },
723
+ "default": {},
724
+ "description": "Container name to HTTP proxy route declarations.",
725
+ "examples": [
726
+ {
727
+ "s3mock": [
728
+ "s3.${{ lane.domain }}"
729
+ ]
730
+ }
731
+ ],
732
+ "type": "object"
733
+ },
734
+ "per_lane": {
735
+ "description": "Compose services instantiated separately in each lane.",
736
+ "examples": [
737
+ [
738
+ "mailpit"
739
+ ]
740
+ ],
741
+ "items": {
742
+ "description": "Compose services instantiated separately in each lane.",
743
+ "examples": [
744
+ "mailpit"
745
+ ],
746
+ "type": "string"
747
+ },
748
+ "type": [
749
+ "array",
750
+ "null"
751
+ ]
752
+ },
753
+ "profiles": {
754
+ "description": "Compose profiles enabled when resolving and starting infrastructure.",
755
+ "examples": [
756
+ [
757
+ "development"
758
+ ]
759
+ ],
760
+ "items": {
761
+ "description": "Compose profiles enabled when resolving and starting infrastructure.",
762
+ "examples": [
763
+ "development"
764
+ ],
765
+ "type": "string"
766
+ },
767
+ "type": [
768
+ "array",
769
+ "null"
770
+ ]
771
+ },
772
+ "project_name": {
773
+ "anyOf": [
774
+ {
775
+ "$ref": "#/$defs/Templated_string"
776
+ },
777
+ {
778
+ "type": "null"
779
+ }
780
+ ],
781
+ "description": "Shared Compose project name; defaults to Compose's own name.",
782
+ "examples": [
783
+ "acme"
784
+ ]
785
+ },
786
+ "setup": {
787
+ "additionalProperties": {
788
+ "$ref": "#/$defs/InfraCommand",
789
+ "description": "Named infrastructure command in shorthand or object form.",
790
+ "examples": [
791
+ "docker compose exec -T postgres createdb acme_${{ lane.name }}",
792
+ {
793
+ "ignore_errors": true,
794
+ "run": [
795
+ "aws",
796
+ "s3",
797
+ "mb",
798
+ "s3://${{ lane.bucket }}"
799
+ ]
800
+ }
801
+ ]
802
+ },
803
+ "default": {},
804
+ "description": "Named commands run once per lane after containers become healthy.",
805
+ "examples": [
806
+ {
807
+ "database": "docker compose exec -T postgres createdb acme_${{ lane.name }}"
808
+ }
809
+ ],
810
+ "type": "object"
811
+ },
812
+ "teardown": {
813
+ "additionalProperties": {
814
+ "$ref": "#/$defs/InfraCommand",
815
+ "description": "Named infrastructure command in shorthand or object form.",
816
+ "examples": [
817
+ "docker compose exec -T postgres createdb acme_${{ lane.name }}",
818
+ {
819
+ "ignore_errors": true,
820
+ "run": [
821
+ "aws",
822
+ "s3",
823
+ "mb",
824
+ "s3://${{ lane.bucket }}"
825
+ ]
826
+ }
827
+ ]
828
+ },
829
+ "default": {},
830
+ "description": "Named cleanup commands run when a lane is explicitly cleaned.",
831
+ "examples": [
832
+ {
833
+ "database": "docker compose exec -T postgres dropdb --if-exists acme_${{ lane.name }}"
834
+ }
835
+ ],
836
+ "type": "object"
837
+ }
838
+ },
839
+ "type": "object"
840
+ },
841
+ "InjectedPresetOptions0": {
842
+ "additionalProperties": false,
843
+ "description": "Options under the service's `vite:` key.",
844
+ "examples": [
845
+ {
846
+ "args": [
847
+ "--open"
848
+ ]
849
+ }
850
+ ],
851
+ "properties": {
852
+ "args": {
853
+ "description": "Extra arguments appended after the preset's flags.",
854
+ "examples": [
855
+ [
856
+ "--open"
857
+ ]
858
+ ],
859
+ "items": {
860
+ "description": "Extra arguments appended after the preset's flags.",
861
+ "examples": [
862
+ "--open"
863
+ ],
864
+ "type": "string"
865
+ },
866
+ "type": [
867
+ "array",
868
+ "null"
869
+ ]
870
+ }
871
+ },
872
+ "type": "object"
873
+ },
874
+ "InjectedPresetOptions1": {
875
+ "additionalProperties": false,
876
+ "description": "Options under the service's `next:` key.",
877
+ "examples": [
878
+ {
879
+ "args": [
880
+ "--turbo"
881
+ ]
882
+ }
883
+ ],
884
+ "properties": {
885
+ "args": {
886
+ "description": "Extra arguments appended after the preset's flags.",
887
+ "examples": [
888
+ [
889
+ "--turbo"
890
+ ]
891
+ ],
892
+ "items": {
893
+ "description": "Extra arguments appended after the preset's flags.",
894
+ "examples": [
895
+ "--turbo"
896
+ ],
897
+ "type": "string"
898
+ },
899
+ "type": [
900
+ "array",
901
+ "null"
902
+ ]
903
+ }
904
+ },
905
+ "type": "object"
906
+ },
907
+ "InjectedPresetOptions2": {
908
+ "additionalProperties": false,
909
+ "description": "Options under the service's `wrangler:` key.",
910
+ "examples": [
911
+ {
912
+ "args": [
913
+ "--env-file",
914
+ ".dev.vars"
915
+ ],
916
+ "isolate_registry": true,
917
+ "vars": {
918
+ "PUBLIC_BASE_URL": "${{ self.public_url }}"
919
+ }
920
+ }
921
+ ],
922
+ "properties": {
923
+ "args": {
924
+ "description": "Extra arguments appended after the preset's flags.",
925
+ "examples": [
926
+ [
927
+ "--env-file",
928
+ ".dev.vars"
929
+ ]
930
+ ],
931
+ "items": {
932
+ "description": "Extra arguments appended after the preset's flags.",
933
+ "examples": [
934
+ "--env-file",
935
+ ".dev.vars"
936
+ ],
937
+ "type": "string"
938
+ },
939
+ "type": [
940
+ "array",
941
+ "null"
942
+ ]
943
+ },
944
+ "isolate_registry": {
945
+ "description": "Give each lane its own dev registry through `WRANGLER_REGISTRY_PATH`.\nDefault: true.",
946
+ "examples": [
947
+ true,
948
+ false
949
+ ],
950
+ "type": [
951
+ "boolean",
952
+ "null"
953
+ ]
954
+ },
955
+ "vars": {
956
+ "additionalProperties": {
957
+ "description": "Worker variables, passed as `--var KEY:VALUE`. Numbers and booleans are\naccepted because config scalars evaluate to them; wrangler sees strings.",
958
+ "examples": [
959
+ "${{ self.public_url }}"
960
+ ],
961
+ "type": [
962
+ "string",
963
+ "number",
964
+ "boolean"
965
+ ]
966
+ },
967
+ "description": "Worker variables, passed as `--var KEY:VALUE`. Numbers and booleans are\naccepted because config scalars evaluate to them; wrangler sees strings.",
968
+ "examples": [
969
+ {
970
+ "PUBLIC_BASE_URL": "${{ self.public_url }}"
971
+ }
972
+ ],
973
+ "type": "object"
974
+ }
975
+ },
976
+ "type": "object"
977
+ },
978
+ "InjectedPresetOptions3": {
979
+ "additionalProperties": false,
980
+ "description": "Options under the service's `tauri:` key, after expression evaluation.",
981
+ "examples": [
982
+ {
983
+ "before_dev_command": "",
984
+ "dev_url": "${{ svc.desktop_web.url }}",
985
+ "identifier": "io.acme.app.lane${{ lane.index }}.client${{ replica.index }}"
986
+ }
987
+ ],
988
+ "properties": {
989
+ "before_dev_command": {
990
+ "description": "`build.beforeDevCommand` override. Set it to an empty string when the\nfrontend runs as its own devlanes service; otherwise every replica\nstarts its own frontend on the port from `tauri.conf.json`.",
991
+ "examples": [
992
+ "",
993
+ "pnpm dev"
994
+ ],
995
+ "type": [
996
+ "string",
997
+ "null"
998
+ ]
999
+ },
1000
+ "dev_url": {
1001
+ "description": "`build.devUrl`, usually another service's `url`.",
1002
+ "examples": [
1003
+ "${{ svc.desktop_web.url }}"
1004
+ ],
1005
+ "type": [
1006
+ "string",
1007
+ "null"
1008
+ ]
1009
+ },
1010
+ "identifier": {
1011
+ "description": "Bundle identifier for this lane and replica. Required; it must differ per\nlane and replica, for example\n`com.acme.app.dev${{ '' if lane.index == 0 else '.lane' ~ lane.index }}.client${{ replica.index }}`.",
1012
+ "examples": [
1013
+ "io.acme.app.lane${{ lane.index }}.client${{ replica.index }}"
1014
+ ],
1015
+ "type": [
1016
+ "string",
1017
+ "null"
1018
+ ]
1019
+ },
1020
+ "product_name": {
1021
+ "description": "`productName` override, shown in the dock and window menus.",
1022
+ "examples": [
1023
+ "Acme Dev"
1024
+ ],
1025
+ "type": [
1026
+ "string",
1027
+ "null"
1028
+ ]
1029
+ }
1030
+ },
1031
+ "type": "object"
1032
+ },
1033
+ "LanesConfig": {
1034
+ "additionalProperties": false,
1035
+ "description": "Worktree registration policy and values computed for each lane.",
1036
+ "examples": [
1037
+ {
1038
+ "hosts_file": "always",
1039
+ "primary": "main",
1040
+ "vars": {
1041
+ "db_name": "acme_${{ lane.name }}"
1042
+ }
1043
+ }
1044
+ ],
1045
+ "properties": {
1046
+ "block_size": {
1047
+ "anyOf": [
1048
+ {
1049
+ "$ref": "#/$defs/Templated_uint16"
1050
+ },
1051
+ {
1052
+ "type": "null"
1053
+ }
1054
+ ],
1055
+ "description": "Fixed port-block capacity; otherwise allocated with fifty percent headroom.",
1056
+ "examples": [
1057
+ 80
1058
+ ]
1059
+ },
1060
+ "hosts_file": {
1061
+ "anyOf": [
1062
+ {
1063
+ "$ref": "#/$defs/HostsFile"
1064
+ },
1065
+ {
1066
+ "type": "null"
1067
+ }
1068
+ ],
1069
+ "description": "Project-specific host-file hint, overriding the user's policy.",
1070
+ "examples": [
1071
+ "auto",
1072
+ "never",
1073
+ "always"
1074
+ ]
1075
+ },
1076
+ "matrix": {
1077
+ "description": "Explicit lane values; entry N describes lane N. Mutually exclusive with vars.",
1078
+ "examples": [
1079
+ [
1080
+ {
1081
+ "domain": "acme.localhost",
1082
+ "port": 20000
1083
+ },
1084
+ {
1085
+ "domain": "acme-1.localhost",
1086
+ "port": 20100
1087
+ }
1088
+ ]
1089
+ ],
1090
+ "items": {
1091
+ "additionalProperties": {
1092
+ "$ref": "#/$defs/Templated_Scalar",
1093
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
1094
+ "examples": [
1095
+ "${{ lane.index }}"
1096
+ ]
1097
+ },
1098
+ "description": "Explicit lane values; entry N describes lane N. Mutually exclusive with vars.",
1099
+ "examples": [
1100
+ {
1101
+ "domain": "acme.localhost",
1102
+ "port": 20000
1103
+ },
1104
+ {
1105
+ "domain": "acme-1.localhost",
1106
+ "port": 20100
1107
+ }
1108
+ ],
1109
+ "type": "object"
1110
+ },
1111
+ "type": [
1112
+ "array",
1113
+ "null"
1114
+ ]
1115
+ },
1116
+ "max": {
1117
+ "anyOf": [
1118
+ {
1119
+ "$ref": "#/$defs/Templated_uint32"
1120
+ },
1121
+ {
1122
+ "type": "null"
1123
+ }
1124
+ ],
1125
+ "description": "Maximum assigned lanes; existing lanes are retained if this is lowered.",
1126
+ "examples": [
1127
+ 6
1128
+ ]
1129
+ },
1130
+ "new_worktrees": {
1131
+ "anyOf": [
1132
+ {
1133
+ "$ref": "#/$defs/NewWorktrees"
1134
+ },
1135
+ {
1136
+ "type": "null"
1137
+ }
1138
+ ],
1139
+ "description": "What happens when a worktree gets its lane; defaults to register. A worktree\nbecomes a lane the first time devlanes runs in it (or `lane new` creates it),\nnot because it exists; only the primary worktree gets one on its own.",
1140
+ "examples": [
1141
+ "register",
1142
+ "setup",
1143
+ "start"
1144
+ ]
1145
+ },
1146
+ "primary": {
1147
+ "description": "Branch assigned lane zero; defaults to the remote default branch, main, or master.",
1148
+ "examples": [
1149
+ "main"
1150
+ ],
1151
+ "type": [
1152
+ "string",
1153
+ "null"
1154
+ ]
1155
+ },
1156
+ "removed_worktrees": {
1157
+ "anyOf": [
1158
+ {
1159
+ "$ref": "#/$defs/RemovedWorktrees"
1160
+ },
1161
+ {
1162
+ "type": "null"
1163
+ }
1164
+ ],
1165
+ "description": "What happens to a running lane whose worktree folder disappears; defaults to\nstop. A lane whose folder is gone and that runs nothing is cleaned; its logs\nstay until log retention removes them.",
1166
+ "examples": [
1167
+ "stop",
1168
+ "clean"
1169
+ ]
1170
+ },
1171
+ "vars": {
1172
+ "additionalProperties": {
1173
+ "$ref": "#/$defs/Templated_Scalar",
1174
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
1175
+ "examples": [
1176
+ "${{ lane.index }}"
1177
+ ]
1178
+ },
1179
+ "default": {},
1180
+ "description": "Scalar lane values available through the lane expression namespace.",
1181
+ "examples": [
1182
+ {
1183
+ "db_name": "acme_${{ lane.name }}"
1184
+ }
1185
+ ],
1186
+ "type": "object"
1187
+ },
1188
+ "worktree_dir": {
1189
+ "anyOf": [
1190
+ {
1191
+ "$ref": "#/$defs/Templated_string"
1192
+ },
1193
+ {
1194
+ "type": "null"
1195
+ }
1196
+ ],
1197
+ "description": "Directory for newly created worktrees, relative to the project.",
1198
+ "examples": [
1199
+ "../${{ project.name }}-lanes"
1200
+ ]
1201
+ }
1202
+ },
1203
+ "type": "object"
1204
+ },
1205
+ "NewWorktrees": {
1206
+ "description": "Action when a worktree gets its lane; defaults to register.",
1207
+ "examples": [
1208
+ "register",
1209
+ "setup",
1210
+ "start"
1211
+ ],
1212
+ "oneOf": [
1213
+ {
1214
+ "const": "register",
1215
+ "description": "Only reserve the lane: its index, ports and domain.",
1216
+ "examples": [
1217
+ "register"
1218
+ ],
1219
+ "type": "string"
1220
+ },
1221
+ {
1222
+ "const": "setup",
1223
+ "description": "Also run infrastructure setup and lane.create tasks, leaving services stopped.",
1224
+ "examples": [
1225
+ "setup"
1226
+ ],
1227
+ "type": "string"
1228
+ },
1229
+ {
1230
+ "const": "start",
1231
+ "description": "Also start the lane with the default profile.",
1232
+ "examples": [
1233
+ "start"
1234
+ ],
1235
+ "type": "string"
1236
+ }
1237
+ ]
1238
+ },
1239
+ "ProfileConfig": {
1240
+ "anyOf": [
1241
+ {
1242
+ "description": "Service names, globs, or +tag selectors.",
1243
+ "examples": [
1244
+ [
1245
+ "+api",
1246
+ "+web"
1247
+ ]
1248
+ ],
1249
+ "items": {
1250
+ "description": "Service names, globs, or +tag selectors.",
1251
+ "examples": [
1252
+ "+api",
1253
+ "+web"
1254
+ ],
1255
+ "type": "string"
1256
+ },
1257
+ "type": "array"
1258
+ },
1259
+ {
1260
+ "$ref": "#/$defs/ProfileOptions",
1261
+ "description": "Selection and overrides expressed as a mapping.",
1262
+ "examples": [
1263
+ {
1264
+ "include": [
1265
+ "+web"
1266
+ ],
1267
+ "infra": false
1268
+ }
1269
+ ]
1270
+ }
1271
+ ],
1272
+ "description": "Named service selection with optional environment, infrastructure, and script overrides.",
1273
+ "examples": [
1274
+ [
1275
+ "+api",
1276
+ "+web"
1277
+ ],
1278
+ {
1279
+ "include": [
1280
+ "+web"
1281
+ ],
1282
+ "infra": false
1283
+ }
1284
+ ]
1285
+ },
1286
+ "ProfileOptions": {
1287
+ "additionalProperties": false,
1288
+ "description": "Service selectors and overrides applied when this profile is active.",
1289
+ "examples": [
1290
+ {
1291
+ "env": {
1292
+ "NODE_ENV": "production"
1293
+ },
1294
+ "include": [
1295
+ "+api",
1296
+ "+web"
1297
+ ],
1298
+ "run_scripts": {
1299
+ "dev": "start"
1300
+ }
1301
+ }
1302
+ ],
1303
+ "properties": {
1304
+ "env": {
1305
+ "additionalProperties": {
1306
+ "$ref": "#/$defs/Templated_Scalar",
1307
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
1308
+ "examples": [
1309
+ "${{ lane.index }}"
1310
+ ]
1311
+ },
1312
+ "default": {},
1313
+ "description": "Profile environment overrides, applied above service environment values.",
1314
+ "examples": [
1315
+ {
1316
+ "NODE_ENV": "production"
1317
+ }
1318
+ ],
1319
+ "type": "object"
1320
+ },
1321
+ "exclude": {
1322
+ "description": "Selectors removed from the included service set.",
1323
+ "examples": [
1324
+ [
1325
+ "+desktop",
1326
+ "sms-stub"
1327
+ ]
1328
+ ],
1329
+ "items": {
1330
+ "description": "Selectors removed from the included service set.",
1331
+ "examples": [
1332
+ "+desktop",
1333
+ "sms-stub"
1334
+ ],
1335
+ "type": "string"
1336
+ },
1337
+ "type": [
1338
+ "array",
1339
+ "null"
1340
+ ]
1341
+ },
1342
+ "include": {
1343
+ "description": "Service names, globs, and +tag selectors included by this profile.",
1344
+ "examples": [
1345
+ [
1346
+ "+api",
1347
+ "+web"
1348
+ ],
1349
+ [
1350
+ "*"
1351
+ ]
1352
+ ],
1353
+ "items": {
1354
+ "description": "Service names, globs, and +tag selectors included by this profile.",
1355
+ "examples": [
1356
+ "+api",
1357
+ "+web",
1358
+ "*"
1359
+ ],
1360
+ "type": "string"
1361
+ },
1362
+ "type": [
1363
+ "array",
1364
+ "null"
1365
+ ]
1366
+ },
1367
+ "infra": {
1368
+ "anyOf": [
1369
+ {
1370
+ "$ref": "#/$defs/Templated_boolean"
1371
+ },
1372
+ {
1373
+ "type": "null"
1374
+ }
1375
+ ],
1376
+ "description": "Set false to skip containers and infra setup.",
1377
+ "examples": [
1378
+ false,
1379
+ true
1380
+ ]
1381
+ },
1382
+ "run_scripts": {
1383
+ "additionalProperties": {
1384
+ "description": "Remap service script names once, such as dev to start; source files stay unchanged.",
1385
+ "examples": [
1386
+ "start"
1387
+ ],
1388
+ "minLength": 1,
1389
+ "pattern": "\\S",
1390
+ "type": "string"
1391
+ },
1392
+ "default": {},
1393
+ "description": "Remap service script names once, such as dev to start; source files stay unchanged.",
1394
+ "examples": [
1395
+ {
1396
+ "dev": "start"
1397
+ }
1398
+ ],
1399
+ "propertyNames": {
1400
+ "minLength": 1,
1401
+ "pattern": "\\S",
1402
+ "type": "string"
1403
+ },
1404
+ "type": "object"
1405
+ }
1406
+ },
1407
+ "type": "object"
1408
+ },
1409
+ "ReadyCheck": {
1410
+ "additionalProperties": false,
1411
+ "description": "Exactly one readiness mechanism is accepted by semantic validation.",
1412
+ "examples": [
1413
+ {
1414
+ "http": {
1415
+ "path": "/healthz"
1416
+ }
1417
+ },
1418
+ {
1419
+ "tcp": true
1420
+ },
1421
+ {
1422
+ "log": "Connected to Redis"
1423
+ },
1424
+ {
1425
+ "cmd": "curl -fsS ${{ self.url }}/healthz"
1426
+ }
1427
+ ],
1428
+ "properties": {
1429
+ "cmd": {
1430
+ "anyOf": [
1431
+ {
1432
+ "$ref": "#/$defs/Run"
1433
+ },
1434
+ {
1435
+ "type": "null"
1436
+ }
1437
+ ],
1438
+ "description": "Retry this command until it exits successfully.",
1439
+ "examples": [
1440
+ "curl -fsS ${{ self.url }}/healthz"
1441
+ ]
1442
+ },
1443
+ "http": {
1444
+ "anyOf": [
1445
+ {
1446
+ "$ref": "#/$defs/HttpReady"
1447
+ },
1448
+ {
1449
+ "type": "null"
1450
+ }
1451
+ ],
1452
+ "description": "Wait for an HTTP response matching the requested path and status.",
1453
+ "examples": [
1454
+ {
1455
+ "path": "/healthz",
1456
+ "status": 200,
1457
+ "timeout": "60s"
1458
+ }
1459
+ ]
1460
+ },
1461
+ "log": {
1462
+ "anyOf": [
1463
+ {
1464
+ "$ref": "#/$defs/Templated_string"
1465
+ },
1466
+ {
1467
+ "type": "null"
1468
+ }
1469
+ ],
1470
+ "description": "Regular expression matched against output with terminal escape codes removed.",
1471
+ "examples": [
1472
+ "Connected to Redis"
1473
+ ]
1474
+ },
1475
+ "tcp": {
1476
+ "anyOf": [
1477
+ {
1478
+ "$ref": "#/$defs/TcpReady"
1479
+ },
1480
+ {
1481
+ "type": "null"
1482
+ }
1483
+ ],
1484
+ "description": "Wait for the primary port with true, or a named port such as inspector.",
1485
+ "examples": [
1486
+ true,
1487
+ "inspector"
1488
+ ]
1489
+ },
1490
+ "timeout": {
1491
+ "anyOf": [
1492
+ {
1493
+ "$ref": "#/$defs/Templated_ConfigDuration"
1494
+ },
1495
+ {
1496
+ "type": "null"
1497
+ }
1498
+ ],
1499
+ "description": "Maximum time to wait for the readiness check.",
1500
+ "examples": [
1501
+ "15s",
1502
+ "10m"
1503
+ ]
1504
+ }
1505
+ },
1506
+ "type": "object"
1507
+ },
1508
+ "ReadyConfig": {
1509
+ "anyOf": [
1510
+ {
1511
+ "$ref": "#/$defs/Started",
1512
+ "description": "Treat a running process as ready without a probe.",
1513
+ "examples": [
1514
+ "started"
1515
+ ]
1516
+ },
1517
+ {
1518
+ "$ref": "#/$defs/ReadyCheck",
1519
+ "description": "Wait for a TCP, HTTP, log, or command check to succeed.",
1520
+ "examples": [
1521
+ {
1522
+ "http": {
1523
+ "path": "/healthz"
1524
+ }
1525
+ },
1526
+ {
1527
+ "tcp": true
1528
+ }
1529
+ ]
1530
+ }
1531
+ ],
1532
+ "description": "Readiness policy; defaults to TCP for services with hosts and started for other services.",
1533
+ "examples": [
1534
+ "started",
1535
+ {
1536
+ "http": {
1537
+ "path": "/healthz"
1538
+ }
1539
+ },
1540
+ {
1541
+ "tcp": true
1542
+ }
1543
+ ]
1544
+ },
1545
+ "RemovedWorktrees": {
1546
+ "description": "Action when a running lane's worktree folder disappears; defaults to stop.",
1547
+ "examples": [
1548
+ "stop",
1549
+ "clean"
1550
+ ],
1551
+ "oneOf": [
1552
+ {
1553
+ "const": "stop",
1554
+ "description": "Stop the lane's processes; once nothing runs, the lane is cleaned.",
1555
+ "examples": [
1556
+ "stop"
1557
+ ],
1558
+ "type": "string"
1559
+ },
1560
+ {
1561
+ "const": "clean",
1562
+ "description": "Clean the lane right away: stop processes, run teardown, and free the lane.",
1563
+ "examples": [
1564
+ "clean"
1565
+ ],
1566
+ "type": "string"
1567
+ }
1568
+ ]
1569
+ },
1570
+ "Run": {
1571
+ "anyOf": [
1572
+ {
1573
+ "$ref": "#/$defs/Templated_string",
1574
+ "description": "Shell command text; supports pipelines and multiline scripts.",
1575
+ "examples": [
1576
+ "pnpm dev"
1577
+ ]
1578
+ },
1579
+ {
1580
+ "description": "Executable and arguments passed directly without shell expansion.",
1581
+ "examples": [
1582
+ [
1583
+ "node",
1584
+ "server.mjs"
1585
+ ]
1586
+ ],
1587
+ "items": {
1588
+ "$ref": "#/$defs/Templated_string",
1589
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
1590
+ "examples": [
1591
+ "${{ lane.index }}"
1592
+ ]
1593
+ },
1594
+ "type": "array"
1595
+ }
1596
+ ],
1597
+ "description": "Shell text runs in a shell; argv is passed directly to the executable.",
1598
+ "examples": [
1599
+ "pnpm dev",
1600
+ [
1601
+ "node",
1602
+ "server.mjs",
1603
+ "--port",
1604
+ "${{ self.port }}"
1605
+ ]
1606
+ ]
1607
+ },
1608
+ "RunScript": {
1609
+ "anyOf": [
1610
+ {
1611
+ "description": "Source file followed by # and the script name.",
1612
+ "examples": [
1613
+ "apps/api/package.json#dev"
1614
+ ],
1615
+ "type": "string"
1616
+ },
1617
+ {
1618
+ "$ref": "#/$defs/ScriptSource",
1619
+ "description": "Source file and script name written as separate fields.",
1620
+ "examples": [
1621
+ {
1622
+ "name": "fixtures",
1623
+ "source": "justfile"
1624
+ }
1625
+ ]
1626
+ }
1627
+ ],
1628
+ "description": "Script selected from a package manifest, Makefile, or justfile.",
1629
+ "examples": [
1630
+ "apps/api/package.json#dev",
1631
+ {
1632
+ "name": "fixtures",
1633
+ "source": "justfile"
1634
+ }
1635
+ ]
1636
+ },
1637
+ "Scalar": {
1638
+ "anyOf": [
1639
+ {
1640
+ "description": "Text used verbatim in the environment or lane variables.",
1641
+ "examples": [
1642
+ "acme"
1643
+ ],
1644
+ "type": "string"
1645
+ },
1646
+ {
1647
+ "description": "Boolean value, rendered as true or false in process environments.",
1648
+ "examples": [
1649
+ true,
1650
+ false
1651
+ ],
1652
+ "type": "boolean"
1653
+ },
1654
+ {
1655
+ "description": "Whole number, such as a port or lane index.",
1656
+ "examples": [
1657
+ 20000
1658
+ ],
1659
+ "format": "int64",
1660
+ "type": "integer"
1661
+ },
1662
+ {
1663
+ "description": "Decimal number, rendered as text in process environments.",
1664
+ "examples": [
1665
+ 1.5
1666
+ ],
1667
+ "format": "double",
1668
+ "type": "number"
1669
+ }
1670
+ ],
1671
+ "description": "A scalar suitable for environment variables and free-form lane variables.",
1672
+ "examples": [
1673
+ "acme",
1674
+ 20000,
1675
+ true
1676
+ ]
1677
+ },
1678
+ "ScriptSource": {
1679
+ "additionalProperties": false,
1680
+ "description": "A source file and the script or target to run from it.",
1681
+ "examples": [
1682
+ {
1683
+ "name": "fixtures",
1684
+ "source": "justfile"
1685
+ }
1686
+ ],
1687
+ "properties": {
1688
+ "name": {
1689
+ "default": "",
1690
+ "description": "Script, target, or recipe name within the source file.\nRequired, unless an override or extends child keeps the inherited name.",
1691
+ "examples": [
1692
+ "dev",
1693
+ "fixtures"
1694
+ ],
1695
+ "type": "string"
1696
+ },
1697
+ "source": {
1698
+ "default": "",
1699
+ "description": "Script source relative to the worktree, such as package.json, Makefile, or justfile.\nRequired, unless an override or extends child keeps the inherited source.",
1700
+ "examples": [
1701
+ "apps/api/package.json",
1702
+ "Makefile",
1703
+ "justfile"
1704
+ ],
1705
+ "type": "string"
1706
+ }
1707
+ },
1708
+ "type": "object"
1709
+ },
1710
+ "ServiceConfig": {
1711
+ "additionalProperties": false,
1712
+ "allOf": [
1713
+ {
1714
+ "if": {
1715
+ "required": [
1716
+ "vite"
1717
+ ]
1718
+ },
1719
+ "then": {
1720
+ "properties": {
1721
+ "preset": {
1722
+ "const": "vite",
1723
+ "description": "`vite` options require `preset: vite`.",
1724
+ "examples": [
1725
+ "vite"
1726
+ ]
1727
+ }
1728
+ }
1729
+ }
1730
+ },
1731
+ {
1732
+ "if": {
1733
+ "required": [
1734
+ "next"
1735
+ ]
1736
+ },
1737
+ "then": {
1738
+ "properties": {
1739
+ "preset": {
1740
+ "const": "next",
1741
+ "description": "`next` options require `preset: next`.",
1742
+ "examples": [
1743
+ "next"
1744
+ ]
1745
+ }
1746
+ }
1747
+ }
1748
+ },
1749
+ {
1750
+ "if": {
1751
+ "required": [
1752
+ "wrangler"
1753
+ ]
1754
+ },
1755
+ "then": {
1756
+ "properties": {
1757
+ "preset": {
1758
+ "const": "wrangler",
1759
+ "description": "`wrangler` options require `preset: wrangler`.",
1760
+ "examples": [
1761
+ "wrangler"
1762
+ ]
1763
+ }
1764
+ }
1765
+ }
1766
+ },
1767
+ {
1768
+ "if": {
1769
+ "required": [
1770
+ "tauri"
1771
+ ]
1772
+ },
1773
+ "then": {
1774
+ "properties": {
1775
+ "preset": {
1776
+ "const": "tauri",
1777
+ "description": "`tauri` options require `preset: tauri`.",
1778
+ "examples": [
1779
+ "tauri"
1780
+ ]
1781
+ }
1782
+ }
1783
+ }
1784
+ }
1785
+ ],
1786
+ "description": "Service settings after typed local and template merging.",
1787
+ "examples": [
1788
+ {
1789
+ "hosts": [
1790
+ "api.${{ lane.domain }}"
1791
+ ],
1792
+ "run_script": "apps/api/package.json#dev",
1793
+ "tags": [
1794
+ "api"
1795
+ ]
1796
+ }
1797
+ ],
1798
+ "properties": {
1799
+ "autostart": {
1800
+ "anyOf": [
1801
+ {
1802
+ "$ref": "#/$defs/Templated_boolean"
1803
+ },
1804
+ {
1805
+ "type": "null"
1806
+ }
1807
+ ],
1808
+ "description": "Start by default unless explicitly selected; defaults to true.",
1809
+ "examples": [
1810
+ true,
1811
+ false
1812
+ ]
1813
+ },
1814
+ "cwd": {
1815
+ "anyOf": [
1816
+ {
1817
+ "$ref": "#/$defs/Templated_string"
1818
+ },
1819
+ {
1820
+ "type": "null"
1821
+ }
1822
+ ],
1823
+ "description": "Working directory relative to the lane worktree.",
1824
+ "examples": [
1825
+ "apps/api"
1826
+ ]
1827
+ },
1828
+ "env": {
1829
+ "additionalProperties": {
1830
+ "$ref": "#/$defs/Templated_Scalar",
1831
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
1832
+ "examples": [
1833
+ "${{ lane.index }}"
1834
+ ]
1835
+ },
1836
+ "default": {},
1837
+ "description": "Service-specific environment overrides, above global_env.",
1838
+ "examples": [
1839
+ {
1840
+ "API_URL": "${{ svc.api.url }}"
1841
+ }
1842
+ ],
1843
+ "type": "object"
1844
+ },
1845
+ "extends": {
1846
+ "description": "Template name; resolved after devlanes.local.yaml is merged.",
1847
+ "examples": [
1848
+ "fastify-api"
1849
+ ],
1850
+ "type": [
1851
+ "string",
1852
+ "null"
1853
+ ]
1854
+ },
1855
+ "fnox": {
1856
+ "anyOf": [
1857
+ {
1858
+ "$ref": "#/$defs/FnoxConfig"
1859
+ },
1860
+ {
1861
+ "type": "null"
1862
+ }
1863
+ ],
1864
+ "description": "Override the project fnox profile for this service.",
1865
+ "examples": [
1866
+ {
1867
+ "profile": "dev"
1868
+ }
1869
+ ]
1870
+ },
1871
+ "hidden": {
1872
+ "anyOf": [
1873
+ {
1874
+ "$ref": "#/$defs/Templated_boolean"
1875
+ },
1876
+ {
1877
+ "type": "null"
1878
+ }
1879
+ ],
1880
+ "description": "Prevent remote port mirroring; defaults to false.",
1881
+ "examples": [
1882
+ false,
1883
+ true
1884
+ ]
1885
+ },
1886
+ "hosts": {
1887
+ "description": "HTTP hosts, wildcard hosts, and routes to named ports.",
1888
+ "examples": [
1889
+ [
1890
+ "api.${{ lane.domain }}"
1891
+ ],
1892
+ [
1893
+ {
1894
+ "host": "inspect.${{ lane.domain }}",
1895
+ "port": "inspector"
1896
+ }
1897
+ ]
1898
+ ],
1899
+ "items": {
1900
+ "$ref": "#/$defs/HostConfig",
1901
+ "description": "Hostname routed by the HTTP proxy, optionally with route settings.",
1902
+ "examples": [
1903
+ "api.${{ lane.domain }}",
1904
+ {
1905
+ "fallback": true,
1906
+ "host": "*.${{ lane.domain }}"
1907
+ }
1908
+ ]
1909
+ },
1910
+ "type": [
1911
+ "array",
1912
+ "null"
1913
+ ]
1914
+ },
1915
+ "name": {
1916
+ "description": "Display name shown in the TUI and human output instead of the service key;\nany text, spaces allowed. Commands, references and `svc.<key>` keep using the key.",
1917
+ "examples": [
1918
+ "Admin API",
1919
+ "Storefront (web)"
1920
+ ],
1921
+ "type": [
1922
+ "string",
1923
+ "null"
1924
+ ]
1925
+ },
1926
+ "next": {
1927
+ "$ref": "#/$defs/InjectedPresetOptions1",
1928
+ "description": "Options under the service's `next:` key.",
1929
+ "examples": [
1930
+ {
1931
+ "args": [
1932
+ "--turbo"
1933
+ ]
1934
+ }
1935
+ ],
1936
+ "type": "object"
1937
+ },
1938
+ "platform": {
1939
+ "description": "Platform: node, bun, deno, python or rust; detected from project files when omitted.",
1940
+ "examples": [
1941
+ "node",
1942
+ "bun",
1943
+ "deno",
1944
+ "python",
1945
+ "rust"
1946
+ ],
1947
+ "type": [
1948
+ "string",
1949
+ "null"
1950
+ ]
1951
+ },
1952
+ "preset": {
1953
+ "description": "Registered framework preset; options use a sibling key with this name.",
1954
+ "enum": [
1955
+ "vite",
1956
+ "next",
1957
+ "wrangler",
1958
+ "tauri"
1959
+ ],
1960
+ "examples": [
1961
+ "vite",
1962
+ "next",
1963
+ "wrangler",
1964
+ "tauri"
1965
+ ],
1966
+ "type": [
1967
+ "string",
1968
+ "null"
1969
+ ]
1970
+ },
1971
+ "pty": {
1972
+ "anyOf": [
1973
+ {
1974
+ "$ref": "#/$defs/Templated_boolean"
1975
+ },
1976
+ {
1977
+ "type": "null"
1978
+ }
1979
+ ],
1980
+ "description": "Use a pseudoterminal; defaults to true.",
1981
+ "examples": [
1982
+ true,
1983
+ false
1984
+ ]
1985
+ },
1986
+ "ready": {
1987
+ "anyOf": [
1988
+ {
1989
+ "$ref": "#/$defs/ReadyConfig"
1990
+ },
1991
+ {
1992
+ "type": "null"
1993
+ }
1994
+ ],
1995
+ "description": "Readiness policy; defaults to TCP with hosts, otherwise started.",
1996
+ "examples": [
1997
+ "started",
1998
+ {
1999
+ "http": {
2000
+ "path": "/healthz"
2001
+ }
2002
+ },
2003
+ {
2004
+ "tcp": true
2005
+ }
2006
+ ]
2007
+ },
2008
+ "replicas": {
2009
+ "anyOf": [
2010
+ {
2011
+ "$ref": "#/$defs/Templated_uint16"
2012
+ },
2013
+ {
2014
+ "type": "null"
2015
+ }
2016
+ ],
2017
+ "description": "Number of instances; replica.index starts at one. Defaults to one.",
2018
+ "examples": [
2019
+ 1,
2020
+ 2
2021
+ ]
2022
+ },
2023
+ "run": {
2024
+ "anyOf": [
2025
+ {
2026
+ "$ref": "#/$defs/Run"
2027
+ },
2028
+ {
2029
+ "type": "null"
2030
+ }
2031
+ ],
2032
+ "description": "Shell command or argv; exactly one of run and run_script is required after inheritance.",
2033
+ "examples": [
2034
+ "pnpm dev",
2035
+ [
2036
+ "node",
2037
+ "server.mjs",
2038
+ "--port",
2039
+ "${{ self.port }}"
2040
+ ]
2041
+ ]
2042
+ },
2043
+ "run_script": {
2044
+ "anyOf": [
2045
+ {
2046
+ "$ref": "#/$defs/RunScript"
2047
+ },
2048
+ {
2049
+ "type": "null"
2050
+ }
2051
+ ],
2052
+ "description": "Script file and name, in shorthand or object form.",
2053
+ "examples": [
2054
+ "apps/api/package.json#dev",
2055
+ {
2056
+ "name": "fixtures",
2057
+ "source": "justfile"
2058
+ }
2059
+ ]
2060
+ },
2061
+ "stop": {
2062
+ "anyOf": [
2063
+ {
2064
+ "$ref": "#/$defs/StopConfig"
2065
+ },
2066
+ {
2067
+ "type": "null"
2068
+ }
2069
+ ],
2070
+ "description": "Stop signal and grace period before killing the process tree.",
2071
+ "examples": [
2072
+ {
2073
+ "signal": "SIGINT",
2074
+ "timeout": "15s"
2075
+ }
2076
+ ]
2077
+ },
2078
+ "sync": {
2079
+ "description": "Folders copied to stable local or remote-client paths.",
2080
+ "examples": [
2081
+ [
2082
+ {
2083
+ "from": "apps/extension/.output/chrome-mv3",
2084
+ "ignore": [
2085
+ "*.map"
2086
+ ]
2087
+ }
2088
+ ]
2089
+ ],
2090
+ "items": {
2091
+ "$ref": "#/$defs/SyncConfig",
2092
+ "description": "Directory copied to a stable local or remote-client path.",
2093
+ "examples": [
2094
+ {
2095
+ "from": "apps/extension/.output/chrome-mv3",
2096
+ "ignore": [
2097
+ "*.map"
2098
+ ]
2099
+ }
2100
+ ]
2101
+ },
2102
+ "type": [
2103
+ "array",
2104
+ "null"
2105
+ ]
2106
+ },
2107
+ "tags": {
2108
+ "description": "Tags used by +tag profile selectors.",
2109
+ "examples": [
2110
+ [
2111
+ "api",
2112
+ "essential"
2113
+ ],
2114
+ [
2115
+ "worker"
2116
+ ],
2117
+ [
2118
+ "web"
2119
+ ]
2120
+ ],
2121
+ "items": {
2122
+ "description": "Tags used by +tag profile selectors.",
2123
+ "examples": [
2124
+ "api",
2125
+ "essential",
2126
+ "worker",
2127
+ "web"
2128
+ ],
2129
+ "type": "string"
2130
+ },
2131
+ "type": [
2132
+ "array",
2133
+ "null"
2134
+ ]
2135
+ },
2136
+ "tauri": {
2137
+ "$ref": "#/$defs/InjectedPresetOptions3",
2138
+ "description": "Options under the service's `tauri:` key, after expression evaluation.",
2139
+ "examples": [
2140
+ {
2141
+ "before_dev_command": "",
2142
+ "dev_url": "${{ svc.desktop_web.url }}",
2143
+ "identifier": "io.acme.app.lane${{ lane.index }}.client${{ replica.index }}"
2144
+ }
2145
+ ],
2146
+ "type": "object"
2147
+ },
2148
+ "vite": {
2149
+ "$ref": "#/$defs/InjectedPresetOptions0",
2150
+ "description": "Options under the service's `vite:` key.",
2151
+ "examples": [
2152
+ {
2153
+ "args": [
2154
+ "--open"
2155
+ ]
2156
+ }
2157
+ ],
2158
+ "type": "object"
2159
+ },
2160
+ "wrangler": {
2161
+ "$ref": "#/$defs/InjectedPresetOptions2",
2162
+ "description": "Options under the service's `wrangler:` key.",
2163
+ "examples": [
2164
+ {
2165
+ "args": [
2166
+ "--env-file",
2167
+ ".dev.vars"
2168
+ ],
2169
+ "isolate_registry": true,
2170
+ "vars": {
2171
+ "PUBLIC_BASE_URL": "${{ self.public_url }}"
2172
+ }
2173
+ }
2174
+ ],
2175
+ "type": "object"
2176
+ }
2177
+ },
2178
+ "type": "object"
2179
+ },
2180
+ "Started": {
2181
+ "description": "Readiness without an application-level probe.",
2182
+ "examples": [
2183
+ "started"
2184
+ ],
2185
+ "oneOf": [
2186
+ {
2187
+ "const": "started",
2188
+ "description": "The process has started; no TCP, HTTP, log, or command probe is needed.",
2189
+ "examples": [
2190
+ "started"
2191
+ ],
2192
+ "type": "string"
2193
+ }
2194
+ ]
2195
+ },
2196
+ "StopConfig": {
2197
+ "additionalProperties": false,
2198
+ "description": "Signal and grace period used when stopping a process tree.",
2199
+ "examples": [
2200
+ {
2201
+ "signal": "SIGINT",
2202
+ "timeout": "15s"
2203
+ }
2204
+ ],
2205
+ "properties": {
2206
+ "signal": {
2207
+ "description": "Initial stop signal; defaults to SIGTERM, followed by SIGKILL if the grace period expires.",
2208
+ "examples": [
2209
+ "SIGTERM",
2210
+ "SIGINT"
2211
+ ],
2212
+ "type": [
2213
+ "string",
2214
+ "null"
2215
+ ]
2216
+ },
2217
+ "timeout": {
2218
+ "anyOf": [
2219
+ {
2220
+ "$ref": "#/$defs/Templated_ConfigDuration"
2221
+ },
2222
+ {
2223
+ "type": "null"
2224
+ }
2225
+ ],
2226
+ "description": "Grace period before SIGKILL; defaults to 10s.",
2227
+ "examples": [
2228
+ "15s",
2229
+ "10m"
2230
+ ]
2231
+ }
2232
+ },
2233
+ "type": "object"
2234
+ },
2235
+ "SyncConfig": {
2236
+ "additionalProperties": false,
2237
+ "description": "Directory copied to a stable local or remote-client path.",
2238
+ "examples": [
2239
+ {
2240
+ "from": "apps/extension/.output/chrome-mv3",
2241
+ "ignore": [
2242
+ "*.map"
2243
+ ]
2244
+ }
2245
+ ],
2246
+ "properties": {
2247
+ "from": {
2248
+ "$ref": "#/$defs/Templated_string",
2249
+ "description": "Directory to copy, relative to the lane's worktree.",
2250
+ "examples": [
2251
+ "apps/extension/.output/chrome-mv3"
2252
+ ]
2253
+ },
2254
+ "ignore": {
2255
+ "default": [],
2256
+ "description": "Glob patterns excluded from the copy and subsequent updates.",
2257
+ "examples": [
2258
+ [
2259
+ "*.map"
2260
+ ]
2261
+ ],
2262
+ "items": {
2263
+ "description": "Glob patterns excluded from the copy and subsequent updates.",
2264
+ "examples": [
2265
+ "*.map"
2266
+ ],
2267
+ "type": "string"
2268
+ },
2269
+ "type": "array"
2270
+ },
2271
+ "to": {
2272
+ "anyOf": [
2273
+ {
2274
+ "$ref": "#/$defs/Templated_string"
2275
+ },
2276
+ {
2277
+ "type": "null"
2278
+ }
2279
+ ],
2280
+ "description": "Destination on the client; defaults to a stable project/lane path under ~/devlanes/sync.",
2281
+ "examples": [
2282
+ "~/devlanes/sync/acme/${{ lane.name }}/chrome-mv3"
2283
+ ]
2284
+ }
2285
+ },
2286
+ "required": [
2287
+ "from"
2288
+ ],
2289
+ "type": "object"
2290
+ },
2291
+ "TagColor": {
2292
+ "description": "Fixed terminal palette for tag color overrides.",
2293
+ "examples": [
2294
+ "red",
2295
+ "green",
2296
+ "yellow",
2297
+ "blue",
2298
+ "magenta",
2299
+ "cyan",
2300
+ "white",
2301
+ "gray",
2302
+ "bright-red",
2303
+ "bright-green",
2304
+ "bright-yellow",
2305
+ "bright-blue",
2306
+ "bright-magenta",
2307
+ "bright-cyan"
2308
+ ],
2309
+ "oneOf": [
2310
+ {
2311
+ "const": "red",
2312
+ "description": "Use the terminal's red palette color.",
2313
+ "examples": [
2314
+ "red"
2315
+ ],
2316
+ "type": "string"
2317
+ },
2318
+ {
2319
+ "const": "green",
2320
+ "description": "Use the terminal's green palette color.",
2321
+ "examples": [
2322
+ "green"
2323
+ ],
2324
+ "type": "string"
2325
+ },
2326
+ {
2327
+ "const": "yellow",
2328
+ "description": "Use the terminal's yellow palette color.",
2329
+ "examples": [
2330
+ "yellow"
2331
+ ],
2332
+ "type": "string"
2333
+ },
2334
+ {
2335
+ "const": "blue",
2336
+ "description": "Use the terminal's blue palette color.",
2337
+ "examples": [
2338
+ "blue"
2339
+ ],
2340
+ "type": "string"
2341
+ },
2342
+ {
2343
+ "const": "magenta",
2344
+ "description": "Use the terminal's magenta palette color.",
2345
+ "examples": [
2346
+ "magenta"
2347
+ ],
2348
+ "type": "string"
2349
+ },
2350
+ {
2351
+ "const": "cyan",
2352
+ "description": "Use the terminal's cyan palette color.",
2353
+ "examples": [
2354
+ "cyan"
2355
+ ],
2356
+ "type": "string"
2357
+ },
2358
+ {
2359
+ "const": "white",
2360
+ "description": "Use the terminal's white palette color.",
2361
+ "examples": [
2362
+ "white"
2363
+ ],
2364
+ "type": "string"
2365
+ },
2366
+ {
2367
+ "const": "gray",
2368
+ "description": "Use the terminal's gray palette color.",
2369
+ "examples": [
2370
+ "gray"
2371
+ ],
2372
+ "type": "string"
2373
+ },
2374
+ {
2375
+ "const": "bright-red",
2376
+ "description": "Use the terminal's bright-red palette color.",
2377
+ "examples": [
2378
+ "bright-red"
2379
+ ],
2380
+ "type": "string"
2381
+ },
2382
+ {
2383
+ "const": "bright-green",
2384
+ "description": "Use the terminal's bright-green palette color.",
2385
+ "examples": [
2386
+ "bright-green"
2387
+ ],
2388
+ "type": "string"
2389
+ },
2390
+ {
2391
+ "const": "bright-yellow",
2392
+ "description": "Use the terminal's bright-yellow palette color.",
2393
+ "examples": [
2394
+ "bright-yellow"
2395
+ ],
2396
+ "type": "string"
2397
+ },
2398
+ {
2399
+ "const": "bright-blue",
2400
+ "description": "Use the terminal's bright-blue palette color.",
2401
+ "examples": [
2402
+ "bright-blue"
2403
+ ],
2404
+ "type": "string"
2405
+ },
2406
+ {
2407
+ "const": "bright-magenta",
2408
+ "description": "Use the terminal's bright-magenta palette color.",
2409
+ "examples": [
2410
+ "bright-magenta"
2411
+ ],
2412
+ "type": "string"
2413
+ },
2414
+ {
2415
+ "const": "bright-cyan",
2416
+ "description": "Use the terminal's bright-cyan palette color.",
2417
+ "examples": [
2418
+ "bright-cyan"
2419
+ ],
2420
+ "type": "string"
2421
+ }
2422
+ ]
2423
+ },
2424
+ "TagConfig": {
2425
+ "additionalProperties": false,
2426
+ "description": "Optional display overrides for a tag; services may also use undeclared tags.",
2427
+ "examples": [
2428
+ {
2429
+ "color": "cyan",
2430
+ "description": "HTTP APIs"
2431
+ }
2432
+ ],
2433
+ "properties": {
2434
+ "color": {
2435
+ "anyOf": [
2436
+ {
2437
+ "$ref": "#/$defs/TagColor"
2438
+ },
2439
+ {
2440
+ "type": "null"
2441
+ }
2442
+ ],
2443
+ "description": "Terminal palette color; inferred by the resolver when omitted.",
2444
+ "examples": [
2445
+ "red",
2446
+ "green",
2447
+ "yellow",
2448
+ "blue",
2449
+ "magenta",
2450
+ "cyan",
2451
+ "white",
2452
+ "gray",
2453
+ "bright-red",
2454
+ "bright-green",
2455
+ "bright-yellow",
2456
+ "bright-blue",
2457
+ "bright-magenta",
2458
+ "bright-cyan"
2459
+ ]
2460
+ },
2461
+ "description": {
2462
+ "description": "Human-readable description available to the TUI.",
2463
+ "examples": [
2464
+ "HTTP APIs",
2465
+ "Background workers"
2466
+ ],
2467
+ "type": [
2468
+ "string",
2469
+ "null"
2470
+ ]
2471
+ }
2472
+ },
2473
+ "type": "object"
2474
+ },
2475
+ "TaskAfter": {
2476
+ "description": "Move a create/start task to a later startup phase.",
2477
+ "examples": [
2478
+ "services"
2479
+ ],
2480
+ "oneOf": [
2481
+ {
2482
+ "const": "services",
2483
+ "description": "Run after selected services are ready; skip if any selected service failed.",
2484
+ "examples": [
2485
+ "services"
2486
+ ],
2487
+ "type": "string"
2488
+ }
2489
+ ]
2490
+ },
2491
+ "TaskConfig": {
2492
+ "additionalProperties": false,
2493
+ "description": "One-shot command, script, or named steps, run on demand or from a lifecycle hook.",
2494
+ "examples": [
2495
+ {
2496
+ "run_script": "apps/api/package.json#migrate",
2497
+ "when": "lane.start"
2498
+ }
2499
+ ],
2500
+ "properties": {
2501
+ "after": {
2502
+ "anyOf": [
2503
+ {
2504
+ "$ref": "#/$defs/TaskAfter"
2505
+ },
2506
+ {
2507
+ "type": "null"
2508
+ }
2509
+ ],
2510
+ "description": "Delay a create/start hook until all selected services are ready.",
2511
+ "examples": [
2512
+ "services"
2513
+ ]
2514
+ },
2515
+ "confirm": {
2516
+ "anyOf": [
2517
+ {
2518
+ "$ref": "#/$defs/Templated_string"
2519
+ },
2520
+ {
2521
+ "type": "null"
2522
+ }
2523
+ ],
2524
+ "description": "Confirmation text; noninteractive clients must explicitly approve.",
2525
+ "examples": [
2526
+ "Reset ${{ lane.db_name }} and re-seed it?"
2527
+ ]
2528
+ },
2529
+ "cwd": {
2530
+ "anyOf": [
2531
+ {
2532
+ "$ref": "#/$defs/Templated_string"
2533
+ },
2534
+ {
2535
+ "type": "null"
2536
+ }
2537
+ ],
2538
+ "description": "Working directory relative to the lane's worktree.",
2539
+ "examples": [
2540
+ "apps/api"
2541
+ ]
2542
+ },
2543
+ "env": {
2544
+ "additionalProperties": {
2545
+ "$ref": "#/$defs/Templated_Scalar",
2546
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
2547
+ "examples": [
2548
+ "${{ lane.index }}"
2549
+ ]
2550
+ },
2551
+ "default": {},
2552
+ "description": "Task-specific environment overrides.",
2553
+ "examples": [
2554
+ {
2555
+ "API_URL": "${{ svc.api.url }}"
2556
+ }
2557
+ ],
2558
+ "type": "object"
2559
+ },
2560
+ "fnox": {
2561
+ "anyOf": [
2562
+ {
2563
+ "$ref": "#/$defs/FnoxConfig"
2564
+ },
2565
+ {
2566
+ "type": "null"
2567
+ }
2568
+ ],
2569
+ "description": "Task-specific fnox profile.",
2570
+ "examples": [
2571
+ {
2572
+ "profile": "dev"
2573
+ }
2574
+ ]
2575
+ },
2576
+ "interactive": {
2577
+ "anyOf": [
2578
+ {
2579
+ "$ref": "#/$defs/Templated_boolean"
2580
+ },
2581
+ {
2582
+ "type": "null"
2583
+ }
2584
+ ],
2585
+ "description": "Require an attached terminal; incompatible with lifecycle hooks.",
2586
+ "examples": [
2587
+ true,
2588
+ false
2589
+ ]
2590
+ },
2591
+ "profiles": {
2592
+ "description": "Profiles for which this lifecycle hook runs automatically.",
2593
+ "examples": [
2594
+ [
2595
+ "default",
2596
+ "backend"
2597
+ ]
2598
+ ],
2599
+ "items": {
2600
+ "description": "Profiles for which this lifecycle hook runs automatically.",
2601
+ "examples": [
2602
+ "default",
2603
+ "backend"
2604
+ ],
2605
+ "type": "string"
2606
+ },
2607
+ "type": [
2608
+ "array",
2609
+ "null"
2610
+ ]
2611
+ },
2612
+ "pty": {
2613
+ "anyOf": [
2614
+ {
2615
+ "$ref": "#/$defs/Templated_boolean"
2616
+ },
2617
+ {
2618
+ "type": "null"
2619
+ }
2620
+ ],
2621
+ "description": "Allocate a pseudoterminal instead of pipes.",
2622
+ "examples": [
2623
+ true,
2624
+ false
2625
+ ]
2626
+ },
2627
+ "run": {
2628
+ "anyOf": [
2629
+ {
2630
+ "$ref": "#/$defs/Run"
2631
+ },
2632
+ {
2633
+ "type": "null"
2634
+ }
2635
+ ],
2636
+ "description": "Shell text or an argument vector. Mutually exclusive with run_script and steps.",
2637
+ "examples": [
2638
+ "pnpm dev",
2639
+ [
2640
+ "node",
2641
+ "server.mjs",
2642
+ "--port",
2643
+ "${{ self.port }}"
2644
+ ]
2645
+ ]
2646
+ },
2647
+ "run_script": {
2648
+ "anyOf": [
2649
+ {
2650
+ "$ref": "#/$defs/RunScript"
2651
+ },
2652
+ {
2653
+ "type": "null"
2654
+ }
2655
+ ],
2656
+ "description": "Script source and name, such as package.json#migrate or Makefile#build.",
2657
+ "examples": [
2658
+ "apps/api/package.json#dev",
2659
+ {
2660
+ "name": "fixtures",
2661
+ "source": "justfile"
2662
+ }
2663
+ ]
2664
+ },
2665
+ "steps": {
2666
+ "description": "Sequential task names or infra.setup/infra.teardown entries, always run explicitly.",
2667
+ "examples": [
2668
+ [
2669
+ "infra.teardown.database",
2670
+ "infra.setup.database",
2671
+ "migrate",
2672
+ "seed"
2673
+ ]
2674
+ ],
2675
+ "items": {
2676
+ "description": "Sequential task names or infra.setup/infra.teardown entries, always run explicitly.",
2677
+ "examples": [
2678
+ "infra.teardown.database",
2679
+ "infra.setup.database",
2680
+ "migrate",
2681
+ "seed"
2682
+ ],
2683
+ "type": "string"
2684
+ },
2685
+ "type": [
2686
+ "array",
2687
+ "null"
2688
+ ]
2689
+ },
2690
+ "timeout": {
2691
+ "anyOf": [
2692
+ {
2693
+ "$ref": "#/$defs/Templated_ConfigDuration"
2694
+ },
2695
+ {
2696
+ "type": "null"
2697
+ }
2698
+ ],
2699
+ "description": "Maximum run duration, for example 10m.",
2700
+ "examples": [
2701
+ "15s",
2702
+ "10m"
2703
+ ]
2704
+ },
2705
+ "when": {
2706
+ "anyOf": [
2707
+ {
2708
+ "$ref": "#/$defs/TaskWhen"
2709
+ },
2710
+ {
2711
+ "type": "null"
2712
+ }
2713
+ ],
2714
+ "description": "Lifecycle hook; omitted tasks run only on demand.",
2715
+ "examples": [
2716
+ "lane.create",
2717
+ "lane.start",
2718
+ "lane.stop",
2719
+ "lane.clean"
2720
+ ]
2721
+ }
2722
+ },
2723
+ "type": "object"
2724
+ },
2725
+ "TaskWhen": {
2726
+ "description": "Lifecycle event that runs a task automatically.",
2727
+ "examples": [
2728
+ "lane.create",
2729
+ "lane.start",
2730
+ "lane.stop",
2731
+ "lane.clean"
2732
+ ],
2733
+ "oneOf": [
2734
+ {
2735
+ "const": "lane.create",
2736
+ "description": "Run until the task succeeds once for this lane.",
2737
+ "examples": [
2738
+ "lane.create"
2739
+ ],
2740
+ "type": "string"
2741
+ },
2742
+ {
2743
+ "const": "lane.start",
2744
+ "description": "Run each time the lane starts.",
2745
+ "examples": [
2746
+ "lane.start"
2747
+ ],
2748
+ "type": "string"
2749
+ },
2750
+ {
2751
+ "const": "lane.stop",
2752
+ "description": "Run when the whole lane stops, on `devlanes daemon stop` and on `daemon restart`; skipped when a signal (logout, system shutdown) stops the daemon.",
2753
+ "examples": [
2754
+ "lane.stop"
2755
+ ],
2756
+ "type": "string"
2757
+ },
2758
+ {
2759
+ "const": "lane.clean",
2760
+ "description": "Run during lane cleanup before infrastructure teardown.",
2761
+ "examples": [
2762
+ "lane.clean"
2763
+ ],
2764
+ "type": "string"
2765
+ }
2766
+ ]
2767
+ },
2768
+ "TcpReady": {
2769
+ "anyOf": [
2770
+ {
2771
+ "description": "Set true to probe the unit's primary port; false is invalid.",
2772
+ "examples": [
2773
+ true
2774
+ ],
2775
+ "type": "boolean"
2776
+ },
2777
+ {
2778
+ "description": "Probe a named extra port instead of the primary port.",
2779
+ "examples": [
2780
+ "inspector"
2781
+ ],
2782
+ "type": "string"
2783
+ }
2784
+ ],
2785
+ "description": "TCP port to probe for readiness.",
2786
+ "examples": [
2787
+ true,
2788
+ "inspector"
2789
+ ]
2790
+ },
2791
+ "Templated_ConfigDuration": {
2792
+ "anyOf": [
2793
+ {
2794
+ "$ref": "#/$defs/ConfigDuration",
2795
+ "description": "Literal value used without expression evaluation."
2796
+ },
2797
+ {
2798
+ "description": "Text containing `${{ ... }}`, evaluated for each lane; write `${{ '${{' }}` for a literal `${{`.",
2799
+ "examples": [
2800
+ "${{ lane.index }}"
2801
+ ],
2802
+ "pattern": "\\$\\{\\{",
2803
+ "type": "string"
2804
+ }
2805
+ ],
2806
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
2807
+ "examples": [
2808
+ "${{ lane.index }}"
2809
+ ]
2810
+ },
2811
+ "Templated_Scalar": {
2812
+ "anyOf": [
2813
+ {
2814
+ "$ref": "#/$defs/Scalar",
2815
+ "description": "Literal value used without expression evaluation."
2816
+ },
2817
+ {
2818
+ "description": "Text containing `${{ ... }}`, evaluated for each lane; write `${{ '${{' }}` for a literal `${{`.",
2819
+ "examples": [
2820
+ "${{ lane.index }}"
2821
+ ],
2822
+ "pattern": "\\$\\{\\{",
2823
+ "type": "string"
2824
+ }
2825
+ ],
2826
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
2827
+ "examples": [
2828
+ "${{ lane.index }}"
2829
+ ]
2830
+ },
2831
+ "Templated_boolean": {
2832
+ "anyOf": [
2833
+ {
2834
+ "description": "Literal value used without expression evaluation.",
2835
+ "type": "boolean"
2836
+ },
2837
+ {
2838
+ "description": "Text containing `${{ ... }}`, evaluated for each lane; write `${{ '${{' }}` for a literal `${{`.",
2839
+ "examples": [
2840
+ "${{ lane.index }}"
2841
+ ],
2842
+ "pattern": "\\$\\{\\{",
2843
+ "type": "string"
2844
+ }
2845
+ ],
2846
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
2847
+ "examples": [
2848
+ "${{ lane.index }}"
2849
+ ]
2850
+ },
2851
+ "Templated_string": {
2852
+ "anyOf": [
2853
+ {
2854
+ "description": "Literal value used without expression evaluation.",
2855
+ "type": "string"
2856
+ },
2857
+ {
2858
+ "description": "Text containing `${{ ... }}`, evaluated for each lane; write `${{ '${{' }}` for a literal `${{`.",
2859
+ "examples": [
2860
+ "${{ lane.index }}"
2861
+ ],
2862
+ "pattern": "\\$\\{\\{",
2863
+ "type": "string"
2864
+ }
2865
+ ],
2866
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
2867
+ "examples": [
2868
+ "${{ lane.index }}"
2869
+ ]
2870
+ },
2871
+ "Templated_uint16": {
2872
+ "anyOf": [
2873
+ {
2874
+ "description": "Literal value used without expression evaluation.",
2875
+ "format": "uint16",
2876
+ "maximum": 65535,
2877
+ "minimum": 0,
2878
+ "type": "integer"
2879
+ },
2880
+ {
2881
+ "description": "Text containing `${{ ... }}`, evaluated for each lane; write `${{ '${{' }}` for a literal `${{`.",
2882
+ "examples": [
2883
+ "${{ lane.index }}"
2884
+ ],
2885
+ "pattern": "\\$\\{\\{",
2886
+ "type": "string"
2887
+ }
2888
+ ],
2889
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
2890
+ "examples": [
2891
+ "${{ lane.index }}"
2892
+ ]
2893
+ },
2894
+ "Templated_uint32": {
2895
+ "anyOf": [
2896
+ {
2897
+ "description": "Literal value used without expression evaluation.",
2898
+ "format": "uint32",
2899
+ "minimum": 0,
2900
+ "type": "integer"
2901
+ },
2902
+ {
2903
+ "description": "Text containing `${{ ... }}`, evaluated for each lane; write `${{ '${{' }}` for a literal `${{`.",
2904
+ "examples": [
2905
+ "${{ lane.index }}"
2906
+ ],
2907
+ "pattern": "\\$\\{\\{",
2908
+ "type": "string"
2909
+ }
2910
+ ],
2911
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
2912
+ "examples": [
2913
+ "${{ lane.index }}"
2914
+ ]
2915
+ }
2916
+ },
2917
+ "$id": "https://devlanes.run/v1/schema.json",
2918
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
2919
+ "additionalProperties": false,
2920
+ "description": "Fully merged project configuration. Map order is declaration order.",
2921
+ "examples": [
2922
+ {
2923
+ "project": "acme",
2924
+ "services": {
2925
+ "api": {
2926
+ "run_script": "apps/api/package.json#dev"
2927
+ }
2928
+ }
2929
+ }
2930
+ ],
2931
+ "properties": {
2932
+ "fnox": {
2933
+ "anyOf": [
2934
+ {
2935
+ "$ref": "#/$defs/FnoxConfig"
2936
+ },
2937
+ {
2938
+ "type": "null"
2939
+ }
2940
+ ],
2941
+ "description": "Project-wide fnox profile for secrets resolved by the runtime.",
2942
+ "examples": [
2943
+ {
2944
+ "profile": "dev"
2945
+ }
2946
+ ]
2947
+ },
2948
+ "global_env": {
2949
+ "additionalProperties": {
2950
+ "$ref": "#/$defs/Templated_Scalar",
2951
+ "description": "A literal value or a `${{ ... }}` expression, checked for the required type after evaluation.\nWrite `${{ '${{' }}` for a literal `${{`.",
2952
+ "examples": [
2953
+ "${{ lane.index }}"
2954
+ ]
2955
+ },
2956
+ "default": {},
2957
+ "description": "Environment overrides for tasks and services, after derived DEVLANES values.",
2958
+ "examples": [
2959
+ {
2960
+ "API_URL": "${{ svc.api.url }}"
2961
+ }
2962
+ ],
2963
+ "type": "object"
2964
+ },
2965
+ "infra": {
2966
+ "$ref": "#/$defs/InfraConfig",
2967
+ "default": {
2968
+ "compose": null,
2969
+ "containers": {},
2970
+ "env": {},
2971
+ "exclude": null,
2972
+ "hidden": null,
2973
+ "hosts": {},
2974
+ "per_lane": null,
2975
+ "profiles": null,
2976
+ "project_name": null,
2977
+ "setup": {},
2978
+ "teardown": {}
2979
+ },
2980
+ "description": "Shared and per-lane containers, setup commands, and teardown commands.",
2981
+ "examples": [
2982
+ {
2983
+ "compose": "docker-compose.yml",
2984
+ "hidden": [
2985
+ "postgres"
2986
+ ]
2987
+ }
2988
+ ]
2989
+ },
2990
+ "lanes": {
2991
+ "$ref": "#/$defs/LanesConfig",
2992
+ "default": {
2993
+ "block_size": null,
2994
+ "hosts_file": null,
2995
+ "matrix": null,
2996
+ "max": null,
2997
+ "new_worktrees": null,
2998
+ "primary": null,
2999
+ "removed_worktrees": null,
3000
+ "vars": {},
3001
+ "worktree_dir": null
3002
+ },
3003
+ "description": "Worktree registration, per-lane variables, and port-block policy.",
3004
+ "examples": [
3005
+ {
3006
+ "hosts_file": "always",
3007
+ "primary": "main",
3008
+ "vars": {
3009
+ "db_name": "acme_${{ lane.name }}"
3010
+ }
3011
+ }
3012
+ ]
3013
+ },
3014
+ "profiles": {
3015
+ "additionalProperties": {
3016
+ "$ref": "#/$defs/ProfileConfig",
3017
+ "description": "Named service selection with optional environment, infrastructure, and script overrides.",
3018
+ "examples": [
3019
+ [
3020
+ "+api",
3021
+ "+web"
3022
+ ],
3023
+ {
3024
+ "include": [
3025
+ "+web"
3026
+ ],
3027
+ "infra": false
3028
+ }
3029
+ ]
3030
+ },
3031
+ "default": {},
3032
+ "description": "Named service selectors with optional environment and infrastructure overrides.",
3033
+ "examples": [
3034
+ {
3035
+ "default": [
3036
+ "+api",
3037
+ "+web"
3038
+ ],
3039
+ "e2e": {
3040
+ "include": [
3041
+ "*"
3042
+ ],
3043
+ "run_scripts": {
3044
+ "dev": "start"
3045
+ }
3046
+ }
3047
+ }
3048
+ ],
3049
+ "type": "object"
3050
+ },
3051
+ "project": {
3052
+ "description": "Project identity shared by every worktree; lowercase letters, digits, dots, underscores, and dashes.",
3053
+ "examples": [
3054
+ "acme"
3055
+ ],
3056
+ "type": "string"
3057
+ },
3058
+ "services": {
3059
+ "additionalProperties": {
3060
+ "$ref": "#/$defs/ServiceConfig",
3061
+ "description": "Service settings after typed local and template merging.",
3062
+ "examples": [
3063
+ {
3064
+ "hosts": [
3065
+ "api.${{ lane.domain }}"
3066
+ ],
3067
+ "run_script": "apps/api/package.json#dev",
3068
+ "tags": [
3069
+ "api"
3070
+ ]
3071
+ }
3072
+ ]
3073
+ },
3074
+ "default": {},
3075
+ "description": "Long-running processes started together after infrastructure and before-service tasks.",
3076
+ "examples": [
3077
+ {
3078
+ "api": {
3079
+ "hosts": [
3080
+ "api.${{ lane.domain }}"
3081
+ ],
3082
+ "run_script": "apps/api/package.json#dev"
3083
+ }
3084
+ }
3085
+ ],
3086
+ "type": "object"
3087
+ },
3088
+ "tags": {
3089
+ "additionalProperties": {
3090
+ "$ref": "#/$defs/TagConfig",
3091
+ "description": "Optional display overrides for a tag; services may also use undeclared tags.",
3092
+ "examples": [
3093
+ {
3094
+ "color": "cyan",
3095
+ "description": "HTTP APIs"
3096
+ }
3097
+ ]
3098
+ },
3099
+ "default": {},
3100
+ "description": "Tag settings. Units are colored by their first tag; colors are inferred from common tag names (api, web, worker, db, ...) when not set here.",
3101
+ "examples": [
3102
+ {
3103
+ "api": {
3104
+ "color": "cyan",
3105
+ "description": "HTTP APIs"
3106
+ }
3107
+ }
3108
+ ],
3109
+ "type": "object"
3110
+ },
3111
+ "tasks": {
3112
+ "additionalProperties": {
3113
+ "$ref": "#/$defs/TaskConfig",
3114
+ "description": "One-shot command, script, or named steps, run on demand or from a lifecycle hook.",
3115
+ "examples": [
3116
+ {
3117
+ "run_script": "apps/api/package.json#migrate",
3118
+ "when": "lane.start"
3119
+ }
3120
+ ]
3121
+ },
3122
+ "default": {},
3123
+ "description": "One-shot commands; lifecycle hooks execute in declaration order.",
3124
+ "examples": [
3125
+ {
3126
+ "migrate": {
3127
+ "run_script": "apps/api/package.json#migrate",
3128
+ "when": "lane.start"
3129
+ }
3130
+ }
3131
+ ],
3132
+ "type": "object"
3133
+ },
3134
+ "templates": {
3135
+ "additionalProperties": {
3136
+ "$ref": "#/$defs/ServiceConfig",
3137
+ "description": "Service settings after typed local and template merging.",
3138
+ "examples": [
3139
+ {
3140
+ "hosts": [
3141
+ "api.${{ lane.domain }}"
3142
+ ],
3143
+ "run_script": "apps/api/package.json#dev",
3144
+ "tags": [
3145
+ "api"
3146
+ ]
3147
+ }
3148
+ ]
3149
+ },
3150
+ "default": {},
3151
+ "description": "Reusable service settings, inherited with extends after local overrides are merged.",
3152
+ "examples": [
3153
+ {
3154
+ "fastify-api": {
3155
+ "platform": "node",
3156
+ "ready": {
3157
+ "http": {
3158
+ "path": "/-/health"
3159
+ }
3160
+ },
3161
+ "tags": [
3162
+ "api"
3163
+ ]
3164
+ }
3165
+ }
3166
+ ],
3167
+ "type": "object"
3168
+ }
3169
+ },
3170
+ "title": "devlanes",
3171
+ "type": "object"
3172
+ }