Roadmap
Internal tracking doc - improvements, new providers, and the path to a publishable NPM package.
Tech Debt
- [x]
config/default.shis superseded byconfig/default.yaml- can be removed once Ansible is confirmed as the standard - [x]
LoadBalancerBuilder(DO) does not extendBaseBuilder- inconsistent lifecycle, usesConfig.isGlobalDryRun()instead ofisDryRunActive(), no sidecar/protection support - [x] DO
DomainBuilderdeletes and recreates records on every deploy instead of true upsert - can cause brief DNS gaps - [x] Firebase
FunctionsBuilderskips eager discovery (resolvesnullimmediately) - diverges from the standard pattern where discovery fires in the constructor - [x] Scattered
as anycasts on Route53 record types and elsewhere - replace with proper SDK type imports where possible - [x]
DropletBuilder.sslKey()method named incorrectly - all other providers use.sshKey(); renamed to.sshKey()with a deprecated.sslKey()shim for backwards compatibility
Testing
- [x] Basic test suite (core:
config.test.ts,output.test.ts) - [x] Provider unit tests with mocked API clients - each builder's
deploy()anddestroy()paths covered (create, skip, update, dry-run) (DO, AWS S3/Route53/Lambda, and Firebase Hosting/Functions fully complete) - [x] Dry-run integration tests - run full stacks with
dryRun: trueagainst real provider credentials to verify discovery without writing - [x] CI pipeline - run unit tests on every push; dry-run suite on PRs that touch provider code
- [x] End-to-end tests against sandboxes (LocalStack for AWS, DO staging token, Firebase emulator)
Provider Improvements
Proxmox
- [x] Cluster-aware node selection - pick the node with the most free RAM via
/nodesAPI instead of always using the first configured node - [x]
.machine()builder method - let users override machine type (i440fx vs q35) per VM rather than the hardcoded default - [x]
CONFIG.PRODUCTIONentry insrc/types/proxmox.ts - [x] Golden Image / VM Templates (
Proxmox.Template) - Declare pre-baked templates with fluent OS base images and playbook provisioning (Packer-like behavior). Clone VMs from these templates to drop VM deployment time from minutes to seconds.
AWS
- [x] CloudFront cache invalidation -
.invalidate(paths[])on a CloudFront builder - [x] S3 file upload -
.upload(filePath)uploads a single file to the bucket on deploy - [x] Route53 record types - A, AAAA, CNAME, MX, TXT, NS, PTR, SRV, CAA, NAPTR, SPF via
.record(); per-record TTL; TXT auto-quoting - [x] S3 static site hosting -
.staticSite()sets index/error documents and public-read policy - [x] IAM - role and inline/managed policy management; useful for cross-service wiring without manual console steps
- [x] CloudWatch alarms - CPU/memory thresholds on Fargate and RDS with SNS notification target
- [x] EC2 - Provision EC2 virtual machines with VPC/SG support and stateless tag-based playbook provisioning.
- [x] Golden Image / VM Templates (
AWS.Template) - Declare pre-baked custom AMIs with fluent OS base images and playbook provisioning (Packer-like behavior). Clone EC2 instances from these templates to drop VM deployment time from minutes to seconds.
DigitalOcean
- [x] Droplet, Domain, Firewall, Certificate, LoadBalancer
- [x]
LoadBalancerBuilderoverhaul - extendBaseBuilder, add.region(),.healthCheck(),.stickySession(), configurable forwarding rules and SSL termination - [x] Spaces - S3-compatible object storage;
.bucket(),.cors(),.acl() - [x] Managed databases - Postgres, MySQL, Redis; analogous to AWS RDS
- [x] App Platform - deploy from a GitHub repo or container image without managing Droplets
- [x] VPC - create and assign Droplets/databases to a private network
- [x] Domain: add AAAA, SRV, CAA record types; implement
destroy()for domain and records
Firebase
- [x] Firebase Hosting - deploy a web app from a local build directory; file-level caching via SHA256
- [x] Firebase Functions - deploy Cloud Functions v2 from source; full create/update/delete lifecycle
- [x] Firebase Firestore - rules deployment and composite index management
- [x] Firebase Auth - email/password, anonymous, phone, and OAuth providers (Google, GitHub, Facebook, Twitter, Apple, Microsoft); authorized domains
- [x] Firebase Storage - rules deployment, CORS configuration, lifecycle policies
- [x] Firebase RemoteConfig - typed parameters (string, bool, number, JSON), conditions, and per-condition overrides; ETag-safe PUT
- [x] Firebase App Check - enforce attestation on Hosting, Functions, and Firestore
Google Cloud Platform (GCP)
- [x] GCP Cloud Run (
GCP.CloudRun) - Deploy containerized services with auto-scaling and public URLs (Fargate parity) - [x] GCP Cloud SQL (
GCP.CloudSQL) - Managed PostgreSQL and MySQL database instances (RDS parity) - [x] GCP Secret Manager (
GCP.Secret) - Manage and inject GCP secrets at deploy-time (SecretsManager parity) - [x] GCP Pub/Sub (
GCP.PubSub) - Topics and subscriptions for decoupled messaging (SQS/SNS parity) - [x] GCP Cloud DNS (
GCP.CloudDNS) - Managed zones, record sets, and DNS routing (Route53 parity) - [x] GCP IAM (
GCP.ServiceAccount/GCP.IAMBinding) - Service accounts, custom roles, and resource-level IAM bindings (IAM parity) - [x] GCP Compute VM (
GCP.VM) - Compute instances with external IP NAT and universal playbook provisioning (EC2/Proxmox parity) - [x] Golden Image / VM Templates (
GCP.Template) - Declare pre-baked GCP custom images with fluent OS base images and playbook provisioning (Packer-like behavior). Clone Compute VMs from these templates to drop VM deployment time from minutes to seconds.
New Providers
Cloudflare
Strong candidate for a first-class provider - widely used alongside or instead of AWS for DNS and CDN, and the API is clean.
@Deploy({ cloudflare: { token: process.env.CF_TOKEN } })
class EdgeStack extends Stack {
zone = CF.Zone("example.com");
worker = CF.Worker("api").script("./workers/api").route("api.example.com/*");
kv = CF.KV("sessions");
r2 = CF.R2("assets");
}
- [x] Zone + DNS - hosted zone discovery, full record type support (mirrors Route53 implementation)
- [x] Workers - deploy a Worker script with routes and env bindings
- [x] KV - key-value namespace management
- [x] R2 - S3-compatible object storage; useful as a cheaper CloudFront+S3 alternative
- [x] Pages - static site hosting with preview deployments
Hetzner Cloud
Popular self-hosting alternative to DigitalOcean - similar API shape, easy to add.
- [x] Server - analogous to DO Droplet; image, type, location, SSH key
- [x] Network / VPC - private networking between servers
- [x] Firewall - inbound/outbound rules
- [x] Load Balancer - HTTP/HTTPS with health checks
- [x] Volume - persistent block storage attached to servers
Vultr
Excellent global footprint with high-performance compute, bare-metal options, and GPU cloud support.
- [ ] Instance - Cloud compute VPS instances (regular and high-frequency)
- [ ] Bare Metal - Dedicated physical servers provisioned via API
- [ ] VPC / Network - Private network boundaries (VPC 2.0)
- [ ] Block Storage - SSD-backed volumes attached to instances
- [ ] Firewall - Group-based access control rules
Microsoft Azure
Enterprise cloud provider - critical for corporate environments. Needs resource group management, VM provisioning, and active directory support.
- [x] Resource Groups - basic resource lifecycle boundary
- [x] Azure App Service (
Azure.AppService) - PaaS web app provisioning with slots support - [x] Azure Virtual Machines (
Azure.VM) - Compute instances with private virtual network support and universal playbook provisioning - [x] Azure SQL Database (
Azure.SQL) - Managed databases with automated failover groups - [x] Azure Blob Storage (
Azure.BlobStorage) - Massively scalable object storage
Akamai
Enterprise CDN/edge - complex enough to warrant a dedicated maintainer; community-driven.
NPM Package
- [x] Switch
package.jsonto"type": "module"(ESM) - [x] Basic test suite
- [x] Add
"exports"map with per-provider sub-paths so consumers can import only what they need (e.g.puls-dev/aws,puls-dev/firebase) - [x] Ship compiled JS +
.d.tsdeclarations - [x] Standard dependencies for zero-friction out-of-the-box pre-1.0 install
- [x] Scoped Monorepo Sub-Packages - Split
puls-devinto separate scoped packages published to the registry (@puls-dev/core,@puls-dev/aws,@puls-dev/gcp, etc.) to provide zero-friction installs with zero dependency bloat - [ ] Semver versioning - provider additions = minor, breaking DSL changes = major
Framework Features
- [x] Stack outputs - pass
Output<T>values between stacks; eager resolution unblocks dependents automatically - [x] Inventory /
@Check- read-only discovery across all configured providers; prints counts, status, and DO cost estimates - [x] Dry run -
dryRun: trueor@DryRunprints a full plan without any API writes - [x]
@Protected- marks a resource so it is never modified or destroyed - [x] Idempotent Configuration State Tracking - Store applied playbook and file hashes directly in VM metadata (e.g. Proxmox notes/tags) to support stateless, change-aware Ansible configuration updates on already created servers
- [x] Hooks -
beforeDeploy/afterDeploycallbacks onStackfor custom side effects (notify Slack, run migrations, etc.) - [x] Multi-region - run the same stack across N regions in parallel;
@Deploy({ regions: [REGION.EU_CENTRAL_1, REGION.US_EAST_1] }) - [x] Parallel resource deployment - resources within a stack that have no declared dependency could deploy concurrently instead of sequentially
- [x] Secrets at deploy time - pull credentials from AWS SSM Parameter Store or HashiCorp Vault instead of requiring them as env vars upfront
- [x] Hybrid Resource Configuration (YAML) - Support loading bulk static configuration sets (like DNS records, firewall rules, or security group rules) directly from a
.yamlor.jsonfile within builder methods while retaining the flexibility to chain programmatic methods for dynamic resource parameters. - [x] Opt-in Infrastructure Blueprint Documentation (
Config.blueprint) - Generate version-controlled markdown blueprints (docs/architecture.md) of live system resources, auto-calculating monthly costs, formatting live endpoints, and rendering Mermaid.js dynamic dependency/topology graphs on local runs. - [x] Multi-account & Multi-tenant Contexts - Dynamic or context-bound provider credentials in Stacks
- [x] Eager Cost Estimation - Estimate monthly infrastructure cost shifts directly in
puls diff/puls plan - [x] Policy-as-Code Guardrails - Enforce declarative pre-deploy compliance policies in pure TypeScript
- [x] Implicit Dependency Resolution via Output Interpolation -
GCP.BigQueryView.query()accepts template-literal-interpolated view builders; sentinels auto-wiredependsOnand resolve to qualified refs (`project.dataset.view`) at deploy time
Roadmap Gap Analysis (Tech Debt / Planned Improvements)
A version-controlled analysis of internal tech debt and feature gaps. Gaps are addressed opportunistically.
- [x] Gap 1: Output
Not Exported -Output<T>is missing from public API index insrc/index.ts. Resolving this enables clean public imports for developer-built custom types and cross-stack variables. - [x] Gap 2: Generic Retry & Backoff Engine - Implement a shared
withRetryor exponential backoff utility across all providers to handle transient network/API throttling errors gracefully under heavy parallel deployments. - [x] Gap 3: Resource Import & Adoption - Provide an
.adoptId()mechanism onBaseBuilderto allow existing, out-of-band cloud infrastructure to be safely imported under Puls management without recreation. - [x] Gap 4: Shell Script Provisioning Deprecation - Explicitly document the deprecation of
.shscript provisioning (in favor of Ansible/Puppet playbooks) to avoid user migration confusion. - [x] Gap 5: Advanced Drift Detection & diff - Clarify stateless tag/note-based metadata tracking in architecture docs, and design a formal
Stack.diff()structural diff engine comparing declared settings against live cloud properties. - [x] Gap 6: Checker Integration Completeness - Newer providers (GCP, Firebase) lack
list.tsimplementations, causing@Checkto silently skip them. Resolve by providing completelist.tsinventory engines for GCP and Firebase. - [x] Gap 7: Provider Plugin & Decoupling API - Establish a standard
registerProvider()hook and split core framework utilities into an independent@puls-dev/corepackage to enable community-built custom providers.
Breaking Changes & Migration Notes
Shell Script (.sh) Provisioning Removal
- Change: Standard
.shshell scripts are no longer supported inside the.provision()method. - Rationale: Shell scripts are inherently stateful and lack change-aware, idempotent execution. Puls standardizes on Ansible playbooks (
.yaml/.yml) and Puppet manifests (.pp) which record provisioning status hashes directly within live resource metadata. - Migration Path: Convert raw shell commands to standard Ansible tasks. For example, migrate package installation or service setup to
ansible.builtin.aptor standard Ansible modules, and save them as a playbook.yamlfile.