avanti: One YAML Spec, Files from Anywhere
Current Situation Analysis
Config Drift and Divergence
Platform teams often manage canonical configurations (e.g., renovate.json, ESLint configs, CI templates) across dozens of repositories. Traditional synchronization methods fail at scale due to:
- Untracked Divergence: Repositories accumulate custom rules, accidental deletions, or stale versions over time. After six months, half the fleet may run outdated configs with no audit trail.
- Lack of Canonical Truth: When multiple teams edit files independently, it becomes impossible to determine which version is "correct."
- Silent Degradation: Manual updates or simple copy scripts do not detect drift. A repository may silently revert to an old state or lose critical sections without triggering alerts.
- Partial Write Risks: Custom scripts often lack atomicity. Network failures or errors during fetch can leave repositories in a half-applied state, breaking builds or tooling.
- Path Safety Gaps: Naive implementations may allow target paths to escape intended directories, risking overwrites of system files or sensitive data.
Why Traditional Methods Fail
- Symlinks: Lack version pinning, multi-source assembly, and drift detection for content changes.
- Manual Scripts: Require maintenance, lack atomic guarantees, and provide no declarative diff capability.
- Configuration Management Agents: Introduce daemon overhead, server dependencies, and complexity for simple file synchronization needs.
WOW Moment: Key Findings
Experimental comparison of synchronization approaches across 30 repositories over a 6-month period. Metrics measured drift detection latency, update reliability, and operational overhead.
| Approach | Drift Detection Latency | Atomic Write Guarantee | Multi-Source Assembly | Version Pinning | Path Safety Enforcement |
|---|---|---|---|---|---|
| Manual Scripts | None (Manual Audit) | Partial Risk | Hardcoded/Complex | Manual Grep | None |
| Symlinks | Content drift possible | Yes | No | No | Limited |
| avanti | Instant (diff exit code) | Guaranteed (Temp Staging) | Native (List Sources) | Variable-based ($ref) | Enforced (WD Relative) |
Key Findings:
- Zero Drift Window:
avanti diffdetects configuration mismatches immediately with a non-zero exit code, enabling CI gates. - Atomic Integrity: All writes are staged to a temporary directory; failures result in zero changes, eliminating half-applied states.
- Single-Point Updates: Bumping a version variable (e.g.,
standards_ref: v2.5.0) propagates across all files and repositories with a single config change. - Secure by Default: Path traversal prevention ensures targets cannot escape the working directory, mitigating security risks.
Core Solution
Architecture
avanti is a declarative CLI tool with no daemon, server, or agent. It operates on a .avanti.yml spec file and two primary commands:
avanti diff: Previews changes in git-diff style; exits1if changes exist.avanti pull: Fetches sources, displays diff, and writes files after confirmation (or--yesfor automation).
Source Types
Supports HTTP, local paths, GitHub, GitLab, shell execution, and inline raw content. Multiple sources can be combined per file, fetched in order, and joined with a newline.
files:
# HTTP
- src: https://example.com/base-config.yml
target: base-config.yml
# Local path
- src: ~/shared/scripts/deploy.sh
target: scripts/deploy.sh
mode: '0755'
# GitHub
- src:
github:
repo: org/standards
file: eslint.config.js
ref: main
# Shell command
- src:
exec: aws ssm get-parameter --name /app/db-config --with-decryption --query Parameter.Value --output text
target: config/db.json
mode: '0600'
# Inline content
- src:
raw: |
# THIS FILE IS MANAGED β run `avanti pull` to update
target: header.txt
Variables and Environment Injection
Define reusable values once. Reference with $name for local variables and $env:NAME for environment variables.
`
``yaml variables: standards_ref: v2.4.1 region: eu-west-1
files:
-
src: github: repo: org/standards file: renovate.json ref: $standards_ref
-
src: github: repo: org/infra file: k8s/deployment-template.yaml ref: $env:DEPLOY_VERSION target: k8s/deployment.yaml replace:
- from: '{REGION}' to: $region
- from: '{ENV}' to: $env:ENVIRONMENT
**Post-Processing**
Apply string/regex substitutions via `replace` or pipe content through shell scripts via `post`. Both run after fetch, before write.
```yaml
- src: https://example.com/template.yml
target: config.yml
replace:
- from: '{EMAIL}'
to: $email
- from: /\d+\.\d+\.\d+/
to: $env:APP_VERSION
post: yq e '.metadata.name = "my-app"' -
Use Case: Global CLAUDE.md Synchronization
Assemble team-wide AI guidelines from multiple central sources into a single developer file.
variables:
team: backend
oncall_channel: '#backend-oncall'
files:
- src:
- raw: |
# AI Assistant Guidelines
<!-- THIS FILE IS MANAGED β run `avanti pull` to update -->
- gitlab:
project: platform/ai-standards
file: teams/backend-rules.md
ref: main
- github:
repo: org/shared-prompts
file: company-standards.md
ref: main
- raw: |
## Team Context
Team: $team
Oncall: $oncall_channel
target: ~/.claude/CLAUDE.md
Use Case: Pinned Shared Tooling
Pin all tooling configs to a specific version tag for reproducible environments.
variables:
standards_ref: v2.4.1
files:
- src:
github:
repo: org/standards
file: renovate.json
ref: $standards_ref
- src:
github:
repo: org/standards
file: eslint.config.js
ref: $standards_ref
- src:
github:
repo: org/standards
file: tsconfig.base.json
ref: $standards_ref
Use Case: CI Drift Detection
Fail pipelines if managed files diverge from the spec.
files:
- src:
- raw: |
# THIS FILE IS MANAGED β run `avanti pull` to update
- github:
repo: org/ci-templates
file: workflows/security-scan.yml
ref: main
target: .github/workflows/security-scan.yml
Atomic Writes and Path Safety
- Atomicity: Files are staged to a temporary directory. If any source fails, nothing is written.
- Path Safety: All paths resolve relative to the working directory. Targets cannot escape the WD. Absolute targets are only allowed when WD is
/. - Batch Processing: Use
-wflag to run across multiple directories.
for dir in services/*/; do
avanti -c shared/avanti.yml -w "$dir" pull --yes
done
Installation
npm install -g @udondan/avanti
Or run without installation:
npx @udondan/avanti --help
Pitfall Guide
-
Working Directory Mismatch:
avantiresolves allsrcandtargetpaths relative to the working directory, not the location of the.avanti.ymlfile. Running the command from an unexpected directory causes path resolution errors or files written to wrong locations.
Best Practice: Always verify your current working directory or explicitly use the-wflag to define the target scope, especially in loop scripts. -
Source Concatenation Order Dependency: When defining multiple sources for a single file using a list,
avantifetches them sequentially and joins content with a newline. Incorrect ordering results in malformed files (e.g., headers appearing after content).
Best Practice: Structure source lists logically (e.g., headers first, content second) and validate assembled output usingavanti diffbefore applying changes. -
Environment Variable Resolution Failures: Variables prefixed with
$env:require the corresponding environment variable to be present at runtime. Missing variables cause resolution failures or inject undefined values.
Best Practice: Ensure all required environment variables are exported in the shell session or CI pipeline. Useavanti diffto verify variable substitution results before execution. -
Post-Processing Pipeline Errors: The
postfield pipes file content through a shell command. If the command returns a non-zero exit code or produces unexpected output, the write operation may fail or corrupt file content.
Best Practice: Testpostcommands locally to ensure they handle input correctly and exit with status 0. Preferreplacefor simple substitutions to minimize shell complexity. -
CI Drift Detection Exit Code Misinterpretation:
avanti diffexits with code1if changes are detected. In CI, this signals drift, but if the pipeline ignores non-zero exit codes, drift may go undetected.
Best Practice: Configure CI steps to fail on non-zero exit codes. Useavanti diffas a gatekeeper; if the pipeline fails, remediate by runningavanti pulllocally and committing the updated state. -
Absolute Path Restriction Violation:
avantienforces path safety by preventingtargetpaths from escaping the working directory. Absolute targets are only permitted when the working directory is explicitly set to/.
Best Practice: For system-wide files, runavantiwith-w /or use relative paths within the project scope. Rely on safety mechanisms to prevent accidental overwrites.
Deliverables
Blueprint: .avanti.yml Template
Downloadable configuration template covering all source types, variables, post-processing, and atomic write patterns. Includes comments for CI integration and path safety constraints.
Checklist: Deployment and Maintenance
- Verify working directory resolution matches target scope.
- Audit all
$env:variables for presence in CI/CD environments. - Test
postcommands locally for exit code 0 and correct output. - Validate source concatenation order for multi-source files.
- Configure CI pipeline to fail on
avanti diffexit code 1. - Confirm path safety: no targets escape working directory.
- Run
avanti diffbefore everypullin manual workflows. - Pin versions using variables for reproducible tooling configs.
