@crvouga/dev-fleet 0.0.0-stage → 0.1.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.
Files changed (333) hide show
  1. package/.mise/locks/aws-cdk/2.1146.1/aube-lock.yaml +24 -0
  2. package/.mise/locks/aws-cdk/2.1146.1/package.json +7 -0
  3. package/.mise/locks/azure-cli/2.91.0~a837e014/pyproject.toml +5 -0
  4. package/.mise/locks/azure-cli/2.91.0~a837e014/uv.lock +2794 -0
  5. package/.mise/locks/gemini/0.66.0~84aac8e6/aube-lock.yaml +123 -0
  6. package/.mise/locks/gemini/0.66.0~84aac8e6/package.json +12 -0
  7. package/.mise/locks/npm-devcontainers-cli/0.90.0/aube-lock.yaml +24 -0
  8. package/.mise/locks/npm-devcontainers-cli/0.90.0/package.json +7 -0
  9. package/.mise/locks/npm-modelcontextprotocol-inspector/2.13.0~4c109bea/aube-lock.yaml +1432 -0
  10. package/.mise/locks/npm-modelcontextprotocol-inspector/2.13.0~4c109bea/package.json +7 -0
  11. package/.mise/locks/npm-vercel/65.8.0/aube-lock.yaml +3595 -0
  12. package/.mise/locks/npm-vercel/65.8.0/package.json +7 -0
  13. package/.mise/locks/npm-wrangler/4.156.0/aube-lock.yaml +895 -0
  14. package/.mise/locks/npm-wrangler/4.156.0/package.json +7 -0
  15. package/.mise/locks/npm-yarnpkg-cli-dist/4.18.1/aube-lock.yaml +24 -0
  16. package/.mise/locks/npm-yarnpkg-cli-dist/4.18.1/package.json +7 -0
  17. package/LICENSE +21 -0
  18. package/README.md +157 -2
  19. package/agents/antigravity-proxy.ts +3 -0
  20. package/agents/audit.md +89 -0
  21. package/agents/claude-proxy +5 -0
  22. package/agents/claude-proxy.ts +3 -0
  23. package/agents/codex-proxy.ts +3 -0
  24. package/agents/grok-proxy.ts +3 -0
  25. package/agents/managed-proxy.ts +55 -0
  26. package/agents/opencode-proxy.ts +3 -0
  27. package/agents/registry.json +209 -0
  28. package/agents/registry.schema.json +149 -0
  29. package/agents/setup.md +128 -0
  30. package/agents/t3.json +40 -0
  31. package/ansible/macos/manager.yml +30 -0
  32. package/ansible/macos/policy.json +17 -0
  33. package/ansible/monitoring/README.md +154 -0
  34. package/ansible/monitoring/agent-darwin.yml +198 -0
  35. package/ansible/monitoring/agent.yml +134 -0
  36. package/ansible/monitoring/beszel-agent.service +42 -0
  37. package/ansible/monitoring/compose.yml +74 -0
  38. package/ansible/monitoring/hub-darwin.yml +102 -0
  39. package/ansible/monitoring/lock.json +11 -0
  40. package/ansible/net/remote-probe.sh +13 -0
  41. package/ansible/ubuntu/authorize-sudo.sh +51 -0
  42. package/ansible/ubuntu/baseline.yml +89 -0
  43. package/ansible/ubuntu/disk-guard.py +104 -0
  44. package/ansible/ubuntu/policy.json +43 -0
  45. package/ansible/ubuntu/recovery.yml +15 -0
  46. package/ansible/ubuntu/t3/policy.json +7 -0
  47. package/ansible/ubuntu/t3-desktop.yml +220 -0
  48. package/ansible/ubuntu/t3-health.sh +33 -0
  49. package/ansible/ubuntu/t3-policy.yml +76 -0
  50. package/ansible/ubuntu/t3-route.yml +28 -0
  51. package/ansible/ubuntu/tailscale.yml +75 -0
  52. package/ansible/ubuntu/tasks/credentials.yml +47 -0
  53. package/ansible/ubuntu/tasks/docker.yml +31 -0
  54. package/ansible/ubuntu/tasks/packages.yml +56 -0
  55. package/ansible/ubuntu/tasks/power.yml +51 -0
  56. package/ansible/ubuntu/tasks/recovery.yml +39 -0
  57. package/ansible/ubuntu/tasks/resources.yml +252 -0
  58. package/ansible/ubuntu/tasks/services.yml +31 -0
  59. package/ansible/ubuntu/tasks/ssh.yml +71 -0
  60. package/ansible/ubuntu/tasks/user.yml +120 -0
  61. package/bin/devfleet.mjs +36 -0
  62. package/bootstrap/bootstrap.ps1 +50 -0
  63. package/bootstrap/bootstrap.sh +73 -0
  64. package/bootstrap/devfleet +7 -0
  65. package/bootstrap/docker-desktop.sh +33 -0
  66. package/bootstrap/doctor.ts +189 -0
  67. package/bootstrap/fleet-manager-run.sh +76 -0
  68. package/bootstrap/fleet-remote-bootstrap.sh +185 -0
  69. package/bootstrap/global-config.ts +113 -0
  70. package/bootstrap/install-launcher.sh +7 -0
  71. package/bootstrap/native-aws.ts +86 -0
  72. package/bootstrap/native-t3.ts +154 -0
  73. package/bootstrap/npm.ts +350 -0
  74. package/bootstrap/setup-status.ts +51 -0
  75. package/bootstrap/setup.ts +88 -0
  76. package/bootstrap/shell-path.ts +105 -0
  77. package/bootstrap/verify-t3-archive.py +49 -0
  78. package/bootstrap/worker-auth.ts +65 -0
  79. package/bootstrap/worker-github.ts +47 -0
  80. package/bootstrap/worker-tools.ts +24 -0
  81. package/cliproxy/AGENTS.md +11 -0
  82. package/cliproxy/README.md +269 -0
  83. package/cliproxy/clients/bootstrap.py +143 -0
  84. package/cliproxy/clients/launcher.py +57 -0
  85. package/cliproxy/compose.yaml +90 -0
  86. package/cliproxy/config.template.yaml +70 -0
  87. package/cliproxy/docs/cloud-adoption.md +16 -0
  88. package/cliproxy/docs/deployment.png +0 -0
  89. package/cliproxy/docs/deployment.svg +109 -0
  90. package/cliproxy/docs/health-workflow.example.yml +185 -0
  91. package/cliproxy/docs/migration.md +131 -0
  92. package/cliproxy/docs/model-health-report.schema.json +364 -0
  93. package/cliproxy/docs/model-health.md +393 -0
  94. package/cliproxy/image.lock.json +5 -0
  95. package/cliproxy/launchd/dev.devfleet.cliproxy-backup-check.plist +38 -0
  96. package/cliproxy/launchd/dev.devfleet.cliproxy-backup.plist +48 -0
  97. package/cliproxy/launchd/dev.devfleet.cliproxy-fleet.plist +32 -0
  98. package/cliproxy/launchd/dev.devfleet.cliproxy-gc.plist +38 -0
  99. package/cliproxy/launchd/dev.devfleet.cliproxy-monitor.plist +29 -0
  100. package/cliproxy/launchd/dev.devfleet.cliproxy-vault-renew.plist +31 -0
  101. package/cliproxy/models.json +1618 -0
  102. package/cliproxy/requirements.lock +78 -0
  103. package/cliproxy/scripts/accounts.py +38 -0
  104. package/cliproxy/scripts/audit.py +123 -0
  105. package/cliproxy/scripts/backup +234 -0
  106. package/cliproxy/scripts/check.py +34 -0
  107. package/cliproxy/scripts/checkpoint.py +226 -0
  108. package/cliproxy/scripts/cli.py +64 -0
  109. package/cliproxy/scripts/cliproxy_host.py +257 -0
  110. package/cliproxy/scripts/cloud_state.py +150 -0
  111. package/cliproxy/scripts/container-health +6 -0
  112. package/cliproxy/scripts/docker +24 -0
  113. package/cliproxy/scripts/external-health.py +79 -0
  114. package/cliproxy/scripts/fleet_config.py +43 -0
  115. package/cliproxy/scripts/fleet_sync.py +274 -0
  116. package/cliproxy/scripts/initialize +84 -0
  117. package/cliproxy/scripts/install-dependencies +48 -0
  118. package/cliproxy/scripts/install.py +406 -0
  119. package/cliproxy/scripts/model_health.py +16 -0
  120. package/cliproxy/scripts/modelhealth/__init__.py +5 -0
  121. package/cliproxy/scripts/modelhealth/checks.py +429 -0
  122. package/cliproxy/scripts/modelhealth/cli.py +117 -0
  123. package/cliproxy/scripts/modelhealth/config.py +186 -0
  124. package/cliproxy/scripts/modelhealth/emulator.py +536 -0
  125. package/cliproxy/scripts/modelhealth/expect.py +88 -0
  126. package/cliproxy/scripts/modelhealth/findings.py +183 -0
  127. package/cliproxy/scripts/modelhealth/protocol.py +330 -0
  128. package/cliproxy/scripts/modelhealth/redact.py +28 -0
  129. package/cliproxy/scripts/modelhealth/report.py +150 -0
  130. package/cliproxy/scripts/modelhealth/runner.py +390 -0
  131. package/cliproxy/scripts/modelhealth/scenario.py +131 -0
  132. package/cliproxy/scripts/modelhealth/schema.py +63 -0
  133. package/cliproxy/scripts/modelhealth/simulate.py +111 -0
  134. package/cliproxy/scripts/modelhealth/transport.py +213 -0
  135. package/cliproxy/scripts/monitor +68 -0
  136. package/cliproxy/scripts/ops +527 -0
  137. package/cliproxy/scripts/public-endpoint +127 -0
  138. package/cliproxy/scripts/recover_node.py +177 -0
  139. package/cliproxy/scripts/restore-verify +60 -0
  140. package/cliproxy/scripts/retention.py +144 -0
  141. package/cliproxy/scripts/service-start +7 -0
  142. package/cliproxy/scripts/validate-config +56 -0
  143. package/cliproxy/scripts/vault-access.py +57 -0
  144. package/cliproxy/scripts/vault-backup-login +55 -0
  145. package/cliproxy/scripts/vault-recovery +56 -0
  146. package/cliproxy/scripts/vault-renew +30 -0
  147. package/cliproxy/systemd/cliproxy-backup-check.service +10 -0
  148. package/cliproxy/systemd/cliproxy-backup-check.timer +8 -0
  149. package/cliproxy/systemd/cliproxy-backup.service +13 -0
  150. package/cliproxy/systemd/cliproxy-backup.timer +8 -0
  151. package/cliproxy/systemd/cliproxy-fleet.service +17 -0
  152. package/cliproxy/systemd/cliproxy-gc.service +13 -0
  153. package/cliproxy/systemd/cliproxy-gc.timer +8 -0
  154. package/cliproxy/systemd/cliproxy-monitor.service +8 -0
  155. package/cliproxy/systemd/cliproxy-monitor.timer +7 -0
  156. package/cliproxy/systemd/cliproxy-vault-renew.service +8 -0
  157. package/cliproxy/systemd/cliproxy-vault-renew.timer +7 -0
  158. package/cliproxy/vendor/LICENSE +22 -0
  159. package/cliproxy/vendor/config.upstream.yaml +1349 -0
  160. package/examples/fleet.json +95 -0
  161. package/examples/roster.json +13 -0
  162. package/mise.lock +1492 -0
  163. package/mise.toml +99 -0
  164. package/package.json +65 -4
  165. package/schema/fleet.schema.json +364 -0
  166. package/schema/roster.schema.json +77 -0
  167. package/src/agents/account-relay.ts +111 -0
  168. package/src/agents/accounts.ts +85 -0
  169. package/src/agents/audit.ts +77 -0
  170. package/src/agents/cli.ts +13 -0
  171. package/src/agents/command.ts +204 -0
  172. package/src/agents/converge.ts +123 -0
  173. package/src/agents/doctor.ts +107 -0
  174. package/src/agents/errors.ts +2 -0
  175. package/src/agents/files.ts +73 -0
  176. package/src/agents/fleet-verify.ts +156 -0
  177. package/src/agents/launch.ts +290 -0
  178. package/src/agents/native-verify.ts +226 -0
  179. package/src/agents/provider-errors.ts +50 -0
  180. package/src/agents/registry.ts +55 -0
  181. package/src/agents/render.ts +110 -0
  182. package/src/agents/round-trip.ts +192 -0
  183. package/src/agents/secrets.ts +13 -0
  184. package/src/agents/toolchain.ts +34 -0
  185. package/src/agents/verify-cache.ts +103 -0
  186. package/src/agents/verify.ts +127 -0
  187. package/src/auth-checks.ts +163 -0
  188. package/src/cli/agent-guide.ts +95 -0
  189. package/src/cli/app.ts +115 -0
  190. package/src/cli/cli.ts +21 -0
  191. package/src/cli/command-index.ts +50 -0
  192. package/src/cli/contracts.ts +25 -0
  193. package/src/cli/fleet-reference.ts +17 -0
  194. package/src/cli/fleet-sync-checkout.ts +91 -0
  195. package/src/cli/fleet-sync-enrollment.ts +144 -0
  196. package/src/cli/fleet-sync-forward.ts +134 -0
  197. package/src/cli/fleet-sync-manager.ts +193 -0
  198. package/src/cli/fleet-sync-monitoring.ts +185 -0
  199. package/src/cli/fleet-sync-output.ts +314 -0
  200. package/src/cli/fleet-sync-privilege.ts +27 -0
  201. package/src/cli/fleet-sync-progress.ts +109 -0
  202. package/src/cli/fleet-sync-remote.ts +236 -0
  203. package/src/cli/fleet-sync-report.ts +26 -0
  204. package/src/cli/fleet-sync-schedule.ts +138 -0
  205. package/src/cli/fleet-sync-vault.ts +166 -0
  206. package/src/cli/fleet-sync.ts +309 -0
  207. package/src/cli/fleet.ts +163 -0
  208. package/src/cli/managed-health.ts +219 -0
  209. package/src/cli/node-deployment.ts +34 -0
  210. package/src/cli/node-sync.ts +114 -0
  211. package/src/cli/node-t3.ts +31 -0
  212. package/src/cli/options.ts +141 -0
  213. package/src/cli/probe-source.ts +7 -0
  214. package/src/cli/program.ts +169 -0
  215. package/src/cli/register-fleet.ts +246 -0
  216. package/src/cli/registry.ts +158 -0
  217. package/src/cli/repair-apply.ts +67 -0
  218. package/src/cli/repair-guard.ts +11 -0
  219. package/src/cli/repair-inspect.ts +150 -0
  220. package/src/cli/repair-script.ts +76 -0
  221. package/src/cli/repair.ts +209 -0
  222. package/src/cli/roster.ts +89 -0
  223. package/src/cli/search.ts +35 -0
  224. package/src/cli/settings.ts +64 -0
  225. package/src/cli/source-operations.ts +78 -0
  226. package/src/cli/t3/command.ts +90 -0
  227. package/src/cli/t3/register.ts +55 -0
  228. package/src/cli/tailnet.ts +127 -0
  229. package/src/cli/ui-actions.ts +133 -0
  230. package/src/cli/ui-controller.ts +113 -0
  231. package/src/cli/ui-data.ts +106 -0
  232. package/src/cli/ui-execute.ts +163 -0
  233. package/src/cli/ui-repairs.ts +34 -0
  234. package/src/cli/ui-reports.ts +211 -0
  235. package/src/cli/ui-targets.ts +100 -0
  236. package/src/cli/ui-terminal.ts +109 -0
  237. package/src/cli/ui-types.ts +49 -0
  238. package/src/cli/ui-wizard.ts +101 -0
  239. package/src/cli/ui.ts +9 -0
  240. package/src/cli/worker-health-output.ts +37 -0
  241. package/src/config.ts +186 -0
  242. package/src/configure.ts +255 -0
  243. package/src/definition.ts +260 -0
  244. package/src/diagnostics.ts +92 -0
  245. package/src/doctor-check.ts +10 -0
  246. package/src/errors.ts +1 -0
  247. package/src/fingerprint.ts +120 -0
  248. package/src/fleet-config.ts +88 -0
  249. package/src/index.ts +6 -0
  250. package/src/input-hashes.ts +73 -0
  251. package/src/machine/local-source.ts +52 -0
  252. package/src/machine/lock-error.ts +2 -0
  253. package/src/machine/platform.ts +44 -0
  254. package/src/machine/source.ts +68 -0
  255. package/src/machine/state.ts +185 -0
  256. package/src/machine-health.ts +95 -0
  257. package/src/managed-source.ts +47 -0
  258. package/src/manager-failure.ts +48 -0
  259. package/src/manager-sync.ts +400 -0
  260. package/src/manager.ts +62 -0
  261. package/src/monitoring/apply.ts +171 -0
  262. package/src/monitoring/beszel.ts +191 -0
  263. package/src/monitoring/enroll.ts +110 -0
  264. package/src/monitoring/hub-access.ts +113 -0
  265. package/src/monitoring/hub-viewer.ts +142 -0
  266. package/src/monitoring/hub.ts +93 -0
  267. package/src/monitoring/manager-agent.ts +73 -0
  268. package/src/monitoring/manager-hub.ts +232 -0
  269. package/src/monitoring/remote.ts +65 -0
  270. package/src/network-definition.ts +83 -0
  271. package/src/node-converge-linux.ts +372 -0
  272. package/src/node-converge-shared.ts +83 -0
  273. package/src/node-converge.ts +40 -0
  274. package/src/onboard.ts +35 -0
  275. package/src/platform/ansible-receipt.ts +128 -0
  276. package/src/platform/ansible.ts +62 -0
  277. package/src/platform/darwin.ts +203 -0
  278. package/src/platform/detect.ts +11 -0
  279. package/src/platform/fallback.ts +110 -0
  280. package/src/platform/index.ts +38 -0
  281. package/src/platform/launchd.ts +98 -0
  282. package/src/platform/linux.ts +139 -0
  283. package/src/platform/ps.ts +45 -0
  284. package/src/platform/resource-verify.ts +128 -0
  285. package/src/platform/systemd-user.ts +95 -0
  286. package/src/platform/t3-policy.ts +137 -0
  287. package/src/platform/t3-route.ts +68 -0
  288. package/src/platform/t3-service.ts +75 -0
  289. package/src/platform/types.ts +123 -0
  290. package/src/platform/ubuntu-audit.ts +63 -0
  291. package/src/platform/ubuntu-verify.ts +105 -0
  292. package/src/platform/windows.ts +148 -0
  293. package/src/power-recovery.ts +55 -0
  294. package/src/probe.ts +51 -0
  295. package/src/protocol.ts +119 -0
  296. package/src/proxy-converge.ts +85 -0
  297. package/src/remote-bootstrap.ts +212 -0
  298. package/src/remote-entry.ts +89 -0
  299. package/src/remote-lock.ts +12 -0
  300. package/src/repair-catalog.ts +206 -0
  301. package/src/repair-plan.ts +78 -0
  302. package/src/repair-runner.ts +84 -0
  303. package/src/report.ts +71 -0
  304. package/src/runner.ts +104 -0
  305. package/src/secrets.ts +169 -0
  306. package/src/service-auth.ts +115 -0
  307. package/src/ssh.ts +135 -0
  308. package/src/sync.ts +104 -0
  309. package/src/t3/accounts.ts +81 -0
  310. package/src/t3/desired.ts +165 -0
  311. package/src/t3/files.ts +81 -0
  312. package/src/t3/names-check.ts +53 -0
  313. package/src/t3/names.ts +155 -0
  314. package/src/t3/plan.ts +82 -0
  315. package/src/t3/providers.ts +74 -0
  316. package/src/t3/reconcile.ts +123 -0
  317. package/src/t3-endpoint.ts +48 -0
  318. package/src/t3-linked-check.ts +101 -0
  319. package/src/tailnet-health.ts +231 -0
  320. package/src/tailnet-matching.ts +37 -0
  321. package/src/tailscale.ts +141 -0
  322. package/src/test-fixtures.ts +36 -0
  323. package/src/toolchain-checks.ts +83 -0
  324. package/src/topology.ts +24 -0
  325. package/src/transport.ts +122 -0
  326. package/src/types.ts +95 -0
  327. package/src/vault-config.ts +38 -0
  328. package/src/worker-access-checks.ts +115 -0
  329. package/src/worker-capacity.ts +34 -0
  330. package/src/worker-host-checks.ts +176 -0
  331. package/src/worker-policy.ts +64 -0
  332. package/src/worker-readiness.ts +64 -0
  333. package/src/workstation-checks.ts +29 -0
@@ -0,0 +1,393 @@
1
+ # Model validation and health checks
2
+
3
+ This is the declarative validation layer for the hosted OpenAI-compatible endpoint
4
+ `https://cli-proxy.example.com/v1`. It extends the existing external health workflow; it does
5
+ not replace the provenance, backup-freshness or recovery checks.
6
+
7
+ Models are tested under the ids the proxy serves in `/v1/models` (`claude-opus-5-5`, `claude-sonnet-5-5`, `gpt-6-astra`, `gpt-6.1-sol`), the conventional setup with no alias layer. Everything model-specific lives in [`models.json`](../models.json). The code in
8
+ `scripts/modelhealth/` is generic: adding a model, capability, check or fault scenario is a
9
+ configuration change.
10
+
11
+ ## What counts as evidence
12
+
13
+ Every result is labelled, and the report never blends the classes:
14
+
15
+ | Evidence | Meaning |
16
+ | ---------------------- | ------------------------------------------------------------------------------------------- |
17
+ | `live` | A real request to the configured endpoint passed or failed protocol and invariant checks. |
18
+ | `simulated` | A scenario ran against the local emulator. It proves the harness detects the behavior. |
19
+ | `untested` | Nothing exercised it. It is never reported as healthy, whatever the model status says. |
20
+ | `unsupported` | Declared unsupported in configuration with a reason. It is not requested and not "broken". |
21
+ | `observed_unsupported` | Declared `optional`, and the request failed cleanly (rejected, wrong shape). Informational. |
22
+
23
+ Account failover, quota exhaustion and all-accounts-unavailable behavior cannot be provoked against
24
+ the hosted proxy without burning real subscription quota. Those are `simulated` only, and their
25
+ live status stays `untested`.
26
+
27
+ **Cursor.** The Cursor suite is protocol-level compatibility: public OpenAI Chat Completions and
28
+ Responses request shapes, streaming tool calls, tool round trips, a scripted multi-step coding-agent
29
+ workflow, cancellation and recovery, usage and finish reasons. It does not reproduce Cursor's
30
+ private behavior, and no run of this suite proves the Cursor application works. Every report states
31
+ `Verified with the actual Cursor application: no`. Verifying the application needs a human running
32
+ Cursor against the endpoint with the same model ids and recording the result separately.
33
+
34
+ ## Architecture
35
+
36
+ ```
37
+ models.json ──► config.py (validate, resolve capability states)
38
+ │
39
+ levels ▼
40
+ liveness ─► readiness ─► e2e ── per model, in parallel, isolated ──► derive status ─► JSON + Markdown
41
+ (no key) (key, no │ checks.py engines ◄── scenario.py (turn → chat | responses body)
42
+ inference) │ transport.py (HTTP/SSE, no redirects, no hidden retry)
43
+ │ protocol.py (wire contracts) + expect.py (declared invariants)
44
+ ▼
45
+ emulator.py + simulate.py (routing, rate limit, timeout, truncation: `simulated`)
46
+ ```
47
+
48
+ - **Protocol-neutral turns.** A check describes one conversation turn (`system`, `messages`,
49
+ `tools`, `tool_choice`, `json_schema`, `stream`, …). `scenario.py` renders it as a Chat
50
+ Completions body and as a Responses body, so one declaration yields `chat.<id>` and
51
+ `responses.<id>` cases.
52
+ - **Wire contract before semantics.** `protocol.py` normalizes a response and records violations
53
+ (object type, ids, usage arithmetic, finish reasons, tool-call ids and JSON arguments, SSE
54
+ framing, `[DONE]`, terminal Responses event, sequence numbers, streamed vs final consistency).
55
+ `expect.py` then checks the declared invariants. Exact natural-language output is never asserted;
56
+ text checks use random per-run tokens (`{codeword}`, `{marker}`, `{nonce}`) and tool checks use
57
+ forced tool choice with JSON-Schema-validated arguments.
58
+ - **Independence.** Each model gets its own context, request budget share and consecutive-failure
59
+ counter. An exception in one check becomes a `harness` failure for that check only.
60
+
61
+ ## Levels and profiles
62
+
63
+ | Profile | Levels | Inference | Intended use |
64
+ | ----------- | ------------------- | ------------------ | ---------------------------------------------------------------------------------------------- |
65
+ | `liveness` | liveness | none | "Is it reachable and does it reject anonymous callers?" No credentials. |
66
+ | `readiness` | liveness, readiness | none | Key works, `/v1/models` valid, **every configured model served**. |
67
+ | `light` | + cheapest e2e | 2 requests/model | Hourly. Chat non-stream + Responses stream. |
68
+ | `nightly` | + all `full` checks | ~53 requests/model | Comprehensive protocol, tools, agent workflow, errors, concurrency; also runs the simulations. |
69
+ | `manual` | + `manual` checks | + wrong-key probe | Full diagnostics, plus the fault-injection scenarios. |
70
+
71
+ Liveness checks that `GET /v1/models` without a key returns 401 (a 200 is a failure) and that the
72
+ dashboard serves. Readiness lists discovered models and reports any not in configuration
73
+ (`discovered_unconfigured`). A configured model id missing from `/v1/models` makes that model
74
+ `unhealthy` with category `model_missing` and no inference is sent to it. It is never skipped
75
+ silently.
76
+
77
+ The wrong-key probe is `manual` only. Upstream counts failed _management_ logins toward an IP ban,
78
+ and scheduled checks must not generate failed logins; the harness never sends a management key at
79
+ all.
80
+
81
+ ## Commands
82
+
83
+ ```bash
84
+ # Frequent, cheap: liveness + readiness + 2 requests per model
85
+ devfleet cliproxy model-health # default profile: light
86
+ devfleet cliproxy model-health --profile readiness # no inference
87
+ devfleet cliproxy model-health --profile liveness # no credentials
88
+
89
+ # Complete suite (default profile: nightly)
90
+ devfleet cliproxy model-suite
91
+ devfleet cliproxy model-suite --suite cursor # Cursor-style agent checks only
92
+ devfleet cliproxy model-suite --profile manual --model gpt-6.1-sol --output ./report
93
+
94
+ # Offline: the same declarative suite against the local emulator. No key, no spend, no network.
95
+ devfleet cliproxy model-suite --target mock --profile manual
96
+ ```
97
+
98
+ Useful flags: `--model MODEL_ID` (repeatable), `--check CAPABILITY_GLOB` (repeatable), `--force-probe`, `--suite core|cursor|all`, `--json`, `--output DIR`
99
+ (writes `model-health.json`, `model-health.md` and `agent-brief.md`), `--state FILE` (last-success memory),
100
+ `--max-requests N`, `--concurrency N`, `--timeout-scale F`, `--seed N` (reproducible tokens),
101
+ `--fail-on unhealthy|degraded`, `--allow-unknown`.
102
+
103
+ Exit codes: `0` ok, `1` unhealthy (or degraded with `--fail-on degraded`), `2` unknown (for example
104
+ no credentials; a result that was not obtained is never a pass), `3` bad configuration or arguments.
105
+
106
+ The client key is read, in order, from `CLIPROXY_API_KEY`, an existing `VAULT_TOKEN`
107
+ (`secret/personal/prd:CLIPROXY_FLEET_CLIENT_API_KEY`, the same short-lived GitHub OIDC login the
108
+ workflow already uses), then the installed host's `state/secrets/client-key`. It is held in memory,
109
+ sent only as a bearer header, registered with the redactor, and never printed or written.
110
+
111
+ ## Status model
112
+
113
+ Per model: `healthy`, `degraded`, `unhealthy`, `unknown`.
114
+
115
+ - `unknown`: inference was not exercised at this scope, readiness did not pass, or no check
116
+ completed. Readiness-only profiles therefore report models as `unknown`, not `healthy`.
117
+ - `unhealthy`: model id not served; a `critical` required capability fails; or at least
118
+ `health.unhealthy_if_failed_ratio` of the exercised required capabilities fail.
119
+ - `degraded`: a non-critical required capability fails, a required capability's optional sibling
120
+ hit an infrastructure failure, latency exceeds `health.latency_ms`, or one model id resolved to
121
+ several response model ids (`health.model_consistency`).
122
+ - `healthy`: everything that was exercised passed. **Healthy applies to the exercised capabilities
123
+ only**; read `coverage` and the `untested` rows. A `light` run exercises 2 of 38.
124
+
125
+ Run-level status is the worst of the levels and models. Simulation failures degrade it.
126
+
127
+ Safeguards against runaway cost: an exhausted budget leaves the remaining checks `untested` with
128
+ reason `budget`; four consecutive failures, or any HTTP 429, stop further requests to that model
129
+ (`aborted`); inference requests are never retried (`retry.inference` must be 0 and the validator
130
+ rejects anything else). Only the read-only model listing is retried once, on transport errors.
131
+
132
+ ## Configuration reference (`models.json`)
133
+
134
+ | Section | Purpose |
135
+ | --------------------------------------- | --------------------------------------------------------------------------------------- |
136
+ | `endpoint` | Base URL (HTTPS), key environment variable, Vault field. |
137
+ | `runs` | Profiles: levels, highest check tier, request/token budget, concurrency, `simulations`. |
138
+ | `timeouts`, `retry` | Per-request, stream idle/deadline, liveness; retry policy. |
139
+ | `health` | Abort threshold, unhealthy ratio, latency warnings, model-id consistency. |
140
+ | `protocols` | Path and token-limit field for `chat` and `responses`. |
141
+ | `capability_profiles` | Default state, `optional` and `unsupported` capability globs, shared request extras. |
142
+ | `models` | Model id, provider, profile, per-model capability overrides and request extras. |
143
+ | `tools` | Function definitions (JSON Schema) shared by checks. |
144
+ | `checks` | Declarative test cases (below). |
145
+ | `simulated_capabilities`, `simulations` | Routing, rate-limit, timeout and truncation scenarios. |
146
+ | `cursor` | Compatibility statement shown in every report. |
147
+ | `diagnostics` | Actionable advice per failure category. |
148
+
149
+ Capability ids are `<protocol>.<check id>`, for example `responses.tools_stream`. States are
150
+ `required`, `optional` (failure by assertion, protocol or rejection becomes
151
+ `observed_unsupported`; infrastructure failures still count) and `unsupported` (needs a reason).
152
+ Globs such as `*.tools*` are matched with `fnmatch` and must match at least one capability, so a
153
+ typo is a configuration error.
154
+
155
+ Check kinds (the only code paths): `request`, `roundtrip` (tool call, result, answer), `agent`
156
+ (scripted read, edit, test workflow with a virtual file system), `cancel_recover`, `concurrent`,
157
+ `error_probe`. Expectations: `finish_reason`, `content` (`non_empty`, `contains`), `usage`,
158
+ `stream` (`min_events`, `max_gap_s`), `json` (schema), `tool_calls` (`min`, `max`, `names`,
159
+ `unique_ids`, `arguments_schema: from_tools`, `arguments`, `values`), and for probes `status` and
160
+ `error_envelope`. Tiers: `light` < `full` < `manual`. Severities: `critical`, `major`, `minor`.
161
+
162
+ ### Add a model
163
+
164
+ Append to `models` and nothing else:
165
+
166
+ ```json
167
+ {
168
+ "id": "new-vendor-model",
169
+ "provider": "anthropic",
170
+ "profile": "frontier-agent",
171
+ "capabilities": {
172
+ "*.json_schema": {
173
+ "state": "unsupported",
174
+ "reason": "No structured output on this route."
175
+ },
176
+ "responses.parallel_tools": "optional"
177
+ },
178
+ "extra": { "chat": { "reasoning_effort": "low" } }
179
+ }
180
+ ```
181
+
182
+ Run `python3 -B cliproxy/scripts/check.py` (it validates `models.json`), then
183
+ `devfleet cliproxy model-suite --target mock` and finally a live `--model` run. Unit tests
184
+ (`tests/test_model_config.py`) demonstrate that a new model is picked up with no code changes.
185
+
186
+ ### Add a capability or check
187
+
188
+ Append to `checks`. Reuse a kind, write the turn and the expectation, choose `severity`, `tier` and
189
+ `suites`. List the protocols it applies to; the capability ids appear automatically in every
190
+ model's report, defaulting to the profile's state. If no existing kind can express it, add a kind
191
+ to `checks.RUNNERS`; that is the only case that needs code.
192
+
193
+ ### Add a fault scenario
194
+
195
+ Append to `simulations` (accounts with `quota` or `fail_next`, then `request`, `fault`,
196
+ `account`, `advance` steps with `expect` keys such as `served_by_all`, `served_set`, `category`,
197
+ `retry_after`, `no_retry`). The emulator's virtual clock (`advance`) makes cooldown recovery
198
+ instantaneous and deterministic.
199
+
200
+ ## Multi-account routing: fill first
201
+
202
+ The proxy is configured to multiplex across accounts with a **fill-first** pattern: one account
203
+ takes all traffic until its quota is exhausted (a 429 puts it into cooldown), then the next
204
+ account serves, and so on. This is `routing.strategy: fill-first` in
205
+ [`config.template.yaml`](../config.template.yaml), together with `session-affinity: true` (a
206
+ session stays on its account while that account is available and rebinds on failover),
207
+ `cooldown.disable-cooling: false` (cooldown is what moves the fill to the next account) and
208
+ `retry.max-retry-credentials: 0` (every eligible account may be tried, so several exhausted
209
+ accounts still reach the next usable one). `models.json` mirrors the policy under `routing`, and a
210
+ test fails if the two disagree.
211
+
212
+ What is enforced where:
213
+
214
+ - **New or recovered deployments** start from the template, so they fill first.
215
+ - **`cliproxy apply FILE`** passes `--require-fill-first` to `validate-config`; a candidate config with
216
+ another strategy is refused. Starting an existing config is not blocked, so an older deployment
217
+ still comes up after an install.
218
+ - **The five-minute host monitor** reports `Live routing strategy is not fill-first` when the
219
+ running `state/runtime/config.yaml` differs from the policy. This is the signal that the live
220
+ config still needs the change below.
221
+ - **The emulator** implements the same policy (ordered fill, quota and transient-error cooldowns of
222
+ 30s and 60s, affinity binding that outranks order, rebinding on failover) and the scenarios
223
+ `fill_first_*`, `transient_failure_cools_the_account_then_it_rejoins` and
224
+ `session_binding_survives_recovery_and_rebinds_on_failover` assert it. The same scenarios fail
225
+ when the emulator is switched to round robin, so they cannot pass vacuously.
226
+
227
+ **Applying it to the running proxy is an operator step.** The repository cannot change the live
228
+ config, and the strategy is not observable through the API, so the health report labels the policy
229
+ `declared` and never `live_verified`. On the proxy host:
230
+
231
+ ```bash
232
+ cp /opt/cliproxy-fleet/state/runtime/config.yaml /protected/candidate.yaml
233
+ # edit routing: strategy -> fill-first, retry.max-retry-credentials -> 0; change nothing else
234
+ devfleet cliproxy apply /protected/candidate.yaml # validate, isolated staging, restart, health wait
235
+ devfleet cliproxy status # monitor-failed clears on the next 5-minute run
236
+ ```
237
+
238
+ Not established by this repository: which account counts as "first". Upstream chooses the order
239
+ among OAuth credentials; the vendored configuration documents `priority` (larger first) only for
240
+ API-key entries. Confirm the fill order on the host (for example by watching which account's quota
241
+ moves in the dashboard) before relying on a particular account being drained first.
242
+
243
+ ## Running in T3 Code and other agent sandboxes
244
+
245
+ The offline suite is hermetic: it uses only loopback sockets on ephemeral ports, standard-library
246
+ Python (3.9 through 3.15, so both the system and the mise-pinned interpreter work), temporary
247
+ directories it removes, and no network, credentials, Docker, Restic or PyYAML. Tests scrub ambient
248
+ `CLIPROXY_API_KEY`, `VAULT_TOKEN`, `CLIPROXY_ROOT` and proxy variables, and a test proves a
249
+ planted key is never used or printed. The suite passes under `python -X dev -W error` (no leaked
250
+ sockets), with a hostile environment, and 8-way parallel with CPU hogs running.
251
+
252
+ ```bash
253
+ # T3 project action (runs the shared bootstrap first, then the personal CLI)
254
+ bash bootstrap/project-action.sh infra-cliproxy model-suite --target mock --profile manual
255
+ bash bootstrap/project-action.sh infra-cliproxy model-health # live, needs a key
256
+
257
+ # Unit tests only, through the pinned toolchain
258
+ mise exec -- bun run --filter @pkgs/cliproxy-fleet test:models
259
+ mise exec -- bun run --filter @pkgs/cliproxy-fleet lint
260
+ ```
261
+
262
+ Suggested T3 script labels: `Infra: Cliproxy model health` (`infra-cliproxy model-health`) and
263
+ `Infra: Cliproxy model suite` (`infra-cliproxy model-suite`). The full package `test` still needs
264
+ Restic and PyYAML for the older backup and recovery tests; `test:models` does not.
265
+
266
+ ## Emulator and contract tests
267
+
268
+ `scripts/modelhealth/emulator.py` is a deterministic implementation of the public wire protocols
269
+ plus the proxy's documented routing policy from `config.template.yaml`: round robin, session
270
+ affinity, cooldown after quota exhaustion, bounded credential retries. It supports injected faults
271
+ (status codes, stalls, truncation, malformed SSE, missing ids or usage, cross-request token
272
+ contamination). It is a test double, not a model of any provider's behavior.
273
+
274
+ Pull requests run these as part of `bun run --filter @pkgs/cliproxy-fleet test` (offline, a few
275
+ seconds, no spend): protocol validators against valid fixtures and one mutation per defect, SSE
276
+ framing edge cases against a raw socket server, property-style tests (randomized tool-argument
277
+ fragmentation, schema validation), fill-first routing, the full suite against the emulator, per-model isolation,
278
+ budgets, fault detection, last-success persistence, and secret hygiene.
279
+
280
+ ## Scheduling and cost
281
+
282
+ [`cliproxy-health.yml`](../../../.github/workflows/cliproxy-health.yml) has five entry points:
283
+
284
+ | Trigger | Profile | Inference | Notes |
285
+ | ---------------- | ----------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------- |
286
+ | Every 15 minutes | `readiness` | none | Key, `/v1/models`, every configured model served, plus cloud checkpoint freshness. Free. |
287
+ | Hourly (`:17`) | `light` | 2 requests per model (about 8/run) | About 190 requests and well under 5,000 output tokens a day across four models. |
288
+ | 03:41 UTC | `nightly` | about 53 requests per model | Capped at 240 requests and 24,000 output tokens per run. |
289
+ | Pull request | (offline) | none | `contract` job: `models.json` lint, the offline tests and the whole suite against the emulator. No credentials. |
290
+ | Manual dispatch | any | your choice | `model`, `check`, `max_requests` and `force_probe` inputs. |
291
+
292
+ Controls that keep usage bounded, all in `models.json`:
293
+
294
+ - Per-profile caps on total requests, requests per model, output tokens and concurrency. Exhaustion leaves
295
+ the remaining checks `untested` (reason `budget`); it never fails silently or spends more.
296
+ - Small fixtures: every check caps output at 400 tokens or fewer; the long-stream and cancellation
297
+ checks ask for 300 and 200.
298
+ - No inference retries, ever. Four consecutive failures stop a model.
299
+ - **Rate-limit pause.** A 429 stops that model immediately and records the time in the state file. For
300
+ `health.rate_limit_backoff_s` (30 minutes) later runs send that model nothing: its status stays
301
+ `unhealthy` (still excluded from the overall verdict), the finding is `paused`, and the reason says when probing resumes. The first probe after
302
+ the pause that succeeds clears it. `--force-probe` overrides. Quota exhaustion therefore costs one
303
+ rejected request per half hour, not a request per run.
304
+ - A 429 is rejected before inference and does not consume provider usage; successful requests are tiny.
305
+ - Last-success and pause state persist between runs through the Actions cache, shared by all profiles.
306
+
307
+ Each live run uploads `model-health.json`, `model-health.md` and `agent-brief.md` as an artifact
308
+ (30 days) and writes the brief and the report to the job summary.
309
+
310
+ ## Findings, the agent brief and the tracking issue
311
+
312
+ Every failure becomes a **finding** in `model-health.json` (`findings[]`, validated by
313
+ [`model-health-report.schema.json`](model-health-report.schema.json)) and in `agent-brief.md`:
314
+
315
+ - `id`: stable (`<model>/<capability>/<category>`), so a fix can be confirmed by its absence.
316
+ - `resolver` / `agent_fixable`: `operator` for quota, credentials, the proxy host or proxy configuration,
317
+ which no edit to this repository can fix; `agent` for protocol or assertion mismatches, harness defects
318
+ and budgets. Operator findings are listed first.
319
+ - `evidence`: the failure details plus one **trace** per request: method, path, HTTP status, timings,
320
+ Cloudflare `cf-ray` and `x-request-id`, `retry-after`, resolved model id, finish reason, event count,
321
+ tool-call names, usage, and the protocol violations found. Traces contain structure and numbers only:
322
+ never prompt text, completions or keys, and error messages are redacted and truncated.
323
+ - `reproduce`: the exact cheap command, for example
324
+ `devfleet cliproxy model-suite --profile nightly --model gpt-6.1-sol --check chat.tools --seed 4` (one
325
+ check, one or two requests). `--check` takes capability globs.
326
+ - `fix_hints`: where to edit (`models.json` declaration, check fixture, validator, or the operator
327
+ action), and what not to do (delete a check, loosen an assertion, call an untested capability healthy).
328
+
329
+ On scheduled and full manual runs the workflow also keeps one issue per scope,
330
+ `[ops] CLI proxy model health (live)` and `(nightly)`: opened with the brief when the run is unhealthy or
331
+ degraded, updated (with a comment) only when the set of findings changes (`summary.findings.fingerprint`),
332
+ and closed when a full run is healthy. Partial runs (`model` or `check` set) never touch it. The issue body
333
+ is the redacted brief, which includes provider error text such as `usage_limit_reached` and request ids;
334
+ keep that in mind if the repository is public.
335
+
336
+ ### Agent runbook
337
+
338
+ ```bash
339
+ gh workflow run "CLI proxy health" -f profile=readiness # free
340
+ gh workflow run "CLI proxy health" -f profile=nightly -f model=claude-opus-5-5 # one model
341
+ gh run list --workflow "CLI proxy health" --limit 5
342
+ gh run download <run-id> -n model-health-nightly-<run-id> # agent-brief.md, model-health.json
343
+ ```
344
+
345
+ The same flow is the `/model-health` agent command (`.agents/commands/model-health.md`): read the brief,
346
+ stop on operator findings, reproduce an agent finding with its command, fix the declaration, check or
347
+ validator, add an offline test, run `test:models`, and verify with a live run of the reproduce command.
348
+
349
+ ## Report
350
+
351
+ `model-health.json` (`schema: cliproxy-model-health/1`) contains `levels`, `models[]` (status,
352
+ reasons, `coverage`, `capabilities` with declared state and observed result, `checks[]` with
353
+ category, endpoint, severity, details and observations, `metrics`, `last_success`),
354
+ `simulations`, `budget`, `cursor` and `summary.diagnostics`. Metrics per model: availability, check
355
+ success rate, TTFT p50/max, latency p50/p95, streaming completion rate, tool-call success rate,
356
+ error categories, upstream failures and the resolved model ids. Routing outcomes are reported only
357
+ for simulations.
358
+
359
+ Failure categories: `credentials`, `auth`, `not_found`, `rate_limit`, `timeout`, `transport`,
360
+ `upstream`, `protocol`, `assertion`, `request_rejected`, `budget`, `aborted`, `model_missing`,
361
+ `harness`. Diagnostics never contain keys, tokens, request bodies or prompt text; messages from the
362
+ endpoint are redacted and truncated to a few hundred characters.
363
+
364
+ ## Investigating a failure
365
+
366
+ 1. Open the run summary. Read **Levels** first: a liveness or readiness failure explains every
367
+ model failure below it.
368
+ 2. `transport`/`timeout` at liveness: host, tunnel or DNS. Use `devfleet cliproxy status` on the
369
+ workstation. `auth` at readiness: the client key and `access.api-keys` disagree.
370
+ 3. `model_missing`: the model id is not in `/v1/models`. Compare `devfleet cliproxy models` with
371
+ `models.json`; the provider account behind it may be unauthenticated or the model retired.
372
+ 4. A model `unhealthy` with `upstream`: provider account or upstream outage. Check the dashboard and
373
+ `devfleet cliproxy logs`. A model with `rate_limit` (quota exhausted, every credential cooling down)
374
+ is listed in `summary.rate_limited` and as an operator finding, but never fails the run or turns
375
+ `summary.status` red: the proxy answered, and the limit clears on its own. The harness already
376
+ stopped requesting after the first 429.
377
+ 5. `protocol` or `assertion`: reproduce one case with
378
+ `model-suite --profile nightly --model MODEL_ID --seed N` (the seed is in the report). `protocol`
379
+ after a CLIProxyAPI upgrade usually means the translation changed; compare the check's details
380
+ with the validator in `protocol.py`.
381
+ 6. If the capability is genuinely unavailable on that route, change its state to `optional` or
382
+ `unsupported` with a reason, in a reviewed commit. Do not delete checks to make a report green.
383
+ 7. `harness`: a defect in the checks, not the endpoint. Run the unit tests.
384
+
385
+ ## What was and was not verified
386
+
387
+ The emulator and unit tests prove the harness's assertions, classification, budgets and reports.
388
+ They do not prove the hosted endpoint is healthy. Live health is established only by a report whose
389
+ target is `live` with `evidence: live` checks; until a scheduled or manual run has completed with a
390
+ valid client key, no model has a live validation on record. The first live run may legitimately
391
+ surface capability declarations in `models.json` that need adjusting (for example parallel tool
392
+ calls or structured output on a given route); such results are the signal the configuration
393
+ exists to capture.
@@ -0,0 +1,5 @@
1
+ {
2
+ "eceasy/cli-proxy-api": "eceasy/cli-proxy-api@sha256:afe1135e8d8752867b73d717c1ca8ed27c44bfe8c6e1a2bebf228dba98889eac",
3
+ "tailscale/tailscale": "tailscale/tailscale@sha256:ed6480b33c6eb67c9cbd203ed42b9fb57e361986725b6856def71b7a3d9e276c",
4
+ "cloudflare/cloudflared": "cloudflare/cloudflared@sha256:072c067d25ccbe61d46e18f0d0723255f2bb5304f7317caa95b27031520ff92c"
5
+ }
@@ -0,0 +1,38 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>Label</key>
6
+ <string>dev.devfleet.cliproxy-backup-check</string>
7
+ <key>ProgramArguments</key>
8
+ <array>
9
+ <string>/bin/sh</string>
10
+ <string>-c</string>
11
+ <string>PATH="$HOME/Library/Application Support/cliproxy-fleet/tools/bin:$PATH" exec "$HOME/Library/Application Support/cliproxy-fleet/scripts/backup" check</string>
12
+ </array>
13
+ <key>EnvironmentVariables</key>
14
+ <dict>
15
+ <key>PATH</key>
16
+ <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Docker.app/Contents/Resources/bin</string>
17
+ <key>PYTHONDONTWRITEBYTECODE</key>
18
+ <string>1</string>
19
+ </dict>
20
+ <key>Umask</key>
21
+ <integer>63</integer>
22
+ <key>ProcessType</key>
23
+ <string>Background</string>
24
+ <key>Nice</key>
25
+ <integer>10</integer>
26
+ <key>StartCalendarInterval</key>
27
+ <dict>
28
+ <key>Weekday</key>
29
+ <integer>0</integer>
30
+ <key>Hour</key>
31
+ <integer>5</integer>
32
+ <key>Minute</key>
33
+ <integer>0</integer>
34
+ </dict>
35
+ <key>LowPriorityIO</key>
36
+ <true/>
37
+ </dict>
38
+ </plist>
@@ -0,0 +1,48 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>Label</key>
6
+ <string>dev.devfleet.cliproxy-backup</string>
7
+ <key>ProgramArguments</key>
8
+ <array>
9
+ <string>/bin/sh</string>
10
+ <string>-c</string>
11
+ <string>PATH="$HOME/Library/Application Support/cliproxy-fleet/tools/bin:$PATH" exec "$HOME/Library/Application Support/cliproxy-fleet/scripts/backup" backup</string>
12
+ </array>
13
+ <key>EnvironmentVariables</key>
14
+ <dict>
15
+ <key>PATH</key>
16
+ <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Docker.app/Contents/Resources/bin</string>
17
+ <key>PYTHONDONTWRITEBYTECODE</key>
18
+ <string>1</string>
19
+ </dict>
20
+ <key>Umask</key>
21
+ <integer>63</integer>
22
+ <key>ProcessType</key>
23
+ <string>Background</string>
24
+ <key>Nice</key>
25
+ <integer>10</integer>
26
+ <key>StartCalendarInterval</key>
27
+ <array>
28
+ <dict>
29
+ <key>Minute</key>
30
+ <integer>0</integer>
31
+ </dict>
32
+ <dict>
33
+ <key>Minute</key>
34
+ <integer>15</integer>
35
+ </dict>
36
+ <dict>
37
+ <key>Minute</key>
38
+ <integer>30</integer>
39
+ </dict>
40
+ <dict>
41
+ <key>Minute</key>
42
+ <integer>45</integer>
43
+ </dict>
44
+ </array>
45
+ <key>LowPriorityIO</key>
46
+ <true/>
47
+ </dict>
48
+ </plist>
@@ -0,0 +1,32 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>Label</key>
6
+ <string>dev.devfleet.cliproxy-fleet</string>
7
+ <key>ProgramArguments</key>
8
+ <array>
9
+ <string>/bin/sh</string>
10
+ <string>-c</string>
11
+ <string>PATH="$HOME/Library/Application Support/cliproxy-fleet/tools/bin:$PATH" exec "$HOME/Library/Application Support/cliproxy-fleet/scripts/service-start"</string>
12
+ </array>
13
+ <key>EnvironmentVariables</key>
14
+ <dict>
15
+ <key>PATH</key>
16
+ <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Docker.app/Contents/Resources/bin</string>
17
+ <key>PYTHONDONTWRITEBYTECODE</key>
18
+ <string>1</string>
19
+ </dict>
20
+ <key>Umask</key>
21
+ <integer>63</integer>
22
+ <key>RunAtLoad</key>
23
+ <true/>
24
+ <key>KeepAlive</key>
25
+ <dict>
26
+ <key>SuccessfulExit</key>
27
+ <false/>
28
+ </dict>
29
+ <key>ThrottleInterval</key>
30
+ <integer>60</integer>
31
+ </dict>
32
+ </plist>
@@ -0,0 +1,38 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>Label</key>
6
+ <string>dev.devfleet.cliproxy-gc</string>
7
+ <key>ProgramArguments</key>
8
+ <array>
9
+ <string>/bin/sh</string>
10
+ <string>-c</string>
11
+ <string>PATH="$HOME/Library/Application Support/cliproxy-fleet/tools/bin:$PATH" exec "$HOME/Library/Application Support/cliproxy-fleet/scripts/backup" gc</string>
12
+ </array>
13
+ <key>EnvironmentVariables</key>
14
+ <dict>
15
+ <key>PATH</key>
16
+ <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Docker.app/Contents/Resources/bin</string>
17
+ <key>PYTHONDONTWRITEBYTECODE</key>
18
+ <string>1</string>
19
+ </dict>
20
+ <key>Umask</key>
21
+ <integer>63</integer>
22
+ <key>ProcessType</key>
23
+ <string>Background</string>
24
+ <key>Nice</key>
25
+ <integer>10</integer>
26
+ <key>StartCalendarInterval</key>
27
+ <dict>
28
+ <key>Weekday</key>
29
+ <integer>0</integer>
30
+ <key>Hour</key>
31
+ <integer>4</integer>
32
+ <key>Minute</key>
33
+ <integer>0</integer>
34
+ </dict>
35
+ <key>LowPriorityIO</key>
36
+ <true/>
37
+ </dict>
38
+ </plist>
@@ -0,0 +1,29 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>Label</key>
6
+ <string>dev.devfleet.cliproxy-monitor</string>
7
+ <key>ProgramArguments</key>
8
+ <array>
9
+ <string>/bin/sh</string>
10
+ <string>-c</string>
11
+ <string>PATH="$HOME/Library/Application Support/cliproxy-fleet/tools/bin:$PATH" exec "$HOME/Library/Application Support/cliproxy-fleet/scripts/monitor"</string>
12
+ </array>
13
+ <key>EnvironmentVariables</key>
14
+ <dict>
15
+ <key>PATH</key>
16
+ <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Docker.app/Contents/Resources/bin</string>
17
+ <key>PYTHONDONTWRITEBYTECODE</key>
18
+ <string>1</string>
19
+ </dict>
20
+ <key>Umask</key>
21
+ <integer>63</integer>
22
+ <key>ProcessType</key>
23
+ <string>Background</string>
24
+ <key>Nice</key>
25
+ <integer>10</integer>
26
+ <key>StartInterval</key>
27
+ <integer>300</integer>
28
+ </dict>
29
+ </plist>
@@ -0,0 +1,31 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>Label</key>
6
+ <string>dev.devfleet.cliproxy-vault-renew</string>
7
+ <key>ProgramArguments</key>
8
+ <array>
9
+ <string>/bin/sh</string>
10
+ <string>-c</string>
11
+ <string>PATH="$HOME/Library/Application Support/cliproxy-fleet/tools/bin:$PATH" exec "$HOME/Library/Application Support/cliproxy-fleet/scripts/vault-renew"</string>
12
+ </array>
13
+ <key>EnvironmentVariables</key>
14
+ <dict>
15
+ <key>PATH</key>
16
+ <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Docker.app/Contents/Resources/bin</string>
17
+ <key>PYTHONDONTWRITEBYTECODE</key>
18
+ <string>1</string>
19
+ </dict>
20
+ <key>Umask</key>
21
+ <integer>63</integer>
22
+ <key>ProcessType</key>
23
+ <string>Background</string>
24
+ <key>Nice</key>
25
+ <integer>10</integer>
26
+ <key>RunAtLoad</key>
27
+ <true/>
28
+ <key>StartInterval</key>
29
+ <integer>900</integer>
30
+ </dict>
31
+ </plist>