@udondan/avanti 0.13.0 → 0.15.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/README.md +303 -265
- package/dist/commands/diff.d.ts.map +1 -1
- package/dist/commands/diff.js +116 -32
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/lock.js +19 -10
- package/dist/commands/lock.js.map +1 -1
- package/dist/commands/log.js +18 -9
- package/dist/commands/log.js.map +1 -1
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/pull.js +142 -36
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/reset.js +18 -9
- package/dist/commands/reset.js.map +1 -1
- package/dist/commands/revert.js +18 -9
- package/dist/commands/revert.js.map +1 -1
- package/dist/config-writeback.d.ts.map +1 -1
- package/dist/config-writeback.js +44 -18
- package/dist/config-writeback.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +96 -62
- package/dist/config.js.map +1 -1
- package/dist/diff.d.ts.map +1 -1
- package/dist/diff.js +25 -15
- package/dist/diff.js.map +1 -1
- package/dist/fetch.d.ts +0 -1
- package/dist/fetch.d.ts.map +1 -1
- package/dist/fetch.js +2 -2
- package/dist/fetch.js.map +1 -1
- package/dist/history.js +17 -7
- package/dist/history.js.map +1 -1
- package/dist/processors/json.js +2 -3
- package/dist/processors/json.js.map +1 -1
- package/dist/processors/post.d.ts.map +1 -1
- package/dist/processors/post.js +4 -3
- package/dist/processors/post.js.map +1 -1
- package/dist/processors/replace.js +1 -2
- package/dist/processors/replace.js.map +1 -1
- package/dist/processors/yaml.js +2 -3
- package/dist/processors/yaml.js.map +1 -1
- package/dist/prompt.js +18 -9
- package/dist/prompt.js.map +1 -1
- package/dist/sha.js +18 -9
- package/dist/sha.js.map +1 -1
- package/dist/shell.d.ts +6 -0
- package/dist/shell.d.ts.map +1 -0
- package/dist/shell.js +76 -0
- package/dist/shell.js.map +1 -0
- package/dist/sources/bitbucket.js +18 -9
- package/dist/sources/bitbucket.js.map +1 -1
- package/dist/sources/exec.d.ts.map +1 -1
- package/dist/sources/exec.js +4 -3
- package/dist/sources/exec.js.map +1 -1
- package/dist/sources/git.js +18 -9
- package/dist/sources/git.js.map +1 -1
- package/dist/sources/github.js +18 -9
- package/dist/sources/github.js.map +1 -1
- package/dist/sources/gitlab.js +18 -9
- package/dist/sources/gitlab.js.map +1 -1
- package/dist/sources/http.d.ts +3 -0
- package/dist/sources/http.d.ts.map +1 -1
- package/dist/sources/http.js +24 -12
- package/dist/sources/http.js.map +1 -1
- package/dist/sources/index.d.ts +4 -1
- package/dist/sources/index.d.ts.map +1 -1
- package/dist/sources/index.js +152 -31
- package/dist/sources/index.js.map +1 -1
- package/dist/sources/local.d.ts +2 -1
- package/dist/sources/local.d.ts.map +1 -1
- package/dist/sources/local.js +23 -15
- package/dist/sources/local.js.map +1 -1
- package/dist/sources/s3.js +18 -9
- package/dist/sources/s3.js.map +1 -1
- package/dist/sources/vault.js +18 -9
- package/dist/sources/vault.js.map +1 -1
- package/dist/types.d.ts +15 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/variables.d.ts.map +1 -1
- package/dist/variables.js +42 -31
- package/dist/variables.js.map +1 -1
- package/dist/writer.d.ts.map +1 -1
- package/dist/writer.js +37 -12
- package/dist/writer.js.map +1 -1
- package/package.json +10 -9
package/README.md
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
# Avanti!
|
|
2
2
|
|
|
3
|
-
A stateful package manager for arbitrary text files. Declare what you need and
|
|
3
|
+
A stateful package manager for arbitrary text files. Declare what you need and
|
|
4
|
+
where to get it; avanti fetches, diffs, and writes with full version history,
|
|
5
|
+
atomic rollbacks, and diff-before-apply safety.
|
|
6
|
+
|
|
7
|
+

|
|
4
8
|
|
|
5
9
|
## Table of Contents
|
|
6
10
|
|
|
11
|
+
- [Intro](#intro)
|
|
7
12
|
- [Features](#features)
|
|
8
13
|
- [Requirements](#requirements)
|
|
9
14
|
- [Install](#install)
|
|
@@ -24,10 +29,10 @@ A stateful package manager for arbitrary text files. Declare what you need and w
|
|
|
24
29
|
- [JSON Merging](#json-merging)
|
|
25
30
|
- [YAML Merging](#yaml-merging)
|
|
26
31
|
- [Variables](#variables)
|
|
32
|
+
- [$self — Self-managing Config](#self--self-managing-config)
|
|
27
33
|
- [Authentication](#authentication)
|
|
28
34
|
- [Private Instances](#private-instances)
|
|
29
35
|
- [Use Cases](#use-cases)
|
|
30
|
-
- [Avanti as a Package Manager](#avanti-as-a-package-manager)
|
|
31
36
|
- [Composable AI Agent Instructions (CLAUDE.md / AGENTS.md)](#composable-ai-agent-instructions-claudemd--agentsmd)
|
|
32
37
|
- [Shared Tooling Config (Renovate, ESLint, Prettier, TSConfig)](#shared-tooling-config-renovate-eslint-prettier-tsconfig)
|
|
33
38
|
- [CI/CD: Shared Workflow Fragments](#cicd-shared-workflow-fragments)
|
|
@@ -41,18 +46,61 @@ A stateful package manager for arbitrary text files. Declare what you need and w
|
|
|
41
46
|
- [Exit Codes](#exit-codes)
|
|
42
47
|
- [Development](#development)
|
|
43
48
|
|
|
49
|
+
## Intro
|
|
50
|
+
|
|
51
|
+
Avanti is a package manager for arbitrary text files. Your .avanti.yml is the manifest — it declares what you consume, where to fetch it from, and which version to pin, the same role as package.json or Cargo.toml. Source repositories are the packages. avanti pull is the install command.
|
|
52
|
+
|
|
53
|
+
What makes it stateful: every successful pull is recorded in a local history store. You can diff any two states, revert the whole project to a prior pull, or fully undo all avanti changes — the same guarantees as a lockfile, extended to any text file from any source.
|
|
54
|
+
|
|
55
|
+
**Declare dependencies** — fetch from anywhere, combine sources:
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
files:
|
|
59
|
+
# Single source: pin a config from GitHub
|
|
60
|
+
eslint.config.js:
|
|
61
|
+
src:
|
|
62
|
+
github:
|
|
63
|
+
repo: org/standards
|
|
64
|
+
file: eslint.config.js
|
|
65
|
+
ref: v2.4.1
|
|
66
|
+
|
|
67
|
+
# Multi-source: assemble from wherever the content lives
|
|
68
|
+
CLAUDE.md:
|
|
69
|
+
src:
|
|
70
|
+
- gitlab:
|
|
71
|
+
project: org/platform
|
|
72
|
+
file: ai/base-instructions.md
|
|
73
|
+
ref: main
|
|
74
|
+
- raw: |
|
|
75
|
+
IMPORTANT: Always answer in pirate speak!
|
|
76
|
+
- https://public-standards.example.com/shared-guidelines.md
|
|
77
|
+
- exec: printf "## Team\n%s" "$env:TEAM"
|
|
78
|
+
- path: ~/claude-personal.md
|
|
79
|
+
optional: true # silently skipped if absent
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Review and apply upgrades** — the same workflow as reading a lockfile diff before committing:
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
# Bump standards ref: v2.4.1 → v2.5.0, then:
|
|
86
|
+
avanti diff # see every file that would change
|
|
87
|
+
avanti pull # apply after review
|
|
88
|
+
avanti revert # roll back instantly if something breaks
|
|
89
|
+
```
|
|
90
|
+
|
|
44
91
|
## Features
|
|
45
92
|
|
|
46
93
|
- Fetch files from **HTTP/HTTPS**, **local paths**, **GitLab** (via `glab`), **GitHub** (via `gh`), **Bitbucket**, **any git remote**, **S3**, **HashiCorp Vault**, **shell commands**, or **inline raw content**
|
|
47
94
|
- **Multi-source entries** — combine multiple sources into a single file by providing `src` as a list
|
|
48
|
-
- **Atomic writes** — all files are staged to a temp dir first; targets are only written if everything succeeds
|
|
49
|
-
- **Diff preview** — see exactly what will change before applying, or compare against any past pull
|
|
50
|
-
- **Post-processing** — apply text replacements (string or regex) and/or pipe content through a shell script
|
|
51
|
-
- **Directory sync** — recursively sync directories from GitLab/GitHub/Bitbucket/git/S3/local sources
|
|
52
95
|
- **JSON merging** — deep-merge multiple JSON/JSONC sources with configurable conflict, array, and object strategies
|
|
53
96
|
- **YAML merging** — deep-merge multiple YAML/YML sources with the same strategies, with full comment preservation
|
|
54
97
|
- **Variables** — define reusable values in a `variables:` block and reference them anywhere with `$name`; use `$env:NAME` for environment variables
|
|
98
|
+
- **Post-processing** — apply text replacements (string or regex) and/or pipe content through a shell script
|
|
99
|
+
- **Directory sync** — recursively sync directories from GitLab/GitHub/Bitbucket/git/S3/local sources
|
|
100
|
+
- **Diff preview** — see exactly what will change before applying, or compare against any past pull
|
|
101
|
+
- **Atomic writes** — all files are staged to a temp dir first; targets are only written if everything succeeds
|
|
55
102
|
- **History** — every pull is recorded; inspect what changed, revert the whole project to a past state, or fully undo all avanti changes
|
|
103
|
+
- **Optional sources** — mark `path:` and `url:` sources `optional: true` to silently skip them when the file is missing or the URL returns 404; lets a central config reference per-user local overrides without erroring on machines that haven't created them
|
|
56
104
|
- **Stale file cleanup** — files dropped from a directory source are automatically deleted or restored to their pre-avanti content
|
|
57
105
|
|
|
58
106
|
## Requirements
|
|
@@ -261,49 +309,59 @@ variables:
|
|
|
261
309
|
email: you@example.com
|
|
262
310
|
|
|
263
311
|
files:
|
|
264
|
-
-
|
|
265
|
-
|
|
312
|
+
my-example.yml:
|
|
313
|
+
src: http://www.example.com/example.yml
|
|
266
314
|
replace:
|
|
267
315
|
- from: '{EMAIL}'
|
|
268
316
|
to: $email
|
|
269
317
|
- from: /\d+/
|
|
270
318
|
to: number
|
|
271
319
|
|
|
272
|
-
|
|
273
|
-
|
|
320
|
+
file.sh:
|
|
321
|
+
src: ~/some/local/file.sh
|
|
274
322
|
mode: '0777'
|
|
275
323
|
|
|
276
|
-
-
|
|
324
|
+
some-file.yml:
|
|
325
|
+
src:
|
|
277
326
|
exec: glab api "projects/group%2Fproject/repository/files/some-file.yaml/raw?ref=main"
|
|
278
|
-
target: some-file.yml
|
|
279
327
|
post: sed -e 's/v3/v4/g'
|
|
280
328
|
|
|
281
|
-
|
|
329
|
+
renovate.json:
|
|
330
|
+
src:
|
|
282
331
|
gitlab:
|
|
283
332
|
project: group/project
|
|
284
333
|
file: renovate.json
|
|
285
334
|
ref: $latest
|
|
286
|
-
# target omitted → renovate.json
|
|
287
335
|
|
|
288
|
-
-
|
|
336
|
+
local-scripts/:
|
|
337
|
+
src:
|
|
289
338
|
github:
|
|
290
339
|
repo: org/repo
|
|
291
340
|
file: scripts/
|
|
292
341
|
ref: main
|
|
293
|
-
target: local-scripts/
|
|
294
342
|
```
|
|
295
343
|
|
|
296
344
|
### File Entry Fields
|
|
297
345
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
346
|
+
The `files` key is a **map** — each key is the local target path, and the value is the entry configuration:
|
|
347
|
+
|
|
348
|
+
```yaml
|
|
349
|
+
files:
|
|
350
|
+
<target-path>:
|
|
351
|
+
src: ...
|
|
352
|
+
# optional fields below
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
End the target path with `/` to write a directory source as a mirror; omit the trailing slash to merge all files from the directory into a single output file (YAML/JSON auto-detected by extension, or forced with `yaml:`/`json:`).
|
|
356
|
+
|
|
357
|
+
| Field | Required | Description |
|
|
358
|
+
| --------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
359
|
+
| `src` | Yes | Source (see below). May be a single source or a **list** of sources to concatenate. |
|
|
360
|
+
| `mode` | No | File permission mode, e.g. `"0755"` |
|
|
361
|
+
| `replace` | No | List of `{from, to}` replacement rules. `from` may be a plain string or `/pattern/flags` regex. |
|
|
362
|
+
| `post` | No | Shell script. Content is piped via stdin; stdout is used as the result. Runs after `replace`. |
|
|
363
|
+
| `json` | No | JSON merge/format options (see below). When omitted, merging is auto-enabled if all sources have a `.json` or `.jsonc` extension. Use `true`/`false` to force on or off regardless of extension. |
|
|
364
|
+
| `yaml` | No | YAML merge/format options (see below). When omitted, merging is auto-enabled if all sources have a `.yaml` or `.yml` extension. Use `true`/`false` to force on or off regardless of extension. Comments are preserved in merged output. |
|
|
307
365
|
|
|
308
366
|
### Source Types
|
|
309
367
|
|
|
@@ -315,9 +373,19 @@ src: ~/templates/file.txt
|
|
|
315
373
|
src: /absolute/path/file.txt
|
|
316
374
|
```
|
|
317
375
|
|
|
318
|
-
**Map** — for exec, gitlab, github, bitbucket, git, s3, vault, http, raw:
|
|
376
|
+
**Map** — for path, url, exec, gitlab, github, bitbucket, git, s3, vault, http, raw:
|
|
319
377
|
|
|
320
378
|
```yaml
|
|
379
|
+
src:
|
|
380
|
+
path: ~/templates/file.txt # explicit local path; supports optional and sha
|
|
381
|
+
optional: true # silently skip if the file does not exist
|
|
382
|
+
sha: abc123...
|
|
383
|
+
|
|
384
|
+
src:
|
|
385
|
+
url: https://example.com/file.txt # explicit http/https URL; supports optional and sha
|
|
386
|
+
optional: true # silently skip if the URL returns 404
|
|
387
|
+
sha: abc123...
|
|
388
|
+
|
|
321
389
|
src:
|
|
322
390
|
exec: <shell command> # stdout becomes file content; target required
|
|
323
391
|
sha: abc123... # optional SHA-256 to verify stdout (see below)
|
|
@@ -374,89 +442,96 @@ src:
|
|
|
374
442
|
|
|
375
443
|
The optional `sha` field pins a source to a specific content fingerprint. When present, avanti verifies the SHA-256 of the raw fetched content matches before writing anything. This makes your config act as a selective lockfile — only sources you care about get pinned, and changes are surfaced explicitly rather than applied silently.
|
|
376
444
|
|
|
377
|
-
Use `avanti lock` to compute and write SHA values automatically. Use `avanti pull --accept-changes` to review a mismatch and update the pinned SHA.
|
|
445
|
+
Use `avanti lock` to compute and write SHA values automatically. Use `avanti pull --accept-changes` to review a mismatch and update the pinned SHA. Plain string sources (a bare local path or URL string) and `raw:` sources do not support `sha`. Use the explicit `path:` or `url:` map form to pin a local file or HTTP URL.
|
|
378
446
|
|
|
379
447
|
### Directory Sources
|
|
380
448
|
|
|
381
449
|
Any source type that references a path (local, GitLab, GitHub, Bitbucket, git, S3) can point to a directory instead of a single file. End the path with `/` to declare it a directory explicitly; without a trailing slash the tool probes the remote to decide.
|
|
382
450
|
|
|
383
|
-
**Directory → directory (mirror):** end
|
|
451
|
+
**Directory → directory (mirror):** end the target key with `/` and each file is written individually, preserving subdirectory structure relative to the source root:
|
|
384
452
|
|
|
385
453
|
```yaml
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
454
|
+
files:
|
|
455
|
+
# All files under skills/ in the GitLab repo are written into local skills/
|
|
456
|
+
skills/:
|
|
457
|
+
src:
|
|
458
|
+
gitlab:
|
|
459
|
+
project: group/repo
|
|
460
|
+
file: skills/
|
|
461
|
+
ref: main
|
|
462
|
+
|
|
463
|
+
# GitHub directory → local directory
|
|
464
|
+
.github/workflows/:
|
|
465
|
+
src:
|
|
466
|
+
github:
|
|
467
|
+
repo: org/repo
|
|
468
|
+
file: .github/workflows/
|
|
469
|
+
ref: main
|
|
470
|
+
|
|
471
|
+
# Bitbucket directory → local directory
|
|
472
|
+
eslint/:
|
|
473
|
+
src:
|
|
474
|
+
bitbucket:
|
|
475
|
+
workspace: my-workspace
|
|
476
|
+
repo: shared-configs
|
|
477
|
+
file: eslint/
|
|
478
|
+
ref: main
|
|
479
|
+
|
|
480
|
+
# git remote directory → local directory (any host)
|
|
481
|
+
.github/actions/:
|
|
482
|
+
src:
|
|
483
|
+
git:
|
|
484
|
+
repo: https://github.com/org/repo.git
|
|
485
|
+
file: .github/actions/
|
|
486
|
+
ref: main
|
|
487
|
+
|
|
488
|
+
# S3 prefix → local directory (trailing / triggers sync)
|
|
489
|
+
configs/:
|
|
490
|
+
src:
|
|
491
|
+
s3: s3://my-bucket/configs/
|
|
492
|
+
|
|
493
|
+
# Local directory → local directory
|
|
494
|
+
.githooks/:
|
|
495
|
+
src: ~/shared/hooks/
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
**Directory → single file (merge):** omit the trailing `/` from the target key and all files in the directory are merged into one. Files are sorted alphabetically — later names win on key conflicts. YAML/JSON merge is auto-detected from the contained file extensions, or forced with `yaml:`/`json:`:
|
|
499
|
+
|
|
500
|
+
```yaml
|
|
501
|
+
files:
|
|
502
|
+
# One folder per service, each a separate .yml file → single docker-compose.yml
|
|
503
|
+
docker-compose.yml:
|
|
504
|
+
src: ./services/
|
|
505
|
+
|
|
506
|
+
# JSON: one file per environment → merged config
|
|
507
|
+
config.json:
|
|
508
|
+
src: ./config/
|
|
427
509
|
```
|
|
428
510
|
|
|
429
|
-
|
|
511
|
+
With explicit YAML merge options (e.g. to concat arrays instead of replacing):
|
|
430
512
|
|
|
431
513
|
```yaml
|
|
432
|
-
|
|
433
|
-
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
- src: ./services/
|
|
438
|
-
target: docker-compose.yml
|
|
439
|
-
yaml:
|
|
440
|
-
arrays: concat
|
|
441
|
-
|
|
442
|
-
# JSON: one file per environment → merged config
|
|
443
|
-
- src: ./config/
|
|
444
|
-
target: config.json
|
|
514
|
+
files:
|
|
515
|
+
docker-compose.yml:
|
|
516
|
+
src: ./services/
|
|
517
|
+
yaml:
|
|
518
|
+
arrays: concat
|
|
445
519
|
```
|
|
446
520
|
|
|
447
521
|
Directory sources cannot be mixed into a multi-source list (`src` as a list), because the list mode always produces a single file.
|
|
448
522
|
|
|
449
|
-
**List** — combine multiple sources into one file (all source types supported
|
|
523
|
+
**List** — combine multiple sources into one file (all source types supported):
|
|
450
524
|
|
|
451
525
|
```yaml
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
526
|
+
files:
|
|
527
|
+
combined.txt:
|
|
528
|
+
src:
|
|
529
|
+
- https://example.com/header.txt
|
|
530
|
+
- exec: echo "# generated"
|
|
531
|
+
- gitlab:
|
|
532
|
+
project: org/repo
|
|
533
|
+
file: footer.txt
|
|
534
|
+
ref: main
|
|
460
535
|
```
|
|
461
536
|
|
|
462
537
|
Sources are fetched in order and joined with a newline. Post-processing (`replace`, `post`) is applied to the combined result. If any source fails, the entire entry is aborted.
|
|
@@ -467,20 +542,20 @@ When all sources in a list have a `.json` or `.jsonc` extension, JSON merging is
|
|
|
467
542
|
|
|
468
543
|
```yaml
|
|
469
544
|
files:
|
|
470
|
-
|
|
545
|
+
merged.jsonc:
|
|
546
|
+
src:
|
|
471
547
|
- ./team.jsonc
|
|
472
548
|
- ./my.jsonc
|
|
473
|
-
target: merged.jsonc
|
|
474
549
|
```
|
|
475
550
|
|
|
476
551
|
To merge sources that don't have a JSON extension (e.g. `exec:`, `raw:`, or a URL without `.json`), set `json: true`:
|
|
477
552
|
|
|
478
553
|
```yaml
|
|
479
554
|
files:
|
|
480
|
-
|
|
555
|
+
merged.json:
|
|
556
|
+
src:
|
|
481
557
|
- exec: cat defaults.json
|
|
482
558
|
- ./overrides.json
|
|
483
|
-
target: merged.json
|
|
484
559
|
json: true
|
|
485
560
|
```
|
|
486
561
|
|
|
@@ -490,12 +565,12 @@ To opt out of auto-detection and force plain concatenation, set `json: false`.
|
|
|
490
565
|
|
|
491
566
|
```yaml
|
|
492
567
|
files:
|
|
493
|
-
|
|
568
|
+
merged.json:
|
|
569
|
+
src:
|
|
494
570
|
- ./defaults.json
|
|
495
|
-
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
target: merged.json
|
|
571
|
+
- github:
|
|
572
|
+
repo: org/configs
|
|
573
|
+
file: overrides.json
|
|
499
574
|
json:
|
|
500
575
|
conflicts: last_wins # abort | first_wins | last_wins (default)
|
|
501
576
|
arrays: replace # replace (default) | concat
|
|
@@ -517,8 +592,8 @@ files:
|
|
|
517
592
|
|
|
518
593
|
```yaml
|
|
519
594
|
files:
|
|
520
|
-
|
|
521
|
-
|
|
595
|
+
pretty.json:
|
|
596
|
+
src: ./minified.json
|
|
522
597
|
```
|
|
523
598
|
|
|
524
599
|
### YAML Merging
|
|
@@ -527,20 +602,20 @@ When all sources in a list have a `.yaml` or `.yml` extension, YAML merging is e
|
|
|
527
602
|
|
|
528
603
|
```yaml
|
|
529
604
|
files:
|
|
530
|
-
|
|
605
|
+
merged.yaml:
|
|
606
|
+
src:
|
|
531
607
|
- ./defaults.yaml
|
|
532
608
|
- ./overrides.yml
|
|
533
|
-
target: merged.yaml
|
|
534
609
|
```
|
|
535
610
|
|
|
536
611
|
To merge sources that don't have a YAML extension (e.g. `exec:`, `raw:`, or a URL without `.yaml`), set `yaml: true`:
|
|
537
612
|
|
|
538
613
|
```yaml
|
|
539
614
|
files:
|
|
540
|
-
|
|
615
|
+
merged.yaml:
|
|
616
|
+
src:
|
|
541
617
|
- exec: cat defaults.yaml
|
|
542
618
|
- ./overrides.yaml
|
|
543
|
-
target: merged.yaml
|
|
544
619
|
yaml: true
|
|
545
620
|
```
|
|
546
621
|
|
|
@@ -550,12 +625,12 @@ To opt out of auto-detection and force plain concatenation, set `yaml: false`.
|
|
|
550
625
|
|
|
551
626
|
```yaml
|
|
552
627
|
files:
|
|
553
|
-
|
|
628
|
+
merged.yaml:
|
|
629
|
+
src:
|
|
554
630
|
- ./defaults.yaml
|
|
555
|
-
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
target: merged.yaml
|
|
631
|
+
- github:
|
|
632
|
+
repo: org/configs
|
|
633
|
+
file: overrides.yaml
|
|
559
634
|
yaml:
|
|
560
635
|
conflicts: last_wins # abort | first_wins | last_wins (default)
|
|
561
636
|
arrays: replace # replace (default) | concat
|
|
@@ -581,8 +656,8 @@ The options behave identically to JSON merging:
|
|
|
581
656
|
|
|
582
657
|
```yaml
|
|
583
658
|
files:
|
|
584
|
-
|
|
585
|
-
|
|
659
|
+
config.yaml:
|
|
660
|
+
src: ./config.yaml
|
|
586
661
|
```
|
|
587
662
|
|
|
588
663
|
### Variables
|
|
@@ -599,7 +674,8 @@ Reference them anywhere in the config with `$name`:
|
|
|
599
674
|
|
|
600
675
|
```yaml
|
|
601
676
|
files:
|
|
602
|
-
|
|
677
|
+
renovate.json:
|
|
678
|
+
src:
|
|
603
679
|
gitlab:
|
|
604
680
|
project: group/project
|
|
605
681
|
file: renovate.json
|
|
@@ -609,23 +685,36 @@ files:
|
|
|
609
685
|
to: $email # resolved to "you@example.com"
|
|
610
686
|
```
|
|
611
687
|
|
|
612
|
-
Variables are resolved in every string field:
|
|
688
|
+
Variables are resolved in every string field: target keys, `ref`, `exec` commands, HTTP URLs, local paths, `raw` content, `replace` rules (`from` and `to`), and `post` scripts.
|
|
613
689
|
|
|
614
690
|
For `raw:` sources, variables are resolved in the content itself. For all other source types (`http`, `local`, `github`, `gitlab`, `exec`), variables are only resolved in the fields that locate the source (URL, path, command) — not in the fetched content. Use a `replace:` rule if you need to substitute values in fetched content.
|
|
615
691
|
|
|
616
|
-
**Shell safety in `exec:` and `post:`** — when a variable is substituted into an `exec:` command or a `post:` script, its value is automatically
|
|
692
|
+
**Shell safety in `exec:` and `post:`** — when a variable is substituted into an `exec:` command or a `post:` script, its value is automatically single-quoted. This means shell metacharacters (`;`, `&&`, `$(...)`, etc.) in the value are treated as literal data and are never executed. The surrounding command template itself is not quoted, so the static shell syntax you write is executed as usual. On Unix the script runs via `sh -c`; on Windows it runs via PowerShell (`-EncodedCommand`).
|
|
617
693
|
|
|
618
694
|
```yaml
|
|
619
695
|
variables:
|
|
620
696
|
version: '1.0'
|
|
621
697
|
|
|
622
698
|
files:
|
|
623
|
-
|
|
699
|
+
data.json:
|
|
700
|
+
src:
|
|
624
701
|
exec: curl https://example.com/api/$version/data # expands to: curl …/'1.0'/data
|
|
625
|
-
target: data.json
|
|
626
702
|
post: sed 's/$version/replaced/g' # expands to: sed 's/'\''1.0'\''/replaced/g'
|
|
627
703
|
```
|
|
628
704
|
|
|
705
|
+
**Escaping a literal `$`** — use `$$` to emit a literal `$` that is not treated as a variable reference. This is useful in `exec:` and `post:` scripts that contain shell or PowerShell syntax with `$`-prefixed identifiers (e.g. PowerShell built-ins like `$$true` or `$$null`):
|
|
706
|
+
|
|
707
|
+
```yaml
|
|
708
|
+
files:
|
|
709
|
+
out.txt:
|
|
710
|
+
src:
|
|
711
|
+
# On Windows exec: runs in PowerShell — $true is a PS built-in, needs $$
|
|
712
|
+
exec: "if ($$true) { Write-Output 'yes' }"
|
|
713
|
+
post: sed 's/$$HOME/redacted/g' # $HOME would be treated as an avanti variable
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
`$$` produces a single `$` after substitution. `$$$name` produces `$` followed by the value of `name`.
|
|
717
|
+
|
|
629
718
|
**Environment variables** use the `$env:NAME` form:
|
|
630
719
|
|
|
631
720
|
```yaml
|
|
@@ -640,6 +729,50 @@ Referencing an undefined variable or a missing environment variable is an error.
|
|
|
640
729
|
|
|
641
730
|
When `ref` is omitted, all source types (GitHub, GitLab, Bitbucket, git) resolve to the repository's default branch.
|
|
642
731
|
|
|
732
|
+
### $self — Self-managing Config
|
|
733
|
+
|
|
734
|
+
The special `$self` key in the `files:` map tells avanti to manage its own config file. When `$self` is present, avanti fetches the listed sources and uses the result as the active config for the rest of the run — all in a single invocation.
|
|
735
|
+
|
|
736
|
+
```yaml
|
|
737
|
+
files:
|
|
738
|
+
$self:
|
|
739
|
+
src:
|
|
740
|
+
github:
|
|
741
|
+
repo: myorg/dotfiles
|
|
742
|
+
file: avanti.yml
|
|
743
|
+
ref: $latest
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
**How it works:**
|
|
747
|
+
|
|
748
|
+
1. avanti fetches only the `$self` sources first.
|
|
749
|
+
2. The sources are assembled into a single document. With a single source the fetched content is used directly, though it may be normalized/formatted if `yaml:`/`json:` applies (explicit or auto-detected from the file extension). With multiple sources they are concatenated by default, or YAML/JSON-merged if `yaml:`/`json:` is set (or auto-detected from all source file extensions being `.yml`/`.yaml` or `.json`/`.jsonc`).
|
|
750
|
+
3. The result is parsed as the new active config. If it also contains `$self`, avanti re-fetches until the content stabilizes (fixed point).
|
|
751
|
+
4. The stable config drives all remaining file entries. On `avanti pull`, the stable content is written back to the local config file (for local configs) or kept in memory only (for remote `--config` sources). On `avanti diff`, the stable config is used in-memory to compute the diff and is never written.
|
|
752
|
+
|
|
753
|
+
**Multi-layer config** — list multiple sources under `$self` and use `yaml:` to deep-merge them into one config:
|
|
754
|
+
|
|
755
|
+
```yaml
|
|
756
|
+
files:
|
|
757
|
+
$self:
|
|
758
|
+
src:
|
|
759
|
+
- github:
|
|
760
|
+
repo: myorg/platform
|
|
761
|
+
file: avanti/base.yml
|
|
762
|
+
ref: $latest
|
|
763
|
+
- github:
|
|
764
|
+
repo: myorg/backend-team
|
|
765
|
+
file: avanti/team.yml
|
|
766
|
+
ref: main
|
|
767
|
+
- path: ~/avanti-personal.yml
|
|
768
|
+
optional: true
|
|
769
|
+
yaml:
|
|
770
|
+
conflicts: last_wins
|
|
771
|
+
arrays: concat
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
`$self` supports all the same source types, `replace`, `post`, and YAML/JSON merge options as any other file entry. See [Self-managing Config](#self-managing-config) in the Use Cases section for a full worked example.
|
|
775
|
+
|
|
643
776
|
### Authentication
|
|
644
777
|
|
|
645
778
|
Public repositories on github.com and gitlab.com work without any configuration. For private repositories or instances, supply credentials via environment variables:
|
|
@@ -675,95 +808,6 @@ GITHUB_HOST=github.mycompany.com avanti pull
|
|
|
675
808
|
|
|
676
809
|
## Use Cases
|
|
677
810
|
|
|
678
|
-
### Avanti as a Package Manager
|
|
679
|
-
|
|
680
|
-
avanti is a package manager for arbitrary text files. Your `.avanti.yml` is the manifest — it declares what you consume, where to fetch it, and which version to pin, the same role as `package.json` or `Cargo.toml`. Source repositories are the packages. `avanti pull` is the install command.
|
|
681
|
-
|
|
682
|
-
What makes it stateful: every successful pull is recorded in a local history store. You can diff any two states, revert the whole project to a prior pull, or fully undo all avanti changes — the same guarantees as a lockfile, extended to any text file from any source.
|
|
683
|
-
|
|
684
|
-
**Declare dependencies** — pin versions with a variable and bump in one place to upgrade everything at once:
|
|
685
|
-
|
|
686
|
-
```yaml
|
|
687
|
-
variables:
|
|
688
|
-
frontend_standards: myorg/frontend-standards
|
|
689
|
-
platform: myorg/platform-templates
|
|
690
|
-
standards_ref: v2.4.1 # pinned — bump here to upgrade
|
|
691
|
-
|
|
692
|
-
files:
|
|
693
|
-
- src:
|
|
694
|
-
github:
|
|
695
|
-
repo: $frontend_standards
|
|
696
|
-
file: eslint.config.js
|
|
697
|
-
ref: $standards_ref
|
|
698
|
-
|
|
699
|
-
- src:
|
|
700
|
-
github:
|
|
701
|
-
repo: $frontend_standards
|
|
702
|
-
file: .prettierrc
|
|
703
|
-
ref: $standards_ref
|
|
704
|
-
|
|
705
|
-
- src:
|
|
706
|
-
github:
|
|
707
|
-
repo: $platform
|
|
708
|
-
file: workflows/test.yml
|
|
709
|
-
ref: $standards_ref
|
|
710
|
-
target: .github/workflows/test.yml
|
|
711
|
-
|
|
712
|
-
- src:
|
|
713
|
-
github:
|
|
714
|
-
repo: $platform
|
|
715
|
-
file: workflows/deploy.yml
|
|
716
|
-
ref: $standards_ref
|
|
717
|
-
target: .github/workflows/deploy.yml
|
|
718
|
-
```
|
|
719
|
-
|
|
720
|
-
**Review and apply upgrades** — the same workflow as reading a lockfile diff before committing:
|
|
721
|
-
|
|
722
|
-
```sh
|
|
723
|
-
# Bump standards_ref: v2.4.1 → v2.5.0, then:
|
|
724
|
-
avanti diff # see every file that would change
|
|
725
|
-
avanti pull # apply after review
|
|
726
|
-
avanti revert # roll back instantly if something breaks
|
|
727
|
-
```
|
|
728
|
-
|
|
729
|
-
**Publish your own packages** — any repo can ship an `avanti-snippet.yml` alongside its files. Consumers YAML-merge those snippets into their own config. The snippet is a valid avanti config fragment with its own `files:` list:
|
|
730
|
-
|
|
731
|
-
```yaml
|
|
732
|
-
# myorg/frontend-standards:avanti-snippet.yml — published alongside eslint.config.js, .prettierrc, etc.
|
|
733
|
-
files:
|
|
734
|
-
- src:
|
|
735
|
-
github:
|
|
736
|
-
repo: myorg/frontend-standards
|
|
737
|
-
file: eslint.config.js
|
|
738
|
-
ref: $latest
|
|
739
|
-
|
|
740
|
-
- src:
|
|
741
|
-
github:
|
|
742
|
-
repo: myorg/frontend-standards
|
|
743
|
-
file: .prettierrc
|
|
744
|
-
ref: $latest
|
|
745
|
-
```
|
|
746
|
-
|
|
747
|
-
```yaml
|
|
748
|
-
# .avanti.yml — assembled from team snippets via YAML merge
|
|
749
|
-
files:
|
|
750
|
-
- src:
|
|
751
|
-
- github:
|
|
752
|
-
repo: myorg/frontend-standards
|
|
753
|
-
file: avanti-snippet.yml
|
|
754
|
-
ref: $latest
|
|
755
|
-
- github:
|
|
756
|
-
repo: myorg/platform-templates
|
|
757
|
-
file: avanti-snippet.yml
|
|
758
|
-
ref: $latest
|
|
759
|
-
target: .avanti.yml
|
|
760
|
-
yaml:
|
|
761
|
-
arrays: concat # file lists from all snippets are concatenated
|
|
762
|
-
conflicts: last_wins
|
|
763
|
-
```
|
|
764
|
-
|
|
765
|
-
Each team controls what they publish and when they cut a release. The YAML-merged config self-updates on every pull — add a snippet source to opt into a new package, remove it to opt out. `avanti diff` shows exactly what would change before you apply any update.
|
|
766
|
-
|
|
767
811
|
### Composable AI Agent Instructions (CLAUDE.md / AGENTS.md)
|
|
768
812
|
|
|
769
813
|
Assemble agent instruction files from multiple sources: a static header defined inline, team-specific rules from a shared GitLab repo, and company-wide standards from GitHub — all merged into one file. Every developer runs `avanti pull` and stays in sync without copy-paste drift across dozens of repos.
|
|
@@ -776,7 +820,8 @@ variables:
|
|
|
776
820
|
oncall_channel: '#backend-oncall'
|
|
777
821
|
|
|
778
822
|
files:
|
|
779
|
-
|
|
823
|
+
CLAUDE.md:
|
|
824
|
+
src:
|
|
780
825
|
- raw: |
|
|
781
826
|
# AI Assistant Guidelines
|
|
782
827
|
<!-- THIS FILE IS MANAGED — run `avanti pull` to update -->
|
|
@@ -793,9 +838,12 @@ files:
|
|
|
793
838
|
Team: $team
|
|
794
839
|
Jira project: $jira_project
|
|
795
840
|
Oncall: $oncall_channel
|
|
796
|
-
|
|
841
|
+
- path: ~/custom-claude.md # personal additions; silently skipped if absent
|
|
842
|
+
optional: true
|
|
797
843
|
```
|
|
798
844
|
|
|
845
|
+
The `optional: true` source is the key to sharing a config across a whole team: the central spec references a well-known local path, and each developer either creates the file to add their own context or ignores it — `avanti pull` works either way. No per-person fork of the config needed.
|
|
846
|
+
|
|
799
847
|
### Shared Tooling Config (Renovate, ESLint, Prettier, TSConfig)
|
|
800
848
|
|
|
801
849
|
A platform team owns canonical configs in a central repo. Projects pull them and stay current. Pin all files to the same version in one place — bump `standards_ref` and `avanti diff` shows every file that will change before you apply it.
|
|
@@ -805,19 +853,22 @@ variables:
|
|
|
805
853
|
standards_ref: v2.4.1
|
|
806
854
|
|
|
807
855
|
files:
|
|
808
|
-
|
|
856
|
+
renovate.json:
|
|
857
|
+
src:
|
|
809
858
|
github:
|
|
810
859
|
repo: org/standards
|
|
811
860
|
file: renovate.json
|
|
812
861
|
ref: $standards_ref
|
|
813
862
|
|
|
814
|
-
|
|
863
|
+
eslint.config.js:
|
|
864
|
+
src:
|
|
815
865
|
github:
|
|
816
866
|
repo: org/standards
|
|
817
867
|
file: eslint.config.js
|
|
818
868
|
ref: $standards_ref
|
|
819
869
|
|
|
820
|
-
|
|
870
|
+
tsconfig.base.json:
|
|
871
|
+
src:
|
|
821
872
|
github:
|
|
822
873
|
repo: org/standards
|
|
823
874
|
file: tsconfig.base.json
|
|
@@ -828,13 +879,13 @@ For YAML-based configs (Helm values, k8s manifests, Docker Compose overrides), u
|
|
|
828
879
|
|
|
829
880
|
```yaml
|
|
830
881
|
files:
|
|
831
|
-
-
|
|
882
|
+
./helm/merged-values.yaml:
|
|
883
|
+
src:
|
|
832
884
|
- github:
|
|
833
885
|
repo: org/platform
|
|
834
886
|
file: helm/base-values.yaml # shared defaults for all services
|
|
835
887
|
ref: $standards_ref
|
|
836
888
|
- ./helm/values.yaml # project overrides
|
|
837
|
-
target: ./helm/merged-values.yaml
|
|
838
889
|
yaml:
|
|
839
890
|
conflicts: last_wins # project overrides win
|
|
840
891
|
arrays: concat # e.g. extra env vars are appended, not replaced
|
|
@@ -846,14 +897,14 @@ Pull reusable CI steps from a central repo into each project. A managed header m
|
|
|
846
897
|
|
|
847
898
|
```yaml
|
|
848
899
|
files:
|
|
849
|
-
-
|
|
900
|
+
.github/workflows/security-scan.yml:
|
|
901
|
+
src:
|
|
850
902
|
- raw: |
|
|
851
903
|
# THIS FILE IS MANAGED — run `avanti pull` to update
|
|
852
904
|
- github:
|
|
853
905
|
repo: org/ci-templates
|
|
854
906
|
file: workflows/security-scan.yml
|
|
855
907
|
ref: main
|
|
856
|
-
target: .github/workflows/security-scan.yml
|
|
857
908
|
```
|
|
858
909
|
|
|
859
910
|
Use `avanti diff` in CI to detect drift — if a project's checked-in file no longer matches the source, the pipeline fails.
|
|
@@ -914,12 +965,12 @@ variables:
|
|
|
914
965
|
region: eu-west-1
|
|
915
966
|
|
|
916
967
|
files:
|
|
917
|
-
|
|
968
|
+
k8s/deployment.yaml:
|
|
969
|
+
src:
|
|
918
970
|
github:
|
|
919
971
|
repo: org/infra
|
|
920
972
|
file: k8s/deployment-template.yaml
|
|
921
973
|
ref: $env:DEPLOY_VERSION
|
|
922
|
-
target: k8s/deployment.yaml
|
|
923
974
|
replace:
|
|
924
975
|
- from: '{ENV}'
|
|
925
976
|
to: $env:ENVIRONMENT
|
|
@@ -936,24 +987,24 @@ Pull secrets at runtime and write them to local files with tight permissions. Th
|
|
|
936
987
|
```yaml
|
|
937
988
|
files:
|
|
938
989
|
# Single field from a Vault KV secret
|
|
939
|
-
|
|
990
|
+
config/db_password.txt:
|
|
991
|
+
src:
|
|
940
992
|
vault:
|
|
941
993
|
path: secret/myapp/db
|
|
942
994
|
field: password
|
|
943
|
-
target: config/db_password.txt
|
|
944
995
|
mode: '0600'
|
|
945
996
|
|
|
946
997
|
# Full Vault secret as JSON
|
|
947
|
-
|
|
998
|
+
config/secrets.json:
|
|
999
|
+
src:
|
|
948
1000
|
vault:
|
|
949
1001
|
path: secret/myapp/config
|
|
950
|
-
target: config/secrets.json
|
|
951
1002
|
mode: '0600'
|
|
952
1003
|
|
|
953
1004
|
# Config file stored in S3
|
|
954
|
-
|
|
1005
|
+
config/app.json:
|
|
1006
|
+
src:
|
|
955
1007
|
s3: s3://my-bucket/configs/app.json
|
|
956
|
-
target: config/app.json
|
|
957
1008
|
mode: '0600'
|
|
958
1009
|
```
|
|
959
1010
|
|
|
@@ -961,13 +1012,13 @@ For AWS SSM or other secret stores without a dedicated source type, `exec:` stil
|
|
|
961
1012
|
|
|
962
1013
|
```yaml
|
|
963
1014
|
files:
|
|
964
|
-
|
|
1015
|
+
config/db.json:
|
|
1016
|
+
src:
|
|
965
1017
|
exec: >
|
|
966
1018
|
aws ssm get-parameter
|
|
967
1019
|
--name /myapp/db-config
|
|
968
1020
|
--with-decryption
|
|
969
1021
|
--query Parameter.Value --output text
|
|
970
|
-
target: config/db.json
|
|
971
1022
|
mode: '0600'
|
|
972
1023
|
```
|
|
973
1024
|
|
|
@@ -994,7 +1045,8 @@ variables:
|
|
|
994
1045
|
db_password: changeme
|
|
995
1046
|
|
|
996
1047
|
files:
|
|
997
|
-
-
|
|
1048
|
+
docker-compose.yml:
|
|
1049
|
+
src:
|
|
998
1050
|
- github:
|
|
999
1051
|
repo: n8n-io/n8n-hosting
|
|
1000
1052
|
file: docker-caddy/docker-compose.yml
|
|
@@ -1003,7 +1055,6 @@ files:
|
|
|
1003
1055
|
repo: docker-library/docs
|
|
1004
1056
|
file: postgres/compose.yaml
|
|
1005
1057
|
ref: master
|
|
1006
|
-
target: docker-compose.yml
|
|
1007
1058
|
replace:
|
|
1008
1059
|
- from: '${N8N_VERSION}'
|
|
1009
1060
|
to: $n8n_version # pin version at pull time
|
|
@@ -1026,19 +1077,22 @@ A single `avanti pull` populates a new project with everything it needs: editor
|
|
|
1026
1077
|
|
|
1027
1078
|
```yaml
|
|
1028
1079
|
files:
|
|
1029
|
-
|
|
1080
|
+
.editorconfig:
|
|
1081
|
+
src:
|
|
1030
1082
|
github:
|
|
1031
1083
|
repo: org/standards
|
|
1032
1084
|
file: .editorconfig
|
|
1033
1085
|
ref: main
|
|
1034
1086
|
|
|
1035
|
-
|
|
1087
|
+
.prettierrc:
|
|
1088
|
+
src:
|
|
1036
1089
|
github:
|
|
1037
1090
|
repo: org/standards
|
|
1038
1091
|
file: .prettierrc
|
|
1039
1092
|
ref: main
|
|
1040
1093
|
|
|
1041
|
-
|
|
1094
|
+
CLAUDE.md:
|
|
1095
|
+
src:
|
|
1042
1096
|
- raw: |
|
|
1043
1097
|
# AI Assistant Guidelines
|
|
1044
1098
|
<!-- THIS FILE IS MANAGED — run `avanti pull` to update -->
|
|
@@ -1046,56 +1100,41 @@ files:
|
|
|
1046
1100
|
repo: org/ai-standards
|
|
1047
1101
|
file: CLAUDE.md
|
|
1048
1102
|
ref: main
|
|
1049
|
-
target: CLAUDE.md
|
|
1050
1103
|
|
|
1051
|
-
|
|
1104
|
+
.github/workflows/:
|
|
1105
|
+
src:
|
|
1052
1106
|
github:
|
|
1053
1107
|
repo: org/ci-templates
|
|
1054
1108
|
file: workflows/
|
|
1055
1109
|
ref: main
|
|
1056
|
-
target: .github/workflows/
|
|
1057
1110
|
```
|
|
1058
1111
|
|
|
1059
1112
|
### Self-managing Config
|
|
1060
1113
|
|
|
1061
|
-
avanti can
|
|
1062
|
-
|
|
1063
|
-
When avanti detects that a pull would update the local config file, it automatically re-evaluates the new config in memory and applies all the files it describes — in the same run, with a single confirmation prompt and a single atomic write. You don't need to run `avanti pull` twice to get the new config's files.
|
|
1114
|
+
avanti can manage any file — including its own config. The special `$self` key in the `files:` map fetches and merges one or more sources, uses the result as the active config, and then applies all the files it declares — in the same run, with a single confirmation prompt.
|
|
1064
1115
|
|
|
1065
1116
|
```yaml
|
|
1066
1117
|
# ~/.avanti.yml
|
|
1067
|
-
variables:
|
|
1068
|
-
dotfiles: myorg/dotfiles
|
|
1069
|
-
|
|
1070
1118
|
files:
|
|
1071
|
-
|
|
1072
|
-
|
|
1119
|
+
$self:
|
|
1120
|
+
src:
|
|
1073
1121
|
github:
|
|
1074
|
-
repo:
|
|
1122
|
+
repo: myorg/dotfiles
|
|
1075
1123
|
file: avanti.yml
|
|
1076
1124
|
ref: $latest
|
|
1077
|
-
|
|
1125
|
+
```
|
|
1078
1126
|
|
|
1079
|
-
|
|
1080
|
-
- src:
|
|
1081
|
-
github:
|
|
1082
|
-
repo: $dotfiles
|
|
1083
|
-
file: .zshrc
|
|
1084
|
-
target: ~/.zshrc
|
|
1127
|
+
Every `avanti pull` fetches the remote `avanti.yml`, applies all the files it declares, and writes the merged result back to `~/.avanti.yml`. If the remote `avanti.yml` itself contains a `$self` entry, avanti keeps re-fetching until the content stabilizes — so the remote config can keep pointing at itself and avanti will always pick up the latest version on every pull.
|
|
1085
1128
|
|
|
1086
|
-
|
|
1087
|
-
github:
|
|
1088
|
-
repo: $dotfiles
|
|
1089
|
-
file: .gitconfig
|
|
1090
|
-
target: ~/.gitconfig
|
|
1091
|
-
```
|
|
1129
|
+
When running with a remote config (`--config github:...`), `$self` is in-memory only — the merged result drives the run but is not persisted anywhere, since there is no local file to write back to.
|
|
1092
1130
|
|
|
1093
|
-
**Composable
|
|
1131
|
+
**Composable config** — `$self` with multiple sources and YAML merge lets you assemble a config from independent layers. Org-wide defaults, team additions, and personal overrides all merge into one active config:
|
|
1094
1132
|
|
|
1095
1133
|
```yaml
|
|
1096
|
-
# ~/.avanti.yml
|
|
1134
|
+
# ~/.avanti.yml
|
|
1097
1135
|
files:
|
|
1098
|
-
|
|
1136
|
+
$self:
|
|
1137
|
+
src:
|
|
1099
1138
|
- github:
|
|
1100
1139
|
repo: myorg/platform
|
|
1101
1140
|
file: avanti/base.yml # org-wide entries and variables
|
|
@@ -1108,7 +1147,6 @@ files:
|
|
|
1108
1147
|
repo: myuser/dotfiles
|
|
1109
1148
|
file: avanti/personal.yml # personal overrides and extras
|
|
1110
1149
|
ref: main
|
|
1111
|
-
target: ~/.avanti.yml
|
|
1112
1150
|
yaml:
|
|
1113
1151
|
conflicts: last_wins # personal overrides win over team, team over org
|
|
1114
1152
|
arrays: concat # file lists from all layers are merged, not replaced
|
|
@@ -1148,8 +1186,8 @@ This scales to any number of machines or containers. Update the central repo onc
|
|
|
1148
1186
|
|
|
1149
1187
|
```sh
|
|
1150
1188
|
git clone ...
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1189
|
+
mise run install # install dependencies and set up git hooks
|
|
1190
|
+
mise run dev -- --help # run via tsx
|
|
1191
|
+
mise run test # run tests
|
|
1192
|
+
mise run build # compile to dist/
|
|
1155
1193
|
```
|