@oh-my-pi/pi-coding-agent 10.6.2 → 11.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +80 -79
  3. package/docs/compaction.md +182 -149
  4. package/docs/config-usage.md +141 -78
  5. package/docs/custom-tools.md +45 -16
  6. package/docs/extension-loading.md +56 -954
  7. package/docs/extensions.md +192 -51
  8. package/docs/hooks.md +109 -70
  9. package/docs/python-repl.md +52 -19
  10. package/docs/rpc.md +43 -19
  11. package/docs/sdk.md +270 -211
  12. package/docs/session-tree-plan.md +60 -417
  13. package/docs/session.md +104 -39
  14. package/docs/skills.md +59 -95
  15. package/docs/theme.md +139 -110
  16. package/docs/tree.md +42 -33
  17. package/docs/tui.md +226 -80
  18. package/package.json +8 -9
  19. package/src/capability/index.ts +3 -4
  20. package/src/cli/args.ts +4 -4
  21. package/src/cli/grep-cli.ts +1 -1
  22. package/src/commit/agentic/index.ts +4 -3
  23. package/src/commit/git/index.ts +2 -3
  24. package/src/commit/map-reduce/index.ts +2 -1
  25. package/src/config/prompt-templates.ts +2 -0
  26. package/src/config/settings-schema.ts +30 -7
  27. package/src/config/settings.ts +0 -14
  28. package/src/config.ts +2 -2
  29. package/src/discovery/agents.ts +36 -0
  30. package/src/discovery/index.ts +1 -0
  31. package/src/exa/mcp-client.ts +3 -3
  32. package/src/ipy/executor.ts +5 -7
  33. package/src/ipy/gateway-coordinator.ts +1 -1
  34. package/src/ipy/kernel.ts +20 -15
  35. package/src/ipy/prelude.py +1 -1
  36. package/src/ipy/runtime.ts +7 -6
  37. package/src/lsp/lspmux.ts +3 -3
  38. package/src/main.ts +6 -8
  39. package/src/mcp/tool-bridge.ts +19 -9
  40. package/src/modes/components/assistant-message.ts +2 -2
  41. package/src/modes/components/hook-editor.ts +4 -4
  42. package/src/modes/components/settings-defs.ts +37 -2
  43. package/src/modes/components/tool-execution.ts +7 -7
  44. package/src/modes/controllers/command-controller.ts +2 -2
  45. package/src/modes/controllers/event-controller.ts +4 -7
  46. package/src/modes/controllers/input-controller.ts +4 -4
  47. package/src/modes/controllers/selector-controller.ts +1 -0
  48. package/src/modes/interactive-mode.ts +3 -5
  49. package/src/modes/rpc/rpc-mode.ts +8 -9
  50. package/src/patch/index.ts +6 -6
  51. package/src/prompts/agents/explore.md +2 -2
  52. package/src/prompts/agents/frontmatter.md +5 -5
  53. package/src/prompts/agents/plan.md +3 -2
  54. package/src/prompts/agents/reviewer.md +1 -1
  55. package/src/prompts/system/system-prompt.md +1 -3
  56. package/src/sdk.ts +13 -9
  57. package/src/session/agent-session.ts +6 -4
  58. package/src/session/compaction/compaction.ts +3 -3
  59. package/src/session/session-manager.ts +8 -9
  60. package/src/ssh/connection-manager.ts +4 -4
  61. package/src/system-prompt.ts +2 -6
  62. package/src/task/agents.ts +1 -1
  63. package/src/task/executor.ts +31 -8
  64. package/src/task/index.ts +14 -35
  65. package/src/task/omp-command.ts +3 -1
  66. package/src/task/output-manager.ts +20 -6
  67. package/src/task/parallel.ts +3 -3
  68. package/src/task/render.ts +16 -2
  69. package/src/task/types.ts +13 -20
  70. package/src/task/worktree.ts +3 -3
  71. package/src/tools/ask.ts +3 -8
  72. package/src/tools/fetch.ts +2 -2
  73. package/src/tools/gemini-image.ts +5 -6
  74. package/src/tools/grep.ts +5 -5
  75. package/src/tools/index.ts +12 -5
  76. package/src/tools/read.ts +1 -1
  77. package/src/tools/todo-write.ts +2 -3
  78. package/src/utils/frontmatter.ts +1 -1
  79. package/src/utils/image-resize.ts +1 -1
  80. package/src/utils/timings.ts +3 -2
  81. package/src/web/scrapers/github.ts +2 -2
  82. package/src/web/scrapers/utils.ts +2 -3
  83. package/src/web/scrapers/youtube.ts +2 -3
  84. package/src/web/search/auth.ts +5 -6
  85. package/src/web/search/providers/anthropic.ts +3 -2
  86. package/src/utils/terminal-notify.ts +0 -37
@@ -9,105 +9,168 @@ This document shows how each file uses the config module and what subpaths they
9
9
  │ config.ts exports │
10
10
  ├─────────────────────────────────────────────────────────────────────────────────┤
11
11
  │ Constants: APP_NAME, CONFIG_DIR_NAME, VERSION │
12
- │ Single paths: getAgentDir, getAuthPath, getModelsPath, getCommandsDir, ...
12
+ │ Single paths: getAgentDir, getAuthPath, getModelsPath, getModelsYamlPath,
13
+ │ getAgentDbPath, getToolsDir, getCommandsDir, getPromptsDir, │
14
+ │ getSessionsDir, getDebugLogPath, getCustomThemesDir, │
15
+ │ getChangelogPath, getPackageDir │
13
16
  │ Multi-config: getConfigDirs, getConfigDirPaths, findConfigFile, │
14
- │ readConfigFile, findNearestProjectConfigDir, ...
17
+ findConfigFileWithMeta, readConfigFile, readAllConfigFiles,
18
+ │ findNearestProjectConfigDir, findAllNearestProjectConfigDirs │
15
19
  └─────────────────────────────────────────────────────────────────────────────────┘
16
20
  ```
17
21
 
22
+ ## Architecture Note
23
+
24
+ Many modules now use the **capability/discovery system** (`discovery/builtin.ts`) to load configuration files (skills, hooks, tools, MCP servers, etc.) rather than importing config helpers directly. The capability system provides a unified way to load resources from multiple sources (.omp, .pi, .claude, .codex, .gemini) with proper priority ordering.
25
+
18
26
  ## Usage by Category
19
27
 
20
28
  ### 1. Display/Branding Only (no file I/O)
21
29
 
22
- | File | Imports | Purpose |
23
- | ----------------------------------------- | ----------------------------- | ------------------------ |
24
- | `cli/args.ts` | `APP_NAME`, `CONFIG_DIR_NAME` | Help text, env var names |
25
- | `cli/plugin-cli.ts` | `APP_NAME` | Command output |
26
- | `cli/update-cli.ts` | `APP_NAME`, `VERSION` | Update messages |
27
- | `core/export-html/index.ts` | `APP_NAME` | HTML export title |
28
- | `modes/interactive/components/welcome.ts` | `APP_NAME` | Welcome banner |
29
- | `utils/tools-manager.ts` | `APP_NAME` | Tool download messages |
30
+ | File | Imports | Purpose |
31
+ | ---------------------------- | ----------------------------- | ------------------------ |
32
+ | `cli/args.ts` | `APP_NAME`, `CONFIG_DIR_NAME` | Help text, env var names |
33
+ | `cli/grep-cli.ts` | `APP_NAME` | Grep command output |
34
+ | `cli/jupyter-cli.ts` | `APP_NAME` | Jupyter command output |
35
+ | `cli/plugin-cli.ts` | `APP_NAME` | Plugin command output |
36
+ | `cli/setup-cli.ts` | `APP_NAME` | Setup command output |
37
+ | `cli/shell-cli.ts` | `APP_NAME` | Shell command output |
38
+ | `cli/stats-cli.ts` | `APP_NAME` | Stats command output |
39
+ | `cli/update-cli.ts` | `APP_NAME`, `VERSION` | Update messages |
40
+ | `cli.ts` | `APP_NAME` | Process title |
41
+ | `export/html/index.ts` | `APP_NAME` | HTML export title |
42
+ | `modes/components/welcome.ts`| `APP_NAME` | Welcome banner |
43
+ | `debug/system-info.ts` | `VERSION` | System info display |
30
44
 
31
45
  ### 2. Single Fixed Paths (user-level only)
32
46
 
33
- | File | Imports | Path | Purpose |
34
- | --------------------------------------- | ---------------------------------------------------------------- | -------------------------- | ---------------------- |
35
- | `core/logger.ts` | `CONFIG_DIR_NAME` | `~/.omp/logs/` | Log file directory |
36
- | `core/agent-session.ts` | `getAuthPath` | `~/.omp/agent/auth.json` | Error messages |
37
- | `core/session-manager.ts` | `getAgentDir` | `~/.omp/agent/sessions/` | Session storage |
38
- | `modes/interactive/theme/theme.ts` | `getCustomThemesDir` | `~/.omp/agent/themes/` | Custom themes |
39
- | `modes/interactive/interactive-mode.ts` | `getAuthPath`, `getDebugLogPath` | auth.json, debug log | Status messages |
40
- | `utils/changelog.ts` | `getChangelogPath` | Package CHANGELOG.md | Re-exports |
41
- | `core/system-prompt.ts` | `getAgentDir`, `getDocsPath`, `getExamplesPath`, `getReadmePath` | Package assets + AGENTS.md | System prompt building |
42
- | `migrations.ts` | `getAgentDir` | `~/.omp/agent/` | Auth/session migration |
43
- | `core/plugins/installer.ts` | `getAgentDir` | `~/.omp/agent/` | Plugin installation |
44
- | `core/plugins/paths.ts` | `CONFIG_DIR_NAME` | `~/.omp/plugins/` | Plugin directories |
47
+ | File | Imports | Path | Purpose |
48
+ | ------------------------------------- | -------------------------------- | --------------------------- | ------------------------- |
49
+ | `cli/config-cli.ts` | `APP_NAME`, `getAgentDir` | `~/.omp/agent/` | Prints config path |
50
+ | `session/agent-session.ts` | `getAgentDbPath` | `~/.omp/agent/agent.db` | Database path |
51
+ | `session/session-manager.ts` | `getAgentDir` | `~/.omp/agent/sessions/` | Session storage |
52
+ | `session/agent-storage.ts` | `getAgentDbPath` | `~/.omp/agent/agent.db` | Settings/auth storage |
53
+ | `session/auth-storage.ts` | `getAgentDbPath`, `getAuthPath` | agent.db, auth.json | Auth credential storage |
54
+ | `session/history-storage.ts` | `getAgentDir` | `~/.omp/agent/` | Command history |
55
+ | `session/storage-migration.ts` | `getAgentDbPath` | `~/.omp/agent/agent.db` | JSON→SQLite migration |
56
+ | `modes/theme/theme.ts` | `getCustomThemesDir` | `~/.omp/agent/themes/` | Custom themes |
57
+ | `modes/controllers/selector-controller.ts` | `getAgentDbPath` | `~/.omp/agent/agent.db` | Model selector state |
58
+ | `utils/changelog.ts` | `getChangelogPath` | Package CHANGELOG.md | Re-exports path |
59
+ | `migrations.ts` | `getAgentDir`, `getAgentDbPath` | `~/.omp/agent/` | Auth/session migration |
60
+ | `extensibility/plugins/installer.ts` | `getAgentDir` | `~/.omp/agent/plugins/` | Plugin installation |
61
+ | `extensibility/plugins/paths.ts` | `CONFIG_DIR_NAME` | `~/.omp/plugins/` | Plugin directories |
62
+ | `config/keybindings.ts` | `getAgentDir` | `~/.omp/agent/keybindings.json` | Keybinding config |
63
+ | `config/settings.ts` | `getAgentDir`, `getAgentDbPath` | agent.db, config.yml | Settings management |
64
+ | `config/prompt-templates.ts` | `CONFIG_DIR_NAME`, `getPromptsDir` | `~/.omp/agent/prompts/` | Prompt template loading |
65
+ | `ipy/executor.ts` | `getAgentDir` | `~/.omp/agent/` | Python executor paths |
66
+ | `ipy/gateway-coordinator.ts` | `getAgentDir` | `~/.omp/agent/` | Jupyter gateway socket |
67
+ | `export/custom-share.ts` | `getAgentDir` | `~/.omp/agent/share/` | Custom share scripts |
68
+ | `debug/index.ts` | `getSessionsDir` | `~/.omp/agent/sessions/` | Debug session browser |
69
+ | `ssh/connection-manager.ts` | `CONFIG_DIR_NAME` | `~/.omp/ssh/` | SSH control sockets |
70
+ | `ssh/sshfs-mount.ts` | `CONFIG_DIR_NAME` | `~/.omp/remote/` | Remote mount points |
71
+ | `tools/read.ts` | `CONFIG_DIR_NAME` | Config dir name reference | Internal URL resolution |
72
+ | `utils/tools-manager.ts` | `APP_NAME`, `getToolsDir` | `~/.omp/agent/tools/` | Tool binary management |
45
73
 
46
74
  ### 3. Multi-Config Discovery (with fallbacks)
47
75
 
48
- These use the new helpers to check `.omp`, `.pi`, `.claude` directories:
49
-
50
- | File | Helper Used | Subpath(s) | Levels |
51
- | ----------------------------------- | ------------------------------------------------------ | ------------------------------------ | ------------ |
52
- | `main.ts` | `findConfigFile` | `SYSTEM.md` | project |
53
- | `core/sdk.ts` | `getConfigDirPaths` | `auth.json`, `models.json` | user |
54
- | `core/settings-manager.ts` | `readConfigFile` | `settings.json` | user+project |
55
- | `core/skills.ts` | `getConfigDirPaths` | `skills/` | user+project |
56
- | `core/slash-commands.ts` | `getConfigDirPaths` | `commands/` | project |
57
- | `core/hooks/loader.ts` | `getConfigDirPaths` | `hooks/` | project |
58
- | `core/custom-tools/loader.ts` | `getConfigDirPaths` | `tools/` | project |
59
- | `core/custom-commands/loader.ts` | `getConfigDirPaths` | `commands/` | project |
60
- | `core/plugins/paths.ts` | `getConfigDirPaths` | `plugin-overrides.json` | project |
61
- | `core/mcp/config.ts` | `getConfigDirPaths` | `mcp.json` | user+project |
62
- | `core/tools/lsp/config.ts` | `getConfigDirPaths` | `lsp.json`, `.lsp.json` | user+project |
63
- | `core/tools/task/commands.ts` | `getConfigDirPaths`, `findAllNearestProjectConfigDirs` | `commands/` | user+project |
64
- | `core/tools/task/discovery.ts` | `getConfigDirs`, `findAllNearestProjectConfigDirs` | `agents/` | user+project |
65
- | `core/tools/task/model-resolver.ts` | `readConfigFile` | `settings.json` | user |
66
- | `core/tools/web-search/auth.ts` | `getConfigDirPaths` | `` (root for models.json, auth.json) | user |
76
+ These use helpers to check `.omp`, `.pi`, `.claude`, `.codex`, `.gemini` directories:
77
+
78
+ | File | Helper Used | Subpath(s) | Levels |
79
+ | ---------------------------------------- | ------------------------------------------------------ | --------------------------- | ------------ |
80
+ | `main.ts` | `findConfigFile` | `SYSTEM.md`, `APPEND_SYSTEM.md` | user+project |
81
+ | `sdk.ts` | `getConfigDirPaths` | `auth.json`, `models.yml`, `models.json` | user |
82
+ | `lsp/config.ts` | `getConfigDirPaths` | `lsp.json`, `.lsp.json` | user+project |
83
+ | `task/discovery.ts` | `getConfigDirs`, `findAllNearestProjectConfigDirs` | `agents/` | user+project |
84
+ | `extensibility/plugins/paths.ts` | `getConfigDirPaths` | `plugin-overrides.json` | project |
85
+ | `extensibility/custom-commands/loader.ts`| `getConfigDirs` | `commands/` | user+project |
86
+ | `web/search/auth.ts` | `getConfigDirPaths`, `getAgentDbPath` | auth.json, agent.db | user |
87
+ | `web/search/providers/codex.ts` | `getConfigDirPaths`, `getAgentDbPath` | auth config | user |
88
+ | `web/search/providers/gemini.ts` | `getConfigDirPaths`, `getAgentDbPath` | auth config | user |
89
+
90
+ ### 4. Via Capability/Discovery System
91
+
92
+ These modules use `discovery/builtin.ts` which has its own config directory resolution:
93
+
94
+ | Capability | Config Subpaths | Loaded Via |
95
+ | --------------- | ---------------------------------- | --------------------------- |
96
+ | skills | `skills/` | `skillCapability` |
97
+ | slash-commands | `commands/` | `slashCommandCapability` |
98
+ | rules | `rules/` | `ruleCapability` |
99
+ | prompts | `prompts/` | `promptCapability` |
100
+ | instructions | `instructions/` | `instructionCapability` |
101
+ | hooks | `hooks/pre/`, `hooks/post/` | `hookCapability` |
102
+ | tools | `tools/` | `toolCapability` |
103
+ | extensions | `extensions/` | `extensionCapability` |
104
+ | mcp | `mcp.json`, `.mcp.json` | `mcpCapability` |
105
+ | settings | `settings.json` | `settingsCapability` |
106
+ | system-prompt | `SYSTEM.md` | `systemPromptCapability` |
67
107
 
68
108
  ## Subpath Summary
69
109
 
70
110
  ```
71
- User-level (~/.omp/agent/, ~/.pi/agent/, ~/.claude/):
72
- ├── auth.json sdk.ts, web-search/auth.ts
73
- ├── models.json sdk.ts, web-search/auth.ts
74
- ├── settings.json settings-manager.ts, task/model-resolver.ts
75
- ├── commands/ slash-commands.ts, custom-commands/loader.ts, task/commands.ts
76
- ├── hooks/ hooks/loader.ts
77
- ├── tools/ custom-tools/loader.ts
78
- ├── skills/ skills.ts
79
- ├── themes/ theme.ts (user-level only, no fallback)
80
- ├── sessions/ ← session-manager.ts (user-level only, no fallback)
81
- ├── agents/ ← task/discovery.ts
82
- └── AGENTS.md system-prompt.ts
111
+ User-level (~/.omp/agent/, ~/.pi/agent/, ~/.claude/, ~/.codex/, ~/.gemini/):
112
+ ├── agent.db SQLite storage (settings, auth)
113
+ ├── auth.json Legacy auth (migrated to agent.db)
114
+ ├── models.yml Model configuration (preferred)
115
+ ├── models.json Model configuration (legacy)
116
+ ├── config.yml Settings (alternative to agent.db)
117
+ ├── keybindings.json Custom keybindings
118
+ ├── commands/ Slash commands (via capability)
119
+ ├── hooks/ Pre/post hooks (via capability)
120
+ ├── pre/
121
+ │ └── post/
122
+ ├── tools/ Custom tools (via capability)
123
+ ├── skills/ ← Skills (via capability)
124
+ ├── prompts/ ← Prompt templates
125
+ ├── themes/ ← Custom themes
126
+ ├── sessions/ ← Session storage
127
+ ├── agents/ ← Custom task agents
128
+ ├── plugins/ ← Installed plugins
129
+ ├── extensions/ ← Extension modules
130
+ ├── rules/ ← Rules (via capability)
131
+ ├── instructions/ ← Instructions (via capability)
132
+ ├── share/ ← Custom share scripts
133
+ └── AGENTS.md ← User-level agent instructions
83
134
 
84
135
  User-level root (~/.omp/, ~/.pi/, ~/.claude/) - not under agent/:
85
- ├── mcp.json ← mcp/config.ts
86
- ├── plugins/ ← plugins/paths.ts (primary only)
87
- └── logs/ ← logger.ts (primary only)
88
-
89
- Project-level (.omp/, .pi/, .claude/):
90
- ├── SYSTEM.md ← main.ts
91
- ├── settings.json ← settings-manager.ts
92
- ├── commands/slash-commands.ts, custom-commands/loader.ts, task/commands.ts
93
- ├── hooks/ hooks/loader.ts
94
- ├── tools/ custom-tools/loader.ts
95
- ├── skills/ skills.ts
96
- ├── agents/ task/discovery.ts
97
- ├── plugin-overrides.json plugins/paths.ts
98
- ├── lsp.json lsp/config.ts
99
- └── .mcp.json mcp/config.ts
100
-
101
- Special paths (not under agent/):
102
- ├── ~/.omp/plugins/ plugins/paths.ts
103
- └── ~/.omp/logs/ logger.ts
136
+ ├── mcp.json ← MCP server config (via capability)
137
+ ├── plugins/ ← Plugin storage (primary only)
138
+ ├── logs/ ← Log files (primary only, via pi-utils)
139
+ ├── ssh/ ← SSH control sockets
140
+ └── remote/ ← SSHFS mount points
141
+
142
+ Project-level (.omp/, .pi/, .claude/, .codex/, .gemini/):
143
+ ├── SYSTEM.mdProject system prompt
144
+ ├── APPEND_SYSTEM.md Appended to system prompt
145
+ ├── settings.json Project settings (via capability)
146
+ ├── commands/ Slash commands (via capability)
147
+ ├── hooks/ Pre/post hooks (via capability)
148
+ ├── tools/ Custom tools (via capability)
149
+ ├── skills/ Skills (via capability)
150
+ ├── agents/ Custom task agents
151
+ ├── extensions/ ← Extension modules (via capability)
152
+ ├── rules/ ← Rules (via capability)
153
+ ├── instructions/ Instructions (via capability)
154
+ ├── prompts/ Prompt templates (via capability)
155
+ ├── plugin-overrides.json ← Plugin config overrides
156
+ ├── lsp.json ← LSP server config
157
+ ├── .lsp.json ← LSP server config (dotfile)
158
+ └── .mcp.json ← MCP server config (via capability)
104
159
  ```
105
160
 
106
- ## Files Using Manual Paths (Intentionally)
161
+ ## Notes
162
+
163
+ ### Logger
164
+
165
+ Logging is handled by `@oh-my-pi/pi-utils`, not by this package. Logs go to `~/.omp/logs/omp.YYYY-MM-DD.log` with automatic rotation.
166
+
167
+ ### Config Priority
107
168
 
108
- These files construct paths manually because they only use the primary config dir:
169
+ When multiple config directories exist, priority order is:
170
+ 1. `.omp` (highest)
171
+ 2. `.pi`
172
+ 3. `.claude`
173
+ 4. `.codex`
174
+ 5. `.gemini` (lowest)
109
175
 
110
- | File | Current Approach | Reason |
111
- | ----------------------- | --------------------------------- | --------------------------------------------------- |
112
- | `core/logger.ts` | `CONFIG_DIR_NAME` for logs dir | Logs only written to primary (~/.omp/logs/) |
113
- | `core/plugins/paths.ts` | `CONFIG_DIR_NAME` for plugins dir | Plugins only installed in primary (~/.omp/plugins/) |
176
+ For user-level paths, `.omp/agent` and `.pi/agent` have an "agent" subdirectory; others use the root directly (e.g., `~/.claude/` not `~/.claude/agent/`).
@@ -46,7 +46,7 @@ const factory: CustomToolFactory = (pi) => ({
46
46
  }),
47
47
 
48
48
  async execute(toolCallId, params, onUpdate, ctx, signal) {
49
- const { name } = params as { name: string };
49
+ const { name } = params;
50
50
  return {
51
51
  content: [{ type: "text", text: `Hello, ${name}!` }],
52
52
  details: { greeted: name },
@@ -61,14 +61,25 @@ The tool is automatically discovered and available in your next omp session.
61
61
 
62
62
  ## Tool Locations
63
63
 
64
- Tools must be in a subdirectory with an `index.ts` entry point:
64
+ OMP discovers custom tools through the capability system. Native OMP tools live in a subdirectory with an `index.ts`
65
+ entry point; `.pi` mirrors the same layout as a compatibility alias.
65
66
 
66
- | Location | Scope | Auto-discovered |
67
- | ----------------------------------- | --------------------- | --------------- |
68
- | `~/.omp/agent/tools/*/index.ts` | Global (all projects) | Yes |
69
- | `.omp/tools/*/index.ts` | Project-local | Yes |
70
- | `settings.json` `customTools` array | Configured paths | Yes |
71
- | `--tool <path>` CLI flag | One-off/debugging | No |
67
+ | Location | Scope | Auto-discovered |
68
+ | ------------------------------- | -------------- | --------------- |
69
+ | `~/.omp/agent/tools/*/index.ts` | User (OMP) | Yes |
70
+ | `.omp/tools/*/index.ts` | Project (OMP) | Yes |
71
+ | `~/.pi/agent/tools/*/index.ts` | User (alias) | Yes |
72
+ | `.pi/tools/*/index.ts` | Project (alias) | Yes |
73
+
74
+ Compatibility sources load flat modules (no subdirectory):
75
+
76
+ - `~/.claude/tools/<tool>.ts` (or `.js`, `.sh`, `.bash`, `.py`), `.claude/tools/<tool>.*`
77
+ - `~/.codex/tools/<tool>.ts` or `<tool>.js`, `.codex/tools/<tool>.ts` or `<tool>.js`
78
+
79
+ Tools declared by installed plugins (via `~/.omp/plugins/node_modules` manifests) are also auto-discovered.
80
+
81
+ Only TypeScript/JavaScript modules are executable. `.md` and `.json` files in tools directories are treated as metadata
82
+ and are not loaded as tool modules.
72
83
 
73
84
  **Example structure:**
74
85
 
@@ -82,9 +93,10 @@ Tools must be in a subdirectory with an `index.ts` entry point:
82
93
  └── types.ts # Type definitions (not loaded directly)
83
94
  ```
84
95
 
85
- **Priority:** Later sources win on name conflicts. CLI `--tool` takes highest priority.
96
+ **Name conflicts:** Duplicate tool names are rejected; the first loaded tool keeps its name and later conflicts are
97
+ reported as load errors.
86
98
 
87
- **Reserved names:** Custom tools cannot use built-in tool names (`read`, `write`, `edit`, `bash`, `grep`, `find`, `ls`).
99
+ **Reserved names:** Custom tools cannot use built-in tool names (`read`, `write`, `edit`, `bash`, `grep`, `find`, `python`, `fetch`, `task`, `browser`, `web_search`, etc.).
88
100
 
89
101
  ## Available Imports
90
102
 
@@ -96,6 +108,7 @@ Custom tools can import from these packages:
96
108
  | `@oh-my-pi/pi-coding-agent` | Types and utilities | Via `pi.pi.*` (injected) or direct import for types |
97
109
  | `@oh-my-pi/pi-ai` | AI utilities (`StringEnum` for Google-compatible enums) | Via `pi.pi.*` (re-exported through coding-agent) |
98
110
  | `@oh-my-pi/pi-tui` | TUI components (`Text`, `Box`, etc. for custom rendering) | Via `pi.pi.*` (re-exported through coding-agent) |
111
+ | `@oh-my-pi/pi-utils` | Logging (`logger`) | Via `pi.logger` (injected) |
99
112
 
100
113
  Node.js built-in modules (`node:fs`, `node:path`, etc.) are also available.
101
114
 
@@ -152,7 +165,7 @@ const factory: CustomToolFactory = (pi) => {
152
165
  renderCall(args, theme) {
153
166
  /* return Component */
154
167
  },
155
- renderResult(result, options, theme) {
168
+ renderResult(result, options, theme, args) {
156
169
  /* return Component */
157
170
  },
158
171
  };
@@ -161,6 +174,8 @@ const factory: CustomToolFactory = (pi) => {
161
174
  export default factory;
162
175
  ```
163
176
 
177
+ Set `hidden: true` to exclude a tool from the default tool list; hidden tools must be explicitly enabled by the session.
178
+
164
179
  **Important:** Use `StringEnum` from `pi.pi` instead of `Type.Union`/`Type.Literal` for string enums. The latter doesn't work with Google's API.
165
180
 
166
181
  ## CustomToolAPI Object
@@ -173,6 +188,7 @@ interface CustomToolAPI {
173
188
  exec(command: string, args: string[], options?: ExecOptions): Promise<ExecResult>;
174
189
  ui: ToolUIContext;
175
190
  hasUI: boolean; // false in --print or --mode rpc
191
+ logger: typeof import("@oh-my-pi/pi-utils").logger; // File logger
176
192
  typebox: typeof import("@sinclair/typebox"); // Injected @sinclair/typebox
177
193
  pi: typeof import("@oh-my-pi/pi-coding-agent"); // Injected pi-coding-agent exports
178
194
  }
@@ -182,22 +198,34 @@ interface ToolUIContext {
182
198
  confirm(title: string, message: string): Promise<boolean>;
183
199
  input(title: string, placeholder?: string): Promise<string | undefined>;
184
200
  notify(message: string, type?: "info" | "warning" | "error"): void;
185
- custom(component: Component & { dispose?(): void }): { close: () => void; requestRender: () => void };
201
+ setStatus(key: string, text: string | undefined): void;
202
+ custom<T>(
203
+ factory: (tui: TUI, theme: Theme, done: (result: T) => void) =>
204
+ | (Component & { dispose?(): void })
205
+ | Promise<Component & { dispose?(): void }>,
206
+ ): Promise<T>;
207
+ setEditorText(text: string): void;
208
+ getEditorText(): string;
209
+ editor(title: string, prefill?: string): Promise<string | undefined>;
210
+ readonly theme: Theme;
186
211
  }
187
212
 
188
213
  interface ExecOptions {
189
214
  signal?: AbortSignal; // Cancel the process
190
215
  timeout?: number; // Timeout in milliseconds
216
+ cwd?: string; // Working directory
191
217
  }
192
218
 
193
219
  interface ExecResult {
194
220
  stdout: string;
195
221
  stderr: string;
196
222
  code: number;
197
- killed?: boolean; // True if process was killed by signal/timeout
223
+ killed: boolean; // True if process was killed by signal/timeout
198
224
  }
199
225
  ```
200
226
 
227
+ `TUI` and `Theme` are from `@oh-my-pi/pi-tui` (available via `pi.pi`).
228
+
201
229
  Always check `pi.hasUI` before using UI methods.
202
230
 
203
231
  ### Cancellation Example
@@ -247,7 +275,7 @@ interface CustomToolContext {
247
275
  sessionManager: ReadonlySessionManager; // Read-only access to session
248
276
  modelRegistry: ModelRegistry; // For API key resolution
249
277
  model: Model | undefined; // Current model (may be undefined)
250
- isIdle(): boolean; // Whether agent is streaming
278
+ isIdle(): boolean; // Whether agent is idle (not streaming)
251
279
  hasQueuedMessages(): boolean; // Whether user has queued messages
252
280
  abort(): void; // Abort current operation (fire-and-forget)
253
281
  }
@@ -442,6 +470,7 @@ renderResult(result, { expanded, isPartial }, theme) {
442
470
 
443
471
  - `expanded`: User pressed Ctrl+O to expand
444
472
  - `isPartial`: Result is from `onUpdate` (streaming), not final
473
+ - `spinnerFrame`: Spinner frame index (0-9) during partial updates
445
474
 
446
475
  ### Best Practices
447
476
 
@@ -534,8 +563,8 @@ See [`examples/custom-tools/todo/index.ts`](../examples/custom-tools/todo/index.
534
563
  - Custom `renderCall` and `renderResult`
535
564
  - Proper branching support via details storage
536
565
 
537
- Test with:
566
+ Test by copying the example into your tools directory and restarting omp:
538
567
 
539
568
  ```bash
540
- omp --tool packages/coding-agent/examples/custom-tools/todo/index.ts
569
+ cp -r packages/coding-agent/examples/custom-tools/todo ~/.omp/agent/tools/
541
570
  ```