@vertile-ai/iac 0.0.1

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/README.md ADDED
@@ -0,0 +1,255 @@
1
+ # @vertile-ai/iac
2
+
3
+ Opinionated infrastructure-as-code tooling.
4
+
5
+ Install once, define infrastructure once, then run `vertile-iac plan` or
6
+ guarded `vertile-iac apply` to manage Vercel, AWS, and DigitalOcean changes
7
+ from the same IaC source of truth.
8
+
9
+ Product repos keep their own manifests and env source files, while this package
10
+ renders provider-specific Terraform workspaces and keeps the existing
11
+ Vercel reconciliation flow available as compatibility commands.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ pnpm add -D @vertile-ai/iac
17
+ ```
18
+
19
+ Terraform is required for `vertile-iac plan`. The `render` command does not call
20
+ Terraform and can be used offline.
21
+
22
+ ## Commands
23
+
24
+ ```bash
25
+ vertile-iac render --target=all --env=production
26
+ vertile-iac plan --target=vercel --env=preview
27
+ vertile-iac apply --target=aws --env=production --yes
28
+
29
+ vertile-iac sync-env --repo-root ../noop --variants=local,staging,test
30
+ vertile-iac env --repo-root ../noop --scope=all --targets=preview,production
31
+ vertile-iac projects --repo-root ../noop
32
+ vertile-iac domains --repo-root ../noop
33
+ ```
34
+
35
+ The `render`, `plan`, and `apply` commands read `infrastructure/iac/iac.json`
36
+ and write generated Terraform workspaces to `.vertile/terraform/<target>/`.
37
+
38
+ Apply is guarded. Non-interactive apply requires `--yes`, which passes
39
+ Terraform `-auto-approve`.
40
+
41
+ The `env`, `projects`, and `domains` commands reconcile Vercel through the
42
+ Vercel API. They still read the older compatibility manifest files when those
43
+ files exist, and otherwise derive the same desired state from
44
+ `infrastructure/iac/iac.json`.
45
+
46
+ Apply mode requires `VERCEL_TOKEN`, `VERCEL_API_KEY`, or a token file:
47
+
48
+ ```bash
49
+ VERCEL_TOKEN=... vertile-iac env --repo-root ../noop --apply
50
+ ```
51
+
52
+ ## Manifest Layout
53
+
54
+ The new Terraform flow expects the target project to have:
55
+
56
+ ```text
57
+ infrastructure/iac/iac.json
58
+ infrastructure/shared/.env.development
59
+ infrastructure/shared/.env.staging
60
+ infrastructure/shared/.env.production
61
+ infrastructure/<app-key>/.env.development
62
+ infrastructure/<app-key>/.env.staging
63
+ infrastructure/<app-key>/.env.production
64
+ ```
65
+
66
+ Minimal `iac.json` example:
67
+
68
+ ```json
69
+ {
70
+ "$schema": "./node_modules/@vertile-ai/iac/schema/iac.schema.json",
71
+ "version": 1,
72
+ "project": { "name": "example" },
73
+ "environments": ["development", "preview", "production"],
74
+ "providers": {
75
+ "vercel": { "team": "example-team" },
76
+ "aws": { "region": "us-east-1" },
77
+ "digitalocean": {}
78
+ },
79
+ "apps": [
80
+ {
81
+ "key": "web",
82
+ "name": "example-web",
83
+ "framework": "nextjs",
84
+ "rootDirectory": "apps/web",
85
+ "domains": ["web.example.com"]
86
+ }
87
+ ],
88
+ "env": {
89
+ "sourceDir": "infrastructure",
90
+ "sync": {
91
+ "apps": ["web"]
92
+ }
93
+ },
94
+ "domains": []
95
+ }
96
+ ```
97
+
98
+ Portable concepts currently include:
99
+
100
+ - `apps`
101
+ - `domains`
102
+ - `objectStorage`
103
+ - `databases`
104
+ - `queues`
105
+ - `sandboxes`
106
+ - `clusters`
107
+
108
+ Provider-specific Terraform resources can be added under
109
+ `providers.<target>.resources` as `{ "type", "name", "values" }` objects while
110
+ the manifest schema stays narrow.
111
+
112
+ The compatibility Vercel commands expect the target project to have:
113
+
114
+ ```text
115
+ infrastructure/shared/.env.development
116
+ infrastructure/shared/.env.staging
117
+ infrastructure/shared/.env.production
118
+ infrastructure/<project-key>/.env.development
119
+ infrastructure/<project-key>/.env.staging
120
+ infrastructure/<project-key>/.env.production
121
+ ```
122
+
123
+ When the old compatibility files exist, they are used directly:
124
+
125
+ ```text
126
+ infrastructure/iac/env-manifest.json
127
+ infrastructure/iac/project-settings.json
128
+ infrastructure/iac/project-domains.json
129
+ ```
130
+
131
+ When they do not exist, the Vercel commands derive equivalent manifests from
132
+ `iac.json`:
133
+
134
+ - `providers.vercel.teamSlug` or `providers.vercel.team` becomes the Vercel team.
135
+ - `env.sourceDir` selects the env source folder and defaults to `infrastructure`.
136
+ - `apps[].key`, `apps[].id` or `apps[].projectId`, and `apps[].name` become managed Vercel projects.
137
+ - `apps[].rootDirectory`, `apps[].nodeVersion`, and
138
+ `apps[].enableAffectedProjectsDeployments` become project settings.
139
+ - `apps[].domains` and top-level `domains[]` become project domains.
140
+
141
+ Vercel targets map to env files as follows:
142
+
143
+ - `development` -> `.env.development`
144
+ - `preview` -> `.env.staging`
145
+ - `production` -> `.env.production`
146
+
147
+ Pure local env files such as `.env.local` are intentionally not synced to
148
+ Vercel. The default manifest location can be overridden:
149
+
150
+ ```bash
151
+ vertile-iac env \
152
+ --repo-root ../some-project \
153
+ --manifest ./deploy/env-manifest.json \
154
+ --infra-dir infrastructure
155
+ ```
156
+
157
+ ## Env File Sync
158
+
159
+ `vertile-iac sync-env` generates package-local `.env.*` files from the env
160
+ source tree declared by `iac.json`. This is separate from `vertile-iac env`,
161
+ which reconciles Vercel remote environment variables.
162
+
163
+ The boundary is:
164
+
165
+ - `env.sourceDir` is the source tree, defaulting to `infrastructure`.
166
+ - `env.sync.sharedKey` is the shared source folder, defaulting to `shared`.
167
+ - `env.sync.apps` limits which `apps[]` are materialized locally. Without it,
168
+ all apps are synced.
169
+ - Each app reads from `<env.sourceDir>/<app.key>` by default.
170
+ - Each app writes into `apps[].rootDirectory` by default.
171
+ - `apps[].env.sourceKey` and `apps[].env.outputDir` override those defaults.
172
+ - `apps[].env.sharedPrefix` projects prefixed shared keys into one app, strips
173
+ the prefix in that app's generated file, and keeps those prefixed keys out of
174
+ other generated app env files.
175
+
176
+ Examples:
177
+
178
+ ```json
179
+ {
180
+ "env": {
181
+ "sourceDir": "infrastructure",
182
+ "sync": {
183
+ "apps": ["landing", "web-client", "web-server"],
184
+ "sharedKey": "shared"
185
+ }
186
+ },
187
+ "apps": [
188
+ {
189
+ "key": "web-client",
190
+ "rootDirectory": "packages/web-client",
191
+ "env": { "sharedPrefix": "WEB_CLIENT_" }
192
+ }
193
+ ]
194
+ }
195
+ ```
196
+
197
+ Supported local sync variants are `local`, `staging`, `preview`, `production`,
198
+ and `test`. `preview` is an alias for `.env.staging`.
199
+
200
+ ## Shared Options
201
+
202
+ - `--repo-root <path>`: product repo root containing `infrastructure/`.
203
+ - `--iac-dir <path>`: manifest directory, default `infrastructure/iac`.
204
+ - `--manifest <path>`: env manifest path.
205
+ - `--project-settings <path>`: project settings manifest path.
206
+ - `--project-domains <path>`: project domains manifest path.
207
+ - `--infra-dir <path>`: override `env-manifest.json` `infraDir`.
208
+ - `--token-file <path>`: token file, default `<repo-root>/.vercel.token`.
209
+ - `--auto-create-keys <a,b>`: project keys allowed for Vercel auto-create.
210
+ - `--auto-create-prefixes <a,b>`: project key prefixes allowed for Vercel auto-create.
211
+ - `--iac-manifest <path>`: source-of-truth IaC manifest, default `<iac-dir>/iac.json`.
212
+ - `--out <path>`: generated Terraform root, default `.vertile/terraform`.
213
+ - `--target <name|all>`: `vercel`, `aws`, `digitalocean`, or `all`.
214
+ - `--env <name>`: environment to render, plan, or apply, default `production`.
215
+ - `--terraform-bin <path>`: Terraform executable for `plan`, default `terraform`.
216
+ - `--yes`: allow non-interactive `apply` with Terraform auto-approve.
217
+
218
+ ## Docs
219
+
220
+ Public-facing docs live in `docs/`. The static docs website entrypoint is:
221
+
222
+ ```text
223
+ docs/index.html
224
+ ```
225
+
226
+ ## Examples
227
+
228
+ `examples/dynomic` is a publishable fixture project that shows the current app
229
+ shape for Vercel project settings, domains, preview/production env
230
+ provisioning, local package env sync, portable resource concepts, provider
231
+ overrides, and provider-specific escape hatch resources.
232
+
233
+ ## Schema
234
+
235
+ The manifest schema is published as JSON Schema Draft 2020-12:
236
+
237
+ ```text
238
+ schema/iac.schema.json
239
+ ```
240
+
241
+ Product manifests can reference the package copy:
242
+
243
+ ```json
244
+ {
245
+ "$schema": "./node_modules/@vertile-ai/iac/schema/iac.schema.json"
246
+ }
247
+ ```
248
+
249
+ ## Publishing
250
+
251
+ Publish with public access:
252
+
253
+ ```bash
254
+ pnpm publish --access public
255
+ ```
package/docs/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # Vertile AI IaC Docs
2
+
3
+ Vertile AI IaC is an app-first infrastructure abstraction for solo builders and
4
+ small teams. Define infrastructure intent once, then compile it into
5
+ provider-specific infrastructure without adopting Kubernetes as a control plane.
6
+
7
+ ## Start Here
8
+
9
+ - [Positioning](./positioning.md)
10
+ - [Roadmap](./roadmap.md)
11
+ - [Manifest Guide](./manifest.md)
12
+ - [Static Website](./index.html)
13
+
14
+ ## Core Idea
15
+
16
+ Crossplane is Kubernetes-first platform infrastructure.
17
+ Terraform and OpenTofu are provider-specific execution engines.
18
+ Vertile AI IaC is app-first portable infrastructure intent.
19
+
20
+ The user-authored source of truth is:
21
+
22
+ ```text
23
+ infrastructure/iac/iac.json
24
+ ```
25
+
26
+ Generated Terraform lives under:
27
+
28
+ ```text
29
+ .vertile/terraform/<provider>/
30
+ ```
31
+
32
+ Users edit the manifest. Vertile AI IaC renders provider-specific infrastructure.
33
+
34
+ ## Commands
35
+
36
+ ```bash
37
+ vertile-iac render --target=all --env=production
38
+ vertile-iac plan --target=aws --env=production
39
+ vertile-iac apply --target=aws --env=production --yes
40
+ ```
@@ -0,0 +1,276 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Vertile AI IaC</title>
7
+ <style>
8
+ :root {
9
+ color-scheme: light;
10
+ --bg: #fbfaf7;
11
+ --ink: #161615;
12
+ --muted: #66615b;
13
+ --line: #ddd7ce;
14
+ --panel: #ffffff;
15
+ --accent: #0f766e;
16
+ --accent-ink: #0b4f4a;
17
+ --code: #f1eee8;
18
+ }
19
+
20
+ * {
21
+ box-sizing: border-box;
22
+ }
23
+
24
+ body {
25
+ margin: 0;
26
+ background: var(--bg);
27
+ color: var(--ink);
28
+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
29
+ line-height: 1.55;
30
+ }
31
+
32
+ header,
33
+ main,
34
+ footer {
35
+ width: min(1080px, calc(100% - 40px));
36
+ margin: 0 auto;
37
+ }
38
+
39
+ header {
40
+ min-height: 78vh;
41
+ display: grid;
42
+ align-content: center;
43
+ padding: 56px 0 40px;
44
+ border-bottom: 1px solid var(--line);
45
+ }
46
+
47
+ nav {
48
+ position: absolute;
49
+ top: 20px;
50
+ left: 50%;
51
+ transform: translateX(-50%);
52
+ width: min(1080px, calc(100% - 40px));
53
+ display: flex;
54
+ align-items: center;
55
+ justify-content: space-between;
56
+ gap: 20px;
57
+ }
58
+
59
+ nav a {
60
+ color: var(--muted);
61
+ text-decoration: none;
62
+ font-size: 14px;
63
+ }
64
+
65
+ .brand {
66
+ color: var(--ink);
67
+ font-weight: 700;
68
+ }
69
+
70
+ .links {
71
+ display: flex;
72
+ gap: 18px;
73
+ flex-wrap: wrap;
74
+ justify-content: flex-end;
75
+ }
76
+
77
+ h1 {
78
+ max-width: 820px;
79
+ margin: 0;
80
+ font-size: clamp(46px, 8vw, 90px);
81
+ line-height: 0.98;
82
+ letter-spacing: 0;
83
+ }
84
+
85
+ .lede {
86
+ max-width: 720px;
87
+ margin: 26px 0 0;
88
+ color: var(--muted);
89
+ font-size: clamp(18px, 2.3vw, 24px);
90
+ }
91
+
92
+ .actions {
93
+ display: flex;
94
+ gap: 14px;
95
+ flex-wrap: wrap;
96
+ margin-top: 34px;
97
+ }
98
+
99
+ .button {
100
+ display: inline-flex;
101
+ min-height: 44px;
102
+ align-items: center;
103
+ justify-content: center;
104
+ border: 1px solid var(--ink);
105
+ border-radius: 6px;
106
+ padding: 10px 16px;
107
+ color: var(--ink);
108
+ text-decoration: none;
109
+ font-weight: 650;
110
+ }
111
+
112
+ .button.primary {
113
+ border-color: var(--accent);
114
+ background: var(--accent);
115
+ color: #fff;
116
+ }
117
+
118
+ main {
119
+ padding: 42px 0 64px;
120
+ }
121
+
122
+ section {
123
+ padding: 34px 0;
124
+ border-bottom: 1px solid var(--line);
125
+ }
126
+
127
+ h2 {
128
+ margin: 0 0 14px;
129
+ font-size: 28px;
130
+ line-height: 1.15;
131
+ letter-spacing: 0;
132
+ }
133
+
134
+ p {
135
+ max-width: 780px;
136
+ }
137
+
138
+ .grid {
139
+ display: grid;
140
+ grid-template-columns: repeat(3, minmax(0, 1fr));
141
+ gap: 14px;
142
+ margin-top: 22px;
143
+ }
144
+
145
+ .tile {
146
+ min-height: 160px;
147
+ border: 1px solid var(--line);
148
+ border-radius: 8px;
149
+ background: var(--panel);
150
+ padding: 18px;
151
+ }
152
+
153
+ .tile h3 {
154
+ margin: 0 0 8px;
155
+ font-size: 18px;
156
+ }
157
+
158
+ .tile p {
159
+ margin: 0;
160
+ color: var(--muted);
161
+ }
162
+
163
+ pre {
164
+ overflow: auto;
165
+ border: 1px solid var(--line);
166
+ border-radius: 8px;
167
+ background: var(--code);
168
+ padding: 18px;
169
+ }
170
+
171
+ code {
172
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
173
+ font-size: 0.94em;
174
+ }
175
+
176
+ footer {
177
+ padding: 28px 0 42px;
178
+ color: var(--muted);
179
+ font-size: 14px;
180
+ }
181
+
182
+ @media (max-width: 760px) {
183
+ header {
184
+ min-height: 84vh;
185
+ }
186
+
187
+ nav {
188
+ align-items: flex-start;
189
+ flex-direction: column;
190
+ }
191
+
192
+ .links {
193
+ justify-content: flex-start;
194
+ }
195
+
196
+ .grid {
197
+ grid-template-columns: 1fr;
198
+ }
199
+ }
200
+ </style>
201
+ </head>
202
+ <body>
203
+ <nav>
204
+ <a class="brand" href="#top">Vertile AI IaC</a>
205
+ <div class="links">
206
+ <a href="#manifest">Manifest</a>
207
+ <a href="#providers">Providers</a>
208
+ <a href="#roadmap">Roadmap</a>
209
+ </div>
210
+ </nav>
211
+
212
+ <header id="top">
213
+ <h1>App-first infrastructure intent.</h1>
214
+ <p class="lede">Define infrastructure once, then render, plan, and apply provider-specific Terraform for Vercel, AWS, DigitalOcean, and future app infrastructure providers.</p>
215
+ <div class="actions">
216
+ <a class="button primary" href="#manifest">Read the manifest guide</a>
217
+ <a class="button" href="./roadmap.md">View roadmap</a>
218
+ </div>
219
+ </header>
220
+
221
+ <main>
222
+ <section id="manifest">
223
+ <h2>One Source Of Truth</h2>
224
+ <p>The user-authored source of truth is <code>infrastructure/iac/iac.json</code>. Terraform files are generated output under <code>.vertile/terraform/&lt;provider&gt;/</code>.</p>
225
+ <pre><code>{
226
+ "version": 1,
227
+ "project": { "name": "example" },
228
+ "environments": ["development", "preview", "production"],
229
+ "providers": {
230
+ "vercel": { "team": "example-team" },
231
+ "aws": { "region": "us-east-1" },
232
+ "digitalocean": {}
233
+ },
234
+ "apps": [{ "key": "web", "domains": ["web.example.com"] }],
235
+ "objectStorage": [{ "key": "uploads" }],
236
+ "databases": [{ "key": "appdb", "engine": "postgres" }],
237
+ "queues": [{ "key": "jobs" }],
238
+ "sandboxes": [{ "key": "runner" }],
239
+ "clusters": [{ "key": "workers", "size": 2 }]
240
+ }</code></pre>
241
+ </section>
242
+
243
+ <section id="providers">
244
+ <h2>Provider Adapters</h2>
245
+ <p>Vertile AI IaC keeps portable concepts in the manifest and compiles them into provider-specific resources. Provider overrides are available when a platform has unique behavior.</p>
246
+ <div class="grid">
247
+ <div class="tile">
248
+ <h3>Vercel</h3>
249
+ <p>Apps, domains, env vars, and project settings for frontend and serverless deployments.</p>
250
+ </div>
251
+ <div class="tile">
252
+ <h3>AWS</h3>
253
+ <p>Object storage, databases, queues, compute, and clusters for broader infrastructure needs.</p>
254
+ </div>
255
+ <div class="tile">
256
+ <h3>DigitalOcean</h3>
257
+ <p>Spaces, managed databases, app hosting, droplets, and pragmatic compute defaults.</p>
258
+ </div>
259
+ </div>
260
+ </section>
261
+
262
+ <section id="roadmap">
263
+ <h2>Built For Small Teams And AI Workflows</h2>
264
+ <p>Crossplane makes Kubernetes the infrastructure control plane. Vertile AI IaC uses a Git repo and CLI as the control surface, which is lighter for solo builders and app-first teams.</p>
265
+ <pre><code>pnpm add -D @vertile-ai/iac
266
+ vertile-iac render --target=all --env=production
267
+ vertile-iac plan --target=aws --env=production
268
+ vertile-iac apply --target=aws --env=production --yes</code></pre>
269
+ </section>
270
+ </main>
271
+
272
+ <footer>
273
+ Crossplane is Kubernetes-first platform infrastructure. Terraform/OpenTofu is provider-specific execution. Vertile AI IaC is app-first portable infrastructure intent.
274
+ </footer>
275
+ </body>
276
+ </html>
@@ -0,0 +1,130 @@
1
+ # Manifest Guide
2
+
3
+ The manifest is the source of truth for app infrastructure intent.
4
+
5
+ ```text
6
+ infrastructure/iac/iac.json
7
+ ```
8
+
9
+ Generated Terraform is an implementation detail:
10
+
11
+ ```text
12
+ .vertile/terraform/vercel/
13
+ .vertile/terraform/aws/
14
+ .vertile/terraform/digitalocean/
15
+ ```
16
+
17
+ ## Minimal Manifest
18
+
19
+ ```json
20
+ {
21
+ "$schema": "./node_modules/@vertile-ai/iac/schema/iac.schema.json",
22
+ "version": 1,
23
+ "project": { "name": "example" },
24
+ "environments": ["development", "preview", "production"],
25
+ "providers": {
26
+ "vercel": { "team": "example-team" },
27
+ "aws": { "region": "us-east-1" },
28
+ "digitalocean": {}
29
+ },
30
+ "apps": [
31
+ {
32
+ "key": "web",
33
+ "name": "example-web",
34
+ "framework": "nextjs",
35
+ "rootDirectory": "apps/web",
36
+ "domains": ["web.example.com"]
37
+ }
38
+ ],
39
+ "domains": [],
40
+ "objectStorage": [{ "key": "uploads", "visibility": "private" }],
41
+ "databases": [{ "key": "appdb", "engine": "postgres" }],
42
+ "queues": [{ "key": "jobs" }],
43
+ "sandboxes": [{ "key": "runner" }],
44
+ "clusters": [{ "key": "workers", "size": 2 }]
45
+ }
46
+ ```
47
+
48
+ The schema is published as JSON Schema Draft 2020-12 at
49
+ `schema/iac.schema.json`.
50
+
51
+ ## Provider Overrides
52
+
53
+ Portable concepts should be shared by default, with provider-specific overrides
54
+ only where the provider really differs.
55
+
56
+ ```json
57
+ {
58
+ "objectStorage": [
59
+ {
60
+ "key": "assets",
61
+ "visibility": "private",
62
+ "providers": {
63
+ "aws": { "storageClass": "standard" },
64
+ "digitalocean": { "region": "nyc3" }
65
+ }
66
+ }
67
+ ]
68
+ }
69
+ ```
70
+
71
+ ## Escape Hatch
72
+
73
+ Provider-specific Terraform resources can be expressed under
74
+ `providers.<target>.resources` while the portable schema matures.
75
+
76
+ ```json
77
+ {
78
+ "providers": {
79
+ "aws": {
80
+ "resources": [
81
+ {
82
+ "type": "aws_s3_bucket",
83
+ "name": "assets",
84
+ "values": {
85
+ "bucket": "example-assets"
86
+ }
87
+ }
88
+ ]
89
+ }
90
+ }
91
+ }
92
+ ```
93
+
94
+ Use this as a bridge, not as the primary authoring model. The long-term goal is
95
+ to promote common patterns into first-class portable concepts.
96
+
97
+ ## Supported Concepts
98
+
99
+ | Concept | Vercel | AWS | DigitalOcean |
100
+ | --- | --- | --- | --- |
101
+ | `apps` | Vercel Project | - | - |
102
+ | `domains` | Vercel Project Domain | - | - |
103
+ | `objectStorage` | - | S3 Bucket | Spaces Bucket |
104
+ | `databases` | - | RDS Instance | Managed Database Cluster |
105
+ | `queues` | - | SQS Queue | - |
106
+ | `sandboxes` | - | EC2 Instance | Droplet |
107
+ | `clusters` | - | EC2 Instance group | Droplet group |
108
+
109
+ Unsupported provider cells are intentionally blank. Use provider-specific
110
+ resources or another provider for those capabilities.
111
+
112
+ ## Commands
113
+
114
+ Render generated Terraform:
115
+
116
+ ```bash
117
+ vertile-iac render --target=all --env=production
118
+ ```
119
+
120
+ Preview changes with Terraform:
121
+
122
+ ```bash
123
+ vertile-iac plan --target=aws --env=production
124
+ ```
125
+
126
+ Apply changes with explicit non-interactive approval:
127
+
128
+ ```bash
129
+ vertile-iac apply --target=aws --env=production --yes
130
+ ```