@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.
- package/.agents/skills/harper-best-practices/AGENTS.md +702 -490
- package/.agents/skills/harper-best-practices/SKILL.md +1 -0
- package/.agents/skills/harper-best-practices/rules/automatic-apis.md +46 -78
- package/.agents/skills/harper-best-practices/rules/defining-relationships.md +41 -63
- package/.agents/skills/harper-best-practices/rules/delegating-to-the-built-in-agent.md +141 -0
- package/.agents/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +59 -45
- package/.agents/skills/harper-best-practices/rules/load-env.md +24 -23
- package/.agents/skills/harper-best-practices/rules/programmatic-table-requests.md +62 -78
- package/.agents/skills/harper-best-practices/rules/querying-rest-apis.md +92 -65
- package/.agents/skills/harper-best-practices/rules/schema-design-tooling.md +53 -55
- package/.agents/skills/harper-best-practices/rules/v5-upgrade.md +98 -62
- package/.agents/skills/harper-best-practices/rules/vector-indexing.md +113 -42
- package/.agents/skills/harper-best-practices/rules.manifest.yaml +9 -0
- package/.agents/skills/harper-mcp/AGENTS.md +501 -0
- package/.agents/skills/harper-mcp/SKILL.md +91 -0
- package/.agents/skills/harper-mcp/rules/automatic-verb-tools.md +50 -0
- package/.agents/skills/harper-mcp/rules/connecting-clients.md +59 -0
- package/.agents/skills/harper-mcp/rules/custom-mcp-prompts.md +52 -0
- package/.agents/skills/harper-mcp/rules/custom-mcp-resources.md +64 -0
- package/.agents/skills/harper-mcp/rules/custom-mcp-tools.md +72 -0
- package/.agents/skills/harper-mcp/rules/durable-quotas.md +73 -0
- package/.agents/skills/harper-mcp/rules/enabling-mcp.md +63 -0
- package/.agents/skills/harper-mcp/rules/rate-limiting.md +62 -0
- package/.agents/skills/harper-mcp/rules/resources-surface.md +44 -0
- package/.agents/skills/harper-mcp/rules/security-posture.md +36 -0
- package/.agents/skills/harper-mcp/rules.manifest.yaml +203 -0
- package/agent/skills/harper-best-practices/AGENTS.md +702 -490
- package/agent/skills/harper-best-practices/SKILL.md +1 -0
- package/agent/skills/harper-best-practices/rules/automatic-apis.md +46 -78
- package/agent/skills/harper-best-practices/rules/defining-relationships.md +41 -63
- package/agent/skills/harper-best-practices/rules/delegating-to-the-built-in-agent.md +141 -0
- package/agent/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +59 -45
- package/agent/skills/harper-best-practices/rules/load-env.md +24 -23
- package/agent/skills/harper-best-practices/rules/programmatic-table-requests.md +62 -78
- package/agent/skills/harper-best-practices/rules/querying-rest-apis.md +92 -65
- package/agent/skills/harper-best-practices/rules/schema-design-tooling.md +53 -55
- package/agent/skills/harper-best-practices/rules/v5-upgrade.md +98 -62
- package/agent/skills/harper-best-practices/rules/vector-indexing.md +113 -42
- package/agent/skills/harper-best-practices/rules.manifest.yaml +9 -0
- package/agent/skills/harper-mcp/AGENTS.md +501 -0
- package/agent/skills/harper-mcp/SKILL.md +83 -0
- package/agent/skills/harper-mcp/rules/automatic-verb-tools.md +50 -0
- package/agent/skills/harper-mcp/rules/connecting-clients.md +59 -0
- package/agent/skills/harper-mcp/rules/custom-mcp-prompts.md +52 -0
- package/agent/skills/harper-mcp/rules/custom-mcp-resources.md +64 -0
- package/agent/skills/harper-mcp/rules/custom-mcp-tools.md +72 -0
- package/agent/skills/harper-mcp/rules/durable-quotas.md +73 -0
- package/agent/skills/harper-mcp/rules/enabling-mcp.md +63 -0
- package/agent/skills/harper-mcp/rules/rate-limiting.md +62 -0
- package/agent/skills/harper-mcp/rules/resources-surface.md +44 -0
- package/agent/skills/harper-mcp/rules/security-posture.md +36 -0
- package/agent/skills/harper-mcp/rules.manifest.yaml +203 -0
- package/package.json +1 -1
- package/skills-lock.json +7 -1
|
@@ -84,6 +84,7 @@ See the concrete examples embedded in each rule subsection below (GraphQL schema
|
|
|
84
84
|
- `logging` — Best practices for logging in Harper, including console capture, the granular logger interface, and programmatic log retrieval.
|
|
85
85
|
- `load-env` — How to load environment variables from .env files into a Harper application using the loadEnv plugin.
|
|
86
86
|
- `v5-upgrade` — Breaking changes and recommended updates when migrating a Harper application to v5.
|
|
87
|
+
- `delegating-to-the-built-in-agent` — How to delegate tasks to Harper's built-in agent via the CLI and the agent operations API.
|
|
87
88
|
|
|
88
89
|
<!-- END GENERATED INDEX -->
|
|
89
90
|
|
|
@@ -6,8 +6,8 @@ metadata:
|
|
|
6
6
|
sources:
|
|
7
7
|
- reference/v5/rest/overview.md
|
|
8
8
|
- reference/v5/rest/websockets.md
|
|
9
|
-
sourceCommit:
|
|
10
|
-
inputHash:
|
|
9
|
+
sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd
|
|
10
|
+
inputHash: 6c7013b1307d9f7b
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# Automatic APIs
|
|
@@ -20,13 +20,13 @@ Apply this rule when adding REST or WebSocket API access to Harper tables or cus
|
|
|
20
20
|
|
|
21
21
|
## How It Works
|
|
22
22
|
|
|
23
|
-
1. **Enable the REST plugin**: Add `rest: true` to your application's `config.yaml`. This activates the HTTP REST interface and enables WebSocket support
|
|
23
|
+
1. **Enable the REST plugin**: Add `rest: true` to your application's `config.yaml`. This activates the HTTP REST interface on the application server port (default `9926`) and enables WebSocket support automatically.
|
|
24
24
|
|
|
25
25
|
```yaml
|
|
26
26
|
rest: true
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
To configure
|
|
29
|
+
To configure options explicitly:
|
|
30
30
|
|
|
31
31
|
```yaml
|
|
32
32
|
rest:
|
|
@@ -34,69 +34,26 @@ Apply this rule when adding REST or WebSocket API access to Harper tables or cus
|
|
|
34
34
|
webSocket: false # disables automatic WebSocket support (enabled by default)
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
2. **Export your resource in the schema**: Tables are not exposed by default. Use the `@export` directive in your schema definition to
|
|
37
|
+
2. **Export your resource in the schema**: Tables are not exposed by default. Use the `@export` directive in your schema definition to expose a table as a REST endpoint. The exported name defines the base URL path.
|
|
38
38
|
|
|
39
|
-
3. **Use the correct URL structure**:
|
|
39
|
+
3. **Use the correct URL structure**: Target resources using these path conventions:
|
|
40
40
|
|
|
41
|
-
| Path | Description
|
|
42
|
-
| -------------------------------------------- |
|
|
43
|
-
| `/my-resource` | Returns
|
|
44
|
-
| `/my-resource/` |
|
|
45
|
-
| `/my-resource/record-id` |
|
|
46
|
-
| `/my-resource/record-id/` |
|
|
47
|
-
| `/my-resource/record-id/with/multiple/parts` | Record id with multiple path segments
|
|
41
|
+
| Path | Description |
|
|
42
|
+
| -------------------------------------------- | ----------------------------------------------------------- |
|
|
43
|
+
| `/my-resource` | Returns resource metadata |
|
|
44
|
+
| `/my-resource/` | Collection — all records; append query parameters to search |
|
|
45
|
+
| `/my-resource/record-id` | Specific record by primary key |
|
|
46
|
+
| `/my-resource/record-id/` | Collection of records with the given id prefix |
|
|
47
|
+
| `/my-resource/record-id/with/multiple/parts` | Record id with multiple path segments |
|
|
48
48
|
|
|
49
|
-
4. **Map HTTP methods
|
|
50
|
-
- **GET** — Retrieve a record or search. Calls `get()`.
|
|
49
|
+
4. **Map operations to HTTP methods**: Each HTTP method maps to a resource method:
|
|
50
|
+
- **GET** — Retrieve a record or search. Calls `get()`. Responses include an `ETag` header; send `If-None-Match` on subsequent requests to receive `304 Not Modified` when unchanged.
|
|
51
|
+
- **PUT** — Create or replace a record (upsert). Calls `put(record)`. The stored record exactly matches the submitted body; omitted properties are removed.
|
|
52
|
+
- **POST** — Create a record without specifying a primary key. Calls `post(data)`. The assigned key is returned in the `Location` response header.
|
|
53
|
+
- **PATCH** — Partially update a record, merging only provided top-level properties. Calls the resource's patch handler. Merge is **shallow** — nested objects are replaced entirely, not deep-merged.
|
|
54
|
+
- **DELETE** — Delete a record by id or all records matching a query.
|
|
51
55
|
|
|
52
|
-
|
|
53
|
-
GET /MyTable/123
|
|
54
|
-
GET /MyTable/?name=Harper
|
|
55
|
-
GET /MyTable/123.propertyName
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Responses include an `ETag` header. Clients may send `If-None-Match` to receive `304 Not Modified` when the record is unchanged.
|
|
59
|
-
|
|
60
|
-
- **PUT** — Create or replace a record (upsert). Calls `put(record)`. Properties not in the body are removed.
|
|
61
|
-
|
|
62
|
-
```
|
|
63
|
-
PUT /MyTable/123
|
|
64
|
-
Content-Type: application/json
|
|
65
|
-
|
|
66
|
-
{ "name": "some data" }
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
- **POST** — Create a new record without specifying a primary key. Calls `post(data)`. The assigned key is returned in the `Location` response header.
|
|
70
|
-
|
|
71
|
-
```
|
|
72
|
-
POST /MyTable/
|
|
73
|
-
Content-Type: application/json
|
|
74
|
-
|
|
75
|
-
{ "name": "some data" }
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
- **PATCH** — Partially update a record, merging only provided properties. Unspecified properties are preserved.
|
|
79
|
-
|
|
80
|
-
```
|
|
81
|
-
PATCH /MyTable/123
|
|
82
|
-
Content-Type: application/json
|
|
83
|
-
|
|
84
|
-
{ "status": "active" }
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
- **DELETE** — Delete a record or all records matching a query.
|
|
88
|
-
```
|
|
89
|
-
DELETE /MyTable/123
|
|
90
|
-
DELETE /MyTable/?status=archived
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
5. **Access the auto-generated OpenAPI spec**: Harper generates an OpenAPI specification for all exported resources. Retrieve it at:
|
|
94
|
-
|
|
95
|
-
```
|
|
96
|
-
GET /openapi
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
6. **Connect via WebSocket**: When `rest` is enabled, WebSocket support is on by default. Connect to a resource URL to subscribe to change events for that resource.
|
|
56
|
+
5. **Connect via WebSocket**: A WebSocket connection to a resource URL subscribes to that resource and streams change events. See [real-time-apps.md](real-time-apps.md) for full real-time patterns.
|
|
100
57
|
|
|
101
58
|
```javascript
|
|
102
59
|
let ws = new WebSocket('wss://server/my-resource/341');
|
|
@@ -105,13 +62,17 @@ Apply this rule when adding REST or WebSocket API access to Harper tables or cus
|
|
|
105
62
|
};
|
|
106
63
|
```
|
|
107
64
|
|
|
108
|
-
|
|
65
|
+
6. **Implement a custom `connect()` handler** on a resource class to control WebSocket behavior. The method receives `incomingMessages` and must return an async iterable producing messages to send to the client.
|
|
66
|
+
|
|
67
|
+
7. **Retrieve the OpenAPI spec**: Harper auto-generates an OpenAPI specification for all exported resources, available at:
|
|
109
68
|
|
|
110
|
-
|
|
69
|
+
```
|
|
70
|
+
GET /openapi
|
|
71
|
+
```
|
|
111
72
|
|
|
112
73
|
## Examples
|
|
113
74
|
|
|
114
|
-
**Simple echo server
|
|
75
|
+
**Simple echo WebSocket server**:
|
|
115
76
|
|
|
116
77
|
```javascript
|
|
117
78
|
export class Echo extends Resource {
|
|
@@ -123,7 +84,7 @@ export class Echo extends Resource {
|
|
|
123
84
|
}
|
|
124
85
|
```
|
|
125
86
|
|
|
126
|
-
**
|
|
87
|
+
**Custom `connect()` using the default iterable with `send()` and `close` event**:
|
|
127
88
|
|
|
128
89
|
```javascript
|
|
129
90
|
export class Example extends Resource {
|
|
@@ -147,19 +108,26 @@ export class Example extends Resource {
|
|
|
147
108
|
}
|
|
148
109
|
```
|
|
149
110
|
|
|
150
|
-
**
|
|
111
|
+
**Common REST operations**:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
GET /MyTable/123
|
|
115
|
+
GET /MyTable/?name=Harper
|
|
116
|
+
PUT /MyTable/123
|
|
117
|
+
PATCH /MyTable/123
|
|
118
|
+
DELETE /MyTable/?status=archived
|
|
119
|
+
```
|
|
151
120
|
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
webSocket: false
|
|
121
|
+
```json
|
|
122
|
+
{ "name": "some data" }
|
|
155
123
|
```
|
|
156
124
|
|
|
157
125
|
## Notes
|
|
158
126
|
|
|
159
|
-
-
|
|
160
|
-
-
|
|
161
|
-
-
|
|
162
|
-
-
|
|
163
|
-
-
|
|
164
|
-
-
|
|
165
|
-
-
|
|
127
|
+
- `rest: true` is the minimal config to enable both REST and WebSocket support. Set `webSocket: false` under the `rest` key to disable WebSocket only.
|
|
128
|
+
- The `@export` directive in the schema is required for any table to appear as a REST endpoint — tables are not exported by default.
|
|
129
|
+
- PATCH merges are shallow (top-level only). Nested objects in the request body replace the entire existing sub-object. Dot-path keys (e.g., `"settings.theme"`) are stored as literal keys, not interpreted as paths.
|
|
130
|
+
- For MQTT over WebSocket, set the sub-protocol header `Sec-WebSocket-Protocol: mqtt`.
|
|
131
|
+
- In distributed environments, non-retained messages are delivered in arrival order; retained messages (PUT/updated records) keep only the latest timestamp as the winning record.
|
|
132
|
+
- For full query syntax on GET and DELETE, see [querying-rest-apis.md](querying-rest-apis.md).
|
|
133
|
+
- For building real-time features with WebSocket subscriptions, see [real-time-apps.md](real-time-apps.md).
|
|
@@ -6,8 +6,8 @@ metadata:
|
|
|
6
6
|
sources:
|
|
7
7
|
- reference/v5/database/schema.md#Relationships
|
|
8
8
|
- reference/v5/rest/querying.md#Relationships and Joins
|
|
9
|
-
sourceCommit:
|
|
10
|
-
inputHash:
|
|
9
|
+
sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd
|
|
10
|
+
inputHash: fd399fd81a88f13e
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# Defining Relationships Between Tables in Harper
|
|
@@ -16,17 +16,17 @@ Instructions for the agent to follow when defining and querying relationships be
|
|
|
16
16
|
|
|
17
17
|
## When to Use
|
|
18
18
|
|
|
19
|
-
Apply this rule
|
|
19
|
+
Apply this rule when adding foreign key relationships between schema tables, enabling join queries, or returning nested related records in query results. Use it any time a schema type needs to reference records in another table via a foreign key attribute.
|
|
20
20
|
|
|
21
21
|
## How It Works
|
|
22
22
|
|
|
23
|
-
1. **Use `@relationship(from: attribute)` for many-to-one or many-to-many**: Place this on
|
|
23
|
+
1. **Use `@relationship(from: attribute)` for many-to-one or many-to-many**: Place this on the field in the table that holds the foreign key. The `from` parameter names the attribute on this table that stores the foreign key referencing the target table's primary key.
|
|
24
24
|
|
|
25
25
|
```graphql
|
|
26
26
|
type RealityShow @table @export {
|
|
27
27
|
id: Long @primaryKey
|
|
28
28
|
networkId: Long @indexed
|
|
29
|
-
network: Network @relationship(from: networkId)
|
|
29
|
+
network: Network @relationship(from: networkId) # many-to-one
|
|
30
30
|
title: String @indexed
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -36,7 +36,7 @@ Apply this rule whenever a schema requires linking two tables via a foreign key
|
|
|
36
36
|
}
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
If the foreign key attribute is an array, the relationship becomes many-to-many:
|
|
40
40
|
|
|
41
41
|
```graphql
|
|
42
42
|
type RealityShow @table @export {
|
|
@@ -46,24 +46,24 @@ Apply this rule whenever a schema requires linking two tables via a foreign key
|
|
|
46
46
|
}
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
2. **Use `@relationship(to: attribute)` for one-to-many or many-to-many**: Place this on
|
|
49
|
+
2. **Use `@relationship(to: attribute)` for one-to-many or many-to-many**: Place this on the table whose primary key is referenced by the foreign key in the target table. The `to` parameter names the attribute on the target table that holds the foreign key. The result type **must** be an array.
|
|
50
50
|
|
|
51
51
|
```graphql
|
|
52
52
|
type Network @table @export {
|
|
53
53
|
id: Long @primaryKey
|
|
54
54
|
name: String @indexed
|
|
55
|
-
shows: [RealityShow] @relationship(to: networkId)
|
|
55
|
+
shows: [RealityShow] @relationship(to: networkId) # one-to-many
|
|
56
56
|
}
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
3. **Use `@relationship(from: attribute, to: attribute)` for foreign key to foreign key joins**: Specify both `from` and `to` when neither side uses the primary key.
|
|
59
|
+
3. **Use `@relationship(from: attribute, to: attribute)` for foreign key to foreign key joins**: Specify both `from` and `to` when neither side uses the primary key. Harper resolves the relationship by searching the target table's `to` attribute for matches using this record's `from` attribute value. The result type must be an array.
|
|
60
60
|
|
|
61
61
|
```graphql
|
|
62
62
|
type OrderItem @table @export {
|
|
63
63
|
id: Long @primaryKey
|
|
64
64
|
orderId: Long @indexed
|
|
65
65
|
productSku: Long @indexed
|
|
66
|
-
|
|
66
|
+
products: [Product] @relationship(from: productSku, to: sku)
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
type Product @table @export {
|
|
@@ -73,15 +73,14 @@ Apply this rule whenever a schema requires linking two tables via a foreign key
|
|
|
73
73
|
}
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
4. **Query across relationships using dot-syntax**: Filter by related table attributes using chained dot notation. This behaves as an INNER JOIN.
|
|
76
|
+
4. **Query across relationships using dot-syntax**: Filter records by related table attributes using chained dot notation. This behaves as an INNER JOIN — only records with a matching related record are returned.
|
|
77
77
|
|
|
78
78
|
```
|
|
79
|
-
GET /RealityShow?network.name=Bravo
|
|
80
79
|
GET /Product/?brand.name=Microsoft
|
|
81
80
|
GET /Brand/?products.name=Keyboard
|
|
82
81
|
```
|
|
83
82
|
|
|
84
|
-
5. **
|
|
83
|
+
5. **Include relationship fields in results using `select()`**: Relationship attributes are not returned by default. Use `select()` to include them, optionally specifying nested fields with `{}`.
|
|
85
84
|
|
|
86
85
|
```
|
|
87
86
|
GET /Product/?brand.name=Microsoft&select(name,brand)
|
|
@@ -89,77 +88,56 @@ Apply this rule whenever a schema requires linking two tables via a foreign key
|
|
|
89
88
|
GET /Product/?name=Keyboard&select(name,brand{name,id})
|
|
90
89
|
```
|
|
91
90
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
**Many-to-one relationship** — a show belongs to a network:
|
|
91
|
+
When selecting a relationship without filtering on it, Harper performs a LEFT JOIN — the relationship property is omitted if the foreign key is null or references a non-existent record.
|
|
95
92
|
|
|
96
|
-
|
|
97
|
-
type RealityShow @table @export {
|
|
98
|
-
id: Long @primaryKey
|
|
99
|
-
networkId: Long @indexed
|
|
100
|
-
network: Network @relationship(from: networkId)
|
|
101
|
-
title: String @indexed
|
|
102
|
-
}
|
|
93
|
+
6. **Model many-to-many without a junction table**: Store an array of foreign key values and use `@relationship(from: ...)` pointing to that array attribute. The array order of the foreign key values is preserved when resolving the relationship.
|
|
103
94
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
95
|
+
```graphql
|
|
96
|
+
type Product @table @export {
|
|
97
|
+
id: Long @primaryKey
|
|
98
|
+
name: String
|
|
99
|
+
resellerIds: [Long] @indexed
|
|
100
|
+
resellers: [Reseller] @relationship(from: "resellerIds")
|
|
101
|
+
}
|
|
102
|
+
```
|
|
109
103
|
|
|
110
|
-
|
|
104
|
+
7. **Define self-referential relationships** for parent-child hierarchies by pointing `@relationship` back at the same table type.
|
|
111
105
|
|
|
112
|
-
|
|
113
|
-
GET /RealityShow?network.name=Bravo
|
|
114
|
-
```
|
|
106
|
+
## Examples
|
|
115
107
|
|
|
116
|
-
**
|
|
108
|
+
**Full schema with bidirectional relationships:**
|
|
117
109
|
|
|
118
110
|
```graphql
|
|
119
|
-
type
|
|
111
|
+
type Product @table @export {
|
|
120
112
|
id: Long @primaryKey
|
|
121
|
-
name: String
|
|
122
|
-
|
|
113
|
+
name: String
|
|
114
|
+
brandId: Long @indexed
|
|
115
|
+
brand: Brand @relationship(from: "brandId")
|
|
123
116
|
}
|
|
124
|
-
```
|
|
125
117
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
```graphql
|
|
129
|
-
type Product @table @export {
|
|
118
|
+
type Brand @table @export {
|
|
130
119
|
id: Long @primaryKey
|
|
131
120
|
name: String
|
|
132
|
-
|
|
133
|
-
resellers: [Reseller] @relationship(from: resellerIds)
|
|
121
|
+
products: [Product] @relationship(to: "brandId")
|
|
134
122
|
}
|
|
135
123
|
```
|
|
136
124
|
|
|
137
|
-
|
|
125
|
+
**Querying with joins and nested select:**
|
|
138
126
|
|
|
139
127
|
```
|
|
140
|
-
GET /Product/?
|
|
128
|
+
GET /Product/?brand.name=Microsoft&select(name,brand{name,id})
|
|
129
|
+
GET /Brand/?products.name=Keyboard
|
|
141
130
|
```
|
|
142
131
|
|
|
143
|
-
**
|
|
132
|
+
**Many-to-many query with nested select:**
|
|
144
133
|
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
id: Long @primaryKey
|
|
148
|
-
orderId: Long @indexed
|
|
149
|
-
productSku: Long @indexed
|
|
150
|
-
product: Product @relationship(from: productSku, to: sku)
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
type Product @table @export {
|
|
154
|
-
id: Long @primaryKey
|
|
155
|
-
sku: Long @indexed
|
|
156
|
-
name: String
|
|
157
|
-
}
|
|
134
|
+
```
|
|
135
|
+
GET /Product/?resellers.name=Cool Shop&select(id,name,resellers{name,id})
|
|
158
136
|
```
|
|
159
137
|
|
|
160
138
|
## Notes
|
|
161
139
|
|
|
162
|
-
-
|
|
163
|
-
-
|
|
164
|
-
- The array
|
|
165
|
-
-
|
|
140
|
+
- Every attribute named in `from` or `to` must exist on the respective table and be annotated with `@indexed` to support join queries.
|
|
141
|
+
- The `to`-only and `from`+`to` forms both require the result field type to be an array (e.g., `[RealityShow]`).
|
|
142
|
+
- The `from`-only form on a non-array attribute produces a many-to-one relationship; on an array attribute it produces many-to-many.
|
|
143
|
+
- Self-referential relationships are supported for hierarchical data within a single table.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: delegating-to-the-built-in-agent
|
|
3
|
+
description: How to delegate tasks to Harper's built-in agent via the CLI and the agent operations API.
|
|
4
|
+
metadata:
|
|
5
|
+
mode: synthesized
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Delegating to the Built-in Agent
|
|
9
|
+
|
|
10
|
+
Harper 5.2+ ships with a **built-in agent** that runs _inside_ the server, on the main thread
|
|
11
|
+
adjacent to the operations API. Because it runs in-process, it can do things a remote client
|
|
12
|
+
cannot: call the operations API as RBAC-filtered tools, read and write component files under the
|
|
13
|
+
instance's components root, attach the V8 inspector to worker threads to debug and profile them,
|
|
14
|
+
schedule follow-up work, and consult the Harper best-practices skill. You send it a natural-language
|
|
15
|
+
task; it runs a tool-using loop under a super_user identity and reports back.
|
|
16
|
+
|
|
17
|
+
## When to Use
|
|
18
|
+
|
|
19
|
+
Delegate to the built-in agent when the work is best done **on the instance itself** rather than
|
|
20
|
+
from your local client:
|
|
21
|
+
|
|
22
|
+
- Operating on a deployed instance in place — inspect the schema, build or adjust a component,
|
|
23
|
+
restart, run an operation.
|
|
24
|
+
- Debugging or profiling a running instance — attach to a worker thread, capture a CPU profile,
|
|
25
|
+
set a logpoint.
|
|
26
|
+
- Handing off a larger, multi-step task to an agent that already has the instance's tools,
|
|
27
|
+
filesystem, and credentials in context.
|
|
28
|
+
|
|
29
|
+
Do the work in your own client instead when it's purely local (editing source before deploy) or
|
|
30
|
+
when you don't want a server-side agent making changes.
|
|
31
|
+
|
|
32
|
+
**Prerequisites:** the target instance must have the agent enabled (an `agent:` config block with
|
|
33
|
+
`enabled: true`) and a configured generative model backend. All agent operations require
|
|
34
|
+
**super_user**.
|
|
35
|
+
|
|
36
|
+
## How It Works
|
|
37
|
+
|
|
38
|
+
The lifecycle assumes you have already deployed to and authenticated with the target instance (see
|
|
39
|
+
[deploying-to-harper-fabric.md](deploying-to-harper-fabric.md) — `harper login` stores a token so
|
|
40
|
+
you don't repeat credentials). Delegation reuses that same target and credentials.
|
|
41
|
+
|
|
42
|
+
There are two equivalent ways to drive the agent.
|
|
43
|
+
|
|
44
|
+
### Option A — the `harper agent` CLI (simplest)
|
|
45
|
+
|
|
46
|
+
A thin client over the agent operations API that reuses your stored `harper login` credentials, so
|
|
47
|
+
no connector setup is needed:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# One-shot: send a task, print the reply, exit
|
|
51
|
+
harper agent "Describe the schema, then add a price index to the Product table."
|
|
52
|
+
|
|
53
|
+
# Interactive session (REPL)
|
|
54
|
+
harper agent
|
|
55
|
+
|
|
56
|
+
# Against a specific remote instead of the logged-in default
|
|
57
|
+
harper agent --target <Application URL> "List the databases and tables."
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The CLI polls the run to completion and renders the transcript (tool calls, results, and the
|
|
61
|
+
agent's reply). When a run needs approval for a destructive action, it prompts you inline.
|
|
62
|
+
|
|
63
|
+
### Option B — the agent operations API (programmatic)
|
|
64
|
+
|
|
65
|
+
Call the operations API directly (HTTP POST to the ops endpoint, super_user auth). This is the path
|
|
66
|
+
to use from scripts and services.
|
|
67
|
+
|
|
68
|
+
1. **Start a task** with `agent_prompt`. Returns a `session_id` and a `status`.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
curl -s -u <user>:<pass> <ops-endpoint> \
|
|
72
|
+
-H 'Content-Type: application/json' \
|
|
73
|
+
-d '{"operation":"agent_prompt","message":"Build a Customer table (id, email, name) exported over REST."}'
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
2. **Poll for progress** with `get_agent_session`, passing the `session_id`. The returned session
|
|
77
|
+
carries the `status`, the `messages` transcript, and any `pendingApprovals`.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
curl -s -u <user>:<pass> <ops-endpoint> \
|
|
81
|
+
-H 'Content-Type: application/json' \
|
|
82
|
+
-d '{"operation":"get_agent_session","session_id":"<id>"}'
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Poll until `status` leaves `running` — terminal states are `completed`, `aborted`, and `error`;
|
|
86
|
+
`awaiting_approval` means it is paused for an approval decision (see step 3).
|
|
87
|
+
|
|
88
|
+
3. **Approve or deny a paused action.** When the agent enabled configuration has `autoApprove:false`,
|
|
89
|
+
a destructive tool call pauses the run with a `pendingApprovals[]` entry. Resolve it with
|
|
90
|
+
`approve_agent_action`, then poll again — approval executes the saved call, denial hands the
|
|
91
|
+
rejection back to the agent so it can adjust.
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
curl -s -u <user>:<pass> <ops-endpoint> \
|
|
95
|
+
-H 'Content-Type: application/json' \
|
|
96
|
+
-d '{"operation":"approve_agent_action","session_id":"<id>","approval_id":"<approval-id>","approved":true}'
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
4. **Continue the conversation** by passing the same `session_id` back into `agent_prompt` with a
|
|
100
|
+
new `message`. Omit `session_id` to start a fresh session.
|
|
101
|
+
|
|
102
|
+
Supporting operations: `list_agent_sessions` (recent sessions), `cancel_agent_run` (terminate a
|
|
103
|
+
running or paused session), and `set_agent_config` (adjust `autoApprove`, `allowDestructive`,
|
|
104
|
+
`model`, and related settings on a running instance).
|
|
105
|
+
|
|
106
|
+
## Examples
|
|
107
|
+
|
|
108
|
+
**Delegate a build to a deployed Fabric instance and wait for the result:**
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
harper login <Application URL>
|
|
112
|
+
harper agent --target <Application URL> \
|
|
113
|
+
"Create a Product table (id, name, price) exported over REST, then confirm the endpoint responds."
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Programmatic start-and-poll loop:**
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
SID=$(curl -s -u <user>:<pass> <ops-endpoint> -H 'Content-Type: application/json' \
|
|
120
|
+
-d '{"operation":"agent_prompt","message":"Add a vector index to the Document.embedding field."}' \
|
|
121
|
+
| jq -r .session_id)
|
|
122
|
+
|
|
123
|
+
while [ "$(curl -s -u <user>:<pass> <ops-endpoint> -H 'Content-Type: application/json' \
|
|
124
|
+
-d "{\"operation\":\"get_agent_session\",\"session_id\":\"$SID\"}" | jq -r .status)" = "running" ]; do
|
|
125
|
+
sleep 3
|
|
126
|
+
done
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Notes
|
|
130
|
+
|
|
131
|
+
- **All agent operations require super_user.** Authenticate with `harper login`, which stores a
|
|
132
|
+
short-lived JWT (operation token) plus a refresh token rather than your password — prefer that
|
|
133
|
+
over passing credentials inline, and never embed a raw password in scripts or client config.
|
|
134
|
+
- **Approvals are your safety gate.** With `autoApprove:false`, the agent pauses before destructive
|
|
135
|
+
tools (writing files, deploying, restarting) so an operator decides. Set `autoApprove:true` only
|
|
136
|
+
when you want unattended runs.
|
|
137
|
+
- **Sessions are single-active.** A session that is `running` or `awaiting_approval` rejects a new
|
|
138
|
+
`agent_prompt`; resolve the approval or cancel the run first.
|
|
139
|
+
- **MCP alternative.** For MCP-native clients, an instance with MCP enabled exposes the agent as
|
|
140
|
+
curated MCP tools (`agent_prompt`, `get_agent_session`, `list_agent_sessions`) at the ops API's
|
|
141
|
+
`/mcp` endpoint — the same delegation loop over the MCP transport instead of raw operations.
|