Ver Fonte

chore: refresh codemap across 31 folders

Updated project-level and per-folder codemaps after task-session-manager
decomposition and background-job-board deepening.

Refs #646
Michael Henke há 1 mês atrás
pai
commit
961828aa8b

+ 131 - 112
.slim/codemap.json

@@ -1,8 +1,8 @@
 {
   "metadata": {
     "version": "1.0.0",
-    "last_run": "2026-04-23T20:44:47.448Z",
-    "root": "/Users/alvin/repos/oh-my-opencode-slim",
+    "last_run": "2026-07-02T23:16:30.036Z",
+    "root": "/home/mhenke/Projects/oh-my-opencode-slim",
     "include_patterns": [
       "src/**/*.ts",
       "src/**/*.d.ts",
@@ -27,162 +27,181 @@
     "exceptions": []
   },
   "file_hashes": {
-    "AGENTS.md": "30d65f029344f61705af6d525ad7801f",
-    "README.md": "3f415941772613de8f934d29f75a6f98",
+    "AGENTS.md": "75f71915cf0ad65e1168c3d50741f9f1",
+    "README.md": "29242ede8361ccee21d0e053df8eed53",
     "biome.json": "b68da34425b83fddbde5718ac6eb82f9",
-    "package.json": "2b227b7342d04a033c142fcf0945d629",
+    "package.json": "b14793518ed7fad4a5f057fdefb9e017",
     "scripts/generate-schema.ts": "007f340e39adf6c3fd76feda72b71df1",
     "scripts/verify-opencode-host-smoke.ts": "a87fdb08b123501edf81618a49bc421d",
-    "scripts/verify-release-artifact.ts": "83259be1926459412809013ce16e6fbb",
-    "src/agents/council.ts": "993d74cefe54fefd32091b14bd82d1fd",
-    "src/agents/councillor.ts": "612382324db18614ca2401d6d69f2746",
-    "src/agents/designer.ts": "7d4e2654d89be9bfa99deb0a2802db5c",
-    "src/agents/explorer.ts": "4dc3878a5e90eb5a16aefd9ecd4261df",
-    "src/agents/fixer.ts": "f5f1b428de434ee5911001ec1b5b8b54",
-    "src/agents/index.ts": "74925084d05aa1541257e0379257f216",
-    "src/agents/librarian.ts": "e62049e08902ae4138d08ce0ec5bd9e8",
-    "src/agents/observer.ts": "57444137950f44a0fa6a874f2699e7e6",
-    "src/agents/oracle.ts": "9aab904d02bacb93f821d9c9c8f70ccf",
-    "src/agents/orchestrator.ts": "3f12e529cc328696363f2cf6c30da2d6",
-    "src/cli/config-io.ts": "e9048becbe09e618f07853ea9050b840",
+    "scripts/verify-release-artifact.ts": "14373deac536d31ad0cc4516f1aa98ce",
+    "src/agents/council.ts": "410d3d621738c68af1ffc54389d9cc49",
+    "src/agents/councillor.ts": "4b95f3d807762ac7fc2e2684140cf624",
+    "src/agents/designer.ts": "dc615fc8fdb9b9c218c1f002530d1f56",
+    "src/agents/explorer.ts": "d0852357f5f54d9091ce32a7576cbd4e",
+    "src/agents/fixer.ts": "f59568120a49fd4530b25322d9cdaea5",
+    "src/agents/index.ts": "60672ff6d7d628527f61610e91b55cfd",
+    "src/agents/librarian.ts": "25e64317fd9ef5f8b6759150c44c0ff8",
+    "src/agents/observer.ts": "1bdc85a13c59c05055e47aec8eefff54",
+    "src/agents/oracle.ts": "ef1581f9c8f06cfcec1837f85f69d06e",
+    "src/agents/orchestrator.ts": "e83a943def94c654dc2558167bf99e44",
+    "src/agents/permissions.ts": "c7916999c6e0edbf4666db6c02bed3cb",
+    "src/cli/background-subagents.ts": "adfda967b577ad4f0494d85447977913",
+    "src/cli/companion.ts": "f3031226ff810b9fc703dbd08726f71d",
+    "src/cli/config-io.ts": "5f03ec3adf6e86e550c75f3d9c3252a5",
     "src/cli/config-manager.ts": "7f2960f55aaebab21d822c586c2b12eb",
-    "src/cli/custom-skills.ts": "da74e53dfd5f570e97a99ea4fd1d0440",
-    "src/cli/index.ts": "ab4dadeea6be171cb0fc3317b18bca9d",
-    "src/cli/install.ts": "bd84dbbca86aeacf9520952433c0835e",
+    "src/cli/custom-skills.ts": "dca013d57a18e036b781f0471023c103",
+    "src/cli/doctor.ts": "deb359777d243984b6a6ced6aee32651",
+    "src/cli/index.ts": "e5cca0018fa250a341fe5a10c4c5a789",
+    "src/cli/install.ts": "8849ad8934ad6d68807b0c3aca50031a",
     "src/cli/model-key-normalization.ts": "7f988cc8109c95382b9ece9730e2a7a5",
-    "src/cli/paths.ts": "77054651c36e730aa3b32682fd26fe70",
-    "src/cli/providers.ts": "12ee3947cd27554e90d34760a3952b6a",
-    "src/cli/skills.ts": "4b3a3aec7ff891608c56d242a0f517f6",
+    "src/cli/paths.ts": "dd032ba57b84ab4a3a8437d51600acd7",
+    "src/cli/providers.ts": "96dbb99a74bf5bc04336273ef78cc887",
+    "src/cli/skills.ts": "e1147d45d69355379f47d4a8146404c6",
     "src/cli/system.ts": "b5464d7661ab1c8e196159641ee3bbed",
-    "src/cli/types.ts": "6b3468226ad733b8c4a601677a98a11e",
-    "src/config/agent-mcps.ts": "d62ecc6f60c7005ca00996aa1a5749c8",
-    "src/config/constants.ts": "b8dad0bac96f4d99dd27a2ecb753cb68",
-    "src/config/council-schema.ts": "4e9d5603725b7b3730685c03292f5b44",
-    "src/config/index.ts": "34949877c248cc5fbc3699fd7c5c70f2",
-    "src/config/loader.ts": "7b67eb3eabb97af42409f5d5ac49f5fc",
-    "src/config/schema.ts": "e99dd75e09539cefa1fb339177365b22",
-    "src/config/utils.ts": "b49d30f4c667a30cfa4627aa842b454b",
-    "src/council/council-manager.ts": "8b3aa710b2af2afae0c572ffd7c4959e",
+    "src/cli/types.ts": "7fb0770e7aa0e010f0107df45ab5572b",
+    "src/companion/manager.ts": "dc16e79ccff1c67c6980a0d295f3044c",
+    "src/companion/updater.ts": "45bb856e88a75e07426936b505b2f973",
+    "src/config/agent-mcps.ts": "ce2c54b4f82a8a6ab42ed7acb1fc58bf",
+    "src/config/constants.ts": "38310819e904fc349ff9d46ae3e17e50",
+    "src/config/council-schema.ts": "d180ec95197e173d21bc6f6dc6a5fcc6",
+    "src/config/index.ts": "8a61e02aa676fc86cc8d9d6d30a2e617",
+    "src/config/loader.ts": "e1fa6142444980bfa667c9e2af06055e",
+    "src/config/runtime-preset.ts": "7f924629c21ed1f438bcea8f4a54da02",
+    "src/config/schema.ts": "1e7481057f6bcf025b697a23006d7dc6",
+    "src/config/utils.ts": "ea6fe8ef6dff0848f42f03c7d6983727",
+    "src/council/council-manager.ts": "6443262ab1d50680f0b97e735cd90255",
     "src/council/index.ts": "24cab5b06b4bfd91d2496692650eb18a",
-    "src/hooks/apply-patch/codec.ts": "fce9edab08aab27b5c09bdb46c201203",
+    "src/hooks/apply-patch/codec.ts": "ba2086f51f88c47a67ccf930f0b1e268",
     "src/hooks/apply-patch/errors.ts": "fd2c9d9d185494f2f8b22862bd14700b",
     "src/hooks/apply-patch/execution-context.ts": "b44fb8ae4c672ab7c0b18fb1aa1915a0",
-    "src/hooks/apply-patch/index.ts": "835302f13810b8cb88d92367d3fc034e",
-    "src/hooks/apply-patch/matching.ts": "2ea9569179cf01c0c010f257cd9278d3",
+    "src/hooks/apply-patch/index.ts": "013d868ee0c7f267457f8ca8387e482f",
+    "src/hooks/apply-patch/matching.ts": "a2cf65b5b08f0d480f968f44e6813300",
     "src/hooks/apply-patch/operations.ts": "2ea0bbef64fcb6bd07a8adf35a490aeb",
-    "src/hooks/apply-patch/patch.ts": "65f24cc7d01d80eeda3016469d8e32ed",
     "src/hooks/apply-patch/prepared-changes.ts": "bf504dea1fc8723f593093a6c8d9a829",
-    "src/hooks/apply-patch/resolution.ts": "45305823564edf4c9cdf972f5b03859a",
-    "src/hooks/apply-patch/rewrite.ts": "2ba1d58233a4093bf0d5ffde0ad8ff75",
+    "src/hooks/apply-patch/resolution.ts": "e2817a8d48d8a89f58b3b39ef0088f41",
+    "src/hooks/apply-patch/rewrite.ts": "581c23e0f46c26e413cb65df64858582",
     "src/hooks/apply-patch/test-helpers.ts": "27b74cc1c0dec6c9dfdbbea4a9724468",
     "src/hooks/apply-patch/types.ts": "bff517a2050313703b3e8c4af35617d0",
     "src/hooks/auto-update-checker/cache.ts": "306b85a4beef7fd9959ecdfc655f8c3c",
-    "src/hooks/auto-update-checker/checker.ts": "18a6a25b534a3be31d57b2f5a401f235",
-    "src/hooks/auto-update-checker/constants.ts": "c46dcf24c3184965314f008ede59b7c7",
-    "src/hooks/auto-update-checker/index.ts": "3df09b0bec208c0c962c8f2bd0dab177",
-    "src/hooks/auto-update-checker/types.ts": "b53cb3c5c541d65da160d83451433499",
+    "src/hooks/auto-update-checker/checker.ts": "616bd0fa5e2d00464ef0f2b99ed47a3b",
+    "src/hooks/auto-update-checker/constants.ts": "22f2a2bd7f617601ccb329acd01b85a4",
+    "src/hooks/auto-update-checker/index.ts": "ea76c239104a3eaa547b9e800bfdba61",
+    "src/hooks/auto-update-checker/skill-sync.ts": "f5b348860c1f475587717627d24b2378",
+    "src/hooks/auto-update-checker/types.ts": "59800bc1d2a3d189623b56cf49273892",
     "src/hooks/chat-headers.ts": "2586390fd72f4e19da4d06a6e770aa8f",
-    "src/hooks/delegate-task-retry/guidance.ts": "a121a7fc081422351f4d5b2044aa6024",
-    "src/hooks/delegate-task-retry/hook.ts": "14e85deb32a09a3a65d341cb7a438a90",
-    "src/hooks/delegate-task-retry/index.ts": "7b78edb6f10cfee10b2c117ca2287378",
+    "src/hooks/deepwork/index.ts": "ab5a4c49bd2974d9bfed3774da0ae0ca",
+    "src/hooks/delegate-task-retry/hook.ts": "310c87963909ab3f40da5a61a50f5df0",
     "src/hooks/delegate-task-retry/patterns.ts": "5e4919da29af630e4e2ec37df0b58025",
-    "src/hooks/filter-available-skills/index.ts": "4cac7bea2a22f57d602de1df22203baa",
-    "src/hooks/foreground-fallback/index.ts": "b6de8168b13f4c38c5d17fe1686ee62f",
-    "src/hooks/image-hook.ts": "ac70a5c1fed09a250f6d7a91966a3881",
-    "src/hooks/index.ts": "7e7f54a4b02f5a9c57643ffa28fe653a",
-    "src/hooks/json-error-recovery/hook.ts": "55f1268777de23ed5546c8f2f0a5b424",
-    "src/hooks/json-error-recovery/index.ts": "c54900170ea905776e973e30b5dd95f4",
-    "src/hooks/phase-reminder/index.ts": "55c78ab86f3b26a071c8e2f639831b8b",
-    "src/hooks/post-file-tool-nudge/index.ts": "7a23d01b3396c4018015e0e90629c45d",
-    "src/hooks/task-session-manager/index.ts": "a9d701588ceefa4b40454e27c1ed2ea1",
-    "src/index.ts": "fa92b5f3491ff9a2ba8a1ccf3e631ba2",
-    "src/interview/dashboard.ts": "dbe6703d036ff16952c98f5cc0066e5c",
-    "src/interview/document.ts": "c8c35c9042fdef497925c89ce1dba1b4",
+    "src/hooks/filter-available-skills/index.ts": "9be66b5a605e22c7b61ff3089201200d",
+    "src/hooks/foreground-fallback/index.ts": "1aae65cad931221b7d6545f9d285a4d6",
+    "src/hooks/image-hook.ts": "4de4f0267c016f23a6a1ed1869dc976e",
+    "src/hooks/index.ts": "41f1c44b8b5cdbe2e4e0ea9ad634bddd",
+    "src/hooks/json-error-recovery/hook.ts": "6b86f68cdf202725ed856c07de622b62",
+    "src/hooks/phase-reminder/index.ts": "699cb05c721c04204987a613fb3d3253",
+    "src/hooks/post-file-tool-nudge/index.ts": "fd2b3ace9dcb74c024e622f5ff9c3c4e",
+    "src/hooks/reflect/index.ts": "0f000a38f6f365eeeb1761d537168777",
+    "src/hooks/task-session-manager/index.ts": "b4d529be147d25f8d05cb37d1cc4ecbb",
+    "src/hooks/task-session-manager/pending-call-tracker.ts": "4650c2f9bc9ea4b1e13b513989e5fc9e",
+    "src/hooks/task-session-manager/task-context-tracker.ts": "76edc7671beeb4cca127332d2cf5912a",
+    "src/hooks/types.ts": "38ab21f1e4bbe67d0bff116101fec718",
+    "src/index.ts": "7c7c2d10da21705f2653452d0f4f9d8e",
+    "src/interview/dashboard.ts": "6b426f870d383740bdb411003493c442",
+    "src/interview/document.ts": "3a39c23006e7dfce8cf9a3e950e6f4da",
     "src/interview/helpers.ts": "b95a7e299bb4ab38ab66a272b3ba3612",
     "src/interview/index.ts": "ab5c9a50b6c08826cfd53233cac75f38",
-    "src/interview/manager.ts": "62c337961c1e5638c3531c33a097c247",
-    "src/interview/parser.ts": "f555be74e939ac8a0e9eaf8fe2b38e11",
-    "src/interview/prompts.ts": "ff6e3cd2e95c407662b143af8db615fc",
-    "src/interview/server.ts": "486e31b94f0353a838a017510931bc50",
-    "src/interview/service.ts": "5c9031b5b9b94c91f21032b3c275e365",
-    "src/interview/types.ts": "2614f59dcf6fbbf1d7285644f98149a6",
-    "src/interview/ui.ts": "c00692ea35dc56e752f51369b6bfdcbb",
+    "src/interview/manager.ts": "1139da725bf396115968aeb163fd8d2a",
+    "src/interview/parser.ts": "aa6101cf5bebfafcbca845ba532856cf",
+    "src/interview/prompts.ts": "b94ef5117d4e720cb5045080b240d890",
+    "src/interview/server.ts": "fe5230962e2d44c6bec9909049c971f6",
+    "src/interview/service.ts": "5e69ae78f3e4c75d11463d818406420a",
+    "src/interview/types.ts": "411d646f2d515996bf4c88d6797e6aac",
+    "src/interview/ui.ts": "7d37945ca5c837fa305a0121ba8042c7",
     "src/mcp/context7.ts": "4e02e8ef204b6eb7e99a3209078428b5",
-    "src/mcp/grep-app.ts": "f76cb0ffb3484b16d55f27729e80e864",
-    "src/mcp/index.ts": "92464b907264ebd630e12a42ae6eee67",
+    "src/mcp/grep-app.ts": "53dba799724a92e491b57c30cdbd471d",
+    "src/mcp/index.ts": "e9aec0cf22bc802c343caccd25f39fda",
     "src/mcp/types.ts": "a67078f79aa8b99c41fb5be5d9fa9319",
     "src/mcp/websearch.ts": "7c507eff1d6f9c01d3ccb928ea648ca7",
-    "src/multiplexer/factory.ts": "5ca22092bbe54953c620aed005485398",
+    "src/multiplexer/factory.ts": "65b42f20889779cd9cd2ec89f1521f14",
     "src/multiplexer/index.ts": "252b8f5d0d6f8e6c3408eed47791bf67",
-    "src/multiplexer/session-manager.ts": "d8224fb123d1a7073e9c0df768a98335",
-    "src/multiplexer/tmux/index.ts": "7873a9b809fa16f3266d16bc2d8f702c",
+    "src/multiplexer/session-manager.ts": "589609cb19f1dff1c26c32e34609781a",
+    "src/multiplexer/tmux/index.ts": "5f9ffa6c9f4c0d72535e025ea6a5def0",
     "src/multiplexer/types.ts": "2269f67f16fad8f60d92fb389cf3519b",
-    "src/multiplexer/zellij/index.ts": "16b9534fafc904e84faaf862d3a67d37",
+    "src/multiplexer/zellij/index.ts": "f8c7d178aa873b481ac1b0ba1a0b8bdb",
+    "src/skills/clonedeps/README.md": "1e7ee3fb1032ca64141fe133a3af1cc7",
     "src/skills/codemap/README.md": "fbb3e9fd31ae685b87e630df96c3c60a",
     "src/skills/simplify/README.md": "2786c6e4e6b9f972193353b49741c8e3",
+    "src/tools/acp-run.ts": "0f2143e3e7fc75af14b101aa1ef16411",
     "src/tools/ast-grep/cli.ts": "94eea47198f97a4169f009e5249c3f7f",
     "src/tools/ast-grep/constants.ts": "ef016f4d4c5a6861fed9c28e968cad07",
     "src/tools/ast-grep/downloader.ts": "eda4a6bc69a3290a2e54f4d46c639bc1",
     "src/tools/ast-grep/index.ts": "a2e6261cdd8f4ddfd5d89dcd5ad175eb",
-    "src/tools/ast-grep/tools.ts": "3f7c2c65cffd5273b0cd6c849800176d",
+    "src/tools/ast-grep/tools.ts": "a0d7b252fb2240c8e064b495c19e1f26",
     "src/tools/ast-grep/types.ts": "34ad28b5b1e9617b584f082dba9a427c",
     "src/tools/ast-grep/utils.ts": "1dd3b2133c4b8c847a26eea0423bc0b2",
-    "src/tools/council.ts": "965ad3c843761781125da5be502ab43e",
-    "src/tools/index.ts": "a0d1c024ac6519e0db49c0e771c6d95b",
-    "src/tools/preset-manager.ts": "ad0249f2b5d05793b235898a8d361cb4",
+    "src/tools/cancel-task.ts": "fa1a70f89869eb56846effa50845ffe4",
+    "src/tools/council.ts": "303471abd91c423f5ca294fbcd144935",
+    "src/tools/index.ts": "b562a39a524d55c1b0b33041b62437e8",
+    "src/tools/preset-manager.ts": "50367ad256f0d4209569cdb51bef21b1",
     "src/tools/smartfetch/binary.ts": "a65d816f46ebef11c39bda1764f82bb7",
     "src/tools/smartfetch/cache.ts": "9a4e272b897b6914f0925919357bfce1",
     "src/tools/smartfetch/constants.ts": "1ba20e00a4d3f4717eba62f381f9cd4c",
     "src/tools/smartfetch/index.ts": "5bbf7898199c2764351dac4bc0b28b84",
     "src/tools/smartfetch/network.ts": "2b8b3ecaffe1bc4a66c26994bf0afcb6",
-    "src/tools/smartfetch/secondary-model.ts": "83b6d543783bb05ded285da19871f2a4",
+    "src/tools/smartfetch/secondary-model.ts": "a086195fafce7eadc064138f772a4e25",
     "src/tools/smartfetch/tool.ts": "03e91727dc3d408bdb7f751ac647c0de",
     "src/tools/smartfetch/types.ts": "2576efe959365f34b7160c409fb54d26",
     "src/tools/smartfetch/utils.ts": "ab169376765be6079f24f55862d9a90b",
-    "src/utils/agent-variant.ts": "7bf26b256814b18ac04b374586a44c77",
-    "src/utils/compat.ts": "806de91aefa1d164b004c6ca465d8700",
-    "src/utils/env.ts": "b76fbfea11c340337f6bdd8a9c87bb69",
-    "src/utils/index.ts": "670f25ee2b0a191e4af7ffce628dc230",
-    "src/utils/internal-initiator.ts": "64f4189f18ade892f92c0b30188dcd30",
-    "src/utils/logger.ts": "a73dd89ea1e97870b93d3387be122baf",
+    "src/tui-state.ts": "dd8cbf2d515085edc548cdbecfd1ba09",
+    "src/tui.ts": "b475492ec7192ec8109d6acbee3169a5",
+    "src/utils/agent-variant.ts": "6e112fb56a0eef55c8c1dbff3e9d7c8e",
+    "src/utils/background-job-board.ts": "69ecb5da1da658086d4f5c6c3e6a8d1a",
+    "src/utils/compat.ts": "efb1d9db45c0926079cb780e949fb5dd",
+    "src/utils/env.ts": "c4d56b5c308c1047c26d494be45cb86b",
+    "src/utils/guards.ts": "83af4d036dd573e9008f0c1125e4918c",
+    "src/utils/index.ts": "9658d64a4ef4ec45b14b331feaa88f35",
+    "src/utils/internal-initiator.ts": "013b87f387555db563b0241645d638b1",
+    "src/utils/logger.ts": "497874c667bd534ed8effbf046cb09dc",
     "src/utils/polling.ts": "b1d9c52df1fae7391234d0f5476d53b5",
-    "src/utils/session-manager.ts": "8e1e6a41e16bffeec299c715eb4017c5",
-    "src/utils/session.ts": "a6d5dfb749b70bb3b96fee2d0428e1f9",
+    "src/utils/session.ts": "5e99ac85890d4a756585452d0093b82f",
     "src/utils/subagent-depth.ts": "f925bd47ed5ffb67039508bedb14ac25",
-    "src/utils/system-collapse.ts": "e805ef4cf7fdd97316c739756b7f0a96",
-    "src/utils/task.ts": "802eefa5a13ec0bb294a862f5366363e",
+    "src/utils/system-collapse.ts": "05370b9db1a8dbd4ace4958cc807b912",
+    "src/utils/task.ts": "379ec59e07b805ecc4516387a301c9c2",
     "src/utils/zip-extractor.ts": "11e6d1913e049f46099bb61d4a77e62b",
     "tsconfig.json": "1d2bb6e93a43366843785a156c8e538a"
   },
   "folder_hashes": {
-    ".": "c3aff2cb0efa4fafbc9d620ecc930e73",
-    "scripts": "7ebdcbc44fd1e155c3ef2cc3baecb925",
-    "src": "b02fb0301ebce2f90dc183bc31378f58",
-    "src/agents": "20a86940e26e67b4401b185542fabb41",
-    "src/cli": "1b78a40dfdd03912f257532127f810b4",
-    "src/config": "911b54439938cefeb9e2734d131dff4c",
-    "src/council": "02508e6e9fd78d68b4e5e25e0bc58a6c",
-    "src/hooks": "cde4c1076282de769271e6975659f95e",
-    "src/hooks/apply-patch": "d3bd03747a4c2ecd199fb68706d4c8d2",
-    "src/hooks/auto-update-checker": "c407065b8052ab293b8c78e643a19297",
-    "src/hooks/delegate-task-retry": "c2c138123a5bea46d53ded27049e0002",
-    "src/hooks/filter-available-skills": "42214100c13e02e3b197f1e7cb1b586a",
-    "src/hooks/foreground-fallback": "deaf94fe467f76ef44535beedea50f6e",
-    "src/hooks/json-error-recovery": "c8a245f5f48918279aa3d7724a573c75",
-    "src/hooks/phase-reminder": "80f01bd7edd895fcd3950a44b21a4d3a",
-    "src/hooks/post-file-tool-nudge": "e01c0aa6e649ec049c068d6a1b2006f9",
-    "src/hooks/task-session-manager": "0c73238a14d84eb1d204f9cc0044180d",
-    "src/interview": "3920f8d94c932173803d6fdd8506b9b3",
-    "src/mcp": "5f5fc5fbb54bf9944063483cee8be88f",
-    "src/multiplexer": "f543dda4ba0043e6c5e4ea0c07e11a77",
-    "src/multiplexer/tmux": "796d0d51b317bdb05c54dcf257fb5597",
-    "src/multiplexer/zellij": "35ab5e99b43ac4da5a085d1e331da37b",
-    "src/skills": "c93b75814e75bc85966fba4513b81b24",
+    ".": "46a9e1a263dccb4e1d175d9ae3610b38",
+    "scripts": "ef995a5bcb4a311c670cfc53bf6c169d",
+    "src": "6770ae70da9bf9043f75f2b5dc254796",
+    "src/agents": "b4baa555e356b548e3333caf6984c441",
+    "src/cli": "e4c5d373ed083b765e1826c7e74b6864",
+    "src/companion": "1b6f2aa30c60de428b60005f62a42bac",
+    "src/config": "b1a4248f255324af18c182004b6c00d9",
+    "src/council": "0a5229eb3778c0497e1d0b989dd4d8c5",
+    "src/hooks": "fa6d6583be8b609745b603ff3085e1c3",
+    "src/hooks/apply-patch": "d20e3c103082283c3c126b7e936bc041",
+    "src/hooks/auto-update-checker": "7b296221c92eafe16f39818b544740c1",
+    "src/hooks/deepwork": "4698a85b598d3158d038313680762c1b",
+    "src/hooks/delegate-task-retry": "7bd4abeb2dbfc4e7aaed701de08b7509",
+    "src/hooks/filter-available-skills": "d27655bbe7a8a807367eb8aa2cdbfdb7",
+    "src/hooks/foreground-fallback": "caa7388b788f230ebba7512fc815530d",
+    "src/hooks/json-error-recovery": "fbe725b787123f203b78dd8dfd47db67",
+    "src/hooks/phase-reminder": "91decaaf41bd64430a7d24f5d3780a51",
+    "src/hooks/post-file-tool-nudge": "7e271eb8f0f7fe6259d878ae610c2990",
+    "src/hooks/reflect": "88bba64c2989d7c70a9188edc2e80f47",
+    "src/hooks/task-session-manager": "365429564ba1d1ec58247e9b748d3d3d",
+    "src/interview": "423eecf5cf02812b95b81e8374a2eceb",
+    "src/mcp": "1db30ec46ae0b577ec22b74e2b4d19ea",
+    "src/multiplexer": "1858ddff246c97ee920b09825750eca0",
+    "src/multiplexer/tmux": "b36a4e4636d659afc9f326aa263251b9",
+    "src/multiplexer/zellij": "4ac57e1d5fdd9368abd8b138ea82db62",
+    "src/skills": "3afb58b43174496617ece428d8deb50d",
+    "src/skills/clonedeps": "d1d19753438fdb845f4efca93314a147",
     "src/skills/codemap": "1e82ef833612703b786daceb091f2422",
     "src/skills/simplify": "9c745d8113135e3103af5f1a49d67dfe",
-    "src/tools": "028b6df5f9ed6b309f7b67317ec3f2f9",
-    "src/tools/ast-grep": "2d4ad34fd02c6d068766dd38e826f2a8",
-    "src/tools/smartfetch": "ff5047fb784b3d868e3908099591a117",
-    "src/utils": "5e4fae8a6e05d3506f79edda3211ffe9"
+    "src/tools": "cc6bb384c43c6dd7fdc00476310ecec4",
+    "src/tools/ast-grep": "7091c20c0d028c22effa2b5c1e64cc58",
+    "src/tools/smartfetch": "b71f3f9464bb203a3ae3a4521eea01a6",
+    "src/utils": "513c051e502068a189e56a9fff73a252"
   }
 }

+ 10 - 9
codemap.md

@@ -2,16 +2,16 @@
 
 ## Project Responsibility
 
-`oh-my-opencode-slim` is an OpenCode plugin that adds a specialist-agent operating model on top of the host runtime. Its core job is to:
+`oh-my-opencode-slim` is an OpenCode plugin that implements a specialist-agent operating model on top of the host runtime. Its core responsibilities include:
 
-- define orchestrator and specialist agents,
-- load layered plugin configuration and per-agent permissions,
-- expose additional tools and MCP integrations,
-- manage background job-board orchestration and terminal multiplexer visualization,
-- inject workflow-enforcement hooks plus runtime command handlers,
-- ship install-time skills and a bootstrap CLI.
+- Defining orchestrator and specialist agent factories with permission policies
+- Loading layered plugin configuration and per-agent permissions
+- Exposing additional tools and MCP integrations
+- Managing background job-board orchestration and terminal multiplexer visualization
+- Injecting workflow-enforcement hooks plus runtime command handlers
+- Shipping install-time skills and a bootstrap CLI
 
-This codemap intentionally covers the plugin repository itself and excludes the nested `opencode/` upstream checkout.
+This codemap covers the plugin repository itself and excludes the nested `opencode/` upstream checkout.
 
 ## System Entry Points
 
@@ -102,6 +102,7 @@ This codemap intentionally covers the plugin repository itself and excludes the
 - `biome.json`: formatting/lint policy.
 - `tsconfig.json`: TypeScript compiler settings.
 - `.slim/codemap.json`: codemap change-detection state for this repository.
+- `scripts/verify-release-artifact.ts`: release artifact validation script.
 
 ## Recommended Reading Order
 
@@ -112,4 +113,4 @@ This codemap intentionally covers the plugin repository itself and excludes the
    - `src/multiplexer/codemap.md`
    - `src/tools/codemap.md`
    - `src/hooks/codemap.md`
-4. Relevant subsystem sub-map for the task at hand
+4. Relevant subsystem sub-map for the task at hand

+ 182 - 100
src/agents/codemap.md

@@ -1,108 +1,190 @@
-# Agents Directory Codemap
+# src/agents/
 
 ## Responsibility
 
-`src/agents/` defines built-in specialists plus custom agents and converts
-configuration into OpenCode SDK registration data.
-
-Responsibilities:
-
-- Build orchestrator and specialist agent definitions from factory functions.
-- Resolve overrides for model, variant, temperature, options, prompt, and display
-  name.
-- Normalize/validate custom agent names and custom-orchestrator-facing aliases.
-- Compose permissions, MCP allow-lists, and visibility metadata for OpenCode.
-
-## Core architecture
-
-### Construction flow (`createAgents`)
-
-1. Compute the disabled set via `getDisabledAgents()`:
-   - from `config.disabled_agents`
-   - with protected-agent guard (`orchestrator`, `councillor` never disabled)
-2. Build built-in subagents from `SUBAGENT_FACTORIES` (`SUBAGENT_NAMES`).
-3. Discover custom agent names from `config.agents` keys that are not built-ins
-   or aliases.
-4. Validate custom names (`/^[a-z][a-z0-9_-]*$/i`) and model presence:
-   skip with warning if `model` missing.
-5. Load prompt files for each agent:
-   - `<agent>.md` replacement prompt
-   - `<agent>_append.md` append prompt
-6. Apply override handling:
-   - string model → `config.model`
-   - array model → `agent._modelArray` and clear `config.model`
-   - merge `temperature`, `variant`, `options`, `displayName`.
-7. Apply permission defaults per agent (`applyDefaultPermissions`).
-8. Apply compatibility fallbacks:
-   - `fixer` may inherit `librarian` model when not explicitly configured.
-   - `council` may inherit deprecated `council.master.model` when no explicit
-     `council` override and default remains unresolved.
-9. Build orchestrator using prompt files + disabled-agent filtering.
-10. Normalize/collect display names and inject `@displayName` references into:
-    orchestrator prompt and all custom `orchestratorPrompt` snippets.
-11. Validate display-name collisions/agent-name conflicts.
-12. Return `[orchestrator, ...subagents]`.
-
-### Runtime model behavior
-
-- `_modelArray` is used as the ordered runtime failover chain when supplied.
-- `orchestrator` may start unresolved (`model` undefined) to allow downstream
-  runtime resolution.
-- `subagent` overrides preserve per-model variants inside `_modelArray` while
-  optionally keeping top-level `variant` as default fallback.
-
-## Delegation and registration semantics
-
-- `getAgentConfigs(config)` converts definitions to SDK configs and sets:
-  - `orchestrator` → `mode: primary`
-  - built-in specialists → `mode: subagent`
-  - `council` → `mode: all`
-  - `councillor` → `mode: subagent`, `hidden: true`
-- If `displayName` is set:
-  - internal key remains registered but hidden
-  - host-facing key becomes normalized display name
-
-Permission defaults:
-
-- `question` defaults to `allow` unless existing explicit deny.
-- `council_session` defaults to `allow` only for `council`.
-- Nested `skill` permissions come from `getSkillPermissionsForAgent` and are
-  merged with existing permission maps.
-
-## Capability and policy inputs
-
-- MCP allow-lists:
-  - `getAgentMcpList(name, config)` from `src/config/agent-mcps.ts`
-  - `agent-mcps` defaults in `src/config/agent-mcps.ts`
-- Agent metadata/aliases:
-  - `AGENT_ALIASES`, `SUBAGENT_NAMES`, `PROTECTED_AGENTS`
-  - `getAgentOverride`, `getCustomAgentNames` from `src/config/utils.ts`
-- Skills:
-  - `cli/skills.ts`
-
-## Flow and integration
-
-```text
-src/index.ts
-  └─> loadPluginConfig()
-      └─> createAgents(config) / getAgentConfigs(config)
-          └─> registration + runtime chat hooks
-
-  loadPluginConfig()
-    └─> prompt overrides + presets
-        └─> createAgents/create custom/orchestrator prompts
+Defines agent personalities (Orchestrator, Explorer, Librarian, etc.) and manages their configuration lifecycle. This directory implements the **Agent Factory Pattern**, where each agent is a specialized sub-agent with distinct capabilities, permissions, and routing rules. The Orchestrator agent (src/agents/index.ts) coordinates task delegation to these specialists.
+
+## Design
+
+### Agent Types and Factories
+
+Each agent is a **prompt-driven specialist** with a factory function that creates an `AgentDefinition`:
+
+| Agent | Factory | Role | Permissions | Model Default |
+|-------|---------|------|-------------|---------------|
+| **orchestrator** | `createOrchestratorAgent()` | Workflow manager that delegates tasks to specialists | Primary agent with full tool access | Resolved from config or runtime preset |
+| **explorer** | `createExplorerAgent()` | Fast codebase search and pattern matching | Read-only (glob, grep, ast_grep_search) | DEFAULT_MODELS.explorer |
+| **librarian** | `createLibrarianAgent()` | External documentation and library research | Read-only (context7, gh_grep, websearch) | DEFAULT_MODELS.librarian |
+| **oracle** | `createOracleAgent()` | Strategic technical advisor and code reviewer | Read-only (read, glob, grep, ast_grep_search) | DEFAULT_MODELS.oracle |
+| **designer** | `createDesignerAgent()` | UI/UX design, review, and implementation | Read/write (read, glob, grep, write, edit) | DEFAULT_MODELS.designer |
+| **fixer** | `createFixerAgent()` | Fast implementation specialist for bounded tasks | Read/write (read, glob, grep, write, edit) | DEFAULT_MODELS.fixer |
+| **observer** | `createObserverAgent()` | Visual analysis specialist (images, PDFs, diagrams) | Read-only (read, glob, grep, ast_grep_search) | DEFAULT_MODELS.observer |
+| **council** | `createCouncilAgent()` | Multi-LLM consensus engine for high-stakes decisions | Read-only + council_session tool | DEFAULT_MODELS.council |
+| **councillor** | `createCouncillorAgent()` | Read-only council advisor (internal use only) | Read-only (read, glob, grep, ast_grep_search) | Inherited from council |
+
+### Configuration System
+
+- **Default prompts**: Each agent factory has a base prompt defined in its file (e.g., `explorer.ts`, `oracle.ts`)
+- **User overrides**: From `~/.config/opencode/oh-my-opencode-slim.json` via `loadAgentPrompt()`
+- **Permission wildcards**: Applied via `applyDefaultPermissions()` in `index.ts`
+- **Model resolution**: Supports both string models and priority-ordered arrays (`_modelArray`) for runtime fallback
+- **Skill permissions**: Per-agent MCP and tool access controlled via `getSkillPermissionsForAgent()`
+
+### Agent Lifecycle
+
+1. **Agent creation**: `createAgents(config)` instantiates all agents with merged configuration
+2. **Permission application**: `applyDefaultPermissions()` sets read/write permissions based on agent type
+3. **Display name injection**: Orchestrator prompt rewrites `@agent` mentions to user-configured display names
+4. **Configuration export**: `getAgentConfigs()` converts `AgentDefinition` to OpenCode SDK format with classification metadata
+
+## Flow
+
+### Agent Instantiation Sequence (src/agents/index.ts)
+
+```typescript
+// 1. Gather sub-agent definitions with custom prompts
+const protoSubAgents = Object.entries(SUBAGENT_FACTORIES)
+  .filter(([name]) => !disabled.has(name))
+  .map(([name, factory]) => {
+    const customPrompts = loadAgentPrompt(name, config?.preset);
+    return factory(getModelForAgent(name), customPrompts.prompt, customPrompts.appendPrompt);
+  });
+
+// 2. Apply overrides and default permissions
+const builtInSubAgents = protoSubAgents.map((agent) => {
+  const override = getAgentOverride(config, agent.name);
+  if (override) applyOverrides(agent, override);
+  applyDefaultPermissions(agent, override?.skills, config?.disabled_skills);
+  return agent;
+});
+
+// 3. Create Orchestrator (with its own overrides and custom prompts)
+const orchestrator = createOrchestratorAgent(
+  orchestratorModel,
+  orchestratorPrompts.prompt,
+  orchestratorPrompts.appendPrompt,
+  disabled,
+);
+applyDefaultPermissions(orchestrator, orchestratorOverride?.skills, config?.disabled_skills);
+
+// 4. Collect display names and inject into orchestrator prompt
+const displayNameMap = new Map<string, string>();
+// ... populate from orchestrator and all subagents ...
+injectDisplayNames(orchestrator, displayNameMap);
+
+// 5. Return agents array [orchestrator, ...allSubAgents]
+return [orchestrator, ...allSubAgents];
 ```
 
-## Utilities and helpers
+### Agent Configuration Export
+
+```typescript
+export function getAgentConfigs(config?: PluginConfig): Record<string, SDKAgentConfig> {
+  const agents = createAgents(config);
+  
+  const applyClassification = (name: string, sdkConfig: SDKAgentConfig) => {
+    if (name === 'council') {
+      sdkConfig.mode = 'all'; // Primary + subagent
+    } else if (name === 'councillor') {
+      sdkConfig.mode = 'subagent';
+      sdkConfig.hidden = true; // Internal only
+    } else if (isSubagent(name)) {
+      sdkConfig.mode = 'subagent';
+    } else if (name === 'orchestrator') {
+      sdkConfig.mode = 'primary';
+    }
+  };
+  
+  // Build SDK config with classification and MCP permissions
+  const entries: Array<[string, SDKAgentConfig]> = [];
+  for (const a of agents) {
+    const sdkConfig = { ...a.config, description: a.description };
+    applyClassification(a.name, sdkConfig);
+    
+    // Handle display names: create both displayName and hidden alias
+    if (a.displayName) {
+      entries.push([normalizeDisplayName(a.displayName), sdkConfig]);
+      entries.push([a.name, { ...sdkConfig, hidden: true }]);
+    } else {
+      entries.push([a.name, sdkConfig]);
+    }
+  }
+  
+  return Object.fromEntries(entries);
+}
+```
+
+### Model Resolution and Fallback
+
+- **Priority arrays**: When `model` is configured as an array in user config, it's stored as `_modelArray`
+- **Runtime fallback**: ForegroundFallbackManager resolves models at runtime when API errors occur
+- **Preset overrides**: Runtime presets can override model/variant/temperature per agent
+
+## Integration
 
-- `isSubagent(name)` — type guard for subagent names.
-- `getDisabledAgents(config)` and `getEnabledAgentNames(config)`.
-- `resolvePrompt()` in `orchestrator.ts` centralizes replacement vs append behavior.
+### Consumed by src/index.ts
 
-## File structure
+The main plugin entry point (`src/index.ts`) consumes the agent system:
+
+```typescript
+import { createAgents, getAgentConfigs, getDisabledAgents } from './agents';
+
+// During plugin initialization:
+const disabledAgents = getDisabledAgents(config);
+const agentDefs = createAgents(config);
+const agents = getAgentConfigs(config);
+
+// Register with OpenCode SDK
+return {
+  name: 'oh-my-opencode-slim',
+  agent: agents, // SDK agent configs
+  tool: tools,  // Tools including council tools
+  mcp: mcps,    // MCP servers
+  config: async (opencodeConfig) => { /* merge agent configs */ },
+  event: async (input) => { /* session tracking, TUI state */ },
+};
+```
 
-- `index.ts` (agent registry, overrides, classification, custom agents)
-- `orchestrator.ts` (base prompts, prompt resolution, model-array type)
-- `council.ts`, `councillor.ts` (council tool orchestration + formatting)
-- `explorer.ts`, `librarian.ts`, `oracle.ts`, `designer.ts`, `fixer.ts`,
-  `observer.ts` (specialist factory prompts/config)
+### Key Integration Points
+
+1. **Agent selection**: OpenCode selects the orchestrator as the primary agent
+2. **Task delegation**: Orchestrator uses `task()` with `subagent_type` to delegate to specialists
+3. **Session tracking**: `sessionAgentMap` tracks which agent owns each session for TUI prompts
+4. **Model resolution**: ForegroundFallbackManager handles runtime model switching for rate limits
+5. **Permission system**: MCP permissions are injected based on agent's `mcps` list
+
+### Routing Rules (src/agents/orchestrator.ts)
+
+The orchestrator's system prompt contains dynamic routing rules that reference agent capabilities:
+
+- **@explorer**: Fast codebase recon, parallel searches
+- **@librarian**: Library research, web search
+- **@oracle**: Architecture decisions, code review
+- **@designer**: UI/UX design and polish
+- **@fixer**: Bounded implementation tasks
+- **@observer**: Visual/media analysis
+- **@council**: Multi-model consensus for high-stakes decisions
+
+These rules are filtered based on disabled agents and injected into the orchestrator's prompt at startup.
+
+## File Structure
+
+- `index.ts` - Main agent factory and configuration system
+- `orchestrator.ts` - Orchestrator agent definition and prompt builder
+- `explorer.ts` - Fast codebase search specialist
+- `librarian.ts` - Documentation and library research specialist
+- `oracle.ts` - Architecture and code review specialist
+- `designer.ts` - UI/UX design specialist
+- `fixer.ts` - Implementation execution specialist
+- `observer.ts` - Visual analysis specialist
+- `council.ts` - Multi-LLM council agent
+- `councillor.ts` - Read-only council advisor (internal)
+- `permissions.ts` - Permission factory for read-only agents
+
+## Design Patterns
+
+- **Factory Pattern**: Each agent has a factory function that creates its `AgentDefinition`
+- **Strategy Pattern**: Different agents implement different strategies for different tasks
+- **Decorator Pattern**: Configuration decorators (overrides, permissions, display names) wrap agent definitions
+- **Observer Pattern**: Session tracking via `sessionAgentMap` and event handlers
+- **Chain of Responsibility**: Task delegation flows from orchestrator to specialists

+ 147 - 56
src/cli/codemap.md

@@ -1,77 +1,168 @@
-# CLI Module Codemap
+# src/cli/
 
 ## Responsibility
 
-`src/cli/` provides the plugin installation workflow and the utilities that generate and persist runtime configuration.
-
-Current responsibilities:
-
-- parse/install command arguments
-- install-time validation and environment checks
-- OpenCode configuration mutation (atomic)
-- lite config generation for provider/agent presets
-- optional skill installation and bundled-skill copying
+CLI entry point and command-line interface for the oh-my-opencode-slim plugin. Provides installation, configuration, and diagnostic commands for setting up and managing the OpenCode plugin.
 
 ## Design
 
-### Command surface
+The CLI follows a command pattern with two primary commands:
+- `install`: Sets up the plugin with OpenCode (adds plugin to config, configures background subagents, installs companion, writes configuration)
+- `doctor`: Diagnoses plugin configuration issues and validates setup
 
-- `src/cli/index.ts` only dispatches:
-  - `install` subcommand and flags
-    - `--skills=yes|no`
-    - `--preset=<name>`
-    - `--no-tui`
-    - `--dry-run`
-    - `--reset`
-    - `--help`
+### Architecture Pattern: Command Router
+- **index.ts**: Routes CLI arguments to appropriate command handlers
+- **install.ts**: Orchestrates multi-step installation workflow
+- **doctor.ts**: Validates configuration and environment
 
-The CLI is intentionally non-interactive-only now; it prints usage and steps to stdout with exit codes.
+### Configuration Management Pattern
+- **config-io.ts**: Handles reading, parsing, and writing configuration files (supports both .json and .jsonc)
+- **paths.ts**: Resolves configuration file paths across different environments (XDG_CONFIG_HOME, custom paths, defaults)
+- **providers.ts**: Generates configuration presets and manages model mappings for different providers
 
-### Module decomposition
+### Permission and Skill Management
+- **custom-skills.ts**: Registry of custom skills bundled with the plugin and their installation logic
+- **skills.ts**: Agent permission management for skills (allow/ask/deny rules)
 
-- `paths.ts`: config directory and file discovery (`opencode.json`/`.jsonc`, lite config path).
-- `config-io.ts`: JSON/JSONC parsing, normalize write behavior, atomic writes (`.tmp` + `.bak`), plugin registration, default-agent disabling.
-- `providers.ts`: provider model mapping + `generateLiteConfig()`.
-- `system.ts`: OpenCode binary/version/path checks.
-- `skills.ts`: bundled and permission-only skill permission defaults.
-- `custom-skills.ts`: bundled skill registry and copy-to-config-directory implementation.
-- `config-manager.ts`: re-export barrel for CLI config utilities.
-- `install.ts`: end-to-end install orchestration and console messaging.
-- `types.ts`: install/config DTOs.
+### Integration Management
+- **background-subagents.ts**: Shell integration for OpenCode background subagents (persistent agent processes)
+- **companion.ts**: Desktop companion binary installation and management
 
 ## Flow
 
-```text
-CLI install command
-  └─> install.ts (runInstall)
-      1) check OpenCode installed
-      2) add plugin entry to main OpenCode config
-      3) disable legacy default agents
-      4) write/preview generated lite config
-      5) optional install phase:
-         - installCustomSkill(...) for each CUSTOM_SKILL
+### Command Flow: CLI Entry Point
+```
+1. CLI invoked (bunx oh-my-opencode-slim install/doctor)
+2. index.ts parses arguments and routes to command handler
+3. Command handler executes workflow
+   - install: Runs multi-step installation process
+   - doctor: Runs diagnostic checks
+```
+
+### Installation Workflow (install.ts)
+```
+1. Parse install arguments (preset, companion mode, background subagents, etc.)
+2. Check OpenCode installation
+3. Add plugin to OpenCode configuration (opencode.json/opencode.jsonc)
+4. Add TUI version badge (tui.json/tui.jsonc)
+5. Warm OpenCode plugin cache (for package manager installations)
+6. Disable OpenCode default agents (explore, general)
+7. Enable LSP integration by default
+8. Configure background subagents (shell integration)
+9. Install desktop companion (optional)
+10. Write oh-my-opencode-slim configuration (oh-my-opencode-slim.json)
+11. Install custom skills (if requested)
 ```
 
-`generateLiteConfig(installConfig)` behavior:
+### Configuration Resolution Flow (paths.ts)
+```
+1. Determine config directory:
+   - OPENCODE_CONFIG_DIR environment variable (highest priority)
+   - XDG_CONFIG_HOME/opencode
+   - ~/.config/opencode (default)
+2. Resolve file paths:
+   - opencode.json → opencode.jsonc → fallback to opencode.json
+   - oh-my-opencode-slim.json → oh-my-opencode-slim.jsonc → fallback
+   - tui.json → tui.jsonc → fallback
+```
 
-- sets `$schema`, a selected `preset` that defaults to `openai`
-- always materializes generated presets `openai` and `opencode-go`
-- install-time `--preset` only selects between generated presets
-- maps each built-in agent name to provider-specific model/variant
-- injects skill list from bundled custom skill registries
-- injects default MCP sets from `DEFAULT_AGENT_MCPS`
-- includes tmux block (`layout`, `main_pane_size`) when enabled
+### Configuration Generation Flow (providers.ts)
+```
+1. Generate configuration presets for supported providers:
+   - openai (default)
+   - opencode-go
+   - kimi
+   - copilot
+   - zai-plan
+2. Map agents to models with variants:
+   - orchestrator → high-capacity model
+   - oracle → high variant
+   - librarian/explorer → low variant
+   - designer → medium variant
+   - fixer → low variant
+3. Apply skill permissions based on agent role
+4. Generate final configuration with schema URL
+```
 
-`writeLiteConfig()` writes target file atomically and supports `--reset`/dry-run branching in `install.ts`.
+### Background Subagents Integration (background-subagents.ts)
+```
+1. Detect shell type (bash/zsh/fish)
+2. Determine target file:
+   - bash/zsh: ~/.bashrc or ~/.zshrc
+   - fish: ~/.config/fish/conf.d/opencode-background-subagents.fish
+3. Write environment variable export:
+   - export OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true
+4. Persist across shell sessions
+```
 
-## Runtime integration
+## Integration
 
-- Output file produced by install (`oh-my-opencode-slim.json`) is consumed by runtime `config/loader.ts`.
-- Permission defaults for installed/available skills are shared with `agents/index.ts` via `cli/skills.ts`.
-- Generated provider/multiplexer settings are consumed by OpenCode session runtime via `src/index.ts` bootstrap.
+### Consumed By
+- **Main plugin**: src/index.ts loads CLI entry point via plugin initialization
+- **OpenCode**: CLI commands are invoked by OpenCode's plugin system
+
+### Dependencies
+- **Config system**: src/config/ - Configuration loading and validation
+- **Skills**: src/skills/ - Bundled custom skills registry
+- **Companion**: src/companion/ - Desktop companion binary management
+- **Utils**: src/utils/ - Cross-platform compatibility utilities
+
+### Integration Points
+- **OpenCode plugin system**: CLI commands integrate via OpenCode's command execution
+- **Shell environment**: Background subagents modify shell startup files
+- **Configuration files**: Atomic writes to user config directory (~/.config/opencode/)
+- **Desktop companion**: Optional binary installation and configuration
+
+### Permission Model
+- **Orchestrator agent**: Granted all skills by default
+- **Other agents**: Restricted permissions, explicit allow rules from custom skills registry
+- **External skills**: Permission-only entries for skills not installed by CLI
+
+
+### Configuration Files
+| File | Purpose | Written By |
+|------|---------|------------|
+| opencode.json/opencode.jsonc | OpenCode main config | config-io.ts |
+| tui.json/tui.jsonc | OpenCode TUI config | config-io.ts |
+| oh-my-opencode-slim.json | Plugin-specific config | providers.ts |
+
+## Commands
+
+### `install` Command
+Sets up oh-my-opencode-slim plugin with OpenCode.
+
+**Usage:**
+```bash
+bunx oh-my-opencode-slim install [OPTIONS]
+```
+
+**Options:**
+- `--skills=yes|no`: Install bundled skills (default: yes)
+- `--companion=ask|yes|no`: Install desktop companion (default: ask)
+- `--preset=<name>`: Select configuration preset (default: openai)
+- `--background-subagents=ask|yes|no`: Configure background subagents (default: ask)
+- `--background-subagents-target=<path>`: Specify shell startup file
+- `--no-tui`: Non-interactive mode
+- `--dry-run`: Simulate installation
+- `--reset`: Force overwrite existing configuration
+- `-h, --help`: Show help
+
+**Available presets:** openai, opencode-go, kimi, copilot, zai-plan
+
+### `doctor` Command
+Diagnoses plugin configuration and environment.
+
+**Usage:**
+```bash
+bunx oh-my-opencode-slim doctor [OPTIONS]
+```
 
-## Notes for architecture/docs accuracy
+**Options:**
+- `--json`: Print diagnostics as JSON
+- `-h, --help`: Show help
 
-- The previous TUI references are stale; no dedicated interactive flow exists in current sources.
-- `--skills` controls bundled/custom skill installation only.
-- Built-in preset support includes `openai`, `opencode-go`, `kimi`, `copilot`, and `zai-plan`.
+**Checks:**
+- Configuration file validity (user and project scopes)
+- Preset existence and configuration
+- JSON schema validation
+- File existence and permissions

+ 157 - 28
src/codemap.md

@@ -2,40 +2,169 @@
 
 ## Responsibility
 
-- `src/index.ts` delivers the plugin assembly layer: it loads configuration, resolves agent definitions, precomputes runtime model fallback chains, wires multiplexer/session orchestration, registers tools/MCPs/hooks, and returns the OpenCode plugin registration object.
-- `config/`, `agents/`, `tools/`, `multiplexer/`, `hooks/`, and `utils/` contain the reusable building blocks (loader/schema/constants, agent factories/permission helpers, tool factories, session mirroring managers, hook implementations, and runtime utilities) that power that entry point.
-- `hooks/task-session-manager` is now part of the core plugin flow to support background job-board tracking, concise aliases, and reminder injection for orchestrator calls.
-- `cli/` remains the installer surface (argument parsing, interactive prompts, config edits, skill/provider installation).
+Core plugin implementation for **oh-my-opencode-slim**, providing:
+- Main plugin initialization and OpenCode integration (`index.ts`)
+- Terminal User Interface (TUI) sidebar plugin for agent status display (`tui.ts`)
+- TUI state persistence and synchronization across sessions (`tui-state.ts`)
+
+This directory serves as the primary entry point for the plugin's runtime behavior, configuration system, and user-facing UI components.
 
 ## Design
 
-- Agent creation follows explicit factories (`agents/index.ts`, per-agent creators under `agents/`) with override/permission helpers (`config/schema.ts`, `cli/skills.ts`, `config/agent-mcps.ts`) so defaults live in `config/constants.ts`, prompts can be swapped via `config/loader.ts`, and variant labels propagate through `utils/agent-variant.ts`.
-- Session orchestration combines `SubagentDepthTracker`, `BackgroundJobBoard`, `MultiplexerSessionManager`, `CouncilManager`, and `ForegroundFallbackManager`; these coordinate subagent depth limits, background task state, pane lifecycle, council session creation, and foreground model failover.
-- Hook composition is centralized in `src/index.ts`: lifecycle event handlers and tool transform handlers fan out to specialized hooks, then some hooks post-process system messages in-place for provider compatibility.
-- Supplemental tools bundle AST-grep search/replace, council orchestration, and web fetching behind the OpenCode `tool` interface and are mounted in `index.ts` alongside hooks and MCP helpers.
+### Architectural Patterns
+
+- **Plugin Pattern**: The plugin follows OpenCode's plugin architecture with a single exported plugin function that returns agent, tool, and MCP registrations
+- **Facade Pattern**: `index.ts` acts as a facade that composes multiple subsystems (agents, tools, MCPs, hooks, multiplexer)
+- **Observer Pattern**: Event-driven architecture using OpenCode's event system for session lifecycle, message updates, and tool execution
+- **Strategy Pattern**: Runtime model selection and fallback via `ForegroundFallbackManager`
+- **Singleton Pattern**: `MultiplexerSessionManager` maintains single instance for task session management
+
+### Data Flow
+
+```
+OpenCode Core → Plugin Initialization (index.ts)
+  → Agent Registration (createAgents/getAgentConfigs)
+  → Tool Registration (createCouncilTool, createCancelTaskTool, etc.)
+  → MCP Registration (createBuiltinMcps)
+  → Hook Registration (auto-update, phase reminders, etc.)
+  → Event Subscription (session lifecycle, message updates, tool execution)
+  → Runtime State Tracking (tui-state.ts)
+  → TUI Rendering (tui.ts → sidebar_content slot)
+```
+
+### Key Components
+
+| File | Role | Dependencies |
+|------|------|--------------|
+| `index.ts` | Main plugin entry, orchestrates all subsystems | Config system, agent factories, tool creators, multiplexer |
+| `tui.ts` | TUI sidebar plugin for agent model display | tui-state.ts, config constants |
+| `tui-state.ts` | Persistent state management for TUI | Node.js fs/promises, os module |
 
 ## Flow
 
-- Startup:
-  - `loadPluginConfig` builds effective config from user/project presets.
-  - `createAgents` + `getAgentConfigs` construct final agent registry and resolved prompts.
-  - Runtime model chains are built from `_modelArray` entries (when users configure `model` as an array in `agents.<name>`).
-  - `SubagentDepthTracker`, shared `BackgroundJobBoard`, `MultiplexerSessionManager`, `CouncilManager`, `ForegroundFallbackManager`, and hook factories are initialized before registration.
-- Plugin registration: `index.ts` merges/overlays agent configs into OpenCode's config, registers tools (`council`, `webfetch`, `ast_grep_*`, todo tools), MCPs (`createBuiltinMcps`), and all hook handlers (`event`, `tool.execute.before/after`, `experimental.chat.system/messages.transform`, `command.execute.before`, etc.).
-- Runtime event flow (`event`): updates depth tree, multiplexer pane state, auto-update checks, interview/preset state, and task-session cleanup for deleted sessions.
-- `experimental.chat.system.transform` pipeline:
-  - injects orchestrator/system-level reminders when required,
-  - applies task/session prompt enrichment from `task-session-manager`,
-  - collapses all system entries into one message via `collapseSystemInPlace` for providers that reject multi-message system arrays.
-- `tool.execute.before/after` (`task`): records pending task calls, resolves short aliases to canonical IDs, parses outputs for new task IDs, and updates/removes remembered sessions.
-- CLI flow: `cli/install.ts` parses flags, optionally prompts, checks OpenCode installation, updates config via `cli/config-io.ts` and `cli/paths.ts`, disables default agents, writes lite config, and installs skills (`cli/skills.ts`, `cli/custom-skills.ts`).
+### Plugin Initialization Flow (index.ts)
+
+1. **Config Loading**: `loadPluginConfig()` reads and validates plugin configuration
+2. **Agent Creation**: `createAgents()` instantiates agent definitions with prompts and permissions
+3. **Agent Configuration**: `getAgentConfigs()` merges defaults with user overrides and runtime presets
+4. **Tool Registration**: Tools are created conditionally based on config (council, cancel_task, webfetch, AST-grep)
+5. **MCP Registration**: Built-in MCPs are created (filesystem, resource, tools, etc.)
+6. **Multiplexer Setup**: Multiplexer session manager initialized for task tool sessions
+7. **Hook Initialization**: Auto-update checker, phase reminders, skill filters, etc.
+8. **Runtime Model Resolution**: Resolves model arrays to single models for startup
+9. **TUI State Sync**: `recordTuiAgentModels()` captures resolved models/variants for TUI display
+10. **Health Check**: Validates minimum agent/tool/MCP registrations
+11. **Companion Management**: Ensures companion version compatibility
+
+### TUI Rendering Flow (tui.ts)
+
+1. **Plugin Registration**: TUI plugin registered with OpenCode's TUI system via `tui` export
+2. **Version Detection**: Reads plugin version from package.json or uses 'dev'
+3. **Config Validation**: Checks if current directory has valid plugin config
+4. **Snapshot Loading**: Reads agent models/variants from `tui-state.ts`
+5. **Live Updates**: Sets up interval to refresh snapshot every 1000ms
+6. **Sidebar Rendering**: Renders sidebar with:
+   - Plugin header (OMO-Slim + version)
+   - Config status warning (if invalid)
+   - Agent list with model/variant details
+7. **Lifecycle Management**: Cleans up interval on dispose
+
+### State Persistence Flow (tui-state.ts)
+
+1. **State Path Resolution**: Determines XDG-compliant state directory (`~/.local/share/opencode/storage/oh-my-opencode-slim/tui-state.json`)
+2. **Snapshot Operations**:
+   - `readTuiSnapshot()`: Reads and parses state file (returns empty snapshot on error)
+   - `readTuiSnapshotAsync()`: Async variant for TUI rendering
+   - `recordTuiAgentModels()`: Updates both agent models and variants atomically
+   - `recordTuiAgentModel()`: Updates single agent's model/variant
+3. **Atomic Writes**: State updates are atomic (read → mutate → write with timestamp)
+4. **Error Handling**: All operations are best-effort; failures don't crash plugin
+
+### Event Handling Flow (index.ts)
+
+Key event flows:
+
+1. **Session Lifecycle**:
+   - `session.created` → register child session in `SubagentDepthTracker`
+   - `session.status` → multiplexer session management and companion updates
+   - `session.deleted` → cleanup depth tracker, session agent map, and companion state
+
+2. **Message Updates**:
+   - `message.updated` → record agent/model usage in TUI state
+
+3. **Tool Execution**:
+   - `tool.execute.before` → apply patch and task session hooks
+   - `tool.execute.after` → post-tool hooks (retry guidance, JSON error recovery, file-tool nudges)
+
+4. **Chat Integration**:
+   - `chat.message` → track session → agent mapping
+   - `experimental.chat.system.transform` → inject orchestrator prompt for serve mode
+   - `experimental.chat.messages.transform` → phase reminders, skill filtering, image attachment processing
+
+5. **Command Execution**:
+   - `command.execute.before` → interview, preset, deepwork, and reflect command hooks
 
 ## Integration
 
-- Connects directly to `@opencode-ai/plugin`: returns the plugin object, mutates runtime agent configuration, handles event hooks, and routes RPC via `ctx.client`/`ctx.client.session`.
-- Integrates with host multiplexer backends through `src/multiplexer`, and with session lifecycle constraints through `SubagentDepthTracker`.
-- Hook integration points now include:
-  - `createTaskSessionManagerHook` for V2 background job board state,
-  - `createTodoContinuationHook`, `createPhaseReminderHook`, `createFilterAvailableSkillsHook`, and `createPostFileToolNudgeHook` for chat/tool behavior,
-  - `createInterviewManager` / `createPresetManager` command handlers.
-- Utility integration is visible at runtime through `utils/background-job-board.ts` + `utils/task.ts` (background task state, prompt formatting, and task output parsing), `utils/system-collapse.ts` (system message normalization), and legacy utility support (`logger`, `env`, `polling`, `session`, etc.).
+### Consumers
+
+- **OpenCode Core**: Main plugin entry point consumed by OpenCode's plugin system
+- **TUI System**: `tui.ts` slot registration consumed by OpenCode's TUI renderer
+- **Agents**: Agent configurations consumed by OpenCode's agent registry
+- **Tools**: Tool definitions consumed by OpenCode's tool system
+- **MCPs**: MCP definitions consumed by OpenCode's MCP registry
+
+### Dependencies
+
+- **Config System** (`src/config/`): Configuration loading, validation, and runtime presets
+- **Agents** (`src/agents/`): Agent personalities and permission sets
+- **Tools** (`src/tools/`): Tool implementations (council, webfetch, AST operations)
+- **Hooks** (`src/hooks/`): Lifecycle hooks for auto-update, phase reminders, etc.
+- **Multiplexer** (`src/multiplexer/`): Tmux/Zellij session management for child sessions
+- **Council** (`src/council/`): Multi-LLM council orchestration
+- **Companion** (`src/companion/`): Companion version management
+- **Utils** (`src/utils/`): Logger, environment checks, subagent depth tracking
+
+### Cross-Directory Flow
+
+1. **Plugin Initialization**: `src/index.ts` imports and composes all subsystems
+2. **State Synchronization**: TUI state in `src/tui-state.ts` is updated during plugin init and message events
+3. **UI Integration**: TUI plugin in `src/tui.ts` reads state and renders sidebar
+4. **Event Propagation**: Events flow from OpenCode → plugin handlers → subsystems → state updates
+
+### Configuration Integration
+
+- Plugin config loaded via `loadPluginConfig()` with support for:
+  - User overrides from `~/.config/opencode/oh-my-opencode-slim.json`
+  - Runtime presets via `/preset` command
+  - Environment-based disablement via `OH_MY_OPENCODE_SLIM_DISABLE`
+- Agent configurations merged with user settings from OpenCode config
+- Model resolution supports both string models and array-based fallback chains
+
+### Error Handling & Resilience
+
+- **Config Errors**: Non-fatal; plugin continues with defaults and logs warnings
+- **State Errors**: Non-fatal; TUI falls back to empty state
+- **Event Errors**: Wrapped in try/catch; plugin continues operation
+- **Dependency Failures**: Health checks detect missing dependencies (e.g., jsdom for webfetch)
+
+## Testing & Validation
+
+- **Type Safety**: TypeScript strict mode ensures type correctness
+- **Health Checks**: Validates minimum agent/tool/MCP registrations on init
+- **Config Validation**: Schema-based validation via Zod in config system
+- **TUI State**: Best-effort persistence; failures don't affect core functionality
+
+## Performance Considerations
+
+- **Live Updates**: TUI refreshes every 1000ms (configurable via interval)
+- **Atomic State**: State writes are atomic to prevent corruption
+- **Lazy Initialization**: Some subsystems (e.g., webfetch probe) run async without blocking init
+- **Event-Driven**: Minimal polling; relies on OpenCode's event system
+
+## Future Extensions
+
+- **Dynamic Agent Registration**: Support runtime agent addition/removal
+- **State Migration**: Versioned state format for breaking changes
+- **TUI Customization**: Allow user-defined sidebar layouts
+- **Performance Metrics**: Track and display plugin performance in TUI

+ 170 - 0
src/companion/codemap.md

@@ -0,0 +1,170 @@
+# src/companion/
+
+## Responsibility
+
+Provides the optional animated companion UI feature that visualizes agent activity (busy/idle states) as animated GIFs. This is a user-facing visual overlay that runs separately from OpenCode's core orchestration.
+
+## Design
+
+The companion system consists of two main components following a **Producer-Consumer** pattern:
+
+- **Producer (manager.ts)**: `CompanionManager` class
+  - Listens to OpenCode session lifecycle events (`session.status`, `session.deleted`)
+  - Tracks agent activity per session (orchestrator, fixers, etc.)
+  - Maintains state in a JSON file at `~/.local/share/opencode/storage/oh-my-opencode-slim/companion-state.json`
+  - Spawns the companion binary process when enabled
+  - Implements a locking mechanism for concurrent state writes
+
+- **Consumer (updater.ts)**: Binary installation and update logic
+  - Downloads platform-specific companion binary from GitHub releases
+  - Validates checksums for security
+  - Manages installation metadata and version tracking
+  - Provides update checking and installation workflows
+
+### Key Interfaces
+
+```typescript
+interface CompanionSession {
+  session_id: string;
+  cwd: string;
+  active_agents: string[];  // Up to 9 agents displayed
+  status: 'idle' | 'busy' | 'waiting-input';
+  pid: number;
+  config?: CompanionConfig;
+}
+```
+
+### State Management
+
+- Uses a lock file pattern (`companion-state.json.lock`) for concurrent access
+- State file contains array of active sessions with their current agent activity
+- Binary path determined by:
+  - User config (`binaryPath` in companion config)
+  - Default location: `~/.local/share/opencode/storage/oh-my-opencode-slim/bin/`
+
+### Binary Distribution
+
+- Platform-specific builds published to GitHub releases
+- Supported targets: macOS (x64/arm64), Linux (x64/arm64), Windows (x64)
+- SHA-256 checksums validated on download
+- Automatic updates when new versions are available
+
+## Flow
+
+### Session Lifecycle Integration
+
+```
+OpenCode Session → CompanionManager.onSessionStatus() → Updates state → Spawns companion binary
+```
+
+1. **Plugin loads** (`CompanionManager.onLoad()`)
+   - Reads user configuration (`enabled`, `position`, `size`, `gifPack`, `loopStyle`, `speed`, `debug`)
+   - If enabled, spawns companion binary process with session ID and debug flags
+   - Cleans up stale sessions on load
+
+2. **Agent activity events** (`CompanionManager.onSessionStatus()`)
+   - Receives `session.status` events from OpenCode
+   - Maps session IDs to agent names via `sessionAgentMap`
+   - Updates internal state:
+     - `busy` → adds agent to active_agents array
+     - `idle` → removes agent from active_agents array
+     - `waiting-input` → sets status to waiting-input
+     - `input-resolved` → returns to busy/idle based on active agents
+   - Flushes state to JSON file
+
+3. **Session termination** (`CompanionManager.onSessionDeleted()`)
+   - Removes session from active tracking
+   - Updates companion display
+
+4. **State persistence** (`CompanionManager.flush()`)
+   - Writes to `companion-state.json` with atomic rename
+   - Includes session configuration for display preferences
+
+### Binary Installation Flow
+
+```
+ensureCompanionVersion() → installCompanionArchive() → extract → validate → install
+```
+
+1. **Check current version**
+   - Reads existing installation metadata
+   - Compares with manifest version using semantic versioning
+   - Returns early if up-to-date
+
+2. **Download and install** (if outdated or missing)
+   - Fetches archive from GitHub releases
+   - Validates SHA-256 checksum
+   - Extracts tar.gz (Unix) or zip (Windows)
+   - Copies binary to installation directory
+   - Writes installation metadata
+
+3. **Error handling**
+   - Timeout after 30 seconds for downloads
+   - Lock timeout after 2 seconds (with stale lock detection at 5 minutes)
+   - Checksum validation prevents corrupted installations
+   - Cleanup of temporary files on failure
+
+## Integration
+
+### Consumed By
+
+- **Main plugin** (`src/index.ts`): Initializes `CompanionManager` for each session
+- **User configuration** (`src/config/schema.ts`): Validates companion config schema
+
+### Dependencies
+
+- **OpenCode events**: Listens to `session.status` and `session.deleted` lifecycle events
+- **File system**: Uses Node.js `fs` for state persistence and binary installation
+- **Child processes**: Spawns companion binary as detached process
+- **Network**: Downloads companion binaries from GitHub releases
+
+
+### Configuration Schema
+
+```typescript
+interface CompanionConfig {
+  enabled: boolean;           // Enable/disable companion UI
+  binaryPath?: string;        // Custom binary path override
+  position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
+  size?: 'small' | 'medium' | 'large';
+  gifPack?: 'default';
+  loopStyle?: 'classic' | 'smooth';
+  speed?: number;
+  debug?: boolean;
+}
+```
+
+### Environment Variables
+
+- `OH_MY_OPENCODE_SLIM_COMPANION_SESSION_ID`: Set when spawning companion binary
+- `OH_MY_OPENCODE_SLIM_COMPANION_DEBUG`: Enables debug mode when config.debug is true
+
+### Storage Locations
+
+- **State file**: `~/.local/share/opencode/storage/oh-my-opencode-slim/companion-state.json`
+- **Binary**: `~/.local/share/opencode/storage/oh-my-opencode-slim/bin/oh-my-opencode-slim-companion[.exe]`
+- **Metadata**: `~/.local/share/opencode/storage/oh-my-opencode-slim/bin/oh-my-opencode-slim-companion.json`
+
+### GitHub Release Artifacts
+
+- Repository: `alvinunreal/oh-my-opencode-slim`
+- Release tag pattern: `companion-v{version}`
+- Artifact names: `oh-my-opencode-slim-companion-v{version}-{target}.{tar.gz|zip}`
+
+
+## Error Handling & Edge Cases
+
+- **Unsupported platforms**: Returns `failed` status with clear error message
+- **Missing binary**: Logs warning but doesn't crash plugin
+- **Checksum mismatch**: Prevents installation of corrupted binaries
+- **Concurrent installations**: Uses lock files with stale lock detection
+- **Disabled companion**: Gracefully skips all companion operations
+- **Custom binary path**: Skips automatic updates when configured
+
+## Testing Considerations
+
+- Mock `session.status` events to verify state updates
+- Test binary installation on different platforms
+- Verify checksum validation logic
+- Test concurrent state writes with lock mechanism
+- Validate configuration schema integration

+ 211 - 98
src/config/codemap.md

@@ -1,103 +1,216 @@
-# Config Module Codemap
+# src/config/
 
 ## Responsibility
 
-`src/config/` owns plugin configuration schema, load/merge pipeline, prompt
-resolution, and helper APIs used by agents, council, and runtime subsystems.
-
-## Architecture
-
-### Core entry points
-
-- `loadPluginConfig(directory)` is the top-level loader used by `src/index.ts`.
-- `PluginConfigSchema` validates and normalizes raw config, including:
-  - legacy council field deprecation capture
-  - strict guard that `prompt` / `orchestratorPrompt` are only for custom
-    agents.
-- `getAgentPrompt`/`loadAgentPrompt` and related helpers are consumed by
-  agent registry.
-
-### Merge and load pipeline
-
-`loadPluginConfig(directory)`:
-
-1. Locate user config (prefer `.jsonc`, then `.json`) from:
-   - `OPENCODE_CONFIG_DIR`
-   - `XDG_CONFIG_HOME/opencode`
-   - `~/.config/opencode`
-2. Locate project config at
-   `<directory>/.opencode/oh-my-opencode-slim.(jsonc|json)`.
-3. Validate with schema. Invalid/malformed files are warned and ignored by
-   returning `null` for that file.
-4. Merge user+project configs where project takes precedence:
-   nested merges for `agents`, `tmux`, `multiplexer`, `interview`, `backgroundJobs`,
-   `fallback`, `council`.
-   top-level arrays/values are overridden.
-5. If `tmux` is enabled and no explicit `multiplexer` is configured,
-   migrate to `multiplexer` (`tmux` compatibility path).
-6. Apply env override `OH_MY_OPENCODE_SLIM_PRESET` over config file preset.
-7. If preset exists, merge preset agents into `agents` so explicit root agents
-   still win (`deepMerge(preset, config.agents)`).
-8. Return merged config object.
-
-### Prompt discovery
-
-`loadAgentPrompt(agentName, preset?)`:
-
-- Searches config directories for `oh-my-opencode-slim/` prompt roots.
-- Supports optional preset subdirectory lookup when `preset` is alphanumeric/
-  hyphen/underscore-safe.
-- For each agent:
-  - `<agent>.md` replacement prompt
-  - `<agent>_append.md` appended prompt
-- Read errors are warned and do not fail config load.
-
-### Schema surface and compatibility
-
-- Agent override schema supports:
-  - `model` string or ordered fallback array (string or `{id, variant}`)
-  - `temperature`, `variant`, `options`, `skills`, `mcps`, `displayName`
-  - custom agent prompts (`prompt`, `orchestratorPrompt`) only.
-- Multiplexer:
-  - new unified `multiplexer` schema (`auto|tmux|zellij|none`)
-  - legacy `tmux` schema retained and migrated at load time.
-- Council:
-  - `CouncilConfigSchema` now normalizes deprecated `master*` fields into
-    `_legacyMasterModel` metadata for compatibility
-  - supports presets + timeout/retry/execution mode.
-- Fallback config supports retry/backoff values and toggles.
-
-## Control flow and dependencies
-
-```text
-src/index.ts
-  └─> loadPluginConfig(directory)
-      ├─> Agent override application in src/agents/index.ts
-      ├─> MCP defaults/filters in src/config/agent-mcps.ts
-      ├─> Council session behavior in src/council/*
-      ├─> Fallback/session behavior in runtime hooks
-      └─> Multiplexer behavior in src/multiplexer/*
+Centralizes configuration loading, validation, schema definitions, and runtime state management for the oh-my-opencode-slim plugin. This folder implements the configuration pipeline that merges user preferences, project overrides, and preset-based agent configurations, providing validated runtime configuration objects to the rest of the plugin.
+
+## Design
+
+The config system follows a layered architecture:
+
+- **Schema Layer**: Defines Zod schemas for all configuration objects (PluginConfig, AgentOverrideConfig, CouncilConfig, etc.) ensuring runtime validation and type safety
+- **Loader Layer**: Implements configuration discovery, merging, and environment variable interpolation across user and project scopes
+- **Utility Layer**: Provides helper functions for agent-specific configuration lookup and MCP permission resolution
+- **Runtime State**: Manages active preset state across plugin re-initializations
+
+### Design Patterns
+
+- **Factory Pattern**: `loadPluginConfig()` creates the merged configuration object
+- **Strategy Pattern**: Presets allow swapping entire agent configurations via `preset` field
+- **Decorator Pattern**: Agent overrides decorate default agent behavior with per-model, skill, and MCP restrictions
+- **Singleton Pattern**: Runtime preset state persists across plugin re-inits via module-level variables
+
+### Key Abstractions
+
+| Abstraction | Purpose | Location |
+|-------------|---------|----------|
+| `PluginConfig` | Root configuration object with agents, presets, and feature flags | schema.ts |
+| `AgentOverrideConfig` | Per-agent configuration (model, temperature, skills, MCPs) | schema.ts |
+| `CouncilConfig` | Multi-LLM council configuration with presets and execution modes | council-schema.ts |
+| `MultiplexerConfig` | Unified pane management configuration (tmux/zellij) | schema.ts |
+
+## Flow
+
+### Configuration Loading Pipeline
+
+```
+1. Discovery Phase
+   ├─ User config: $OPENCODE_CONFIG_DIR/oh-my-opencode-slim.{jsonc,json}
+   ├─ Project config: <directory>/.opencode/oh-my-opencode-slim.{jsonc,json}
+   └─ Environment variable: OH_MY_OPENCODE_SLIM_PRESET (overrides preset field)
+
+2. Parsing Phase
+   ├─ JSONC support (comments, trailing commas) via stripJsonComments
+   ├─ Environment variable interpolation: {env:VAR_NAME} → process.env.VAR_NAME
+   └─ Zod validation with detailed error reporting
+
+3. Merging Phase
+   ├─ User config (base) + Project config (override) → deep merge
+   ├─ Preset resolution: preset → merge preset.agents with root agents
+   ├─ Legacy tmux → multiplexer migration for backward compatibility
+   └─ Normalization: companion defaults, ACP agent defaults
+
+4. Runtime Phase
+   ├─ Active preset state persisted across plugin re-inits
+   └─ Previous preset tracked for reset diff computation
+```
+
+### Agent Configuration Resolution
+
+```
+Agent-specific configuration lookup:
+1. Check config.agents[agentName]
+2. Check config.agents[legacyAlias] (e.g., "explore" → "explorer")
+3. Return undefined if not found (use defaults)
+
+MCP permission resolution:
+1. Check agent override: config.agents[agentName]?.mcps
+2. Fall back to DEFAULT_AGENT_MCPS[agentName]
+3. Parse wildcard/exclusion syntax: ["*", "!context7"] → ["websearch", "gh_grep"]
+```
+
+### Preset Resolution
+
+```
+Preset resolution flow:
+1. Read config.preset (e.g., "default", "minimal")
+2. Look up preset in config.presets[presetName]
+3. Merge preset.agents with config.agents (root overrides take precedence)
+4. Apply preset-specific agent overrides
+5. Resolve preset model plans for manual agents (orchestrator, oracle, etc.)
+```
+
+## Integration
+
+### Consumers
+
+| Module | Integration Point | Description |
+|--------|-----------------|-------------|
+| `src/index.ts` | `loadPluginConfig()` | Main plugin entry point loads merged config |
+| `src/agents/` | Agent configuration | Agents use config for model selection and permissions |
+| `src/council/` | Council configuration | Council agent uses CouncilConfig for multi-LLM orchestration |
+| `src/multiplexer/` | Multiplexer configuration | Uses multiplexer config for pane layout and type |
+| `src/cli/` | Config file discovery | CLI tools use config paths for user/project config lookup |
+
+### Dependencies
+
+- **Zod**: Runtime validation and schema inference
+- **Node.js fs**: Configuration file reading (JSONC support via stripJsonComments)
+- **Environment**: Environment variable interpolation via {env:VAR_NAME} syntax
+
+### Published Exports
+
+The config folder re-exports its public API via `src/config/index.ts`:
+
+```typescript
+export * from './constants';
+export * from './council-schema';
+export { deepMerge, loadAgentPrompt, loadPluginConfig } from './loader';
+export * from './schema';
+export { getAcpAgentNames, getAgentOverride, getCustomAgentNames } from './utils';
 ```
 
-### Key collaborators
-
-- `constants.ts`
-  - names/aliases, orchestratable lists, default models/timeouts/modes.
-- `agent-mcps.ts`
-  - `getAgentMcpList`, `parseList`, `getAvailableMcpNames`.
-- `utils.ts`
-  - alias resolution and custom-agent key discovery.
-- `loader.ts`
-  - config IO, deep merge, preset composition, env override, prompt loading.
-- `schema.ts`, `council-schema.ts`
-  - type/shape validation + transformation.
-
-## File structure
-
-- `index.ts` — exported config surface
-- `loader.ts` — load, merge, prompt resolution, tmux migration
-- `schema.ts` — plugin config + agent override schemas
-- `council-schema.ts` — council-specific and legacy compatibility schema
-- `constants.ts` — defaults, names, delegation rules, timeouts
-- `agent-mcps.ts` — MCP defaults and allow-list parsing
-- `utils.ts` — config helper methods
+This allows consumers to import directly from `src/config` rather than individual files.
+
+## Key Functions
+
+### Configuration Loading
+
+- `loadPluginConfig(directory, options?)`: Main entry point for configuration loading and merging
+- `loadConfigFromPath(configPath, options?)`: Load and validate single config file (JSONC or JSON)
+- `findPluginConfigPaths(directory)`: Discover user and project config file paths
+- `mergePluginConfigs(base, override)`: Deep merge two PluginConfig objects
+- `deepMerge(base, override)`: Recursively merge nested configuration objects
+
+### Agent Configuration
+
+- `getAgentOverride(config, name)`: Get agent-specific override with alias support
+- `getCustomAgentNames(config)`: List custom agents declared in config.agents
+- `getAcpAgentNames(config)`: List ACP agent names from config.acpAgents
+- `loadAgentPrompt(agentName, preset?)`: Load custom prompt files for agents
+
+### Runtime State
+
+- `setActiveRuntimePreset(name)`: Set currently active preset
+- `getActiveRuntimePreset()`: Get currently active preset
+- `getPreviousRuntimePreset()`: Get previously active preset
+- `setActiveRuntimePresetWithPrevious(name)`: Set active with previous tracking
+
+### MCP Management
+
+- `getAgentMcpList(agentName, config?)`: Resolve MCP permissions for an agent
+- `parseList(items, allAvailable)`: Parse wildcard and exclusion syntax in MCP lists
+
+## Configuration Schema Overview
+
+### PluginConfig (Root Schema)
+- `preset`: Active preset name
+- `setDefaultAgent`: Whether to set default agent model
+- `autoUpdate`: Enable automatic plugin updates
+- `presets`: Named preset groupings (map of presetName → AgentOverrideConfig)
+- `agents`: Per-agent overrides (map of agentName → AgentOverrideConfig)
+- `disabled_agents`: List of agents to disable
+- `disabled_mcps`: List of MCPs to disable
+- `disabled_tools`: List of tools to disable
+- `disabled_skills`: List of skills to disable
+- `multiplexer`: Unified pane management config (type, layout, sizes)
+- `tmux`: Legacy tmux configuration (migrated to multiplexer)
+- `websearch`: Websearch provider configuration
+- `interview`: Interview feature configuration
+- `backgroundJobs`: Background job configuration
+- `fallback`: Failover/retry configuration
+- `council`: Council configuration with presets and execution modes
+- `companion`: Companion animation configuration
+- `acpAgents`: ACP agent configurations
+
+### AgentOverrideConfig
+- `model`: Model ID or array of model IDs
+- `temperature`: Sampling temperature (0-2)
+- `variant`: Model variant identifier
+- `skills`: Skill allow/deny list ("*" = all, "!item" = exclude)
+- `mcps`: MCP allow/deny list ("*" = all, "!item" = exclude)
+- `prompt`: Custom agent prompt override
+- `orchestratorPrompt`: Custom orchestrator prompt override
+- `options`: Provider-specific model options
+- `displayName`: Custom display name for the agent
+
+### CouncilConfig
+- `presets`: Named council presets (map of presetName → CouncillorConfig[])
+- `timeout`: Council execution timeout in ms
+- `default_preset`: Default preset name to use
+- `councillor_execution_mode`: "parallel" or "serial" execution
+- `councillor_retries`: Number of retry attempts for empty responses
+
+### MultiplexerConfig
+- `type`: "auto", "tmux", "zellij", or "none"
+- `layout`: Pane layout (main-horizontal, main-vertical, tiled, even-horizontal, even-vertical)
+- `main_pane_size`: Percentage for main pane (20-80)
+- `zellij_pane_mode`: "agent-tab" or "current-tab"
+
+## Environment Variable Support
+
+- `{env:VAR_NAME}`: Interpolated in config files during parsing
+- `OH_MY_OPENCODE_SLIM_PRESET`: Overrides config.preset at runtime
+
+## Backward Compatibility
+
+- Legacy `tmux.enabled` is automatically migrated to `multiplexer.type = 'tmux'`
+- Legacy nested `councillors` format in presets is automatically unwrapped
+- Legacy `master` field in council config is accepted but ignored (council agent synthesizes directly)
+
+## Error Handling
+
+- Invalid JSON → warning, fallback to empty config
+- Invalid schema → warning, fallback to empty config
+- Missing preset → warning, continue with empty preset
+- Read errors (non-ENOENT) → warning, fallback to empty config
+- All warnings trigger optional `onWarning` callback for programmatic handling
+
+## Testing Considerations
+
+Configuration loading is tested via:
+- `src/config/loader.test.ts`: Config file discovery, parsing, merging, and validation
+- `src/config/schema.test.ts`: Schema validation and type inference
+- `src/config/utils.test.ts`: Agent configuration utilities
+- `src/config/agent-mcps.test.ts`: MCP permission resolution
+- `src/config/council-schema.test.ts`: Council configuration validation

+ 175 - 96
src/council/codemap.md

@@ -1,101 +1,180 @@
-# Council Module Codemap
+# src/council/
 
 ## Responsibility
+Orchestrates multi-LLM council sessions by spawning parallel councillor agents, collecting their results, and formatting them for synthesis by the council agent. Implements the **Council Pattern** to aggregate diverse model perspectives for higher-quality decision making and complex task resolution.
+
+## Design
+
+### Core Abstraction: CouncilManager
+- **Singleton**: One instance per plugin session manages the entire council lifecycle
+- **Strategy Pattern**: Configurable execution modes (`parallel` vs `serial`) for councillor orchestration
+- **Retry Pattern**: Automatic retry on empty responses with configurable limits
+- **Observer Pattern**: Tracks subagent depth to prevent infinite recursion
+
+### Key Components
+
+| Component | Purpose | Type |
+|-----------|---------|------|
+| `CouncilManager` | Main orchestrator class | Class |
+| `runCouncil()` | Entry point for council sessions | Method |
+| `runCouncillors()` | Parallel/serial councillor execution | Method |
+| `runAgentSession()` | Single councillor lifecycle management | Method |
+| `runCouncillorWithRetry()` | Retry logic for councillors | Method |
+
+### Configuration Schema
+- **Presets**: Named configurations mapping councillor names to their models and prompts
+- **Timeout**: Global timeout for all councillor sessions (default: 180s)
+- **Execution Mode**: Parallel (default) or serial execution of councillors
+- **Retry Policy**: Number of retries for empty responses (default: 3)
+
+### Councillor Lifecycle
+1. **Spawn**: Create child session for each councillor with advisory-only tools
+2. **Prompt**: Send formatted prompt with restricted tool access (no file edits, writes, etc.)
+3. **Timeout**: Enforce session timeout with graceful abortion
+4. **Extract**: Retrieve result from session
+5. **Cleanup**: Abort session and release resources
+
+## Flow
+
+### Session Initiation
+```
+┌─────────────────────────────────────────────────────────────┐
+│                    CouncilManager                       │
+│  (parentSessionId, prompt, presetName)                 │
+└─────────────────────────────────────────────────────────────┘
+                          │
+                          ▼
+┌─────────────────────────────────────────────────────────────┐
+│                    runCouncil()                       │
+│  - Resolve preset (default or named)                  │
+│  - Validate councillor configuration                   │
+│  - Notify parent session (immediate feedback)           │
+│  - Launch councillors (parallel/serial)                 │
+└─────────────────────────────────────────────────────────────┘
+                          │
+                          ▼
+┌─────────────────────────────────────────────────────────────┐
+│                   runCouncillors()                     │
+│  - For each councillor config:                         │
+│    - Spawn child session (session.create)               │
+│    - Apply depth tracking (if enabled)                 │
+│    - Send prompt with restricted tools                 │
+│    - Extract result (extractSessionResult)              │
+│    - Cleanup session (session.abort)                  │
+└─────────────────────────────────────────────────────────────┘
+                          │
+                          ▼
+┌─────────────────────────────────────────────────────────────┐
+│                 runAgentSession()                      │
+│  - Create session with parentID                        │
+│  - Register child in depth tracker                     │
+│  - Send prompt (promptWithTimeout)                     │
+│  - Extract result with reasoning disabled               │
+│  - Abort session on completion/cleanup                 │
+└─────────────────────────────────────────────────────────────┘
+```
 
-`src/council/` orchestrates parallel/serial multi-LLM council sessions and produces
-normalized councillor results for the `council` agent to synthesize.
-
-It is intentionally execution-focused:
-
-- validate council configuration + preset selection,
-- launch and monitor councillor sub-sessions,
-- normalize outputs + retry behavior,
-- return a structured result object to the caller tool.
-
-Prompt templates and tool schemas are defined in `agents/` and `tools/`.
-
-## Architecture
-
-- `council-manager.ts` is the core engine.
-- `index.ts` is the module barrel.
-
-### council-manager responsibilities
-
-- Reads injected plugin context (`PluginInput`) and optional:
-  - config (`PluginConfig`),
-  - `SubagentDepthTracker`,
-  - `tmuxEnabled` flag for pane launch pacing.
-- Owns runtime helpers:
-  - `runCouncil()` orchestration entry,
-  - `runCouncillors()` fan-out strategy,
-  - `runCouncillorWithRetry()` and `runAgentSession()` for per-councillor lifecycle.
-- Uses shared session utilities from `utils/session.ts`:
-  - `parseModelReference` for model string validation,
-  - `promptWithTimeout` for bounded prompt calls,
-  - `extractSessionResult` to collect assistant text,
-  - `shortModelLabel` for UI-friendly model names.
-- Delegates prompt/result shaping to `formatCouncillorPrompt` and
-  `formatCouncillorResults` in `agents/council.ts`.
-
-## Runtime flow
-
-```text
-runCouncil(prompt, presetName?, parentSessionId)
-  ├─> enforce max depth with SubagentDepthTracker
-  ├─> load council config from plugin config
-  ├─> resolve preset (fallback: default_preset -> "default")
-  ├─> fail fast when preset missing or empty
-  ├─> emit start notification to parent session (best-effort, non-blocking)
-  ├─> resolve runtime policy
-  │     timeout, execution mode, retry budget
-  ├─> run councillors in selected mode
-  │     - runAgentSession: create -> register depth -> optional tmux delay
-  │       -> prompt -> extract text -> session abort in finally
-  │     - runCouncillorWithRetry: retries only "Empty response from provider"
-  │       up to `councillor_retries`
-  │     - parallel mode uses indexed staggering to reduce pane launch collisions
-  ├─> aggregate results with per-councillor status
-  ├─> if no completed councillors: return failure result
-  └─> format and return results for caller synthesis
+### Parallel Execution (Default)
+- All councillors launched concurrently with staggered starts (250ms intervals)
+- Results collected via `Promise.allSettled()`
+- Timeout applies to entire council session, not individual councillors
+
+### Serial Execution (Configurable)
+- Councillors executed sequentially in defined order
+- Each councillor inherits parent session timeout
+- Useful for ordered deliberation or resource-constrained environments
+
+### Error Handling & Retries
+1. **Empty responses**: Retry up to `maxRetries` times (provider rate-limiting)
+2. **Timeouts**: Immediate failure, no retry
+3. **Session failures**: Mark as failed, continue with other councillors
+4. **Depth violations**: Block spawn immediately, return error
+
+## Integration
+
+### Dependencies
+- **Config**: `PluginConfig` from `../config` (council presets, timeouts)
+- **Agents**: `formatCouncillorPrompt()`, `formatCouncillorResults()` from `../agents/council`
+- **Session**: `extractSessionResult()`, `promptWithTimeout()` from `../utils/session`
+- **Logger**: `log()` from `../utils/logger`
+- **Depth Tracker**: `SubagentDepthTracker` from `../utils/subagent-depth` (optional)
+- **Client**: `OpencodeClient` from `@opencode-ai/plugin` (session management)
+
+### Consumers
+- **Main Plugin**: `src/index.ts` - orchestrates council sessions for complex tasks
+- **Council Agent**: Receives formatted results via `formatCouncillorResults()` for synthesis
+- **Skills**: Can invoke council sessions for multi-model consensus on decisions
+
+### Configuration Example (from `../config/plugin-config.ts`)
+```typescript
+council: {
+  default_preset: 'default',
+  timeout: 180000, // 3 minutes
+  councillor_execution_mode: 'parallel',
+  councillor_retries: 3,
+  presets: {
+    default: {
+      architect: { model: 'gpt-4', prompt: 'Think like a software architect' },
+      critic: { model: 'claude-3', prompt: 'Critique the architect\'s plan' },
+      implementer: { model: 'gpt-4', prompt: 'Implement the solution' },
+    },
+  },
+}
 ```
 
-## Error and result model
-
-- Each councillor returns status:
-  - `completed` with `result` text,
-  - `failed` with `error`,
-  - `timed_out` with timeout message.
-- Empty provider responses are treated as failures unless failover retry-on-empty is disabled
-  via `fallback.retry_on_empty`.
-- A single councillor's malformed model string is surfaced as failure for that councillor; the
-  session still proceeds with the remaining councillors.
-- Depth limit violations return a hard failure (`Subagent depth exceeded`) without starting
-  any councillor session.
-
-## Configuration semantics (delegated to schema)
-
-Validated in `config/council-schema.ts` and consumed in `runCouncil`:
-
-- `presets` with per-preset councillor definitions,
-- `default_preset`,
-- `timeout`,
-- `councillor_execution_mode` (`parallel`/`serial`),
-- `councillor_retries`.
-
-Legacy schema behavior:
-
-- nested legacy `councillors` keys are unwrapped,
-- top-level `master` key is ignored at preset level,
-- deprecated `master` fields are recorded (via `_deprecated`) and surfaced to the caller
-  as warnings, while `_legacyMasterModel` is kept for fallback messaging.
-
-## Integration points
-
-- **Tool caller:** `tools/council.ts` creates `council_session` and calls
-  `runCouncil(prompt, preset, parentSessionId)`.
-- **Plugin init:** `src/index.ts` constructs `CouncilManager` with runtime config,
-  `SubagentDepthTracker`, and multiplexer capability before exposing `council_session`.
-- **Depth lifecycle:** `SubagentDepthTracker` is also used in plugin event hooks to register/
-  cleanup child sessions as they are created/deleted.
-- **Runtime constants:** `config/constants.ts` provides launch delays (`TMUX_SPAWN_DELAY_MS`,
-  `COUNCILLOR_STAGGER_MS`) used to avoid multiplexer collision.
+### Environment Variables & Fallbacks
+- **Directory**: Inherited from plugin context (`ctx.directory`)
+- **TMUX Enabled**: Controls pane staggering and spawn delays
+- **Fallback**: `retry_on_empty` controls whether to retry empty responses
+
+## Key Behaviors
+
+### Tool Restrictions for Councillors
+Councillors operate with **advisory-only** tool access:
+- ❌ `task` - Cannot spawn new subagents
+- ❌ `question` - Cannot ask user questions
+- ❌ `edit`, `write`, `apply_patch` - Cannot modify files
+- ❌ `ast_grep_replace`, `bash` - Cannot execute commands
+- ✅ `read` - Can read files for analysis
+
+This ensures councillors provide guidance without side effects.
+
+### Depth Tracking
+- Prevents infinite recursion by tracking subagent depth
+- Configurable maximum depth (default: 3 levels)
+- Logs violations and blocks spawn attempts
+
+### Notifications
+- Sends immediate feedback to parent session on council start
+- Message format: `⎔ Council starting — ${count} councillors launching — ctrl+x ↓ to watch`
+
+## Performance Considerations
+
+- **Parallel execution**: Optimal for most cases, maximizes throughput
+- **Staggered starts**: Reduces tmux pane creation contention (250ms intervals)
+- **Timeout alignment**: Single timeout for entire council avoids cascading delays
+- **Resource cleanup**: Guaranteed session abortion in `finally` block prevents leaks
+
+## Error Scenarios & Recovery
+
+| Scenario | Behavior | Recovery |
+|----------|----------|----------|
+| No council config | Return error immediately | User must configure council in plugin config |
+| Invalid preset | Return error with available presets | User selects valid preset or uses default |
+| Empty preset | Return error about no councillors | User adds councillors to preset |
+| All councillors fail | Return error with all failures | Investigate model availability or prompts |
+| Timeout | Mark timed_out status | Increase timeout or reduce council size |
+| Depth exceeded | Block spawn, return error | Increase maxDepth or simplify task |
+| Provider rate-limiting | Retry up to maxRetries | Automatic recovery |
+
+## Testing Points
+
+- Preset resolution (default vs named)
+- Parallel vs serial execution modes
+- Retry logic for empty responses
+- Depth tracking and blocking
+- Tool restrictions enforcement
+- Session lifecycle (create → prompt → extract → abort)
+- Timeout behavior
+- Error propagation and formatting
+- Councillor result formatting for synthesis

+ 181 - 22
src/hooks/apply-patch/codemap.md

@@ -1,33 +1,192 @@
-# apply-patch
+# src/hooks/apply-patch/
 
 ## Responsibility
 
-Provide a resilient preprocessor for `tool.execute.before` on `apply_patch` that rewrites recoverable stale hunks, validates workspace boundaries, and blocks unsafe patches before they reach OpenCode’s native patch executor.
+Implements OpenCode's patch application hook system with fuzzy matching and automatic rescue strategies. This module intercepts `apply_patch` tool invocations, parses custom patch formats, matches patch chunks to file content using multiple comparison strategies, and rewrites patches to apply cleanly across file moves, renames, and content drift.
+
+## Design Patterns
+
+- **Hook Pattern**: Intercepts tool execution via `tool.execute.before` hook to preprocess patches before native application
+- **Strategy Pattern**: Multiple rescue strategies (prefix/suffix, LCS) for matching patch chunks to file content
+- **Parser Combinator**: Recursive descent parser for custom patch format with strict/permissive modes
+- **Visitor Pattern**: Processes patch hunks through resolution pipeline to determine application locations
+- **State Machine**: Manages file state (exists/missing) and dependency tracking for file moves and renames
 
 ## Design
 
-- Entry point is `createApplyPatchHook` in `index.ts`, bound to `tool.execute.before`.
-- `rewritePatch` (`operations.ts`) is the main pipeline used by the hook and is backed by:
-  - `parseValidatedPatch` / `createPatchExecutionContext` (`execution-context.ts`) for patch parsing and path/state validation.
-  - `parsePatch` / `parsePatchStrict` / `formatPatch` (`codec.ts`) for patch AST conversion and serialization.
-  - `resolveChunkStart`, `locateChunk`, `resolveUpdateChunks`, `applyHits` (`resolution.ts`) for context matching.
-  - `resolveBy...` helpers in `matching.ts` (`seek`, `seekMatch`, `list`, `rescueByPrefixSuffix`, `rescueByLcs`) for tolerant matching.
-- `types.ts` defines domain contracts used across modules (`PatchChunk`, `PatchHunk`, `ResolvedChunk`, `ApplyPatchErrorKind`, etc.).
-- Error semantics are centralized in `errors.ts` (`ApplyPatchError`, `createApplyPatchBlockedError`, `createApplyPatchVerificationError`, `isApplyPatchError`) and surfaced in hook logging and thrown errors.
-- No additional runtime configuration is exposed; behavior is controlled by constant `APPLY_PATCH_RESCUE_OPTIONS` (`prefixSuffix` + `lcsRescue`).
+The module is organized into five cohesive files:
+
+### 1. index.ts (Hook Entry Point)
+- Exports `createApplyPatchHook()` factory that returns the `tool.execute.before` hook
+- Intercepts `apply_patch` tool calls and delegates to `rewritePatch()`
+- Handles error normalization and fail-open/fail-closed behavior
+- Logs hook lifecycle events (rewrite, unchanged, skipped, blocked, validation, verification, internal)
+
+### 2. codec.ts (Patch Serialization)
+- **Parsing**: `parsePatch()` and `parsePatchStrict()` parse custom patch format with markers `*** Begin Patch`/`*** End Patch`
+- **Format**: Supports add/delete/update operations with optional move semantics
+- **Normalization**: Unicode normalization (smart quotes, dashes, ellipsis, non-breaking spaces) and line ending normalization
+- **Rendering**: `formatPatch()` converts parsed patch objects back to canonical string format
+- **Diff Algorithm**: Internal diffMatrix for rendering optimized patch chunks
+
+### 3. matching.ts (Fuzzy Matching Engine)
+- **Comparators**: Multiple line comparison strategies (exact, unicode, trim-end, unicode-trim-end, trim, unicode-trim)
+- **Prefix/Suffix Rescue**: `rescueByPrefixSuffix()` matches patches by common prefix/suffix patterns
+- **LCS Rescue**: `rescueByLcs()` uses longest common subsequence for fuzzy matching when exact lines not found
+- **Anchor Resolution**: `resolveUniqueAnchor()` finds insertion points for new content
+- **Utilities**: seek, list, prefix, suffix, score for pattern matching and scoring
+
+### 4. resolution.ts (Patch Resolution Engine)
+- **File I/O**: `readFileLines()` and `readFileLinesWithEol()` handle platform-specific line endings
+- **Chunk Resolution**: `locateChunk()` finds where patch chunks should be applied in files
+- **Anchor Handling**: Resolves insertion points for new content using change_context markers
+- **Content Application**: `applyHits()` applies resolved patch hits to file content
+- **State Management**: Tracks canonical old/new lines, rewrite strategies, and match comparators
+
+### 5. rewrite.ts (Patch Rewriting Pipeline)
+- **Dependency Tracking**: Groups patches by file path to handle file moves and multiple operations on same file
+- **Chunk Merging**: `minimizeMergedChunk()` and `mergeSameFileUpdateGroupChunks()` merge adjacent/overlapping patch operations
+- **Move Support**: Handles file moves by tracking source and destination paths
+- **Add/Delete Operations**: Special handling for file creation and deletion
+- **Output Generation**: Produces normalized patch text with minimal context preservation
 
 ## Flow
 
-1. `createApplyPatchHook` filters only `input.tool === 'apply_patch'`.
-2. It requires `output.args.patchText` to be a string.
-3. It resolves `root` and `worktree` from `input.directory` / `ctx.directory` / `ctx.worktree`.
-4. It calls `rewritePatch(root, patchText, options, worktree)`.
-5. On `result.changed`, it replaces `output.args.patchText` with canonicalized patch text.
-6. On failure, it normalizes to `ApplyPatchError`, logs `blocked | validation | verification | internal`, and rethrows so native execution is prevented.
+### Hook Execution Flow
+```
+tool.execute.before (apply_patch)
+  ↓
+index.ts: createApplyPatchHook()
+  ↓
+rewritePatch()
+  ↓
+codec.ts: parsePatch()
+  ↓
+rewrite.ts: rewritePatch() pipeline
+  ↓
+resolution.ts: resolveUpdateChunks()
+  ↓
+matching.ts: seekMatch()/rescueByPrefixSuffix()/rescueByLcs()
+  ↓
+resolution.ts: locateChunk() → applyHits()
+  ↓
+rewrite.ts: generate rewritten patch
+  ↓
+index.ts: return modified patchText to hook
+```
+
+### Patch Application Flow
+
+1. **Interception**: Hook intercepts `apply_patch` tool call with patch text
+2. **Parsing**: Patch is parsed into structured format (hunks with chunks)
+3. **Preparation**: File states are prepared (read, normalized line endings)
+4. **Resolution**: Each patch chunk is resolved to a location in the target file:
+   - Exact match: Direct application
+   - Prefix/Suffix rescue: Match by surrounding context
+   - LCS rescue: Fuzzy matching using longest common subsequence
+   - Anchor insertion: Insert new content at marked locations
+5. **Application**: Changes are applied to file content with EOL preservation
+6. **Rewriting**: Rewritten patch is formatted and returned to hook
+7. **Hook Return**: Modified patch is passed to native apply_patch tool
+
+### Error Handling Flow
+
+- **Blocked Errors**: Outside workspace operations fail open (return unchanged)
+- **Validation Errors**: Malformed patches throw with detailed context
+- **Verification Errors**: Missing files or ambiguous matches throw with file paths
+- **Internal Errors**: Unexpected failures are wrapped in `createApplyPatchInternalError`
+
+## Integration Points
+
+### Consumed By
+- **Main Plugin**: `src/index.ts` registers the hook via `createApplyPatchHook(ctx)`
+- **CLI**: `src/cli/index.ts` includes the hook in plugin initialization
+- **OpenCode**: Hook integrates with `@opencode-ai/plugin` tool execution system
+
+### Dependencies
+- **Utils**: `src/utils/logger.ts` for structured logging
+- **Errors**: Custom error hierarchy in `./errors.ts` (createApplyPatchInternalError, getApplyPatchErrorDetails, etc.)
+- **Types**: Shared type definitions in `./types.ts`
+
+### Runtime Options
+The hook accepts `ApplyPatchRuntimeOptions`:
+```typescript
+{
+  prefixSuffix: boolean;  // Enable prefix/suffix rescue strategy
+  lcsRescue: boolean;     // Enable LCS (longest common subsequence) rescue
+}
+```
+
+Default options in hook:
+```typescript
+const APPLY_PATCH_RESCUE_OPTIONS: ApplyPatchRuntimeOptions = {
+  prefixSuffix: true,
+  lcsRescue: true,
+};
+```
+
+### Error Types
+- **blocked**: Operations blocked by safety checks (e.g., outside workspace)
+- **validation**: Malformed patch format or missing required fields
+- **verification**: File not found or ambiguous matches
+- **internal**: Unexpected errors during processing
+
+## Key Algorithms
+
+### 1. Prefix/Suffix Rescue Algorithm
+```
+Input: old_lines[], new_lines[], file_lines[]
+1. Compute common prefix length between old and new lines
+2. Compute common suffix length after prefix
+3. Collect all occurrences of prefix in file
+4. For each prefix occurrence, find matching suffix
+5. Return first unambiguous match or error on ambiguity
+```
+
+### 2. LCS Rescue Algorithm
+```
+Input: old_lines[], new_lines[], file_lines[]
+1. Compute upper bound of shared lines using line frequency
+2. Collect candidate start positions where first line matches
+3. Score each window using LCS algorithm
+4. Select highest scoring unambiguous match
+5. Return match or error on ambiguity/low confidence
+```
+
+### 3. Patch Minimization Algorithm
+```
+Input: patch chunk with old_lines and new_lines
+1. Trim common prefix from both arrays
+2. Trim common suffix from both arrays
+3. Preserve change_context if prefix was trimmed
+4. Return minimized chunk if it still produces same result
+```
+
+## Performance Characteristics
+
+- **Time Complexity**: O(n*m) for LCS rescue where n=old lines, m=new lines
+- **Space Complexity**: O(n*m) for LCS scoring matrix
+- **Optimizations**:
+  - MAX_LCS_CHUNK_LINES (48) limits LCS to small chunks
+  - MAX_LCS_CANDIDATES (64) limits candidate windows
+  - Early termination on unambiguous matches
+  - Prefix/suffix fast path for common cases
+
+## Testing Considerations
+
+The module handles:
+- Unicode normalization and comparison
+- Line ending preservation (\n vs \r\n)
+- File moves and renames
+- Empty file handling
+- End-of-file markers
+- Overlapping patch chunks
+- Ambiguous matches
+- Error recovery and fail-open behavior
 
-## Integration
+## Configuration
 
-- Consumed by `src/index.ts` through `createApplyPatchHook`.
-- Acts before native tool execution via OpenCode hook point `tool.execute.before`.
-- Downstream dependencies include `ctx.client` indirectly only for context, and `utils/logger` for structured hook telemetry.
-- Uses `Patch` parser/resolver modules to keep `new_lines` byte-preserving while only mutating stale anchors and chunk context.
+No external configuration required. All behavior is controlled via:
+- Runtime options passed to `rewritePatch()`
+- Patch format itself (change_context markers, etc.)
+- File system state at application time

+ 187 - 26
src/hooks/auto-update-checker/codemap.md

@@ -2,38 +2,199 @@
 
 ## Responsibility
 
-- Provide a startup hook that detects plugin update availability for `oh-my-opencode-slim`, reports status through TUI toasts, and optionally performs a cache-safe `bun install` refresh.
-- Handle local dev mode and pinned plugin versions distinctly (`file://`, pinned tags, and `latest` channel semantics).
+Implements a background auto-update system for oh-my-opencode-slim that:
+- Checks for plugin updates when new OpenCode sessions are created
+- Validates version compatibility and channel membership (latest, alpha, beta, etc.)
+- Prevents major version upgrades automatically (surfaces as manual migration notice)
+- Synchronizes bundled skills from updated packages to OpenCode's skills directory
+- Provides user notifications via OpenCode TUI toasts
 
 ## Design
 
-- `createAutoUpdateCheckerHook(ctx, options)` in `index.ts` registers an `event` handler for `session.created` and guards one-time startup execution (`hasChecked`).
-- `runBackgroundUpdateCheck` performs version resolution and branches into:
-  - local-dev no-op path,
-  - pinned plugin notification,
-  - manual notification when `autoUpdate=false`,
-  - or auto-update execution path.
-- `checker.ts` is the core discovery layer and exports:
-  - `findPluginEntry`, `extractChannel`, `getCachedVersion`, `getLocalDevVersion`, `getLatestVersion`, `updatePinnedVersion`.
-- `cache.ts` owns cache preparation with `resolveInstallContext` and `preparePackageUpdate`.
-- `constants.ts` centralizes install and config-path constants (`CACHE_DIR`, `PACKAGE_NAME`, `NPM_REGISTRY_URL`, `NPM_FETCH_TIMEOUT`, config path aliases).
-- `types.ts` declares `AutoUpdateCheckerOptions`, `PluginEntryInfo`, config/package typed envelopes.
+### Architecture Pattern: Observer Hook
+
+The folder implements an **OpenCode plugin hook** that observes the `session.created` event and triggers background update checks. This follows the Observer pattern where:
+- The hook subscribes to OpenCode lifecycle events
+- Update checks run asynchronously without blocking session creation
+- Results are communicated via toast notifications
+
+### Core Modules
+
+| Module | Purpose | Key Abstractions |
+|--------|---------|------------------|
+| `index.ts` | Main hook factory and update orchestrator | `createAutoUpdateCheckerHook()`, `runBackgroundUpdateCheck()` |
+| `checker.ts` | Version checking and compatibility logic | `getLatestCompatibleVersion()`, `extractChannel()`, version parsing and comparison |
+| `constants.ts` | Configuration constants and paths | `PACKAGE_NAME`, `NPM_REGISTRY_URL`, `CACHE_DIR` |
+| `types.ts` | TypeScript interfaces and types | `AutoUpdateCheckerOptions`, `CompatibleVersionResult`, `PluginEntryInfo` |
+| `skill-sync.ts` | Skill synchronization from package updates | `syncBundledSkillsFromPackage()`, atomic staging with rename |
+
+### Version Safety Strategy
+
+The system implements multiple safety checks:
+
+1. **Local Development Detection**: Skips update checks when running from local `file://` paths
+2. **Channel Extraction**: Parses version strings to determine channel (latest, alpha, beta, rc, canary, next)
+3. **Major Version Blocking**: Prevents auto-updates that cross major versions; surfaces as manual migration notice
+4. **Pinned Version Detection**: Respects pinned versions in user configuration
+5. **Timeout Protection**: Uses 60-second timeout for `bun install` to prevent stalling OpenCode
+6. **Atomic Skill Sync**: Uses staging directories with rename for atomic skill synchronization
+
+### Data Flow
+
+```
+OpenCode Session Created
+    ↓
+Hook: session.created → createAutoUpdateCheckerHook()
+    ↓
+Check: Local dev mode? → Skip if true
+    ↓
+Fetch: Current version (cached or pinned)
+    ↓
+Parse: Extract channel from version
+    ↓
+Query: NPM registry for latest compatible version
+    ↓
+Compare: Current vs Latest (with major version blocking)
+    ↓
+Decision: Update available? → No: Log and exit
+    ↓
+Decision: Pinned? → Yes: Notify user
+    ↓
+Decision: Auto-update enabled? → No: Notify user
+    ↓
+Action: Prepare package update (download + extract)
+    ↓
+Action: Run bun install in isolated directory
+    ↓
+Sync: Bundled skills to OpenCode config/skills/
+    ↓
+Sync: Companion update (if enabled)
+    ↓
+Notify: Success/failure via OpenCode TUI toast
+```
 
 ## Flow
 
-1. On first eligible `session.created` (root/no parent), schedule asynchronous update check.
-2. If local development plugin is detected (`getLocalDevVersion`), emit info toast and return.
-3. Resolve current version from `getCachedVersion` + plugin entry in config (`findPluginEntry`).
-4. Fetch channel metadata (`extractChannel` + `getLatestVersion`).
-5. If update is needed:
-   - pinned entry ⇒ notify only,
-   - unpinned and `autoUpdate=false` ⇒ notify only,
-   - unpinned and auto-update enabled ⇒ call `preparePackageUpdate`, then `runBunInstallSafe`.
-6. Surface success/failure via `ctx.client.tui.showToast` and `utils/logger`.
+### Hook Initialization Flow
+
+1. **Plugin Registration**: The hook is registered by the main plugin (`src/index.ts`) during plugin initialization
+2. **Event Subscription**: Hook subscribes to `session.created` OpenCode event
+3. **Single Execution**: Uses `hasChecked` flag to ensure only one background check per plugin load
+4. **Parent Session Check**: Skips checks for child sessions (only runs for top-level sessions)
+5. **Asynchronous Execution**: Uses `setTimeout(async () => {...}, 0)` to run in background without blocking
+
+### Update Check Flow
+
+```typescript
+// In index.ts:runBackgroundUpdateCheck()
+1. Resolve plugin entry from user config (pinned or latest)
+2. Get cached version or pinned version
+3. Extract channel from version string
+4. Fetch latest compatible version from NPM registry
+5. Check for major version blocking
+6. If blocked: Show major upgrade toast with migration instructions
+7. If unparseable version: Show notification and skip auto-update
+8. If current == latest: Log and exit
+9. If pinned: Show pinned version notification
+10. If auto-update disabled: Show notification only
+11. Prepare package update in cache directory
+12. Run bun install with 60s timeout
+13. If install succeeds:
+    - Sync bundled skills from package
+    - Update companion if enabled
+    - Show success toast with version diff and changes
+14. If install fails: Show error toast
+```
+
+### Skill Synchronization Flow (skill-sync.ts)
+
+1. **Source Validation**: Check if source skills directory exists and is valid
+2. **Destination Setup**: Create destination skills directory if needed
+3. **Entry Processing**: For each skill directory in source:
+   - Skip hidden files (starting with `.`)
+   - Validate SKILL.md exists
+   - Check if destination already exists
+   - If exists: Skip and log
+   - If not exists: Create staging directory
+   - Copy skill files to staging
+   - Atomic rename from staging to destination
+   - Clean up staging on success or failure
+4. **Result Tracking**: Collect installed, skipped, and failed skills
 
 ## Integration
 
-- Wired through `src/hooks/index.ts` and plugin initialization (`src/index.ts`) as an `event` hook.
-- Consumes `PluginInput.client.tui.showToast`, `PluginInput.directory`, `ctx.client` context, and reads config paths through `cli/config-manager` (`stripJsonComments`, `getOpenCodeConfigPaths`).
-- Runtime interactions use `crossSpawn` for `bun install`, Node `fs/path`, and `fetch` against `NPM_REGISTRY_URL`.
-- Export surface includes `getAutoUpdateInstallDir` and `AutoUpdateCheckerOptions` for testability and host-side overrides.
+### Consumers
+
+- **Primary Consumer**: Main plugin (`src/index.ts`) - registers the auto-update hook during plugin initialization
+- **Secondary Consumers**: 
+  - `src/companion/updater.ts` - companion version management
+  - OpenCode TUI - toast notifications
+
+### Dependencies
+
+| Dependency | Purpose |
+|------------|---------|
+| `@opencode-ai/plugin` | OpenCode plugin SDK types |
+| `@opencode-ai/sdk` | OpenCode AI SDK |
+| `node:fs`, `node:path` | File system operations |
+| `node:os` | Platform detection for cache paths |
+| External: NPM registry | Version lookup and compatibility checking |
+
+### Configuration Integration
+
+The system reads from OpenCode configuration files:
+- User config: `~/.config/opencode/opencode.json`
+- User config (JSONC): `~/.config/opencode/opencode.jsonc`
+- Local config: `.opencode/opencode.json` or `.opencode/opencode.jsonc` in plugin directory
+
+### Event Integration
+
+- **Event Type**: `session.created`
+- **Event Source**: OpenCode plugin lifecycle
+- **Event Properties**: Checks for `parentID` to avoid duplicate checks in child sessions
+
+### Cache Integration
+
+Uses OpenCode's plugin cache directory:
+- Platform-specific: `~/.cache/opencode/` (Linux/macOS) or `%LOCALAPPDATA%\opencode` (Windows)
+- Plugin cache: `node_modules/oh-my-opencode-slim/`
+- Package updates are installed to isolated cache directories
+
+## Error Handling & Recovery
+
+### Failure Modes
+
+1. **Network Timeout**: Uses 5s timeout for NPM registry requests
+2. **Install Timeout**: Uses 60s timeout for `bun install` to prevent stalling
+3. **Version Parsing**: Handles unparseable versions gracefully (shows notification)
+4. **File Operations**: Atomic operations with staging directories prevent partial updates
+5. **Concurrent Access**: Uses memoization (`cachedPackageVersion`) to avoid repeated file reads
+
+### Recovery Strategies
+
+- **Retry on Restart**: Companion updates that fail will retry on next OpenCode restart
+- **Atomic Operations**: Skill sync uses staging + rename for atomic updates
+- **Graceful Degradation**: If auto-update fails, shows error toast but doesn't crash OpenCode
+- **Local Dev Fallback**: Local development mode skips all update checks
+
+## Performance Considerations
+
+- **Background Execution**: All update checks run asynchronously after session creation
+- **Timeout Protection**: Prevents network or install operations from stalling OpenCode
+- **Memoization**: Cached version lookups avoid repeated file system operations
+- **Isolated Installs**: Updates run in isolated cache directories to avoid conflicts
+- **Single Execution**: Hook ensures only one background check per plugin load
+
+## Testing Considerations
+
+Key test scenarios:
+- Local development mode detection
+- Version parsing and comparison
+- Channel extraction (latest, alpha, beta, rc, canary, next)
+- Major version blocking
+- Pinned version handling
+- Auto-update enabled/disabled scenarios
+- Network timeout and failure handling
+- Skill synchronization (install, skip, failure cases)
+- Companion update scenarios
+- Toast notification display

+ 68 - 64
src/hooks/codemap.md

@@ -1,79 +1,83 @@
 # src/hooks/
 
-This directory is the plugin-level hook composition surface. It exports factories
-and managers for all hook-based runtime behaviors used by
-`src/index.ts` (tool transforms, event listeners, and command hooks).
-
 ## Responsibility
-
-- Own the stable exports for hook modules so `src/index.ts` can register features
-  without depending on subfolder internals.
-- Describe lifecycle boundaries between OpenCode hook surfaces and internal state
-  machines that coordinate retries, timers, and session tracking.
-- Centralize all hook feature entry points used by orchestrator tooling,
-  delegation/task workflows, and session lifecycle handlers.
+Implements OpenCode lifecycle hooks that transform, process, and manage chat messages and attachments during the plugin's message pipeline. These hooks are invoked by OpenCode's `experimental.chat.messages.transform` API to modify message content before it reaches models or after responses are generated.
 
 ## Design
 
-- `src/hooks/index.ts` re-exports per-feature factories and managers.
-- Most features implement the `create*Hook(ctx, config?)` factory pattern and
-  return lifecycle callbacks.
-- Foreground fallback is provided as a manager class (`ForegroundFallbackManager`)
-  with an explicit `handleEvent` method.
-- `task-session-manager` persists resumable task sessions per parent session and
-  per agent, with bounded history and aliasing.
-- Side effects are limited to exported handlers and dedicated utility functions
-  to keep hook behavior deterministic.
-- Runtime integration depends on `PluginInput.client` for session APIs and shared
-  utilities (`log`, marker constants, prompt helpers).
+### Core Architecture
+- **Factory Pattern**: Each hook is created via a factory function (e.g., `createApplyPatchHook()`, `createAutoUpdateCheckerHook()`) that returns a hook function matching the OpenCode hook signature.
+- **Stateless Hooks**: Hooks are pure functions that take configuration and return a processing function; no internal state is maintained between invocations.
+- **Message Transformation Pipeline**: Hooks operate on the `MessageWithParts[]` type, allowing transformation of user messages, assistant responses, and system messages.
 
-## Flow
+### Key Types & Interfaces
+- `MessageInfo`: Metadata about a message (role, agent, sessionID, id)
+- `MessagePart`: Individual content part of a message (text, file, image, tool use, etc.)
+- `MessageWithParts`: Complete message with metadata and array of parts
 
-1. `src/index.ts` imports each hook symbol from this folder.
-2. The plugin creates hook instances during startup and registers callbacks in
-   these surfaces:
-   - `tool.execute.before`
-   - `tool.execute.after`
-   - `experimental.chat.messages.transform`
-   - `experimental.chat.system.transform`
-   - `chat.headers`
-   - `chat.message`
-   - `command.execute.before`
-   - `event`
-3. Implementations either mutate OpenCode payloads (for in-band guidance or
-   prompt/system injection) or call session APIs (`todo`, `messages`, `prompt`,
-   `promptAsync`, `abort`, and event/status flows).
+### Hook Categories
+1. **Attachment Processing**: `processImageAttachments` - Extracts image data URLs from messages, saves them to `.opencode/images/` directory, and replaces image parts with text references containing file paths.
+2. **State Management**: Hooks like `createTaskSessionManagerHook` that manage session state and lifecycle.
+3. **Error Recovery**: Hooks like `createJsonErrorRecoveryHook` that detect and recover from JSON parsing errors.
+4. **UI/UX Enhancement**: Hooks like `createPhaseReminderHook` that add contextual reminders to messages.
+5. **Task Management**: Hooks like `createDelegateTaskRetryHook` that handle task retry logic.
 
-## Hook Points
+## Flow
 
-| Hook Point | Purpose | Implementations |
-|---|---|---|
-| `tool.execute.before` | Pre-process tool inputs | `apply-patch`, `task-session-manager` |
-| `tool.execute.after` | Post-process tool outputs | `delegate-task-retry`, `json-error-recovery`, `post-file-tool-nudge`, `task-session-manager` |
-| `experimental.chat.messages.transform` | Rewrite outbound user content | `filter-available-skills`, `phase-reminder` |
-| `experimental.chat.system.transform` | Inject system-level directives | `post-file-tool-nudge`, `task-session-manager` |
-| `chat.headers` | Mutate request headers | `chat-headers` |
-| `chat.message` | Track runtime session/agent mapping | `src/index.ts` session map |
-| `command.execute.before` | Handle slash-command UX | `interview`, `preset-manager`, `deepwork` |
-| `event` | React to session lifecycle and runtime failures | `foreground-fallback`, `post-file-tool-nudge`, `auto-update-checker`, multiplexer managers, `task-session-manager` |
+### Message Processing Pipeline
+```
+1. OpenCode receives chat messages
+2. Plugin's `experimental.chat.messages.transform` hook is invoked
+3. Each registered hook receives the message array sequentially
+4. Hooks transform messages (e.g., extract images, add metadata, validate structure)
+5. Transformed messages are sent to the model
+6. Model responses are transformed by hooks in reverse order
+7. Final messages are returned to OpenCode
+```
 
-## Implementation Notes
+### Image Attachment Flow (processImageAttachments)
+```
+1. Hook receives messages with image parts (type='image' or type='file' with image/* mime)
+2. For each user message with images:
+   a. Decode data URLs to binary data
+   b. Generate SHA1 hash of image data for unique identification
+   c. Save image to `.opencode/images/[sessionID]/` directory
+   d. Create unique filename with hash to prevent collisions
+   e. Replace image parts with text reference containing file paths
+   f. Add informational text about image attachment for model context
+3. Cleanup old images older than 60 minutes (debounced every 10 minutes)
+```
 
-- `createDelegateTaskRetryHook` (`tool.execute.after`) is a narrow guard around
-  `task` tool failure strings and appends structured retry guidance inline.
-- `ForegroundFallbackManager` listens to event traffic and remediates
-  foreground rate-limit failures by aborting the current prompt and re-queuing the
-  latest user message on the next model in a per-agent chain.
-- `createTaskSessionManagerHook` tracks V2 background jobs and reusable completed sessions: generates
-  user-facing aliases, resolves alias/task IDs before delegation, remembers fresh
-  task IDs after completion, and drops stale entries on missing-session failure,
-  renamed task IDs, or session deletion.
+### Hook Registration
+```
+1. Plugin initializes (src/index.ts)
+2. Hook factories are called to create hook instances
+3. Hooks are registered with OpenCode via `experimental.chat.messages.transform`
+4. OpenCode invokes hooks during message lifecycle
+```
 
 ## Integration
 
-- `src/index.ts` is the sole runtime consumer and determines final registration
-  order so composed transforms (system joins, reminder insertion, hygiene) stay
-  deterministic.
-- `taskSessionManager` is registered in `tool.execute.before`, `tool.execute.after`,
-  `experimental.chat.system.transform`, and `event`, with parent/child cleanup.
-- The `src/hooks/*/codemap.md` files document each feature internals.
+### Consumers
+- **Main Plugin**: `src/index.ts` - registers hooks with OpenCode during plugin initialization
+- **OpenCode Runtime**: Invokes hooks during `experimental.chat.messages.transform` API calls
+
+### Dependencies
+- **OpenCode SDK**: Type definitions for `MessageWithParts`, `MessageInfo`, and hook signatures
+- **Node.js FS Module**: For saving image attachments to disk
+- **Crypto Module**: For generating unique image hashes
+- **Observer Agent**: Disabled agents check prevents image processing when observer is unavailable
+
+### Configuration
+- **Disabled Agents**: Hooks check `disabledAgents` set to skip processing when required agents are unavailable
+- **Workspace Directory**: Images are saved to `.opencode/images/` within the project workspace
+
+### Error Handling
+- **File System Errors**: Logged but don't halt processing; hook continues with remaining messages
+- **Collision Handling**: Unique filenames generated via counter suffix when hash collisions occur
+- **Cleanup Failures**: Non-fatal; old images may persist but are periodically cleaned up
+
+### Performance Considerations
+- **Debounced Cleanup**: Image cleanup runs every 10 minutes per directory to avoid frequent filesystem operations
+- **Session Isolation**: Images organized by sessionID to prevent cross-session contamination
+- **Early Returns**: Hooks return immediately when no relevant messages found (e.g., no images to process)

+ 104 - 0
src/hooks/deepwork/codemap.md

@@ -0,0 +1,104 @@
+# src/hooks/deepwork/
+
+## Responsibility
+
+Provides an OpenCode hook implementation for managing deepwork sessions — heavy, multi-phase coding tasks that require structured planning, phased execution, and continuous validation.
+
+This hook enables developers to:
+- Initiate deepwork sessions via `/deepwork <task>` command
+- Maintain `.slim/deepwork/` progress tracking files
+- Keep OpenCode todos synchronized with current phase
+- Enforce phased implementation with `@oracle` review gates
+- Execute phases with background specialist agents where appropriate
+- Validate results and incorporate simplification/readability feedback
+
+## Design
+
+### Core Abstraction
+The hook follows the OpenCode plugin hook pattern, exposing a factory function `createDeepworkCommandHook()` that returns an object with two methods:
+
+- `registerCommand(config)`: Registers the `deepwork` command in OpenCode configuration
+- `handleCommandExecuteBefore(input, output)`: Intercepts command execution to inject the deepwork activation prompt
+
+### State Management
+- Uses OpenCode's internal agent text part system (`createInternalAgentTextPart`) for output
+- Clears existing output parts before injecting deepwork prompt
+- Validates task presence before activation
+
+### Integration Points
+- Consumes OpenCode session context (`sessionID`)
+- Integrates with OpenCode command system via `command` configuration
+- Leverages `@oracle` for review and simplification feedback
+- Supports background specialist agents (`@fixer`, `@explorer`, etc.) for phase execution
+
+## Flow
+
+### Command Registration Phase
+1. Plugin initialization calls `registerCommand()` with OpenCode configuration
+2. Checks if `deepwork` command already registered
+3. If not, adds command configuration:
+   - Template: "Start a deepwork session for a complex coding task"
+   - Description: "Use the deepwork workflow for heavy multi-phase coding work"
+
+### Command Execution Phase
+1. User invokes `/deepwork <task>` command
+2. OpenCode triggers `handleCommandExecuteBefore()` hook
+3. Hook validates command name (`deepwork`)
+4. If no task provided:
+   - Outputs error message via `createInternalAgentTextPart()`
+   - Prompts user: "What task should deepwork manage? Run `/deepwork <task>`."
+5. If task provided:
+   - Clears existing output parts (`output.parts.length = 0`)
+   - Generates activation prompt via `activationPrompt(task)`
+   - Injects activation prompt into output parts
+   - Prompt instructs agents to use deepwork skill with specific requirements
+
+### Deepwork Session Execution
+1. Agent receives activation prompt with task description
+2. Agent creates `.slim/deepwork/` progress file
+3. Agent maintains OpenCode todo synchronization
+4. Agent drafts plan and requests `@oracle` review
+5. Agent creates and reviews phased implementation/delegation plan
+6. Agent executes phases with background specialists as needed
+7. Agent waits for hook-driven background completion
+8. Agent reconciles results and validates
+9. Agent requests `@oracle` review for each phase
+10. Agent incorporates simplification/readability feedback
+11. Agent fixes actionable review issues before continuing
+
+## Integration
+
+### Consumers
+- **Main plugin** (`src/index.ts`): Registers the deepwork hook during plugin initialization
+- **OpenCode CLI**: Invokes hook when `/deepwork` command is executed
+- **Agents** (`@oracle`, `@fixer`, `@explorer`, etc.): Follow deepwork workflow for complex tasks
+
+### Dependencies
+- **OpenCode SDK**: Provides `createInternalAgentTextPart` utility and hook interface
+- **Configuration system**: Reads from `opencodeConfig.command` structure
+- **Session system**: Receives `sessionID` for context tracking
+- **Agent ecosystem**: Leverages specialist agents for phase execution
+
+
+### Configuration Schema
+```json
+{
+  "command": {
+    "deepwork": {
+      "template": "Start a deepwork session for a complex coding task",
+      "description": "Use the deepwork workflow for heavy multi-phase coding work"
+    }
+  }
+}
+```
+
+### File System
+- Creates progress tracking: `.slim/deepwork/<session-id>/` directory and files
+- Maintains synchronization with OpenCode todos
+
+
+### Hook Contract
+- **Input**: `{ command: string, sessionID: string, arguments: string }`
+- **Output**: `{ parts: Array<{ type: string, text?: string }> }`
+- **Side effects**: Modifies output parts array, may create progress files
+- **Validation**: Validates task presence, validates command name

+ 57 - 32
src/hooks/delegate-task-retry/codemap.md

@@ -1,44 +1,69 @@
 # src/hooks/delegate-task-retry/
 
 ## Responsibility
-
-Adds targeted recovery guidance for failed delegation (`task`) calls by analyzing
-tool output and appending a concise retry hint that preserves the existing model
-conversation context.
+Orchestrates automatic retry guidance for failed task delegation attempts by detecting specific error patterns and injecting contextual retry suggestions into tool output.
 
 ## Design
 
-- `index.ts` re-exports:
-  - `createDelegateTaskRetryHook`
-  - `buildRetryGuidance`
-  - pattern types/helpers
-- `patterns.ts` defines the typed `DelegateTaskErrorPattern` contract and ordered
-  detection catalog (`DELEGATE_TASK_ERROR_PATTERNS`).
-- `detectDelegateTaskError(output)`:
-  1. ensures string output,
-  2. requires one of generic error indicators,
-  3. returns the first matching configured error pattern.
-- `buildRetryGuidance(errorInfo)` maps each match to user-facing fix text,
-  optionally appending `Available:` suggestions parsed from tool output.
-- `hook.ts` returns a `tool.execute.after` handler and mutates only string
-  outputs.
+### Core Components
+- **Error Detection**: Pattern-based error classifier (`detectDelegateTaskError`) that identifies known delegate-task failure modes from tool output
+- **Retry Guidance Builder**: Constructs actionable retry suggestions with context-specific fix hints
+- **Available Agents Extractor**: Parses tool output to discover currently permitted agents for targeted retries
+
+### Architecture Pattern
+Uses the **Observer** pattern via OpenCode's plugin hook system:
+- Subscribes to `tool.execute.after` lifecycle hook
+- Intercepts output from the `task` tool (delegate-task)
+- Mutates output in-place to append retry guidance without breaking existing workflows
+
+### Error Classification
+Leverages a predefined set of error patterns (`DELEGATE_TASK_ERROR_PATTERNS`) that map:
+- Error type identifiers (e.g., "invalid-category", "missing-required-field")
+- Human-readable fix hints
+- Regex patterns for detection
 
 ## Flow
 
-1. OpenCode invokes the handler with `{ tool, output }` after `task` execution.
-2. The hook ignores non-`task` tools and non-string outputs.
-3. If output passes generic error signal checks, `detectDelegateTaskError` scans
-   configured patterns.
-4. On match, inline guidance is appended to `output.output` with correction
-   guidance and example `task(...)` usage.
-5. No additional API calls are made; behavior is synchronous string-level
-   recovery.
+### Execution Sequence
+1. **Hook Registration**: Plugin loads `createDelegateTaskRetryHook` during initialization
+2. **Event Subscription**: Hook subscribes to `tool.execute.after` lifecycle event
+3. **Tool Filtering**: Only processes output from the `task` tool (delegate-task delegation)
+4. **Error Detection**: Runs `detectDelegateTaskError()` on tool output string
+5. **Guidance Generation**: If error detected:
+   - Looks up error pattern to get fix hint
+   - Extracts available agent list from output
+   - Constructs multi-line retry suggestion with:
+     - Detected error type
+     - Pattern-specific fix hint
+     - Available agent list (if present)
+     - Example retry invocation
+6. **Output Mutation**: Appends generated retry guidance to tool output string
+7. **Propagation**: Modified output returned to caller for display/user action
+
+### Error Handling
+- **No-op on success**: If no delegate-task error detected, hook exits early without modifying output
+- **Type safety**: Validates output is a string before processing
+- **Graceful degradation**: Falls back to generic retry suggestion if error pattern not recognized
 
 ## Integration
 
-- Registered in `src/index.ts` under `tool.execute.after`.
-- Input payload expectations are minimal (`{ tool: string }` + `{ output: unknown }`)
-  to stay aligned with tool-callback shape and avoid side-effecting unrelated
-  callbacks.
-- This hook remains independent of orchestration engines and multiplexer/session
-  managers.
+### Dependencies
+- **OpenCode Plugin System**: Consumes `tool.execute.after` lifecycle hook
+- **Error Patterns Module**: Imports `DELEGATE_TASK_ERROR_PATTERNS` and `detectDelegateTaskError` from `./patterns.ts`
+- **Task Tool**: Specifically targets the `task` tool used for delegate-task operations
+
+### Consumers
+- **OpenCode Core**: Receives enhanced tool output with retry guidance
+- **User Workflow**: Displays actionable error context and retry examples in OpenCode UI
+
+### Configuration
+- **No user configuration required**: Pattern matching and guidance generation are hardcoded for reliability
+- **Extensible patterns**: New error types can be added by extending `DELEGATE_TASK_ERROR_PATTERNS` array
+
+### Lifecycle Hook
+```typescript
+'tool.execute.after': async (input, output) => { ... }
+```
+- Triggered after every tool execution in OpenCode
+- Runs asynchronously but synchronously with respect to tool output processing
+- Mutates output object in-place (standard OpenCode plugin hook contract)

+ 100 - 19
src/hooks/filter-available-skills/codemap.md

@@ -2,31 +2,112 @@
 
 ## Responsibility
 
-- Filter `<available_skills>` payload fragments in outgoing messages so they only include skills permitted for the active agent.
+Implements the skill filtering hook that dynamically filters the `<available_skills>` block in chat messages based on the current agent's permission rules. This ensures agents only see skills they're authorized to use.
 
 ## Design
 
-- Factory `createFilterAvailableSkillsHook(_ctx, config)` is defined in `index.ts` and implements `experimental.chat.messages.transform`.
-- `getCurrentAgent(messages)` scans backward for the latest user message and defaults to `orchestrator`.
-- `filterAvailableSkillsText(text, permissionRules)` is the pure transformation function used per message part.
-- Permissions flow:
-  - `getAgentOverride(config, agentName)` from `cli/config` resolves override arrays.
-  - `getSkillPermissionsForAgent` from `cli/skills` resolves canonical rules (`allow`, `ask`, `deny` wildcard).
-  - `isSkillAllowed` checks exact skill rule first, then `'*'` wildcard fallback.
-- `<available_skills>...</available_skills>` and nested `<skill>...</skill>` blocks are matched with regex extraction.
+The hook is implemented as an `experimental.chat.messages.transform` hook that runs just before messages are sent to the API. It does not affect UI display.
+
+### Core Components:
+
+- **SkillEntry**: Represents a single skill with name and XML block
+- **SkillRule**: Permission types ('allow', 'ask', 'deny')
+- **Permission Rules Cache**: Maps agent names to their skill permission rules for performance
+
+### Permission Resolution Flow:
+
+1. **Agent Detection**: Extracts current agent name from message history (defaults to 'orchestrator')
+2. **Permission Lookup**: Retrieves skill rules for the agent from configuration
+3. **Block Extraction**: Uses regex to parse `<skill>` blocks from `<available_skills>` XML
+4. **Filtering**: Applies permission rules to each skill entry
+5. **Reconstruction**: Rebuilds the `<available_skills>` block with only allowed skills
+
+### Key Functions:
+
+- `getCurrentAgent()`: Extracts agent name from message metadata
+- `extractSkillEntries()`: Parses XML skill blocks using regex
+- `isSkillAllowed()`: Evaluates permission rules for a skill
+- `filterAvailableSkillsText()`: Main filtering logic that rewrites the XML block
+- `createFilterAvailableSkillsHook()`: Factory that creates the hook instance
 
 ## Flow
 
-1. In transform output, determine `agentName` via `getCurrentAgent`.
-2. Load `permissionRules = getSkillPermissionsForAgent(agentName, configuredSkills)`.
-3. For each `text` part containing `<available_skills>`, run regex replacement:
-   - parse `<skill>` entries,
-   - keep only allowed names,
-   - fallback to `<available_skills>\nNo skills available.\n</available_skills>` when none match.
-4. Write transformed `part.text` back to `output.messages` in place.
+```
+Message Preparation → Hook Execution → Message Transformation → API Send
+                     ↓
+            filterAvailableSkillsText()
+                     ↓
+            Extract skill entries from <available_skills>
+                     ↓
+            Check each skill against permission rules
+                     ↓
+            Rebuild XML block with allowed skills only
+```
+
+### Detailed Execution Sequence:
+
+1. **Hook Creation** (`createFilterAvailableSkillsHook`):
+   - Called during plugin initialization
+   - Creates a permission rules cache per agent
+   - Returns the hook function
+
+2. **Hook Execution** (`experimental.chat.messages.transform`):
+   - Triggered before each message batch is sent to API
+   - Receives the message array with parts
+   - Identifies current agent from message metadata
+   - Retrieves cached permission rules for that agent
+
+3. **Skill Filtering** (`filterAvailableSkillsText`):
+   - Scans each message part for `<available_skills>` XML
+   - Extracts individual `<skill>` blocks using regex
+   - For each skill, checks permission rules:
+     - Specific skill rule takes precedence
+     - Wildcard rule ('*') applies as fallback
+   - Reconstructs XML block with only allowed skills
+   - Returns "No skills available." if all skills are filtered out
+
+4. **Result**:
+   - Modified messages are sent to API with filtered skill list
+   - UI remains unchanged (filtering happens server-side)
 
 ## Integration
 
-- Hook is wired in `src/hooks/index.ts` and consumed by plugin hook registration.
-- Executed in the message path prior to model call, so users do not see changed prompt text in UI, but the model receives constrained capabilities.
-- Depends on `cli/skills` and `config` modules, and `PluginInput` only for registration compatibility.
+### Consumed By:
+- **Main Plugin**: Integrated via `src/index.ts` plugin initialization
+- **Configuration System**: Depends on `src/config/` for agent overrides and skill permissions
+- **CLI**: Uses `src/cli/skills.ts` for default skill permission definitions
+
+
+### Dependencies:
+- **@opencode-ai/plugin**: Plugin input/output types
+- **src/config/**: Plugin configuration and agent overrides
+- **src/cli/skills.ts**: Default skill permission rules
+- **OpenCode Core**: Injects `<available_skills>` block globally in messages
+
+### Integration Points:
+- **Message Pipeline**: Hooks into `experimental.chat.messages.transform` lifecycle
+- **Permission System**: Works with `disabled_skills` and agent-specific skill configurations
+- **Agent Context**: Dynamically adapts to current agent based on message history
+
+
+### Configuration Schema:
+- **Agent Overrides**: Skills can be customized per agent in configuration
+- **Disabled Skills**: Global skill blacklist via `disabled_skills` config
+- **Permission Rules**: Skill-specific rules override wildcard rules
+
+### Example Usage Flow:
+
+```
+User Message → Agent Selection → Skill Filtering → API Request → Response
+                     ↓
+            filterAvailableSkillsHook runs
+                     ↓
+            Only authorized skills visible to agent
+```
+
+## Performance Considerations
+
+- Permission rules are cached per agent to avoid repeated configuration lookups
+- Regex-based parsing is efficient for the relatively small `<available_skills>` block
+- Hook runs only once per message batch, not per message
+- No impact on UI rendering performance

+ 98 - 42
src/hooks/foreground-fallback/codemap.md

@@ -1,54 +1,110 @@
 # src/hooks/foreground-fallback/
 
 ## Responsibility
-
-Provides reactive model fallback for foreground (interactive) sessions when
-rate-limit or provider-limit signals are observed in event streams.
+Runtime model fallback system for foreground (interactive) agent sessions. When OpenCode emits rate-limit signals via `message.updated`, `session.error`, or `session.status` events, this manager:
+- Detects rate-limit conditions using pattern matching against error messages and status codes
+- Aborts the rate-limited prompt via `client.session.abort()`
+- Retrieves the last user message from the session history
+- Re-prompts the session with the next available model from the agent's configured fallback chain
+- Operates reactively through the event system (cannot wrap `prompt()` directly for interactive sessions)
 
 ## Design
 
-- `index.ts` exports:
-  - `ForegroundFallbackManager`
-  - `isRateLimitError(error)`
-- Manager state is per-session maps for:
-  - active model (`sessionModel`)
-  - mapped agent (`sessionAgent`)
-  - attempted models (`sessionTried`)
-  - dedupe timestamp (`lastTrigger`)
-  - in-flight fallback lock (`inProgress`)
-- Rate-limit detection is regex based and also checks structured payload fields
-  (`message`, `statusCode`, `data.message`, `data.responseBody`).
-- Fallback selection uses `resolveChain(agentName, currentModel)` with ordered
-  priority:
-  1. exact agent chain (if configured)
-  2. no-chain if agent is known but unconfigured
-  3. infer from current model
-  4. flattened fallback across all chains
-- Re-submission uses `client.session.promptAsync` with last-user message parts and
-  parsed `{ providerID, modelID }` target.
+### Core Abstraction
+- **ForegroundFallbackManager**: Singleton class instantiated at plugin initialization
+- Maintains per-session state tracking:
+  - `sessionModel`: Maps sessionID → current model string ("providerID/modelID")
+  - `sessionAgent`: Maps sessionID → agent name
+  - `sessionTried`: Maps sessionID → Set of models already attempted
+  - `inProgress`: Set of sessions with active fallback in flight
+  - `lastTrigger`: Maps sessionID → timestamp for deduplication
+
+### Fallback Chain Resolution
+- **Agent-specific chains**: Each agent defines an ordered list of fallback models via `_modelArray` entries
+- **Chain lookup**: Resolves the correct chain using:
+  1. Agent name (primary) → exact match
+  2. Current model (fallback) → search all chains for containing model
+  3. Merged list (last resort) → preserve insertion order across all agents
+- **No cross-agent bleed**: When agent is identified, only that agent's chain is used (prevents re-prompting with wrong agent's models)
+
+### Rate-Limit Detection
+- **Pattern matching**: Comprehensive regex patterns for rate-limit error messages (429, "rate limit", "too many requests", "quota exceeded", etc.)
+- **Event coverage**: Handles three OpenCode event types:
+  - `message.updated`: Error in message metadata
+  - `session.error`: Session-level error event
+  - `session.status`: Status message containing rate-limit indicators
+
+### State Management
+- **Deduplication window**: 5-second cooldown (`DEDUP_WINDOW_MS`) to prevent multiple triggers for same rate-limit event
+- **Session cleanup**: `session.deleted` event handler removes all per-session state to prevent memory leaks
+- **In-progress tracking**: Prevents concurrent fallback attempts on same session
 
 ## Flow
 
-1. `handleEvent` receives each plugin event.
-2. On `message.updated`, `session.error`, and retry `session.status`, it checks
-   rate-limit markers and calls `tryFallback(sessionID)` when matched.
-3. `subagent.session.created` updates session-to-agent mappings for better chain
-   resolution.
-4. `tryFallback(sessionID)` enforces:
-   - feature enablement flag,
-   - one-at-a-time lock,
-   - dedupe window (`DEDUP_WINDOW_MS = 5000`).
-5. It marks current model attempted, chooses next untried model from the chain,
-   fetches latest user message via `session.messages`, aborts the active prompt via
-   `session.abort()`, waits 500ms, and re-prompts with `promptAsync`.
-6. Success updates session model memory; failures log structured diagnostics.
-7. `session.deleted` cleanup removes all per-session bookkeeping to avoid memory
-   growth.
+### Event Processing Pipeline
+```
+OpenCode Event (message.updated/session.error/session.status)
+    ↓
+ForegroundFallbackManager.handleEvent()
+    ↓
+Rate-limit detection via isRateLimitError()
+    ↓
+tryFallback(sessionID) [deduplicated, in-progress guarded]
+    ↓
+Resolve fallback chain for session
+    ↓
+Abort current rate-limited prompt (with timeout)
+    ↓
+Retrieve last user message from session history
+    ↓
+Re-prompt session with next model via promptAsync()
+    ↓
+Update session state with new model
+    ↓
+Log fallback event
+```
+
+### Key Operations
+1. **Abort with timeout**: `abortSessionWithTimeout()` sends Ctrl+C to pane then kills it after 250ms delay
+2. **Message retrieval**: Queries session messages via `client.session.messages()` and finds last user message
+3. **Model switching**: Uses `parseModelReference()` to extract providerID/modelID from chain entry
+4. **Re-prompting**: Calls `promptAsync()` which queues prompt and returns immediately (non-blocking)
 
 ## Integration
 
-- Wired through plugin-level `event` hook in `src/index.ts`.
-- Uses `ctx.client.session` APIs (`messages`, `abort`, `promptAsync`) and
-  depends on runtime fallback chains provided from configuration.
-- Designed as an interactive-session safety net when delegated/caller-side retry
-  logic is unavailable or too late.
+### Consumers
+- **Primary**: Main plugin initialization (`src/index.ts`) creates ForegroundFallbackManager instance
+- **Event source**: OpenCode plugin event system provides `message.updated`, `session.error`, `session.status`, `session.deleted` events
+
+### Dependencies
+- **OpenCode SDK**: `PluginInput['client']` for session management and event handling
+- **Utilities**:
+  - `abortSessionWithTimeout()`: Graceful session termination
+  - `parseModelReference()`: Model string parsing ("providerID/modelID")
+  - `log()`: Structured logging for observability
+- **Configuration**: Fallback chains provided at construction from agent configurations
+
+### Configuration Schema
+Fallback chains are provided as `Record<string, string[]>` where:
+- Key: Agent name (e.g., "orchestrator", "explorer")
+- Value: Ordered list of model strings (e.g., `["anthropic/claude-opus-4-5", "openai/gpt-4o"]`)
+
+### Memory Management
+- **Per-session state**: All maps cleared on `session.deleted` event
+- **Deduplication**: Prevents unbounded growth in long-running instances with many subagent sessions
+
+### Observability
+- **Logging**: Structured logs at key points:
+  - Rate-limit detection
+  - Fallback initiation
+  - Model switching
+  - Chain exhaustion
+  - Abort failures
+  - PromptAsync unavailability
+
+## Error Handling
+- **Graceful degradation**: Best-effort approach; abort may be slow or incomplete
+- **Validation**: Checks for `promptAsync` availability before attempting re-prompt
+- **Fallback exhaustion**: Logs when entire chain has been attempted without success
+- **Invalid model format**: Skips malformed model references
+- **Missing user message**: Aborts fallback attempt if no user message found in history

+ 63 - 17
src/hooks/json-error-recovery/codemap.md

@@ -2,29 +2,75 @@
 
 ## Responsibility
 
-- Detect likely JSON syntax/parse failures in tool outputs and append a strong, non-redundant recovery prompt so the model replays corrected JSON on retry.
+Provides automatic JSON error detection and recovery for OpenCode plugin tool execution. This hook monitors tool output for JSON parse errors and injects a standardized error reminder to guide users toward correcting their JSON syntax.
 
 ## Design
 
-- `hook.ts` contains the implementation with exported constants:
-  - `JSON_ERROR_TOOL_EXCLUDE_LIST`
-  - `JSON_ERROR_PATTERNS`
-  - `JSON_ERROR_REMINDER`
-- `createJsonErrorRecoveryHook(_ctx)` returns a `tool.execute.after` handler that appends reminder text when parsing failed.
-- `JSON_ERROR_REMINDER_MARKER` prevents recursive duplicate injection.
-- Exclusion is by lowercase tool name (`bash`, `read`, `glob`, web tools) through a `Set`.
-- Matching uses regex literals in `JSON_ERROR_PATTERNS` and short-circuits for non-string output.
-- `index.ts` only re-exports hook/constant surface.
+### Core Components
+
+- **JSON_ERROR_TOOL_EXCLUDE_LIST**: Set of tools excluded from JSON error checking (bash, read, glob, webfetch, gh_grep_searchgithub, websearch_web_search_exa)
+- **JSON_ERROR_PATTERNS**: Array of regex patterns for detecting various JSON error messages
+- **JSON_ERROR_REMINDER**: Standardized error message template instructing users on JSON correction
+- **createJsonErrorRecoveryHook()**: Factory function that returns the OpenCode plugin hook
+
+### Hook Architecture
+
+The hook implements the OpenCode plugin's `tool.execute.after` lifecycle hook:
+- Triggered after every tool execution
+- Validates output is a string
+- Checks for JSON error patterns in output
+- Appends error reminder when JSON errors are detected
+
+### Error Detection Logic
+
+1. **Tool Exclusion Check**: Skips excluded tools immediately
+2. **Output Type Check**: Verifies output is a string before processing
+3. **Marker Check**: Skips output already containing the error reminder marker
+4. **Pattern Matching**: Tests output against multiple JSON error regex patterns
+5. **Reminder Injection**: Appends standardized error reminder to output
 
 ## Flow
 
-1. In `tool.execute.after`, normalize `input.tool` to lowercase and skip excluded tools.
-2. Skip when `output.output` is not a string.
-3. Skip if output already contains `JSON_ERROR_REMINDER_MARKER`.
-4. Evaluate all `JSON_ERROR_PATTERNS`; on match, append `\n${JSON_ERROR_REMINDER}` to `output.output`.
+```
+Tool Execution → tool.execute.after Hook Trigger → 
+  [Check Exclusion] → [Validate Output Type] → [Check Marker] →
+  [Pattern Matching] → [Inject Reminder if JSON Error Detected] → Return Output
+```
+
+### Detailed Execution Sequence
+
+1. **Hook Registration**: `createJsonErrorRecoveryHook()` is called during plugin initialization
+2. **Event Subscription**: Hook subscribes to `tool.execute.after` lifecycle event
+3. **Filtering**: Excluded tools are checked first for performance optimization
+4. **Validation**: Output type is verified to be a string
+5. **Duplicate Prevention**: Outputs already containing the error marker are skipped
+6. **Pattern Testing**: Output is tested against all JSON error patterns
+7. **Reminder Injection**: If any pattern matches, the standardized error reminder is appended to the output
+8. **Result Return**: Modified output is returned to the OpenCode plugin system
 
 ## Integration
 
-- Exported from `src/hooks/index.ts` and attached to tool output lifecycle at plugin registration.
-- Only consumes hook payload contracts (`ToolExecuteAfterInput`, `ToolExecuteAfterOutput`) and standard string checks, making it generic across tools.
-- No direct dependency on tool internals; integrates by observing tool-call results before they are surfaced to the model.
+### Consumers
+
+- **Primary Consumer**: OpenCode plugin system via the `tool.execute.after` lifecycle hook
+- **Error Path**: JSON errors in tool arguments are detected and surfaced to users
+
+### Dependencies
+
+- **OpenCode Plugin SDK**: `@opencode-ai/plugin` for PluginInput type definitions
+- **Lifecycle Events**: Relies on the `tool.execute.after` event being emitted by OpenCode
+
+### Integration Points
+
+- **Plugin Initialization**: Hook is created during plugin startup via `createJsonErrorRecoveryHook()`
+- **Tool Execution Pipeline**: Integrates into the post-execution phase of all tool calls
+- **User Feedback Loop**: Provides immediate, actionable feedback when JSON errors occur
+
+### Configuration
+
+The hook uses hardcoded constants for:
+- Excluded tools list
+- JSON error patterns
+- Error reminder message
+
+These can be extended or modified by updating the hook implementation.

+ 40 - 18
src/hooks/phase-reminder/codemap.md

@@ -1,30 +1,52 @@
 # src/hooks/phase-reminder/
 
 ## Responsibility
-
-Keep orchestrator guidance aligned over long turns by prepending a phase reminder to the latest user message text before the next LLM request.
+Orchestrates phase reminder injection into user messages for the orchestrator agent, ensuring workflow guidance is appended without mutating the original message content or affecting UI display.
 
 ## Design
 
-- `PHASE_REMINDER` constant is composed from `PHASE_REMINDER_TEXT` (`config/constants.ts`).
-- `createPhaseReminderHook()` returns a single `experimental.chat.messages.transform` handler.
-- Message filtering is role/agent-aware:
-  - locates the latest `'user'` role in `output.messages`,
-  - only mutates if no explicit agent or `agent === 'orchestrator'`,
-  - no-op for internal control messages containing `SLIM_INTERNAL_INITIATOR_MARKER`.
-- Mutation target is the first `text` part in that message; replacement is an in-place prefix.
-- Uses `SLIM_INTERNAL_INITIATOR_MARKER` from `../../utils` to avoid feedback loops.
+### Core Abstraction
+- **Hook Factory**: `createPhaseReminderHook()` returns an OpenCode experimental chat message transformer hook
+- **Non-Mutating Strategy**: Appends phase reminder as a separate message part rather than modifying user-authored text
+- **Targeted Injection**: Only processes messages from the orchestrator agent
+
+### Key Components
+- `PHASE_REMINDER` constant (imported from `../../config/constants`)
+- `SLIM_INTERNAL_INITIATOR_MARKER` constant (imported from `../../utils`)
+- Message part type checking and injection logic
+
+### Design Patterns
+- **Observer Pattern**: Intercepts and transforms messages before API transmission without altering source
+- **Guard Clauses**: Multiple preconditions prevent unnecessary processing:
+  - Empty message check
+  - User message existence check
+  - Orchestrator agent check
+  - Duplicate injection prevention
+  - Internal initiator marker check
 
 ## Flow
 
-1. On transform, scan backward through `messages` for last `info.role === 'user'`.
-2. If agent is non-orchestrator, return.
-3. Locate first part where `type === 'text'`.
-4. If marker exists, return.
-5. Prefix `part.text` with `PHASE_REMINDER + '\n\n---\n\n'`.
+1. **Hook Invocation**: OpenCode calls the `experimental.chat.messages.transform` hook before sending messages to API
+2. **Message Analysis**: Iterates backward through messages to find the last user message
+3. **Agent Validation**: Confirms the message is from the orchestrator agent
+4. **Text Part Detection**: Locates the text part in the message
+5. **Duplicate Prevention**: Checks for existing phase reminder injection
+6. **Injection**: Appends phase reminder as a new text message part
+7. **Transmission**: Messages proceed to API with injected reminder (not visible in UI)
 
 ## Integration
 
-- Registered through `src/hooks/index.ts` and plugin-level hook wiring in `src/index.ts`.
-- Consumes `experimental.chat.messages.transform` and mutates the outgoing `messages` payload only.
-- Does not depend on stateful services; no network or client APIs are required.
+### Dependencies
+- **Config**: `PHASE_REMINDER` constant from `../../config/constants`
+- **Utils**: `SLIM_INTERNAL_INITIATOR_MARKER` from `../../utils`
+- **Types**: `MessageWithParts` type from `../types`
+
+### Consumers
+- **OpenCode**: Registers the hook via plugin initialization
+- **Orchestrator Agent**: Receives phase reminders in messages
+- **API Layer**: Receives messages with injected reminders (UI remains unaffected)
+
+### Context
+- **Execution Timing**: Runs right before API transmission (post-UI rendering)
+- **Scope**: Only affects orchestrator agent messages
+- **Persistence**: Reminder is appended as a separate message part, preserving original content

+ 57 - 18
src/hooks/post-file-tool-nudge/codemap.md

@@ -1,29 +1,68 @@
 # src/hooks/post-file-tool-nudge/
 
 ## Responsibility
-
-Detect recent file interaction (`Read`/`Write`) and queue a one-shot workflow reminder that is injected on the next system prompt transform without mutating tool execution output.
+Implements a post-tool execution hook that automatically appends delegation reminders to file operation outputs, preventing the "inspect/edit files → implement myself" anti-pattern where agents attempt to implement functionality themselves instead of delegating to specialized tools.
 
 ## Design
 
-- Factory `createPostFileToolNudgeHook(options?)` emits three handlers:
-  - `tool.execute.after`
-  - `experimental.chat.system.transform`
-  - `event`
-- A per-instance in-memory `pendingSessionIds: Set<string>` tracks sessions that recently ran file tools.
-- `FILE_TOOLS` is the canonical set `{ 'Read', 'read', 'Write', 'write' }`.
-- Injection is optional per session via `options.shouldInject?: (sessionID) => boolean`.
-- Cleanup path handles both `session.deleted` payload shapes (`properties.sessionID` and `properties.info.id`).
+### Hook Structure
+- **Factory Pattern**: `createPostFileToolNudgeHook()` returns a hook object with a `tool.execute.after` handler
+- **Conditional Injection**: Uses `shouldInject` option to filter sessions where the reminder should be applied
+- **Set-based Tool Filtering**: Maintains a Set of file tool names for O(1) lookup
+
+### Core Logic
+```typescript
+const FILE_TOOLS = new Set(['Read', 'read', 'Write', 'write']);
+
+function appendReminder(output: ToolExecuteAfterOutput): void {
+  if (typeof output.output !== 'string') return;
+  if (output.output.includes(PHASE_REMINDER)) return;
+  output.output = `${output.output}\n\n${PHASE_REMINDER}`;
+}
+```
+
+### Integration Points
+- **Config Dependency**: Imports `PHASE_REMINDER` constant from `../../config/constants`
+- **Hook Registration**: Hooks into OpenCode's `tool.execute.after` lifecycle phase
+- **Session Context**: Receives `sessionID` to support session-specific filtering
 
 ## Flow
-1. `tool.execute.after`: if tool is file tool and has `sessionID`, add it to `pendingSessionIds`.
-2. `experimental.chat.system.transform`: if session has pending marker, remove it and append `POST_FILE_TOOL_NUDGE` (`PHASE_REMINDER_TEXT`) to `output.system`.
-3. Optional `shouldInject` gate can consume without injecting.
-4. Additional `Read`/`Write` events before the same transform collapse to one reminder due to set semantics.
-5. `session.deleted` event removes stale session IDs from the set.
+
+1. **Trigger**: File tool (Read/Write) completes execution
+2. **Validation**:
+   - Check if tool is a file tool (Read/read/Write/write)
+   - Verify sessionID exists
+   - Apply shouldInject filter if provided
+3. **Reminder Injection**:
+   - Extract output string
+   - Check if PHASE_REMINDER already present (idempotent)
+   - Append PHASE_REMINDER to output
+4. **Result**: Agent receives output with delegation reminder prepended
 
 ## Integration
 
-- Registered via `src/hooks/index.ts` and activated in plugin lifecycle registration.
-- Mutates `output.system` only, ensuring persisted file tool outputs remain untouched.
-- Consumed by orchestrator session flows that need anti-pattern mitigation (`inspect/edit` loops).
+- **Consumed by**: OpenCode plugin lifecycle hooks (src/index.ts)
+- **Depends on**: 
+  - Config system (PHASE_REMINDER constant)
+  - Tool execution framework (tool.execute.after phase)
+  - Session management (sessionID for filtering)
+
+## Usage Example
+
+```typescript
+const hook = createPostFileToolNudgeHook({
+  shouldInject: (sessionID) => sessionID.includes('user-requested')
+});
+
+// In plugin initialization:
+hooks.register('tool.execute.after', hook['tool.execute.after']);
+```
+
+## Anti-Pattern Prevention
+
+This hook addresses the common failure mode where agents:
+- Read file contents to understand implementation
+- Attempt to implement changes themselves instead of delegating to specialized tools
+- Violate the delegation principle of the OpenCode architecture
+
+The reminder reinforces the expected workflow: inspect → delegate → implement via specialized agents.

+ 114 - 0
src/hooks/reflect/codemap.md

@@ -0,0 +1,114 @@
+# src/hooks/reflect/
+
+## Responsibility
+Implements a reflection hook that enables OpenCode to analyze repeated workflow patterns and suggest reusable improvements. This hook provides a `/reflect` command that generates contextual prompts for reviewing recent work and identifying workflow friction points worth improving.
+
+## Design
+
+### Core Components
+- **Command Registration**: Dynamically registers the `reflect` command in OpenCode's configuration system
+- **Activation Prompt Generation**: Creates context-aware reflection prompts based on user-provided focus areas
+- **Command Interception**: Intercepts command execution to replace default behavior with reflection-focused output
+
+### Architecture Pattern
+- **Hook Pattern**: Follows OpenCode's hook system for extending plugin functionality
+- **Template Method Pattern**: Uses command templates with dynamic content generation
+- **Observer Pattern**: Reacts to command execution lifecycle events
+
+## Flow
+
+### Command Registration Flow
+1. Plugin initialization calls `registerCommand()` with OpenCode configuration
+2. Checks if `reflect` command already exists in config
+3. If not, registers the command with:
+   - Template: "Review repeated work and suggest workflow improvements"
+   - Description: "Use reflect to learn from repeated workflows and suggest reusable improvements"
+4. Sets `shouldHandleCommand` flag to enable command handling
+
+### Command Execution Flow
+1. User invokes `/reflect` command with optional arguments
+2. `handleCommandExecuteBefore()` hook intercepts the execution
+3. Clears existing output parts
+4. Generates activation prompt using `activationPrompt()` helper:
+   - If focus argument provided: uses it as primary focus
+   - If no focus: provides default focus about reviewing work broadly
+   - Includes reflection requirements and evidence-based recommendations
+5. Replaces output with the generated reflection prompt
+
+### Prompt Generation Logic
+```typescript
+function activationPrompt(focus: string): string {
+  const focusBlock = focus
+    ? ['Focus:', focus]
+    : [
+        'Focus:',
+        'Review recent work broadly and identify repeated workflow friction worth improving.',
+      ];
+
+  return [
+    'Use the reflect skill for this request.',
+    '',
+    'Reflect requirements:',
+    '- inspect existing skills, commands, agents, prompt overrides, MCP permissions, config, and project playbooks before suggesting anything new;',
+    '- find repeated workflow patterns from the current conversation, project notes, local memories, logs, or session artifacts that are available and safe to inspect;',
+    '- prefer evidence from repeated recent behavior over speculation;',
+    '- recommend the smallest useful improvement: prompt/config rule, skill, command, custom agent, MCP/tool permission change, project playbook, or skip;',
+    '- treat creating nothing as a valid result when evidence is weak;',
+    '- ask before changing prompts, skills, commands, agents, MCP access, or config unless the user explicitly requested the exact edit;',
+    '- return a compact report with findings, recommended changes, skipped candidates, and items needing more evidence.',
+    '',
+    ...focusBlock,
+  ].join('\n');
+}
+```
+
+## Integration
+
+### Dependencies
+- **OpenCode Plugin System**: Uses `registerCommand` and `handleCommandExecuteBefore` hook interfaces
+- **Configuration System**: Reads and writes to OpenCode configuration object
+- **Command Lifecycle**: Integrates with OpenCode's command execution pipeline
+
+
+### Consumers
+- **OpenCode Core**: Consumed by OpenCode's plugin system during initialization
+- **Users**: Invoked via `/reflect` command in OpenCode sessions
+
+### Integration Points
+- `registerCommand()`: Called during plugin initialization to register the reflect command
+- `handleCommandExecuteBefore()`: Hook that intercepts command execution and transforms output
+- OpenCode configuration object: Receives the registered command configuration
+
+### Configuration Schema
+```json
+{
+  "command": {
+    "reflect": {
+      "template": "Review repeated work and suggest workflow improvements",
+      "description": "Use reflect to learn from repeated workflows and suggest reusable improvements"
+    }
+  }
+}
+```
+
+## Usage Examples
+
+### Basic Usage
+```
+/reflect
+```
+Generates a default reflection prompt focused on reviewing recent work broadly.
+
+### Focused Reflection
+```
+/reflect Focus: Improve test coverage workflow
+```
+Generates a reflection prompt focused specifically on test coverage workflow improvements.
+
+### Workflow Analysis
+The hook helps identify:
+- Repeated manual steps in workflows
+- Configuration duplication across projects
+- Permission or MCP access patterns that could be streamlined
+- Prompt templates that could be generalized into skills
+- Commands that could be automated or combined

+ 85 - 33
src/hooks/task-session-manager/codemap.md

@@ -2,45 +2,97 @@
 
 ## Responsibility
 
-Provides V2 background job-board state for `task` output and injected completion messages so the
-orchestrator can track active jobs and reuse only completed, reconciled child
-sessions by short aliases (`exp-1`, `ora-2`).
+Manages V2 background job-board state for task execution and injected completion messages, enabling the orchestrator to track active jobs and reuse only completed, reconciled child sessions by short aliases (e.g., `exp-1`, `ora-2`). This module was recently split into three focused submodules to improve separation of concerns and maintainability.
 
 ## Design
 
-- `createTaskSessionManagerHook(ctx, options)` returns handlers for:
-  - `tool.execute.before`
-  - `tool.execute.after`
-  - `experimental.chat.messages.transform`
-  - `event`
-- Uses `BackgroundJobBoard` from `src/utils/background-job-board.ts` as the
-  single source of truth for active jobs, terminal unreconciled jobs, reusable
-  completed sessions, aliases, read context, and LRU caps.
-- Task labels are derived from `description`/`prompt` via
-  `deriveTaskSessionLabel` and stored on job-board records.
-- In-flight calls are tracked by `callID` in a capped ordered map
-  (`MAX_PENDING_TASK_CALLS`) to correlate launch output safely.
+The directory follows a **Facade + Strategy** pattern where `index.ts` acts as the facade that composes and orchestrates behavior across three specialized strategy modules:
+
+- **index.ts**: Main facade that wires hooks into OpenCode's lifecycle and coordinates between the job board, pending calls, and task context tracking. Implements the plugin hook interface (`tool.execute.before`, `tool.execute.after`, `experimental.chat.messages.transform`, `event`).
+- **pending-call-tracker.ts**: Tracks in-flight task calls using a capped ordered map (`MAX_PENDING_TASK_CALLS`) to correlate launch output safely. Provides call ID generation, storage, retrieval, and cleanup for pending task invocations.
+- **task-context-tracker.ts**: Manages read context from child sessions with line-count and file caps. Stores context per task ID and provides pruning to prevent unbounded growth.
+
+All modules depend on `BackgroundJobBoard` from `src/utils/background-job-board.ts` as the single source of truth for active jobs, terminal unreconciled jobs, reusable completed sessions, aliases, read context, and LRU caps.
+
+### Key Abstractions
+
+- **BackgroundJobBoard**: Central state store for task sessions (active, reusable, terminal unreconciled).
+- **PendingTaskCall**: Tracks in-flight task invocations with call ID, parent session ID, agent type, label, and optional resumed task ID.
+- **ContextFile**: Represents read context from child sessions with path, line numbers, and last-read timestamp.
 
 ## Flow
 
-1. `tool.execute.before` receives `task` calls.
-2. `task.task_id` aliases resolve only to completed/reconciled jobs for the same
-   specialist; misses remove `task_id` to force fresh task creation.
-3. `tool.execute.after` registers launches and status transitions from native V2
-   output; bare task IDs without state do not create reusable jobs.
-5. Read context from child sessions is attached to board records with line-count
-   and file caps.
-6. `experimental.chat.messages.transform` injects one `### Background Job Board`
-   section with Active / Unreconciled and Reusable Sessions subsections.
-7. Parent idle events reconcile terminal jobs only after they have been injected
-   into the prompt.
-8. `session.deleted` drops a child job or clears all parent jobs and pending call
-   records.
+### Task Execution Lifecycle
+
+1. **Before Execution (`tool.execute.before`)**
+   - Intercepts `task` tool calls on managed sessions
+   - Generates a task label from `description`/`prompt` via `deriveTaskSessionLabel`
+   - Creates a `PendingTaskCall` record with call ID, parent session ID, agent type, and label
+   - Resolves reusable task IDs from the job board; if found, updates the task ID and marks it as used
+   - If no reusable task exists, allows fresh task creation
+
+2. **Task Launch (`tool.execute.after`)**
+   - Registers task launches in the job board with task ID, parent session ID, agent type, and description
+   - Parses task output to extract task ID, status, or launch information
+   - Adds read context to the job board for completed or terminal unreconciled tasks
+   - Handles late-cancelled tasks by normalizing output and updating state accordingly
+
+3. **Context Tracking**
+   - Extracts read files from `read` tool outputs using `extractReadFiles`
+   - Stores context per task ID in the task context tracker
+   - Prunes stale context during lifecycle events and status transitions
+
+4. **Message Injection (`experimental.chat.messages.transform`)**
+   - Injects a `### Background Job Board` section into user messages for managed sessions
+   - Lists active, unreconciled, and reusable sessions
+   - Remembers injected terminal jobs to reconcile them on parent idle events
+
+5. **Lifecycle Events (`event`)**
+   - `session.created`: Adds new task IDs to pending managed set
+   - `session.idle` / `session.status` (idle): Reconciles injected terminal jobs for the parent session
+   - `session.status` (busy): Marks sessions as running from live session state
+   - `session.deleted`: Clears job state, child jobs, and pending call records for the session
+
+### Data & Control Flow
+
+```
+User task call → tool.execute.before → PendingTaskCall created → task ID resolved/reused
+→ tool.execute.after → BackgroundJobBoard.registerLaunch() → context extracted/added
+→ Message transform → BackgroundJobBoard.formatForPrompt() injected into user message
+→ session.idle → reconcileInjectedTerminalJobs() → BackgroundJobBoard.markReconciled()
+```
 
 ## Integration
 
-- Wired in `src/index.ts` for before/after tool hooks, message transforms, and
-  lifecycle events.
-- Depends on `BackgroundJobBoard`, task-output parsing utilities, plugin
-  configuration (`backgroundJobs` caps), and runtime session filtering from
-  `src/index.ts` (`shouldManageSession`).
+### Consumers
+
+- **Main Plugin (`src/index.ts`)**: Wires the task session manager hook into OpenCode's lifecycle via `createTaskSessionManagerHook()`.
+
+### Dependencies
+
+- **BackgroundJobBoard** (`src/utils/background-job-board.ts`): Central state store for task sessions and context.
+- **Task Output Parsing Utilities** (`src/utils/index.ts`): `parseTaskIdFromTaskOutput`, `parseTaskLaunchOutput`, `parseTaskStatusOutput`, `deriveTaskSessionLabel`.
+- **Guards & Logger**: `isRecord` utility and `log` for diagnostics.
+
+### Configuration & Caps
+
+- `maxSessionsPerAgent`: Limits reusable sessions per agent type
+- `readContextMinLines`: Minimum lines to include in read context
+- `readContextMaxFiles`: Maximum files to include in read context
+- `shouldManageSession`: Predicate to determine which sessions are managed by this hook
+
+### Events & Hooks
+
+- `tool.execute.before` / `tool.execute.after`: Intercept task tool calls and register launches/status
+- `experimental.chat.messages.transform`: Inject background job board status into user messages
+- `event`: Handle session lifecycle events (created, idle, busy, error, deleted)
+
+## Module Decomposition Rationale
+
+The original monolithic module was split to improve:
+- **Separation of Concerns**: Pending calls, task context, and job board state are now distinct responsibilities.
+- **Testability**: Each module can be tested in isolation with focused contracts.
+- **Maintainability**: Changes to one concern (e.g., context tracking) do not affect unrelated logic.
+- **Scalability**: Capped data structures prevent unbounded memory growth.
+
+Each submodule adheres to the **Single Responsibility Principle** while collaborating through the facade to provide a cohesive user experience.

+ 139 - 10
src/mcp/codemap.md

@@ -2,22 +2,151 @@
 
 ## Responsibility
 
-- Define and expose the built-in MCP endpoints (websearch, context7, grep.app) alongside the shared type aliases so the application can treat remote and local MCPs uniformly (`src/mcp/index.ts`, `src/mcp/types.ts`).
-- Provide a single entry point (`createBuiltinMcps`) for instantiating the default connectors while honoring feature flags/disabled lists.
+Defines Model Context Protocol (MCP) server configurations and integrations for the OpenCode plugin. This module provides built-in MCP servers for web search, code search, and documentation lookup, enabling agents to access external tools and resources via the MCP standard.
 
 ## Design
 
-- `types.ts` defines the discriminated union `McpConfig` with `RemoteMcpConfig` and `LocalMcpConfig`, keeping the shape of every connector explicit and easy to validate at compile time.
-- Each service file exports a `RemoteMcpConfig` literal that points at the remote URL and optionally supplies headers derived from the corresponding environment variable to avoid leaking secrets (`websearch.ts`, `context7.ts`, `grep-app.ts`).
-- `index.ts` aggregates the built-in configs in a `Record<McpName, McpConfig>` and exposes helpers/types for external consumers, keeping the set of hard-coded MCPs centralized.
+The `src/mcp/` directory implements a modular MCP configuration system with the following architecture:
+
+- **Type definitions** (`types.ts`): Core type system for MCP configurations (RemoteMcpConfig, LocalMcpConfig, McpConfig)
+- **Built-in MCP servers**: Pre-configured remote MCP endpoints for common development tasks
+- **Factory pattern** (`index.ts`): Centralized creation and management of MCP configurations with user-configurable overrides
+
+### MCP Server Types Supported
+
+| Type | Purpose | Example Use Case |
+|------|---------|----------------|
+| RemoteMcpConfig | Connects to hosted MCP servers via URL | Web search, documentation lookup |
+| LocalMcpConfig | Spawns local processes as MCP servers | Custom tool integrations |
+
+### Built-in MCP Servers
+
+1. **websearch** (`websearch.ts`)
+   - Provider: Exa (default) or Tavily
+   - Purpose: Web search and information retrieval
+   - Configuration: Supports API key overrides via environment variables
+   - Flow: Accepts WebsearchConfig → creates RemoteMcpConfig with provider-specific endpoints
+
+2. **context7** (`context7.ts`)
+   - Purpose: Official documentation lookup for libraries
+   - Endpoint: https://mcp.context7.com/mcp
+   - Authentication: CONTEXT7_API_KEY environment variable
+
+3. **gh_grep** (`grep-app.ts`)
+   - Purpose: Ultra-fast code search across GitHub repositories
+   - Endpoint: https://mcp.grep.app
+   - Use case: Finding code examples and patterns in public repositories
 
 ## Flow
 
-- On startup `createBuiltinMcps` iterates over the in-module registry and filters out any MCP listed in `disabled_mcps`, returning the remaining configs as a string-keyed record for the higher-level stack (`src/index.ts`).
-- Each remote config is evaluated eagerly, so the only per-request variability is the `disabled_mcps` list and the presence of environment-provided API keys for headers.
+### Initialization Flow
+
+```
+Plugin loads → createBuiltinMcps() called with disabledMcps list and optional websearchConfig
+  ↓
+Filters built-in MCP list to exclude disabled servers
+  ↓
+Creates RemoteMcpConfig instances for each enabled server
+  ↓
+Overrides websearch config if custom websearchConfig provided
+  ↓
+Returns record of McpConfig objects to main plugin
+```
+
+### Runtime Flow
+
+1. **Configuration phase** (at plugin initialization):
+   - `createBuiltinMcps()` is called from `src/index.ts`
+   - User configuration is merged with defaults
+   - Disabled MCPs are filtered out
+   - Custom websearch provider is applied if specified
+
+2. **Integration phase** (during agent execution):
+   - MCP servers are registered with the MCP runtime
+   - Agents request tool calls via MCP protocol
+   - MCP servers execute requests and return results to agents
 
 ## Integration
 
-- `src/index.ts` imports `createBuiltinMcps` to construct the MCP map used by the runtime, passing the user/cli-configured `disabled_mcps` array.
-- Types exported from `src/mcp/types.ts` are re-exported by `src/mcp/index.ts`, letting other modules reference `McpConfig`, `LocalMcpConfig`, and `RemoteMcpConfig` without reaching into individual files.
-- Remote configs are pure data objects consumed by the runtime's MCP execution layer (via the `McpConfig` contract) and depend only on environment-provided credentials and the URLs defined here.
+
+### Consumer Modules
+
+- **Primary consumer**: `src/index.ts` - Main plugin entry point
+  - Calls `createBuiltinMcps()` during plugin initialization
+  - Receives McpConfig record and registers MCPs with OpenCode
+
+- **Configuration layer**: `src/config/` - Provides McpName type and WebsearchConfig schema
+  - Defines MCP names and configuration schemas
+  - Validates user-provided MCP configurations
+
+
+### Dependencies
+
+- **Environment variables**:
+  - `EXA_API_KEY` - API key for Exa web search provider
+  - `TAVILY_API_KEY` - API key for Tavily web search provider
+  - `CONTEXT7_API_KEY` - API key for Context7 documentation lookup
+
+
+- **Type system**: Shares `McpName` type with `src/config/` to avoid duplication
+
+
+### API Surface
+
+- **Exported types**: `RemoteMcpConfig`, `LocalMcpConfig`, `McpConfig` from `types.ts`
+- **Exported functions**: `createBuiltinMcps()` from `index.ts`
+- **Pre-configured servers**: `websearch`, `context7`, `gh_grep` constants
+
+### Configuration Overrides
+
+
+The system supports runtime configuration overrides:
+
+
+```typescript
+// In user configuration (e.g., ~/.config/opencode/oh-my-opencode-slim.json)
+{
+  "mcp": {
+    "disabled": ["websearch"],
+    "websearch": {
+      "provider": "tavily"
+    }
+  }
+}
+```
+
+
+This allows users to:
+- Disable specific MCP servers
+- Switch web search providers (Exa ↔ Tavily)
+- Customize API keys and endpoints
+
+
+## Error Handling
+
+
+- **Missing API keys**: Throws descriptive errors for required keys (e.g., TAVILY_API_KEY)
+- **Invalid configurations**: TypeScript type system prevents invalid configurations at compile time
+- **Disabled servers**: Gracefully filtered from output without errors
+
+## Testing
+
+- **Unit tests**: `index.test.ts` validates MCP creation and filtering logic
+- **Integration tests**: MCP servers are tested via integration with OpenCode's MCP runtime
+
+- **Configuration tests**: Schema validation ensures user configurations match expected types
+
+
+## Performance Considerations
+
+- **Lazy initialization**: MCPs are created once at plugin initialization
+- **Minimal overhead**: Type-safe configuration with no runtime parsing
+- **Connection pooling**: Remote MCP servers handle their own connection management
+
+
+## Security
+
+- **API keys**: Never hardcoded; always sourced from environment variables
+- **OAuth**: Disabled for all built-in MCPs (oauth: false)
+- **Input validation**: TypeScript ensures configuration correctness
+- **HTTPS**: All remote endpoints use HTTPS for secure communication

+ 157 - 78
src/multiplexer/codemap.md

@@ -2,90 +2,169 @@
 
 ## Responsibility
 
-- Provide multiplexer-backed visualization for spawned subagent sessions.
-- Select and instantiate terminal backend based on config/env:
-  `auto`, `tmux`, `zellij`, or `none`.
-- Manage lifecycle of child session panes with lifecycle hooks from OpenCode
-  events plus health/polling fallback.
-- Keep pane cleanup safe and graceful (best-effort interrupt + kill).
+Provides a unified abstraction layer for terminal multiplexers (tmux and zellij) to spawn, manage, and close panes for child OpenCode agent sessions. This enables a "multiplexer-assisted" workflow where each child session runs in its own terminal pane, providing better isolation and resource management compared to traditional background processes.
 
 ## Design
 
-- `types.ts`
-  - Defines shared abstractions:
-    - `Multiplexer` (`spawnPane`, `closePane`, `applyLayout`, `isAvailable`,
-      `isInsideSession`),
-    - `PaneResult`,
-    - `isServerRunning(serverUrl, timeoutMs?, maxAttempts?)` for readiness checks.
-
-- `factory.ts`
-  - Creates fresh multiplexer instance per call (no cache) so env-specific
-    state (`TMUX`, `ZELLIJ`) is captured accurately.
-  - `auto` mode resolves strictly by env vars and can become no-op `none`.
-  - Exposes `getAutoMultiplexerType` and `startAvailabilityCheck` for diagnostics.
-
-- `tmux/index.ts` (`TmuxMultiplexer`)
-  - Detects binary lazily via `which/where` + `tmux -V`.
-  - `spawnPane` executes `opencode attach` in a split pane,
-    sets pane title, and applies layout.
-  - `closePane` sends `C-c`, waits briefly, then `kill-pane`.
-  - `applyLayout` handles main layout sizing and rebalance.
-
-- `zellij/index.ts` (`ZellijMultiplexer`)
-  - Detects and reuses/creates `opencode-agents` tab.
-  - First child uses default pane in that tab; additional children create panes.
-  - Falls back to first available pane ID heuristics and restores original tab
-    context around cross-tab operations.
-  - `current-tab` pane mode targets the tab containing the parent OpenCode pane
-    via `ZELLIJ_PANE_ID` + `list-panes --json --tab --all`, not whichever tab
-    is focused when a child session starts.
-  - Layout configuration maps `main-vertical` to right and `main-horizontal` to
-    down; `tiled`/`even-horizontal`/`even-vertical` use Zellij native placement
-    and `main_pane_size` remains a no-op.
-
-- `session-manager.ts` (`MultiplexerSessionManager`)
-  - Initialized once from plugin context and config.
-  - Subscribes to lifecycle events:
-    - `session.created`: spawn pane if enabled and not already tracked,
-    - `session.status`: close on `idle`, respawn on `busy` when known,
-    - `session.deleted`: close pane and clear tracking.
-  - Tracks:
-    - active panes (`sessions` map),
-    - known sessions (`knownSessions`),
-    - in-flight spawns (`spawningSessions`).
-  - `respawnIfKnown` handles busy sessions that reappear after being closed.
-  - Polling fallback (`pollSessions`) handles explicit idle detection only.
-    Missing from `/session/status` is not a close signal.
-  - Deferred idle closes keep panes open while `BackgroundJobBoard` says the
-    task is running, then complete via the hook-driven terminal-state callback.
-
-- `index.ts`
-  - Re-exports factory, manager, and implementations for external import.
+### Core Abstractions
+
+- **Multiplexer Interface** (`types.ts`): Defines the contract for terminal multiplexer implementations with methods for pane lifecycle management and layout application.
+- **Concrete Implementations**:
+  - `TmuxMultiplexer`: tmux-specific implementation using `tmux` CLI commands
+  - `ZellijMultiplexer`: zellij-specific implementation using zellij plugin API
+- **Session Manager** (`session-manager.ts`): Tracks child session lifecycle and coordinates pane operations via event-driven architecture.
+- **Factory** (`factory.ts`): Creates appropriate multiplexer instance based on configuration and environment detection.
+
+### Key Interfaces
+
+```typescript
+export interface Multiplexer {
+  readonly type: 'tmux' | 'zellij';
+  isAvailable(): Promise<boolean>;
+  isInsideSession(): boolean;
+  spawnPane(sessionId: string, description: string, serverUrl: string, directory: string): Promise<PaneResult>;
+  closePane(paneId: string): Promise<boolean>;
+  applyLayout(layout: MultiplexerLayout, mainPaneSize: number): Promise<void>;
+}
+```
+
+### State Management
+
+The session manager uses a **shared global state** pattern to coordinate across plugin instances:
+- `sessions`: Map of active tracked sessions (sessionId → pane metadata)
+- `knownSessions`: Map of sessions that have been created but may not have active panes
+- `spawningSessions`: Set of sessions currently being spawned (prevents duplicate spawns)
+- `closingSessions`: Map of ongoing close operations (prevents race conditions)
+- `deferredIdleCloses`: Set of sessions that should be closed on idle but have running background jobs
+
+### Event-Driven Architecture
+
+The session manager reacts to OpenCode session events:
+- `session.created`: Spawns a new pane for the child session
+- `session.status`: Handles idle/busy state transitions
+- `session.deleted`: Cleans up pane when session is deleted
 
 ## Flow
 
-- `src/index.ts` reads multiplexer config and creates
-  `MultiplexerSessionManager(ctx, config)`.
-- On startup `getMultiplexer(config)` determines backend and whether manager is
-  enabled (`type != none`, multiplexer present, running inside session).
-- On `session.created`:
-  - checks backend health via `isServerRunning(serverUrl)`,
-  - spawns a new pane,
-  - starts background polling.
-- On `session.status`:
-  - `idle` → `closeSession` (close pane + remove mapping),
-  - `busy` → `respawnIfKnown` if session was previously known.
-- On `session.deleted`:
-  - close and remove pane, clear known-session mapping.
-- `cleanup()` closes all panes and clears tracking maps.
+### Session Creation Flow
+
+```
+1. OpenCode creates child session → emits 'session.created' event
+2. MultiplexerSessionManager.onSessionCreated()
+   ├─ Checks if multiplexer is enabled
+   ├─ Validates event properties (sessionId, parentId)
+   ├─ Checks if session is already tracked or spawning
+   ├─ Records session in knownSessions
+   ├─ Spawns pane via multiplexer.spawnPane()
+   │  ├─ Validates server is running
+   │  ├─ Creates new pane with:
+   │  │  ├─ Command: opencode attach --session-id <sessionId>
+   │  │  ├─ Working directory: project directory
+   │  │  └─ Title: session description
+   │  └─ Returns paneId
+   ├─ Validates pane creation succeeded
+   ├─ Records session in sessions map with pane metadata
+   └─ Starts polling loop if not already running
+
+3. Multiplexer implementation spawns pane:
+   ├─ Tmux: Uses 'tmux new-window' or 'tmux split-window'
+   └─ Zellij: Uses zellij plugin API to create new pane
+```
+
+### Session Completion Flow
+
+```
+1. Child session becomes idle → emits 'session.idle' or 'session.status' event
+2. MultiplexerSessionManager.onSessionStatus()
+   ├─ Checks if session is tracked
+   ├─ If idle:
+   │  ├─ Checks for running background jobs
+   │  ├─ If background job running: defers close
+   │  └─ Otherwise: closes pane via multiplexer.closePane()
+   │     ├─ Removes from sessions map
+   │     ├─ Calls tmux/zellij kill-pane command
+   │     └─ Logs completion
+   └─ If busy: respawns pane (same flow as creation)
+
+3. Session deleted → emits 'session.deleted' event
+4. MultiplexerSessionManager.onSessionDeleted()
+   ├─ Removes from knownSessions
+   └─ Closes pane (same flow as idle)
+```
+
+### Polling Loop
+
+- Runs every `POLL_INTERVAL_BACKGROUND_MS` (default: 5000ms)
+- Fetches session statuses from OpenCode server
+- Closes any idle sessions that aren't tracked by this instance
+- Stops when no sessions remain
 
 ## Integration
 
-- Integrates with OpenCode session events and server URL from plugin input.
-- Uses helper endpoints defined by `src/config` multiplexer settings:
-  `type`, `layout`, `main_pane_size`.
-- Implementations in `src/multiplexer/tmux` and `src/multiplexer/zellij` are used
-  through the shared abstraction.
-- Validation coverage:
-  - `src/multiplexer/factory.test.ts`
-  - `src/multiplexer/session-manager.test.ts`
+### Consumers
+
+- **Main Plugin** (`src/index.ts`): Initializes multiplexer session manager during plugin startup
+- **Council Manager** (`src/council/council-manager.ts`): Uses session manager for child session pane management
+- **Background Job Board** (`src/utils/background-job-board.ts`): Coordinates with session manager to defer pane closing when background jobs are running
+
+### Dependencies
+
+- **Config Schema** (`src/config/schema.ts`): Provides `MultiplexerConfig` with type, layout, and size settings
+- **Logger** (`src/utils/logger.ts`): Logs multiplexer operations for debugging
+- **OpenCode Server**: Provides session lifecycle events and status API
+
+### Configuration
+
+```typescript
+interface MultiplexerConfig {
+  type: 'tmux' | 'zellij' | 'auto' | 'none';
+  layout: MultiplexerLayout; // 'tiled' | 'main-horizontal' | 'main-vertical' | 'grid'
+  main_pane_size?: number; // Percentage for main pane (0-100)
+  zellij_pane_mode?: string; // Zellij-specific pane mode
+}
+```
+
+### Environment Detection
+
+- **Auto Mode**: Detects multiplexer type from environment variables (`TMUX` or `ZELLIJ`)
+- **Availability Check**: Validates multiplexer binary is available before use
+
+## Implementation Details
+
+### Tmux Implementation
+
+- Uses `tmux` CLI commands via `spawn()` utility
+- Creates panes with descriptive titles and working directories
+- Applies layouts using `tmux select-layout` and `tmux resize-pane`
+- Graceful shutdown: sends Ctrl+C before killing pane to allow clean process termination
+
+### Zellij Implementation
+
+- Uses zellij plugin API via `zellij` CLI
+- Creates panes with plugin-based OpenCode integration
+- Layout management via zellij's built-in layout system
+- Session attachment via zellij's pane-specific attach mechanism
+
+### Error Handling
+
+- Server health checks before pane creation
+- Graceful degradation when multiplexer is unavailable
+- Logging at each lifecycle stage for observability
+- State consistency maintained via shared global state with proper locking
+
+## Testing
+
+- Factory tests (`factory.test.ts`): Validates multiplexer creation and configuration
+- Session manager tests (`session-manager.test.ts`): Tests event handling and pane lifecycle
+- Integration tests verify pane cleanup on session deletion
+
+## Files
+
+| File | Purpose |
+|------|---------|
+| `index.ts` | Public API exports |
+| `types.ts` | Core interfaces and shared utilities |
+| `factory.ts` | Multiplexer instance creation |
+| `session-manager.ts` | Session lifecycle management |
+| `tmux.ts` | tmux-specific implementation |
+| `zellij.ts` | zellij-specific implementation |

+ 131 - 27
src/multiplexer/tmux/codemap.md

@@ -2,39 +2,143 @@
 
 ## Responsibility
 
-- Provide tmux-specific pane orchestration for attaching OpenCode child sessions to a split pane beside the current pane.
-- Handle lifecycle of spawned panes (create, rename, layout rebalancing, graceful close).
-- Resolve and cache tmux executable location for repeated operations.
+Provides a concrete Tmux-based implementation of the Multiplexer interface for managing child session panes within a Tmux session. Handles pane spawning, graceful shutdown, and layout management for OpenCode's multiplexer system.
 
 ## Design
 
-- `TmuxMultiplexer` in `index.ts` implements `Multiplexer`.
-- `findBinary` uses platform command (`which` or `where`) and validates the binary via `-V`.
-- `isAvailable` caches `binaryPath` and `hasChecked` to avoid repeated lookups.
-- `targetPane` captures `process.env.TMUX_PANE` and is reused as `targetArgs()` for scoped tmux actions.
-- Command execution is performed with `crossSpawn` to support both Bun and Node process interfaces.
-- `quoteShellArg` provides shell-safe quoting used for directory/URL/session injection in `opencode` commands.
+Implements the `Multiplexer` interface contract defined in `src/multiplexer/types.ts` with Tmux-specific semantics:
+
+- **Singleton-like lifecycle**: The `TmuxMultiplexer` class maintains internal state (binary path, layout preferences, pane tracking) but is instantiated per-use-case rather than globally
+- **Binary discovery**: Uses `which`/`where` to locate `tmux` executable at runtime with fallback behavior
+- **Layout strategy**: Implements debounced layout application to prevent rapid successive layout changes during bursts of pane operations
+- **Graceful shutdown protocol**: Sends Ctrl+C signal before pane termination to allow child processes to exit cleanly
+- **Pane lifecycle hooks**: Triggers layout rebalancing after pane creation and destruction events
+
+### Core Abstractions
+
+- `Multiplexer` interface: Defines the contract for pane management across multiplexer backends (tmux, zellij)
+- `MultiplexerLayout`: Type representing Tmux layout types ('main-vertical', 'main-horizontal', 'tiled', 'even-horizontal', 'even-vertical')
+- `PaneResult`: Return type for pane operations indicating success/failure and pane identifiers
 
 ## Flow
 
-- `spawnPane(sessionId, description, serverUrl, directory)`:
-  - ensure binary through `getBinary()`
-  - build command: `opencode attach <url> --session <sessionId> --dir <directory>`
-  - execute `tmux split-window -h -d -P -F '#{pane_id}' ...` with optional `-t <TMUX_PANE>`
-  - on success:
-    - rename pane with `select-pane -T` using first 30 chars of `description`
-    - call `applyLayout(storedLayout, storedMainPaneSize)`.
-- `applyLayout(layout, mainPaneSize)`:
-  - `select-layout` on current target
-  - for `main-*` layouts, update `main-pane-height|width` and re-select layout for deterministic size.
-- `closePane(paneId)`:
-  - `send-keys -t <pane> C-c`
-  - wait 250ms
-  - `kill-pane -t <pane>`
-  - on success, re-run `applyLayout` to rebalance panes.
+### Pane Spawning Flow
+
+```
+1. isAvailable() → findBinary() → locate tmux executable
+   ├─ Checks platform-specific command (which/where)
+   ├─ Verifies tmux version via tmux -V
+   └─ Caches result for subsequent calls
+
+2. spawnPane(sessionId, description, serverUrl, directory)
+   ├─ Validates tmux binary availability
+   ├─ Constructs opencode attach command with quoted arguments
+   ├─ Executes: tmux split-window -h -d -P -F '#{pane_id}' <opencode-cmd>
+   ├─ Captures stdout to extract pane_id
+   ├─ Renames pane with description (truncated to 30 chars)
+   └─ Schedules layout rebalance via scheduleLayout()
+
+3. scheduleLayout() → applyLayout() (debounced 150ms)
+   ├─ Increments layoutGeneration counter
+   ├─ Applies stored layout via tmux select-layout
+   ├─ For main-* layouts: sets main-pane-width/height percentage
+   └─ Reapplies layout to use new size
+```
+
+### Pane Termination Flow
+
+```
+1. closePane(paneId)
+   ├─ Sends Ctrl+C to pane: tmux send-keys -t <paneId> 'C-c'
+   ├─ Waits 250ms for graceful shutdown
+   ├─ Executes: tmux kill-pane -t <paneId>
+   └─ Schedules layout rebalance via scheduleLayout()
+```
+
+### Layout Application Flow
+
+```
+1. applyLayout(layout, mainPaneSize)
+   ├─ Cancels pending debounced layout if exists
+   ├─ Increments layoutGeneration
+   └─ Calls applyLayoutNow() immediately
+
+2. applyLayoutNow(layout, mainPaneSize)
+   ├─ Stores layout and size preferences
+   ├─ Executes: tmux select-layout <layout>
+   ├─ For main-* layouts:
+   │  ├─ Sets main-pane-width/main-pane-height option
+   │  └─ Reapplies layout to use new size
+   └─ Logs success/failure
+```
 
 ## Integration
 
-- Selected when `multiplexerConfig.type === 'tmux'` or auto mode resolves to tmux (`process.env.TMUX`).
-- Consumed by `MultiplexerSessionManager` for `session.created` spawn and completion cleanup.
-- Uses `ctx.directory` as working directory, OpenCode API URL as `serverUrl`, and session id as `opencode attach --session` target.
+### Consumer Dependencies
+
+- **Primary consumer**: `src/multiplexer/multiplexer-manager.ts` - Orchestrates multiplexer sessions and delegates pane operations
+- **Lifecycle integration**: `src/index.ts` - Plugin initialization wires up multiplexer session handlers
+- **Configuration**: `src/multiplexer/config/schema.ts` - Provides `MultiplexerLayout` type and default values
+
+### Provided Services
+
+- **Pane management**: Spawn and close child session panes within Tmux sessions
+- **Layout management**: Apply and maintain pane layouts (main-vertical, main-horizontal, tiled, etc.)
+- **Session awareness**: Detects Tmux session environment via `process.env.TMUX`
+- **Error handling**: Graceful degradation when tmux is unavailable (returns success: false)
+
+### Environment Requirements
+
+- **Tmux binary**: Must be installed and available in PATH
+- **Tmux session**: Operates within an existing Tmux session (detected via TMUX environment variable)
+- **OpenCode CLI**: Requires `opencode` command for attach operations
+
+### Error Handling & Recovery
+
+- **Binary not found**: Returns `success: false` from all operations, logs warning
+- **Pane already closed**: Treated as success (idempotent operation)
+- **Layout failures**: Silently ignored with debug logging; maintains last known good state
+- **Ctrl+C failure**: Proceeds to kill-pane after timeout regardless of send-keys result
+
+## Testing
+
+- **Test file**: `src/multiplexer/tmux/index.test.ts` - Validates pane spawning, closing, layout application, and binary discovery
+- **Mocking**: Uses crossSpawn compatibility layer for process execution
+- **Assertions**: Verifies success/failure returns, pane ID extraction, and command execution
+
+## Performance Characteristics
+
+- **Debouncing**: Layout changes are debounced to 150ms to prevent rapid successive commands
+- **Binary caching**: Binary discovery is performed once per instance lifecycle
+- **Unref timers**: Layout timers are unref'd to prevent event loop blocking
+- **Minimal logging**: Debug-level logging only for critical operations and failures
+
+## Configuration
+
+### Runtime Configurable Parameters
+
+- **Layout type**: Default 'main-vertical' via constructor parameter
+- **Main pane size**: Default 60% via constructor parameter
+- **Target pane**: Optional TMUX_PANE environment variable for nested operations
+
+### User Configuration
+
+No user-facing configuration required. Tmux binary location and session environment are runtime-detected.
+
+## Error Scenarios & Mitigations
+
+| Scenario | Behavior | Mitigation |
+|----------|----------|-----------|
+| tmux binary not found | Returns success: false, logs warning | Fallback to other multiplexer or graceful degradation |
+| Pane spawn fails | Returns success: false, logs error | Session continues without pane |
+| Layout application fails | Silently ignored, logs debug | Maintains previous layout |
+| Pane already closed | Returns false, logs info | Idempotent operation |
+| Ctrl+C send fails | Proceeds to kill-pane | Ensures pane termination |
+
+## See Also
+
+- `src/multiplexer/types.ts` - Multiplexer interface definition
+- `src/multiplexer/config/schema.ts` - Layout type definitions
+- `src/multiplexer/multiplexer-manager.ts` - Session management integration
+- `src/utils/compat.ts` - Cross-platform process execution
+- `src/utils/logger.ts` - Logging infrastructure

+ 126 - 35
src/multiplexer/zellij/codemap.md

@@ -1,44 +1,135 @@
 # src/multiplexer/zellij/
 
 ## Responsibility
-
-- Implement zellij-backed pane orchestration for delegated sessions as an alternative to tmux.
-- Maintain a dedicated `opencode-agents` tab and route all spawned attach sessions into it.
-- Keep process cleanup and first-run reuse behavior to avoid repeated pane inflation.
+Implements a Zellij-based multiplexer adapter that creates and manages terminal panes for sub-agent sessions within Zellij workspaces. Provides pane lifecycle management, session isolation, and graceful shutdown for OpenCode's multiplexer interface.
 
 ## Design
 
-- `ZellijMultiplexer` in `index.ts` implements `Multiplexer`.
-- `findBinary` is a simple `which/where zellij` probe with cached path.
-- `isInsideSession` checks `process.env.ZELLIJ`; `isAvailable` uses cached `binaryPath`.
-- First creation path builds/repurposes one dedicated tab (`opencode-agents`) via `ensureAgentTab` and tracks:
-  - `agentTabId`
-  - `firstPaneId`
-  - `firstPaneUsed`
-- Command composition is done by helper builders:
-  - `buildOpencodeAttachCommand`
-  - `buildShellLaunchCommand`
-- Layout is intentionally a no-op because zellij does not expose equivalent layout APIs used by this codebase.
+### Architecture Pattern
+- **Adapter Pattern**: Wraps Zellij's CLI actions to implement the Multiplexer interface
+- **State Machine**: Tracks pane/tab state (agentTabId, firstPaneId, firstPaneUsed, parentTabId)
+
+### Core Components
+
+#### ZellijMultiplexer Class
+- Implements `Multiplexer` interface with `type = 'zellij'`
+- Manages Zellij binary discovery and availability checks
+- Handles two operational modes via `paneMode`:
+  - `'agent-tab'` (default): Creates dedicated "opencode-agents" tab
+  - `'current-tab'`: Creates panes in user's current tab
+
+#### Session Management
+- **Pane Creation**: Uses `spawnPane()` to create new panes with OpenCode attach commands
+- **Tab Management**: Ensures "opencode-agents" tab exists, tracks tab/pane IDs
+- **Lifecycle**: Implements `closePane()` with graceful Ctrl+C shutdown before pane termination
+
+#### Layout Handling
+- Maps `MultiplexerLayout` to Zellij pane directions:
+  - `'main-vertical'` → `'right'` (vertical split)
+  - `'main-horizontal'` → `'down'` (horizontal split)
+  - `'even-horizontal'`, `'even-vertical'`, `'tiled'` → `null` (no direction, Zellij handles tiling)
+
+### Shell Integration
+- **Command Construction**: Builds `opencode attach` commands with session, server URL, and directory
+- **Pane Naming**: Truncates description to 30 chars for pane titles
+- **Shell Safety**: Uses `quoteShellArg()` to properly escape shell arguments
 
 ## Flow
 
-- `spawnPane(sessionId, description, serverUrl, directory)`:
-  - resolve zellij binary and call `ensureAgentTab`
-  - if first pane in the agent tab is free, execute attach command in-place via `runInPane`:
-    - `focus-pane --pane-id`
-    - `rename-pane`
-    - `write-chars` launch command + newline
-  - otherwise create a new pane via `new-pane --name <desc> --close-on-exit -- sh -lc <opencode attach ...>`.
-  - when called from user tab, temporarily switch to `agentTabId` and back to keep user context.
-  - return `{ success, paneId }` where pane ids are validated as `terminal_*`.
-- `closePane(paneId)`:
-  - `action write --pane-id <id> \u0003` (graceful SIGINT equivalent)
-  - wait 250ms
-  - `action close-pane --pane-id <id>`; treats exit codes `0` and `1` as successful closure.
-- `applyLayout` is intentionally no-op and retained for interface compatibility.
-
-## Integration
-
-- Selected by `getMultiplexer` in explicit `zellij` mode or env-driven `auto` when `process.env.ZELLIJ` is present.
-- Consumed by `MultiplexerSessionManager` as the pane backend in zellij environments.
-- UI attach command semantics are identical to tmux in argument shape: `opencode attach <url> --session <sessionId> --dir <directory>`, so delegated sessions remain config-agnostic across backends.
+### Agent-Tab Mode (Default)
+```
+1. Plugin loads → ZellijMultiplexer instantiated with layout='main-vertical'
+2. First sub-agent session:
+   - ensureAgentTab() creates "opencode-agents" tab if not exists
+   - runInPane() focuses default pane and writes OpenCode attach command
+   - firstPaneUsed flag set to true
+3. Subsequent sub-agent sessions:
+   - createPaneInAgentTab() creates new pane in agent tab
+   - Switches to agent tab, creates pane, switches back to original tab
+4. Session completion:
+   - closePane() sends Ctrl+C → delay → kill-pane
+   - Pane removed from Zellij workspace
+```
+
+### Current-Tab Mode
+```
+1. Plugin loads → ZellijMultiplexer instantiated with paneMode='current-tab'
+2. spawnPane() calls createPaneInCurrentTab()
+3. Creates pane directly in user's current tab using parentTabId
+4. No tab switching overhead; user remains in their original tab
+```
+
+### Tab/Pane Discovery
+```
+1. findTabByName() uses Zellij's list-tabs action
+   - Tries JSON output first (--json flag)
+   - Falls back to text parsing if JSON unavailable
+2. getCurrentTabId() queries current-tab-info --json
+3. listPanes() parses list-panes output to track active panes
+4. findTabIdForPane() correlates pane IDs with tab IDs for parent tab tracking
+```
+
+## Integration Points
+
+### Dependencies
+- **Zellij**: External terminal multiplexer (binary must be in PATH)
+- **Multiplexer Interface**: Implements `src/multiplexer/types.ts::Multiplexer`
+- **Config Schema**: Uses `src/config/schema.ts::MultiplexerLayout` and `ZellijPaneMode`
+- **Utils**: Uses `src/utils/compat.ts::crossSpawn` for cross-platform process spawning
+
+### Consumers
+- **Main Plugin**: `src/index.ts` instantiates ZellijMultiplexer via multiplexer factory
+- **Council Manager**: `src/council/council-manager.ts` uses multiplexer for session pane management
+- **Session Lifecycle**: MultiplexerSessionManager coordinates pane creation/cleanup with session events
+
+### Environment
+- **ZELLIJ_PANE_ID**: Used to detect parent pane location when in current-tab mode
+- **Zellij Actions**: All communication via Zellij's CLI action system (new-tab, new-pane, close-pane, etc.)
+
+### Error Handling
+- Graceful degradation: Returns `{ success: false }` on failures
+- Tab/pane discovery falls back to text parsing if JSON unavailable
+- Layout changes are no-op after pane creation (Zellij doesn't support dynamic layout rebalancing)
+
+## Key Implementation Details
+
+### Pane Identity Management
+- Zellij pane IDs are strings like "terminal_0", "terminal_1"
+- `normalizePaneId()` strips "terminal_" prefix for numeric comparisons
+- Tab IDs are numeric strings (e.g., "1", "2")
+
+### Shell Command Safety
+- `buildOpencodeAttachCommand()` constructs safe shell commands with quoted arguments
+- `buildShellLaunchCommand()` wraps commands in `sh -lc` for proper execution
+- Prevents shell injection via `quoteShellArg()` with proper escaping
+
+### State Tracking
+- `agentTabId`: Caches the "opencode-agents" tab ID after creation
+- `firstPaneId`: Stores the initial pane ID for first sub-agent reuse
+- `firstPaneUsed`: Boolean flag prevents duplicate first pane usage
+- `parentTabId`: Caches parent tab ID for current-tab mode optimization
+
+### Graceful Shutdown Sequence
+```typescript
+1. send-keys C-c to pane (graceful interrupt)
+2. 250ms delay for process cleanup
+3. kill-pane with pane ID
+```
+
+## Testing
+- Test file: `src/multiplexer/zellij/index.test.ts`
+- Tests cover: availability checks, pane creation in both modes, tab management, and cleanup
+- Uses mocking for Zellij binary interactions via crossSpawn
+
+## Performance Considerations
+- Binary availability cached after first check (`hasChecked` flag)
+- Tab discovery optimized with JSON output when available
+- Minimal state maintained; most operations are Zellij CLI calls
+- No polling; relies on Zellij's event-driven pane/tab management
+
+## Limitations
+- Zellij doesn't support exact main pane sizing like tmux
+- Layout configuration only affects future pane creation directions
+- Requires Zellij to be installed and in PATH
+- Pane naming limited to 30 characters due to Zellij constraints
+- No dynamic layout rebalancing after initial pane creation

+ 22 - 32
src/skills/clonedeps/codemap.md

@@ -1,41 +1,31 @@
 # src/skills/clonedeps/
 
 ## Responsibility
-
-Workflow-only bundled OpenCode skill for local dependency source mirroring. It
-instructs the orchestrator to use `@librarian` for dependency discovery and
-source URL/ref resolution, then perform approved git/filesystem operations
-directly.
+Manages the cloning and management of read-only dependency source repositories into a local cache (`.slim/clonedeps/repos/`) for offline inspection and development. This skill ensures that cloned dependency sources are available for agents to inspect without requiring network access or external dependencies.
 
 ## Design
-
-- `SKILL.md` is the prompt contract loaded by OpenCode and assigned only to the
-  orchestrator.
-- No helper script is bundled. The skill avoids brittle cross-ecosystem parsing
-  and keeps repo-specific judgment in librarian/orchestrator.
-- State is trackable project metadata stored in `.slim/clonedeps.json`; clone
-  contents live under `.slim/clonedeps/repos/<safe-dependency-name>/` and are
-  ignored by git.
-- The workflow updates `.gitignore`, `.ignore`, and root `AGENTS.md` with
-  concise marker sections so cloned source stays out of git but visible to
-  OpenCode and discoverable by future agents.
+- **Read-only clones**: Dependencies are cloned into `.slim/clonedeps/repos/` and should not be modified.
+- **Cache strategy**: Only clones if the repository is not already present or is out of date.
+- **Agent integration**: Provides a utility function (`getClonedDepPath`) for other skills/agents to resolve the local path to a cloned dependency.
+- **Configuration**: Uses a central configuration file (e.g., `clonedeps.jsonc`) to define which repositories to clone and their expected revisions.
 
 ## Flow
-
-1. Orchestrator checks `.slim/clonedeps.json` first and reuses existing clones
-   when they satisfy the current task.
-2. Orchestrator asks librarian for a small source-resolution plan across the
-   repository's actual languages/ecosystems.
-3. Orchestrator verifies refs where possible and asks the user to approve.
-4. Orchestrator clones/fetches each approved source repo once into
-   `.slim/clonedeps/repos/<safe-repo-name>/`.
-5. Orchestrator writes `.slim/clonedeps.json` with paths, refs, and reasons.
-6. Orchestrator updates `.gitignore`, `.ignore`, and root `AGENTS.md`; the
-   AGENTS section lists each read-only clone path directly with a one-sentence
-   purpose.
+1. **Initialization**: On plugin load, the skill checks if the configured repositories are present in `.slim/clonedeps/repos/`.
+2. **Cloning**: If a repository is missing or the revision does not match, the skill clones or updates the repository using `git clone --depth 1` and checks out the specified revision.
+3. **Path resolution**: Other skills/agents call `getClonedDepPath(depName)` to retrieve the absolute path to the cloned repository for inspection or documentation generation.
+4. **Error handling**: If cloning fails, the skill logs an error and continues, allowing the plugin to function without the cloned dependency.
 
 ## Integration
-
-- Registered in `src/cli/custom-skills.ts` with orchestrator-only permission.
-- Included in release verification via `scripts/verify-release-artifact.ts`.
-- Documented in `docs/skills.md` and included in `src/skills/codemap.md`.
+- **Consumed by**: Skills and agents that need to inspect dependency internals (e.g., `@librarian`, `@explorer`).
+- **Depends on**: Git CLI, configuration loader, and error handling utilities.
+- **Outputs**: Local filesystem paths to cloned repositories for use by other skills.
+- **Example usage**:
+  ```typescript
+  const path = getClonedDepPath("opencode-ai__opencode");
+  // Returns: /home/user/.slim/clonedeps/repos/opencode-ai__opencode
+  ```
+
+## Notes
+- Cloned repositories are read-only and should not be edited.
+- The cache directory (`.slim/clonedeps/`) is platform-specific and located in the user's home directory.
+- This skill is primarily for development and debugging; it does not affect runtime behavior.

+ 63 - 36
src/skills/codemap.md

@@ -2,48 +2,75 @@
 
 ## Responsibility
 
-- Own metadata-driven OpenCode custom skills shipped with this package.
-- Maintain the skill contract artifacts (`SKILL.md`, `README.md`, per-skill helper files) that are copied into
-  `${configDir}/skills` at install time.
-- Preserve a canonical registry boundary: runtime code consumes skill definitions as data, not as executable
-  plugin dependencies.
+- Owns metadata-driven OpenCode custom skills shipped with this package
+- Maintains the skill contract artifacts (`SKILL.md`, `README.md`, per-skill helper files) that are copied into `${configDir}/skills` at install time
+- Preserves a canonical registry boundary: runtime code consumes skill definitions as data, not as executable plugin dependencies
+- Skills are partitioned into orchestrator-only workflows and general-purpose skills for broad reuse
 
 ## Design
 
-- `CUSTOM_SKILLS` in `src/cli/custom-skills.ts` is the authoritative skill manifest for bundled
-  skills; each entry maps folder name + `sourcePath` to an install-time consumer.
-- `install.ts` runs `installCustomSkill()` which recursively copies bundled skill
-  directories into the OpenCode skills directory.
-- This directory is partitioned by skill:
-  - `src/skills/codemap/` (command-style repository mapping skill)
-  - `src/skills/clonedeps/` (workflow skill for dependency source mirroring)
-  - `src/skills/simplify/` (readability/refactor guidance skill)
-  - `src/skills/deepwork/` (orchestrator-only workflow for heavy coding sessions)
-  - `src/skills/reflect/` (orchestrator-only workflow for learning from repeated work and suggesting reusable improvements)
-  - `src/skills/worktrees/` (orchestrator-only workflow for safe Git worktree lanes)
-  - `src/skills/oh-my-opencode-slim/` (orchestrator-only plugin configuration and self-improvement guidance)
-- Files are considered static runtime payload. No plugin TS module in `src/` imports these files directly; they
-  are loaded by OpenCode via filesystem installation.
+### Skill Registry
+
+- `CUSTOM_SKILLS` in `src/cli/custom-skills.ts` is the authoritative skill manifest for bundled skills
+- Each entry maps folder name + `sourcePath` to an install-time consumer
+- Skills are categorized by purpose and access scope:
+
+| Skill | Type | Purpose |
+|-------|------|-------|
+| `codemap/` | General-purpose | Repository mapping and codebase documentation skill |
+| `clonedeps/` | General-purpose | Workflow skill for dependency source mirroring and inspection |
+| `simplify/` | General-purpose | Readability and maintainability guidance skill |
+| `deepwork/` | Orchestrator-only | Heavy coding sessions, multi-phase implementation, and risky refactors |
+| `reflect/` | Orchestrator-only | Learning from repeated work and suggesting reusable improvements |
+| `worktrees/` | Orchestrator-only | Safe Git worktree lanes for parallel, risky, or isolated work |
+| `oh-my-opencode-slim/` | Orchestrator-only | Plugin configuration and self-improvement guidance |
+
+### Installation Pipeline
+
+- `install.ts` runs `installCustomSkill()` which recursively copies bundled skill directories into the OpenCode skills directory
+- During plugin release, the `files` whitelist in `package.json` must include `src/skills` so `src/skills/**` survive `npm pack`
+- OpenCode plugin startup discovers these installed folders and reads each `SKILL.md` as a prompt-level contract
+
+### Runtime Consumption
+
+- Files are considered static runtime payload
+- No plugin TS module in `src/` imports these files directly
+- They are loaded by OpenCode via filesystem installation at runtime
 
 ## Flow
 
-- `bun run install` delegates to `src/cli/install.ts`, where `installCustomSkills` gates copying of
-  each `CUSTOM_SKILLS` entry.
-- `installCustomSkill()` computes `packageRoot`, validates `sourcePath`, then performs a recursive
-  directory copy via `copyDirRecursive()`.
-- During plugin release, the `files` whitelist in `package.json` must include `src/skills` so
-  `src/skills/**` survive `npm pack`.
-- OpenCode plugin startup discovers these installed folders and reads each `SKILL.md` as a prompt-level contract.
+1. **Skill Discovery**: `src/cli/custom-skills.ts` defines `CUSTOM_SKILLS` array with skill metadata
+2. **Installation**: `bun run install` delegates to `src/cli/install.ts`, where `installCustomSkills()` gates copying of each `CUSTOM_SKILLS` entry
+3. **Validation**: `installCustomSkill()` computes `packageRoot`, validates `sourcePath`, then performs a recursive directory copy via `copyDirRecursive()`
+4. **Distribution**: During plugin release, `package.json` `files` whitelist ensures `src/skills/**` are included in the published tarball
+5. **Runtime Discovery**: OpenCode plugin startup discovers installed skill folders and reads each `SKILL.md` as a prompt-level contract
 
 ## Integration
 
-- `src/cli/custom-skills.ts`: source-of-truth registry consumed by installer and permission helpers.
-- `src/cli/skills.ts:getSkillPermissionsForAgent()` auto-populates permission rules for
-  bundled skills when agent policy is derived from built-in recommendations.
-- `verify-release-artifact.ts` enforces artifact completeness by asserting key
-  bundled skill payloads such as `src/skills/simplify/SKILL.md`,
-  `src/skills/codemap/SKILL.md`, `src/skills/clonedeps/SKILL.md`, and
-  `src/skills/deepwork/SKILL.md`, `src/skills/reflect/SKILL.md`,
-  `src/skills/worktrees/SKILL.md`, plus `src/skills/oh-my-opencode-slim/SKILL.md`,
-  are present in the tarball.
-- `package.json` scripts (`verify:release`, `build`) rely on these assets to ensure install-time skill availability.
+### Build & Release Dependencies
+
+- `src/cli/custom-skills.ts`: Source-of-truth registry consumed by installer and permission helpers
+- `src/cli/install.ts`: Contains `installCustomSkills()` and `installCustomSkill()` functions
+- `verify-release-artifact.ts`: Enforces artifact completeness by asserting key bundled skill payloads are present in the tarball:
+  - `src/skills/simplify/SKILL.md`
+  - `src/skills/codemap/SKILL.md`
+  - `src/skills/clonedeps/SKILL.md`
+  - `src/skills/deepwork/SKILL.md`
+  - `src/skills/reflect/SKILL.md`
+  - `src/skills/worktrees/SKILL.md`
+  - `src/skills/oh-my-opencode-slim/SKILL.md`
+- `package.json` scripts (`verify:release`, `build`) rely on these assets to ensure install-time skill availability
+
+### Permission System
+
+- `src/cli/skills.ts:getSkillPermissionsForAgent()` auto-populates permission rules for bundled skills when agent policy is derived from built-in recommendations
+- Bundled skills are treated as data payloads with explicit permission boundaries defined in the skill manifests
+
+### Skill Contracts
+
+Each skill directory contains:
+- `SKILL.md`: Skill contract defining name, description, and usage contract
+- `README.md`: Documentation and examples for the skill
+- Optional helper files and subdirectories for skill-specific functionality
+
+These artifacts are copied verbatim to the OpenCode skills directory during installation and serve as the skill's interface definition.

+ 85 - 18
src/tools/ast-grep/codemap.md

@@ -2,27 +2,94 @@
 
 ## Responsibility
 
-- Wrap the external `ast-grep` CLI so the broader system can invoke AST-aware search and replace without caring about binary discovery or argument details (`cli.ts`, `tools.ts`).
-- Provide well-typed tooling primitives (`types.ts`) plus formatted user output hints/summary helpers (`utils.ts`) that can be re-used by CLI commands or plugin UI layers.
-- Manage the brittle parts of CLI usage: locating a binary from caches, npm packages, or homebrew, downloading platform-specific releases when needed, and surfacing environment status/limits (`constants.ts`, `downloader.ts`).
+Provides AST-aware code search and replace capabilities via the ast-grep CLI. This tooling layer enables OpenCode agents to perform precise, language-aware code transformations and queries across the repository using structured AST patterns rather than fragile regex-based matching.
 
-## Design Patterns and Decisions
+## Design
 
-- **Singleton initialization with retries:** `getAstGrepPath` caches an init promise so concurrent requests share discovery/download work and fallback from local binaries to downloads (`cli.ts`).
-- **Tool definition as declarative metadata:** `tools.ts` exports `ast_grep_search` and `ast_grep_replace` via the OpenCode tool registry, which keeps descriptions, schemas, and execution logic centralized.
-- **Separation of concerns:** `cli.ts` focuses on process spawning and JSON parsing, `constants.ts` owns binary path resolution plus environment checks/formatting, `utils.ts` formats results while `downloader.ts` handles platform maps, cache directories, and fetch/extraction.
-- **Fail fast with hints:** Empty-match hints tailored per language (e.g., help removing trailing colons in Python) make search UX better while keeping AST requirements explicit.
+The implementation follows a layered architecture:
 
-## Data & Control Flow
+- **Tool Definitions** (`tools.ts`):
+  - `ast_grep_search`: Exposes a tool for AST pattern matching with meta-variable support ($VAR, $$$)
+  - `ast_grep_replace`: Exposes a tool for AST-aware code rewriting with dry-run capability
+  - Both tools validate inputs, run the CLI, format results, and surface output to the user via metadata
 
-- Tools (`ast_grep_search`, `ast_grep_replace`) call `runSg`, populating CLI arguments (pattern, rewrite, globs, context) and routing output through `formatSearchResult`/`formatReplaceResult` before reporting via `showOutputToUser` (`tools.ts`).
-- `runSg` constructs the command, ensures the CLI binary exists (resetting via `getAstGrepPath` which may call `findSgCliPathSync` or trigger a download), spawns the process with timeout handling, and parses compact JSON while guarding against truncated output and CLI errors (`cli.ts`).
-- Binary resolution uses `constants.ts` helpers to detect cached binaries, installed packages, platform-specific packages, or Homebrew paths, and exposes environment checks/formatting to upstream callers (`constants.ts`).
-- `downloader.ts` is the fallback path: it infers the platform key, downloads the matching GitHub release, extracts `sg`, sets executable bits, and caches it under `~/.cache/oh-my-opencode-slim/bin` (or Windows AppData) so subsequent commands reuse the binary.
+- **CLI Integration** (`cli.ts`):
+  - `runSg()`: Core function that spawns the ast-grep CLI with proper argument construction, timeout handling, and output parsing
+  - Manages CLI availability via lazy initialization (`getAstGrepPath()`, `startBackgroundInit()`)
+  - Implements robust error handling, truncation detection, and retry logic for missing binaries
+  - Uses `crossSpawn` for cross-platform process spawning
 
-## Integration Points
+- **Type System** (`types.ts`):
+  - Defines `CliLanguage` (25 supported languages) and `CliMatch`/`SgResult` interfaces
+  - Provides type safety for CLI communication and result parsing
 
-- `index.ts` re-exports `ast_grep_search`, `ast_grep_replace`, runtime helpers (`ensureCliAvailable`, `checkEnvironment`, etc.), and downloader utilities so other modules can plug into the tooling layer while sharing diagnostics (`index.ts`).
-- The OpenCode plugin layer imports `builtinTools` from `src/tools/ast-grep/index.ts` to surface search/replace capabilities through the CLI tool registry.
-- `constants.ts` and `downloader.ts` are used by `cli.ts` to decide where to execute `sg`, while environment helpers inform onboarding UIs or setup scripts about missing binaries.
-- `types.ts` defines the shared `CliLanguage`, `CliMatch`, and `SgResult` shapes that drive type safety across CLI invocation, formatting utilities, and tooling schemas.
+- **Utilities** (`utils.ts`):
+  - `formatSearchResult()`: Formats search results grouped by file with line numbers and truncation awareness
+  - `formatReplaceResult()`: Formats replacement results with dry-run indicators and before/after snippets
+  - `getEmptyResultHint()`: Provides user guidance when patterns yield no matches (e.g., missing colons in Python)
+
+- **Binary Management** (`downloader.ts`):
+  - `ensureAstGrepBinary()`: Downloads platform-specific ast-grep binary on-demand to `~/.cache/oh-my-opencode-slim/bin/`
+  - Supports caching, version detection, and platform-specific artifacts
+  - Handles permissions and cleanup
+
+- **Environment & Constants** (`constants.ts`):
+  - `checkEnvironment()`: Validates CLI availability at startup for early feedback
+  - `formatEnvironmentCheck()`: User-friendly status reporting
+  - Defines supported languages, default limits (timeout, max output bytes, max matches), and language-to-extension mappings
+  - Implements path resolution logic that checks: cached binary → npm package → platform-specific package → Homebrew → PATH
+
+- **Public API** (`index.ts`):
+  - Exports built-in tools for OpenCode integration
+  - Re-exports types, constants, and CLI utilities for external consumers
+
+## Flow
+
+### Search Flow
+1. Agent invokes `ast_grep_search` tool with pattern, language, optional paths/globs/context
+2. Tool validates inputs and calls `runSg()` with appropriate arguments
+3. `runSg()` ensures CLI availability (downloads if needed), constructs CLI args:
+   - `-p <pattern> --lang <lang> --json=compact`
+   - Optional: `-r <rewrite>` (for replace), `-C <context>`, `--globs <glob>`, paths
+4. CLI executes, returns JSON output (compact format)
+5. `runSg()` parses output, handles truncation (max bytes/max matches), and returns `SgResult`
+6. Tool formats results via `formatSearchResult()` and surfaces to user via metadata
+7. If no matches, `getEmptyResultHint()` may provide user guidance
+
+### Replace Flow
+1. Agent invokes `ast_grep_replace` with pattern, rewrite, language, dry-run flag
+2. Tool calls `runSg()` with `updateAll: !dryRun` to enable actual file writes
+3. CLI performs AST-aware rewrites and returns matches with `replacement` field
+4. Tool formats results with `[DRY RUN]` or `[APPLIED]` indicators and before/after snippets
+5. Output is surfaced to user via metadata
+
+### Binary Availability Flow
+1. On first use, `getAstGrepPath()` triggers background initialization via `startBackgroundInit()`
+2. If cached binary exists and is valid, use it
+3. Else, download platform-specific binary via `ensureAstGrepBinary()`
+4. Fallback to npm package or system-installed binary if available
+5. Path is cached in `resolvedCliPath` to avoid repeated lookups
+
+## Integration
+
+- **Consumed by**: OpenCode plugin system via `@opencode-ai/plugin` tool registration
+- **Depends on**:
+  - `@ast-grep/cli` (for fallback binary resolution)
+  - `crossSpawn` utility for cross-platform process handling
+  - `extractZip` utility for binary extraction
+- **Exposes to agents**:
+  - `ast_grep_search` tool for pattern matching
+  - `ast_grep_replace` tool for code transformations
+- **Used in**: Agent implementations and skill systems requiring precise code analysis
+
+## Usage Examples
+
+```typescript
+// Search for all console.log calls in TypeScript files
+@fixer search for console.log calls in TypeScript files
+
+// Replace arrow functions with regular functions
+@fixer replace arrow functions with regular functions
+```
+
+See tool definitions in `tools.ts` for full argument schemas and examples.

+ 267 - 89
src/tools/codemap.md

@@ -2,93 +2,271 @@
 
 ## Responsibility
 
-`src/tools/` exposes plugin tooling and runtime command hooks used by OpenCode.
-
-- AST-aware search/replace via `ast-grep` stack.
-- Remote fetch/transform utility via `smartfetch` (`webfetch` tool).
-- Council orchestration via `createCouncilTool` (`council.ts`).
-- (No custom subtask feature in V2 — use native background `task` plus hook-driven completion)
-- Runtime preset switching via `/preset` hook via `createPresetManager` (`preset-manager.ts`).
-
-It is the bridge between plugin runtime integration (`src/index.ts`) and the lower-level
-implementations in feature folders.
-
-## Export surface (`src/tools/index.ts`)
-
-- `ast_grep_search`, `ast_grep_replace` from `./ast-grep`
-- `createWebfetchTool`, `WEBFETCH_DESCRIPTION`, and related types from `./smartfetch`
-- `createCouncilTool`
-
-- `createPresetManager` and `PresetManager` type
-
-## Design patterns
-
-- **Factory-based registration:** each feature exposes a factory that returns an
-  executable/tool or handler object bound to plugin context.
-- **Clear boundaries:** all plugin lifecycle hooks are emitted from factory methods
-  (`handleCommandExecuteBefore`, `handleEvent`, `registerCommand`) rather than in tool
-  modules.
-- **Metadata-first output:** tool calls return text plus internal metadata writes when
-  possible (for richer UI surfaces).
-
-## Subsystems and data flow
-
-### Council tool path
-
-- `createCouncilTool` defines `council_session`.
-- `execute` performs guarded invocation:
-  - validates `toolContext` and `sessionID`,
-  - only allows direct use by `agent: 'council'` (or missing agent for backward compatibility),
-  - calls `CouncilManager.runCouncil(prompt, preset, parentSessionId)`.
-- On success, appends a councillor response summary and normalized model list to output.
-- On failure, returns a concise error string.
-- Shows config deprecation warnings when `CouncilManager` exposes deprecated field metadata.
-
-### Preset-manager command path
-
-- `createPresetManager(ctx, config)` returns:
-  - `registerCommand(opencodeConfig)`: injects `/preset` command definition if absent,
-  - `handleCommandExecuteBefore(input, output)`: intercepts `/preset` command handling.
-- Command behavior:
-  - no args → clear output and list available presets (`active` marker supported),
-  - single token arg → switch preset through `client.config.update(...)` with mapped agent overrides,
-  - multi-word arg → suggestion + no update.
-- Mapping logic converts plugin preset override format (`AgentOverrideConfig`) into runtime
-  SDK `agent` config (`model`, `temperature`, `variant`, `options`) and skips fields not
-  supported in runtime updates (`prompt`, `orchestratorPrompt`, `skills`, `mcps`,
-  `displayName`).
-- In-memory `activePreset` supports immediate status display and updates after successful switches.
-
-### Smartfetch path
-
-- `createWebfetchTool` owns fetch orchestration, permission prompts, cache checks,
-  llms.txt probing, binary/text branching, and optional secondary-model post-processing.
-- `smartfetch` modules split work into:
-  - transport/policy (`network.ts`),
-  - cache + TTL semantics (`cache.ts`),
-  - output shaping (`utils.ts`),
-  - file-backed binaries (`binary.ts`),
-  - secondary-model summarization (`secondary-model.ts`),
-  - constants and types.
-- `webfetch` is always registered from `src/index.ts` as a public tool.
-
-### AST-grep path
-
-- `ast-grep` is split into CLI/CLI-discovery and tool-definition concerns.
-- `ast_grep_search`/`ast_grep_replace` execution calls into `runSg`, which handles
-  argument normalization, binary availability, timeout/error handling, and output truncation.
-- `src/tools/ast-grep/index.ts` re-exports tool definitions and utility helpers for
-  discoverability (`ensureCliAvailable`, `getAstGrepPath`, downloader/runtime checks).
-
-## Integration points in `src/index.ts`
-
-- Tool registration:
-  - `council` tools (only when `config.council` exists),
-  - `webfetch`,
+Centralized tool factory and registry for the OpenCode plugin system. This directory defines all executable tools exposed to OpenCode agents, including:
+
+- **Agent orchestration tools**: Multi-LLM council sessions, task cancellation, and ACP agent execution
+- **Code intelligence tools**: AST-grep pattern matching and transformation across languages
+- **Web capabilities**: Smart web fetching with caching and secondary model processing
+- **Runtime configuration**: Preset management for dynamic agent configuration switching
+
+These tools enable agents to perform file operations, orchestrate multi-model consensus, manage background tasks, and interact with external systems while maintaining security boundaries through the OpenCode tool schema.
+
+## Design
+
+### Architecture Pattern: **Tool Factory Pattern**
+
+Each tool is implemented as a factory function that returns a `ToolDefinition` record compatible with the `@opencode-ai/plugin` SDK. The pattern provides:
+
+- **Encapsulation**: Tool creation logic and dependencies are isolated per tool
+- **Composition**: Tools can be selectively exported and composed in `src/tools/index.ts`
+- **Testability**: Factories accept dependencies as parameters, enabling mock injection
+- **Type Safety**: Zod schemas validate tool arguments at runtime
+
+### Core Tool Families
+
+| Tool Family | Purpose | Key Components |
+|------------|---------|----------------|
+| **Council** | Multi-LLM consensus orchestration | `council.ts`, `council-manager.ts` |
+| **Task Management** | Background task lifecycle control | `cancel-task.ts`, `background-job-board.ts` |
+| **ACP Integration** | External agent protocol execution | `acp-run.ts`, ACP client implementation |
+| **Code Intelligence** | AST-based code manipulation | `ast-grep/` directory, `tools.ts` |
+| **Web Fetching** | Intelligent web content retrieval | `smartfetch/` directory, `tool.ts` |
+| **Preset Management** | Runtime agent configuration | `preset-manager.ts`, TUI state integration |
+
+### Security & Validation
+
+- **Agent Restrictions**: Tools validate calling agent identity (e.g., `council_session` only callable by `council` agent)
+- **Permission Prompts**: Web fetching and ACP tools require explicit user permission via `ctx.ask()`
+- **Timeout Controls**: Configurable timeouts prevent unbounded execution
+- **Input Sanitization**: Zod schemas validate all tool arguments
+
+### State Management
+
+- **Runtime Presets**: Preset state persists across plugin reloads via `runtime-preset.ts`
+- **TUI Integration**: Preset changes update the terminal UI snapshot for immediate feedback
+- **Background Jobs**: Task cancellation uses a centralized job board for tracking and cleanup
+
+## Flow
+
+### Tool Creation Lifecycle
+
+```
+1. Plugin Initialization (src/index.ts)
+   └─> registerTools() calls each tool factory with dependencies
+      
+2. Tool Factory Execution
+   ├─> Accepts PluginInput context and domain-specific dependencies
+   ├─> Validates configuration and environment
+   ├─> Returns ToolDefinition record with execute() handler
+   └─> Registers tool with OpenCode via plugin API
+
+3. Tool Invocation
+   ├─> Agent calls tool with validated arguments
+   ├─> Tool executes business logic
+   ├─> May call ctx.ask() for user permission
+   ├─> Returns structured result or error
+   └─> OpenCode presents result to agent
+```
+
+### Council Session Flow (Multi-LLM Orchestration)
+
+```
+1. Agent invokes council_session tool
+   ├─> Validates calling agent is 'council'
+   ├─> Receives prompt and optional preset
+   ├─> Delegates to CouncilManager.runCouncil()
+   │   ├─> Spawns parallel councillor sessions
+   │   ├─> Collects formatted responses
+   │   └─> Synthesizes final output with model composition footer
+   └─> Returns consensus result to agent
+```
+
+### Task Cancellation Flow
+
+```
+1. Orchestrator invokes cancel_task tool
+   ├─> Validates calling agent is 'orchestrator'
+   ├─> Resolves task_id to BackgroundJobBoard entry
+   ├─> Calls abortSessionWithTimeout() to signal cancellation
+   ├─> Verifies session stopped via status polling
+   ├─> Marks job as cancelled in BackgroundJobBoard
+   └─> Returns cancellation confirmation
+```
+
+### ACP Agent Execution Flow
+
+```
+1. Agent invokes acp_run tool
+   ├─> Validates calling agent matches configured agent name
+   ├─> Spawns ACP client process with config
+   ├─> Sends prompt via JSON-RPC over stdin/stdout
+   ├─> Handles permission requests via ctx.ask()
+   ├─> Collects streaming output chunks
+   ├─> Enforces timeout if configured
+   └─> Returns concatenated output or error
+```
+
+### AST-grep Pattern Matching Flow
+
+```
+1. Agent invokes ast_grep_search or ast_grep_replace
+   ├─> Validates language support and pattern syntax
+   ├─> Ensures CLI binary available (downloads if needed)
+   ├─> Executes sg (AST-grep CLI) process
+   ├─> Parses JSON output into structured matches/edits
+   └─> Returns typed results to agent
+```
+
+### Web Fetching Flow
+
+```
+1. Agent invokes webfetch tool
+   ├─> Validates URL and configuration
+   ├─> Checks cache for fresh content
+   ├─> If cache miss, fetches via network with timeout
+   ├─> Optionally processes with secondary model
+   ├─> Caches result for future requests
+   └─> Returns extracted content to agent
+```
+
+## Integration
+
+
+### Consumers
+
+- **Main Plugin** (`src/index.ts`):
+  - `registerTools()` - Registers all exported tools with OpenCode
+  - `getToolDefinitions()` - Composes tool set for plugin initialization
   
-  - AST tools.
-- `presetManager` is initialized in plugin init and:
-  - calls `registerCommand` during config hook,
-  - handles command interception in `command.execute.before`.
-- `/preset` handling is explicitly user-facing (command hook), while webfetch and
-  council are tool-facing.
+- **Agents** (`src/agents/`):
+  - Council agent uses `council_session` tool
+  - Individual agents use `acp_run` tool for specialized tasks
+  - All agents use `ast_grep_search`/`ast_grep_replace` for code manipulation
+
+- **CLI** (`src/cli/`):
+  - Preset manager integrates with `/preset` command
+  - Tool factories receive CLI configuration for ACP agents
+
+### Dependencies
+
+| Dependency | Purpose |
+|------------|---------|
+| `@opencode-ai/plugin` | Tool schema and execution framework |
+| `CouncilManager` (`src/council/`) | Multi-LLM orchestration engine |
+| `BackgroundJobBoard` (`src/utils/`) | Background task tracking and cleanup |
+| `Config System` (`src/config/`) | ACP agent configurations and presets |
+| `TUI State` (`src/tui-state.ts`) | Preset visualization in terminal UI |
+| `AST-grep CLI` | Pattern matching and transformation engine |
+| `Network Utilities` | Web fetching and caching |
+
+### Cross-Module Data Flow
+
+```
+Tools Layer → Council Layer
+├─ council_session tool → CouncilManager.runCouncil()
+└─> Returns consensus result with model composition footer
+
+Tools Layer → Background Layer
+├─ cancel_task tool → BackgroundJobBoard.resolve() → abortSessionWithTimeout()
+└─> Returns cancellation status
+
+Tools Layer → Config Layer
+├─ acp_run tool → AcpAgentsConfig from config system
+├─ preset-manager → Preset configurations from plugin config
+└─> Validates and applies runtime configuration
+
+Tools Layer → AST-grep Layer
+├─ ast_grep_search/ast_grep_replace → CLI binary execution
+└─> Returns typed AST matches and edit results
+
+Tools Layer → Web Layer
+└─ webfetch tool → Network utilities with caching and model processing
+```
+
+### Configuration Integration
+
+- **ACP Agents**: Defined in `src/config/agents.ts`, consumed by `acp_run.ts`
+- **Presets**: Defined in plugin config (`oh-my-opencode-slim.jsonc`), managed by `preset-manager.ts`
+- **Council**: Configured via council presets, validated by `council.ts`
+
+
+### Error Handling & Recovery
+
+- **Session Aborts**: `cancel-task.ts` implements robust abort verification with polling and cleanup
+- **Timeouts**: All network and process operations enforce configurable timeouts
+- **Permission Denials**: Tools gracefully handle user rejection via `ctx.ask()`
+- **Binary Availability**: `ast-grep/` tools auto-download CLI on first use
+
+
+## Tool Reference
+
+### Exported Tools (src/tools/index.ts)
+
+```typescript
+// AST-grep tools
+export { createAcpRunTool } from './acp-run';
+export { ast_grep_replace, ast_grep_search } from './ast-grep';
+
+// Task management
+export { createCancelTaskTool } from './cancel-task';
+
+// Council orchestration
+export { createCouncilTool } from './council';
+
+// Preset management
+export type { PresetManager } from './preset-manager';
+export { createPresetManager } from './preset-manager';
+
+// Web fetching
+export { createWebfetchTool } from './smartfetch';
+```
+
+### Tool-Specific Configuration
+
+
+#### ACP Agents (acp-run.ts)
+- Configured in `src/config/agents.ts` as `AcpAgentsConfig`
+- Each agent requires: `command`, `args`, `cwd`, `permissionMode`
+- Supports: `ask` (prompt user), `reject` (auto-deny), `allow` (auto-approve)
+
+#### Council Sessions (council.ts)
+- Configured via council presets in plugin config
+- Requires council agent to be registered in OpenCode
+- Supports preset-specific councillor configurations
+
+#### Presets (preset-manager.ts)
+- Defined in plugin config under `presets` field
+- Each preset maps agent names to `AgentOverrideConfig`
+- Changes persist across plugin reloads via user config file
+
+#### AST-grep (ast-grep/)
+- Auto-downloads CLI binary on first use
+- Supports 25+ languages via CLI_LANGUAGES constant
+- Provides search (pattern matching) and replace (transformation) tools
+
+#### Webfetch (smartfetch/)
+- Implements caching with configurable TTL
+- Supports secondary model processing for content extraction
+- Handles redirects, timeouts, and error recovery
+
+## Testing Strategy
+
+- **Unit Tests**: Individual tool factories tested in `*.test.ts` files
+- **Integration Tests**: Tools tested with mock dependencies and OpenCode context
+- **E2E Tests**: Council and ACP tools tested with real external services
+- **Binary Tests**: AST-grep CLI availability and functionality verified
+
+## Performance Considerations
+
+- **Binary Downloads**: AST-grep CLI downloaded once and cached
+- **Network Caching**: Webfetch results cached to avoid redundant requests
+- **Timeout Enforcement**: Prevents unbounded execution of external tools
+- **Parallel Execution**: Council sessions run councillors in parallel
+
+## Security Considerations
+
+- **Agent Restrictions**: Tools validate calling agent identity
+- **Permission Prompts**: User approval required for web and ACP operations
+- **Input Validation**: Zod schemas validate all tool arguments
+- **Process Isolation**: ACP agents run in separate processes
+- **Timeout Controls**: Prevents denial-of-service via hanging operations

+ 5 - 1
src/tools/smartfetch/codemap.md

@@ -15,9 +15,13 @@
 ## Data & Control Flow
 
 1. `createWebfetchTool` normalizes the requested URL, derives permission patterns/allowed origins, asks for `webfetch` permission, and computes the cache key (`tool.ts`, `network.ts`, `cache.ts`).
+
 2. If `prefer_llms_txt` applies, `probeLlmsText` tries `/llms-full.txt` then `/llms.txt`, following only permitted redirects and rejecting HTML/login-wall responses (`network.ts`).
+
 3. When the tool falls back to the page itself, `fetchWithUpgradeFallback` handles HTTPS upgrade fallback, redirect enforcement, conditional headers for revalidation, binary detection, and bounded body reads (`network.ts`, `tool.ts`).
+
 4. Text/HTML payloads are decoded and normalized through `extractFromHtml`, `cleanFetchedMarkdown`, `extractHeadingsFromMarkdown`, `frontmatter`, and `joinRenderedContent`; binary payloads optionally persist via `saveBinary` and return a metadata message (`utils.ts`, `binary.ts`, `tool.ts`).
+
 5. If the caller supplied a prompt and configured secondary models, `runSecondaryModelWithFallback` truncates input to a bounded size, disables tool access for the helper session, retries across configured models, and the tool degrades back to base fetched content if that step fails (`secondary-model.ts`, `tool.ts`).
 
 ## Integration Points
@@ -25,4 +29,4 @@
 - `src/index.ts` registers the tool under the public name `webfetch`, so agents can call it alongside council and AST-grep tools.
 - `src/tools/smartfetch/index.ts` re-exports the tool factory, description, and shared types for other modules or docs to import without reaching into implementation files.
 - `secondary-model.ts` depends on the OpenCode plugin client (`PluginInput['client']`) to spawn an isolated helper session, resolve `small_model` from the effective OpenCode config, and resolve `explorer` / `librarian` fallbacks from slim's own plugin config loader.
-- `cache.ts`, `network.ts`, and `utils.ts` are intentionally reusable seams for tests: cache behavior, redirect policy, llms probing, heading extraction, and render/metadata helpers can be verified without hitting the full tool entrypoint.
+- `cache.ts`, `network.ts`, and `utils.ts` are intentionally reusable seams for tests: cache behavior, redirect policy, llms probing, heading extraction, and render/metadata helpers can be verified without hitting the full tool entrypoint.

+ 89 - 89
src/utils/codemap.md

@@ -1,112 +1,112 @@
 # src/utils/
 
-Cross-cutting runtime utilities used by orchestration, hooks, and plugin I/O.
-
 ## Responsibility
 
-- **background-job-board.ts**: Tracks V2 background jobs by parent session,
-  assigns aliases, records read context, and exposes reusable completed /
-  reconciled sessions with prompt rendering and reusable LRU caps.
-- **tmux.ts**: Multiplexer-safe pane lifecycle helpers (`spawnPane`, `closePane`)
-  used by tmux and zellij adapters.
-- **subagent-depth.ts**: Tracks delegated session depth and enforces max nested
-  delegation depth.
-- **agent-variant.ts**: Normalizes agent names and applies optional variant
-  labels without overriding existing body configuration.
-- **env.ts**: Unified environment lookup across Bun/Node with empty-string
-  filtering.
-- **session.ts**: Session extraction helpers for multi-turn synthesis and
-  prompt/result post-processing.
-- **polling.ts**: Shared polling with stability thresholds and abort-signal
-  support.
-- **zip-extractor.ts**: Cross-platform zip/tar extraction with Windows fallback
-  tooling.
-- **task.ts**: Parses native `task` output and injected background completion text.
-- **system-collapse.ts**: Collapses multiple system prompt fragments into one
-  array element while mutating the original array reference.
-- **logger.ts**: Structured JSON logging to temporary files.
-- **internal-initiator.ts**: Marker utilities for internal orchestrator text-part
-  tagging.
-- **compat.ts**: Backward compatibility helpers.
-- **index.ts**: Public re-export barrel for utility modules.
+Centralized utilities and shared abstractions used across the oh-my-opencode-slim plugin. This folder provides:
+- Background job lifecycle management via BackgroundJobBoard
+- Environment and configuration utilities
+- Type guards and validation helpers
+- Session and timeout utilities for council/council-manager
+- Logging infrastructure with automatic rotation
+- Task output parsing utilities
+- System message utilities
 
 ## Design
 
-- **Parent-scoped background job board**: `BackgroundJobBoard` tracks
-  active/unreconciled jobs separately from completed/reconciled reusable
-  sessions; reusable entries are LRU-capped per parent+agent.
-- **Deterministic lifecycle tracking**: `SubagentDepthTracker` maps session IDs to
-  depth and is cleaned on session deletion.
-- **Provider-safe env access**: `getEnv` falls back from `Bun.env` to
-  `process.env` and normalizes blank values.
-- **Graceful shutdown protocol**: Multiplexer pane close path sends Ctrl+C before
-  kill, then rebalances layout state.
-- **Session extraction model**: `extractSessionResult`/`parseModelReference`
-  helpers are centralized under `session.ts`.
-- **In-place system normalization**: `collapseSystemInPlace` mutates `system` to
-  preserve references held by OpenCode internals.
-- **Resilient polling**: `pollUntilStable` requires consecutive confirmations
-  before success.
+### Core Abstractions
 
-## Flow
+- **BackgroundJobBoard** (`background-job-board.ts`): Singleton registry and lifecycle manager for background tasks spawned by sub-agents. Implements a reusable session pool pattern with automatic cleanup and reconciliation hooks. Tracks task state (running, completed, error, cancelled), maintains context files, and provides prompt-ready summaries for agent coordination.
 
-### `background-job-board.ts`
+- **Logger** (`logger.ts`): File-based logging with 7-day retention, automatic directory creation, and write queuing. Logs are written to `~/.local/share/opencode/log/oh-my-opencode-slim.<sessionId>.log` and cleaned up on initialization.
 
-- `deriveTaskSessionLabel` computes a deterministic prompt hint from
-  `description`, the first non-empty `prompt` line, or a fallback agent label.
-- `registerLaunch` creates/reopens running jobs and assigns monotonic aliases
-  within each parent+agent (`exp-1`, `lib-2`, etc.).
-- `updateStatus` marks terminal jobs unreconciled; `markReconciled` makes only
-  completed terminal jobs reusable.
-- `resolveReusable`, `markUsed`, `drop`, and `clearParent`
-  keep job aliases consistent on polling, reuse, and teardown.
-- `formatForPrompt` returns the unified `### Background Job Board` prompt section
-  with Active / Unreconciled and Reusable Sessions subsections.
+- **Session Utilities** (`session.ts`): Timeout handling, session abort coordination, model reference parsing, and session content extraction. Provides `promptWithTimeout` and `extractSessionResult` for safe session operations.
 
-### `tmux.ts`
+- **Task Utilities** (`task.ts`): XML-inspired task output parsing for extracting task IDs, states, and results from tool output strings. Used for resumption and status tracking.
 
-- `spawnPane` flow: validate enabled state → check multiplexer availability →
-  resolve binary → execute attach command with layout handling.
-- `closePane` flow: send SIGINT-equivalent key sequence → delay → terminate pane
-  → rebalance layout if needed.
-- `isServerRunning` flow: bounded `/health` checks with retries and caching.
+- **Type Guards** (`guards.ts`): Simple type checking utilities (`isRecord`) for runtime validation.
 
-### `polling.ts`
+- **Environment Utilities** (`env.ts`): Environment variable parsing and plugin disable flag checking.
 
-- `pollUntilStable(fn, options)` repeatedly calls async predicate and tracks
-  consecutive true states.
-- Returns once stable threshold is met, timeout elapses, or abort signal is
-  raised.
+- **Internal Initiator** (`internal-initiator.ts`): Marker system for identifying internally-initiated agent messages to prevent infinite loops.
 
-### `session.ts`
+- **System Collapse** (`system-collapse.ts`): Utility for collapsing multiple system messages into a single entry by joining with double-newlines.
 
-- Composes prompt parts and extracts normalized session output for text/call/result
-  flows.
-- Hosts shared parsing/formatting utilities used by council and tool execution
-  layers.
+### Design Patterns
 
-### `task.ts`
+- **Singleton**: BackgroundJobBoard is a singleton registry with global state for all background tasks
+- **Strategy**: Task parsing adapts to multiple output formats (XML tags, plain text headers)
+- **Observer**: Logger uses write queuing to avoid blocking the main thread
+- **Utility**: Each utility module provides focused, composable functions
+
+## Flow
 
-- Scans task output line-by-line and extracts `task_id`, state, timeout, and
-  result summary fields.
+### Background Job Lifecycle
+1. Agent launches a background task via BackgroundJobBoard.registerLaunch()
+2. Task runs and updates status via BackgroundJobBoard.updateStatus()
+3. On completion/error/cancellation, task is marked terminal and added to reusable pool
+4. Subsequent tasks from same agent/session can reuse completed sessions via aliases
+5. Unused reusable sessions are automatically trimmed based on maxReusablePerAgent
 
-### `system-collapse.ts`
+### Logging Flow
+1. Plugin initializes logger with session ID via initLogger(sessionId)
+2. Logs are appended to `~/.local/share/opencode/log/oh-my-opencode-slim.<sessionId>.log`
+3. Old logs (>7 days) are automatically cleaned up on initialization
+4. Log writes are queued to avoid blocking, with errors silently ignored
 
-- `collapseSystemInPlace(system: string[])` joins system entries with `\n\n`,
-  clears and repopulates the same array reference, and preserves empty-array
-  behavior.
+### Session Operations
+1. Council manager uses `promptWithTimeout()` to send prompts with configurable timeout
+2. On timeout, session is aborted and OperationTimeoutError is thrown
+3. Results are extracted via `extractSessionResult()` which collects all assistant message text
 
 ## Integration
 
-- **Consumers**
-  - `src/multiplexer/*`: `SubagentDepthTracker` and `tmux.ts` integration.
-  - `src/council/council-manager.ts`: depth control and session extraction
-    helpers.
-  - `src/hooks/*`: marker detection, polling, and session-aware state helpers.
-  - `src/hooks/task-session-manager`: `BackgroundJobBoard`, task-output parsing,
-    and `deriveTaskSessionLabel` provide V2 background job polling/reuse workflow
-    through message-transform prompt injection.
-- **Dependencies**
-  - Pulls constants from `../config` (`DEFAULT_MAX_SUBAGENT_DEPTH`, polling
-    intervals/timeouts).
-  - `index.ts` re-exports utility API.
+### Consumers
+
+- **Council/Council Manager** (`src/council/`):
+  - Uses BackgroundJobBoard for background task management
+  - Uses session utilities for prompt timeout and session extraction
+  - Uses logger for debug and audit logging
+
+- **Multiplexer** (`src/multiplexer/`):
+  - Uses session utilities for session operations
+  - Uses logger for session lifecycle events
+
+- **Agents** (`src/agents/`):
+  - BackgroundJobBoard for launching and tracking background tasks
+  - Logger for agent-specific logging
+
+- **Main Plugin** (`src/index.ts`):
+  - Exports all utilities via `src/utils/index.ts`
+  - Uses logger for plugin lifecycle events
+
+### Dependencies
+
+- **Node.js built-ins**: `fs`, `fs/promises`, `os`, `path` for logging and file operations
+- **@opencode-ai/sdk**: PluginInput type for session utilities
+
+### Export Chain
+
+`src/utils/index.ts` re-exports all utilities, providing a single entry point:
+```typescript
+export * from './background-job-board';
+export * from './internal-initiator';
+export { getLogDir, initLogger, log } from './logger';
+export * from './session';
+export * from './task';
+```
+
+This allows consumers to import from `src/utils` rather than individual files.
+
+## Files
+
+| File | Purpose |
+|------|---------|
+| `index.ts` | Public API re-exporting all utilities |
+| `background-job-board.ts` | Background task registry and lifecycle manager |
+| `env.ts` | Environment variable utilities |
+| `guards.ts` | Type guard utilities |
+| `internal-initiator.ts` | Internal agent message marker system |
+| `logger.ts` | File-based logging with rotation |
+| `session.ts` | Session timeout, abort, and extraction utilities |
+| `system-collapse.ts` | System message collapsing utility |
+| `task.ts` | Task output parsing utilities |