clickhousectl 0.2.0

The CLI for ClickHouse: local and cloud.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
use clap::{Args, Subcommand};

#[derive(Args)]
pub struct LocalArgs {
    /// Output as JSON
    #[arg(long, global = true)]
    pub json: bool,

    #[command(subcommand)]
    pub command: LocalCommands,
}

#[derive(Subcommand)]
pub enum LocalCommands {
    /// Install a ClickHouse version
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  `clickhousectl local use <version>` will auto-install if the version is missing and set as default.")]
    Install {
        /// Version to install (e.g., latest, stable, lts, 25, 25.12, 25.12.9.61)
        version: String,

        /// Force re-install even if version is already installed
        #[arg(long)]
        force: bool,
    },

    /// List installed versions
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  Without flags: shows locally installed versions (exact version strings).
  With --remote: shows versions available for download from builds.clickhouse.com.
  Use the exact version strings from this output with `clickhousectl local remove` or `clickhousectl local use`.
  Related: `clickhousectl local install <version>` to install, `clickhousectl local which` to see current default.")]
    List {
        /// List versions available for download
        #[arg(long)]
        remote: bool,
    },

    /// Set the default version
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  Sets the default ClickHouse version used by `clickhousectl local client` and `clickhousectl local server`.
  Accepts version specs: \"stable\", \"lts\", partial like \"25.12\", or exact like \"25.12.5.44\".
  Auto-installs the version if not already present.
  Related: `clickhousectl local which` to verify, `clickhousectl local server start` to start a server.")]
    Use {
        /// Version to use as default
        version: String,
    },

    /// Remove an installed version
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  Removes an installed ClickHouse version from ~/.clickhouse/versions/.
  Takes an exact version string as shown by `clickhousectl local list` (e.g., \"25.12.5.44\").
  Does NOT accept keywords like \"stable\" — use the exact version number.
  Related: `clickhousectl local list` to see installed versions.")]
    Remove {
        /// Version to remove
        version: String,
    },

    /// Show the current default version
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  Shows the current default version and binary path. No arguments needed.
  Use this to verify which version is active before running commands.
  Related: `clickhousectl local use <version>` to change the default.")]
    Which,

    /// Initialize a project-local ClickHouse configuration
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  Creates a .clickhouse/ directory (runtime data, git-ignored) and a clickhouse/ project
  scaffold with subdirs: tables/, materialized_views/, queries/, seed/ (each with .gitkeep).
  The clickhouse/ directory is meant to be committed — organize your SQL files there.
  Related: `clickhousectl local server start` to start a server with project-local data.")]
    Init,

    /// Connect to a running ClickHouse server with clickhouse-client
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  Two connection modes:
  1. Named server: `clickhousectl local client --name dev` — looks up port and version from a
     locally managed server started via `clickhousectl local server start`. Defaults to \"default\".
  2. Explicit host/port: `clickhousectl local client --host myhost --port 9000` — connects to any
     ClickHouse server directly, bypassing local server lookup.
  --query and --queries-file execute SQL inline or from a file.
  Additional clickhouse-client args can be passed after --.
  Related: `clickhousectl local server start` to start a local server, `clickhousectl local server list` to see servers.")]
    Client {
        /// Server name to connect to (default: "default")
        #[arg(long, short)]
        name: Option<String>,

        /// Host to connect to (bypasses local server lookup)
        #[arg(long)]
        host: Option<String>,

        /// TCP port to connect to (bypasses local server lookup if set)
        #[arg(long, short)]
        port: Option<u16>,

        /// Execute a SQL query
        #[arg(long, short)]
        query: Option<String>,

        /// Execute queries from a SQL file
        #[arg(long)]
        queries_file: Option<String>,

        /// Additional arguments to pass to clickhouse-client
        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
        args: Vec<String>,
    },

    /// Manage local ClickHouse server instances
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  Manage named ClickHouse server instances. Each server has its own data directory.
  Data is stored in .clickhouse/servers/<name>/data/ and persists between restarts.
  Typical: `clickhousectl local server start` (starts \"default\"), `clickhousectl local server start --name test`.
  Related: `clickhousectl local client` to connect to a running server.")]
    Server {
        #[command(subcommand)]
        command: ServerCommands,
    },

    /// Manage local Postgres instances (Docker-backed)
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  Manage named Postgres server instances backed by Docker. Each instance is keyed on
  (name, major version) and runs as a `postgres:<tag>` container with data bind-mounted
  at .clickhouse/servers/<name>-pg<major>/data/.
  Typical: `clickhousectl local postgres start` (starts \"default\" on port 5432).
  `local server list` shows ClickHouse + Postgres entries together.
  Requires Docker to be installed and running.")]
    Postgres {
        #[command(subcommand)]
        command: PostgresCommands,
    },
}

#[derive(Subcommand)]
pub enum ServerCommands {
    /// Start a ClickHouse server instance
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  Starts a named clickhouse-server instance with its own data directory.
  Data is stored in .clickhouse/servers/<name>/data/ and persists between restarts.
  Without --name, the first server is called \"default\"; if \"default\" is already running,
  a random name is generated (e.g., \"bold-crane\").
  Use --name to give a server a stable identity (e.g., --name dev, --name test).
  Use --version (-v) to run a specific ClickHouse version without changing the default.
  Accepts same specs as install/use: stable, lts, latest, 25.12, etc. Installs if needed.
  Ports default to 8123 (HTTP) and 9000 (TCP). If they're in use, free ports are auto-assigned.
  Use --http-port and --tcp-port to set explicit ports.
  Runs in background by default. Use --foreground (-F / --fg) to run in foreground.
  If --name is given and that server is already running, the command will error.
  Shows count of already-running servers before starting.
  Related: `clickhousectl local server list` to see servers, `clickhousectl local server stop <name>` to stop one.")]
    Start {
        /// Server name (default: \"default\", or random if default is already running)
        #[arg(long)]
        name: Option<String>,

        /// ClickHouse version to use (e.g. stable, lts, latest, 25.12). Installs if needed. Does not change the default version.
        #[arg(long, short = 'v')]
        version: Option<String>,

        /// HTTP port (default: 8123, auto-assigns a free port if in use)
        #[arg(long)]
        http_port: Option<u16>,

        /// TCP port (default: 9000, auto-assigns a free port if in use)
        #[arg(long)]
        tcp_port: Option<u16>,

        /// Run server in foreground (default: background)
        #[arg(long, alias = "fg", short = 'F')]
        foreground: bool,

        /// Arguments to pass to clickhouse-server
        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
        args: Vec<String>,
    },

    /// List all server instances (running and stopped)
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  Shows all named ClickHouse server instances and their status.
  Automatically cleans up stale entries for processes that are no longer running.
  Shows name, status (running/stopped), PID, version, and ports.
  Related: `clickhousectl local server start` to start a server, `clickhousectl local server stop <name>` to stop one.")]
    List {
        /// System-wide maintenance only: list servers across all projects. You almost certainly want the default project-scoped list instead.
        #[arg(long)]
        global: bool,
    },

    /// Stop a running server by name
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  Stops a named ClickHouse server. Use the name from `clickhousectl local server list`.
  Sends SIGTERM first, then SIGKILL if the process doesn't exit gracefully.
  The server's data directory is preserved — restart with `clickhousectl local server start --name <name>`.
  Related: `clickhousectl local server list` to see servers.")]
    Stop {
        /// Name of the server to stop
        name: String,

        /// System-wide maintenance only: stop a server from any project. You almost certainly want the default project-scoped stop instead.
        #[arg(long)]
        global: bool,

        /// Project directory to disambiguate when using --global
        #[arg(long, requires = "global")]
        project: Option<String>,
    },

    /// Stop all running server instances
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  Stops all running ClickHouse server instances.
  Sends SIGTERM first, then SIGKILL if processes don't exit.
  Data directories are preserved.
  Related: `clickhousectl local server list` to see servers.")]
    StopAll {
        /// System-wide maintenance only: stop all servers across all projects. You almost certainly want the default project-scoped stop-all instead.
        #[arg(long)]
        global: bool,
    },

    /// Remove a stopped server and its data
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  Permanently deletes a server's data directory. The server must be stopped first.
  This is irreversible — all data for this server instance will be lost.
  Related: `clickhousectl local server stop <name>` to stop first, `clickhousectl local server list` to see servers.")]
    Remove {
        /// Name of the server to remove
        name: String,
    },

    /// Write ClickHouse connection env vars to a .env file
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  Writes CLICKHOUSE_HOST, CLICKHOUSE_PORT, and CLICKHOUSE_HTTP_PORT into a .env file
  (or .env.local with --local) based on a running server's actual connection details.
  Optionally includes CLICKHOUSE_USER, CLICKHOUSE_PASSWORD, and CLICKHOUSE_DATABASE when
  the corresponding flags are provided.
  If the file already exists, existing CLICKHOUSE_* vars are replaced in-place. Otherwise the file is created.
  Useful for configuring apps that read from dotenv files.
  Related: `clickhousectl local server start` to start a server, `clickhousectl local server list` to see servers.")]
    Dotenv {
        /// Server name (default: "default")
        #[arg(long)]
        name: Option<String>,

        /// Write to .env.local instead of .env
        #[arg(long)]
        local: bool,

        /// Include CLICKHOUSE_USER with this value
        #[arg(long)]
        user: Option<String>,

        /// Include CLICKHOUSE_PASSWORD with this value
        #[arg(long)]
        password: Option<String>,

        /// Include CLICKHOUSE_DATABASE with this value
        #[arg(long)]
        database: Option<String>,
    },
}

#[derive(Subcommand)]
pub enum PostgresCommands {
    /// Start a Postgres container
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  Starts a named Postgres server backed by a Docker container.
  Without --name, the first server is called \"default\"; if \"default\" is running,
  a random name is generated (e.g. \"bold-crane\").
  --version (-v) selects a postgres image tag (16, 17, or 18 — e.g. 16, 16-alpine, 17.0, 18-bookworm).
  Defaults to 18. Image is pulled if not already present locally.
  --port defaults to 5432; if taken, a free port is auto-assigned.
  Data persists at .clickhouse/servers/<name>/data/ and is bind-mounted into the container.
  A random POSTGRES_PASSWORD is generated unless --password or `-e POSTGRES_PASSWORD=...` is given.
  Containers are labeled `clickhousectl.engine=postgres`, `clickhousectl.name=<name>`,
  `clickhousectl.project=<cwd>`, `created_by=clickhousectl_<version>` for safe discovery.
  Requires Docker to be installed and running.")]
    Start {
        /// Server name (default: "default", or random if default is already running)
        #[arg(long)]
        name: Option<String>,

        /// Postgres image tag (16, 17, or 18 — e.g. 16, 16-alpine, 17.0, 18-bookworm). Default: 18. Pulls if missing.
        #[arg(long, short = 'v')]
        version: Option<String>,

        /// Host TCP port (default: 5432, auto-assigns a free port if in use)
        #[arg(long)]
        port: Option<u16>,

        /// POSTGRES_USER (default: postgres)
        #[arg(long)]
        user: Option<String>,

        /// POSTGRES_PASSWORD (default: random 24-char alphanumeric)
        #[arg(long)]
        password: Option<String>,

        /// POSTGRES_DB (default: postgres)
        #[arg(long)]
        database: Option<String>,

        /// Extra env vars for the container, repeatable: -e KEY=VALUE
        #[arg(short = 'e', long = "env", value_name = "KEY=VALUE")]
        env: Vec<String>,
    },

    /// Stop a running Postgres container by name
    Stop {
        /// Name of the server to stop
        name: String,
        /// Postgres version to disambiguate when multiple share a name
        #[arg(long, short = 'v')]
        version: Option<String>,
    },

    /// Stop all running Postgres containers in this project
    StopAll,

    /// Remove a stopped Postgres server and its data directory
    Remove {
        /// Name of the server to remove
        name: String,
        /// Postgres version to disambiguate when multiple share a name
        #[arg(long, short = 'v')]
        version: Option<String>,
    },

    /// Connect to a running Postgres instance with psql
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  Two connection modes:
  1. Named server: `clickhousectl local postgres client --name dev` — looks up the host port
     and credentials from a locally managed Postgres started via `local postgres start`.
     Defaults to \"default\".
  2. Explicit host/port: `clickhousectl local postgres client --host myhost --port 5432`.
  If `psql` is on PATH on the host, it is execed directly. Otherwise, falls back to running
  `psql` inside the container via Docker exec (no host psql required).
  --query and --queries-file pass through to psql (-c / -f).
  Additional psql args can be passed after --.")]
    Client {
        /// Server name to connect to (default: "default")
        #[arg(long, short)]
        name: Option<String>,

        /// Postgres version to disambiguate when multiple share a name
        #[arg(long, short = 'v')]
        version: Option<String>,

        /// Host to connect to (bypasses local server lookup)
        #[arg(long)]
        host: Option<String>,

        /// TCP port to connect to (bypasses local server lookup if set)
        #[arg(long, short)]
        port: Option<u16>,

        /// Execute a single SQL query
        #[arg(long, short)]
        query: Option<String>,

        /// Execute queries from a SQL file
        #[arg(long)]
        queries_file: Option<String>,

        /// Additional arguments to pass to psql
        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
        args: Vec<String>,
    },

    /// Write Postgres connection env vars to a .env file
    #[command(after_help = "\
CONTEXT FOR AGENTS:
  Writes POSTGRES_HOST, POSTGRES_PORT, POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DATABASE
  into .env (or .env.local with --local) based on a running Postgres server.
  If the file already exists, existing POSTGRES_* vars are replaced in-place.")]
    Dotenv {
        /// Server name (default: "default")
        #[arg(long)]
        name: Option<String>,

        /// Postgres version to disambiguate when multiple share a name
        #[arg(long, short = 'v')]
        version: Option<String>,

        /// Write to .env.local instead of .env
        #[arg(long)]
        local: bool,
    },
}