@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
@@ -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: b7fbddadd42eb4487190b650a9abc4bcfeef5819
10
- inputHash: 8fcf0cfe190e013e
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 by default.
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 optional behavior:
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 make a table available as a REST endpoint. The exported name defines the base URL path, served on the application HTTP server port (default `9926`).
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**: The REST interface follows a consistent path convention.
39
+ 3. **Use the correct URL structure**: Target resources using these path conventions:
40
40
 
41
- | Path | Description |
42
- | -------------------------------------------- | ---------------------------------------------------------------------------------- |
43
- | `/my-resource` | Returns a description of the resource (e.g., table metadata) |
44
- | `/my-resource/` | Trailing slash — represents the full collection; append query parameters to search |
45
- | `/my-resource/record-id` | A specific record identified by its primary key |
46
- | `/my-resource/record-id/` | Trailing slash — collection of records with the given id prefix |
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 to operations**: Each HTTP method maps to a resource method and operation.
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
- Connecting to `wss://server/my-resource/341` accesses the `my-resource` resource with record id `341` and subscribes to it. When the record changes or a message is published to it, the WebSocket connection receives the update.
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
- 7. **Implement a custom `connect()` handler**: Override `connect(incomingMessages)` on a resource class to control WebSocket behavior. The method must return an async iterable or generator that produces messages to send to the client.
69
+ ```
70
+ GET /openapi
71
+ ```
111
72
 
112
73
  ## Examples
113
74
 
114
- **Simple echo server using an async generator**:
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
- **Using the default `connect()` with event-style access and a timer**:
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
- **Minimal `config.yaml` enabling REST with WebSocket disabled**:
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
- ```yaml
153
- rest:
154
- webSocket: false
121
+ ```json
122
+ { "name": "some data" }
155
123
  ```
156
124
 
157
125
  ## Notes
158
126
 
159
- - Tables must be explicitly exported using `@export` in the schema — they are not exposed by default.
160
- - `rest: true` is the minimal configuration to enable both REST and WebSocket support. See [real-time-apps.md](real-time-apps.md) for patterns around real-time WebSocket usage.
161
- - For full query syntax on `GET` and `DELETE` with query parameters, see [querying-rest-apis.md](querying-rest-apis.md).
162
- - The default `connect()` returns an iterable with a `send(message)` method and a `close` event for cleanup on disconnect.
163
- - For MQTT over WebSockets, set the sub-protocol header `Sec-WebSocket-Protocol: mqtt`.
164
- - In distributed environments, non-retained messages are delivered in the order received per node; retained messages (PUT/updated records) keep only the latest-timestamp version as the winning record across the cluster.
165
- - Use the `Content-Type` request header to specify body format and the `Accept` header to request a specific response format.
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: 4fe4c9c95e0974eaa77032f6f10e36fbd8ec64ac
10
- inputHash: 6953f507f0cde0f7
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 whenever a schema requires linking two tables via a foreign key — for example, modeling shows and networks, products and brands, or orders and items. Use it when queries need to filter or select nested related records using dot-syntax.
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 a field in the current table when the foreign key lives in this table and references the primary key of the target table.
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
- For a many-to-many relationship, make the foreign key an array:
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 a field in the current table when the foreign key lives in the target table and references the primary key of this table. The result type must be an array.
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. This is useful for joining on non-primary-key attributes.
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
- product: Product @relationship(from: productSku, to: sku)
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. **Select nested relationship fields with `select()`**: Relationship attributes are not included by default. Use `select()` to include them in results. When selecting without a filter on the related table, this acts as a LEFT JOIN — the relationship property is omitted if the foreign key is null or references a non-existent record.
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
- ## Examples
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
- ```graphql
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
- type Network @table @export {
105
- id: Long @primaryKey
106
- name: String @indexed
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
- Query:
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
- **One-to-many relationship** — a network has many shows:
108
+ **Full schema with bidirectional relationships:**
117
109
 
118
110
  ```graphql
119
- type Network @table @export {
111
+ type Product @table @export {
120
112
  id: Long @primaryKey
121
- name: String @indexed
122
- shows: [RealityShow] @relationship(to: networkId)
113
+ name: String
114
+ brandId: Long @indexed
115
+ brand: Brand @relationship(from: "brandId")
123
116
  }
124
- ```
125
117
 
126
- **Many-to-many with array foreign keys** — a product has multiple resellers:
127
-
128
- ```graphql
129
- type Product @table @export {
118
+ type Brand @table @export {
130
119
  id: Long @primaryKey
131
120
  name: String
132
- resellerIds: [Long] @indexed
133
- resellers: [Reseller] @relationship(from: resellerIds)
121
+ products: [Product] @relationship(to: "brandId")
134
122
  }
135
123
  ```
136
124
 
137
- Query with nested select:
125
+ **Querying with joins and nested select:**
138
126
 
139
127
  ```
140
- GET /Product/?resellers.name=Cool Shop&select(id,name,resellers{name,id})
128
+ GET /Product/?brand.name=Microsoft&select(name,brand{name,id})
129
+ GET /Brand/?products.name=Keyboard
141
130
  ```
142
131
 
143
- **Foreign key to foreign key join** — order item joined on SKU:
132
+ **Many-to-many query with nested select:**
144
133
 
145
- ```graphql
146
- type OrderItem @table @export {
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
- - The `@relationship` directive requires the referenced attribute to be `@indexed` on the foreign key side.
163
- - Self-referential relationships are supported, enabling parent-child hierarchies within a single table.
164
- - The array order of foreign key values (e.g., `resellerIds`) is preserved when resolving many-to-many relationships.
165
- - When using `select()` without a filter on the related table, the join behaves as a LEFT JOIN — missing or null foreign keys result in the relationship property being omitted rather than causing an error.
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.