DEV Community

Vedran Lebo
Vedran Lebo

Posted on

Why I built ctx_: the context switcher that actually gets DevOps work

The problem every DevOps engineer faces

It's 3 AM. Production is down. You need to debug NOW.

What do you do?

$ export AWS_PROFILE=production
$ kubectx production-cluster
$ kubectl config set-context --current --namespace=api
$ ssh -f -N -L 5432:db.prod:5432 bastion.prod
$ export VAULT_ADDR=https://vault.prod
$ # ... wait, which profile am I using again?
Enter fullscreen mode Exit fullscreen mode

6+ commands. Every. Single. Time.

And that's assuming you remember them all correctly. One wrong command at 3 AM and you've just deployed to the wrong cluster. Or worse, accidentally modified production with dev credentials still active.

Why kubectx isn't enough

Don't get me wrong, kubectx is great for what it does. But it only solves one piece of the puzzle: Kubernetes contexts.

What about:

  • AWS/GCP/Azure credentials?
  • SSH tunnels to databases?
  • VPN connections?
  • Environment variables?
  • Vault tokens?
  • Git user configs?
  • Browser profiles for SSO?

You're still managing 7+ different tools and hoping they all stay in sync.

Meet ctx: one command for your entire environment

ctx treats your entire DevOps environment as a single switchable context:

$ ctx use production

⚠  Switching to PRODUCTION environment: production
Type 'yes' to confirm: yes

✓ AWS profile: production (us-east-1)
✓ Kubernetes: prod-cluster/default
✓ VPN connected: wireguard (wg0)
✓ Tunnel postgres: localhost:5432 → db.prod:5432
✓ Tunnel redis: localhost:6379 → cache.prod:6379
✓ Browser: Chrome (Production Profile)
✓ Environment variables loaded
✓ Secrets loaded from Vault

[ctx: production] $
Enter fullscreen mode Exit fullscreen mode

One command. Everything switches.

Real-world comparison

Let's see how different tools stack up for a typical multi-cloud, multi-environment setup:

Feature kubectx direnv aws-vault ctx
Kubernetes context
Multi-cloud (AWS/GCP/Azure) AWS only
Environment variables
SSH tunnels
VPN management
Production safeguards
Auto-fetch K8s credentials
Context inheritance
Variable interpolation
Secrets management
Browser profiles
URL quick links

What makes ctx different

1. Production safeguards (because 3 AM you is dangerous)

$ ctx use production

⚠  Switching to PRODUCTION environment: production
Type 'yes' to confirm: yes

✓ Context 'production' is now active.

⚠  You are now in PRODUCTION environment.
Enter fullscreen mode Exit fullscreen mode

You have to WANT to be in production. No more "oops, wrong cluster".

The production environment type requires explicit confirmation. No flags, no shortcuts, just type "yes" to confirm you really want to access production.

2. Auto-fetch Kubernetes credentials from cloud providers

ctx automatically fetches K8s credentials when you switch contexts:

# Your context config
kubernetes:
  context: my-cluster
  namespace: default
  eks:
    cluster: my-cluster
    region: us-west-2
Enter fullscreen mode Exit fullscreen mode

When you switch, ctx automatically runs:

  • EKS: aws eks update-kubeconfig --name <cluster> --region <region>
  • GKE: gcloud container clusters get-credentials <cluster> --zone <zone> --project <project>
  • AKS: az aks get-credentials --name <cluster> --resource-group <rg>

No more manual credential refreshes. It just works.

3. Context inheritance + variable interpolation for DRY configs

Managing 50 similar clusters? Combine inheritance with variables:

# base-acme.yaml (abstract base)
name: acme-base
abstract: true
cloud: acme
kubernetes:
  context: "acme-${CLUSTER_NAME}-cluster"
  kubeconfig: "~/clusters/acme/${CLUSTER_NAME}/config"
env:
  API_URL: "https://api.${CLUSTER_NAME}.acme.com"
  CLUSTER: "${CLUSTER_NAME}"

# daisy.yaml (extends base + sets variable)
name: daisy
extends: acme-base
env:
  CLUSTER_NAME: daisy

# eve.yaml (extends base + sets variable)
name: eve
extends: acme-base
env:
  CLUSTER_NAME: eve
Enter fullscreen mode Exit fullscreen mode

Two clusters. 8 lines total. Variables are expanded after inheritance merging, so you can reference them in the base config.

4. SSH tunnels through bastion with auto-reconnect

Tunnels that actually stay up, all go through your bastion host:

ssh:
  bastion:
    host: bastion.example.com
    user: deploy  # defaults to $USER if not specified
    port: 22

tunnels:
  - name: postgres
    remote_host: db.internal
    remote_port: 5432
    local_port: 5432
    timeout: 10s  # configurable timeout
  - name: redis
    remote_host: cache.internal
    remote_port: 6379
    local_port: 6379
Enter fullscreen mode Exit fullscreen mode

All tunnels go through the bastion. ctx manages the SSH connection lifecycle. When you switch contexts, old tunnels are cleaned up. No more orphaned SSH processes.

$ ctx tunnel list
Active tunnels for context 'staging':
  postgres: localhost:5432 → db.internal:5432 (PID: 12345)
  redis: localhost:6379 → cache.internal:6379 (PID: 12346)

$ ctx tunnel down postgres
✓ Tunnel 'postgres' stopped

$ ctx tunnel up postgres
✓ Tunnel 'postgres' started
Enter fullscreen mode Exit fullscreen mode

If a local port is already in use, ctx will detect the conflict and let you know.

5. Secrets from multiple secret stores

Fetch secrets from any supported secret manager:

secrets:
  # Bitwarden
  bitwarden:
    DB_PASSWORD: "Production DB#password"
    API_KEY: "Production API Key"

  # 1Password
  onepassword:
    SMTP_PASSWORD: "SendGrid#password"

  # HashiCorp Vault
  vault:
    CONSUL_TOKEN: "operations/consul#http_token"
    NOMAD_TOKEN: "operations/nomad#token"

  # AWS Secrets Manager
  aws_secrets_manager:
    DATADOG_API_KEY: "prod/datadog#api_key"

  # AWS SSM Parameter Store
  aws_ssm:
    DATABASE_URL: "/prod/database/url"

  # GCP Secret Manager
  gcp_secret_manager:
    SENTRY_DSN: "prod-sentry-dsn"

# Secret store configs
bitwarden:
  auto_login: true

vault:
  address: https://vault.prod.internal
  namespace: operations
Enter fullscreen mode Exit fullscreen mode

When you switch contexts, ctx fetches all configured secrets and exports them as environment variables. No hardcoded credentials.

All secret stores support automated login/authentication:

  • Bitwarden: auto-login with SSO support (org_identifier)
  • 1Password: biometric/system authentication
  • Vault: token management with auto-refresh
  • AWS: SSO, aws-vault integration
  • GCP: gcloud authentication with SSO
  • Azure: az CLI authentication with SSO

6. VPN support (OpenVPN, WireGuard, Tailscale)

Auto-connect to VPN when switching:

# OpenVPN
vpn:
  openvpn:
    config: /etc/openvpn/production.ovpn
    auth_file: /etc/openvpn/auth.txt

# WireGuard
vpn:
  wireguard:
    interface: wg0
    config: /etc/wireguard/prod.conf

# Tailscale
vpn:
  tailscale:
    network: prod-network

# Custom command
vpn:
  command: /usr/local/bin/connect-prod-vpn.sh
Enter fullscreen mode Exit fullscreen mode

VPN connects automatically when you switch contexts, disconnects when you deactivate.

7. Browser profiles (Chrome & Firefox)

Launch the right browser profile for each context:

browser:
  type: chrome
  profile: Production Profile  # Chrome profile name

# Or Firefox
browser:
  type: firefox
  profile: work-prod  # Firefox profile name
Enter fullscreen mode Exit fullscreen mode

Perfect for SSO workflows. Each context can have its own browser profile with saved credentials, cookies, and sessions.

$ ctx open https://console.aws.amazon.com
# Opens URL in Chrome with "Production Profile"
Enter fullscreen mode Exit fullscreen mode

8. Multi-cloud support

Switch between AWS, GCP, and Azure seamlessly:

# AWS context
aws:
  profile: myapp-prod
  region: us-east-1
  sso: true

# GCP context
gcp:
  project: myapp-prod
  region: us-central1
  zone: us-central1-a

# Azure context
azure:
  subscription: myapp-prod
  tenant: 12345-abcde
  resource_group: production
Enter fullscreen mode Exit fullscreen mode

One interface. Multiple clouds.

9. Quick links for context-specific URLs

Store frequently accessed URLs for each context:

urls:
  dashboard: https://grafana.prod.internal/d/prod-overview
  logs: https://kibana.prod.internal/app/logs
  console: https://console.aws.amazon.com
  docs: https://docs.prod.internal
Enter fullscreen mode Exit fullscreen mode

Access them quickly:

$ ctx open dashboard
# Opens https://grafana.prod.internal/d/prod-overview in context browser

$ ctx open logs
# Opens https://kibana.prod.internal/app/logs
Enter fullscreen mode Exit fullscreen mode

Perfect for keeping all your production links organized and context-aware.

10. Smart defaults

SSH user not specified? ctx defaults to your OS user, just like SSH does:

ssh:
  bastion:
    host: bastion.internal
    # user: defaults to $USER
    port: 22
Enter fullscreen mode Exit fullscreen mode

Teams can share base contexts without hardcoding usernames. Everyone uses their own username automatically.

Real-world use cases

Multi-environment juggling

$ ctx list
NAME               ENVIRONMENT  CLOUD  ORCHESTRATION
myapp-dev          development  aws    kubernetes
myapp-staging      staging      aws    kubernetes
myapp-prod         production   aws    kubernetes

$ ctx use myapp-staging
✓ Context 'staging' is now active

$ ctx use myapp-prod
⚠  Type 'yes' to confirm: yes
✓ Context 'production' is now active
Enter fullscreen mode Exit fullscreen mode

Multi-client consultant

Managing 10 clients with different clouds, clusters, and tools?

$ ctx list
NAME               ENVIRONMENT  CLOUD  ORCHESTRATION
client-a-prod      production   aws    kubernetes
client-b-prod      production   gcp    kubernetes
client-c-staging   staging      azure  nomad

$ ctx use client-b-prod
⚠  Type 'yes' to confirm: yes
✓ GCP project: client-b-production
✓ GKE cluster: prod-cluster-eu
✓ VPN connected
Enter fullscreen mode Exit fullscreen mode

No confusion. No mistakes.

Incident response at 3 AM

[03:42] ALERT: Production API down!

[03:43] $ ctx use api-prod
[03:43] ⚠  Type 'yes' to confirm: yes
[03:43] ✓ AWS profile: production
[03:43] ✓ Kubernetes: prod-cluster/api
[03:43] ✓ VPN connected
[03:43] ✓ Tunnels connected
[03:43] ✓ Secrets loaded

[03:44] $ kubectl get pods
[03:44] # Debug and fix...

[03:56] $ kubectl apply -f hotfix.yaml
[03:56] ✓ Incident resolved

[03:57] $ ctx deactivate
[03:57] ✓ Safely exited production
Enter fullscreen mode Exit fullscreen mode

Under pressure. No mistakes. Fast.

How it works

ctx is a single Go binary with zero dependencies. It reads YAML configs from ~/.config/ctx/contexts/:

name: myapp-prod
description: "MyApp Production"
environment: production

aws:
  profile: prod
  region: us-west-2

kubernetes:
  context: prod-cluster
  namespace: default
  eks:
    cluster: prod-cluster
    region: us-west-2

ssh:
  bastion:
    host: bastion.prod.internal
    user: deploy

tunnels:
  - name: postgres
    remote_host: db.internal
    remote_port: 5432
    local_port: 5432

vpn:
  wireguard:
    interface: wg0
    config: /etc/wireguard/prod.conf

browser:
  type: chrome
  profile: Production

urls:
  dashboard: https://grafana.prod.internal
  console: https://console.aws.amazon.com
  logs: https://kibana.prod.internal

secrets:
  vault:
    NOMAD_TOKEN: "operations/nomad#token"

env:
  API_URL: https://api.prod.example.com
  LOG_LEVEL: info
Enter fullscreen mode Exit fullscreen mode

When you run ctx use myapp-prod, it:

  1. Fetches K8s credentials from AWS (if configured)
  2. Switches AWS profile
  3. Switches Kubernetes context and namespace
  4. Connects VPN
  5. Establishes SSH connection to bastion
  6. Starts SSH tunnels through bastion
  7. Fetches secrets from Vault/Bitwarden/etc
  8. Exports environment variables
  9. Makes URL quick links available
  10. Updates your shell prompt

One command. Everything switches.

Getting started

Install

# macOS / Linux
curl -fsSL https://github.com/vlebo/ctx/releases/latest/download/install.sh | sh
Enter fullscreen mode Exit fullscreen mode

Setup shell integration

Add to ~/.zshrc or ~/.bashrc:

eval "$(ctx shell-hook zsh)"   # for Zsh
eval "$(ctx shell-hook bash)"  # for Bash
Enter fullscreen mode Exit fullscreen mode

Create your first context

ctx init my-dev
Enter fullscreen mode Exit fullscreen mode

Or manually create ~/.config/ctx/contexts/my-dev.yaml:

name: my-dev
environment: development

aws:
  profile: dev
  region: us-west-2

kubernetes:
  context: dev-cluster
  namespace: default

env:
  API_URL: https://api.dev.example.com
Enter fullscreen mode Exit fullscreen mode

Switch

ctx use my-dev
Enter fullscreen mode Exit fullscreen mode

That's it.

Why ctx vs everything else?

Tool combo Commands needed Production safety Team sharing
kubectx + aws-vault + custom scripts 6+ commands ❌ No ❌ No
direnv + kubectx + aws-vault 3-4 commands ❌ No ⚠️ Git only
ctx 1 command ✅ Yes ✅ Yes (coming soon)

ctx isn't just replacing one tool, it's replacing your entire context-switching workflow.

TL;DR

ctx combines:

  • ✅ Variable interpolation (${VAR} in configs)
  • ✅ Auto-fetch K8s credentials from EKS/GKE/AKS
  • ✅ Additional cloud parameter for non-standard providers
  • ✅ Context inheritance to avoid duplication
  • ✅ Production environment safeguards
  • ✅ Multi-cloud support (AWS/GCP/Azure) with SSO
  • ✅ VPN management (OpenVPN/WireGuard/Tailscale)
  • ✅ SSH tunnels through bastion
  • ✅ Secrets from 6 secret stores with auto-auth
  • ✅ Browser profile switching (Chrome/Firefox)
  • ✅ URL quick links for dashboards/consoles
  • ✅ Git user configuration

What's next?

Roadmap for 2026:

  • Q2 2026:

    • ✅ Context inheritance + variable interpolation
    • ✅ Auto-fetch K8s credentials
    • 🚧 Zsh plugin with completions
    • 🚧 GitHub Actions integration
  • Q3 2026:

    • ctx-cloud for team context sharing
    • Web UI for context management
    • Docker context integration
    • Plugin system for custom integrations

Coming soon: ctx-cloud

Team context sharing and centralized management:

$ ctx cloud login https://ctx-cloud-url
$ ctx cloud sync production
✓ Context 'production' synced 
Enter fullscreen mode Exit fullscreen mode

Features:

  • Team context sharing
  • Audit logs
  • Web UI
  • SAML/SSO integration
  • Centralized secrets management

Beta coming Q3 2026. Currently under active development. Star the repo to stay updated!

Try it now

curl -fsSL https://github.com/vlebo/ctx/releases/latest/download/install.sh | sh

Enter fullscreen mode Exit fullscreen mode

Have you tried ctx? What's your current context-switching setup? Let me know in the comments!


Found this useful? ⭐ Star the repo: github.com/vlebo/ctx

Top comments (8)

Collapse
 
vmarusic profile image
Vedran Marusic

Exactly what's needed to manage multiple levels of organisations and/or clients!

Also, a magnet for Vedrans I see :D

Collapse
 
vlebo profile image
Vedran Lebo

Yes, individuals or agencies. Everyone can benefit.

Collapse
 
dsego profile image
Davorin Šego

Keep up the good work, can't wait for the Zsh plugin and completions.

Collapse
 
vlebo profile image
Vedran Lebo • Edited

Zsh plugin is already in the making, but will be released a bit later :) Thanks!

Collapse
 
sepsep profile image
Jurica Šeparović

Truly remarkable tool, saves ton of manual context switching and I can no longer drop prod databases by accidentally running commands in unwanted context. Great work!

Collapse
 
vlebo profile image
Vedran Lebo

Thanks!

Collapse
 
vkarcic profile image
Vedran Karačić

Looks awesome!

Collapse
 
vlebo profile image
Vedran Lebo

Thank you!