@tyvm/knowhow 0.0.109 → 0.0.110
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/autodoc/README.md +324 -0
- package/autodoc/chat-guide.md +268 -365
- package/autodoc/cli-reference.md +399 -473
- package/autodoc/config-reference.md +431 -330
- package/autodoc/embeddings-guide.md +223 -322
- package/autodoc/generate-guide.md +261 -301
- package/autodoc/language-plugin-guide.md +221 -247
- package/autodoc/modules-guide.md +242 -215
- package/autodoc/plugins-guide.md +470 -469
- package/autodoc/quickstart-guide.md +67 -70
- package/autodoc/skills-guide.md +455 -339
- package/autodoc/worker-guide.md +301 -308
- package/package.json +1 -1
- package/scripts/build-for-node.sh +10 -24
- package/src/agents/tools/list.ts +2 -2
- package/src/ai.ts +81 -37
- package/src/chat/CliChatService.ts +1 -1
- package/src/chat/modules/AgentModule.ts +7 -2
- package/src/chat/modules/SessionsModule.ts +40 -1
- package/src/chat/modules/SystemModule.ts +2 -2
- package/src/clients/anthropic.ts +1 -1
- package/src/clients/index.ts +25 -6
- package/src/clients/openai.ts +8 -5
- package/src/clients/types.ts +29 -6
- package/src/clients/withRetry.ts +89 -0
- package/src/commands/agent.ts +30 -0
- package/src/commands/modules.ts +417 -47
- package/src/config.ts +1 -1
- package/src/fileSync.ts +20 -12
- package/src/hashes.ts +43 -22
- package/src/index.ts +4 -2
- package/src/processors/Base64ImageDetector.ts +73 -0
- package/src/services/MediaProcessorService.ts +79 -10
- package/src/services/modules/index.ts +47 -18
- package/tests/processors/Base64ImageDetector.test.ts +160 -0
- package/tests/unit/clients/AIClient.test.ts +446 -0
- package/tests/unit/clients/withRetry.test.ts +319 -0
- package/tests/unit/commands/github-credentials.test.ts +1 -2
- package/ts_build/package.json +1 -1
- package/ts_build/src/agents/tools/list.js +2 -2
- package/ts_build/src/agents/tools/list.js.map +1 -1
- package/ts_build/src/ai.d.ts +3 -3
- package/ts_build/src/ai.js +51 -23
- package/ts_build/src/ai.js.map +1 -1
- package/ts_build/src/chat/CliChatService.js +1 -1
- package/ts_build/src/chat/CliChatService.js.map +1 -1
- package/ts_build/src/chat/modules/AgentModule.js +5 -2
- package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
- package/ts_build/src/chat/modules/SessionsModule.js +30 -1
- package/ts_build/src/chat/modules/SessionsModule.js.map +1 -1
- package/ts_build/src/chat/modules/SystemModule.js +2 -2
- package/ts_build/src/chat/modules/SystemModule.js.map +1 -1
- package/ts_build/src/clients/anthropic.js +1 -1
- package/ts_build/src/clients/anthropic.js.map +1 -1
- package/ts_build/src/clients/index.js +7 -6
- package/ts_build/src/clients/index.js.map +1 -1
- package/ts_build/src/clients/openai.js +4 -4
- package/ts_build/src/clients/openai.js.map +1 -1
- package/ts_build/src/clients/types.d.ts +12 -6
- package/ts_build/src/clients/withRetry.d.ts +2 -0
- package/ts_build/src/clients/withRetry.js +60 -0
- package/ts_build/src/clients/withRetry.js.map +1 -0
- package/ts_build/src/commands/agent.js +25 -0
- package/ts_build/src/commands/agent.js.map +1 -1
- package/ts_build/src/commands/modules.js +359 -32
- package/ts_build/src/commands/modules.js.map +1 -1
- package/ts_build/src/config.js +1 -1
- package/ts_build/src/config.js.map +1 -1
- package/ts_build/src/fileSync.d.ts +2 -2
- package/ts_build/src/fileSync.js +13 -11
- package/ts_build/src/fileSync.js.map +1 -1
- package/ts_build/src/hashes.d.ts +2 -2
- package/ts_build/src/hashes.js +40 -16
- package/ts_build/src/hashes.js.map +1 -1
- package/ts_build/src/index.js +1 -1
- package/ts_build/src/index.js.map +1 -1
- package/ts_build/src/processors/Base64ImageDetector.d.ts +3 -0
- package/ts_build/src/processors/Base64ImageDetector.js +42 -0
- package/ts_build/src/processors/Base64ImageDetector.js.map +1 -1
- package/ts_build/src/services/MediaProcessorService.d.ts +5 -4
- package/ts_build/src/services/MediaProcessorService.js +53 -8
- package/ts_build/src/services/MediaProcessorService.js.map +1 -1
- package/ts_build/src/services/modules/index.js +35 -12
- package/ts_build/src/services/modules/index.js.map +1 -1
- package/ts_build/tests/processors/Base64ImageDetector.test.js +111 -0
- package/ts_build/tests/processors/Base64ImageDetector.test.js.map +1 -1
- package/ts_build/tests/unit/clients/AIClient.test.d.ts +1 -0
- package/ts_build/tests/unit/clients/AIClient.test.js +339 -0
- package/ts_build/tests/unit/clients/AIClient.test.js.map +1 -0
- package/ts_build/tests/unit/clients/withRetry.test.d.ts +1 -0
- package/ts_build/tests/unit/clients/withRetry.test.js +225 -0
- package/ts_build/tests/unit/clients/withRetry.test.js.map +1 -0
- package/ts_build/tests/unit/commands/github-credentials.test.js +1 -2
- package/ts_build/tests/unit/commands/github-credentials.test.js.map +1 -1
package/autodoc/plugins-guide.md
CHANGED
|
@@ -1,720 +1,721 @@
|
|
|
1
|
-
# Plugins Guide
|
|
1
|
+
# Plugins Guide
|
|
2
2
|
|
|
3
|
-
Knowhow
|
|
3
|
+
Knowhow plugins extend the agent with **extra context sources**, **URL/file resolution**, **semantic retrieval**, and **IDE/session awareness**. Plugins can be enabled/disabled in `knowhow.json` and can also be added as **custom npm modules**.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- **Load live editor/session context** (e.g., open Vim buffers) (`vim`)
|
|
7
|
-
- **Perform semantic retrieval** using embeddings (`embeddings`)
|
|
8
|
-
- **Resolve work-item references** (GitHub, Asana, Jira, Linear) into readable context (`github`, `asana`, `jira`, `linear`)
|
|
9
|
-
- **Load rich external content** (web pages, downloads/transcripts, design docs) (`url`, `download`, `figma`, `notion`)
|
|
10
|
-
- **Add codebase signals** (git diff/log) (`git`)
|
|
11
|
-
- **Run safety/quality tooling** after edits (linting) (`linter`)
|
|
12
|
-
- **Incorporate terminal/session state** (`tmux`)
|
|
13
|
-
- **Load local guidance docs** (`agents-md`, `skills`)
|
|
14
|
-
- **Execute commands for context** (`exec`)
|
|
5
|
+
---
|
|
15
6
|
|
|
16
|
-
|
|
7
|
+
## 1) What plugins are
|
|
17
8
|
|
|
18
|
-
|
|
9
|
+
A **plugin** is a module registered with the Knowhow plugin system. Each plugin is identified by a **plugin key** (e.g. `language`, `url`) and exposes:
|
|
10
|
+
|
|
11
|
+
- `call(userInput?: string): Promise<string>`
|
|
12
|
+
- `callMany(userInput?: string): Promise<string>`
|
|
13
|
+
- `embed(userInput?: string): Promise<MinimalEmbedding[]>`
|
|
14
|
+
- `enable() / disable() / isEnabled()`
|
|
15
|
+
- `meta` (key/name/description + optional `requires` env vars)
|
|
19
16
|
|
|
20
|
-
|
|
17
|
+
Internally, `PluginService` keeps a map of plugin instances and invokes them by key. Before calling a plugin, Knowhow checks whether the plugin is enabled and its required environment variables are present.
|
|
21
18
|
|
|
22
|
-
###
|
|
23
|
-
Most plugins fall into one or more of these roles:
|
|
19
|
+
### Common ways plugins provide value
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
#### A) Context expansions (especially for “language terms”)
|
|
22
|
+
The `language` plugin expands configured “terms” into sources (files/text/URLs and optionally other plugins).
|
|
27
23
|
|
|
28
|
-
-
|
|
29
|
-
|
|
24
|
+
- It loads term sources of `kind: "file"` and reads the file contents
|
|
25
|
+
- It loads `kind: "text"` sources directly
|
|
26
|
+
- It can also route sources to **other plugins**:
|
|
27
|
+
- For each enabled plugin key `p`, if a language term source has `kind === p`, Knowhow calls that plugin with the source data.
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
Returns `MinimalEmbedding[]` items so Knowhow can do semantic retrieval over fetched/constructed content.
|
|
29
|
+
This happens in `LanguagePlugin.resolveSources()`.
|
|
33
30
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
A plugin detects an identifier in the user prompt and fetches/normalizes it into agent-ready context.
|
|
37
|
-
Examples: GitHub PR/issue, Jira ticket, Linear issue, Notion page.
|
|
31
|
+
#### B) Event-driven context
|
|
32
|
+
Some plugins register handlers on Knowhow events (via `context.Events`). For example:
|
|
38
33
|
|
|
39
|
-
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
- URLs or references (often via `kind: "url"` or a service plugin key like `github`)
|
|
34
|
+
- `language` listens to configured events and triggers context expansions
|
|
35
|
+
- `linter` listens to `file:post-edit`
|
|
36
|
+
- `embeddings` listens to `file:post-edit` and starts embedding generation
|
|
37
|
+
- `git` listens to `file:post-edit`, `agent:newTask`, `agent:taskComplete`, and `linter:*`
|
|
44
38
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
- `git`: injects git diff/log context
|
|
48
|
-
- `tmux`: injects terminal pane/session context
|
|
39
|
+
#### C) Semantic context via embeddings
|
|
40
|
+
Plugins like `embeddings` (semantic search) can return relevant IDs/documents based on the user prompt.
|
|
49
41
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
- `exec`: runs commands for context (powerful; see security note)
|
|
42
|
+
#### D) Tool/assistant awareness
|
|
43
|
+
Plugins like `vim`, `tmux`, `agents-md`, and `skills` expose “what’s going on right now” (open buffers, terminal sessions, local agent instructions, reusable skills).
|
|
53
44
|
|
|
54
45
|
---
|
|
55
46
|
|
|
56
|
-
## 2)
|
|
47
|
+
## 2) Enabling / disabling plugins
|
|
57
48
|
|
|
58
|
-
Plugins are controlled
|
|
49
|
+
Plugins are controlled via `knowhow.json` under `plugins.enabled` and `plugins.disabled`.
|
|
59
50
|
|
|
60
|
-
|
|
61
|
-
|
|
51
|
+
> The code excerpt shows plugin enable/disable methods (`PluginService.enablePlugin()` / `disablePlugin()`), and plugins are considered enabled only if:
|
|
52
|
+
> 1) they are not manually disabled, and
|
|
53
|
+
> 2) their required environment variables are set (via `meta.requires` in `PluginBase.isEnabled()`).
|
|
62
54
|
|
|
63
|
-
###
|
|
64
|
-
```jsonc
|
|
65
|
-
{
|
|
66
|
-
"plugins": {
|
|
67
|
-
"enabled": ["language", "github", "embeddings", "git", "url", "linter"],
|
|
68
|
-
"disabled": []
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
```
|
|
55
|
+
### Example `knowhow.json`
|
|
72
56
|
|
|
73
|
-
|
|
74
|
-
```jsonc
|
|
57
|
+
```json
|
|
75
58
|
{
|
|
76
59
|
"plugins": {
|
|
77
|
-
"enabled": ["language", "
|
|
78
|
-
"disabled": ["
|
|
60
|
+
"enabled": ["language", "git", "linter", "url", "skills"],
|
|
61
|
+
"disabled": ["embeddings"]
|
|
79
62
|
}
|
|
80
63
|
}
|
|
81
64
|
```
|
|
82
65
|
|
|
83
|
-
|
|
66
|
+
**Rules of thumb**
|
|
67
|
+
- Use `disabled` to quickly turn off a plugin.
|
|
68
|
+
- Use `enabled` to explicitly choose which built-ins to run.
|
|
69
|
+
- A plugin may still refuse to run if its `meta.requires` env vars are missing.
|
|
84
70
|
|
|
85
71
|
---
|
|
86
72
|
|
|
87
|
-
## 3) Built-in plugins
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
73
|
+
## 3) Built-in plugins
|
|
74
|
+
|
|
75
|
+
Below are the built-in plugins and how to configure them.
|
|
76
|
+
|
|
77
|
+
> For some plugins, implementation details aren’t included in the provided source excerpt. Where that happens, configuration examples are based on the plugin’s purpose and its typical API surface (key name, tokens, and expected sources). When in doubt, check the plugin’s own `meta.requires` and configuration getters in your repository.
|
|
78
|
+
|
|
79
|
+
### Quick reference table
|
|
80
|
+
|
|
81
|
+
| Plugin key | Purpose |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `language` | Expand configured language terms into files/text/URLs and plugin-sourced context |
|
|
84
|
+
| `vim` | Load currently open Vim swap files (`*.swp`) as context |
|
|
85
|
+
| `embeddings` | Semantic search over an embeddings knowledgebase |
|
|
86
|
+
| `github` | Resolve GitHub PRs/issues/code (token-based) |
|
|
87
|
+
| `git` | Provide `.knowhow/.git` tracking context (diff/log + auto-commit behavior) |
|
|
88
|
+
| `asana` | Resolve Asana tasks (token-based) |
|
|
89
|
+
| `jira` | Resolve Jira issues (token-based) |
|
|
90
|
+
| `linear` | Resolve Linear issues (token-based) |
|
|
91
|
+
| `figma` | Resolve Figma design file context (token-based) |
|
|
92
|
+
| `notion` | Resolve Notion page context (token-based) |
|
|
93
|
+
| `download` | Download / transcribe URLs and handle YouTube videos |
|
|
94
|
+
| `url` | Fetch and parse web pages from URLs found in text |
|
|
95
|
+
| `linter` | Run background lint on file edits |
|
|
96
|
+
| `tmux` | Provide tmux session/window/pane context |
|
|
97
|
+
| `agents-md` | Detect nearby `agents.md` and alert the agent |
|
|
98
|
+
| `exec` | Execute shell commands for context (triggered via `language` “exec” sources) |
|
|
99
|
+
| `skills` | Load reusable `SKILL.md` instructions from configured directories |
|
|
110
100
|
|
|
111
101
|
---
|
|
112
102
|
|
|
113
|
-
###
|
|
103
|
+
### `language` plugin
|
|
104
|
+
|
|
105
|
+
**Key:** `language`
|
|
106
|
+
**What it does:** Looks for configured “terms” inside prompts/events. When matches occur, it **expands** them into configured sources:
|
|
107
|
+
- `kind: "file"` → reads file contents
|
|
108
|
+
- `kind: "text"` → injects literal text
|
|
109
|
+
- `kind: <pluginKey>` → calls that plugin with the source data (only if the target plugin is enabled)
|
|
110
|
+
|
|
111
|
+
**Event support:** Each term can define an `events` list. The plugin registers handlers for all `file*` events separately from other events, and emits an `agent:msg` containing the resolved sources.
|
|
114
112
|
|
|
115
|
-
|
|
116
|
-
- Detects configured **language terms / hotkeys**
|
|
117
|
-
- Expands them into context sources like:
|
|
118
|
-
- local files
|
|
119
|
-
- literal snippets
|
|
120
|
-
- plugin-backed resolutions (e.g., `github`)
|
|
121
|
-
- URLs
|
|
113
|
+
#### Example config: language terms
|
|
122
114
|
|
|
123
|
-
|
|
124
|
-
|
|
115
|
+
Your repository contains `getLanguageConfig()` / `getLanguageConfig` in `src/config`; the excerpt implies this shape:
|
|
116
|
+
|
|
117
|
+
```json
|
|
125
118
|
{
|
|
126
|
-
"plugins": {
|
|
127
|
-
"enabled": ["language"]
|
|
128
|
-
},
|
|
129
119
|
"language": {
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
|
|
133
|
-
"
|
|
134
|
-
|
|
135
|
-
]
|
|
136
|
-
|
|
137
|
-
"@pr": {
|
|
138
|
-
"events": ["agent:msg"],
|
|
139
|
-
"sources": [
|
|
140
|
-
{ "kind": "github", "data": ["owner/repo#123"] }
|
|
141
|
-
]
|
|
142
|
-
}
|
|
120
|
+
"hotkey1": {
|
|
121
|
+
"events": ["file:post-edit", "agent:msg"],
|
|
122
|
+
"sources": [
|
|
123
|
+
{ "kind": "file", "data": ["./docs/hotkey1.md"] },
|
|
124
|
+
{ "kind": "text", "data": ["Use the Makefile targets to reproduce the issue."] },
|
|
125
|
+
{ "kind": "url", "data": ["https://example.com/runbook"] }
|
|
126
|
+
]
|
|
143
127
|
},
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
128
|
+
|
|
129
|
+
"ABC-123, #ticket, ticket*": {
|
|
130
|
+
"events": ["agent:msg"],
|
|
131
|
+
"sources": [
|
|
132
|
+
{ "kind": "jira", "data": ["ABC-123"] }
|
|
133
|
+
]
|
|
151
134
|
}
|
|
152
135
|
}
|
|
153
136
|
}
|
|
154
137
|
```
|
|
155
138
|
|
|
156
|
-
**
|
|
157
|
-
-
|
|
139
|
+
**Notes**
|
|
140
|
+
- Terms can be a comma-separated list of patterns, as `language` splits `term.split(",")`.
|
|
141
|
+
- Pattern matching:
|
|
142
|
+
- If a term pattern contains `*`, it uses glob matching (`minimatch`)
|
|
143
|
+
- Otherwise it checks `userPrompt.toLowerCase().includes(pattern)`
|
|
158
144
|
|
|
159
145
|
---
|
|
160
146
|
|
|
161
|
-
###
|
|
147
|
+
### `vim` plugin
|
|
148
|
+
|
|
149
|
+
**Key:** `vim`
|
|
150
|
+
**What it does:** Finds Vim swap files `./**/*.swp` (including dotfiles), then maps swap files back to their likely source file paths and reads content (with safeguards for size).
|
|
151
|
+
|
|
152
|
+
#### Behavior (from code)
|
|
153
|
+
- `call()` returns a message listing the swap files it finds.
|
|
154
|
+
- It resolves swap file paths by stripping the swap suffix and checking for either:
|
|
155
|
+
- the non-dot file, or
|
|
156
|
+
- the dotfile variant in the same directory.
|
|
162
157
|
|
|
163
|
-
|
|
164
|
-
- Reads the contents of **open Vim buffers**
|
|
165
|
-
- Supplies them to the agent as context
|
|
158
|
+
#### Example config
|
|
166
159
|
|
|
167
|
-
|
|
168
|
-
```jsonc
|
|
160
|
+
```json
|
|
169
161
|
{
|
|
170
162
|
"plugins": {
|
|
171
163
|
"enabled": ["vim"]
|
|
172
|
-
},
|
|
173
|
-
"vim": {
|
|
174
|
-
"maxBuffers": 10,
|
|
175
|
-
"maxBytesPerBuffer": 200000
|
|
176
164
|
}
|
|
177
165
|
}
|
|
178
166
|
```
|
|
179
167
|
|
|
180
|
-
|
|
181
|
-
- Usually none.
|
|
168
|
+
No additional plugin-specific config is visible in the excerpt.
|
|
182
169
|
|
|
183
170
|
---
|
|
184
171
|
|
|
185
|
-
###
|
|
172
|
+
### `embeddings` plugin
|
|
173
|
+
|
|
174
|
+
**Key:** `embeddings`
|
|
175
|
+
**What it does:**
|
|
176
|
+
1. On `file:post-edit`, it starts a background `knowhow embed` process to refresh embeddings.
|
|
177
|
+
2. `call()` runs semantic search (`queryEmbedding`) and returns the **IDs** for the top results (after pruning vector/metadata).
|
|
186
178
|
|
|
187
|
-
|
|
188
|
-
-
|
|
189
|
-
-
|
|
190
|
-
- subscribes to file lifecycle events (e.g., post-edit)
|
|
191
|
-
- may run `knowhow embed` asynchronously in the background after edits
|
|
192
|
-
- returns top results (implementation chooses the final limit)
|
|
179
|
+
#### What it needs
|
|
180
|
+
- Embeddings must be configured via “configured embeddings” returned by `getConfiguredEmbeddings()` (not shown in excerpt).
|
|
181
|
+
- `config.embeddingModel` is used in `queryEmbedding(...)`.
|
|
193
182
|
|
|
194
|
-
|
|
195
|
-
|
|
183
|
+
#### Example config (typical)
|
|
184
|
+
|
|
185
|
+
```json
|
|
196
186
|
{
|
|
187
|
+
"embeddingModel": "text-embedding-model-name",
|
|
188
|
+
"embeddings": {
|
|
189
|
+
"stores": [
|
|
190
|
+
{
|
|
191
|
+
"type": "local",
|
|
192
|
+
"path": "./.knowhow/embeddings"
|
|
193
|
+
}
|
|
194
|
+
]
|
|
195
|
+
},
|
|
197
196
|
"plugins": {
|
|
198
197
|
"enabled": ["embeddings"]
|
|
199
|
-
},
|
|
200
|
-
"embeddings": {
|
|
201
|
-
"embeddingModel": "text-embedding-3-small",
|
|
202
|
-
"topK": 7,
|
|
203
|
-
"indexDirs": ["./docs", "./src", "./skills"]
|
|
204
198
|
}
|
|
205
199
|
}
|
|
206
200
|
```
|
|
207
201
|
|
|
208
|
-
|
|
209
|
-
|
|
202
|
+
If you don’t have embeddings set up, the plugin returns:
|
|
203
|
+
|
|
204
|
+
> “EMBEDDING PLUGIN: No embeddings configured. Run 'knowhow embed' to generate embeddings.”
|
|
210
205
|
|
|
211
206
|
---
|
|
212
207
|
|
|
213
|
-
###
|
|
208
|
+
### `github` plugin
|
|
209
|
+
|
|
210
|
+
**Key:** `github`
|
|
211
|
+
**What it does (expected):**
|
|
212
|
+
- Resolve GitHub PRs/issues/code and return relevant context for the agent.
|
|
213
|
+
- Likely triggered by `language` term sources like `{ "kind": "github", "data": ["owner/repo#123"] }`.
|
|
214
214
|
|
|
215
|
-
|
|
216
|
-
- Resolves GitHub identifiers / URLs found in prompts into context:
|
|
217
|
-
- PRs
|
|
218
|
-
- issues
|
|
219
|
-
- (often) code changes/diffs and structured summaries
|
|
215
|
+
#### Example config
|
|
220
216
|
|
|
221
|
-
|
|
222
|
-
```jsonc
|
|
217
|
+
```json
|
|
223
218
|
{
|
|
224
219
|
"plugins": {
|
|
225
|
-
"enabled": ["github"]
|
|
220
|
+
"enabled": ["github", "language"]
|
|
226
221
|
},
|
|
227
|
-
"
|
|
228
|
-
"
|
|
229
|
-
|
|
230
|
-
|
|
222
|
+
"language": {
|
|
223
|
+
"owner/repo#*": {
|
|
224
|
+
"events": ["agent:msg"],
|
|
225
|
+
"sources": [
|
|
226
|
+
{ "kind": "github", "data": ["$MATCH"] }
|
|
227
|
+
]
|
|
228
|
+
}
|
|
231
229
|
}
|
|
232
230
|
}
|
|
233
231
|
```
|
|
234
232
|
|
|
235
|
-
|
|
236
|
-
- `GITHUB_TOKEN` (commonly required)
|
|
233
|
+
> Exact term/source formatting depends on how your `language` config is processed in your codebase. The excerpt only shows that `language` passes joined `data` strings directly to `Plugins.call(plugin, data)`.
|
|
237
234
|
|
|
238
235
|
---
|
|
239
236
|
|
|
240
|
-
###
|
|
237
|
+
### `git` plugin
|
|
241
238
|
|
|
242
|
-
**
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
-
|
|
239
|
+
**Key:** `git`
|
|
240
|
+
**What it does:**
|
|
241
|
+
- Provides project git status (via `git status --porcelain`)
|
|
242
|
+
- Tracks agent edits in a separate git repo at:
|
|
243
|
+
- `.knowhow/.git`
|
|
244
|
+
- Auto-commits on `file:post-edit` and creates task branches on `agent:newTask`, and squashes on `agent:taskComplete`.
|
|
247
245
|
|
|
248
|
-
|
|
249
|
-
|
|
246
|
+
#### Example config
|
|
247
|
+
|
|
248
|
+
```json
|
|
250
249
|
{
|
|
251
250
|
"plugins": {
|
|
252
|
-
"enabled": ["git"]
|
|
253
|
-
},
|
|
254
|
-
"git": {
|
|
255
|
-
"mode": "diff",
|
|
256
|
-
"logDepth": 20,
|
|
257
|
-
"maxChars": 20000
|
|
251
|
+
"enabled": ["git", "linter"]
|
|
258
252
|
}
|
|
259
253
|
}
|
|
260
254
|
```
|
|
261
255
|
|
|
262
|
-
**
|
|
263
|
-
-
|
|
256
|
+
**Where it stores data**
|
|
257
|
+
- `.knowhow/.git` (inside your current working directory)
|
|
264
258
|
|
|
265
259
|
---
|
|
266
260
|
|
|
267
|
-
###
|
|
261
|
+
### `asana` plugin
|
|
268
262
|
|
|
269
|
-
**
|
|
270
|
-
|
|
271
|
-
-
|
|
263
|
+
**Key:** `asana`
|
|
264
|
+
**What it does (expected):**
|
|
265
|
+
- Resolve Asana tasks into agent context (likely based on a task URL or ID).
|
|
266
|
+
- Typically used via `language` term expansions.
|
|
272
267
|
|
|
273
|
-
|
|
274
|
-
|
|
268
|
+
#### Example config
|
|
269
|
+
|
|
270
|
+
```json
|
|
275
271
|
{
|
|
276
|
-
"plugins": {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
272
|
+
"plugins": { "enabled": ["asana", "language"] },
|
|
273
|
+
"language": {
|
|
274
|
+
"asana:*": {
|
|
275
|
+
"events": ["agent:msg"],
|
|
276
|
+
"sources": [
|
|
277
|
+
{ "kind": "asana", "data": ["asana:1234567890"] }
|
|
278
|
+
]
|
|
279
|
+
}
|
|
283
280
|
}
|
|
284
281
|
}
|
|
285
282
|
```
|
|
286
283
|
|
|
287
|
-
**Env vars**
|
|
288
|
-
- `ASANA_TOKEN` (required/expected)
|
|
289
|
-
|
|
290
284
|
---
|
|
291
285
|
|
|
292
|
-
###
|
|
286
|
+
### `jira` plugin
|
|
287
|
+
|
|
288
|
+
**Key:** `jira`
|
|
289
|
+
**What it does (expected):**
|
|
290
|
+
- Resolve Jira issues (e.g. `ABC-123`) into context.
|
|
293
291
|
|
|
294
|
-
|
|
295
|
-
- Detects Jira issue keys/URLs
|
|
296
|
-
- Fetches ticket context and formats it for the agent
|
|
292
|
+
#### Example config
|
|
297
293
|
|
|
298
|
-
|
|
299
|
-
```jsonc
|
|
294
|
+
```json
|
|
300
295
|
{
|
|
301
|
-
"plugins": {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
296
|
+
"plugins": { "enabled": ["jira", "language"] },
|
|
297
|
+
"language": {
|
|
298
|
+
"ABC-*, #*": {
|
|
299
|
+
"events": ["agent:msg"],
|
|
300
|
+
"sources": [
|
|
301
|
+
{ "kind": "jira", "data": ["ABC-123"] }
|
|
302
|
+
]
|
|
303
|
+
}
|
|
308
304
|
}
|
|
309
305
|
}
|
|
310
306
|
```
|
|
311
307
|
|
|
312
|
-
**Env vars**
|
|
313
|
-
- Commonly one or more of:
|
|
314
|
-
- `JIRA_TOKEN`
|
|
315
|
-
- (sometimes) `JIRA_EMAIL`, `JIRA_BASE_URL`
|
|
316
|
-
- Check your plugin’s `meta.requires` list for exact names.
|
|
317
|
-
|
|
318
308
|
---
|
|
319
309
|
|
|
320
|
-
###
|
|
310
|
+
### `linear` plugin
|
|
321
311
|
|
|
322
|
-
**
|
|
323
|
-
|
|
312
|
+
**Key:** `linear`
|
|
313
|
+
**What it does (expected):**
|
|
314
|
+
- Resolve Linear issues (team/issue IDs or URLs) into context.
|
|
324
315
|
|
|
325
|
-
|
|
326
|
-
|
|
316
|
+
#### Example config
|
|
317
|
+
|
|
318
|
+
```json
|
|
327
319
|
{
|
|
328
|
-
"plugins": {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
320
|
+
"plugins": { "enabled": ["linear", "language"] },
|
|
321
|
+
"language": {
|
|
322
|
+
"LIN-*, linear:*": {
|
|
323
|
+
"events": ["agent:msg"],
|
|
324
|
+
"sources": [
|
|
325
|
+
{ "kind": "linear", "data": ["LIN-456"] }
|
|
326
|
+
]
|
|
327
|
+
}
|
|
334
328
|
}
|
|
335
329
|
}
|
|
336
330
|
```
|
|
337
331
|
|
|
338
|
-
**Env vars**
|
|
339
|
-
- `LINEAR_TOKEN` (commonly required)
|
|
340
|
-
|
|
341
332
|
---
|
|
342
333
|
|
|
343
|
-
###
|
|
334
|
+
### `figma` plugin
|
|
335
|
+
|
|
336
|
+
**Key:** `figma`
|
|
337
|
+
**What it does (expected):**
|
|
338
|
+
- Fetch Figma file/design references and provide context (frames, metadata, etc.).
|
|
344
339
|
|
|
345
|
-
|
|
346
|
-
- Accepts Figma file links (often with optional `node-id` targets)
|
|
347
|
-
- Uses Figma API to fetch frame/node images or metadata
|
|
348
|
-
- Can use vision/LLM to describe relevant nodes (implementation-dependent)
|
|
340
|
+
#### Example config
|
|
349
341
|
|
|
350
|
-
|
|
351
|
-
```jsonc
|
|
342
|
+
```json
|
|
352
343
|
{
|
|
353
|
-
"plugins": {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
344
|
+
"plugins": { "enabled": ["figma", "language"] },
|
|
345
|
+
"language": {
|
|
346
|
+
"figma:*": {
|
|
347
|
+
"events": ["agent:msg"],
|
|
348
|
+
"sources": [
|
|
349
|
+
{ "kind": "figma", "data": ["figma:FILEKEY#node-id"] }
|
|
350
|
+
]
|
|
351
|
+
}
|
|
358
352
|
}
|
|
359
353
|
}
|
|
360
354
|
```
|
|
361
355
|
|
|
362
|
-
**Env vars**
|
|
363
|
-
- `FIGMA_API_KEY` (or `FIGMA_TOKEN`, depending on your plugin implementation)
|
|
364
|
-
- Verify against the plugin’s `meta.requires`.
|
|
365
|
-
|
|
366
356
|
---
|
|
367
357
|
|
|
368
|
-
###
|
|
358
|
+
### `notion` plugin
|
|
369
359
|
|
|
370
|
-
**
|
|
371
|
-
|
|
372
|
-
-
|
|
373
|
-
- Often supports recursive traversal up to a configured depth
|
|
360
|
+
**Key:** `notion`
|
|
361
|
+
**What it does (expected):**
|
|
362
|
+
- Load Notion pages (block/page text) as context.
|
|
374
363
|
|
|
375
|
-
|
|
376
|
-
|
|
364
|
+
#### Example config
|
|
365
|
+
|
|
366
|
+
```json
|
|
377
367
|
{
|
|
378
|
-
"plugins": {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
368
|
+
"plugins": { "enabled": ["notion", "language"] },
|
|
369
|
+
"language": {
|
|
370
|
+
"notion:*": {
|
|
371
|
+
"events": ["agent:msg"],
|
|
372
|
+
"sources": [
|
|
373
|
+
{ "kind": "notion", "data": ["notion:xxxxxxxxxxxxxxxxxxxxxxxxxxxx"] }
|
|
374
|
+
]
|
|
375
|
+
}
|
|
384
376
|
}
|
|
385
377
|
}
|
|
386
378
|
```
|
|
387
379
|
|
|
388
|
-
**Env vars**
|
|
389
|
-
- `NOTION_TOKEN` (commonly required)
|
|
390
|
-
- Some implementations may also need database/page identifiers (config-based).
|
|
391
|
-
|
|
392
380
|
---
|
|
393
381
|
|
|
394
|
-
###
|
|
382
|
+
### `download` plugin
|
|
383
|
+
|
|
384
|
+
**Key:** `download`
|
|
385
|
+
**What it does (expected):**
|
|
386
|
+
- Download content from URLs and optionally transcribe (especially for YouTube).
|
|
395
387
|
|
|
396
|
-
|
|
397
|
-
- Downloads and/or transcribes content from URLs (including video sources like YouTube)
|
|
398
|
-
- Converts to text context for the agent
|
|
399
|
-
- May use chunking + transcription + optional vision keyframe descriptions (implementation-dependent)
|
|
388
|
+
#### Example config
|
|
400
389
|
|
|
401
|
-
|
|
402
|
-
```jsonc
|
|
390
|
+
```json
|
|
403
391
|
{
|
|
404
|
-
"plugins": {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
392
|
+
"plugins": { "enabled": ["download", "language"] },
|
|
393
|
+
"language": {
|
|
394
|
+
"https://*youtube.com/*": {
|
|
395
|
+
"events": ["agent:msg"],
|
|
396
|
+
"sources": [
|
|
397
|
+
{ "kind": "download", "data": ["$MATCH"] }
|
|
398
|
+
]
|
|
399
|
+
}
|
|
412
400
|
}
|
|
413
401
|
}
|
|
414
402
|
```
|
|
415
403
|
|
|
416
|
-
**Env vars**
|
|
417
|
-
- Often depends on the transcription/vision provider used by the plugin
|
|
418
|
-
- Commonly an OpenAI/compatible API key, but verify the plugin’s `meta.requires`.
|
|
419
|
-
|
|
420
404
|
---
|
|
421
405
|
|
|
422
|
-
###
|
|
406
|
+
### `url` plugin
|
|
423
407
|
|
|
424
|
-
**
|
|
425
|
-
|
|
426
|
-
-
|
|
427
|
-
-
|
|
408
|
+
**Key:** `url`
|
|
409
|
+
**What it does:**
|
|
410
|
+
- Extracts URLs from the user prompt using regex: `/(https?:\/\/[^\s]+)/g`
|
|
411
|
+
- Fetches each URL (with a browser-like user agent)
|
|
412
|
+
- Strips HTML tags (simple conversion) and returns parsed text
|
|
413
|
+
- In `call()`, it limits to **10 URLs** max.
|
|
428
414
|
|
|
429
|
-
|
|
430
|
-
|
|
415
|
+
#### Example config
|
|
416
|
+
|
|
417
|
+
```json
|
|
431
418
|
{
|
|
432
419
|
"plugins": {
|
|
433
420
|
"enabled": ["url"]
|
|
434
|
-
},
|
|
435
|
-
"url": {
|
|
436
|
-
"maxUrls": 10,
|
|
437
|
-
"maxCharsPerPage": 120000,
|
|
438
|
-
"followRedirects": true
|
|
439
421
|
}
|
|
440
422
|
}
|
|
441
423
|
```
|
|
442
424
|
|
|
443
|
-
|
|
444
|
-
|
|
425
|
+
You typically don’t need to wire `url` via `language`; it can fetch URLs found directly in prompts. If you *do* want to drive it via `language`, you can.
|
|
426
|
+
|
|
427
|
+
#### Example language config using `url`
|
|
428
|
+
|
|
429
|
+
```json
|
|
430
|
+
{
|
|
431
|
+
"language": {
|
|
432
|
+
"runbook: url:*": {
|
|
433
|
+
"events": ["agent:msg"],
|
|
434
|
+
"sources": [
|
|
435
|
+
{ "kind": "url", "data": ["https://example.com/runbook"] }
|
|
436
|
+
]
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
```
|
|
445
441
|
|
|
446
442
|
---
|
|
447
443
|
|
|
448
|
-
###
|
|
444
|
+
### `linter` plugin
|
|
445
|
+
|
|
446
|
+
**Key:** `linter`
|
|
447
|
+
**What it does (from code):**
|
|
448
|
+
- Listens for `file:post-edit`
|
|
449
|
+
- Looks up a per-extension lint command in `config.lintCommands`
|
|
450
|
+
- Runs it in the background (spawn with `shell: true`)
|
|
451
|
+
- Emits:
|
|
452
|
+
- `linter:started`
|
|
453
|
+
- `linter:finished`
|
|
454
|
+
- If lint fails (determined by **any stderr output**), it notifies the agent with the output.
|
|
455
|
+
|
|
456
|
+
#### Required config: `lintCommands`
|
|
449
457
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
- Runs lint commands (by extension or configured command list)
|
|
453
|
-
- Emits lint failures/results into the agent context
|
|
458
|
+
`config.lintCommands` should be a mapping of extension → command.
|
|
459
|
+
If the command includes `$1`, it is replaced with the edited `filePath`.
|
|
454
460
|
|
|
455
|
-
|
|
456
|
-
|
|
461
|
+
Example:
|
|
462
|
+
|
|
463
|
+
```json
|
|
457
464
|
{
|
|
458
|
-
"
|
|
459
|
-
"
|
|
465
|
+
"lintCommands": {
|
|
466
|
+
"ts": "eslint $1",
|
|
467
|
+
"js": "eslint $1",
|
|
468
|
+
"py": "python -m compileall $1"
|
|
460
469
|
},
|
|
461
|
-
"
|
|
462
|
-
"
|
|
463
|
-
".ts": "npm run lint --silent -- $1",
|
|
464
|
-
".js": "npm run lint --silent -- $1",
|
|
465
|
-
".md": "markdownlint $1"
|
|
466
|
-
},
|
|
467
|
-
"failOnError": false
|
|
470
|
+
"plugins": {
|
|
471
|
+
"enabled": ["linter", "git"]
|
|
468
472
|
}
|
|
469
473
|
}
|
|
470
474
|
```
|
|
471
475
|
|
|
472
|
-
**Env vars**
|
|
473
|
-
- Usually none.
|
|
474
|
-
|
|
475
476
|
---
|
|
476
477
|
|
|
477
|
-
###
|
|
478
|
+
### `tmux` plugin
|
|
478
479
|
|
|
479
|
-
**
|
|
480
|
-
|
|
481
|
-
-
|
|
480
|
+
**Key:** `tmux`
|
|
481
|
+
**What it does:**
|
|
482
|
+
- Checks if the current process is inside tmux by evaluating `echo $TMUX`
|
|
483
|
+
- If in tmux, it runs:
|
|
484
|
+
- `tmux display-message -p '#{session_name}:#{window_index}:#{window_name}'`
|
|
485
|
+
- `tmux list-sessions`
|
|
486
|
+
- `tmux list-windows`
|
|
487
|
+
- `tmux list-panes -a ...`
|
|
488
|
+
- Produces a structured overview and a small “useful commands” section.
|
|
482
489
|
|
|
483
|
-
|
|
484
|
-
|
|
490
|
+
#### Example config
|
|
491
|
+
|
|
492
|
+
```json
|
|
485
493
|
{
|
|
486
494
|
"plugins": {
|
|
487
495
|
"enabled": ["tmux"]
|
|
488
|
-
},
|
|
489
|
-
"tmux": {
|
|
490
|
-
"includePaneHistory": true,
|
|
491
|
-
"maxCharsPerPane": 20000
|
|
492
496
|
}
|
|
493
497
|
}
|
|
494
498
|
```
|
|
495
499
|
|
|
496
|
-
**Env vars**
|
|
497
|
-
- Usually none (but requires tmux availability in your environment).
|
|
498
|
-
|
|
499
500
|
---
|
|
500
501
|
|
|
501
|
-
###
|
|
502
|
+
### `agents-md` plugin
|
|
503
|
+
|
|
504
|
+
**Key:** `agents-md`
|
|
505
|
+
**What it does (from code):**
|
|
506
|
+
- Traverses upward from the edited file to find the nearest `agents.md`
|
|
507
|
+
- Alerts the agent via `agent:msg` when it finds one
|
|
508
|
+
- It listens to these events:
|
|
509
|
+
- `file:pre-write`, `file:post-write`, `file:write`, `file:edit`
|
|
502
510
|
|
|
503
|
-
|
|
504
|
-
- Loads repository/directory guidance files (commonly `AGENTS.md`)
|
|
505
|
-
- Intended for agent behavior instructions, conventions, constraints, etc.
|
|
511
|
+
#### Example config
|
|
506
512
|
|
|
507
|
-
|
|
508
|
-
```jsonc
|
|
513
|
+
```json
|
|
509
514
|
{
|
|
510
515
|
"plugins": {
|
|
511
516
|
"enabled": ["agents-md"]
|
|
512
|
-
},
|
|
513
|
-
"agents-md": {
|
|
514
|
-
"glob": "**/AGENTS.md",
|
|
515
|
-
"maxFiles": 30
|
|
516
517
|
}
|
|
517
518
|
}
|
|
518
519
|
```
|
|
519
520
|
|
|
520
|
-
**Env vars**
|
|
521
|
-
- Usually none.
|
|
522
|
-
|
|
523
521
|
---
|
|
524
522
|
|
|
525
|
-
###
|
|
523
|
+
### `exec` plugin
|
|
526
524
|
|
|
527
|
-
**
|
|
528
|
-
|
|
529
|
-
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
- **Security risk:** can run arbitrary commands.
|
|
525
|
+
**Key:** `exec`
|
|
526
|
+
**What it does:**
|
|
527
|
+
- Executes shell commands synchronously via `execSync(command, ...)`.
|
|
528
|
+
- `callMany()` is special: it only executes when `input` starts with `!` or `/!`.
|
|
529
|
+
- `call()` executes any non-empty trimmed input.
|
|
533
530
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
"plugins": {
|
|
538
|
-
"enabled": ["exec"]
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
```
|
|
531
|
+
This is designed to be triggered from `language` expansions where a source routes to the `exec` plugin.
|
|
532
|
+
|
|
533
|
+
#### Example language config to run commands
|
|
542
534
|
|
|
543
|
-
|
|
544
|
-
```jsonc
|
|
535
|
+
```json
|
|
545
536
|
{
|
|
546
|
-
"plugins": {
|
|
547
|
-
"enabled": ["language", "exec"]
|
|
548
|
-
},
|
|
549
537
|
"language": {
|
|
550
|
-
"
|
|
551
|
-
"
|
|
552
|
-
|
|
553
|
-
"
|
|
554
|
-
|
|
555
|
-
]
|
|
556
|
-
}
|
|
538
|
+
"ls: command": {
|
|
539
|
+
"events": ["agent:msg"],
|
|
540
|
+
"sources": [
|
|
541
|
+
{ "kind": "exec", "data": ["ls -la"] }
|
|
542
|
+
]
|
|
557
543
|
}
|
|
544
|
+
},
|
|
545
|
+
"plugins": {
|
|
546
|
+
"enabled": ["language", "exec"]
|
|
558
547
|
}
|
|
559
548
|
}
|
|
560
549
|
```
|
|
561
550
|
|
|
562
|
-
**Env vars**
|
|
563
|
-
- None inherent to the plugin, but your executed commands may depend on your environment.
|
|
564
|
-
|
|
565
551
|
---
|
|
566
552
|
|
|
567
|
-
###
|
|
553
|
+
### `skills` plugin
|
|
568
554
|
|
|
569
|
-
**
|
|
570
|
-
|
|
571
|
-
-
|
|
572
|
-
-
|
|
555
|
+
**Key:** `skills`
|
|
556
|
+
**What it does (from code):**
|
|
557
|
+
- Reads `SKILL.md` files from configured directories (`config.skills`)
|
|
558
|
+
- Each `SKILL.md` must contain YAML-like frontmatter between `---` blocks with at least:
|
|
573
559
|
- `name`
|
|
574
|
-
- `description`
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
560
|
+
- optionally `description`
|
|
561
|
+
|
|
562
|
+
When `call()` / `embed()` runs:
|
|
563
|
+
- It checks which skill names appear in the user prompt (case-insensitive)
|
|
564
|
+
- If matches exist, it loads full content and returns embeddings for each
|
|
565
|
+
- Otherwise, it returns a “skills discovery summary” with all available skills
|
|
566
|
+
|
|
567
|
+
#### Required config: `skills`
|
|
568
|
+
|
|
569
|
+
```json
|
|
582
570
|
{
|
|
571
|
+
"skills": [
|
|
572
|
+
"~/knowhow/skills",
|
|
573
|
+
"./.knowhow/skills"
|
|
574
|
+
],
|
|
583
575
|
"plugins": {
|
|
584
576
|
"enabled": ["skills"]
|
|
585
|
-
}
|
|
586
|
-
"skills": [
|
|
587
|
-
"./skills",
|
|
588
|
-
"./docs/skills"
|
|
589
|
-
]
|
|
577
|
+
}
|
|
590
578
|
}
|
|
591
579
|
```
|
|
592
580
|
|
|
593
|
-
|
|
581
|
+
#### Example `SKILL.md`
|
|
582
|
+
|
|
594
583
|
```md
|
|
595
584
|
---
|
|
596
|
-
name:
|
|
597
|
-
description:
|
|
585
|
+
name: "React: component patterns"
|
|
586
|
+
description: "Preferred patterns for component composition and state handling."
|
|
598
587
|
---
|
|
599
588
|
|
|
600
|
-
#
|
|
589
|
+
# React: component patterns
|
|
601
590
|
|
|
602
|
-
|
|
603
|
-
1. Inspect `EXPLAIN`
|
|
604
|
-
2. Find missing indexes
|
|
605
|
-
3. Rewrite joins/filters
|
|
591
|
+
Use function components...
|
|
606
592
|
```
|
|
607
593
|
|
|
608
|
-
**Env vars**
|
|
609
|
-
- Usually none.
|
|
610
|
-
|
|
611
594
|
---
|
|
612
595
|
|
|
613
|
-
## 4) Custom plugins via `
|
|
596
|
+
## 4) Custom plugins via `modules`
|
|
614
597
|
|
|
615
|
-
Knowhow can load **custom plugins**
|
|
598
|
+
Knowhow can also load **custom plugins** as npm packages (dynamic import). The plugin loader supports ESM import specifiers (e.g. `"my-knowhow-plugin"` or `"./plugins/foo"`).
|
|
616
599
|
|
|
617
|
-
|
|
600
|
+
Although the configuration loader code isn’t included in the excerpt, the presence of:
|
|
618
601
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
602
|
+
- `PluginService.loadPlugin(spec: string)` which:
|
|
603
|
+
- `import(spec)` and expects a **default export** class
|
|
604
|
+
- instantiates it as `new PluginCtor(this)`
|
|
605
|
+
- registers it under `instance.meta.key`
|
|
606
|
+
|
|
607
|
+
implies the `modules` config should list import specifiers to load.
|
|
608
|
+
|
|
609
|
+
### Writing a custom plugin package
|
|
610
|
+
|
|
611
|
+
Your plugin module must:
|
|
612
|
+
|
|
613
|
+
1. Default-export a class that implements the Knowhow `Plugin` contract (or extends `PluginBase`)
|
|
614
|
+
2. Provide `static meta` or an instance `meta` with:
|
|
615
|
+
- `meta.key` (plugin key string)
|
|
616
|
+
- `meta.name`
|
|
617
|
+
- optionally `meta.requires` (env vars)
|
|
618
|
+
|
|
619
|
+
#### Minimal example (TypeScript)
|
|
620
|
+
|
|
621
|
+
```ts
|
|
622
|
+
// src/index.ts
|
|
623
|
+
import { PluginBase } from "knowhow/plugins/PluginBase";
|
|
624
|
+
import { PluginMeta } from "knowhow/plugins/PluginBase";
|
|
625
|
+
import { PluginContext } from "knowhow/plugins/types";
|
|
626
|
+
import { MinimalEmbedding } from "knowhow/types";
|
|
627
|
+
|
|
628
|
+
export default class MyPlugin extends PluginBase {
|
|
629
|
+
static readonly meta: PluginMeta = {
|
|
630
|
+
key: "my-plugin",
|
|
631
|
+
name: "My Plugin",
|
|
632
|
+
requires: ["MY_PLUGIN_TOKEN"]
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
meta = MyPlugin.meta;
|
|
636
|
+
|
|
637
|
+
constructor(context: PluginContext) {
|
|
638
|
+
super(context);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
async call(input?: string): Promise<string> {
|
|
642
|
+
return `MyPlugin saw: ${input ?? ""}`;
|
|
626
643
|
}
|
|
627
|
-
}
|
|
628
|
-
```
|
|
629
644
|
|
|
630
|
-
|
|
645
|
+
async callMany(input?: string): Promise<string> {
|
|
646
|
+
return this.call(input);
|
|
647
|
+
}
|
|
631
648
|
|
|
632
|
-
|
|
633
|
-
|
|
649
|
+
async embed(_input: string): Promise<MinimalEmbedding[]> {
|
|
650
|
+
return [];
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
```
|
|
634
654
|
|
|
635
|
-
|
|
636
|
-
- `meta.requires` (optional; env vars needed for auth/integration)
|
|
655
|
+
### Registering the plugin in `knowhow.json`
|
|
637
656
|
|
|
638
|
-
|
|
639
|
-
- `call(input?)`
|
|
640
|
-
- `callMany(input?)`
|
|
641
|
-
- `embed(input)`
|
|
657
|
+
A typical pattern is:
|
|
642
658
|
|
|
643
|
-
|
|
644
|
-
```jsonc
|
|
659
|
+
```json
|
|
645
660
|
{
|
|
661
|
+
"modules": ["my-knowhow-plugin"],
|
|
646
662
|
"plugins": {
|
|
647
|
-
"enabled": ["
|
|
648
|
-
"disabled": []
|
|
649
|
-
},
|
|
650
|
-
"pluginPackages": {
|
|
651
|
-
"my-custom-plugin": "@acme/knowhow-my-custom-plugin"
|
|
663
|
+
"enabled": ["my-plugin"]
|
|
652
664
|
}
|
|
653
665
|
}
|
|
654
666
|
```
|
|
655
667
|
|
|
668
|
+
> If your local development build exports a file path instead of a package name, you can use an ESM specifier like `"./plugins/my-plugin/index.js"`.
|
|
669
|
+
|
|
656
670
|
---
|
|
657
671
|
|
|
658
|
-
## 5) Required environment variables
|
|
672
|
+
## 5) Required environment variables per plugin
|
|
673
|
+
|
|
674
|
+
Knowhow decides plugin enablement using `PluginBase.isEnabled()`:
|
|
675
|
+
|
|
676
|
+
- If `plugin.meta.requires` is set, every env var listed must exist and be non-empty.
|
|
677
|
+
- Manual `plugins.disabled` also turns it off.
|
|
659
678
|
|
|
660
|
-
|
|
679
|
+
In the provided excerpt, the following plugin env requirements are explicitly not defined (their `meta.requires` is empty or omitted):
|
|
680
|
+
**`language`, `vim`, `embeddings` (not shown as requiring), `url`, `git`, `linter`, `tmux`, `agents-md`, `exec`, `skills`, `skills`**.
|
|
661
681
|
|
|
662
|
-
|
|
682
|
+
For the token-based services, plugin implementations commonly require API tokens. Configure these environment variables to ensure the plugins can activate.
|
|
663
683
|
|
|
664
|
-
|
|
684
|
+
### Recommended env vars (by plugin purpose)
|
|
685
|
+
|
|
686
|
+
| Plugin key | Common env vars (typical) |
|
|
665
687
|
|---|---|
|
|
666
688
|
| `github` | `GITHUB_TOKEN` |
|
|
667
689
|
| `asana` | `ASANA_TOKEN` |
|
|
668
|
-
| `jira` | `JIRA_TOKEN` (or
|
|
690
|
+
| `jira` | `JIRA_TOKEN` (or `JIRA_API_TOKEN` / `JIRA_EMAIL`, depending on implementation) |
|
|
669
691
|
| `linear` | `LINEAR_TOKEN` |
|
|
670
|
-
| `figma` | `
|
|
671
|
-
| `notion` | `NOTION_TOKEN` |
|
|
672
|
-
| `
|
|
673
|
-
|
|
674
|
-
|
|
692
|
+
| `figma` | `FIGMA_TOKEN` |
|
|
693
|
+
| `notion` | `NOTION_TOKEN` (often also `NOTION_DATABASE_ID` or similar) |
|
|
694
|
+
| `download` | (usually none, unless a transcription backend requires credentials) |
|
|
695
|
+
|
|
696
|
+
### Example `.env` / environment
|
|
675
697
|
|
|
676
|
-
### Example: setting environment variables
|
|
677
698
|
```bash
|
|
678
|
-
export GITHUB_TOKEN="
|
|
679
|
-
export ASANA_TOKEN="
|
|
680
|
-
export
|
|
681
|
-
export
|
|
682
|
-
export
|
|
683
|
-
export NOTION_TOKEN="secret_notion_xxx"
|
|
684
|
-
export OPENAI_API_KEY="sk_xxx"
|
|
699
|
+
export GITHUB_TOKEN="ghp_..."
|
|
700
|
+
export ASANA_TOKEN="..."
|
|
701
|
+
export LINEAR_TOKEN="..."
|
|
702
|
+
export FIGMA_TOKEN="..."
|
|
703
|
+
export NOTION_TOKEN="..."
|
|
685
704
|
```
|
|
686
705
|
|
|
687
|
-
|
|
706
|
+
If you want, paste the repo files for `src/plugins/github.ts`, `src/plugins/asana.ts`, `src/plugins/jira.ts`, `src/plugins/linear.ts`, `src/plugins/figma.ts`, `src/plugins/notion.ts`, and `src/plugins/download.ts`, and I can replace the “typical” env vars with the exact ones listed in each plugin’s `meta.requires`.
|
|
688
707
|
|
|
689
|
-
|
|
708
|
+
---
|
|
690
709
|
|
|
691
|
-
|
|
710
|
+
## Summary
|
|
692
711
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
"jira",
|
|
702
|
-
"linear",
|
|
703
|
-
"asana",
|
|
704
|
-
"notion",
|
|
705
|
-
"url",
|
|
706
|
-
"embeddings",
|
|
707
|
-
"git",
|
|
708
|
-
"linter"
|
|
709
|
-
],
|
|
710
|
-
"disabled": ["exec", "download", "vim", "tmux"]
|
|
711
|
-
},
|
|
712
|
-
"pluginPackages": {}
|
|
713
|
-
}
|
|
714
|
-
```
|
|
715
|
-
|
|
716
|
-
> Enable `exec`/`download` only if you trust prompts and external content sources you’ll process.
|
|
717
|
-
|
|
718
|
-
---
|
|
712
|
+
- Use **`language`** to expand terms into contextual sources.
|
|
713
|
+
- Turn plugins on/off with **`knowhow.json -> plugins.enabled/disabled`**.
|
|
714
|
+
- Configure plugin-specific settings like:
|
|
715
|
+
- `language` term sources
|
|
716
|
+
- `lintCommands`
|
|
717
|
+
- `skills` directories
|
|
718
|
+
- embedding store/model settings
|
|
719
|
+
- Add new capabilities with **custom plugins** loaded via `modules`.
|
|
719
720
|
|
|
720
|
-
If you
|
|
721
|
+
If you share your current `knowhow.json` (redact secrets) I can propose an end-to-end plugin setup tailored to your workflow.
|