graph-agents-cli 0.3.1__py3-none-any.whl

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 (291) hide show
  1. graph_agents_cli/__init__.py +26 -0
  2. graph_agents_cli/_api_policy.py +2145 -0
  3. graph_agents_cli/_approvals.py +400 -0
  4. graph_agents_cli/_build.py +186 -0
  5. graph_agents_cli/_build_info.json +7 -0
  6. graph_agents_cli/_chat_client.py +462 -0
  7. graph_agents_cli/_click.py +157 -0
  8. graph_agents_cli/_defaults.py +139 -0
  9. graph_agents_cli/_experiments.py +64 -0
  10. graph_agents_cli/_http.py +192 -0
  11. graph_agents_cli/_output.py +83 -0
  12. graph_agents_cli/_project.py +462 -0
  13. graph_agents_cli/_remote.py +220 -0
  14. graph_agents_cli/_response_schema.py +264 -0
  15. graph_agents_cli/_runner.py +319 -0
  16. graph_agents_cli/_skills_check.py +274 -0
  17. graph_agents_cli/_tools.py +189 -0
  18. graph_agents_cli/_trust.py +66 -0
  19. graph_agents_cli/api/__init__.py +15 -0
  20. graph_agents_cli/api/_changes.py +506 -0
  21. graph_agents_cli/api/_files.py +658 -0
  22. graph_agents_cli/api/cmd_api.py +2480 -0
  23. graph_agents_cli/deploy/__init__.py +15 -0
  24. graph_agents_cli/deploy/_config.py +171 -0
  25. graph_agents_cli/deploy/_image.py +128 -0
  26. graph_agents_cli/deploy/_kube.py +286 -0
  27. graph_agents_cli/deploy/_modes.py +234 -0
  28. graph_agents_cli/deploy/_preflight.py +370 -0
  29. graph_agents_cli/deploy/_values.py +168 -0
  30. graph_agents_cli/deploy/cmd_deploy.py +1866 -0
  31. graph_agents_cli/deploy/gitops.py +562 -0
  32. graph_agents_cli/deploy/local_load.py +273 -0
  33. graph_agents_cli/dev/__init__.py +13 -0
  34. graph_agents_cli/dev/cmd_build.py +131 -0
  35. graph_agents_cli/dev/cmd_install.py +78 -0
  36. graph_agents_cli/dev/cmd_lint.py +119 -0
  37. graph_agents_cli/dev/cmd_playground.py +297 -0
  38. graph_agents_cli/dev/policy_check.py +1287 -0
  39. graph_agents_cli/eval/__init__.py +22 -0
  40. graph_agents_cli/eval/_client.py +670 -0
  41. graph_agents_cli/eval/_common.py +177 -0
  42. graph_agents_cli/eval/_judge.py +168 -0
  43. graph_agents_cli/eval/_judge_runner.py +238 -0
  44. graph_agents_cli/eval/_paths.py +212 -0
  45. graph_agents_cli/eval/checks.py +581 -0
  46. graph_agents_cli/eval/cmd_analyze.py +278 -0
  47. graph_agents_cli/eval/cmd_compare.py +284 -0
  48. graph_agents_cli/eval/cmd_eval_group.py +80 -0
  49. graph_agents_cli/eval/cmd_generate.py +558 -0
  50. graph_agents_cli/eval/cmd_grade.py +466 -0
  51. graph_agents_cli/eval/cmd_metric.py +156 -0
  52. graph_agents_cli/eval/cmd_run.py +370 -0
  53. graph_agents_cli/eval/cmd_submit.py +400 -0
  54. graph_agents_cli/eval/config.py +435 -0
  55. graph_agents_cli/eval/dataset.py +350 -0
  56. graph_agents_cli/eval/gate.py +420 -0
  57. graph_agents_cli/eval/transcript.py +192 -0
  58. graph_agents_cli/extension/__init__.py +13 -0
  59. graph_agents_cli/extension/_compat.py +86 -0
  60. graph_agents_cli/extension/_loader.py +293 -0
  61. graph_agents_cli/extension/_manifest.py +135 -0
  62. graph_agents_cli/extension/_overrides.py +195 -0
  63. graph_agents_cli/extension/_paths.py +91 -0
  64. graph_agents_cli/extension/_refs.py +193 -0
  65. graph_agents_cli/extension/_resolver.py +453 -0
  66. graph_agents_cli/extension/_schema.py +106 -0
  67. graph_agents_cli/extension/_spec.py +253 -0
  68. graph_agents_cli/extension/_sync.py +102 -0
  69. graph_agents_cli/extension/_trust.py +58 -0
  70. graph_agents_cli/extension/cmd_extension_add.py +259 -0
  71. graph_agents_cli/extension/cmd_extension_group.py +57 -0
  72. graph_agents_cli/extension/cmd_extension_list.py +56 -0
  73. graph_agents_cli/extension/cmd_extension_remove.py +61 -0
  74. graph_agents_cli/extension/cmd_extension_update.py +195 -0
  75. graph_agents_cli/info/__init__.py +13 -0
  76. graph_agents_cli/info/cmd_info.py +222 -0
  77. graph_agents_cli/infra/__init__.py +15 -0
  78. graph_agents_cli/infra/checks.py +1169 -0
  79. graph_agents_cli/infra/cmd_infra.py +103 -0
  80. graph_agents_cli/main.py +591 -0
  81. graph_agents_cli/peer/__init__.py +15 -0
  82. graph_agents_cli/peer/_generate.py +254 -0
  83. graph_agents_cli/peer/cmd_peer.py +1151 -0
  84. graph_agents_cli/run/__init__.py +13 -0
  85. graph_agents_cli/run/_local_server.py +1157 -0
  86. graph_agents_cli/run/_signals.py +141 -0
  87. graph_agents_cli/run/cmd_approvals.py +530 -0
  88. graph_agents_cli/run/cmd_run.py +1421 -0
  89. graph_agents_cli/scaffold/__init__.py +19 -0
  90. graph_agents_cli/scaffold/agents/README.md +24 -0
  91. graph_agents_cli/scaffold/agents/empty_py/.template/templateconfig.yaml +22 -0
  92. graph_agents_cli/scaffold/agents/langgraph/.env.example +292 -0
  93. graph_agents_cli/scaffold/agents/langgraph/.template/templateconfig.yaml +28 -0
  94. graph_agents_cli/scaffold/agents/langgraph/Dockerfile +59 -0
  95. graph_agents_cli/scaffold/agents/langgraph/Dockerfile.langgraph-server +59 -0
  96. graph_agents_cli/scaffold/agents/langgraph/README.md +571 -0
  97. graph_agents_cli/scaffold/agents/langgraph/api-policy.yaml +60 -0
  98. graph_agents_cli/scaffold/agents/langgraph/app/__init__.py +20 -0
  99. graph_agents_cli/scaffold/agents/langgraph/app/agent.py +174 -0
  100. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/__init__.py +15 -0
  101. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/a2a.py +2162 -0
  102. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/a2a_client.py +1167 -0
  103. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/api_client.py +4220 -0
  104. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/approvals.py +1349 -0
  105. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/auth.py +1986 -0
  106. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/chat.py +2962 -0
  107. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/checkpointer.py +432 -0
  108. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/content.py +569 -0
  109. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/db.py +580 -0
  110. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/limits.py +203 -0
  111. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/metrics.py +231 -0
  112. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/middleware.py +361 -0
  113. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/model.py +611 -0
  114. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/playground.py +230 -0
  115. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/run_locks.py +459 -0
  116. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/structured.py +755 -0
  117. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/telemetry.py +681 -0
  118. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/threads.py +493 -0
  119. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/token_exchange.py +959 -0
  120. graph_agents_cli/scaffold/agents/langgraph/app/fast_api_app.py +770 -0
  121. graph_agents_cli/scaffold/agents/langgraph/app/policies/__init__.py +55 -0
  122. graph_agents_cli/scaffold/agents/langgraph/app/policies/custom.py +97 -0
  123. graph_agents_cli/scaffold/agents/langgraph/app/tools/__init__.py +46 -0
  124. graph_agents_cli/scaffold/agents/langgraph/app/tools/example_api.py +92 -0
  125. graph_agents_cli/scaffold/agents/langgraph/app/tools/weather.py +33 -0
  126. graph_agents_cli/scaffold/agents/langgraph/langgraph.json +14 -0
  127. graph_agents_cli/scaffold/agents/langgraph/pyproject.toml +78 -0
  128. graph_agents_cli/scaffold/agents/langgraph/tests/conftest.py +376 -0
  129. graph_agents_cli/scaffold/agents/langgraph/tests/eval/datasets/basic-dataset.json +53 -0
  130. graph_agents_cli/scaffold/agents/langgraph/tests/eval/eval_config.yaml +32 -0
  131. graph_agents_cli/scaffold/agents/langgraph/tests/integration/approval_graph.py +137 -0
  132. graph_agents_cli/scaffold/agents/langgraph/tests/integration/fake_issuer.py +216 -0
  133. graph_agents_cli/scaffold/agents/langgraph/tests/integration/fake_openai.py +357 -0
  134. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_a2a_outcomes.py +569 -0
  135. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_a2a_relay.py +479 -0
  136. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_api_surface.py +812 -0
  137. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_approvals.py +1367 -0
  138. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_approvals_server.py +794 -0
  139. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_cross_actor.py +497 -0
  140. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_cross_actor_server.py +247 -0
  141. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_history_repair.py +278 -0
  142. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_model_apis.py +242 -0
  143. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_postgres.py +637 -0
  144. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_resilience_postgres.py +770 -0
  145. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_runtime_guardrails.py +854 -0
  146. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_server_e2e.py +340 -0
  147. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_server_runtime.py +989 -0
  148. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_structured_answers.py +584 -0
  149. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_structured_server.py +222 -0
  150. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_token_exchange_issuer.py +650 -0
  151. graph_agents_cli/scaffold/agents/langgraph/tests/load_test/.results/.placeholder +0 -0
  152. graph_agents_cli/scaffold/agents/langgraph/tests/load_test/README.md +22 -0
  153. graph_agents_cli/scaffold/agents/langgraph/tests/load_test/conftest.py +21 -0
  154. graph_agents_cli/scaffold/agents/langgraph/tests/load_test/load_test.py +81 -0
  155. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_a2a_client.py +824 -0
  156. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_a2a_scoping.py +724 -0
  157. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_client.py +1214 -0
  158. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_client_hardening.py +716 -0
  159. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_policy_rpc.py +767 -0
  160. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_approval_ledger.py +1536 -0
  161. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_fake_model.py +115 -0
  162. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_jwt_policy.py +991 -0
  163. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_limits.py +310 -0
  164. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_logging.py +148 -0
  165. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_logging_hardening.py +271 -0
  166. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_policy.py +378 -0
  167. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_resilience.py +610 -0
  168. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_server_auth.py +702 -0
  169. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_structured.py +673 -0
  170. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_telemetry.py +404 -0
  171. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_thread_listing.py +255 -0
  172. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_threads.py +268 -0
  173. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_token_exchange.py +1320 -0
  174. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_untrusted_content.py +393 -0
  175. graph_agents_cli/scaffold/agents/langgraph/uv-fastapi.lock +2084 -0
  176. graph_agents_cli/scaffold/agents/langgraph/uv-langgraph-server.lock +2106 -0
  177. graph_agents_cli/scaffold/agents/langgraph/{{cookiecutter.agent_guidance_filename}} +129 -0
  178. graph_agents_cli/scaffold/base_templates/_shared/graph-agents-cli-manifest.yaml +36 -0
  179. graph_agents_cli/scaffold/base_templates/python/.dockerignore +32 -0
  180. graph_agents_cli/scaffold/base_templates/python/.github/CODEOWNERS +30 -0
  181. graph_agents_cli/scaffold/base_templates/python/.github/agent.env +7 -0
  182. graph_agents_cli/scaffold/base_templates/python/.github/workflows/pr_checks.yaml +214 -0
  183. graph_agents_cli/scaffold/base_templates/python/.gitignore +209 -0
  184. graph_agents_cli/scaffold/base_templates/python/tests/unit/test_dummy.py +23 -0
  185. graph_agents_cli/scaffold/base_templates/python/{{cookiecutter.agent_guidance_filename}} +35 -0
  186. graph_agents_cli/scaffold/cmd_scaffold_group.py +49 -0
  187. graph_agents_cli/scaffold/commands/__init__.py +13 -0
  188. graph_agents_cli/scaffold/commands/create.py +1424 -0
  189. graph_agents_cli/scaffold/commands/enhance.py +1652 -0
  190. graph_agents_cli/scaffold/commands/upgrade.py +570 -0
  191. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/agent.env +12 -0
  192. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/workflows/promote-to-prod.yaml +371 -0
  193. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/workflows/staging.yaml +450 -0
  194. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-dev.yaml +43 -0
  195. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-prod.yaml +41 -0
  196. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-staging.yaml +43 -0
  197. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/.helmignore +14 -0
  198. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/Chart.yaml +21 -0
  199. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/examples/networkpolicy.yaml +103 -0
  200. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/NOTES.txt +48 -0
  201. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/_helpers.tpl +189 -0
  202. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/certificate.yaml +15 -0
  203. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/configmap.yaml +10 -0
  204. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/deployment.yaml +199 -0
  205. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/hpa.yaml +22 -0
  206. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/httproute.yaml +30 -0
  207. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/ingress.yaml +39 -0
  208. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/networkpolicy.yaml +48 -0
  209. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/pdb.yaml +13 -0
  210. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/postgresql-secret.yaml +37 -0
  211. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/service.yaml +15 -0
  212. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/serviceaccount.yaml +13 -0
  213. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/servicemonitor.yaml +42 -0
  214. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-dev.yaml +22 -0
  215. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-prod.yaml +45 -0
  216. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-staging.yaml +29 -0
  217. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values.yaml +396 -0
  218. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/tests/integration/test_chart.py +269 -0
  219. graph_agents_cli/scaffold/deployment_targets/none/README.md +5 -0
  220. graph_agents_cli/scaffold/deployment_targets/none/python/README.md +6 -0
  221. graph_agents_cli/scaffold/utils/__init__.py +13 -0
  222. graph_agents_cli/scaffold/utils/backup.py +212 -0
  223. graph_agents_cli/scaffold/utils/build_record.py +257 -0
  224. graph_agents_cli/scaffold/utils/cli_options.py +184 -0
  225. graph_agents_cli/scaffold/utils/fs.py +83 -0
  226. graph_agents_cli/scaffold/utils/generate_locks.py +214 -0
  227. graph_agents_cli/scaffold/utils/generation_metadata.py +88 -0
  228. graph_agents_cli/scaffold/utils/keyedit.py +768 -0
  229. graph_agents_cli/scaffold/utils/keymerge.py +537 -0
  230. graph_agents_cli/scaffold/utils/language.py +138 -0
  231. graph_agents_cli/scaffold/utils/lock_utils.py +94 -0
  232. graph_agents_cli/scaffold/utils/logging.py +77 -0
  233. graph_agents_cli/scaffold/utils/manifest.py +292 -0
  234. graph_agents_cli/scaffold/utils/merge.py +970 -0
  235. graph_agents_cli/scaffold/utils/merge3.py +216 -0
  236. graph_agents_cli/scaffold/utils/openapi_seed.py +199 -0
  237. graph_agents_cli/scaffold/utils/remote_template.py +376 -0
  238. graph_agents_cli/scaffold/utils/template.py +1352 -0
  239. graph_agents_cli/scaffold/utils/upgrade.py +894 -0
  240. graph_agents_cli/scaffold/utils/version.py +438 -0
  241. graph_agents_cli/secrets/__init__.py +15 -0
  242. graph_agents_cli/secrets/_apply.py +954 -0
  243. graph_agents_cli/secrets/_required.py +188 -0
  244. graph_agents_cli/secrets/cmd_secrets.py +211 -0
  245. graph_agents_cli/setup/__init__.py +13 -0
  246. graph_agents_cli/setup/_antigravity.py +221 -0
  247. graph_agents_cli/setup/cmd_auth.py +1030 -0
  248. graph_agents_cli/setup/cmd_dev_token.py +513 -0
  249. graph_agents_cli/setup/cmd_setup.py +428 -0
  250. graph_agents_cli/setup/cmd_update.py +140 -0
  251. graph_agents_cli/skills/__init__.py +13 -0
  252. graph_agents_cli/skills/_bundle.py +65 -0
  253. graph_agents_cli/skills/data/README.md +19 -0
  254. graph_agents_cli/skills/data/graph-agents-cli-deploy/SKILL.md +357 -0
  255. graph_agents_cli/skills/data/graph-agents-cli-deploy/references/github-settings.md +113 -0
  256. graph_agents_cli/skills/data/graph-agents-cli-deploy/references/gitops.md +137 -0
  257. graph_agents_cli/skills/data/graph-agents-cli-deploy/references/kubernetes.md +315 -0
  258. graph_agents_cli/skills/data/graph-agents-cli-deploy/references/secrets.md +160 -0
  259. graph_agents_cli/skills/data/graph-agents-cli-eval/SKILL.md +303 -0
  260. graph_agents_cli/skills/data/graph-agents-cli-eval/references/dataset_schema.md +282 -0
  261. graph_agents_cli/skills/data/graph-agents-cli-eval/references/metrics-guide.md +143 -0
  262. graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/SKILL.md +659 -0
  263. graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/langchain-models.md +124 -0
  264. graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/langgraph.md +235 -0
  265. graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/template-contract.md +477 -0
  266. graph_agents_cli/skills/data/graph-agents-cli-observability/SKILL.md +231 -0
  267. graph_agents_cli/skills/data/graph-agents-cli-observability/references/langsmith.md +46 -0
  268. graph_agents_cli/skills/data/graph-agents-cli-observability/references/otel.md +59 -0
  269. graph_agents_cli/skills/data/graph-agents-cli-scaffold/SKILL.md +414 -0
  270. graph_agents_cli/skills/data/graph-agents-cli-scaffold/references/flags.md +134 -0
  271. graph_agents_cli/skills/data/graph-agents-cli-workflow/SKILL.md +478 -0
  272. graph_agents_cli/skills/data/graph-agents-cli-workflow/references/brainstorming.md +118 -0
  273. graph_agents_cli/skills/data/graph-agents-cli-workflow/references/commands.md +419 -0
  274. graph_agents_cli/skills/data/graph-agents-cli-workflow/references/extension.md +156 -0
  275. graph_agents_cli/skills/data/graph-agents-cli-workflow/references/internals.md +67 -0
  276. graph_agents_cli/skills/data/graph-agents-cli-workflow/references/spec-template.md +56 -0
  277. graph_agents_cli/skills/data/graph-agents-cli-workflow/references/terminology.md +119 -0
  278. graph_agents_cli/system/__init__.py +15 -0
  279. graph_agents_cli/system/_apply.py +519 -0
  280. graph_agents_cli/system/_checks.py +1023 -0
  281. graph_agents_cli/system/_deploy.py +215 -0
  282. graph_agents_cli/system/_model.py +363 -0
  283. graph_agents_cli/system/_system.py +664 -0
  284. graph_agents_cli/system/_views.py +208 -0
  285. graph_agents_cli/system/cmd_system.py +423 -0
  286. graph_agents_cli-0.3.1.dist-info/METADATA +162 -0
  287. graph_agents_cli-0.3.1.dist-info/RECORD +291 -0
  288. graph_agents_cli-0.3.1.dist-info/WHEEL +4 -0
  289. graph_agents_cli-0.3.1.dist-info/entry_points.txt +2 -0
  290. graph_agents_cli-0.3.1.dist-info/licenses/LICENSE +201 -0
  291. graph_agents_cli-0.3.1.dist-info/licenses/NOTICE +19 -0
@@ -0,0 +1,357 @@
1
+ ---
2
+ name: graph-agents-cli-deploy
3
+ description: >
4
+ This skill should be used when the user wants to "deploy an agent",
5
+ "deploy to Kubernetes", "deploy to our cluster", "set up CI/CD", "set up
6
+ Argo CD", "configure secrets", "rotate a key", "promote to production",
7
+ "check cluster prerequisites", "deploy to kind/k3s/minikube", "deploy
8
+ air-gapped", or "troubleshoot a deployment". Covers the deployment modes
9
+ (direct local-load, direct registry, helm-push, argocd), the dev/staging/
10
+ prod environments, the secrets procedure and rotation, the Argo CD PR
11
+ flow and the single production merge gate, the required GitHub
12
+ environment and branch-protection settings, `infra check`, local-load dev
13
+ clusters, and the disconnected profile. Part of the graph-agents-cli
14
+ skills suite. Do NOT use for agent code (graph-agents-cli-langgraph-code),
15
+ evaluation (graph-agents-cli-eval), scaffolding
16
+ (graph-agents-cli-scaffold), or tracing (graph-agents-cli-observability).
17
+ metadata:
18
+ author: graph-agents-cli contributors
19
+ license: Apache-2.0
20
+ version: "0.3.1"
21
+ requires:
22
+ bins:
23
+ - graph-agents-cli
24
+ install: "uv tool install git+https://github.com/ss7172/graph-agents-cli@v0.3.1"
25
+ ---
26
+
27
+ # Deployment guide
28
+
29
+ > **Requires:** `graph-agents-cli`, plus `docker`, `helm`, `kubectl`, `git`, a kubeconfig, `gh` for
30
+ > GitHub-hosted CD, and `argocd` when `cd: argocd`. The CLI shells out to these; it never installs cluster components. If the
31
+ > project has no deployment target, `/graph-agents-cli-scaffold` adds one with `scaffold enhance`.
32
+
33
+ > **Never deploy without explicit human approval.** In `argocd` mode you open a PR; a code owner
34
+ > merges it. You never merge it.
35
+
36
+ ## Reference files
37
+
38
+ | File | Contents |
39
+ |---|---|
40
+ | `references/kubernetes.md` | Helm chart values and render-time refusals, pod security, probes, published routes (`route.publicPaths`), traffic entry (Gateway API / Ingress / TLS), metrics and NetworkPolicy, Postgres and Redis toggles, HPA/PDB, local-load dev clusters, rollback, disconnected profile |
41
+ | `references/gitops.md` | The argocd mode: `Application` manifests, the `deploy` PR flow, staging auto-merge, production promotion, rollback by revert, `--restart` under self-heal |
42
+ | `references/secrets.md` | The Secret contract, allow-listed and required keys, env-file and context rules, `secrets apply/status` (server-side apply, key merge, `API_KEY` handling), ownership in CD modes, rotation |
43
+ | `references/github-settings.md` | Required GitHub environment and branch-protection settings, `CODEOWNERS`, secrets and variables (`DEPLOY_KUBECONFIG`, `GH_PR_TOKEN`), the self-hosted runner, what `infra check` reports |
44
+
45
+ ---
46
+
47
+ ## Deployment modes (determined by the manifest's `cd` and the environment)
48
+
49
+ | Mode | Who applies the release | What `deploy` does |
50
+ |---|---|---|
51
+ | *direct, local-load* (`cd: skip`, local cluster) | `deploy` | builds the image with the `docker` CLI, loads it into the kind/k3d/k3s/minikube node (nothing for Docker Desktop, Rancher Desktop, OrbStack), applies the Secret from the allow-listed keys of the env file, runs `helm upgrade --install --wait` |
52
+ | *direct, registry* (`cd: skip`, any other cluster) | `deploy` | builds, pushes to the manifest's registry, applies the Secret, runs `helm upgrade --install --wait` |
53
+ | *helm-push* (`cd: helm-push`) | GitHub Actions on a self-hosted runner | CI builds and pushes; the runner job runs `deploy --env <env> --image <ref> --context <ctx> --yes`, which only runs helm (after checking the live Secret's required keys). From a workstation `dev` is allowed; `staging`/`prod` are refused outside CI (`GITHUB_ACTIONS=true`) **even with `--image`**, unless `--force-direct` |
54
+ | *argocd* (`cd: argocd`) | Argo CD inside the cluster | **`deploy` never runs helm, never contacts the cluster and never merges.** `deploy --env <env> --image <ref>` writes the desired state: it updates `image.tag` in `deployment/helm/<name>/values-<env>.yaml` (and nothing else), commits on a branch `deploy/<env>/<short sha>` built with git plumbing from `origin/main` (the developer's checkout is never switched), and opens or updates a pull request with `gh` (else GitHub REST with `GITHUB_TOKEN`; `GH_HOST=<host>` for a GitHub Enterprise Server). `--image` names the CI-pushed image; without it the tag is `--tag` or the short git sha with a warning. Argo reconciles from `main`, so nothing reaches the cluster until the PR merges, and a PR touching `values-prod.yaml` merges only after the production approval, whoever opened it. In argocd environments only `--status`, `--restart`, and `secrets` touch the cluster |
55
+
56
+ Local-load is decided from the cluster itself (its nodes), confirmed with `kind get clusters`,
57
+ `k3d cluster list` or `minikube profile list`; the context name decides only when the nodes
58
+ cannot be read. `deploy --dry-run` prints the docker, helm, kubectl, and gh commands plus the
59
+ rendered manifests, changes nothing and never prompts. It runs the same checks as the real run,
60
+ including a read-only read of the live Secret, so it refuses (exit 1) a deploy the real run
61
+ would refuse for a missing required key (and says so when the cluster cannot be read).
62
+ `helm dependency build deployment/helm/<name>` is printed with the `[dry-run]` prefix and still
63
+ executed when a declared subchart is missing from `charts/`, because it only writes into the
64
+ chart directory and the `helm template` render needs the subcharts. Use `--dry-run` to show the
65
+ user what will happen.
66
+
67
+ Images are tagged with the **short commit SHA**: `${GITHUB_SHA::7}` in the `staging` workflow,
68
+ `git rev-parse --short HEAD` for a workstation `deploy`, plus `-dirty-<YYYYmmddHHMMSS>` (with a
69
+ warning) when the tree has uncommitted changes outside `deployment/`, `.github/`, `tests/` and
70
+ `docs/`; a UTC timestamp outside git; `--tag TAG` overrides. The argocd branch is
71
+ `deploy/<env>/<short sha>` and the `promote-to-prod` `image_tag` input is a short sha. A
72
+ placeholder registry (`ghcr.io/CHANGE-ME`) or an invalid image reference is exit 3 before
73
+ `docker` runs. The chart refuses an empty `image.tag` and an unquoted numeric one.
74
+
75
+ Exit codes: `0` ok; `1` refused (policy or mode, a declined or missing context confirmation, a
76
+ Secret missing a required key, `--status` on a rollout that is not complete within `--timeout`);
77
+ `2` tool failure (helm/kubectl/docker non-zero or missing from `PATH`, a failed rollout, a
78
+ `--restart` whose new pods do not become ready, another helm operation holding the release,
79
+ `helm dependency build` failing because `registry-1.docker.io` is unreachable); `3`
80
+ configuration error (no env file outside dev, an unknown context, a placeholder registry, a
81
+ `CHANGE-ME` left in the chart `env` outside dev, `jwt` without a verification key, issuer or
82
+ audience outside dev, a blank `gateway.parentRef.name`).
83
+
84
+ ## Environments
85
+
86
+ `dev`, `staging`, `prod`. Each has a values file `deployment/helm/<name>/values-<env>.yaml`, a
87
+ namespace `<name>-<env>` (recorded with its kube context under `environments:` in the manifest),
88
+ a Secret `<name>-app`, and under argocd an `Application`. `dev` may be a local-load cluster.
89
+
90
+ | Values file | Defaults |
91
+ |---|---|
92
+ | `values-dev.yaml` | `env.APP_ENV=dev`, `secretOptional: true`, `postgresql.enabled=true` (bundled subchart; Redis too under `langgraph-server`), `gateway.enabled=false` |
93
+ | `values-staging.yaml` | `secretOptional: false` (pods need the Secret), `postgresql.enabled=false` (external DSN from the Secret), gateway on, hostnames blank for the operator to fill |
94
+ | `values-prod.yaml` | as staging, plus `replicaCount: 2`, a PDB, topology spread and larger requests |
95
+
96
+ ## Rules `deploy` and `secrets apply` follow
97
+
98
+ - **Env file:** `--env-file`, else `.env.<env>`. Only `dev` falls back to `.env`; any other
99
+ environment without one exits 3 (local development keys never reach staging or prod).
100
+ - **Kube context:** `--context`, else `environments.<env>.context`, else the kubeconfig's current
101
+ context. Outside `dev` the current context needs a confirmation (a prompt at a terminal,
102
+ `--yes` otherwise; exit 1 without). An explicit context missing from the kubeconfig is exit 3.
103
+ The resolved context and API server are printed before anything happens. Prefer recording the
104
+ context in the manifest for staging and prod.
105
+ - **Order (direct mode):** project checks (chart, values, image reference, env file, chart `env`
106
+ placeholders, `jwt` settings the chart lists); the context; a read-only check that the Secret
107
+ the deploy would produce holds every required key (exit 1 before anything is built) and that
108
+ `jwt` can verify tokens with it; a refusal (exit 2) while another helm operation holds the
109
+ release, with the command that clears a lock left by an interrupted helm; then build, load or
110
+ push, the namespace (created when missing), the Secret, and `helm upgrade --install --wait
111
+ --timeout <--timeout, default 5m>`.
112
+ - **Chart env placeholders:** a `CHANGE-ME` left in the merged chart `env` (an API base URL from
113
+ `api add`, `OPENAI_BASE_URL` of an `openai-compatible` project) is refused outside dev in every
114
+ mode (exit 3, naming the key and the values file) and a warning in dev.
115
+ - **`jwt` settings:** outside dev (or when `APP_ENV` is not `dev`) the chart env or the Secret
116
+ must provide a verification key (`AUTH_JWT_JWKS_URL` or `AUTH_JWT_PUBLIC_KEY`), the issuer and
117
+ the audience, or `deploy` exits 3 (the pods would refuse to start). A setting the chart env
118
+ lists, even empty, overrides the Secret. In dev a missing key source is a warning (the pods
119
+ start and answer 503).
120
+ - **Failed rollout:** the pods' states, this release's warning events since the deploy started
121
+ and the logs are printed, then with `--atomic` (default) the release is rolled back to the
122
+ newest good revision, or a first install that never succeeded is uninstalled. Only the
123
+ revision this run created is ever undone. Once the release is back where it was, the app
124
+ Secret (and `<name>-metrics`) this deploy applied is restored to its previous values, or
125
+ deleted if this deploy created it, unless someone changed it since. `--no-atomic` leaves the
126
+ failed revision and the new Secret values in place and says so.
127
+ - **Same image:** when the release already runs the image being deployed, `deploy` says so up
128
+ front; after the upgrade it reports when no pod was replaced and, if the Secret changed, that
129
+ `deploy --restart` is what makes the pods read it.
130
+ - **Protected environments:** `deploy --env staging|prod` refuses while the manifest says
131
+ `auth_policy_implemented: false` (the `custom` stub).
132
+
133
+ ## Standard procedure
134
+
135
+ 1. **Gate:** `graph-agents-cli eval run` exits 0 and the user approved deploying.
136
+ 2. **Prerequisites:** `graph-agents-cli infra check --env <env>`. Read-only; reports the required
137
+ tools and the kube context, Gateway API CRDs and classes (only when `gateway.enabled`) /
138
+ Ingress classes, cert-manager (only when `tls.certManager.enabled`), Argo CD (only when `cd:
139
+ argocd`), metrics-server (only when `hpa.enabled`), the namespace, the image pull secret, the
140
+ app Secret and its required keys, the `jwt` verification settings, the ServiceMonitor's token
141
+ Secret, whether an external DSN requires TLS, every `CHANGE-ME` placeholder (registry, chart
142
+ image and env, CODEOWNERS, Argo CD `repoURL`), where pending approvals are kept when
143
+ `api-policy.yaml` gates calls (the `approvals` table of the app database; a warning under
144
+ `CHECKPOINTER=memory`, which loses paused runs on a restart), and, when `gh` is logged in,
145
+ the environment protection, branch protection and (helm-push) `DEPLOY_KUBECONFIG` settings.
146
+ Nothing is created; install hints are printed for the operator, and every printed command
147
+ runs as is.
148
+ 3. **Values:** fill `hostname`, `parentRef`, `tls`, `resources` in `values-<env>.yaml` and review
149
+ `route.publicPaths` (what the Gateway or Ingress publishes). For network isolation copy the
150
+ `networkPolicy` block of `deployment/helm/<name>/examples/networkpolicy.yaml` (DNS, the
151
+ database, the model endpoint, public HTTPS for hosted APIs) and set its addresses. For an
152
+ external database use a least-privileged role and `sslmode=verify-full` (see
153
+ `references/kubernetes.md`). These are config files: never
154
+ overwritten by upgrade, never containing secrets. `gateway.parentRef.name` is **required**
155
+ whenever `gateway.enabled` (the staging/prod default): `deploy` checks the merged values
156
+ before building or pushing anything and exits 3 naming the file when it is blank. Set
157
+ `appUrl` (or a hostname) so the A2A card advertises a reachable URL. Keep `image:` a nested
158
+ mapping (`image:` newline `tag: ...`), never an inline `{}` map, because `deploy` rewrites
159
+ `image.tag` textually. Record `environments.<env>.context` in the manifest.
160
+ 4. **Secrets:** `graph-agents-cli secrets apply --env <env>` (from `.env.<env>`). CD modes: the
161
+ manifest's `secrets.owner` runs it from a workstation with cluster access; CI never holds
162
+ application secrets; Argo never manages the Secret. `secrets status --env <env>` lists keys
163
+ without values and exits 1 when a required key is missing. `deploy` refuses to touch Secrets
164
+ in `helm-push` and `argocd` modes and prints the procedure.
165
+ 5. **Deploy:** `graph-agents-cli deploy --env <env>` (direct), or let CI run it (`helm-push`), or
166
+ open the PR (`argocd`).
167
+ 6. **Verify:** `graph-agents-cli deploy --status --env <env>` (a bounded rollout status, 60 s by
168
+ default, with the image, helm revision and each pod's readiness and restarts; diagnostics and
169
+ exit 1 when not ready; `argocd app get` in argocd mode), then
170
+ `graph-agents-cli run --url https://<host> "hello"` with the environment's credential in
171
+ `GRAPH_AGENTS_CLI_API_KEY` (the environment's `API_KEY` under `shared-bearer`, a user's token
172
+ under `jwt`; kept out of argv and shell history), or `--header` / `--cookie` under `custom`.
173
+ Readiness is `/ready` (probed inside the cluster; not published on the route).
174
+
175
+ ## Agents calling agents
176
+
177
+ - **One project:** `peer add` writes the peer's URL into each `values-<env>.yaml` from a
178
+ template with `{env}`:
179
+ `graph-agents-cli peer add orders --cluster-url 'http://orders-agent.orders-agent-{env}.svc.cluster.local'`.
180
+ - **Several projects:** `graph-agents-system.yaml` names them, the agents each calls, the
181
+ issuer and the environments. `graph-agents-cli system apply --dry-run`, then without it,
182
+ writes both sides of every edge per environment: the callers' peer URLs,
183
+ `TOKEN_EXCHANGE_URL` and `TOKEN_EXCHANGE_CLIENT_ID`; the called agents' `appUrl` (the URL
184
+ callers dial, which their card advertises: SC05), `AUTH_JWT_AUDIENCE` when empty and the
185
+ callers' actor ids in `AUTH_ALLOWED_ACTORS` (under `jwt` an agent not listed gets 403); and
186
+ NetworkPolicy `egressTo`/`ingressFrom` rules. It never writes gates, secrets or `.env`.
187
+ `graph-agents-cli system check --env <env>` (add `--live` after a deploy), then
188
+ `graph-agents-cli system deploy --env <env>` (the agents called first, `--parallel` at
189
+ once; outside dev every project records its kube context). Give the issuer's admin
190
+ `graph-agents-cli system delegations`: what each client may exchange for.
191
+ - **Callers** keep `TOKEN_EXCHANGE_CLIENT_SECRET` and `PRINCIPAL_HASH_SALT` in `secrets.keys`;
192
+ outside dev `deploy` refuses a peer credential over plain http (except loopback,
193
+ single-label and `.svc` hosts) and an exchange API without the issuer settings.
194
+ - **Keep A2A internal:** when only agents call an agent, drop `/a2a/<agent>` from
195
+ `route.publicPaths` (SC13) and turn on `networkPolicy`.
196
+ - **Sizing:** replicas share A2A tasks only on Postgres (more than one replica with in-memory
197
+ tasks is SC06). Agents sharing one database server open replicas x (`DB_POOL_MAX_SIZE` + 1)
198
+ connections each: set `database.max_connections` in the file (SC10), and above about 120
199
+ connections give agents their own databases or a session-mode PgBouncer.
200
+
201
+ ## Secrets and rotation (summary)
202
+
203
+ - Only variables in the manifest's `secrets.keys` are exported: the provider key
204
+ (`OPENAI_API_KEY` | `ANTHROPIC_API_KEY` | `GOOGLE_API_KEY` | `MODEL_API_KEY`), `JUDGE_API_KEY`,
205
+ `POSTGRES_DSN` (fastapi) or `DATABASE_URI` + `REDIS_URI` (langgraph-server), `API_KEY`,
206
+ `LANGSMITH_API_KEY`, the `token_env` of every `auth: bearer` API in `api-policy.yaml`, and
207
+ `AUTH_JWT_SECRET` automatically under `jwt` with HS*. Never the whole env file. Add other
208
+ secrets (`METRICS_TOKEN`, `PRINCIPAL_HASH_SALT`) to the list.
209
+ - Server-side apply; allow-listed keys the env file leaves out are kept from the live Secret.
210
+ - `API_KEY`: the live key wins; it is replaced only when the env file sets another **and**
211
+ `--rotate-api-key` is passed. Under `shared-bearer` (the only policy that reads it), when
212
+ neither has one, a key is generated, applied and written to the env file (0600), never printed;
213
+ `jwt` and `custom` never get one generated. Values must be single-line.
214
+ - `METRICS_TOKEN` is also written alone into `<name>-metrics`, the Secret the ServiceMonitor
215
+ reads (Prometheus never needs the app Secret).
216
+ - **Rotation:** put the new value in `.env.<env>`, `secrets apply` (with `--rotate-api-key` for
217
+ `API_KEY`), then `deploy --restart --env <env>` (`kubectl rollout restart`, then it waits for
218
+ the new pods and prints diagnostics if they do not become ready), because an externally
219
+ managed Secret does not change the pod template. In argocd environments the restart is drift
220
+ that self-heal may revert; the warning suggests an Argo resource action instead.
221
+ - Details: `references/secrets.md`.
222
+
223
+ ## argocd PR flow and the single production gate (summary)
224
+
225
+ - Staging: the `staging` workflow (on `main`) builds and pushes `<registry>/<name>:<short sha>`
226
+ (`${GITHUB_SHA::7}`), writes the tag into `values-staging.yaml` on `deploy/staging/<short sha>`
227
+ (built on the latest `main`, superseding older staging PRs) and opens a PR with auto-merge;
228
+ Argo syncs staging with self-heal. A PR opened with the workflow `GITHUB_TOKEN` never triggers
229
+ `pr_checks`, so auto-merge on that required check needs a fine-grained PAT or GitHub App token
230
+ (pull-request and contents write) in the `GH_PR_TOKEN` repository secret.
231
+ - Production: desired state changes **only** through a PR touching `values-prod.yaml`, opened by
232
+ the `promote-to-prod` workflow (running in the GitHub `production` environment) or by a
233
+ workstation `deploy --env prod --image <ref>`. Neither path merges. The merge requires review
234
+ from the code owners of `values-prod.yaml`, cannot be self-approved, and requires `pr_checks`
235
+ to pass. That merge is the single gate. Prod `Application` has no automated sync; an operator
236
+ syncs in Argo after the merge.
237
+ - Rollback is a git revert (a PR under the same gate). No inbound access from GitHub to the
238
+ cluster. Details: `references/gitops.md`.
239
+
240
+ ## Required GitHub settings (summary)
241
+
242
+ Repository configuration a workflow cannot create for itself; the operator sets it, `infra
243
+ check` reports it, the scaffolded README documents it:
244
+
245
+ - Environment `production`: required reviewers (at least one), prevent self-review, deployment
246
+ branches restricted to `main`, optional wait timer. Environment `staging`: deployment branches
247
+ restricted to `main`.
248
+ - `helm-push`: the `DEPLOY_KUBECONFIG` secret in **each environment** (never a repository
249
+ secret), and a self-hosted runner with `kubectl` and `curl`.
250
+ - Branch protection on `main` (argocd and helm-push): pull requests required; code-owner review
251
+ required; dismiss stale approvals; prevent self-approval; `pr_checks` required; auto-merge
252
+ allowed.
253
+ - `.github/CODEOWNERS` owns `deployment/` (except the dev and staging values), `.github/`,
254
+ `api-policy.yaml`, `tests/eval/`, the extensions and the manifest; replace the
255
+ `@CHANGE-ME/production-approvers` placeholder.
256
+ - Repository secret `GH_PR_TOKEN` so the desired-state PRs opened by CI trigger `pr_checks`.
257
+ - Optional: the provider key secret (or `MODEL_PROVIDER` / `MODEL_NAME` variables) so the
258
+ `pr_checks` eval gate runs on a real model.
259
+ - GitHub Enterprise Server: set `GH_HOST=<host>` (plus `GH_ENTERPRISE_TOKEN` or `GITHUB_TOKEN`)
260
+ where `deploy` runs so argocd-mode PRs go to that host.
261
+ - Details: `references/github-settings.md`.
262
+
263
+ ## Local-load dev clusters
264
+
265
+ With `cd: skip` and a local cluster (kind, k3d, k3s on this machine, minikube, Docker Desktop,
266
+ Rancher Desktop, OrbStack), `deploy --env dev` skips the registry: it builds with `docker build`,
267
+ loads the image into the node (`kind load docker-image`, `k3d image import`, `docker save` then
268
+ `k3s ctr images import`, `minikube image load`; nothing for the shared-daemon clusters), applies
269
+ the Secret, runs `helm dependency build` when the subcharts are missing, and runs helm with
270
+ `values-dev.yaml` (bundled Postgres, and Redis under `langgraph-server`, gateway off,
271
+ `APP_ENV=dev` so `/playground` is served). The k3s import runs without `sudo` and needs root on
272
+ most k3s hosts. Reach it with `kubectl -n <name>-dev port-forward svc/<name> 8000:80`. Only the
273
+ `docker` CLI is supported for builds.
274
+
275
+ ## Disconnected profile
276
+
277
+ The one configuration in which the whole lifecycle runs without internet access:
278
+
279
+ | Component | Requirement |
280
+ |---|---|
281
+ | Agent model | `MODEL_PROVIDER=openai-compatible`, `OPENAI_BASE_URL` at an in-cluster or on-network server (vLLM, TGI, Ollama) with a tool-capable model |
282
+ | Judge | same via `JUDGE_*`; may be the same endpoint |
283
+ | Runtime | `fastapi` (the LangGraph Server image checks for a licence at startup; the local `langgraph dev` server needs none) |
284
+ | Python deps | private index or mirror (`UV_INDEX_URL`), `install --locked` |
285
+ | Images | base images mirrored into `--registry` (`PYTHON_IMAGE` / `UV_IMAGE` build args); the chart's Bitnami subcharts vendored under `deployment/helm/<name>/charts/` and their images mirrored, otherwise `deploy` runs `helm dependency build` against `registry-1.docker.io` (exit 2 offline) |
286
+ | Tracing | `TRACING_ENABLED=true` with OTLP to an in-cluster collector, or off; no LangSmith |
287
+ | Evals | local datasets, deterministic checks, judge run in the project's environment against the on-network endpoint; `eval submit` disabled |
288
+ | CLI | installed from a mirror (`GRAPH_AGENTS_CLI_INSTALL_SPEC`); `GRAPH_AGENTS_CLI_NO_UPDATE_CHECK=1`; skills from the wheel bundle |
289
+ | Scaffold | built-in templates only |
290
+ | CD | only with an on-network GitHub Enterprise Server; otherwise `cd: skip` and direct-mode `deploy` |
291
+
292
+ `infra check --profile disconnected` and `login --profile disconnected` verify these and fail on
293
+ any hosted dependency. "Runs locally" (orchestration on the developer's machine) is not "runs
294
+ disconnected" (this profile).
295
+
296
+ ## Troubleshooting
297
+
298
+ | Symptom | Fix |
299
+ |---|---|
300
+ | `deploy` exit 3 "No env file for <env>" | create `.env.<env>` with the allow-listed keys, or pass `--env-file`; `.env` is used for `dev` only |
301
+ | `deploy` exit 1 "Refusing to deploy to <env> on the kubeconfig's current context" | record `environments.<env>.context` in the manifest, pass `--context <name>`, or `--yes` after checking the printed context |
302
+ | `deploy` exit 3 "Kube context 'x' ... is not in the kubeconfig" | fix the manifest's context or `--context`; the known contexts are listed |
303
+ | `deploy` exit 1 "Secret ... is missing required key(s)" | add them to `.env.<env>` and re-run (direct), or run `secrets apply` (helm-push); or drop the key from `secrets.keys` if the environment does not need it |
304
+ | `deploy` exit 2 "Another helm operation ... is in progress" | wait for it (`helm history`); if nothing else runs, the printed `helm rollback` / `helm uninstall` clears the lock an interrupted helm left |
305
+ | `deploy` exit 2 "helm upgrade failed ... rolled back to revision N" | read the printed pod diagnostics (states, this rollout's events, logs); the Secret was restored too ("Secret ... was restored"); fix and deploy again |
306
+ | "Secret ... keeps this deploy's values for ..." after a failed deploy | the release stayed on the failed revision (`--no-atomic`, another deploy): roll it back, then re-apply the previous values with `secrets apply --env-file <previous file>` |
307
+ | `deploy` exit 3 "still hold(s) the placeholder CHANGE-ME" | set the real value (an API base URL, `OPENAI_BASE_URL`) in `values-<env>.yaml` or `values.yaml` |
308
+ | `deploy` / `infra check` "The jwt auth policy cannot verify tokens" | set `AUTH_JWT_JWKS_URL` (or `AUTH_JWT_PUBLIC_KEY`), `AUTH_JWT_ISSUER` and `AUTH_JWT_AUDIENCE` under `env:` in `values-<env>.yaml` (an empty value there overrides the Secret) |
309
+ | `deploy --status` exit 1 "did not complete within" | read the printed pods, events and logs; `--timeout` waits longer |
310
+ | `deploy --restart` exit 2 "did not become ready" | the old pods keep serving; fix the cause (often a Secret value) and restart again, or `kubectl rollout undo` |
311
+ | "No pods were replaced" / "The Secret changed ... run deploy --restart" | same image and chart values: the pods read a changed Secret only at start |
312
+ | Warning "POSTGRES_DSN does not require TLS" | add `sslmode=verify-full` (and `sslrootcert`) to the DSN; see `references/kubernetes.md` |
313
+ | `deploy` exit 1 "Refusing to deploy <env> from outside CI in helm-push mode" | run from the CI runner, or `--force-direct` for a deliberate workstation deploy (dev is always allowed) |
314
+ | `deploy` exit 1 "--env-file is not accepted in argocd mode" (or helm-push) | Secrets are applied separately: `secrets apply --env <env>`; `deploy --env <env> --image <ref>` only opens the PR (argocd) or runs helm (helm-push) |
315
+ | `deploy` exit 1 "the manifest records auth_policy_implemented: false" | implement `app/policies/custom.py`, flip the manifest flag |
316
+ | `build` / `deploy` exit 3 "still the placeholder 'ghcr.io/CHANGE-ME'" | `graph-agents-cli scaffold enhance --registry <host>/<org>` (sets `create_params.registry` in the manifest, `image.repository` in the chart values and `IMAGE_REPOSITORY` in `.github/agent.env`); `build` also takes `--registry` |
317
+ | `deploy` exit 3 "gateway.parentRef.name is blank" | set `gateway.parentRef.name` in `values-<env>.yaml` (or `gateway.enabled: false` / `ingress.enabled: true`) |
318
+ | chart error "image.tag is empty" / "must be a quoted string" | deploy with a built image (`deploy` passes the tag); quote tags in values files (`tag: "0123456"`) |
319
+ | `deploy` exit 3 "is a digest reference" | pass `<registry>/<repo>:<tag>`; the chart has no `image.digest` |
320
+ | `deploy` exit 3 "not committed on origin/main" (argocd) | commit `values-<env>.yaml` on `main` first; the PR is built from the base branch's copy, never the working tree |
321
+ | `secrets apply` exit 3 "must be single-line" | put the value on one line (for example base64) or create the Secret with kubectl directly |
322
+ | "API_KEY in <file> differs from the live Secret; the live key is kept" | intended; pass `--rotate-api-key` to replace it, then `deploy --restart` |
323
+ | A2A client dials `127.0.0.1:8000` after fetching the card | `APP_URL` is unset in the pod: set `appUrl` or a gateway/ingress hostname in the values file |
324
+ | An agent's calls to another agent fail with 403 "Delegated caller ... is not allowed here (AUTH_ALLOWED_ACTORS)" | list the id the error names (the `act.sub` of the caller's exchanged tokens) in the called agent's `AUTH_ALLOWED_ACTORS`: `system apply` lists the caller's `actor_id` (default its `client_id`), so set `actor_id` when the issuer names it differently; then `deploy` it |
325
+ | "<peer>'s agent card names <url> as its A2A endpoint, not the URL this agent calls" | set the called agent's `appUrl` to the URL the caller dials (`system apply` does); `graph-agents-cli system check --env <env>` (SC05) or `peer show <name> --check` finds it |
326
+ | `deploy` exit 2 "missing in charts/ directory" or `helm dependency build` failed (429) | `registry-1.docker.io` is unreachable or rate-limited; retry, authenticate, or vendor the charts under `deployment/helm/<name>/charts/` |
327
+ | `deploy` exit 2 naming a tool | helm, kubectl, docker, git or gh is not on `PATH` |
328
+ | Staging PR opened by CI never runs `pr_checks` | PRs opened with `GITHUB_TOKEN` do not trigger workflows; store a PAT or App token as `GH_PR_TOKEN` |
329
+ | helm-push job: "DEPLOY_KUBECONFIG is empty" | store the kubeconfig as the `DEPLOY_KUBECONFIG` secret of that GitHub environment |
330
+ | Workflow step "Load project settings" fails on `.github/agent.env` | only the six known names are accepted; rename `CLI_VERSION_PIN` to `GRAPH_AGENTS_CLI_SPEC` |
331
+ | `k3s ctr images import` permission denied | the import needs root on that host |
332
+ | Pod `CreateContainerConfigError` | the Secret `<name>-app` is missing (required outside dev): `secrets apply`, then `secrets status --env <env>` |
333
+ | Pod not Ready, `/ready` 503 | the database is unreachable from the pod: check the DSN in the Secret and network policies |
334
+ | `ImagePullBackOff` | pull secret missing (`imagePullSecrets` in values; `infra check` reports it) or the image was not pushed / loaded |
335
+ | No route / 404 at the hostname | `gateway.parentRef` or `ingress.className` unset, or the path is not in `route.publicPaths`; `infra check` lists classes |
336
+ | TLS errors | `tls.existingSecret` name wrong, or cert-manager not installed while `tls.certManager.enabled` |
337
+ | 401 from `run --url` | wrong credential for the policy; `secrets status`; pass `--header` |
338
+ | 503 on every request under `custom` | the stub is still in place |
339
+ | Argo shows `OutOfSync` after `--restart` | self-heal reverted the restart annotation; use an Argo resource action |
340
+ | `ApiPolicyError` in tool results after deploy (outside dev, clients see `The tool call did not succeed. Reference: <error_id>`; the pod log has `tool call failed (error_id=...)` with its `error_type`, and `api call refused: ...` naming the rule) | the deployed `api-policy.yaml` differs from local (it is baked into the image; rebuild), or a base URL / token variable is missing in the pod (`api call not sent`); "limits.max_calls_per_run" or "rate_per_minute" in the refusal means a limit was reached (per run / per replica) |
341
+
342
+ ## Not covered by this skill
343
+
344
+ - Writing the auth policy or tools: `/graph-agents-cli-langgraph-code`.
345
+ - Adding the Kubernetes target or CD mode to a project: `/graph-agents-cli-scaffold`.
346
+ - The eval gate that precedes deployment: `/graph-agents-cli-eval`.
347
+ - Tracing configuration after deploy: `/graph-agents-cli-observability`.
348
+ - Installing cluster components (Gateway controller, cert-manager, Argo CD, metrics-server),
349
+ provisioning clusters or registries, or a managed-cloud deployment target: none exist here.
350
+ - External Secrets Operator, Sealed Secrets, Kustomize, Terraform, GitLab CI: not in this release.
351
+
352
+ ## Migration note
353
+
354
+ Compared with google-agents-cli: Agent Runtime, Cloud Run, and GKE targets, Terraform
355
+ provisioning (`infra single-project`, `infra cicd`), Cloud Build, Secret Manager, and Agent
356
+ Gateway are gone. Any Kubernetes cluster via a Helm chart replaces them; secrets are Kubernetes
357
+ Secrets applied from allow-listed `.env` keys; `infra check` is read-only.
@@ -0,0 +1,113 @@
1
+ # Required GitHub settings
2
+
3
+ These are repository settings a workflow cannot create for itself with the default token. The
4
+ operator sets them once; `graph-agents-cli infra check` reports whether they exist when a
5
+ `GITHUB_TOKEN` (or `gh auth`) is available; the scaffolded README documents them. The CLI never
6
+ creates or changes them.
7
+
8
+ ## Environments
9
+
10
+ | Environment | Settings |
11
+ |---|---|
12
+ | `production` | required reviewers (at least one); "prevent self-review" enabled; deployment branches restricted to `main`; optional wait timer; in `helm-push` mode the `DEPLOY_KUBECONFIG` secret |
13
+ | `staging` | deployment branches restricted to `main`; no reviewers; in `helm-push` mode the `DEPLOY_KUBECONFIG` secret |
14
+
15
+ The production jobs (`promote-to-prod` in both modes) declare `environment: production` and run
16
+ only from `main`.
17
+
18
+ ## Branch protection on `main` (argocd and helm-push modes)
19
+
20
+ - Pull requests required.
21
+ - Required review from code owners.
22
+ - "Dismiss stale approvals" enabled.
23
+ - "Prevent self-approval" enabled.
24
+ - `pr_checks` as a required status check.
25
+ - No bypass for the Actions token, except the staging auto-merge mechanism (auto-merge allowed
26
+ on the repository; the staging PR merges once `pr_checks` passes).
27
+
28
+ ## `CODEOWNERS`
29
+
30
+ Scaffolded at `.github/CODEOWNERS` for every project:
31
+
32
+ ```
33
+ /deployment/ @CHANGE-ME/production-approvers # kubernetes target only
34
+ /deployment/helm/*/values-dev.yaml # unowned, so the staging PR can auto-merge
35
+ /deployment/helm/*/values-staging.yaml
36
+ /.github/ @CHANGE-ME/production-approvers # workflows, agent.env, this file
37
+ /api-policy.yaml @CHANGE-ME/production-approvers
38
+ /tests/eval/ @CHANGE-ME/production-approvers
39
+ /graph-agents-cli-extensions.yaml @CHANGE-ME/production-approvers
40
+ /extensions/ @CHANGE-ME/production-approvers
41
+ /.graph-agents-cli/ @CHANGE-ME/production-approvers
42
+ /graph-agents-cli-manifest.yaml @CHANGE-ME/production-approvers
43
+ ```
44
+
45
+ Replace the placeholder team (`infra check` reports it: a required item under `helm-push` or
46
+ `argocd`, a warning under `skip`; GitHub ignores unknown owners, so the gate would require
47
+ nobody). With code-owner review required, a PR touching `values-prod.yaml`, the policy, the eval
48
+ gate inputs, the workflows or the extensions cannot merge without a production approver, whoever
49
+ opened it.
50
+
51
+ ## Secrets and variables
52
+
53
+ | Name | Kind | Mode | Purpose |
54
+ |---|---|---|---|
55
+ | (none for images on GHCR) | | argocd, helm-push | `GITHUB_TOKEN` pushes to `ghcr.io/<org>` |
56
+ | `REGISTRY_USERNAME`, `REGISTRY_PASSWORD` | repository secrets | any CD mode with a non-GHCR registry | `docker login` in `staging.yaml` |
57
+ | `DEPLOY_KUBECONFIG` | **environment** secret of `staging` and of `production` | helm-push | the self-hosted runner's cluster credentials, written under `RUNNER_TEMP` and removed after the job. Never a repository secret: any branch's workflow could read that one and it would bypass the production reviewers. The retired repository secret `KUBECONFIG` is no longer read; delete it |
58
+ | `GH_PR_TOKEN` | repository secret | argocd, helm-push | a fine-grained PAT or GitHub App token with pull-request and contents write access, used to push the desired-state branches and open the PRs (`secrets.GH_PR_TOKEN \|\| secrets.GITHUB_TOKEN`). A PR opened with the workflow `GITHUB_TOKEN` does not trigger `pr_checks`, so auto-merge on a required check needs it |
59
+ | provider key (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GOOGLE_API_KEY` or `MODEL_API_KEY`) | repository secret | any | the `pr_checks` eval gate runs on the project's real provider when its key exists; tests always run on the fake model |
60
+ | `MODEL_PROVIDER`, `MODEL_NAME` | repository variables | any | override the eval gate's model (`MODEL_NAME` is required when `MODEL_PROVIDER` differs from the project's provider) |
61
+ | `JUDGE_MODEL_PROVIDER`, `JUDGE_MODEL_NAME`, `JUDGE_BASE_URL`; `JUDGE_API_KEY` | variables; secret | any | a separate eval judge |
62
+
63
+ Without a provider key the gate runs on the deterministic fake model and prints the warning
64
+ "Eval gate is not a quality signal". **Never** application secrets (`API_KEY`, `POSTGRES_DSN`,
65
+ provider keys for the deployed app) in GitHub: those are Kubernetes Secrets applied by the owner
66
+ (`secrets.md`).
67
+
68
+ ## Self-hosted runner (helm-push)
69
+
70
+ A runner with network access to the cluster (the jobs use `runs-on: self-hosted`), with `kubectl`
71
+ and `curl` on `PATH` (the jobs resolve the kube context and verify the rollout with them; `uv` is
72
+ installed by the job). Its kubeconfig (`DEPLOY_KUBECONFIG`) needs rights to deploy the release
73
+ and to read the app Secret (deploy checks its required keys).
74
+
75
+ ## GitHub Enterprise Server
76
+
77
+ Set `GH_HOST=<host>` (or `GITHUB_HOST`; `GITHUB_SERVER_URL` is honoured inside Actions) with
78
+ `GH_ENTERPRISE_TOKEN` or `GITHUB_TOKEN` where `deploy` runs, so argocd-mode PRs go to that host
79
+ (API base `https://<host>/api/v3`). `infra check --profile disconnected` and
80
+ `login --profile disconnected` treat GitHub-hosted CI as outside the disconnected profile unless
81
+ `GH_HOST` / `GITHUB_SERVER_URL` names an on-network GHES.
82
+
83
+ ## What `infra check` reports
84
+
85
+ Through the `gh` CLI (`gh api`, so `gh auth login` or `GITHUB_TOKEN`), skipped when `cd: skip`:
86
+ whether the `production` environment exists with required reviewers, prevent self-review and
87
+ deployment branches restricted; whether the `staging` environment exists with restricted
88
+ branches; whether `main` branch protection requires pull requests, code-owner review, dismisses
89
+ stale approvals and lists `pr_checks` as a required status check. For `helm-push` it also
90
+ reports whether `DEPLOY_KUBECONFIG` exists as a secret of each environment and warns about a
91
+ repository-level (or shared organization) `KUBECONFIG` / `DEPLOY_KUBECONFIG` secret; these rows
92
+ are informational when the account cannot read secrets. When the GitHub API does not answer, the
93
+ GitHub rows collapse into one informational row. Independently of GitHub it reports every
94
+ `CHANGE-ME` placeholder (registry, chart `image.repository` and `env` (required outside dev,
95
+ a warning in dev, as `deploy` treats it), CODEOWNERS, Argo CD `repoURL`), and with `--env` the
96
+ `jwt` policy's verification settings (a JWKS URL or public key; issuer and audience outside
97
+ dev), the ServiceMonitor's token Secret and whether an external DSN requires TLS. Rows for
98
+ components the environment does not use (a disabled Gateway, cert-manager, metrics-server,
99
+ Argo CD) are `skip` with no install hint. It never changes anything.
100
+
101
+ ```bash
102
+ GITHUB_TOKEN=... graph-agents-cli infra check --env prod --json
103
+ ```
104
+
105
+ ## Verifying by hand
106
+
107
+ ```bash
108
+ gh api repos/<owner>/<repo>/environments
109
+ gh api repos/<owner>/<repo>/environments/production
110
+ gh api repos/<owner>/<repo>/environments/production/secrets
111
+ gh api repos/<owner>/<repo>/branches/main/protection
112
+ gh api repos/<owner>/<repo> --jq .allow_auto_merge
113
+ ```
@@ -0,0 +1,137 @@
1
+ # GitOps: the `argocd` CD mode
2
+
3
+ With `cd: argocd`, Argo CD inside the cluster reconciles from `main`. `graph-agents-cli deploy`
4
+ never runs helm, never contacts the cluster and never merges; it writes desired state and opens
5
+ a pull request.
6
+
7
+ ## Scaffolded artefacts
8
+
9
+ - `deployment/argocd/application-<env>.yaml`: one Argo `Application` per environment;
10
+ `targetRevision: main`, `path: deployment/helm/<name>`,
11
+ `valueFiles: [values.yaml, values-<env>.yaml]`, destination namespace `<name>-<env>`
12
+ (`CreateNamespace`). `dev` and `staging` have automated sync with self-heal; **prod has no
13
+ automated sync** (an operator syncs in Argo after the merge). They ignore the data of the
14
+ chart-managed `<name>-postgresql-auth` Secret (`RespectIgnoreDifferences`), so the dev database
15
+ password is not regenerated on every sync. Set `repoURL` (a `CHANGE-ME` placeholder that
16
+ `infra check` reports). An environment shows a comparison error until its values file has an
17
+ image tag: the chart refuses an empty one.
18
+ - `.github/workflows/pr_checks.yaml`: ruff, unit and integration tests on the fake model, `lint`
19
+ (with the API-policy check) and the eval gate. The gate uses the project's real provider when
20
+ its key is a repository secret (or the `MODEL_PROVIDER` / `MODEL_NAME` repository variables);
21
+ on the fake model it warns that the gate only checks the plumbing.
22
+ - `.github/workflows/staging.yaml` (on `main`, or by hand from `main`): builds and pushes
23
+ `<registry>/<name>:<short sha>` (`${GITHUB_SHA::7}`), then writes the tag (double-quoted) into
24
+ `values-staging.yaml` on branch `deploy/staging/<short sha>`, built on the latest `main`, and
25
+ opens a PR with auto-merge (`gh pr merge --auto --squash`); branch protection must permit
26
+ auto-merge. It closes older open `deploy/staging/*` PRs it supersedes (with a comment, deleting
27
+ their branches) and does nothing when `main` or an open PR already carries this build or a
28
+ newer one, so a re-run of an older build never moves staging back. PRs whose tag is not a
29
+ commit (a workstation `<sha>-dirty-<time>`) are left alone. Pushes that only change
30
+ `values-*.yaml` do not start the workflow, so a merged staging PR never triggers another build.
31
+ - `.github/workflows/promote-to-prod.yaml`: runs in the GitHub `production` environment (which
32
+ controls who may *initiate* a promotion from CI), only from `main`; its `image_tag` input is the
33
+ short sha (empty = the tag in `values-staging.yaml`). It runs
34
+ `uvx --from "$GRAPH_AGENTS_CLI_SPEC" graph-agents-cli deploy --env prod --image <registry>/<name>:<short sha> --yes`,
35
+ which opens a PR updating `values-prod.yaml`. It does not merge.
36
+ - Both workflows use `secrets.GH_PR_TOKEN || secrets.GITHUB_TOKEN`. A pull request opened with
37
+ the workflow `GITHUB_TOKEN` does not trigger `pr_checks` (GitHub never starts workflows from
38
+ `GITHUB_TOKEN` events), so auto-merge on a required check needs a fine-grained PAT or GitHub
39
+ App token stored as the `GH_PR_TOKEN` repository secret, with pull-request **and contents**
40
+ write access (the staging job pushes the branch with it).
41
+ - Every job that runs graph-agents-cli sets `GRAPH_AGENTS_CLI_DISABLE_OVERRIDES=1`, so project or
42
+ user extensions cannot replace `lint`, `eval` or `deploy` in CI and CD.
43
+ - `.github/agent.env` (rendered for every project, read only by the workflows): `IMAGE_REPOSITORY`,
44
+ `RELEASE_NAME`, `CHART_PATH`, `RUNTIME`, `CD` and `GRAPH_AGENTS_CLI_SPEC` (where CI installs the
45
+ CLI: the creating version's git tag). It is data, never sourced: one `NAME=VALUE` per line, `#`
46
+ comments and blank lines skipped, one pair of surrounding quotes and a trailing ` # comment`
47
+ dropped. Any other name (including the retired `CLI_VERSION_PIN`), a duplicate or a control
48
+ character fails the `Load project settings` step before anything is exported. To add a setting,
49
+ extend `known` in all three workflows.
50
+ - `.github/CODEOWNERS`: `/.github/`, `/CODEOWNERS`, `/api-policy.yaml`, `/tests/eval/`, the
51
+ extensions files, the manifest, and `/deployment/` except `values-dev.yaml` and
52
+ `values-staging.yaml` (left unowned so the staging PR can auto-merge) ->
53
+ `@CHANGE-ME/production-approvers` (placeholder to fill; `infra check` reports it).
54
+
55
+ The `Application` manifests and the values files are config: `upgrade` never overwrites them.
56
+
57
+ ## The `deploy` PR flow
58
+
59
+ ```bash
60
+ graph-agents-cli deploy --env staging --image ghcr.io/acme/my-agent:abc1234
61
+ graph-agents-cli deploy --env prod --image ghcr.io/acme/my-agent:abc1234
62
+ ```
63
+
64
+ 1. Reads `values-<env>.yaml` **as `origin/main` holds it** (`git cat-file blob origin/main:<path>`;
65
+ `HEAD` when `origin/main` is unavailable), changes `image.tag` and nothing else. Your working
66
+ tree is not modified and never used: a checkout behind `main` or with local edits cannot leak
67
+ into the PR, and "nothing to change" is judged on the base branch (a closed, unmerged PR is
68
+ re-opened by a re-run). A values file not committed on the base is exit 3. Paths are
69
+ repository-relative, so a project below the git root works.
70
+ 2. Builds branch `deploy/<env>/<short sha>` with git plumbing (`hash-object --stdin`,
71
+ `read-tree`, `update-index`, `write-tree`, `commit-tree`, `update-ref`) and pushes it with
72
+ `git push --force-with-lease=refs/heads/<branch>:<sha on origin>`; when `origin/<branch>`
73
+ already holds the change it prints "nothing to push", so a retry is idempotent. Your checkout
74
+ and index are never switched. A git identity must be configured (`commit-tree` needs one; the
75
+ scaffolded workflow sets it).
76
+ 3. Opens or updates a PR against `main` with `gh` when available, else GitHub REST with
77
+ `GITHUB_TOKEN`, `GH_TOKEN` or `GH_ENTERPRISE_TOKEN`. Only GitHub and GitHub Enterprise Server
78
+ hosts are supported; a GHES host is recognised from `GH_HOST` (or `GITHUB_HOST`,
79
+ `GITHUB_SERVER_URL`), API base `https://<host>/api/v3`. Without `gh` and without a token the
80
+ branch is still pushed and the command exits 3 with instructions.
81
+ 4. Prints the PR URL and stops. **You never merge it.** Argo reconciles after the merge.
82
+
83
+ `deploy` prints "No cluster is contacted" in this mode: no kube context is used, so `--context`
84
+ and `--yes` change nothing here. `--env-file` and `--rotate-api-key` are refused (exit 1):
85
+ Secrets are applied with `secrets apply`. `--dry-run` prints the values rewrite, the git plumbing
86
+ and the `gh pr list/create` commands. `--image` names the CI-pushed image (a tagged reference; a
87
+ digest reference is refused with exit 3 because the chart has no `image.digest`; a repository
88
+ other than the chart's `image.repository` gets a warning, since only `image.tag` is written);
89
+ without it `deploy` uses `--tag` or the short git sha and warns that the image must already have
90
+ been pushed by CI (the CLI does not build or push in this mode). A chart `image.repository` that
91
+ still holds `CHANGE-ME` is exit 3.
92
+
93
+ ## The single production gate
94
+
95
+ Production desired state changes only through a PR touching `values-prod.yaml`. Two paths open
96
+ such a PR (`promote-to-prod` from CI, `deploy --env prod` from a workstation); neither merges.
97
+ The merge requires:
98
+
99
+ - review from the production approvers in `CODEOWNERS` for `values-prod.yaml`,
100
+ - no self-approval (branch protection "prevent self-approval" and environment "prevent
101
+ self-review"),
102
+ - `pr_checks` green.
103
+
104
+ Argo watches `main`, so approval necessarily precedes the production change on both paths. No
105
+ inbound access from GitHub to the cluster exists. No Argo Image Updater is used. After deploying,
106
+ Argo's own health assessment (the readiness probe on `/ready`) shows whether the rollout landed;
107
+ the workflows have no cluster access by design.
108
+
109
+ ## Operating in argocd environments
110
+
111
+ | Need | Command |
112
+ |---|---|
113
+ | Status | `graph-agents-cli deploy --status --env <env>` (`argocd app get <name>-<env>`; without the `argocd` CLI a bounded `kubectl rollout status` plus the pods' readiness, exit 1 when not ready) |
114
+ | Restart after secret rotation | `graph-agents-cli deploy --restart --env <env>` (`kubectl rollout restart`, then waits for the new pods); the CLI warns that self-heal may revert the annotation and recommends an Argo resource action (`argocd app actions run <name>-<env> restart --kind Deployment`) |
115
+ | Secrets | `graph-agents-cli secrets apply/status --env <env>` from the owner's workstation; Argo never manages the app Secret |
116
+ | Rollback | revert the values change on `main` through a PR (same gate); for emergencies `argocd app history` / `argocd app rollback` on the Argo side, then reconcile git |
117
+ | Diff before merge | `argocd app diff <name>-<env> --revision <branch>` |
118
+
119
+ `--status`, `--restart` and `secrets` follow the kube context rules (recorded context or
120
+ `--context`; outside dev the current context needs a confirmation or `--yes`). Direct
121
+ `helm upgrade` or `kubectl apply` against an argocd environment is drift: self-heal reverts it
122
+ (dev, staging) or Argo reports `OutOfSync` (prod). Do not do it.
123
+
124
+ ## `helm-push` for comparison
125
+
126
+ A self-hosted GitHub runner inside the network gets the cluster credentials from the
127
+ `DEPLOY_KUBECONFIG` secret of the `staging` or `production` **environment** (written under
128
+ `RUNNER_TEMP` and removed after the job), resolves one kube context (the manifest's
129
+ `environments.<env>.context`, else the kubeconfig's current one), runs
130
+ `graph-agents-cli deploy --env <env> --image <ref> --context "$KUBE_CONTEXT" --yes` (helm only),
131
+ and verifies the rollout (`kubectl rollout status`, `/health` and `/ready` through a
132
+ port-forward; the runner needs `kubectl` and `curl`). The `production` job declares
133
+ `environment: production` and is gated by that environment's reviewers. Workstation deploys are
134
+ allowed for `dev`; `staging`/`prod` are refused outside CI (`GITHUB_ACTIONS=true`) even with
135
+ `--image`, unless `--force-direct`. Secrets are still provisioned by the owner from a
136
+ workstation, never by CI; the runner's kubeconfig needs permission to read the Secret (deploy
137
+ checks its required keys).