@turmind/halo 0.1.9

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.
Files changed (296) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +143 -0
  3. package/admin-out/404.html +1 -0
  4. package/admin-out/_next/static/IBP_mwBDf-cPwZSZZGpi8/_buildManifest.js +1 -0
  5. package/admin-out/_next/static/IBP_mwBDf-cPwZSZZGpi8/_ssgManifest.js +1 -0
  6. package/admin-out/_next/static/chunks/1d2d5650-810a3ca1ae20cab5.js +18 -0
  7. package/admin-out/_next/static/chunks/200.3b8f8a74f005a134.js +1 -0
  8. package/admin-out/_next/static/chunks/220.3dc41cd6269b88e6.js +1 -0
  9. package/admin-out/_next/static/chunks/298-d6b224b569da4de0.js +1 -0
  10. package/admin-out/_next/static/chunks/304eda7d.b1ee7f523653e027.js +1 -0
  11. package/admin-out/_next/static/chunks/330.3b784cf0dcd69163.js +1 -0
  12. package/admin-out/_next/static/chunks/442.f4302087bddb1ec1.js +1 -0
  13. package/admin-out/_next/static/chunks/443.d1b289781793f8de.js +25 -0
  14. package/admin-out/_next/static/chunks/503-7c6d9935df6e0cea.js +1 -0
  15. package/admin-out/_next/static/chunks/533.5f2d4bfe3d076095.js +1 -0
  16. package/admin-out/_next/static/chunks/579.a2718ddd395a2f3a.js +1 -0
  17. package/admin-out/_next/static/chunks/635-3dd0043ed0520b9d.js +1 -0
  18. package/admin-out/_next/static/chunks/65.859665ba6717967a.js +1 -0
  19. package/admin-out/_next/static/chunks/661.a4fe93f3f2a5e871.js +1 -0
  20. package/admin-out/_next/static/chunks/688.4e014ac6cfc7e152.js +1 -0
  21. package/admin-out/_next/static/chunks/868.0c95dfe283400a00.js +1 -0
  22. package/admin-out/_next/static/chunks/app/_not-found/page-8e35399c8fd5016d.js +1 -0
  23. package/admin-out/_next/static/chunks/app/layout-58f773336e6fce61.js +1 -0
  24. package/admin-out/_next/static/chunks/app/page-cc8043335282d745.js +1 -0
  25. package/admin-out/_next/static/chunks/db534642.09d3c650ff587175.js +1 -0
  26. package/admin-out/_next/static/chunks/fb4ec4d6-3fa44f69484f91b9.js +1 -0
  27. package/admin-out/_next/static/chunks/framework-c3031ae54a63fe16.js +1 -0
  28. package/admin-out/_next/static/chunks/main-14b48e3c2588354f.js +1 -0
  29. package/admin-out/_next/static/chunks/main-app-483b436873410ddc.js +1 -0
  30. package/admin-out/_next/static/chunks/pages/_app-b2fc6e5f920d1b1a.js +1 -0
  31. package/admin-out/_next/static/chunks/pages/_error-f3696a8f3d67d150.js +1 -0
  32. package/admin-out/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  33. package/admin-out/_next/static/chunks/webpack-8bd7ef88a6527feb.js +1 -0
  34. package/admin-out/_next/static/css/659eccb5db697b76.css +1 -0
  35. package/admin-out/_next/static/css/8fce4e1a54dac12a.css +3 -0
  36. package/admin-out/_next/static/media/19cfc7226ec3afaa-s.woff2 +0 -0
  37. package/admin-out/_next/static/media/21350d82a1f187e9-s.woff2 +0 -0
  38. package/admin-out/_next/static/media/8e9860b6e62d6359-s.woff2 +0 -0
  39. package/admin-out/_next/static/media/ba9851c3c22cd980-s.woff2 +0 -0
  40. package/admin-out/_next/static/media/c5fe6dc8356a8c31-s.woff2 +0 -0
  41. package/admin-out/_next/static/media/df0a9ae256c0569c-s.woff2 +0 -0
  42. package/admin-out/_next/static/media/e4af272ccee01ff0-s.p.woff2 +0 -0
  43. package/admin-out/favicon.ico +0 -0
  44. package/admin-out/icon.svg +18 -0
  45. package/admin-out/index.html +1 -0
  46. package/admin-out/index.txt +23 -0
  47. package/admin-out/monaco/vs/_commonjsHelpers-CT9FvmAN.js +1 -0
  48. package/admin-out/monaco/vs/abap-D-t0cyap.js +1 -0
  49. package/admin-out/monaco/vs/apex-CcIm7xu6.js +1 -0
  50. package/admin-out/monaco/vs/assets/css.worker-HnVq6Ewq.js +93 -0
  51. package/admin-out/monaco/vs/assets/editor.worker-Be8ye1pW.js +26 -0
  52. package/admin-out/monaco/vs/assets/html.worker-B51mlPHg.js +470 -0
  53. package/admin-out/monaco/vs/assets/json.worker-DKiEKt88.js +58 -0
  54. package/admin-out/monaco/vs/assets/ts.worker-CMbG-7ft.js +67731 -0
  55. package/admin-out/monaco/vs/azcli-BA0tQDCg.js +1 -0
  56. package/admin-out/monaco/vs/basic-languages/monaco.contribution.js +1 -0
  57. package/admin-out/monaco/vs/bat-C397hTD6.js +1 -0
  58. package/admin-out/monaco/vs/bicep-DF5aW17k.js +2 -0
  59. package/admin-out/monaco/vs/cameligo-plsz8qhj.js +1 -0
  60. package/admin-out/monaco/vs/clojure-Y2auQMzK.js +1 -0
  61. package/admin-out/monaco/vs/coffee-Bu45yuWE.js +1 -0
  62. package/admin-out/monaco/vs/cpp-CkKPQIni.js +1 -0
  63. package/admin-out/monaco/vs/csharp-CX28MZyh.js +1 -0
  64. package/admin-out/monaco/vs/csp-D8uWnyxW.js +1 -0
  65. package/admin-out/monaco/vs/css-CaeNmE3S.js +3 -0
  66. package/admin-out/monaco/vs/cssMode-CjiAH6dQ.js +1 -0
  67. package/admin-out/monaco/vs/cypher-DVThT8BS.js +1 -0
  68. package/admin-out/monaco/vs/dart-CmGfCvrO.js +1 -0
  69. package/admin-out/monaco/vs/dockerfile-CZqqYdch.js +1 -0
  70. package/admin-out/monaco/vs/ecl-30fUercY.js +1 -0
  71. package/admin-out/monaco/vs/editor/editor.main.css +1 -0
  72. package/admin-out/monaco/vs/editor/editor.main.js +5 -0
  73. package/admin-out/monaco/vs/editor.api-CalNCsUg.js +903 -0
  74. package/admin-out/monaco/vs/elixir-xjPaIfzF.js +1 -0
  75. package/admin-out/monaco/vs/flow9-DqtmStfK.js +1 -0
  76. package/admin-out/monaco/vs/freemarker2-Cz_sV6Md.js +3 -0
  77. package/admin-out/monaco/vs/fsharp-BOMdg4U1.js +1 -0
  78. package/admin-out/monaco/vs/go-D_hbi-Jt.js +1 -0
  79. package/admin-out/monaco/vs/graphql-CKUU4kLG.js +1 -0
  80. package/admin-out/monaco/vs/handlebars-OwglfO-1.js +1 -0
  81. package/admin-out/monaco/vs/hcl-DTaboeZW.js +1 -0
  82. package/admin-out/monaco/vs/html-Pa1xEWsY.js +1 -0
  83. package/admin-out/monaco/vs/htmlMode-Bz67EXwp.js +1 -0
  84. package/admin-out/monaco/vs/ini-CsNwO04R.js +1 -0
  85. package/admin-out/monaco/vs/java-CI4ZMsH9.js +1 -0
  86. package/admin-out/monaco/vs/javascript-PczUCGdz.js +1 -0
  87. package/admin-out/monaco/vs/jsonMode-DULH5oaX.js +7 -0
  88. package/admin-out/monaco/vs/julia-BwzEvaQw.js +1 -0
  89. package/admin-out/monaco/vs/kotlin-IUYPiTV8.js +1 -0
  90. package/admin-out/monaco/vs/language/css/monaco.contribution.js +1 -0
  91. package/admin-out/monaco/vs/language/html/monaco.contribution.js +1 -0
  92. package/admin-out/monaco/vs/language/json/monaco.contribution.js +1 -0
  93. package/admin-out/monaco/vs/language/typescript/monaco.contribution.js +1 -0
  94. package/admin-out/monaco/vs/less-C0eDYdqa.js +2 -0
  95. package/admin-out/monaco/vs/lexon-iON-Kj97.js +1 -0
  96. package/admin-out/monaco/vs/liquid-DqKjdPGy.js +1 -0
  97. package/admin-out/monaco/vs/loader.js +1368 -0
  98. package/admin-out/monaco/vs/lspLanguageFeatures-kM9O9rjY.js +4 -0
  99. package/admin-out/monaco/vs/lua-DtygF91M.js +1 -0
  100. package/admin-out/monaco/vs/m3-CsR4AuFi.js +1 -0
  101. package/admin-out/monaco/vs/markdown-C_rD0bIw.js +1 -0
  102. package/admin-out/monaco/vs/mdx-DEWtB1K5.js +1 -0
  103. package/admin-out/monaco/vs/mips-CiYP61RB.js +1 -0
  104. package/admin-out/monaco/vs/monaco.contribution-D2OdxNBt.js +1 -0
  105. package/admin-out/monaco/vs/monaco.contribution-DO3azKX8.js +1 -0
  106. package/admin-out/monaco/vs/monaco.contribution-EcChJV6a.js +1 -0
  107. package/admin-out/monaco/vs/monaco.contribution-qLAYrEOP.js +1 -0
  108. package/admin-out/monaco/vs/msdax-C38-sJlp.js +1 -0
  109. package/admin-out/monaco/vs/mysql-CdtbpvbG.js +1 -0
  110. package/admin-out/monaco/vs/nls.messages-loader.js +1 -0
  111. package/admin-out/monaco/vs/nls.messages.cs.js.js +17 -0
  112. package/admin-out/monaco/vs/nls.messages.de.js.js +17 -0
  113. package/admin-out/monaco/vs/nls.messages.es.js.js +17 -0
  114. package/admin-out/monaco/vs/nls.messages.fr.js.js +15 -0
  115. package/admin-out/monaco/vs/nls.messages.it.js.js +15 -0
  116. package/admin-out/monaco/vs/nls.messages.ja.js.js +17 -0
  117. package/admin-out/monaco/vs/nls.messages.js.js +10 -0
  118. package/admin-out/monaco/vs/nls.messages.ko.js.js +25 -0
  119. package/admin-out/monaco/vs/nls.messages.pl.js.js +17 -0
  120. package/admin-out/monaco/vs/nls.messages.pt-br.js.js +6 -0
  121. package/admin-out/monaco/vs/nls.messages.ru.js.js +17 -0
  122. package/admin-out/monaco/vs/nls.messages.tr.js.js +15 -0
  123. package/admin-out/monaco/vs/nls.messages.zh-cn.js.js +17 -0
  124. package/admin-out/monaco/vs/nls.messages.zh-tw.js.js +15 -0
  125. package/admin-out/monaco/vs/objective-c-CntZFaHX.js +1 -0
  126. package/admin-out/monaco/vs/pascal-r6kuqfl_.js +1 -0
  127. package/admin-out/monaco/vs/pascaligo-BiXoTmXh.js +1 -0
  128. package/admin-out/monaco/vs/perl-DABw_TcH.js +1 -0
  129. package/admin-out/monaco/vs/pgsql-me_jFXeX.js +1 -0
  130. package/admin-out/monaco/vs/php-D_kh-9LK.js +1 -0
  131. package/admin-out/monaco/vs/pla-VfZjczW0.js +1 -0
  132. package/admin-out/monaco/vs/postiats-BBSzz8Pk.js +1 -0
  133. package/admin-out/monaco/vs/powerquery-Dt-g_2cc.js +1 -0
  134. package/admin-out/monaco/vs/powershell-B-7ap1zc.js +1 -0
  135. package/admin-out/monaco/vs/protobuf-BmtuEB1A.js +2 -0
  136. package/admin-out/monaco/vs/pug-BRpRNeEb.js +1 -0
  137. package/admin-out/monaco/vs/python-Cr0UkIbn.js +1 -0
  138. package/admin-out/monaco/vs/qsharp-BzsFaUU9.js +1 -0
  139. package/admin-out/monaco/vs/r-f8dDdrp4.js +1 -0
  140. package/admin-out/monaco/vs/razor-BYAHOTkz.js +1 -0
  141. package/admin-out/monaco/vs/redis-fvZQY4PI.js +1 -0
  142. package/admin-out/monaco/vs/redshift-45Et0LQi.js +1 -0
  143. package/admin-out/monaco/vs/restructuredtext-C7UUFKFD.js +1 -0
  144. package/admin-out/monaco/vs/ruby-CZO8zYTz.js +1 -0
  145. package/admin-out/monaco/vs/rust-Bfetafyc.js +1 -0
  146. package/admin-out/monaco/vs/sb-3GYllVck.js +1 -0
  147. package/admin-out/monaco/vs/scala-foMgrKo1.js +1 -0
  148. package/admin-out/monaco/vs/scheme-CHdMtr7p.js +1 -0
  149. package/admin-out/monaco/vs/scss-C1cmLt9V.js +3 -0
  150. package/admin-out/monaco/vs/shell-ClXCKCEW.js +1 -0
  151. package/admin-out/monaco/vs/solidity-MZ6ExpPy.js +1 -0
  152. package/admin-out/monaco/vs/sophia-DWkuSsPQ.js +1 -0
  153. package/admin-out/monaco/vs/sparql-AUGFYSyk.js +1 -0
  154. package/admin-out/monaco/vs/sql-32GpJSV2.js +1 -0
  155. package/admin-out/monaco/vs/st-CuDFIVZ_.js +1 -0
  156. package/admin-out/monaco/vs/swift-n-2HociN.js +3 -0
  157. package/admin-out/monaco/vs/systemverilog-Ch4vA8Yt.js +1 -0
  158. package/admin-out/monaco/vs/tcl-D74tq1nH.js +1 -0
  159. package/admin-out/monaco/vs/tsMode-CZz1Umrk.js +11 -0
  160. package/admin-out/monaco/vs/twig-C6taOxMV.js +1 -0
  161. package/admin-out/monaco/vs/typescript-DfOrAzoV.js +1 -0
  162. package/admin-out/monaco/vs/typespec-D-PIh9Xw.js +1 -0
  163. package/admin-out/monaco/vs/vb-Dyb2648j.js +1 -0
  164. package/admin-out/monaco/vs/wgsl-BhLXMOR0.js +298 -0
  165. package/admin-out/monaco/vs/workers-DcJshg-q.js +1 -0
  166. package/admin-out/monaco/vs/xml-CdsdnY8S.js +1 -0
  167. package/admin-out/monaco/vs/yaml-DYGvmE88.js +1 -0
  168. package/bin/halo.js +9 -0
  169. package/bundled-docs/design/agent.md +145 -0
  170. package/bundled-docs/design/architecture.md +270 -0
  171. package/bundled-docs/design/background-dispatch.md +151 -0
  172. package/bundled-docs/design/command.md +58 -0
  173. package/bundled-docs/design/cron.md +88 -0
  174. package/bundled-docs/design/evolution.md +383 -0
  175. package/bundled-docs/design/express-self.md +145 -0
  176. package/bundled-docs/design/feishu.md +224 -0
  177. package/bundled-docs/design/halo-city.md +112 -0
  178. package/bundled-docs/design/prompt-system.md +411 -0
  179. package/bundled-docs/design/session.md +321 -0
  180. package/bundled-docs/design/slack.md +212 -0
  181. package/bundled-docs/design/storage.md +578 -0
  182. package/bundled-docs/design/telegram.md +161 -0
  183. package/bundled-docs/design/web.md +222 -0
  184. package/bundled-docs/design/wechat.md +146 -0
  185. package/bundled-docs/design/ws.md +144 -0
  186. package/bundled-docs/dev/acp-adapter.md +337 -0
  187. package/bundled-docs/dev/add-channel.md +376 -0
  188. package/bundled-docs/dev/add-model-provider.md +386 -0
  189. package/bundled-docs/dev/api.md +686 -0
  190. package/bundled-docs/dev/deploy.md +198 -0
  191. package/bundled-docs/dev/desktop-packaging.md +327 -0
  192. package/bundled-docs/dev/env.md +158 -0
  193. package/bundled-docs/dev/logging.md +85 -0
  194. package/bundled-docs/dev/previews.md +225 -0
  195. package/bundled-docs/dev/tools.md +331 -0
  196. package/bundled-docs/guide/README.md +29 -0
  197. package/bundled-docs/guide/agents.md +264 -0
  198. package/bundled-docs/guide/channels/README.md +62 -0
  199. package/bundled-docs/guide/channels/acp.md +150 -0
  200. package/bundled-docs/guide/channels/feishu.md +154 -0
  201. package/bundled-docs/guide/channels/slack.md +156 -0
  202. package/bundled-docs/guide/channels/telegram.md +112 -0
  203. package/bundled-docs/guide/channels/web.md +149 -0
  204. package/bundled-docs/guide/channels/wechat.md +110 -0
  205. package/bundled-docs/guide/chat.md +112 -0
  206. package/bundled-docs/guide/cli.md +197 -0
  207. package/bundled-docs/guide/getting-started.md +93 -0
  208. package/bundled-docs/guide/secrets-and-credentials.md +161 -0
  209. package/bundled-docs/guide/sessions.md +104 -0
  210. package/bundled-docs/guide/skills.md +302 -0
  211. package/bundled-docs/guide/testing-agents-and-skills.md +136 -0
  212. package/bundled-docs/guide/workspace.md +131 -0
  213. package/bundled-docs/plans/cron-tasks.md +362 -0
  214. package/bundled-docs/plans/design-suggestions.md +203 -0
  215. package/bundled-docs/plans/issue-session-deep-nesting.md +208 -0
  216. package/bundled-docs/plans/launch-plan.md +111 -0
  217. package/bundled-docs/plans/md-and-agent-refactor.md +197 -0
  218. package/bundled-docs/plans/remote-mac-worker.md +196 -0
  219. package/bundled-docs/plans/roadmap.md +40 -0
  220. package/bundled-docs/plans/self-evolution.md +1379 -0
  221. package/bundled-docs/plans/todo.md +32 -0
  222. package/bundled-docs/plans/weixin-channel.md +255 -0
  223. package/bundled-docs/requirements/agent.md +92 -0
  224. package/bundled-docs/requirements/chat.md +81 -0
  225. package/bundled-docs/requirements/command.md +130 -0
  226. package/bundled-docs/requirements/editor.md +82 -0
  227. package/bundled-docs/requirements/explorer.md +89 -0
  228. package/bundled-docs/requirements/overview.md +62 -0
  229. package/bundled-docs/requirements/session.md +73 -0
  230. package/bundled-docs/requirements/settings.md +224 -0
  231. package/bundled-docs/requirements/skill.md +125 -0
  232. package/bundled-docs/requirements/source-control.md +82 -0
  233. package/bundled-docs/requirements/terminal.md +118 -0
  234. package/bundled-docs/requirements/workspace.md +80 -0
  235. package/bundled-docs/test/docs-seeding.md +101 -0
  236. package/bundled-docs/test/session.md +374 -0
  237. package/dist/index.js +26750 -0
  238. package/package.json +67 -0
  239. package/templates/INSTRUCTIONS.md +25 -0
  240. package/templates/agents/__apply_agent__/AGENT.md +229 -0
  241. package/templates/agents/__apply_agent__/agent.yaml +30 -0
  242. package/templates/agents/__evo_agent__/AGENT.md +323 -0
  243. package/templates/agents/__evo_agent__/agent.yaml +29 -0
  244. package/templates/agents/__score__/AGENT.md +177 -0
  245. package/templates/agents/__score__/agent.yaml +29 -0
  246. package/templates/agents/deep-executor/AGENT.md +60 -0
  247. package/templates/agents/deep-executor/agent.yaml +25 -0
  248. package/templates/agents/default/AGENT.md +38 -0
  249. package/templates/agents/default/agent.yaml +51 -0
  250. package/templates/agents/executor/AGENT.md +38 -0
  251. package/templates/agents/executor/agent.yaml +25 -0
  252. package/templates/aliases.yaml +26 -0
  253. package/templates/canvas/self.html +660 -0
  254. package/templates/config.yaml +69 -0
  255. package/templates/models/anthropic.yaml +47 -0
  256. package/templates/models/aws-bedrock-claude-invoke.yaml +156 -0
  257. package/templates/models/aws-bedrock-mantle.yaml +89 -0
  258. package/templates/models/deepseek.yaml +62 -0
  259. package/templates/models/doubao.yaml +137 -0
  260. package/templates/models/hunyuan.yaml +56 -0
  261. package/templates/models/kimi.yaml +41 -0
  262. package/templates/models/mimo-token-plan-china.yaml +61 -0
  263. package/templates/models/minimax.yaml +80 -0
  264. package/templates/models/openai.yaml +51 -0
  265. package/templates/models/qwen.yaml +78 -0
  266. package/templates/optional-skills/tavily-web-search/SKILL.md +91 -0
  267. package/templates/optional-skills/tavily-web-search/config.yaml +10 -0
  268. package/templates/prompts/all/TOOL_GUIDELINES.md +35 -0
  269. package/templates/prompts/all/TOOL_SHELL.md +4 -0
  270. package/templates/prompts/all/TOOL_SHELL.windows.md +7 -0
  271. package/templates/prompts/bootstrap/BOOTSTRAP.md +26 -0
  272. package/templates/prompts/root/WORKSPACE_MEMORY.md +11 -0
  273. package/templates/schema.sql +30 -0
  274. package/templates/skills/acp/SKILL.md +236 -0
  275. package/templates/skills/acp/templates/SKILL.md.tmpl +74 -0
  276. package/templates/skills/acp/templates/ask.py +176 -0
  277. package/templates/skills/acp/templates/config.yaml.tmpl +33 -0
  278. package/templates/skills/agent/SKILL.md +128 -0
  279. package/templates/skills/aws-knowledge/SKILL.md +82 -0
  280. package/templates/skills/aws-knowledge/scripts/aws_kb.py +61 -0
  281. package/templates/skills/cron/SKILL.md +217 -0
  282. package/templates/skills/cron/manage-cron.py +434 -0
  283. package/templates/skills/halo/SKILL.md +98 -0
  284. package/templates/skills/nova-web-search/SKILL.md +65 -0
  285. package/templates/skills/self/SKILL.md +139 -0
  286. package/templates/skills/send-file/SKILL.md +28 -0
  287. package/templates/skills/send-file/feishu.md +16 -0
  288. package/templates/skills/send-file/slack.md +7 -0
  289. package/templates/skills/send-file/telegram.md +9 -0
  290. package/templates/skills/send-file/web.md +6 -0
  291. package/templates/skills/send-file/wechat.md +8 -0
  292. package/templates/skills/skill/SKILL.md +131 -0
  293. package/templates/skills/workspace/SKILL.md +28 -0
  294. package/templates/skills/workspace/setup-tidy.md +265 -0
  295. package/templates/skills/workspace/share.md +187 -0
  296. package/templates/skills/workspace/stage.py +487 -0
@@ -0,0 +1,578 @@
1
+ # Storage Protocol
2
+
3
+ Defines the persisted-data format for every Halo surface. Format changes must respect the compatibility rules in this doc.
4
+
5
+ ## Directory layout
6
+
7
+ ```
8
+ ~/.halo/ # Global (user-level)
9
+ ├── global/ # Non-sensitive config + data
10
+ │ ├── INSTRUCTIONS.md # Global instructions (injected into every agent)
11
+ │ ├── USER.md # User profile (bootstrap-generated)
12
+ │ ├── prompts/ # User-editable system prompts (externalised)
13
+ │ │ ├── bootstrap/BOOTSTRAP.md # First-run guidance
14
+ │ │ ├── all/ # Every agent (TOOL_GUIDELINES.md, TOOL_SHELL[.windows].md)
15
+ │ │ └── root/ # Root agent only — empty by default; user-set
16
+ │ ├── agents/<id>/
17
+ │ │ ├── agent.yaml # Agent config
18
+ │ │ └── AGENT.md # Agent personality
19
+ │ ├── models/ # Model registry — one file per provider, scanned at startup
20
+ │ │ └── <providerId>.yaml # e.g. aws-bedrock-claude-invoke.yaml
21
+ │ ├── skills/<id>/
22
+ │ │ └── SKILL.md # Skill definition (frontmatter + body)
23
+ │ ├── internal-sessions/<agentId>/ # Internal-agent sessions (`__evo_agent__`, `__score__`, `__apply_agent__`)
24
+ │ │ # — global so they don't pollute any workspace's halo.db
25
+ │ │ └── <sessionId>.json
26
+ │ ├── evo.db # Cross-workspace evolution queue (evolution_runs + evolution_applies)
27
+ │ ├── cron.db # Cross-workspace cron jobs + run history (cron_jobs + cron_runs)
28
+ │ ├── logs/ # Runtime logs
29
+ │ │ ├── evo/ # Per-evo-run wrapper logs
30
+ │ │ └── cron/ # Per-cron-run cli stdout/stderr (30-day retention)
31
+ │ ├── server.lock # Single-instance pid lock
32
+ │ └── .template-version # Template-seed marker (used by ensureHaloHome)
33
+ ├── secrets/ # Sensitive files (not mounted into sandbox)
34
+ │ ├── settings.yaml # Global settings (API keys, credentials)
35
+ │ ├── config.yaml # System config (admin password, server settings)
36
+ │ └── channels/
37
+ │ └── channels.db # Channel accounts DB
38
+
39
+ <workspace>/.halo/ # Workspace-level (overrides same-name global configs)
40
+ ├── USER.md # Optional, overrides global
41
+ ├── INSTRUCTIONS.md # Project-level instructions (overrides global INSTRUCTIONS.md)
42
+ ├── INDEX.md # Project overview + doc index (always injected)
43
+ ├── agents/<id>/ # Workspace agent (overrides same-id global)
44
+ ├── skills/<id>/
45
+ ├── prompts/ # System prompts (directory-level override of global)
46
+ │ ├── bootstrap/ # Overrides ~/.halo/global/prompts/bootstrap/ if present
47
+ │ ├── all/ # Overrides ~/.halo/global/prompts/all/ if present
48
+ │ └── root/ # Overrides ~/.halo/global/prompts/root/ if present
49
+ ├── sessions/<agentId>/ # Session files (one per regular session)
50
+ ├── memory/ # Project memory (dated entries)
51
+ ├── logs/
52
+ ├── evo/ # Self-evolution per-workspace artifacts
53
+ │ ├── runs/<id>/ # per-evaluation: source-snapshot.json, tool-flow.md,
54
+ │ │ # evo-context.json, sandbox/, patch.md, score.json,
55
+ │ │ # sub-cli.log, optional .skip.md
56
+ │ ├── applies/<id>/ # per-apply: meta.json, sandbox/, regress/<runId>/, apply.log
57
+ │ ├── history/apply-<id>/ # pre-apply rollback snapshot (MANIFEST.json + the overwritten files)
58
+ │ └── archive/ # zipped runs/applies past the retention window
59
+ ├── tmp/ # Agent scratch files (logs, downloads, intermediate artifacts) — convention from TOOL_GUIDELINES, not auto-created
60
+ ├── assets/<channel>/inbound/<accountId>/<date>/ # Inbound media per channel (image/voice/video/file)
61
+ ├── halo.db # Per-workspace sqlite (sessions metadata, command registry, disabled-items)
62
+ └── docs/ # Project docs (requirements/design/dev/test/plans)
63
+ ```
64
+
65
+ Precedence: workspace > global, **at folder granularity**. For the same id, a workspace `agents/<id>/` or `skills/<id>/` folder entirely replaces the global one — every file in it, no per-file fallback to global (a workspace agent folder with only `AGENT.md` loses the global `agent.yaml`). Same whole-folder rule for `prompts/{bootstrap,all,root}/` (workspace scope directory replaces the global one). INSTRUCTIONS.md is the single-file exception: workspace root suppresses global.
66
+
67
+ ### Path constructors
68
+
69
+ All `.halo/...` path math goes through `packages/server/src/paths.ts` (e.g. `wsHaloDir(ws)`, `wsEvoRunDir(ws, runId)`, `globalInternalSessionFile(agentId, seg)`, `cronLogFile(runId)`). Treat `paths.ts` as the canonical reference for the layout above; if the layout changes, update `paths.ts` first and call sites follow.
70
+
71
+ ## Session file format (v1)
72
+
73
+ Path: `.halo/sessions/{agentId}/{sessionId}.json`
74
+
75
+ ```jsonc
76
+ {
77
+ "version": 1,
78
+ "id": "oogezptkmoaeflb5",
79
+ "agentId": "default",
80
+ "agentName": "Default",
81
+ "title": "First user message...", // auto-generated, max 60 chars
82
+ "source": "explorer", // "explorer" (root) | "delegated" (sub-session)
83
+ "createdAt": "ISO8601",
84
+ "updatedAt": "ISO8601",
85
+ "messageCount": 42,
86
+ "contextTokens": 5975,
87
+ "totalOutputTokens": 6058,
88
+ "parentSessionId": "parent_id", // sub-sessions only
89
+ "messages": [SessionMessage], // UI event-log format (written by WS handler / UIState reducer)
90
+ "rawMessages": [AnthropicMessage], // raw Bedrock API shape (written by SessionManager saveAgentState)
91
+ "output": "..." // accumulated assistant text from the latest turn
92
+ }
93
+ ```
94
+
95
+ ### SessionMessage
96
+
97
+ ```typescript
98
+ type MessageType =
99
+ | 'user' | 'assistant'
100
+ | 'tool_call' | 'tool_result'
101
+ | 'usage' | 'context'
102
+ | 'agent_start' | 'agent_done'
103
+ | 'notification'
104
+
105
+ interface SessionMessage {
106
+ // Required
107
+ id: string // "m_{timestamp36}_{counter36}"
108
+ type: MessageType
109
+ role: 'user' | 'assistant' | 'system'
110
+ content: string
111
+ timestamp: number // Unix ms
112
+ agentName: string
113
+
114
+ // Optional scope
115
+ taskId?: string // Sub-agent task ID
116
+
117
+ // assistant-only
118
+ toolCalls?: ToolCallEntry[]
119
+ contentBlocks?: ContentBlockEntry[]
120
+
121
+ // tool_call-only
122
+ toolName?: string
123
+ toolInput?: unknown
124
+ toolOutput?: unknown
125
+ durationMs?: number
126
+
127
+ // usage-only
128
+ turnId?: string // LLM call UUID
129
+ usage?: {
130
+ inputTokens, outputTokens, totalTokens
131
+ cacheReadInputTokens, cacheWriteInputTokens?
132
+ ttftMs?, e2eMs?, thinkingEffort?
133
+ }
134
+ modelId?: string
135
+
136
+ // context-only (not persisted)
137
+ systemPrompt?: string
138
+
139
+ // Transient (not persisted)
140
+ streaming?: boolean
141
+ }
142
+ ```
143
+
144
+ ### ToolCallEntry
145
+
146
+ ```typescript
147
+ interface ToolCallEntry {
148
+ name: string
149
+ input: string // formatted summary
150
+ output?: string
151
+ durationMs?: number
152
+ }
153
+ ```
154
+
155
+ ### ContentBlockEntry
156
+
157
+ Keeps the interleaved order of text and tool calls within one assistant turn.
158
+
159
+ ```typescript
160
+ type ContentBlockEntry =
161
+ | { type: 'text'; text: string; turnId?: string }
162
+ | { type: 'thinking'; text: string; turnId?: string }
163
+ | { type: 'tool_call'; toolCall: ToolCallEntry; turnId?: string }
164
+ ```
165
+
166
+ `turnId` uniquely identifies each LLM API call. Content blocks and the corresponding usage message in the same turn share the same turnId.
167
+
168
+ ### Render rules
169
+
170
+ | Mode | Visible | Hidden |
171
+ |---|---|---|
172
+ | Normal | user, assistant, notification | tool_call, tool_result, usage, context, agent_start, agent_done |
173
+ | Debug | user, assistant, notification, context, agent_start, agent_done + inlined usage | tool_call, tool_result (already inlined in the assistant's contentBlocks) |
174
+
175
+ Assistant rendering priority:
176
+ 1. Has `contentBlocks` → render in contentBlocks order
177
+ 2. No contentBlocks, has `toolCalls` → tools first, then content (legacy)
178
+ 3. Neither → render only `content`
179
+
180
+ ### Backwards compatibility
181
+
182
+ 1. Missing `type`: infer from `role` + existing fields
183
+ 2. Missing `contentBlocks`: fall back to the `toolCalls` + `content` split layout
184
+ 3. Missing `version`: treat as v0, apply inference rules
185
+
186
+ ### Change rules
187
+
188
+ - Format changes **must** bump `version`
189
+ - Readers **must** handle every historical version
190
+ - Persisted fields **must not** be removed
191
+ - Adding optional fields does **not** require a version bump
192
+
193
+ ## Agent Config format
194
+
195
+ ### agent.yaml
196
+
197
+ ```yaml
198
+ name: Default # required
199
+ description: Default agent # optional
200
+ model:
201
+ provider: aws-bedrock-claude-invoke # matches ~/.halo/global/models/<providerId>.yaml
202
+ id: global.anthropic.claude-sonnet-4-6
203
+ endpoint: https://bedrock-runtime.us-west-2.amazonaws.com # full endpoint URL; supports custom proxy
204
+ maxTokens: 16384 # optional, model's max output tokens
205
+ thinking:
206
+ enabled: true
207
+ effort: medium # optional: low/medium/high/xhigh/max
208
+ budget: medium # optional legacy alias for effort
209
+ promptCaching: 1h # true / '5m' / '1h'
210
+ system_prompt: > # AGENT.md wins if present
211
+ You are...
212
+ context:
213
+ maxTokens: 200000 # context window cap
214
+ compressAt: 0.8 # auto-compact threshold (default; settings: general.compact.compress_at)
215
+ tools:
216
+ - file_read
217
+ - file_write
218
+ - shell_exec
219
+ skills:
220
+ - agent-creator
221
+ priority: 99 # sort weight (higher first); default 0
222
+ ```
223
+
224
+ TypeScript type (`packages/server/src/agents/agent-loader.ts`):
225
+
226
+ ```typescript
227
+ interface AgentYamlConfig {
228
+ name: string
229
+ description?: string
230
+ model?: {
231
+ provider?: string // required — no default fallback
232
+ id?: string // required — no default fallback
233
+ endpoint?: string // required — no default fallback
234
+ maxTokens?: number
235
+ promptCaching?: boolean | string
236
+ thinking?: { enabled?: boolean; budget?: string; effort?: string }
237
+ }
238
+ system_prompt?: string
239
+ tools?: string[]
240
+ skills?: string[]
241
+ context?: { maxTokens?: number; compressAt?: number }
242
+ priority?: number
243
+ }
244
+ ```
245
+
246
+ ### AGENT.md
247
+
248
+ Path: `.halo/agents/{agent-id}/AGENT.md`
249
+
250
+ Plain Markdown describing the agent's personality, behaviour, and constraints. **Takes precedence over** the `system_prompt` field in `agent.yaml`.
251
+
252
+ ### Load precedence
253
+
254
+ 1. `{workspace}/.halo/agents/{id}/` — workspace
255
+ 2. `~/.halo/global/agents/{id}/` — global
256
+
257
+ **Whole-folder override.** Resolution is by the agent's **folder**, not by
258
+ individual files: if the workspace dir `{workspace}/.halo/agents/{id}/`
259
+ exists, the agent is served entirely from it — both `agent.yaml` and
260
+ `AGENT.md` — and the global folder is ignored. A file missing inside the
261
+ workspace folder is simply absent; there is **no per-file fallback** to
262
+ global (a workspace agent with only `AGENT.md` has no `agent.yaml`, hence
263
+ no model config). When the workspace folder doesn't exist, the agent is
264
+ served entirely from global.
265
+
266
+ ## Settings format
267
+
268
+ Path: `~/.halo/secrets/settings.yaml` (global) / `<workspace>/.halo/settings.yaml` (workspace overlay).
269
+
270
+ Layout follows VSCode's `contributes.configuration` model: schema lives with each declarer (provider yaml, skill yaml, server built-ins); only the values live in `settings.yaml`. Full spec: [requirements/settings.md](../requirements/settings.md).
271
+
272
+ ```yaml
273
+ # Top-level keys are namespace ids; nested keys are kind (`params` / `secrets`)
274
+ # then leaf key.
275
+
276
+ general: # built-in declarer (the server itself)
277
+ session:
278
+ max_queue_size: 256
279
+ max_nesting_depth: 16
280
+ compact:
281
+ keep_messages: 5
282
+ max_summary_input: 15000
283
+ max_message_slice: 800
284
+ summarize_timeout_sec: 300
285
+ sandbox:
286
+ hidden_dirs: "~/.halo/secrets,~/.aws,~/.ssh,~/.gnupg,~/.docker"
287
+ hidden_files: "~/.npmrc,~/.bash_history,~/.gitconfig"
288
+ logging:
289
+ level: warn
290
+
291
+ aws-bedrock-claude-invoke: # provider id (matches models/<id>.yaml)
292
+ secrets:
293
+ access_key_id: AKIA…
294
+ secret_access_key: <<AWS_SECRET_ACCESS_KEY>>
295
+
296
+ kimi:
297
+ secrets:
298
+ api_key: <<KIMI_API_KEY>>
299
+
300
+ tavily-web-search: # skill id (matches skills/<id>/)
301
+ params:
302
+ api_key: <<TAVILY_API_KEY>>
303
+ ```
304
+
305
+ Path conventions:
306
+ - `general.<key>` — built-in server knobs (the only namespace that doesn't follow `<id>.<kind>s.<key>`)
307
+ - `<provider-id>.secrets.<key>` — server-side credentials for a model provider
308
+ - `<skill-id>.params.<key>` — values an agent can reference via `{{<skill-id>.params.<key>}}`
309
+ - `<skill-id>.secrets.<key>` — server-side keys a skill needs but agents must not see
310
+
311
+ ### Load precedence
312
+
313
+ ```
314
+ process env (via <<ENV>>) > workspace settings.yaml > global settings.yaml > schema default
315
+ ```
316
+
317
+ Workspace `settings.yaml` deep-merges over global, leaf by leaf. The Settings page surfaces source per field (`workspace` / `inherited from global` / `unset`) and lets users reset a workspace override.
318
+
319
+ ### Env-var interpolation: `<<ENV_NAME>>`
320
+
321
+ A value of the form `<<ENV_NAME>>` is replaced at read time with `process.env.ENV_NAME`. **If the env var is unset, the literal `<<ENV_NAME>>` stays verbatim** — calls fail loudly with the placeholder visible, instead of silently falling through to a different env var. This is intentional: it makes typos discoverable.
322
+
323
+ `<<>>` substitution is honored only inside settings-resolved values; cmd text the agent itself writes is **not** scanned (`shell_exec "echo <<HOME>>"` keeps the literal). Trust boundary is "settings file content", not "string happens to look like a placeholder".
324
+
325
+ ### Built-in keys (declared by the server)
326
+
327
+ | Path | Default | Notes |
328
+ |---|---|---|
329
+ | `general.session.max_queue_size` | 256 | Max queued messages per session |
330
+ | `general.session.max_nesting_depth` | 16 | Sub-session nesting cap |
331
+ | `general.compact.keep_messages` | 5 | Recent messages kept intact during compaction |
332
+ | `general.compact.max_summary_input` | 15000 | Local truncation fallback total char cap |
333
+ | `general.compact.max_message_slice` | 800 | Local truncation per-message char cap |
334
+ | `general.compact.summarize_timeout_sec` | 300 | LLM summary timeout |
335
+ | `general.limits.shell_output_bytes` | 5242880 | Max bytes captured from one `shell_exec` (stdout+stderr); excess truncated with a `[truncated]` marker |
336
+ | `general.limits.web_fetch_bytes` | 51200 | Max bytes downloaded by one `web_fetch` |
337
+ | `general.limits.grep_default_matches` | 50 | Default `grep` match cap when no explicit `max` is passed |
338
+ | `general.limits.tool_result_render_chars` | 8000 | Per-tool-result cap on the content **fed to the LLM** (truncated with a re-run marker to protect the context window / prompt cache). The UI gets a much larger slice — see `tool_result_ui_chars` and `agent-loop.ts` (`resultContent` = LLM cap, `resultTextFull` = UI cap) |
339
+ | `general.limits.tool_result_ui_chars` | 65536 | Per-tool-result cap on the content **stored for UI display** (admin/web chat panel). Far larger than the LLM cap so a normal command's full output stays visible, but bounded so a multi-MB `cat` can't bloat the session file / WS payload / browser render; excess truncated with a marker pointing at `file_read` |
340
+ | `general.limits.ws_event_buffer` | 5000 | Events buffered per detached WS session before oldest are dropped on reattach |
341
+ | `general.limits.terminal_scrollback_bytes` | 50000 | Off-screen scrollback bytes retained per detached persistent terminal |
342
+ | `general.sandbox.hidden_dirs` | `~/.halo/secrets,~/.aws,~/.ssh,~/.gnupg,~/.docker` | bwrap tmpfs overlay (Linux only) |
343
+ | `general.sandbox.hidden_files` | `~/.npmrc,~/.bash_history,~/.gitconfig` | bwrap /dev/null bind (Linux only) |
344
+ | `general.logging.level` | warn | `debug` / `info` / `warn` / `error` |
345
+
346
+ Schema source: [packages/server/src/settings-schema.ts](../../../packages/server/src/settings-schema.ts) `generalSection()`.
347
+
348
+ ### Caching
349
+
350
+ `config.ts` reads settings.yaml lazily with mtime-watching: every read stats the file and reparses if mtime changed. UI saves bump mtime, so the server picks up new values on the next read **without a restart**.
351
+
352
+ ### Orphans
353
+
354
+ Values present in `settings.yaml` whose namespace isn't currently declared by any provider/skill are surfaced as **orphans** in the Settings UI. They aren't deleted automatically — uninstalling a skill keeps its values around so re-installing pops them back in. Users prune them via the orphan tab.
355
+
356
+ > There is no longer a global "file access level" setting. Per-session access level is tracked on the session itself (`agent_sessions.access_level`) and, for channel bots, on the account (`channel_accounts.access_level`).
357
+
358
+ ## Model registry format
359
+
360
+ Path: `~/.halo/global/models/<providerId>.yaml` — one file per provider. All files are scanned at startup and merged into the in-memory registry. The same yaml also declares the provider's required server-side credentials (`secrets:` section), which the Settings page renders.
361
+
362
+ ```yaml
363
+ # aws-bedrock-claude-invoke.yaml
364
+ id: aws-bedrock-claude-invoke # required, must match filename and agent.yaml model.provider
365
+ displayName: AWS Bedrock Claude (Invoke API) # shown in UI
366
+ displayName_zh: AWS Bedrock Claude(Invoke API) # optional zh override
367
+ description: Invokes Bedrock via InvokeModel (non-streaming)
368
+ description_zh: 通过 Bedrock InvokeModel(非流式)调用
369
+ defaultEndpoint: https://bedrock-runtime.us-west-2.amazonaws.com
370
+ defaultModelId: global.anthropic.claude-sonnet-4-6 # picked when user switches to this provider
371
+ endpointPresets:
372
+ - https://bedrock-runtime.us-west-2.amazonaws.com
373
+ - https://bedrock-runtime.us-east-1.amazonaws.com
374
+
375
+ # Server-side credentials. Stored at <provider-id>.secrets.<key> in
376
+ # settings.yaml; never injected into agent prompts or shell_exec.
377
+ secrets:
378
+ - key: access_key_id
379
+ description: AWS Access Key ID. Leave empty to use the AWS credential chain.
380
+ description_zh: AWS Access Key ID。留空则使用凭证链
381
+ secret: true
382
+ - key: secret_access_key
383
+ description: AWS Secret Access Key.
384
+ description_zh: AWS Secret Access Key
385
+ secret: true
386
+
387
+ models:
388
+ - id: global.anthropic.claude-sonnet-4-6
389
+ displayName: Claude Sonnet 4.6
390
+ maxOutputTokens: 64000
391
+ capabilities:
392
+ image: true # supports image input
393
+ video: false
394
+ audio: false
395
+ promptCaching:
396
+ default: 1h # auto-on value when toggled / on provider switch
397
+ ttlPresets:
398
+ - { value: 5m, label: 5min }
399
+ - { value: 1h, label: 1hour }
400
+ thinking:
401
+ mode: adaptive # 'adaptive' | 'manual'
402
+ defaultEnabled: true # start with Thinking checked for new agents
403
+ default: medium # effort selected when Thinking is on (adaptive)
404
+ defaultBudgetTokens: 4000 # budget when Thinking is on (manual mode only)
405
+ effortPresets:
406
+ - { value: low, label: Low }
407
+ - { value: medium, label: Medium }
408
+ - { value: high, label: High }
409
+ - { value: max, label: Max }
410
+ ```
411
+
412
+ ### Capability defaults — what each `default*` field controls
413
+
414
+ | Path | Used when | Fallback |
415
+ |---|---|---|
416
+ | `<provider>.defaultModelId` | User switches provider; form picks this model | `models[0].id` |
417
+ | `<provider>.defaultEndpoint` | Same; endpoint input | `''` |
418
+ | `capabilities.promptCaching.default` | Toggle on / provider switch into a caching-capable model | `ttlPresets[0].value` |
419
+ | `capabilities.thinking.defaultEnabled` | New agent or provider switch with no prior thinking config | `false` |
420
+ | `capabilities.thinking.default` | Thinking toggled on, adaptive mode | `effortPresets[0].value` |
421
+ | `capabilities.thinking.defaultBudgetTokens` | Thinking toggled on, manual mode | `8192` |
422
+
423
+ Existing agent yaml values always win over these defaults — switching providers carries the user's effort/ttl over when valid for the new model. The defaults only fire when there's nothing to carry, or the carry-over isn't valid in the new vocabulary (e.g. Bedrock `medium` → Kimi `enabled/disabled` mismatch resets to the new provider's `default`).
424
+
425
+ **`capabilities` drives the UI and runtime behavior**:
426
+ - `image` / `video` / `audio` (boolean) → modality badges in the form; at runtime, unsupported modality inputs are filtered out with a text notice instead of causing API errors
427
+ - `promptCaching.ttlPresets` → Prompt Caching dropdown
428
+ - `thinking.mode`:
429
+ - `adaptive` → wire format `thinking: {type: 'adaptive'}` + `output_config.effort` (Sonnet 4.6 / Opus 4.6+ / Opus 4.7)
430
+ - `manual` → wire format `thinking: {type: 'enabled', budget_tokens: N}` (Haiku 4.5 and other legacy thinking models). UI offers a budget number input; runtime translates effort labels via the table in `bedrock-agent.ts` if needed.
431
+ - `thinking.effortPresets` → Thinking effort dropdown (when `mode: adaptive`)
432
+ - Omit a block → the UI hides that control for this model
433
+
434
+ **`secrets:` declarations** drive the Settings page: each entry becomes a masked input grouped under the provider's display name. Values land at `<provider-id>.secrets.<key>` in settings.yaml.
435
+
436
+ `agent.yaml`'s `model.provider` must match a provider's `id` — otherwise session spawn fails.
437
+
438
+ Routing: `createModelRuntime(providerId, cfg)` → looks up the implementation by `providerId`. See [design/agent.md](../design/agent.md#agent-instance).
439
+
440
+ ## Skill schema (`config.yaml`)
441
+
442
+ Optional file at `<skill-dir>/config.yaml` (next to `SKILL.md`). Declares which params and secrets the skill needs; the Settings page renders these grouped under the skill's display name.
443
+
444
+ ```yaml
445
+ # tavily-web-search/config.yaml
446
+ displayName_zh: Tavily 联网搜索 # optional override; falls back to SKILL.md `name`
447
+ description: Real-time web search via Tavily Search API.
448
+ description_zh: 通过 Tavily 搜索 API 进行实时联网搜索。
449
+
450
+ params: # values an agent can use via {{<skill>.params.<key>}}
451
+ - key: api_key
452
+ description: Tavily Search API Key
453
+ description_zh: Tavily 搜索 API Key
454
+ default: <<TAVILY_API_KEY>> # placeholder/hint; user can leave as-is to use env var
455
+ secret: true # masked input + masked API responses
456
+
457
+ secrets: [] # optional — server-only keys, never reach the agent
458
+ ```
459
+
460
+ Skill bodies can use the **short form** `{{params.<key>}}` — the activation pipeline rewrites it to `{{<skill-id>.params.<key>}}` before handing the body to the agent. Long form (`{{nano-banana.params.endpoint}}`) is also accepted, useful when one skill needs to reference another skill's param. AGENT.md must use the long form.
461
+
462
+ ## Skill format
463
+
464
+ Path: `.halo/skills/{skill-id}/SKILL.md`
465
+
466
+ ```markdown
467
+ ---
468
+ name: skill-id # kebab-case, = directory name
469
+ description: One-line description for agent discovery
470
+ command: /review # optional, explicit opt-in registers a slash command
471
+ ---
472
+
473
+ # Skill Title
474
+
475
+ Detailed instructions...
476
+ ```
477
+
478
+ ```typescript
479
+ interface SkillMeta {
480
+ id: string // directory name
481
+ name: string // from frontmatter
482
+ description: string // from frontmatter
483
+ path: string // absolute path to SKILL.md
484
+ }
485
+ ```
486
+
487
+ Load precedence matches agents: workspace > global, **whole-folder override**. A workspace `skills/<id>/` folder replaces the global skill wholesale — SKILL.md plus every sibling resource file — with no per-file fallback to global.
488
+
489
+ ## SQLite databases
490
+
491
+ Workspace DB: `<workspace>/.halo/halo.db`
492
+ Channel DB: `~/.halo/secrets/channels/channels.db`
493
+ Schema seed: `packages/server/templates/schema.sql`
494
+ ORM: `packages/server/src/db/schema.ts`, `packages/server/src/db/channel-db.ts`
495
+
496
+ The databases hold session metadata indexes and workspace-scoped preferences (e.g. disabled items); message content lives in JSON files. Agent/skill/project config goes through the filesystem.
497
+
498
+ ### Tables
499
+
500
+ **`sessions`** — frontend session index (created on first chat)
501
+
502
+ | Column | Type | Notes |
503
+ |---|---|---|
504
+ | id | TEXT PK | Session ID |
505
+ | title | TEXT NOT NULL DEFAULT '' | Truncated first user message |
506
+ | messages | TEXT | Legacy field, unused (content now in JSON) |
507
+ | message_count | INTEGER | Message count |
508
+ | created_at / updated_at | INTEGER | Unix ms |
509
+
510
+ **`agent_sessions`** — agent session index (root + sub-sessions)
511
+
512
+ | Column | Type | Notes |
513
+ |---|---|---|
514
+ | id | TEXT PK | Session ID (hierarchical: `sid_abc` or `sid_abc>sid_def`) |
515
+ | parent_id | TEXT | Parent session ID (null = root) |
516
+ | agent_id | TEXT NOT NULL | Agent YAML ID |
517
+ | agent_name | TEXT | Display name |
518
+ | description | TEXT | Task description |
519
+ | working_dir | TEXT | Workspace-relative path; null = project root |
520
+ | access_level | TEXT | `'readonly'`, `'workspace'`, or null (null = full access). Added via idempotent ALTER in `db/index.ts`. |
521
+ | created_at / updated_at | INTEGER | Unix ms |
522
+ | stopped_at | INTEGER | Stopped timestamp (null = active) |
523
+ | archived_at | INTEGER | Archived timestamp (null = not archived) |
524
+
525
+ **`disabled_items`** — per-workspace disable state for agents and skills (allows the same global item to be independently toggled in each workspace)
526
+
527
+ | Column | Type | Notes |
528
+ |---|---|---|
529
+ | item_type | TEXT NOT NULL | `'agent'` or `'skill'` |
530
+ | item_id | TEXT NOT NULL | Agent/skill ID |
531
+ | scope | TEXT NOT NULL | `'global'` or `'workspace'` — which source the item comes from |
532
+ | disabled_at | INTEGER NOT NULL | Unix ms |
533
+ | | | **PK**: `(item_type, item_id, scope)` |
534
+
535
+ **`channel_accounts`** — unified channel account index (lives in `~/.halo/secrets/channels/channels.db`)
536
+
537
+ All channel types (telegram, web, wechat, slack, feishu) share one table. Common fields are explicit columns; channel-specific fields live in the `config` JSON column.
538
+
539
+ | Column | Type | Notes |
540
+ |---|---|---|
541
+ | account_id | TEXT PK | Channel-specific ID (e.g. `halo_agent_bot`, `abc-im-bot`, `e718bb7b`) |
542
+ | channel_type | TEXT NOT NULL | `'telegram'`, `'web'`, `'wechat'`, `'slack'`, or `'feishu'` |
543
+ | workspace_path | TEXT NOT NULL | Absolute path of the bound workspace |
544
+ | label | TEXT | User-chosen name |
545
+ | enabled | INTEGER | 1 = active, 0 = disabled |
546
+ | access_level | TEXT | `'full'`, `'workspace'`, or `'readonly'` (default `'readonly'`) |
547
+ | language | TEXT | `'en'` or `'zh'` (default `'en'`) |
548
+ | config | TEXT | JSON — channel-specific fields (see below) |
549
+ | created_at / updated_at | INTEGER | Unix ms |
550
+
551
+ **Config JSON by channel type:**
552
+
553
+ | Channel | Config fields |
554
+ |---|---|
555
+ | telegram | `botToken`, `botUsername`, `allowedUsers` |
556
+ | web | `token` |
557
+ | wechat | `botToken`, `baseUrl`, `userId`, `syncBuf` |
558
+ | slack | `botToken`, `appToken`, `botUserId`, `teamId` |
559
+ | feishu | `appId`, `appSecret`, `verificationToken`, `encryptKey`, `botOpenId` |
560
+
561
+ ### Schema change rules
562
+
563
+ - Add columns via `ALTER TABLE ... ADD COLUMN` + try/catch (skip if already present)
564
+ - Do not drop or rename existing columns
565
+ - New tables: add to `templates/schema.sql`
566
+ - Centralise migration logic in `db/index.ts` and `db/channel-db.ts`
567
+ - New channel types: add rows with a new `channel_type` value + define config shape in the channel's `accounts.ts` adapter
568
+
569
+ ## Changelog
570
+
571
+ | Version | Date | Change |
572
+ |---|---|---|
573
+ | v1 | 2026-04-22 | Initial protocol. SessionMessage gains `type`; SessionFileData gains `version`. |
574
+ | v1+ | 2026-04-22 | Optional additions: `thinking` ContentBlockEntry; usage fields `thinkingEffort`, `cacheWriteInputTokens`; agent.yaml `thinking`, `promptCaching`; `is_main` → `is_default`; path `explorer/main/` → `explorer/default/`. |
575
+ | v1+ | 2026-04-28 | Model registry reshaped from `models.yaml` to per-provider files under `models/`. Provider id `bedrock` renamed to `aws-bedrock-claude-invoke`. Added `agent_sessions.access_level` column; added `weixin_accounts.access_level` and `weixin_accounts.sync_buf`. Removed global file-access setting. |
576
+ | v1+ | 2026-05-12 | Restructured `~/.halo/`: sensitive files (settings.yaml, config.yaml, channels/) moved to `secrets/`; non-sensitive config remains in `global/`. `migrateSecrets()` auto-migrates on first startup. Access level expanded to three tiers: `full` / `workspace` / `readonly` (agent_sessions + channel_accounts). Tool execution routed through bwrap sandbox for non-full access levels. `agent_sessions.working_dir` now stored as workspace-relative path. |
577
+ | v1+ | 2026-05-13 | Settings i18n + UI polish: compact keys renamed camelCase → snake_case (`keep_messages`, `max_summary_input`, `max_message_slice`, `summarize_timeout_sec`). Added `description_zh` on all leaf nodes and `description`/`description_zh` on branch nodes (replaces `_hint`/`_hint_zh`). Added `secret: true` attribute for masked input. Added Tavily to default params. Admin UI fully i18n'd (agents, skills, settings, nav). |
578
+ | v1+ | 2026-05-13 | Added `packages/cli` — standalone CLI/TUI client with embedded agent loop (no server required). Imports server agent-core via subpath exports. Session prefix: `cli_`. Added `exports` + `typesVersions` to server `package.json`. |