[{"data":1,"prerenderedAt":682},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fv2\u002Ftui\u002Fstructure\u002Fpolicy":3},{"id":4,"title":5,"body":6,"description":673,"extension":674,"meta":675,"navigation":677,"path":678,"seo":679,"stem":680,"__hash__":681},"docs\u002Fdocs\u002Fv2\u002Ftui\u002Fstructure\u002Fpolicy.md","profile policy",{"type":7,"value":8,"toc":665},"minimark",[9,14,23,155,162,167,186,190,211,216,231,246,250,257,277,293,382,392,396,399,515,535,542,556,560,563,574,597,613,617,624,632,636,643,652,661],[10,11,13],"h1",{"id":12},"profile-policy","Profile policy",[15,16,17,18,22],"p",{},"A ",[19,20,21],"strong",{},"ceiling over every agent on this machine."," An agent narrows within it and can never\nwiden it — so a profile that says \"ask me before any shell command\" means every agent asks,\nincluding one you installed from the registry and never read.",[24,25,30],"pre",{"className":26,"code":27,"language":28,"meta":29,"style":29},"language-ts shiki shiki-themes dark-plus","\u002F\u002F profile.config.ts\nexport default defineProfile({\n    policy: {\n        tools: {\n            search: \"escalate\",     \u002F\u002F ask before any @axon\u002Fsearch tool\n        },\n        process: {\n            run: \"escalate\",        \u002F\u002F every one-shot command asks\n            spawn: false,           \u002F\u002F long-lived children: off entirely\n        },\n    },\n})\n","ts","",[31,32,33,42,60,70,78,94,100,108,122,138,143,149],"code",{"__ignoreMap":29},[34,35,38],"span",{"class":36,"line":37},"line",1,[34,39,41],{"class":40},"sOLPB","\u002F\u002F profile.config.ts\n",[34,43,45,49,52,56],{"class":36,"line":44},2,[34,46,48],{"class":47},"sYbnZ","export",[34,50,51],{"class":47}," default",[34,53,55],{"class":54},"sCudf"," defineProfile",[34,57,59],{"class":58},"sTNBD","({\n",[34,61,63,67],{"class":36,"line":62},3,[34,64,66],{"class":65},"s3F5K","    policy:",[34,68,69],{"class":58}," {\n",[34,71,73,76],{"class":36,"line":72},4,[34,74,75],{"class":65},"        tools:",[34,77,69],{"class":58},[34,79,81,84,88,91],{"class":36,"line":80},5,[34,82,83],{"class":65},"            search:",[34,85,87],{"class":86},"sKc5r"," \"escalate\"",[34,89,90],{"class":58},",     ",[34,92,93],{"class":40},"\u002F\u002F ask before any @axon\u002Fsearch tool\n",[34,95,97],{"class":36,"line":96},6,[34,98,99],{"class":58},"        },\n",[34,101,103,106],{"class":36,"line":102},7,[34,104,105],{"class":65},"        process:",[34,107,69],{"class":58},[34,109,111,114,116,119],{"class":36,"line":110},8,[34,112,113],{"class":65},"            run:",[34,115,87],{"class":86},[34,117,118],{"class":58},",        ",[34,120,121],{"class":40},"\u002F\u002F every one-shot command asks\n",[34,123,125,128,132,135],{"class":36,"line":124},9,[34,126,127],{"class":65},"            spawn:",[34,129,131],{"class":130},"scz_3"," false",[34,133,134],{"class":58},",           ",[34,136,137],{"class":40},"\u002F\u002F long-lived children: off entirely\n",[34,139,141],{"class":36,"line":140},10,[34,142,99],{"class":58},[34,144,146],{"class":36,"line":145},11,[34,147,148],{"class":58},"    },\n",[34,150,152],{"class":36,"line":151},12,[34,153,154],{"class":58},"})\n",[15,156,157,158,161],{},"That ",[31,159,160],{},"search: \"escalate\""," is what the rule looks like from the other side. The agent calls\na search tool, the call suspends, and you answer — whichever agent it was, whether or not\nits own config had anything to say about searching:",[163,164],"terminal-image",{"alt":165,"src":166},"The terminal paused on a search.web call, showing the query and three choices: allow once, allow always, and deny","\u002Ftui\u002Fpolicy-escalation-prompt.webp",[15,168,169,170,173,174,177,178,181,182,185],{},"Answer ",[19,171,172],{},"allow always"," and a grant is written, so that call stops asking. Answer ",[19,175,176],{},"deny","\n— or write ",[31,179,180],{},"false"," instead of ",[31,183,184],{},"\"escalate\""," — and the agent is told the call was blocked:",[163,187],{"alt":188,"src":189},"A denied call shown as CAPSULE_POLICY_DENIED: search.web denied by policy, with the agent explaining it cannot reach live web results and offering another route","\u002Ftui\u002Fpolicy-denied.webp",[15,191,192,193,196,197,200,201,204,205,207,208,210],{},"It sits at the ",[19,194,195],{},"top level",", beside ",[31,198,199],{},"extensions"," and ",[31,202,203],{},"settings"," — never inside them.\n",[31,206,203],{}," is the set of keys the terminal acts on; policy is read by the runtime. A\npolicy block nested under ",[31,209,203],{}," is silently ignored rather than honoured, because a\nboundary that moves depending on where you wrote it is not a boundary.",[212,213,215],"h2",{"id":214},"why-the-profile-not-the-agent","Why the profile, not the agent",[15,217,218,219,222,223,226,227,230],{},"An agent's own ",[31,220,221],{},"policy"," block is a statement about what that agent needs. That is the\nright layer for \"this agent only reads ",[31,224,225],{},".\u002Fsrc","\" — the author knows. It is the wrong layer\nfor \"nothing on my laptop touches ",[31,228,229],{},"~\u002F.ssh","\", because it depends on every agent author\nagreeing with you, forever, including in agents you install without reading.",[15,232,233,234,237,238,241,242,245],{},"The ceiling is resolved in the ",[19,235,236],{},"kernel",", at the one seam every consumer passes through:\nthe TUI, ",[31,239,240],{},"axon dev",", ",[31,243,244],{},"axon run"," in a script, a test harness. A ceiling applied only on the\nterminal's spawn path would be advisory, and the CLI is exactly where someone scripting\nwould step around it without meaning to.",[212,247,249],{"id":248},"the-two-layers","The two layers",[15,251,252,253,256],{},"Both layers keep their rules. They are not merged into one — the pair is carried down and\nevaluated ",[19,254,255],{},"per call",", so a verdict can always name which layer produced it.",[15,258,259,260,263,264,267,268,272,273,276],{},"That split matters more than it looks. Merging two glob rules is where a ceiling springs a\nleak: a profile allowing ",[31,261,262],{},"git status"," unioned with an agent allowing ",[31,265,266],{},"git push"," would\npermit a command that neither layer permits alone. Composing the ",[269,270,271],"em",{},"shape"," and deferring the\n",[269,274,275],{},"verdict"," is what makes that impossible.",[15,278,279,282,283,285,286,285,289,292],{},[19,280,281],{},"The stricter layer wins",", ranked ",[31,284,176],{}," > ",[31,287,288],{},"escalate",[31,290,291],{},"allow",". On a tie the profile is\nreported as the source, because telling you the agent denied something your profile also\ndenies sends you to the wrong file to fix it.",[294,295,296,312],"table",{},[297,298,299],"thead",{},[300,301,302,306,309],"tr",{},[303,304,305],"th",{},"Profile says",[303,307,308],{},"Agent says",[303,310,311],{},"Result",[313,314,315,331,348,361,372],"tbody",{},[300,316,317,322,325],{},[318,319,320],"td",{},[31,321,180],{},[318,323,324],{},"anything",[318,326,327,330],{},[19,328,329],{},"denied"," — a bare profile denial is final",[300,332,333,337,342],{},[318,334,335],{},[31,336,184],{},[318,338,339,340],{},"anything but ",[31,341,180],{},[318,343,344,347],{},[19,345,346],{},"asks"," — the agent cannot skip the prompt",[300,349,350,355,358],{},[318,351,352],{},[31,353,354],{},"true",[318,356,357],{},"its own rule",[318,359,360],{},"the agent's rule stands",[300,362,363,368,370],{},[318,364,365],{},[269,366,367],{},"(nothing)",[318,369,357],{},[318,371,360],{},[300,373,374,377,379],{},[318,375,376],{},"glob rule",[318,378,376],{},[318,380,381],{},"both evaluated; stricter verdict wins",[15,383,384,385,388,389,391],{},"A profile grant is a ",[19,386,387],{},"ceiling, not a grant",": ",[31,390,354],{}," removes a constraint you might have\nimposed, it does not hand an agent a capability its own policy withholds.",[212,393,395],{"id":394},"rule-shapes","Rule shapes",[15,397,398],{},"Any capability takes one of four forms:",[24,400,402],{"className":26,"code":401,"language":28,"meta":29,"style":29},"tools: {\n    github: true,           \u002F\u002F allow\n    payments: false,        \u002F\u002F deny — final if written at the profile\n    search: \"escalate\",     \u002F\u002F ask, every time\n    shell: {                \u002F\u002F glob rule\n        allow:    [\"git *\"],\n        escalate: [\"docker *\"],\n        deny:     [\"rm -rf *\"],\n    },\n}\n",[31,403,404,413,427,441,455,466,480,493,506,510],{"__ignoreMap":29},[34,405,406,410],{"class":36,"line":37},[34,407,409],{"class":408},"sqDPy","tools",[34,411,412],{"class":58},": {\n",[34,414,415,418,420,422,424],{"class":36,"line":44},[34,416,417],{"class":408},"    github",[34,419,388],{"class":58},[34,421,354],{"class":130},[34,423,134],{"class":58},[34,425,426],{"class":40},"\u002F\u002F allow\n",[34,428,429,432,434,436,438],{"class":36,"line":62},[34,430,431],{"class":408},"    payments",[34,433,388],{"class":58},[34,435,180],{"class":130},[34,437,118],{"class":58},[34,439,440],{"class":40},"\u002F\u002F deny — final if written at the profile\n",[34,442,443,446,448,450,452],{"class":36,"line":72},[34,444,445],{"class":408},"    search",[34,447,388],{"class":58},[34,449,184],{"class":86},[34,451,90],{"class":58},[34,453,454],{"class":40},"\u002F\u002F ask, every time\n",[34,456,457,460,463],{"class":36,"line":80},[34,458,459],{"class":408},"    shell",[34,461,462],{"class":58},": {                ",[34,464,465],{"class":40},"\u002F\u002F glob rule\n",[34,467,468,471,474,477],{"class":36,"line":96},[34,469,470],{"class":408},"        allow",[34,472,473],{"class":58},":    [",[34,475,476],{"class":86},"\"git *\"",[34,478,479],{"class":58},"],\n",[34,481,482,485,488,491],{"class":36,"line":102},[34,483,484],{"class":408},"        escalate",[34,486,487],{"class":58},": [",[34,489,490],{"class":86},"\"docker *\"",[34,492,479],{"class":58},[34,494,495,498,501,504],{"class":36,"line":110},[34,496,497],{"class":408},"        deny",[34,499,500],{"class":58},":     [",[34,502,503],{"class":86},"\"rm -rf *\"",[34,505,479],{"class":58},[34,507,508],{"class":36,"line":124},[34,509,148],{"class":58},[34,511,512],{"class":36,"line":140},[34,513,514],{"class":58},"}\n",[15,516,517,518,527,528,531,532,534],{},"Inside a glob rule, ",[19,519,520,522,523,522,525],{},[31,521,176],{}," beats ",[31,524,288],{},[31,526,291],{}," regardless of the order you\nwrite them. A consequence worth knowing: an ",[31,529,530],{},"escalate: [\"**\"]"," catch-all alongside an\nallowlist makes the allowlist unreachable — everything matches the catch-all first. If you\nmean \"ask me about all of it\", write ",[31,533,184],{}," on its own.",[15,536,537,538,541],{},"A glob rule that is declared but matches nothing is a ",[19,539,540],{},"denial",", not silence. Naming what\nis permitted and hitting none of it is an answer.",[15,543,544,545,548,549,551,552,555],{},"Rules key on the ",[19,546,547],{},"namespace"," a module registers its tools under, not on individual\nfunctions — ",[31,550,160],{}," covers every tool ",[31,553,554],{},"@axon\u002Fsearch"," brings.",[212,557,559],{"id":558},"fs-limits-and-isolation","fs, limits and isolation",[15,561,562],{},"Three keys behave differently, because they are OS-layer facts rather than per-call\ndecisions:",[15,564,565,573],{},[19,566,567,200,570],{},[31,568,569],{},"fs",[31,571,572],{},"limits"," are enforced by bind mounts and cgroups, which the mediator never\nsees and which cannot express an intersection of globs. When the profile declares either,\nthe profile's value is taken outright — a ceiling a bind mount ignores is not a ceiling.",[15,575,576,581,582,585,586,589,590,593,594,596],{},[19,577,578],{},[31,579,580],{},"isolation"," is a tier, not a rule, so it resolves as a maximum: ",[31,583,584],{},"none"," \u003C ",[31,587,588],{},"auto"," \u003C\n",[31,591,592],{},"hardened",". A profile asking for ",[31,595,592],{}," cannot be loosened by an agent, but an agent\nmay harden beyond its profile.",[15,598,599,600,241,602,605,606,608,609,612],{},"Declaring any of ",[31,601,569],{},[31,603,604],{},"network"," or ",[31,607,572],{}," at the profile also opts ",[19,610,611],{},"every agent on the\nmachine"," into rootless confinement, even one that declares no policy of its own. Setting\nnothing at all means full machine access — the deliberate default, so that a new user is\nnot fighting a sandbox before they have an agent worth confining.",[212,614,616],{"id":615},"when-the-config-is-broken","When the config is broken",[15,618,619,620,623],{},"A profile that fails to parse yields ",[19,621,622],{},"no ceiling"," rather than refusing to boot. It fails\nopen, matching the rest of the profile: the config loader reports the breakage where you\ncan see it, and a ceiling that made a typo unbootable would strand you inside the very\nfile you need to edit.",[15,625,626,627,631],{},"Worth knowing if you rely on the ceiling for something that matters — it is a safety rail\nfor your own machine, not an adversarial sandbox. The confinement layer is what contains a\nhostile agent; see ",[628,629,221],"a",{"href":630},"\u002Fdocs\u002Fv2\u002Fapi\u002Fconfig\u002Fpolicy"," for what the capsule enforces.",[212,633,635],{"id":634},"see-also","See also",[15,637,638,642],{},[19,639,640],{},[628,641,221],{"href":630}," — the agent-level block, and what each key means.",[15,644,645,651],{},[19,646,647],{},[628,648,650],{"href":649},"\u002Fdocs\u002Fv2\u002Fconcepts\u002Fkernel-and-policy","Kernel & Policy"," — how enforcement works, and\nwhere the mediator sits.",[15,653,654,660],{},[19,655,656],{},[628,657,659],{"href":658},"\u002Fdocs\u002Fv2\u002Ftui\u002Fstructure\u002Fconfig","profile.config.ts"," — the rest of the file.",[662,663,664],"style",{},"html pre.shiki code .sOLPB, html code.shiki .sOLPB{--shiki-default:#6A9955}html pre.shiki code .sYbnZ, html code.shiki .sYbnZ{--shiki-default:#C586C0}html pre.shiki code .sCudf, html code.shiki .sCudf{--shiki-default:#DCDCAA}html pre.shiki code .sTNBD, html code.shiki .sTNBD{--shiki-default:#D4D4D4}html pre.shiki code .s3F5K, html code.shiki .s3F5K{--shiki-default:#9CDCFE}html pre.shiki code .sKc5r, html code.shiki .sKc5r{--shiki-default:#CE9178}html pre.shiki code .scz_3, html code.shiki .scz_3{--shiki-default:#569CD6}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 pre.shiki code .sqDPy, html code.shiki .sqDPy{--shiki-default:#C8C8C8}",{"title":29,"searchDepth":44,"depth":44,"links":666},[667,668,669,670,671,672],{"id":214,"depth":44,"text":215},{"id":248,"depth":44,"text":249},{"id":394,"depth":44,"text":395},{"id":558,"depth":44,"text":559},{"id":615,"depth":44,"text":616},{"id":634,"depth":44,"text":635},"A ceiling over every agent on this machine. An agent narrows within it and can never\nwiden it — so a profile that says \"ask me before any shell command\" means every agent asks,\nincluding one you installed from the registry and never read.","md",{"icon":676},"vscode-icons:file-type-typescript",true,"\u002Fdocs\u002Fv2\u002Ftui\u002Fstructure\u002Fpolicy",{"title":5,"description":673},"docs\u002Fv2\u002Ftui\u002Fstructure\u002Fpolicy","mLbF-LAOfUSaRKEFUAWPlAe3as9Z31MPawvvMwZL4yw",1786881117846]