@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.
@@ -0,0 +1,65 @@
1
+ # Positioning
2
+
3
+ Vertile AI IaC is for developers who want portable infrastructure intent without
4
+ operating a platform control plane.
5
+
6
+ ## Why This Exists
7
+
8
+ In the AI era, more products are built by one-person companies and very small
9
+ teams. Collaboration overhead matters less than abstraction quality. A single
10
+ developer, or an AI working with that developer, should not need to hand-author
11
+ different infrastructure definitions for every provider.
12
+
13
+ Vertile AI IaC provides one manifest for app infrastructure needs:
14
+
15
+ - app hosting
16
+ - domains
17
+ - environment variables and secrets
18
+ - object storage
19
+ - databases
20
+ - queues
21
+ - sandboxes and runtimes
22
+ - clusters and compute
23
+
24
+ Provider adapters compile those needs into Vercel, AWS, DigitalOcean, and later
25
+ other providers.
26
+
27
+ ## Crossplane Comparison
28
+
29
+ Crossplane is a strong reference point, but it makes Kubernetes the control
30
+ plane. Your app does not have to run on Kubernetes to use Crossplane, but the
31
+ Crossplane controllers do.
32
+
33
+ That is powerful for platform teams that need:
34
+
35
+ - RBAC
36
+ - audit logs
37
+ - CRDs
38
+ - admission policies
39
+ - namespaces
40
+ - Kubernetes secrets
41
+ - continuous controllers
42
+
43
+ Those are mostly developer-platform collaboration features. They are valuable
44
+ inside larger engineering organizations, but heavy for solo builders and small
45
+ teams that only want app infrastructure.
46
+
47
+ Vertile AI IaC takes a different position:
48
+
49
+ ```text
50
+ Crossplane:
51
+ Kubernetes as the infrastructure control plane.
52
+
53
+ Vertile AI IaC:
54
+ Git repo + CLI as the infrastructure control surface.
55
+ ```
56
+
57
+ ## Terraform And OpenTofu
58
+
59
+ Terraform and OpenTofu are execution engines, not portable abstractions.
60
+ Terraform can manage many providers, but provider resources are not portable by
61
+ themselves. An AWS S3 bucket resource is not the same as a DigitalOcean Spaces
62
+ resource or a Cloudflare R2 resource.
63
+
64
+ Vertile AI IaC treats Terraform/OpenTofu files as generated output. The portable
65
+ source of truth is the manifest.
@@ -0,0 +1,77 @@
1
+ # Roadmap
2
+
3
+ ## Phase 1: Stable Compiler Core
4
+
5
+ - Keep `infrastructure/iac/iac.json` as the only user-authored source of truth.
6
+ - Render provider-specific Terraform into `.vertile/terraform/<provider>/`.
7
+ - Keep legacy Vercel API reconciliation working until the Terraform path is
8
+ verified.
9
+ - Support `render`, `plan`, and guarded `apply`.
10
+ - Add schema validation with clear errors.
11
+
12
+ ## Phase 2: First-Class Resource Concepts
13
+
14
+ Move provider-specific escape hatches behind portable app infrastructure
15
+ concepts:
16
+
17
+ - `apps`
18
+ - `domains`
19
+ - `env`
20
+ - `objectStorage`
21
+ - `databases`
22
+ - `queues`
23
+ - `sandboxes`
24
+ - `clusters`
25
+
26
+ Each concept should have shared fields and optional provider overrides.
27
+
28
+ Current implementation status:
29
+
30
+ - `apps` and `domains` render to Vercel resources.
31
+ - `objectStorage` renders to AWS S3 and DigitalOcean Spaces.
32
+ - `databases` renders to AWS RDS and DigitalOcean Managed Databases.
33
+ - `queues` renders to AWS SQS.
34
+ - `sandboxes` and `clusters` render to AWS EC2 instances and DigitalOcean
35
+ Droplets.
36
+
37
+ ## Phase 3: Provider Matrix
38
+
39
+ Initial providers:
40
+
41
+ - Vercel: apps, domains, env vars, project settings.
42
+ - AWS: S3, RDS or DynamoDB, SQS, Lambda or ECS, EC2 where needed.
43
+ - DigitalOcean: Spaces, Managed Databases, App Platform, Droplets, Kubernetes
44
+ where needed.
45
+
46
+ Likely later providers:
47
+
48
+ - Cloudflare for DNS, Workers, R2, and queues.
49
+ - Neon and Supabase for databases.
50
+ - Fly.io, Render, and Railway for app hosting.
51
+ - Modal, E2B, and Daytona for sandbox or runtime providers.
52
+ - Hetzner and Vultr for cheaper compute and clusters.
53
+
54
+ ## Phase 4: AI-Native Workflow
55
+
56
+ - `vertile-iac explain`: explain a manifest in product language.
57
+ - `vertile-iac doctor`: detect unsupported mappings, missing credentials, and
58
+ risky settings.
59
+ - `vertile-iac migrate`: suggest moves between providers.
60
+ - Plan summaries that say what changes mean, not just what Terraform will do.
61
+
62
+ ## Phase 5: State And Outputs
63
+
64
+ - Use local state by default.
65
+ - Support optional remote backend configuration later.
66
+ - Add drift detection through `plan`.
67
+ - Write provider outputs to `.vertile/outputs/<env>.json`.
68
+
69
+ ## Guiding Rule
70
+
71
+ Vertile AI IaC should not become Terraform, Pulumi, or Crossplane.
72
+
73
+ It should stay focused on app-first portable infrastructure intent:
74
+
75
+ ```text
76
+ one manifest -> provider adapters -> Terraform/OpenTofu execution
77
+ ```
@@ -0,0 +1,22 @@
1
+ # Dynomic
2
+
3
+ Dynomic is a fixture project used to exercise Vertile AI IaC from the shape a
4
+ product repo would keep. It intentionally uses the full current manifest surface:
5
+ multiple Vercel apps, domains, preview/production env provisioning, local env
6
+ sync, portable storage/database/queue/compute concepts, provider overrides, and
7
+ provider-specific escape hatch resources.
8
+
9
+ It intentionally contains no real secrets. The env files use placeholder values
10
+ so package consumers can inspect and run dry-runs without extra setup.
11
+
12
+ ## Commands
13
+
14
+ ```bash
15
+ vertile-iac sync-env --repo-root examples/dynomic --variants=staging,production
16
+ vertile-iac env --repo-root examples/dynomic --targets=preview,production
17
+ vertile-iac projects --repo-root examples/dynomic --projects=web
18
+ vertile-iac domains --repo-root examples/dynomic --projects=web
19
+ vertile-iac render --repo-root examples/dynomic --target=all --env=production
20
+ ```
21
+
22
+ Apply commands require `VERCEL_TOKEN` and a real Vercel team/project.
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "dynomic-admin",
3
+ "private": true,
4
+ "scripts": {
5
+ "build": "echo \"dynomic admin fixture build\""
6
+ }
7
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://openapi.vercel.sh/vercel.json",
3
+ "framework": "nextjs"
4
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "dynomic-web",
3
+ "private": true,
4
+ "scripts": {
5
+ "build": "echo \"dynomic fixture build\""
6
+ }
7
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://openapi.vercel.sh/vercel.json",
3
+ "framework": "nextjs"
4
+ }
@@ -0,0 +1,191 @@
1
+ {
2
+ "$schema": "../../../../schema/iac.schema.json",
3
+ "version": 1,
4
+ "project": {
5
+ "key": "dynomic",
6
+ "name": "dynomic"
7
+ },
8
+ "environments": ["development", "preview", "production"],
9
+ "providers": {
10
+ "vercel": {
11
+ "teamSlug": "vertile-ai",
12
+ "projectDefaults": {
13
+ "nodeVersion": "20.x",
14
+ "enableAffectedProjectsDeployments": true
15
+ },
16
+ "resources": [
17
+ {
18
+ "type": "vercel_project_environment_variable",
19
+ "name": "example_escape_hatch",
20
+ "values": {
21
+ "project_id": "prj_dynomic_placeholder",
22
+ "key": "ESCAPE_HATCH_EXAMPLE",
23
+ "value": "configured-through-provider-resource",
24
+ "target": ["preview"]
25
+ }
26
+ }
27
+ ]
28
+ },
29
+ "aws": {
30
+ "region": "us-east-1",
31
+ "defaultTags": {
32
+ "Owner": "vertile-ai",
33
+ "Fixture": "dynomic"
34
+ },
35
+ "resources": [
36
+ {
37
+ "type": "aws_sns_topic",
38
+ "name": "events",
39
+ "values": {
40
+ "name": "dynomic-events"
41
+ }
42
+ }
43
+ ]
44
+ },
45
+ "digitalocean": {
46
+ "region": "nyc3",
47
+ "version": ">= 2.0.0",
48
+ "resources": [
49
+ {
50
+ "type": "digitalocean_project",
51
+ "name": "main",
52
+ "values": {
53
+ "name": "dynomic"
54
+ }
55
+ }
56
+ ]
57
+ }
58
+ },
59
+ "env": {
60
+ "sourceDir": "infrastructure",
61
+ "sync": {
62
+ "apps": ["web", "admin"],
63
+ "sharedKey": "shared"
64
+ }
65
+ },
66
+ "apps": [
67
+ {
68
+ "key": "web",
69
+ "id": "prj_dynomic_web_placeholder",
70
+ "name": "dynomic-web",
71
+ "framework": "nextjs",
72
+ "rootDirectory": "apps/web",
73
+ "nodeVersion": "20.x",
74
+ "domains": [
75
+ "dynomic.example.com",
76
+ {
77
+ "name": "preview.dynomic.example.com",
78
+ "gitBranch": "preview"
79
+ }
80
+ ],
81
+ "providers": {
82
+ "vercel": {
83
+ "enableAffectedProjectsDeployments": true
84
+ }
85
+ }
86
+ },
87
+ {
88
+ "key": "admin",
89
+ "id": "prj_dynomic_admin_placeholder",
90
+ "name": "dynomic-admin",
91
+ "framework": "nextjs",
92
+ "rootDirectory": "apps/admin",
93
+ "nodeVersion": "20.x",
94
+ "domains": [
95
+ "admin.dynomic.example.com",
96
+ {
97
+ "name": "admin-preview.dynomic.example.com",
98
+ "gitBranch": "preview"
99
+ }
100
+ ],
101
+ "env": {
102
+ "sharedPrefix": "ADMIN_"
103
+ }
104
+ }
105
+ ],
106
+ "domains": [
107
+ {
108
+ "name": "www.dynomic.example.com",
109
+ "app": "web"
110
+ }
111
+ ],
112
+ "objectStorage": [
113
+ {
114
+ "key": "uploads",
115
+ "visibility": "private",
116
+ "providers": {
117
+ "aws": {
118
+ "bucket": "dynomic-production-uploads",
119
+ "forceDestroy": true
120
+ },
121
+ "digitalocean": {
122
+ "name": "dynomic-uploads",
123
+ "acl": "private",
124
+ "region": "nyc3"
125
+ }
126
+ }
127
+ }
128
+ ],
129
+ "databases": [
130
+ {
131
+ "key": "appdb",
132
+ "engine": "postgres",
133
+ "providers": {
134
+ "aws": {
135
+ "engineVersion": "16",
136
+ "instanceClass": "db.t4g.micro",
137
+ "allocatedStorage": 20,
138
+ "databaseName": "dynomic",
139
+ "username": "dynomic",
140
+ "skipFinalSnapshot": true
141
+ },
142
+ "digitalocean": {
143
+ "engine": "pg",
144
+ "version": "16",
145
+ "size": "db-s-1vcpu-1gb",
146
+ "nodeCount": 1
147
+ }
148
+ }
149
+ }
150
+ ],
151
+ "queues": [
152
+ {
153
+ "key": "jobs",
154
+ "kind": "fifo",
155
+ "providers": {
156
+ "aws": {
157
+ "visibilityTimeoutSeconds": 60,
158
+ "messageRetentionSeconds": 345600
159
+ }
160
+ }
161
+ }
162
+ ],
163
+ "sandboxes": [
164
+ {
165
+ "key": "runner",
166
+ "providers": {
167
+ "aws": {
168
+ "instanceType": "t3.micro"
169
+ },
170
+ "digitalocean": {
171
+ "sizeSlug": "s-1vcpu-1gb"
172
+ }
173
+ }
174
+ }
175
+ ],
176
+ "clusters": [
177
+ {
178
+ "key": "workers",
179
+ "size": 2,
180
+ "providers": {
181
+ "aws": {
182
+ "instanceType": "t3.small"
183
+ },
184
+ "digitalocean": {
185
+ "nodes": 2,
186
+ "sizeSlug": "s-1vcpu-2gb"
187
+ }
188
+ }
189
+ }
190
+ ]
191
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "dynomic",
3
+ "private": true,
4
+ "scripts": {
5
+ "iac:env:dry-run": "vertile-iac env --repo-root . --targets=preview,production",
6
+ "iac:env:apply": "vertile-iac env --repo-root . --targets=preview,production --apply",
7
+ "iac:projects:dry-run": "vertile-iac projects --repo-root .",
8
+ "iac:projects:apply": "vertile-iac projects --repo-root . --apply",
9
+ "iac:domains:dry-run": "vertile-iac domains --repo-root .",
10
+ "iac:domains:apply": "vertile-iac domains --repo-root . --apply",
11
+ "iac:sync-env": "vertile-iac sync-env --repo-root . --variants=staging,production",
12
+ "iac:render": "vertile-iac render --repo-root . --target=vercel --env=production"
13
+ },
14
+ "devDependencies": {
15
+ "@vertile-ai/iac": "0.0.1"
16
+ }
17
+ }
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@vertile-ai/iac",
3
+ "version": "0.0.1",
4
+ "description": "App-first portable infrastructure intent for Vercel, AWS, and DigitalOcean.",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/vertile-ai/iac.git"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/vertile-ai/iac/issues"
12
+ },
13
+ "homepage": "https://github.com/vertile-ai/iac#readme",
14
+ "bin": {
15
+ "vertile-iac": "src/cli.mjs",
16
+ "vertile-iac-render": "src/render.mjs",
17
+ "vertile-iac-plan": "src/plan.mjs",
18
+ "vertile-iac-apply": "src/apply.mjs",
19
+ "vertile-iac-sync-env": "src/sync-env.mjs",
20
+ "vertile-iac-env": "src/provision-env.mjs",
21
+ "vertile-iac-projects": "src/reconcile-project-settings.mjs",
22
+ "vertile-iac-domains": "src/reconcile-project-domains.mjs"
23
+ },
24
+ "files": [
25
+ "src",
26
+ "docs",
27
+ "schema",
28
+ "examples",
29
+ "!examples/**/.env",
30
+ "!examples/**/.env.*",
31
+ "README.md"
32
+ ],
33
+ "scripts": {
34
+ "test": "node --test",
35
+ "check": "find src -name '*.mjs' -print0 | xargs -0 -n1 node --check",
36
+ "sync-env": "node src/sync-env.mjs",
37
+ "env:dry-run": "node src/provision-env.mjs",
38
+ "env:apply": "node src/provision-env.mjs --apply",
39
+ "projects:dry-run": "node src/reconcile-project-settings.mjs",
40
+ "projects:apply": "node src/reconcile-project-settings.mjs --apply",
41
+ "domains:dry-run": "node src/reconcile-project-domains.mjs",
42
+ "domains:apply": "node src/reconcile-project-domains.mjs --apply"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
+ "engines": {
48
+ "node": ">=20"
49
+ },
50
+ "packageManager": "pnpm@10.33.0"
51
+ }