@harperfast/template-react-ts-studio 1.11.2 → 1.11.4

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 (54) hide show
  1. package/.agents/skills/harper-best-practices/AGENTS.md +702 -490
  2. package/.agents/skills/harper-best-practices/SKILL.md +1 -0
  3. package/.agents/skills/harper-best-practices/rules/automatic-apis.md +46 -78
  4. package/.agents/skills/harper-best-practices/rules/defining-relationships.md +41 -63
  5. package/.agents/skills/harper-best-practices/rules/delegating-to-the-built-in-agent.md +141 -0
  6. package/.agents/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +59 -45
  7. package/.agents/skills/harper-best-practices/rules/load-env.md +24 -23
  8. package/.agents/skills/harper-best-practices/rules/programmatic-table-requests.md +62 -78
  9. package/.agents/skills/harper-best-practices/rules/querying-rest-apis.md +92 -65
  10. package/.agents/skills/harper-best-practices/rules/schema-design-tooling.md +53 -55
  11. package/.agents/skills/harper-best-practices/rules/v5-upgrade.md +98 -62
  12. package/.agents/skills/harper-best-practices/rules/vector-indexing.md +113 -42
  13. package/.agents/skills/harper-best-practices/rules.manifest.yaml +9 -0
  14. package/.agents/skills/harper-mcp/AGENTS.md +501 -0
  15. package/.agents/skills/harper-mcp/SKILL.md +91 -0
  16. package/.agents/skills/harper-mcp/rules/automatic-verb-tools.md +50 -0
  17. package/.agents/skills/harper-mcp/rules/connecting-clients.md +59 -0
  18. package/.agents/skills/harper-mcp/rules/custom-mcp-prompts.md +52 -0
  19. package/.agents/skills/harper-mcp/rules/custom-mcp-resources.md +64 -0
  20. package/.agents/skills/harper-mcp/rules/custom-mcp-tools.md +72 -0
  21. package/.agents/skills/harper-mcp/rules/durable-quotas.md +73 -0
  22. package/.agents/skills/harper-mcp/rules/enabling-mcp.md +63 -0
  23. package/.agents/skills/harper-mcp/rules/rate-limiting.md +62 -0
  24. package/.agents/skills/harper-mcp/rules/resources-surface.md +44 -0
  25. package/.agents/skills/harper-mcp/rules/security-posture.md +36 -0
  26. package/.agents/skills/harper-mcp/rules.manifest.yaml +203 -0
  27. package/agent/skills/harper-best-practices/AGENTS.md +702 -490
  28. package/agent/skills/harper-best-practices/SKILL.md +1 -0
  29. package/agent/skills/harper-best-practices/rules/automatic-apis.md +46 -78
  30. package/agent/skills/harper-best-practices/rules/defining-relationships.md +41 -63
  31. package/agent/skills/harper-best-practices/rules/delegating-to-the-built-in-agent.md +141 -0
  32. package/agent/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +59 -45
  33. package/agent/skills/harper-best-practices/rules/load-env.md +24 -23
  34. package/agent/skills/harper-best-practices/rules/programmatic-table-requests.md +62 -78
  35. package/agent/skills/harper-best-practices/rules/querying-rest-apis.md +92 -65
  36. package/agent/skills/harper-best-practices/rules/schema-design-tooling.md +53 -55
  37. package/agent/skills/harper-best-practices/rules/v5-upgrade.md +98 -62
  38. package/agent/skills/harper-best-practices/rules/vector-indexing.md +113 -42
  39. package/agent/skills/harper-best-practices/rules.manifest.yaml +9 -0
  40. package/agent/skills/harper-mcp/AGENTS.md +501 -0
  41. package/agent/skills/harper-mcp/SKILL.md +83 -0
  42. package/agent/skills/harper-mcp/rules/automatic-verb-tools.md +50 -0
  43. package/agent/skills/harper-mcp/rules/connecting-clients.md +59 -0
  44. package/agent/skills/harper-mcp/rules/custom-mcp-prompts.md +52 -0
  45. package/agent/skills/harper-mcp/rules/custom-mcp-resources.md +64 -0
  46. package/agent/skills/harper-mcp/rules/custom-mcp-tools.md +72 -0
  47. package/agent/skills/harper-mcp/rules/durable-quotas.md +73 -0
  48. package/agent/skills/harper-mcp/rules/enabling-mcp.md +63 -0
  49. package/agent/skills/harper-mcp/rules/rate-limiting.md +62 -0
  50. package/agent/skills/harper-mcp/rules/resources-surface.md +44 -0
  51. package/agent/skills/harper-mcp/rules/security-posture.md +36 -0
  52. package/agent/skills/harper-mcp/rules.manifest.yaml +203 -0
  53. package/package.json +1 -1
  54. package/skills-lock.json +7 -1
@@ -7,101 +7,137 @@ metadata:
7
7
  mode: generate
8
8
  sources:
9
9
  - release-notes/v5-lincoln/v5-migration.md
10
- sourceCommit: de2aaf1c759a7ff5b93e862ba704153e2a392fcb
11
- inputHash: 80314689f3a7f42e
10
+ sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd
11
+ inputHash: 5ee6407370219136
12
12
  ---
13
13
 
14
- # Upgrading a Harper Application to v5
14
+ # v5 Upgrade: Breaking Changes and Migration Guide
15
15
 
16
- Instructions for the agent to follow when migrating an existing Harper application to version 5, addressing the breaking changes and adopting the recommended patterns.
16
+ Instructions for the agent to apply when migrating a Harper application to v5, covering all breaking changes and required code updates.
17
17
 
18
18
  ## When to Use
19
19
 
20
- Apply this rule when upgrading a Harper application from v4.x (or earlier) to v5, or when code written against older APIs behaves differently after a v5 upgrade — for example a record that can no longer be mutated, a query that returns stale data, or a `spawn` call that now throws. Harper v5 introduces breaking changes; applications built on documented APIs need the updates below, while code relying on undocumented behavior or timing may need broader review.
20
+ Apply this rule when upgrading an existing Harper application to v5, when encountering runtime errors related to renamed packages, changed APIs, or security restrictions introduced in v5, or when reviewing application code for v5 compatibility before deployment.
21
21
 
22
22
  ## How It Works
23
23
 
24
- 1. **Adopt the `harper` package name**: HarperDB is now Harper, and the package was renamed. Install the open source edition with `npm i -g harper` and the pro edition with `npm i -g @harperfast/harper-pro`. Update application imports from `harperdb` to `harper`:
24
+ 1. **Update the package import from `harperdb` to `harper`**: All application code must import from `harper` instead of `harperdb`.
25
25
 
26
26
  ```javascript
27
27
  import { tables } from 'harper';
28
28
  ```
29
29
 
30
- 2. **Opt in to install scripts when required**: Harper now installs packages with `--ignore-scripts` to guard against accidental script execution, a common security risk. If an application genuinely needs install scripts to run (for example to build native binaries), pass the `allowInstallScripts` option when deploying.
30
+ 2. **Enable `allowInstallScripts` if packages require install scripts**: Harper v5 uses `--ignore-scripts` by default when installing packages. If your application requires installation scripts (e.g., to install additional binaries), set the `allowInstallScripts` option when deploying.
31
31
 
32
- 3. **Update `Table.get` return-value handling**: `Table.get` now returns a plain, frozen record object rather than an instance of the table class, so instance methods are no longer available on the result. The commonly used `wasLoadedFromSource()` method is gone; cache-vs-origin information now lives on the request `target` as `target.loadedFromSource`. Pass a `RequestTarget` to `Table.get` and read the flag from it. Because the record is frozen, create a copy instead of mutating it in place.
32
+ 3. **Update `Table.get` usage — return value is now a frozen record object**: `Table.get` now returns a plain record object, not a table class instance. The record is frozen; you cannot mutate it directly.
33
+ - Replace `wasLoadedFromSource()` with `target.loadedFromSource`:
33
34
 
34
- 4. **Account for automatic transaction context**: With RocksDB, transactions are fully supported by the storage engine, and Harper v5 uses asynchronous context tracking to carry the current transaction across calls automatically. A nested `Table.get` now reads within the current transaction's snapshot, so it will not observe newly written data until you commit. Access the context through `getContext()` and either commit the current transaction (`getContext().transaction.commit()`) or run the read inside a fresh `transaction(...)` to see the latest data. This matters most for code executing outside the context of a Harper request.
35
+ ```javascript
36
+ // Old — remove this pattern:
37
+ const record = await Table.get(id);
38
+ if (record.wasLoadedFromSource()) { ... }
35
39
 
36
- 5. **Register spawnable commands**: Spawning processes is now tightly controlled. `spawn`, `exec`, and `execFile` may only run executables listed in the `applications.allowedSpawnCommands` configuration, and each call must pass a `name` in its `options` so that only a single named process is started across Harper's multiple threads. Use a distinct `name` when you deliberately need a separate process.
40
+ // New — use loadedFromSource on the target:
41
+ const target = new RequestTarget();
42
+ target.id = id;
43
+ const record = await Table.get(target);
44
+ if (target.loadedFromSource) {
45
+ // record was loaded from origin (not cache)
46
+ }
47
+ ```
37
48
 
38
- 6. **Return Response-like objects to set headers**: If a REST method returns an object with a `headers` property, Harper uses it as the response headers.
49
+ - Replace in-place mutation with object spread, since records are frozen:
39
50
 
40
- 7. **Replace `blob.save()`**: The `blob.save()` method has been removed. Pass the `saveBeforeCommit` flag in the options to the `Blob` constructor instead.
51
+ ```javascript
52
+ // Old — throws in v5:
53
+ const record = await Table.get(id);
54
+ record.property = 'changed';
41
55
 
42
- 8. **Configure the VM module loader**: v5 loads application modules through Node.js's VM module API, giving each application its own module cache and an application-scoped `harper` module. All of this is controlled by the `applications` section of `harperdb-config.yaml`:
43
- - `moduleLoader` — `vm-current-context` (default), `vm`, `native`, or `compartment`. The default shares intrinsics with Harper for best compatibility; choose `vm` only if you need per-application intrinsics, and `native` to disable the VM loader entirely (restores pre-v5 loading, but per-app `logger`/`config` context is unavailable).
44
- - `lockdown` — `freeze-after-load` (default), `freeze`, `ses`, or `none`. Freezing intrinsics prevents prototype-pollution attacks; set `lockdown: none` only as a temporary workaround if a dependency mutates built-in prototypes.
45
- - `allowedDirectory` — `app` (default) restricts module loading to the application's own directory tree; set `any` if the app must load files from outside it in production.
46
- - `allowedBuiltinModules` — an optional allowlist restricting which Node.js built-ins the application may import (all are allowed if omitted).
47
- - `dependencyLoader` — `auto` (default), `app`, or `native`, controlling how npm dependencies are loaded through or around the VM loader.
56
+ // New — copy instead of mutate:
57
+ let record = await Table.get(id);
58
+ record = { ...record, property: 'changed' };
59
+ ```
48
60
 
49
- ## Examples
61
+ - `getUpdatedTime` and `getExpiresAt` methods remain available on the record object.
50
62
 
51
- **Updating `Table.get` and its cache check:**
63
+ 4. **Update transaction and context handling**: Harper v5 uses asynchronous context tracking. `Table.get` and other table calls now automatically inherit the current transaction context. Code that previously omitted context to bypass a transaction will no longer work as expected. Use `getContext` (imported from `harper`) to access and commit the current transaction explicitly when you need to see updated data.
52
64
 
53
- ```javascript
54
- // Old (v4.x)
55
- const record = await Table.get(id);
56
- if (record.wasLoadedFromSource()) {
57
- // loaded from origin, not cache
58
- }
59
-
60
- // New (v5)
61
- const target = new RequestTarget(); // passed in when overriding `get`
62
- target.id = id;
63
- const record = await Table.get(target);
64
- if (target.loadedFromSource) {
65
- // loaded from origin, not cache
66
- }
67
- ```
65
+ ```javascript
66
+ import { setTimeout as delay } from 'node:timers/promises';
67
+ import { getContext, transaction } from 'harper';
68
+
69
+ class MyResource {
70
+ static async get(target) {
71
+ // Commit the current transaction to read latest data:
72
+ await getContext().transaction.commit();
73
+ // Optionally wrap each poll in a new transaction:
74
+ while ((await transaction(() => Table.get(target))).status !== 'ready') {
75
+ await delay(100);
76
+ }
77
+ return Table.get(target);
78
+ }
79
+ }
80
+ ```
68
81
 
69
- **Committing the transaction to read fresh data:**
82
+ 5. **Register allowed spawn commands via `allowedSpawnCommands`**: Any use of `spawn`, `exec`, or `execFile` from `node:child_process` must reference executables listed in `applications.allowedSpawnCommands` in `harperdb-config.yaml`. Provide a `name` property in the options argument to ensure only a single named process is started across threads.
70
83
 
71
- ```javascript
72
- import { setTimeout as delay } from 'node:timers/promises';
73
- import { getContext, transaction } from 'harper';
74
-
75
- class MyResource {
76
- static async get(target) {
77
- // The current transaction is a consistent snapshot; commit it to see updates.
78
- await getContext().transaction.commit();
79
- while ((await transaction(() => Table.get(target))).status !== 'ready') {
80
- delay(100);
81
- }
82
- return Table.get(target);
83
- }
84
- }
85
- ```
84
+ 6. **Replace `blob.save()` with `saveBeforeCommit`**: The `blob.save()` method has been removed. Use the `saveBeforeCommit` flag in the options passed to the `Blob` constructor instead.
86
85
 
87
- **Module loader and security configuration in `harperdb-config.yaml`:**
86
+ 7. **Configure the `moduleLoader` and `lockdown` settings**: Harper v5 loads application modules through Node.js's VM module API. Control this behavior in `harperdb-config.yaml` under the `applications` key.
87
+
88
+ | Setting | Default | Options |
89
+ | ------------------ | -------------------- | --------------------------------------------------- |
90
+ | `moduleLoader` | `vm-current-context` | `vm-current-context`, `vm`, `native`, `compartment` |
91
+ | `lockdown` | `freeze-after-load` | `freeze-after-load`, `freeze`, `ses`, `none` |
92
+ | `dependencyLoader` | `auto` | `auto`, `app`, `native` |
93
+ | `allowedDirectory` | `app` | `app`, `any` |
94
+ - Use `moduleLoader: native` to disable the VM loader entirely and restore pre-v5 behavior (application-specific context such as tagged logging and per-app `config` will not be available).
95
+ - Use `lockdown: none` as a temporary workaround if a dependency modifies intrinsic prototypes at runtime and throws a `TypeError`.
96
+
97
+ ## Examples
98
+
99
+ ### Full `harperdb-config.yaml` `applications` block
88
100
 
89
101
  ```yaml
90
102
  applications:
91
- lockdown: freeze-after-load # default
92
- moduleLoader: vm-current-context # vm-current-context (default) | vm | native | compartment
93
- dependencyLoader: auto # auto (default) | app | native
94
- allowedDirectory: app # app (default) | any
103
+ lockdown: freeze-after-load
104
+ moduleLoader: vm-current-context
105
+ dependencyLoader: auto
106
+ allowedDirectory: app
95
107
  allowedSpawnCommands:
96
108
  - npm
97
109
  - node
98
- # allowedBuiltinModules: [] # if omitted, all Node.js built-ins are allowed
99
110
  ```
100
111
 
101
- ## Recommended Changes
112
+ ### Restricting allowed built-in modules
113
+
114
+ ```yaml
115
+ applications:
116
+ allowedBuiltinModules:
117
+ - fs
118
+ - path
119
+ - http
120
+ ```
121
+
122
+ ### Disabling the VM loader for package compatibility
123
+
124
+ ```yaml
125
+ applications:
126
+ moduleLoader: native
127
+ ```
128
+
129
+ ### Accessing context and committing a transaction
130
+
131
+ ```javascript
132
+ import { getContext } from 'harper';
133
+
134
+ await getContext().transaction.commit();
135
+ ```
102
136
 
103
- Beyond the required fixes above, Harper v5 encourages these patterns for new and migrated code:
137
+ ## Notes
104
138
 
105
- - Implement endpoints with `static` methods on Resources/Tables, reading request information from the request `target` argument (or from `getContext()`).
106
- - Rely on automatic context propagation rather than threading context through every call manually; access it via `getContext()` exported from `harper`.
107
- - Access Harper functions and APIs through the `harper` package rather than through global variables.
139
+ - The `lockdown: freeze-after-load` default freezes `Object`, `Array`, `Promise`, `Map`, `Set`, and other intrinsics after all application code loads. Any code or dependency that mutates intrinsic prototypes after startup will throw a `TypeError`.
140
+ - Under `lockdown: ses`, the constrained `fetch` (https-only) is applied only in `vm` mode. In `vm-current-context` and `native` modes, application code uses the standard global `fetch`.
141
+ - In production, `allowedDirectory: app` prevents loading modules from outside the application's own directory tree. Set `allowedDirectory: any` only if your application legitimately requires it.
142
+ - `dependencyLoader: native` is a narrower alternative to `moduleLoader: native` — it uses native loading only for npm packages while keeping the VM loader for first-party application source files.
143
+ - Access Harper functions and APIs through the `harper` package rather than through global variables. Use `getContext` from `harper` to access request context without passing it explicitly through every call.
@@ -5,8 +5,8 @@ metadata:
5
5
  mode: generate
6
6
  sources:
7
7
  - reference/v5/database/schema.md#Vector Indexing
8
- sourceCommit: 4fe4c9c95e0974eaa77032f6f10e36fbd8ec64ac
9
- inputHash: d90b1b74597d08a6
8
+ sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd
9
+ inputHash: 225b9bea420d9adc
10
10
  ---
11
11
 
12
12
  # Vector Indexing
@@ -15,11 +15,11 @@ Instructions for the agent to enable HNSW vector indexes on table fields and que
15
15
 
16
16
  ## When to Use
17
17
 
18
- Apply this rule when adding a vector similarity search capability to a Harper table — for example, storing text embeddings and querying for nearest neighbors, filtering by distance threshold, or tuning index construction and search parameters. Use it alongside [adding-tables-with-schemas.md](adding-tables-with-schemas.md) when defining the schema that hosts the vector field.
18
+ Apply this rule when adding a vector similarity search capability to a Harper table — for example, storing text embeddings and querying for nearest neighbors, filtering by distance threshold, or combining vector search with record-level access control. See [adding-tables-with-schemas.md](adding-tables-with-schemas.md) for how to define the surrounding table schema.
19
19
 
20
20
  ## How It Works
21
21
 
22
- 1. **Declare the vector index on a field**: Add `@indexed(type: "HNSW")` to a `[Float]` field inside a `@table` type. This creates an HNSW (Hierarchical Navigable Small World) index for approximate nearest-neighbor search.
22
+ 1. **Declare the vector index** on a `[Float]` field using `@indexed(type: "HNSW")`:
23
23
 
24
24
  ```graphql
25
25
  type Document @table {
@@ -28,7 +28,7 @@ Apply this rule when adding a vector similarity search capability to a Harper ta
28
28
  }
29
29
  ```
30
30
 
31
- 2. **Query by nearest neighbors using `sort`**: Call `.search()` with a `sort` descriptor that specifies the indexed `attribute` and a `target` vector. Use `limit` to cap results.
31
+ 2. **Query nearest neighbors** using the `sort` parameter with `attribute` and `target`:
32
32
 
33
33
  ```javascript
34
34
  let results = Document.search({
@@ -37,7 +37,7 @@ Apply this rule when adding a vector similarity search capability to a Harper ta
37
37
  });
38
38
  ```
39
39
 
40
- 3. **Combine with filter conditions**: Add a `conditions` array alongside `sort` to pre-filter records before ranking by similarity.
40
+ 3. **Combine with filter conditions** to narrow results before or during traversal:
41
41
 
42
42
  ```javascript
43
43
  let results = Document.search({
@@ -47,7 +47,25 @@ Apply this rule when adding a vector similarity search capability to a Harper ta
47
47
  });
48
48
  ```
49
49
 
50
- 4. **Filter by distance threshold**: To return only records within a similarity cutoff (without ranking), place `target` directly on the condition alongside `comparator` and `value`. This bounds result quality rather than ranking by similarity.
50
+ Conditions are evaluated _during_ graph traversal (predicate-aware search), not after. Very selective conditions are automatically diverted to an exact-scan strategy.
51
+
52
+ 4. **Use a `vectorFilter` function** for predicates not expressible as conditions (JavaScript API only):
53
+
54
+ ```javascript
55
+ let results = Document.search(
56
+ {
57
+ sort: { attribute: 'textEmbeddings', target: searchVector },
58
+ vectorFilter: (record) =>
59
+ record.tenantId === context.user.tenantId && record.status === 'published',
60
+ limit: 10,
61
+ },
62
+ context,
63
+ );
64
+ ```
65
+
66
+ The function receives a frozen candidate record and must return a boolean synchronously. It must be side-effect free and fast — it can run once per candidate visited during traversal (verdicts are memoized per query).
67
+
68
+ 5. **Filter by distance threshold** using `target` on a condition instead of `sort`:
51
69
 
52
70
  ```javascript
53
71
  let results = Document.search({
@@ -60,7 +78,7 @@ Apply this rule when adding a vector similarity search capability to a Harper ta
60
78
  });
61
79
  ```
62
80
 
63
- 5. **Include computed distance in results**: Use the special `$distance` field in `select` to return the distance from the target vector. Available in both `sort`-based and threshold-based queries.
81
+ 6. **Include computed distance in results** using the `$distance` field in `select`:
64
82
 
65
83
  ```javascript
66
84
  let results = Document.search({
@@ -70,7 +88,9 @@ Apply this rule when adding a vector similarity search capability to a Harper ta
70
88
  });
71
89
  ```
72
90
 
73
- 6. **Tune per-query search options**: Pass `distance` and `ef` directly on the `sort` descriptor to override index defaults for a single query.
91
+ `$distance` works in both `sort`-based and threshold-based queries.
92
+
93
+ 7. **Override the distance function or exploration budget per query** via options on the `sort` descriptor:
74
94
 
75
95
  ```javascript
76
96
  let results = Document.search({
@@ -79,31 +99,76 @@ Apply this rule when adding a vector similarity search capability to a Harper ta
79
99
  });
80
100
  ```
81
101
 
82
- - `distance` — overrides the distance function for this query: `"cosine"`, `"euclidean"`, or `"dotProduct"`.
83
- - `ef` — overrides the search exploration budget. Higher values improve recall at the cost of latency.
102
+ - `distance` — `"cosine"`, `"euclidean"`, or `"dotProduct"`.
103
+ - `ef` — overrides the search exploration budget for this query. Higher values improve recall at the cost of latency.
84
104
 
85
- 7. **Configure HNSW index parameters**: Pass parameters directly in the `@indexed` directive. Structural parameters (`distance`, `M`, `efConstruction`, `quantization`) trigger an index rebuild when changed; `efConstructionSearch` does not.
105
+ 8. **Tune filtered traversal** when a `vectorFilter` is very selective by raising `ef` or `filterExpansion`:
86
106
 
87
- ```graphql
88
- type Document @table {
89
- id: Long @primaryKey
90
- textEmbeddings: [Float]
91
- @indexed(type: "HNSW", distance: "euclidean", optimizeRouting: 0, efConstructionSearch: 100)
92
- }
107
+ ```javascript
108
+ let results = Document.search(
109
+ {
110
+ sort: { attribute: 'textEmbeddings', target: searchVector, ef: 200, filterExpansion: 40 },
111
+ vectorFilter: (record) => record.category === 'rare',
112
+ limit: 10,
113
+ },
114
+ context,
115
+ );
93
116
  ```
94
117
 
95
- 8. **Enable vector quantization**: Use `quantization: "int8"` to store vectors as 8-bit integers, reducing index size and memory usage. Harper re-ranks nearest-neighbor `sort` results against full-precision vectors automatically.
118
+ Filtered traversal visits at most `ef * filterExpansion` nodes (`filterExpansion` defaults to `24`). If the budget is exhausted before results fill, the search returns what was found rather than erroring.
119
+
120
+ 9. **Configure HNSW index parameters** directly on the directive:
96
121
 
97
122
  ```graphql
98
123
  type Document @table {
99
124
  id: Long @primaryKey
100
- textEmbeddings: [Float] @indexed(type: "HNSW", quantization: "int8")
125
+ textEmbeddings: [Float]
126
+ @indexed(type: "HNSW", distance: "euclidean", optimizeRouting: 0, efConstructionSearch: 100)
101
127
  }
102
128
  ```
103
129
 
130
+ | Parameter | Default | Description |
131
+ | ---------------------- | ----------------- | ------------------------------------------------------------------------------------------------ |
132
+ | `distance` | `"cosine"` | Distance function: `"cosine"`, `"euclidean"`, or `"dotProduct"` |
133
+ | `efConstruction` | `100` | Max nodes explored during index construction. Higher = better recall, lower = better performance |
134
+ | `M` | `16` | Preferred connections per graph layer |
135
+ | `optimizeRouting` | `0.5` | Heuristic aggressiveness for omitting redundant connections (0 = off, 1 = most aggressive) |
136
+ | `mL` | computed from `M` | Normalization factor for level generation |
137
+ | `efConstructionSearch` | auto-scaled | Max nodes explored during search. When unset, auto-scales with index size |
138
+ | `quantization` | — | `"int8"` stores vectors quantized to int8 |
139
+ | `filterExpansion` | `24` | Visit-budget multiplier for filtered search |
140
+
141
+ Changing `efConstructionSearch` on an existing index does not trigger a rebuild. Changing structural parameters (`distance`, `M`, `efConstruction`, `quantization`) does rebuild the index.
142
+
143
+ 10. **Enable int8 quantization** to reduce index size and memory usage:
144
+
145
+ ```graphql
146
+ type Document @table {
147
+ id: Long @primaryKey
148
+ textEmbeddings: [Float] @indexed(type: "HNSW", quantization: "int8")
149
+ }
150
+ ```
151
+
152
+ Graph navigation uses quantized distances. For `sort` queries, Harper re-ranks results against full-precision vectors, restoring exact ordering and exact `$distance` values. Distance-threshold queries filter on the approximate distance.
153
+
154
+ 11. **Implement record-level access control** by overriding `allowRead(user, target, context)` on the table resource. During vector queries the check participates in graph traversal, so a restricted user receives the k nearest records they are allowed to see:
155
+
156
+ ```javascript
157
+ export class Reports extends tables.Reports {
158
+ allowRead(user, target, context) {
159
+ if (!super.allowRead(user, target, context)) return false;
160
+ if (user.role.permission.super_user) return true;
161
+ if (this.ownerId == null) return true;
162
+ return this.ownerId === user.id;
163
+ }
164
+ }
165
+ ```
166
+
167
+ The check must be synchronous, side-effect free, and fast. `this` is the frozen record during per-record evaluation. A thrown exception denies that record (fail closed).
168
+
104
169
  ## Examples
105
170
 
106
- Full schema with custom HNSW parameters and a nearest-neighbor query with distance output:
171
+ **Full schema with custom HNSW parameters:**
107
172
 
108
173
  ```graphql
109
174
  type Document @table {
@@ -113,16 +178,33 @@ type Document @table {
113
178
  }
114
179
  ```
115
180
 
181
+ **Nearest-neighbor search with distance output:**
182
+
116
183
  ```javascript
117
- // Nearest-neighbor search with distance scores
118
184
  let results = Document.search({
119
185
  select: ['name', '$distance'],
120
186
  sort: { attribute: 'textEmbeddings', target: searchVector },
121
187
  limit: 5,
122
188
  });
189
+ ```
190
+
191
+ **Filtered vector search with tuned traversal budget:**
123
192
 
124
- // Distance-threshold query (no ranking)
125
- let closeMatches = Document.search({
193
+ ```javascript
194
+ let results = Document.search(
195
+ {
196
+ sort: { attribute: 'textEmbeddings', target: searchVector, ef: 200, filterExpansion: 40 },
197
+ vectorFilter: (record) => record.category === 'rare',
198
+ limit: 10,
199
+ },
200
+ context,
201
+ );
202
+ ```
203
+
204
+ **Distance threshold query (no ranking, cutoff only):**
205
+
206
+ ```javascript
207
+ let results = Document.search({
126
208
  conditions: {
127
209
  attribute: 'textEmbeddings',
128
210
  comparator: 'lt',
@@ -134,21 +216,10 @@ let closeMatches = Document.search({
134
216
 
135
217
  ## Notes
136
218
 
137
- ### HNSW Parameters
138
-
139
- | Parameter | Default | Description |
140
- | ---------------------- | ----------------- | ------------------------------------------------------------------------------------------------------ |
141
- | `distance` | `"cosine"` | Distance function: `"cosine"`, `"euclidean"`, or `"dotProduct"` |
142
- | `efConstruction` | `100` | Max nodes explored during index construction. Higher = better recall, lower = better performance |
143
- | `M` | `16` | Preferred connections per graph layer. Higher = more space, better recall for high-dimensional data |
144
- | `optimizeRouting` | `0.5` | Heuristic aggressiveness for omitting redundant connections (0 = off, 1 = most aggressive) |
145
- | `mL` | computed from `M` | Normalization factor for level generation |
146
- | `efConstructionSearch` | auto-scaled | Max nodes explored during search. When unset, auto-scales with index size; setting it fixes the budget |
147
- | `quantization` | — | `"int8"` stores vectors quantized to int8 |
148
-
149
- - The `distance` option on a per-query `sort` descriptor accepts `"cosine"`, `"euclidean"`, or `"dotProduct"`.
150
- - When no `ef` is passed and `efConstructionSearch` (or `efConstruction`) is not explicitly set on the index, the search budget auto-scales with index size.
151
- - `efConstruction` seeds the initial value of `efConstructionSearch`; setting either one fixes the search budget.
152
- - The correct parameter name is `efConstructionSearch` (not `efSearchConstruction`).
153
- - `$distance` is available in both `sort`-based ranking and `conditions`-based threshold queries.
154
- - For `quantization: "int8"`, distance-threshold (`lt`/`le`) queries filter on approximate distance; `sort` queries re-rank against full-precision vectors.
219
+ - Use `@indexed(type: "HNSW")` on a `[Float]` field — not on scalar fields.
220
+ - The default `distance` is `"cosine"`. Override it per-index via the directive or per-query via the `sort` descriptor.
221
+ - `efConstruction` seeds the initial value of `efConstructionSearch`. When neither is set, the search budget auto-scales with index size.
222
+ - `vectorFilter` is available from the JavaScript API only; it cannot be expressed in a REST query string.
223
+ - The parameter name Harper reads is `efConstructionSearch` (not `efSearchConstruction`).
224
+ - `$distance` must be listed explicitly in `select` to appear in results.
225
+ - For record-level `allowRead` overrides: collection-scope calls (where `this.ownerId` is `null`) should return `true` to open the connection; per-record filtering happens during query execution and event delivery.
@@ -422,3 +422,12 @@ rules:
422
422
  - 'moduleLoader'
423
423
  - 'lockdown'
424
424
  - 'Table.get'
425
+
426
+ - rule: delegating-to-the-built-in-agent
427
+ description: How to delegate tasks to Harper's built-in agent via the CLI and the agent operations API.
428
+ category: ops
429
+ priority: 4
430
+ order: 8
431
+ mode: synthesized
432
+ cross_links:
433
+ - deploying-to-harper-fabric