@turmind/halo 1.4.0 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin-out/404.html +1 -1
- package/admin-out/index.html +1 -1
- package/admin-out/index.txt +1 -1
- package/bundled-docs/design/agent.md +4 -5
- package/bundled-docs/design/prompt-system.md +1 -1
- package/bundled-docs/dev/tools.md +2 -5
- package/bundled-docs/guide/README.md +1 -0
- package/bundled-docs/guide/agents.md +2 -0
- package/bundled-docs/guide/delegation-and-access.md +161 -0
- package/bundled-docs/guide/sessions.md +1 -1
- package/dist/index.js +124 -34
- package/package.json +1 -1
- package/templates/skills/halo/SKILL.md +2 -1
- /package/admin-out/_next/static/{9_eFiojb_-MS8CJ2oJg8_ → Jf-8TVLoHHwpT-gitolxN}/_buildManifest.js +0 -0
- /package/admin-out/_next/static/{9_eFiojb_-MS8CJ2oJg8_ → Jf-8TVLoHHwpT-gitolxN}/_ssgManifest.js +0 -0
package/admin-out/404.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><!--
|
|
1
|
+
<!DOCTYPE html><!--Jf_8TVLoHHwpT_gitolxN--><html lang="en" class="dark"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/e4af272ccee01ff0-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/css/c0ea31cd787f7aa7.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-ca926228f8cba1ff.js"/><script src="/_next/static/chunks/1b86ba38-c29611e086b2ce25.js" async=""></script><script src="/_next/static/chunks/698-19872069fed27164.js" async=""></script><script src="/_next/static/chunks/main-app-340a5b58ed229c4d.js" async=""></script><script src="/_next/static/chunks/989-6a0ec35b8ae2cb39.js" async=""></script><script src="/_next/static/chunks/app/layout-5ec6c5f713a8562b.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><title>Halo - Multi-Agent Workspace</title><meta name="description" content="Multi-agent collaboration workspace for complex project delivery"/><link rel="icon" href="/favicon.ico" type="image/x-icon" sizes="16x16"/><link rel="icon" href="/icon.svg?3a6863548daca964" type="image/svg+xml" sizes="any"/><script>try{var t=localStorage.getItem('halo_theme');if(t==='light'||t==='midnight'||t==='warm')document.documentElement.dataset.theme=t}catch(e){}</script><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body class="__variable_f367f3 font-sans antialiased"><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-ca926228f8cba1ff.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[58321,[\"989\",\"static/chunks/989-6a0ec35b8ae2cb39.js\",\"177\",\"static/chunks/app/layout-5ec6c5f713a8562b.js\"],\"ThemeProvider\"]\n3:I[24554,[\"989\",\"static/chunks/989-6a0ec35b8ae2cb39.js\",\"177\",\"static/chunks/app/layout-5ec6c5f713a8562b.js\"],\"AppI18nProvider\"]\n4:I[63693,[],\"\"]\n5:I[74713,[],\"\"]\n6:I[23632,[],\"OutletBoundary\"]\n8:I[86889,[],\"AsyncMetadataOutlet\"]\na:I[23632,[],\"ViewportBoundary\"]\nc:I[23632,[],\"MetadataBoundary\"]\nd:\"$Sreact.suspense\"\nf:I[1935,[],\"\"]\n:HL[\"/_next/static/media/e4af272ccee01ff0-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/css/c0ea31cd787f7aa7.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"Jf-8TVLoHHwpT-gitolxN\",\"p\":\"\",\"c\":[\"\",\"_not-found\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/c0ea31cd787f7aa7.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"dark\",\"suppressHydrationWarning\":true,\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"try{var t=localStorage.getItem('halo_theme');if(t==='light'||t==='midnight'||t==='warm')document.documentElement.dataset.theme=t}catch(e){}\"}}]}],[\"$\",\"body\",null,{\"className\":\"__variable_f367f3 font-sans antialiased\",\"children\":[\"$\",\"$L2\",null,{\"children\":[\"$\",\"$L3\",null,{\"children\":[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]}]}]]}]]}],{\"children\":[\"/_not-found\",[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L6\",null,{\"children\":[\"$L7\",[\"$\",\"$L8\",null,{\"promise\":\"$@9\"}]]}]]}],{},null,false]},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[[\"$\",\"$La\",null,{\"children\":\"$Lb\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$Lc\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$d\",null,{\"fallback\":null,\"children\":\"$Le\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$f\",[]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"b:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n7:null\n"])</script><script>self.__next_f.push([1,"10:I[88809,[],\"IconMark\"]\n9:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"Halo - Multi-Agent Workspace\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Multi-agent collaboration workspace for complex project delivery\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico\",\"type\":\"image/x-icon\",\"sizes\":\"16x16\"}],[\"$\",\"link\",\"3\",{\"rel\":\"icon\",\"href\":\"/icon.svg?3a6863548daca964\",\"type\":\"image/svg+xml\",\"sizes\":\"any\"}],[\"$\",\"$L10\",\"4\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"e:\"$9:metadata\"\n"])</script></body></html>
|
package/admin-out/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><!--
|
|
1
|
+
<!DOCTYPE html><!--Jf_8TVLoHHwpT_gitolxN--><html lang="en" class="dark"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/e4af272ccee01ff0-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/css/c0ea31cd787f7aa7.css" data-precedence="next"/><link rel="stylesheet" href="/_next/static/css/659eccb5db697b76.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-ca926228f8cba1ff.js"/><script src="/_next/static/chunks/1b86ba38-c29611e086b2ce25.js" async=""></script><script src="/_next/static/chunks/698-19872069fed27164.js" async=""></script><script src="/_next/static/chunks/main-app-340a5b58ed229c4d.js" async=""></script><script src="/_next/static/chunks/989-6a0ec35b8ae2cb39.js" async=""></script><script src="/_next/static/chunks/app/layout-5ec6c5f713a8562b.js" async=""></script><script src="/_next/static/chunks/1d2d5650-d8d130c85727fdbb.js" async=""></script><script src="/_next/static/chunks/23-092ac3901411582e.js" async=""></script><script src="/_next/static/chunks/app/page-bf9c0b21ae431c92.js" async=""></script><meta name="next-size-adjust" content=""/><title>Halo - Multi-Agent Workspace</title><meta name="description" content="Multi-agent collaboration workspace for complex project delivery"/><link rel="icon" href="/favicon.ico" type="image/x-icon" sizes="16x16"/><link rel="icon" href="/icon.svg?3a6863548daca964" type="image/svg+xml" sizes="any"/><script>try{var t=localStorage.getItem('halo_theme');if(t==='light'||t==='midnight'||t==='warm')document.documentElement.dataset.theme=t}catch(e){}</script><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body class="__variable_f367f3 font-sans antialiased"><div hidden=""><!--$--><!--/$--></div><div class="flex h-screen w-screen items-center justify-center bg-[var(--background)]"><div class="text-sm text-[var(--muted-foreground)]">Loading...</div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-ca926228f8cba1ff.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[58321,[\"989\",\"static/chunks/989-6a0ec35b8ae2cb39.js\",\"177\",\"static/chunks/app/layout-5ec6c5f713a8562b.js\"],\"ThemeProvider\"]\n3:I[24554,[\"989\",\"static/chunks/989-6a0ec35b8ae2cb39.js\",\"177\",\"static/chunks/app/layout-5ec6c5f713a8562b.js\"],\"AppI18nProvider\"]\n4:I[63693,[],\"\"]\n5:I[74713,[],\"\"]\n6:I[5444,[],\"ClientPageRoot\"]\n7:I[18100,[\"560\",\"static/chunks/1d2d5650-d8d130c85727fdbb.js\",\"23\",\"static/chunks/23-092ac3901411582e.js\",\"989\",\"static/chunks/989-6a0ec35b8ae2cb39.js\",\"974\",\"static/chunks/app/page-bf9c0b21ae431c92.js\"],\"default\"]\na:I[23632,[],\"OutletBoundary\"]\nc:I[86889,[],\"AsyncMetadataOutlet\"]\ne:I[23632,[],\"ViewportBoundary\"]\n10:I[23632,[],\"MetadataBoundary\"]\n11:\"$Sreact.suspense\"\n13:I[1935,[],\"\"]\n:HL[\"/_next/static/media/e4af272ccee01ff0-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/css/c0ea31cd787f7aa7.css\",\"style\"]\n:HL[\"/_next/static/css/659eccb5db697b76.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"Jf-8TVLoHHwpT-gitolxN\",\"p\":\"\",\"c\":[\"\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"__PAGE__\",{}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/c0ea31cd787f7aa7.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"dark\",\"suppressHydrationWarning\":true,\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"try{var t=localStorage.getItem('halo_theme');if(t==='light'||t==='midnight'||t==='warm')document.documentElement.dataset.theme=t}catch(e){}\"}}]}],[\"$\",\"body\",null,{\"className\":\"__variable_f367f3 font-sans antialiased\",\"children\":[\"$\",\"$L2\",null,{\"children\":[\"$\",\"$L3\",null,{\"children\":[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]}]}]]}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L6\",null,{\"Component\":\"$7\",\"searchParams\":{},\"params\":{},\"promises\":[\"$@8\",\"$@9\"]}],[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/659eccb5db697b76.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"$La\",null,{\"children\":[\"$Lb\",[\"$\",\"$Lc\",null,{\"promise\":\"$@d\"}]]}]]}],{},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[null,[[\"$\",\"$Le\",null,{\"children\":\"$Lf\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$L10\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$11\",null,{\"fallback\":null,\"children\":\"$L12\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$13\",[]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"8:{}\n9:\"$0:f:0:1:2:children:1:props:children:0:props:params\"\n"])</script><script>self.__next_f.push([1,"f:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\nb:null\n"])</script><script>self.__next_f.push([1,"14:I[88809,[],\"IconMark\"]\nd:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"Halo - Multi-Agent Workspace\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Multi-agent collaboration workspace for complex project delivery\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico\",\"type\":\"image/x-icon\",\"sizes\":\"16x16\"}],[\"$\",\"link\",\"3\",{\"rel\":\"icon\",\"href\":\"/icon.svg?3a6863548daca964\",\"type\":\"image/svg+xml\",\"sizes\":\"any\"}],[\"$\",\"$L14\",\"4\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"12:\"$d:metadata\"\n"])</script></body></html>
|
package/admin-out/index.txt
CHANGED
|
@@ -14,7 +14,7 @@ e:I[23632,[],"ViewportBoundary"]
|
|
|
14
14
|
:HL["/_next/static/media/e4af272ccee01ff0-s.p.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
|
|
15
15
|
:HL["/_next/static/css/c0ea31cd787f7aa7.css","style"]
|
|
16
16
|
:HL["/_next/static/css/659eccb5db697b76.css","style"]
|
|
17
|
-
0:{"P":null,"b":"
|
|
17
|
+
0:{"P":null,"b":"Jf-8TVLoHHwpT-gitolxN","p":"","c":["",""],"i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/c0ea31cd787f7aa7.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","className":"dark","suppressHydrationWarning":true,"children":[["$","head",null,{"children":["$","script",null,{"dangerouslySetInnerHTML":{"__html":"try{var t=localStorage.getItem('halo_theme');if(t==='light'||t==='midnight'||t==='warm')document.documentElement.dataset.theme=t}catch(e){}"}}]}],["$","body",null,{"className":"__variable_f367f3 font-sans antialiased","children":["$","$L2",null,{"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}]}]]}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$L6",null,{"Component":"$7","searchParams":{},"params":{},"promises":["$@8","$@9"]}],[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/659eccb5db697b76.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","$La",null,{"children":["$Lb",["$","$Lc",null,{"promise":"$@d"}]]}]]}],{},null,false]},null,false],["$","$1","h",{"children":[null,[["$","$Le",null,{"children":"$Lf"}],["$","meta",null,{"name":"next-size-adjust","content":""}]],["$","$L10",null,{"children":["$","div",null,{"hidden":true,"children":["$","$11",null,{"fallback":null,"children":"$L12"}]}]}]]}],false]],"m":"$undefined","G":["$13",[]],"s":false,"S":true}
|
|
18
18
|
8:{}
|
|
19
19
|
9:"$0:f:0:1:2:children:1:props:children:0:props:params"
|
|
20
20
|
f:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
|
|
@@ -49,14 +49,13 @@ See [prompt-system.md](prompt-system.md).
|
|
|
49
49
|
|
|
50
50
|
### When agent.yaml changes take effect
|
|
51
51
|
|
|
52
|
-
`agent.yaml` is read **only at agent-instance build time** —
|
|
52
|
+
`agent.yaml` (and AGENT.md, INSTRUCTIONS, USER.md, prompts, skill metadata) is read **only at agent-instance build time** — nothing re-reads it mid-turn. But an instance doesn't outlive its run: `runSession`'s finally calls `releaseSession` on every run end, dropping the session from the in-memory Map, so the next message goes through `ensureSession` and rebuilds from the current files. Build points in `SessionManager`:
|
|
53
53
|
|
|
54
|
-
1. **`createSession`** — every new session builds fresh
|
|
55
|
-
2. **`ensureSession`** —
|
|
54
|
+
1. **`createSession`** — every new session (sub-agents included) builds fresh
|
|
55
|
+
2. **`ensureSession`** — any session not in the Map rebuilds on next access; since every run ends in `releaseSession`, this is the normal path for an existing session's next turn
|
|
56
56
|
3. **Access-level change** — `sendUserMessage` with a different `accessLevel` rebuilds in place (messages preserved)
|
|
57
|
-
4. **`resetAgent`** — post-compact rebuild (messages preserved)
|
|
58
57
|
|
|
59
|
-
Practical consequence:
|
|
58
|
+
Practical consequence: a yaml edit reaches an existing session on its **next turn**, not at the next restart. The run in flight — including queued messages it drains before releasing — finishes on the old instance; a session loaded into memory by a view path (`getSessionContext`, `/context`, compact) runs one more turn on the config it was loaded with. User-facing summary: [guide/delegation-and-access.md](../guide/delegation-and-access.md#2-when-a-config-edit-takes-effect).
|
|
60
59
|
|
|
61
60
|
## Session tools
|
|
62
61
|
|
|
@@ -212,7 +212,7 @@ If `mdPrompt` is empty:
|
|
|
212
212
|
|
|
213
213
|
**Placement.** The roster is passed into `composeMdPrompt` as section 3, landing directly behind AGENT.md so the "who's on my team" read happens while model attention is still high (delegation is an orchestrator's first decision). Routing it through `composeMdPrompt` — rather than string-concatenating it after `mdPrompt` — is what gives it proper `\n\n---\n\n` separators on both sides; an earlier version appended it with a single `\n` and it glued onto the following `allPrompt` heading.
|
|
214
214
|
|
|
215
|
-
**
|
|
215
|
+
**Rebuilt per agent instance, the single team source.** The roster is generated by `composeSystemPrompt` on every `buildAgentInstance` — it's the only place an orchestrator learns who its team is. Because a session's instance is released after every run and rebuilt on the next one, the roster picks up `team` edits, enable/disable toggles and added/removed agents from the next turn on; it is static only within a single run (including the queued messages that run drains). (There used to be a `list_agents` tool that returned the same set at runtime; it was removed once the roster covered the discovery need — the block is always present for a delegating agent, so a per-turn tool call was redundant.) For *detail* on a specific teammate (full tools / skills / model), the agent calls `query_agent <id>` — itself team-gated, so it can only inspect agents already on its roster.
|
|
216
216
|
|
|
217
217
|
## Step 7 — Append skills and tool list
|
|
218
218
|
|
|
@@ -173,7 +173,7 @@ Sensitive directories and files are hidden from workspace/readonly sessions via
|
|
|
173
173
|
| `hidden_files` | `~/.npmrc,~/.bash_history,~/.gitconfig,~/.git-credentials,~/.netrc,~/.halo/global/{evo,cron,runs}.db` + their `-wal`/`-shm` files | bwrap `--ro-bind ~/.halo/.sandbox-empty` (reads as empty); Seatbelt `literal` deny |
|
|
174
174
|
| `writable_dirs` | (empty) | bwrap `--bind` read-write / Seatbelt write allow — for external CLIs that keep local state (e.g. `~/.kiro`); not applied to readonly sessions |
|
|
175
175
|
|
|
176
|
-
Changes take effect immediately — `
|
|
176
|
+
Changes saved through the settings API (admin Settings page, `PUT` / `PATCH /api/settings`) take effect immediately — the save fires `onSettingsChange`, which re-reads the lists into `sandbox.ts` (`setSandboxHiddenPaths`), so the next tool call uses them. A hand edit of `settings.yaml` is not watched for these keys: it applies at the next restart or the next API save. These keys are `globalOnly` in the schema — a workspace `settings.yaml` cannot override them, since they define the security boundary agents run inside.
|
|
177
177
|
|
|
178
178
|
**Workspace-relative set (hardcoded)** — the workspace's own runtime state, which holds other channels'/users' conversations on a shared workspace. Code constants in `sandbox.ts` (`WORKSPACE_HIDDEN_DIRS` / `WORKSPACE_HIDDEN_FILES`), deliberately not settings: this is a security boundary (a config edit must not be able to open it), and the entries are workspace-relative while the settings lists are absolute/`~` paths.
|
|
179
179
|
|
|
@@ -186,10 +186,7 @@ The rest of `.halo/` (INSTRUCTIONS.md, INDEX.md, docs/, memory/, skills/, agents
|
|
|
186
186
|
|
|
187
187
|
`/tmp` is not in the hidden list — under bwrap it receives a standalone `--tmpfs` mount for process isolation (each invocation gets its own empty `/tmp`), not for hiding secrets. Seatbelt has no mount namespace, so on macOS `/tmp` is the real one and writes to it persist.
|
|
188
188
|
|
|
189
|
-
Per-channel defaults:
|
|
190
|
-
- **Web** — inherits account's `access_level` (default `full`)
|
|
191
|
-
- **Telegram** — inherits account's `access_level` (default `readonly`)
|
|
192
|
-
- **WeChat** — inherits account's `access_level` (default `readonly`)
|
|
189
|
+
Per-channel defaults: every channel session (Web, Telegram, Slack, Feishu, WeCom, WeChat) inherits its account's `access_level` — `full` → full, `workspace` → workspace, `readonly` / `observer` → readonly — and new accounts default to `readonly` (DB column default, `insertAccount` fallback and the admin create forms). Level sources for every entry point (admin, cron, cli, relay, goal, sub-agents): [guide/delegation-and-access.md](../guide/delegation-and-access.md#where-a-sessions-level-comes-from).
|
|
193
190
|
|
|
194
191
|
### Binary file detection
|
|
195
192
|
`grep` and `glob` read the first 512 bytes looking for a null byte and skip binaries.
|
|
@@ -10,6 +10,7 @@ Aimed at Halo end-users. Pick the doc that matches your situation.
|
|
|
10
10
|
4. [agents.md](agents.md) — creating, editing, configuring agents
|
|
11
11
|
5. [skills.md](skills.md) — skill concepts, creating skills, attaching them to agents
|
|
12
12
|
6. [sessions.md](sessions.md) — viewing session history, debug mode, multi-agent collaboration
|
|
13
|
+
7. [delegation-and-access.md](delegation-and-access.md) — runtime rules: scope override, when edits take effect, team/roster, access levels
|
|
13
14
|
|
|
14
15
|
## Channels — talk to your agent from somewhere other than the admin UI
|
|
15
16
|
|
|
@@ -81,6 +81,8 @@ team: # a non-empty team is what enables delegation
|
|
|
81
81
|
|
|
82
82
|
Form view lets you check workspace tools on/off and pick the team; there's no separate session-tools checklist — delegation rides entirely on the team.
|
|
83
83
|
|
|
84
|
+
Roster rules, `start_session` checks and errors, access-level inheritance, and when an edit takes effect: [delegation-and-access.md](delegation-and-access.md).
|
|
85
|
+
|
|
84
86
|
## Skill mounting
|
|
85
87
|
|
|
86
88
|
`skills: [skill_id_1, skill_id_2]` — Halo injects skill metadata into the prompt, and the agent calls `activate_skill` to load the full SKILL.md when needed.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Delegation and Access
|
|
2
|
+
|
|
3
|
+
How Halo decides, at runtime, **which agent / skill files are used**, **when a config edit takes effect**, **who an agent may delegate to**, and **what access level a session runs at**. Written for people (and agents such as a workspace builder) who configure agents and need the actual behavior without reading source.
|
|
4
|
+
|
|
5
|
+
Field-by-field `agent.yaml` reference: [agents.md](agents.md). Per-tool schemas and sandbox internals: [dev/tools.md](../dev/tools.md).
|
|
6
|
+
|
|
7
|
+
## 1. Which files are used — scope resolution
|
|
8
|
+
|
|
9
|
+
| Item | Workspace location | Global location | Rule |
|
|
10
|
+
|---|---|---|---|
|
|
11
|
+
| Agent | `<ws>/.halo/agents/<id>/` | `~/.halo/global/agents/<id>/` | **Whole-folder override.** If the workspace folder exists, `agent.yaml` and `AGENT.md` are read **only** from it — no per-file fallback to global. |
|
|
12
|
+
| Skill | `<ws>/.halo/skills/<id>/` | `~/.halo/global/skills/<id>/` | Whole-folder override, including resource files next to `SKILL.md`. |
|
|
13
|
+
| System prompts | `<ws>/.halo/prompts/<scope>/` | `~/.halo/global/prompts/<scope>/` | Per scope (`bootstrap` / `all` / `root`): a workspace scope dir replaces the global one. |
|
|
14
|
+
| INSTRUCTIONS.md | `<ws>/.halo/INSTRUCTIONS.md` | `~/.halo/global/INSTRUCTIONS.md` | Workspace file **replaces** global (not stacked). |
|
|
15
|
+
| USER.md | `<ws>/.halo/USER.md` | `~/.halo/global/USER.md` | Workspace file replaces global. |
|
|
16
|
+
| Disabled flag | `disabled_items` in the workspace `halo.db` | — | Checked against the scope that actually serves the id (workspace if its folder exists, else global). |
|
|
17
|
+
|
|
18
|
+
Gotchas:
|
|
19
|
+
- An empty or half-copied `<ws>/.halo/agents/<id>/` folder **shadows** the global agent completely. With no `agent.yaml` inside, the agent can't be used: `start_session` returns "not found" and opening a session fails with "agent.yaml missing or unreadable" — yet rosters and pickers may still show the global copy. When customizing, copy both files; an `agent.yaml` without `model.provider` / `model.id` / `model.endpoint` fails with "missing model config".
|
|
20
|
+
- Same id in both scopes: everything (roster, chat selector, delegation) sees only the workspace version.
|
|
21
|
+
- Built-in agents (`default`, `executor`, `deep-executor`, `goal`, and the internal `__evo_agent__` / `__score__` / `__apply_agent__`) and built-in skills are platform-owned: a template reseed after an upgrade overwrites them (an agent's `model:` / `context:` blocks are kept). Customize through a workspace copy, not by editing the global files.
|
|
22
|
+
|
|
23
|
+
## 2. When a config edit takes effect
|
|
24
|
+
|
|
25
|
+
No restart is needed for agent / skill / prompt edits. An agent instance (model runtime, tool set, system prompt) is built from disk when a session is loaded into memory, and a session is **released from memory at the end of every run**. The next message rebuilds it from the current files.
|
|
26
|
+
|
|
27
|
+
| You edit | Takes effect |
|
|
28
|
+
|---|---|
|
|
29
|
+
| `agent.yaml` (model, tools, skills, team, context, thinking), `AGENT.md` | Next turn of any existing session; immediately for new sessions (including sub-agents started after the edit) |
|
|
30
|
+
| `INSTRUCTIONS.md`, `USER.md`, `INDEX.md`, `prompts/` | Same — next turn / new sessions |
|
|
31
|
+
| Skill frontmatter (`name`, `description`, `requiresAccess`), adding/removing a skill id in `skills:` | Next turn / new sessions |
|
|
32
|
+
| `SKILL.md` **body** | Immediately — `activate_skill` reads the file at call time |
|
|
33
|
+
| `team` list — the `start_session` / `query_agent` check | Immediately (the caller's `agent.yaml` is re-read on every call) |
|
|
34
|
+
| `team` list — the roster in the prompt, and gaining/losing the session tools (empty ↔ non-empty) | Next turn |
|
|
35
|
+
| Disable / enable an agent | `start_session` / `query_agent` reject a disabled agent immediately; rosters update next turn |
|
|
36
|
+
| `general.sandbox.hidden_dirs` / `hidden_files` / `writable_dirs` | Immediately when saved from the admin Settings page; a hand edit of `settings.yaml` applies after a restart (or the next Settings save) |
|
|
37
|
+
| `general.session.max_nesting_depth` | **Server restart only** — read once at startup |
|
|
38
|
+
|
|
39
|
+
What "next turn" means precisely:
|
|
40
|
+
- The turn that is running now finishes on the old config. Messages queued behind it and drained in the same run also use the old config.
|
|
41
|
+
- A session that was only loaded for viewing (context panel, `/context`, compact) runs its next turn on the config it was loaded with, then picks up the new config after that.
|
|
42
|
+
- An access-level change on a session rebuilds it immediately, with messages kept (see §5).
|
|
43
|
+
|
|
44
|
+
## 3. Delegation — team, roster, start_session
|
|
45
|
+
|
|
46
|
+
**`team` is the on/off switch.** An agent gets the 8 session tools (`start_session`, `session_list`, `query_session`, `interrupt_session`, `stop_session`, `archive_session`, `get_session_output`, `query_agent`) only when its `agent.yaml` has a **non-empty `team`**. Absent or empty `team` means no session tools and no roster; the agent still has `continue_task`. Listing session tools under `tools:` does nothing. Internal agents never delegate, whatever their `team` says.
|
|
47
|
+
|
|
48
|
+
**Roster** (`## Your Team` block, placed right after AGENT.md in the system prompt):
|
|
49
|
+
- Candidates: every agent in both scopes, collapsed to the effective record per id (workspace shadows global).
|
|
50
|
+
- Removed: disabled agents, `internal: true` agents, and anything not in `team`.
|
|
51
|
+
- The agent itself is listed first, tagged `(you)`, only if its own id is in `team` (that is what allows parallel self-spawn). The rest are sorted by `priority`, highest first, as `` `id` — name: description ``.
|
|
52
|
+
- A workspace agent may list global agents in its `team` and vice versa — ids are resolved to whatever scope serves them.
|
|
53
|
+
|
|
54
|
+
**`start_session` checks, in order** (the first failure is returned as `{"code": 1, "error": …}`):
|
|
55
|
+
|
|
56
|
+
| # | Check | Error |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| 1 | `agent_id` and `message` present | `agent_id and message are required` |
|
|
59
|
+
| 2 | Target exists, is not `internal`, is not disabled | `agent "<id>" not found. The agents you can delegate to are listed in your system prompt.` |
|
|
60
|
+
| 3 | Target is in the caller's `team` | `agent "<id>" is not in your team. …` |
|
|
61
|
+
| 4 | Caller's depth < `max_nesting_depth` | `Maximum nesting depth (16) reached. Complete this task directly instead of delegating to a sub-agent.` |
|
|
62
|
+
| 5 | `working_dir` (optional) is inside the workspace and is an existing directory | `working_dir "<x>" is outside the workspace` / `is not a directory` / `does not exist` |
|
|
63
|
+
|
|
64
|
+
On success the child is created at the **parent's access level** (§5) and runs asynchronously. When it goes idle its wrap-up is reported back to the parent automatically.
|
|
65
|
+
|
|
66
|
+
**Nesting depth.** Session ids are `root>child>grandchild…`; depth is the number of segments (a root session is depth 1). A caller at depth ≥ `max_nesting_depth` cannot spawn. With the default 16, a tree has at most 16 levels. Set it in `~/.halo/secrets/settings.yaml` under `general.session.max_nesting_depth` (global only, a workspace `settings.yaml` can't override it) and restart the server.
|
|
67
|
+
|
|
68
|
+
**The other session tools:**
|
|
69
|
+
- `query_agent <id>`: same checks as rows 2–3 above, but every failure reads `agent "<id>" not found.`. Returns name, description, model, `tools`, and skills — **not** AGENT.md. When the caller is readonly, `file_write` / `file_edit` / `shell_exec` / `web_fetch` are dropped from the listed tools, and skills whose `requiresAccess` is above the caller's level are hidden.
|
|
70
|
+
- `query_session` / `interrupt_session` / `stop_session` / `archive_session` / `get_session_output`: only work on sessions in the caller's own tree (same root id). Anything else returns `session <id> not found`.
|
|
71
|
+
- `session_list`: direct children of the calling session only (up to 500).
|
|
72
|
+
|
|
73
|
+
**Delegating further.** A sub-agent delegates only if its own `agent.yaml` has a non-empty `team`. It gets its own roster. Depth is the only other limit.
|
|
74
|
+
|
|
75
|
+
## 4. What a sub-agent's system prompt contains
|
|
76
|
+
|
|
77
|
+
| Layer | Root session | Sub-agent | Internal agent |
|
|
78
|
+
|---|---|---|---|
|
|
79
|
+
| USER.md | ✓ | — | — |
|
|
80
|
+
| AGENT.md (+ roster if `team`) | ✓ | ✓ | AGENT.md only |
|
|
81
|
+
| INSTRUCTIONS.md (workspace, else global) | ✓ | ✓ | — |
|
|
82
|
+
| INSTRUCTIONS.md along the `working_dir` path (stacked, general → specific) | if `working_dir` set | if `working_dir` set | if `working_dir` set |
|
|
83
|
+
| INDEX.md | ✓ | ✓ | — |
|
|
84
|
+
| `prompts/root` | ✓ | — | — |
|
|
85
|
+
| `prompts/all` | ✓ | ✓ | — |
|
|
86
|
+
| Skill metadata (`skills:` minus disabled minus `requiresAccess` above the session level) | ✓ | ✓ | ✓ |
|
|
87
|
+
| Trailing "Your available tools: …" line | ✓ | ✓ | ✓ |
|
|
88
|
+
|
|
89
|
+
So a sub-agent knows nothing about the user except what the parent puts in the `start_session` message / `system_prompt_context`.
|
|
90
|
+
|
|
91
|
+
## 5. Access levels
|
|
92
|
+
|
|
93
|
+
Three session levels, stored per session (`agent_sessions.access_level`; `full` is stored as null):
|
|
94
|
+
|
|
95
|
+
| Level | Tools the agent can get (from its `tools:` list) | Sandbox |
|
|
96
|
+
|---|---|---|
|
|
97
|
+
| `full` | all 9 workspace tools | none (the `rm` guard still applies) |
|
|
98
|
+
| `workspace` | all 9 | writes only inside the workspace; credentials and workspace runtime state are hidden |
|
|
99
|
+
| `readonly` | all 9 with an OS sandbox (writes fail); only `file_read`, `view_image`, `file_list`, `grep`, `glob` without one | nothing writable |
|
|
100
|
+
|
|
101
|
+
Extra rules:
|
|
102
|
+
- Without an OS sandbox (Linux without working bubblewrap, and Windows), `shell_exec` fails for every non-full session. Windows has no path boundary at all — see [dev/tools.md](../dev/tools.md#access-level-per-session-dynamic).
|
|
103
|
+
- A readonly `shell_exec` gets no secret substitution — `{{…params…}}` / `<<ENV>>` placeholders stay literal.
|
|
104
|
+
- `view_image` also needs a vision-capable model.
|
|
105
|
+
- A skill with `requiresAccess` above the session level is hidden (no metadata, no `activate_skill`).
|
|
106
|
+
- Relay tools are only built for `full` sessions.
|
|
107
|
+
- Hidden from `workspace` / `readonly` sessions: the `general.sandbox.hidden_dirs` / `hidden_files` lists (default: `~/.halo/secrets`, `~/.aws`, `~/.ssh`, `~/.gnupg`, `~/.docker`, `~/.config/gh`, `~/.gitconfig`, `~/.git-credentials`, `~/.npmrc`, `~/.netrc`, the global evo/cron/runs databases, internal-session transcripts, logs, …) plus the workspace's own `.halo/sessions`, `.halo/logs`, `.halo/evo`, `.halo/halo.db*` (fixed in code). The rest of `.halo/` stays readable.
|
|
108
|
+
|
|
109
|
+
### Where a session's level comes from
|
|
110
|
+
|
|
111
|
+
| Entry point | Level of a new session | Existing session |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| Admin chat | Chat-input selector (defaults to Full; locked to Full on a host without an OS sandbox) | Re-applied on each message sent while the session is idle. A message queued behind a running turn keeps the running turn's level. |
|
|
114
|
+
| Channel account (Web / Telegram / Slack / Feishu / WeCom / WeChat, and the ACP adapter via its Web token) | The account's `accessLevel`: `full` → full, `workspace` → workspace, `readonly` and `observer` → readonly. New accounts default to **readonly**. | Re-applied on every inbound message. Changing an account's level takes effect on the next message. |
|
|
115
|
+
| Channel `/session new` | The account's level | — |
|
|
116
|
+
| `start_session` (sub-agent) | **Parent's level at creation time** | Kept. A later change on the parent doesn't reach existing children; start a new child to get the new level. |
|
|
117
|
+
| Cron job | Full (the `halo cli` default) | Keeps its stored level (passed through as `--access`) |
|
|
118
|
+
| `halo cli` / TUI | `--access`, default `full` | `--access` value (a different level is persisted) |
|
|
119
|
+
| `relay_send` into another workspace | Full | Keeps its stored level |
|
|
120
|
+
| `/goal create` | The goal session is full (`/goal` verbs need full access) | — |
|
|
121
|
+
| AgentCore runtime | Full | — |
|
|
122
|
+
|
|
123
|
+
Consequences:
|
|
124
|
+
- A sub-agent can never have more access than its parent had when it was spawned. A readonly channel user can't escalate by delegating.
|
|
125
|
+
- To give a sub-agent more access, raise the root session's level first (admin selector / channel account), then spawn a **new** child.
|
|
126
|
+
|
|
127
|
+
## 6. Relay (cross-workspace)
|
|
128
|
+
|
|
129
|
+
Relay is separate from `team` delegation:
|
|
130
|
+
- Enabled by listing `relay_send` in `tools:` (that one name brings `relay_send` / `relay_interrupt` / `relay_stop` / `relay_read` / `relay_list`), and **only in full sessions** — a workspace/readonly session with `relay_send` listed gets nothing.
|
|
131
|
+
- **Not team-checked.** Any agent in the target workspace can be named with `agent_id`. Without it, the target workspace's default entry agent is used: highest `priority`, not disabled, not internal, workspace scope wins ties.
|
|
132
|
+
- The target session is created at full if missing, otherwise keeps its level. Its wrap-up comes back as a `[Relay report …]` message, once per dispatch.
|
|
133
|
+
- Server only (not in `halo cli` / TUI). Details: [dev/tools.md → Relay tools](../dev/tools.md#relay-tools).
|
|
134
|
+
|
|
135
|
+
## 7. Quick answers
|
|
136
|
+
|
|
137
|
+
| Question | Answer |
|
|
138
|
+
|---|---|
|
|
139
|
+
| I edited `agent.yaml` / AGENT.md — restart? | No. Next turn of existing sessions, immediately for new ones (§2). |
|
|
140
|
+
| The agent has no `start_session` | `team` is empty or missing — add at least one id. It shows up from the next turn. |
|
|
141
|
+
| `start_session` says "not found" but the agent exists | It's disabled, `internal`, or shadowed by a workspace folder with no `agent.yaml` (§1). |
|
|
142
|
+
| "is not in your team" | Add the id to the **caller's** `team`. Takes effect on the next call. |
|
|
143
|
+
| Sub-agent has fewer tools than its `tools:` list | It inherited a restricted level from its parent (§5), or the model has no vision (`view_image`). |
|
|
144
|
+
| Sub-agent can't see the user's preferences | Sub-agents don't get USER.md (§4). Put what they need in the brief. |
|
|
145
|
+
| Delegation stops at some depth | `max_nesting_depth` (default 16, global setting, restart to change). |
|
|
146
|
+
| Make an agent the default for new channel sessions | Give it the highest `priority` in that workspace. |
|
|
147
|
+
| Hand work to another workspace | Relay: `relay_send` in `tools:`, full session (§6). |
|
|
148
|
+
|
|
149
|
+
## Where this lives in code
|
|
150
|
+
|
|
151
|
+
For maintainers keeping this page in sync — paths under `packages/server/src/`:
|
|
152
|
+
|
|
153
|
+
| Topic | File |
|
|
154
|
+
|---|---|
|
|
155
|
+
| Scope resolution, `canDelegate`, `isTeamMember`, `isAgentDisabled` | `agents/agent-loader.ts` |
|
|
156
|
+
| Tool set, roster, prompt composition | `agents/session-agent-builder.ts`, `prompts/md-loader.ts`, `prompts/system-prompts.ts` |
|
|
157
|
+
| Session tool checks | `agents/session-tools.ts` |
|
|
158
|
+
| Release after each run, access-level rebuild | `agents/session-manager.ts` (`runSession` finally → `releaseSession`; `sendUserMessage`) |
|
|
159
|
+
| Channel level mapping | `channels/shared/inbound.ts` (`sessionAccess`), `channels/web/handler.ts` |
|
|
160
|
+
| Tool filtering and sandbox | `tools/workspace-tools.ts`, `tools/sandbox.ts` |
|
|
161
|
+
| Relay | `agents/relay.ts` |
|
|
@@ -93,7 +93,7 @@ Agents can manage other sessions via tools. The whole bundle is granted automati
|
|
|
93
93
|
| `get_session_output` | Read a session's latest turn output |
|
|
94
94
|
| `query_agent` | Inspect another agent (team-gated to the roster) |
|
|
95
95
|
|
|
96
|
-
See [dev/tools.md](../dev/tools.md).
|
|
96
|
+
A sub-agent runs at its parent's access level. See [delegation-and-access.md](delegation-and-access.md) for team/roster rules, errors, nesting depth and access levels, and [dev/tools.md](../dev/tools.md) for tool schemas.
|
|
97
97
|
|
|
98
98
|
## Scenarios
|
|
99
99
|
|
package/dist/index.js
CHANGED
|
@@ -2501,7 +2501,7 @@ var init_init = __esm({
|
|
|
2501
2501
|
path8.resolve(__dirname, "..", "bundled-docs"),
|
|
2502
2502
|
path8.resolve(__dirname, "..", "..", "..", ".halo", "docs")
|
|
2503
2503
|
];
|
|
2504
|
-
TEMPLATE_VERSION =
|
|
2504
|
+
TEMPLATE_VERSION = 66;
|
|
2505
2505
|
VERSION_FILE = ".template-version";
|
|
2506
2506
|
SKIP_NAMES = /* @__PURE__ */ new Set([".DS_Store", "schema.sql", "__pycache__", ".pytest_cache"]);
|
|
2507
2507
|
BUILTIN_AGENT_IDS = /* @__PURE__ */ new Set([
|
|
@@ -2556,6 +2556,7 @@ var init_init = __esm({
|
|
|
2556
2556
|
"guide/skills.md",
|
|
2557
2557
|
"guide/testing-agents-and-skills.md",
|
|
2558
2558
|
"guide/secrets-and-credentials.md",
|
|
2559
|
+
"guide/delegation-and-access.md",
|
|
2559
2560
|
"dev/tools.md",
|
|
2560
2561
|
"dev/add-model-provider.md",
|
|
2561
2562
|
"dev/add-channel.md",
|
|
@@ -11805,7 +11806,7 @@ async function initObservability() {
|
|
|
11805
11806
|
return true;
|
|
11806
11807
|
}
|
|
11807
11808
|
const { registerSdk: registerSdk2 } = await Promise.resolve().then(() => (init_otel_sdk(), otel_sdk_exports));
|
|
11808
|
-
providers = registerSdk2(process.env.OTEL_SERVICE_NAME, "1.4.
|
|
11809
|
+
providers = registerSdk2(process.env.OTEL_SERVICE_NAME, "1.4.2");
|
|
11809
11810
|
console.log(`[Observability] OTLP export \u2192 ${process.env.OTEL_EXPORTER_OTLP_ENDPOINT} (service.name=${process.env.OTEL_SERVICE_NAME}, capture_content=${config.observability.captureContent})`);
|
|
11810
11811
|
return true;
|
|
11811
11812
|
}
|
|
@@ -13950,29 +13951,6 @@ ${result.summary}`, agentName: "user", report: true, taskId });
|
|
|
13950
13951
|
opts?.onProgress?.("done");
|
|
13951
13952
|
}
|
|
13952
13953
|
}
|
|
13953
|
-
/**
|
|
13954
|
-
* Reset agent instance (destroy + allow rebuild) without destroying sub-sessions.
|
|
13955
|
-
* Used after compact to rebuild with new context.
|
|
13956
|
-
*/
|
|
13957
|
-
async resetAgent(sessionId) {
|
|
13958
|
-
const session = this.sessions.get(sessionId);
|
|
13959
|
-
if (!session)
|
|
13960
|
-
return;
|
|
13961
|
-
if (session.abortController) {
|
|
13962
|
-
session.abortController.abort();
|
|
13963
|
-
session.abortController = null;
|
|
13964
|
-
}
|
|
13965
|
-
session.toolCallLog = [];
|
|
13966
|
-
session.warnedToolHashes.clear();
|
|
13967
|
-
session.interruptRequested = false;
|
|
13968
|
-
const savedMessages = session.agent.messages;
|
|
13969
|
-
const { agent, modelId, systemPrompt, draftReset } = await this.buildAgentInstance(session.agentId, sessionId, session.parentId, session.workingDir ?? void 0, session.accessLevel);
|
|
13970
|
-
session.agent = agent;
|
|
13971
|
-
session.agent.messages = savedMessages;
|
|
13972
|
-
session.currentModelId = modelId;
|
|
13973
|
-
session.systemPrompt = systemPrompt;
|
|
13974
|
-
session.draftReset = draftReset;
|
|
13975
|
-
}
|
|
13976
13954
|
/**
|
|
13977
13955
|
* Set raw agent messages directly (for compact rebuild).
|
|
13978
13956
|
*/
|
|
@@ -25714,14 +25692,14 @@ var init_event_adapter = __esm({
|
|
|
25714
25692
|
try {
|
|
25715
25693
|
await this.deps.sendText(text6);
|
|
25716
25694
|
} catch (err) {
|
|
25717
|
-
console.
|
|
25695
|
+
console.warn(`[Telegram] sendText failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
25718
25696
|
}
|
|
25719
25697
|
}
|
|
25720
25698
|
for (const p of mediaPaths) {
|
|
25721
25699
|
try {
|
|
25722
25700
|
await this.deps.sendMedia(p);
|
|
25723
25701
|
} catch (err) {
|
|
25724
|
-
console.
|
|
25702
|
+
console.warn(`[Telegram] sendMedia ${p} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
25725
25703
|
}
|
|
25726
25704
|
}
|
|
25727
25705
|
}
|
|
@@ -25787,6 +25765,21 @@ ${agentText}`;
|
|
|
25787
25765
|
});
|
|
25788
25766
|
return sessionId;
|
|
25789
25767
|
}
|
|
25768
|
+
function restoreChannelRoute(args) {
|
|
25769
|
+
const { registry: registry2, workspacePath, bridge, sessionPrefix: sessionPrefix2, route } = args;
|
|
25770
|
+
const sm = registry2.peek(workspacePath) ?? (claimWorkspaceRuntime(workspacePath) ? registry2.getOrCreate(workspacePath) : void 0);
|
|
25771
|
+
if (!sm) {
|
|
25772
|
+
console.warn(`[${bridge.channel}] reply route not restored for ${sessionPrefix2}*: ${workspacePath} runtime is owned by another live process (.halo/runtime.lock)`);
|
|
25773
|
+
return null;
|
|
25774
|
+
}
|
|
25775
|
+
const latest = sm.findLatestByPrefix(sessionPrefix2);
|
|
25776
|
+
if (!latest)
|
|
25777
|
+
return null;
|
|
25778
|
+
const sessionId = resolveGoalRoute(sm.getDb(), latest.id);
|
|
25779
|
+
bridge.setRoute(sessionId, route);
|
|
25780
|
+
bridge.ensureListener(sm, sessionId);
|
|
25781
|
+
return sessionId;
|
|
25782
|
+
}
|
|
25790
25783
|
async function dispatchChannelCommand(ctx, command, arg, opts) {
|
|
25791
25784
|
const { bridge, route, channelName, extraHelpLines } = opts;
|
|
25792
25785
|
const result = await dispatchCommand(ctx, command, arg, { channelName, extraHelpLines });
|
|
@@ -25805,6 +25798,7 @@ var init_inbound = __esm({
|
|
|
25805
25798
|
"../server/dist/channels/shared/inbound.js"() {
|
|
25806
25799
|
"use strict";
|
|
25807
25800
|
init_goal_mode();
|
|
25801
|
+
init_workspace_runtime_lock();
|
|
25808
25802
|
init_accounts();
|
|
25809
25803
|
init_commands2();
|
|
25810
25804
|
init_busy_hint();
|
|
@@ -25929,6 +25923,25 @@ function isUserAllowed(account, userId, username) {
|
|
|
25929
25923
|
function buildTgSessionPrefix(userId) {
|
|
25930
25924
|
return sessionPrefix("tg", String(userId));
|
|
25931
25925
|
}
|
|
25926
|
+
function restoreReplyRoute(args) {
|
|
25927
|
+
const { registry: registry2, db, account, bridge } = args;
|
|
25928
|
+
const chatId = getAccount(db, account.accountId)?.config.lastActiveChatId;
|
|
25929
|
+
if (typeof chatId !== "string" || !/^\d+$/.test(chatId))
|
|
25930
|
+
return;
|
|
25931
|
+
const workspacePath = resolveAccountWorkspace(account);
|
|
25932
|
+
if (!workspacePath)
|
|
25933
|
+
return;
|
|
25934
|
+
const userId = Number(chatId);
|
|
25935
|
+
const sid = restoreChannelRoute({
|
|
25936
|
+
registry: registry2,
|
|
25937
|
+
workspacePath,
|
|
25938
|
+
bridge,
|
|
25939
|
+
sessionPrefix: buildTgSessionPrefix(userId),
|
|
25940
|
+
route: { chatId: userId }
|
|
25941
|
+
});
|
|
25942
|
+
if (sid)
|
|
25943
|
+
console.log(`[Telegram] account ${account.accountId} reply route restored for ${sid}`);
|
|
25944
|
+
}
|
|
25932
25945
|
function startTelegramChannel(deps) {
|
|
25933
25946
|
const { registry: registry2, db } = deps;
|
|
25934
25947
|
const runners = /* @__PURE__ */ new Map();
|
|
@@ -25992,6 +26005,7 @@ function startTelegramChannel(deps) {
|
|
|
25992
26005
|
}
|
|
25993
26006
|
})
|
|
25994
26007
|
});
|
|
26008
|
+
restoreReplyRoute({ registry: registry2, db, account, bridge });
|
|
25995
26009
|
const promise = runBot({ registry: registry2, db, account, bot, abort, bridge, activeOverrides: activeOverrides2, restartSelf }).catch((err) => console.log(`[Telegram] account ${accountId} bot crashed: ${String(err)}`));
|
|
25996
26010
|
runners.set(accountId, { accountId, bot, abort, promise, bridge, activeOverrides: activeOverrides2 });
|
|
25997
26011
|
console.log(`[Telegram] account ${accountId} started (@${account.botUsername}, workspace=${account.workspacePath})`);
|
|
@@ -26889,14 +26903,14 @@ var init_event_adapter2 = __esm({
|
|
|
26889
26903
|
try {
|
|
26890
26904
|
await this.deps.sendText(text6);
|
|
26891
26905
|
} catch (err) {
|
|
26892
|
-
console.
|
|
26906
|
+
console.warn(`[WeChat] sendText failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
26893
26907
|
}
|
|
26894
26908
|
}
|
|
26895
26909
|
for (const p of mediaPaths) {
|
|
26896
26910
|
try {
|
|
26897
26911
|
await this.deps.sendMedia(p);
|
|
26898
26912
|
} catch (err) {
|
|
26899
|
-
console.
|
|
26913
|
+
console.warn(`[WeChat] sendMedia ${p} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
26900
26914
|
}
|
|
26901
26915
|
}
|
|
26902
26916
|
}
|
|
@@ -27287,6 +27301,7 @@ function startWechatChannel(deps) {
|
|
|
27287
27301
|
});
|
|
27288
27302
|
});
|
|
27289
27303
|
};
|
|
27304
|
+
restoreReplyRoutes({ registry: registry2, db, account, bridge });
|
|
27290
27305
|
const promise = runAccountLoop({ registry: registry2, db, account, abort: abort.signal, bridge, activeOverrides: activeOverrides2, restartSelf, startNewAccount: startAccount }).catch((err) => console.log(`[WeChat] account ${accountId} loop crashed: ${String(err)}`));
|
|
27291
27306
|
runners.set(accountId, { accountId, abort, promise, bridge, activeOverrides: activeOverrides2 });
|
|
27292
27307
|
console.log(`[WeChat] account ${accountId} started (workspace=${account.workspacePath})`);
|
|
@@ -27317,6 +27332,27 @@ function startWechatChannel(deps) {
|
|
|
27317
27332
|
startAccount(acc.accountId);
|
|
27318
27333
|
return { startAccount, stopAccount, stopAll };
|
|
27319
27334
|
}
|
|
27335
|
+
function restoreReplyRoutes(args) {
|
|
27336
|
+
const { registry: registry2, db, account, bridge } = args;
|
|
27337
|
+
const tokens = getAccount(db, account.accountId)?.config.contextTokens ?? {};
|
|
27338
|
+
const users = Object.keys(tokens);
|
|
27339
|
+
if (users.length === 0)
|
|
27340
|
+
return;
|
|
27341
|
+
const workspacePath = resolveAccountWorkspace(account);
|
|
27342
|
+
if (!workspacePath)
|
|
27343
|
+
return;
|
|
27344
|
+
for (const userId of users) {
|
|
27345
|
+
const sid = restoreChannelRoute({
|
|
27346
|
+
registry: registry2,
|
|
27347
|
+
workspacePath,
|
|
27348
|
+
bridge,
|
|
27349
|
+
sessionPrefix: buildWxSessionPrefix(userId),
|
|
27350
|
+
route: wxRoute(userId, tokens[userId])
|
|
27351
|
+
});
|
|
27352
|
+
if (sid)
|
|
27353
|
+
console.log(`[WeChat] ${account.accountId} reply route restored for ${sid}`);
|
|
27354
|
+
}
|
|
27355
|
+
}
|
|
27320
27356
|
async function runAccountLoop(args) {
|
|
27321
27357
|
const { registry: registry2, db, account, abort, bridge, activeOverrides: activeOverrides2, restartSelf, startNewAccount } = args;
|
|
27322
27358
|
try {
|
|
@@ -27852,8 +27888,8 @@ async function dispatch2(accountId, text6, explicitChatId, media) {
|
|
|
27852
27888
|
throw new Error("no wechat target \u2014 bind the account first (the QR-login owner becomes the default cron recipient)");
|
|
27853
27889
|
}
|
|
27854
27890
|
const out = [];
|
|
27891
|
+
const contextToken = readContextToken(accountId, chatId);
|
|
27855
27892
|
if (text6) {
|
|
27856
|
-
const contextToken = readContextToken(accountId, chatId);
|
|
27857
27893
|
const chunks = splitText(text6, WECHAT_TEXT_LIMIT);
|
|
27858
27894
|
for (const [i, chunk] of chunks.entries()) {
|
|
27859
27895
|
try {
|
|
@@ -27875,6 +27911,7 @@ async function dispatch2(accountId, text6, explicitChatId, media) {
|
|
|
27875
27911
|
baseUrl: acct.baseUrl,
|
|
27876
27912
|
token: acct.botToken,
|
|
27877
27913
|
toUserId: chatId,
|
|
27914
|
+
contextToken,
|
|
27878
27915
|
filePath
|
|
27879
27916
|
});
|
|
27880
27917
|
out.push({ channelType: "wechat", accountId, chatId, ok: true });
|
|
@@ -28456,14 +28493,14 @@ var init_event_adapter3 = __esm({
|
|
|
28456
28493
|
try {
|
|
28457
28494
|
await this.deps.sendText(text6);
|
|
28458
28495
|
} catch (err) {
|
|
28459
|
-
console.
|
|
28496
|
+
console.warn(`[Slack] sendText failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
28460
28497
|
}
|
|
28461
28498
|
}
|
|
28462
28499
|
for (const p of mediaPaths) {
|
|
28463
28500
|
try {
|
|
28464
28501
|
await this.deps.sendMedia(p);
|
|
28465
28502
|
} catch (err) {
|
|
28466
|
-
console.
|
|
28503
|
+
console.warn(`[Slack] sendMedia ${p} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
28467
28504
|
}
|
|
28468
28505
|
}
|
|
28469
28506
|
}
|
|
@@ -28689,6 +28726,32 @@ function rememberEventId(id) {
|
|
|
28689
28726
|
function buildSessionPrefixForThread(channelId, rootTs) {
|
|
28690
28727
|
return sessionPrefix("slack", `${channelId}:${rootTs}`);
|
|
28691
28728
|
}
|
|
28729
|
+
function restoreReplyRoute2(args) {
|
|
28730
|
+
const { registry: registry2, db, account, bridge } = args;
|
|
28731
|
+
const chatKey = getAccount(db, account.accountId)?.config.lastActiveChatId;
|
|
28732
|
+
if (typeof chatKey !== "string")
|
|
28733
|
+
return;
|
|
28734
|
+
const sep2 = chatKey.indexOf(":");
|
|
28735
|
+
if (sep2 <= 0)
|
|
28736
|
+
return;
|
|
28737
|
+
const channelId = chatKey.slice(0, sep2);
|
|
28738
|
+
const rootTs = chatKey.slice(sep2 + 1);
|
|
28739
|
+
if (!rootTs)
|
|
28740
|
+
return;
|
|
28741
|
+
const workspacePath = resolveAccountWorkspace(account);
|
|
28742
|
+
if (!workspacePath)
|
|
28743
|
+
return;
|
|
28744
|
+
const sid = restoreChannelRoute({
|
|
28745
|
+
registry: registry2,
|
|
28746
|
+
workspacePath,
|
|
28747
|
+
bridge,
|
|
28748
|
+
sessionPrefix: buildSessionPrefixForThread(channelId, rootTs),
|
|
28749
|
+
// Same mapping as pickSessionKey: DMs reply flat, threads into the root.
|
|
28750
|
+
route: { channelId, replyTs: rootTs === "dm" ? void 0 : rootTs }
|
|
28751
|
+
});
|
|
28752
|
+
if (sid)
|
|
28753
|
+
console.log(`[Slack] ${account.accountId} reply route restored for ${sid}`);
|
|
28754
|
+
}
|
|
28692
28755
|
function pickSessionKey(event) {
|
|
28693
28756
|
const channelId = event.channel;
|
|
28694
28757
|
const isDM = event.channel_type === "im";
|
|
@@ -28874,6 +28937,9 @@ function startSlackChannel(deps) {
|
|
|
28874
28937
|
st.stopped = false;
|
|
28875
28938
|
if (st.ws)
|
|
28876
28939
|
return;
|
|
28940
|
+
const account = getAccount5(db, accountId);
|
|
28941
|
+
if (account && account.enabled === 1)
|
|
28942
|
+
restoreReplyRoute2({ registry: registry2, db, account, bridge: st.bridge });
|
|
28877
28943
|
connect(accountId);
|
|
28878
28944
|
}
|
|
28879
28945
|
async function stopAccount(accountId) {
|
|
@@ -29740,6 +29806,27 @@ import * as Lark from "@larksuiteoapi/node-sdk";
|
|
|
29740
29806
|
function buildSessionPrefixForThread2(chatId, rootId) {
|
|
29741
29807
|
return sessionPrefix("feishu", `${chatId}:${rootId}`);
|
|
29742
29808
|
}
|
|
29809
|
+
function restoreReplyRoute3(args) {
|
|
29810
|
+
const { registry: registry2, db, account, bridge } = args;
|
|
29811
|
+
const chatKey = getAccount(db, account.accountId)?.config.lastActiveChatId;
|
|
29812
|
+
if (typeof chatKey !== "string" || !chatKey.endsWith(":dm"))
|
|
29813
|
+
return;
|
|
29814
|
+
const chatId = chatKey.slice(0, -":dm".length);
|
|
29815
|
+
if (!chatId)
|
|
29816
|
+
return;
|
|
29817
|
+
const workspacePath = resolveAccountWorkspace(account);
|
|
29818
|
+
if (!workspacePath)
|
|
29819
|
+
return;
|
|
29820
|
+
const sid = restoreChannelRoute({
|
|
29821
|
+
registry: registry2,
|
|
29822
|
+
workspacePath,
|
|
29823
|
+
bridge,
|
|
29824
|
+
sessionPrefix: buildSessionPrefixForThread2(chatId, "dm"),
|
|
29825
|
+
route: { inboundMessageId: "", isP2P: true, chatId }
|
|
29826
|
+
});
|
|
29827
|
+
if (sid)
|
|
29828
|
+
console.log(`[Feishu] ${account.accountId} reply route restored for ${sid}`);
|
|
29829
|
+
}
|
|
29743
29830
|
function pickSessionKey2(event) {
|
|
29744
29831
|
const chatId = event.message.chat_id;
|
|
29745
29832
|
const inboundMessageId = event.message.message_id;
|
|
@@ -30004,6 +30091,9 @@ function startFeishuChannel(deps) {
|
|
|
30004
30091
|
st.stopped = false;
|
|
30005
30092
|
if (st.wsClient)
|
|
30006
30093
|
return;
|
|
30094
|
+
const account = getAccount6(db, accountId);
|
|
30095
|
+
if (account && account.enabled === 1)
|
|
30096
|
+
restoreReplyRoute3({ registry: registry2, db, account, bridge: st.bridge });
|
|
30007
30097
|
void connect(accountId);
|
|
30008
30098
|
}
|
|
30009
30099
|
async function stopAccount(accountId) {
|
|
@@ -31592,7 +31682,7 @@ var init_dist2 = __esm({
|
|
|
31592
31682
|
init_git_ssh();
|
|
31593
31683
|
__dirname3 = path68.dirname(fileURLToPath3(import.meta.url));
|
|
31594
31684
|
PORT = config.server.port;
|
|
31595
|
-
HALO_VERSION = "1.4.
|
|
31685
|
+
HALO_VERSION = "1.4.2";
|
|
31596
31686
|
PROJECT_ROOT = findProjectRoot();
|
|
31597
31687
|
HALO_HOME4 = path68.join(homedir24(), ".halo");
|
|
31598
31688
|
GIT_SHA = readGitSha();
|
|
@@ -32531,7 +32621,7 @@ import path69 from "node:path";
|
|
|
32531
32621
|
import fs63 from "node:fs";
|
|
32532
32622
|
import { homedir as homedir25 } from "node:os";
|
|
32533
32623
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
32534
|
-
var VERSION = "1.4.
|
|
32624
|
+
var VERSION = "1.4.2";
|
|
32535
32625
|
var HELP_TOP = `Usage: halo <command> [options]
|
|
32536
32626
|
|
|
32537
32627
|
Commands:
|
package/package.json
CHANGED
|
@@ -69,7 +69,7 @@ Bundled docs: `~/.halo/global/docs/`. These reflect the installed Halo version;
|
|
|
69
69
|
|
|
70
70
|
What's bundled (and what's not):
|
|
71
71
|
|
|
72
|
-
- `guide/` — end-user guides (
|
|
72
|
+
- `guide/` — end-user guides (9 files, see table below)
|
|
73
73
|
- `dev/` — developer-facing topics (3 files: tools, add-model-provider, add-channel)
|
|
74
74
|
- `requirements/` — product requirements (2 files: settings, command)
|
|
75
75
|
- `design/`, `plans/`, `test/` — **not bundled** (live in the source repo only). Cross-links from bundled docs into these paths will 404; answer from the doc body, not the link.
|
|
@@ -82,6 +82,7 @@ What's bundled (and what's not):
|
|
|
82
82
|
| Where do I see past conversations? | `guide/sessions.md` |
|
|
83
83
|
| Create / edit / delete an agent? AGENT.md vs agent.yaml? Global vs workspace? Thinking / prompt caching? | `guide/agents.md` |
|
|
84
84
|
| What tools can an agent use? How do I add one? | `dev/tools.md` |
|
|
85
|
+
| Workspace vs global override? When does an agent.yaml / AGENT.md edit take effect? `team` / roster / `start_session` errors? Nesting depth? Which access level does a session / sub-agent / channel / cron / relay run at? | `guide/delegation-and-access.md` |
|
|
85
86
|
| What is a skill? How do I create / test one? | `guide/skills.md` + `guide/testing-agents-and-skills.md` |
|
|
86
87
|
| How do I test the agent I just made? | `guide/testing-agents-and-skills.md` |
|
|
87
88
|
| Slash commands (how they work, registering) | `guide/skills.md` (skill-as-command) + `requirements/command.md` |
|
/package/admin-out/_next/static/{9_eFiojb_-MS8CJ2oJg8_ → Jf-8TVLoHHwpT-gitolxN}/_buildManifest.js
RENAMED
|
File without changes
|
/package/admin-out/_next/static/{9_eFiojb_-MS8CJ2oJg8_ → Jf-8TVLoHHwpT-gitolxN}/_ssgManifest.js
RENAMED
|
File without changes
|