eggpool 0.1.0__tar.gz → 0.1.2__tar.gz

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 (196) hide show
  1. {eggpool-0.1.0 → eggpool-0.1.2}/.github/workflows/ci.yml +5 -2
  2. {eggpool-0.1.0 → eggpool-0.1.2}/AGENTS.md +6 -2
  3. {eggpool-0.1.0 → eggpool-0.1.2}/CHANGELOG.md +21 -0
  4. {eggpool-0.1.0 → eggpool-0.1.2}/PKG-INFO +42 -30
  5. {eggpool-0.1.0 → eggpool-0.1.2}/README.md +39 -28
  6. {eggpool-0.1.0 → eggpool-0.1.2}/architecture/README.md +1 -1
  7. eggpool-0.1.2/docs/deployment.md +235 -0
  8. eggpool-0.1.2/docs/raspberry-pi.md +93 -0
  9. {eggpool-0.1.0 → eggpool-0.1.2}/pyproject.toml +5 -4
  10. {eggpool-0.1.0 → eggpool-0.1.2}/scripts/install.sh +5 -5
  11. eggpool-0.1.2/src/eggpool/__init__.py +10 -0
  12. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/api/proxy_request.py +2 -2
  13. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/api/stats.py +10 -16
  14. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/app.py +2 -1
  15. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/catalog/cache.py +23 -32
  16. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/cli.py +372 -37
  17. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/routes.py +9 -15
  18. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/deploy/__init__.py +105 -0
  19. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/onboard.py +18 -1
  20. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/providers/connect.py +17 -23
  21. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/providers/contract.py +8 -1
  22. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/routing/provider.py +11 -4
  23. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/stats/__init__.py +2 -0
  24. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/stats/service.py +21 -8
  25. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/toml_edit.py +22 -0
  26. {eggpool-0.1.0 → eggpool-0.1.2}/uv.lock +132 -4
  27. eggpool-0.1.0/docs/deployment.md +0 -322
  28. eggpool-0.1.0/docs/raspberry-pi.md +0 -356
  29. eggpool-0.1.0/src/eggpool/__init__.py +0 -5
  30. {eggpool-0.1.0 → eggpool-0.1.2}/.env.example +0 -0
  31. {eggpool-0.1.0 → eggpool-0.1.2}/.github/workflows/release.yml +0 -0
  32. {eggpool-0.1.0 → eggpool-0.1.2}/.gitignore +0 -0
  33. {eggpool-0.1.0 → eggpool-0.1.2}/LICENSE +0 -0
  34. {eggpool-0.1.0 → eggpool-0.1.2}/config-examples/claude-code.env +0 -0
  35. {eggpool-0.1.0 → eggpool-0.1.2}/config-examples/opencode.jsonc +0 -0
  36. {eggpool-0.1.0 → eggpool-0.1.2}/config.example.toml +0 -0
  37. {eggpool-0.1.0 → eggpool-0.1.2}/deploy/eggpool-logrotate.conf +0 -0
  38. {eggpool-0.1.0 → eggpool-0.1.2}/deploy/eggpool.service +0 -0
  39. {eggpool-0.1.0 → eggpool-0.1.2}/deploy/env.example +0 -0
  40. {eggpool-0.1.0 → eggpool-0.1.2}/docs/backup-restore.md +0 -0
  41. {eggpool-0.1.0 → eggpool-0.1.2}/docs/filesystem-layout.md +0 -0
  42. {eggpool-0.1.0 → eggpool-0.1.2}/docs/firewall.md +0 -0
  43. {eggpool-0.1.0 → eggpool-0.1.2}/docs/model-limits.md +0 -0
  44. {eggpool-0.1.0 → eggpool-0.1.2}/docs/providers.md +0 -0
  45. {eggpool-0.1.0 → eggpool-0.1.2}/docs/proxy.md +0 -0
  46. {eggpool-0.1.0 → eggpool-0.1.2}/scripts/__init__.py +0 -0
  47. {eggpool-0.1.0 → eggpool-0.1.2}/scripts/check_database.py +0 -0
  48. {eggpool-0.1.0 → eggpool-0.1.2}/scripts/install_prompt.py +0 -0
  49. {eggpool-0.1.0 → eggpool-0.1.2}/scripts/smoke_test.py +0 -0
  50. {eggpool-0.1.0 → eggpool-0.1.2}/scripts/verify_upstream_auth.py +0 -0
  51. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/__main__.py +0 -0
  52. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/_share/.env.example +0 -0
  53. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/_share/config.example.toml +0 -0
  54. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/accounts/__init__.py +0 -0
  55. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/accounts/registry.py +0 -0
  56. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/accounts/state.py +0 -0
  57. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/api/__init__.py +0 -0
  58. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/api/chat_completions.py +0 -0
  59. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/api/errors.py +0 -0
  60. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/api/messages.py +0 -0
  61. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/api/models.py +0 -0
  62. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/auth.py +0 -0
  63. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/background/__init__.py +0 -0
  64. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/background/cleanup.py +0 -0
  65. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/catalog/__init__.py +0 -0
  66. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/catalog/fetcher.py +0 -0
  67. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/catalog/limits.py +0 -0
  68. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/catalog/normalizer.py +0 -0
  69. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/catalog/pricing.py +0 -0
  70. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/catalog/protocols.py +0 -0
  71. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/catalog/service.py +0 -0
  72. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/constants.py +0 -0
  73. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/__init__.py +0 -0
  74. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/_resources.py +0 -0
  75. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/escape.py +0 -0
  76. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/render.py +0 -0
  77. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/static/chart.umd.min.js +0 -0
  78. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/static/dashboard.css +0 -0
  79. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/static/favicon.svg +0 -0
  80. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/theme.py +0 -0
  81. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Booberry.toml +0 -0
  82. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Catppuccin Latte.toml +0 -0
  83. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Catppuccin Macchiato.toml +0 -0
  84. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Catppuccin Mocha.toml +0 -0
  85. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Cyber Red.toml +0 -0
  86. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Cyberpunk.toml +0 -0
  87. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Dark Green.toml +0 -0
  88. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Discord (80_ Saturation).toml +0 -0
  89. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Discord.toml +0 -0
  90. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Dracula.toml +0 -0
  91. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Ferra Light.toml +0 -0
  92. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Flexor Dark.toml +0 -0
  93. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Gruvbox.toml +0 -0
  94. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Halcyon Dark.toml +0 -0
  95. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/IntelliJ Light.toml +0 -0
  96. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Kanagawa.toml +0 -0
  97. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Macaw Dark.toml +0 -0
  98. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Macaw Light.toml +0 -0
  99. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Matrix.toml +0 -0
  100. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Noctis Lilac.toml +0 -0
  101. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Nord.toml +0 -0
  102. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Nostromo Terminal.toml +0 -0
  103. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/One Dark.toml +0 -0
  104. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Oxocarbon.toml +0 -0
  105. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Rose Pine Dawn.toml +0 -0
  106. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Rose Pine Moon.toml +0 -0
  107. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Rose Pine.toml +0 -0
  108. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Solarized Dark.toml +0 -0
  109. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Sonokai.toml +0 -0
  110. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Tokyo Night Storm.toml +0 -0
  111. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/VESPER.toml +0 -0
  112. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/Zenburn.toml +0 -0
  113. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/acton.toml +0 -0
  114. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/bam.toml +0 -0
  115. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/base16-atelier-forest-light.toml +0 -0
  116. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/berlin.toml +0 -0
  117. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/black but with important highlights.toml +0 -0
  118. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/broc.toml +0 -0
  119. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/cork.toml +0 -0
  120. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/ferra.toml +0 -0
  121. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/forest.toml +0 -0
  122. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/lisbon.toml +0 -0
  123. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/midnight.toml +0 -0
  124. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/oslo.toml +0 -0
  125. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/plum.toml +0 -0
  126. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/portland.toml +0 -0
  127. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/sunset.toml +0 -0
  128. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/tofino.toml +0 -0
  129. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/vanimo.toml +0 -0
  130. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/dashboard/themes/vik.toml +0 -0
  131. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/__init__.py +0 -0
  132. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/connection.py +0 -0
  133. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/migrations.py +0 -0
  134. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/repositories.py +0 -0
  135. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0001_initial.sql +0 -0
  136. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0002_indexes.sql +0 -0
  137. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0003_request_attempts.sql +0 -0
  138. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0004_integration_hardening.sql +0 -0
  139. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0005_price_microdollars.sql +0 -0
  140. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0006_correct_price_microdollars.sql +0 -0
  141. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0007_price_cache_rates.sql +0 -0
  142. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0008_proxy_request_identity.sql +0 -0
  143. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0009_model_protocol_source.sql +0 -0
  144. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0010_health_probe.sql +0 -0
  145. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0011_model_resolution_status.sql +0 -0
  146. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0012_drop_reservations_estimated_microdollars.sql +0 -0
  147. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0013_request_attempts_account_id_index.sql +0 -0
  148. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0014_bandwidth_tracking.sql +0 -0
  149. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0015_multi_provider.sql +0 -0
  150. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0016_requests_provider_id.sql +0 -0
  151. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0017_price_snapshots_provider_id.sql +0 -0
  152. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0018_provider_pings.sql +0 -0
  153. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0019_client_ip.sql +0 -0
  154. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0020_performance_indexes.sql +0 -0
  155. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0021_provider_model_metadata.sql +0 -0
  156. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/0022_dashboard_indexes.sql +0 -0
  157. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/db/schema/checksums.json +0 -0
  158. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/errors.py +0 -0
  159. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/health/__init__.py +0 -0
  160. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/health/circuit_breaker.py +0 -0
  161. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/health/health_manager.py +0 -0
  162. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/integrations/__init__.py +0 -0
  163. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/integrations/opencode.py +0 -0
  164. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/logging.py +0 -0
  165. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/models/__init__.py +0 -0
  166. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/models/api.py +0 -0
  167. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/models/config.py +0 -0
  168. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/models/database.py +0 -0
  169. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/models/domain.py +0 -0
  170. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/providers/__init__.py +0 -0
  171. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/providers/_templates.toml +0 -0
  172. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/providers/client_pool.py +0 -0
  173. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/providers/pproxy_transport.py +0 -0
  174. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/proxy/__init__.py +0 -0
  175. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/proxy/client.py +0 -0
  176. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/proxy/sse_observer.py +0 -0
  177. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/proxy/usage.py +0 -0
  178. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/py.typed +0 -0
  179. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/quota/__init__.py +0 -0
  180. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/quota/estimation.py +0 -0
  181. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/quota/reservation.py +0 -0
  182. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/quota/scorer.py +0 -0
  183. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/request/__init__.py +0 -0
  184. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/request/attempt_finalizer.py +0 -0
  185. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/request/body.py +0 -0
  186. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/request/coordinator.py +0 -0
  187. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/request/finalizer.py +0 -0
  188. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/request/limits.py +0 -0
  189. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/retry/__init__.py +0 -0
  190. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/retry/classification.py +0 -0
  191. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/routing/__init__.py +0 -0
  192. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/routing/eligibility.py +0 -0
  193. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/routing/router.py +0 -0
  194. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/security/__init__.py +0 -0
  195. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/security/redaction.py +0 -0
  196. {eggpool-0.1.0 → eggpool-0.1.2}/src/eggpool/stats/queries.py +0 -0
@@ -36,12 +36,15 @@ jobs:
36
36
 
37
37
  test:
38
38
  runs-on: ubuntu-latest
39
+ strategy:
40
+ matrix:
41
+ python-version: ["3.11", "3.12"]
39
42
  steps:
40
43
  - uses: actions/checkout@v4
41
44
  - uses: astral-sh/setup-uv@v4
42
45
  - uses: actions/setup-python@v5
43
46
  with:
44
- python-version: "3.12"
47
+ python-version: ${{ matrix.python-version }}
45
48
  - run: uv sync --frozen --extra dev
46
49
  - name: Verify coverage plugin is present
47
50
  run: uv run pytest --help | grep -- --cov
@@ -55,5 +58,5 @@ jobs:
55
58
  if: always()
56
59
  uses: actions/upload-artifact@v4
57
60
  with:
58
- name: coverage-report
61
+ name: coverage-report-py${{ matrix.python-version }}
59
62
  path: coverage.xml
@@ -27,7 +27,7 @@ All four must pass with zero errors.
27
27
 
28
28
  ## Code Style
29
29
 
30
- - Python 3.12+ with `from __future__ import annotations` in ALL files
30
+ - Python 3.11+ with `from __future__ import annotations` in ALL files
31
31
  - Type hints on all function signatures and return types
32
32
  - Ruff: E, F, W, I, N, UP, B, A, SIM, TCH rules
33
33
  - Pyright strict mode — covers `src/` AND `scripts/` (not tests)
@@ -92,19 +92,23 @@ Use the hierarchy in `errors.py`. Chain exceptions with `raise ... from err` or
92
92
 
93
93
  | Command | Description |
94
94
  |---------|-------------|
95
+ | `eggpool help` | Show help message and available commands |
96
+ | `eggpool version` | Print the installed version |
95
97
  | `eggpool serve` | Start the aggregation proxy server (default command) |
96
98
  | `eggpool check-config` | Validate the configuration file |
97
99
  | `eggpool migrate` | Run database migrations |
98
- | `eggpool onboard` | Run the interactive onboarding setup |
100
+ | `eggpool onboard` | Run the interactive onboarding setup (connect providers, start server) |
99
101
  | `eggpool connect` | Connect to a new provider interactively |
100
102
  | `eggpool connect list` | List available providers |
101
103
  | `eggpool logout` | Remove a configured provider account |
102
104
  | `eggpool rehash` | Restart to apply config changes |
105
+ | `eggpool croncheck` | Lightweight check: exit 0 if server is running, exit 1 if not |
103
106
  | `eggpool models refresh` | Refresh model catalog from upstream |
104
107
  | `eggpool configsetup opencode` | Print OpenCode provider config JSON with model limits |
105
108
  | `eggpool db vacuum` | Reclaim SQLite space |
106
109
 
107
110
  All commands accept `--config /path/to/config.toml` (defaults to `config.toml`).
111
+ Running `eggpool` with no arguments prints the help message.
108
112
 
109
113
  ## Git Workflow
110
114
 
@@ -5,6 +5,27 @@ All notable changes to EggPool are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.1.2] - 2026-06-23
9
+
10
+ ### Fixed
11
+
12
+ - Create minimal config when `config.toml` is missing during `eggpool
13
+ onboard`, so fresh installs no longer fail with "Failed to update config".
14
+ - Fix `update` command misidentifying source installs as pipx (causing
15
+ wrong upgrade method).
16
+
17
+ ### Changed
18
+
19
+ - Add `--install` flag to `deploy` subcommands for automated setup.
20
+ - Rewrite deployment docs with personal-use and production sections.
21
+
22
+ ## [0.1.1] - 2026-06-23
23
+
24
+ ### Added
25
+
26
+ - `eggpool deploy` subcommands: `systemd`, `logrotate`, `cron`, `all`.
27
+ - Dynamic deploy snippets based on detected install paths.
28
+
8
29
  ## [0.1.0] - 2026-06-23
9
30
 
10
31
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eggpool
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: A lightweight proxy that aggregates multiple LLM provider accounts behind one OpenAI-compatible endpoint
5
5
  Project-URL: Homepage, https://github.com/eggstack/eggpool
6
6
  Project-URL: Repository, https://github.com/eggstack/eggpool
@@ -19,10 +19,11 @@ Classifier: License :: OSI Approved :: MIT License
19
19
  Classifier: Operating System :: POSIX :: Linux
20
20
  Classifier: Programming Language :: Python :: 3
21
21
  Classifier: Programming Language :: Python :: 3 :: Only
22
+ Classifier: Programming Language :: Python :: 3.11
22
23
  Classifier: Programming Language :: Python :: 3.12
23
24
  Classifier: Topic :: System :: Monitoring
24
25
  Classifier: Typing :: Typed
25
- Requires-Python: >=3.12
26
+ Requires-Python: >=3.11
26
27
  Requires-Dist: aiosqlite
27
28
  Requires-Dist: click
28
29
  Requires-Dist: fastapi
@@ -42,7 +43,7 @@ Requires-Dist: ruff; extra == 'dev'
42
43
  Description-Content-Type: text/markdown
43
44
 
44
45
  [![PyPI version](https://badge.fury.io/py/eggpool.svg)](https://pypi.org/project/eggpool/)
45
- [![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue.svg)](https://www.python.org/)
46
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
46
47
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
47
48
  [![CI](https://github.com/eggstack/eggpool/actions/workflows/ci.yml/badge.svg)](https://github.com/eggstack/eggpool/actions/workflows/ci.yml)
48
49
 
@@ -65,7 +66,7 @@ behind one OpenAI/Anthropic-compatible endpoint.
65
66
 
66
67
  ## Requirements
67
68
 
68
- - Python 3.12+
69
+ - Python 3.11+
69
70
  - [uv](https://docs.astral.sh/uv/) for dependency management
70
71
 
71
72
  ## Quick Start
@@ -74,25 +75,16 @@ behind one OpenAI/Anthropic-compatible endpoint.
74
75
 
75
76
  ```bash
76
77
  pipx install eggpool
77
- pipx run eggpool --help # or just `eggpool --help` if PATH includes it
78
+ eggpool help
79
+ eggpool onboard
78
80
  ```
79
81
 
80
- `pipx` installs `eggpool` into its own venv and exposes the
81
- `eggpool` console script globally. The bundled themes and
82
- provider templates ship inside the package — no extra files
83
- required to start.
82
+ `eggpool onboard` lets you add several providers at once, does a config check, then runs the server. You can also run `eggpool connect` for each provider you want to add and `eggpool serve` to start the server.
83
+ `eggpool configsetup` will help setup config for opencode.
84
84
 
85
- Then copy and edit configuration:
85
+ To get the server to run on startup, run `eggpool deploy` for options, see docs/deployment.md for more info and configs.
86
86
 
87
- ```bash
88
- cp /path/to/your/eggpool-venv/lib/python*/site-packages/eggpool/_share/config.example.toml ~/.config/eggpool/config.toml
89
- ```
90
-
91
- Or use the built-in helper:
92
-
93
- ```bash
94
- eggpool init-config
95
- ```
87
+ `pipx` installs `eggpool` into its own venv and exposes the `eggpool` command on your PATH.
96
88
 
97
89
  ### Option 2: Automated install
98
90
 
@@ -104,13 +96,14 @@ The script:
104
96
 
105
97
  - Downloads the repository if not running from a clone
106
98
  - Installs `uv` if missing
107
- - Verifies Python 3.12+
99
+ - Verifies Python 3.11+
108
100
  - Installs dependencies
109
101
  - Copies example configuration files
110
102
  - Attempts configuration validation
111
103
 
112
- Validation fails until `.env` contains real, non-placeholder keys. Edit
113
- `config.toml` and `.env`, then run the validation and migration commands below.
104
+ The script will ask if you want to continue with onboarding. if you select no, make sure you `cd eggpool`, then you can run `uv run eggpool onboard` to get started. `uv run eggpool connect` for one off provider adds, `uv run eggpool serve` to start server. `uv run eggpool help` for other commands.
105
+
106
+ Run `uv run eggpool deploy` for options on running the server on startup. See docs/deployment.md for more info and configs.
114
107
 
115
108
  ### Option 3: Manual install
116
109
 
@@ -127,19 +120,20 @@ cp .env.example .env
127
120
 
128
121
  # Validate configuration
129
122
  set -a; source .env; set +a
130
- uv run eggpool --config config.toml check-config
123
+ uv run eggpool check-config
131
124
 
132
125
  # Run database migrations
133
- uv run eggpool --config config.toml migrate
126
+ uv run eggpool migrate
134
127
 
135
128
  # Start the server
136
- uv run eggpool --config config.toml serve
129
+ uv run eggpool serve
137
130
  ```
138
131
 
139
132
  ### Option 4: Interactive setup
140
133
 
141
134
  ```bash
142
- # Run the interactive onboarding wizard
135
+ # Run the interactive onboarding wizard — connects one or more
136
+ # providers, validates configuration, and starts the server.
143
137
  uv run eggpool onboard
144
138
 
145
139
  # Or connect to a specific provider
@@ -151,10 +145,12 @@ uv run eggpool connect list
151
145
 
152
146
  | Command | Description |
153
147
  |---------|-------------|
148
+ | `eggpool help` | Show help message and available commands |
149
+ | `eggpool version` | Print the installed version |
154
150
  | `eggpool serve` | Start the aggregation proxy server (default command) |
155
151
  | `eggpool check-config` | Validate the configuration file |
156
152
  | `eggpool migrate` | Run database migrations |
157
- | `eggpool onboard` | Run the interactive onboarding setup |
153
+ | `eggpool onboard` | Run the interactive onboarding setup (connect providers, start server) |
158
154
  | `eggpool connect` | Connect to a new provider interactively |
159
155
  | `eggpool connect list` | List available providers for connection |
160
156
  | `eggpool logout` | Remove a configured provider account |
@@ -169,6 +165,7 @@ uv run eggpool connect list
169
165
  | `eggpool configsetup opencode` | Print OpenCode provider config JSON with model limits |
170
166
  | `eggpool configsetup claude-code` | Print Claude Code config snippet |
171
167
  | `eggpool update` | Check for updates and reinstall if newer |
168
+ | `eggpool croncheck` | Lightweight check: exit 0 if server is running, exit 1 if not |
172
169
  | `eggpool models refresh` | Refresh the model catalog from upstream |
173
170
  | `eggpool accounts status` | Show configured account status |
174
171
  | `eggpool accounts list` | List configured provider accounts |
@@ -181,6 +178,7 @@ uv run eggpool connect list
181
178
  | `eggpool deploy all` | Print every deployment snippet in sequence |
182
179
 
183
180
  All commands accept `--config /path/to/config.toml` (defaults to `config.toml`).
181
+ Running `eggpool` with no arguments prints the help message.
184
182
  Configuration changes require a service restart; live reload is intentionally
185
183
  not supported.
186
184
 
@@ -492,14 +490,28 @@ MIT
492
490
 
493
491
  ## Deployment
494
492
 
495
- See `docs/deployment.md` for production deployment instructions.
493
+ See `docs/deployment.md` for full deployment instructions.
496
494
 
497
- For production (systemd):
495
+ ### Quick start (personal use)
498
496
 
499
497
  ```bash
500
- sudo systemctl enable --now eggpool
498
+ pipx install eggpool
499
+ eggpool onboard
500
+ sudo eggpool deploy systemd --install
501
501
  ```
502
502
 
503
+ The `--install` flag writes the systemd unit, enables the service,
504
+ and starts it — all in one command. It detects your install method
505
+ and config paths automatically.
506
+
507
+ ### Production (separate user, hardened)
508
+
509
+ For public-facing deployments, see the Production Deployment section
510
+ in `docs/deployment.md`. This creates a dedicated `eggpool` system
511
+ user with proper file permissions.
512
+
513
+ ### Configuration changes
514
+
503
515
  Configuration changes require a service restart; the unit
504
516
  intentionally does not advertise any reload action:
505
517
 
@@ -1,5 +1,5 @@
1
1
  [![PyPI version](https://badge.fury.io/py/eggpool.svg)](https://pypi.org/project/eggpool/)
2
- [![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue.svg)](https://www.python.org/)
2
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
3
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
4
4
  [![CI](https://github.com/eggstack/eggpool/actions/workflows/ci.yml/badge.svg)](https://github.com/eggstack/eggpool/actions/workflows/ci.yml)
5
5
 
@@ -22,7 +22,7 @@ behind one OpenAI/Anthropic-compatible endpoint.
22
22
 
23
23
  ## Requirements
24
24
 
25
- - Python 3.12+
25
+ - Python 3.11+
26
26
  - [uv](https://docs.astral.sh/uv/) for dependency management
27
27
 
28
28
  ## Quick Start
@@ -31,25 +31,16 @@ behind one OpenAI/Anthropic-compatible endpoint.
31
31
 
32
32
  ```bash
33
33
  pipx install eggpool
34
- pipx run eggpool --help # or just `eggpool --help` if PATH includes it
34
+ eggpool help
35
+ eggpool onboard
35
36
  ```
36
37
 
37
- `pipx` installs `eggpool` into its own venv and exposes the
38
- `eggpool` console script globally. The bundled themes and
39
- provider templates ship inside the package — no extra files
40
- required to start.
38
+ `eggpool onboard` lets you add several providers at once, does a config check, then runs the server. You can also run `eggpool connect` for each provider you want to add and `eggpool serve` to start the server.
39
+ `eggpool configsetup` will help setup config for opencode.
41
40
 
42
- Then copy and edit configuration:
41
+ To get the server to run on startup, run `eggpool deploy` for options, see docs/deployment.md for more info and configs.
43
42
 
44
- ```bash
45
- cp /path/to/your/eggpool-venv/lib/python*/site-packages/eggpool/_share/config.example.toml ~/.config/eggpool/config.toml
46
- ```
47
-
48
- Or use the built-in helper:
49
-
50
- ```bash
51
- eggpool init-config
52
- ```
43
+ `pipx` installs `eggpool` into its own venv and exposes the `eggpool` command on your PATH.
53
44
 
54
45
  ### Option 2: Automated install
55
46
 
@@ -61,13 +52,14 @@ The script:
61
52
 
62
53
  - Downloads the repository if not running from a clone
63
54
  - Installs `uv` if missing
64
- - Verifies Python 3.12+
55
+ - Verifies Python 3.11+
65
56
  - Installs dependencies
66
57
  - Copies example configuration files
67
58
  - Attempts configuration validation
68
59
 
69
- Validation fails until `.env` contains real, non-placeholder keys. Edit
70
- `config.toml` and `.env`, then run the validation and migration commands below.
60
+ The script will ask if you want to continue with onboarding. if you select no, make sure you `cd eggpool`, then you can run `uv run eggpool onboard` to get started. `uv run eggpool connect` for one off provider adds, `uv run eggpool serve` to start server. `uv run eggpool help` for other commands.
61
+
62
+ Run `uv run eggpool deploy` for options on running the server on startup. See docs/deployment.md for more info and configs.
71
63
 
72
64
  ### Option 3: Manual install
73
65
 
@@ -84,19 +76,20 @@ cp .env.example .env
84
76
 
85
77
  # Validate configuration
86
78
  set -a; source .env; set +a
87
- uv run eggpool --config config.toml check-config
79
+ uv run eggpool check-config
88
80
 
89
81
  # Run database migrations
90
- uv run eggpool --config config.toml migrate
82
+ uv run eggpool migrate
91
83
 
92
84
  # Start the server
93
- uv run eggpool --config config.toml serve
85
+ uv run eggpool serve
94
86
  ```
95
87
 
96
88
  ### Option 4: Interactive setup
97
89
 
98
90
  ```bash
99
- # Run the interactive onboarding wizard
91
+ # Run the interactive onboarding wizard — connects one or more
92
+ # providers, validates configuration, and starts the server.
100
93
  uv run eggpool onboard
101
94
 
102
95
  # Or connect to a specific provider
@@ -108,10 +101,12 @@ uv run eggpool connect list
108
101
 
109
102
  | Command | Description |
110
103
  |---------|-------------|
104
+ | `eggpool help` | Show help message and available commands |
105
+ | `eggpool version` | Print the installed version |
111
106
  | `eggpool serve` | Start the aggregation proxy server (default command) |
112
107
  | `eggpool check-config` | Validate the configuration file |
113
108
  | `eggpool migrate` | Run database migrations |
114
- | `eggpool onboard` | Run the interactive onboarding setup |
109
+ | `eggpool onboard` | Run the interactive onboarding setup (connect providers, start server) |
115
110
  | `eggpool connect` | Connect to a new provider interactively |
116
111
  | `eggpool connect list` | List available providers for connection |
117
112
  | `eggpool logout` | Remove a configured provider account |
@@ -126,6 +121,7 @@ uv run eggpool connect list
126
121
  | `eggpool configsetup opencode` | Print OpenCode provider config JSON with model limits |
127
122
  | `eggpool configsetup claude-code` | Print Claude Code config snippet |
128
123
  | `eggpool update` | Check for updates and reinstall if newer |
124
+ | `eggpool croncheck` | Lightweight check: exit 0 if server is running, exit 1 if not |
129
125
  | `eggpool models refresh` | Refresh the model catalog from upstream |
130
126
  | `eggpool accounts status` | Show configured account status |
131
127
  | `eggpool accounts list` | List configured provider accounts |
@@ -138,6 +134,7 @@ uv run eggpool connect list
138
134
  | `eggpool deploy all` | Print every deployment snippet in sequence |
139
135
 
140
136
  All commands accept `--config /path/to/config.toml` (defaults to `config.toml`).
137
+ Running `eggpool` with no arguments prints the help message.
141
138
  Configuration changes require a service restart; live reload is intentionally
142
139
  not supported.
143
140
 
@@ -449,14 +446,28 @@ MIT
449
446
 
450
447
  ## Deployment
451
448
 
452
- See `docs/deployment.md` for production deployment instructions.
449
+ See `docs/deployment.md` for full deployment instructions.
453
450
 
454
- For production (systemd):
451
+ ### Quick start (personal use)
455
452
 
456
453
  ```bash
457
- sudo systemctl enable --now eggpool
454
+ pipx install eggpool
455
+ eggpool onboard
456
+ sudo eggpool deploy systemd --install
458
457
  ```
459
458
 
459
+ The `--install` flag writes the systemd unit, enables the service,
460
+ and starts it — all in one command. It detects your install method
461
+ and config paths automatically.
462
+
463
+ ### Production (separate user, hardened)
464
+
465
+ For public-facing deployments, see the Production Deployment section
466
+ in `docs/deployment.md`. This creates a dedicated `eggpool` system
467
+ user with proper file permissions.
468
+
469
+ ### Configuration changes
470
+
460
471
  Configuration changes require a service restart; the unit
461
472
  intentionally does not advertise any reload action:
462
473
 
@@ -87,7 +87,7 @@ Legacy flat `[[accounts]]` configs auto-normalize to a default `opencode-go` pro
87
87
 
88
88
  ### Model ID Format
89
89
 
90
- Models are exposed with provider-suffixed IDs: `model-id/provider-id` (e.g., `claude-sonnet-4/opencode-go`). `parse_model_id()` in `catalog/cache.py` handles suffix parsing.
90
+ Models are exposed with provider-suffixed IDs: `model-id/provider-id` (e.g., `claude-sonnet-4/opencode-go`). `parse_model_provider()` in `routing/provider.py` is the canonical suffix parser; `catalog/cache.py` retains a compatibility alias.
91
91
 
92
92
  ### Provider-Specific Paths
93
93
 
@@ -0,0 +1,235 @@
1
+ # Deployment Guide
2
+
3
+ Two deployment modes: **personal use** (quick, current user) and
4
+ **production** (separate user, hardened). Pick the one that fits.
5
+
6
+ ## Personal Use (Recommended for LAN/Raspberry Pi)
7
+
8
+ Runs under your current user with your existing config. Not intended
9
+ for public-facing deployments.
10
+
11
+ ### 1. Install
12
+
13
+ ```bash
14
+ pipx install eggpool
15
+ eggpool onboard
16
+ ```
17
+
18
+ Or from source:
19
+
20
+ ```bash
21
+ git clone https://github.com/eggstack/eggpool.git && cd eggpool
22
+ uv sync --no-dev
23
+ uv run eggpool onboard
24
+ ```
25
+
26
+ ### 2. Start on boot
27
+
28
+ The `--install` flag writes the systemd unit, enables the service,
29
+ and starts it — all in one command:
30
+
31
+ ```bash
32
+ sudo eggpool deploy systemd --install
33
+ ```
34
+
35
+ This generates a unit file tailored to your system (correct binary
36
+ path, config path, data directory) and sets it up automatically.
37
+
38
+ Without `--install`, the command prints copy-paste instructions
39
+ instead.
40
+
41
+ ### 3. Verify
42
+
43
+ ```bash
44
+ sudo systemctl status eggpool
45
+ curl http://localhost:11300/v1/healthz
46
+ ```
47
+
48
+ ### Other deploy commands
49
+
50
+ ```bash
51
+ # Set up logrotate
52
+ sudo eggpool deploy logrotate --install
53
+
54
+ # Set up daily backup cron (user cron, ~/backups/eggpool/)
55
+ sudo eggpool deploy cron --install
56
+
57
+ # Set up everything at once
58
+ sudo eggpool deploy all --install
59
+ ```
60
+
61
+ Without `--install`, each command prints the snippet and manual
62
+ instructions for you to copy-paste.
63
+
64
+ ### Configuration changes
65
+
66
+ Live reload is not supported. Restart after any config change:
67
+
68
+ ```bash
69
+ sudo systemctl restart eggpool
70
+ ```
71
+
72
+ ### Logs
73
+
74
+ ```bash
75
+ sudo journalctl -u eggpool -f
76
+ ```
77
+
78
+ ### Alternative: cron (no systemd)
79
+
80
+ For systems without systemd, `deploy cron` sets up a user cron
81
+ entry that checks if the server is running and restarts it:
82
+
83
+ ```bash
84
+ # Check every 5 minutes, restart if stopped
85
+ eggpool croncheck || eggpool serve &
86
+ ```
87
+
88
+ This is a personal-use fallback — prefer systemd when available.
89
+
90
+ ---
91
+
92
+ ## Production Deployment
93
+
94
+ For public-facing or multi-user deployments. Uses a dedicated
95
+ `eggpool` system user with proper file permissions and a hardened
96
+ systemd unit.
97
+
98
+ **Not recommended for personal LAN use** — the personal-use path
99
+ above is simpler and sufficient for single-user setups.
100
+
101
+ ### 1. Create system user
102
+
103
+ ```bash
104
+ sudo useradd -r -s /usr/sbin/nologin -d /var/lib/eggpool eggpool
105
+ sudo mkdir -p /var/lib/eggpool /var/log/eggpool /etc/eggpool
106
+ sudo chown eggpool:eggpool /var/lib/eggpool /var/log/eggpool
107
+ sudo chown root:eggpool /etc/eggpool
108
+ sudo chmod 750 /var/lib/eggpool /var/log/eggpool
109
+ sudo chmod 755 /etc/eggpool
110
+ ```
111
+
112
+ ### 2. Install application
113
+
114
+ ```bash
115
+ cd /opt
116
+ sudo git clone https://github.com/eggstack/eggpool.git
117
+ sudo chown -R root:eggpool /opt/eggpool
118
+ cd /opt/eggpool
119
+ sudo uv sync --no-dev
120
+ sudo chown -R root:eggpool /opt/eggpool
121
+ sudo chmod -R o+rX /opt/eggpool
122
+ ```
123
+
124
+ ### 3. Configure
125
+
126
+ ```bash
127
+ sudo cp config.example.toml /etc/eggpool/config.toml
128
+ sudo cp deploy/env.example /etc/eggpool/env
129
+ sudo chown root:eggpool /etc/eggpool/config.toml /etc/eggpool/env
130
+ sudo chmod 640 /etc/eggpool/config.toml /etc/eggpool/env
131
+
132
+ sudo nano /etc/eggpool/config.toml
133
+ sudo nano /etc/eggpool/env
134
+ ```
135
+
136
+ Minimal config:
137
+
138
+ ```toml
139
+ [server]
140
+ host = "0.0.0.0"
141
+ port = 11300
142
+
143
+ [database]
144
+ path = "/var/lib/eggpool/usage.sqlite3"
145
+ ```
146
+
147
+ ### 4. Validate and start
148
+
149
+ ```bash
150
+ sudo -u eggpool bash -c 'set -a; source /etc/eggpool/env; set +a; /opt/eggpool/.venv/bin/eggpool check-config --config /etc/eggpool/config.toml'
151
+ sudo -u eggpool /opt/eggpool/.venv/bin/eggpool migrate --config /etc/eggpool/config.toml
152
+
153
+ # Install the hardened systemd unit
154
+ sudo cp deploy/eggpool.service /etc/systemd/system/
155
+ sudo systemctl daemon-reload
156
+ sudo systemctl enable eggpool
157
+ sudo systemctl start eggpool
158
+ sudo systemctl status eggpool
159
+ ```
160
+
161
+ ### 5. Logrotate
162
+
163
+ ```bash
164
+ sudo cp deploy/eggpool-logrotate.conf /etc/logrotate.d/eggpool
165
+ ```
166
+
167
+ ### 6. Automated backup
168
+
169
+ ```bash
170
+ sudo cp deploy/eggpool.service /etc/systemd/system/
171
+ # Or use the deploy command:
172
+ sudo eggpool deploy cron
173
+ ```
174
+
175
+ ### Filesystem layout
176
+
177
+ ```
178
+ /etc/eggpool/
179
+ ├── config.toml # Configuration
180
+ └── env # API keys
181
+
182
+ /var/lib/eggpool/
183
+ ├── usage.sqlite3 # Database
184
+ ├── usage.sqlite3-wal # WAL journal
185
+ └── usage.sqlite3-shm # Shared memory
186
+
187
+ /opt/eggpool/
188
+ ├── .venv/ # Python virtual environment
189
+ └── src/ # Application source
190
+ ```
191
+
192
+ ### Systemd unit features
193
+
194
+ - `ProtectSystem=strict` — read-only system directories
195
+ - `ReadWritePaths=/var/lib/eggpool` — data directory writable
196
+ - `NoNewPrivileges`, `PrivateTmp`, `RestrictNamespaces` — hardened
197
+ - No `ExecReload` — config changes require `systemctl restart`
198
+
199
+ ---
200
+
201
+ ## Troubleshooting
202
+
203
+ ### Service fails to start
204
+
205
+ ```bash
206
+ sudo journalctl -u eggpool --since "5 minutes ago"
207
+ # or for personal use:
208
+ sudo journalctl -u eggpool -n 50 --no-pager
209
+ ```
210
+
211
+ ### Database locked errors
212
+
213
+ 1. Ensure only one instance: `pgrep -f eggpool`
214
+ 2. Confirm WAL mode in config
215
+ 3. Increase `busy_timeout_ms` (try `10000` on Pi)
216
+
217
+ ### Cannot connect from LAN
218
+
219
+ 1. Verify `server.host = "0.0.0.0"` in config
220
+ 2. Check firewall: `ss -tlnp | grep 11300`
221
+ 3. See `docs/firewall.md`
222
+
223
+ ### Deploy commands reference
224
+
225
+ | Command | Description |
226
+ |---------|-------------|
227
+ | `eggpool deploy systemd` | Print systemd unit + instructions |
228
+ | `eggpool deploy systemd --install` | Write unit, enable, start |
229
+ | `eggpool deploy logrotate` | Print logrotate config |
230
+ | `eggpool deploy logrotate --install` | Write logrotate config |
231
+ | `eggpool deploy cron` | Print backup cron entry |
232
+ | `eggpool deploy cron --install` | Write backup script + cron entry |
233
+ | `eggpool deploy all` | Print all snippets |
234
+ | `eggpool deploy all --install` | Install everything |
235
+ | `eggpool croncheck` | Check if server is running (exit 0/1) |