CDKTF Has a Free API: Write Terraform Infrastructure with TypeScript Instead of HCL

What is CDKTF?

CDKTF (Cloud Development Kit for Terraform) lets you write Terraform infrastructure using TypeScript, Python, Go, C#, or Java instead of HCL. You get the full Terraform ecosystem — thousands of providers — with real programming language features.

Quick Start

npm install -g cdktf-cli
cdktf init --template=typescript --providers=aws
cdktf deploy

Define Infrastructure

import { Construct } from "constructs";
import { App, TerraformStack, TerraformOutput } from "cdktf";
import { AwsProvider } from "@cdktf/provider-aws/lib/provider";
import { S3Bucket } from "@cdktf/provider-aws/lib/s3-bucket";
import { Instance } from "@cdktf/provider-aws/lib/instance";
import { SecurityGroup } from "@cdktf/provider-aws/lib/security-group";

class MyStack extends TerraformStack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    new AwsProvider(this, "aws", { region: "us-east-1" });

    // S3 bucket
    const bucket = new S3Bucket(this, "my-bucket", {
      bucket: "my-app-assets-2026",
      tags: { Environment: "production" },
    });

    // Security group
    const sg = new SecurityGroup(this, "web-sg", {
      name: "web-server-sg",
      ingress: [
        { fromPort: 80, toPort: 80, protocol: "tcp", cidrBlocks: ["0.0.0.0/0"] },
        { fromPort: 443, toPort: 443, protocol: "tcp", cidrBlocks: ["0.0.0.0/0"] },
      ],
      egress: [
        { fromPort: 0, toPort: 0, protocol: "-1", cidrBlocks: ["0.0.0.0/0"] },
      ],
    });

    // EC2 instance
    const server = new Instance(this, "web-server", {
      ami: "ami-0c55b159cbfafe1f0",
      instanceType: "t3.micro",
      vpcSecurityGroupIds: [sg.id],
      tags: { Name: "Web Server" },
    });

    new TerraformOutput(this, "bucket-name", { value: bucket.bucket });
    new TerraformOutput(this, "server-ip", { value: server.publicIp });
  }
}

const app = new App();
new MyStack(app, "my-infrastructure");
app.synth();

Real Programming — Loops and Functions

// Create multiple environments with a loop
const environments = ["dev", "staging", "production"];

for (const env of environments) {
  new S3Bucket(this, `bucket-${env}`, {
    bucket: `myapp-${env}-assets`,
    tags: { Environment: env },
  });
}

// Reusable function
function createVpc(stack: TerraformStack, name: string, cidr: string) {
  return new Vpc(stack, name, {
    cidrBlock: cidr,
    enableDnsHostnames: true,
    tags: { Name: name },
  });
}

const devVpc = createVpc(this, "dev-vpc", "10.0.0.0/16");
const prodVpc = createVpc(this, "prod-vpc", "10.1.0.0/16");

Constructs (Reusable Components)

class WebService extends Construct {
  public readonly url: string;

  constructor(scope: Construct, id: string, props: {
    port: number;
    instanceType?: string;
    environment: string;
  }) {
    super(scope, id);

    const sg = new SecurityGroup(this, "sg", {
      ingress: [{
        fromPort: props.port,
        toPort: props.port,
        protocol: "tcp",
        cidrBlocks: ["0.0.0.0/0"],
      }],
    });

    const instance = new Instance(this, "server", {
      ami: "ami-0c55b159cbfafe1f0",
      instanceType: props.instanceType || "t3.micro",
      vpcSecurityGroupIds: [sg.id],
      tags: {
        Name: `${id}-server`,
        Environment: props.environment,
      },
    });

    this.url = instance.publicIp;
  }
}

// Use like a building block
new WebService(this, "api", { port: 3000, environment: "prod" });
new WebService(this, "admin", { port: 8080, environment: "prod", instanceType: "t3.small" });

Testing Infrastructure

import { Testing } from "cdktf";

describe("MyStack", () => {
  it("should create an S3 bucket", () => {
    const app = Testing.app();
    const stack = new MyStack(app, "test");
    const synth = Testing.synth(stack);

    expect(Testing.toHaveResource(synth, "aws_s3_bucket")).toBeTruthy();
  });

  it("should use t3.micro for instances", () => {
    const app = Testing.app();
    const stack = new MyStack(app, "test");
    const synth = Testing.synth(stack);

    expect(
      Testing.toHaveResourceWithProperties(synth, "aws_instance", {
        instance_type: "t3.micro",
      })
    ).toBeTruthy();
  });
});

Deploy

# Synthesize to Terraform JSON
cdktf synth

# Plan changes
cdktf diff

# Deploy
cdktf deploy

# Destroy
cdktf destroy

CDKTF vs Terraform HCL vs Pulumi

Feature CDKTF Terraform HCL Pulumi
Language TS/Python/Go HCL TS/Python/Go
Ecosystem Terraform providers Terraform providers Own providers
State Terraform state Terraform state Pulumi state
Testing Jest/pytest Terratest Jest/pytest
Maturity GA Mature GA

Need cloud infrastructure automation or IaC consulting?

📧 [email protected]
🔧 My tools on Apify Store

CDKTF, Pulumi, or plain Terraform? Let me know your pick!

Telnyx Python SDK Compromised on PyPI: Malware Delivered via Steganography in WAV Files, Mitigation Strategies Discussed

Incident Overview

The Telnyx Python SDK on the Python Package Index (PyPI) was compromised in a sophisticated supply chain attack executed by the threat actor TeamPCP. Malicious versions of the SDK (4.87.1 and 4.87.2) were uploaded to PyPI, engineered to execute arbitrary code immediately upon import, ensuring cross-platform compatibility. The attack’s technical sophistication is exemplified by its payload delivery mechanism: WAV steganography, which embeds malicious data within the frame metadata of ostensibly benign audio files.

Below is a detailed technical analysis of the attack:

  • Upon import, the compromised package fetches a .wav file from a command-and-control (C&C) server located at 83.142.209.203:8080. The WAV file maintains structural validity, concealing malicious data within its frame metadata.
  • The malware extracts the hidden data from the frame metadata, applies base64 decoding, and performs an XOR operation using the initial bytes as the encryption key. This process reconstructs the payload by reversing the deformation applied to the encoded data structure, transforming it into executable code.
  • The payload execution diverges based on the target operating system:
    • Windows: The payload deploys msbuild.exe into the Startup folder, ensuring persistence by leveraging the system’s boot sequence.
    • Linux/macOS: A staged Python loader fetches the WAV file, extracts the second-stage payload, and executes it via stdin. The payload then AES-encrypts sensitive data and exfiltrates it, causing anomalous outbound traffic that saturates network interfaces.

The C&C server employs endpoints such as /hangup.wav and /ringtone.wav, masquerading malicious files as benign audio to evade detection. Traditional security tools fail to identify the steganographic payload due to the WAV files’ structural validity, which circumvents anomaly detection mechanisms.

This attack exposes critical vulnerabilities in software supply chain security:

  • PyPI’s verification process: The absence of rigorous integrity checks enabled the malicious package to be published, undermining trust in open-source ecosystems.
  • Outbound traffic monitoring: Inadequate monitoring of network activity allowed exfiltration to proceed undetected, expanding the attack surface across compromised systems.
  • Steganography detection: Overreliance on traditional security tools, which lack metadata and frame data analysis capabilities, created a critical blind spot in threat detection.

For affected systems, immediate mitigation measures include downgrading to a verified safe version of the SDK, rotating compromised cryptographic secrets, and implementing continuous monitoring for outbound traffic to the identified C&C IP. This incident underscores the imperative for robust package verification protocols, advanced steganography detection capabilities, and proactive threat hunting within open-source repositories to fortify software supply chain resilience.

Technical Analysis: Deconstructing the Telnyx Python SDK Supply Chain Attack

The recent compromise of the Telnyx Python SDK on PyPI by TeamPCP exemplifies the escalating sophistication of supply chain attacks. This incident underscores the critical need for robust security frameworks within open-source ecosystems. The attack’s technical ingenuity lies in its exploitation of WAV steganography for payload delivery, a method that seamlessly embeds malicious code within legitimate audio files. This analysis dissects the attack’s mechanisms, its cross-platform persistence strategies, and the broader implications for software supply chain security.

Payload Delivery Mechanism: WAV Steganography Explained

The attack’s efficacy hinges on the covert embedding of malicious code within the frame metadata of WAV files. The causal mechanism unfolds as follows:

  • Stealth Mechanism: The WAV file retains its audio functionality, rendering it indistinguishable from benign files to both human inspection and conventional security tools.
  • Execution Process:

    • The compromised package retrieves a WAV file (e.g., /hangup.wav or /ringtone.wav) from the command-and-control (C2) server at 83.142.209.203:8080.
    • The frame metadata is parsed to extract hidden bytes encoded in base64.
    • The initial bytes serve as an XOR key, decrypting the embedded payload.
    • The decrypted data is reconstructed into executable code, which is dynamically executed upon import, bypassing static analysis tools.
  • Operational Impact: The malicious code executes seamlessly, leveraging the disparity between human auditory perception and machine data interpretation to evade detection.

This technique parallels the physical process of encoding information within the grooves of a vinyl record, where the primary function (audio playback) remains intact while secondary data (the payload) is concealed within the structure.

Cross-Platform Persistence and Exfiltration Strategies

The payload employs OS-specific tactics to ensure persistence and maximize exfiltration efficiency:

Operating System Attack Strategy
Windows * Persistence Mechanism: A malicious instance of msbuild.exe is placed in the Startup folder, ensuring execution on system boot. * Operational Impact: Unauthorized processes spawn at startup, consuming system resources and maintaining persistent access.
Linux/macOS * Exfiltration Mechanism: A staged Python loader retrieves the WAV file, extracts the payload, and executes it via stdin. Sensitive data is encrypted using AES and exfiltrated to the C2 server. * Operational Impact: Network interfaces are saturated with outbound traffic, degrading system performance and masking malicious activity.

The attack’s risk amplification stems from its dual-pronged approach: persistence ensures prolonged access, while exfiltration exploits network resources, creating a feedback loop that complicates detection and remediation.

C2 Server Obfuscation and Detection Challenges

The C2 server employs disguised endpoints (e.g., /hangup.wav, /ringtone.wav) to obfuscate malicious activity. The causal chain is as follows:

  • Obfuscation Mechanism: Security tools prioritize file type over metadata analysis, failing to flag WAV files as suspicious.
  • Detection Gap: Steganography detection requires deep packet inspection, a capability rarely implemented in standard security pipelines.
  • Operational Impact: Malicious traffic masquerades as legitimate audio downloads, evading traditional monitoring systems.

This tactic mirrors the Trojan horse strategy, where the WAV file serves as the innocuous exterior, concealing the malicious payload within.

Mitigation Strategies: Addressing Root Causes

The incident exposes systemic vulnerabilities within PyPI’s ecosystem, necessitating proactive, multi-layered defenses:

  • Package Integrity: Implement mandatory cryptographic signing and integrity checks to prevent unauthorized package uploads.
  • Traffic Monitoring: Deploy advanced tools capable of identifying anomalous WAV file downloads and detecting encrypted exfiltration patterns.
  • Steganography Detection: Integrate metadata analysis into security pipelines to uncover hidden payloads within benign file formats.

For compromised systems, immediate remediation includes downgrading to verified package versions, rotating compromised secrets, and monitoring for communication with the C2 server at 83.142.209.203:8080. The broader imperative is clear: supply chain security demands anticipatory, stratified defenses, not reactive patches.

Mitigation and Prevention: Fortifying the Software Supply Chain Against Advanced Adversaries

The compromise of the Telnyx Python SDK on PyPI exemplifies a paradigm shift in supply chain attacks, leveraging sophisticated techniques such as WAV steganography to bypass conventional defenses. This incident underscores the critical need for a multi-layered security approach that addresses both technical vulnerabilities and the evolving tactics of threat actors. By deconstructing the attack’s methodology, we can engineer resilient defenses at the intersection of code integrity, data inspection, and network behavior analysis.

1. Package Integrity: Cryptographic Signing as a Foundational Defense

The absence of mandatory code signing in PyPI’s upload process enabled the undetected publication of malicious versions 4.87.1 and 4.87.2. To mitigate this vulnerability:

  • Mechanical Process: Enforce cryptographic signing using asymmetric key pairs. Each package upload must include a detached signature, verified against the maintainer’s public key. This ensures end-to-end integrity, preventing tampering during transit or storage.
  • Causal Mechanism: Cryptographic signing shifts the trust model from implicit reliance on repository infrastructure to explicit proof of authorship. By requiring a valid signature, the attack surface is reduced, as unauthorized uploads become computationally infeasible without access to the private key.
  • Edge Case Mitigation: In the event of key compromise, implement multi-signature requirements for critical packages. This necessitates multiple valid signatures, exponentially increasing the complexity of unauthorized modifications.

2. Steganography Detection: Unmasking Covert Payloads in WAV Metadata

The malicious use of WAV steganography exploited the gap between human-perceptible audio and machine-interpretable metadata. To counter this technique:

  • Mechanical Process: Deploy deep packet inspection (DPI) tools capable of analyzing WAV frame metadata for anomalies, such as base64 encoding or XOR-based obfuscation patterns.
  • Causal Mechanism: Steganography leverages the perceptual gap between human auditory processing and machine data interpretation. DPI bridges this gap by extending inspection beyond the audio stream to metadata layers, where covert payloads reside.
  • Edge Case Mitigation: To address adaptive steganography, employ machine learning models trained on datasets of benign and malicious WAV metadata. These models detect subtle deviations indicative of embedded payloads, even as steganographic techniques evolve.

3. Network Traffic Monitoring: Detecting Exfiltration Through Behavioral Anomalies

83.142.209.203:8080 remained undetected due to the absence of anomaly detection mechanisms. To prevent such incidents:

  • Mechanical Process: Implement behavioral analytics solutions that establish baselines of normal network activity. Flag deviations such as sudden increases in WAV file transfers or AES-encrypted traffic.
  • Causal Mechanism: Data exfiltration generates anomalous network patterns, particularly on Linux/macOS systems where payloads saturate bandwidth. Behavioral analytics tools identify these patterns, triggering alerts before data egress occurs.
  • Edge Case Mitigation: If attackers employ domain fronting, block traffic to known command-and-control (C2) IPs and enforce DNS filtering to prevent resolution of suspicious domains.

4. Remediation: Neutralizing Compromised Systems

For systems compromised by versions 4.87.1 or 4.87.2, execute the following steps:

  • Code Rollback: Downgrade to a verified safe version. This interrupts the malicious execution chain by removing compromised code.
  • Secret Rotation: Replace all API keys and tokens associated with the compromised package. This severes the attacker’s access vector to sensitive systems.
  • Persistence Removal: On Windows, delete msbuild.exe from startup folders. On Linux/macOS, terminate rogue Python processes and remove staged payloads from temporary directories.

5. Proactive Threat Hunting: Anticipating Adversarial Tactics

Reactive defenses are insufficient against proactive adversaries. Adopt a threat-hunting posture:

  • Mechanical Process: Utilize YARA rules to scan repositories for WAV files with steganographic indicators. Continuously update rules to incorporate emerging techniques.
  • Causal Mechanism: Threat hunting transcends detection beyond signature-based approaches, identifying threats through behavioral and structural anomalies before execution.
  • Edge Case Mitigation: If attackers evade static analysis, employ sandboxed execution environments to observe runtime behavior without exposing production systems.

The Telnyx incident is not a failure of technology but a failure of anticipatory security design. By dissecting the physical and logical mechanisms of the attack—from cryptographic integrity violations to steganographic payload delivery—we can engineer defenses that are both reactive and proactive. The software supply chain’s resilience is determined by its weakest link. Through rigorous integrity checks, deep data inspection, and behavioral monitoring, every link can be fortified against advanced adversaries.

Kamal 2 Has a Free API: Deploy Web Apps to Any Server Without Kubernetes

What is Kamal?

Kamal (formerly MRSK) is a deployment tool from the creators of Rails (37signals/Basecamp). It deploys containerized web apps to any server — bare metal, VPS, or cloud — without Kubernetes complexity.

Kamal 2 powers HEY.com and Basecamp in production.

Quick Start

gem install kamal
kamal init
kamal setup
kamal deploy

Configuration

# config/deploy.yml
service: my-app
image: myorg/my-app

servers:
  web:
    hosts:
      - 192.168.1.1
      - 192.168.1.2
    options:
      memory: 512m
  worker:
    hosts:
      - 192.168.1.3
    cmd: bundle exec sidekiq

registry:
  username: myorg
  password:
    - KAMAL_REGISTRY_PASSWORD

env:
  clear:
    RAILS_ENV: production
    DATABASE_URL: postgres://db-host/myapp
  secret:
    - RAILS_MASTER_KEY
    - STRIPE_SECRET_KEY

proxy:
  ssl: true
  host: myapp.com
  app_port: 3000

accessories:
  db:
    image: postgres:16
    host: 192.168.1.4
    port: 5432
    env:
      clear:
        POSTGRES_DB: myapp_production
      secret:
        - POSTGRES_PASSWORD
    directories:
      - data:/var/lib/postgresql/data
  redis:
    image: redis:7
    host: 192.168.1.4
    port: 6379
    directories:
      - data:/data

Zero-Downtime Deploys

# Deploy with zero downtime
kamal deploy

# What happens:
# 1. Build Docker image locally
# 2. Push to registry
# 3. Pull on servers
# 4. Start new container
# 5. Health check passes
# 6. Switch traffic (kamal-proxy)
# 7. Stop old container

The built-in kamal-proxy handles traffic switching — no nginx config needed.

Key Commands

# First-time setup (installs Docker, kamal-proxy)
kamal setup

# Deploy latest code
kamal deploy

# Rollback to previous version
kamal rollback

# View logs
kamal app logs
kamal app logs -f  # Follow

# Run console
kamal app exec -i 'bin/rails console'

# Run one-off task
kamal app exec 'bin/rails db:migrate'

# Manage accessories
kamal accessory boot db
kamal accessory logs db

# Check server details
kamal details

Kamal 2 New Features

Built-in Proxy (replaces Traefik)

Kamal 2 ships with kamal-proxy — a purpose-built reverse proxy:

proxy:
  ssl: true
  host: myapp.com
  buffering:
    requests: true
    responses: true
    max_request_body: 10m
  response_timeout: 30
  healthcheck:
    interval: 3
    path: /up
    timeout: 3

Aliases

# config/deploy.yml
aliases:
  console: app exec -i 'bin/rails console'
  logs: app logs -f
  shell: app exec -i bash
kamal console  # Opens Rails console on production
kamal logs     # Follows production logs

Multi-App on Single Server

# app1/config/deploy.yml
proxy:
  host: app1.com

# app2/config/deploy.yml  
proxy:
  host: app2.com

Multiple apps share the same server, kamal-proxy routes by hostname.

Cost Comparison

Setup Monthly Cost
Heroku (2 dynos) $50-100
AWS ECS/Fargate $50-150
Kubernetes (EKS) $75-200+
Kamal + Hetzner VPS $5-20

Kamal + a $5 VPS = production-ready deployment.

Need help deploying apps or setting up CI/CD pipelines?

📧 [email protected]
🔧 My tools on Apify Store

Kamal, Docker Compose, or Kubernetes? Share your deployment stack!

How AI workloads changed the queue I was already building

I did not start glide-mq because of AI.

I started it because I needed a queue, wanted mechanics I liked better than what was out there, and wanted it built on top of Valkey Glide.

Up through v0.13, that is basically what it was: a feature-rich queue.

Then I kept building AI systems on top of it.

That is where the shape started changing.

The queue itself was usually fine. The pain was everything around it. Long-running jobs that were not actually stuck. Streaming that wanted to be part of the job instead of a side channel. Budget checks that needed to happen before the spend, not after. Token-aware rate limits. Pause/resume because real flows sometimes need a human or have to wait for CI.

Different project. Same pile of glue.

After enough rounds, the pattern stops looking normal. The queue is doing the easy part. Everything AI-specific is leaking out around it.

That is what pushed glide-mq in a different direction.

AI workloads expose the wrong assumptions in normal queue design

Most queues were built for ordinary background work.

AI workloads are not ordinary background work.

They stream. They run long without being stuck. They spend money while they execute. They wait on humans. They hit limits based on tokens, not job count. They can fail semantically while every operational metric stays green.

If the queue does not understand that shape, the missing behavior does not disappear. It ends up patched on from the outside.

That is the part that started feeling wrong to me.

Not because queues are bad. Because a lot of the assumptions underneath them were built for a different class of workload.

1. Locks are the wrong model for long AI jobs

Most queues assume the worker proves it is alive by renewing a lock. Miss the renewal, retry the job.

That is reasonable for short jobs.

It is a bad model for LLM workloads.

A long generation is not dead. A reasoning-heavy call sitting on a hard prompt for 90 seconds is not dead. But a normal queue cannot tell the difference, so it retries, and now you are paying twice for the same work.

Nothing crashed. Nothing exploded. You just had the wrong execution model.

The usual workaround is increasing a global lock timeout.

That is also wrong.

A tiny classifier and a two-minute generation should not share the same timeout assumptions just because they live in the same queue.

So in glide-mq, lock duration is per job:

await queue.add("classify", { text: "short" }, { lockDuration: 10_000 });
await queue.add("research", { topic: "complex" }, { lockDuration: 180_000 });

Same queue. Different expectations.

That should be normal.

2. Budget control belongs in the execution path

The ugly failures in agent systems are often not technical failures.

The requests succeed.
The responses are valid.
The logs look clean.
The dashboards stay green.

And meanwhile the system is stuck in some useless loop spending money.

That is why budget control does not belong only in dashboards, analytics, or some side service that tells you later what happened. By then the spend is already gone.

The queue is the choke point. Every step passes through it. That is where the budget check belongs.

So I put budgets on flows:

await flowProducer.add(
  {
    name: "pipeline",
    queueName: "ai",
    data: { topic: "research" },
    children: [
      { name: "search", queueName: "ai", data: {} },
      { name: "analyze", queueName: "ai", data: {} },
      { name: "draft", queueName: "ai", data: {} },
    ],
  },
  {
    budget: {
      maxTotalTokens: 50_000,
      maxTotalCost: 2.0,
      tokenWeights: { reasoning: 2.0 },
      onExceeded: "fail",
    },
  },
);

When a job reports usage, the budget check happens atomically in Valkey. If the flow is out of budget, the next step stops there.

Not later. Not after the invoice. At the point where it still matters.

3. Streaming should not be a second system

If the model is producing the result incrementally, that stream is part of the job.

Treating it as a separate system is already the smell.

But most queues only understand one shape: job starts, job finishes, here is the result.

LLMs do not behave like that.

So people bolt on pub/sub. Or WebSockets. Or SSE through some different route. Then reconnect logic. Then ordering. Then another pile of glue to keep the stream state and the job state from drifting apart.

Now the job lives in one place and the live output lives somewhere else.

That split is artificial.

So in glide-mq, the stream stays on the job:

const worker = new Worker(
  "ai",
  async (job) => {
    for await (const token of generateTokens(job.data.prompt)) {
      await job.streamChunk("token", token);
    }
    await job.streamChunk("done");
    return { completed: true };
  },
  { connection },
);

const chunks = await queue.readStream(jobId, { block: 5000 });

No extra pub/sub layer. No second system just to watch a job do its work. The stream is attached to the job, stored in Valkey, and resumable after disconnect.

That is the model that actually matches the workload.

The rest is the same mismatch in different clothes

Once you accept that AI workloads are a different class of work, the rest stops looking like extra features and starts looking like missing queue behavior.

Pause/resume for human approval.
Wake the flow back up when CI finishes.
Fallbacks across models.
Rate limiting based on tokens instead of job count.
Usage tracking that does not break when the next model adds a new token category.

These are not edge cases. They are part of the shape of the work.

That is what v0.14 is really about

Not AI branding. Not pretending glide-mq started as an AI queue from day one.

It did not.

It started as the queue I wanted to have.

Then building real AI systems on top of it kept exposing the same gaps, and eventually patching around them started feeling like the wrong move.

So v0.14 moves those behaviors into the queue

That is what changed.

glide-mq is still a queue. But v0.14 is where it started absorbing the behaviors that AI systems kept forcing into side systems.

  • Per-job lockDuration so long jobs stop fighting short ones.
  • job.reportUsage() so budgets and accounting live in the execution path.
  • job.streamChunk() so streaming stays attached to the job.
  • job.suspend() and queue.signal() for human-in-the-loop flows.
  • Ordered fallbacks.
  • Token-aware throttling.
  • Flow budgets that fail before the spend gets worse.

That is the direction now.

Not queue plus five things you will bolt on later anyway.

The queue should understand more of the workload it is running.

Final thought

I do not think this is only a glide-mq story.

I think AI workloads are exposing the wrong assumptions in a lot of older tooling.

The problem is not just that queues need a few more integrations. The problem is that many of the abstractions we still lean on were designed for ordinary jobs, requests, and background work. AI systems have a different shape, and when the abstraction does not match, the missing behavior leaks out into glue.

That is the part I stopped wanting to patch from the outside.

npm install glide-mq

GitHub | Examples | Docs

Pulumi Has a Free API: Infrastructure as Code with Real Programming Languages

What is Pulumi?

Pulumi lets you define cloud infrastructure using real programming languages — TypeScript, Python, Go, C#, Java — instead of YAML or HCL. You get loops, conditionals, functions, type checking, and IDE autocomplete for your infrastructure.

The open-source engine is completely free.

Quick Start

curl -fsSL https://get.pulumi.com | sh
pulumi new aws-typescript
pulumi up

Define Infrastructure in TypeScript

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

// S3 bucket with website hosting
const bucket = new aws.s3.Bucket("my-site", {
  website: {
    indexDocument: "index.html",
    errorDocument: "error.html",
  },
});

// Upload files
new aws.s3.BucketObject("index", {
  bucket: bucket.id,
  key: "index.html",
  content: "<h1>Hello Pulumi!</h1>",
  contentType: "text/html",
});

// CloudFront CDN
const cdn = new aws.cloudfront.Distribution("cdn", {
  origins: [{
    domainName: bucket.websiteEndpoint,
    originId: bucket.arn,
    customOriginConfig: {
      httpPort: 80,
      httpsPort: 443,
      originProtocolPolicy: "http-only",
      originSslProtocols: ["TLSv1.2"],
    },
  }],
  enabled: true,
  defaultCacheBehavior: {
    targetOriginId: bucket.arn,
    viewerProtocolPolicy: "redirect-to-https",
    allowedMethods: ["GET", "HEAD"],
    cachedMethods: ["GET", "HEAD"],
    forwardedValues: { queryString: false, cookies: { forward: "none" } },
  },
  restrictions: { geoRestriction: { restrictionType: "none" } },
  viewerCertificate: { cloudfrontDefaultCertificate: true },
});

export const url = pulumi.interpolate`https://${cdn.domainName}`;

Automation API (Programmatic Control)

Pulumi’s Automation API lets you manage stacks from your own code:

import { LocalWorkspace } from "@pulumi/pulumi/automation";

async function deploy() {
  const stack = await LocalWorkspace.createOrSelectStack({
    stackName: "production",
    projectName: "my-infra",
    program: async () => {
      const bucket = new aws.s3.Bucket("my-bucket");
      return { bucketName: bucket.id };
    },
  });

  await stack.setConfig("aws:region", { value: "us-east-1" });

  const result = await stack.up({ onOutput: console.log });
  console.log(`Bucket: ${result.outputs.bucketName.value}`);
}

async function destroy() {
  const stack = await LocalWorkspace.selectStack({
    stackName: "production",
    projectName: "my-infra",
    program: async () => {},
  });
  await stack.destroy({ onOutput: console.log });
}

Build internal developer platforms, self-service portals, or CI/CD pipelines with full infrastructure control.

Component Resources (Reusable Modules)

class StaticSite extends pulumi.ComponentResource {
  public readonly url: pulumi.Output<string>;

  constructor(name: string, args: { path: string; domain?: string }, opts?: pulumi.ComponentResourceOptions) {
    super("custom:StaticSite", name, {}, opts);

    const bucket = new aws.s3.Bucket(`${name}-bucket`, {
      website: { indexDocument: "index.html" },
    }, { parent: this });

    // Upload all files from path
    // ... (sync logic)

    this.url = bucket.websiteEndpoint;
    this.registerOutputs({ url: this.url });
  }
}

// Use it like any other resource
const site = new StaticSite("docs", { path: "./dist" });
export const siteUrl = site.url;

Multi-Cloud

import * as gcp from "@pulumi/gcp";
import * as azure from "@pulumi/azure-native";

// Same language, any cloud
const gcpBucket = new gcp.storage.Bucket("gcp-bucket");
const azureBlob = new azure.storage.StorageAccount("azure-storage", {
  resourceGroupName: "my-rg",
  sku: { name: "Standard_LRS" },
  kind: "StorageV2",
});

Pulumi vs Terraform

Feature Pulumi Terraform
Language TypeScript/Python/Go HCL
IDE Support Full (autocomplete, types) Limited
Testing Standard test frameworks Terratest
Loops/Conditions Native language count/for_each
State Free (Pulumi Cloud) Terraform Cloud ($)
Reuse npm/pip packages Modules (HCL)

Need infrastructure automation or cloud architecture help?

📧 [email protected]
🔧 My tools on Apify Store

Pulumi or Terraform — which do you prefer? Comment below!

Elazığ'da “Astro Hackathon” heyecanı başladı

Türkiye Uzay Ajansı öncülüğünde düzenlenen ‘Astro Hackathon’ etkinliği, Elazığ’da lise ve üniversite öğrencilerinin uzay ve teknoloji projelerini geliştireceği bir maraton olarak başladı. Katılımcılar, bilim ve mühendislik alanında iki gün boyunca çözümler geliştirecek.

Samsun'da “TUA Astro Hackathon” etkinliği başladı

Türkiye Uzay Ajansı’nın düzenlediği TUA Astro Hackathon etkinliği, Samsun Üniversitesi’nde başladı. 52 takımda 256 öğrenci, uzay araştırmaları ve sistem mühendisliği üzerine yarışıyor. Etkinlik, gençlerin uzay alanında farkındalığını artırmayı hedefliyor.