@jini-ai/agent-plugins 0.6.16 → 0.6.19

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 (335) hide show
  1. package/CHANGELOG.md +35 -1
  2. package/NOTICE +14 -0
  3. package/README.md +35 -14
  4. package/charts-echarts/plugin.json +39 -0
  5. package/charts-echarts/skills/charts-echarts/SKILL.md +110 -0
  6. package/charts-recharts/plugin.json +32 -0
  7. package/charts-recharts/skills/charts-recharts/SKILL.md +108 -0
  8. package/cloudflare/NOTES.md +16 -0
  9. package/cloudflare/form-destinations/cloudflare-d1.mjs +9 -0
  10. package/cloudflare/lib/api.mjs +96 -0
  11. package/cloudflare/lib/assets.mjs +65 -0
  12. package/cloudflare/lib/dns.mjs +32 -0
  13. package/cloudflare/lib/domain-inventory.mjs +61 -0
  14. package/cloudflare/lib/domain-status.mjs +48 -0
  15. package/cloudflare/lib/domains.mjs +95 -0
  16. package/cloudflare/lib/forms.mjs +254 -0
  17. package/cloudflare/lib/pages-upload.mjs +51 -0
  18. package/cloudflare/lib/target.mjs +165 -0
  19. package/cloudflare/lib/workers-upload.mjs +48 -0
  20. package/cloudflare/lib/zones.mjs +25 -0
  21. package/cloudflare/mcp.json +4 -0
  22. package/cloudflare/plugin.json +96 -0
  23. package/cloudflare/skills/cloudflare/SKILL.md +57 -0
  24. package/cloudflare/skills/cloudflare/references/domains.md +31 -0
  25. package/cloudflare/skills/cloudflare/references/pages.md +18 -0
  26. package/cloudflare/skills/cloudflare/references/permissions.md +29 -0
  27. package/cloudflare/skills/cloudflare/references/troubleshooting.md +20 -0
  28. package/cloudflare/skills/cloudflare/references/workers.md +42 -0
  29. package/cloudflare/targets/cloudflare-pages.mjs +12 -0
  30. package/cloudflare/targets/cloudflare-workers.mjs +17 -0
  31. package/cloudflare/tovu-consent.json +6 -0
  32. package/cloudflare/tovu-deploy-targets.json +630 -0
  33. package/cloudflare/tovu-form-destinations.json +12 -0
  34. package/cloudflare/worker/forms-receiver.mjs +249 -0
  35. package/composio/mcp.json +10 -0
  36. package/composio/plugin.json +68 -0
  37. package/composio/skills/composio/SKILL.md +85 -0
  38. package/dist/core/identity-namespace.d.ts +12 -0
  39. package/dist/core/identity-namespace.js +20 -0
  40. package/dist/folder-zip-node.js +29 -7
  41. package/dist/lifecycle/bundled-digests.js +4 -3
  42. package/dist/lifecycle/install.d.ts +7 -0
  43. package/dist/lifecycle/install.js +45 -3
  44. package/dist/lifecycle/manifest.d.ts +2 -2
  45. package/dist/lifecycle/manifest.js +5 -3
  46. package/dist/lifecycle/node.js +2 -0
  47. package/dist/lifecycle/persistent-state.js +1 -1
  48. package/dist/lifecycle/ports.d.ts +8 -0
  49. package/dist/lifecycle/seed-bundled.js +4 -1
  50. package/dist/manifest.d.ts +1 -1
  51. package/dist/manifest.js +3 -2
  52. package/fly/deploy-configs/fly.mjs +115 -0
  53. package/fly/deploy-ops/fly.mjs +102 -0
  54. package/fly/mcp.json +4 -0
  55. package/fly/plugin.json +81 -0
  56. package/fly/scripts/render-deploy-workflow.mjs +150 -0
  57. package/fly/skills/fly/SKILL.md +43 -0
  58. package/fly/skills/fly/references/fly-deploy.template.yml +117 -0
  59. package/fly/skills/fly/references/fly.template.toml +81 -0
  60. package/fly/tovu-credential-schemes.json +11 -0
  61. package/fly/tovu-deploy-configs.json +21 -0
  62. package/fly/tovu-deploy-ops.json +14 -0
  63. package/github/deploy-ops/github-actions.mjs +164 -0
  64. package/github/deployments/github.mjs +415 -0
  65. package/github/mcp.json +4 -0
  66. package/github/plugin.json +105 -0
  67. package/github/skills/github/SKILL.md +249 -0
  68. package/github/skills/github/references/actions.md +224 -0
  69. package/github/skills/github/references/auth-and-tokens.md +140 -0
  70. package/github/skills/github/references/repo-files.md +135 -0
  71. package/github/skills/github/references/site-backup.md +159 -0
  72. package/github/skills/github/references/source-control.md +123 -0
  73. package/github/source-control/backup-push.mjs +242 -0
  74. package/github/source-control/commit-site.mjs +459 -0
  75. package/github/source-control/github.mjs +93 -0
  76. package/github/source-control/write-files.mjs +468 -0
  77. package/github/tovu-deploy-ops.json +13 -0
  78. package/github/tovu-source-control.json +117 -0
  79. package/github-pages/NOTES.md +19 -0
  80. package/github-pages/mcp.json +4 -0
  81. package/github-pages/plugin.json +48 -0
  82. package/github-pages/skills/github-pages/SKILL.md +44 -0
  83. package/github-pages/targets/github-pages.mjs +543 -0
  84. package/github-pages/tovu-deploy-targets.json +327 -0
  85. package/google-login/exports/google-g.svg +1 -0
  86. package/google-login/exports/sign-in-button.css +68 -0
  87. package/google-login/exports/sign-in-button.html +4 -0
  88. package/google-login/mcp.json +4 -0
  89. package/google-login/plugin.json +59 -0
  90. package/google-login/skills/google-login/SKILL.md +96 -0
  91. package/google-login/tovu-login-providers.json +21 -0
  92. package/google-workspace/README.md +132 -0
  93. package/google-workspace/form-destinations/README.md +87 -0
  94. package/google-workspace/form-destinations/dedupe.mjs +43 -0
  95. package/google-workspace/form-destinations/delivery-result.mjs +69 -0
  96. package/google-workspace/form-destinations/mapping.mjs +152 -0
  97. package/google-workspace/form-destinations/sheets.mjs +202 -0
  98. package/google-workspace/lib/auth.mjs +81 -0
  99. package/google-workspace/lib/drive-files.mjs +54 -0
  100. package/google-workspace/lib/form-destination-settings.mjs +72 -0
  101. package/google-workspace/lib/http.mjs +168 -0
  102. package/google-workspace/lib/picker-flow.mjs +171 -0
  103. package/google-workspace/lib/picker-selection.mjs +107 -0
  104. package/google-workspace/lib/product-state.mjs +93 -0
  105. package/google-workspace/lib/request-policy.mjs +163 -0
  106. package/google-workspace/lib/sheets-a1.mjs +79 -0
  107. package/google-workspace/lib/sheets-admin-csv.mjs +82 -0
  108. package/google-workspace/lib/sheets-admin-request-kinds.mjs +183 -0
  109. package/google-workspace/lib/sheets-client.mjs +286 -0
  110. package/google-workspace/lib/surface-actions.mjs +107 -0
  111. package/google-workspace/mcp.json +4 -0
  112. package/google-workspace/plugin.json +77 -0
  113. package/google-workspace/products.json +12 -0
  114. package/google-workspace/skills/google-workspace/SKILL.md +82 -0
  115. package/google-workspace/skills/google-workspace/references/connection.md +102 -0
  116. package/google-workspace/skills/google-workspace/references/form-delivery.md +50 -0
  117. package/google-workspace/skills/google-workspace/references/sheets.md +149 -0
  118. package/google-workspace/skills/google-workspace/references/troubleshooting.md +31 -0
  119. package/google-workspace/tools/account-info.mjs +18 -0
  120. package/google-workspace/tools/sheets/README.md +54 -0
  121. package/google-workspace/tools/sheets/copy-tab.mjs +23 -0
  122. package/google-workspace/tools/sheets/copy.mjs +23 -0
  123. package/google-workspace/tools/sheets/create.mjs +35 -0
  124. package/google-workspace/tools/sheets/find-replace.mjs +38 -0
  125. package/google-workspace/tools/sheets/find.mjs +52 -0
  126. package/google-workspace/tools/sheets/get-by-data-filter.mjs +23 -0
  127. package/google-workspace/tools/sheets/get.mjs +22 -0
  128. package/google-workspace/tools/sheets/values-append.mjs +27 -0
  129. package/google-workspace/tools/sheets/values-batch-clear.mjs +20 -0
  130. package/google-workspace/tools/sheets/values-batch-get.mjs +20 -0
  131. package/google-workspace/tools/sheets/values-batch-update.mjs +29 -0
  132. package/google-workspace/tools/sheets/values-by-data-filter.mjs +62 -0
  133. package/google-workspace/tools/sheets/values-clear.mjs +20 -0
  134. package/google-workspace/tools/sheets/values-get.mjs +21 -0
  135. package/google-workspace/tools/sheets/values-update.mjs +26 -0
  136. package/google-workspace/tools/sheets-admin/README.md +45 -0
  137. package/google-workspace/tools/sheets-admin/basic-filter.mjs +32 -0
  138. package/google-workspace/tools/sheets-admin/batch-update.mjs +25 -0
  139. package/google-workspace/tools/sheets-admin/developer-metadata.mjs +28 -0
  140. package/google-workspace/tools/sheets-admin/export-csv.mjs +67 -0
  141. package/google-workspace/tools/sheets-admin/filter-views.mjs +38 -0
  142. package/google-workspace/tools/sheets-admin/format.mjs +70 -0
  143. package/google-workspace/tools/sheets-admin/named-ranges.mjs +42 -0
  144. package/google-workspace/tools/sheets-admin/open-existing.mjs +34 -0
  145. package/google-workspace/tools/sheets-admin/protected-ranges-get.mjs +18 -0
  146. package/google-workspace/tools/sheets-admin/sort.mjs +18 -0
  147. package/google-workspace/tools/sheets-admin/tab-modify.mjs +36 -0
  148. package/google-workspace/tovu-admin-surfaces.json +63 -0
  149. package/google-workspace/tovu-agent-tools.json +1178 -0
  150. package/google-workspace/tovu-connections.json +35 -0
  151. package/google-workspace/tovu-form-destinations.json +10 -0
  152. package/google-workspace/ui/README.md +73 -0
  153. package/google-workspace/ui/connection-panel.handler.mjs +167 -0
  154. package/google-workspace/ui/connection-panel.html +17 -0
  155. package/google-workspace/ui/connection-panel.mjs +189 -0
  156. package/google-workspace/ui/connection-view.mjs +120 -0
  157. package/google-workspace/ui/destination-panel.handler.mjs +106 -0
  158. package/google-workspace/ui/destination-panel.html +17 -0
  159. package/google-workspace/ui/destination-panel.mjs +150 -0
  160. package/google-workspace/ui/dom.mjs +140 -0
  161. package/google-workspace/ui/panel.css +170 -0
  162. package/google-workspace/ui/picker-flow.mjs +87 -0
  163. package/google-workspace/ui/picker-view.mjs +44 -0
  164. package/google-workspace/ui/picker.handler.mjs +56 -0
  165. package/google-workspace/ui/picker.html +17 -0
  166. package/google-workspace/ui/picker.mjs +88 -0
  167. package/google-workspace/ui/surface-client.mjs +227 -0
  168. package/higgsfield-media/mcp.json +9 -0
  169. package/higgsfield-media/plugin.json +109 -0
  170. package/higgsfield-media/skills/higgsfield-media/SKILL.md +325 -0
  171. package/higgsfield-media/skills/higgsfield-media/references/failure-modes.md +116 -0
  172. package/higgsfield-media/skills/higgsfield-media/references/models-and-plan-gates.md +142 -0
  173. package/jev/mcp.json +4 -0
  174. package/jev/plugin.json +44 -0
  175. package/jev/skills/jev/SKILL.md +308 -0
  176. package/jev/skills/jev/references/cookbooks.md +197 -0
  177. package/jev/skills/jev/references/jaggedness.md +135 -0
  178. package/jev/skills/jev/references/javascript-sdk.md +146 -0
  179. package/jev/skills/jev/references/patterns.md +123 -0
  180. package/jev/skills/jev/references/primitives-reference.md +187 -0
  181. package/langfuse/plugin.json +22 -0
  182. package/meilisearch/mcp.json +4 -0
  183. package/meilisearch/plugin.json +54 -0
  184. package/meilisearch/providers/meilisearch.mjs +651 -0
  185. package/meilisearch/skills/meilisearch/SKILL.md +43 -0
  186. package/meilisearch/tovu-search-providers.json +10 -0
  187. package/netlify/NOTES.md +13 -0
  188. package/netlify/mcp.json +4 -0
  189. package/netlify/plugin.json +47 -0
  190. package/netlify/skills/netlify/SKILL.md +39 -0
  191. package/netlify/targets/netlify.mjs +384 -0
  192. package/netlify/tovu-consent.json +6 -0
  193. package/netlify/tovu-deploy-targets.json +163 -0
  194. package/opentelemetry/mcp.json +4 -0
  195. package/opentelemetry/plugin.json +52 -0
  196. package/opentelemetry/skills/opentelemetry/SKILL.md +39 -0
  197. package/package.json +161 -6
  198. package/posthog/mcp.json +4 -0
  199. package/posthog/plugin.json +46 -0
  200. package/posthog/skills/posthog/SKILL.md +36 -0
  201. package/railway/deploy-configs/railway.mjs +135 -0
  202. package/railway/deploy-ops/railway.mjs +167 -0
  203. package/railway/mcp.json +4 -0
  204. package/railway/plugin.json +45 -0
  205. package/railway/skills/railway/SKILL.md +66 -0
  206. package/railway/tovu-deploy-configs.json +16 -0
  207. package/railway/tovu-deploy-ops.json +11 -0
  208. package/render/deploy-configs/render.mjs +141 -0
  209. package/render/deploy-ops/render.mjs +152 -0
  210. package/render/mcp.json +4 -0
  211. package/render/plugin.json +47 -0
  212. package/render/skills/render/SKILL.md +63 -0
  213. package/render/tovu-deploy-configs.json +16 -0
  214. package/render/tovu-deploy-ops.json +11 -0
  215. package/resend/NOTES.md +52 -0
  216. package/resend/adapters/resend.mjs +161 -0
  217. package/resend/lib/domains.mjs +137 -0
  218. package/resend/lib/errors.mjs +25 -0
  219. package/resend/lib/feedback.mjs +118 -0
  220. package/resend/mcp.json +13 -0
  221. package/resend/plugin.json +192 -0
  222. package/resend/skills/resend/SKILL.md +107 -0
  223. package/resend/tovu-mail-adapters.json +22 -0
  224. package/s3-compatible/NOTES.md +11 -0
  225. package/s3-compatible/mcp.json +4 -0
  226. package/s3-compatible/object-stores/s3-compatible.mjs +287 -0
  227. package/s3-compatible/plugin.json +56 -0
  228. package/s3-compatible/skills/s3-compatible/SKILL.md +39 -0
  229. package/s3-compatible/targets/s3-compatible.mjs +1054 -0
  230. package/s3-compatible/tovu-deploy-targets.json +432 -0
  231. package/s3-compatible/tovu-object-stores.json +29 -0
  232. package/sentry/mcp.json +4 -0
  233. package/sentry/plugin.json +49 -0
  234. package/sentry/skills/sentry/SKILL.md +34 -0
  235. package/shopify/mcp.json +4 -0
  236. package/shopify/plugin.json +22 -0
  237. package/shopify/skills/shopify/SKILL.md +103 -0
  238. package/shopify/skills/shopify/references/catalog-sync.md +74 -0
  239. package/shopify/skills/shopify/references/domains.md +26 -0
  240. package/shopify/skills/shopify/references/live-storefront.md +34 -0
  241. package/shopify/skills/shopify/references/storefront-snippets.md +21 -0
  242. package/site-compliance/mcp.json +4 -0
  243. package/site-compliance/plugin.json +34 -0
  244. package/site-compliance/skills/site-compliance/SKILL.md +220 -0
  245. package/site-compliance/skills/site-compliance/references/ccpa-cpra.md +115 -0
  246. package/site-compliance/skills/site-compliance/references/gdpr-eu-uk.md +143 -0
  247. package/site-compliance/skills/site-compliance/references/wcag-2-2.md +129 -0
  248. package/site-import/mcp.json +4 -0
  249. package/site-import/plugin.json +41 -0
  250. package/site-import/skills/site-import/SKILL.md +232 -0
  251. package/site-import/skills/site-import/references/content-mapping.md +166 -0
  252. package/site-import/skills/site-import/references/discovery-and-classification.md +117 -0
  253. package/site-import/skills/site-import/references/theme-extraction.md +34 -0
  254. package/slide-design/com.anthropic.claude-code/hooks/hooks.json +4 -0
  255. package/slide-design/mcp.json +4 -0
  256. package/slide-design/plugin.json +26 -0
  257. package/slide-design/skills/slide-design/SKILL.md +103 -0
  258. package/slide-design/skills/slide-design/references/charts-and-exhibits.md +100 -0
  259. package/slide-design/skills/slide-design/references/html-deck.md +175 -0
  260. package/slide-design/skills/slide-design/references/layout-and-style.md +131 -0
  261. package/slide-design/skills/slide-design/references/review.md +93 -0
  262. package/slide-design/skills/slide-design/references/storyline.md +118 -0
  263. package/stripe/plugin.json +22 -0
  264. package/supabase/mcp.json +26 -0
  265. package/supabase/plugin.json +78 -0
  266. package/supabase/skills/supabase/SKILL.md +169 -0
  267. package/supabase/skills/supabase/references/failure-modes.md +101 -0
  268. package/ui-ux-design/CHANGELOG.md +28 -0
  269. package/ui-ux-design/LICENSE +201 -0
  270. package/ui-ux-design/NOTICE +14 -0
  271. package/ui-ux-design/README.md +62 -0
  272. package/ui-ux-design/com.anthropic.claude-code/hooks/hooks.json +4 -0
  273. package/ui-ux-design/mcp.json +4 -0
  274. package/ui-ux-design/plugin.json +26 -0
  275. package/ui-ux-design/skills/frontend-accessibility/SKILL.md +60 -0
  276. package/ui-ux-design/skills/gstack-design/SKILL.md +53 -0
  277. package/ui-ux-design/skills/gstack-design/references/consultation.md +30 -0
  278. package/ui-ux-design/skills/gstack-design/references/html.md +29 -0
  279. package/ui-ux-design/skills/gstack-design/references/review.md +28 -0
  280. package/ui-ux-design/skills/gstack-design/references/shotgun.md +33 -0
  281. package/ui-ux-design/skills/gstack-design/references/upstream-notes.md +23 -0
  282. package/ui-ux-design/skills/interface-design/ORIGINAL.md +16 -0
  283. package/ui-ux-design/skills/interface-design/SKILL.md +41 -0
  284. package/ui-ux-design/skills/interface-design/references/commands/audit.md +40 -0
  285. package/ui-ux-design/skills/interface-design/references/commands/critique.md +21 -0
  286. package/ui-ux-design/skills/interface-design/references/commands/extract.md +34 -0
  287. package/ui-ux-design/skills/interface-design/references/commands/init.md +31 -0
  288. package/ui-ux-design/skills/interface-design/references/commands/status.md +22 -0
  289. package/ui-ux-design/skills/interface-design/references/examples/system-precision.md +29 -0
  290. package/ui-ux-design/skills/interface-design/references/examples/system-warmth.md +29 -0
  291. package/ui-ux-design/skills/interface-design/references/system-template.md +57 -0
  292. package/ui-ux-design/skills/shadcn-ui/README.md +244 -0
  293. package/ui-ux-design/skills/shadcn-ui/SKILL.md +333 -0
  294. package/ui-ux-design/skills/shadcn-ui/examples/auth-layout.tsx +177 -0
  295. package/ui-ux-design/skills/shadcn-ui/examples/data-table.tsx +313 -0
  296. package/ui-ux-design/skills/shadcn-ui/examples/form-pattern.tsx +177 -0
  297. package/ui-ux-design/skills/shadcn-ui/resources/component-catalog.md +481 -0
  298. package/ui-ux-design/skills/shadcn-ui/resources/customization-guide.md +516 -0
  299. package/ui-ux-design/skills/shadcn-ui/resources/migration-guide.md +463 -0
  300. package/ui-ux-design/skills/shadcn-ui/resources/setup-guide.md +412 -0
  301. package/ui-ux-design/skills/shadcn-ui/scripts/verify-setup.sh +134 -0
  302. package/ui-ux-design/skills/ui-ux-design/SKILL.md +171 -0
  303. package/ui-ux-design/skills/ui-ux-design/references/brand-and-voice.md +78 -0
  304. package/ui-ux-design/skills/ui-ux-design/references/chrome-mobile-test-matrix.md +137 -0
  305. package/ui-ux-design/skills/ui-ux-design/references/components-and-states.md +112 -0
  306. package/ui-ux-design/skills/ui-ux-design/references/delight-and-motion.md +54 -0
  307. package/ui-ux-design/skills/ui-ux-design/references/foundations.md +145 -0
  308. package/ui-ux-design/skills/ui-ux-design/references/inclusive-ai-imagery.md +57 -0
  309. package/ui-ux-design/skills/ui-ux-design/references/kole-jain-uiux-concepts.md +104 -0
  310. package/ui-ux-design/skills/ui-ux-design/references/kuinetic-reference.md +184 -0
  311. package/ui-ux-design/skills/ui-ux-design/references/openai-frontend-skill.md +139 -0
  312. package/ui-ux-design/skills/ui-ux-design/references/premium-ui.md +55 -0
  313. package/ui-ux-design/skills/ui-ux-design/references/research-and-validation.md +88 -0
  314. package/ui-ux-design/skills/ui-ux-design/references/sam-crawford-premium-websites.md +103 -0
  315. package/ui-ux-design/skills/ui-ux-design/references/self-made-web-designer-core-skills.md +119 -0
  316. package/ui-ux-design/skills/ui-ux-design/references/ui-animation.md +173 -0
  317. package/ui-ux-design/skills/ui-ux-design/references/ui-loop.md +234 -0
  318. package/ui-ux-design/skills/ui-ux-design/references/visual-storytelling.md +54 -0
  319. package/ui-ux-design/skills/vercel-web-design-guidelines/SKILL.md +39 -0
  320. package/ui-ux-design/skills/web-compliance/SKILL.md +134 -0
  321. package/ui-ux-design/skills/web-compliance/references/audit-evidence.md +59 -0
  322. package/vercel/NOTES.md +23 -0
  323. package/vercel/mcp.json +4 -0
  324. package/vercel/object-stores/vercel-blob.mjs +147 -0
  325. package/vercel/plugin.json +47 -0
  326. package/vercel/skills/vercel/SKILL.md +48 -0
  327. package/vercel/targets/vercel.mjs +586 -0
  328. package/vercel/tovu-consent.json +6 -0
  329. package/vercel/tovu-deploy-targets.json +219 -0
  330. package/vercel/tovu-object-stores.json +10 -0
  331. package/wordpress/NOTES.md +33 -0
  332. package/wordpress/plugin.json +30 -0
  333. package/wordpress/skills/wordpress/SKILL.md +43 -0
  334. package/wordpress/skills/wordpress/references/free-site-redirect.md +46 -0
  335. package/wordpress/skills/wordpress/references/subdomain.md +66 -0
@@ -0,0 +1,249 @@
1
+ ---
2
+ name: github
3
+ description: Work against a GitHub repository through this workspace's own saved credentials — write and update files in one atomic commit, dispatch and follow a GitHub Actions run, read a failed run's logs, commit the site's rendered static export, back up the site itself to a private repository, deploy the host's server through its GitHub Actions deploy workflow — with no git, no gh CLI, and no token ever passing through the assistant. Encodes the rules generic GitHub knowledge gets wrong here: a 204 dispatch means queued and never deployed, a workflow only fires on the branch its own trigger names, a repository secret is always the human's step, a 403 on an org-wide listing is a normal app-scoped-token boundary rather than a broken credential, and editing an existing file means diffing the MODIFIED files and not only the added and deleted ones.
4
+ ---
5
+
6
+ # GitHub, through the site's saved credentials
7
+
8
+ ## Connection card
9
+
10
+ Choose the card yourself from its `usedFor` list. Reuse a saved key or working sign-in for that
11
+ task. Never offer a replacement unless the person asks.
12
+
13
+ Open **Connect GitHub** with `credential_save {kind:"plugin-provider",target:"github"}`; it saves the API credential labelled `github`. For `github-source-control`, use `credential_save {kind:"plugin-provider",target:"github-source-control"}`; it saves through the source-control owner. For Pages hosting use the `github-pages` plugin’s card. These remain distinct save contracts. Each card names the repository permissions and links to fine-grained token creation. Never collect a token in chat.
14
+
15
+ ## Scope
16
+
17
+ This plugin owns **GitHub**: repositories, commits, branches, Actions, and the token and permission
18
+ semantics behind all of them. It owns nothing else.
19
+
20
+ It knows nothing about where a build is *deployed to*. Fly, Render, Railway, a container registry,
21
+ a VPS — none of that is here, and a rule that only makes sense for one host does not belong here.
22
+ A host-specific procedure (the bundled `fly` plugin's server deploy is the one that ships
23
+ today) is expected to describe its own hosting rules and then hand the GitHub half to this
24
+ document. That split is deliberate: every
25
+ skill of every enabled plugin reaches the assistant's prompt at the same time, so the same rule
26
+ written twice, slightly differently, becomes a contradiction rather than emphasis.
27
+
28
+ ---
29
+
30
+ ## Which job is this? Source control or a deploy
31
+
32
+ Decide this first; the two jobs use different tools.
33
+
34
+ - **Source control and backup** — write files into a repository, commit the site's rendered export,
35
+ back up the site, or start and follow any other workflow: the tools in the rest of this document.
36
+ - **Deploying the host's server with GitHub Actions** — use the deployment tools with platform
37
+ `github-actions`, never a hand-built dispatch. Call `deployment_ops_deploy` with target
38
+ `owner/repo` and the branch or tag. It resolves the ref to a full SHA and dispatches the host's
39
+ deploy workflow pinned to that commit; the host guidance describes that workflow's own inputs and
40
+ refusals. Say which commit will build. A started deploy is queued, never deployed: follow it with
41
+ `deployment_ops_wait` (pass the returned runId) until `finished`, then check the live site. Use
42
+ `deployment_ops_status` and `deployment_ops_logs` to find a failed job and step. Never retry a
43
+ deploy whose connection dropped before checking `deployment_ops_status`. The saved
44
+ `api.github.com` credential needs Actions write. Setting up the server host itself (its config,
45
+ volume and secrets) is the host plugin's job, not this one's.
46
+
47
+ ---
48
+
49
+ ## What you are allowed to use, and what does not exist here
50
+
51
+ Two native host tools do everything below. **This plugin ships no MCP server and adds no tool.**
52
+ Its deploy half is only the `github-actions` platform behind the core `deployment_ops_*` tools.
53
+
54
+ | Tool | What it is |
55
+ |---|---|
56
+ | `custom_credential_make_request` | One authenticated `GET`/`POST`/`PUT`/`PATCH`/`DELETE` to GitHub's REST API through a saved credential. You pass a `label` and a **full absolute URL**; the server injects the real `Authorization` header. |
57
+ | `custom_credential_write_files` | A human-confirmed, atomic write of 1–25 named files onto an **existing** branch (blob → tree → commit → non-force ref update). |
58
+
59
+ Two more exist for a narrower job — `source_control_get_capabilities` and
60
+ `source_control_execute_commit` — and they are **not** general-purpose repo writes. See
61
+ `references/source-control.md` before you reach for either; the distinction between them and
62
+ `custom_credential_write_files` is the single easiest thing to get wrong in this document.
63
+
64
+ And two back up the site itself — `site_backup_plan`, then `site_backup_push` — into a private
65
+ repository. See `references/site-backup.md`.
66
+
67
+ There is no `git`, no `gh`, and no shell path. **Never shell out to `curl`, `wget`, or `git` to
68
+ talk to GitHub.** A raw shell request bypasses the saved-credential store entirely and either
69
+ fails outright or forces a token into your context to make it work — which is exactly the thing
70
+ the store exists to prevent.
71
+
72
+ ### You do not choose the host
73
+
74
+ `custom_credential_make_request` refuses any URL whose host is not on that credential's own saved
75
+ allowlist (its base URL plus any saved additional hosts), **before any request is sent**. This is
76
+ not a limitation to route around. It is the property that makes an agent-held credential safe at
77
+ all: the human decided, once, at save time, which origins this token may ever reach.
78
+
79
+ So: build every URL from `https://api.github.com` (or whatever base the credential actually
80
+ saved — GitHub Enterprise has its own). If a call is refused, the error names the hosts that
81
+ *are* allowed. Read it and use one; do not try a different host to see what sticks.
82
+
83
+ To find the label, call `content_read.custom_credential` with `{}`. It returns each saved
84
+ credential's label, category, base URL and additional hosts — never a token. A workspace with a
85
+ credential labelled `github` is the expected case, but do not assume the label: read it.
86
+
87
+ ---
88
+
89
+ ## The rules
90
+
91
+ These are the reason this plugin exists. Each one has cost a real debugging session.
92
+
93
+ ### Rule 1 — A repository secret is ALWAYS the human's step. This is not negotiable.
94
+
95
+ Creating or updating a GitHub Actions secret through the API requires encrypting the value against
96
+ the repository's own public key. To do that, **the secret value would have to pass through your
97
+ context** — you would have to hold the plaintext token in order to encrypt it.
98
+
99
+ That is not an inconvenience on the way to a shortcut. **It is the failure mode.** The entire
100
+ saved-credential design exists so a secret never reaches the assistant, and a step that requires
101
+ holding one is a step the assistant does not perform, no matter how much friction it saves.
102
+
103
+ So you never call `PUT /repos/{owner}/{repo}/actions/secrets/{name}`, you never fetch
104
+ `.../actions/secrets/public-key` in order to encrypt something, and you never ask a human to paste
105
+ a token into the chat so you can do it for them. You hand them the exact instruction instead:
106
+
107
+ > Go to **Settings → Secrets and variables → Actions → New repository secret** in
108
+ > `<owner>/<repo>`. Name it exactly `<SECRET_NAME>`. Paste only the value — do not commit it
109
+ > anywhere, and do not paste it into this chat.
110
+
111
+ Then **wait for them to confirm.** Do not dispatch a workflow that needs a secret before they have
112
+ said it is set: the run fails on the runner in a way that reads like a config problem rather than a
113
+ missing secret, and you will debug the wrong thing.
114
+
115
+ The same rule covers environment secrets, organization secrets, and Dependabot secrets. Reading
116
+ which secret *names* exist (`GET .../actions/secrets`) is fine — GitHub never returns a value — and
117
+ is a genuinely useful way to confirm a human's "I set it" without asking twice.
118
+
119
+ ### Rule 2 — A 204 from a workflow dispatch means QUEUED. It does not mean anything ran.
120
+
121
+ `POST /repos/{owner}/{repo}/actions/workflows/{file}/dispatches` returns **204 with an empty body**
122
+ on success. All that 204 asserts is that GitHub accepted the request.
123
+
124
+ Nothing has built. Nothing has deployed. Nothing has even started — the run may not appear in the
125
+ runs list for a second or two, and it may sit `queued` behind another run after that.
126
+
127
+ **Never report success at the dispatch.** Report "queued", then follow the run
128
+ (`references/actions.md` has the poll loop and how to read a failure). Say what you actually
129
+ observed, at the stage you observed it.
130
+
131
+ ### Rule 3 — A workflow only fires on the branch its own trigger names.
132
+
133
+ A workflow's `on: push:` names branches. A push to any other branch does **nothing** — no run, no
134
+ error, no warning. The same is true of `workflow_dispatch`: the `ref` you dispatch against must be
135
+ a branch the workflow file exists on, and GitHub reads the workflow definition *from that ref*.
136
+
137
+ Two failure shapes follow, and both look like "the workflow is broken":
138
+
139
+ - You wrote the workflow onto a branch its own `push:` trigger does not list, pushed, and nothing
140
+ happened. Nothing is broken; the trigger simply did not match.
141
+ - You dispatched against a `ref` where the workflow file does not exist yet. GitHub returns
142
+ **422**, not 404, and the message is about the workflow rather than the ref.
143
+
144
+ So before you push or dispatch: read the workflow's own trigger, and name the branch explicitly.
145
+ Never assume `main`; a repository's default branch is a fact to look up
146
+ (`GET /repos/{owner}/{repo}` → `default_branch`), not a convention to rely on.
147
+
148
+ ### Rule 4 — When you EDIT an existing file, diff the MODIFIED files. Not just added and deleted.
149
+
150
+ This one has already cost two silent production failures.
151
+
152
+ A history force-push once rewrote a workflow file and dropped two `--build-arg` flags from it. A
153
+ review that looked at which files were **added** and which were **deleted** saw nothing wrong —
154
+ the file was neither. It was modified, and the modification quietly removed two load-bearing lines.
155
+ Two deploys failed before anyone connected the two facts.
156
+
157
+ `custom_credential_write_files` replaces a file's **entire content**; it does not patch. So when
158
+ you are updating a file that already exists:
159
+
160
+ 1. Read the current content first (`GET /repos/{owner}/{repo}/contents/{path}?ref={branch}`,
161
+ which returns base64, or the raw blob via the Git Data API).
162
+ 2. Produce the new content from what is actually there — never from memory, and never from a
163
+ template you assume matches.
164
+ 3. Before writing, state what changed, **line by line, including every line you removed.**
165
+
166
+ The confirmation dialog names each path as a create or an update, resolved against the branch's
167
+ real current state. An "update" label is your cue that a full-content replacement is about to
168
+ happen and that everything you did not carry forward is about to be gone.
169
+
170
+ ### Rule 5 — A 403 on an org-wide or account-wide listing is a permission BOUNDARY, not a broken credential.
171
+
172
+ Many real tokens are scoped to a single repository or a single app. Such a token can fully manage
173
+ its own resource and still **403 on any call that enumerates an organization or an account** — the
174
+ org's repositories, the account's installations, every-app-in-the-org listings.
175
+
176
+ That 403 looks *exactly* like an expired, revoked, or wrong-scoped credential. It is neither.
177
+ Misreading it once cost a full debugging session and nearly caused a working credential to be
178
+ replaced.
179
+
180
+ The rule: **prefer per-resource endpoints over listings.** If you know the `owner/repo`, ask about
181
+ that repository directly. Resolve the identifier from the human, from a file already in the repo,
182
+ or from the conversation — never by listing the org and searching it. If you genuinely have no
183
+ identifier, ask; a question costs one turn, a wrong diagnosis costs a session.
184
+
185
+ If a call does come back 401 or 403, **read the `authDiagnostic` field on the result before
186
+ reporting a bare failure**, follow the remedy it names, and retry at most **once**. There is
187
+ deliberately no diagnostic hint on a 403 at all — 403 covers scopes, policy, and missing headers,
188
+ so any guess would be a false lead. Report the failure and GitHub's own message plainly.
189
+
190
+ ### Rule 6 — Never print, echo, or reconstruct a secret.
191
+
192
+ Not in a file you write, not in a commit message, not in a summary of what the human just did, not
193
+ "redacted" with the first four characters showing. If a secret value must exist, the human types
194
+ it — into GitHub's own secret form, or into the host's credential form's masked field.
195
+
196
+ Nothing in this plugin's procedures requires you to see one, which is what makes this rule cheap to
197
+ keep.
198
+
199
+ ---
200
+
201
+ ## Choosing the right tool
202
+
203
+ Answer one question first: **is this app source, or is it the site's rendered output?**
204
+
205
+ | You want to… | Use |
206
+ |---|---|
207
+ | Add or update named files — a config file, a workflow, a script, a Dockerfile | `custom_credential_write_files` |
208
+ | Read anything at all from GitHub | `custom_credential_make_request` (`GET`) |
209
+ | Deploy the host's server through its deploy workflow | `deployment_ops_deploy` with platform `github-actions` — see "Which job is this?" above |
210
+ | Start any other workflow, or follow a run | `custom_credential_make_request` — see `references/actions.md` |
211
+ | Back up the **site itself** (database, media, themes, plugins, settings) into a private repo | `site_backup_plan`, then `site_backup_push` — see `references/site-backup.md` |
212
+ | Publish the **site's rendered static export** into a repo | `source_control_execute_commit` — see `references/source-control.md` |
213
+
214
+ Conflating the last row with the rest wastes real work. `source_control_execute_commit` runs a
215
+ fresh static export of the site and commits the resulting HTML and assets, and it **deletes** paths
216
+ it previously wrote that the export no longer produces. It is a publishing target, not a way to put
217
+ a file in a repository. A container build needs app source, and a rendered export is not app
218
+ source — a build fed the wrong one either fails or, worse, succeeds and ships a site with no
219
+ server. `references/source-control.md` states the difference in full; read it before you use
220
+ either tool for the first time in a task.
221
+
222
+ ---
223
+
224
+ ## Reporting rules
225
+
226
+ - **Report the stage you actually reached.** Queued is queued. Confirmed-but-unrun is not written.
227
+ - **Name the branch, the repository, and the commit** in your result. A commit SHA and URL come
228
+ back from a successful write; use them rather than describing what you believe happened.
229
+ - **A declined confirmation is a real outcome, not an error.** Say the human declined and stop.
230
+ Do not re-raise the dialog to see if they change their mind.
231
+ - **Never re-dispatch on a hunch.** A second run queued behind a broken one wastes the human's
232
+ time and tells you nothing new.
233
+ - **Say what you left unverified.** A value you guessed, a branch you assumed, a placeholder you
234
+ did not replace — each is a thing the human needs to know, not a detail.
235
+
236
+ ## References
237
+
238
+ - `references/repo-files.md` — writing and updating files: the confirmation dialog, the limits,
239
+ every refusal reason, the workflow-path warning, and the read-then-replace procedure for edits.
240
+ - `references/actions.md` — dispatching a workflow, polling a run, reading a failed run's logs,
241
+ and telling the distinct failure signatures apart.
242
+ - `references/auth-and-tokens.md` — what a saved GitHub credential can and cannot do, scopes,
243
+ `authDiagnostic`, rate limits, and why repository secrets are the human's step.
244
+ - `references/source-control.md` — `source_control_execute_commit` versus
245
+ `custom_credential_write_files`: two different credential stores, two different jobs, and the
246
+ app-source-versus-rendered-export distinction.
247
+ - `references/site-backup.md` — backing up the site itself: plan then push, private repositories
248
+ only, what the dialog shows, the limits, every code and what to tell the human, and why a refused
249
+ push is planned again rather than forced.
@@ -0,0 +1,224 @@
1
+ # GitHub Actions: dispatch, follow, diagnose
2
+
3
+ Everything here goes through `custom_credential_make_request` against the saved GitHub credential.
4
+ Nothing here needs a new tool, and nothing here needs a shell.
5
+
6
+ ---
7
+
8
+ ## Before you dispatch anything
9
+
10
+ Three facts, none of which you may guess:
11
+
12
+ 1. **The repository** — `owner/repo`, exactly.
13
+ 2. **The workflow** — its filename (`deploy.yml`) or its numeric id. The filename is what a human
14
+ recognizes, so prefer it.
15
+ 3. **The ref** — the branch to run on. GitHub reads the workflow definition *from that ref*, so the
16
+ workflow file must already exist there. `GET /repos/{owner}/{repo}` returns `default_branch` if
17
+ you need it; do not assume `main`. And naming the ref is not knowing it — resolve it to a commit
18
+ before you dispatch, per the section below.
19
+
20
+ And one check worth its single call: confirm the workflow is actually registered.
21
+
22
+ ```
23
+ custom_credential_make_request({
24
+ label: "github",
25
+ method: "GET",
26
+ url: "https://api.github.com/repos/<owner>/<repo>/actions/workflows"
27
+ })
28
+ ```
29
+
30
+ Each entry carries `id`, `name`, `path`, and `state`. A workflow whose `state` is
31
+ `disabled_manually` or `disabled_inactivity` accepts a dispatch and then never runs — worth
32
+ catching here rather than in a confused poll loop ten minutes later.
33
+
34
+ If a file you just wrote is not in that list, GitHub has not picked it up yet, or it is not on the
35
+ ref you are looking at. Do not dispatch into that gap.
36
+
37
+ ---
38
+
39
+ ## Resolve the ref to a commit, and say which commit, before you dispatch
40
+
41
+ **A branch name is not a commit.** `main` reads as the same string on the day your work lands on it
42
+ and on a day it is a month behind — the name cannot tell those two apart, and neither can the human,
43
+ unless you tell them. One GET turns the name into a fact:
44
+
45
+ ```
46
+ custom_credential_make_request({
47
+ label: "github",
48
+ method: "GET",
49
+ url: "https://api.github.com/repos/<owner>/<repo>/branches/<ref>"
50
+ })
51
+ ```
52
+
53
+ Three fields off that response:
54
+
55
+ | Field | What it gives you |
56
+ |---|---|
57
+ | `name` | The ref, confirmed to exist. A 404 here is the same missing ref the dispatch would have returned as a **422**, caught one call earlier and in a message that names it plainly. |
58
+ | `commit.sha` | The exact commit this run will build. |
59
+ | `commit.commit.committer.date` | When that commit landed on the ref. |
60
+
61
+ **State all three before you POST the dispatch**, with the age in plain words:
62
+
63
+ > Deploying `main` @ `f2997c6e` — committed 2026-09-11, 7 days ago.
64
+
65
+ The date is the half that does the work. A tip a week old, told to someone who has been working all
66
+ week, is the visible shape of *"this is about to ship something other than what you just wrote"* —
67
+ and it is one line, at the only moment it is still cheap.
68
+
69
+ **This step reports. It never blocks.** Say what the ref resolves to, then dispatch. Do not ask for
70
+ confirmation, do not refuse, and do not wait to be told to continue. Whether this deploy should go
71
+ out is the human's call, and they can only make it if you have said what it is.
72
+
73
+ ### One more comparison, already paid for
74
+
75
+ The runs list you will poll *after* the dispatch also answers a question worth asking *before* it:
76
+
77
+ ```
78
+ custom_credential_make_request({
79
+ label: "github",
80
+ method: "GET",
81
+ url: "https://api.github.com/repos/<owner>/<repo>/actions/workflows/<file.yml>/runs?per_page=1"
82
+ })
83
+ ```
84
+
85
+ If `workflow_runs[0].head_sha` equals the `commit.sha` you just resolved, this run will build
86
+ **byte-identical source to the last one**. Say so, in those words, before you dispatch. A green run
87
+ that changes nothing is the most confusing outcome anything in this document can produce, and it is
88
+ fully predictable one call ahead of it happening.
89
+
90
+ ### What you cannot compare against
91
+
92
+ The human's own working copy. There is no `git` and no shell here — their local branch, their
93
+ uncommitted work, and whether they have pushed any of it are all invisible to you. Do not guess at
94
+ them, and do not imply you checked. Give them the ref, the SHA and its date; if that tip reads older
95
+ than the conversation you are having, say the date out loud and let them draw the conclusion.
96
+
97
+ ---
98
+
99
+ ## Dispatch
100
+
101
+ ```
102
+ custom_credential_make_request({
103
+ label: "github",
104
+ method: "POST",
105
+ url: "https://api.github.com/repos/<owner>/<repo>/actions/workflows/<file.yml>/dispatches",
106
+ headers: { "Accept": "application/vnd.github+json", "Content-Type": "application/json" },
107
+ body: "{\"ref\":\"<branch>\"}"
108
+ })
109
+ ```
110
+
111
+ **Success is 204 with an empty body, and 204 means QUEUED.** Not built, not deployed, not started.
112
+ This is the single most reported-wrong result in this whole document. Say "queued", then follow it.
113
+
114
+ The failures you will actually see, and what each one means:
115
+
116
+ | Status | What it actually is |
117
+ |---|---|
118
+ | **404** | The workflow file does not exist at that path — *or* the token cannot see this repository at all. Both look identical here. Confirm the repo with `GET /repos/{owner}/{repo}` before you assume the path is wrong. |
119
+ | **422** | The workflow exists but has no `workflow_dispatch` trigger, or the `ref` you named does not exist. GitHub's message names which; read it rather than retrying. |
120
+ | **403** | Usually the token lacks Actions write. Occasionally an org policy. See `auth-and-tokens.md`. |
121
+
122
+ Never retry a 422 with a different guess. Fix the actual cause.
123
+
124
+ ---
125
+
126
+ ## Follow the run
127
+
128
+ There is no callback and no webhook here. You poll.
129
+
130
+ ```
131
+ custom_credential_make_request({
132
+ label: "github",
133
+ method: "GET",
134
+ url: "https://api.github.com/repos/<owner>/<repo>/actions/workflows/<file.yml>/runs?per_page=1"
135
+ })
136
+ ```
137
+
138
+ Read `workflow_runs[0]`: `id`, `status`, `conclusion`, `html_url`, `head_branch`, `head_sha`,
139
+ `created_at`. `head_sha` is the commit that actually built: check it against the SHA you resolved
140
+ before dispatching, and report it next to the conclusion. The two differ when someone pushed
141
+ between your read and your dispatch — a fact to state, not a problem to solve.
142
+
143
+ **Two things to get right before you interpret it:**
144
+
145
+ - The newest run may not be yours. Check `created_at` against when you dispatched, and check
146
+ `head_branch`. Reporting on someone else's run is worse than reporting nothing.
147
+ - `status` and `conclusion` are different fields. `status` is `queued` / `in_progress` /
148
+ `completed`. `conclusion` is `null` until `status` is `completed`, and only then is it
149
+ `success` / `failure` / `cancelled` / `timed_out` / `skipped` / `action_required`.
150
+
151
+ **A run sitting in `queued` is not stuck.** A concurrency group that queues rather than cancels
152
+ will hold a run behind another one for as long as that one takes. Say "queued behind an earlier
153
+ run" — do not diagnose a hang, and do not dispatch a second run to "get things moving": that
154
+ lengthens the queue you are complaining about.
155
+
156
+ Poll a handful of times with a real gap between calls, and report what you actually see each time.
157
+ If it is still running when you run out of patience, say so and give the human `html_url`. An
158
+ honest "still in progress after N checks, here is the link" is a better answer than a guess.
159
+
160
+ ---
161
+
162
+ ## When a run fails
163
+
164
+ Do not report "the workflow failed" and stop. Find the step.
165
+
166
+ ```
167
+ custom_credential_make_request({
168
+ label: "github",
169
+ method: "GET",
170
+ url: "https://api.github.com/repos/<owner>/<repo>/actions/runs/<run_id>/jobs"
171
+ })
172
+ ```
173
+
174
+ Each job carries `name`, `status`, `conclusion`, and a `steps` array where every step has its own
175
+ `name`, `number`, and `conclusion`. **The first step whose `conclusion` is `failure` is the
176
+ answer** — everything after it is `skipped`, and reporting a skipped step as the failure sends the
177
+ human to the wrong place.
178
+
179
+ Report: the job name, the step name and number, and the run's `html_url`.
180
+
181
+ ### The raw-logs endpoint does not work from here, and that is by design
182
+
183
+ `GET /repos/{owner}/{repo}/actions/jobs/{job_id}/logs` does not return logs. It returns a **302**
184
+ whose `Location` points at an object-store host.
185
+
186
+ `custom_credential_make_request` follows **zero** redirects, and that object-store host is not on
187
+ the credential's saved allowlist, so you cannot follow it either. You will see the 302 and its
188
+ `Location` header, and that is where it ends. This is not a bug to work around — following an
189
+ arbitrary redirect target with a credential attached is exactly the egress hazard the single-hop
190
+ policy exists to close.
191
+
192
+ So the honest procedure is:
193
+
194
+ 1. Get the failing job and step from the `/jobs` response above. That is genuinely most of what a
195
+ log would tell you.
196
+ 2. Give the human the run's `html_url` and name the failing step, so one click lands them on it.
197
+ 3. If the actual log text matters, **ask them to paste the relevant lines.** Do not claim you read
198
+ logs you did not read.
199
+
200
+ ### Telling failure signatures apart
201
+
202
+ These four are the ones that get confused with each other, and each needs a different next move:
203
+
204
+ | Signature | What it means | What to do |
205
+ |---|---|---|
206
+ | The run never appears | The trigger did not match, or the file is not on that ref | Re-read the workflow's own `on:` block and the ref you pushed to. Do not re-dispatch. |
207
+ | Fails immediately, in the first seconds, on a setup or auth step | A missing or wrong repository secret | Confirm with the human that the secret is set, by exact name. `GET .../actions/secrets` lists names (never values). |
208
+ | Fails mid-run in a build or deploy step | A real error in the thing being built or shipped | Name the step and hand over the run URL. This is not a GitHub problem. |
209
+ | `conclusion: "action_required"` | Waiting on a human — an approval, or a first-time contributor gate | Tell the human it is waiting on them, and where. Nothing you can do moves it. |
210
+
211
+ A cancelled run and a timed-out run are also distinct from a failure, and both are commonly a
212
+ human's or a queue's doing rather than a defect. Read `conclusion` before you write the word
213
+ "failed".
214
+
215
+ ---
216
+
217
+ ## Rate limits
218
+
219
+ Every response carries `x-ratelimit-remaining` and `x-ratelimit-reset`. A **403 with
220
+ `x-ratelimit-remaining: 0`** is a rate limit, not a permission problem — and telling a human their
221
+ token is broken when they are merely throttled is a real, avoidable mistake.
222
+
223
+ Polling is the only thing here that makes a meaningful number of calls, which is the practical
224
+ argument for a real gap between polls rather than a tight loop.
@@ -0,0 +1,140 @@
1
+ # Tokens, scopes, and permission boundaries
2
+
3
+ ## Where the token lives, and why you never see it
4
+
5
+ Open `credential_save {kind:"plugin-provider",target:"github"}` for the plugin’s own GitHub card. It saves label `github` and base URL `https://api.github.com`, with the token sealed server-side. Existing rows can still be rotated by their exact saved label.
6
+
7
+ You name the **label**. The server resolves the credential and injects the real `Authorization`
8
+ header itself. The token never appears in a tool's input, in a tool's output, or anywhere in your
9
+ context.
10
+
11
+ To discover what is saved, call `content_read.custom_credential` with `{}`. It returns
12
+ each credential's label, category, base URL, and additional hosts — never a token, and never a
13
+ saved username. An empty list is the signal to ask a human to save one, not to look for another
14
+ way in.
15
+
16
+ Two headers you must never set on `custom_credential_make_request`: `Authorization` and `Cookie`
17
+ (also `Host` and `Proxy-Authorization`). The server injects the real one, and a call trying to set
18
+ any of these is refused.
19
+
20
+ ---
21
+
22
+ ## The host allowlist is a feature
23
+
24
+ Every URL you pass must have a host on that credential's own saved list — its base URL plus any
25
+ saved additional hosts. Anything else is refused **before any request is sent**, and the error
26
+ names which hosts *are* allowed.
27
+
28
+ This is the property that makes an agent-held credential safe: the human decided once, at save
29
+ time, which origins this token may ever reach. Do not try alternate hosts to find one that works.
30
+ Read the error, use a named host, or ask.
31
+
32
+ The same policy follows **zero redirects**. A GitHub endpoint that answers with a 302 to an
33
+ object-store host (the Actions job-logs endpoint is the one you will actually hit) simply ends
34
+ there. See `actions.md`.
35
+
36
+ ---
37
+
38
+ ## Repository secrets are the human's step. Always.
39
+
40
+ Writing a GitHub Actions secret through the API requires encrypting the value against the
41
+ repository's public key — which requires **holding the plaintext value**, in your context, to
42
+ encrypt it.
43
+
44
+ That is the failure mode the entire credential design exists to prevent. It is not a shortcut you
45
+ are being denied; it is the thing that must not happen.
46
+
47
+ So you never:
48
+
49
+ - call `PUT /repos/{owner}/{repo}/actions/secrets/{name}`,
50
+ - fetch `GET /repos/{owner}/{repo}/actions/secrets/public-key` in order to encrypt something,
51
+ - ask a human to paste a token into chat so you can set it for them,
52
+ - or accept one they volunteer. If a secret appears in the conversation anyway, do not use it, do
53
+ not repeat it, and tell them to rotate it.
54
+
55
+ You hand them this instead:
56
+
57
+ > **Settings → Secrets and variables → Actions → New repository secret** in `<owner>/<repo>`.
58
+ > Name it exactly `<SECRET_NAME>`. Paste only the value — do not commit it anywhere, and do not
59
+ > paste it into this chat.
60
+
61
+ Then **wait for confirmation before dispatching anything that needs it.** A run that starts without
62
+ its secret fails on the runner in a way that reads like a config problem, and you will spend the
63
+ next twenty minutes debugging the wrong thing.
64
+
65
+ What you *may* do: **list secret names.** `GET /repos/{owner}/{repo}/actions/secrets` returns names
66
+ and timestamps and never a value. It is the honest way to verify a human's "I set it" without
67
+ asking them twice, and it catches the common typo of a name that does not match the workflow's
68
+ `${{ secrets.… }}` reference.
69
+
70
+ Organization secrets, environment secrets, and Dependabot secrets are all covered by the same rule.
71
+
72
+ ---
73
+
74
+ ## Scopes, and what a 403 actually means
75
+
76
+ **A 403 on an org-wide or account-wide listing endpoint is a normal permission boundary for an
77
+ app-scoped or repo-scoped token. It is not a broken credential.**
78
+
79
+ Misreading this cost a full debugging session once already, and nearly got a perfectly good
80
+ credential replaced. A token scoped to one repository can fully manage that repository and still
81
+ 403 on any call that enumerates an organization or an account.
82
+
83
+ The rule that follows: **prefer per-resource endpoints over listings.** Resolve `owner/repo` from
84
+ the human, from the conversation, or from a file already in the repository — never by listing an
85
+ org and searching it. If you have no identifier, ask. One question beats one wrong diagnosis.
86
+
87
+ Roughly what each capability needs, so you can say something useful when a 403 does appear:
88
+
89
+ | To do this | The token needs |
90
+ |---|---|
91
+ | Read a repository, its contents, its branches | read access to that repository |
92
+ | Write files, create commits, update a ref | **write** access to repository contents |
93
+ | Write anything under `.github/workflows/` | contents write **plus** workflow permission — a token without it is refused specifically on workflow paths and nowhere else, which is confusing if you do not know to look for it |
94
+ | Dispatch a workflow, read runs and jobs | Actions permission (read for following, write for dispatching) |
95
+ | Read secret **names** | Actions/secrets read |
96
+
97
+ The workflow-permission row is the one that surprises people: a write that succeeds for every other
98
+ path and fails only for `.github/workflows/…` is a scope problem, not a path problem.
99
+
100
+ ---
101
+
102
+ ## Reading `authDiagnostic`
103
+
104
+ A 401 or 403 response from `custom_credential_make_request` carries an `authDiagnostic` object
105
+ alongside GitHub's untouched `bodyText`. **Read it before reporting a bare failure.**
106
+
107
+ - On a **401** where the scheme sent was `Bearer` and no username is stored, `hint` names the one
108
+ narrow guess the system is willing to make: this provider may need HTTP Basic with a saved
109
+ username. Treat it as a hypothesis. Ask the human for the username, save it with
110
+ `custom_credential_set_username`, retry **once**. Never invent a username, and never loop past
111
+ one retry.
112
+ - When a username is already stored, there is no hint — the cause is something else and unguessable.
113
+ - On a **403 there is no hint at all**, deliberately. 403 covers scopes, org policy, rate limits,
114
+ and missing headers; a Basic-auth guess there would be a false lead rather than a hedge. Report
115
+ the failure and GitHub's own message plainly.
116
+
117
+ If you suspect the credential itself, `custom_credential_verify` checks one saved credential
118
+ against its own API, live, and reports `valid` / `invalid` / `unreachable`. **`unreachable` does
119
+ not mean the credential is bad** — it is a network failure. Do not tell a human to replace a token
120
+ over a DNS error.
121
+
122
+ ---
123
+
124
+ ## Rate limits
125
+
126
+ Every response carries `x-ratelimit-remaining` and `x-ratelimit-reset`. **A 403 with
127
+ `x-ratelimit-remaining: 0` is a rate limit**, and saying "your token is broken" when a human is
128
+ merely throttled is an avoidable, expensive mistake. Read the header before you diagnose.
129
+
130
+ Polling an Actions run is the only thing here that makes a meaningful number of calls — which is
131
+ the practical reason to leave a real gap between polls.
132
+
133
+ ---
134
+
135
+ ## The rule under all of the above
136
+
137
+ **Never print, echo, or reconstruct a secret.** Not in a file you write, not in a commit message,
138
+ not in a summary of what the human just did, not partially masked. Nothing in this plugin's
139
+ procedures requires you to hold one, which is what makes that rule cheap to keep and inexcusable to
140
+ break.