@redaksjon/protokoll 1.0.2 → 1.0.7

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.
@@ -0,0 +1,355 @@
1
+ # Workspace-Level Configuration
2
+
3
+ ## Overview
4
+
5
+ Protokoll's MCP server now uses **workspace-level configuration** instead of having each tool navigate up the directory tree to find configuration. This provides:
6
+
7
+ 1. **Better Performance** - Configuration is loaded once at startup
8
+ 2. **Consistency** - All tools use the same configuration
9
+ 3. **Simplicity** - No need to pass `contextDirectory` to every tool
10
+ 4. **Predictability** - Configuration comes from the workspace root
11
+
12
+ ## How It Works
13
+
14
+ ### 1. Server Initialization
15
+
16
+ When the MCP server starts:
17
+
18
+ 1. It receives workspace roots from the client (via MCP roots capability)
19
+ 2. It uses the first workspace root to find `.protokoll` configuration
20
+ 3. It loads the configuration once and caches it
21
+ 4. All tools use this cached configuration
22
+
23
+ ### 2. Configuration Discovery
24
+
25
+ The server looks for `.protokoll/config.yaml` in the workspace root:
26
+
27
+ ```
28
+ /Users/me/workspace/
29
+ └── .protokoll/
30
+ └── config.yaml
31
+ ```
32
+
33
+ ### 3. Directory Resolution
34
+
35
+ Configuration values are resolved relative to the workspace root:
36
+
37
+ ```yaml
38
+ # .protokoll/config.yaml
39
+ inputDirectory: ./recordings # → /Users/me/workspace/recordings
40
+ outputDirectory: ~/notes # → /Users/me/notes (absolute)
41
+ processedDirectory: ./processed # → /Users/me/workspace/processed
42
+ ```
43
+
44
+ ## Configuration Structure
45
+
46
+ ### Workspace Root
47
+
48
+ The workspace root is determined by:
49
+
50
+ 1. **MCP Roots** (preferred): First root provided by the client
51
+ 2. **Environment Variable**: `WORKSPACE_ROOT` if set
52
+ 3. **Fallback**: Current working directory
53
+
54
+ ### Directory Configuration
55
+
56
+ Three directories are configured at the workspace level:
57
+
58
+ | Directory | Purpose | Default |
59
+ |-----------|---------|---------|
60
+ | `inputDirectory` | Where audio files are stored | `./recordings` |
61
+ | `outputDirectory` | Where transcripts are saved | `./notes` |
62
+ | `processedDirectory` | Where processed audio is moved | `./processed` |
63
+
64
+ ### Context Instance
65
+
66
+ The server also loads and caches a context instance, providing access to:
67
+ - Projects
68
+ - People
69
+ - Terms
70
+ - Companies
71
+ - Smart assistance configuration
72
+
73
+ ## Tool Simplification
74
+
75
+ ### Before (Per-Tool Navigation)
76
+
77
+ Each tool had to:
78
+ 1. Accept a `contextDirectory` parameter
79
+ 2. Navigate up the directory tree to find `.protokoll`
80
+ 3. Load configuration independently
81
+ 4. Resolve directories relative to the found configuration
82
+
83
+ **Example**:
84
+ ```typescript
85
+ await client.callTool('protokoll_process_audio', {
86
+ audioFile: 'recording.m4a',
87
+ contextDirectory: '/Users/me/workspace/.protokoll' // ❌ Required
88
+ });
89
+ ```
90
+
91
+ ### After (Workspace-Level)
92
+
93
+ Tools now:
94
+ 1. Use the pre-loaded workspace configuration
95
+ 2. No need to navigate or search
96
+ 3. Consistent configuration across all tools
97
+ 4. Faster execution (no repeated discovery)
98
+
99
+ **Example**:
100
+ ```typescript
101
+ await client.callTool('protokoll_process_audio', {
102
+ audioFile: 'recording.m4a' // ✅ Just the filename
103
+ });
104
+ ```
105
+
106
+ ## Removed Parameters
107
+
108
+ The following parameters have been removed from tools (no longer needed):
109
+
110
+ ### Audio Tools
111
+ - `protokoll_process_audio`: Removed `contextDirectory`
112
+ - `protokoll_batch_process`: Removed `contextDirectory`
113
+
114
+ ### Transcript Tools
115
+ - All transcript tools: `contextDirectory` is now optional and rarely needed
116
+
117
+ ## Server Configuration API
118
+
119
+ The server exposes a configuration API for internal use:
120
+
121
+ ```typescript
122
+ import * as ServerConfig from './serverConfig';
123
+
124
+ // Get the full configuration
125
+ const config = ServerConfig.getServerConfig();
126
+ console.log(config.workspaceRoot);
127
+ console.log(config.inputDirectory);
128
+ console.log(config.outputDirectory);
129
+
130
+ // Get specific directories
131
+ const inputDir = ServerConfig.getInputDirectory();
132
+ const outputDir = ServerConfig.getOutputDirectory();
133
+ const processedDir = ServerConfig.getProcessedDirectory(); // may be null
134
+
135
+ // Get the context instance
136
+ const context = ServerConfig.getContext();
137
+ if (context) {
138
+ const projects = context.getAllProjects();
139
+ const people = context.getAllPeople();
140
+ }
141
+
142
+ // Check if initialized
143
+ if (ServerConfig.isInitialized()) {
144
+ // Configuration is ready
145
+ }
146
+ ```
147
+
148
+ ## Configuration Lifecycle
149
+
150
+ ### Initialization
151
+
152
+ ```typescript
153
+ // Server startup
154
+ const roots = await client.listRoots();
155
+ await ServerConfig.initializeServerConfig(roots);
156
+ ```
157
+
158
+ ### Reload
159
+
160
+ ```typescript
161
+ // When workspace changes
162
+ const roots = await client.listRoots();
163
+ await ServerConfig.reloadServerConfig(roots);
164
+ ```
165
+
166
+ ### Clear
167
+
168
+ ```typescript
169
+ // When shutting down
170
+ ServerConfig.clearServerConfig();
171
+ ```
172
+
173
+ ## Error Handling
174
+
175
+ ### No Context Available
176
+
177
+ If no `.protokoll` directory is found in the workspace:
178
+
179
+ ```
180
+ Protokoll context not available. Ensure .protokoll directory exists in workspace.
181
+ ```
182
+
183
+ **Solution**: Create a `.protokoll` directory in your workspace root with a `config.yaml` file.
184
+
185
+ ### Configuration Not Initialized
186
+
187
+ If tools are called before server initialization:
188
+
189
+ ```
190
+ Server configuration not initialized. Call initializeServerConfig() first.
191
+ ```
192
+
193
+ **Solution**: This is a server-side error. The server should initialize configuration on startup.
194
+
195
+ ## Fallback Behavior
196
+
197
+ If configuration cannot be loaded, the server uses defaults:
198
+
199
+ | Setting | Default |
200
+ |---------|---------|
201
+ | `workspaceRoot` | Current working directory |
202
+ | `inputDirectory` | `./recordings` (relative to workspace) |
203
+ | `outputDirectory` | `./notes` (relative to workspace) |
204
+ | `processedDirectory` | `./processed` (relative to workspace) |
205
+
206
+ ## Benefits
207
+
208
+ ### 1. Performance
209
+
210
+ - Configuration loaded once, not on every tool call
211
+ - No repeated directory tree navigation
212
+ - Faster tool execution
213
+
214
+ ### 2. Consistency
215
+
216
+ - All tools use the same configuration
217
+ - No risk of tools finding different `.protokoll` directories
218
+ - Predictable behavior
219
+
220
+ ### 3. Simplicity
221
+
222
+ - Fewer parameters to pass
223
+ - Cleaner tool signatures
224
+ - Easier to use
225
+
226
+ ### 4. Workspace Awareness
227
+
228
+ - Respects workspace boundaries
229
+ - Uses workspace-relative paths
230
+ - Integrates with IDE/editor workspace concept
231
+
232
+ ## Migration from Per-Tool Configuration
233
+
234
+ ### Code Changes
235
+
236
+ **Before**:
237
+ ```typescript
238
+ // Every tool needed contextDirectory
239
+ await client.callTool('protokoll_process_audio', {
240
+ audioFile: '/path/to/audio.m4a',
241
+ contextDirectory: '/path/to/.protokoll'
242
+ });
243
+
244
+ await client.callTool('protokoll_read_transcript', {
245
+ transcriptPath: '/path/to/transcript.md',
246
+ contextDirectory: '/path/to/.protokoll'
247
+ });
248
+ ```
249
+
250
+ **After**:
251
+ ```typescript
252
+ // No contextDirectory needed - uses workspace config
253
+ await client.callTool('protokoll_process_audio', {
254
+ audioFile: 'audio.m4a'
255
+ });
256
+
257
+ await client.callTool('protokoll_read_transcript', {
258
+ transcriptPath: 'transcript.md'
259
+ });
260
+ ```
261
+
262
+ ### Configuration Changes
263
+
264
+ No changes needed to your `.protokoll/config.yaml` files. The server automatically discovers and uses them from the workspace root.
265
+
266
+ ## Implementation Details
267
+
268
+ ### Server Configuration Module
269
+
270
+ New module: `src/mcp/serverConfig.ts`
271
+
272
+ **Key Functions**:
273
+ - `initializeServerConfig(roots)` - Initialize from workspace roots
274
+ - `reloadServerConfig(roots)` - Reload when workspace changes
275
+ - `getServerConfig()` - Get full configuration
276
+ - `getInputDirectory()` - Get input directory
277
+ - `getOutputDirectory()` - Get output directory
278
+ - `getProcessedDirectory()` - Get processed directory
279
+ - `getContext()` - Get context instance
280
+ - `getWorkspaceRoot()` - Get workspace root
281
+
282
+ ### Integration Points
283
+
284
+ 1. **Server Startup** (`src/mcp/server.ts`):
285
+ - Initializes configuration from workspace roots
286
+ - Handles WORKSPACE_ROOT environment variable
287
+
288
+ 2. **Tool Handlers** (`src/mcp/tools/*.ts`):
289
+ - Import and use `ServerConfig` module
290
+ - No longer navigate directory tree
291
+ - Use cached configuration
292
+
293
+ 3. **Shared Utilities** (`src/mcp/tools/shared.ts`):
294
+ - `getConfiguredDirectory()` now uses `ServerConfig`
295
+ - Simplified implementation
296
+ - No context parameter needed
297
+
298
+ ## Testing
299
+
300
+ ### Manual Testing
301
+
302
+ 1. Start MCP server in a workspace with `.protokoll/config.yaml`
303
+ 2. Verify configuration is loaded correctly
304
+ 3. Call tools without `contextDirectory` parameter
305
+ 4. Verify tools use workspace configuration
306
+
307
+ ### Unit Testing
308
+
309
+ Tests should mock the `ServerConfig` module to provide test configuration:
310
+
311
+ ```typescript
312
+ import * as ServerConfig from '@/mcp/serverConfig';
313
+
314
+ // Mock configuration for tests
315
+ vi.mock('@/mcp/serverConfig', () => ({
316
+ getInputDirectory: () => '/test/recordings',
317
+ getOutputDirectory: () => '/test/notes',
318
+ getProcessedDirectory: () => '/test/processed',
319
+ getContext: () => mockContext,
320
+ }));
321
+ ```
322
+
323
+ ## Future Enhancements
324
+
325
+ ### Configuration Hot Reload
326
+
327
+ When workspace roots change, the server could automatically reload configuration:
328
+
329
+ ```typescript
330
+ server.onNotification('notifications/roots/list_changed', async () => {
331
+ const roots = await client.listRoots();
332
+ await ServerConfig.reloadServerConfig(roots);
333
+ });
334
+ ```
335
+
336
+ ### Multi-Workspace Support
337
+
338
+ For workspaces with multiple projects, the server could:
339
+ - Detect which project a file belongs to
340
+ - Use project-specific configuration
341
+ - Switch configuration based on file location
342
+
343
+ ### Configuration Validation
344
+
345
+ On initialization, validate that:
346
+ - Configured directories exist
347
+ - Directories are writable
348
+ - Audio extensions are valid
349
+ - Required dependencies are available
350
+
351
+ ## See Also
352
+
353
+ - [Smart File Lookup](./MCP_SMART_TRANSCRIPT_LOOKUP.md)
354
+ - [MCP Resources](./MCP_RESOURCES.md)
355
+ - [MCP Tools](./MCP_TOOLS.md)
@@ -208,8 +208,8 @@ interface PipelineInstance {
208
208
 
209
209
  | Package | Purpose |
210
210
  |---------|---------|
211
- | `@theunwalked/dreadcabinet` | Filesystem structure patterns |
212
- | `@theunwalked/cardigantime` | Hierarchical config discovery |
211
+ | `@utilarium/dreadcabinet` | Filesystem structure patterns |
212
+ | `@utilarium/cardigantime` | Hierarchical config discovery |
213
213
  | `@riotprompt/riotprompt` | Prompt building and agentic execution |
214
214
  | `openai` | Whisper and GPT APIs |
215
215
  | `@anthropic-ai/sdk` | Claude API |
@@ -226,8 +226,8 @@ npm run lint:fix
226
226
 
227
227
  | Package | Purpose |
228
228
  |---------|---------|
229
- | `@theunwalked/dreadcabinet` | Filesystem patterns |
230
- | `@theunwalked/cardigantime` | Hierarchical config discovery |
229
+ | `@utilarium/dreadcabinet` | Filesystem patterns |
230
+ | `@utilarium/cardigantime` | Hierarchical config discovery |
231
231
  | `@riotprompt/riotprompt` | Prompt building and agentic execution |
232
232
  | `openai` | OpenAI API (Whisper and GPT) |
233
233
  | `@anthropic-ai/sdk` | Anthropic API (Claude) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redaksjon/protokoll",
3
- "version": "1.0.2",
3
+ "version": "1.0.7",
4
4
  "description": "Focused audio transcription with intelligent context integration",
5
5
  "main": "dist/main.js",
6
6
  "type": "module",
@@ -45,11 +45,11 @@
45
45
  "@anthropic-ai/sdk": "^0.71.2",
46
46
  "@google/generative-ai": "^0.24.1",
47
47
  "@modelcontextprotocol/sdk": "^1.25.2",
48
- "@redaksjon/context": "^0.0.3",
48
+ "@redaksjon/context": "^0.0.4",
49
49
  "@riotprompt/riotprompt": "^0.0.21",
50
- "@theunwalked/cardigantime": "^0.0.22",
51
- "@theunwalked/dreadcabinet": "^0.0.15",
52
- "@theunwalked/overcontext": "^0.0.3",
50
+ "@utilarium/cardigantime": "^0.0.24",
51
+ "@utilarium/dreadcabinet": "^0.0.16",
52
+ "@utilarium/overcontext": "^0.0.4",
53
53
  "@types/fluent-ffmpeg": "^2.1.28",
54
54
  "cli-table3": "^0.6.5",
55
55
  "commander": "^14.0.2",
@@ -63,7 +63,7 @@
63
63
  "moment-timezone": "^0.6.0",
64
64
  "openai": "^6.9.0",
65
65
  "winston": "^3.18.3",
66
- "zod": "^4.1.12"
66
+ "zod": "^4.3.6"
67
67
  },
68
68
  "devDependencies": {
69
69
  "@eslint/eslintrc": "^3.3.1",
package/vite.config.ts CHANGED
@@ -62,8 +62,8 @@ export default defineConfig({
62
62
  '@modelcontextprotocol/sdk/server/stdio.js',
63
63
  '@modelcontextprotocol/sdk/types.js',
64
64
  '@riotprompt/riotprompt',
65
- '@theunwalked/cardigantime',
66
- '@theunwalked/dreadcabinet',
65
+ '@utilarium/cardigantime',
66
+ '@utilarium/dreadcabinet',
67
67
  '@types/fluent-ffmpeg',
68
68
  'commander',
69
69
  'dayjs',