You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: AGENTS.md
+44-10Lines changed: 44 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,7 +6,7 @@ This guide helps AI agents quickly navigate the constructive-functions workspace
6
6
7
7
See [docs/spec/function-templating.md](docs/spec/function-templating.md) for the full specification.
8
8
9
-
Functions use a **templating system**: developers write `handler.ts` + `handler.json` in `functions/`, and `scripts/generate.ts`produces workspace packages in `generated/` with all boilerplate.
9
+
Functions use a **template-based system**: developers write `handler.ts` + `handler.json` in `functions/`, and `scripts/generate.ts`copies template files from `templates/<type>/` into `generated/` with placeholder replacement and dependency merging.
The function templating system reduces each Constructive function to two user-authored files (`handler.ts` + `handler.json`) and generates all boilerplate (package.json, tsconfig, entry point) into a separate `generated/` directory.
5
+
The function templating system reduces each Constructive function to two user-authored files (`handler.ts` + `handler.json`) and generates all boilerplate into a separate `generated/` directory by copying and processing template files.
6
6
7
-
The `fn-runtime` package provides the runtime wiring: Express server via `fn-app`, per-request GraphQL clients, structured logging, and job metadata extraction.
7
+
Templates live in `templates/<type>/` as real, readable files with `{{placeholder}}` tokens. The generator copies them, replaces placeholders, merges dependencies, and symlinks handler source. The `fn-runtime` package provides the runtime wiring: Express server via `fn-app`, per-request GraphQL clients, structured logging, and job metadata extraction.
8
8
9
9
## Directory Structure
10
10
@@ -13,7 +13,7 @@ constructive-functions/
13
13
functions/ # User-authored source (git tracked)
14
14
example/
15
15
handler.ts # Business logic
16
-
handler.json # Metadata + dependencies
16
+
handler.json # Metadata + dependencies + template type
17
17
simple-email/
18
18
handler.ts
19
19
handler.json
@@ -22,15 +22,22 @@ constructive-functions/
22
22
handler.json
23
23
types.d.ts # Optional type declarations
24
24
25
+
templates/ # Template definitions (git tracked)
26
+
node-graphql/ # Default template type
27
+
package.json # Base package.json with {{name}}, {{version}}, {{description}}
28
+
tsconfig.json # Static compiler config
29
+
index.ts # Entry point with {{name}} placeholder
30
+
Dockerfile # Per-function production Docker build
31
+
k8s/
32
+
knative-service.yaml # Base Knative Service manifest
33
+
25
34
generated/ # All generated (gitignored)
26
35
example/
27
-
package.json # Workspace package
28
-
tsconfig.json # Compiler config
29
-
index.ts # Entry point (wires runtime + handler)
36
+
package.json # Merged from template + handler.json
37
+
tsconfig.json # Copied from template (+ .d.ts includes)
38
+
index.ts # Copied from template with {{name}} replaced
Minimal manifest with name, version, and any extra npm dependencies:
81
+
Manifest with name, version, template type, and extra npm dependencies:
74
82
75
83
```json
76
84
{
77
85
"name": "send-email-link",
78
86
"version": "1.1.0",
79
87
"description": "Sends invite, password reset, and verification emails",
88
+
"type": "node-graphql",
80
89
"dependencies": {
81
90
"graphql-tag": "^2.12.6"
82
91
}
83
92
}
84
93
```
85
94
86
-
Dependencies listed here are merged with `@constructive-io/fn-runtime` (always included) into the generated `package.json`.
95
+
| Field | Required | Description |
96
+
|---|---|---|
97
+
|`name`| Yes | Function name (used in package name and k8s manifests) |
98
+
|`version`| Yes | Semver version |
99
+
|`description`| No | Description for package.json |
100
+
|`type`| No | Template type from `templates/<type>/` (default: `"node-graphql"`) |
101
+
|`dependencies`| No | Extra npm deps merged into template's base package.json |
102
+
103
+
## Templates
104
+
105
+
Templates live in `templates/<type>/` and contain real files with `{{placeholder}}` tokens.
106
+
107
+
### Placeholder Tokens
108
+
109
+
| Token | Replaced With |
110
+
|---|---|
111
+
|`{{name}}`|`manifest.name` from handler.json |
112
+
|`{{version}}`|`manifest.version` from handler.json |
113
+
|`{{description}}`|`manifest.description` from handler.json (or empty string) |
114
+
115
+
### Template Files
116
+
117
+
| File | Processing |
118
+
|---|---|
119
+
|`package.json`| Placeholder replacement + deep merge of handler.json `dependencies`|
120
+
|`tsconfig.json`| Copied verbatim + `.d.ts` filenames appended to `include`|
121
+
|`index.ts`| Placeholder replacement only |
122
+
|`Dockerfile`| Used by `scripts/docker-build.ts` (not copied to generated/) |
123
+
|`k8s/*.yaml`| Reference manifests for new functions (not copied to generated/) |
124
+
125
+
### Adding a New Template Type
126
+
127
+
1. Create `templates/<new-type>/` with package.json, tsconfig.json, index.ts
128
+
2. Optionally add Dockerfile and k8s/ manifests
129
+
3. Reference it in handler.json: `"type": "<new-type>"`
87
130
88
131
## fn-runtime Package
89
132
@@ -128,44 +171,61 @@ GraphQL clients are created per-request (databaseId varies per job). If `GRAPHQL
128
171
129
172
## Generator Script
130
173
131
-
`scripts/generate.ts` is a TypeScript script that runs during `preinstall` via Node's native type stripping (`--experimental-strip-types`).
174
+
`scripts/generate.ts` runs during `preinstall` via Node's native type stripping (`--experimental-strip-types`). It uses only Node built-ins (no npm dependencies).
175
+
176
+
### How It Works
177
+
178
+
1. Discovers all `functions/*/handler.json` files
179
+
2. For each function, resolves the template type (default: `node-graphql`)
180
+
3. Copies template files (`package.json`, `tsconfig.json`, `index.ts`) into `generated/<name>/`
181
+
4. Replaces `{{placeholder}}` tokens with values from handler.json
182
+
5. Deep merges handler.json `dependencies` into template's `package.json`
183
+
6. Appends `.d.ts` filenames to `tsconfig.json``include` array
184
+
7. Creates symlinks for `handler.ts` and any `.d.ts` files
132
185
133
-
For each `functions/*/handler.json` it generates into `generated/<name>/`:
186
+
### CLI Flags
134
187
135
-
|File|Content|
188
+
|Flag|Description|
136
189
|---|---|
137
-
|`package.json`| Workspace package: name from `@constructive-io/<name>-fn`, deps merged from handler.json |
138
-
|`tsconfig.json`| Extends root tsconfig, compiles `index.ts` + `handler.ts` into `dist/`|
The generator uses `writeIfChanged()` — files are only written when content differs. Running `pnpm generate` twice produces no disk writes on the second run.
0 commit comments