[{"data":1,"prerenderedAt":2109},["ShallowReactive",2],{"navigation_docs":3,"-reference-configuration-workers":571,"-reference-configuration-workers-surround":2104},[4,32,59,214,245,536],{"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,434,452,478,482,486,520,524,528,532],{"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],{"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,"children":438},"Chain file keys","\u002Freference\u002Fchain-nodes","5.reference\u002F04.chain-nodes\u002Findex",[439,440,444,448],{"title":10,"path":436,"stem":437},{"title":441,"path":442,"stem":443},"Subprocess tasks","\u002Freference\u002Fchain-nodes\u002Fsubprocess-tasks","5.reference\u002F04.chain-nodes\u002F2.subprocess-tasks",{"title":445,"path":446,"stem":447},"Fix loop and judge","\u002Freference\u002Fchain-nodes\u002Ffix-loop","5.reference\u002F04.chain-nodes\u002F3.fix-loop",{"title":449,"path":450,"stem":451},"Result file","\u002Freference\u002Fchain-nodes\u002Fresult-file","5.reference\u002F04.chain-nodes\u002F4.result-file",{"title":453,"path":454,"stem":455,"children":456},"Agent harnesses","\u002Freference\u002Fharnesses","5.reference\u002F05.harnesses\u002Findex",[457,458,462,466,470,474],{"title":10,"path":454,"stem":455},{"title":459,"path":460,"stem":461},"Unattended runs","\u002Freference\u002Fharnesses\u002Funattended-runs","5.reference\u002F05.harnesses\u002F2.unattended-runs",{"title":463,"path":464,"stem":465},"Agent profiles","\u002Freference\u002Fharnesses\u002Fagent-profiles","5.reference\u002F05.harnesses\u002F3.agent-profiles",{"title":467,"path":468,"stem":469},"Harness definition files","\u002Freference\u002Fharnesses\u002Fharness-files","5.reference\u002F05.harnesses\u002F4.harness-files",{"title":471,"path":472,"stem":473},"Fallback and escalation","\u002Freference\u002Fharnesses\u002Ffallback-and-escalation","5.reference\u002F05.harnesses\u002F5.fallback-and-escalation",{"title":475,"path":476,"stem":477},"Cost reporting","\u002Freference\u002Fharnesses\u002Fcost-reporting","5.reference\u002F05.harnesses\u002F6.cost-reporting",{"title":479,"path":480,"stem":481},"Permission gate","\u002Freference\u002Fpermissions","5.reference\u002F06.permissions",{"title":483,"path":484,"stem":485},"Inbound triggers","\u002Freference\u002Ftriggers","5.reference\u002F07.triggers",{"title":487,"path":488,"stem":489,"children":490},"HTTP API","\u002Freference\u002Fhttp-api","5.reference\u002F08.http-api\u002Findex",[491,492,496,500,504,508,512,516],{"title":10,"path":488,"stem":489},{"title":493,"path":494,"stem":495},"Filing, reading and changing work items","\u002Freference\u002Fhttp-api\u002Fwork-items","5.reference\u002F08.http-api\u002F2.work-items",{"title":497,"path":498,"stem":499},"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":501,"path":502,"stem":503},"The work item object","\u002Freference\u002Fhttp-api\u002Fwork-item-object","5.reference\u002F08.http-api\u002F4.work-item-object",{"title":505,"path":506,"stem":507},"Budget, events, diff and documents","\u002Freference\u002Fhttp-api\u002Fbudget-and-events","5.reference\u002F08.http-api\u002F5.budget-and-events",{"title":509,"path":510,"stem":511},"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":513,"path":514,"stem":515},"Drafts","\u002Freference\u002Fhttp-api\u002Fdrafts","5.reference\u002F08.http-api\u002F7.drafts",{"title":517,"path":518,"stem":519},"Ops for each draft area","\u002Freference\u002Fhttp-api\u002Fdraft-ops","5.reference\u002F08.http-api\u002F8.draft-ops",{"title":521,"path":522,"stem":523},"MCP tools","\u002Freference\u002Fmcp-tools","5.reference\u002F09.mcp-tools",{"title":525,"path":526,"stem":527},"Events","\u002Freference\u002Fevents","5.reference\u002F10.events",{"title":529,"path":530,"stem":531},"VS Code extension","\u002Freference\u002Fvscode-extension","5.reference\u002F11.vscode-extension",{"title":533,"path":534,"stem":535},"Changes from 1.4 to 2.0","\u002Freference\u002Fchanges-from-1-4","5.reference\u002F12.changes-from-1-4",{"title":537,"path":538,"stem":539,"children":540},"Project","\u002Fproject","6.project",[541,543,547,551,555,559,563,567],{"title":10,"path":538,"stem":542},"6.project\u002Findex",{"title":544,"path":545,"stem":546},"Security","\u002Fproject\u002Fsecurity","6.project\u002F1.security",{"title":548,"path":549,"stem":550},"Data and privacy","\u002Fproject\u002Fdata-and-privacy","6.project\u002F2.data-and-privacy",{"title":552,"path":553,"stem":554},"What's new in 2.0","\u002Fproject\u002Fwhats-new","6.project\u002F3.whats-new",{"title":556,"path":557,"stem":558},"Status and support","\u002Fproject\u002Fstatus-and-support","6.project\u002F4.status-and-support",{"title":560,"path":561,"stem":562},"Architecture","\u002Fproject\u002Farchitecture","6.project\u002F5.architecture",{"title":564,"path":565,"stem":566},"Source map","\u002Fproject\u002Fsource-map","6.project\u002F6.source-map",{"title":568,"path":569,"stem":570},"Contributing","\u002Fproject\u002Fcontributing","6.project\u002F7.contributing",{"id":572,"title":431,"body":573,"description":2097,"extension":2098,"links":2099,"meta":2100,"navigation":2101,"path":432,"seo":2102,"stem":433,"__hash__":2103},"docs\u002F5.reference\u002F03.configuration\u002F15.workers.md",{"type":574,"value":575,"toc":2073},"minimark",[576,583,597,803,813,1011,1018,1036,1041,1050,1141,1144,1155,1170,1204,1206,1228,1234,1264,1267,1276,1314,1318,1333,1336,1357,1361,1366,1377,1394,1399,1406,1416,1430,1433,1440,1466,1472,1482,1489,1493,1501,1597,1602,1610,1614,1656,1659,1662,1665,1670,1704,1714,1721,1724,1728,1743,1754,1764,1778,1785,1795,1799,1814,1831,1837,1843,1847,1860,1873,1877,1890,1898,1908,1911,1914,1917,1920,1923,1927,1941,1947,1957,1961,1970,1973,1979,1983,1986,2000,2003,2007,2069],[577,578,579],"p",{},[580,581,582],"em",{},"Added in 2.4",[577,584,585,588,589,592,593,596],{},[586,587,431],"code",{}," lists the machines Kraft may run steps on. A machine is another computer with the agent CLIs installed and ",[586,590,591],{},"kraft"," on its ",[586,594,595],{},"PATH",". A connected machine runs the steps that work items place on it.",[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","workers:\n  gpu-box:\n    ssh: gpu-box              # ssh mode: a host or an ~\u002F.ssh\u002Fconfig alias\n    capacity: 2               # sessions at once, at most; unset: the machine's own limit, else 1\n    repos: [kraft, infra]     # optional; left out means every connected repo\n    give_up_after: 2h         # default 2h; \"never\" turns the limit off\n    groups: [gpu, linux]      # optional; the groups a step's runner can name\n    enabled: true             # default true; false: running steps finish, nothing new starts\n  home-server:\n    token_sha256: \"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08\"\nlocal:\n  capacity: 3                 # sessions this machine's own worker runs at once; unset: no limit\n  groups: [linux]             # optional; the local worker joins groups too\n  enabled: true               # default true; false: local steps wait\n","config\u002Fworkers.yaml","yaml","",[586,606,607,620,628,645,660,683,697,719,733,741,752,760,774,790],{"__ignoreMap":604},[608,609,612,616],"span",{"class":610,"line":611},"line",1,[608,613,615],{"class":614},"sb7M8","workers",[608,617,619],{"class":618},"s7iLA",":\n",[608,621,623,626],{"class":610,"line":622},2,[608,624,625],{"class":614},"  gpu-box",[608,627,619],{"class":618},[608,629,631,634,637,641],{"class":610,"line":630},3,[608,632,633],{"class":614},"    ssh",[608,635,636],{"class":618},": ",[608,638,640],{"class":639},"semJd","gpu-box",[608,642,644],{"class":643},"sq92B","              # ssh mode: a host or an ~\u002F.ssh\u002Fconfig alias\n",[608,646,648,651,653,657],{"class":610,"line":647},4,[608,649,650],{"class":614},"    capacity",[608,652,636],{"class":618},[608,654,656],{"class":655},"ssYy9","2",[608,658,659],{"class":643},"               # sessions at once, at most; unset: the machine's own limit, else 1\n",[608,661,663,666,669,671,674,677,680],{"class":610,"line":662},5,[608,664,665],{"class":614},"    repos",[608,667,668],{"class":618},": [",[608,670,591],{"class":639},[608,672,673],{"class":618},", ",[608,675,676],{"class":639},"infra",[608,678,679],{"class":618},"]     ",[608,681,682],{"class":643},"# optional; left out means every connected repo\n",[608,684,686,689,691,694],{"class":610,"line":685},6,[608,687,688],{"class":614},"    give_up_after",[608,690,636],{"class":618},[608,692,693],{"class":639},"2h",[608,695,696],{"class":643},"         # default 2h; \"never\" turns the limit off\n",[608,698,700,703,705,708,710,713,716],{"class":610,"line":699},7,[608,701,702],{"class":614},"    groups",[608,704,668],{"class":618},[608,706,707],{"class":639},"gpu",[608,709,673],{"class":618},[608,711,712],{"class":639},"linux",[608,714,715],{"class":618},"]      ",[608,717,718],{"class":643},"# optional; the groups a step's runner can name\n",[608,720,722,725,727,730],{"class":610,"line":721},8,[608,723,724],{"class":614},"    enabled",[608,726,636],{"class":618},[608,728,729],{"class":655},"true",[608,731,732],{"class":643},"             # default true; false: running steps finish, nothing new starts\n",[608,734,736,739],{"class":610,"line":735},9,[608,737,738],{"class":614},"  home-server",[608,740,619],{"class":618},[608,742,744,747,749],{"class":610,"line":743},10,[608,745,746],{"class":614},"    token_sha256",[608,748,636],{"class":618},[608,750,751],{"class":639},"\"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08\"\n",[608,753,755,758],{"class":610,"line":754},11,[608,756,757],{"class":614},"local",[608,759,619],{"class":618},[608,761,763,766,768,771],{"class":610,"line":762},12,[608,764,765],{"class":614},"  capacity",[608,767,636],{"class":618},[608,769,770],{"class":655},"3",[608,772,773],{"class":643},"                 # sessions this machine's own worker runs at once; unset: no limit\n",[608,775,777,780,782,784,787],{"class":610,"line":776},13,[608,778,779],{"class":614},"  groups",[608,781,668],{"class":618},[608,783,712],{"class":639},[608,785,786],{"class":618},"]             ",[608,788,789],{"class":643},"# optional; the local worker joins groups too\n",[608,791,793,796,798,800],{"class":610,"line":792},14,[608,794,795],{"class":614},"  enabled",[608,797,636],{"class":618},[608,799,729],{"class":655},[608,801,802],{"class":643},"               # default true; false: local steps wait\n",[577,804,805,808,809,812],{},[586,806,807],{},"kraft admin worker add"," and ",[586,810,811],{},"edit"," write this file for you. The file does not exist until the first machine is added.",[814,815,816,835],"table",{},[817,818,819],"thead",{},[820,821,822,826,829,832],"tr",{},[823,824,825],"th",{},"Field",[823,827,828],{},"Type",[823,830,831],{},"Default",[823,833,834],{},"Meaning",[836,837,838,859,877,898,918,941,976],"tbody",{},[820,839,840,846,849,852],{},[841,842,843],"td",{},[586,844,845],{},"ssh",[841,847,848],{},"string",[841,850,851],{},"unset",[841,853,854,855,858],{},"Ssh mode. A host, ",[586,856,857],{},"user@host"," or an ssh config alias that Kraft's server dials.",[820,860,861,866,868,870],{},[841,862,863],{},[586,864,865],{},"token_sha256",[841,867,848],{},[841,869,851],{},[841,871,872,873,876],{},"Dial-in mode. The SHA-256 of the machine's token, as 64 lowercase hex characters. ",[586,874,875],{},"worker add"," writes it; the token itself is never stored.",[820,878,879,884,887,889],{},[841,880,881],{},[586,882,883],{},"capacity",[841,885,886],{},"integer, 1 or more",[841,888,851],{},[841,890,891,892,897],{},"How many sessions the machine may run at once. The machine's own limit applies too: the lower of the two is used, and one that is unset takes the other. Both unset is 1. See ",[893,894,896],"a",{"href":895},"#the-machines-own-limit","The machine's own limit",".",[820,899,900,905,908,911],{},[841,901,902],{},[586,903,904],{},"repos",[841,906,907],{},"list of names",[841,909,910],{},"every connected repo",[841,912,913,914,897],{},"Limits the machine to these repos. See ",[893,915,917],{"href":916},"#naming-a-repo","Naming a repo",[820,919,920,925,927,930],{},[841,921,922],{},[586,923,924],{},"groups",[841,926,907],{},[841,928,929],{},"none",[841,931,932,933,936,937,897],{},"The groups the machine is in. A step's ",[586,934,935],{},"runner:"," can name a group. See ",[893,938,940],{"href":939},"#groups","Groups",[820,942,943,948,965,969],{},[841,944,945],{},[586,946,947],{},"give_up_after",[841,949,950,673,953,673,956,673,958,961,962],{},[586,951,952],{},"30s",[586,954,955],{},"90m",[586,957,693],{},[586,959,960],{},"1d"," or ",[586,963,964],{},"never",[841,966,967],{},[586,968,693],{},[841,970,971,972,897],{},"How long a step waits for the other side before it is given up, on the server and on the machine. See ",[893,973,975],{"href":974},"#when-the-server-is-gone","When the server is gone",[820,977,978,983,990,994],{},[841,979,980],{},[586,981,982],{},"enabled",[841,984,985,961,987],{},[586,986,729],{},[586,988,989],{},"false",[841,991,992],{},[586,993,729],{},[841,995,996,998,999,1002,1003,1006,1007,897],{},[586,997,989],{}," stops new steps starting on the machine: the ones running finish, a step that names it waits ",[586,1000,1001],{},"waiting for NAME (disabled)",", and a group or ",[586,1004,1005],{},"any"," skips it. See ",[893,1008,1010],{"href":1009},"#disabling-a-machine","Disabling a machine",[577,1012,1013,1014,808,1016,897],{},"Each machine sets exactly one of ",[586,1015,845],{},[586,1017,865],{},[577,1019,1020,1021,1024,1025,636,1029,673,1031,808,1033,1035],{},"The top-level ",[586,1022,1023],{},"local:"," key is not a machine. It holds the settings of the ",[893,1026,1028],{"href":1027},"#the-local-worker","local worker",[586,1030,883],{},[586,1032,924],{},[586,1034,982],{},". Adding, editing or removing a machine keeps it.",[1037,1038,1040],"h2",{"id":1039},"the-local-worker","The local worker",[577,1042,1043,1044,1046,1047,1049],{},"Starting Kraft also starts the local worker, a second process on the same machine that runs every local step: agent sessions and the commands of test tasks. It needs no entry in ",[586,1045,431],{},", no token and no ",[586,1048,875],{},". The server finds it again after a restart, and starts a new one if it dies.",[1051,1052,1053,1080,1094,1101,1108,1118,1128,1131,1134],"ul",{},[1054,1055,1056,1057,1059,1060,1063,1064,1067,1068,1071,1072,1075,1076,1079],"li",{},"It appears as ",[586,1058,757],{}," in Settings › Workers and in ",[586,1061,1062],{},"kraft admin worker list",", with whether it is up, how many steps it runs and its Kraft version. It runs as many steps as ",[586,1065,1066],{},"local: capacity"," allows, and has no limit when that is unset; ",[586,1069,1070],{},"max_concurrent"," limits work items, not steps. It cannot be removed, and ",[586,1073,1074],{},"enabled: false"," makes local steps wait (",[586,1077,1078],{},"waiting for local (disabled)",") while the ones running finish.",[1054,1081,1082,1083,1086,1087,1090,1091,897],{},"It listens on a unix socket under ",[586,1084,1085],{},"run\u002Flocal-worker\u002F"," (a private folder under ",[586,1088,1089],{},"\u002Ftmp"," when that path is too long for a socket), and only your user can reach it. Its log is ",[586,1092,1093],{},"run\u002Flogs\u002Flocal-worker.log",[1054,1095,1096,1097,1100],{},"There is one worker for each installed Kraft, named by its version and a hash of where it is installed (",[586,1098,1099],{},"worker-\u003Cversion>-\u003Chash>.sock","). After an update the new server starts a worker of its own and takes over the running steps; the old one gets no new steps, reaps the processes it started and exits.",[1054,1102,1103,1104,1107],{},"Stopping or restarting the server does not stop the worker. The steps of worktree items it runs carry on, and the next server picks them up; ",[586,1105,1106],{},"kraft admin stop --now"," stops them. Under a systemd service the worker starts outside the unit's cgroup, so stopping the unit leaves it running.",[1054,1109,1110,1111,1113,1114,1117],{},"A step placed on ",[586,1112,757],{},", or on nothing, waits while the worker is not connected, and the board says ",[586,1115,1116],{},"waiting for local",". It is never run in the server instead.",[1054,1119,1120,1121,1123,1124,1127],{},"A step beyond ",[586,1122,1066],{}," waits before it has a session. The board says ",[586,1125,1126],{},"waiting for local (2 of 2 running)",", the wait does not count against its time cap, and the step's log starts with how long it waited. Every local step counts, test commands included, so a low limit runs parallel test scopes one at a time. Steps the worker kept running through a restart count too, and a new one waits for them.",[1054,1129,1130],{},"A step the worker started keeps running if the worker dies. The next worker takes it over, and the server goes on watching it.",[1054,1132,1133],{},"It exits by itself a few seconds after the server is gone and nothing is running.",[1054,1135,1136,1137,1140],{},"A worker on another machine and the server must run the same major version of Kraft. The handshake turns a machine on another major away with ",[586,1138,1139],{},"update kraft on this machine to X.y","; one on an older release of the same major keeps getting steps.",[1037,1142,896],{"id":1143},"the-machines-own-limit",[577,1145,1146,1147,1150,1151,1154],{},"A machine can set its own limit, so it never takes more than it can run whatever a server sends. Put it in ",[586,1148,1149],{},"machine.yaml"," in the config directory of the Kraft that runs the machine's steps (",[586,1152,1153],{},"$KRAFT_HOME\u002Fconfig","):",[598,1156,1159],{"className":600,"code":1157,"filename":1158,"language":603,"meta":604,"style":604},"capacity: 2\n","config\u002Fmachine.yaml on the machine",[586,1160,1161],{"__ignoreMap":604},[608,1162,1163,1165,1167],{"class":610,"line":611},[608,1164,883],{"class":614},[608,1166,636],{"class":618},[608,1168,1169],{"class":655},"2\n",[1051,1171,1172,1175,1187,1193,1196,1199],{},[1054,1173,1174],{},"The machine reports the limit when it connects and again when the file changes. It rereads the file before each step and every 20 seconds, so a raised limit reaches the server within 20 seconds. A file that does not parse is logged and read as no limit.",[1054,1176,1177,1178,1180,1181,1183,1184,1186],{},"The server uses the lower of its ",[586,1179,883],{}," and the machine's, and ",[586,1182,1062],{}," and Settings › Workers say when the machine's is the lower. A machine that sets none, or an older one, is limited by the server's ",[586,1185,883],{}," alone.",[1054,1188,1189,1190,1192],{},"Before it builds a step for a machine that has a limit, the server asks the machine to hold a slot. A machine at its limit refuses, and the step goes to another free machine it may use (",[586,1191,1005],{},"), or waits for the named one. Nothing has been made for it yet, so a refusal leaves no session and sends no files.",[1054,1194,1195],{},"A refusal does not count as a failure or a retry. The machine is not asked again until it reports a new limit, one of its steps ends, or 30 seconds pass.",[1054,1197,1198],{},"The limit belongs to the connection to one server. A machine used by several servers applies it to each; it is not shared between them.",[1054,1200,1201,1203],{},[586,1202,1149],{}," is kept across a major update.",[1037,1205,940],{"id":924},[577,1207,1208,1209,1211,1212,1215,1216,1219,1220,1223,1224,1227],{},"A group is a name you choose for a set of machines. A step whose ",[586,1210,935],{}," names the group goes to one of its members, so you can say \"a GPU machine\" without picking which. A machine lists its groups in ",[586,1213,1214],{},"groups:",", and can be in several. The local worker joins groups with ",[586,1217,1218],{},"local: groups:",", and ",[586,1221,1222],{},"kraft admin worker add NAME --group G"," (repeatable) writes a machine's; ",[586,1225,1226],{},"edit NAME --group G"," replaces them.",[577,1229,1230,1231,1233],{},"Kraft takes the first member that is online, may work on every repo of the item, and has a free slot: remote members first, in name order, then the local worker. So a group that includes the local worker sends work to its machines first; an unlimited local worker would otherwise take every step. ",[586,1232,1005],{}," is a separate word: every remote machine, never the local worker.",[1051,1235,1236,1239,1244,1251,1254,1257],{},[1054,1237,1238],{},"The slot is taken when Kraft chooses, so two steps never both start on the one free slot, and a step is never held for one member while another is free.",[1054,1240,1241,1242,897],{},"A member at its own limit turns the step away, and Kraft goes on to the next member. See ",[893,1243,896],{"href":895},[1054,1245,1246,1247,1250],{},"With no member free, the board says ",[586,1248,1249],{},"waiting for a machine in gpu",". The step starts on the first member that frees, looked at again every 30 seconds. A group that loses its last member while steps wait for it refuses them at the next check.",[1054,1252,1253],{},"A resumed session (a paused agent step, an escalation thread's later turn or a review reply) goes back to the machine it started on (or the local worker) and waits for it. Every other launch is placed afresh: a fix-loop relaunch, each test scope and a fallback harness each take whichever member is free.",[1054,1255,1256],{},"A remote member cannot take an in-place item or one with workspace members. Such an item runs on the local worker when it is a member. When it is not, Kraft refuses the item when it is filed, naming the group.",[1054,1258,1259,1260,1263],{},"A step that needs a capability a member lacks, a ",[586,1261,1262],{},"codex"," step needing Kraft's permission hook or a step of a Git LFS repo on a member without git-lfs, goes to a member that has it, else the local worker when it is a member.",[1037,1265,1010],{"id":1266},"disabling-a-machine",[577,1268,1269,1272,1273,1275],{},[586,1270,1271],{},"kraft admin worker disable NAME"," (or ",[586,1274,1074],{},") is for taking a machine out of rotation without forgetting it: it keeps its token or ssh entry, its slots and its connection.",[1051,1277,1278,1281,1291,1297],{},[1054,1279,1280],{},"Steps already running on it finish, hand in their results and give their slots back.",[1054,1282,1283,1284,1287,1288,1290],{},"Nothing new starts on it. A step that names the machine waits, and the board says ",[586,1285,1286],{},"waiting for gpu-box (disabled)",", even when the machine is also offline. A group or ",[586,1289,1005],{}," goes on to another member.",[1054,1292,1293,1296],{},[586,1294,1295],{},"enable"," undoes it; the waiting steps start on the next check.",[1054,1298,1299,1301,1302,1305,1306,1309,1310,1313],{},[586,1300,1062],{}," shows ",[586,1303,1304],{},"disabled",", with ",[586,1307,1308],{},"· offline:"," and the reason after it when the machine is also out of reach. ",[586,1311,1312],{},"kraft admin doctor"," reports it as disabled, not as a warning.",[1037,1315,1317],{"id":1316},"names","Names",[577,1319,1320,1321,961,1324,1327,1328,808,1330,1332],{},"A machine's name is 1 to 39 lowercase letters, digits, ",[586,1322,1323],{},"-",[586,1325,1326],{},"_",", starting with a letter or digit. A group's name follows the same rule. Machines and groups share one namespace: a group named like a machine, or a machine like a group, is refused. ",[586,1329,757],{},[586,1331,1005],{}," are refused for both: they are placement words.",[1037,1334,917],{"id":1335},"naming-a-repo",[577,1337,1338,1339,1341,1342,1345,1346,1349,1350,1353,1354,1356],{},"An entry in ",[586,1340,904],{}," matches a connected repo by its ",[586,1343,1344],{},"id",", its ",[586,1347,1348],{},"name",", or the last part of its ",[586,1351,1352],{},"path",". A name that matches no connected repo is refused when you save the file in Settings or add the machine with ",[586,1355,875],{},". A hand edit that names one is shown as a problem on the pending reload.",[1037,1358,1360],{"id":1359},"two-ways-to-connect","Two ways to connect",[1362,1363,1365],"h3",{"id":1364},"dial-in","Dial-in",[577,1367,1368,1369,1372,1373,1376],{},"The machine opens a connection to the server, so it works behind a NAT and needs no inbound port. This is the default mode: ",[586,1370,1371],{},"kraft admin worker add NAME"," with no ",[586,1374,1375],{},"--ssh"," registers one.",[1378,1379,1380,1387],"ol",{},[1054,1381,1382,1383,1386],{},"Run ",[586,1384,1385],{},"kraft admin worker add home-server",". It prints a token once, and the command to run on the machine.",[1054,1388,1389,1390,1393],{},"On the machine, run ",[586,1391,1392],{},"kraft admin worker serve --server URL --token TOKEN",". It redials by itself after a drop, a refusal or an unreachable server, until you stop it.",[577,1395,1396,1397,897],{},"The server must be reachable from the machine. That means binding it beyond loopback with a password, as in ",[893,1398,159],{"href":160},[577,1400,1401,1402,1405],{},"The connection route is ",[586,1403,1404],{},"\u002Fapi\u002Fworkers\u002Fconnect",". It is exempt from the login cookie: the machine proves itself with its token and nothing else. It still obeys the rest of the perimeter, so a server with no password refuses a peer that is not local, token or not.",[577,1407,1408,1409,1412,1413,897],{},"Kraft speaks plain WebSocket, so TLS is your reverse proxy's job. Put the ",[586,1410,1411],{},"https:\u002F\u002F"," address in ",[586,1414,1415],{},"--server",[577,1417,1418,1419,1422,1423,1425,1426,1429],{},"The token appears in the process list on the machine, because it is on the command line. Treat that machine as trusted with it. To change it, run ",[586,1420,1421],{},"kraft admin worker rotate-token NAME",": it prints a new token once, the old one stops working at once and the machine's connection ends. Steps running on the machine wait for it, up to its ",[586,1424,947],{},", until ",[586,1427,1428],{},"serve"," runs again with the new token. An ssh machine has no token to rotate.",[1362,1431,1432],{"id":845},"Ssh",[577,1434,1435,1436,1439],{},"The server dials the machine with ",[586,1437,1438],{},"ssh HOST kraft admin worker serve --stdio"," and redials when the connection ends. Nothing runs on the machine until the server connects.",[577,1441,1442,1443,1445,1446,1449,1450,961,1453,1456,1457,1460,1461,1463,1464,897],{},"Kraft uses the server process's own ",[586,1444,845],{}," and its own ",[586,1447,1448],{},"~\u002F.ssh\u002Fconfig",". A server started by ",[586,1451,1452],{},"launchd",[586,1454,1455],{},"systemd"," may not reach your SSH agent, so give it a key file with no passphrase prompt, or an agent socket it can see. The connection runs with ",[586,1458,1459],{},"BatchMode=yes",", so it never asks for a password. ",[586,1462,591],{}," must be on the remote machine's non-interactive ",[586,1465,595],{},[577,1467,1468,1471],{},[586,1469,1470],{},"kraft admin worker add NAME --ssh HOST"," saves the machine, connects once and prints the result. A failed connect leaves the machine saved and exits 1, because a machine that is asleep or not yet reachable is still worth registering.",[577,1473,1474,1475,1478,1479,897],{},"A machine that connects over ssh keeps its state in a small background process, the machine daemon, so a step outlives the ssh session that started it. The first connection starts it, detached, and later ones reuse it. It listens on a unix socket in ",[586,1476,1477],{},"$KRAFT_HOME\u002Fremote",", which only the machine's user can enter, and logs to ",[586,1480,1481],{},"$KRAFT_HOME\u002Fremote\u002Fdaemon.log",[577,1483,1484,1485,1488],{},"The daemon exits after ten minutes with no connection and no unfinished step. After an upgrade, the first connection from the newer Kraft retires the older daemon as soon as it holds no step. A dial-in machine does not use it: ",[586,1486,1487],{},"serve --server"," is already a long-running process.",[1037,1490,1492],{"id":1491},"when-a-machine-is-offline","When a machine is offline",[577,1494,1495,1301,1497,1500],{},[586,1496,1062],{},[586,1498,1499],{},"offline:"," and the reason.",[814,1502,1503,1513],{},[817,1504,1505],{},[820,1506,1507,1510],{},[823,1508,1509],{},"Reason",[823,1511,1512],{},"What it means",[836,1514,1515,1525,1535,1545,1555,1565,1584],{},[820,1516,1517,1522],{},[841,1518,1519],{},[586,1520,1521],{},"never connected",[841,1523,1524],{},"Nothing has dialled in, or the server has not connected yet since it started.",[820,1526,1527,1532],{},[841,1528,1529],{},[586,1530,1531],{},"refused: invalid token",[841,1533,1534],{},"The token does not belong to any machine. It was removed, rotated or mistyped.",[820,1536,1537,1542],{},[841,1538,1539],{},[586,1540,1541],{},"refused: update kraft on this machine to X.y: ...",[841,1543,1544],{},"The machine runs another major version of Kraft than the server. Update Kraft on the machine.",[820,1546,1547,1552],{},[841,1548,1549],{},[586,1550,1551],{},"refused: incompatible protocol: ...",[841,1553,1554],{},"The machine and the server speak different protocol versions. The reason names both, with each side's Kraft version. Update the older one.",[820,1556,1557,1562],{},[841,1558,1559],{},[586,1560,1561],{},"disconnected: ...",[841,1563,1564],{},"The connection ended, or the other side was silent for 60 seconds.",[820,1566,1567,1572],{},[841,1568,1569],{},[586,1570,1571],{},"ssh: ...",[841,1573,1574,1575,1577,1578,1580,1581,897],{},"The server's ",[586,1576,845],{}," ended before the machine answered. The reason is the last of what ",[586,1579,845],{}," printed, such as ",[586,1582,1583],{},"Permission denied (publickey)",[820,1585,1586,1591],{},[841,1587,1588],{},[586,1589,1590],{},"could not run ssh: ...",[841,1592,1593,1594,1596],{},"The server could not start ",[586,1595,845],{}," at all.",[577,1598,1599,1601],{},[586,1600,1312],{}," shows each offline machine as a warning with the same reason. For an ssh machine it is the server's own attempt, not your shell's, so a failure there that your terminal does not show points to the SSH agent.",[577,1603,1604,1605,961,1607,1609],{},"A second connection from a machine replaces the first. A machine that is removed, or whose ",[586,1606,845],{},[586,1608,865],{}," changes, loses its connection at once.",[1037,1611,1613],{"id":1612},"how-kraft-reads-the-file","How Kraft reads the file",[1051,1615,1616,1623,1629,1647,1650],{},[1054,1617,1618,1619,1622],{},"Kraft reads the file at startup and again on ",[586,1620,1621],{},"kraft admin reload",". A hand edit shows in Settings as waiting to be reloaded.",[1054,1624,1625,1626,1628],{},"A file that does not load is not used: at startup no machine is connected, and on a reload the running set is kept. ",[586,1627,1312],{}," names the problem.",[1054,1630,1631,673,1633,673,1635,673,1637,673,1640,808,1643,1646],{},[586,1632,807],{},[586,1634,811],{},[586,1636,1295],{},[586,1638,1639],{},"disable",[586,1641,1642],{},"rotate-token",[586,1644,1645],{},"remove"," write the file themselves and apply it at once.",[1054,1648,1649],{},"A Kraft session cannot add, edit, rotate, list or remove a machine. Only a person, or an assistant a person is working with, can.",[1054,1651,1652,1653,1655],{},"A new ",[586,1654,947],{}," is used by the server at once and reaches the machine the next time it connects.",[1037,1657,975],{"id":1658},"when-the-server-is-gone",[577,1660,1661],{},"A step keeps running when the server goes away: the laptop sleeps, ssh drops, the server restarts. The agent's calls to Kraft wait for the connection and are answered after it comes back. A call already sent when the connection dropped fails with a 503 saying so, because sending it again could act twice.",[577,1663,1664],{},"A step that finishes while the connection is down keeps its log, commits and documents on the machine and hands them in when it reconnects. Its log carries on from the byte the server has.",[577,1666,1667,1669],{},[586,1668,947],{}," is how long either side waits:",[1051,1671,1672,1682,1696,1699],{},[1054,1673,1674,1675,1677,1678,1681],{},"The machine stops the step it is running once it has had no connection for ",[586,1676,947],{},", and writes ",[586,1679,1680],{},"kraft: stopped on this machine after 2h without Kraft"," at the end of the step's log.",[1054,1683,1684,1685,1688,1689,1691,1692,1695],{},"The server ends the step as ",[586,1686,1687],{},"unknown",", the status a process that vanished gets, once the machine has been out of reach for ",[586,1690,947],{},". It records ",[586,1693,1694],{},"remote_step_given_up",", and tells the machine to stop the step if it comes back. Whatever the machine hands in after that is thrown away.",[1054,1697,1698],{},"Only time the server was awake counts. A laptop that sleeps for a night does not give up on a machine: the clock starts again on wake.",[1054,1700,1701,1703],{},[586,1702,964],{}," turns both off for that machine. Its steps run to the end and wait, however long, to hand in. The board shows the step as unreachable since the time the connection dropped, until the machine returns or you cancel the step.",[577,1705,1706,1707,1710,1711,1713],{},"A machine that holds a step cannot be removed: the server answers ",[586,1708,1709],{},"409",", naming the items, and says to disable the machine and remove it once the steps end. A step held by a machine that is offline is freed by pausing or cancelling its item, or by ",[586,1712,947],{},". Steps only waiting for the machine do not block its removal; they are refused at their next check. The local worker cannot be removed at all.",[577,1715,1716,1717,1720],{},"The time cap and the idle-output limit of a step are enforced on the machine as well as on the server, since a sleeping laptop enforces nothing. Whichever side fires first stops the step with the same ",[586,1718,1719],{},"time_cap_reached"," event.",[577,1722,1723],{},"A machine drops its copy of an item, its working files and its job folders, when the item is archived or abandoned, and on reconnect for every item the server no longer lists. It keeps the copy of an item while one of the item's steps is still running there.",[1037,1725,1727],{"id":1726},"running-a-step-on-a-machine","Running a step on a machine",[577,1729,1730,1731,1733,1734,1738,1739,1742],{},"Name a machine in a chain's ",[586,1732,935],{}," (see ",[893,1735,1737],{"href":1736},"\u002Freference\u002Fconfiguration\u002Flibrary-and-chains#placing-a-step-on-a-machine","Placing a step on a machine",") or give one item its own with ",[586,1740,1741],{},"kraft item create --runner NAME",". A step placed there runs on the machine; the board, gates, repos and the item's branch stay on the server.",[577,1744,1745,1746,1749,1750,1753],{},"Before every step the server sends the commits the machine lacks as a git bundle, the item's ",[586,1747,1748],{},"docs\u002F"," folder, earlier sessions' results and summaries, and the job. The machine runs the repo's ",[586,1751,1752],{},"setup_command"," in its own copy first.",[577,1755,1756,1757,673,1760,1763],{},"The log streams home as it is written. After the step the machine's new commits, ",[586,1758,1759],{},"result.json",[586,1761,1762],{},"summary.md"," and changed documents come back, and only then does the server look at the step.",[577,1765,1766,1767,1770,1771,1773,1774,1777],{},"The machine uses its own login for the agent CLI. No credential or environment variable leaves the server: ",[586,1768,1769],{},"env:"," values from ",[586,1772,331],{}," travel, and ",[586,1775,1776],{},"env_passthrough:"," names are read from the machine's own environment.",[577,1779,1780,1781,1784],{},"A step's own calls to Kraft (",[586,1782,1783],{},"kraft item progress",", a reply to a review thread, a read of its own item) cross the same connection. The server answers only what a worker session may call, for its own work item.",[577,1786,1787,1788,1791,1792,1794],{},"An unsandboxed step has no session MCP endpoint (",[586,1789,1790],{},"\u002Fmcp",") on a machine, so it uses the ",[586,1793,591],{}," command. An escalation turn, a review reply or a gate review that runs on a machine gets the same worker rights and nothing wider.",[1037,1796,1798],{"id":1797},"sandboxed-items-on-a-machine","Sandboxed items on a machine",[577,1800,1801,1802,1805,1806,1809,1810,897],{},"A step of a sandboxed item runs on a machine inside the sandbox the item was filed with, built by the machine. The server sends the ",[586,1803,1804],{},"sandbox"," value, the network lists and the credential declarations, never a secret: the secrets are read from the machine's own environment. A machine that cannot build the sandbox stops the step as ",[586,1807,1808],{},"config_error",", naming itself and what is missing, and runs nothing. See ",[893,1811,1813],{"href":1812},"\u002Freference\u002Fconfiguration\u002Fsandbox#on-a-remote-machine","On a remote machine",[577,1815,1816,1819,1820,1823,1824,808,1827,1830],{},[586,1817,1818],{},"kraft admin worker check"," shows one ",[586,1821,1822],{},"sandbox:"," row per backend, ",[586,1825,1826],{},"docker",[586,1828,1829],{},"os",", with its own health detail, and skips a backend that does not work there. When none works it warns that sandboxed items cannot run on the machine.",[577,1832,1833,1834,1836],{},"A sandboxed worker's calls to Kraft, its permission requests over ",[586,1835,1790],{}," included, go out through the machine's egress proxy and across the connection. The machine refuses a call outside the worker's allowlist before it sends it, and the server checks it again.",[577,1838,1839,1840,1842],{},"A sandboxed ",[586,1841,1262],{}," step whose policy needs its permission hook cannot run on a machine.",[1037,1844,1846],{"id":1845},"codex-steps-on-a-machine","Codex steps on a machine",[577,1848,1849,1850,1853,1854,1856,1857,1859],{},"Codex skips a hook it does not trust and says nothing. When a step's tool policy needs Kraft's ",[893,1851,1852],{"href":480},"permission hook",", the machine's own ",[586,1855,1262],{}," trusts the hook, in the machine's copy of the worktree, just before the step starts. The server's ",[586,1858,1262],{}," is never asked, because another version may hash the hook another way. The hook runs with the machine's own Kraft.",[577,1861,1862,1863,1865,1866,1868,1869,1872],{},"If the machine's ",[586,1864,1262],{}," cannot trust the hook, the step stops as ",[586,1867,1808],{}," with the reason in its log and runs nothing. A machine whose Kraft is too old to do this check is refused the same way, with ",[586,1870,1871],{},"update Kraft on that machine","; its other steps still run.",[1037,1874,1876],{"id":1875},"git-lfs-repos-on-a-machine","Git LFS repos on a machine",[577,1878,1879,1880,1883,1884,1886,1887,897],{},"A step of an item in a Git LFS repo runs on a machine that has ",[586,1881,1882],{},"git-lfs",". A machine without it is never given the step: ",[586,1885,1005],{}," and a group pass it over, and a named machine is refused with a message that starts ",[586,1888,1889],{},"the repo uses Git LFS: machine 'gpu-box' has no git-lfs; install git-lfs there",[577,1891,1892,1894,1895,1897],{},[586,1893,1818],{}," shows a ",[586,1896,1882],{}," row, skipped when it is missing. Kraft on the machine must be as new as the server's, or it does not list git-lfs.",[577,1899,1900,1901,1903,1904,1907],{},"The machine's worker looks for ",[586,1902,1882],{}," once, when it starts, and keeps the answer. If you install it later, the machine does not list it until its worker restarts: ",[586,1905,1906],{},"kraft admin worker serve"," for a dial-in machine, and for an ssh machine the background process the server's ssh talks to.",[577,1909,1910],{},"An ssh reconnect does not restart that process while it runs; it exits on its own after about ten minutes with no job and no connection, and the next connection starts a fresh one.",[577,1912,1913],{},"The machine never fetches from the forge. The objects the step's head checks out travel through the server, beside the git bundle, one at a time. The server sends only those it holds, and only those the machine does not already have. Each item has its own copy on the machine, so an item's first step there receives every LFS object its head checks out: transfer time and disk, per item.",[577,1915,1916],{},"An object the server lacks stays a pointer file on the machine, as it would in a local worktree that could not fetch it.",[577,1918,1919],{},"The files the agent adds or changes come back the same way. Kraft checks each returned object against a pointer in the commits it came with, by hash and size, and refuses the whole result if one does not match, or if a new pointer has no object behind it. The branch then does not move.",[577,1921,1922],{},"What passes goes into the server's LFS store and is pushed with the branch, as a local step's would be. An object is sent again whole if the connection drops mid-transfer.",[1037,1924,1926],{"id":1925},"waiting-and-capacity","Waiting and capacity",[577,1928,1929,1930,1933,1934,1936,1937,1940],{},"A step whose machine is offline or full waits: the item shows ",[586,1931,1932],{},"waiting for gpu-box (full)"," (",[586,1935,1249],{}," for a ",[893,1938,1939],{"href":939},"group","), holds no slot on the server, and its time cap does not run.",[577,1942,1943,1944,1946],{},"It never runs anywhere else. ",[586,1945,1005],{}," means the first connected machine that may work on every repo the item uses and has a free slot; it never means the server. A machine runs at most as many sessions as its limit. Pause, skip and cancel work as usual.",[577,1948,1949,1950,1953,1954,1956],{},"A step that was resumed with the agent CLI's ",[586,1951,1952],{},"--resume"," (a paused session, an escalation thread's later turns) goes back to the machine that ran its first turn, because the CLI's resume state lives there. A step placed on ",[586,1955,1005],{}," also stays on the machine its node first ran on, for the rest of that pass of the node.",[1037,1958,1960],{"id":1959},"what-a-machine-refuses","What a machine refuses",[577,1962,1963,1964,1966,1967,1969],{},"Kraft refuses, with a 422 when the item is filed or overridden and ",[586,1965,1808],{}," at launch, an item that names a machine or group not in ",[586,1968,431],{},", a machine not allowed for its repo, or a group none of whose members could take it; an in-place item; and an item with workspace members, which a single bundle does not carry.",[577,1971,1972],{},"A repo with submodules is not refused when the item declares no members: its submodules stay uninitialized on the machine as they do on the server, and Kraft refuses the machine's commits when they add or move a submodule pointer.",[577,1974,1975,1976,1978],{},"A machine without the agent CLI the step needs, or whose ",[586,1977,1752],{}," fails, stops the step with the reason in its log.",[1037,1980,1982],{"id":1981},"if-something-goes-wrong","If something goes wrong",[577,1984,1985],{},"A bundle that does not fetch, adds a nested git repository, or does not continue from the head it was sent fails the step with the reason in its log and leaves the branch alone.",[577,1987,1988,1989,808,1992,1995,1996,1999],{},"If the branch moved while the step ran, the commits are kept at ",[586,1990,1991],{},"refs\u002Fkraft\u002Funsynced\u002F...",[586,1993,1994],{},"sandbox_branch_not_synced"," is recorded. A document you edited while the step ran keeps your version; the step's copy is saved in the session's folder and ",[586,1997,1998],{},"remote_docs_conflict"," names it.",[577,2001,2002],{},"When the server restarts, a running step carries on and its log resumes without a gap.",[1037,2004,2006],{"id":2005},"related","Related",[1051,2008,2009,2014,2039,2059,2064],{},[1054,2010,2011,2013],{},[893,2012,56],{"href":57},": how the local worker and machines fit together, and why.",[1054,2015,2016,636,2019,673,2021,673,2023,673,2025,673,2027,673,2029,673,2032,673,2034,808,2036,897],{},[893,2017,313],{"href":2018},"\u002Freference\u002Fcli\u002Fadmin#machines",[586,2020,807],{},[586,2022,811],{},[586,2024,1295],{},[586,2026,1639],{},[586,2028,1642],{},[586,2030,2031],{},"list",[586,2033,1645],{},[586,2035,1428],{},[586,2037,2038],{},"check",[1054,2040,2041,636,2044,673,2047,673,2050,673,2053,808,2056,897],{},[893,2042,521],{"href":2043},"\u002Freference\u002Fmcp-tools#machines",[586,2045,2046],{},"add_worker",[586,2048,2049],{},"edit_worker",[586,2051,2052],{},"rotate_worker_token",[586,2054,2055],{},"list_workers",[586,2057,2058],{},"remove_worker",[1054,2060,2061,2063],{},[893,2062,159],{"href":160},": binding the server beyond loopback.",[1054,2065,2066,2068],{},[893,2067,325],{"href":326},": the other files in the config directory.",[2070,2071,2072],"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":2074},[2075,2076,2077,2078,2079,2080,2081,2086,2087,2088,2089,2090,2091,2092,2093,2094,2095,2096],{"id":1039,"depth":622,"text":1040},{"id":1143,"depth":622,"text":896},{"id":924,"depth":622,"text":940},{"id":1266,"depth":622,"text":1010},{"id":1316,"depth":622,"text":1317},{"id":1335,"depth":622,"text":917},{"id":1359,"depth":622,"text":1360,"children":2082},[2083,2085],{"id":1364,"depth":630,"text":2084},"Dial-​in",{"id":845,"depth":630,"text":1432},{"id":1491,"depth":622,"text":1492},{"id":1612,"depth":622,"text":1613},{"id":1658,"depth":622,"text":975},{"id":1726,"depth":622,"text":1727},{"id":1797,"depth":622,"text":1798},{"id":1845,"depth":622,"text":1846},{"id":1875,"depth":622,"text":1876},{"id":1925,"depth":622,"text":1926},{"id":1959,"depth":622,"text":1960},{"id":1981,"depth":622,"text":1982},{"id":2005,"depth":622,"text":2006},"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.","md",null,{},true,{"title":431,"description":2097},"fUuPQPPQGj6pRapS_38ATgBQ6JDY1Ig2kAJPlXo295U",[2105,2107],{"title":427,"path":428,"stem":429,"description":2106,"children":-1},"Every field in update.yaml: automatic updates, restarting when Kraft is free, the release channel and the hours Kraft may update in.",{"title":10,"path":436,"stem":437,"description":2108,"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.",1793024386568]