[{"data":1,"prerenderedAt":1569},["ShallowReactive",2],{"navigation_docs":3,"-reference-permissions":270,"-reference-permissions-surround":1564},[4,28,51,110,243],{"title":5,"path":6,"stem":7,"children":8},"Get started","\u002Fget-started","1.get-started",[9,12,16,20,24],{"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},"Troubleshooting and FAQ","\u002Fget-started\u002Ftroubleshooting","1.get-started\u002F3.troubleshooting",{"title":29,"path":30,"stem":31,"children":32},"Concepts","\u002Fconcepts","2.concepts",[33,35,39,43,47],{"title":10,"path":30,"stem":34},"2.concepts\u002Findex",{"title":36,"path":37,"stem":38},"Vocabulary","\u002Fconcepts\u002Fvocabulary","2.concepts\u002F1.vocabulary",{"title":40,"path":41,"stem":42},"How a work item runs","\u002Fconcepts\u002Fhow-a-work-item-runs","2.concepts\u002F2.how-a-work-item-runs",{"title":44,"path":45,"stem":46},"Caps and budgets","\u002Fconcepts\u002Fcaps-and-budgets","2.concepts\u002F3.caps-and-budgets",{"title":48,"path":49,"stem":50},"Why a permission gate","\u002Fconcepts\u002Fpermission-gate","2.concepts\u002F4.permission-gate",{"title":52,"path":53,"stem":54,"children":55},"Guides","\u002Fguides","3.guides",[56,58,62,66,70,74,78,82,86,90,94,98,102,106],{"title":10,"path":53,"stem":57},"3.guides\u002Findex",{"title":59,"path":60,"stem":61},"Use Kraft from your agent","\u002Fguides\u002Fagent-integration","3.guides\u002F01.agent-integration",{"title":63,"path":64,"stem":65},"Kraft Lite","\u002Fguides\u002Fkraft-lite","3.guides\u002F02.kraft-lite",{"title":67,"path":68,"stem":69},"Remote access","\u002Fguides\u002Fremote-access","3.guides\u002F03.remote-access",{"title":71,"path":72,"stem":73},"Add or override a harness","\u002Fguides\u002Fadding-a-harness","3.guides\u002F04.adding-a-harness",{"title":75,"path":76,"stem":77},"Schedule or webhook work","\u002Fguides\u002Fschedule-and-webhook-work","3.guides\u002F05.schedule-and-webhook-work",{"title":79,"path":80,"stem":81},"Add a security review or a gate reviewer","\u002Fguides\u002Fadd-review-agents","3.guides\u002F06.add-review-agents",{"title":83,"path":84,"stem":85},"Kraft for VS Code","\u002Fguides\u002Fvscode","3.guides\u002F07.vscode",{"title":87,"path":88,"stem":89},"Reviewing a change","\u002Fguides\u002Freview-a-change","3.guides\u002F08.review-a-change",{"title":91,"path":92,"stem":93},"Write your own chain","\u002Fguides\u002Fwrite-your-own-chain","3.guides\u002F09.write-your-own-chain",{"title":95,"path":96,"stem":97},"Switch a harness","\u002Fguides\u002Fswitch-harness","3.guides\u002F10.switch-harness",{"title":99,"path":100,"stem":101},"Upgrade your templates","\u002Fguides\u002Fupgrading-templates","3.guides\u002F11.upgrading-templates",{"title":103,"path":104,"stem":105},"Operations","\u002Fguides\u002Foperations","3.guides\u002F12.operations",{"title":107,"path":108,"stem":109},"Worker Kit","\u002Fguides\u002Fworker-kit","3.guides\u002F13.worker-kit",{"title":111,"path":112,"stem":113,"children":114},"Reference","\u002Freference","4.reference",[115,117,139,183,201,205,227,231,235,239],{"title":10,"path":112,"stem":116},"4.reference\u002Findex",{"title":118,"path":119,"stem":120,"children":121},"CLI","\u002Freference\u002Fcli","4.reference\u002F1.cli\u002Findex",[122,123,127,131,135],{"title":10,"path":119,"stem":120},{"title":124,"path":125,"stem":126},"Item verbs","\u002Freference\u002Fcli\u002Fitem","4.reference\u002F1.cli\u002F2.item",{"title":128,"path":129,"stem":130},"View verbs","\u002Freference\u002Fcli\u002Fview","4.reference\u002F1.cli\u002F3.view",{"title":132,"path":133,"stem":134},"Repo verbs","\u002Freference\u002Fcli\u002Frepo","4.reference\u002F1.cli\u002F4.repo",{"title":136,"path":137,"stem":138},"Admin verbs","\u002Freference\u002Fcli\u002Fadmin","4.reference\u002F1.cli\u002F5.admin",{"title":140,"path":141,"stem":142,"children":143},"Configuration","\u002Freference\u002Fconfiguration","4.reference\u002F2.configuration\u002Findex",[144,145,155,159,163,167,171,175,179],{"title":10,"path":141,"stem":142},{"title":146,"path":147,"stem":148,"children":149},"Repos","\u002Freference\u002Fconfiguration\u002Frepos","4.reference\u002F2.configuration\u002F2.repos\u002Findex",[150,151],{"title":10,"path":147,"stem":148},{"title":152,"path":153,"stem":154},"Workspaces","\u002Freference\u002Fconfiguration\u002Frepos\u002Fworkspaces","4.reference\u002F2.configuration\u002F2.repos\u002F3.workspaces",{"title":156,"path":157,"stem":158},"Policy","\u002Freference\u002Fconfiguration\u002Fpolicy","4.reference\u002F2.configuration\u002F3.policy",{"title":160,"path":161,"stem":162},"Library and chains","\u002Freference\u002Fconfiguration\u002Flibrary-and-chains","4.reference\u002F2.configuration\u002F4.library-and-chains",{"title":164,"path":165,"stem":166},"Harnesses file","\u002Freference\u002Fconfiguration\u002Fharnesses-file","4.reference\u002F2.configuration\u002F5.harnesses-file",{"title":168,"path":169,"stem":170},"Access","\u002Freference\u002Fconfiguration\u002Faccess","4.reference\u002F2.configuration\u002F6.access",{"title":172,"path":173,"stem":174},"Intake","\u002Freference\u002Fconfiguration\u002Fintake","4.reference\u002F2.configuration\u002F7.intake",{"title":176,"path":177,"stem":178},"Sandbox host","\u002Freference\u002Fconfiguration\u002Fsandbox","4.reference\u002F2.configuration\u002F8.sandbox",{"title":180,"path":181,"stem":182},"Environment variables","\u002Freference\u002Fconfiguration\u002Fenvironment-variables","4.reference\u002F2.configuration\u002F9.environment-variables",{"title":184,"path":185,"stem":186,"children":187},"Chain nodes","\u002Freference\u002Fchain-nodes","4.reference\u002F3.chain-nodes\u002Findex",[188,189,193,197],{"title":10,"path":185,"stem":186},{"title":190,"path":191,"stem":192},"Subprocess tasks","\u002Freference\u002Fchain-nodes\u002Fsubprocess-tasks","4.reference\u002F3.chain-nodes\u002F2.subprocess-tasks",{"title":194,"path":195,"stem":196},"Fix loop and judge","\u002Freference\u002Fchain-nodes\u002Ffix-loop","4.reference\u002F3.chain-nodes\u002F3.fix-loop",{"title":198,"path":199,"stem":200},"Result file","\u002Freference\u002Fchain-nodes\u002Fresult-file","4.reference\u002F3.chain-nodes\u002F4.result-file",{"title":202,"path":203,"stem":204},"Permission gate","\u002Freference\u002Fpermissions","4.reference\u002F4.permissions",{"title":206,"path":207,"stem":208,"children":209},"Agent harnesses","\u002Freference\u002Fharnesses","4.reference\u002F5.harnesses\u002Findex",[210,211,215,219,223],{"title":10,"path":207,"stem":208},{"title":212,"path":213,"stem":214},"Unattended runs","\u002Freference\u002Fharnesses\u002Funattended-runs","4.reference\u002F5.harnesses\u002F2.unattended-runs",{"title":216,"path":217,"stem":218},"Agent profiles","\u002Freference\u002Fharnesses\u002Fagent-profiles","4.reference\u002F5.harnesses\u002F3.agent-profiles",{"title":220,"path":221,"stem":222},"Harness files","\u002Freference\u002Fharnesses\u002Fharness-files","4.reference\u002F5.harnesses\u002F4.harness-files",{"title":224,"path":225,"stem":226},"Fallback and escalation","\u002Freference\u002Fharnesses\u002Ffallback-and-escalation","4.reference\u002F5.harnesses\u002F5.fallback-and-escalation",{"title":228,"path":229,"stem":230},"Inbound triggers","\u002Freference\u002Ftriggers","4.reference\u002F6.triggers",{"title":232,"path":233,"stem":234},"HTTP API","\u002Freference\u002Fhttp-api","4.reference\u002F7.http-api",{"title":236,"path":237,"stem":238},"MCP tools","\u002Freference\u002Fmcp-tools","4.reference\u002F8.mcp-tools",{"title":240,"path":241,"stem":242},"Events","\u002Freference\u002Fevents","4.reference\u002F9.events",{"title":244,"path":245,"stem":246,"children":247},"Project","\u002Fproject","5.project",[248,250,254,258,262,266],{"title":10,"path":245,"stem":249},"5.project\u002Findex",{"title":251,"path":252,"stem":253},"Architecture","\u002Fproject\u002Farchitecture","5.project\u002F1.architecture",{"title":255,"path":256,"stem":257},"Contributing","\u002Fproject\u002Fcontributing","5.project\u002F2.contributing",{"title":259,"path":260,"stem":261},"Security","\u002Fproject\u002Fsecurity","5.project\u002F3.security",{"title":263,"path":264,"stem":265},"Data and privacy","\u002Fproject\u002Fdata-and-privacy","5.project\u002F4.data-and-privacy",{"title":267,"path":268,"stem":269},"Status and support","\u002Fproject\u002Fstatus-and-support","5.project\u002F5.status-and-support",{"id":271,"title":202,"body":272,"description":1557,"extension":1558,"links":1559,"meta":1560,"navigation":1561,"path":203,"seo":1562,"stem":204,"__hash__":1563},"docs\u002F4.reference\u002F4.permissions.md",{"type":273,"value":274,"toc":1541},"minimark",[275,283,288,438,483,500,503,510,517,562,565,593,623,626,725,741,760,762,772,789,800,845,849,858,875,904,921,975,978,1018,1022,1034,1121,1127,1129,1147,1218,1224,1334,1345,1350,1353,1408,1412,1422,1439,1443,1464,1468,1474,1495,1498,1531,1537],[276,277,278,279,282],"p",{},"Kraft's permission gate answers a worker's tool-permission request from the\ntask's own policy. Each answer, allow or deny and why, lands on the work\nitem's timeline. For the reasoning behind this design, see\n",[280,281,48],"a",{"href":49},".",[284,285,287],"h2",{"id":286},"which-harnesses-reach-the-gate","Which harnesses reach the gate",[289,290,291,313],"table",{},[292,293,294],"thead",{},[295,296,297,301,304,307,310],"tr",{},[298,299,300],"th",{},"Harness",[298,302,303],{},"Mechanism",[298,305,306],{},"Reaches the gate",[298,308,309],{},"Timeline events",[298,311,312],{},"Grants",[314,315,316,332,350,367,382,395,413],"tbody",{},[295,317,318,322,325,328,330],{},[319,320,321],"td",{},"Claude",[319,323,324],{},"Permission prompt tool",[319,326,327],{},"Yes",[319,329,327],{},[319,331,327],{},[295,333,334,337,344,346,348],{},[319,335,336],{},"Cursor",[319,338,339,343],{},[340,341,342],"code",{},"preToolUse"," hook",[319,345,327],{},[319,347,327],{},[319,349,327],{},[295,351,352,355,361,363,365],{},[319,353,354],{},"Codex",[319,356,357,360],{},[340,358,359],{},"PreToolUse"," hook, trusted per launch",[319,362,327],{},[319,364,327],{},[319,366,327],{},[295,368,369,372,375,378,380],{},[319,370,371],{},"OpenCode",[319,373,374],{},"Rules written at launch",[319,376,377],{},"No",[319,379,377],{},[319,381,377],{},[295,383,384,387,389,391,393],{},[319,385,386],{},"Amp",[319,388,374],{},[319,390,377],{},[319,392,377],{},[319,394,377],{},[295,396,397,400,407,409,411],{},[319,398,399],{},"Gemini",[319,401,402,403,406],{},"Its most permissive unattended mode (",[340,404,405],{},"--approval-mode yolo",")",[319,408,377],{},[319,410,377],{},[319,412,377],{},[295,414,415,418,432,434,436],{},[319,416,417],{},"Antigravity",[319,419,402,420,423,424,427,428,431],{},[340,421,422],{},"--dangerously-skip-permissions","); a task with ",[340,425,426],{},"deny_tools"," or ",[340,429,430],{},"allowed_tools"," is refused",[319,433,377],{},[319,435,377],{},[319,437,377],{},[276,439,440,441,445,446,449,450,453,454,457,458,461,462,464,465,467,468,470,471,474,475,477,478,482],{},"Under a ",[280,442,444],{"href":443},"\u002Freference\u002Fconfiguration\u002Frepos#sandboxed-workers","sandbox"," with ",[340,447,448],{},"network:",", the Codex hook reaches Kraft through the sandbox's own route out: its command is Kraft's ",[340,451,452],{},"kraft"," shim, mounted read-only in every such container at ",[340,455,456],{},"\u002Fopt\u002Fkraft\u002Fbin",", which asks the permission gate in the Kraft server as that session and denies whenever it gets no answer. The hook is trusted by the hash the image's own ",[340,459,460],{},"codex"," gives, asked in a short container with no network: Codex skips an untrusted hook without a word and runs the call, so a task whose image cannot vouch for the hook is refused. The launch also switches hooks on and marks Kraft's enabled, so a Codex config a worker writes into its home directory cannot turn the hook off. A sandbox without ",[340,463,448],{}," has no route to Kraft, so there a Codex or Cursor task with something to enforce is refused instead of run unenforced, and the refusal says so. (Cursor ignores a proxy, so a sandbox with ",[340,466,448],{}," refuses it anyway.) Claude asks the same way: under ",[340,469,448],{}," it is launched with Kraft's own MCP server at ",[340,472,473],{},"http:\u002F\u002Fkraft\u002Fmcp"," and no other, which answers its permission tool for that session alone. Without ",[340,476,448],{}," a sandboxed Claude task is refused whatever its policy, since its permission tool would be missing and the CLI exits at start. See ",[280,479,481],{"href":480},"\u002Freference\u002Fconfiguration\u002Frepos#callbacks-from-a-sandbox","Callbacks from a sandbox",". OpenCode and Amp keep their mechanism.",[276,484,485,486,488,489,491,492,496,497,282],{},"OpenCode and Amp still enforce ",[340,487,426],{}," and ",[340,490,430],{}," through\n",[280,493,495],{"href":494},"#opencode-and-amp-rules-written-at-launch","rules written at launch",". See\n",[280,498,499],{"href":213},"How each harness runs unattended",[284,501,321],{"id":502},"claude",[276,504,505,506,509],{},"Kraft launches Claude with its own MCP tool, ",[340,507,508],{},"mcp__kraft__permission_request",",\nas the permission prompt tool. Claude calls it for any tool call its own\nclassifier does not settle, and Kraft answers from the task's policy.",[276,511,512,513,516],{},"What reaches the gate depends on ",[340,514,515],{},"permission_mode",":",[289,518,519,534],{},[292,520,521],{},[295,522,523,528,531],{},[298,524,525,526],{},"Task's ",[340,527,430],{},[298,529,530],{},"Claude's mode",[298,532,533],{},"What reaches the gate",[314,535,536,549],{},[295,537,538,541,546],{},[319,539,540],{},"Not set",[319,542,543],{},[340,544,545],{},"auto",[319,547,548],{},"Only calls Claude's classifier declines to settle.",[295,550,551,554,559],{},[319,552,553],{},"Set",[319,555,556],{},[340,557,558],{},"manual",[319,560,561],{},"Every call the built-in tool-name allowlist does not cover.",[284,563,336],{"id":564},"cursor",[276,566,567,568,570,571,574,575,578,579,582,583,585,586,588,589,592],{},"Cursor runs a ",[340,569,342],{}," hook before every tool call, ahead of its own\n",[340,572,573],{},"--auto-review"," classifier. When a Cursor task's policy has something to\nenforce, Kraft writes an entry into the worktree's ",[340,576,577],{},".cursor\u002Fhooks.json"," that\nruns ",[340,580,581],{},"kraft admin permission-hook cursor",". Something to enforce means an\n",[340,584,430],{}," list, any ",[340,587,426],{},", or a grant other than ",[340,590,591],{},"git-commit",".\nWith nothing to enforce, Kraft writes no hook.",[594,595,596,600,603,609],"ul",{},[597,598,599],"li",{},"Your repository's own hooks in that file stay. Kraft's entry sits beside\nthem.",[597,601,602],{},"The entry stays for the worktree's life and is the same for every launch.",[597,604,605,606,608],{},"If a launch needs the hook and ",[340,607,577],{}," cannot be read, Kraft\nrefuses the launch and names the file.",[597,610,611,612,614,615,618,619,622],{},"The file never reaches a commit. Kraft excludes an untracked\n",[340,613,577],{}," through one marked line in the repository's\n",[340,616,617],{},"info\u002Fexclude",", and a tracked one through ",[340,620,621],{},"skip-worktree"," in that\nworktree's index. A skip-worktree file can make a rebase that touches it\nrefuse to run.",[276,624,625],{},"The hook sees Cursor's tools under the names your policy uses:",[289,627,628,641],{},[292,629,630],{},[295,631,632,635,638],{},[298,633,634],{},"Cursor's tool",[298,636,637],{},"Checked as",[298,639,640],{},"Note",[314,642,643,657,670,687,700,714],{},[295,644,645,650,655],{},[319,646,647],{},[340,648,649],{},"Shell",[319,651,652],{},[340,653,654],{},"Bash",[319,656],{},[295,658,659,664,668],{},[319,660,661],{},[340,662,663],{},"Read",[319,665,666],{},[340,667,663],{},[319,669],{},[295,671,672,677,684],{},[319,673,674],{},[340,675,676],{},"Write",[319,678,679,488,681],{},[340,680,676],{},[340,682,683],{},"Edit",[319,685,686],{},"Cursor creates and edits files with it. Denied if either is denied. Allowed under an allowlist only if both are listed.",[295,688,689,694,698],{},[319,690,691],{},[340,692,693],{},"Delete",[319,695,696],{},[340,697,693],{},[319,699],{},[295,701,702,707,711],{},[319,703,704],{},[340,705,706],{},"Grep",[319,708,709],{},[340,710,706],{},[319,712,713],{},"Also covers Cursor's glob.",[295,715,716,719,722],{},[319,717,718],{},"Web fetch, web search",[319,720,721],{},"none",[319,723,724],{},"Never reach the hook.",[276,726,727,728,427,731,734,735,737,738,740],{},"Kraft cannot deny a web fetch or web search on Cursor. A Cursor launch whose\npolicy would have to deny one is refused, rather than run with that part of\nits policy unenforced. That means ",[340,729,730],{},"WebFetch",[340,732,733],{},"WebSearch"," in ",[340,736,426],{},",\nor an ",[340,739,430],{}," list that does not name both.",[276,742,743,744,748,749,751,752,755,756,759],{},"The hook asks the gate in ",[745,746,747],"strong",{},"enforce"," mode. Under an ",[340,750,430],{}," list, the\nlaunch sets ",[340,753,754],{},"KRAFT_PERMISSION_FAIL_CLOSED=1"," in the worker's environment, and\nthe hook fails closed: if Kraft is unreachable, the payload is unreadable or\nthe policy cannot be resolved, the call is denied. Without an allowlist, any\nof those is no opinion, and Cursor's classifier decides as if there were no\nhook. Kraft's entry also sets ",[340,757,758],{},"failClosed: true",", so a hook that crashes or\ntakes longer than its 10-second timeout denies the call, with or without an\nallowlist: Cursor would otherwise allow it.",[284,761,354],{"id":460},[276,763,764,765,767,768,771],{},"Codex runs a ",[340,766,359],{}," hook before each tool call. When a Codex task's\npolicy has something to enforce (the same rule as Cursor), the launch adds two\n",[340,769,770],{},"-c"," flags, on the resume command line too:",[594,773,774,783],{},[597,775,776,779,780,282],{},[340,777,778],{},"hooks.PreToolUse"," runs ",[340,781,782],{},"kraft admin permission-hook codex",[597,784,785,788],{},[340,786,787],{},"hooks.state"," trusts exactly that hook.",[276,790,791,792,795,796,799],{},"Kraft never passes ",[340,793,794],{},"--dangerously-bypass-hook-trust",", since that also trusts\nevery hook a repository ships. Kraft writes nothing to your ",[340,797,798],{},"~\u002F.codex"," or to\nthe worktree. If Codex cannot list the hook, does not trust it, or does not\nanswer within 15 seconds, Kraft refuses the launch.",[594,801,802,812,826,832,835],{},[597,803,804,805,808,809,811],{},"The hook also fires for Codex's own background agents. A call whose working\ndirectory is inside Codex's home (",[340,806,807],{},"$CODEX_HOME",", else ",[340,810,798],{},") gets no\nopinion and never reaches the gate. Every other call is asked, wherever it\nruns.",[597,813,814,815,817,818,821,822,488,824,282],{},"Codex calls its shell ",[340,816,654],{},". ",[340,819,820],{},"apply_patch",", its one tool for creating and\nediting files, is checked as both ",[340,823,676],{},[340,825,683],{},[597,827,828,829,831],{},"Web search runs on OpenAI's side and never reaches the hook. A Codex launch\nwhose policy would have to deny ",[340,830,733],{}," is refused.",[597,833,834],{},"Fail-closed under an allowlist works as it does for Cursor.",[597,836,837,838,841,842,282],{},"No opinion is ",[340,839,840],{},"{}",", which leaves the decision to Codex's own reviewer. A\ndeny blocks the call, and the agent sees\n",[340,843,844],{},"Command blocked by PreToolUse hook: Kraft: \u003Creason>",[284,846,848],{"id":847},"opencode-and-amp-rules-written-at-launch","OpenCode and Amp: rules written at launch",[276,850,851,852,854,855,857],{},"OpenCode and Amp get no per-call hook. Kraft writes the task's ",[340,853,426],{}," and\n",[340,856,430],{}," into the CLI's own permission configuration for that one\nlaunch, and the CLI enforces them itself. With neither set, Kraft writes\nnothing.",[276,859,860,862,863,866,867,870,871,874],{},[745,861,371],{}," gets the rules as a ",[340,864,865],{},"permission"," block in\n",[340,868,869],{},"OPENCODE_CONFIG_CONTENT",", and runs as ",[340,872,873],{},"opencode run --standalone",", because\nonly a standalone run reads that block.",[594,876,877,883,894],{},[597,878,879,880,282],{},"A denied tool is ",[340,881,882],{},"deny",[597,884,885,886,889,890,893],{},"An allowlist is ",[340,887,888],{},"\"*\": \"deny\""," followed by ",[340,891,892],{},"allow"," for each listed tool.",[597,895,896,897,899,900,903],{},"Denying ",[340,898,654],{}," also denies ",[340,901,902],{},"execute",", OpenCode's code mode.",[276,905,906,908,909,912,913,916,917,920],{},[745,907,386],{}," gets a settings file of the launch's own,\n",[340,910,911],{},"$KRAFT_HOME\u002Frun\u002Fharness-config\u002Famp\u002F\u003Csession>.json",", passed with\n",[340,914,915],{},"--settings-file",". For that run it replaces ",[340,918,919],{},"~\u002F.config\u002Famp\u002Fsettings.json",",\nwhich Kraft never reads or writes. Your Amp login still works.",[594,922,923,930,937,955,964],{},[597,924,925,926,929],{},"Its ",[340,927,928],{},"amp.permissions"," rules come before Amp's built-in ones, and the first\nmatch wins.",[597,931,932,933,936],{},"A denied tool gets a ",[340,934,935],{},"reject"," rule and everything else is left to Amp's\nbuilt-ins.",[597,938,939,940,942,943,946,947,950,951,954],{},"Under an allowlist, each listed tool gets an ",[340,941,892],{}," rule and a final ",[340,944,945],{},"*","\nrule rejects the rest. An allowlisted tool is therefore allowed outright:\nAmp's own built-in asks (a ",[340,948,949],{},"git push",", an ",[340,952,953],{},"rm -rf",") no longer apply to it.",[597,956,896,957,959,960,963],{},[340,958,654],{}," rejects ",[340,961,962],{},"shell_command"," and its async and legacy forms.",[597,965,966,967,427,969,971,972,974],{},"Amp has no read, grep or glob tool of its own. ",[340,968,663],{},[340,970,706],{}," in\n",[340,973,426],{}," refuses an Amp launch, and in an allowlist grants nothing.",[276,976,977],{},"On both:",[594,979,980,983,986,1000,1007],{},[597,981,982],{},"A denied tool name that no tool on that CLI maps to refuses the launch and\nnames the tool.",[597,984,985],{},"An allowlisted name the CLI has no tool for grants nothing. Every tool not\nlisted is denied anyway.",[597,987,988,989,992,993,995,996,854,998,282],{},"A CLI tool that covers two policy names is denied if either is denied, and\nallowed under an allowlist only if both are listed. This applies to\nOpenCode's ",[340,990,991],{},"edit"," and Amp's ",[340,994,820],{},", which each cover ",[340,997,683],{},[340,999,676],{},[597,1001,1002,1003,1006],{},"Nothing reaches the gate, so none of this appears as a ",[340,1004,1005],{},"permission_decision","\non the timeline.",[597,1008,1009,1010,1013,1014,1017],{},"Grants are not applied. A CLI rule like ",[340,1011,1012],{},"git push *"," would also match\n",[340,1015,1016],{},"git push x; rm -rf y",", so Kraft writes no grant.",[284,1019,1021],{"id":1020},"how-the-gate-decides","How the gate decides",[276,1023,1024,1025,1027,1028,488,1030,1033],{},"The gate answers from the resolved policy of the task the calling session is\nrunning: the same ",[340,1026,430],{},", ",[340,1029,426],{},[340,1031,1032],{},"grants"," its launch\nresolved. It checks these rows in order:",[289,1035,1036,1049],{},[292,1037,1038],{},[295,1039,1040,1043,1046],{},[298,1041,1042],{},"The call",[298,1044,1045],{},"Prompt mode (Claude)",[298,1047,1048],{},"Enforce mode (Cursor and Codex hooks)",[314,1050,1051,1063,1073,1085,1096,1111],{},[295,1052,1053,1058,1061],{},[319,1054,1055,1056],{},"Names a tool in ",[340,1057,426],{},[319,1059,1060],{},"Deny",[319,1062,1060],{},[295,1064,1065,1068,1071],{},[319,1066,1067],{},"Is an instance of one of the task's grants",[319,1069,1070],{},"Allow",[319,1072,1070],{},[295,1074,1075,1080,1082],{},[319,1076,1077,1078],{},"No layer set ",[340,1079,430],{},[319,1081,1070],{},[319,1083,1084],{},"No opinion: the CLI's own classifier or reviewer decides",[295,1086,1087,1092,1094],{},[319,1088,1089,1091],{},[340,1090,430],{}," is set and names the tool",[319,1093,1070],{},[319,1095,1070],{},[295,1097,1098,1107,1109],{},[319,1099,1100,1102,1103,1106],{},[340,1101,430],{}," is set and does not name it (",[340,1104,1105],{},"[]"," names nothing)",[319,1108,1060],{},[319,1110,1060],{},[295,1112,1113,1116,1118],{},[319,1114,1115],{},"The policy cannot be resolved (the task or its profile is gone)",[319,1117,1060],{},[319,1119,1120],{},"Deny if the session is fail-closed, else no opinion",[276,1122,1123,1124,1126],{},"A deny is a deny on every harness. An allow is not always final. On Cursor, a\nhook allow does not override ",[340,1125,573],{},", so Cursor's classifier can still\nrefuse a call the gate allowed. Whether a Codex hook allow outranks Codex's\nreviewer is not guaranteed.",[284,1128,312],{"id":1032},[276,1130,1131,1132,1134,1135,1027,1137,427,1140,1143,1144,1146],{},"A grant is a named operation the gate allows a task even outside its\n",[340,1133,430],{},": ",[340,1136,591],{},[340,1138,1139],{},"git-rebase",[340,1141,1142],{},"git-push",". It matches a ",[340,1145,654],{},"\ncall only when the command is exactly one plain git invocation of that\nsubcommand. Otherwise the call falls through to the rest of the decision\ntable. A command is refused as a grant if it has:",[594,1148,1149,1165,1172,1195],{},[597,1150,1151,1152,1155,1156,427,1159,1161,1162,1164],{},"a shell operator, substitution, redirection, subshell, brace or glob\nexpansion, backslash, ",[340,1153,1154],{},"!"," or a newline. A commit message with ",[340,1157,1158],{},"$",[340,1160,1154],{}," in\nit, a multi-line one, or one written through a heredoc is not granted. With\nno allowlist that leaves it to the CLI's classifier. Under an allowlist\nwithout ",[340,1163,654],{}," it is denied.",[597,1166,1167,1168,1171],{},"an env prefix, or anything but ",[340,1169,1170],{},"git"," as the first word.",[597,1173,1174,1175,1027,1178,1181,1182,1184,1185,427,1188,817,1191,1194],{},"a git option before the subcommand other than ",[340,1176,1177],{},"--no-pager",[340,1179,1180],{},"-P",", or ",[340,1183,770],{},"\nsetting ",[340,1186,1187],{},"user.name",[340,1189,1190],{},"user.email",[340,1192,1193],{},"-C"," is refused because it would point\ngit at another repository's config and hooks.",[597,1196,1197,1198,854,1201,1204,1205,1207,1208,488,1211,1207,1214,1217],{},"an option that runs a command of the caller's choosing: ",[340,1199,1200],{},"--exec",[340,1202,1203],{},"--receive-pack"," on push, ",[340,1206,1200],{},"\u002F",[340,1209,1210],{},"-x",[340,1212,1213],{},"--strategy",[340,1215,1216],{},"-s"," on rebase, and\nany abbreviation of those long options.",[276,1219,1220,1221,1223],{},"A ",[340,1222,1142],{}," grant is further held to one named remote and the work item's own\nbranch.",[594,1225,1226,1246,1267,1313],{},[597,1227,1228,1229,1027,1232,1234,1235,1238,1239,1027,1241,427,1243,1245],{},"Its first positional must be a plain remote name (letters, digits, ",[340,1230,1231],{},"_",[340,1233,282],{},",\n",[340,1236,1237],{},"-",", not starting with ",[340,1240,282],{},[340,1242,1231],{},[340,1244,1237],{},"), never a URL or path.",[597,1247,1248,1249,1027,1252,1255,1256,1259,1260,1263,1264,1266],{},"At least one refspec must follow, and every one must update the item's\nbranch and nothing else: ",[340,1250,1251],{},"\u003Cbranch>",[340,1253,1254],{},"refs\u002Fheads\u002F\u003Cbranch>",", or\n",[340,1257,1258],{},"\u003Csrc>:"," either of those, such as ",[340,1261,1262],{},"HEAD:\u003Cbranch>",". A push that names no\nrefspec, such as a bare ",[340,1265,949],{},", is not a grant: where it goes depends on\ngit config the gate cannot see.",[597,1268,1269,1270,1207,1273,1027,1276,1027,1279,1282,1283,1286,1287,1027,1290,1027,1293,1027,1296,1027,1299,1234,1302,1207,1305,1308,1309,1312],{},"Kraft refuses ",[340,1271,1272],{},"--delete",[340,1274,1275],{},"-d",[340,1277,1278],{},"--mirror",[340,1280,1281],{},"--all"," (and ",[340,1284,1285],{},"--branches","),\n",[340,1288,1289],{},"--prune",[340,1291,1292],{},"--tags",[340,1294,1295],{},"--follow-tags",[340,1297,1298],{},"--recurse-submodules",[340,1300,1301],{},"--repo",[340,1303,1304],{},"-o",[340,1306,1307],{},"--push-option",", and a refspec with an empty ",[340,1310,1311],{},"\u003Csrc>",", which deletes.",[597,1314,1315,1316,1207,1319,1322,1323,1326,1327,1330,1331,282],{},"Kraft refuses a plain ",[340,1317,1318],{},"--force",[340,1320,1321],{},"-f"," and a forced ",[340,1324,1325],{},"+refspec",".\n",[340,1328,1329],{},"--force-with-lease"," stays allowed, because an escalation that rebased the\nbranch has to force-push it. An escalation turn is told the command:\n",[340,1332,1333],{},"git push --force-with-lease origin HEAD:\u003Cbranch>",[276,1335,1336,1337,1340,1341,1344],{},"A grant does not stop git's own hooks. A commit or push under a grant still\nruns the repository's hooks, including a ",[340,1338,1339],{},"core.hooksPath"," inside the tree\n(",[340,1342,1343],{},".husky\u002F",", say), which the agent can edit.",[1346,1347,1349],"h3",{"id":1348},"where-a-grant-takes-effect","Where a grant takes effect",[276,1351,1352],{},"A grant is the gate's decision, a logged allow on the item's timeline. Whether\nthe CLI then runs the call is the CLI's own business.",[289,1354,1355,1364],{},[292,1356,1357],{},[295,1358,1359,1361],{},[298,1360,300],{},[298,1362,1363],{},"Limit",[314,1365,1366,1376,1384,1400],{},[295,1367,1368,1370],{},[319,1369,336],{},[319,1371,1372,1373,1375],{},"A hook allow does not override ",[340,1374,573],{},", so the classifier can still refuse a granted call.",[295,1377,1378,1381],{},[319,1379,1380],{},"Claude, no allowlist",[319,1382,1383],{},"The gate already allows every tool, so a grant adds nothing.",[295,1385,1386,1391],{},[319,1387,1388,1389],{},"Claude, allowlist without ",[340,1390,654],{},[319,1392,1393,1394,1396,1397,1399],{},"Claude launches without a ",[340,1395,654],{}," tool at all, so a granted ",[340,1398,949],{}," never reaches the gate.",[295,1401,1402,1405],{},[319,1403,1404],{},"OpenCode, Amp",[319,1406,1407],{},"Grants are not applied.",[1346,1409,1411],{"id":1410},"how-grants-combine","How grants combine",[276,1413,1414,1415,1418,1419,1421],{},"Grants accumulate down the layers (repository ",[340,1416,1417],{},"policy:",", chain, node, step,\ntask), as ",[340,1420,426],{}," does. A workspace grants only what every repository in\nit grants. A work item's own override, and a retry's, can drop a grant but\nnever add one.",[276,1423,1424,1425,1428,1429,1432,1433,1435,1436,1438],{},"An escalation turn holds its node's grants plus ",[340,1426,1427],{},"defaults.escalation_grants","\nfrom ",[340,1430,1431],{},"policy.yaml",". Unset, that is all three grants. Set it to a shorter list,\nor ",[340,1434,1105],{},", to grant escalations less. A gate's reviewer gets no such default.\nA chain task's ",[340,1437,591],{}," already comes with its launch.",[284,1440,1442],{"id":1441},"configuring-the-gate","Configuring the gate",[276,1444,1445,1446,1027,1448,488,1450,1452,1453,1027,1455,488,1457,1459,1460,1463],{},"The gate enforces whatever ",[340,1447,430],{},[340,1449,426],{},[340,1451,1032],{}," resolve\nto at the task's scope. Set them like any other policy field. See the\n",[340,1454,430],{},[340,1456,426],{},[340,1458,1032],{}," rows in\n",[280,1461,140],{"href":1462},"\u002Freference\u002Fconfiguration\u002Fpolicy#policy-fields"," for how the layers\ncombine.",[284,1465,1467],{"id":1466},"reading-decisions","Reading decisions",[276,1469,1470,1471,1473],{},"Kraft appends every decision to the work item's timeline as a\n",[340,1472,1005],{}," event. The event carries:",[594,1475,1476,1479,1482,1485],{},[597,1477,1478],{},"the tool name, and the session and node it came from;",[597,1480,1481],{},"the decision and the reason;",[597,1483,1484],{},"the grant that allowed it, if one did;",[597,1486,1487,1488,1234,1491,1494],{},"for a hook, the harness and the CLI's own tool name (",[340,1489,1490],{},"harness: cursor",[340,1492,1493],{},"cli_tool: Shell",").",[276,1496,1497],{},"No opinion is not a decision, so an enforce-mode call left to Cursor's\nclassifier logs nothing. Read the events with:",[1499,1500,1505],"pre",{"className":1501,"code":1502,"language":1503,"meta":1504,"style":1504},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","kraft view events ID --type permission_decision\n","bash","",[340,1506,1507],{"__ignoreMap":1504},[1508,1509,1512,1515,1519,1522,1525,1528],"span",{"class":1510,"line":1511},"line",1,[1508,1513,452],{"class":1514},"sBMFI",[1508,1516,1518],{"class":1517},"sfazB"," view",[1508,1520,1521],{"class":1517}," events",[1508,1523,1524],{"class":1517}," ID",[1508,1526,1527],{"class":1517}," --type",[1508,1529,1530],{"class":1517}," permission_decision\n",[276,1532,1533,1534,1536],{},"Add ",[340,1535,1321],{}," to watch a live item.",[1538,1539,1540],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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":1504,"searchDepth":1542,"depth":1542,"links":1543},2,[1544,1545,1546,1547,1548,1549,1550,1555,1556],{"id":286,"depth":1542,"text":287},{"id":502,"depth":1542,"text":321},{"id":564,"depth":1542,"text":336},{"id":460,"depth":1542,"text":354},{"id":847,"depth":1542,"text":848},{"id":1020,"depth":1542,"text":1021},{"id":1032,"depth":1542,"text":312,"children":1551},[1552,1554],{"id":1348,"depth":1553,"text":1349},3,{"id":1410,"depth":1553,"text":1411},{"id":1441,"depth":1542,"text":1442},{"id":1466,"depth":1542,"text":1467},"What Kraft's permission gate does per harness, how it decides, and the keys that configure it.","md",null,{},true,{"title":202,"description":1557},"fRgIZKtKTm4haInKlrNiAWWkQyF6LyoLkoorOybr_l4",[1565,1567],{"title":198,"path":199,"stem":200,"description":1566,"children":-1},"The JSON file a task writes at $KRAFT_RESULT_PATH, and every field Kraft reads from it.",{"title":10,"path":207,"stem":208,"description":1568,"children":-1},"Which agent CLIs Kraft runs, what each supports, and how a task picks one.",1790824507725]