Docs Get started Introduction

Getting started

Gretl gives every local service a name. Register a port once, then start, stop, and open it by name — from the desktop app, the CLI, or any SDK.

Installation

Choose the surface that fits your workflow. All options share the same config file at ~/.gretl/config.json.

Desktop app

The desktop app is the recommended way to get started. Download for your platform:

# macOS Apple Silicon
https://gretl.dev  → click Download → macOS (M1/M2/M3)

# macOS Intel
https://gretl.dev  → click Download → macOS (Intel)

# Windows
https://gretl.dev  → click Download → Windows

# Linux
curl -fsSL https://gretl.dev/install.sh | sh

CLI only

If you don't need the GUI, install the CLI and start the daemon manually:

npm install -g @gretl/cli

# Start the background daemon (binds to 127.0.0.1:27892)
gr daemon start

# Check it's running
gr daemon status
# ✓ daemon running  pid 12345  127.0.0.1:27892
Local-first. The daemon binds to 127.0.0.1:27892 only. Your ports and config never leave your machine unless you connect a team account.

Daemon

Both the desktop app and the CLI expose a local HTTP API on 127.0.0.1:27892. Only one should run at a time — if the desktop app is open, there's no need to run gr daemon start.

CommandDescription
gr daemon startStart the background daemon and detach.
gr daemon stopStop the daemon.
gr daemon statusShow whether the daemon is running and its PID.

Your first service

Open the desktop app and click + Add Port, or use the CLI:

# Register a service
gr add 3000 --name "My App" --cmd "npm run dev"

# Start it
gr start "My App"

# Check status
gr status

gr.toml

Check a gr.toml into your repo so every teammate gets the same setup automatically on gr link:

# gr.toml
[[service]]
port    = 3000
name    = "Frontend"
command = "npm run dev"
group   = "App"

[[service]]
port    = 8080
name    = "API"
command = "go run ./cmd/server"
group   = "App"

Export your current config as gr.toml from Settings → Projects → Export gr.toml.

Groups

Assign ports to a group to start and stop them together:

gr group start App
gr group stop  App
gr group status App

Docs CLI Reference

CLI reference

The gr binary talks to the daemon at 127.0.0.1:27892. Install with npm i -g @gretl/cli.

Configuration

CommandDescription
gr add <port>Register a port with Gretl. Flags: --name --cmd --group
gr add 9001 --name "Worker" --cmd "node worker.js" --group "Backend"

Team registry sync

Share your service definitions with teammates via gr push and gr pull. Requires GR_TOKEN set to your Gretl API token.

CommandDescription
gr pushPush your local config to the team registry.
gr push --toml <path>Push from a gr.toml file instead of local config.
gr pullPull the team registry into your local config.
gr pull --tomlPull and write a gr.toml to the current directory.

Committing a gr.toml to your repo means every teammate gets the same port names, groups, and start commands after running gr pull or gr link.

# gr.toml — commit this to your repo
[[service]]
port  = 3000
name  = "Frontend"
cmd   = "npm run dev"
group = "Frontend"

[[service]]
port  = 4000
name  = "API Server"
cmd   = "node server.js"
group = "Backend"

Lifecycle

CommandDescription
gr start <name|port>Start a registered service.
gr stop <name|port>Stop a running service (kills all PIDs on that port).
gr statusTabular view of every known service.
gr logs <name|port>Print the last 50 log lines for a service.
gr open <name|port>Open the service in your browser.
gr listList all registered ports.

Groups

CommandDescription
gr group start <group>Start every service in the group.
gr group stop <group>Stop every service in the group.
gr group status <group>Show status for the group.

Daemon

CommandDescription
gr daemon startStart the background HTTP daemon.
gr daemon stopStop the daemon.
gr daemon statusShow daemon status and PID.

Kubernetes

Manage Kubernetes clusters, workloads, and port-forward tethers from the CLI. Requires GR_TOKEN. Clusters are registered at app.gretl.dev/k8s.

CommandDescription
gr k8s clustersList registered clusters.
gr k8s workloads [cluster-id]List workloads. Omit cluster-id to show all.
gr k8s sync <cluster-id>Discover and sync deployments from the cluster.
gr k8s sleep <workload-id>Scale a workload to 0 replicas immediately.
gr k8s wake <workload-id>Scale a workload back to its last known replica count.
gr k8s tethersList active port-forward tethers.
gr k8s tether <workload-id> --port <n>Open a port-forward tether. Prints localhost:PORT for direct access.
gr k8s detach <tether-id>Close a port-forward tether.
# List your clusters
gr k8s clusters

# Sync workloads from a cluster (use first 6+ chars of the ID)
gr k8s sync abc123

# See what's running / sleeping
gr k8s workloads

# Scale an idle agent pod to zero
gr k8s sleep def456

# Wake it later (restores previous replica count)
gr k8s wake def456

# Port-forward into a running pod — no kubectl required
gr k8s tether def456 --port 8000
# ✓  Tether active — localhost:21042 → pod:8000
Agent workload labels: Tag your Kubernetes deployments with gretl.dev/agent=true and gretl.dev/agent-type=langgraph (or crewai, vllm, ollama, ray) to surface them in the Agent workloads section of the dashboard with auto-sleep enabled by default.

eBPF pipeline

Deploy and manage the eBPF observability pipeline from the CLI. Requires kubectl on your PATH and an active kubeconfig context. See eBPF observability for full details.

CommandDescription
gr ebpf deployDeploy kernel-collector, k8s-collector, and reducer to current K8s context. Reads GR_TOKEN from env or --token=<key>.
gr ebpf deploy --namespace <ns>Deploy to a custom namespace (default: gretl-ebpf).
gr ebpf deploy --endpoint <url>Override the OTLP endpoint (default: https://api.gretl.dev).
gr ebpf statusShow DaemonSet, Deployment, and pod status in the eBPF namespace.
gr ebpf removeDelete the eBPF namespace and all associated resources (prompts for confirmation).
# Deploy with token from env
export GR_TOKEN=gr_live_xxxx
gr ebpf deploy

# Or pass inline
gr ebpf deploy --token=gr_live_xxxx

# Check pods are running
gr ebpf status

# Tear down
gr ebpf remove

Docs Desktop App

Desktop app

The desktop app is a Tauri (Rust + React) app that runs the same daemon locally and gives you a visual interface for managing all your ports.

Ports tab

The main view shows every registered port with its status, PID, and process name. From here you can:

Settings tab

General

Network

Shows all your local network IPs and your public IP, each with a one-click Copy button. Useful when sharing a local service with teammates on the same network.

Backup & restore

Export all your ports, names, groups, and commands to a gretl-backup.json file. Import it on any machine to restore your full setup instantly.

# Settings → Projects → Export backup
# Downloads gretl-backup.json

# Settings → Projects → Import backup
# Pick the .json file to restore
Tip: Export a backup before deleting or reinstalling the app. Your config persists at ~/.gretl/config.json through normal uninstalls, but a backup gives you an extra safety net.

Projects & gr.toml

Link project folders that contain a gr.toml — Gretl will auto-import their services on startup. Use Scan to find projects automatically, or Link folder to add one manually.


Docs Config

Config file

All state is stored at ~/.gretl/config.json. This file is shared by the desktop app, the CLI daemon, and all SDKs — changes made in one surface are immediately visible in all others.

{
  "watched": [3000, 8080],
  "names":    { "3000": "Frontend", "8080": "API" },
  "commands": { "3000": "npm run dev", "8080": "go run ./cmd/server" },
  "cwds":     { "3000": "/Users/you/my-app" },
  "groups":   { "3000": "App", "8080": "App" },
  "links":    { "3000": [8080] },
  "refresh_interval": 3,
  "theme": "dark",
  "alert_on_drop": true
}

Docs SDKs

SDK reference

Every SDK talks to the local daemon at 127.0.0.1:27892. Start either the desktop app or gr daemon start before using an SDK.

Node.js

npm install @gretl/sdk
import { PA } from '@gretl/sdk';

const ports = await PA.ports();          // all registered ports
const api   = await PA.port('API');      // find by name
await PA.start('Frontend');             // start by name
await PA.stop('Frontend');              // stop by name
await PA.waitForActive('API', 30000);   // poll until active

Python

pip install gretl
from gretl import PA

ports = PA.ports()          # list all
api   = PA.port("API")     # find by name or port number
PA.start("Frontend")
PA.stop("Frontend")
PA.wait_for_active("API", timeout=30)

Ruby

gem install gretl
require "gretl"

client = Gretl::Client.new
client.ports                          # all ports
client.port("API")                   # find by name
client.start("Frontend")
client.stop("Frontend")
client.wait_for_active("API", timeout: 30)

Go

go get github.com/slowdutch/gretl-sdks/go
import gretl "github.com/slowdutch/gretl-sdks/go"

c := gretl.NewClient()
ports, _ := c.Ports()
api,   _ := c.Port("API")
c.Start("Frontend")
c.Stop("Frontend")
_ = api

BYOC — self-hosted

Deploy the full Gretl control plane inside your own Kubernetes cluster using the official Helm chart. All data stays in your infrastructure — no traffic leaves except for license heartbeats to api.gretl.dev.

Helm install

Requires Helm ≥ 3.10 and a Kubernetes cluster. Get your license key from app.gretl.dev/settings.

# Add the Gretl chart repo
helm repo add gretl https://charts.gretl.dev
helm repo update

# Install into its own namespace
helm install gretl gretl/gretl \
  --namespace gretl --create-namespace \
  --set license.key=<your-key> \
  --set backend.supabaseUrl=<url> \
  --set backend.supabaseServiceKey=<key> \
  --set backend.supabaseJwtSecret=<secret> \
  --set backend.encryptionKey=<32-char-random> \
  --set clickhouse.password=<password>

Key values

ValueDefaultDescription
license.key""Enterprise license key (required)
license.gracePeriodHours24Hours before features disable if heartbeat fails
ebpf.enabledtrueDeploy eBPF observability pipeline
ebpf.minKernelVersion5.8Nodes below this skip the kernel-collector safely
clickhouse.enabledtrueDeploy in-cluster ClickHouse for telemetry
dashboard.enabledfalseDeploy dashboard inside cluster (vs. using app.gretl.dev)
backend.ingress.enabledfalseExpose backend via Ingress
backend.ingress.hostgretl.internalIngress hostname for the backend API

eBPF observability

eBPF telemetry gives you kernel-level visibility into every pod — CPU, memory, and network flows — with zero code changes. Requires Linux kernel ≥ 5.8 on cluster nodes.

The pipeline runs three components as a DaemonSet + two Deployments:

ComponentTypePurpose
kernel-collectorDaemonSetAttaches eBPF probes, captures TCP, CPU, process spawns per node
k8s-collectorDeploymentWatches K8s API, maps PIDs to workload identity
reducerDeploymentEnriches events, converts to OTLP, forwards to Gretl backend

Deploy (standalone)

If you're not using the Helm chart, deploy with the CLI:

gr ebpf deploy --token=<GR_TOKEN>

Or with kustomize directly:

# Create secret first
kubectl create secret generic gretl-ebpf-secret \
  --namespace gretl-ebpf \
  --from-literal=GR_TOKEN=<token> \
  --from-literal=GRETL_OTLP_ENDPOINT=https://api.gretl.dev/otlp \
  --dry-run=client -o yaml | kubectl apply -f -

# Deploy everything
kubectl apply -k https://github.com/slowdutch/gretl-sdks//gretl-ebpf/k8s

# Check status
gr ebpf status

What's collected

SignalGranularityRetention
CPU millicoresPer pod, ~30s90 days
Memory MiB (RSS)Per pod, ~30s90 days
Per-process CPU/memoryPer process within pod, ~30s30 days
Network flowsPer workload pair30 days
Inferred service callsPer service edge, per minute14 days
CPU stack profilesPer workload30 days
Security eventsPer process spawn / connection90 days

View this data in the dashboard under Telemetry — six tabs: Metrics, Processes, Profiles, Traffic, Traces, Security.

Dashboard tabs

Metrics

Workload-level CPU, memory, and network time-series. Summary cards show the latest snapshot per workload with colour-coded CPU health. The full table shows per-minute averages with inline sparkbars.

Filter by cluster, workload, and time window (1h / 6h / 24h / 7d).

Processes

Per-process CPU/memory attribution within a workload. Answers "which process is consuming the most resources?" without any instrumentation — data comes from execve events and CPU samples captured by the eBPF kernel-collector.

Example: a pod running LangGraph + a FastAPI server will show two rows — python (langgraph) and uvicorn — each with their own CPU share bar.

Select a workload to activate this tab.

Profiles

CPU stack trace samples from eBPF perf-event profiling. Shows the top 50 unique stack traces by sample count, with frame chains (leaf → root) and estimated CPU time. Useful for finding hot functions without adding a profiler SDK.

Traffic

Service-to-service network dependency graph. The SVG map shows which workloads are talking to each other — edge weight represents traffic volume. The table below shows flow count, total bytes, and average latency per edge.

Built from kernel-observed TCP connections — no Istio or Linkerd required.

Traces

Inferred service call timelines derived from eBPF-observed TCP connections. Shows call counts, avg/p99 latency, and total bytes per (caller → callee, port) edge per minute.

Note: These are eBPF-inferred spans, not full distributed traces. They show that service A called service B and how often/fast, but cannot correlate individual requests across hops. For full end-to-end traces with span IDs, instrument your services with the OTel SDK — the two are complementary.

Security

eBPF-observed security-relevant kernel events. The pipeline detects:

RuleSeverityWhat triggers it
SHELL_SPAWN_NONROOTwarnShell (bash/sh/zsh) spawned by a non-root process inside a container
NETWORK_TOOL_EXECcriticalnmap, masscan, netcat, socat executed
CREDENTIAL_TOOL_EXECcriticalCredential access tools (mimikatz, hashcat, john)
SUDO_EXECwarnsudo/su called by non-root
PKG_MANAGER_EXECinfoapt, pip, npm, yum executed at runtime (unusual in containers)
SHELL_OUTBOUND_CONNwarnShell or interpreter makes outbound TCP connection to a non-standard port

Events are grouped by severity (critical / warn / info) with badge counts at the top. Click any row to see the full process name, cmdline, and remote IP if applicable.

Agent auto-detection

Gretl automatically tags workloads as agent workloads based on eBPF-observed process names and command lines — no gr.mark_agent() call required.

The detection sweeper runs every 5 minutes and queries process_metrics for recently-seen processes. Matches are upserted to k8s_workloads.is_agent = true with the detected framework:

FrameworkDetected from
vLLMprocess name or cmdline contains vllm
Ollamaprocess name is ollama
Rayprocess name starts with ray::, or raylet, or cmdline contains ray.serve
LangGraphcmdline contains langgraph or langchain
CrewAIcmdline contains crewai
CustomPython/Node running a file with agent or worker in its name

Manual tags set via the dashboard or SDK always take precedence — auto-detection only fires if is_agent is currently false.