[{"data":1,"prerenderedAt":1888},["ShallowReactive",2],{"navigation_docs":3,"-reference-configuration-forges":575,"-reference-configuration-forges-surround":1883},[4,32,59,214,245,540],{"title":5,"path":6,"stem":7,"children":8},"Get started","\u002Fget-started","1.get-started",[9,12,16,20,24,28],{"title":10,"path":6,"stem":11},"Overview","1.get-started\u002Findex",{"title":13,"path":14,"stem":15},"Why Kraft","\u002Fget-started\u002Fwhy-kraft","1.get-started\u002F0.why-kraft",{"title":17,"path":18,"stem":19},"Install","\u002Fget-started\u002Finstall","1.get-started\u002F1.install",{"title":21,"path":22,"stem":23},"Your first work item","\u002Fget-started\u002Ffirst-work-item","1.get-started\u002F2.first-work-item",{"title":25,"path":26,"stem":27},"The real chain","\u002Fget-started\u002Fthe-real-chain","1.get-started\u002F3.the-real-chain",{"title":29,"path":30,"stem":31},"FAQ","\u002Fget-started\u002Ffaq","1.get-started\u002F4.faq",{"title":33,"path":34,"stem":35,"children":36},"Concepts","\u002Fconcepts","2.concepts",[37,39,43,47,51,55],{"title":10,"path":34,"stem":38},"2.concepts\u002Findex",{"title":40,"path":41,"stem":42},"How a work item runs","\u002Fconcepts\u002Fhow-a-work-item-runs","2.concepts\u002F1.how-a-work-item-runs",{"title":44,"path":45,"stem":46},"Caps and budgets","\u002Fconcepts\u002Fcaps-and-budgets","2.concepts\u002F2.caps-and-budgets",{"title":48,"path":49,"stem":50},"Why a permission gate","\u002Fconcepts\u002Fpermission-gate","2.concepts\u002F3.permission-gate",{"title":52,"path":53,"stem":54},"Vocabulary","\u002Fconcepts\u002Fvocabulary","2.concepts\u002F4.vocabulary",{"title":56,"path":57,"stem":58},"Where a step runs","\u002Fconcepts\u002Fwhere-a-step-runs","2.concepts\u002F5.where-a-step-runs",{"title":60,"path":61,"stem":62,"children":63},"Guides","\u002Fguides","3.guides",[64,66,104,130,152,210],{"title":10,"path":61,"stem":65},"3.guides\u002Findex",{"title":67,"path":68,"stem":69,"children":70},"Day to day","\u002Fguides\u002Fday-to-day","3.guides\u002F1.day-to-day\u002Findex",[71,72,76,80,84,88,92,96,100],{"title":10,"path":68,"stem":69},{"title":73,"path":74,"stem":75},"The setup wizard on first start","\u002Fguides\u002Fday-to-day\u002Ffirst-run","3.guides\u002F1.day-to-day\u002F2.first-run",{"title":77,"path":78,"stem":79},"File a work item","\u002Fguides\u002Fday-to-day\u002Ffile-a-work-item","3.guides\u002F1.day-to-day\u002F3.file-a-work-item",{"title":81,"path":82,"stem":83},"Use Kraft from your agent","\u002Fguides\u002Fday-to-day\u002Fagent-integration","3.guides\u002F1.day-to-day\u002F4.agent-integration",{"title":85,"path":86,"stem":87},"Reviewing a change","\u002Fguides\u002Fday-to-day\u002Freview-a-change","3.guides\u002F1.day-to-day\u002F5.review-a-change",{"title":89,"path":90,"stem":91},"Raise a cap on a stopped item","\u002Fguides\u002Fday-to-day\u002Fraise-a-cap","3.guides\u002F1.day-to-day\u002F6.raise-a-cap",{"title":93,"path":94,"stem":95},"Kraft for VS Code","\u002Fguides\u002Fday-to-day\u002Fvscode","3.guides\u002F1.day-to-day\u002F7.vscode",{"title":97,"path":98,"stem":99},"Kraft on a phone","\u002Fguides\u002Fday-to-day\u002Fkraft-on-a-phone","3.guides\u002F1.day-to-day\u002F8.kraft-on-a-phone",{"title":101,"path":102,"stem":103},"Get notified when an item needs you","\u002Fguides\u002Fday-to-day\u002Fnotifications","3.guides\u002F1.day-to-day\u002F9.notifications",{"title":105,"path":106,"stem":107,"children":108},"Customize and automate","\u002Fguides\u002Fcustomize","3.guides\u002F2.customize\u002Findex",[109,110,114,118,122,126],{"title":10,"path":106,"stem":107},{"title":111,"path":112,"stem":113},"Write your own chain","\u002Fguides\u002Fcustomize\u002Fwrite-your-own-chain","3.guides\u002F2.customize\u002F1.write-your-own-chain",{"title":115,"path":116,"stem":117},"Add a security review or a gate reviewer","\u002Fguides\u002Fcustomize\u002Fadd-review-agents","3.guides\u002F2.customize\u002F2.add-review-agents",{"title":119,"path":120,"stem":121},"Schedule or webhook work","\u002Fguides\u002Fcustomize\u002Fschedule-and-webhook-work","3.guides\u002F2.customize\u002F3.schedule-and-webhook-work",{"title":123,"path":124,"stem":125},"Share chains with add-ons","\u002Fguides\u002Fcustomize\u002Fshare-chains-with-addons","3.guides\u002F2.customize\u002F4.share-chains-with-addons",{"title":127,"path":128,"stem":129},"Publish an add-on","\u002Fguides\u002Fcustomize\u002Fpublish-an-add-on","3.guides\u002F2.customize\u002F5.publish-an-add-on",{"title":131,"path":132,"stem":133,"children":134},"Agents and harnesses","\u002Fguides\u002Fharnesses","3.guides\u002F3.harnesses\u002Findex",[135,136,140,144,148],{"title":10,"path":132,"stem":133},{"title":137,"path":138,"stem":139},"Switch a task to another harness","\u002Fguides\u002Fharnesses\u002Fswitch-harness","3.guides\u002F3.harnesses\u002F1.switch-harness",{"title":141,"path":142,"stem":143},"Add or override a harness","\u002Fguides\u002Fharnesses\u002Fadding-a-harness","3.guides\u002F3.harnesses\u002F2.adding-a-harness",{"title":145,"path":146,"stem":147},"Build a worker Kit","\u002Fguides\u002Fharnesses\u002Fworker-kit","3.guides\u002F3.harnesses\u002F3.worker-kit",{"title":149,"path":150,"stem":151},"Give a worker its login","\u002Fguides\u002Fharnesses\u002Fgive-a-worker-its-login","3.guides\u002F3.harnesses\u002F4.give-a-worker-its-login",{"title":153,"path":154,"stem":155,"children":156},"Run the server","\u002Fguides\u002Frun","3.guides\u002F4.run\u002Findex",[157,158,162,166,170,174,178,182,186,190,194,198,202,206],{"title":10,"path":154,"stem":155},{"title":159,"path":160,"stem":161},"Remote access","\u002Fguides\u002Frun\u002Fremote-access","3.guides\u002F4.run\u002F01.remote-access",{"title":163,"path":164,"stem":165},"Put a proxy in front of Kraft","\u002Fguides\u002Frun\u002Fput-a-proxy-in-front-of-kraft","3.guides\u002F4.run\u002F02.put-a-proxy-in-front-of-kraft",{"title":167,"path":168,"stem":169},"Restart Kraft without ending running steps","\u002Fguides\u002Frun\u002Frestart-kraft","3.guides\u002F4.run\u002F03.restart-kraft",{"title":171,"path":172,"stem":173},"Back up and restore the database","\u002Fguides\u002Frun\u002Fback-up-and-restore","3.guides\u002F4.run\u002F04.back-up-and-restore",{"title":175,"path":176,"stem":177},"Logs and disk space","\u002Fguides\u002Frun\u002Flogs-and-disk-space","3.guides\u002F4.run\u002F05.logs-and-disk-space",{"title":179,"path":180,"stem":181},"Run Kraft as a service","\u002Fguides\u002Frun\u002Frun-as-a-service","3.guides\u002F4.run\u002F06.run-as-a-service",{"title":183,"path":184,"stem":185},"Upgrade Kraft","\u002Fguides\u002Frun\u002Fupgrade-kraft","3.guides\u002F4.run\u002F07.upgrade-kraft",{"title":187,"path":188,"stem":189},"Upgrade your configuration","\u002Fguides\u002Frun\u002Fupgrade-your-configuration","3.guides\u002F4.run\u002F08.upgrade-your-configuration",{"title":191,"path":192,"stem":193},"Upgrade from 1.4","\u002Fguides\u002Frun\u002Fupgrade-from-1-4","3.guides\u002F4.run\u002F09.upgrade-from-1-4",{"title":195,"path":196,"stem":197},"Upgrade from 0.x or a release candidate","\u002Fguides\u002Frun\u002Fupgrade-from-0-x-or-a-release-candidate","3.guides\u002F4.run\u002F10.upgrade-from-0-x-or-a-release-candidate",{"title":199,"path":200,"stem":201},"Roll back to 1.4","\u002Fguides\u002Frun\u002Froll-back","3.guides\u002F4.run\u002F11.roll-back",{"title":203,"path":204,"stem":205},"Run items in your own checkout","\u002Fguides\u002Frun\u002Frun-items-in-place","3.guides\u002F4.run\u002F12.run-items-in-place",{"title":207,"path":208,"stem":209},"Run a step on another machine","\u002Fguides\u002Frun\u002Frun-a-step-on-another-machine","3.guides\u002F4.run\u002F13.run-a-step-on-another-machine",{"title":211,"path":212,"stem":213},"Kraft Lite","\u002Fguides\u002Fkraft-lite","3.guides\u002F5.kraft-lite",{"title":215,"path":216,"stem":217,"children":218},"Troubleshooting","\u002Ftroubleshooting","4.troubleshooting",[219,221,225,229,233,237,241],{"title":10,"path":216,"stem":220},"4.troubleshooting\u002Findex",{"title":222,"path":223,"stem":224},"Why did my item stop?","\u002Ftroubleshooting\u002Fwhy-did-my-item-stop","4.troubleshooting\u002F1.why-did-my-item-stop",{"title":226,"path":227,"stem":228},"Stop reasons in detail","\u002Ftroubleshooting\u002Fstop-reasons-in-detail","4.troubleshooting\u002F2.stop-reasons-in-detail",{"title":230,"path":231,"stem":232},"Starting and reaching Kraft","\u002Ftroubleshooting\u002Fstarting-and-reaching-kraft","4.troubleshooting\u002F3.starting-and-reaching-kraft",{"title":234,"path":235,"stem":236},"Doctor failures","\u002Ftroubleshooting\u002Fdoctor-failures","4.troubleshooting\u002F4.doctor-failures",{"title":238,"path":239,"stem":240},"Sandbox and Kit stops","\u002Ftroubleshooting\u002Fsandbox-and-kit-stops","4.troubleshooting\u002F5.sandbox-and-kit-stops",{"title":242,"path":243,"stem":244},"Add-on problems","\u002Ftroubleshooting\u002Faddon-problems","4.troubleshooting\u002F6.addon-problems",{"title":246,"path":247,"stem":248,"children":249},"Reference","\u002Freference","5.reference",[250,252,294,316,320,324,438,456,482,486,490,524,528,532,536],{"title":10,"path":247,"stem":251},"5.reference\u002Findex",{"title":253,"path":254,"stem":255,"children":256},"Web UI","\u002Freference\u002Fweb-ui","5.reference\u002F00.web-ui\u002Findex",[257,258,262,266,270,274,278,282,286,290],{"title":10,"path":254,"stem":255},{"title":259,"path":260,"stem":261},"Sidebar, search, and keyboard","\u002Freference\u002Fweb-ui\u002Fsidebar-search-and-keyboard","5.reference\u002F00.web-ui\u002F0.sidebar-search-and-keyboard",{"title":263,"path":264,"stem":265},"The board","\u002Freference\u002Fweb-ui\u002Fboard","5.reference\u002F00.web-ui\u002F1.board",{"title":267,"path":268,"stem":269},"An item's page","\u002Freference\u002Fweb-ui\u002Fitem-page","5.reference\u002F00.web-ui\u002F2.item-page",{"title":271,"path":272,"stem":273},"Fix loops and test scopes","\u002Freference\u002Fweb-ui\u002Ffix-loops-and-test-scopes","5.reference\u002F00.web-ui\u002F3.fix-loops-and-test-scopes",{"title":275,"path":276,"stem":277},"Config before an item starts","\u002Freference\u002Fweb-ui\u002Fconfig-before-start","5.reference\u002F00.web-ui\u002F4.config-before-start",{"title":279,"path":280,"stem":281},"The review page","\u002Freference\u002Fweb-ui\u002Freview-page","5.reference\u002F00.web-ui\u002F5.review-page",{"title":283,"path":284,"stem":285},"Templates and Settings","\u002Freference\u002Fweb-ui\u002Ftemplates-and-settings","5.reference\u002F00.web-ui\u002F6.templates-and-settings",{"title":287,"path":288,"stem":289},"Analytics","\u002Freference\u002Fweb-ui\u002Fanalytics","5.reference\u002F00.web-ui\u002F7.analytics",{"title":291,"path":292,"stem":293},"Cap stops and raises","\u002Freference\u002Fweb-ui\u002Fcap-stops-and-raises","5.reference\u002F00.web-ui\u002F8.cap-stops-and-raises",{"title":295,"path":296,"stem":297,"children":298},"CLI","\u002Freference\u002Fcli","5.reference\u002F01.cli\u002Findex",[299,300,304,308,312],{"title":10,"path":296,"stem":297},{"title":301,"path":302,"stem":303},"Item verbs","\u002Freference\u002Fcli\u002Fitem","5.reference\u002F01.cli\u002F2.item",{"title":305,"path":306,"stem":307},"View verbs","\u002Freference\u002Fcli\u002Fview","5.reference\u002F01.cli\u002F3.view",{"title":309,"path":310,"stem":311},"Repo verbs","\u002Freference\u002Fcli\u002Frepo","5.reference\u002F01.cli\u002F4.repo",{"title":313,"path":314,"stem":315},"Admin verbs","\u002Freference\u002Fcli\u002Fadmin","5.reference\u002F01.cli\u002F5.admin",{"title":317,"path":318,"stem":319},"Console","\u002Freference\u002Fconsole","5.reference\u002F01.console",{"title":321,"path":322,"stem":323},"Work item statuses","\u002Freference\u002Fstatuses","5.reference\u002F02.statuses",{"title":325,"path":326,"stem":327,"children":328},"Configuration","\u002Freference\u002Fconfiguration","5.reference\u002F03.configuration\u002Findex",[329,330,348,352,356,360,364,368,372,376,414,418,422,426,430,434],{"title":10,"path":326,"stem":327},{"title":331,"path":332,"stem":333,"children":334},"repos.yaml","\u002Freference\u002Fconfiguration\u002Frepos","5.reference\u002F03.configuration\u002F02.repos\u002Findex",[335,336,340,344],{"title":10,"path":332,"stem":333},{"title":337,"path":338,"stem":339},"How connect proposes commands","\u002Freference\u002Fconfiguration\u002Frepos\u002Fconnect-proposals","5.reference\u002F03.configuration\u002F02.repos\u002F1.connect-proposals",{"title":341,"path":342,"stem":343},"detectors.yaml","\u002Freference\u002Fconfiguration\u002Frepos\u002Fdetectors","5.reference\u002F03.configuration\u002F02.repos\u002F2.detectors",{"title":345,"path":346,"stem":347},"Workspaces","\u002Freference\u002Fconfiguration\u002Frepos\u002Fworkspaces","5.reference\u002F03.configuration\u002F02.repos\u002F3.workspaces",{"title":349,"path":350,"stem":351},"policy.yaml","\u002Freference\u002Fconfiguration\u002Fpolicy","5.reference\u002F03.configuration\u002F03.policy",{"title":353,"path":354,"stem":355},"Library and chains","\u002Freference\u002Fconfiguration\u002Flibrary-and-chains","5.reference\u002F03.configuration\u002F04.library-and-chains",{"title":357,"path":358,"stem":359},"harnesses.yaml","\u002Freference\u002Fconfiguration\u002Fharnesses-file","5.reference\u002F03.configuration\u002F05.harnesses-file",{"title":361,"path":362,"stem":363},"access.yaml","\u002Freference\u002Fconfiguration\u002Faccess","5.reference\u002F03.configuration\u002F06.access",{"title":365,"path":366,"stem":367},"intake.yaml","\u002Freference\u002Fconfiguration\u002Fintake","5.reference\u002F03.configuration\u002F07.intake",{"title":369,"path":370,"stem":371},"notify.yaml","\u002Freference\u002Fconfiguration\u002Fnotify","5.reference\u002F03.configuration\u002F08.notify",{"title":373,"path":374,"stem":375},"theme.yaml","\u002Freference\u002Fconfiguration\u002Ftheme","5.reference\u002F03.configuration\u002F09.theme",{"title":377,"path":378,"stem":379,"children":380},"Sandboxed workers","\u002Freference\u002Fconfiguration\u002Fsandbox","5.reference\u002F03.configuration\u002F10.sandbox\u002Findex",[381,382,386,390,394,398,402,406,410],{"title":10,"path":378,"stem":379},{"title":383,"path":384,"stem":385},"Resource limits","\u002Freference\u002Fconfiguration\u002Fsandbox\u002Fresource-limits","5.reference\u002F03.configuration\u002F10.sandbox\u002F1.resource-limits",{"title":387,"path":388,"stem":389},"Callbacks from a sandbox","\u002Freference\u002Fconfiguration\u002Fsandbox\u002Fcallbacks","5.reference\u002F03.configuration\u002F10.sandbox\u002F2.callbacks",{"title":391,"path":392,"stem":393},"Network policy","\u002Freference\u002Fconfiguration\u002Fsandbox\u002Fnetwork-policy","5.reference\u002F03.configuration\u002F10.sandbox\u002F3.network-policy",{"title":395,"path":396,"stem":397},"Credentials","\u002Freference\u002Fconfiguration\u002Fsandbox\u002Fcredentials","5.reference\u002F03.configuration\u002F10.sandbox\u002F4.credentials",{"title":399,"path":400,"stem":401},"Kits","\u002Freference\u002Fconfiguration\u002Fsandbox\u002Fkits","5.reference\u002F03.configuration\u002F10.sandbox\u002F5.kits",{"title":403,"path":404,"stem":405},"sandbox.yaml","\u002Freference\u002Fconfiguration\u002Fsandbox\u002Fsandbox-yaml","5.reference\u002F03.configuration\u002F10.sandbox\u002F6.sandbox-yaml",{"title":407,"path":408,"stem":409},"Git in a sandbox","\u002Freference\u002Fconfiguration\u002Fsandbox\u002Fgit-in-a-sandbox","5.reference\u002F03.configuration\u002F10.sandbox\u002F7.git-in-a-sandbox",{"title":411,"path":412,"stem":413},"The OS sandbox","\u002Freference\u002Fconfiguration\u002Fsandbox\u002Fos-sandbox","5.reference\u002F03.configuration\u002F10.sandbox\u002F8.os-sandbox",{"title":415,"path":416,"stem":417},"Environment variables","\u002Freference\u002Fconfiguration\u002Fenvironment-variables","5.reference\u002F03.configuration\u002F11.environment-variables",{"title":419,"path":420,"stem":421},"Add-ons and collections","\u002Freference\u002Fconfiguration\u002Faddons","5.reference\u002F03.configuration\u002F12.addons",{"title":423,"path":424,"stem":425},"Repo libraries","\u002Freference\u002Fconfiguration\u002Frepo-libraries","5.reference\u002F03.configuration\u002F13.repo-libraries",{"title":427,"path":428,"stem":429},"update.yaml","\u002Freference\u002Fconfiguration\u002Fupdate","5.reference\u002F03.configuration\u002F14.update",{"title":431,"path":432,"stem":433},"workers.yaml","\u002Freference\u002Fconfiguration\u002Fworkers","5.reference\u002F03.configuration\u002F15.workers",{"title":435,"path":436,"stem":437},"forges.yaml","\u002Freference\u002Fconfiguration\u002Fforges","5.reference\u002F03.configuration\u002F16.forges",{"title":439,"path":440,"stem":441,"children":442},"Chain file keys","\u002Freference\u002Fchain-nodes","5.reference\u002F04.chain-nodes\u002Findex",[443,444,448,452],{"title":10,"path":440,"stem":441},{"title":445,"path":446,"stem":447},"Subprocess tasks","\u002Freference\u002Fchain-nodes\u002Fsubprocess-tasks","5.reference\u002F04.chain-nodes\u002F2.subprocess-tasks",{"title":449,"path":450,"stem":451},"Fix loop and judge","\u002Freference\u002Fchain-nodes\u002Ffix-loop","5.reference\u002F04.chain-nodes\u002F3.fix-loop",{"title":453,"path":454,"stem":455},"Result file","\u002Freference\u002Fchain-nodes\u002Fresult-file","5.reference\u002F04.chain-nodes\u002F4.result-file",{"title":457,"path":458,"stem":459,"children":460},"Agent harnesses","\u002Freference\u002Fharnesses","5.reference\u002F05.harnesses\u002Findex",[461,462,466,470,474,478],{"title":10,"path":458,"stem":459},{"title":463,"path":464,"stem":465},"Unattended runs","\u002Freference\u002Fharnesses\u002Funattended-runs","5.reference\u002F05.harnesses\u002F2.unattended-runs",{"title":467,"path":468,"stem":469},"Agent profiles","\u002Freference\u002Fharnesses\u002Fagent-profiles","5.reference\u002F05.harnesses\u002F3.agent-profiles",{"title":471,"path":472,"stem":473},"Harness definition files","\u002Freference\u002Fharnesses\u002Fharness-files","5.reference\u002F05.harnesses\u002F4.harness-files",{"title":475,"path":476,"stem":477},"Fallback and escalation","\u002Freference\u002Fharnesses\u002Ffallback-and-escalation","5.reference\u002F05.harnesses\u002F5.fallback-and-escalation",{"title":479,"path":480,"stem":481},"Cost reporting","\u002Freference\u002Fharnesses\u002Fcost-reporting","5.reference\u002F05.harnesses\u002F6.cost-reporting",{"title":483,"path":484,"stem":485},"Permission gate","\u002Freference\u002Fpermissions","5.reference\u002F06.permissions",{"title":487,"path":488,"stem":489},"Inbound triggers","\u002Freference\u002Ftriggers","5.reference\u002F07.triggers",{"title":491,"path":492,"stem":493,"children":494},"HTTP API","\u002Freference\u002Fhttp-api","5.reference\u002F08.http-api\u002Findex",[495,496,500,504,508,512,516,520],{"title":10,"path":492,"stem":493},{"title":497,"path":498,"stem":499},"Filing, reading and changing work items","\u002Freference\u002Fhttp-api\u002Fwork-items","5.reference\u002F08.http-api\u002F2.work-items",{"title":501,"path":502,"stem":503},"Gates, run control, ending and retry","\u002Freference\u002Fhttp-api\u002Fgates-run-control-and-ending","5.reference\u002F08.http-api\u002F3.gates-run-control-and-ending",{"title":505,"path":506,"stem":507},"The work item object","\u002Freference\u002Fhttp-api\u002Fwork-item-object","5.reference\u002F08.http-api\u002F4.work-item-object",{"title":509,"path":510,"stem":511},"Budget, events, diff and documents","\u002Freference\u002Fhttp-api\u002Fbudget-and-events","5.reference\u002F08.http-api\u002F5.budget-and-events",{"title":513,"path":514,"stem":515},"Repos, chains, harnesses and the server","\u002Freference\u002Fhttp-api\u002Frepos-chains-harnesses-and-server","5.reference\u002F08.http-api\u002F6.repos-chains-harnesses-and-server",{"title":517,"path":518,"stem":519},"Drafts","\u002Freference\u002Fhttp-api\u002Fdrafts","5.reference\u002F08.http-api\u002F7.drafts",{"title":521,"path":522,"stem":523},"Ops for each draft area","\u002Freference\u002Fhttp-api\u002Fdraft-ops","5.reference\u002F08.http-api\u002F8.draft-ops",{"title":525,"path":526,"stem":527},"MCP tools","\u002Freference\u002Fmcp-tools","5.reference\u002F09.mcp-tools",{"title":529,"path":530,"stem":531},"Events","\u002Freference\u002Fevents","5.reference\u002F10.events",{"title":533,"path":534,"stem":535},"VS Code extension","\u002Freference\u002Fvscode-extension","5.reference\u002F11.vscode-extension",{"title":537,"path":538,"stem":539},"Changes from 1.4 to 2.0","\u002Freference\u002Fchanges-from-1-4","5.reference\u002F12.changes-from-1-4",{"title":541,"path":542,"stem":543,"children":544},"Project","\u002Fproject","6.project",[545,547,551,555,559,563,567,571],{"title":10,"path":542,"stem":546},"6.project\u002Findex",{"title":548,"path":549,"stem":550},"Security","\u002Fproject\u002Fsecurity","6.project\u002F1.security",{"title":552,"path":553,"stem":554},"Data and privacy","\u002Fproject\u002Fdata-and-privacy","6.project\u002F2.data-and-privacy",{"title":556,"path":557,"stem":558},"What's new","\u002Fproject\u002Fwhats-new","6.project\u002F3.whats-new",{"title":560,"path":561,"stem":562},"Status and support","\u002Fproject\u002Fstatus-and-support","6.project\u002F4.status-and-support",{"title":564,"path":565,"stem":566},"Architecture","\u002Fproject\u002Farchitecture","6.project\u002F5.architecture",{"title":568,"path":569,"stem":570},"Source map","\u002Fproject\u002Fsource-map","6.project\u002F6.source-map",{"title":572,"path":573,"stem":574},"Contributing","\u002Fproject\u002Fcontributing","6.project\u002F7.contributing",{"id":576,"title":435,"body":577,"description":1876,"extension":1877,"links":1878,"meta":1879,"navigation":1880,"path":436,"seo":1881,"stem":437,"__hash__":1882},"docs\u002F5.reference\u002F03.configuration\u002F16.forges.md",{"type":578,"value":579,"toc":1863},"minimark",[580,587,597,699,702,870,1083,1109,1114,1120,1222,1243,1252,1255,1274,1283,1325,1329,1349,1353,1382,1391,1394,1401,1429,1442,1456,1470,1493,1497,1519,1526,1530,1553,1556,1567,1575,1579,1588,1619,1632,1641,1644,1648,1662,1745,1749,1759,1776,1782,1789,1797,1802,1817,1820,1844,1848,1859],[581,582,583],"p",{},[584,585,586],"em",{},"Added in 2.5",[581,588,589,592,593,596],{},[590,591,435],"code",{}," names forge accounts. An account records which forge a host runs and its web address, so ",[590,594,595],{},"kraft repo connect"," stops asking about a self-hosted host whose name does not say which forge it is. The file does not exist until you write it, and without it nothing changes.",[598,599,605],"pre",{"className":600,"code":601,"filename":602,"language":603,"meta":604,"style":604},"language-yaml shiki shiki-themes github-light-high-contrast github-light-high-contrast github-dark-high-contrast","accounts:\n  corp-gitlab:\n    forge: gitlab                 # github | gitlab\n    web_url: https:\u002F\u002Fcode.corp.example\u002Fgitlab\n    default_for_host: true        # repos on this host use it unless they name another\n  acme-gh:\n    forge: github\n    web_url: https:\u002F\u002Fgithub.com\n","config\u002Fforges.yaml","yaml","",[590,606,607,620,628,645,656,671,679,689],{"__ignoreMap":604},[608,609,612,616],"span",{"class":610,"line":611},"line",1,[608,613,615],{"class":614},"sb7M8","accounts",[608,617,619],{"class":618},"s7iLA",":\n",[608,621,623,626],{"class":610,"line":622},2,[608,624,625],{"class":614},"  corp-gitlab",[608,627,619],{"class":618},[608,629,631,634,637,641],{"class":610,"line":630},3,[608,632,633],{"class":614},"    forge",[608,635,636],{"class":618},": ",[608,638,640],{"class":639},"semJd","gitlab",[608,642,644],{"class":643},"sq92B","                 # github | gitlab\n",[608,646,648,651,653],{"class":610,"line":647},4,[608,649,650],{"class":614},"    web_url",[608,652,636],{"class":618},[608,654,655],{"class":639},"https:\u002F\u002Fcode.corp.example\u002Fgitlab\n",[608,657,659,662,664,668],{"class":610,"line":658},5,[608,660,661],{"class":614},"    default_for_host",[608,663,636],{"class":618},[608,665,667],{"class":666},"ssYy9","true",[608,669,670],{"class":643},"        # repos on this host use it unless they name another\n",[608,672,674,677],{"class":610,"line":673},6,[608,675,676],{"class":614},"  acme-gh",[608,678,619],{"class":618},[608,680,682,684,686],{"class":610,"line":681},7,[608,683,633],{"class":614},[608,685,636],{"class":618},[608,687,688],{"class":639},"github\n",[608,690,692,694,696],{"class":610,"line":691},8,[608,693,650],{"class":614},[608,695,636],{"class":618},[608,697,698],{"class":639},"https:\u002F\u002Fgithub.com\n",[581,700,701],{},"An account that talks to the forge's API names where its token comes from:",[598,703,705],{"className":600,"code":704,"filename":602,"language":603,"meta":604,"style":604},"accounts:\n  corp-gitlab:\n    forge: gitlab\n    client: api                   # api | cli\n    web_url: https:\u002F\u002Fcode.corp.example\u002Fgitlab\n    ca_file: \u002Fetc\u002Fssl\u002Fcorp-ca.pem # optional\n    default_for_host: true\n    token: { from: git-credential, kind: unknown }\n  acme-gh:\n    forge: github\n    client: api\n    web_url: https:\u002F\u002Fgithub.com\n    token: { from: file, file: ~\u002F.kraft\u002Fsecrets\u002Facme-gh, kind: pat }\n",[590,706,707,713,719,728,741,749,762,771,801,808,817,827,836],{"__ignoreMap":604},[608,708,709,711],{"class":610,"line":611},[608,710,615],{"class":614},[608,712,619],{"class":618},[608,714,715,717],{"class":610,"line":622},[608,716,625],{"class":614},[608,718,619],{"class":618},[608,720,721,723,725],{"class":610,"line":630},[608,722,633],{"class":614},[608,724,636],{"class":618},[608,726,727],{"class":639},"gitlab\n",[608,729,730,733,735,738],{"class":610,"line":647},[608,731,732],{"class":614},"    client",[608,734,636],{"class":618},[608,736,737],{"class":639},"api",[608,739,740],{"class":643},"                   # api | cli\n",[608,742,743,745,747],{"class":610,"line":658},[608,744,650],{"class":614},[608,746,636],{"class":618},[608,748,655],{"class":639},[608,750,751,754,756,759],{"class":610,"line":673},[608,752,753],{"class":614},"    ca_file",[608,755,636],{"class":618},[608,757,758],{"class":639},"\u002Fetc\u002Fssl\u002Fcorp-ca.pem",[608,760,761],{"class":643}," # optional\n",[608,763,764,766,768],{"class":610,"line":681},[608,765,661],{"class":614},[608,767,636],{"class":618},[608,769,770],{"class":666},"true\n",[608,772,773,776,779,782,784,787,790,793,795,798],{"class":610,"line":691},[608,774,775],{"class":614},"    token",[608,777,778],{"class":618},": { ",[608,780,781],{"class":614},"from",[608,783,636],{"class":618},[608,785,786],{"class":639},"git-credential",[608,788,789],{"class":618},", ",[608,791,792],{"class":614},"kind",[608,794,636],{"class":618},[608,796,797],{"class":639},"unknown",[608,799,800],{"class":618}," }\n",[608,802,804,806],{"class":610,"line":803},9,[608,805,676],{"class":614},[608,807,619],{"class":618},[608,809,811,813,815],{"class":610,"line":810},10,[608,812,633],{"class":614},[608,814,636],{"class":618},[608,816,688],{"class":639},[608,818,820,822,824],{"class":610,"line":819},11,[608,821,732],{"class":614},[608,823,636],{"class":618},[608,825,826],{"class":639},"api\n",[608,828,830,832,834],{"class":610,"line":829},12,[608,831,650],{"class":614},[608,833,636],{"class":618},[608,835,698],{"class":639},[608,837,839,841,843,845,847,850,852,854,856,859,861,863,865,868],{"class":610,"line":838},13,[608,840,775],{"class":614},[608,842,778],{"class":618},[608,844,781],{"class":614},[608,846,636],{"class":618},[608,848,849],{"class":639},"file",[608,851,789],{"class":618},[608,853,849],{"class":614},[608,855,636],{"class":618},[608,857,858],{"class":639},"~\u002F.kraft\u002Fsecrets\u002Facme-gh",[608,860,789],{"class":618},[608,862,792],{"class":614},[608,864,636],{"class":618},[608,866,867],{"class":639},"pat",[608,869,800],{"class":618},[871,872,873,892],"table",{},[874,875,876],"thead",{},[877,878,879,883,886,889],"tr",{},[880,881,882],"th",{},"Field",[880,884,885],{},"Type",[880,887,888],{},"Default",[880,890,891],{},"Meaning",[893,894,895,920,965,991,1025,1045,1062],"tbody",{},[877,896,897,903,911,914],{},[898,899,900],"td",{},[590,901,902],{},"forge",[898,904,905,908,909],{},[590,906,907],{},"github"," or ",[590,910,640],{},[898,912,913],{},"required",[898,915,916,917,919],{},"The forge the account is on. It must agree with the ",[590,918,902],{}," of each repo that uses it.",[877,921,922,927,934,938],{},[898,923,924],{},[590,925,926],{},"client",[898,928,929,908,932],{},[590,930,931],{},"cli",[590,933,737],{},[898,935,936],{},[590,937,931],{},[898,939,940,941,943,944,947,948,951,952,947,955,958,959,961,962,964],{},"How Kraft talks to the forge. ",[590,942,931],{}," keeps the sign-in of ",[590,945,946],{},"gh"," and ",[590,949,950],{},"glab",", and refuses ",[590,953,954],{},"token",[590,956,957],{},"ca_file",". ",[590,960,737],{}," reads a token from the source ",[590,963,954],{}," names.",[877,966,967,972,978,980],{},[898,968,969],{},[590,970,971],{},"web_url",[898,973,974,977],{},[590,975,976],{},"https:\u002F\u002F"," address",[898,979,913],{},[898,981,982,983,986,987,990],{},"The forge's web address. A trailing ",[590,984,985],{},"\u002F"," is dropped. ",[590,988,989],{},"http:\u002F\u002F"," is refused.",[877,992,993,998,1002,1005],{},[898,994,995],{},[590,996,997],{},"api_url",[898,999,1000,977],{},[590,1001,976],{},[898,1003,1004],{},"derived",[898,1006,1007,1008,1010,1011,1014,1015,947,1018,1014,1021,1024],{},"The API address. It must have ",[590,1009,971],{},"'s origin (host and port), except ",[590,1012,1013],{},"api.github.com"," for ",[590,1016,1017],{},"github.com",[590,1019,1020],{},"api.SUBDOMAIN.ghe.com",[590,1022,1023],{},"SUBDOMAIN.ghe.com",".",[877,1026,1027,1031,1034,1039],{},[898,1028,1029],{},[590,1030,954],{},[898,1032,1033],{},"mapping",[898,1035,1036],{},[590,1037,1038],{},"from: git-credential",[898,1040,1041,1042,1044],{},"An ",[590,1043,737],{}," account only. Where the token comes from, and its kind. See the tables below. A bare string is refused: the file never holds a token.",[877,1046,1047,1051,1054,1057],{},[898,1048,1049],{},[590,1050,957],{},[898,1052,1053],{},"path",[898,1055,1056],{},"none",[898,1058,1041,1059,1061],{},[590,1060,737],{}," account only. A PEM file of certificate authorities to trust for the forge, for a private CA.",[877,1063,1064,1069,1076,1080],{},[898,1065,1066],{},[590,1067,1068],{},"default_for_host",[898,1070,1071,908,1073],{},[590,1072,667],{},[590,1074,1075],{},"false",[898,1077,1078],{},[590,1079,1075],{},[898,1081,1082],{},"Repos on this web host use the account unless their entry names another. Only one account may be the default for a host.",[581,1084,1085,1086,1088,1089,1092,1093,1096,1097,1100,1101,1104,1105,1108],{},"An unset ",[590,1087,997],{}," is ",[590,1090,1091],{},"https:\u002F\u002Fapi.github.com"," for github.com, ",[590,1094,1095],{},"https:\u002F\u002Fapi.SUBDOMAIN.ghe.com"," for a ",[590,1098,1099],{},"ghe.com"," host, ",[590,1102,1103],{},"https:\u002F\u002FHOST\u002Fapi\u002Fv3"," for another GitHub host, and ",[590,1106,1107],{},"WEB_URL\u002Fapi\u002Fv4"," for GitLab.",[1110,1111,1113],"h2",{"id":1112},"where-the-token-comes-from","Where the token comes from",[581,1115,1116,1119],{},[590,1117,1118],{},"token.from"," names one source, and the one key that source needs. Any other key is refused.",[871,1121,1122,1136],{},[874,1123,1124],{},[877,1125,1126,1130,1133],{},[880,1127,1128],{},[590,1129,781],{},[880,1131,1132],{},"Key",[880,1134,1135],{},"What it stores and where it runs",[893,1137,1138,1153,1178,1192],{},[877,1139,1140,1144,1146],{},[898,1141,1142],{},[590,1143,786],{},[898,1145,1056],{},[898,1147,1148,1149,1152],{},"Nothing. Kraft runs ",[590,1150,1151],{},"git credential fill",", asked by host only, and never prompts. It reuses what your git helper holds.",[877,1154,1155,1160,1164],{},[898,1156,1157],{},[590,1158,1159],{},"command",[898,1161,1162],{},[590,1163,1159],{},[898,1165,1166,1167,1170,1171,1174,1175,1024],{},"Nothing. Set only with ",[590,1168,1169],{},"kraft admin forge"," or connect's option ",[608,1172,1173],{},"3"," on the server's machine, or by hand: never over HTTP. The command runs without a shell and its stdout is the token. Wrap a pipe in ",[590,1176,1177],{},"sh -c",[877,1179,1180,1185,1189],{},[898,1181,1182],{},[590,1183,1184],{},"env",[898,1186,1187],{},[590,1188,1184],{},[898,1190,1191],{},"Nothing. The variable is taken out of the server's environment when it starts, so a change needs a restart.",[877,1193,1194,1198,1202],{},[898,1195,1196],{},[590,1197,849],{},[898,1199,1200],{},[590,1201,849],{},[898,1203,1204,1205,789,1207,908,1210,1213,1214,1217,1218,1221],{},"The token, in one file only you can read. The path starts with ",[590,1206,985],{},[590,1208,1209],{},"~\u002F",[590,1211,1212],{},"$",". A pasted token (",[590,1215,1216],{},"--token-stdin",") goes to ",[590,1219,1220],{},"secrets\u002FNAME"," under Kraft's home.",[581,1223,1224,1225,1227,1228,947,1231,1234,1235,1238,1239,1242],{},"A ",[590,1226,849],{}," path may use ",[590,1229,1230],{},"~",[590,1232,1233],{},"$VAR","; an unset variable is refused, naming it. The file is refused when it is a symlink, is not owned by the user the server runs as, or has any group or other permission bit. It is also refused inside a connected repo, a worktree, a ",[590,1236,1237],{},"sandbox.expose"," root, ",[590,1240,1241],{},"\u002Fetc",", or a system directory every sandbox mounts.",[581,1244,1245,1246,1248,1249,1251],{},"Settings > Forge accounts sets every source but ",[590,1247,1159],{},", and a pasted token goes to the same ",[590,1250,1220],{}," file.",[581,1253,1254],{},"A sandboxed worker never sees the file. A host (unsandboxed) worker runs as the same user as the server, so it can read the file.",[581,1256,1041,1257,1259,1260,789,1263,789,1266,1269,1270,1273],{},[590,1258,1184],{}," name may not be one Kraft needs: ",[590,1261,1262],{},"KRAFT_*",[590,1264,1265],{},"GIT_*",[590,1267,1268],{},"PATH"," and the other variables every child gets, or ",[590,1271,1272],{},"ANTHROPIC_API_KEY"," and the other credentials Kraft passes to agents.",[581,1275,1276,1279,1280,1024],{},[590,1277,1278],{},"token.kind"," says what the token is. Every kind is sent as ",[590,1281,1282],{},"Authorization: Bearer",[871,1284,1285,1295],{},[874,1286,1287],{},[877,1288,1289,1293],{},[880,1290,1291],{},[590,1292,792],{},[880,1294,891],{},[893,1296,1297,1306,1316],{},[877,1298,1299,1303],{},[898,1300,1301],{},[590,1302,867],{},[898,1304,1305],{},"A personal or project access token.",[877,1307,1308,1313],{},[898,1309,1310],{},[590,1311,1312],{},"oauth",[898,1314,1315],{},"An OAuth access token.",[877,1317,1318,1322],{},[898,1319,1320],{},[590,1321,797],{},[898,1323,1324],{},"The default. Kraft does not say what it is.",[1110,1326,1328],{"id":1327},"the-origin-rule","The origin rule",[581,1330,1331,1333,1334,1336,1337,1339,1340,1014,1342,947,1344,1014,1346,1348],{},[590,1332,997],{}," must be on ",[590,1335,971],{},"'s origin: the same host and the same port, where no port means 443. An ",[590,1338,997],{}," on another port is refused. The two exceptions are ",[590,1341,1013],{},[590,1343,1017],{},[590,1345,1020],{},[590,1347,1023],{},", where both addresses must be on 443.",[1110,1350,1352],{"id":1351},"git-push-and-fetch-over-https","Git push and fetch over HTTPS",[581,1354,1355,1356,1359,1360,789,1362,908,1364,1366,1367,1369,1370,1373,1374,1377,1378,1381],{},"On an account with ",[590,1357,1358],{},"client: api"," and a ",[590,1361,1159],{},[590,1363,1184],{},[590,1365,849],{}," token, git push, fetch and the git-lfs upload to an ",[590,1368,976],{}," remote at the account's address send the token in a header set for that one call. It is never written to ",[590,1371,1372],{},".git\u002Fconfig"," and no hook sees it. The user name is ",[590,1375,1376],{},"x-access-token"," on GitHub and ",[590,1379,1380],{},"oauth2"," on GitLab.",[581,1383,1384,1386,1387,1390],{},[590,1385,786],{}," accounts and SSH remotes are unchanged: git asks its own credential. So do the repo library check (",[590,1388,1389],{},"kraft repo library",") and the git-lfs downloads, at checkout and in the fast-forward that brings the reviewed head home.",[581,1392,1393],{},"A push follows the account the item is pinned to. A fetch follows the account configured now. A push URL on another address is refused, and so is a push when any one of several push URLs is. Kraft never sends the token there.",[581,1395,1396,1397,1400],{},"A base fetch the token cannot authenticate stops the item and names the account, instead of starting from a stale base. Redirects are never followed with the header: a redirect stops the item, and the fix is to point ",[590,1398,1399],{},"origin"," at the new address. The stop card still shows the token hint.",[581,1402,1403,1404,1407,1408,1411,1412,1414,1415,908,1418,1421,1422,1425,1426,1428],{},"For these calls ",[590,1405,1406],{},"http.sslVerify"," is forced on and ",[590,1409,1410],{},"GIT_SSL_NO_VERIFY"," is ignored. The CA git trusts is the account's ",[590,1413,957],{},", else ",[590,1416,1417],{},"GIT_SSL_CAINFO",[590,1419,1420],{},"GIT_SSL_CAPATH",", else the system or global gitconfig's ",[590,1423,1424],{},"http.sslCAInfo",", else the CA bundle Kraft ships (certifi). A CA set only in a repo's own ",[590,1427,1372],{}," is ignored.",[581,1430,1431,1432,1434,1435,1437,1438,1441],{},"A corporate CA that lives only in the macOS keychain is not seen: set the account's ",[590,1433,957],{},", or ",[590,1436,1424],{}," in your global gitconfig, or these calls stop with a certificate error that names the account. ",[590,1439,1440],{},"GIT_TRACE"," variables are removed and trace2 is switched off.",[581,1443,1444,1445,1448,1449,947,1452,1455],{},"The repo's local git config on the server's machine is inside the trust boundary: whoever can write it can read the token source directly. A sandboxed worker cannot write it (the common gitdir's config is mounted read-only); an unsandboxed one runs as you. Repository content is outside it, which is why a base ",[590,1446,1447],{},".lfsconfig"," is checked. Kraft pins ",[590,1450,1451],{},"push.gpgSign",[590,1453,1454],{},"core.alternateRefsCommand",", refuses git-lfs custom transfer agents, and pins the routing keys as defence in depth.",[581,1457,1458,1459,1462,1463,1466,1467,1469],{},"Kraft pins the header only at the exact URL git dials, and redirects, ",[590,1460,1461],{},"sslVerify",", the CA, the proxy (including ",[590,1464,1465],{},"remote.origin.proxy",") and the resolve list at those and at the origin. It dials ",[590,1468,1399],{}," by name, runs no signer, alternate-refs command, bundle fetch or ssh with the header, and refuses an origin URL that names a user, a remote helper, a push URL that differs from the fetch URL, and a git-lfs custom transfer agent.",[581,1471,1472,1473,789,1476,789,1479,908,1482,1485,1486,1488,1489,1492],{},"A push with LFS objects is refused when ",[590,1474,1475],{},"lfs.url",[590,1477,1478],{},"lfs.pushurl",[590,1480,1481],{},"remote.origin.lfsurl",[590,1483,1484],{},"remote.origin.lfspushurl"," is set, or when the base branch's ",[590,1487,1447],{}," names an endpoint other than origin's own. git-lfs matches ",[590,1490,1491],{},"http.\u003Curl>"," keys against the remote URL only. git-lfs routing to a non-loopback host is unverified: the tests run against loopback.",[1110,1494,1496],{"id":1495},"which-account-a-repo-uses","Which account a repo uses",[581,1498,1499,1500,1502,1503,1506,1507,1509,1510,1512,1513,1515,1516,1518],{},"A repo uses the account its ",[590,1501,331],{}," entry names with ",[590,1504,1505],{},"forge_account",". Otherwise it uses the account marked ",[590,1508,1068],{}," for the host of its ",[590,1511,1399],{}," remote, when that account's ",[590,1514,902],{}," is the repo's ",[590,1517,902],{},"; a default for another forge is skipped, and doctor says so. Otherwise it uses the CLI as before.",[581,1520,1521,1522,1525],{},"Hosts compare in lowercase, without a port or a trailing dot. An SSH alias such as ",[590,1523,1524],{},"github-work"," is not the account's host, so a repo with one names its account itself.",[1110,1527,1529],{"id":1528},"a-file-that-does-not-load","A file that does not load",[581,1531,1532,1533,1536,1537,1540,1541,1544,1545,1548,1549,1552],{},"A file that does not load is refused when the server rereads it: the running accounts are kept, ",[590,1534,1535],{},"\u002Fhealth"," reports ",[590,1538,1539],{},"degraded"," with ",[590,1542,1543],{},"invalid_forges",", and ",[590,1546,1547],{},"kraft admin doctor"," names the file and the key, or for a file that is not valid YAML, the line and column. ",[590,1550,1551],{},"kraft admin reload"," rereads it.",[581,1554,1555],{},"A file that does not load when the server starts leaves no accounts to keep. Items already pinned keep their pins.",[581,1557,1558,1559,1562,1563,1566],{},"Every repo not yet pinned stops at its next forge node, until the file loads and a person retries it: with ",[590,1560,1561],{},"forges.yaml does not load (\u003Cwhy>); fix it, then a person's `kraft item retry` ",", or for a repo that names an account, ",[590,1564,1565],{},"forge_account \u003Cname>: forges.yaml does not load (\u003Cwhy>)",". Its forge reads, labels and merge request calls are refused the same way. A missing file is not this case: it means no accounts.",[581,1568,1569,1571,1572,1574],{},[590,1570,1543],{}," also names a repo whose ",[590,1573,1505],{}," names no account, or an account on another forge. A save that fixes it clears it.",[1110,1576,1578],{"id":1577},"how-kraft-talks-to-gitlab-over-the-api","How Kraft talks to GitLab over the API",[581,1580,1581,1582,1584,1585,1587],{},"On a ",[590,1583,1358],{}," GitLab account, Kraft runs every forge node and forge read over GitLab's REST API with the account's token. It does not run ",[590,1586,950],{},". It works on gitlab.com and on a self-hosted GitLab on any domain or path.",[581,1589,1590,1591,1414,1594,1597,1598,1601,1602,1604,1605,1607,1608,1611,1612,1615,1616,1618],{},"The project comes from the repo's push URL as configured: ",[590,1592,1593],{},"remote.origin.pushurl",[590,1595,1596],{},"remote.origin.url",", before any ",[590,1599,1600],{},"insteadOf"," rewrite. An ",[590,1603,976],{}," URL loses the path prefix of ",[590,1606,971],{},", so ",[590,1609,1610],{},"https:\u002F\u002Fcode.corp.example\u002Fgitlab\u002Fgroup\u002Fsub\u002Fapp.git"," is the project ",[590,1613,1614],{},"group\u002Fsub\u002Fapp",". An SSH URL keeps its path. An ",[590,1617,976],{}," push URL on another host than the account's is refused, without quoting it.",[581,1620,1621,1622,1625,1626,1628,1629,1631],{},"Kraft reads each account's token once and keeps it in the server's memory. A request answered ",[590,1623,1624],{},"401"," reads the token again and retries once, only if it changed. An ",[590,1627,1184],{}," source is never read again, so a new value needs a restart. ",[590,1630,1551],{}," clears the cache, and so does saving an account in Settings.",[581,1633,1634,1635,1637,1638,1640],{},"Each item uses the backend and account its first forge node pinned, and each repo of a workspace is run from its own pin. A repo pinned to ",[590,1636,950],{}," keeps running ",[590,1639,950],{}," under a workspace root on an API account.",[581,1642,1643],{},"A failed job's log is read as its last part: a log past the size cap keeps its end. A very large log can still time out, and the item's log route then answers 502. Jobs of a pipeline are read a page at a time, so one with up to 1,000 jobs is no longer cut short, on either backend.",[1110,1645,1647],{"id":1646},"gitlab-versions","GitLab versions",[581,1649,1650,1651,1654,1655,1658,1659,1024],{},"Kraft reads the server's version for the last two calls. For recent merged merge requests it does not: it asks for ",[590,1652,1653],{},"merged_at"," and, on a ",[590,1656,1657],{},"400",", asks again sorted by ",[590,1660,1661],{},"updated_at",[871,1663,1664,1680],{},[874,1665,1666],{},[877,1667,1668,1671,1674,1677],{},[880,1669,1670],{},"Call",[880,1672,1673],{},"Newer GitLab",[880,1675,1676],{},"Older GitLab",[880,1678,1679],{},"Version unreadable",[893,1681,1682,1704,1728],{},[877,1683,1684,1687,1693,1701],{},[898,1685,1686],{},"Recent merged merge requests",[898,1688,1689,1692],{},[590,1690,1691],{},"order_by=merged_at",", from 17.2.",[898,1694,1695,1696,1698,1699,1024],{},"Sorts by ",[590,1697,1661],{},", after a ",[590,1700,1657],{},[898,1702,1703],{},"Same as either, by the answer.",[877,1705,1706,1709,1715,1720],{},[898,1707,1708],{},"Merge when the pipeline passes",[898,1710,1711,1714],{},[590,1712,1713],{},"auto_merge",", from 17.11.",[898,1716,1717,1024],{},[590,1718,1719],{},"merge_when_pipeline_succeeds",[898,1721,1722,1724,1725,1727],{},[590,1723,1713],{},", as ",[590,1726,950],{}," sends it.",[877,1729,1730,1733,1739,1742],{},[898,1731,1732],{},"Cancel an auto-merge",[898,1734,1735,1738],{},[590,1736,1737],{},"cancel_auto_merge",", from 19.5.",[898,1740,1741],{},"The deprecated cancel endpoint.",[898,1743,1744],{},"The deprecated endpoint.",[1110,1746,1748],{"id":1747},"how-kraft-talks-to-github-over-the-api","How Kraft talks to GitHub over the API",[581,1750,1581,1751,1753,1754,1756,1757,1024],{},[590,1752,1358],{}," GitHub account, Kraft runs every forge node and forge read over GitHub's REST and GraphQL APIs with the account's token. It does not run ",[590,1755,946],{},". It works on github.com, on GitHub Enterprise Server and on ",[590,1758,1099],{},[581,1760,1761,1762,1764,1765,1768,1769,1772,1773,1775],{},"The repository comes from the repo's push URL as configured, before any ",[590,1763,1600],{}," rewrite, and is exactly ",[590,1766,1767],{},"owner\u002Fname",". Any other path, such as ",[590,1770,1771],{},"a\u002Fb\u002Fc",", or an ",[590,1774,976],{}," URL on another host than the account's, is refused without quoting the URL.",[581,1777,1778,1779,1024],{},"On Enterprise Server, GraphQL is at ",[590,1780,1781],{},"https:\u002F\u002FHOST\u002Fapi\u002Fgraphql",[581,1783,1784,1785,1788],{},"A job log lives in GitHub's storage, so GitHub answers its request with a redirect. Kraft follows that one ",[590,1786,1787],{},"https"," redirect without the token or GitHub's headers, and refuses a second. A failure there names the storage's host, never the signed address, and is not read as a token problem. The redirect and the download share one timeout, so a log read takes no longer than a single call.",[581,1790,1791,1792,1794,1795,1024],{},"The download trusts the system's certificate authorities and the account's CA together: its ",[590,1793,957],{},", else git's ",[590,1796,1424],{},[1798,1799,1801],"h3",{"id":1800},"what-the-token-needs","What the token needs",[581,1803,1804,1805,1808,1809,1816],{},"A classic personal access token needs the ",[590,1806,1807],{},"repo"," scope. A fine-grained one needs access to the repository, with the permissions GitHub lists for the REST endpoints Kraft calls: see ",[1810,1811,1815],"a",{"href":1812,"rel":1813},"https:\u002F\u002Fdocs.github.com\u002Fen\u002Frest\u002Fauthentication\u002Fpermissions-required-for-fine-grained-personal-access-tokens",[1814],"nofollow","Permissions required for fine-grained personal access tokens",". Kraft reads and writes pull requests, labels, check runs, commit statuses and Actions job logs.",[581,1818,1819],{},"An organization with single sign-on refuses a token until you authorize it. The stop names the account and carries the address of GitHub's authorize page; open it, authorize the token, then retry.",[581,1821,1822,1823,1826,1827,1830,1831,1834,1835,1838,1839,1841,1842,1024],{},"A workflow's ",[590,1824,1825],{},"GITHUB_TOKEN"," or a GitHub App installation token can run items, but it is not a supported kind. The probe asks ",[590,1828,1829],{},"GET \u002Fuser",", which GitHub answers ",[590,1832,1833],{},"403"," to such a token, so ",[590,1836,1837],{},"kraft admin forge test"," reports it as forbidden and ",[590,1840,1535],{}," stays ",[590,1843,1539],{},[1110,1845,1847],{"id":1846},"what-this-release-does-not-do-yet","What this release does not do yet",[1849,1850,1851],"ul",{},[1852,1853,1854,1856,1857,1024],"li",{},[590,1855,435],{}," is carried across a major update unchanged, like ",[590,1858,431],{},[1860,1861,1862],"style",{},"html pre.shiki code .sb7M8, html code.shiki .sb7M8{--shiki-light:#024C1A;--shiki-default:#024C1A;--shiki-dark:#72F088}html pre.shiki code .s7iLA, html code.shiki .s7iLA{--shiki-light:#0E1116;--shiki-default:#0E1116;--shiki-dark:#F0F3F6}html pre.shiki code .semJd, html code.shiki .semJd{--shiki-light:#032563;--shiki-default:#032563;--shiki-dark:#ADDCFF}html pre.shiki code .sq92B, html code.shiki .sq92B{--shiki-light:#66707B;--shiki-default:#66707B;--shiki-dark:#BDC4CC}html pre.shiki code .ssYy9, html code.shiki .ssYy9{--shiki-light:#023B95;--shiki-default:#023B95;--shiki-dark:#91CBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":604,"searchDepth":622,"depth":622,"links":1864},[1865,1866,1867,1868,1869,1870,1871,1872,1875],{"id":1112,"depth":622,"text":1113},{"id":1327,"depth":622,"text":1328},{"id":1351,"depth":622,"text":1352},{"id":1495,"depth":622,"text":1496},{"id":1528,"depth":622,"text":1529},{"id":1577,"depth":622,"text":1578},{"id":1646,"depth":622,"text":1647},{"id":1747,"depth":622,"text":1748,"children":1873},[1874],{"id":1800,"depth":630,"text":1801},{"id":1846,"depth":622,"text":1847},"Every field in forges.yaml: the named forge accounts, how a repo picks one, the token sources, the address rules, and what the first release of the file does not do.","md",null,{},true,{"title":435,"description":1876},"XfedJ77lz02rOzZR23WNIm5KXzsMj9t9fdRvmClZVzE",[1884,1886],{"title":431,"path":432,"stem":433,"description":1885,"children":-1},"Every field in workers.yaml: the machines that may run work item steps, their two ways of connecting, the name rules, and how a connection is kept, refused and shown.",{"title":10,"path":440,"stem":441,"description":1887,"children":-1},"Every key a chain file accepts, from the chain down to each kind of task, plus read_only, extends, icons and canonical paths.",1793547790267]