@intentius/chant-lexicon-gitlab 0.0.4 → 0.0.8

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.
@@ -28,20 +28,7 @@ npm install --save-dev @intentius/chant-lexicon-gitlab
28
28
 
29
29
  ## Quick Start
30
30
 
31
- \`\`\`typescript
32
- import { Job, Image, Cache, Artifacts, CI } from "@intentius/chant-lexicon-gitlab";
33
-
34
- export const test = new Job({
35
- stage: "test",
36
- image: new Image({ name: "node:20" }),
37
- cache: new Cache({ key: CI.CommitRef, paths: ["node_modules/"] }),
38
- script: ["npm ci", "npm test"],
39
- artifacts: new Artifacts({
40
- paths: ["coverage/"],
41
- expireIn: "1 week",
42
- }),
43
- });
44
- \`\`\`
31
+ {{file:docs-snippets/src/quickstart.ts}}
45
32
 
46
33
  The lexicon provides **3 resources** (Job, Workflow, Default), **13 property types** (Image, Cache, Artifacts, Rule, Environment, Trigger, and more), the \`CI\` pseudo-parameter object for predefined variables, and the \`reference()\` intrinsic for YAML \`!reference\` tags.
47
34
  `;
@@ -71,8 +58,7 @@ The generated file includes:
71
58
  | Chant (TypeScript) | YAML output | Rule |
72
59
  |--------------------|-------------|------|
73
60
  | \`export const buildApp = new Job({...})\` | \`build-app:\` | Export name → kebab-case job key |
74
- | \`expireIn: "1 week"\` | \`expire_in: 1 week\` | camelCase snake_case |
75
- | \`ifCondition: ...\` | \`if: ...\` | Reserved word properties use suffixed names |
61
+ | \`expire_in: "1 week"\` | \`expire_in: 1 week\` | Property names use spec-native snake_case |
76
62
  | \`new Image({ name: "node:20" })\` | \`image: node:20\` | Single-property objects are collapsed |
77
63
 
78
64
  ## Validating locally
@@ -113,6 +99,7 @@ export async function generateDocs(opts?: { verbose?: boolean }): Promise<void>
113
99
  outputFormat,
114
100
  serviceFromType,
115
101
  suppressPages: ["intrinsics", "rules"],
102
+ examplesDir: join(pkgDir, "examples"),
116
103
  extraPages: [
117
104
  {
118
105
  slug: "pipeline-concepts",
@@ -120,19 +107,12 @@ export async function generateDocs(opts?: { verbose?: boolean }): Promise<void>
120
107
  description: "Jobs, stages, artifacts, caching, images, rules, environments, and triggers in the GitLab CI/CD lexicon",
121
108
  content: `Every exported \`Job\` declaration becomes a job entry in the generated \`.gitlab-ci.yml\`. The serializer handles the translation automatically:
122
109
 
123
- - Converts camelCase property names to snake_case (\`expireIn\` \`expire_in\`)
110
+ - Property names use spec-native snake_case (\`expire_in\`, \`allow_failure\`)
124
111
  - Converts export names to kebab-case job keys (\`buildApp\` → \`build-app\`)
125
112
  - Collects stages from all jobs into a \`stages:\` list
126
113
  - Collapses single-property objects (\`new Image({ name: "node:20" })\` → \`image: node:20\`)
127
114
 
128
- \`\`\`typescript
129
- // This chant declaration...
130
- export const buildApp = new Job({
131
- stage: "build",
132
- image: new Image({ name: "node:20" }),
133
- script: ["npm ci", "npm run build"],
134
- });
135
- \`\`\`
115
+ {{file:docs-snippets/src/job-basic.ts}}
136
116
 
137
117
  Produces this YAML:
138
118
 
@@ -177,47 +157,17 @@ The lexicon provides 3 resource types and 13 property types:
177
157
  | \`Release\` | Job | GitLab Release creation |
178
158
  | \`AutoCancel\` | Workflow | Pipeline auto-cancellation settings |
179
159
 
180
- ## The barrel file
181
-
182
- Every chant project has a barrel file (conventionally \`_.ts\`) that re-exports the lexicon:
183
-
184
- \`\`\`typescript
185
- // _.ts — the barrel file
186
- export * from "@intentius/chant-lexicon-gitlab";
187
- export * from "./config";
188
- \`\`\`
160
+ ## Shared config
189
161
 
190
- Other files import the barrel and use its exports:
162
+ Extract reusable objects into a shared config file and import them across your pipeline files:
191
163
 
192
- \`\`\`typescript
193
- // pipeline.ts
194
- import * as _ from "./_";
195
-
196
- export const build = new _.Job({
197
- stage: "build",
198
- image: _.nodeImage, // from config.ts via barrel
199
- cache: _.npmCache, // from config.ts via barrel
200
- script: ["npm ci", "npm run build"],
201
- artifacts: _.buildArtifacts,
202
- });
203
- \`\`\`
164
+ {{file:docs-snippets/src/pipeline-barrel.ts}}
204
165
 
205
166
  ## Jobs
206
167
 
207
168
  A \`Job\` is the fundamental unit. Every exported \`Job\` becomes a job entry in the YAML:
208
169
 
209
- \`\`\`typescript
210
- export const test = new Job({
211
- stage: "test",
212
- image: new Image({ name: "node:20-alpine" }),
213
- script: ["npm ci", "npm test"],
214
- artifacts: new Artifacts({
215
- paths: ["coverage/"],
216
- expireIn: "1 week",
217
- reports: { junit: "coverage/junit.xml" },
218
- }),
219
- });
220
- \`\`\`
170
+ {{file:docs-snippets/src/job-test.ts}}
221
171
 
222
172
  Key properties:
223
173
  - \`script\` — **required** (or \`trigger\`/\`run\`). Array of shell commands to execute.
@@ -229,12 +179,7 @@ Key properties:
229
179
 
230
180
  Stages define the execution order of a pipeline. The serializer automatically collects unique stage values from all jobs:
231
181
 
232
- \`\`\`typescript
233
- export const lint = new Job({ stage: "test", script: ["npm run lint"] });
234
- export const test = new Job({ stage: "test", script: ["npm test"] });
235
- export const build = new Job({ stage: "build", script: ["npm run build"] });
236
- export const deploy = new Job({ stage: "deploy", script: ["npm run deploy"] });
237
- \`\`\`
182
+ {{file:docs-snippets/src/stages.ts}}
238
183
 
239
184
  Produces:
240
185
 
@@ -249,30 +194,9 @@ Jobs in the same stage run in parallel. Stages run sequentially in declaration o
249
194
 
250
195
  ## Artifacts and caching
251
196
 
252
- **Artifacts** are files produced by a job and passed to later stages or stored for download:
197
+ **Artifacts** are files produced by a job and passed to later stages or stored for download. **Caches** persist files between pipeline runs to speed up builds. Both are shown in the shared config:
253
198
 
254
- \`\`\`typescript
255
- export const buildArtifacts = new Artifacts({
256
- paths: ["dist/"],
257
- expireIn: "1 hour", // always set expiry (WGL004 warns if missing)
258
- });
259
-
260
- export const testArtifacts = new Artifacts({
261
- paths: ["coverage/"],
262
- expireIn: "1 week",
263
- reports: { junit: "coverage/junit.xml" }, // parsed by GitLab for MR display
264
- });
265
- \`\`\`
266
-
267
- **Caches** persist files between pipeline runs to speed up builds:
268
-
269
- \`\`\`typescript
270
- export const npmCache = new Cache({
271
- key: "$CI_COMMIT_REF_SLUG", // cache per branch
272
- paths: ["node_modules/"],
273
- policy: "pull-push", // "pull" for read-only, "push" for write-only
274
- });
275
- \`\`\`
199
+ {{file:docs-snippets/src/config.ts:4-22}}
276
200
 
277
201
  The key difference: artifacts are for passing files between **stages in the same pipeline**; caches are for speeding up **repeated pipeline runs**.
278
202
 
@@ -280,22 +204,7 @@ The key difference: artifacts are for passing files between **stages in the same
280
204
 
281
205
  \`Rule\` objects control when a job runs. They map to \`rules:\` entries in the YAML:
282
206
 
283
- \`\`\`typescript
284
- export const onMergeRequest = new Rule({
285
- ifCondition: CI.MergeRequestIid, // → if: $CI_MERGE_REQUEST_IID
286
- });
287
-
288
- export const onDefaultBranch = new Rule({
289
- ifCondition: \`\${CI.CommitBranch} == \${CI.DefaultBranch}\`,
290
- when: "manual", // require manual trigger
291
- });
292
-
293
- export const deploy = new Job({
294
- stage: "deploy",
295
- script: ["npm run deploy"],
296
- rules: [onDefaultBranch],
297
- });
298
- \`\`\`
207
+ {{file:docs-snippets/src/rules-conditions.ts}}
299
208
 
300
209
  Produces:
301
210
 
@@ -315,19 +224,7 @@ The \`ifCondition\` property maps to \`if:\` in the YAML (since \`if\` is a rese
315
224
 
316
225
  \`Environment\` defines a deployment target:
317
226
 
318
- \`\`\`typescript
319
- export const productionEnv = new Environment({
320
- name: "production",
321
- url: "https://example.com",
322
- });
323
-
324
- export const deploy = new Job({
325
- stage: "deploy",
326
- script: ["npm run deploy"],
327
- environment: productionEnv,
328
- rules: [onDefaultBranch],
329
- });
330
- \`\`\`
227
+ {{file:docs-snippets/src/environment.ts}}
331
228
 
332
229
  GitLab tracks deployments to environments and provides rollback capabilities in the UI.
333
230
 
@@ -335,44 +232,19 @@ GitLab tracks deployments to environments and provides rollback capabilities in
335
232
 
336
233
  \`Image\` specifies the Docker image for a job:
337
234
 
338
- \`\`\`typescript
339
- export const nodeImage = new Image({ name: "node:20-alpine" });
340
-
341
- // With entrypoint override
342
- export const customImage = new Image({
343
- name: "registry.example.com/my-image:latest",
344
- entrypoint: ["/bin/sh", "-c"],
345
- });
346
- \`\`\`
235
+ {{file:docs-snippets/src/images.ts}}
347
236
 
348
237
  ## Workflow
349
238
 
350
239
  \`Workflow\` controls pipeline-level settings — when pipelines run, auto-cancellation, and global includes:
351
240
 
352
- \`\`\`typescript
353
- export const workflow = new Workflow({
354
- name: "CI Pipeline for $CI_COMMIT_REF_NAME",
355
- rules: [
356
- new Rule({ ifCondition: CI.MergeRequestIid }),
357
- new Rule({ ifCondition: CI.CommitBranch }),
358
- ],
359
- autoCancel: new AutoCancel({
360
- onNewCommit: "interruptible",
361
- }),
362
- });
363
- \`\`\`
241
+ {{file:docs-snippets/src/workflow.ts}}
364
242
 
365
243
  ## Default
366
244
 
367
245
  \`Default\` sets shared configuration inherited by all jobs:
368
246
 
369
- \`\`\`typescript
370
- export const defaults = new Default({
371
- image: new Image({ name: "node:20-alpine" }),
372
- cache: new Cache({ key: CI.CommitRef, paths: ["node_modules/"] }),
373
- retry: new Retry({ max: 2, when: ["runner_system_failure"] }),
374
- });
375
- \`\`\`
247
+ {{file:docs-snippets/src/defaults.ts}}
376
248
 
377
249
  Jobs can override any default property individually.
378
250
 
@@ -380,16 +252,7 @@ Jobs can override any default property individually.
380
252
 
381
253
  \`Trigger\` creates downstream pipeline jobs:
382
254
 
383
- \`\`\`typescript
384
- export const deployInfra = new Job({
385
- stage: "deploy",
386
- trigger: new Trigger({
387
- project: "my-group/infra-repo",
388
- branch: "main",
389
- strategy: "depend",
390
- }),
391
- });
392
- \`\`\``,
255
+ {{file:docs-snippets/src/trigger.ts}}`,
393
256
  },
394
257
  {
395
258
  slug: "variables",
@@ -397,25 +260,7 @@ export const deployInfra = new Job({
397
260
  description: "GitLab CI/CD predefined variable references",
398
261
  content: `The \`CI\` object provides type-safe access to GitLab CI/CD predefined variables. These map to \`$CI_*\` environment variables at runtime.
399
262
 
400
- \`\`\`typescript
401
- import { CI, Job, Rule } from "@intentius/chant-lexicon-gitlab";
402
-
403
- // Use in rule conditions
404
- const onDefault = new Rule({
405
- ifCondition: \`\${CI.CommitBranch} == \${CI.DefaultBranch}\`,
406
- });
407
-
408
- // Use in cache keys
409
- const cache = new Cache({
410
- key: CI.CommitRef, // → $CI_COMMIT_REF_NAME
411
- paths: ["node_modules/"],
412
- });
413
-
414
- // Use in workflow names
415
- const workflow = new Workflow({
416
- name: \`Pipeline for \${CI.CommitRef}\`,
417
- });
418
- \`\`\`
263
+ {{file:docs-snippets/src/variables-usage.ts}}
419
264
 
420
265
  ## Variable reference
421
266
 
@@ -442,44 +287,7 @@ const workflow = new Workflow({
442
287
 
443
288
  ## Common patterns
444
289
 
445
- **Conditional on branch type:**
446
-
447
- \`\`\`typescript
448
- // Only on merge requests
449
- new Rule({ ifCondition: CI.MergeRequestIid })
450
-
451
- // Only on default branch
452
- new Rule({ ifCondition: \`\${CI.CommitBranch} == \${CI.DefaultBranch}\` })
453
-
454
- // Only on tags
455
- new Rule({ ifCondition: CI.CommitTag })
456
- \`\`\`
457
-
458
- **Dynamic naming:**
459
-
460
- \`\`\`typescript
461
- export const deploy = new Job({
462
- stage: "deploy",
463
- environment: new Environment({
464
- name: \`review/\${CI.CommitRef}\`,
465
- url: \`https://\${CI.CommitRef}.preview.example.com\`,
466
- }),
467
- script: ["deploy-preview"],
468
- });
469
- \`\`\`
470
-
471
- **Container registry:**
472
-
473
- \`\`\`typescript
474
- export const buildImage = new Job({
475
- stage: "build",
476
- image: new Image({ name: "docker:24" }),
477
- script: [
478
- \`docker build -t \${CI.RegistryImage}:\${CI.CommitSha} .\`,
479
- \`docker push \${CI.RegistryImage}:\${CI.CommitSha}\`,
480
- ],
481
- });
482
- \`\`\`
290
+ {{file:docs-snippets/src/variables-patterns.ts}}
483
291
  `,
484
292
  },
485
293
  {
@@ -488,21 +296,11 @@ export const buildImage = new Job({
488
296
  description: "GitLab CI/CD intrinsic functions and their chant syntax",
489
297
  content: `The GitLab lexicon provides one intrinsic function: \`reference()\`, which maps to GitLab's \`!reference\` YAML tag.
490
298
 
491
- \`\`\`typescript
492
- import { reference } from "@intentius/chant-lexicon-gitlab";
493
- \`\`\`
494
-
495
299
  ## \`reference()\` — reuse job properties
496
300
 
497
301
  The \`reference()\` intrinsic lets you reuse properties from other jobs or hidden keys. It produces the \`!reference\` YAML tag:
498
302
 
499
- \`\`\`typescript
500
- import { reference, Job } from "@intentius/chant-lexicon-gitlab";
501
-
502
- export const deploy = new Job({
503
- script: reference(".setup", "script"),
504
- });
505
- \`\`\`
303
+ {{file:docs-snippets/src/reference-basic.ts}}
506
304
 
507
305
  Serializes to:
508
306
 
@@ -522,24 +320,7 @@ reference(jobName: string, property: string): ReferenceTag
522
320
 
523
321
  ### Use cases
524
322
 
525
- **Shared setup scripts:**
526
-
527
- \`\`\`typescript
528
- // Hidden key with shared setup (defined in .gitlab-ci.yml or included)
529
- // Reference its script from multiple jobs:
530
-
531
- export const test = new Job({
532
- stage: "test",
533
- beforeScript: reference(".node-setup", "before_script"),
534
- script: ["npm test"],
535
- });
536
-
537
- export const lint = new Job({
538
- stage: "test",
539
- beforeScript: reference(".node-setup", "before_script"),
540
- script: ["npm run lint"],
541
- });
542
- \`\`\`
323
+ {{file:docs-snippets/src/reference-shared.ts}}
543
324
 
544
325
  Produces:
545
326
 
@@ -557,46 +338,9 @@ lint:
557
338
  - npm run lint
558
339
  \`\`\`
559
340
 
560
- **Shared rules:**
561
-
562
- \`\`\`typescript
563
- export const build = new Job({
564
- stage: "build",
565
- rules: reference(".default-rules", "rules"),
566
- script: ["npm run build"],
567
- });
568
- \`\`\`
569
-
570
- **Nested references (multi-level):**
571
-
572
- \`\`\`typescript
573
- // Reference a specific nested element
574
- export const deploy = new Job({
575
- script: reference(".setup", "script"),
576
- environment: reference(".deploy-defaults", "environment"),
577
- });
578
- \`\`\`
579
-
580
341
  ### When to use \`reference()\` vs barrel imports
581
342
 
582
- Use **barrel imports** (\`_.$\`) when referencing chant-managed objects — the serializer resolves them at build time:
583
-
584
- \`\`\`typescript
585
- // Preferred for chant-managed config
586
- export const test = new Job({
587
- cache: _.npmCache, // resolved at build time
588
- artifacts: _.testArtifacts, // resolved at build time
589
- });
590
- \`\`\`
591
-
592
- Use **\`reference()\`** when referencing jobs or hidden keys defined outside chant (e.g. in included YAML files or templates):
593
-
594
- \`\`\`typescript
595
- // For external/included YAML definitions
596
- export const test = new Job({
597
- beforeScript: reference(".ci-setup", "before_script"),
598
- });
599
- \`\`\`
343
+ {{file:docs-snippets/src/reference-vs-barrel.ts}}
600
344
  `,
601
345
  },
602
346
  {
@@ -615,23 +359,7 @@ Lint rules analyze your TypeScript source code before build.
615
359
 
616
360
  Flags usage of \`only:\` and \`except:\` keywords, which are deprecated in favor of \`rules:\`. The \`rules:\` syntax is more flexible and is the recommended approach.
617
361
 
618
- \`\`\`typescript
619
- // Triggers WGL001
620
- export const deploy = new Job({
621
- stage: "deploy",
622
- script: ["npm run deploy"],
623
- only: ["main"], // deprecated
624
- });
625
-
626
- // Fixed — use rules instead
627
- export const deploy = new Job({
628
- stage: "deploy",
629
- script: ["npm run deploy"],
630
- rules: [new Rule({
631
- ifCondition: \`\${CI.CommitBranch} == \${CI.DefaultBranch}\`,
632
- })],
633
- });
634
- \`\`\`
362
+ {{file:docs-snippets/src/lint-wgl001.ts}}
635
363
 
636
364
  ### WGL002 — Missing script
637
365
 
@@ -639,26 +367,7 @@ export const deploy = new Job({
639
367
 
640
368
  A GitLab CI job must have \`script\`, \`trigger\`, or \`run\` defined. Jobs without any of these will fail pipeline validation.
641
369
 
642
- \`\`\`typescript
643
- // Triggers WGL002
644
- export const build = new Job({
645
- stage: "build",
646
- image: new Image({ name: "node:20" }),
647
- // Missing script!
648
- });
649
-
650
- // Fixed — add script
651
- export const build = new Job({
652
- stage: "build",
653
- image: new Image({ name: "node:20" }),
654
- script: ["npm run build"],
655
- });
656
-
657
- // Also valid — trigger job (no script needed)
658
- export const downstream = new Job({
659
- trigger: new Trigger({ project: "my-group/other-repo" }),
660
- });
661
- \`\`\`
370
+ {{file:docs-snippets/src/lint-wgl002.ts}}
662
371
 
663
372
  ### WGL003 — Missing stage
664
373
 
@@ -666,19 +375,7 @@ export const downstream = new Job({
666
375
 
667
376
  Jobs should declare a \`stage\` property. Without it, the job defaults to the \`test\` stage, which may not be the intended behavior.
668
377
 
669
- \`\`\`typescript
670
- // Triggers WGL003
671
- export const build = new Job({
672
- script: ["npm run build"],
673
- // No stage — defaults to "test"
674
- });
675
-
676
- // Fixed — declare the stage
677
- export const build = new Job({
678
- stage: "build",
679
- script: ["npm run build"],
680
- });
681
- \`\`\`
378
+ {{file:docs-snippets/src/lint-wgl003.ts}}
682
379
 
683
380
  ### WGL004 — Artifacts without expiry
684
381
 
@@ -686,25 +383,7 @@ export const build = new Job({
686
383
 
687
384
  Flags \`Artifacts\` without \`expireIn\`. Artifacts without expiry are kept indefinitely, consuming storage. Always set an expiration.
688
385
 
689
- \`\`\`typescript
690
- // Triggers WGL004
691
- export const build = new Job({
692
- script: ["npm run build"],
693
- artifacts: new Artifacts({
694
- paths: ["dist/"],
695
- // Missing expireIn!
696
- }),
697
- });
698
-
699
- // Fixed — set expiry
700
- export const build = new Job({
701
- script: ["npm run build"],
702
- artifacts: new Artifacts({
703
- paths: ["dist/"],
704
- expireIn: "1 hour",
705
- }),
706
- });
707
- \`\`\`
386
+ {{file:docs-snippets/src/lint-wgl004.ts}}
708
387
 
709
388
  ## Post-synth checks
710
389
 
@@ -722,16 +401,7 @@ Flags jobs that reference a stage not present in the collected stages list. This
722
401
 
723
402
  Flags jobs where all \`rules:\` entries have \`when: "never"\`, making the job unreachable. This usually indicates a configuration error.
724
403
 
725
- \`\`\`typescript
726
- // Triggers WGL011 — job can never run
727
- export const noop = new Job({
728
- script: ["echo unreachable"],
729
- rules: [
730
- new Rule({ ifCondition: CI.CommitBranch, when: "never" }),
731
- new Rule({ ifCondition: CI.CommitTag, when: "never" }),
732
- ],
733
- });
734
- \`\`\`
404
+ {{file:docs-snippets/src/lint-wgl011.ts}}
735
405
 
736
406
  ## Running lint
737
407
 
@@ -756,7 +426,7 @@ To suppress globally in \`chant.config.ts\`:
756
426
  export default {
757
427
  lint: {
758
428
  rules: {
759
- WGL003: "off", // don't require stage on every job
429
+ WGL003: "off",
760
430
  },
761
431
  },
762
432
  };
@@ -783,100 +453,21 @@ bun test # runs the example's tests
783
453
 
784
454
  \`\`\`
785
455
  src/
786
- ├── _.ts # Barrel — re-exports lexicon + shared config
787
456
  ├── config.ts # Shared config: images, caches, artifacts, rules, environments
788
457
  └── pipeline.ts # Job definitions: build, test, deploy
789
458
  \`\`\`
790
459
 
791
- ### Barrel file
792
-
793
- The barrel re-exports both the lexicon and shared config, so pipeline files only need one import:
794
-
795
- \`\`\`typescript
796
- // _.ts
797
- export * from "@intentius/chant-lexicon-gitlab";
798
- export * from "./config";
799
- \`\`\`
800
-
801
460
  ### Shared configuration
802
461
 
803
462
  \`config.ts\` extracts reusable objects — images, caches, artifacts, rules, and environments — so jobs stay concise:
804
463
 
805
- \`\`\`typescript
806
- // config.ts
807
- import * as _ from "./_";
808
-
809
- export const nodeImage = new _.Image({ name: "node:20-alpine" });
810
-
811
- export const npmCache = new _.Cache({
812
- key: "$CI_COMMIT_REF_SLUG",
813
- paths: ["node_modules/"],
814
- policy: "pull-push",
815
- });
816
-
817
- export const buildArtifacts = new _.Artifacts({
818
- paths: ["dist/"],
819
- expireIn: "1 hour",
820
- });
821
-
822
- export const testArtifacts = new _.Artifacts({
823
- paths: ["coverage/"],
824
- expireIn: "1 week",
825
- reports: { junit: "coverage/junit.xml" },
826
- });
827
-
828
- export const onMergeRequest = new _.Rule({
829
- ifCondition: _.CI.MergeRequestIid,
830
- });
831
-
832
- export const onCommit = new _.Rule({
833
- ifCondition: _.CI.CommitBranch,
834
- });
835
-
836
- export const onDefaultBranch = new _.Rule({
837
- ifCondition: \`\${_.CI.CommitBranch} == \${_.CI.DefaultBranch}\`,
838
- when: "manual",
839
- });
840
-
841
- export const productionEnv = new _.Environment({
842
- name: "production",
843
- url: "https://example.com",
844
- });
845
- \`\`\`
464
+ {{file:getting-started/src/config.ts}}
846
465
 
847
466
  ### Pipeline jobs
848
467
 
849
- \`pipeline.ts\` defines three jobs that reference shared config via the barrel:
468
+ \`pipeline.ts\` defines three jobs that import shared config directly:
850
469
 
851
- \`\`\`typescript
852
- // pipeline.ts
853
- import * as _ from "./_";
854
-
855
- export const build = new _.Job({
856
- stage: "build",
857
- image: _.nodeImage,
858
- cache: _.npmCache,
859
- script: ["npm ci", "npm run build"],
860
- artifacts: _.buildArtifacts,
861
- });
862
-
863
- export const test = new _.Job({
864
- stage: "test",
865
- image: _.nodeImage,
866
- cache: _.npmCache,
867
- script: ["npm ci", "npm test"],
868
- artifacts: _.testArtifacts,
869
- rules: [_.onMergeRequest, _.onCommit],
870
- });
871
-
872
- export const deploy = new _.Job({
873
- stage: "deploy",
874
- image: _.nodeImage,
875
- script: ["npm run deploy"],
876
- environment: _.productionEnv,
877
- rules: [_.onDefaultBranch],
878
- });
879
- \`\`\`
470
+ {{file:getting-started/src/pipeline.ts}}
880
471
 
881
472
  ### Generated output
882
473
 
@@ -947,6 +538,61 @@ deploy:
947
538
  5. **JUnit reports** — test artifacts include JUnit XML for GitLab MR display
948
539
  `,
949
540
  },
541
+ {
542
+ slug: "skills",
543
+ title: "AI Skills",
544
+ description: "AI agent skills bundled with the GitLab CI/CD lexicon",
545
+ content: `The GitLab lexicon ships an AI skill called **chant-gitlab** that teaches AI coding agents (like Claude Code) how to build, validate, and deploy GitLab CI pipelines from a chant project.
546
+
547
+ ## What are skills?
548
+
549
+ Skills are structured markdown documents bundled with a lexicon. When an AI agent works in a chant project, it discovers and loads relevant skills automatically — giving it operational knowledge about the deployment workflow without requiring the user to explain each step.
550
+
551
+ ## Installation
552
+
553
+ When you scaffold a new project with \`chant init --lexicon gitlab\`, the skill is installed to \`.claude/skills/chant-gitlab/SKILL.md\` for automatic discovery by Claude Code.
554
+
555
+ For existing projects, create the file manually:
556
+
557
+ \`\`\`
558
+ .claude/
559
+ skills/
560
+ chant-gitlab/
561
+ SKILL.md # skill content (see below)
562
+ \`\`\`
563
+
564
+ ## Skill: chant-gitlab
565
+
566
+ The \`chant-gitlab\` skill covers the full deployment lifecycle:
567
+
568
+ - **Build** — \`chant build src/ --output .gitlab-ci.yml\`
569
+ - **Validate** — \`chant lint src/\` + GitLab CI Lint API
570
+ - **Deploy** — commit and push the generated YAML
571
+ - **Status** — GitLab UI or pipelines API
572
+ - **Retry** — retry failed jobs via UI or API
573
+ - **Cancel** — cancel running pipelines via API
574
+ - **Troubleshooting** — job logs, lint rule codes (WGL001–WGL004), post-synth checks (WGL010, WGL011)
575
+
576
+ The skill is invocable as a slash command: \`/chant-gitlab\`
577
+
578
+ ## MCP integration
579
+
580
+ The lexicon also provides MCP (Model Context Protocol) tools and resources that AI agents can use programmatically:
581
+
582
+ | MCP tool | Description |
583
+ |----------|-------------|
584
+ | \`build\` | Build the chant project |
585
+ | \`lint\` | Run lint rules |
586
+ | \`explain\` | Summarize project resources |
587
+ | \`scaffold\` | Generate starter files |
588
+ | \`search\` | Search available resource types |
589
+ | \`gitlab:diff\` | Compare current build output against previous |
590
+
591
+ | MCP resource | Description |
592
+ |--------------|-------------|
593
+ | \`resource-catalog\` | JSON list of all supported GitLab CI entity types |
594
+ | \`examples/basic-pipeline\` | Example pipeline with build, test, and deploy jobs |`,
595
+ },
950
596
  ],
951
597
  basePath: "/chant/lexicons/gitlab/",
952
598
  };