purecontext-mcp 1.5.0 → 1.5.2

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.
@@ -1,26 +1,31 @@
1
- # Language Support
1
+ # Language Support — Reference
2
2
 
3
+ This is the reference page: the per-language symbol-kind table and grammar notes.
3
4
 
4
- PureContext supports **34 languages** via tree-sitter WASM grammars. All grammars are bundled in the `grammars/` directory no separate install needed.
5
+ For the **user-friendly tour** category groupings, framework integration notes, "Adding a new language" guidesee [`LANGUAGE-SUPPORT.md`](../LANGUAGE-SUPPORT.md) at the project root.
5
6
 
6
7
  ---
7
8
 
8
- ## Supported languages
9
+ PureContext supports **34 languages** via tree-sitter WASM grammars plus four regex-based handlers for CSS-family languages. All grammars are bundled in `grammars/` — no separate install needed.
9
10
 
10
- | Language | Extensions | Symbol Types | Doc Comments |
11
+ ---
12
+
13
+ ## Symbol-kind matrix (tree-sitter handlers)
14
+
15
+ | Language | Extensions | Symbol Kinds | Doc Comments |
11
16
  |----------|-----------|--------------|--------------|
12
17
  | TypeScript | `.ts`, `.tsx`, `.mts`, `.cts` | function, class, method, const, type, interface, enum | JSDoc `/** */` |
13
18
  | JavaScript | `.js`, `.jsx`, `.mjs`, `.cjs` | function, class, method, const | JSDoc `/** */` |
14
- | Python | `.py` | function, class, method, const | Docstrings `"""` |
19
+ | Python | `.py` | function, class, method, const | `"""` docstrings |
15
20
  | Go | `.go` | function, method, class (struct), interface, const, type | `//` preceding comments |
16
21
  | Rust | `.rs` | function, method, class (struct), enum, interface (trait), const, type | `///` doc comments |
17
22
  | Java | `.java` | class, interface, enum, method, const | Javadoc `/** */` |
18
23
  | C# | `.cs` | class, interface, enum, struct, record, method, const, property | XML docs `/// <summary>` |
19
- | PHP | `.php` | function, class, interface, trait, enum, method, const | PHPDoc `/** */` |
20
- | Ruby | `.rb` | function, class, method, module, const | `#` comments |
21
- | Kotlin | `.kt`, `.kts` | function, class, interface, enum, method, typealias, object | KDoc `/**` |
24
+ | PHP | `.php` | function, class, interface, trait, enum, method, const, property | PHPDoc `/** */` |
25
+ | Ruby | `.rb` | function, class, method, module, const, property (DSL macros) | `#` comments |
26
+ | Kotlin | `.kt`, `.kts` | function, class, interface, enum, method, typealias, object, property | KDoc `/**` |
22
27
  | C | `.c`, `.h` | function, struct, enum, macro, type | `//` and `/* */` |
23
- | C++ | `.cpp`, `.cxx`, `.cc`, `.hpp`, `.hxx`, `.hh` | All C types + namespace, template | `///` Doxygen |
28
+ | C++ | `.cpp`, `.cxx`, `.cc`, `.hpp`, `.hxx`, `.hh` | All C kinds + namespace, template, template-class | `///` Doxygen |
24
29
  | Lua | `.lua` | function, method, const | `--` comments |
25
30
  | Dart | `.dart` | class, mixin, extension, enum, function, method, const, type | `///` doc comments |
26
31
  | Swift | `.swift` | class, struct, protocol, actor, extension, method, enum, type | `///` DocC |
@@ -28,61 +33,79 @@ PureContext supports **34 languages** via tree-sitter WASM grammars. All grammar
28
33
  | Haskell | `.hs`, `.lhs` | function, data (class), typeclass (interface), instance, type, newtype | Haddock `-- \|` |
29
34
  | Scala | `.scala`, `.sc` | class, trait, object, case class, function, method, type, enum | Scaladoc `/** */` |
30
35
  | R | `.r`, `.R`, `.Rmd` | function, const, S3/S4/R6 class | Roxygen2 `#'` |
31
- | Bash | `.sh`, `.bash` | function |
32
- | Perl | `.pl`, `.pm` | function, package |
33
- | Terraform / HCL | `.tf`, `.hcl` | resource, module, variable, output |
34
- | Nix | `.nix` | function, attribute |
35
- | Protobuf | `.proto` | message, service, enum, rpc |
36
- | GraphQL | `.graphql`, `.gql` | type, query, mutation, subscription, fragment |
37
- | Groovy | `.groovy` | function, class, method |
38
- | Erlang | `.erl`, `.hrl` | function, module |
39
- | Gleam | `.gleam` | function, type |
40
- | GDScript | `.gd` | function, class, signal |
41
- | XML | `.xml` | element (configurable patterns) |
42
- | Objective-C | `.m`, `.h` | function, class, method |
43
- | Fortran | `.f90`, `.f95`, `.for`, `.f` | function, subroutine, module |
44
- | SQL | `.sql` | table, view, function, procedure |
45
- | OpenAPI / YAML | `.yaml`, `.yml` (OpenAPI detected by content) | endpoint, schema |
36
+ | Bash | `.sh`, `.bash`, extensionless (shebang-detected) | function | — |
37
+ | Perl | `.pl`, `.pm` | function, package | — |
38
+ | Groovy | `.groovy` | function, class, method | |
39
+ | Erlang | `.erl`, `.hrl` | function (bare name; arity in `frameworkMeta`), module | — |
40
+ | Gleam | `.gleam` | function, type | |
41
+ | GDScript | `.gd` | function, class, signal | |
42
+ | Objective-C | `.m`, `.h` (guarded) | function, class, protocol, method (full selector), property, category | — |
43
+ | Fortran | `.f90`, `.f95`, `.for`, `.f`, `.F90` (case-insensitive) | function, subroutine, module | — |
44
+ | Terraform / HCL | `.tf`, `.tfvars`, `.hcl` | variable, output, resource, data, module, provider, locals | — |
45
+ | Nix | `.nix` | function, attribute | |
46
+ | SQL | `.sql` | table, view, function, procedure | — |
47
+ | Protobuf | `.proto` | message, service, enum, rpc | — |
48
+ | GraphQL | `.graphql`, `.gql` | type, query, mutation, subscription, fragment | — |
49
+ | OpenAPI / YAML | `.yaml`, `.yml` (content-detected) | endpoint, schema | |
50
+ | XML | `.xml` | element (disambiguated as `tag@module` in multi-module repos) | |
51
+ | Angular HTML | `.html` (guarded) | component selector, structural directive, control flow, event binding, template ref | — |
46
52
 
47
53
  ---
48
54
 
49
- ## What gets indexed
55
+ ## Symbol-kind matrix (regex handlers, no WASM grammar)
50
56
 
51
- For all languages, the indexer extracts:
57
+ | Language | Extensions | Symbol Kinds |
58
+ |----------|-----------|--------------|
59
+ | SCSS / SASS | `.scss`, `.sass` | `@mixin` → function, `@function` → function, top-level `$var` → const, `%placeholder` → class, `@keyframes` → type |
60
+ | LESS | `.less` | `.mixin(@params)` → function, top-level `@var` → const, `@keyframes` → type |
61
+ | CSS | `.css` | `--custom-property` → const (opt-in via `indexing.cssVariables: true`) |
52
62
 
53
- - **Symbol name**the identifier as it appears in source
54
- - **Symbol kind** — function, class, method, route, component, etc.
55
- - **Byte offsets** (`startByte`, `endByte`) — for precise source retrieval without reading the whole file
56
- - **Signature** — a one-line declaration (TypeScript shows full type annotations, Python shows type hints if present)
57
- - **Summary** — sourced from docstring, framework inference, AI, or signature fallback
58
- - **Import/dependency edges** — for the dependency graph
63
+ CSS-family languages don't have a stable tree-sitter grammar, so PureContext uses targeted regex extraction. Only named, reusable constructs are indexed plain selectors would flood the index with noise.
59
64
 
60
65
  ---
61
66
 
62
- ## What is excluded automatically
67
+ ## Visibility filtering
63
68
 
64
- The indexer skips these automatically:
69
+ | Language | What is excluded |
70
+ |----------|------------------|
71
+ | Go | Unexported identifiers (lowercase first letter) |
72
+ | C | `static` functions (translation-unit internal) |
73
+ | Java | `private` members |
74
+ | C# | `private` members; interface members are implicitly public |
75
+ | PHP | `private` members |
76
+ | Dart | `_`-prefixed identifiers |
77
+ | Rust | Non-`pub` impl methods |
65
78
 
66
- - `node_modules/`, `.git/`, `dist/`, `build/`, `.claude/`, `target/`, `.next/`, `.nuxt/`
67
- - `*.lock` files, `.env*` files
68
- - Binary files (detected by null-byte scanning of the first 8 KB)
69
- - Files > 1 MB (configurable via `maxFileSizeBytes`)
70
- - Secret files: `*.pem`, `*.key`, `id_rsa`, `credentials.json`, `serviceAccountKey*.json`, etc.
71
- - Language-specific private symbols:
72
- - Go: unexported names (lowercase)
73
- - C: `static` functions (translation-unit internal)
74
- - Java/C#/PHP: `private` members
75
- - Dart: `_`-prefixed names
79
+ `get_public_api` and related tools depend on these rules being applied consistently.
76
80
 
77
81
  ---
78
82
 
79
- ## Grammar notes
83
+ ## File-system exclusions
84
+
85
+ Applied before any handler runs:
86
+
87
+ - Directories: `node_modules/`, `.git/`, `dist/`, `build/`, `target/`, `.next/`, `.nuxt/`, `.claude/`
88
+ - Lock files (`*.lock`), env files (`.env*`)
89
+ - Binary files (null-byte scan of first 8 KB; no hardcoded extension list)
90
+ - Files larger than 1 MB (override via `indexing.maxFileSizeBytes`)
91
+ - Secret patterns: `*.pem`, `*.key`, `id_rsa`, `credentials.json`, `serviceAccountKey*.json`
80
92
 
81
- Grammars are bundled as `.wasm` files in the `grammars/` directory. They are loaded once per worker thread at startup. Grammar versions are pinned in `package.json` and tested against the test fixtures in `test/handlers/`.
93
+ ---
94
+
95
+ ## Grammar notes and known limitations
82
96
 
83
- Known limitations:
84
- - **TypeScript JSX** (`.tsx`): the `tree-sitter-tsx` grammar is separate from `tree-sitter-typescript` and is used for all `.tsx` files.
85
- - **Python**: type hints in stubs (`.pyi`) are not indexed only `.py` files.
97
+ - **TypeScript JSX** (`.tsx`) uses `tree-sitter-tsx`, a separate grammar from `tree-sitter-typescript`. Both are bundled.
98
+ - **Python stubs** (`.pyi`) are not indexed only `.py` files.
99
+ - **Objective-C** `.h` files are guarded: parsed as ObjC only if the first 16 KB contain `@interface` or `@protocol`; otherwise treated as C.
100
+ - **Angular HTML** `.html` files are guarded: parsed as Angular templates only if a sibling `.component.ts` exists or the first 4 KB contain Angular markers.
86
101
  - **Terraform**: complex `dynamic` blocks may not be fully extracted.
87
- - **XML**: element extraction uses configurable patterns not all XML files are indexed by default.
102
+ - **XML**: element extraction uses configurable patterns; not every tag is indexed by default. Root-element symbols are stored as `tag@module` in multi-module repos to avoid collisions.
103
+ - **OpenAPI**: schema-name extraction supports hyphens (`[\w-]+`), so GitHub-style schemas like `pull-request` are indexed.
104
+
105
+ ---
106
+
107
+ ## Related reference
88
108
 
109
+ - [Framework Adapters](08-framework-adapters.md) — adapter layer that adds framework-specific symbols on top of these handlers
110
+ - [Configuration](04-configuration.md) — `indexing.*` flags including `cssVariables`, `maxFileSizeBytes`, `xmlElementPatterns`
111
+ - [Architecture Overview](25-architecture-overview.md) — three-layer design (Core → Handlers → Adapters)
@@ -1,9 +1,14 @@
1
- # Framework Adapters
1
+ # Framework Adapters — Reference
2
2
 
3
+ This is the reference page: detection criteria, extracted symbol kinds, and `frameworkMeta` shape for every adapter.
4
+
5
+ For the **user-friendly tour** — how adapters change what you see in search results, with examples and "useful for" notes — see [`FRAMEWORK-ADAPTERS.md`](../FRAMEWORK-ADAPTERS.md) at the project root.
6
+
7
+ ---
3
8
 
4
9
  Framework adapters layer domain-specific symbol extraction on top of language handlers. They are auto-detected from project config files.
5
10
 
6
- ## How adapters work
11
+ ## The `FrameworkAdapter` interface
7
12
 
8
13
  Each adapter implements the `FrameworkAdapter` interface:
9
14
 
@@ -1,209 +1,56 @@
1
- # Team Setup & Multi-Tenant
1
+ # Team Setup & Multi-Tenant — Reference
2
2
 
3
+ This is the reference page: API key permissions, rate-limit configuration, admin API endpoints, and the production hardening checklist.
3
4
 
4
- Run PureContext as a shared server so your whole team queries the same index no per-developer re-indexing.
5
+ For the **user-friendly walkthrough** — why a shared server matters, deployment options, end-to-end setup with examplessee [`TEAM-SETUP.md`](../TEAM-SETUP.md) at the project root.
5
6
 
6
7
  ---
7
8
 
8
- ## Overview
9
+ ## Workspace and key model
9
10
 
10
- ```
11
- Local mode: Server mode (shared):
12
- Claude Code (each dev) Claude Code (each dev)
13
- stdio ↓ HTTP + API key
14
- PureContext (local) PureContext (shared server)
15
- ↓ ↓
16
- Local SQLite index Shared SQLite index(es)
17
- ```
18
-
19
- **Why a shared server?** Each developer re-indexes the same codebase independently in local mode. A shared server indexes once and serves all team members — consistent results and no redundant work.
11
+ | Concept | Description |
12
+ |---------|-------------|
13
+ | Workspace | The unit of isolation. One team = one workspace. All repos and keys belong to a workspace. |
14
+ | API key | A per-developer credential. Shown once on creation and never displayed again. Stored as a SHA-256 hash. |
15
+ | Admin key | A long-lived secret (`PCTX_ADMIN_KEY`) that authenticates workspace and key management calls. Set via env var only. |
20
16
 
21
17
  ---
22
18
 
23
- ## Step 1 — Deploy the server
24
-
25
- ### Docker (recommended)
26
-
27
- ```bash
28
- mkdir -p ./purecontext-data
29
-
30
- docker run -d \
31
- --name purecontext \
32
- -p 3000:3000 \
33
- -v "$(pwd)/purecontext-data:/data" \
34
- -e PCTX_ADMIN_KEY="$(openssl rand -hex 32)" \
35
- --restart unless-stopped \
36
- purecontext/purecontext-mcp:latest
37
- ```
38
-
39
- Note your `PCTX_ADMIN_KEY` — you need it to manage workspaces and keys.
40
-
41
- ### Docker Compose
42
-
43
- ```yaml
44
- version: '3.8'
45
- services:
46
- purecontext:
47
- image: purecontext/purecontext-mcp:latest
48
- ports:
49
- - "3000:3000"
50
- volumes:
51
- - ./data:/data
52
- environment:
53
- PCTX_ADMIN_KEY: "change-me-before-deploying"
54
- restart: unless-stopped
55
- ```
56
-
57
- ```bash
58
- docker compose up -d
59
- ```
60
-
61
- ### npm (no Docker)
62
-
63
- ```bash
64
- npm install -g purecontext-mcp
65
- PCTX_ADMIN_KEY=your-secret purecontext-mcp --server --host 0.0.0.0 --port 3000
66
- ```
67
-
68
- ### Verify the server is running
69
-
70
- ```bash
71
- curl http://localhost:3000/health
72
- # {"status":"ok","version":"1.x.x","repoCount":0}
73
- ```
74
-
75
- ---
76
-
77
- ## Step 2 — Create a workspace
78
-
79
- A workspace is the unit of isolation — one team = one workspace. All repos and API keys belong to a workspace.
80
-
81
- ```bash
82
- export ADMIN_KEY="your-pctx-admin-key"
83
- export SERVER="http://localhost:3000"
84
-
85
- curl -s -X POST "$SERVER/admin/workspaces" \
86
- -H "Authorization: Bearer $ADMIN_KEY" \
87
- -H "Content-Type: application/json" \
88
- -d '{"name": "my-team", "plan": "team"}' | jq .
89
- ```
90
-
91
- Response:
92
-
93
- ```json
94
- {"id": "ws_abc123", "name": "my-team", "plan": "team", "created_at": 1714000000}
95
- ```
96
-
97
- Save the `id` — you'll use it when creating API keys.
98
-
99
- ---
100
-
101
- ## Step 3 — Create API keys
102
-
103
- Each developer gets their own API key. Keys are shown once on creation and never again.
104
-
105
- ```bash
106
- curl -s -X POST "$SERVER/admin/keys" \
107
- -H "Authorization: Bearer $ADMIN_KEY" \
108
- -H "Content-Type: application/json" \
109
- -d '{
110
- "label": "alice-macbook",
111
- "permissions": ["read", "write"],
112
- "workspace_id": "ws_abc123"
113
- }' | jq .
114
- ```
115
-
116
- **Response (key shown only once):**
117
-
118
- ```json
119
- {
120
- "key": "pctx_00000000_..._1234",
121
- "label": "alice-macbook",
122
- "permissions": ["read", "write"],
123
- "key_hash_prefix": "deadbeef"
124
- }
125
- ```
126
-
127
- ### Permission levels
19
+ ## Permission levels
128
20
 
129
21
  | Permission | Allowed operations |
130
- |------------|-------------------|
131
- | `read` | Search symbols, get outlines, get source |
132
- | `write` | + `index_folder`, `index_repo` |
22
+ |------------|--------------------|
23
+ | `read` | Search symbols, get outlines, fetch source |
24
+ | `write` | + `index_folder`, `index_repo`, `invalidate_cache` |
133
25
  | `admin` | + Manage keys and workspaces |
134
26
 
135
- For AI agents that only query (not index), use `read` permission. For CI pipelines that re-index on push, use `write`.
27
+ For AI agents that only query, use `read`. For CI pipelines that re-index on push, use `write`. Never issue `admin` to a developer or agent — keep it on the admin key alone.
136
28
 
137
29
  ---
138
30
 
139
- ## Step 4 — Index the shared codebase
140
-
141
- Connect Claude Code (step 5) and ask it to index, or call the API directly:
142
-
143
- ```bash
144
- curl -s -X POST "$SERVER/mcp/sse" \
145
- -H "Authorization: Bearer pctx_yourwritekey" \
146
- -H "Content-Type: application/json" \
147
- -d '{
148
- "jsonrpc": "2.0",
149
- "method": "tools/call",
150
- "params": {"name": "index_folder", "arguments": {"path": "/path/to/repo"}},
151
- "id": 1
152
- }'
153
- ```
154
-
155
- ---
156
-
157
- ## Step 5 — Connect each developer
158
-
159
- Each developer runs this once:
160
-
161
- ```bash
162
- claude mcp add purecontext-remote \
163
- --transport http \
164
- --url https://purecontext.mycompany.com/mcp/sse \
165
- --header "Authorization: Bearer pctx_yourpersonalkey"
166
- ```
167
-
168
- After adding, verify in Claude Code:
169
-
170
- ```
171
- /mcp
172
- # Should show purecontext-remote as connected
173
-
174
- List my indexed repositories using list_repos
175
- ```
176
-
177
- ---
178
-
179
- ## Step 6 — Manage keys over time
180
-
181
- ```bash
182
- # List all keys (shows label, prefix, permissions — never the raw key)
183
- curl -s "$SERVER/admin/keys" -H "Authorization: Bearer $ADMIN_KEY" | jq .
184
-
185
- # Revoke a key (e.g., when someone leaves the team)
186
- curl -s -X DELETE "$SERVER/admin/keys/deadbeef" \
187
- -H "Authorization: Bearer $ADMIN_KEY"
188
-
189
- # Check key usage stats
190
- curl -s "$SERVER/admin/keys/deadbeef/usage" \
191
- -H "Authorization: Bearer $ADMIN_KEY" | jq .
192
- ```
31
+ ## Rate limiting
193
32
 
194
- ---
33
+ HTTP mode uses a token-bucket per API key.
195
34
 
196
- ## Rate limiting
35
+ | Field | Default | Description |
36
+ |-------|--------:|-------------|
37
+ | `rateLimit.enabled` | `true` | Disable to allow unbounded usage (single-tenant only) |
38
+ | `rateLimit.maxTokens` | `100` | Bucket capacity per key |
39
+ | `rateLimit.refillRate` | `10` | Tokens added per second |
40
+ | `rateLimit.perToolLimits.<tool>` | varies | Per-tool cost override |
197
41
 
198
- HTTP mode uses a token-bucket algorithm to prevent any single client from overwhelming the server:
42
+ Default per-tool costs:
199
43
 
200
- - Each key gets a bucket with capacity `rateLimit.maxTokens` (default: 100)
201
- - Tokens refill at `rateLimit.refillRate` per second (default: 10)
202
- - Expensive tools (e.g., `index_folder`) cost more tokens
44
+ | Tool | Cost |
45
+ |------|-----:|
46
+ | `search_symbols`, `search_text`, `search_semantic` | 1 |
47
+ | `get_symbol_source`, `get_file_outline`, `get_context_bundle` | 1 |
48
+ | `index_folder`, `index_repo` | 10 |
49
+ | `health_radar`, `get_debt_report`, `detect_antipatterns` | 5 |
203
50
 
204
- When rate limited, responses return `429 Too Many Requests` with a `Retry-After` header.
51
+ When a bucket empties, the server returns `429 Too Many Requests` with a `Retry-After` header.
205
52
 
206
- Configure per-tool costs in `config.json`:
53
+ Example config:
207
54
 
208
55
  ```json
209
56
  {
@@ -223,29 +70,52 @@ Configure per-tool costs in `config.json`:
223
70
 
224
71
  ## Admin API reference
225
72
 
226
- All endpoints require `Authorization: Bearer <PCTX_ADMIN_KEY>`.
73
+ All endpoints require `Authorization: Bearer <PCTX_ADMIN_KEY>`. Base URL: the server's bind address (default `http://localhost:3000`).
227
74
 
228
75
  | Endpoint | Method | Description |
229
76
  |----------|--------|-------------|
230
- | `/admin/workspaces` | `POST` | Create workspace |
231
- | `/admin/workspaces` | `GET` | List workspaces |
232
- | `/admin/workspaces/:id` | `DELETE` | Delete workspace and all data |
233
- | `/admin/keys` | `POST` | Create API key |
234
- | `/admin/keys` | `GET` | List keys |
235
- | `/admin/keys/:prefix` | `DELETE` | Revoke key |
236
- | `/admin/keys/:prefix/usage` | `GET` | Key usage stats |
237
- | `/admin/stats` | `GET` | Server-wide statistics |
77
+ | `/admin/workspaces` | `POST` | Create workspace. Body: `{name, plan}`. Returns `{id, name, plan, created_at}`. |
78
+ | `/admin/workspaces` | `GET` | List workspaces. |
79
+ | `/admin/workspaces/:id` | `DELETE` | Delete workspace and all data. |
80
+ | `/admin/keys` | `POST` | Create API key. Body: `{label, permissions[], workspace_id}`. **Raw key returned once.** |
81
+ | `/admin/keys` | `GET` | List keys (label + prefix + permissions; never raw key). |
82
+ | `/admin/keys/:prefix` | `DELETE` | Revoke key by hash prefix. |
83
+ | `/admin/keys/:prefix/usage` | `GET` | Per-key usage counters. |
84
+ | `/admin/stats` | `GET` | Server-wide statistics. |
85
+ | `/health` | `GET` | Public health check (no auth). Returns `{status, version, repoCount}`. |
238
86
 
239
87
  ---
240
88
 
241
- ## Production checklist
89
+ ## Server-mode environment variables
90
+
91
+ | Variable | Required | Description |
92
+ |----------|----------|-------------|
93
+ | `PCTX_ADMIN_KEY` | yes | Admin secret. Minimum 32 hex chars recommended. |
94
+ | `PCTX_DATA_DIR` | no | Override default `/data` (Docker) or `~/.purecontext` (npm). |
95
+ | `PCTX_BIND_HOST` | no | Default `0.0.0.0` in server mode. |
96
+ | `PCTX_BIND_PORT` | no | Default `3000`. |
97
+ | `PCTX_LOG_LEVEL` | no | `debug` / `info` / `warn` / `error`. |
98
+
99
+ CLI flags `--server`, `--host`, `--port` take precedence over env vars.
100
+
101
+ ---
242
102
 
243
- - [ ] `PCTX_ADMIN_KEY` is a long random secret (≥ 32 hex chars), set via env var only — never in a committed config file
103
+ ## Production hardening checklist
104
+
105
+ - [ ] `PCTX_ADMIN_KEY` is a ≥32-char random secret, set via env var only — never in a committed config file
244
106
  - [ ] Server is behind a reverse proxy (nginx, Caddy) with TLS
245
- - [ ] Port 3000 is not directly exposed to the internet (terminate TLS at the proxy)
246
- - [ ] `/data` volume is on a backed-up disk
247
- - [ ] `restart: unless-stopped` is set in docker-compose
248
- - [ ] Developers have `read` permission only unless they need to re-index
107
+ - [ ] Port 3000 is not directly exposed to the public internet (terminate TLS at the proxy)
108
+ - [ ] `/data` volume sits on a backed-up disk
109
+ - [ ] `restart: unless-stopped` set in docker-compose
110
+ - [ ] Developers have `read` permission only unless they specifically need to re-index
249
111
  - [ ] Admin key is rotated if ever exposed
112
+ - [ ] Rate limiting enabled and tuned for your team size
113
+
114
+ ---
115
+
116
+ ## Related reference
250
117
 
251
- See [Docker Deployment](16-docker.md) for full reverse proxy examples.
118
+ - [Transport Modes](14-transport-modes.md) stdio vs HTTP/SSE deep dive
119
+ - [Docker Deployment](16-docker.md) — container image, compose examples, reverse-proxy templates
120
+ - [Security](24-security.md) — threat model, API-key storage, path-traversal protections
121
+ - [Configuration](04-configuration.md) — full `config.json` schema