@udondan/avanti 0.12.1 → 0.14.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 +341 -271
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/diff.d.ts.map +1 -1
- package/dist/commands/diff.js +117 -26
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/lock.d.ts +3 -0
- package/dist/commands/lock.d.ts.map +1 -0
- package/dist/commands/lock.js +112 -0
- package/dist/commands/lock.js.map +1 -0
- package/dist/commands/log.js +48 -9
- package/dist/commands/log.js.map +1 -1
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/pull.js +260 -43
- 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 +12 -0
- package/dist/config-writeback.d.ts.map +1 -0
- package/dist/config-writeback.js +209 -0
- package/dist/config-writeback.js.map +1 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +139 -65
- package/dist/config.js.map +1 -1
- package/dist/diff.js +22 -13
- 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.d.ts +8 -1
- package/dist/history.d.ts.map +1 -1
- package/dist/history.js +22 -10
- 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.js +1 -2
- 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.d.ts +2 -0
- package/dist/sha.d.ts.map +1 -0
- package/dist/sha.js +41 -0
- package/dist/sha.js.map +1 -0
- package/dist/sources/bitbucket.js +18 -9
- package/dist/sources/bitbucket.js.map +1 -1
- package/dist/sources/exec.js +1 -2
- 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 +11 -1
- package/dist/sources/index.d.ts.map +1 -1
- package/dist/sources/index.js +287 -41
- 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 +21 -10
- 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 +27 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/variables.js +4 -4
- 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
|
|
@@ -79,15 +127,16 @@ npx @udondan/avanti --help
|
|
|
79
127
|
avanti [options] [command]
|
|
80
128
|
|
|
81
129
|
Options:
|
|
82
|
-
-c, --config <path|url>
|
|
83
|
-
-w, --working-dir <path>
|
|
130
|
+
-c, --config <path|url> path or remote spec for config file (default: auto-detected)
|
|
131
|
+
-w, --working-dir <path> working directory for resolving paths (default: current directory)
|
|
84
132
|
|
|
85
133
|
Commands:
|
|
86
|
-
diff [pullId]
|
|
87
|
-
pull [--yes]
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
134
|
+
diff [pullId] Show diff between remote sources and local files, or vs a past pull
|
|
135
|
+
pull [--yes] [--accept-changes] Pull remote sources and write to local files
|
|
136
|
+
lock [--force] Pin SHA values for all remote sources in the config
|
|
137
|
+
log [file] Show pull history for the current project
|
|
138
|
+
revert [pullId] [--yes] Atomically revert all project files to a past pull state
|
|
139
|
+
reset [--yes] Restore all tracked files to their pre-avanti state
|
|
91
140
|
```
|
|
92
141
|
|
|
93
142
|
### `avanti diff`
|
|
@@ -98,8 +147,35 @@ Shows a colored git-diff-like output of what would change. Exits `0` if no chang
|
|
|
98
147
|
|
|
99
148
|
Fetches all sources, shows the diff, and prompts for confirmation before writing. Use `--yes` to skip the prompt.
|
|
100
149
|
|
|
150
|
+
If any source has a `sha` field and the fetched content's SHA no longer matches, the pull is aborted with a mismatch error. Use `--accept-changes` to review the diff, confirm, and automatically update the SHA values in the config file.
|
|
151
|
+
|
|
101
152
|
When avanti has previously synced a directory from a remote source and a file is no longer present in that source, the file is treated as stale: if avanti created it, it is deleted; if it existed before avanti first touched it, the original content is restored. Stale file changes appear in the diff before you confirm.
|
|
102
153
|
|
|
154
|
+
### `avanti lock`
|
|
155
|
+
|
|
156
|
+
Fetches all remote sources and writes a SHA-256 fingerprint for each one into the config file. Comments and formatting are preserved.
|
|
157
|
+
|
|
158
|
+
```sh
|
|
159
|
+
avanti lock # pin all unpinned remote sources
|
|
160
|
+
avanti lock --force # overwrite existing SHA values with fresh ones
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Once a source is pinned, `avanti pull` will verify the fetched content's SHA before applying any changes. If the upstream changed unexpectedly, avanti aborts with a clear error pointing to the affected source:
|
|
164
|
+
|
|
165
|
+
```text
|
|
166
|
+
SHA mismatch for github:org/standards:company-rules.md
|
|
167
|
+
expected: abc123...
|
|
168
|
+
got: def456...
|
|
169
|
+
|
|
170
|
+
Run `avanti pull --accept-changes` to review the diff and update SHA values.
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
`avanti diff` shows a `⚠ SHA mismatch` warning inline for any source that no longer matches its pinned SHA.
|
|
174
|
+
|
|
175
|
+
SHA is computed over the raw fetched content of each source, before any `replace` or `post` processing. Each file's path and content are fed into the hash in sorted order, separated by null bytes — so renames and additions affect the fingerprint even for single-file sources. Pull history records the observed SHA for every source, so `avanti log` shows a full audit trail of what changed and when.
|
|
176
|
+
|
|
177
|
+
Excluded from SHA pinning: local paths and `raw:` sources (their content is either authored locally or inline in the config, so changes are always visible).
|
|
178
|
+
|
|
103
179
|
## History
|
|
104
180
|
|
|
105
181
|
Every successful `avanti pull` that writes at least one file is recorded in a local history store. This lets you inspect what changed, preview past states, revert the whole project, or fully undo all avanti changes.
|
|
@@ -233,49 +309,59 @@ variables:
|
|
|
233
309
|
email: you@example.com
|
|
234
310
|
|
|
235
311
|
files:
|
|
236
|
-
-
|
|
237
|
-
|
|
312
|
+
my-example.yml:
|
|
313
|
+
src: http://www.example.com/example.yml
|
|
238
314
|
replace:
|
|
239
315
|
- from: '{EMAIL}'
|
|
240
316
|
to: $email
|
|
241
317
|
- from: /\d+/
|
|
242
318
|
to: number
|
|
243
319
|
|
|
244
|
-
|
|
245
|
-
|
|
320
|
+
file.sh:
|
|
321
|
+
src: ~/some/local/file.sh
|
|
246
322
|
mode: '0777'
|
|
247
323
|
|
|
248
|
-
-
|
|
324
|
+
some-file.yml:
|
|
325
|
+
src:
|
|
249
326
|
exec: glab api "projects/group%2Fproject/repository/files/some-file.yaml/raw?ref=main"
|
|
250
|
-
target: some-file.yml
|
|
251
327
|
post: sed -e 's/v3/v4/g'
|
|
252
328
|
|
|
253
|
-
|
|
329
|
+
renovate.json:
|
|
330
|
+
src:
|
|
254
331
|
gitlab:
|
|
255
332
|
project: group/project
|
|
256
333
|
file: renovate.json
|
|
257
334
|
ref: $latest
|
|
258
|
-
# target omitted → renovate.json
|
|
259
335
|
|
|
260
|
-
-
|
|
336
|
+
local-scripts/:
|
|
337
|
+
src:
|
|
261
338
|
github:
|
|
262
339
|
repo: org/repo
|
|
263
340
|
file: scripts/
|
|
264
341
|
ref: main
|
|
265
|
-
target: local-scripts/
|
|
266
342
|
```
|
|
267
343
|
|
|
268
344
|
### File Entry Fields
|
|
269
345
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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. |
|
|
279
365
|
|
|
280
366
|
### Source Types
|
|
281
367
|
|
|
@@ -287,27 +373,44 @@ src: ~/templates/file.txt
|
|
|
287
373
|
src: /absolute/path/file.txt
|
|
288
374
|
```
|
|
289
375
|
|
|
290
|
-
**Map** — for exec, gitlab, github, bitbucket, git, s3, vault, raw:
|
|
376
|
+
**Map** — for path, url, exec, gitlab, github, bitbucket, git, s3, vault, http, raw:
|
|
291
377
|
|
|
292
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
|
+
|
|
293
389
|
src:
|
|
294
390
|
exec: <shell command> # stdout becomes file content; target required
|
|
391
|
+
sha: abc123... # optional SHA-256 to verify stdout (see below)
|
|
295
392
|
|
|
296
393
|
src:
|
|
297
394
|
raw: | # inline content; target required
|
|
298
395
|
your content here
|
|
299
396
|
|
|
397
|
+
src:
|
|
398
|
+
http: https://example.com/file.txt # explicit http/https URL with optional SHA
|
|
399
|
+
sha: abc123...
|
|
400
|
+
|
|
300
401
|
src:
|
|
301
402
|
gitlab:
|
|
302
403
|
project: group/repo # GitLab project path
|
|
303
404
|
file: path/to/file.txt # file or directory in repo
|
|
304
405
|
ref: main # branch, tag, or $latest (optional)
|
|
406
|
+
sha: abc123... # optional SHA-256 fingerprint
|
|
305
407
|
|
|
306
408
|
src:
|
|
307
409
|
github:
|
|
308
410
|
repo: owner/repo # GitHub owner/repo
|
|
309
411
|
file: path/to/file.txt # file or directory in repo
|
|
310
412
|
ref: main # branch, tag, or $latest (optional)
|
|
413
|
+
sha: abc123... # optional SHA-256 fingerprint
|
|
311
414
|
|
|
312
415
|
src:
|
|
313
416
|
bitbucket:
|
|
@@ -315,103 +418,120 @@ src:
|
|
|
315
418
|
repo: my-repo # repository slug
|
|
316
419
|
file: path/to/file.txt # file or directory in repo
|
|
317
420
|
ref: main # branch, tag, or $latest (optional)
|
|
421
|
+
sha: abc123... # optional SHA-256 fingerprint
|
|
318
422
|
|
|
319
423
|
src:
|
|
320
424
|
git:
|
|
321
425
|
repo: https://github.com/org/repo.git # any git remote (HTTPS or SSH)
|
|
322
426
|
file: path/to/file.txt # file or directory in repo
|
|
323
427
|
ref: main # branch, tag, or commit hash (optional)
|
|
428
|
+
sha: abc123... # optional SHA-256 fingerprint
|
|
324
429
|
|
|
325
430
|
src:
|
|
326
431
|
s3: s3://my-bucket/path/to/file.txt # S3 URI; end with / for a prefix sync
|
|
432
|
+
sha: abc123... # optional SHA-256 fingerprint
|
|
327
433
|
|
|
328
434
|
src:
|
|
329
435
|
vault:
|
|
330
436
|
path: secret/myapp/config # Vault KV path (mount/subpath)
|
|
331
437
|
field: db_password # specific field to extract (optional; omit for full JSON)
|
|
438
|
+
sha: abc123... # optional SHA-256 fingerprint
|
|
332
439
|
```
|
|
333
440
|
|
|
441
|
+
#### SHA pinning
|
|
442
|
+
|
|
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.
|
|
444
|
+
|
|
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.
|
|
446
|
+
|
|
334
447
|
### Directory Sources
|
|
335
448
|
|
|
336
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.
|
|
337
450
|
|
|
338
|
-
**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:
|
|
452
|
+
|
|
453
|
+
```yaml
|
|
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:`:
|
|
339
499
|
|
|
340
500
|
```yaml
|
|
341
|
-
|
|
342
|
-
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
# GitHub directory → local directory
|
|
350
|
-
- src:
|
|
351
|
-
github:
|
|
352
|
-
repo: org/repo
|
|
353
|
-
file: .github/workflows/
|
|
354
|
-
ref: main
|
|
355
|
-
target: .github/workflows/
|
|
356
|
-
|
|
357
|
-
# Bitbucket directory → local directory
|
|
358
|
-
- src:
|
|
359
|
-
bitbucket:
|
|
360
|
-
workspace: my-workspace
|
|
361
|
-
repo: shared-configs
|
|
362
|
-
file: eslint/
|
|
363
|
-
ref: main
|
|
364
|
-
target: eslint/
|
|
365
|
-
|
|
366
|
-
# git remote directory → local directory (any host)
|
|
367
|
-
- src:
|
|
368
|
-
git:
|
|
369
|
-
repo: https://github.com/org/repo.git
|
|
370
|
-
file: .github/workflows/
|
|
371
|
-
ref: main
|
|
372
|
-
target: .github/workflows/
|
|
373
|
-
|
|
374
|
-
# S3 prefix → local directory (trailing / triggers sync)
|
|
375
|
-
- src:
|
|
376
|
-
s3: s3://my-bucket/configs/
|
|
377
|
-
target: configs/
|
|
378
|
-
|
|
379
|
-
# Local directory → local directory
|
|
380
|
-
- src: ~/shared/hooks/
|
|
381
|
-
target: .githooks/
|
|
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/
|
|
382
509
|
```
|
|
383
510
|
|
|
384
|
-
|
|
511
|
+
With explicit YAML merge options (e.g. to concat arrays instead of replacing):
|
|
385
512
|
|
|
386
513
|
```yaml
|
|
387
|
-
|
|
388
|
-
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
- src: ./services/
|
|
393
|
-
target: docker-compose.yml
|
|
394
|
-
yaml:
|
|
395
|
-
arrays: concat
|
|
396
|
-
|
|
397
|
-
# JSON: one file per environment → merged config
|
|
398
|
-
- src: ./config/
|
|
399
|
-
target: config.json
|
|
514
|
+
files:
|
|
515
|
+
docker-compose.yml:
|
|
516
|
+
src: ./services/
|
|
517
|
+
yaml:
|
|
518
|
+
arrays: concat
|
|
400
519
|
```
|
|
401
520
|
|
|
402
521
|
Directory sources cannot be mixed into a multi-source list (`src` as a list), because the list mode always produces a single file.
|
|
403
522
|
|
|
404
|
-
**List** — combine multiple sources into one file (all source types supported
|
|
523
|
+
**List** — combine multiple sources into one file (all source types supported):
|
|
405
524
|
|
|
406
525
|
```yaml
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
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
|
|
415
535
|
```
|
|
416
536
|
|
|
417
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.
|
|
@@ -422,20 +542,20 @@ When all sources in a list have a `.json` or `.jsonc` extension, JSON merging is
|
|
|
422
542
|
|
|
423
543
|
```yaml
|
|
424
544
|
files:
|
|
425
|
-
|
|
545
|
+
merged.jsonc:
|
|
546
|
+
src:
|
|
426
547
|
- ./team.jsonc
|
|
427
548
|
- ./my.jsonc
|
|
428
|
-
target: merged.jsonc
|
|
429
549
|
```
|
|
430
550
|
|
|
431
551
|
To merge sources that don't have a JSON extension (e.g. `exec:`, `raw:`, or a URL without `.json`), set `json: true`:
|
|
432
552
|
|
|
433
553
|
```yaml
|
|
434
554
|
files:
|
|
435
|
-
|
|
555
|
+
merged.json:
|
|
556
|
+
src:
|
|
436
557
|
- exec: cat defaults.json
|
|
437
558
|
- ./overrides.json
|
|
438
|
-
target: merged.json
|
|
439
559
|
json: true
|
|
440
560
|
```
|
|
441
561
|
|
|
@@ -445,12 +565,12 @@ To opt out of auto-detection and force plain concatenation, set `json: false`.
|
|
|
445
565
|
|
|
446
566
|
```yaml
|
|
447
567
|
files:
|
|
448
|
-
|
|
568
|
+
merged.json:
|
|
569
|
+
src:
|
|
449
570
|
- ./defaults.json
|
|
450
|
-
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
target: merged.json
|
|
571
|
+
- github:
|
|
572
|
+
repo: org/configs
|
|
573
|
+
file: overrides.json
|
|
454
574
|
json:
|
|
455
575
|
conflicts: last_wins # abort | first_wins | last_wins (default)
|
|
456
576
|
arrays: replace # replace (default) | concat
|
|
@@ -472,8 +592,8 @@ files:
|
|
|
472
592
|
|
|
473
593
|
```yaml
|
|
474
594
|
files:
|
|
475
|
-
|
|
476
|
-
|
|
595
|
+
pretty.json:
|
|
596
|
+
src: ./minified.json
|
|
477
597
|
```
|
|
478
598
|
|
|
479
599
|
### YAML Merging
|
|
@@ -482,20 +602,20 @@ When all sources in a list have a `.yaml` or `.yml` extension, YAML merging is e
|
|
|
482
602
|
|
|
483
603
|
```yaml
|
|
484
604
|
files:
|
|
485
|
-
|
|
605
|
+
merged.yaml:
|
|
606
|
+
src:
|
|
486
607
|
- ./defaults.yaml
|
|
487
608
|
- ./overrides.yml
|
|
488
|
-
target: merged.yaml
|
|
489
609
|
```
|
|
490
610
|
|
|
491
611
|
To merge sources that don't have a YAML extension (e.g. `exec:`, `raw:`, or a URL without `.yaml`), set `yaml: true`:
|
|
492
612
|
|
|
493
613
|
```yaml
|
|
494
614
|
files:
|
|
495
|
-
|
|
615
|
+
merged.yaml:
|
|
616
|
+
src:
|
|
496
617
|
- exec: cat defaults.yaml
|
|
497
618
|
- ./overrides.yaml
|
|
498
|
-
target: merged.yaml
|
|
499
619
|
yaml: true
|
|
500
620
|
```
|
|
501
621
|
|
|
@@ -505,12 +625,12 @@ To opt out of auto-detection and force plain concatenation, set `yaml: false`.
|
|
|
505
625
|
|
|
506
626
|
```yaml
|
|
507
627
|
files:
|
|
508
|
-
|
|
628
|
+
merged.yaml:
|
|
629
|
+
src:
|
|
509
630
|
- ./defaults.yaml
|
|
510
|
-
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
target: merged.yaml
|
|
631
|
+
- github:
|
|
632
|
+
repo: org/configs
|
|
633
|
+
file: overrides.yaml
|
|
514
634
|
yaml:
|
|
515
635
|
conflicts: last_wins # abort | first_wins | last_wins (default)
|
|
516
636
|
arrays: replace # replace (default) | concat
|
|
@@ -536,8 +656,8 @@ The options behave identically to JSON merging:
|
|
|
536
656
|
|
|
537
657
|
```yaml
|
|
538
658
|
files:
|
|
539
|
-
|
|
540
|
-
|
|
659
|
+
config.yaml:
|
|
660
|
+
src: ./config.yaml
|
|
541
661
|
```
|
|
542
662
|
|
|
543
663
|
### Variables
|
|
@@ -554,7 +674,8 @@ Reference them anywhere in the config with `$name`:
|
|
|
554
674
|
|
|
555
675
|
```yaml
|
|
556
676
|
files:
|
|
557
|
-
|
|
677
|
+
renovate.json:
|
|
678
|
+
src:
|
|
558
679
|
gitlab:
|
|
559
680
|
project: group/project
|
|
560
681
|
file: renovate.json
|
|
@@ -564,7 +685,7 @@ files:
|
|
|
564
685
|
to: $email # resolved to "you@example.com"
|
|
565
686
|
```
|
|
566
687
|
|
|
567
|
-
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.
|
|
568
689
|
|
|
569
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.
|
|
570
691
|
|
|
@@ -575,9 +696,9 @@ variables:
|
|
|
575
696
|
version: '1.0'
|
|
576
697
|
|
|
577
698
|
files:
|
|
578
|
-
|
|
699
|
+
data.json:
|
|
700
|
+
src:
|
|
579
701
|
exec: curl https://example.com/api/$version/data # expands to: curl …/'1.0'/data
|
|
580
|
-
target: data.json
|
|
581
702
|
post: sed 's/$version/replaced/g' # expands to: sed 's/'\''1.0'\''/replaced/g'
|
|
582
703
|
```
|
|
583
704
|
|
|
@@ -595,6 +716,50 @@ Referencing an undefined variable or a missing environment variable is an error.
|
|
|
595
716
|
|
|
596
717
|
When `ref` is omitted, all source types (GitHub, GitLab, Bitbucket, git) resolve to the repository's default branch.
|
|
597
718
|
|
|
719
|
+
### $self — Self-managing Config
|
|
720
|
+
|
|
721
|
+
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.
|
|
722
|
+
|
|
723
|
+
```yaml
|
|
724
|
+
files:
|
|
725
|
+
$self:
|
|
726
|
+
src:
|
|
727
|
+
github:
|
|
728
|
+
repo: myorg/dotfiles
|
|
729
|
+
file: avanti.yml
|
|
730
|
+
ref: $latest
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
**How it works:**
|
|
734
|
+
|
|
735
|
+
1. avanti fetches only the `$self` sources first.
|
|
736
|
+
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`).
|
|
737
|
+
3. The result is parsed as the new active config. If it also contains `$self`, avanti re-fetches until the content stabilizes (fixed point).
|
|
738
|
+
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.
|
|
739
|
+
|
|
740
|
+
**Multi-layer config** — list multiple sources under `$self` and use `yaml:` to deep-merge them into one config:
|
|
741
|
+
|
|
742
|
+
```yaml
|
|
743
|
+
files:
|
|
744
|
+
$self:
|
|
745
|
+
src:
|
|
746
|
+
- github:
|
|
747
|
+
repo: myorg/platform
|
|
748
|
+
file: avanti/base.yml
|
|
749
|
+
ref: $latest
|
|
750
|
+
- github:
|
|
751
|
+
repo: myorg/backend-team
|
|
752
|
+
file: avanti/team.yml
|
|
753
|
+
ref: main
|
|
754
|
+
- path: ~/avanti-personal.yml
|
|
755
|
+
optional: true
|
|
756
|
+
yaml:
|
|
757
|
+
conflicts: last_wins
|
|
758
|
+
arrays: concat
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
`$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.
|
|
762
|
+
|
|
598
763
|
### Authentication
|
|
599
764
|
|
|
600
765
|
Public repositories on github.com and gitlab.com work without any configuration. For private repositories or instances, supply credentials via environment variables:
|
|
@@ -630,95 +795,6 @@ GITHUB_HOST=github.mycompany.com avanti pull
|
|
|
630
795
|
|
|
631
796
|
## Use Cases
|
|
632
797
|
|
|
633
|
-
### Avanti as a Package Manager
|
|
634
|
-
|
|
635
|
-
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.
|
|
636
|
-
|
|
637
|
-
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.
|
|
638
|
-
|
|
639
|
-
**Declare dependencies** — pin versions with a variable and bump in one place to upgrade everything at once:
|
|
640
|
-
|
|
641
|
-
```yaml
|
|
642
|
-
variables:
|
|
643
|
-
frontend_standards: myorg/frontend-standards
|
|
644
|
-
platform: myorg/platform-templates
|
|
645
|
-
standards_ref: v2.4.1 # pinned — bump here to upgrade
|
|
646
|
-
|
|
647
|
-
files:
|
|
648
|
-
- src:
|
|
649
|
-
github:
|
|
650
|
-
repo: $frontend_standards
|
|
651
|
-
file: eslint.config.js
|
|
652
|
-
ref: $standards_ref
|
|
653
|
-
|
|
654
|
-
- src:
|
|
655
|
-
github:
|
|
656
|
-
repo: $frontend_standards
|
|
657
|
-
file: .prettierrc
|
|
658
|
-
ref: $standards_ref
|
|
659
|
-
|
|
660
|
-
- src:
|
|
661
|
-
github:
|
|
662
|
-
repo: $platform
|
|
663
|
-
file: workflows/test.yml
|
|
664
|
-
ref: $standards_ref
|
|
665
|
-
target: .github/workflows/test.yml
|
|
666
|
-
|
|
667
|
-
- src:
|
|
668
|
-
github:
|
|
669
|
-
repo: $platform
|
|
670
|
-
file: workflows/deploy.yml
|
|
671
|
-
ref: $standards_ref
|
|
672
|
-
target: .github/workflows/deploy.yml
|
|
673
|
-
```
|
|
674
|
-
|
|
675
|
-
**Review and apply upgrades** — the same workflow as reading a lockfile diff before committing:
|
|
676
|
-
|
|
677
|
-
```sh
|
|
678
|
-
# Bump standards_ref: v2.4.1 → v2.5.0, then:
|
|
679
|
-
avanti diff # see every file that would change
|
|
680
|
-
avanti pull # apply after review
|
|
681
|
-
avanti revert # roll back instantly if something breaks
|
|
682
|
-
```
|
|
683
|
-
|
|
684
|
-
**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:
|
|
685
|
-
|
|
686
|
-
```yaml
|
|
687
|
-
# myorg/frontend-standards:avanti-snippet.yml — published alongside eslint.config.js, .prettierrc, etc.
|
|
688
|
-
files:
|
|
689
|
-
- src:
|
|
690
|
-
github:
|
|
691
|
-
repo: myorg/frontend-standards
|
|
692
|
-
file: eslint.config.js
|
|
693
|
-
ref: $latest
|
|
694
|
-
|
|
695
|
-
- src:
|
|
696
|
-
github:
|
|
697
|
-
repo: myorg/frontend-standards
|
|
698
|
-
file: .prettierrc
|
|
699
|
-
ref: $latest
|
|
700
|
-
```
|
|
701
|
-
|
|
702
|
-
```yaml
|
|
703
|
-
# .avanti.yml — assembled from team snippets via YAML merge
|
|
704
|
-
files:
|
|
705
|
-
- src:
|
|
706
|
-
- github:
|
|
707
|
-
repo: myorg/frontend-standards
|
|
708
|
-
file: avanti-snippet.yml
|
|
709
|
-
ref: $latest
|
|
710
|
-
- github:
|
|
711
|
-
repo: myorg/platform-templates
|
|
712
|
-
file: avanti-snippet.yml
|
|
713
|
-
ref: $latest
|
|
714
|
-
target: .avanti.yml
|
|
715
|
-
yaml:
|
|
716
|
-
arrays: concat # file lists from all snippets are concatenated
|
|
717
|
-
conflicts: last_wins
|
|
718
|
-
```
|
|
719
|
-
|
|
720
|
-
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.
|
|
721
|
-
|
|
722
798
|
### Composable AI Agent Instructions (CLAUDE.md / AGENTS.md)
|
|
723
799
|
|
|
724
800
|
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.
|
|
@@ -731,7 +807,8 @@ variables:
|
|
|
731
807
|
oncall_channel: '#backend-oncall'
|
|
732
808
|
|
|
733
809
|
files:
|
|
734
|
-
|
|
810
|
+
CLAUDE.md:
|
|
811
|
+
src:
|
|
735
812
|
- raw: |
|
|
736
813
|
# AI Assistant Guidelines
|
|
737
814
|
<!-- THIS FILE IS MANAGED — run `avanti pull` to update -->
|
|
@@ -748,9 +825,12 @@ files:
|
|
|
748
825
|
Team: $team
|
|
749
826
|
Jira project: $jira_project
|
|
750
827
|
Oncall: $oncall_channel
|
|
751
|
-
|
|
828
|
+
- path: ~/custom-claude.md # personal additions; silently skipped if absent
|
|
829
|
+
optional: true
|
|
752
830
|
```
|
|
753
831
|
|
|
832
|
+
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.
|
|
833
|
+
|
|
754
834
|
### Shared Tooling Config (Renovate, ESLint, Prettier, TSConfig)
|
|
755
835
|
|
|
756
836
|
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.
|
|
@@ -760,19 +840,22 @@ variables:
|
|
|
760
840
|
standards_ref: v2.4.1
|
|
761
841
|
|
|
762
842
|
files:
|
|
763
|
-
|
|
843
|
+
renovate.json:
|
|
844
|
+
src:
|
|
764
845
|
github:
|
|
765
846
|
repo: org/standards
|
|
766
847
|
file: renovate.json
|
|
767
848
|
ref: $standards_ref
|
|
768
849
|
|
|
769
|
-
|
|
850
|
+
eslint.config.js:
|
|
851
|
+
src:
|
|
770
852
|
github:
|
|
771
853
|
repo: org/standards
|
|
772
854
|
file: eslint.config.js
|
|
773
855
|
ref: $standards_ref
|
|
774
856
|
|
|
775
|
-
|
|
857
|
+
tsconfig.base.json:
|
|
858
|
+
src:
|
|
776
859
|
github:
|
|
777
860
|
repo: org/standards
|
|
778
861
|
file: tsconfig.base.json
|
|
@@ -783,13 +866,13 @@ For YAML-based configs (Helm values, k8s manifests, Docker Compose overrides), u
|
|
|
783
866
|
|
|
784
867
|
```yaml
|
|
785
868
|
files:
|
|
786
|
-
-
|
|
869
|
+
./helm/merged-values.yaml:
|
|
870
|
+
src:
|
|
787
871
|
- github:
|
|
788
872
|
repo: org/platform
|
|
789
873
|
file: helm/base-values.yaml # shared defaults for all services
|
|
790
874
|
ref: $standards_ref
|
|
791
875
|
- ./helm/values.yaml # project overrides
|
|
792
|
-
target: ./helm/merged-values.yaml
|
|
793
876
|
yaml:
|
|
794
877
|
conflicts: last_wins # project overrides win
|
|
795
878
|
arrays: concat # e.g. extra env vars are appended, not replaced
|
|
@@ -801,14 +884,14 @@ Pull reusable CI steps from a central repo into each project. A managed header m
|
|
|
801
884
|
|
|
802
885
|
```yaml
|
|
803
886
|
files:
|
|
804
|
-
-
|
|
887
|
+
.github/workflows/security-scan.yml:
|
|
888
|
+
src:
|
|
805
889
|
- raw: |
|
|
806
890
|
# THIS FILE IS MANAGED — run `avanti pull` to update
|
|
807
891
|
- github:
|
|
808
892
|
repo: org/ci-templates
|
|
809
893
|
file: workflows/security-scan.yml
|
|
810
894
|
ref: main
|
|
811
|
-
target: .github/workflows/security-scan.yml
|
|
812
895
|
```
|
|
813
896
|
|
|
814
897
|
Use `avanti diff` in CI to detect drift — if a project's checked-in file no longer matches the source, the pipeline fails.
|
|
@@ -869,12 +952,12 @@ variables:
|
|
|
869
952
|
region: eu-west-1
|
|
870
953
|
|
|
871
954
|
files:
|
|
872
|
-
|
|
955
|
+
k8s/deployment.yaml:
|
|
956
|
+
src:
|
|
873
957
|
github:
|
|
874
958
|
repo: org/infra
|
|
875
959
|
file: k8s/deployment-template.yaml
|
|
876
960
|
ref: $env:DEPLOY_VERSION
|
|
877
|
-
target: k8s/deployment.yaml
|
|
878
961
|
replace:
|
|
879
962
|
- from: '{ENV}'
|
|
880
963
|
to: $env:ENVIRONMENT
|
|
@@ -891,24 +974,24 @@ Pull secrets at runtime and write them to local files with tight permissions. Th
|
|
|
891
974
|
```yaml
|
|
892
975
|
files:
|
|
893
976
|
# Single field from a Vault KV secret
|
|
894
|
-
|
|
977
|
+
config/db_password.txt:
|
|
978
|
+
src:
|
|
895
979
|
vault:
|
|
896
980
|
path: secret/myapp/db
|
|
897
981
|
field: password
|
|
898
|
-
target: config/db_password.txt
|
|
899
982
|
mode: '0600'
|
|
900
983
|
|
|
901
984
|
# Full Vault secret as JSON
|
|
902
|
-
|
|
985
|
+
config/secrets.json:
|
|
986
|
+
src:
|
|
903
987
|
vault:
|
|
904
988
|
path: secret/myapp/config
|
|
905
|
-
target: config/secrets.json
|
|
906
989
|
mode: '0600'
|
|
907
990
|
|
|
908
991
|
# Config file stored in S3
|
|
909
|
-
|
|
992
|
+
config/app.json:
|
|
993
|
+
src:
|
|
910
994
|
s3: s3://my-bucket/configs/app.json
|
|
911
|
-
target: config/app.json
|
|
912
995
|
mode: '0600'
|
|
913
996
|
```
|
|
914
997
|
|
|
@@ -916,13 +999,13 @@ For AWS SSM or other secret stores without a dedicated source type, `exec:` stil
|
|
|
916
999
|
|
|
917
1000
|
```yaml
|
|
918
1001
|
files:
|
|
919
|
-
|
|
1002
|
+
config/db.json:
|
|
1003
|
+
src:
|
|
920
1004
|
exec: >
|
|
921
1005
|
aws ssm get-parameter
|
|
922
1006
|
--name /myapp/db-config
|
|
923
1007
|
--with-decryption
|
|
924
1008
|
--query Parameter.Value --output text
|
|
925
|
-
target: config/db.json
|
|
926
1009
|
mode: '0600'
|
|
927
1010
|
```
|
|
928
1011
|
|
|
@@ -949,7 +1032,8 @@ variables:
|
|
|
949
1032
|
db_password: changeme
|
|
950
1033
|
|
|
951
1034
|
files:
|
|
952
|
-
-
|
|
1035
|
+
docker-compose.yml:
|
|
1036
|
+
src:
|
|
953
1037
|
- github:
|
|
954
1038
|
repo: n8n-io/n8n-hosting
|
|
955
1039
|
file: docker-caddy/docker-compose.yml
|
|
@@ -958,7 +1042,6 @@ files:
|
|
|
958
1042
|
repo: docker-library/docs
|
|
959
1043
|
file: postgres/compose.yaml
|
|
960
1044
|
ref: master
|
|
961
|
-
target: docker-compose.yml
|
|
962
1045
|
replace:
|
|
963
1046
|
- from: '${N8N_VERSION}'
|
|
964
1047
|
to: $n8n_version # pin version at pull time
|
|
@@ -981,19 +1064,22 @@ A single `avanti pull` populates a new project with everything it needs: editor
|
|
|
981
1064
|
|
|
982
1065
|
```yaml
|
|
983
1066
|
files:
|
|
984
|
-
|
|
1067
|
+
.editorconfig:
|
|
1068
|
+
src:
|
|
985
1069
|
github:
|
|
986
1070
|
repo: org/standards
|
|
987
1071
|
file: .editorconfig
|
|
988
1072
|
ref: main
|
|
989
1073
|
|
|
990
|
-
|
|
1074
|
+
.prettierrc:
|
|
1075
|
+
src:
|
|
991
1076
|
github:
|
|
992
1077
|
repo: org/standards
|
|
993
1078
|
file: .prettierrc
|
|
994
1079
|
ref: main
|
|
995
1080
|
|
|
996
|
-
|
|
1081
|
+
CLAUDE.md:
|
|
1082
|
+
src:
|
|
997
1083
|
- raw: |
|
|
998
1084
|
# AI Assistant Guidelines
|
|
999
1085
|
<!-- THIS FILE IS MANAGED — run `avanti pull` to update -->
|
|
@@ -1001,56 +1087,41 @@ files:
|
|
|
1001
1087
|
repo: org/ai-standards
|
|
1002
1088
|
file: CLAUDE.md
|
|
1003
1089
|
ref: main
|
|
1004
|
-
target: CLAUDE.md
|
|
1005
1090
|
|
|
1006
|
-
|
|
1091
|
+
.github/workflows/:
|
|
1092
|
+
src:
|
|
1007
1093
|
github:
|
|
1008
1094
|
repo: org/ci-templates
|
|
1009
1095
|
file: workflows/
|
|
1010
1096
|
ref: main
|
|
1011
|
-
target: .github/workflows/
|
|
1012
1097
|
```
|
|
1013
1098
|
|
|
1014
1099
|
### Self-managing Config
|
|
1015
1100
|
|
|
1016
|
-
avanti can
|
|
1017
|
-
|
|
1018
|
-
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.
|
|
1101
|
+
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.
|
|
1019
1102
|
|
|
1020
1103
|
```yaml
|
|
1021
1104
|
# ~/.avanti.yml
|
|
1022
|
-
variables:
|
|
1023
|
-
dotfiles: myorg/dotfiles
|
|
1024
|
-
|
|
1025
1105
|
files:
|
|
1026
|
-
|
|
1027
|
-
|
|
1106
|
+
$self:
|
|
1107
|
+
src:
|
|
1028
1108
|
github:
|
|
1029
|
-
repo:
|
|
1109
|
+
repo: myorg/dotfiles
|
|
1030
1110
|
file: avanti.yml
|
|
1031
1111
|
ref: $latest
|
|
1032
|
-
|
|
1112
|
+
```
|
|
1033
1113
|
|
|
1034
|
-
|
|
1035
|
-
- src:
|
|
1036
|
-
github:
|
|
1037
|
-
repo: $dotfiles
|
|
1038
|
-
file: .zshrc
|
|
1039
|
-
target: ~/.zshrc
|
|
1114
|
+
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.
|
|
1040
1115
|
|
|
1041
|
-
|
|
1042
|
-
github:
|
|
1043
|
-
repo: $dotfiles
|
|
1044
|
-
file: .gitconfig
|
|
1045
|
-
target: ~/.gitconfig
|
|
1046
|
-
```
|
|
1116
|
+
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.
|
|
1047
1117
|
|
|
1048
|
-
**Composable
|
|
1118
|
+
**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:
|
|
1049
1119
|
|
|
1050
1120
|
```yaml
|
|
1051
|
-
# ~/.avanti.yml
|
|
1121
|
+
# ~/.avanti.yml
|
|
1052
1122
|
files:
|
|
1053
|
-
|
|
1123
|
+
$self:
|
|
1124
|
+
src:
|
|
1054
1125
|
- github:
|
|
1055
1126
|
repo: myorg/platform
|
|
1056
1127
|
file: avanti/base.yml # org-wide entries and variables
|
|
@@ -1063,7 +1134,6 @@ files:
|
|
|
1063
1134
|
repo: myuser/dotfiles
|
|
1064
1135
|
file: avanti/personal.yml # personal overrides and extras
|
|
1065
1136
|
ref: main
|
|
1066
|
-
target: ~/.avanti.yml
|
|
1067
1137
|
yaml:
|
|
1068
1138
|
conflicts: last_wins # personal overrides win over team, team over org
|
|
1069
1139
|
arrays: concat # file lists from all layers are merged, not replaced
|
|
@@ -1103,8 +1173,8 @@ This scales to any number of machines or containers. Update the central repo onc
|
|
|
1103
1173
|
|
|
1104
1174
|
```sh
|
|
1105
1175
|
git clone ...
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1176
|
+
mise run install # install dependencies and set up git hooks
|
|
1177
|
+
mise run dev -- --help # run via tsx
|
|
1178
|
+
mise run test # run tests
|
|
1179
|
+
mise run build # compile to dist/
|
|
1110
1180
|
```
|