Skip to content

Install

Terminal window
curl -fsSL https://cloudticon.com/install.sh | sudo sh

The script detects your OS and architecture, downloads the matching binary, and places it in /usr/local/bin/ct.

If you already have a Go toolchain (1.22+):

Terminal window
go install github.com/cloudticon/ct/cmd/ct@latest

The binary lands in $GOPATH/bin (usually ~/go/bin). Make sure it is in your PATH.

Terminal window
git clone https://github.com/cloudticon/ct.git
cd ct
go build -o ct ./cmd/ct
sudo mv ct /usr/local/bin/

Re-run the same install command you used originally — the installer overwrites the existing binary:

Terminal window
curl -fsSL https://cloudticon.com/install.sh | sudo sh

For go install, simply run the command again — Go fetches the latest tag:

Terminal window
go install github.com/cloudticon/ct/cmd/ct@latest

Remove the binary and the local cache:

Terminal window
sudo rm "$(which ct)"
rm -rf ~/.ct
Terminal window
ct init my-app
cd my-app

This creates a minimal project:

my-app/
main.ct # resource definitions (TypeScript syntax)
values.json # configurable values

Edit main.ct — a few lines of TypeScript replace hundreds of YAML:

import { deployment, service, ingress } from "github.com/cloudticon/k8s@master";
const app = "api";
const labels = {
"app.kubernetes.io/name": app,
"app.kubernetes.io/part-of": "my-app",
"app.kubernetes.io/managed-by": "ct",
};
deployment({
name: app,
labels,
image: "ghcr.io/acme/api:1.4.2",
replicas: 3,
resources: {
requests: { cpu: "100m", memory: "128Mi" },
limits: { cpu: "500m", memory: "512Mi" },
},
});
service({
name: app,
labels,
selector: labels,
ports: [
{ name: "http", port: 80, targetPort: 3000 },
{ name: "metrics", port: 9090, targetPort: 9090 },
],
});
ingress({
name: app,
labels,
rules: [
{
host: "api.example.com",
http: {
paths: [
{
path: "/",
pathType: "Prefix",
backend: { service: app, port: 80 },
},
],
},
},
],
});
Terminal window
ct template . --namespace default

CT bundles main.ct, evaluates it against values.json, and prints Kubernetes YAML to stdout — ~40 lines of CT become ~120 lines of YAML. Review the output before touching the cluster.

Show generated YAML
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: default
labels:
app.kubernetes.io/name: api
app.kubernetes.io/part-of: my-app
app.kubernetes.io/managed-by: ct
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: api
app.kubernetes.io/part-of: my-app
app.kubernetes.io/managed-by: ct
template:
metadata:
labels:
app.kubernetes.io/name: api
app.kubernetes.io/part-of: my-app
app.kubernetes.io/managed-by: ct
spec:
containers:
- name: api
image: ghcr.io/acme/api:1.4.2
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
---
apiVersion: v1
kind: Service
metadata:
name: api
namespace: default
labels:
app.kubernetes.io/name: api
app.kubernetes.io/part-of: my-app
app.kubernetes.io/managed-by: ct
spec:
selector:
app.kubernetes.io/name: api
app.kubernetes.io/part-of: my-app
app.kubernetes.io/managed-by: ct
ports:
- name: http
port: 80
targetPort: 3000
- name: metrics
port: 9090
targetPort: 9090
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api
namespace: default
labels:
app.kubernetes.io/name: api
app.kubernetes.io/part-of: my-app
app.kubernetes.io/managed-by: ct
spec:
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api
port:
number: 80

Create a dev.ct file to configure your dev loop:

config({
namespace: "my-app-dev",
});
dev("api", {
command: ["npm", "run", "dev"],
sync: [{ from: "./src", to: "/app/src" }],
ports: [[3000, 3000]],
terminal: "bash",
});

Then run:

Terminal window
ct dev

CT applies your resources, patches the workload for development (removes probes, overrides command), and starts:

  • File sync — local changes stream into the container instantly.
  • Port forwardinglocalhost:3000 hits your running app.
  • Log streaming — colored output from all dev targets.
  • Terminal — drops you into the container shell.

Edit code locally, see it live on the cluster — no image rebuilds, no redeploys. See CT Dev for the full config reference.

When ready for a clean deploy without dev mode:

Terminal window
ct apply . --namespace default

Uses server-side apply — no kubectl pipe needed.

CT does not ship built-in completions yet. You can create a simple alias helper in your shell profile:

Terminal window
# ~/.bashrc or ~/.zshrc
alias ctt='ct template . --namespace'
alias cta='ct apply . --namespace'
  1. Restart your shell session or run source ~/.bashrc / source ~/.zshrc.
  2. Check whether the binary exists:
Terminal window
ls -l /usr/local/bin/ct
  1. If you used go install, make sure $GOPATH/bin is in PATH:
Terminal window
export PATH="$PATH:$(go env GOPATH)/bin"

Run the installer with sudo:

Terminal window
curl -fsSL https://cloudticon.com/install.sh | sudo sh

If your system policy blocks sudo, install via go install or build from source into a directory you own.

  • Verify network access: curl -I https://raw.githubusercontent.com.
  • Check corporate proxy / VPN settings.
  • Try downloading the binary manually from the GitHub releases page.

CT resolves github.com/… imports at bundle time. If they fail:

  1. Check git and HTTPS access to the repository.
  2. Clear the import cache:
Terminal window
rm -rf ~/.ct/cache/
  1. Re-run ct template ..