lynkr 0.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.
Files changed (52) hide show
  1. package/.eslintrc.cjs +12 -0
  2. package/CLAUDE.md +39 -0
  3. package/LICENSE +21 -0
  4. package/README.md +417 -0
  5. package/bin/cli.js +3 -0
  6. package/index.js +3 -0
  7. package/package.json +54 -0
  8. package/src/api/middleware/logging.js +37 -0
  9. package/src/api/middleware/session.js +55 -0
  10. package/src/api/router.js +80 -0
  11. package/src/cache/prompt.js +183 -0
  12. package/src/clients/databricks.js +72 -0
  13. package/src/config/index.js +301 -0
  14. package/src/db/index.js +192 -0
  15. package/src/diff/comments.js +153 -0
  16. package/src/edits/index.js +171 -0
  17. package/src/indexer/index.js +1610 -0
  18. package/src/indexer/navigation/index.js +32 -0
  19. package/src/indexer/navigation/providers/treeSitter.js +36 -0
  20. package/src/indexer/parser.js +324 -0
  21. package/src/logger/index.js +27 -0
  22. package/src/mcp/client.js +194 -0
  23. package/src/mcp/index.js +34 -0
  24. package/src/mcp/permissions.js +69 -0
  25. package/src/mcp/registry.js +225 -0
  26. package/src/mcp/sandbox.js +238 -0
  27. package/src/metrics/index.js +38 -0
  28. package/src/orchestrator/index.js +1492 -0
  29. package/src/policy/index.js +212 -0
  30. package/src/policy/web-fallback.js +33 -0
  31. package/src/server.js +73 -0
  32. package/src/sessions/index.js +15 -0
  33. package/src/sessions/record.js +31 -0
  34. package/src/sessions/store.js +179 -0
  35. package/src/tasks/store.js +349 -0
  36. package/src/tests/coverage.js +173 -0
  37. package/src/tests/index.js +171 -0
  38. package/src/tests/store.js +213 -0
  39. package/src/tools/edits.js +94 -0
  40. package/src/tools/execution.js +169 -0
  41. package/src/tools/git.js +1346 -0
  42. package/src/tools/index.js +258 -0
  43. package/src/tools/indexer.js +360 -0
  44. package/src/tools/mcp-remote.js +81 -0
  45. package/src/tools/mcp.js +116 -0
  46. package/src/tools/process.js +151 -0
  47. package/src/tools/stubs.js +55 -0
  48. package/src/tools/tasks.js +260 -0
  49. package/src/tools/tests.js +132 -0
  50. package/src/tools/web.js +286 -0
  51. package/src/tools/workspace.js +173 -0
  52. package/src/workspace/index.js +95 -0
package/.eslintrc.cjs ADDED
@@ -0,0 +1,12 @@
1
+ module.exports = {
2
+ env: {
3
+ node: true,
4
+ es2021: true,
5
+ },
6
+ extends: ["eslint:recommended"],
7
+ parserOptions: {
8
+ ecmaVersion: "latest",
9
+ sourceType: "script",
10
+ },
11
+ rules: {},
12
+ };
package/CLAUDE.md ADDED
@@ -0,0 +1,39 @@
1
+ <!-- Generated by claude-code indexer -->
2
+ # CLAUDE.md
3
+
4
+ - After invoking `web_search`, wait for the tool result and let the assistant finish summarizing before sending any new user prompts.
5
+ - When the user asks for news or search results, respond with the summary already generated in the assistant’s next turn; do not restart the conversation unless asked.
6
+ - Avoid repeating warmup or onboarding messages once the user has made their real request.
7
+
8
+ # Project Overview
9
+
10
+ - Workspace root: `/Users/vishalveera.reddy/claude-code`
11
+ - Indexed at: 2025-11-23T23:22:56.258Z
12
+ - Files indexed: 52
13
+
14
+ ## Language Mix
15
+
16
+ - javascript: 44 files (84.62%)
17
+ - json: 3 files (5.77%)
18
+ - yaml: 1 files (1.92%)
19
+ - shell: 1 files (1.92%)
20
+
21
+ ## Framework Signals
22
+
23
+ - **node** (1 signals)
24
+ - package.json detected (package.json)
25
+ - **express** (1 signals)
26
+ - Express dependency detected (package.json)
27
+
28
+ ## Style Guide Insights
29
+
30
+ - eslint: .eslintrc.cjs (ESLint configuration)
31
+
32
+ ## Top Workspace Dependencies
33
+
34
+ - ( (refs: 13)
35
+
36
+ ## Re-index Guidance
37
+
38
+ Run `workspace_index_rebuild` to refresh this document after making large changes.
39
+
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Vishal Veera Reddy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,417 @@
1
+ # Lynkr
2
+
3
+ > Drop-in HTTP proxy that lets Claude Code CLI talk to non-Anthropic backends, manage local tools, and compose Model Context Protocol (MCP) servers with prompt caching, repo intelligence, and Git-aware automation.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Overview](#overview)
8
+ 2. [Core Capabilities](#core-capabilities)
9
+ - [Repo Intelligence & Navigation](#repo-intelligence--navigation)
10
+ - [Git Workflow Enhancements](#git-workflow-enhancements)
11
+ - [Diff & Change Management](#diff--change-management)
12
+ - [Execution & Tooling](#execution--tooling)
13
+ - [Workflow & Collaboration](#workflow--collaboration)
14
+ - [UX, Monitoring, and Logs](#ux-monitoring-and-logs)
15
+ 3. [Architecture](#architecture)
16
+ 4. [Getting Started](#getting-started)
17
+ 5. [Configuration Reference](#configuration-reference)
18
+ 6. [Runtime Operations](#runtime-operations)
19
+ - [Launching the Proxy](#launching-the-proxy)
20
+ - [Connecting Claude Code CLI](#connecting-claude-code-cli)
21
+ - [Using Built-in Workspace Tools](#using-built-in-workspace-tools)
22
+ - [Working with Prompt Caching](#working-with-prompt-caching)
23
+ - [Integrating MCP Servers](#integrating-mcp-servers)
24
+ 7. [Manual Test Matrix](#manual-test-matrix)
25
+ 8. [Troubleshooting](#troubleshooting)
26
+ 9. [Roadmap & Known Gaps](#roadmap--known-gaps)
27
+ 10. [FAQ](#faq)
28
+ 11. [License](#license)
29
+
30
+ ---
31
+
32
+ ## Overview
33
+
34
+ This repository contains a Node.js service that emulates the Anthropic Claude Code backend so that the Claude Code CLI (or any compatible client) can operate against alternative model providers and custom tooling.
35
+
36
+ Key highlights:
37
+
38
+ - **Claude provider adapters** – Works with Databricks (default) and Azure-hosted Anthropic endpoints; requests are normalized to each provider while returning Claude-flavored responses.
39
+ - **Workspace awareness** – Local repo indexing, `CLAUDE.md` summaries, language-aware navigation, and Git helpers mirror core Claude Code workflows.
40
+ - **Model Context Protocol (MCP) orchestration** – Automatically discovers MCP manifests, launches JSON-RPC 2.0 servers, and re-exposes their tools inside the proxy.
41
+ - **Prompt caching** – Re-uses repeated prompts to reduce latency and token consumption, matching Claude’s own cache semantics.
42
+ - **Policy enforcement** – Environment-driven guardrails control Git operations, test requirements, web fetch fallbacks, and sandboxing rules.
43
+
44
+ The result is a self-hosted alternative that stays close to Anthropic’s ergonomics while remaining hackable for experimentation.
45
+
46
+ > **Compatibility note:** Claude models hosted on Databricks work out of the box. Set `MODEL_PROVIDER=azure-anthropic` (and related credentials) to target the Azure-hosted Anthropic `/anthropic/v1/messages` endpoint. Additional providers will require future adapters.
47
+
48
+ ---
49
+
50
+ ## Core Capabilities
51
+
52
+ ### Repo Intelligence & Navigation
53
+
54
+ - Fast indexer builds a lightweight SQLite catalog of files, symbols, references, and framework hints.
55
+ - `CLAUDE.md` summary highlights language mix, frameworks, lint configs, and dependency signals.
56
+ - Symbol search and reference lookups return definition sites and cross-file usage for supported languages (TypeScript/JavaScript/Python via Tree-sitter parsers) with heuristic fallbacks for others.
57
+ - Automatic invalidation ensures removed files disappear from search results after `workspace_index_rebuild`.
58
+
59
+ ### Git Workflow Enhancements
60
+
61
+ - Git status, diff, stage, commit, push, and pull tooling via `src/tools/git.js`.
62
+ - Policy flags such as `POLICY_GIT_ALLOW_PUSH` and `POLICY_GIT_REQUIRE_TESTS` enforce push restrictions or test gating.
63
+ - Diff review endpoints summarise changes and highlight risks, feeding the AI review surface.
64
+ - Release note generator composes summarized change logs for downstream publishing.
65
+
66
+ ### Diff & Change Management
67
+
68
+ - Unified diff summaries with optional AI review (`workspace_diff_review`).
69
+ - Release note synthesis from Git history.
70
+ - Test harness integrates with git policies to ensure guarding before commit/push events.
71
+ - (Planned) Per-file threaded reviews and automated risk estimation (see [Roadmap](#roadmap--known-gaps)).
72
+
73
+ ### Execution & Tooling
74
+
75
+ - Tool execution pipeline sandboxes or runs tools in the host workspace based on policy.
76
+ - MCP sandbox orchestration (Docker runtime by default) optionally isolates external tools with mount and permission controls.
77
+ - Automated testing harness exposes `workspace_test_run`, `workspace_test_history`, and `workspace_test_summary`.
78
+ - Prompt caching reduces repeated token usage for iterative conversations.
79
+
80
+ ### Workflow & Collaboration
81
+
82
+ - Lightweight task tracker (`workspace_task_*` tools) persists TODO items in SQLite.
83
+ - Session database (`data/sessions.db`) stores conversational transcripts for auditing.
84
+ - Policy web fallback fetches limited remote data when explicitly permitted.
85
+
86
+ ### UX, Monitoring, and Logs
87
+
88
+ - Pino-based structured logs with timestamps and severity.
89
+ - Request/response logging for Databricks interactions (visible in stdout).
90
+ - Session appenders log every user, assistant, and tool turn for reproducibility.
91
+ - Metrics directory ready for future Prometheus/StatsD integration.
92
+
93
+ ---
94
+
95
+ ## Architecture
96
+
97
+ ```
98
+ ┌────────────────────┐ ┌───────────────────────┐
99
+ │ Claude Code CLI │──HTTP│ Claude Code Proxy │
100
+ │ (or Claude client) │ │ (Express API gateway) │
101
+ └────────────────────┘ └──────────┬────────────┘
102
+
103
+ ┌───────────────────────────────┼─────────────────────────────┐
104
+ │ │ │
105
+ ┌───────▼───────┐ ┌───────▼────────┐ ┌──────▼───────┐
106
+ │ Orchestrator │ │ Prompt Cache │ │ Session Store│
107
+ │ (agent loop) │ │ (LRU + TTL) │ │ (SQLite) │
108
+ └───────┬───────┘ └───────┬────────┘ └──────┬───────┘
109
+ │ │ │
110
+ ┌───────▼────────────────────────────┐ │ ┌────────────────────────▼──────┐
111
+ │ Tool Registry & Policy Engine │ │ │ Indexer / Repo Intelligence │
112
+ │ (workspace, git, diff, MCP tools) │ │ │ (SQLite catalog + CLAUDE.md) │
113
+ └───────┬────────────────────────────┘ │ └────────────────────────┬──────┘
114
+ │ │ │
115
+ ┌───────▼────────┐ ┌─────────────────────────────┐ ┌──────▼──────────┐
116
+ │ MCP Registry │ │ Provider Adapters │ │ Sandbox Runtime │
117
+ │ (manifest -> │────────RPC────│ (Databricks / Azure Anthropic│──────┐ │ (Docker, etc.) │
118
+ │ JSON-RPC client│ │ + future backends) │ │ └────────────────┘
119
+ └────────────────┘ └───────────┬──────────────────┘ │
120
+ │ │
121
+ ┌───────────▼───────────┐ │
122
+ │ Databricks Serving │─────────────┘
123
+ │ Endpoint (REST) │
124
+ └───────────────────────┘
125
+
126
+ ┌───────────▼───────────┐
127
+ │ Azure Anthropic │
128
+ │ `/anthropic/v1/messages`│
129
+ └───────────────────────┘
130
+
131
+ ┌─────────▼─────────┐
132
+ │ External MCP tools │
133
+ │ (GitHub, Jira, etc)│
134
+ └────────────────────┘
135
+ ```
136
+
137
+ - **`src/api/router.js`** – Express routes that accept Claude-compatible `/v1/messages` requests.
138
+ - **`src/orchestrator/index.js`** – Agent loop handling model invocation, tool execution, prompt caching, and policy enforcement.
139
+ - **`src/cache/prompt.js`** – LRU cache implementation with SHA-256 keying and TTL eviction.
140
+ - **`src/mcp/*`** – Manifest discovery, JSON-RPC 2.0 client, and dynamic tool registration for MCP servers.
141
+ - **`src/tools/*`** – Built-in workspace, git, diff, testing, task, and MCP bridging tools.
142
+ - **`src/indexer/index.js`** – File crawler and metadata extractor that persists into SQLite and regenerates `CLAUDE.md`.
143
+
144
+ ---
145
+
146
+ ## Getting Started
147
+
148
+ ### Prerequisites
149
+
150
+ - **Node.js 18+** (required for the global `fetch` API).
151
+ - **npm** (bundled with Node).
152
+ - **Databricks account** with a Claude-compatible serving endpoint (e.g., `databricks-claude-sonnet-4-5`).
153
+ - Optional: **Docker** for MCP sandboxing and tool isolation.
154
+ - Optional: **Claude Code CLI** (latest release). Configure it to target the proxy URL instead of api.anthropic.com.
155
+
156
+ ### Installation
157
+
158
+ ```bash
159
+ git clone https://github.com/vishalveerareddy123/Lynkr.git
160
+ cd Lynkr
161
+ npm install
162
+ ```
163
+
164
+ Populate an `.env` file (or export environment variables) before starting:
165
+
166
+ ```env
167
+ MODEL_PROVIDER=databricks
168
+ DATABRICKS_API_BASE=https://<your-workspace>.cloud.databricks.com
169
+ DATABRICKS_API_KEY=<personal-access-token>
170
+ PORT=8080
171
+ WORKSPACE_ROOT=/path/to/your/repo
172
+ PROMPT_CACHE_ENABLED=true
173
+ ```
174
+
175
+ You can copy `.env.example` if you maintain one, or rely on shell exports.
176
+
177
+ #### Selecting a model provider
178
+
179
+ Set `MODEL_PROVIDER` to select the upstream endpoint:
180
+
181
+ - `MODEL_PROVIDER=databricks` (default) – expects `DATABRICKS_API_BASE`, `DATABRICKS_API_KEY`, and optionally `DATABRICKS_ENDPOINT_PATH`.
182
+ - `MODEL_PROVIDER=azure-anthropic` – routes requests to Azure’s `/anthropic/v1/messages` endpoint and uses the headers Azure expects.
183
+
184
+ For Azure-hosted Anthropic, supply the Azure-specific credentials:
185
+
186
+ ```env
187
+ MODEL_PROVIDER=azure-anthropic
188
+ AZURE_ANTHROPIC_ENDPOINT=https://<resource-name>.services.ai.azure.com/anthropic/v1/messages
189
+ AZURE_ANTHROPIC_API_KEY=<azure-api-key>
190
+ AZURE_ANTHROPIC_VERSION=2023-06-01
191
+ PORT=8080
192
+ WORKSPACE_ROOT=/path/to/your/repo
193
+ ```
194
+
195
+ ---
196
+
197
+ ## Configuration Reference
198
+
199
+ | Variable | Description | Default |
200
+ |----------|-------------|---------|
201
+ | `PORT` | HTTP port for the proxy server. | `8080` |
202
+ | `WORKSPACE_ROOT` | Filesystem path exposed to workspace tools and indexer. | `process.cwd()` |
203
+ | `MODEL_PROVIDER` | Selects the model backend (`databricks`, `azure-anthropic`). | `databricks` |
204
+ | `MODEL_DEFAULT` | Overrides the default model/deployment name sent to the provider. | Provider-specific default |
205
+ | `DATABRICKS_API_BASE` | Base URL of your Databricks workspace (required when `MODEL_PROVIDER=databricks`). | – |
206
+ | `DATABRICKS_API_KEY` | Databricks PAT used for the serving endpoint (required for Databricks). | – |
207
+ | `DATABRICKS_ENDPOINT_PATH` | Optional override for the Databricks serving endpoint path. | `/serving-endpoints/databricks-claude-sonnet-4-5/invocations` |
208
+ | `AZURE_ANTHROPIC_ENDPOINT` | Full HTTPS endpoint for Azure-hosted Anthropic `/anthropic/v1/messages` (required when `MODEL_PROVIDER=azure-anthropic`). | – |
209
+ | `AZURE_ANTHROPIC_API_KEY` | API key supplied via the `x-api-key` header for Azure Anthropic. | – |
210
+ | `AZURE_ANTHROPIC_VERSION` | Anthropic API version header for Azure Anthropic calls. | `2023-06-01` |
211
+ | `PROMPT_CACHE_ENABLED` | Toggle the prompt cache system. | `true` |
212
+ | `PROMPT_CACHE_TTL_MS` | Milliseconds before cached prompts expire. | `300000` (5 minutes) |
213
+ | `PROMPT_CACHE_MAX_ENTRIES` | Maximum number of cached prompts retained. | `64` |
214
+ | `POLICY_MAX_STEPS` | Max agent loop iterations before timeout. | `8` |
215
+ | `POLICY_GIT_ALLOW_PUSH` | Allow/disallow `workspace_git_push`. | `false` |
216
+ | `POLICY_GIT_REQUIRE_TESTS` | Enforce passing tests before `workspace_git_commit`. | `false` |
217
+ | `POLICY_GIT_TEST_COMMAND` | Custom test command invoked by policies. | `null` |
218
+ | `WEB_SEARCH_ENDPOINT` | URL for policy-driven web fetch fallback. | `http://localhost:8888/search` |
219
+ | `WEB_SEARCH_ALLOWED_HOSTS` | Comma-separated allowlist for `web_fetch`. | `null` |
220
+ | `MCP_SERVER_MANIFEST` | Single manifest file for MCP server. | `null` |
221
+ | `MCP_MANIFEST_DIRS` | Semicolon-separated directories scanned for manifests. | `~/.claude/mcp` |
222
+ | `MCP_SANDBOX_ENABLED` | Enable container sandbox for MCP tools (requires `MCP_SANDBOX_IMAGE`). | `true` |
223
+ | `MCP_SANDBOX_IMAGE` | Docker/OCI image name used for sandboxing. | `null` |
224
+ | `WORKSPACE_TEST_COMMAND` | Default CLI used by `workspace_test_run`. | `null` |
225
+ | `WORKSPACE_TEST_TIMEOUT_MS` | Test harness timeout. | `600000` |
226
+ | `WORKSPACE_TEST_COVERAGE_FILES` | Comma-separated coverage summary files. | `coverage/coverage-summary.json` |
227
+
228
+ See `src/config/index.js` for the full configuration matrix, including sandbox mounts, permissions, and MCP networking policies.
229
+
230
+ ---
231
+
232
+ ## Runtime Operations
233
+
234
+ ### Launching the Proxy
235
+
236
+ ```bash
237
+ # Development: auto-restarts on file changes (requires nodemon)
238
+ npm run dev
239
+
240
+ # Production
241
+ npm start
242
+ ```
243
+
244
+ Logs stream to stdout. The server listens on `PORT` and exposes `/v1/messages` in the Anthropic-compatible shape.
245
+
246
+ ### Connecting Claude Code CLI
247
+
248
+ 1. Install or upgrade Claude Code CLI.
249
+ 2. Export the proxy endpoint:
250
+ ```bash
251
+ export ANTHROPIC_BASE_URL=http://localhost:8080
252
+ export ANTHROPIC_API_KEY=dummy # not used, but Anthropic CLI requires it
253
+ ```
254
+ 3. Launch `claude` CLI within `WORKSPACE_ROOT`.
255
+ 4. Invoke commands as normal; the CLI will route requests through the proxy.
256
+
257
+ ### Using Built-in Workspace Tools
258
+
259
+ You can call tools programmatically via HTTP:
260
+
261
+ ```bash
262
+ curl http://localhost:8080/v1/messages \
263
+ -H 'Content-Type: application/json' \
264
+ -H 'x-session-id: manual-test' \
265
+ -d '{
266
+ "model": "claude-proxy",
267
+ "messages": [{ "role": "user", "content": "Rebuild the workspace index." }],
268
+ "tools": [{
269
+ "name": "workspace_index_rebuild",
270
+ "type": "function",
271
+ "description": "Rebuild the repo index and project summary",
272
+ "input_schema": { "type": "object" }
273
+ }],
274
+ "tool_choice": {
275
+ "type": "function",
276
+ "function": { "name": "workspace_index_rebuild" }
277
+ }
278
+ }'
279
+ ```
280
+
281
+ Tool responses appear in the assistant content block with structured JSON.
282
+
283
+ ### Working with Prompt Caching
284
+
285
+ - Set `PROMPT_CACHE_ENABLED=true` (default) to activate the cache.
286
+ - The cache retains up to `PROMPT_CACHE_MAX_ENTRIES` entries for `PROMPT_CACHE_TTL_MS` milliseconds.
287
+ - A cache hit skips the Databricks call; response metadata populates `cache_read_input_tokens`.
288
+ - Cache misses record `cache_creation_input_tokens`, indicating a fresh prompt was cached.
289
+ - Cache entries are invalidated automatically when they age out; no manual maintenance required.
290
+ - Disable caching temporarily by exporting `PROMPT_CACHE_ENABLED=false` and restarting the server.
291
+
292
+ ### Integrating MCP Servers
293
+
294
+ 1. Place MCP manifest JSON files under `~/.claude/mcp` or configure `MCP_MANIFEST_DIRS`.
295
+ 2. Each manifest should define the server command, arguments, and capabilities per the MCP spec.
296
+ 3. Restart the proxy; manifests are loaded at boot. Registered tools appear with names `mcp_<server>_<tool>`.
297
+ 4. Invoke tools via `workspace_mcp_call` or indirectly when the assistant selects them.
298
+ 5. Sandbox settings (`MCP_SANDBOX_*`) control Docker runtime, mounts, environment passthrough, and permission prompts.
299
+
300
+ ### Running with Docker
301
+
302
+ A `Dockerfile` and `docker-compose.yml` are included for reproducible deployments.
303
+
304
+ #### Build & run with Docker Compose
305
+
306
+ ```bash
307
+ cp .env.example .env # populate with Databricks/Azure credentials, workspace path, etc.
308
+ docker compose up --build
309
+ ```
310
+
311
+ The compose file exposes:
312
+
313
+ - Proxy HTTP API on `8080`
314
+ - Optional SearxNG instance on `8888` (started automatically when `WEB_SEARCH_ENDPOINT` is the default)
315
+
316
+ Workspace files are mounted into the container (`./:/workspace`), and `./data` is persisted for SQLite state.
317
+
318
+ #### Manual Docker build
319
+
320
+ ```bash
321
+ docker build -t claude-code-proxy .
322
+ docker run --rm -p 8080:8080 -p 8888:8888 \
323
+ -v "$(pwd)":/workspace \
324
+ -v "$(pwd)/data":/app/data \
325
+ --env-file .env \
326
+ claude-code-proxy
327
+ ```
328
+
329
+ Adjust port and volume mappings to suit your environment. Ensure the container has access to the target workspace and required credentials.
330
+
331
+ ### Provider-specific behaviour
332
+
333
+ - **Databricks** – Mirrors Anthropic’s hosted behaviour. Automatic policy web fallbacks (`needsWebFallback`) can trigger an extra `web_fetch`, and the upstream service executes dynamic pages on your behalf.
334
+ - **Azure Anthropic** – Requests are normalised to Azure’s payload shape. The proxy disables automatic `web_fetch` fallbacks to avoid duplicate tool executions; instead, the assistant surfaces a diagnostic message and you can trigger the tool manually if required.
335
+ - In both cases, `web_search` and `web_fetch` run locally. They do not execute JavaScript, so pages that render data client-side (Google Finance, etc.) will return scaffolding only. Prefer JSON/CSV quote APIs (e.g. Yahoo chart API) when you need live financial data.
336
+
337
+ ---
338
+
339
+ ## Manual Test Matrix
340
+
341
+ | Area | Scenario | Steps | Expected Outcome |
342
+ |------|----------|-------|------------------|
343
+ | **Indexing & Repo Intelligence** | Rebuild index | 1. `workspace_index_rebuild` 2. Inspect `CLAUDE.md` 3. Run `workspace_symbol_search` | CLAUDE.md and symbol catalog reflect current repo state. |
344
+ | | Remove file & reindex | 1. Delete a tracked file 2. Rebuild index 3. Search for removed symbol | Symbol search returns no hits; CLAUDE.md drops the file from language counts. |
345
+ | **Language Navigation** | Cross-file definition | 1. Choose TS symbol defined/imported across files 2. Search for symbol 3. Get references | Definition points to source file; references list usages in other files only. |
346
+ | | Unsupported language fallback | 1. Use Ruby file with unique method 2. Symbol search and references | Heuristic matches return without crashing. |
347
+ | **Project Summary** | After tests | 1. Run `workspace_index_rebuild` 2. Call `project_summary` | Summary includes latest test stats and style hints (e.g., ESLint). |
348
+ | | Missing coverage files | 1. Move coverage JSON 2. Call `project_summary` | Response notes missing coverage gracefully. |
349
+ | **Task Tracker** | CRUD flow | 1. `workspace_task_create` 2. `workspace_tasks_list` 3. `workspace_task_update` 4. `workspace_task_set_status` 5. `workspace_task_delete` | Tasks persist across calls; deletion removes entry. |
350
+ | **Git Guards** | Push policy | 1. `POLICY_GIT_ALLOW_PUSH=false` 2. `workspace_git_push` | Request denied with policy message. |
351
+ | | Require tests before commit | 1. `POLICY_GIT_REQUIRE_TESTS=true` 2. Attempt commit without running tests | Commit blocked until tests executed. |
352
+ | **Prompt Cache** | Cache hit | 1. Send identical prompt twice 2. Check logs | Second response logs cache hit; response usage shows `cache_read_input_tokens`. |
353
+ | **MCP** | Manifest discovery | 1. Add manifest 2. Restart proxy 3. Call `workspace_mcp_call` | MCP tools execute via JSON-RPC bridge. |
354
+
355
+ ---
356
+
357
+ ## Troubleshooting
358
+
359
+ - **`path must be a non-empty string` errors** – Tool calls like `fs_read` require explicit paths. Verify the CLI sent a valid `path` argument.
360
+ - **Agent loop exceeding limits** – Increase `POLICY_MAX_STEPS` or fix misbehaving tool that loops.
361
+ - **`spawn npm test ENOENT`** – Configure `WORKSPACE_TEST_COMMAND` or ensure `npm test` exists in the workspace.
362
+ - **MCP server not discovered** – Confirm manifests live inside `MCP_MANIFEST_DIRS` and contain executable commands. Check logs for discovery errors.
363
+ - **Prompt cache not activating** – Ensure `PROMPT_CACHE_ENABLED=true`. Cache only stores tool-free completions; tool use requests bypass caching by design.
364
+ - **Claude CLI prompts for missing tools** – Verify `tools` array in the client request lists the functions you expect. The proxy only exposes registered handlers.
365
+ - **Dynamic finance pages return stale data** – `web_fetch` fetches static HTML only. Use an API endpoint (e.g. Yahoo Finance chart JSON) or the Databricks-hosted tooling if you need rendered values from heavily scripted pages.
366
+
367
+ ---
368
+
369
+ ## Roadmap & Known Gaps
370
+
371
+ - **Per-file diff comments & conversation threading** – Planned to mirror Claude’s review UX.
372
+ - **Automated risk assessment tied to diffs** – Future enhancement leveraging test outcomes and static analysis.
373
+ - **Expanded language-server fidelity** – Currently Tree-sitter-based; deeper AST integration or LSP bridging is a future goal.
374
+ - **Claude Skills parity** – Skills are not reproduced; designing a safe, declarative skill layer is an open area.
375
+ - **Coverage dashboards & historical trends** – Test summary tracks latest runs but no long-term history yet.
376
+
377
+ ---
378
+
379
+ ## FAQ
380
+
381
+ **Q: Is this an exact drop-in replacement for Anthropic’s backend?**
382
+ A: No. It mimics key Claude Code CLI behaviors but is intentionally extensible; certain premium features (Claude Skills, hosted sandboxes) are out of scope.
383
+
384
+ **Q: How does the proxy compare with Anthropic’s hosted backend?**
385
+ A: Functionally they overlap on core workflows (chat, tool calls, repo ops), but differ in scope:
386
+
387
+ | Capability | Anthropic Hosted Backend | Claude Code Proxy |
388
+ |------------|-------------------------|-------------------|
389
+ | Claude models | Anthropic-operated Sonnet/Opus | Adapters for Databricks (default) and Azure Anthropic |
390
+ | Prompt cache | Managed, opaque | Local LRU cache with configurable TTL/size |
391
+ | Git & workspace tools | Anthropic-managed hooks | Local Node handlers (`src/tools/`) with policy gate |
392
+ | Web search/fetch | Hosted browsing agent, JS-capable | Local HTTP fetch (no JS) plus optional policy fallback |
393
+ | MCP orchestration | Anthropic-managed sandbox | Local MCP discovery, optional Docker sandbox |
394
+ | Secure sandboxes | Anthropic-provided remote sandboxes | Optional Docker runtime; full access if disabled |
395
+ | Claude Skills / workflows | Available in hosted product | Not implemented (future roadmap) |
396
+ | Support & SLAs | Anthropic-run service | Self-hosted; you own uptime, auth, logging |
397
+ | Cost & scaling | Usage-billed API | Whatever infra you deploy (Node + dependencies) |
398
+
399
+ The proxy is ideal when you need local control, custom tooling, or non-Anthropic model endpoints. If you require fully managed browsing, secure sandboxes, or enterprise SLA, stick with the hosted backend.
400
+
401
+ **Q: Does prompt caching work like Anthropic’s cache?**
402
+ A: Functionally similar. Identical messages (model, messages, tools, sampling params) reuse cached responses until TTL expires. Tool-invoking turns skip caching.
403
+
404
+ **Q: Can I connect multiple MCP servers?**
405
+ A: Yes. Place multiple manifests in `MCP_MANIFEST_DIRS`. Each server is launched and its tools are namespaced.
406
+
407
+ **Q: How do I change the workspace root?**
408
+ A: Set `WORKSPACE_ROOT` before starting the proxy. The indexer and filesystem tools operate relative to that path.
409
+
410
+ **Q: Where are session transcripts stored?**
411
+ A: In SQLite at `data/sessions.db` (configurable via `SESSION_DB_PATH`).
412
+
413
+ ---
414
+
415
+ ## License
416
+
417
+ MIT License. See [LICENSE](LICENSE) for details.
package/bin/cli.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ require("../index.js");
package/index.js ADDED
@@ -0,0 +1,3 @@
1
+ const { start } = require("./src/server");
2
+
3
+ start();
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "lynkr",
3
+ "version": "0.1.0",
4
+ "description": "Self-hosted Claude Code proxy with Databricks and Azure Anthropic adapters, workspace tooling, and MCP integration.",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "lynkr": "./bin/cli.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node index.js",
11
+ "dev": "nodemon index.js",
12
+ "lint": "eslint src index.js",
13
+ "test": "echo \"No automated tests configured\" && exit 0"
14
+ },
15
+ "keywords": [
16
+ "claude",
17
+ "anthropic",
18
+ "proxy",
19
+ "databricks",
20
+ "azure",
21
+ "mcp"
22
+ ],
23
+ "author": "Vishal Veera Reddy",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/vishalveerareddy123/Lynkr.git"
28
+ },
29
+ "bugs": {
30
+ "url": "https://github.com/vishalveerareddy123/Lynkr/issues"
31
+ },
32
+ "homepage": "https://github.com/vishalveerareddy123/Lynkr#readme",
33
+ "engines": {
34
+ "node": ">=18.0.0"
35
+ },
36
+ "dependencies": {
37
+ "better-sqlite3": "^9.4.0",
38
+ "diff": "^5.2.0",
39
+ "dotenv": "^16.4.5",
40
+ "express": "^5.1.0",
41
+ "fast-glob": "^3.3.2",
42
+ "pino": "^8.17.2",
43
+ "pino-http": "^8.6.0",
44
+ "tree-sitter": "^0.20.1",
45
+ "tree-sitter-javascript": "^0.20.3",
46
+ "tree-sitter-python": "^0.20.1",
47
+ "tree-sitter-typescript": "^0.20.3"
48
+ },
49
+ "devDependencies": {
50
+ "eslint": "^8.57.0",
51
+ "nodemon": "^3.1.0",
52
+ "pino-pretty": "^10.2.0"
53
+ }
54
+ }
@@ -0,0 +1,37 @@
1
+ const pinoHttp = require("pino-http");
2
+ const logger = require("../../logger");
3
+
4
+ function maskHeaders(headers = {}) {
5
+ const clone = { ...headers };
6
+ if (typeof clone["x-api-key"] === "string") {
7
+ clone["x-api-key"] = "***redacted***";
8
+ }
9
+ if (typeof clone["x-anthropic-api-key"] === "string") {
10
+ clone["x-anthropic-api-key"] = "***redacted***";
11
+ }
12
+ return clone;
13
+ }
14
+
15
+ const loggingMiddleware = pinoHttp({
16
+ logger,
17
+ customProps: (req) => ({
18
+ sessionId: req.sessionId ?? null,
19
+ }),
20
+ customLogLevel: (req, res, err) => {
21
+ if (err || res.statusCode >= 500) return "error";
22
+ if (res.statusCode >= 400) return "warn";
23
+ return "info";
24
+ },
25
+ wrapSerializers: true,
26
+ serializers: {
27
+ req(req) {
28
+ return {
29
+ method: req.method,
30
+ url: req.url,
31
+ headers: maskHeaders(req.headers),
32
+ };
33
+ },
34
+ },
35
+ });
36
+
37
+ module.exports = loggingMiddleware;
@@ -0,0 +1,55 @@
1
+ const crypto = require("crypto");
2
+ const { getOrCreateSession } = require("../../sessions/store");
3
+
4
+ const PRIMARY_HEADER = "x-session-id";
5
+ const FALLBACK_HEADERS = [
6
+ "x-claude-session-id",
7
+ "x-claude-session",
8
+ "x-claude-conversation-id",
9
+ "anthropic-session-id",
10
+ ];
11
+
12
+ function normaliseSessionId(value) {
13
+ if (typeof value !== "string") return null;
14
+ const trimmed = value.trim();
15
+ return trimmed.length ? trimmed : null;
16
+ }
17
+
18
+ function extractSessionId(req) {
19
+ const primary = normaliseSessionId(req.headers[PRIMARY_HEADER]);
20
+ if (primary) return primary;
21
+
22
+ for (const header of FALLBACK_HEADERS) {
23
+ const candidate = normaliseSessionId(req.headers[header]);
24
+ if (candidate) return candidate;
25
+ }
26
+
27
+ const body = req.body ?? {};
28
+ const bodyId =
29
+ normaliseSessionId(body.session_id) ??
30
+ normaliseSessionId(body.sessionId) ??
31
+ normaliseSessionId(body.conversation_id);
32
+ if (bodyId) return bodyId;
33
+
34
+ const generated = crypto.randomUUID();
35
+ req.generatedSessionId = true;
36
+ return generated;
37
+ }
38
+
39
+ function sessionMiddleware(req, res, next) {
40
+ try {
41
+ const sessionId = extractSessionId(req);
42
+ req.sessionId = sessionId;
43
+
44
+ const session = getOrCreateSession(sessionId);
45
+ req.session = session;
46
+ return next();
47
+ } catch (err) {
48
+ return next(err);
49
+ }
50
+ }
51
+
52
+ module.exports = {
53
+ sessionMiddleware,
54
+ SESSION_HEADER: PRIMARY_HEADER,
55
+ };