flecto 2.0.0 → 3.0.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 CHANGED
@@ -1,21 +1,39 @@
1
- # Flecto
1
+ <p align="center">
2
+ <img src="docs/assets/flecto-hero.png" alt="Flecto — semantic config watcher" width="920"/>
3
+ </p>
2
4
 
3
- **Flecto watches your config files and tells you exactly what changed — in plain English.**
5
+ <h1 align="center">Flecto</h1>
4
6
 
5
- No more staring at raw line diffs. When your `.env`, `YAML`, `JSON`, `TOML`, or `INI` file changes, Flecto shows you what actually happened:
7
+ <p align="center">
8
+ <strong>Know what your config actually changed — and whether it's risky.</strong>
9
+ </p>
6
10
 
7
- ```
8
- [10:42:31] config/prod.yaml 3 changes
9
- ~ database.pool_size: 5 → 20
10
- + feature_flags.dark_mode: true
11
- - deprecated.old_key
12
- ```
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/flecto"><img alt="npm" src="https://img.shields.io/npm/v/flecto?style=flat-square&color=34d399&labelColor=0b1220"/></a>
13
+ <a href="https://github.com/myselfsiddharth/Flecto/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/myselfsiddharth/Flecto/ci.yml?branch=main&style=flat-square&label=CI&labelColor=0b1220"/></a>
14
+ <a href="LICENSE"><img alt="MIT" src="https://img.shields.io/badge/license-MIT-8fa3bf?style=flat-square&labelColor=0b1220"/></a>
15
+ <a href="#documentation"><img alt="Docs" src="https://img.shields.io/badge/docs-read-34d399?style=flat-square&labelColor=0b1220"/></a>
16
+ </p>
17
+
18
+ <p align="center">
19
+ <img src="docs/assets/demo-watch.svg" alt="Flecto reporting semantic config changes in the terminal" width="920"/>
20
+ </p>
13
21
 
14
22
  ---
15
23
 
16
- ## Why Flecto?
24
+ Config drives the parts of a system that break loudest: connection pools, feature
25
+ flags, TLS, retries, secrets. But we still review it as text — so a reordered key
26
+ looks identical to a doubled pool size, and `debug: true` slips through in a
27
+ 40-line formatting diff.
17
28
 
18
- Standard file watchers tell you *a file changed*. Flecto tells you *what* changed and *why it might matter* — flagging secrets, dangerous toggles, and risky config jumps automatically.
29
+ Flecto reads config as structure, not lines. It tells you what changed in plain
30
+ English, flags what looks risky, and gives you an exit code to gate on.
31
+
32
+ | Reviewing config without Flecto | With Flecto |
33
+ |---|---|
34
+ | `+ 40 lines of YAML noise` | `~ database.pool_size: 5 → 20` |
35
+ | Hope someone notices `debug: true` | Policy finding → build fails |
36
+ | "Something in `.env` changed" | The exact keys, with secrets masked |
19
37
 
20
38
  ---
21
39
 
@@ -25,340 +43,456 @@ Standard file watchers tell you *a file changed*. Flecto tells you *what* change
25
43
  npm install -g flecto
26
44
  ```
27
45
 
28
- After that, `flecto` is available globally from anywhere.
46
+ Requires **Node.js 20.19.0+**. Verify:
47
+
48
+ ```bash
49
+ flecto --version
50
+ flecto doctor
51
+ ```
52
+
53
+ Prefer not to install globally? Every example below works with
54
+ `npx --yes flecto@3` instead of `flecto`.
29
55
 
30
56
  ---
31
57
 
32
- ## Quick Start
58
+ ## Quick start
59
+
60
+ A complete walkthrough, start to finish. Copy-paste it anywhere.
33
61
 
34
- Watch any config file:
62
+ **1. Create a config file to track.**
35
63
 
36
64
  ```bash
37
- flecto watch config/prod.yaml
38
- flecto watch .env
39
- flecto watch settings.json
40
- flecto watch pyproject.toml
65
+ mkdir flecto-demo && cd flecto-demo && mkdir config
66
+ cat > config/prod.yaml <<'EOF'
67
+ database:
68
+ host: db.internal
69
+ pool_size: 5
70
+ ssl: true
71
+ logging:
72
+ level: info
73
+ debug: false
74
+ EOF
41
75
  ```
42
76
 
43
- That's it. Flecto starts watching and prints a clear summary every time something changes.
77
+ **2. Save it as your baseline.**
44
78
 
45
- ---
79
+ ```bash
80
+ flecto watch config/prod.yaml --snapshot
81
+ ```
46
82
 
47
- ## Common Use Cases
83
+ ```
84
+ ✓ Snapshot saved: /path/to/flecto-demo/.flecto-snapshots/4b8cbbd70d1832a2.json
85
+ ```
48
86
 
49
- ### Watch multiple files at once
87
+ **3. Make the kind of edit that causes incidents.**
50
88
 
51
89
  ```bash
52
- flecto watch "config/**/*.yaml" ".env"
90
+ cat > config/prod.yaml <<'EOF'
91
+ database:
92
+ host: db.internal
93
+ pool_size: 20
94
+ ssl: true
95
+ logging:
96
+ level: info
97
+ debug: true
98
+ EOF
53
99
  ```
54
100
 
55
- ### See detailed before/after values
101
+ **4. Ask what changed.**
56
102
 
57
103
  ```bash
58
- flecto watch config/prod.yaml --mode verbose
104
+ flecto watch config/prod.yaml --diff
105
+ ```
106
+
107
+ ```
108
+ /path/to/flecto-demo/config/prod.yaml — 2 changes from snapshot:
109
+ ~ database.pool_size: 5 → 20
110
+ ~ logging.debug: false → true
59
111
  ```
60
112
 
61
- ### Ignore noisy keys (like timestamps)
113
+ Two sentences instead of a diff you have to interpret. Now let Flecto judge it:
62
114
 
63
115
  ```bash
64
- flecto watch config/prod.yaml --ignore "updated_at,meta.timestamp"
116
+ flecto ci config/prod.yaml --format github-annotations
65
117
  ```
66
118
 
67
- You can ignore exact keys, entire subtrees, wildcards, or keys anywhere in the file:
119
+ ```
120
+ ::warning title=flecto changed::database.pool_size
121
+ ::warning title=flecto changed::logging.debug
122
+ ::warning title=flecto policy pool-size-jump [default]::database.pool_size: Pool size increased from 5 to 20 (>=2x).
123
+ ::error title=flecto policy dangerous-toggle-enabled [default]::logging.debug: Potentially dangerous toggle enabled.
124
+ ```
68
125
 
69
- | Pattern | What it ignores |
70
- |---|---|
71
- | `meta.timestamp` | That exact key |
72
- | `meta` | Everything under `meta.*` |
73
- | `servers[*].meta.timestamp` | That key inside any array item |
74
- | `**.updated_at` | Any key named `updated_at`, anywhere |
126
+ Exit code `1`. In CI, that's a failed build — before the change ships.
75
127
 
76
- ### Run a command when something changes
128
+ **5. Watch it live.** Leave this running and edit the file in another window:
77
129
 
78
130
  ```bash
79
- flecto watch .env --command "docker-compose restart app"
131
+ flecto watch config/prod.yaml
80
132
  ```
81
133
 
82
- Flecto passes the changes as JSON to your command via the `FLECTO_CHANGES` environment variable.
134
+ ```
135
+ flecto watching /path/to/flecto-demo/config/prod.yaml
136
+ Press Ctrl+C to stop.
83
137
 
84
- ### Send changes to a webhook
138
+ [18:24:48] /path/to/flecto-demo/config/prod.yaml 2 changes
139
+ ~ database.pool_size: 5 → 20
140
+ ~ logging.debug: false → true
141
+ ! policy(warn) [default] database.pool_size: Pool size increased from 5 to 20 (>=2x).
142
+ ! policy(error) [default] logging.debug: Potentially dangerous toggle enabled.
143
+ ```
85
144
 
86
- ```bash
87
- flecto watch config/prod.yaml --webhook https://hooks.example.com/notify
145
+ That's the whole product. Everything below is depth.
146
+
147
+ ---
148
+
149
+ ## What you can do with it
150
+
151
+ ### Catch risky changes before they merge
152
+
153
+ Add one step to your workflow and risky config edits show up as annotations on
154
+ the pull request:
155
+
156
+ ```yaml
157
+ permissions:
158
+ contents: read
159
+
160
+ steps:
161
+ - uses: actions/checkout@v7
162
+ with:
163
+ fetch-depth: 2
164
+ - uses: myselfsiddharth/Flecto/.github/actions/flecto-ci@main
165
+ with:
166
+ targets: config/**/*.{yaml,yml,json,toml,ini}
167
+ snapshot-ref: HEAD~1
88
168
  ```
89
169
 
90
- Add auth headers if needed:
170
+ Prefer a summary nobody can miss? `--format pr-comment` renders the changes and
171
+ policy findings as markdown and, when you opt in with `--pr-comment-post` inside
172
+ a GitHub PR run, keeps **one** sticky comment up to date instead of adding a new
173
+ one per push. Without that flag it just prints the markdown, so it can't post
174
+ from your laptop.
175
+
176
+ The `flecto-pr-risk` Action is that, packaged — the whole adoption is one
177
+ `uses:`, with the baseline resolved from the pull request rather than `HEAD~1`:
178
+
179
+ ```yaml
180
+ permissions:
181
+ contents: read
182
+ pull-requests: write
183
+
184
+ steps:
185
+ - uses: actions/checkout@v7
186
+ with:
187
+ fetch-depth: 0
188
+ - uses: myselfsiddharth/Flecto/.github/actions/flecto-pr-risk@main
189
+ ```
190
+
191
+ A fork's pull request gets a read-only token, so the comment is skipped with a
192
+ warning there — the check itself still runs and still fails on risky changes.
193
+
194
+ Works on any CI runner — it's a plain CLI with meaningful exit codes.
195
+ → **[CI guide](docs/ci.md)**
196
+
197
+ ### Trigger automation on change
198
+
199
+ Restart a service, reload a process, or notify an endpoint whenever config moves:
91
200
 
92
201
  ```bash
202
+ flecto watch .env --command "docker-compose restart app"
203
+
93
204
  flecto watch config/prod.yaml \
94
205
  --webhook https://hooks.example.com/notify \
95
- --webhook-header "Authorization: Bearer TOKEN"
206
+ --delivery-mode at-least-once
96
207
  ```
97
208
 
98
- Each webhook payload includes a full event envelope:
209
+ Changes arrive as a versioned JSON envelope, and `at-least-once` persists and
210
+ retries failed deliveries.
99
211
 
100
- ```json
101
- {
102
- "schema_version": "2.0",
103
- "event_id": "uuid",
104
- "event_type": "changes",
105
- "emitted_at": "2026-04-14T10:42:31.000Z",
106
- "file": "/absolute/path/to/config/prod.yaml",
107
- "changes": [
108
- { "type": "changed", "path": "database.pool_size", "before": 5, "after": 20 }
109
- ],
110
- "policies": [
111
- {
112
- "id": "pool-size-jump",
113
- "severity": "warn",
114
- "path": "database.pool_size",
115
- "message": "Pool size increased from 5 to 20 (>=2x).",
116
- "pack": "default"
117
- }
118
- ]
119
- }
212
+ Posting straight to chat needs no receiver of your own — `--webhook-format`
213
+ shapes the body for Slack, Discord, or Teams, colored by the highest policy
214
+ severity:
215
+
216
+ ```bash
217
+ flecto watch config/prod.yaml \
218
+ --webhook "https://hooks.slack.com/services/T000/B000/XXXX" \
219
+ --webhook-format slack
120
220
  ```
121
221
 
122
- Envelope JSON Schema: [`schemas/flecto-envelope-2.0.json`](schemas/flecto-envelope-2.0.json).
222
+ **[Webhooks and commands](docs/webhooks.md)**
223
+
224
+ ### Compare two environments
123
225
 
124
- ### Policy packs and profiles
226
+ "Works in staging, fails in prod" is usually one key apart:
125
227
 
126
228
  ```bash
127
- flecto ci config/prod.yaml --profile prod --snapshot-ref HEAD~1
229
+ flecto compare config/prod.yaml config/staging.yaml
128
230
  ```
129
231
 
130
- `.flectorc.json` example:
131
-
132
- ```json
133
- {
134
- "defaults": {
135
- "policies": ["default"],
136
- "maskSecrets": false
137
- },
138
- "profiles": {
139
- "prod": {
140
- "policies": ["default", "strict-prod"],
141
- "maskSecrets": true
142
- }
143
- }
144
- }
232
+ ```
233
+ "+" exists only in the compared file, "-" only in the baseline, "~" differs
234
+ /path/to/config/staging.yaml — 2 changes from /path/to/config/prod.yaml:
235
+ - only_in_prod: true
236
+ ~ database.pool_size: 5 → 20
237
+ ! policy(warn) [default] database.pool_size: Pool size increased from 5 to 20 (>=2x).
145
238
  ```
146
239
 
147
- Profile selection: `--profile` > `FLECTO_PROFILE` > defaults. Custom packs live in `policies/<id>.json`. Local ESM plugins export `evaluate(changes, ctx)`.
240
+ The first file is the baseline, the files don't have to share a format, and
241
+ `--format json` gives you the same output `flecto ci` produces.
242
+ → **[CLI reference](docs/cli-reference.md#flecto-compare-filea-fileb)**
148
243
 
149
- ### Opt-in array identity matching
244
+ ### Track drift over time
150
245
 
151
246
  ```bash
152
- flecto watch config/services.yaml --array-id-key id
247
+ flecto history config/prod.yaml --limit 10
153
248
  ```
154
249
 
155
- Without the flag, arrays still diff by index (1.x behavior).
156
-
157
- ### Migrating from envelope 1.1
250
+ Snapshots stay on your machine in `.flecto-snapshots/`. Nothing is uploaded and
251
+ no account is required. → **[CLI reference](docs/cli-reference.md#flecto-history-files)**
158
252
 
159
- - `schema_version` is now `"2.0"`
160
- - Envelope type name is `FlectoEnvelope` (was `SentinelEnvelope` in docs/types only)
161
- - New `policies` array on change envelopes
162
- - Webhook headers are unchanged (`X-Flecto-*`)
163
- ### Use both command and webhook together
253
+ ### Share what changed before the incident
164
254
 
165
255
  ```bash
166
- flecto watch .env \
167
- --command "make reload" \
168
- --webhook https://hooks.example.com/notify
256
+ flecto report --limit 20 --mask-secrets --output drift.html
169
257
  ```
170
258
 
171
- ### Retry on failure
259
+ One HTML file from that same local history: a timeline per file, every change
260
+ with its UTC timestamp, and policy findings grouped by severity. Fully
261
+ self-contained — inline styles, no fonts, no CDN scripts, no analytics — so you
262
+ can attach it to an incident thread and it renders offline. No server and no
263
+ account, same as everything else here.
264
+ → **[CLI reference](docs/cli-reference.md#flecto-report-files)**
265
+
266
+ ### Review a Kubernetes change before it reaches a cluster
267
+
268
+ ArgoCD, Flux, and `helm diff` compare the cluster to the repo — which needs a
269
+ cluster, and an apply that already happened. Flecto compares the manifests *this
270
+ pull request would produce* against the ones `main` produces:
172
271
 
173
272
  ```bash
174
- flecto watch config/prod.yaml \
175
- --webhook https://hooks.example.com/notify \
176
- --delivery-mode at-least-once \
177
- --on-alert-failure retry
273
+ helm template api ./charts/api -f values/prod.yaml > /tmp/head.yaml
274
+ flecto compare /tmp/base.yaml /tmp/head.yaml --policies kubernetes --fail-on error
178
275
  ```
179
276
 
180
- | Flag | Options | What it does |
181
- |---|---|---|
182
- | `--delivery-mode` | `best-effort` (default), `at-least-once` | Whether to persist and retry failed webhook events |
183
- | `--on-alert-failure` | `warn`, `exit`, `retry` | What happens if a command or webhook fails |
277
+ ```
278
+ ~ Service/prod/api.spec.type: "ClusterIP" → "LoadBalancer"
279
+ ! policy(error) [kubernetes] Service type is LoadBalancer, which exposes the
280
+ workload outside the cluster. Confirm the exposure is intended.
281
+ ```
184
282
 
185
- ---
283
+ Multi-document YAML is keyed by `kind/namespace/name`, so findings name the
284
+ resource. Flecto never runs `helm` or `kustomize` — you render, it diffs, so any
285
+ renderer works and no binary is needed in CI.
286
+ → **[Kubernetes](docs/kubernetes.md)**
186
287
 
187
- ## Snapshots & Diffs
288
+ ### Encode your own rules
188
289
 
189
- Save a baseline snapshot of your file:
290
+ Beyond the built-in packs, write rules as declarative JSON or YAML — no code:
190
291
 
191
- ```bash
192
- flecto watch config/prod.yaml --snapshot
193
- # Saved to .flecto-snapshots/<id>.json
292
+ ```json
293
+ {
294
+ "id": "risky-feature-enable",
295
+ "severity": "error",
296
+ "allOf": [
297
+ { "match": { "pathPrefix": "features." } },
298
+ { "afterTruthy": true }
299
+ ]
300
+ }
194
301
  ```
195
302
 
196
- Then compare the current file against it anytime:
303
+ For anything a predicate can't express, a local ESM plugin exporting
304
+ `evaluate(changes, ctx)` gets the full change set.
305
+ → **[Writing policy packs](docs/policy-packs.md)** · **[Plugins](docs/plugins.md)**
306
+
307
+ ### Cut the noise
197
308
 
198
309
  ```bash
199
- flecto watch config/prod.yaml --diff
310
+ flecto watch config/prod.yaml --ignore "updated_at,**.meta.timestamp"
200
311
  ```
201
312
 
202
- Exit codes:
203
- - `0` no changes (file is clean)
204
- - `1` — changes detected
205
-
206
- This is useful in deployment scripts and pre-commit hooks.
313
+ Arrays of objects are matched by `id` or `name`, so reordering a list of named
314
+ services doesn't read as a wall of changes.
315
+ **[Configuration](docs/configuration.md)**
207
316
 
208
317
  ---
209
318
 
210
- ## CI Mode
319
+ ## Built-in policy packs
211
320
 
212
- Catch risky config changes before they ship:
321
+ | Pack | Catches |
322
+ |---|---|
323
+ | `default` | Secret-like keys added or changed, secret-shaped *values* under any key, dangerous toggles, pool-size jumps |
324
+ | `strict-prod` | The same ground, with production-grade severities and matching |
325
+ | `compose` | Privileged services, host networking, Docker socket mounts, sensitive bind mounts |
326
+ | `kubernetes` | Privileged containers, host namespaces, weakened `runAsNonRoot`, added `SYS_ADMIN`, unpinned images, replica jumps, dropped limits, `LoadBalancer`/`NodePort` exposure |
327
+ | `node-runtime` | Dropped engine requirements, TLS verification bypasses, debug/inspector flags |
328
+ | `terraform` | Replaced and destroyed stateful resources, ingress opened to `0.0.0.0/0`, IAM wildcards, public S3, capacity jumps |
329
+ | `sops` | Decryption recipients added or removed, a MAC that moved on its own, a file that stopped being encrypted |
213
330
 
214
331
  ```bash
215
- flecto ci "config/**/*.yaml" \
216
- --snapshot-ref HEAD~1 \
217
- --format github-annotations \
218
- --fail-on "changed,policy,error"
332
+ flecto policies list # see what resolves here, built-in and local
333
+ flecto ci "config/**/*.yaml" --policies "default,strict-prod" --fail-on policy
219
334
  ```
220
335
 
221
- **Output formats:** `json`, `ndjson`, `github-annotations`
336
+ Pass files or glob patterns, quoted so your shell doesn't expand them first — a
337
+ bare directory is not a valid target.
222
338
 
223
- **Fail triggers:** `changed`, `added`, `removed`, `policy`, `error`, `warn`
339
+ A local `policies/<id>.json` overrides the built-in pack of the same id, and
340
+ `severityRemap` raises or silences individual rules per profile without forking
341
+ anything. → **[Policy packs](docs/policy-packs.md)**
224
342
 
225
- ---
343
+ Community packs ship on npm as `flecto-pack-<id>` packages — a package name and
344
+ one declarative JSON file, nothing else:
226
345
 
227
- ## Built-in Policy Checks
346
+ ```bash
347
+ npm install --save-dev flecto-pack-deployment-safety
348
+ flecto policies add deployment-safety
349
+ ```
228
350
 
229
- Flecto automatically flags changes that look risky:
351
+ `policies add` validates the pack, writes it to `policies/deployment-safety.json`,
352
+ and runs no code from the package. →
353
+ **[Installing community packs](docs/policy-packs.md#installing-a-community-pack)**
230
354
 
231
- - 🔑 **Secrets touched** — keys named `secret`, `token`, `password`, `api_key`, etc.
232
- - ⚠️ **Dangerous toggles** — `debug: true`, `disable_tls`, `skip_tls_verify`, `allow_insecure`
233
- - 📈 **Large pool size jumps** — `pool_size` doubled or more
355
+ ---
356
+
357
+ ## Supported formats
234
358
 
235
- Policy violations can fail your CI pipeline with `--fail-on policy`.
359
+ | Format | Extensions |
360
+ |---|---|
361
+ | JSON | `.json` |
362
+ | YAML | `.yaml`, `.yml` |
363
+ | TOML | `.toml` |
364
+ | INI | `.ini` |
365
+ | dotenv | `.env`, `.env.*`, `*.env` |
366
+ | age (armored) | `.age`, or any file whose contents are one armored blob |
367
+
368
+ Multi-document YAML (`---`-separated, the usual shape of a Kubernetes manifest)
369
+ is supported. Each document is diffed under its own key — `kind/name` for
370
+ Kubernetes-shaped documents, so a document inserted at the top of the file does
371
+ not renumber every other path. →
372
+ **[Multi-document YAML](docs/configuration.md#multi-document-yaml)**
236
373
 
237
374
  ---
238
375
 
239
- ## Tuning for Network Drives or Odd Editors
376
+ ## Encrypted files
240
377
 
241
- Some editors write files via a temp file swap, which can confuse standard watchers. Enable polling mode:
378
+ A `sops`- or age-encrypted file is detected from its **contents**, and diffed
379
+ structurally:
242
380
 
243
- ```bash
244
- flecto watch config/prod.yaml --polling --interval 500
381
+ ```
382
+ + cache: {"ttl_seconds":300}
383
+ ~ database.password: <encrypted value changed>
384
+ + sops.age.age1exampleexample…: {"recipient":"age1exampleexample…","enc":"<encrypted value>"}
245
385
  ```
246
386
 
247
- Default polling interval is `100ms`. Polling is off by default.
387
+ You get keys added and removed, which encrypted values moved, and — the useful
388
+ part — who can decrypt the file. A recipient added is a genuine security event
389
+ and the `sops` pack raises it as one.
248
390
 
249
- ---
391
+ **Flecto never decrypts.** It never shells out to `sops` or `age`, never reads a
392
+ key file or agent socket, and never prints ciphertext — not even without
393
+ `--mask-secrets`. Ciphertext is replaced with an opaque sentinel in the parser,
394
+ so no diff, snapshot, webhook, or report can carry it. →
395
+ **[Encrypted files](docs/encrypted-files.md)**
250
396
 
251
- ## Config File (.flectorc)
397
+ ---
252
398
 
253
- Set your defaults once so you don't have to repeat flags every time.
399
+ ## Configuration
254
400
 
255
- Generate a starter config:
401
+ Most teams commit a `.flectorc` so local runs and CI agree:
256
402
 
257
403
  ```bash
258
404
  flecto init
259
405
  ```
260
406
 
261
- Flecto looks for `.flectorc`, `.flectorc.json`, `.flectorc.yaml`, or `.flectorc.yml`.
262
-
263
- Example:
264
-
265
407
  ```json
266
408
  {
267
409
  "defaults": {
268
- "mode": "compact",
269
- "interval": 100,
270
- "ignore": ["**.updated_at"],
271
- "deliveryMode": "best-effort",
272
- "onAlertFailure": "warn"
410
+ "policies": ["default"],
411
+ "ignore": ["**.updated_at"]
273
412
  },
274
413
  "profiles": {
275
414
  "dev": { "mode": "verbose" },
276
- "ci": { "failOn": "policy,error" }
415
+ "ci": { "failOn": "policy,error" },
416
+ "prod": {
417
+ "policies": ["default", "strict-prod"],
418
+ "severityRemap": { "pool-size-jump": "error" },
419
+ "maskSecrets": true
420
+ }
277
421
  },
278
- "files": ["config/**/*.yaml", ".env"],
279
- "exclude": ["**/node_modules/**"]
422
+ "files": ["config/**/*.{yaml,yml,json,toml,ini}", ".env"]
280
423
  }
281
424
  ```
282
425
 
283
- Use a named profile:
284
-
285
426
  ```bash
286
427
  flecto watch --profile dev
287
428
  flecto ci --profile ci
288
429
  ```
289
430
 
290
- CLI flags always override profile/default values.
291
-
292
- Verify your setup:
293
-
294
- ```bash
295
- flecto doctor
296
- ```
431
+ Explicit CLI flags win over profiles, which win over `defaults`.
432
+ → **[Full configuration reference](docs/configuration.md)**
297
433
 
298
434
  ---
299
435
 
300
- ## Output Format Reference
301
-
302
- ### Compact (default)
303
-
304
- ```
305
- [HH:MM:SS] <filepath> — N changes
306
- ~ path: before → after (yellow — value changed)
307
- + path: value (green — key added)
308
- - path: value (red — key removed)
309
- ```
310
-
311
- ### Verbose (`--mode verbose`)
436
+ ## Commands
312
437
 
313
- ```
314
- [HH:MM:SS] <filepath> — N changes
315
- ~ path
316
- before: old_value
317
- after: new_value
318
- + path: value
319
- (key added)
320
- ```
438
+ | Command | What it does |
439
+ |---|---|
440
+ | `flecto watch [files...]` | Watch for changes and print them as they happen |
441
+ | `flecto watch --snapshot` | Save the current state as a baseline |
442
+ | `flecto watch --diff` | Compare against the baseline and exit |
443
+ | `flecto ci [files...]` | One-shot check with a gate-able exit code |
444
+ | `flecto compare <fileA> <fileB>` | Diff two files against each other (`fileA` is the baseline) |
445
+ | `flecto plan <planFiles...>` | Review `terraform show -json` output and gate on it |
446
+ | `flecto history [files...]` | Summarize drift across local snapshots |
447
+ | `flecto report [files...]` | Render that history as a self-contained HTML file |
448
+ | `flecto policies add <name>` | Install a pack from an `flecto-pack-*` npm package |
449
+ | `flecto policies list` | List available policy packs |
450
+ | `flecto policies test <dir>` | Assert pack and plugin findings from fixtures |
451
+ | `flecto init` | Create a `.flectorc` from detected stack signals |
452
+ | `flecto doctor` | Check setup, config, and environment |
453
+
454
+ → **[Every flag, every command](docs/cli-reference.md)**
321
455
 
322
456
  ---
323
457
 
324
- ## Error Handling
325
-
326
- Flecto is designed to keep running even when things go wrong:
458
+ ## Documentation
327
459
 
328
- | Situation | Behavior |
460
+ | Guide | Covers |
329
461
  |---|---|
330
- | File not found | Error message + exit 1 |
331
- | Unsupported file format | Lists supported extensions + exit 1 |
332
- | File has a parse error | Warning shown, last valid state kept, watching continues |
333
- | Command fails | Warning shown, watcher continues |
334
- | Webhook fails | Warning shown, watcher continues |
335
- | Ctrl+C | Clean shutdown message |
462
+ | **[CLI reference](docs/cli-reference.md)** | Every command, flag, and exit code |
463
+ | **[Configuration](docs/configuration.md)** | `.flectorc`, profiles, ignore patterns, array identity, masking |
464
+ | **[Encrypted files](docs/encrypted-files.md)** | SOPS and age: what is detected, what is reported, why nothing is decrypted |
465
+ | **[CI](docs/ci.md)** | Baselines, fail triggers, output formats, the bundled GitHub Actions |
466
+ | **[Kubernetes](docs/kubernetes.md)** | Diffing rendered Helm/Kustomize manifests before they reach a cluster |
467
+ | **[Terraform plans](docs/terraform.md)** | Reviewing `terraform show -json` output and the `terraform` pack |
468
+ | **[Webhooks and commands](docs/webhooks.md)** | Envelope shape, delivery modes, command environment |
469
+ | **[Policy packs](docs/policy-packs.md)** | Writing declarative rules |
470
+ | **[Plugins](docs/plugins.md)** · **[Cookbook](docs/plugin-cookbook.md)** | Rules that need real code |
471
+ | **[Troubleshooting](docs/troubleshooting.md)** | When something doesn't behave |
472
+ | **[Changelog](CHANGELOG.md)** | Release history and migration notes |
336
473
 
337
474
  ---
338
475
 
339
- ## Running Tests
476
+ ## How it works
340
477
 
341
- ```bash
342
- npm test
343
- # or directly:
344
- node --test test/*.test.js
345
- ```
478
+ 1. **Parse** — format detected by extension or dotenv naming → structured values
479
+ 2. **Watch** — [chokidar](https://github.com/paulmillr/chokidar) with debounce
480
+ 3. **Diff** — semantic tree comparison with ignore rules and array identity
481
+ 4. **Evaluate** — policy packs and plugins → severity-tagged findings
482
+ 5. **Emit** — a versioned envelope (`schema_version: "2.0"`)
483
+ 6. **Deliver** — terminal output, shell command, webhook, or CI annotations
346
484
 
347
- Tests cover the differ, watcher behavior, webhook delivery, policy logic, and CI command behavior.
485
+ Flecto runs entirely on your machine. Snapshots are local files, and nothing
486
+ leaves the process unless you configure a webhook or command.
348
487
 
349
488
  ---
350
489
 
351
- ## How It Works
352
-
353
- 1. **Parser** — detects the file format by extension and parses it into structured JS values.
354
- 2. **Watcher** — uses [chokidar](https://github.com/paulmillr/chokidar) with debouncing so rapid saves don't flood you with events.
355
- 3. **Differ** — computes a semantic diff (not a line diff), supporting objects, arrays, scalars, and ignore rules.
356
- 4. **Policy engine** — inspects the changes for patterns that look risky and adds severity findings.
357
- 5. **Envelope** — wraps each batch of changes in a versioned event schema ready for automation.
358
- 6. **Alerter** — delivers events via command execution and/or webhook, with configurable retry logic.
359
-
360
- ---
490
+ ## Project
361
491
 
362
- ## License
492
+ - **Questions and ideas** — [Discussions](https://github.com/myselfsiddharth/Flecto/discussions)
493
+ - **Bugs and requests** — [Issues](https://github.com/myselfsiddharth/Flecto/issues)
494
+ - **Contributing** — [CONTRIBUTING.md](CONTRIBUTING.md) · [Code of Conduct](CODE_OF_CONDUCT.md)
495
+ - **Security** — [SECURITY.md](SECURITY.md), private disclosure only
496
+ - **Roadmap** — [Milestones](https://github.com/myselfsiddharth/Flecto/milestones)
363
497
 
364
- MIT see [LICENSE](./LICENSE).
498
+ Released under the [MIT License](LICENSE).