@probelabs/visor 0.1.130 → 0.1.131

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.
Files changed (134) hide show
  1. package/README.md +7 -0
  2. package/defaults/visor.yaml +5 -2
  3. package/dist/ai-review-service.d.ts +2 -0
  4. package/dist/ai-review-service.d.ts.map +1 -1
  5. package/dist/cli-main.d.ts.map +1 -1
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/config/cli-handler.d.ts +5 -0
  8. package/dist/config/cli-handler.d.ts.map +1 -0
  9. package/dist/config/config-reloader.d.ts +24 -0
  10. package/dist/config/config-reloader.d.ts.map +1 -0
  11. package/dist/config/config-snapshot-store.d.ts +21 -0
  12. package/dist/config/config-snapshot-store.d.ts.map +1 -0
  13. package/dist/config/config-watcher.d.ts +19 -0
  14. package/dist/config/config-watcher.d.ts.map +1 -0
  15. package/dist/config/types.d.ts +16 -0
  16. package/dist/config/types.d.ts.map +1 -0
  17. package/dist/defaults/visor.yaml +5 -2
  18. package/dist/docs/ai-configuration.md +139 -0
  19. package/dist/docs/ai-custom-tools.md +30 -0
  20. package/dist/docs/capacity-planning.md +359 -0
  21. package/dist/docs/commands.md +35 -0
  22. package/dist/docs/database-operations.md +487 -0
  23. package/dist/docs/index.md +6 -1
  24. package/dist/docs/licensing.md +372 -0
  25. package/dist/docs/production-deployment.md +583 -0
  26. package/dist/examples/ai-with-bash.yaml +17 -0
  27. package/dist/generated/config-schema.d.ts +4 -0
  28. package/dist/generated/config-schema.d.ts.map +1 -1
  29. package/dist/index.js +9945 -10907
  30. package/dist/liquid-extensions.d.ts +7 -0
  31. package/dist/liquid-extensions.d.ts.map +1 -1
  32. package/dist/output/traces/{run-2026-02-11T16-20-59-999Z.ndjson → run-2026-02-15T19-14-20-379Z.ndjson} +84 -84
  33. package/dist/{traces/run-2026-02-11T16-21-47-711Z.ndjson → output/traces/run-2026-02-15T19-15-09-410Z.ndjson} +1019 -1019
  34. package/dist/providers/ai-check-provider.d.ts +5 -0
  35. package/dist/providers/ai-check-provider.d.ts.map +1 -1
  36. package/dist/providers/command-check-provider.d.ts.map +1 -1
  37. package/dist/providers/workflow-check-provider.d.ts.map +1 -1
  38. package/dist/scheduler/schedule-tool.d.ts.map +1 -1
  39. package/dist/sdk/{check-provider-registry-PANIXYRB.mjs → check-provider-registry-AAPPJ4CP.mjs} +7 -7
  40. package/dist/sdk/{check-provider-registry-M3Y6JMTW.mjs → check-provider-registry-S7BMQ2FC.mjs} +7 -7
  41. package/dist/sdk/check-provider-registry-ZOLEYDKM.mjs +28 -0
  42. package/dist/sdk/{chunk-VMLORODQ.mjs → chunk-2GCSK3PD.mjs} +4 -4
  43. package/dist/sdk/{chunk-EUUAQBTW.mjs → chunk-6ZZ4DPAA.mjs} +240 -48
  44. package/dist/sdk/chunk-6ZZ4DPAA.mjs.map +1 -0
  45. package/dist/sdk/{chunk-HOKQOO3G.mjs → chunk-EBTD2D4L.mjs} +2 -2
  46. package/dist/sdk/chunk-LDFUW34H.mjs +39912 -0
  47. package/dist/sdk/chunk-LDFUW34H.mjs.map +1 -0
  48. package/dist/sdk/{chunk-UCNT3PDT.mjs → chunk-LQ5B4T6L.mjs} +5 -1
  49. package/dist/sdk/chunk-LQ5B4T6L.mjs.map +1 -0
  50. package/dist/sdk/{chunk-S6CD7GFM.mjs → chunk-MQ57AB4U.mjs} +211 -35
  51. package/dist/sdk/chunk-MQ57AB4U.mjs.map +1 -0
  52. package/dist/sdk/chunk-N4I6ZDCJ.mjs +436 -0
  53. package/dist/sdk/chunk-N4I6ZDCJ.mjs.map +1 -0
  54. package/dist/sdk/chunk-OMFPM576.mjs +739 -0
  55. package/dist/sdk/chunk-OMFPM576.mjs.map +1 -0
  56. package/dist/sdk/chunk-RI77TA6V.mjs +436 -0
  57. package/dist/sdk/chunk-RI77TA6V.mjs.map +1 -0
  58. package/dist/sdk/chunk-VO4N6TEL.mjs +1502 -0
  59. package/dist/sdk/chunk-VO4N6TEL.mjs.map +1 -0
  60. package/dist/sdk/{chunk-V2IV3ILA.mjs → chunk-XJQKTK6V.mjs} +31 -5
  61. package/dist/sdk/chunk-XJQKTK6V.mjs.map +1 -0
  62. package/dist/sdk/{config-OGOS4ZU4.mjs → config-4EG7IQIU.mjs} +2 -2
  63. package/dist/sdk/{failure-condition-evaluator-HC3M5377.mjs → failure-condition-evaluator-GLHZZF47.mjs} +3 -3
  64. package/dist/sdk/failure-condition-evaluator-KN55WXRO.mjs +17 -0
  65. package/dist/sdk/{github-frontend-E2KJSC3Y.mjs → github-frontend-F4TE2JY7.mjs} +3 -3
  66. package/dist/sdk/github-frontend-HCOKL53D.mjs +1356 -0
  67. package/dist/sdk/github-frontend-HCOKL53D.mjs.map +1 -0
  68. package/dist/sdk/{host-EE6EJ2FM.mjs → host-SAT6RHDX.mjs} +2 -2
  69. package/dist/sdk/host-VA3ET7N6.mjs +63 -0
  70. package/dist/sdk/host-VA3ET7N6.mjs.map +1 -0
  71. package/dist/sdk/{liquid-extensions-E4EUOCES.mjs → liquid-extensions-YDIIH33Q.mjs} +2 -2
  72. package/dist/sdk/{routing-OZQWAGAI.mjs → routing-KFYQGOYU.mjs} +5 -5
  73. package/dist/sdk/routing-OXQKETSA.mjs +25 -0
  74. package/dist/sdk/{schedule-tool-handler-IEB2VS7O.mjs → schedule-tool-handler-G353DHS6.mjs} +7 -7
  75. package/dist/sdk/{schedule-tool-handler-B7TMSG6A.mjs → schedule-tool-handler-OQF57URO.mjs} +7 -7
  76. package/dist/sdk/schedule-tool-handler-PJVKWSYX.mjs +38 -0
  77. package/dist/sdk/schedule-tool-handler-PJVKWSYX.mjs.map +1 -0
  78. package/dist/sdk/sdk.d.mts +15 -0
  79. package/dist/sdk/sdk.d.ts +15 -0
  80. package/dist/sdk/sdk.js +621 -183
  81. package/dist/sdk/sdk.js.map +1 -1
  82. package/dist/sdk/sdk.mjs +6 -6
  83. package/dist/sdk/{trace-helpers-PP3YHTAM.mjs → trace-helpers-LOPBHYYX.mjs} +4 -2
  84. package/dist/sdk/trace-helpers-LOPBHYYX.mjs.map +1 -0
  85. package/dist/sdk/trace-helpers-R2ETIEC2.mjs +25 -0
  86. package/dist/sdk/trace-helpers-R2ETIEC2.mjs.map +1 -0
  87. package/dist/sdk/{workflow-check-provider-2ET3SFZH.mjs → workflow-check-provider-57KAR4Y4.mjs} +7 -7
  88. package/dist/sdk/workflow-check-provider-57KAR4Y4.mjs.map +1 -0
  89. package/dist/sdk/{workflow-check-provider-HB4XTD4Z.mjs → workflow-check-provider-LRWD52WN.mjs} +7 -7
  90. package/dist/sdk/workflow-check-provider-LRWD52WN.mjs.map +1 -0
  91. package/dist/sdk/workflow-check-provider-N2DRFQDB.mjs +28 -0
  92. package/dist/sdk/workflow-check-provider-N2DRFQDB.mjs.map +1 -0
  93. package/dist/slack/socket-runner.d.ts.map +1 -1
  94. package/dist/state-machine/context/build-engine-context.d.ts.map +1 -1
  95. package/dist/state-machine/runner.d.ts.map +1 -1
  96. package/dist/state-machine/states/completed.d.ts.map +1 -1
  97. package/dist/telemetry/trace-helpers.d.ts +5 -0
  98. package/dist/telemetry/trace-helpers.d.ts.map +1 -1
  99. package/dist/test-runner/evaluators.d.ts.map +1 -1
  100. package/dist/test-runner/index.d.ts +7 -0
  101. package/dist/test-runner/index.d.ts.map +1 -1
  102. package/dist/test-runner/validator.d.ts.map +1 -1
  103. package/dist/traces/{run-2026-02-11T16-20-59-999Z.ndjson → run-2026-02-15T19-14-20-379Z.ndjson} +84 -84
  104. package/dist/{output/traces/run-2026-02-11T16-21-47-711Z.ndjson → traces/run-2026-02-15T19-15-09-410Z.ndjson} +1019 -1019
  105. package/dist/tui/chat-runner.d.ts.map +1 -1
  106. package/dist/types/cli.d.ts +2 -0
  107. package/dist/types/cli.d.ts.map +1 -1
  108. package/dist/types/config.d.ts +15 -0
  109. package/dist/types/config.d.ts.map +1 -1
  110. package/dist/types/engine.d.ts +2 -0
  111. package/dist/types/engine.d.ts.map +1 -1
  112. package/package.json +3 -3
  113. package/defaults/.visor.yaml +0 -420
  114. package/dist/sdk/chunk-EUUAQBTW.mjs.map +0 -1
  115. package/dist/sdk/chunk-S6CD7GFM.mjs.map +0 -1
  116. package/dist/sdk/chunk-UCNT3PDT.mjs.map +0 -1
  117. package/dist/sdk/chunk-V2IV3ILA.mjs.map +0 -1
  118. package/dist/sdk/chunk-YJRBN3XS.mjs +0 -217
  119. package/dist/sdk/chunk-YJRBN3XS.mjs.map +0 -1
  120. /package/dist/sdk/{check-provider-registry-M3Y6JMTW.mjs.map → check-provider-registry-AAPPJ4CP.mjs.map} +0 -0
  121. /package/dist/sdk/{check-provider-registry-PANIXYRB.mjs.map → check-provider-registry-S7BMQ2FC.mjs.map} +0 -0
  122. /package/dist/sdk/{config-OGOS4ZU4.mjs.map → check-provider-registry-ZOLEYDKM.mjs.map} +0 -0
  123. /package/dist/sdk/{chunk-VMLORODQ.mjs.map → chunk-2GCSK3PD.mjs.map} +0 -0
  124. /package/dist/sdk/{chunk-HOKQOO3G.mjs.map → chunk-EBTD2D4L.mjs.map} +0 -0
  125. /package/dist/sdk/{failure-condition-evaluator-HC3M5377.mjs.map → config-4EG7IQIU.mjs.map} +0 -0
  126. /package/dist/sdk/{liquid-extensions-E4EUOCES.mjs.map → failure-condition-evaluator-GLHZZF47.mjs.map} +0 -0
  127. /package/dist/sdk/{routing-OZQWAGAI.mjs.map → failure-condition-evaluator-KN55WXRO.mjs.map} +0 -0
  128. /package/dist/sdk/{github-frontend-E2KJSC3Y.mjs.map → github-frontend-F4TE2JY7.mjs.map} +0 -0
  129. /package/dist/sdk/{host-EE6EJ2FM.mjs.map → host-SAT6RHDX.mjs.map} +0 -0
  130. /package/dist/sdk/{schedule-tool-handler-B7TMSG6A.mjs.map → liquid-extensions-YDIIH33Q.mjs.map} +0 -0
  131. /package/dist/sdk/{schedule-tool-handler-IEB2VS7O.mjs.map → routing-KFYQGOYU.mjs.map} +0 -0
  132. /package/dist/sdk/{trace-helpers-PP3YHTAM.mjs.map → routing-OXQKETSA.mjs.map} +0 -0
  133. /package/dist/sdk/{workflow-check-provider-2ET3SFZH.mjs.map → schedule-tool-handler-G353DHS6.mjs.map} +0 -0
  134. /package/dist/sdk/{workflow-check-provider-HB4XTD4Z.mjs.map → schedule-tool-handler-OQF57URO.mjs.map} +0 -0
@@ -0,0 +1,359 @@
1
+ # Capacity Planning and Sizing
2
+
3
+ This guide helps you size Visor deployments for different workloads, from single-developer setups to large-scale enterprise deployments.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ - [Resource Profiles](#resource-profiles)
10
+ - [Deployment Tiers](#deployment-tiers)
11
+ - [Component Sizing](#component-sizing)
12
+ - [Visor Instances](#visor-instances)
13
+ - [Database](#database)
14
+ - [AI Provider Costs](#ai-provider-costs)
15
+ - [Scaling Guidelines](#scaling-guidelines)
16
+ - [Bottleneck Analysis](#bottleneck-analysis)
17
+ - [Cloud Cost Estimates](#cloud-cost-estimates)
18
+ - [Load Testing](#load-testing)
19
+ - [Monitoring for Scale](#monitoring-for-scale)
20
+
21
+ ---
22
+
23
+ ## Resource Profiles
24
+
25
+ Visor's resource consumption depends primarily on:
26
+
27
+ 1. **Number of concurrent checks**: Each check consumes a thread and memory for provider execution.
28
+ 2. **AI provider usage**: AI checks send/receive large payloads (code diffs, prompts, responses).
29
+ 3. **Sandbox usage**: Docker-based sandboxes consume additional CPU/memory per container.
30
+ 4. **Scheduler load**: Number of active schedules and execution frequency.
31
+
32
+ ### Per-Check Resource Footprint
33
+
34
+ | Check Type | CPU (avg) | Memory (avg) | Network | Duration |
35
+ |-----------|----------|-------------|---------|----------|
36
+ | `command` | 50m | 20MB | Minimal | 1-30s |
37
+ | `script` | 50m | 30MB | None | < 1s |
38
+ | `ai` (Gemini) | 10m | 50MB | Moderate | 5-30s |
39
+ | `ai` (Claude) | 10m | 50MB | Moderate | 10-60s |
40
+ | `claude-code` | 100m | 200MB | High | 30-300s |
41
+ | `mcp` | 50m | 50MB | Varies | 1-60s |
42
+ | `http` / `http_client` | 10m | 10MB | Low | 1-10s |
43
+ | Sandbox (Docker) | 250m+ | 256MB+ | Varies | 10-120s |
44
+
45
+ ---
46
+
47
+ ## Deployment Tiers
48
+
49
+ ### Small (1-10 developers)
50
+
51
+ Single instance, SQLite, ephemeral runs.
52
+
53
+ | Component | Spec | Cost Estimate |
54
+ |-----------|------|---------------|
55
+ | Visor | 1 instance, 256MB RAM, 0.5 CPU | Free (CLI) or $5/mo (small VM) |
56
+ | Database | SQLite (local file) | $0 |
57
+ | AI Provider | ~100 reviews/month | $5-20/mo |
58
+
59
+ **Configuration:**
60
+ ```yaml
61
+ max_parallelism: 3
62
+ scheduler:
63
+ storage:
64
+ driver: sqlite
65
+ ```
66
+
67
+ ### Medium (10-50 developers)
68
+
69
+ 2-3 instances, PostgreSQL, Slack integration.
70
+
71
+ | Component | Spec | Cost Estimate |
72
+ |-----------|------|---------------|
73
+ | Visor | 2-3 instances, 512MB RAM, 1 CPU each | $30-80/mo |
74
+ | Database | PostgreSQL (small managed) | $15-30/mo |
75
+ | AI Provider | ~500-2000 reviews/month | $30-150/mo |
76
+
77
+ **Configuration:**
78
+ ```yaml
79
+ max_parallelism: 5
80
+ scheduler:
81
+ storage:
82
+ driver: postgresql
83
+ connection:
84
+ pool:
85
+ min: 1
86
+ max: 5
87
+ ha:
88
+ enabled: true
89
+ ```
90
+
91
+ ### Large (50-500 developers)
92
+
93
+ 5+ instances, PostgreSQL with PgBouncer, full observability.
94
+
95
+ | Component | Spec | Cost Estimate |
96
+ |-----------|------|---------------|
97
+ | Visor | 5+ instances, 1GB RAM, 2 CPU each | $150-400/mo |
98
+ | Database | PostgreSQL (medium managed + replica) | $50-200/mo |
99
+ | PgBouncer | 1 instance, 128MB RAM | $5-10/mo |
100
+ | AI Provider | ~5000-20000 reviews/month | $200-1500/mo |
101
+ | Observability | Jaeger/Grafana | $50-200/mo |
102
+
103
+ **Configuration:**
104
+ ```yaml
105
+ max_parallelism: 10
106
+ scheduler:
107
+ storage:
108
+ driver: postgresql
109
+ connection:
110
+ pool:
111
+ min: 0
112
+ max: 3 # PgBouncer handles pooling
113
+ ha:
114
+ enabled: true
115
+ lock_ttl: 120
116
+ heartbeat_interval: 15
117
+ ```
118
+
119
+ ---
120
+
121
+ ## Component Sizing
122
+
123
+ ### Visor Instances
124
+
125
+ | Metric | Formula | Example |
126
+ |--------|---------|---------|
127
+ | **Concurrent checks** | `instances * max_parallelism` | 3 * 5 = 15 concurrent |
128
+ | **Memory per instance** | `base (100MB) + checks * avg_per_check` | 100 + 5 * 50 = 350MB |
129
+ | **CPU per instance** | `0.25 base + checks * avg_cpu` | 0.25 + 5 * 0.05 = 0.5 cores |
130
+
131
+ **Recommended instance sizes:**
132
+
133
+ | Workload | vCPU | Memory | `max_parallelism` |
134
+ |----------|------|--------|-------------------|
135
+ | Light (CLI checks only) | 0.5 | 256MB | 3 |
136
+ | Medium (AI + Slack) | 1 | 512MB | 5 |
137
+ | Heavy (Claude Code + sandboxes) | 2 | 1GB | 5-10 |
138
+ | Sandbox-heavy | 4 | 2GB | 3-5 |
139
+
140
+ ### Database
141
+
142
+ Visor's database footprint is small. The `schedules` table grows linearly with active schedules.
143
+
144
+ | Deployment | Rows (approx) | Disk | Recommended Instance |
145
+ |------------|--------------|------|---------------------|
146
+ | Small | < 100 | < 10MB | SQLite |
147
+ | Medium | 100-1000 | < 100MB | db.t3.micro (AWS) / B1ms (Azure) |
148
+ | Large | 1000-10000 | < 1GB | db.t3.small (AWS) / B2s (Azure) |
149
+
150
+ PostgreSQL memory recommendation: **256MB shared_buffers** is sufficient for all Visor workloads.
151
+
152
+ ### AI Provider Costs
153
+
154
+ AI costs scale with the size of code diffs and prompt complexity.
155
+
156
+ | Provider | Model | Cost per 1K tokens (approx) | Avg tokens per review | Cost per review |
157
+ |----------|-------|-----------------------------|----------------------|-----------------|
158
+ | Gemini | gemini-2.0-flash | $0.0001 / $0.0004 | 5K-20K | $0.002-0.01 |
159
+ | Claude | claude-sonnet-4-5 | $0.003 / $0.015 | 5K-20K | $0.03-0.20 |
160
+ | Claude Code | claude-sonnet-4-5 | $0.003 / $0.015 | 10K-50K | $0.10-0.50 |
161
+ | OpenAI | gpt-4o | $0.0025 / $0.01 | 5K-20K | $0.03-0.15 |
162
+
163
+ **Cost optimization strategies:**
164
+ - Use Gemini Flash for high-volume, lower-stakes checks.
165
+ - Reserve Claude/GPT-4 for security and architecture reviews.
166
+ - Use `--tags` to run expensive checks only when needed.
167
+ - Set `max_tokens` in AI provider config to cap response size.
168
+
169
+ ---
170
+
171
+ ## Scaling Guidelines
172
+
173
+ ### When to Add Instances
174
+
175
+ | Signal | Action |
176
+ |--------|--------|
177
+ | Check queue backlog growing | Increase `max_parallelism` or add instances |
178
+ | Response times > 2x baseline | Add instances |
179
+ | Memory usage > 80% | Increase memory or reduce `max_parallelism` |
180
+ | Slack message response > 30s | Add instances for Slack mode |
181
+
182
+ ### When to Upgrade Database
183
+
184
+ | Signal | Action |
185
+ |--------|--------|
186
+ | SQLite lock contention | Migrate to PostgreSQL |
187
+ | Multiple Visor instances needed | Migrate to PostgreSQL with HA |
188
+ | Connection pool exhaustion | Add PgBouncer |
189
+ | Query latency > 100ms | Check indexes, consider larger instance |
190
+
191
+ ### Horizontal vs Vertical Scaling
192
+
193
+ | Dimension | Horizontal (more instances) | Vertical (bigger instance) |
194
+ |-----------|---------------------------|--------------------------|
195
+ | Best for | Slack throughput, HA | Heavy single checks, sandbox execution |
196
+ | Requires | PostgreSQL + HA mode | Nothing special |
197
+ | Limit | Slack API rate limits | Single-machine resources |
198
+ | Recommended | Yes, for production | Yes, up to 4 vCPU / 4GB |
199
+
200
+ ---
201
+
202
+ ## Bottleneck Analysis
203
+
204
+ Common bottlenecks in order of likelihood:
205
+
206
+ ### 1. AI Provider Latency (most common)
207
+
208
+ AI API calls (5-60s) dominate total execution time.
209
+
210
+ **Mitigation:**
211
+ - Increase `max_parallelism` to overlap AI calls.
212
+ - Use faster models (Gemini Flash) for non-critical checks.
213
+ - Use `timeout` per check to prevent hangs.
214
+
215
+ ### 2. Sandbox Startup Time
216
+
217
+ Docker container creation adds 2-10s overhead per sandboxed check.
218
+
219
+ **Mitigation:**
220
+ - Pre-pull images on nodes.
221
+ - Use lightweight base images (`alpine`).
222
+ - Enable cache volumes to avoid re-installing dependencies.
223
+
224
+ ### 3. Database Connection Pool
225
+
226
+ With many instances and high scheduler activity, connections can exhaust.
227
+
228
+ **Mitigation:**
229
+ - Deploy PgBouncer for connection multiplexing.
230
+ - Keep Visor `pool.max` low (3-5) when using PgBouncer.
231
+ - Monitor with `pg_stat_activity`.
232
+
233
+ ### 4. Network / API Rate Limits
234
+
235
+ GitHub API (5000 req/hr), Slack API (tier-based).
236
+
237
+ **Mitigation:**
238
+ - Use GitHub App tokens (higher rate limits) instead of PATs.
239
+ - Batch operations where possible.
240
+ - Monitor rate limit headers.
241
+
242
+ ---
243
+
244
+ ## Cloud Cost Estimates
245
+
246
+ ### AWS
247
+
248
+ | Component | Service | Spec | Monthly Cost |
249
+ |-----------|---------|------|-------------|
250
+ | Visor (2x) | ECS Fargate | 0.5 vCPU, 1GB | ~$30 |
251
+ | Database | RDS PostgreSQL | db.t3.micro | ~$15 |
252
+ | Secrets | Secrets Manager | 3 secrets | ~$1.20 |
253
+ | Monitoring | CloudWatch | Basic | ~$5 |
254
+ | **Total** | | | **~$51/mo** |
255
+
256
+ ### Google Cloud
257
+
258
+ | Component | Service | Spec | Monthly Cost |
259
+ |-----------|---------|------|-------------|
260
+ | Visor (2x) | Cloud Run | 1 vCPU, 512MB | ~$25 |
261
+ | Database | Cloud SQL PostgreSQL | db-f1-micro | ~$10 |
262
+ | Secrets | Secret Manager | 3 secrets | ~$0.18 |
263
+ | Monitoring | Cloud Monitoring | Basic | Free |
264
+ | **Total** | | | **~$35/mo** |
265
+
266
+ ### Azure
267
+
268
+ | Component | Service | Spec | Monthly Cost |
269
+ |-----------|---------|------|-------------|
270
+ | Visor (2x) | Container Instances | 1 vCPU, 1GB | ~$35 |
271
+ | Database | Azure Database for PostgreSQL | B1ms | ~$15 |
272
+ | Secrets | Key Vault | 3 secrets | ~$0.10 |
273
+ | Monitoring | Monitor | Basic | ~$5 |
274
+ | **Total** | | | **~$55/mo** |
275
+
276
+ *Costs are approximate and vary by region. AI provider costs are additional.*
277
+
278
+ ---
279
+
280
+ ## Load Testing
281
+
282
+ ### Test Setup
283
+
284
+ Create a load-test configuration with synthetic checks:
285
+
286
+ ```yaml
287
+ # load-test.visor.yaml
288
+ version: "1.0"
289
+ max_parallelism: 10
290
+
291
+ checks:
292
+ synthetic-fast:
293
+ type: command
294
+ command: "echo ok"
295
+ tags: [load-test]
296
+
297
+ synthetic-slow:
298
+ type: command
299
+ command: "sleep 2 && echo ok"
300
+ tags: [load-test]
301
+
302
+ synthetic-ai:
303
+ type: ai
304
+ prompt: "Say 'ok' in one word."
305
+ tags: [load-test]
306
+ ```
307
+
308
+ ### Running Load Tests
309
+
310
+ ```bash
311
+ # Sequential: measure single-check latency
312
+ time visor --config load-test.visor.yaml --check all --tags load-test
313
+
314
+ # Parallel: measure throughput
315
+ for i in $(seq 1 20); do
316
+ visor --config load-test.visor.yaml --check all --tags load-test &
317
+ done
318
+ wait
319
+ ```
320
+
321
+ ### Key Metrics to Capture
322
+
323
+ - **P50/P95/P99 check duration**: Baseline for SLA.
324
+ - **Throughput**: Checks per minute at different parallelism levels.
325
+ - **Error rate**: Failed checks under load.
326
+ - **Memory growth**: Watch for leaks in long-running mode.
327
+ - **Database connections**: Peak concurrent connections.
328
+
329
+ ---
330
+
331
+ ## Monitoring for Scale
332
+
333
+ ### Alerts to Configure
334
+
335
+ | Alert | Threshold | Action |
336
+ |-------|-----------|--------|
337
+ | Check error rate > 5% | 5min window | Investigate provider health |
338
+ | P95 latency > 120s | 5min window | Scale horizontally or reduce parallelism |
339
+ | Memory > 80% of limit | Sustained | Increase memory or reduce parallelism |
340
+ | DB connections > 80% of max | Sustained | Add PgBouncer or increase pool |
341
+ | Scheduler lock failures | Any | Check HA config, verify DB health |
342
+ | License expiring < 7 days | Daily check | Renew license |
343
+
344
+ ### Grafana Dashboard Queries
345
+
346
+ If using OpenTelemetry with Grafana:
347
+
348
+ ```promql
349
+ # Check execution rate
350
+ rate(visor_check_executions_total[5m])
351
+
352
+ # P95 check duration
353
+ histogram_quantile(0.95, rate(visor_check_duration_seconds_bucket[5m]))
354
+
355
+ # Active Visor instances (from heartbeat)
356
+ count(up{job="visor"})
357
+ ```
358
+
359
+ See [Dashboards](./dashboards/README.md) for pre-built Grafana dashboards.
@@ -78,6 +78,28 @@ visor build <path/to/agent.yaml> [options]
78
78
  visor build agents/my-agent.yaml --message "Add error handling"
79
79
  ```
80
80
 
81
+ #### `visor config`
82
+
83
+ Manage configuration snapshots. Visor automatically snapshots resolved configuration at startup and on each reload, keeping the most recent 3 snapshots in `.visor/config.db`.
84
+
85
+ ```bash
86
+ visor config <command> [options]
87
+ ```
88
+
89
+ **Subcommands:**
90
+ - `snapshots` - List all configuration snapshots
91
+ - `show <id>` - Print the full YAML of a snapshot
92
+ - `diff <id_a> <id_b>` - Show unified diff between two snapshots
93
+ - `restore <id> --output <path>` - Write snapshot YAML to a file
94
+
95
+ **Examples:**
96
+ ```bash
97
+ visor config snapshots # List saved snapshots
98
+ visor config show 1 # Print full YAML of snapshot 1
99
+ visor config diff 1 2 # Unified diff between snapshots
100
+ visor config restore 1 --output restored.yaml # Restore snapshot to file
101
+ ```
102
+
81
103
  #### `visor mcp-server`
82
104
 
83
105
  Start Visor as an MCP (Model Context Protocol) server.
@@ -142,6 +164,9 @@ See [Tag Filtering](tag-filtering.md) for detailed tag filtering documentation.
142
164
  - `--workspace-name <name>` - Workspace directory name
143
165
  - `--workspace-project-name <name>` - Main project folder name inside workspace
144
166
 
167
+ #### Config Reloading
168
+ - `--watch` - Watch config file for changes and reload automatically (requires `--config`). Also reloads on `SIGUSR2` signal (non-Windows). Intended for long-running modes like `--slack`.
169
+
145
170
  #### Other Options
146
171
  - `--slack` - Enable Slack Socket Mode runner
147
172
  - `--mode <mode>` - Run mode: `cli` (default) or `github-actions`
@@ -180,6 +205,16 @@ visor --tui
180
205
 
181
206
  # Debug visualizer
182
207
  visor --debug-server --debug-port 3456
208
+
209
+ # Slack mode with live config reloading
210
+ visor --slack --config .visor.yaml --watch
211
+
212
+ # Reload config at runtime via signal (non-Windows)
213
+ kill -USR2 <visor-pid>
214
+
215
+ # List config snapshots and diff changes
216
+ visor config snapshots
217
+ visor config diff 1 2
183
218
  ```
184
219
 
185
220
  ---