lynkr 3.3.1 → 4.1.0
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/README.md +276 -2177
- package/README.md.backup +2996 -0
- package/docs/GSD_LEARNINGS.md +1116 -0
- package/docs/LOCAL_EMBEDDINGS_PLAN.md +1024 -0
- package/documentation/README.md +98 -0
- package/documentation/api.md +806 -0
- package/documentation/claude-code-cli.md +672 -0
- package/documentation/contributing.md +571 -0
- package/documentation/cursor-integration.md +731 -0
- package/documentation/docker.md +867 -0
- package/documentation/embeddings.md +760 -0
- package/documentation/faq.md +659 -0
- package/documentation/features.md +396 -0
- package/documentation/installation.md +706 -0
- package/documentation/memory-system.md +476 -0
- package/documentation/production.md +601 -0
- package/documentation/providers.md +735 -0
- package/documentation/testing.md +629 -0
- package/documentation/token-optimization.md +323 -0
- package/documentation/tools.md +697 -0
- package/documentation/troubleshooting.md +864 -0
- package/package.json +2 -2
- package/src/api/openai-router.js +919 -0
- package/src/api/router.js +4 -0
- package/src/clients/openai-format.js +427 -0
- package/src/config/index.js +8 -0
- package/test/cursor-integration.test.js +484 -0
|
@@ -0,0 +1,697 @@
|
|
|
1
|
+
# Tool Calling & Execution Modes
|
|
2
|
+
|
|
3
|
+
Complete guide to Lynkr's tool calling system, execution modes, and custom tool development.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
Lynkr supports two tool execution modes:
|
|
10
|
+
|
|
11
|
+
- **Server Mode (default)**: Tools execute on Lynkr server
|
|
12
|
+
- **Client Mode (passthrough)**: Tools execute on client (Claude Code CLI/Cursor)
|
|
13
|
+
|
|
14
|
+
This enables flexible deployment scenarios: centralized tooling, security policies, or client-side file access.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Tool Execution Modes
|
|
19
|
+
|
|
20
|
+
### Server Mode (Default)
|
|
21
|
+
|
|
22
|
+
**How it works:**
|
|
23
|
+
- Client sends request without tools
|
|
24
|
+
- Lynkr injects standard tools
|
|
25
|
+
- Model requests tool execution
|
|
26
|
+
- Tools run on Lynkr server
|
|
27
|
+
- Results sent back to model
|
|
28
|
+
|
|
29
|
+
**Benefits:**
|
|
30
|
+
- ✅ Centralized control
|
|
31
|
+
- ✅ Policy enforcement
|
|
32
|
+
- ✅ Consistent environment
|
|
33
|
+
- ✅ Works with any client
|
|
34
|
+
|
|
35
|
+
**Use cases:**
|
|
36
|
+
- Production deployments
|
|
37
|
+
- Team environments
|
|
38
|
+
- Policy-enforced workflows
|
|
39
|
+
- Air-gapped deployments
|
|
40
|
+
|
|
41
|
+
**Configuration:**
|
|
42
|
+
```bash
|
|
43
|
+
# Default - no configuration needed
|
|
44
|
+
# Server mode activates when client doesn't send tools
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Client Mode (Passthrough)
|
|
48
|
+
|
|
49
|
+
**How it works:**
|
|
50
|
+
- Client sends request with tools
|
|
51
|
+
- Lynkr passes tools to model
|
|
52
|
+
- Model requests tool execution
|
|
53
|
+
- Client executes tools locally
|
|
54
|
+
- Results sent back through Lynkr
|
|
55
|
+
|
|
56
|
+
**Benefits:**
|
|
57
|
+
- ✅ Local file system access
|
|
58
|
+
- ✅ User-specific permissions
|
|
59
|
+
- ✅ No server-side execution
|
|
60
|
+
- ✅ Familiar CLI behavior
|
|
61
|
+
|
|
62
|
+
**Use cases:**
|
|
63
|
+
- Claude Code CLI (default behavior)
|
|
64
|
+
- Local development
|
|
65
|
+
- Personal use
|
|
66
|
+
- Custom tooling
|
|
67
|
+
|
|
68
|
+
**Configuration:**
|
|
69
|
+
```bash
|
|
70
|
+
# Client sends tools in request
|
|
71
|
+
# Lynkr automatically uses passthrough mode
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Built-in Tools
|
|
77
|
+
|
|
78
|
+
### File Operations
|
|
79
|
+
|
|
80
|
+
#### Read Tool
|
|
81
|
+
**Purpose:** Read file contents
|
|
82
|
+
|
|
83
|
+
**Parameters:**
|
|
84
|
+
- `file_path` (string, required): Absolute path to file
|
|
85
|
+
- `offset` (number, optional): Line number to start reading from
|
|
86
|
+
- `limit` (number, optional): Number of lines to read
|
|
87
|
+
|
|
88
|
+
**Example:**
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"name": "Read",
|
|
92
|
+
"input": {
|
|
93
|
+
"file_path": "/path/to/file.js",
|
|
94
|
+
"offset": 0,
|
|
95
|
+
"limit": 100
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Features:**
|
|
101
|
+
- Automatic truncation (2,000 lines max)
|
|
102
|
+
- Line numbering
|
|
103
|
+
- UTF-8 support
|
|
104
|
+
|
|
105
|
+
#### Write Tool
|
|
106
|
+
**Purpose:** Write content to file
|
|
107
|
+
|
|
108
|
+
**Parameters:**
|
|
109
|
+
- `file_path` (string, required): Absolute path to file
|
|
110
|
+
- `content` (string, required): File content
|
|
111
|
+
|
|
112
|
+
**Example:**
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"name": "Write",
|
|
116
|
+
"input": {
|
|
117
|
+
"file_path": "/path/to/file.js",
|
|
118
|
+
"content": "console.log('Hello');"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Features:**
|
|
124
|
+
- Creates directories if needed
|
|
125
|
+
- Overwrites existing files
|
|
126
|
+
- UTF-8 encoding
|
|
127
|
+
|
|
128
|
+
#### Edit Tool
|
|
129
|
+
**Purpose:** Find and replace in file
|
|
130
|
+
|
|
131
|
+
**Parameters:**
|
|
132
|
+
- `file_path` (string, required): Absolute path to file
|
|
133
|
+
- `old_string` (string, required): Text to find
|
|
134
|
+
- `new_string` (string, required): Replacement text
|
|
135
|
+
- `replace_all` (boolean, optional): Replace all occurrences
|
|
136
|
+
|
|
137
|
+
**Example:**
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"name": "Edit",
|
|
141
|
+
"input": {
|
|
142
|
+
"file_path": "/path/to/file.js",
|
|
143
|
+
"old_string": "var x = 1;",
|
|
144
|
+
"new_string": "const x = 1;",
|
|
145
|
+
"replace_all": true
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Git Operations
|
|
151
|
+
|
|
152
|
+
#### git_status Tool
|
|
153
|
+
**Purpose:** Check git repository status
|
|
154
|
+
|
|
155
|
+
**Example:**
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"name": "git_status",
|
|
159
|
+
"input": {}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Returns:**
|
|
164
|
+
- Untracked files
|
|
165
|
+
- Modified files
|
|
166
|
+
- Staged changes
|
|
167
|
+
- Current branch
|
|
168
|
+
|
|
169
|
+
#### git_diff Tool
|
|
170
|
+
**Purpose:** Show git diff
|
|
171
|
+
|
|
172
|
+
**Parameters:**
|
|
173
|
+
- `staged` (boolean, optional): Show staged changes only
|
|
174
|
+
|
|
175
|
+
**Example:**
|
|
176
|
+
```json
|
|
177
|
+
{
|
|
178
|
+
"name": "git_diff",
|
|
179
|
+
"input": {
|
|
180
|
+
"staged": false
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### git_commit Tool
|
|
186
|
+
**Purpose:** Create git commit
|
|
187
|
+
|
|
188
|
+
**Parameters:**
|
|
189
|
+
- `message` (string, required): Commit message
|
|
190
|
+
- `files` (array, optional): Files to stage and commit
|
|
191
|
+
|
|
192
|
+
**Example:**
|
|
193
|
+
```json
|
|
194
|
+
{
|
|
195
|
+
"name": "git_commit",
|
|
196
|
+
"input": {
|
|
197
|
+
"message": "Fix authentication bug",
|
|
198
|
+
"files": ["src/auth.js", "test/auth.test.js"]
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Policy enforcement:**
|
|
204
|
+
```bash
|
|
205
|
+
# Prevent git push
|
|
206
|
+
POLICY_GIT_ALLOW_PUSH=false
|
|
207
|
+
|
|
208
|
+
# Require tests before commit
|
|
209
|
+
POLICY_GIT_REQUIRE_TESTS=true
|
|
210
|
+
POLICY_GIT_TEST_COMMAND="npm test"
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Bash Execution
|
|
214
|
+
|
|
215
|
+
#### Bash Tool
|
|
216
|
+
**Purpose:** Execute shell commands
|
|
217
|
+
|
|
218
|
+
**Parameters:**
|
|
219
|
+
- `command` (string, required): Shell command to execute
|
|
220
|
+
- `timeout` (number, optional): Timeout in milliseconds (default: 120000)
|
|
221
|
+
|
|
222
|
+
**Example:**
|
|
223
|
+
```json
|
|
224
|
+
{
|
|
225
|
+
"name": "Bash",
|
|
226
|
+
"input": {
|
|
227
|
+
"command": "npm test",
|
|
228
|
+
"timeout": 60000
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Features:**
|
|
234
|
+
- Automatic truncation (1,000 lines max)
|
|
235
|
+
- Working directory preservation
|
|
236
|
+
- Environment variable access
|
|
237
|
+
- Timeout protection
|
|
238
|
+
|
|
239
|
+
**Security:**
|
|
240
|
+
```bash
|
|
241
|
+
# Commands are NOT sandboxed by default
|
|
242
|
+
# Use with caution in server mode
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Search Operations
|
|
246
|
+
|
|
247
|
+
#### Grep Tool
|
|
248
|
+
**Purpose:** Search file contents (ripgrep-powered)
|
|
249
|
+
|
|
250
|
+
**Parameters:**
|
|
251
|
+
- `pattern` (string, required): Regex pattern to search
|
|
252
|
+
- `path` (string, optional): Directory to search (default: workspace)
|
|
253
|
+
- `glob` (string, optional): File pattern filter (e.g., "*.js")
|
|
254
|
+
- `type` (string, optional): File type (e.g., "js", "py")
|
|
255
|
+
- `output_mode` (string, optional): "content", "files_with_matches", "count"
|
|
256
|
+
|
|
257
|
+
**Example:**
|
|
258
|
+
```json
|
|
259
|
+
{
|
|
260
|
+
"name": "Grep",
|
|
261
|
+
"input": {
|
|
262
|
+
"pattern": "function.*Auth",
|
|
263
|
+
"glob": "*.js",
|
|
264
|
+
"output_mode": "content"
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
#### Glob Tool
|
|
270
|
+
**Purpose:** Find files by pattern
|
|
271
|
+
|
|
272
|
+
**Parameters:**
|
|
273
|
+
- `pattern` (string, required): Glob pattern (e.g., "**/*.js")
|
|
274
|
+
- `path` (string, optional): Directory to search
|
|
275
|
+
|
|
276
|
+
**Example:**
|
|
277
|
+
```json
|
|
278
|
+
{
|
|
279
|
+
"name": "Glob",
|
|
280
|
+
"input": {
|
|
281
|
+
"pattern": "src/**/*.test.js"
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Memory Operations
|
|
287
|
+
|
|
288
|
+
#### memory_search Tool
|
|
289
|
+
**Purpose:** Search long-term memories
|
|
290
|
+
|
|
291
|
+
**Parameters:**
|
|
292
|
+
- `query` (string, required): Search query
|
|
293
|
+
|
|
294
|
+
**Example:**
|
|
295
|
+
```json
|
|
296
|
+
{
|
|
297
|
+
"name": "memory_search",
|
|
298
|
+
"input": {
|
|
299
|
+
"query": "authentication preferences"
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**Returns:**
|
|
305
|
+
- Top N relevant memories (default: 5)
|
|
306
|
+
- Memory type, content, importance
|
|
307
|
+
- Creation and access timestamps
|
|
308
|
+
|
|
309
|
+
#### memory_add Tool
|
|
310
|
+
**Purpose:** Manually add memory
|
|
311
|
+
|
|
312
|
+
**Parameters:**
|
|
313
|
+
- `content` (string, required): Memory content
|
|
314
|
+
- `memory_type` (string, required): "preference", "decision", "fact", "entity", "relationship"
|
|
315
|
+
- `importance` (number, optional): 0.0-1.0 (default: 1.0)
|
|
316
|
+
|
|
317
|
+
**Example:**
|
|
318
|
+
```json
|
|
319
|
+
{
|
|
320
|
+
"name": "memory_add",
|
|
321
|
+
"input": {
|
|
322
|
+
"content": "User prefers TypeScript over JavaScript",
|
|
323
|
+
"memory_type": "preference",
|
|
324
|
+
"importance": 0.9
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
#### memory_forget Tool
|
|
330
|
+
**Purpose:** Delete specific memory
|
|
331
|
+
|
|
332
|
+
**Parameters:**
|
|
333
|
+
- `query` (string, required): Search query to find memory to delete
|
|
334
|
+
|
|
335
|
+
**Example:**
|
|
336
|
+
```json
|
|
337
|
+
{
|
|
338
|
+
"name": "memory_forget",
|
|
339
|
+
"input": {
|
|
340
|
+
"query": "old preference about MongoDB"
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## MCP Integration
|
|
348
|
+
|
|
349
|
+
### Model Context Protocol (MCP)
|
|
350
|
+
|
|
351
|
+
Lynkr supports MCP for dynamic tool registration.
|
|
352
|
+
|
|
353
|
+
**Features:**
|
|
354
|
+
- Automatic MCP server discovery
|
|
355
|
+
- JSON-RPC 2.0 communication
|
|
356
|
+
- Dynamic tool registration
|
|
357
|
+
- Optional sandbox isolation
|
|
358
|
+
|
|
359
|
+
### MCP Configuration
|
|
360
|
+
|
|
361
|
+
**Enable MCP:**
|
|
362
|
+
```bash
|
|
363
|
+
MCP_ENABLED=true # default: true
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**Sandbox mode:**
|
|
367
|
+
```bash
|
|
368
|
+
# Enable Docker sandbox for MCP tools
|
|
369
|
+
MCP_SANDBOX_ENABLED=true # default: true
|
|
370
|
+
|
|
371
|
+
# Docker image for sandbox
|
|
372
|
+
MCP_SANDBOX_IMAGE=ubuntu:22.04
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### MCP Server Discovery
|
|
376
|
+
|
|
377
|
+
**Locations searched:**
|
|
378
|
+
1. `./mcp-servers/` (workspace directory)
|
|
379
|
+
2. `~/.mcp/servers/` (user directory)
|
|
380
|
+
3. Environment variable: `MCP_SERVER_PATH`
|
|
381
|
+
|
|
382
|
+
**Example MCP server:**
|
|
383
|
+
```json
|
|
384
|
+
{
|
|
385
|
+
"name": "my-custom-tool",
|
|
386
|
+
"description": "Does something useful",
|
|
387
|
+
"inputSchema": {
|
|
388
|
+
"type": "object",
|
|
389
|
+
"properties": {
|
|
390
|
+
"input": {
|
|
391
|
+
"type": "string",
|
|
392
|
+
"description": "Input parameter"
|
|
393
|
+
}
|
|
394
|
+
},
|
|
395
|
+
"required": ["input"]
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Using MCP Tools
|
|
401
|
+
|
|
402
|
+
MCP tools are automatically registered and available to models:
|
|
403
|
+
|
|
404
|
+
```json
|
|
405
|
+
{
|
|
406
|
+
"name": "my-custom-tool",
|
|
407
|
+
"input": {
|
|
408
|
+
"input": "test value"
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## Custom Tool Development
|
|
416
|
+
|
|
417
|
+
### Creating Custom Tools
|
|
418
|
+
|
|
419
|
+
**File structure:**
|
|
420
|
+
```
|
|
421
|
+
src/tools/
|
|
422
|
+
├── workspace.js (Read, Write, Edit)
|
|
423
|
+
├── git.js (git_status, git_diff, git_commit)
|
|
424
|
+
├── bash.js (Bash)
|
|
425
|
+
├── search.js (Grep, Glob)
|
|
426
|
+
├── memory.js (memory_search, memory_add, memory_forget)
|
|
427
|
+
└── custom.js (Your custom tools)
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
**Custom tool template:**
|
|
431
|
+
```javascript
|
|
432
|
+
// src/tools/custom.js
|
|
433
|
+
|
|
434
|
+
const logger = require("pino")();
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Custom tool definition
|
|
438
|
+
*/
|
|
439
|
+
const myCustomTool = {
|
|
440
|
+
name: "my_custom_tool",
|
|
441
|
+
description: "Does something useful",
|
|
442
|
+
input_schema: {
|
|
443
|
+
type: "object",
|
|
444
|
+
properties: {
|
|
445
|
+
input: {
|
|
446
|
+
type: "string",
|
|
447
|
+
description: "Input parameter"
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
required: ["input"]
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Custom tool implementation
|
|
456
|
+
*/
|
|
457
|
+
async function executeMyCustomTool(input) {
|
|
458
|
+
try {
|
|
459
|
+
logger.info({ input }, "Executing my_custom_tool");
|
|
460
|
+
|
|
461
|
+
// Your tool logic here
|
|
462
|
+
const result = doSomething(input);
|
|
463
|
+
|
|
464
|
+
return {
|
|
465
|
+
success: true,
|
|
466
|
+
result: result
|
|
467
|
+
};
|
|
468
|
+
} catch (error) {
|
|
469
|
+
logger.error({ error }, "my_custom_tool failed");
|
|
470
|
+
throw error;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
module.exports = {
|
|
475
|
+
myCustomTool,
|
|
476
|
+
executeMyCustomTool
|
|
477
|
+
};
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### Registering Custom Tools
|
|
481
|
+
|
|
482
|
+
**File:** `src/tools/index.js`
|
|
483
|
+
|
|
484
|
+
```javascript
|
|
485
|
+
const { myCustomTool, executeMyCustomTool } = require("./custom");
|
|
486
|
+
|
|
487
|
+
// Add to STANDARD_TOOLS
|
|
488
|
+
const STANDARD_TOOLS = [
|
|
489
|
+
// ... existing tools
|
|
490
|
+
myCustomTool
|
|
491
|
+
];
|
|
492
|
+
|
|
493
|
+
// Add to tool executor
|
|
494
|
+
async function executeTool(toolName, toolInput) {
|
|
495
|
+
switch (toolName) {
|
|
496
|
+
// ... existing cases
|
|
497
|
+
case "my_custom_tool":
|
|
498
|
+
return await executeMyCustomTool(toolInput);
|
|
499
|
+
default:
|
|
500
|
+
throw new Error(`Unknown tool: ${toolName}`);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Tool Best Practices
|
|
506
|
+
|
|
507
|
+
1. **Error handling:**
|
|
508
|
+
```javascript
|
|
509
|
+
try {
|
|
510
|
+
// Tool logic
|
|
511
|
+
} catch (error) {
|
|
512
|
+
logger.error({ error, input }, "Tool execution failed");
|
|
513
|
+
throw new Error(`Tool failed: ${error.message}`);
|
|
514
|
+
}
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
2. **Input validation:**
|
|
518
|
+
```javascript
|
|
519
|
+
function validateInput(input) {
|
|
520
|
+
if (!input || typeof input !== "string") {
|
|
521
|
+
throw new Error("Invalid input: expected string");
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
3. **Logging:**
|
|
527
|
+
```javascript
|
|
528
|
+
logger.info({
|
|
529
|
+
toolName: "my_custom_tool",
|
|
530
|
+
input: input,
|
|
531
|
+
duration: Date.now() - startTime
|
|
532
|
+
}, "Tool executed successfully");
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
4. **Timeout protection:**
|
|
536
|
+
```javascript
|
|
537
|
+
const timeout = 30000; // 30 seconds
|
|
538
|
+
const result = await Promise.race([
|
|
539
|
+
executeTool(input),
|
|
540
|
+
new Promise((_, reject) =>
|
|
541
|
+
setTimeout(() => reject(new Error("Tool timeout")), timeout)
|
|
542
|
+
)
|
|
543
|
+
]);
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
---
|
|
547
|
+
|
|
548
|
+
## Tool Policies
|
|
549
|
+
|
|
550
|
+
### Git Policies
|
|
551
|
+
|
|
552
|
+
**Prevent git push:**
|
|
553
|
+
```bash
|
|
554
|
+
POLICY_GIT_ALLOW_PUSH=false
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
**Require tests before commit:**
|
|
558
|
+
```bash
|
|
559
|
+
POLICY_GIT_REQUIRE_TESTS=true
|
|
560
|
+
POLICY_GIT_TEST_COMMAND="npm test"
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
**Example:**
|
|
564
|
+
```
|
|
565
|
+
User: "Commit these changes"
|
|
566
|
+
Assistant: *Runs git commit*
|
|
567
|
+
Lynkr: [Blocks] Running tests first (POLICY_GIT_REQUIRE_TESTS=true)
|
|
568
|
+
Lynkr: *Executes npm test*
|
|
569
|
+
Lynkr: Tests passed, proceeding with commit
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
### Web Fetch Policies
|
|
573
|
+
|
|
574
|
+
**Restrict allowed hosts:**
|
|
575
|
+
```bash
|
|
576
|
+
WEB_SEARCH_ALLOWED_HOSTS=github.com,stackoverflow.com
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
**Custom search endpoint:**
|
|
580
|
+
```bash
|
|
581
|
+
WEB_SEARCH_ENDPOINT=http://localhost:8888/search
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
### Workspace Policies
|
|
585
|
+
|
|
586
|
+
**Restrict workspace access:**
|
|
587
|
+
```bash
|
|
588
|
+
WORKSPACE_ROOT=/path/to/projects
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
**Max agent loop iterations:**
|
|
592
|
+
```bash
|
|
593
|
+
POLICY_MAX_STEPS=8
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
---
|
|
597
|
+
|
|
598
|
+
## Tool Security
|
|
599
|
+
|
|
600
|
+
### Server Mode Security
|
|
601
|
+
|
|
602
|
+
**Risks:**
|
|
603
|
+
- Tools run with Lynkr server permissions
|
|
604
|
+
- Can access server filesystem
|
|
605
|
+
- Can execute arbitrary commands
|
|
606
|
+
|
|
607
|
+
**Mitigations:**
|
|
608
|
+
1. **Run as unprivileged user:**
|
|
609
|
+
```bash
|
|
610
|
+
# Create dedicated user
|
|
611
|
+
useradd -r -s /bin/false lynkr
|
|
612
|
+
|
|
613
|
+
# Run as lynkr user
|
|
614
|
+
sudo -u lynkr npm start
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
2. **Use Docker isolation:**
|
|
618
|
+
```yaml
|
|
619
|
+
# docker-compose.yml
|
|
620
|
+
services:
|
|
621
|
+
lynkr:
|
|
622
|
+
user: "1000:1000" # Non-root user
|
|
623
|
+
read_only: true # Read-only root filesystem
|
|
624
|
+
volumes:
|
|
625
|
+
- ./workspace:/workspace # Limited access
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
3. **Enable policies:**
|
|
629
|
+
```bash
|
|
630
|
+
POLICY_GIT_ALLOW_PUSH=false
|
|
631
|
+
POLICY_GIT_REQUIRE_TESTS=true
|
|
632
|
+
WEB_SEARCH_ALLOWED_HOSTS=github.com
|
|
633
|
+
WORKSPACE_ROOT=/workspace
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
### Client Mode Security
|
|
637
|
+
|
|
638
|
+
**Risks:**
|
|
639
|
+
- Tools run with client user permissions
|
|
640
|
+
- Can access client filesystem
|
|
641
|
+
- Can execute commands on client machine
|
|
642
|
+
|
|
643
|
+
**Mitigations:**
|
|
644
|
+
- Review tool calls before execution
|
|
645
|
+
- Use Claude Code CLI safety features
|
|
646
|
+
- Run client in restricted environment
|
|
647
|
+
|
|
648
|
+
---
|
|
649
|
+
|
|
650
|
+
## Debugging Tools
|
|
651
|
+
|
|
652
|
+
### Enable tool logging
|
|
653
|
+
|
|
654
|
+
```bash
|
|
655
|
+
LOG_LEVEL=debug npm start
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
**Output:**
|
|
659
|
+
```json
|
|
660
|
+
{
|
|
661
|
+
"level": "debug",
|
|
662
|
+
"msg": "Tool executed",
|
|
663
|
+
"toolName": "Read",
|
|
664
|
+
"input": {"file_path": "/path/to/file.js"},
|
|
665
|
+
"duration": 12,
|
|
666
|
+
"success": true
|
|
667
|
+
}
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
### Test tool execution
|
|
671
|
+
|
|
672
|
+
```bash
|
|
673
|
+
# Test Read tool
|
|
674
|
+
curl -X POST http://localhost:8081/v1/messages \
|
|
675
|
+
-H "Content-Type: application/json" \
|
|
676
|
+
-d '{
|
|
677
|
+
"model": "claude-3.5-sonnet",
|
|
678
|
+
"messages": [{"role": "user", "content": "Read package.json"}],
|
|
679
|
+
"max_tokens": 1024
|
|
680
|
+
}'
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
---
|
|
684
|
+
|
|
685
|
+
## Next Steps
|
|
686
|
+
|
|
687
|
+
- **[MCP Integration Guide](mcp.md)** - Model Context Protocol setup
|
|
688
|
+
- **[Production Guide](production.md)** - Production deployment
|
|
689
|
+
- **[API Reference](api.md)** - API endpoints
|
|
690
|
+
- **[FAQ](faq.md)** - Common questions
|
|
691
|
+
|
|
692
|
+
---
|
|
693
|
+
|
|
694
|
+
## Getting Help
|
|
695
|
+
|
|
696
|
+
- **[GitHub Discussions](https://github.com/vishalveerareddy123/Lynkr/discussions)** - Ask questions
|
|
697
|
+
- **[GitHub Issues](https://github.com/vishalveerareddy123/Lynkr/issues)** - Report issues
|