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,513 @@
1
+ # Copyright 2026 graph-agents-cli contributors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """graph-agents-cli auth: local credentials for a project's auth policy.
16
+
17
+ ``auth dev-token`` lets a ``jwt`` project run locally without an identity
18
+ provider. It keeps an RSA key pair under ``.graph-agents-cli/dev-jwt/`` (git
19
+ ignored; the private key is mode 0600), puts the public key and a dev issuer
20
+ and audience in ``.env`` (only where ``.env`` leaves them blank), and prints a
21
+ token signed with the private key for the principal and roles asked for (and, with
22
+ ``--act``, the agents presenting it for that principal: the RFC 8693 ``act``
23
+ claim, to try agents calling agents locally).
24
+ ``run`` and ``eval`` send it as the bearer when it is in
25
+ ``GRAPH_AGENTS_CLI_API_KEY``, which keeps it out of argv and shell history.
26
+
27
+ It refuses anything but a local dev setup: the project's policy must be
28
+ ``jwt``, the local server's ``APP_ENV`` exactly ``dev``, and ``.env`` must not
29
+ point at a real issuer (``AUTH_JWT_JWKS_URL``) or hold another public key.
30
+ Deployed environments never see the dev key: ``deploy`` and ``secrets`` read
31
+ the chart values and ``.env.<env>``, and ``AUTH_JWT_PUBLIC_KEY`` is not a
32
+ secret key. Signing runs in the project's environment (``uv run``), whose
33
+ ``pyjwt[crypto]`` is the library the server verifies with, so the CLI itself
34
+ needs no crypto dependency.
35
+ """
36
+
37
+ from __future__ import annotations
38
+
39
+ import json
40
+ import os
41
+ import re
42
+ import shlex
43
+ import subprocess
44
+ import time
45
+ import uuid
46
+ from pathlib import Path
47
+ from typing import Any
48
+
49
+ import click
50
+
51
+ from graph_agents_cli._click import LazyGroup
52
+ from graph_agents_cli._defaults import normalize_auth_policy
53
+ from graph_agents_cli._project import find_project_root, read_project_config
54
+ from graph_agents_cli._remote import API_KEY_ENV
55
+
56
+ EXIT_TOOL_FAILURE = 2
57
+ EXIT_CONFIG_ERROR = 3
58
+
59
+ DEV_KEY_DIR = Path(".graph-agents-cli") / "dev-jwt"
60
+ PRIVATE_KEY_FILE = "private-key.pem"
61
+ PUBLIC_KEY_FILE = "public-key.pem"
62
+ DEV_ISSUER = "graph-agents-cli-dev"
63
+ DEV_KEY_ID = "graph-agents-cli-dev"
64
+ ALGORITHM = "RS256"
65
+ DEFAULT_TTL = "12h"
66
+ MAX_TTL_S = 7 * 24 * 3600
67
+ SIGN_TIMEOUT_S = 300
68
+
69
+ _TTL = re.compile(r"^\s*(\d+)\s*([smhd]?)\s*$")
70
+ _TTL_UNITS = {"": 1, "s": 1, "m": 60, "h": 3600, "d": 86400}
71
+
72
+
73
+ class DevTokenError(click.ClickException):
74
+ """A setup this command will not sign for (exit 3)."""
75
+
76
+ exit_code = EXIT_CONFIG_ERROR
77
+
78
+
79
+ class SigningError(click.ClickException):
80
+ """The project's environment could not create the key or sign (exit 2)."""
81
+
82
+ exit_code = EXIT_TOOL_FAILURE
83
+
84
+
85
+ # The part that runs in the project's environment (`uv run python -c`): it
86
+ # reads {"key_path", "claims", "kid", "algorithm"} on stdin, creates the private
87
+ # key when absent (0600, never overwritten), and prints {"token", "public_key"}
88
+ # or {"error", "detail"}.
89
+ _SIGNER = r"""
90
+ import json, os, sys
91
+ payload = json.load(sys.stdin)
92
+ try:
93
+ import jwt
94
+ from cryptography.hazmat.primitives import serialization
95
+ from cryptography.hazmat.primitives.asymmetric import rsa
96
+ except ImportError as exc:
97
+ print(json.dumps({"error": "missing", "detail": str(exc)}))
98
+ sys.exit(0)
99
+ try:
100
+ path = payload["key_path"]
101
+ if os.path.exists(path):
102
+ with open(path, "rb") as handle:
103
+ key = serialization.load_pem_private_key(handle.read(), password=None)
104
+ if not isinstance(key, rsa.RSAPrivateKey):
105
+ raise ValueError("not an RSA private key")
106
+ else:
107
+ key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
108
+ pem = key.private_bytes(
109
+ serialization.Encoding.PEM,
110
+ serialization.PrivateFormat.PKCS8,
111
+ serialization.NoEncryption(),
112
+ )
113
+ # Written whole under a temporary name, then linked into place: the key
114
+ # appears complete or not at all, and never replaces one that exists.
115
+ tmp = f"{path}.{os.getpid()}.tmp"
116
+ fd = os.open(tmp, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
117
+ try:
118
+ with os.fdopen(fd, "wb") as handle:
119
+ handle.write(pem)
120
+ os.link(tmp, path)
121
+ except FileExistsError:
122
+ # Another run created the key first: sign with that one.
123
+ with open(path, "rb") as handle:
124
+ key = serialization.load_pem_private_key(handle.read(), password=None)
125
+ finally:
126
+ os.unlink(tmp)
127
+ public = key.public_key().public_bytes(
128
+ serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo
129
+ ).decode()
130
+ token = jwt.encode(
131
+ payload["claims"], key, algorithm=payload["algorithm"], headers={"kid": payload["kid"]}
132
+ )
133
+ print(json.dumps({"token": token, "public_key": public}))
134
+ except Exception as exc:
135
+ print(json.dumps({"error": "failed", "detail": f"{type(exc).__name__}: {exc}"}))
136
+ """
137
+
138
+
139
+ def parse_ttl(raw: str) -> int:
140
+ """``3600``, ``90s``, ``30m``, ``12h`` or ``2d`` -> seconds (1 s to 7 days)."""
141
+ match = _TTL.match(raw or "")
142
+ if not match:
143
+ raise click.BadParameter(f"{raw!r}: use seconds or a number with s, m, h or d (e.g. 12h)")
144
+ seconds = int(match.group(1)) * _TTL_UNITS[match.group(2)]
145
+ if not 1 <= seconds <= MAX_TTL_S:
146
+ raise click.BadParameter(f"{raw!r}: between 1 second and 7 days")
147
+ return seconds
148
+
149
+
150
+ def _csv(raw: str | None) -> list[str]:
151
+ return [part.strip() for part in (raw or "").split(",") if part.strip()]
152
+
153
+
154
+ def _set_claim(claims: dict[str, Any], path: str, value: Any) -> None:
155
+ """Put ``value`` at a claim name, or a dotted path (``realm_access.roles``) as the server reads it."""
156
+ if "." not in path:
157
+ claims[path] = value
158
+ return
159
+ *parents, leaf = path.split(".")
160
+ node = claims
161
+ for part in parents:
162
+ child = node.get(part)
163
+ if not isinstance(child, dict):
164
+ child = {}
165
+ node[part] = child
166
+ node = child
167
+ node[leaf] = value
168
+
169
+
170
+ def actor_claim(actors: list[str]) -> dict[str, Any] | None:
171
+ """The RFC 8693 ``act`` claim for ``actors`` (current actor first): each earlier actor
172
+ nested in the ``act`` of the one after it. None without actors."""
173
+ claim: dict[str, Any] | None = None
174
+ for actor in reversed(actors):
175
+ claim = {"sub": actor} if claim is None else {"sub": actor, "act": claim}
176
+ return claim
177
+
178
+
179
+ def build_claims(
180
+ *,
181
+ sub: str,
182
+ roles: list[str],
183
+ issuer: str,
184
+ audience: str,
185
+ ttl_s: int,
186
+ principal_claim: str = "sub",
187
+ roles_claim: str = "roles",
188
+ now: int | None = None,
189
+ actors: list[str] | None = None,
190
+ azp: str | None = None,
191
+ actor_claim_name: str = "act",
192
+ ) -> dict[str, Any]:
193
+ """The token's claims: principal and roles where the server reads them, plus iss/aud/exp.
194
+
195
+ ``actors`` (current first) become the ``act`` claim (``actor_claim_name``,
196
+ ``AUTH_JWT_ACTOR_CLAIM``) and ``azp`` the authorized party.
197
+ """
198
+ issued = int(time.time()) if now is None else now
199
+ claims: dict[str, Any] = {
200
+ "iss": issuer,
201
+ "aud": audience,
202
+ "iat": issued,
203
+ "nbf": issued,
204
+ "exp": issued + ttl_s,
205
+ "jti": uuid.uuid4().hex,
206
+ }
207
+ _set_claim(claims, principal_claim or "sub", sub)
208
+ _set_claim(claims, roles_claim or "roles", roles)
209
+ act = actor_claim(actors or [])
210
+ if act is not None:
211
+ _set_claim(claims, actor_claim_name or "act", act)
212
+ if azp:
213
+ claims["azp"] = azp
214
+ return claims
215
+
216
+
217
+ def _normalised_pem(value: str) -> str:
218
+ """A PEM as the server reads it (``\\n`` escapes accepted), without whitespace."""
219
+ return "".join(value.replace("\\n", "\n").split())
220
+
221
+
222
+ def env_line_value(pem: str) -> str:
223
+ """``AUTH_JWT_PUBLIC_KEY`` as one ``.env`` line: single-quoted, newlines as ``\\n``."""
224
+ return "'" + pem.strip().replace("\n", "\\n") + "'"
225
+
226
+
227
+ def _refuse(message: str) -> None:
228
+ raise DevTokenError(message)
229
+
230
+
231
+ def _check_setup(env: Any, *, manifest_policy: str) -> None:
232
+ """Refuse anything but a local jwt dev setup (``env`` is the login EnvView)."""
233
+ policy = normalize_auth_policy(env.get("AUTH_POLICY").strip() or manifest_policy, warn=False)
234
+ if policy != "jwt":
235
+ local = {
236
+ "shared-bearer": "Local runs of a shared-bearer project send the API_KEY in .env.",
237
+ "custom": (
238
+ "A custom policy reads what its CustomPolicy checks: pass it with "
239
+ "--header 'Name: value' or --cookie name=value."
240
+ ),
241
+ }.get(policy, "")
242
+ _refuse(
243
+ f"This project's auth policy is {policy} (AUTH_POLICY): dev tokens are for jwt "
244
+ f"projects. {local}".rstrip()
245
+ )
246
+ app_env = env.get("APP_ENV")
247
+ if app_env != "dev":
248
+ shown = repr(app_env) if env.has("APP_ENV") else "unset"
249
+ _refuse(
250
+ f"APP_ENV is {shown}; dev tokens are only for a local server under APP_ENV=dev "
251
+ "(set it in .env, as .env.example does). Deployed environments take tokens from "
252
+ "your identity provider."
253
+ )
254
+ if env.has("AUTH_JWT_JWKS_URL"):
255
+ _refuse(
256
+ f"AUTH_JWT_JWKS_URL is set ({env.where('AUTH_JWT_JWKS_URL')}): the local server "
257
+ "verifies tokens from that issuer, not from a dev key. Get a token from the issuer, "
258
+ "or clear AUTH_JWT_JWKS_URL to use a dev key."
259
+ )
260
+ algorithms = [a.upper() for a in _csv(env.get("AUTH_JWT_ALGORITHMS"))]
261
+ if algorithms and ALGORITHM not in algorithms:
262
+ _refuse(
263
+ f"AUTH_JWT_ALGORITHMS ({', '.join(algorithms)}) does not allow {ALGORITHM}, "
264
+ "which the dev key signs with."
265
+ )
266
+
267
+
268
+ def _sign(root: Path, key_path: Path, claims: dict[str, Any]) -> dict[str, str]:
269
+ """Create the key when absent and sign ``claims`` in the project's environment."""
270
+ from graph_agents_cli._runner import run_resolved
271
+ from graph_agents_cli._tools import ToolNotFoundError
272
+
273
+ payload = {"key_path": str(key_path), "claims": claims, "kid": DEV_KEY_ID}
274
+ payload["algorithm"] = ALGORITHM
275
+ env = dict(os.environ)
276
+ env.pop("VIRTUAL_ENV", None) # the project's own .venv, not the CLI's
277
+ try:
278
+ result = run_resolved(
279
+ ["uv", "run", "--quiet", "python", "-c", _SIGNER],
280
+ cwd=str(root),
281
+ input=json.dumps(payload),
282
+ capture_output=True,
283
+ text=True,
284
+ encoding="utf-8",
285
+ errors="replace",
286
+ timeout=SIGN_TIMEOUT_S,
287
+ env=env,
288
+ )
289
+ except ToolNotFoundError as exc:
290
+ raise SigningError(f"{exc}") from exc
291
+ except (OSError, subprocess.SubprocessError) as exc:
292
+ raise SigningError(f"Could not run the project's Python (uv run): {exc}") from exc
293
+ lines = [line for line in (result.stdout or "").splitlines() if line.strip()]
294
+ try:
295
+ answer = json.loads(lines[-1]) if lines else {}
296
+ except json.JSONDecodeError:
297
+ answer = {}
298
+ if result.returncode != 0 or not isinstance(answer, dict) or not answer:
299
+ detail = (result.stderr or result.stdout or "").strip()[-800:]
300
+ raise SigningError(
301
+ "The project's environment could not sign the token (uv run exited "
302
+ f"{result.returncode}).\n {detail}\n Run `graph-agents-cli install` first."
303
+ )
304
+ if answer.get("error") == "missing":
305
+ raise SigningError(
306
+ f"The project's environment has no PyJWT with crypto support ({answer.get('detail')}). "
307
+ "Run `graph-agents-cli install` (the template depends on pyjwt[crypto])."
308
+ )
309
+ if answer.get("error"):
310
+ raise SigningError(
311
+ f"Could not sign with {key_path}: {answer.get('detail')}. If that file is damaged "
312
+ "(not an RSA private key), delete it to create a new dev key, then clear "
313
+ "AUTH_JWT_PUBLIC_KEY in .env and rerun; tokens signed with the old key stop working."
314
+ )
315
+ return {"token": str(answer["token"]), "public_key": str(answer["public_key"])}
316
+
317
+
318
+ def _private_dir(path: Path) -> None:
319
+ path.mkdir(parents=True, exist_ok=True)
320
+ if os.name != "nt":
321
+ path.chmod(0o700)
322
+
323
+
324
+ @click.group("auth", cls=LazyGroup)
325
+ def auth_group() -> None:
326
+ """Local credentials for the project's auth policy (dev-only JWTs).
327
+
328
+ Nothing here touches a cluster or an identity provider.
329
+ """
330
+
331
+
332
+ @auth_group.command("dev-token")
333
+ @click.option(
334
+ "--sub",
335
+ required=True,
336
+ help="The principal id the token carries (in AUTH_JWT_PRINCIPAL_CLAIM, default sub).",
337
+ )
338
+ @click.option(
339
+ "--roles",
340
+ default="",
341
+ help="Comma list of roles (in AUTH_JWT_ROLES_CLAIM, default roles), e.g. user,support.",
342
+ )
343
+ @click.option(
344
+ "--ttl",
345
+ default=DEFAULT_TTL,
346
+ show_default=True,
347
+ help="Lifetime: seconds, or a number with s, m, h or d (at most 7d).",
348
+ )
349
+ @click.option(
350
+ "--act",
351
+ "actors",
352
+ multiple=True,
353
+ metavar="ID",
354
+ help=(
355
+ "An agent presenting the token for --sub (the RFC 8693 act claim); repeat for a chain, "
356
+ "the current agent first. The server refuses it unless AUTH_ALLOWED_ACTORS lists it."
357
+ ),
358
+ )
359
+ @click.option(
360
+ "--azp",
361
+ default=None,
362
+ metavar="ID",
363
+ help="The token's authorized party (client id), as AUTH_JWT_DIRECT_CLIENTS reads it.",
364
+ )
365
+ def cmd_dev_token(sub: str, roles: str, ttl: str, actors: tuple[str, ...], azp: str | None) -> None:
366
+ """Mint a JWT for local runs of a jwt project (APP_ENV=dev only).
367
+
368
+ Prints the token alone on stdout, so it can go straight into the variable
369
+ `run` and `eval` send as the bearer, without appearing in argv or your
370
+ shell history:
371
+
372
+ \b
373
+ export GRAPH_AGENTS_CLI_API_KEY="$(graph-agents-cli auth dev-token --sub alice --roles user)"
374
+ graph-agents-cli run "hello"
375
+ graph-agents-cli eval run
376
+
377
+ \b
378
+ An agent calling another agent for a user presents a token naming both:
379
+ graph-agents-cli auth dev-token --sub alice --act concierge
380
+ (--act billing --act concierge: billing, called by concierge, for alice).
381
+
382
+ \b
383
+ The first call creates a dev RSA key pair in .graph-agents-cli/dev-jwt/
384
+ (git ignored) and fills blank AUTH_JWT_PUBLIC_KEY, AUTH_JWT_ISSUER and
385
+ AUTH_JWT_AUDIENCE in .env (kept 0600); values .env already sets are used
386
+ as they are. Restart a running local server afterwards
387
+ (`graph-agents-cli run --stop-server`). Refused unless the project's
388
+ policy is jwt, APP_ENV is exactly dev, and .env names no JWKS URL and no
389
+ other public key. Never deploy the dev key.
390
+
391
+ \b
392
+ Exit codes:
393
+ 0 token printed
394
+ 2 the project's environment could not sign (run `graph-agents-cli install`)
395
+ 3 not a jwt project under APP_ENV=dev, or another key or issuer is configured
396
+ """
397
+ from graph_agents_cli.setup.cmd_auth import load_env, write_env
398
+
399
+ ttl_s = parse_ttl(ttl)
400
+ sub = sub.strip()
401
+ if not sub:
402
+ raise click.BadParameter("--sub must not be empty")
403
+ role_list = _csv(roles)
404
+ actor_list = [a.strip() for a in actors]
405
+ for actor in actor_list:
406
+ if not actor or len(actor) > 256 or any(c.isspace() or ord(c) < 32 for c in actor):
407
+ raise click.BadParameter(
408
+ f"{actor[:40]!r}: an agent id of 1-256 characters without whitespace",
409
+ param_hint="--act",
410
+ )
411
+ if azp is not None and (not azp.strip() or any(c.isspace() for c in azp.strip())):
412
+ raise click.BadParameter("a client id without whitespace", param_hint="--azp")
413
+ azp = azp.strip() if azp is not None else None
414
+
415
+ root = find_project_root(Path.cwd())
416
+ if root is None:
417
+ raise DevTokenError(
418
+ "Not inside a graph-agents-cli project (no graph-agents-cli-manifest.yaml here or "
419
+ "above)."
420
+ )
421
+ config = read_project_config(str(root))
422
+ env_file = root / ".env"
423
+ if not env_file.is_file():
424
+ raise DevTokenError(
425
+ f"No .env in {root}: the local server reads its settings from it. Create it with "
426
+ "`cp .env.example .env`, then rerun."
427
+ )
428
+ env = load_env(env_file)
429
+ _check_setup(env, manifest_policy=config.auth_policy)
430
+
431
+ key_dir = root / DEV_KEY_DIR
432
+ _private_dir(key_dir)
433
+ key_path = key_dir / PRIVATE_KEY_FILE
434
+ issuer = env.get("AUTH_JWT_ISSUER").strip() or DEV_ISSUER
435
+ audiences = _csv(env.get("AUTH_JWT_AUDIENCE"))
436
+ audience = audiences[0] if audiences else (config.project_name or root.name)
437
+ claims = build_claims(
438
+ sub=sub,
439
+ roles=role_list,
440
+ issuer=issuer,
441
+ audience=audience,
442
+ ttl_s=ttl_s,
443
+ principal_claim=env.get("AUTH_JWT_PRINCIPAL_CLAIM").strip() or "sub",
444
+ roles_claim=env.get("AUTH_JWT_ROLES_CLAIM").strip() or "roles",
445
+ actors=actor_list,
446
+ azp=azp,
447
+ # Where the server reads the actor (AUTH_JWT_ACTOR_CLAIM, `act` when unset or empty).
448
+ actor_claim_name=env.get("AUTH_JWT_ACTOR_CLAIM").strip() or "act",
449
+ )
450
+ signed = _sign(root, key_path, claims)
451
+ public_pem = signed["public_key"]
452
+ (key_dir / PUBLIC_KEY_FILE).write_text(public_pem, encoding="utf-8")
453
+
454
+ configured = env.get("AUTH_JWT_PUBLIC_KEY").strip()
455
+ if configured and _normalised_pem(configured) != _normalised_pem(public_pem):
456
+ where = env.where("AUTH_JWT_PUBLIC_KEY")
457
+ how = "unset it in your shell" if where == "environment" else f"clear it in {where}"
458
+ raise DevTokenError(
459
+ f"AUTH_JWT_PUBLIC_KEY ({where}) is not the dev key in {DEV_KEY_DIR}/, so the local "
460
+ f"server would refuse a dev token. To use the dev key, {how} and rerun."
461
+ )
462
+
463
+ wanted = {
464
+ "AUTH_JWT_PUBLIC_KEY": env_line_value(public_pem),
465
+ "AUTH_JWT_ISSUER": issuer,
466
+ "AUTH_JWT_AUDIENCE": audience,
467
+ }
468
+ written = [name for name in wanted if not env.has(name)]
469
+ write_env(env_file, {name: wanted[name] for name in written})
470
+ if not written and os.name != "nt" and env_file.exists():
471
+ env_file.chmod(0o600) # write_env keeps it 0600 when it writes
472
+
473
+ err = click.get_text_stream("stderr")
474
+ roles_text = ", ".join(role_list) if role_list else "none"
475
+ via = f", presented by {' <- '.join(actor_list)}" if actor_list else ""
476
+ click.echo(
477
+ f"Dev token for {sub} (roles: {roles_text}{via}), valid {ttl.strip()}, accepted only by "
478
+ "a server with this project's dev key.",
479
+ file=err,
480
+ )
481
+ actor_claim_off = "AUTH_JWT_ACTOR_CLAIM" in env.values and not env.has("AUTH_JWT_ACTOR_CLAIM")
482
+ if actor_list and actor_claim_off:
483
+ click.echo(
484
+ "AUTH_JWT_ACTOR_CLAIM is empty in .env: the server reads this token as the user's "
485
+ "own, not as an agent's.",
486
+ file=err,
487
+ )
488
+ if written:
489
+ click.echo(
490
+ f"Wrote {', '.join(written)} to {env_file} (the private key stays in "
491
+ f"{DEV_KEY_DIR / PRIVATE_KEY_FILE}).",
492
+ file=err,
493
+ )
494
+ from graph_agents_cli.run._local_server import get_server_port
495
+
496
+ if get_server_port(root) is not None:
497
+ click.echo(
498
+ "A local server is running with the old settings: restart it with "
499
+ "`graph-agents-cli run --stop-server`.",
500
+ file=err,
501
+ )
502
+ role_flag = f" --roles {shlex.quote(','.join(role_list))}" if role_list else ""
503
+ role_flag += "".join(f" --act {shlex.quote(a)}" for a in actor_list)
504
+ role_flag += f" --azp {shlex.quote(azp)}" if azp else ""
505
+ command = f"graph-agents-cli auth dev-token --sub {shlex.quote(sub)}{role_flag}"
506
+ click.echo(
507
+ "Keep the token out of argv and shell history: put it in the variable run and eval send,\n"
508
+ f' export {API_KEY_ENV}="$({command})"\n'
509
+ "Never deploy the dev key: deployed environments verify tokens from your identity "
510
+ "provider (AUTH_JWT_JWKS_URL in the chart values).",
511
+ file=err,
512
+ )
513
+ click.echo(signed["token"])