failproofai 1.0.1 → 1.0.2-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (389) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +6 -6
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page.js +2 -2
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  12. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page.js +2 -2
  16. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  20. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  21. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
  22. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  23. package/.next/standalone/.next/server/app/api/audit/invite/route.js +3 -2
  24. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/audit/run/route.js +5 -4
  26. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -2
  29. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +4 -3
  31. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/auth/logout/route.js +4 -4
  33. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/auth/status/route.js +4 -4
  35. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  38. package/.next/standalone/.next/server/app/audit/page.js +2 -2
  39. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  41. package/.next/standalone/.next/server/app/index.html +1 -1
  42. package/.next/standalone/.next/server/app/index.rsc +15 -15
  43. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
  44. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  45. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  46. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  47. package/.next/standalone/.next/server/app/page.js +2 -2
  48. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  49. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  50. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +66 -22
  51. package/.next/standalone/.next/server/app/policies/page.js +5 -4
  52. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  54. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  55. package/.next/standalone/.next/server/app/project/[name]/page.js +2 -2
  56. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  58. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  59. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  60. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +2 -2
  61. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  63. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  64. package/.next/standalone/.next/server/app/projects/page.js +2 -2
  65. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
  68. package/.next/standalone/.next/server/app/settings/page.js +1 -1
  69. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/chunks/{[externals]__1qzqcio._.js → [externals]__0e32-7c._.js} +1 -1
  72. package/.next/standalone/.next/server/chunks/[externals]__1s462yl._.js +3 -0
  73. package/.next/standalone/.next/server/chunks/[root-of-the-server]__01eqny5._.js +3 -0
  74. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
  75. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p8poxd._.js → [root-of-the-server]__0igxt32._.js} +2 -2
  76. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0neqlu-._.js +3 -0
  77. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +3 -0
  78. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t9oqnn._.js +3 -0
  79. package/.next/standalone/.next/server/chunks/_0bs-v8p._.js +3 -0
  80. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +3 -0
  81. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +3 -0
  82. package/.next/standalone/.next/server/chunks/_185gyk9._.js +3 -0
  83. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +5 -6
  84. package/.next/standalone/.next/server/chunks/lib_telemetry-id_ts_1k8gj9o._.js +3 -0
  85. package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_09d5c79._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_04op_ou._.js} +1 -1
  86. package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_1d2g73o._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_0dr20uz._.js} +1 -1
  87. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/src_hooks_0xbw3bu._.js +12 -0
  89. package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn._.js +1 -1
  90. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +4 -0
  91. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +4 -0
  92. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +4 -0
  93. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0spkm68._.js → [root-of-the-server]__07gm3zl._.js} +21 -20
  94. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +4 -0
  95. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +4 -0
  96. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
  97. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +4 -0
  98. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +6 -0
  99. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__07tbbf3._.js → [root-of-the-server]__0zig5sv._.js} +2 -2
  100. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__192nhvh._.js +5 -0
  101. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +4 -0
  102. package/.next/standalone/.next/server/chunks/ssr/{_0lvyuv4._.js → _00e9tnf._.js} +2 -2
  103. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  104. package/.next/standalone/.next/server/chunks/ssr/{_0u5zauv._.js → _12l4a_k._.js} +1 -1
  105. package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +1 -1
  106. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  107. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +13 -13
  108. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  109. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  110. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
  111. package/.next/standalone/.next/server/chunks/ssr/src_hooks_08o7bqo._.js +10 -0
  112. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
  113. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
  114. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  115. package/.next/standalone/.next/server/middleware.js +1 -1
  116. package/.next/standalone/.next/server/pages/404.html +1 -1
  117. package/.next/standalone/.next/server/pages/500.html +1 -1
  118. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  119. package/.next/standalone/.next/server/server-reference-manifest.json +71 -27
  120. package/.next/standalone/.next/static/chunks/{37fcpc36x9gpe.js → 0eqky-7n7dgdm.js} +1 -1
  121. package/.next/standalone/.next/static/chunks/{1ide1wl2f7zi1.js → 0sa9v5mhc8861.js} +13 -13
  122. package/.next/standalone/.next/static/chunks/1mfzsja6ftim5.css +2 -0
  123. package/.next/standalone/.next/static/chunks/{3k7mxbp9hiom0.js → 1nuqytbta44af.js} +1 -1
  124. package/.next/standalone/.next/static/chunks/1sl2xmn9inx3y.js +6 -0
  125. package/.next/standalone/.next/static/chunks/{2_2lhuojq2xop.js → 2aawsjld9ied_.js} +1 -1
  126. package/.next/standalone/.next/static/chunks/2gn7ut4svofm2.js +1 -0
  127. package/.next/standalone/.next/static/chunks/{31s1smp-g7gks.js → 2hs7ycvsav7v2.js} +1 -1
  128. package/.next/standalone/.next/static/chunks/{0k5050ezjvv49.js → 2i2yt3hzjredm.js} +1 -1
  129. package/.next/standalone/.next/static/chunks/{3c808qrfcq0im.js → 35xg6retpe6rp.js} +1 -1
  130. package/.next/standalone/.next/static/chunks/{2zpp1we2jv6tb.js → 3y54nw0i7dsjl.js} +1 -1
  131. package/.next/standalone/SECURITY.md +5 -4
  132. package/.next/standalone/app/actions/get-hooks-config.ts +108 -17
  133. package/.next/standalone/app/actions/pack-actions.ts +153 -0
  134. package/.next/standalone/app/audit/_components/run-progress.tsx +1 -1
  135. package/.next/standalone/app/audit/_components/share-templates.ts +13 -13
  136. package/.next/standalone/app/policies/hooks-client.tsx +320 -14
  137. package/.next/standalone/components/navbar.tsx +2 -28
  138. package/.next/standalone/components/reach-developers.tsx +8 -1
  139. package/.next/standalone/docs-old/agenteye/python-sdk-skill.mdx +1 -1
  140. package/.next/standalone/docs-old/agenteye/python-sdk.mdx +59 -35
  141. package/.next/standalone/docs-old/i18n/README.ar.md +1 -0
  142. package/.next/standalone/docs-old/i18n/README.de.md +1 -0
  143. package/.next/standalone/docs-old/i18n/README.es.md +1 -0
  144. package/.next/standalone/docs-old/i18n/README.fr.md +1 -0
  145. package/.next/standalone/docs-old/i18n/README.he.md +1 -0
  146. package/.next/standalone/docs-old/i18n/README.hi.md +1 -0
  147. package/.next/standalone/docs-old/i18n/README.it.md +1 -0
  148. package/.next/standalone/docs-old/i18n/README.ja.md +1 -0
  149. package/.next/standalone/docs-old/i18n/README.ko.md +1 -0
  150. package/.next/standalone/docs-old/i18n/README.pt-br.md +1 -0
  151. package/.next/standalone/docs-old/i18n/README.ru.md +1 -0
  152. package/.next/standalone/docs-old/i18n/README.tr.md +1 -0
  153. package/.next/standalone/docs-old/i18n/README.vi.md +1 -0
  154. package/.next/standalone/docs-old/i18n/README.zh.md +1 -0
  155. package/.next/standalone/fp-cloud-cli/CHANGELOG.md +431 -0
  156. package/.next/standalone/fp-cloud-cli/LICENSE +42 -0
  157. package/.next/standalone/fp-cloud-cli/MANIFEST.in +10 -0
  158. package/.next/standalone/fp-cloud-cli/README.md +259 -0
  159. package/.next/standalone/fp-cloud-cli/fp_cli/__init__.py +10 -0
  160. package/.next/standalone/fp-cloud-cli/fp_cli/__main__.py +4 -0
  161. package/.next/standalone/fp-cloud-cli/fp_cli/_click_compat.py +64 -0
  162. package/.next/standalone/fp-cloud-cli/fp_cli/_context.py +332 -0
  163. package/.next/standalone/fp-cloud-cli/fp_cli/_version.py +1 -0
  164. package/.next/standalone/fp-cloud-cli/fp_cli/analytics.py +432 -0
  165. package/.next/standalone/fp-cloud-cli/fp_cli/analytics_config.py +77 -0
  166. package/.next/standalone/fp-cloud-cli/fp_cli/analytics_registry.py +83 -0
  167. package/.next/standalone/fp-cloud-cli/fp_cli/app.py +492 -0
  168. package/.next/standalone/fp-cloud-cli/fp_cli/auth.py +160 -0
  169. package/.next/standalone/fp-cloud-cli/fp_cli/client.py +1694 -0
  170. package/.next/standalone/fp-cloud-cli/fp_cli/commands/__init__.py +0 -0
  171. package/.next/standalone/fp-cloud-cli/fp_cli/commands/_write.py +214 -0
  172. package/.next/standalone/fp-cloud-cli/fp_cli/commands/agent_cmds.py +407 -0
  173. package/.next/standalone/fp-cloud-cli/fp_cli/commands/alerts_cmds.py +445 -0
  174. package/.next/standalone/fp-cloud-cli/fp_cli/commands/audits_cmds.py +1054 -0
  175. package/.next/standalone/fp-cloud-cli/fp_cli/commands/auth_cmds.py +512 -0
  176. package/.next/standalone/fp-cloud-cli/fp_cli/commands/errors_cmds.py +190 -0
  177. package/.next/standalone/fp-cloud-cli/fp_cli/commands/evals_cmds.py +161 -0
  178. package/.next/standalone/fp-cloud-cli/fp_cli/commands/events_cmds.py +159 -0
  179. package/.next/standalone/fp-cloud-cli/fp_cli/commands/fleet_cmds.py +416 -0
  180. package/.next/standalone/fp-cloud-cli/fp_cli/commands/guardrails_cmds.py +148 -0
  181. package/.next/standalone/fp-cloud-cli/fp_cli/commands/incidents_cmds.py +472 -0
  182. package/.next/standalone/fp-cloud-cli/fp_cli/commands/keys_cmds.py +407 -0
  183. package/.next/standalone/fp-cloud-cli/fp_cli/commands/list_cmds.py +63 -0
  184. package/.next/standalone/fp-cloud-cli/fp_cli/commands/orgs_cmds.py +319 -0
  185. package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +499 -0
  186. package/.next/standalone/fp-cloud-cli/fp_cli/commands/queries_cmds.py +378 -0
  187. package/.next/standalone/fp-cloud-cli/fp_cli/commands/sessions_cmds.py +151 -0
  188. package/.next/standalone/fp-cloud-cli/fp_cli/commands/settings_cmds.py +150 -0
  189. package/.next/standalone/fp-cloud-cli/fp_cli/commands/usage_cmds.py +35 -0
  190. package/.next/standalone/fp-cloud-cli/fp_cli/commands/users_cmds.py +404 -0
  191. package/.next/standalone/fp-cloud-cli/fp_cli/config.py +330 -0
  192. package/.next/standalone/fp-cloud-cli/fp_cli/dates.py +78 -0
  193. package/.next/standalone/fp-cloud-cli/fp_cli/enforcement.py +345 -0
  194. package/.next/standalone/fp-cloud-cli/fp_cli/errors.py +98 -0
  195. package/.next/standalone/fp-cloud-cli/fp_cli/models.py +891 -0
  196. package/.next/standalone/fp-cloud-cli/fp_cli/orgs.py +30 -0
  197. package/.next/standalone/fp-cloud-cli/fp_cli/output.py +6593 -0
  198. package/.next/standalone/fp-cloud-cli/fp_cli/permissions.py +208 -0
  199. package/.next/standalone/fp-cloud-cli/fp_cli/policy_check.py +290 -0
  200. package/.next/standalone/fp-cloud-cli/fp_cli/py.typed +0 -0
  201. package/.next/standalone/fp-cloud-cli/fp_cli/select.py +322 -0
  202. package/.next/standalone/fp-cloud-cli/fp_cli/theme.py +53 -0
  203. package/.next/standalone/fp-cloud-cli/pyproject.toml +106 -0
  204. package/.next/standalone/fp-cloud-cli/skill/SKILL.md +302 -0
  205. package/.next/standalone/fp-cloud-cli/skill/agents/openai.yaml +8 -0
  206. package/.next/standalone/fp-cloud-cli/skill/references/commands.md +254 -0
  207. package/.next/standalone/fp-cloud-cli/tests/__init__.py +0 -0
  208. package/.next/standalone/fp-cloud-cli/tests/conftest.py +92 -0
  209. package/.next/standalone/fp-cloud-cli/tests/test_alerting.py +644 -0
  210. package/.next/standalone/fp-cloud-cli/tests/test_analytics.py +385 -0
  211. package/.next/standalone/fp-cloud-cli/tests/test_audits.py +950 -0
  212. package/.next/standalone/fp-cloud-cli/tests/test_auth.py +98 -0
  213. package/.next/standalone/fp-cloud-cli/tests/test_auth_mode.py +272 -0
  214. package/.next/standalone/fp-cloud-cli/tests/test_click_compat.py +118 -0
  215. package/.next/standalone/fp-cloud-cli/tests/test_client.py +299 -0
  216. package/.next/standalone/fp-cloud-cli/tests/test_commands.py +814 -0
  217. package/.next/standalone/fp-cloud-cli/tests/test_config.py +99 -0
  218. package/.next/standalone/fp-cloud-cli/tests/test_dashboards_agent.py +340 -0
  219. package/.next/standalone/fp-cloud-cli/tests/test_dates.py +76 -0
  220. package/.next/standalone/fp-cloud-cli/tests/test_enforcement_logic.py +481 -0
  221. package/.next/standalone/fp-cloud-cli/tests/test_facets.py +170 -0
  222. package/.next/standalone/fp-cloud-cli/tests/test_failproofai_home.py +722 -0
  223. package/.next/standalone/fp-cloud-cli/tests/test_fp_home_contract.py +198 -0
  224. package/.next/standalone/fp-cloud-cli/tests/test_hardening.py +186 -0
  225. package/.next/standalone/fp-cloud-cli/tests/test_help_table_coverage.py +127 -0
  226. package/.next/standalone/fp-cloud-cli/tests/test_keys_queries.py +496 -0
  227. package/.next/standalone/fp-cloud-cli/tests/test_list.py +59 -0
  228. package/.next/standalone/fp-cloud-cli/tests/test_multivalue.py +183 -0
  229. package/.next/standalone/fp-cloud-cli/tests/test_no_customer_identifiers.py +168 -0
  230. package/.next/standalone/fp-cloud-cli/tests/test_operator.py +492 -0
  231. package/.next/standalone/fp-cloud-cli/tests/test_orgs.py +692 -0
  232. package/.next/standalone/fp-cloud-cli/tests/test_output.py +1732 -0
  233. package/.next/standalone/fp-cloud-cli/tests/test_policy_check.py +191 -0
  234. package/.next/standalone/fp-cloud-cli/tests/test_readme_matches_reality.py +125 -0
  235. package/.next/standalone/fp-cloud-cli/tests/test_review_fixes.py +161 -0
  236. package/.next/standalone/fp-cloud-cli/tests/test_telemetry_completeness.py +90 -0
  237. package/.next/standalone/fp-cloud-cli/tests/test_usage.py +115 -0
  238. package/.next/standalone/fp-cloud-cli/tests/test_v1_origin_diagnostic.py +70 -0
  239. package/.next/standalone/fp-cloud-cli/tests/test_v1_routing.py +214 -0
  240. package/.next/standalone/fp-cloud-cli/tests/test_whoami.py +104 -0
  241. package/.next/standalone/fp-cloud-cli/uv.lock +552 -0
  242. package/.next/standalone/package.json +29 -22
  243. package/.next/standalone/sdk/python/CHANGELOG.md +70 -0
  244. package/.next/standalone/sdk/python/LICENSE +42 -0
  245. package/.next/standalone/sdk/python/MANIFEST.in +21 -0
  246. package/.next/standalone/sdk/python/README.md +466 -0
  247. package/.next/standalone/sdk/python/docs/README.md +249 -0
  248. package/.next/standalone/sdk/python/docs/_shared/README.md +43 -0
  249. package/.next/standalone/sdk/python/docs/_shared/__init__.py +195 -0
  250. package/.next/standalone/sdk/python/docs/crewai/README.md +328 -0
  251. package/.next/standalone/sdk/python/docs/crewai/examples/quickstart.py +61 -0
  252. package/.next/standalone/sdk/python/docs/crewai/examples/research_crew.py +92 -0
  253. package/.next/standalone/sdk/python/docs/langgraph/README.md +481 -0
  254. package/.next/standalone/sdk/python/docs/langgraph/examples/quickstart.py +51 -0
  255. package/.next/standalone/sdk/python/docs/langgraph/examples/research_agent.py +86 -0
  256. package/.next/standalone/sdk/python/docs/langgraph/examples/supervisor_handoff.py +83 -0
  257. package/.next/standalone/sdk/python/docs/llama_index/README.md +332 -0
  258. package/.next/standalone/sdk/python/docs/llama_index/examples/quickstart.py +62 -0
  259. package/.next/standalone/sdk/python/docs/llama_index/examples/research_agent.py +93 -0
  260. package/.next/standalone/sdk/python/docs/manual/README.md +491 -0
  261. package/.next/standalone/sdk/python/docs/manual/examples/quickstart.py +57 -0
  262. package/.next/standalone/sdk/python/docs/manual/examples/research_agent.py +133 -0
  263. package/.next/standalone/sdk/python/docs/pydantic_ai/README.md +323 -0
  264. package/.next/standalone/sdk/python/docs/pydantic_ai/examples/quickstart.py +48 -0
  265. package/.next/standalone/sdk/python/docs/pydantic_ai/examples/research_agent.py +94 -0
  266. package/.next/standalone/sdk/python/failproofai_sdk/__init__.py +131 -0
  267. package/.next/standalone/sdk/python/failproofai_sdk/_context.py +218 -0
  268. package/.next/standalone/sdk/python/failproofai_sdk/_environment.py +78 -0
  269. package/.next/standalone/sdk/python/failproofai_sdk/_events.py +752 -0
  270. package/.next/standalone/sdk/python/failproofai_sdk/_resolver.py +118 -0
  271. package/.next/standalone/sdk/python/failproofai_sdk/_runtime.py +21 -0
  272. package/.next/standalone/sdk/python/failproofai_sdk/_schema.py +317 -0
  273. package/.next/standalone/sdk/python/failproofai_sdk/_scopes.py +422 -0
  274. package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -0
  275. package/.next/standalone/sdk/python/failproofai_sdk/_writer.py +750 -0
  276. package/.next/standalone/sdk/python/failproofai_sdk/integrations/__init__.py +274 -0
  277. package/.next/standalone/sdk/python/failproofai_sdk/integrations/_compat.py +247 -0
  278. package/.next/standalone/sdk/python/failproofai_sdk/integrations/_core.py +1076 -0
  279. package/.next/standalone/sdk/python/failproofai_sdk/integrations/crewai.py +1669 -0
  280. package/.next/standalone/sdk/python/failproofai_sdk/integrations/langchain.py +2151 -0
  281. package/.next/standalone/sdk/python/failproofai_sdk/integrations/llama_index.py +1588 -0
  282. package/.next/standalone/sdk/python/failproofai_sdk/integrations/pydantic_ai.py +977 -0
  283. package/.next/standalone/sdk/python/failproofai_sdk/py.typed +0 -0
  284. package/.next/standalone/sdk/python/pyproject.toml +92 -0
  285. package/.next/standalone/sdk/python/skill/SKILL.md +399 -0
  286. package/.next/standalone/sdk/python/skill/agents/openai.yaml +8 -0
  287. package/.next/standalone/sdk/python/skill/references/events.md +234 -0
  288. package/.next/standalone/sdk/python/skill/references/frameworks.md +314 -0
  289. package/.next/standalone/sdk/python/skill/references/install.md +100 -0
  290. package/.next/standalone/sdk/python/skill/references/integration.md +352 -0
  291. package/.next/standalone/sdk/python/tests/__init__.py +0 -0
  292. package/.next/standalone/sdk/python/tests/conftest.py +169 -0
  293. package/.next/standalone/sdk/python/tests/integrations/__init__.py +6 -0
  294. package/.next/standalone/sdk/python/tests/integrations/test_crewai.py +1299 -0
  295. package/.next/standalone/sdk/python/tests/integrations/test_langchain.py +2338 -0
  296. package/.next/standalone/sdk/python/tests/integrations/test_llama_index.py +1576 -0
  297. package/.next/standalone/sdk/python/tests/integrations/test_pydantic_ai.py +1102 -0
  298. package/.next/standalone/sdk/python/tests/test_context.py +410 -0
  299. package/.next/standalone/sdk/python/tests/test_docs.py +411 -0
  300. package/.next/standalone/sdk/python/tests/test_durability.py +1352 -0
  301. package/.next/standalone/sdk/python/tests/test_encoding.py +571 -0
  302. package/.next/standalone/sdk/python/tests/test_integrations.py +1127 -0
  303. package/.next/standalone/sdk/python/tests/test_no_customer_identifiers.py +214 -0
  304. package/.next/standalone/sdk/python/tests/test_packaging.py +185 -0
  305. package/.next/standalone/sdk/python/tests/test_resolver_umbrella.py +178 -0
  306. package/.next/standalone/sdk/python/tests/test_scopes.py +487 -0
  307. package/.next/standalone/sdk/python/tests/test_sdk.py +923 -0
  308. package/.next/standalone/sdk/python/tests/test_server_contract.py +650 -0
  309. package/.next/standalone/sdk/python/tests/test_site_docs.py +371 -0
  310. package/.next/standalone/sdk/python/tests/test_skill_snippets.py +165 -0
  311. package/.next/standalone/sdk/python/tests/test_spool_contract.py +287 -0
  312. package/.next/standalone/sdk/python/tests/test_spool_creation.py +360 -0
  313. package/.next/standalone/sdk/python/tests/test_wire_format.py +279 -0
  314. package/.next/standalone/sdk/python/tests/test_zero_dependencies.py +378 -0
  315. package/.next/standalone/sdk/python/uv.lock +6005 -0
  316. package/.next/standalone/server.js +1 -1
  317. package/README.md +77 -21
  318. package/bin/failproofai.mjs +145 -11
  319. package/dist/cli.mjs +4482 -2205
  320. package/dist/index.js +5 -5
  321. package/dist/worker.mjs +2399 -1978
  322. package/package.json +29 -22
  323. package/policy-pack/SHA256SUMS +2 -0
  324. package/policy-pack/failproofai-pack.json +732 -0
  325. package/policy-pack/failproofai-pack.mjs +2017 -0
  326. package/scripts/build-policy-pack.mjs +121 -0
  327. package/scripts/changelog-section.py +77 -0
  328. package/scripts/prune-standalone.mjs +3 -0
  329. package/scripts/python-version.py +232 -0
  330. package/scripts/translate-docs/cli.ts +21 -0
  331. package/scripts/translate-docs/mintlify-nav.ts +85 -13
  332. package/scripts/translate-docs/translator.ts +66 -11
  333. package/src/audit/cache.ts +40 -3
  334. package/src/audit/cli.ts +1 -1
  335. package/src/audit/index.ts +1 -1
  336. package/src/audit/replay.ts +89 -3
  337. package/src/audit/report.ts +5 -5
  338. package/src/audit/schedule-cli.ts +49 -53
  339. package/src/hooks/builtin-policies.ts +217 -579
  340. package/src/hooks/cloud-enrollment-cli.ts +66 -27
  341. package/src/hooks/cloud-managed-policies.ts +6 -1
  342. package/src/hooks/configure-wizard.ts +1 -1
  343. package/src/hooks/custom-hooks-loader.ts +89 -6
  344. package/src/hooks/fp-home.ts +92 -4
  345. package/src/hooks/fp-reset.ts +26 -2
  346. package/src/hooks/handler.ts +181 -11
  347. package/src/hooks/harness-cli.ts +79 -25
  348. package/src/hooks/hook-activity-store.ts +13 -3
  349. package/src/hooks/install-prompt.ts +25 -3
  350. package/src/hooks/manager.ts +418 -172
  351. package/src/hooks/migrations.ts +2 -2
  352. package/src/hooks/pack-cli.ts +505 -0
  353. package/src/hooks/pack-failclosed.ts +189 -0
  354. package/src/hooks/pack-manifest.ts +344 -0
  355. package/src/hooks/pack-store.ts +930 -0
  356. package/src/hooks/policy-catalog.ts +535 -0
  357. package/src/hooks/policy-evaluator.ts +24 -16
  358. package/src/hooks/policy-presets.ts +4 -2
  359. package/src/hooks/policy-registry.ts +8 -2
  360. package/src/hooks/policy-types.ts +26 -0
  361. package/src/hooks/session-pause-cli.ts +33 -9
  362. package/src/hooks/tui.ts +570 -0
  363. package/src/hooks/types.ts +15 -1
  364. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_usx0j._.js +0 -3
  365. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_zk340._.js +0 -3
  366. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0agdw2a._.js +0 -3
  367. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d1u_na._.js +0 -3
  368. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0oy4kxb._.js +0 -3
  369. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zf034w._.js +0 -3
  370. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +0 -3
  371. package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +0 -3
  372. package/.next/standalone/.next/server/chunks/_1ger0a2._.js +0 -3
  373. package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +0 -3
  374. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_1iiwm5e._.js +0 -3
  375. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kc8_v5._.js +0 -4
  376. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kgy9da._.js +0 -4
  377. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0mhqk5a._.js +0 -4
  378. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pltpn8._.js +0 -4
  379. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qkcyf-._.js +0 -4
  380. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w0x_ok._.js +0 -4
  381. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_dfocn._.js +0 -4
  382. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1bfex62._.js +0 -5
  383. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1kzapg5._.js +0 -6
  384. package/.next/standalone/.next/static/chunks/36fw6yk1s6x_f.js +0 -1
  385. package/.next/standalone/.next/static/chunks/3tzq0260n17ae.js +0 -6
  386. package/.next/standalone/.next/static/chunks/3wq9x0c-7ld5d.css +0 -2
  387. /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_buildManifest.js +0 -0
  388. /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_clientMiddlewareManifest.js +0 -0
  389. /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_ssgManifest.js +0 -0
@@ -0,0 +1,234 @@
1
+ # Event catalog
2
+
3
+ Every method lives on `failproofai_sdk.event`, is **keyword-only**, and returns `None`.
4
+ Nothing here blocks or does I/O — the call queues the event and returns.
5
+
6
+ `session_id` and `agent_id` are optional on all fifteen: omit them and they come
7
+ from the enclosing `failproofai_sdk.session()` / `failproofai_sdk.agent()` scope. Pass them and
8
+ your value wins. Omit `session_id` with nothing bound and you get a `TypeError`
9
+ naming the fix; `agent_id` falls back to `"main"` and never raises. See
10
+ `integration.md`.
11
+
12
+ Emit only what fits the agent. There is no requirement to use every type, and no
13
+ penalty for skipping one — except `agent_start`, without which the session does
14
+ not exist at all.
15
+
16
+ ## The 15 events
17
+
18
+ Columns: **Required** is beyond `session_id` + `agent_id`, which every event
19
+ carries and which you rarely pass by hand.
20
+ *Optional fields are omitted from the record entirely when left unset* — they are
21
+ not written as `null`.
22
+
23
+ | Method | Required | Optional | Notes |
24
+ |---|---|---|---|
25
+ | `agent_start` | — | `goal`, `parent_id` | **Creates the session.** `parent_id` is the **`agent_id` of the parent agent** — not a session id, not a run id. Pass a session id here and you get no nesting, silently. |
26
+ | `agent_end` | — | `outcome`, `summary` | `outcome` must be `failed`/`error`/`timeout`/`rejected` to count as a failure. |
27
+ | `agent_pause` | `pause_id` | `reason`, `user_id` | Suspends the agent (waiting for a human, throttled, user-paused) **without ending it**. Starts the paused clock for this `pause_id`. |
28
+ | `agent_resume` | `pause_id` | `reason`, `user_id` | Emit **instead of a second `agent_start`** when a paused agent continues. `duration_ms` auto-computed — how long it was paused. |
29
+ | `tool_use` | `tool_name`, `tool_call_id` | `input` | Starts the duration clock for this `tool_call_id`. |
30
+ | `tool_result` | `tool_name`, `tool_call_id` | `output`, `error` | `duration_ms` auto-computed from the matching `tool_use`. |
31
+ | `model_request` | — | `model`, `messages`, `system`, `tools`, `request_id` | `request_id` is what pairs this with its response. |
32
+ | `model_response` | — | `model`, `stop_reason`, `input_tokens`, `output_tokens`, `content`, `role`, `request_id`, `error` | Token counts drive spend reporting. `error` marks a failed call — a 429 or a timeout — without a separate `error` event. |
33
+ | `error` | `error_type`, `message` | `traceback` | Always counts as an error, whatever else is set. |
34
+ | `hook_triggered` | `hook_name`, `hook_id` | `trigger_event`, `input` | Starts the clock for this `hook_id`. |
35
+ | `hook_completed` | `hook_name`, `hook_id` | `outcome`, `output`, `error` | `duration_ms` auto-computed. Same `outcome` rule as `agent_end`. |
36
+ | `human_wait` | `input_id` | `prompt`, `options`, `reason` | Starts the clock for this `input_id`. |
37
+ | `human_input` | `input_id` | `response` | `duration_ms` auto-computed — how long the human took. |
38
+ | `human_pause` | — | `reason`, `user_id` | |
39
+ | `human_interrupt` | — | `reason`, `user_id`, `at_step` | |
40
+
41
+ ## Rules that apply to every event
42
+
43
+ **Payloads should be structured JSON where possible.** Serialization happens on
44
+ a background thread. Unsupported leaves such as `datetime`, `UUID`, `Decimal`,
45
+ `set`, `bytes`, or a Pydantic model are stringified automatically rather than
46
+ stopping the writer. If downstream analysis needs more than that string form,
47
+ serialize the value explicitly into a stable JSON object at the integration
48
+ boundary.
49
+
50
+ **Custom fields are free, and their *names* are unvalidated:**
51
+
52
+ ```python
53
+ failproofai_sdk.event.tool_use(
54
+ session_id=sid, agent_id="planner",
55
+ tool_name="web_search", tool_call_id="toolu_01",
56
+ input={"query": "..."},
57
+ tenant="acme", retry_count=2, # yours, kept verbatim
58
+ )
59
+ ```
60
+
61
+ A misspelled **optional** name is not an error — it is a new field. `inpt={...}`
62
+ is accepted, stored, and invisible; nothing will tell you. When something is
63
+ missing from a surface, suspect a typo before suspecting the platform.
64
+
65
+ A misspelled **required** name is a plain `TypeError` — `tool_name` and friends
66
+ are real parameters, so `tool_nmae="search"` fails loudly at the call site. Only
67
+ the optional names are silent.
68
+
69
+ **Five names are reserved and raise `ValueError`.** `timestamp`, `session_id`,
70
+ `agent_id`, `type`, `environment` — passing any as a custom field. (`session_id`
71
+ and `agent_id` are already named args, so Python raises `TypeError` first.)
72
+
73
+ **`duration_ms` is yours to pass on eleven of the fifteen.** It is computed for you
74
+ on `tool_result`, `hook_completed`, `human_input`, and `agent_resume`, and passing
75
+ it to *those four* raises `ValueError`. On the other eleven there is no guard:
76
+ `agent_end(..., duration_ms=5)` is accepted and stored as an ordinary custom field. Don't.
77
+
78
+ The one place you *should* pass it is **`model_response`**, where nothing computes
79
+ it for you. Time the call yourself and pass whole milliseconds as an **`int`** —
80
+ `round(seconds * 1000)`. A float raises `ValueError` at the call site, naming the
81
+ argument: the server reads this as an unsigned 32-bit integer and would store NULL
82
+ for anything else, so the SDK refuses it rather than letting the duration vanish.
83
+ The same guard covers `input_tokens` and `output_tokens`.
84
+
85
+ **Set `request_id` on both model events.** The same value on the `model_request`
86
+ and its `model_response` — a `uuid4().hex`, or the provider's own request id if it
87
+ gives you one, so your events line up with your provider logs. It links the pair
88
+ in the event detail view.
89
+
90
+ It does **not** yet drive the timeline rail or the model latency reports: those
91
+ still match concurrent LLM calls (a parallel fan-out, a sub-agent, a retry racing
92
+ its original) oldest-first, and will keep bracketing the wrong pairs. **Always
93
+ pass `duration_ms` on the `model_response` too** — that is what keeps the reported
94
+ duration right even when the bracketing is wrong.
95
+
96
+ **Correlation is a process-wide map keyed by your ids.** The SDK holds open
97
+ starts there until their matching end arrives. Consequences, in order of how much
98
+ they hurt:
99
+
100
+ - **Per-run counters are unsafe.** `call_1`, `call_2` — common in home-grown loops
101
+ — collide across overlapping runs. The failure is not the missing duration the
102
+ docs might lead you to expect; it is a *plausible wrong number attributed to the
103
+ wrong run*, which is worse. Reuse your framework's id (Anthropic and OpenAI
104
+ tool-call ids are globally unique), or a `uuid4`. `failproofai_sdk.tool_call()`
105
+ generates a `uuid4` for you.
106
+ - **`tool_call_id` and `hook_id` no longer collide with each other.** They live in
107
+ separate namespaces, so a `hook_completed(hook_id="x")` cannot pair with a
108
+ pending `tool_use(tool_call_id="x")`. The key is `<kind>:<session_id>:<id>`, so
109
+ each id only has to be unique *within one session, for one kind* — two sessions
110
+ reusing `call_1` measure independently. Reuse it twice in the SAME session and
111
+ the second `tool_use` overwrites the first pending entry, so the first
112
+ `tool_result` measures from the wrong start. (If you have read
113
+ older guidance saying one shared id space, that was true and is not any more —
114
+ the ids are namespaced by the SDK, so nothing on your side changes.)
115
+ - **`input_id` and `pause_id` are scoped per session/agent**, so
116
+ `human_wait`/`human_input` and `agent_pause`/`agent_resume` cannot collide
117
+ across runs at all.
118
+ - **The pair must happen in the same process.** A `tool_use` in one worker and a
119
+ `tool_result` in another produces two unpaired events and no duration. The same
120
+ goes for a human pause that resumes in a different process.
121
+ - **The map is capped at 10,000 and evicts oldest-first**, so a long-running
122
+ process that leaks orphaned starts can silently lose the duration on legitimate
123
+ later pairs.
124
+
125
+ **Timestamps are set by the SDK** at the moment you call the method — UTC,
126
+ microsecond precision, `Z`-suffixed (`2026-07-17T09:15:22.123456Z`). You cannot
127
+ override it (`timestamp` is reserved).
128
+
129
+ **There is no event id.** Events carry no unique identifier and no sequence
130
+ number. They are ordered by timestamp and correlated by your ids. This means
131
+ events are not deduplicable — if you emit the same event twice, that is two
132
+ events.
133
+
134
+ ## What one line looks like
135
+
136
+ Each record is one line of JSON in an `event-*.jsonl` file. Key order is stable:
137
+ identity first, then the event's own required fields, then `environment`, then
138
+ whatever optional and custom fields you set.
139
+
140
+ ```json
141
+ {"timestamp": "2026-07-17T09:15:22.123456Z", "session_id": "run-001", "agent_id": "planner", "type": "tool_use", "tool_name": "web_search", "tool_call_id": "toolu_01", "environment": "production", "input": {"query": "latest AI research"}}
142
+ {"timestamp": "2026-07-17T09:15:23.456789Z", "session_id": "run-001", "agent_id": "planner", "type": "tool_result", "tool_name": "web_search", "tool_call_id": "toolu_01", "environment": "production", "output": {"results": ["..."]}, "duration_ms": 1334}
143
+ ```
144
+
145
+ **Parse it; don't grep it.** The whitespace above is what today's writer happens
146
+ to emit — it is not a contract. `grep '"type":"agent_start"'` finds nothing on a
147
+ perfectly healthy integration, and reads as "my events are missing". Use
148
+ `python -m json.tool --json-lines`, or `jq`.
149
+
150
+ `environment` is always present. It is `"dev"` unless you set it — see
151
+ `../SKILL.md` §3.
152
+
153
+ ## A minimal complete run
154
+
155
+ The shape to aim for. `agent_start` and `agent_end` bracket everything; the pairs
156
+ nest inside.
157
+
158
+ ```python
159
+ import failproofai_sdk
160
+
161
+ failproofai_sdk.configure(environment="production")
162
+
163
+ sid = "run-001"
164
+ failproofai_sdk.event.agent_start(session_id=sid, agent_id="planner", goal="answer the user's question")
165
+ try:
166
+ failproofai_sdk.event.model_request(session_id=sid, agent_id="planner", model="claude-opus-4-8",
167
+ request_id="req-1",
168
+ messages=[{"role": "user", "content": "..."}])
169
+ failproofai_sdk.event.model_response(session_id=sid, agent_id="planner", model="claude-opus-4-8",
170
+ request_id="req-1", duration_ms=812,
171
+ stop_reason="tool_use", input_tokens=1200, output_tokens=95)
172
+
173
+ failproofai_sdk.event.tool_use(session_id=sid, agent_id="planner",
174
+ tool_name="web_search", tool_call_id="toolu_01",
175
+ input={"query": "..."})
176
+ failproofai_sdk.event.tool_result(session_id=sid, agent_id="planner",
177
+ tool_name="web_search", tool_call_id="toolu_01",
178
+ output={"results": ["..."]})
179
+ # BaseException, not Exception: `asyncio.CancelledError` inherits from
180
+ # BaseException, so `except Exception` lets a cancelled run through and the
181
+ # session ends with an `agent_start` and no `agent_end` at all.
182
+ except BaseException as e:
183
+ import traceback
184
+ failproofai_sdk.event.error(session_id=sid, agent_id="planner",
185
+ error_type=type(e).__name__, message=str(e),
186
+ traceback=traceback.format_exc())
187
+ failproofai_sdk.event.agent_end(session_id=sid, agent_id="planner", outcome="failed")
188
+ raise
189
+ else:
190
+ failproofai_sdk.event.agent_end(session_id=sid, agent_id="planner",
191
+ outcome="success", summary="answered from 1 search")
192
+ ```
193
+
194
+ Note `outcome="failed"` in the `except` — not `"failure"`, which silently reads as
195
+ a non-failure.
196
+
197
+ Threading `sid` through by hand like this is fine for one function and miserable
198
+ across a real codebase — which is why you do not have to. The same run, with the
199
+ scopes doing the identity and the bracketing:
200
+
201
+ ```python
202
+ with failproofai_sdk.agent("planner", session_id="run-001", goal="answer the user's question"):
203
+ failproofai_sdk.event.model_request(model="claude-opus-4-8", request_id="req-1", messages=[...])
204
+ failproofai_sdk.event.model_response(model="claude-opus-4-8", request_id="req-1", duration_ms=812,
205
+ stop_reason="tool_use", input_tokens=1200, output_tokens=95)
206
+ with failproofai_sdk.tool_call("web_search", input={"query": "..."}) as t:
207
+ t.output = {"results": ["..."]}
208
+ ```
209
+
210
+ `agent_start`/`agent_end`, the `error` event, `outcome="failed"` and the tool
211
+ timing all come for free, including on the exception path. See `integration.md`;
212
+ on a supported framework, `frameworks.md` gets you the same events with no call
213
+ sites at all.
214
+
215
+ ## Pausing and resuming — not ending
216
+
217
+ When a run suspends — waiting for a human, rate-limited, user-paused — do **not**
218
+ emit `agent_end` and then a fresh `agent_start` on the way back: that reads as two
219
+ separate agents, and the wait counts as active work. Bracket the gap with
220
+ `agent_pause` / `agent_resume` instead, reusing one `pause_id`:
221
+
222
+ ```python
223
+ import uuid
224
+ pause_id = str(uuid.uuid4())
225
+ failproofai_sdk.event.agent_pause(session_id=sid, agent_id="planner",
226
+ pause_id=pause_id, reason="waiting_for_user")
227
+ # … the run is parked; a human is deciding …
228
+ failproofai_sdk.event.agent_resume(session_id=sid, agent_id="planner", pause_id=pause_id)
229
+ ```
230
+
231
+ The agent span stays open across the pause (it is not ended); `agent_resume`
232
+ carries the paused `duration_ms` when both halves run in the same process, and
233
+ paused time is reported separately from active work. Persist `pause_id` if the
234
+ resume happens in a different process so it reuses the same value.
@@ -0,0 +1,314 @@
1
+ # Framework integrations
2
+
3
+ If the agent runs on LangChain/LangGraph, CrewAI, LlamaIndex or Pydantic AI, you
4
+ do not write the instrumentation — you turn it on. The adapters ship inside the
5
+ SDK wheel and are imported only when you ask for them.
6
+
7
+ ```python
8
+ import failproofai_sdk
9
+ from langgraph.graph import StateGraph # import your framework FIRST
10
+
11
+ failproofai_sdk.configure(environment="production")
12
+ failproofai_sdk.instrument() # every supported framework already imported
13
+
14
+ graph.invoke({"messages": [...]}) # sessions, tools, models, errors all appear
15
+ ```
16
+
17
+ No call site changes. `graph.invoke()`, `crew.kickoff()`, `await workflow.run()`
18
+ and `await agent.run()` are recorded exactly as they are written today.
19
+
20
+ ## `instrument()` / `uninstrument()`
21
+
22
+ ```python
23
+ failproofai_sdk.instrument() # auto-detect
24
+ failproofai_sdk.instrument("crewai") # exactly one
25
+ failproofai_sdk.instrument("langchain", session_id=request_id, capture_content=False)
26
+ failproofai_sdk.uninstrument() # put everything back
27
+ ```
28
+
29
+ - **Auto-detect reads what is already imported, not what is installed.** This is
30
+ deliberate — a library that imports LangChain to find out whether you use it
31
+ costs you a second of startup for nothing. The consequence is an ordering rule:
32
+ `configure()` → import the framework → `instrument()` → run. Calling
33
+ `instrument()` too early instruments nothing and returns `()` — no exception,
34
+ but it does log a warning, so check stderr when a run records nothing.
35
+ - **It returns the names it newly instrumented**, as a tuple. Assert on it in
36
+ startup code if you want a loud failure: `assert failproofai_sdk.instrument()`.
37
+ - **Instrumenting something already active is a no-op** returning `()`. Calling
38
+ it from two code paths, or from a reloading dev server, cannot double-record.
39
+ - **An unknown name raises `ValueError` listing the valid ones.** A typo that
40
+ silently records nothing is the worst available outcome, so this one is loud.
41
+ Accepted spellings: `langchain` (aliases `langgraph`, `langchain_core`),
42
+ `crewai`, `llama_index` (`llamaindex`, `llama-index`), `pydantic_ai`
43
+ (`pydantic-ai`, `pydanticai`).
44
+ - **One adapter failing does not cost you the others.** With no argument, an
45
+ adapter whose install fails is logged and skipped and the rest still install.
46
+ - **Ask what is wired up** rather than guessing, when a run records nothing:
47
+
48
+ ```python
49
+ from failproofai_sdk.integrations import available, active
50
+
51
+ available() # ('crewai', 'langchain', 'llama_index', 'pydantic_ai') — every adapter that ships
52
+ active() # ('langchain',) — what is instrumented in THIS process right now
53
+ ```
54
+
55
+ An empty `active()` after you called `instrument()` is the ordering bug above:
56
+ the framework was not in `sys.modules` yet.
57
+ - **`uninstrument()` never raises**, restores the original objects it replaced,
58
+ and closes anything still open with `outcome="cancelled"` so teardown does not
59
+ leave a session reported as ongoing forever.
60
+
61
+ Options are keyword arguments to `instrument()`. The same dict reaches every
62
+ adapter, so an option meant for one is ignored by the others rather than raising:
63
+
64
+ | Option | Applies to | Effect |
65
+ |---|---|---|
66
+ | `session_id=` | langchain, crewai, pydantic_ai | Pin every run to this session id. Use it when your service already has a per-request id. |
67
+ | `capture_content=False` | langchain, pydantic_ai | Drop prompts, messages and outputs; keep structure, durations and token counts. |
68
+ | `capture_messages=False` | llama_index | The same, for LlamaIndex. |
69
+ | `include_chains=("rag",)` | langchain | Record these intermediate chains by name. Default: none — see below. |
70
+ | `graph_callbacks=False` | langchain | Turn off LangGraph interrupt/resume wiring. Default on. |
71
+ | `steps=False` | llama_index | Stop emitting a hook pair per workflow step. Default on. |
72
+ | `embeddings=True` | llama_index | Record embedding calls. Default off — they are high volume and low signal. |
73
+ | `stale_after=600.0` | llama_index | Seconds before the background reaper closes a span the workflow never finished. |
74
+ | `reaper_interval=30.0` | llama_index | How often that reaper runs. |
75
+
76
+ ## The rule the mappings follow
77
+
78
+ > A framework construct becomes an Failproof AI **agent** if and only if it owns an
79
+ > LLM decision loop and has its own goal. Everything else with a start and an end
80
+ > becomes the closest kind of leaf.
81
+
82
+ | Kind | Gets | Examples |
83
+ |---|---|---|
84
+ | owns a decision loop | `agent_start` / `agent_end` | the top-level graph, crew or workflow, and anything the framework itself calls an agent — a compiled subgraph, a CrewAI `Agent` role, a LlamaIndex `FunctionAgent` |
85
+ | something the agent *calls* | `tool_use` / `tool_result` | function tools, retrievers, memory and knowledge queries |
86
+ | machinery *around* the agent | `hook_triggered` / `hook_completed` (with `trigger_event`) | LangGraph nodes, LlamaIndex workflow steps, CrewAI flow methods, guardrails |
87
+
88
+ **A LangGraph node is a hook, not a nested agent**, and that is the one mapping
89
+ decision worth understanding, because it is the one you might be tempted to
90
+ "fix". `agent_id` is the primary facet across every session; it has to stay a
91
+ small, stable set of labels. Promote `retrieve`, `grade_documents` and
92
+ `should_continue` to agents and you drown the real agents in the filter, and the
93
+ session ends up labelled with whichever node happened to run first. Hook spans
94
+ draw identically on the timeline — same lanes, same durations — and you get a
95
+ per-node latency surface for free, with `hook_name` as its own facet.
96
+
97
+ ## LangChain / LangGraph
98
+
99
+ Supported: `langchain-core >=1.4.7,<2`, `langgraph >=1.2,<2`.
100
+
101
+ Attaches through LangChain's own callback configuration, so **every** callback
102
+ manager the framework builds carries it — including ones created inside chains
103
+ you never touch.
104
+
105
+ | LangChain / LangGraph | Failproof AI |
106
+ |---|---|
107
+ | root run (the outermost chain/graph) | `agent_start` / `agent_end` |
108
+ | LangGraph node | `hook_triggered` / `hook_completed`, `trigger_event="graph_node"` |
109
+ | compiled subgraph | nested `agent_start` / `agent_end`, `agent_id="root/node"` |
110
+ | tool run | `tool_use` / `tool_result` |
111
+ | retriever run | `tool_use` / `tool_result`, output summarised |
112
+ | chat model / LLM run | `model_request` / `model_response`, paired on `request_id` |
113
+ | `interrupt()` | `human_wait` + `agent_pause` |
114
+ | `Command(resume=...)` | `agent_resume` + `human_input` |
115
+ | intermediate chains | **nothing**, unless you name them in `include_chains` |
116
+
117
+ **Python 3.10 async nodes must forward `RunnableConfig`.** LangGraph cannot
118
+ automatically propagate callback context from an async node into a child
119
+ `ainvoke()` on Python 3.10. Without this, the child model or tool appears as a
120
+ separate root run:
121
+
122
+ ```python
123
+ from langchain_core.runnables import RunnableConfig
124
+
125
+ async def plan(state, config: RunnableConfig):
126
+ reply = await model.ainvoke(state["messages"], config=config)
127
+ return {"messages": [reply]}
128
+ ```
129
+
130
+ Python 3.11 and later propagate this context automatically.
131
+
132
+ `session_id` resolution, in order — the first that produces a value wins:
133
+
134
+ 1. `instrument("langchain", session_id=...)`;
135
+ 2. `config={"metadata": {"failproofai_sdk_session_id": sid}}` on the call — the
136
+ documented per-call key, and the one to use in a web service;
137
+ 3. an enclosing `failproofai_sdk.session()` / `failproofai_sdk.agent()` scope;
138
+ 4. `metadata["session_id" | "conversation_id" | "thread_id"]`;
139
+ 5. the root run id.
140
+
141
+ It is never synthesised from scratch. A made-up id would split one run into many
142
+ sessions, which is a silent wrong answer rather than a loud one.
143
+
144
+ Three behaviours that surprise people:
145
+
146
+ - **A `GraphInterrupt` is control flow, not an error.** LangGraph raises it
147
+ through the same error callback as a genuine failure, so a naive integration
148
+ paints every human approval red and ends the run as `failed`. The adapter
149
+ treats the whole interrupt family as control flow and emits the HITL pairs
150
+ instead.
151
+ - **Streaming never produces per-token events.** Time-to-first-token and the
152
+ chunk count are folded into the closing `model_response` as `fw_ttft_ms` and
153
+ `fw_chunks`.
154
+ - **`agent_id` is the graph or chain name**, never a run UUID. Framework ids land
155
+ in `fw_run_id` / `fw_node` / `fw_thread_id`.
156
+
157
+ ## CrewAI
158
+
159
+ Supported: `crewai >=1.13,<2` (the release where the span tree and normalised
160
+ token usage are both present). Registers a listener on CrewAI's event bus;
161
+ `crew.kickoff()` is unchanged.
162
+
163
+ | CrewAI | Failproof AI |
164
+ |---|---|
165
+ | crew kickoff | `agent_start` / `agent_end`, `agent_id` = crew name |
166
+ | agent execution | nested `agent_start` / `agent_end`, `agent_id` = the agent's **role** |
167
+ | task | no event of its own — folded into the agent execution that runs it |
168
+ | flow method | `hook_triggered` / `hook_completed`, `trigger_event="flow_method"` |
169
+ | guardrail | hook pair; a tripped guardrail closes with `outcome="rejected"` |
170
+ | tool usage | `tool_use` / `tool_result` |
171
+ | memory / knowledge query, save, retrieval | `tool_use` / `tool_result` (`memory.query`, `knowledge.search`, …) |
172
+ | LLM call | `model_request` / `model_response` |
173
+ | LLM stream chunks | folded into the closing `model_response` |
174
+
175
+ `agent_id` is the crew name at the top and the **agent role** underneath —
176
+ `"researcher"`, `"editor"`. CrewAI's `agent.id` is a UUID and goes to
177
+ `fw_agent_id`, never to `agent_id`. CrewAI runs its own internal flow inside
178
+ every agent execution; that one is a pass-through and does not become a span.
179
+
180
+ ## LlamaIndex
181
+
182
+ Supported: `llama-index-core >=0.14.23,<0.15`. Registers on the root dispatcher,
183
+ so one call covers every workflow and agent in the process.
184
+
185
+ | LlamaIndex | Failproof AI |
186
+ |---|---|
187
+ | `Workflow.run` root span | session + `agent_start` / `agent_end` |
188
+ | nested `Workflow.run` span | nested `agent_start` / `agent_end` |
189
+ | workflow step | `hook_triggered` / `hook_completed`, `trigger_event="workflow_step"` |
190
+ | LLM chat start/end | `model_request` / `model_response`, paired on `request_id` |
191
+ | `FunctionTool.call` | `tool_use` / `tool_result` |
192
+ | retrieval start/end | `tool_use` / `tool_result`, output summarised |
193
+ | a tool that waits for an event | `human_wait` + `agent_pause`, then `agent_resume` + `human_input` |
194
+ | embeddings | nothing, unless `embeddings=True` |
195
+
196
+ `agent_id` is the `FunctionAgent.name` when there is one and the workflow class
197
+ name otherwise — never a span id.
198
+
199
+ **Token counts are best-effort here, and deliberately so.** LlamaIndex has no
200
+ standard usage field, so the raw usage dict always ships as `usage`, and the
201
+ top-level `input_tokens` / `output_tokens` are set **only** when a recognised key
202
+ is present. A model integration that names its counters something new gives you a
203
+ populated `usage` and blank token columns. That is the honest outcome; a
204
+ confident wrong number would be worse.
205
+
206
+ **Known gap:** human-in-the-loop is captured only when the wait happens inside a
207
+ tool — the pattern LlamaIndex documents. A plain workflow step that waits for an
208
+ event is resolved by the runtime before anything observable happens, so there is
209
+ no signal to key a pause on.
210
+
211
+ ## Pydantic AI
212
+
213
+ Supported: `pydantic-ai-slim >=2.0,<3`. Every tutorial written for v1 is wrong
214
+ for this range: `Agent(instrument=...)` was removed in 2.0. The adapter installs
215
+ itself as a capability instead — no OpenTelemetry SDK required, and it cannot
216
+ double-count against your own tracing.
217
+
218
+ | Pydantic AI | Failproof AI |
219
+ |---|---|
220
+ | an agent run | `agent_start` / `agent_end` (plus `error` on failure) |
221
+ | a model request | `model_request` / `model_response` |
222
+ | a tool execution | `tool_use` / `tool_result` |
223
+ | graph nodes (`UserPromptNode`, `ModelRequestNode`, `CallToolsNode`) | **nothing** |
224
+
225
+ Graph nodes are Pydantic AI's own loop machinery rather than steps you wrote —
226
+ unlike a LangGraph node — and everything they do that is worth seeing is already
227
+ covered by the model and tool spans.
228
+
229
+ `session_id` is the run's `conversation_id`, so a conversation spanning several
230
+ runs is one session; an enclosing `failproofai_sdk.session()` / `failproofai_sdk.agent()` scope
231
+ always wins. `agent_id` is the `Agent`'s name.
232
+
233
+ **One ordering rule, because it bites:** the capability is attached when an
234
+ `Agent` is constructed, so **agents built before `instrument()` are not
235
+ instrumented**, and agents built while instrumented keep the capability object
236
+ after `uninstrument()` (it turns into a pass-through and stops recording).
237
+ Construct your agents after `instrument()`, or attach it yourself:
238
+
239
+ ```python
240
+ from failproofai_sdk.integrations.pydantic_ai import FailproofAI
241
+
242
+ agent = Agent("openai:gpt-5", capabilities=[FailproofAI()])
243
+ ```
244
+
245
+ ## Mixing adapters with hand-written events
246
+
247
+ They compose, and this is the supported way to add detail an adapter cannot know
248
+ about:
249
+
250
+ ```python
251
+ failproofai_sdk.instrument("langchain")
252
+
253
+ with failproofai_sdk.agent("planner", goal=question): # your bracket
254
+ graph.invoke(...) # adapter events land here
255
+ with failproofai_sdk.tool_call("billing_check") as t: # your own tool span
256
+ t.output = check(user)
257
+ ```
258
+
259
+ Adapter events join **that** session, with `parent_id="planner"`. An adapter
260
+ resolves identity from its own run id first, then that run's parent chain, then
261
+ whatever scope you have open — so a hand-written outer bracket and an adapter
262
+ produce one tree, not two.
263
+
264
+ ## What every adapter guarantees
265
+
266
+ - **They never raise into your agent.** Every callback is wrapped: a failure logs
267
+ at WARNING with a traceback, and after three failures at the same call site
268
+ that site disables itself at ERROR. A broken adapter costs you a log line, not
269
+ your agent. Set `FAILPROOFAI_SDK_STRICT=1` to make it re-raise instead — do that in
270
+ tests and when debugging an adapter that records nothing.
271
+ - **Version ranges are checked at `instrument()` time.** Outside the supported
272
+ range: warn once, keep going. Named explicitly but not importable at all:
273
+ `ImportError` carrying the install command. `FAILPROOFAI_SDK_STRICT_INTEGRATIONS=1`
274
+ promotes every one of those warnings to an exception.
275
+ - **Framework-native ids are namespaced `fw_*`** — `fw_run_id`, `fw_node`,
276
+ `fw_task_id`, `fw_agent_id`, `fw_thread_id`. Flat, never nested. This is a
277
+ safety rule, not a style one: custom fields are merged last, so an un-namespaced
278
+ extra called `tool_name` or `duration_ms` would overwrite the real field.
279
+ - **Large payloads are truncated**, per field and per event, with a
280
+ `…[truncated]` marker. Prompts, retrieved documents and tool outputs are the
281
+ three largest strings in an agent process.
282
+ - **Every event carries `framework`, `framework_version` and
283
+ `integration_version`**, so you can tell adapter output from your own.
284
+ - **No per-token events, ever.** Streaming is folded into the closing
285
+ `model_response`.
286
+ - **Timestamps are stamped when the callback fires.** Nothing is backdated, so an
287
+ adapter cannot import a trace that already happened.
288
+
289
+ ## Verifying an adapter
290
+
291
+ Everything in `../SKILL.md` §5 applies unchanged — the events go to the same
292
+ files. Four checks that are specific to adapter output:
293
+
294
+ 1. **The first event of each session is the root `agent_start`.** Anything
295
+ emitted before it can leave the session labelled by the wrong actor.
296
+ 2. **`agent_id` values are names, not UUIDs** — `"planner"`, `"researcher"`,
297
+ the graph name. A UUID here means something is being passed through that
298
+ should have gone to `fw_agent_id`.
299
+ 3. **`model_request` and `model_response` share a `request_id`**, and every
300
+ `model_response` carries an integer `duration_ms`.
301
+ 4. **Nothing is left open.** Every `tool_use` has a `tool_result`, every
302
+ `agent_start` an `agent_end`.
303
+
304
+ If an adapter records nothing at all, in this order: was the framework imported
305
+ **before** `instrument()` (auto-detect reads imported modules); did
306
+ `instrument()` return a non-empty tuple; and does the run produce anything with
307
+ `FAILPROOFAI_SDK_STRICT=1` set, which converts a swallowed adapter error into a raise.
308
+
309
+ ## A framework that is not on this list
310
+
311
+ Use the shipped context managers at the framework's own boundaries —
312
+ `failproofai_sdk.agent()` around the run, `failproofai_sdk.tool_call()` in the tool hook. See
313
+ `integration.md`. Ask before writing a full callback adapter for an unsupported
314
+ framework: adding one to the SDK is usually the better answer.
@@ -0,0 +1,100 @@
1
+ # Installing the SDK
2
+
3
+ ```bash
4
+ pip install failproofai-sdk # or: uv add failproofai-sdk
5
+ ```
6
+
7
+ The SDK has no dependencies, so that is all it installs. Optional extras pull in
8
+ the **framework**, never the adapter — all four adapters ship in the box:
9
+
10
+ ```bash
11
+ pip install 'failproofai-sdk[langchain]' # also: langgraph, crewai, pydantic-ai
12
+ pip install 'failproofai-sdk[llamaindex]' # note: no hyphen, unlike the dist name
13
+ ```
14
+
15
+ Most agents already have their framework installed and never need one of these.
16
+
17
+ Then `import failproofai_sdk`. There is no token, no private index, and no wheel to
18
+ download by hand — the distribution is on public PyPI. It has no dependencies, so
19
+ it cannot conflict with anything already in the agent's environment.
20
+
21
+ ## The one thing that still goes wrong
22
+
23
+ **`pip install agenteye` does not install this SDK, and can uninstall it.**
24
+
25
+ `agenteye` was the SDK's distribution name inside the private monorepo, and it is
26
+ also the name an old CLI published under. That CLI has moved to `fp-cloud-cli` (command
27
+ `fp`), but its last release as `agenteye` — version `0.1.22` — is stranded on
28
+ public PyPI permanently. PyPI versions cannot be withdrawn and reused, and pip
29
+ resolves the highest version, so that build is what the name still resolves to.
30
+
31
+ | You run | You get | Symptom |
32
+ |---|---|---|
33
+ | `pip install agenteye`, nothing installed | the stranded CLI build | `import failproofai_sdk` → `ModuleNotFoundError`; that build ships `agenteye_cli` |
34
+ | `pip install agenteye`, SDK already present | the stranded CLI build **alongside** it | Confusing but survivable — different distribution names, so the SDK is not removed |
35
+ | `pip install agenteye` on a pre-rename SDK (`agenteye` ≤ `0.0.1b14`) | the stranded CLI build, **replacing the SDK** | The import that worked five minutes ago stops working: same distribution name, higher version, so pip treats it as an upgrade |
36
+
37
+ The last row is the dangerous one and it is why the rename happened. It fires
38
+ *after* a working integration, when someone wants the CLI to check that events
39
+ arrived and installs it into the agent's own environment. Nothing warns them.
40
+
41
+ If you want the CLI, it is a separate distribution and installing it cannot touch
42
+ `failproofai-sdk` — but give it its own environment anyway:
43
+
44
+ ```bash
45
+ pipx install fp-cloud-cli # or: uv tool install fp-cloud-cli (the command is `fp`)
46
+ ```
47
+
48
+ ## Migrating from the old `agenteye` distribution
49
+
50
+ Two changes, both mechanical:
51
+
52
+ ```bash
53
+ pip uninstall agenteye
54
+ pip install failproofai-sdk
55
+ ```
56
+
57
+ ```diff
58
+ -import agenteye
59
+ -agenteye.configure(base_dir=None, flush_interval=0.5)
60
+ -agenteye.event.agent_start(session_id="run-001", agent_id="planner")
61
+ +import failproofai_sdk
62
+ +failproofai_sdk.configure(base_dir=None, flush_interval=0.5)
63
+ +failproofai_sdk.event.agent_start(session_id="run-001", agent_id="planner")
64
+ ```
65
+
66
+ Every method name, argument, and emitted field is unchanged, and so is
67
+ `AGENTEYE_ENVIRONMENT` — a contract with a daemon that releases separately.
68
+
69
+ **Two things changed on disk.** The default spool root is now
70
+ `~/.failproofai/custom-agents`, not `~/.agenteye`; and **`AGENTEYE_HOME` no
71
+ longer moves the SDK's spool at all.** It used to sit above the default, so
72
+ exporting it for `agenteye-collector` — the component that genuinely reads it —
73
+ relocated this SDK as an unasked-for side effect. Resolution is now exactly
74
+ `configure(base_dir=...)`, else `~/.failproofai/custom-agents` (with
75
+ `$FAILPROOFAI_HOME` moving the umbrella, never the spool out of it).
76
+
77
+ `failproofaid` watches both roots, so if that is your daemon there is nothing to
78
+ do and already-spooled batches still get collected. If you run the older
79
+ `agenteye-collector`, point **it** at the SDK with
80
+ `AGENTEYE_HOME=~/.failproofai/custom-agents`, or pass `base_dir` explicitly.
81
+ (`AGENTEYE_SPOOL_TO_FAILPROOFAI` is retired: it also required the directory to
82
+ pre-exist, which nothing created, so it never took effect.)
83
+
84
+ ## Confirm what you have
85
+
86
+ ```bash
87
+ python -c "import failproofai_sdk; print(failproofai_sdk.__version__)"
88
+ ```
89
+
90
+ - A version string such as `0.0.1b1` → the SDK. Good.
91
+ - `ModuleNotFoundError: No module named 'failproofai_sdk'` → not installed. If
92
+ `pip show agenteye` returns something, you installed the wrong name; see above.
93
+
94
+ ## Pinning
95
+
96
+ Pin `failproofai-sdk` in your dependency file like any other package. Never leave
97
+ an unpinned `agenteye` requirement anywhere a CI job will resolve it from PyPI —
98
+ it will pull the stranded CLI build on the next clean install. If you are
99
+ migrating, grep for `agenteye` in every `requirements*.txt`, `pyproject.toml`,
100
+ `Pipfile` and Dockerfile, not just the one you remember.