@metabase/rde 0.1.14 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +41 -53
  2. package/dist/cli.mjs +694 -856
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @metabase/rde
2
2
 
3
- `rde` prepares a Mac or Linux machine for data-engineering work with Metabase and coding agents. One command, `rde init`, sets up everything a working setup needs: the `mb` CLI, the `rde` skill for your coding agents, a running Metabase Enterprise instance (in Docker, or a jar run with the machine's Java), an admin user, an API key wired into `mb`, a Postgres sample database with transforms switched on, your license, the databases you want to work with, and a git repository connected through Metabase's remote sync. It decides what it can on its own and asks only for what it cannot know: your license token, a connection string for your own database, and with a license, where the git repository lives. Every step checks whether it is already done, so the wizard can be interrupted at any prompt and picked up again with the same command.
3
+ `rde` prepares a Mac or Linux machine for data-engineering work with Metabase and coding agents. One command, `rde init`, sets up everything a working setup needs: the `mb` CLI, the `rde` skill for your coding agents, a running Metabase Enterprise instance (in Docker, or a jar run with the machine's Java), an admin user, an API key wired into `mb`, transforms switched on, your license, a database of your own for transforms to write to, and a git repository connected through Metabase's remote sync. It decides what it can on its own and asks only for what it cannot know: your license token, a connection string for your own database (`init` goes no further without one), and with a license, where the git repository lives. Every step checks whether it is already done, so the wizard can be interrupted at any prompt and picked up again with the same command.
4
4
 
5
5
  After `init`, the rest is lifecycle: `rde start`, `rde stop`, `rde status`, `rde logs`, `rde open`, and `rde db add` when another database comes along. The instance lives under `~/.rde`, listens on `127.0.0.1` only, and is used through `mb` and through the agent skill.
6
6
 
@@ -36,7 +36,6 @@ The wizard shows its checklist first (`✓` done, `○` to do, `↑` done but be
36
36
  ○ Create the admin user
37
37
  ○ Connect the Metabase CLI
38
38
  ○ Enable transforms
39
- ○ Connect a sample database
40
39
  ○ Activate your license
41
40
  – Connect a git repository
42
41
  ○ Connect your databases
@@ -45,11 +44,11 @@ The wizard shows its checklist first (`✓` done, `○` to do, `↑` done but be
45
44
  ● Running npm install -g @metabase/cli@alpha-release-65-integration-branch
46
45
  ```
47
46
 
48
- The steps up to the license run without a question, save one: `mb` is installed with the package manager that installed `rde`, the skill goes to the coding agents you pick from the ones found on the machine (at a terminal; without one, to every agent found), Metabase runs in Docker when Docker is there (the jar with your Java otherwise), on the first free port from 23000 up that no other container or instance claims, with an admin user whose password is generated and kept in `~/.rde`, `mb` is logged in under its `default` profile (the one question here comes when `default` already points at another Metabase), and a Postgres sample database comes up in a second container, connected to Metabase as a place transforms can write. Each of those choices is printed as it is made and can be overridden with a flag. The prompts that remain are the license token (Enter skips it), with a license that includes remote sync where the git repository lives and which remote it uses, and your own databases (Enter skips them).
47
+ The steps up to the license run without a question, save one: `mb` is installed with the package manager that installed `rde`, the skill goes to the coding agents you pick from the ones found on the machine (at a terminal; without one, to every agent found), Metabase runs in Docker when Docker is there (the jar with your Java otherwise), on the first free port from 23000 up that no other container or instance claims, with an admin user whose password is generated and kept in `~/.rde`, `mb` is logged in under its `default` profile (the one question here comes when `default` already points at another Metabase), and transforms are switched on. Each of those choices is printed as it is made and can be overridden with a flag. The prompts that remain are the license token (Enter skips it), with a license that includes remote sync where the git repository lives and which remote it uses, and your own database, which `init` needs.
49
48
 
50
- The databases step asks once. At a terminal, without `--yes` or `--skip-databases`, and while none of your own databases is connected, it lists what is connected (the sample database) and asks for a connection string: paste one and `rde` reads the engine from it (or asks which, when the string fits several, or shows the engine list when it fits none), then shows the connection for review, tests it, adds it, and offers another. Enter skips it, and the skip is remembered, so the next `rde init` does not ask again; `rde init --only databases` and `rde db add` still do. With `--yes` or without a terminal it asks nothing and the sample database stands in; `--database` connects yours ahead of time.
49
+ The databases step is the one `init` cannot do without: transforms write their tables to a database of your own, so `init` goes no further until one is connected, and it has to be connected as a user that can create tables. A database already on the instance counts, whether `rde` connected it or you did in Metabase's admin settings. At a terminal, without `--yes`, while there is none, the step says so and asks for a connection string: paste one and `rde` reads the engine from it (or asks which, when the string fits several, or shows the engine list when it fits none), then shows the connection for review, tests it, adds it, and offers another. Enter goes to the engine list, which offers no way to finish until a database is connected; Ctrl-C stops the run, and the next `rde init` asks again. `--database`, or the answers file's `databases` section, names it ahead of time. With `--yes` or without a terminal and nothing named, the step fails with exit code 2 and names both. Metabase starts with `MB_LOAD_SAMPLE_CONTENT=false`, so its bundled H2 sample database, which cannot be a transform target, and the example content built on it are never created.
51
50
 
52
- It runs after the git step because content imported from a repository names its databases, and Metabase only finds them by name. Every database the content names that this instance lacks becomes a stub: a placeholder with that name and no connection, which keeps the content importable and which Metabase leaves out of its own database lists. When there are stubs, the step asks for them instead of the connection string: a checklist of their names, none picked, where you pick the few you work on (a repository can name dozens, most of them someone else's or out of reach from your machine). Each one picked asks for its connection string (Enter goes to the engine list, whose last choice leaves that one unconnected), then review, test, and connect: the stub becomes the real database under the same name and id, so the content on it works and its sync starts. Picking none skips the step like Enter does. The ones left over are named at the end of the step and in the summary, and `rde db add` and `rde db list` show them until they are connected. A database named ahead of time (`--database`, an answers file, `rde db add --url --name`) whose name is a stub's connects that stub too, never a second database of the same name.
51
+ It runs after the git step because content imported from a repository names its databases, and Metabase only finds them by name. Every database the content names that this instance lacks becomes a stub: a placeholder with that name and no connection, which keeps the content importable and which Metabase leaves out of its own database lists. When there are stubs, the step asks for them instead of the connection string: a checklist of their names, none picked, where you pick the few you work on (a repository can name dozens, most of them someone else's or out of reach from your machine). Each one picked asks for its connection string (Enter goes to the engine list, whose last choice leaves that one unconnected), then review, test, and connect: the stub becomes the real database under the same name and id, so the content on it works and its sync starts. Picking none goes on to the connection-string question while no database is connected. The ones left over are named at the end of the step and in the summary, and `rde db add` and `rde db list` show them until they are connected. A database named ahead of time (`--database`, an answers file, `rde db add --url --name`) whose name is a stub's connects that stub too, never a second database of the same name.
53
52
 
54
53
  The git step reads `–` until a license with remote sync is active; it is checked again when its turn comes, so a run that activates a license connects the repository in the same pass.
55
54
 
@@ -63,10 +62,9 @@ The git step reads `–` until a license with remote sync is active; it is check
63
62
  | Create the admin user | `admin@metabase.local` with a generated password that `rde credentials` shows, or your own with `--admin prompted`, see [Credentials](#credentials) |
64
63
  | Connect the Metabase CLI | Creates an API key named `rde` and logs `mb` in with it under the profile `default`, so plain `mb` uses the instance; when `default` already points at another Metabase it asks first, see [The `mb` profile](#the-mb-profile); a key Metabase rejects is replaced |
65
64
  | Enable transforms | Turns transforms on, unless someone already set them either way: turned off in the admin settings, they stay off on every later `rde init`, and the admin settings turn them back on |
66
- | Connect a sample database | Runs Metabase's Postgres sample data (`metabase/qa-databases:postgres-sample-15`) in a container named `rde-sampledb-default` on the first free port from 25432 (or one Docker picks, when another program or a concurrent `rde init` takes that port first), and connects it as `Sample Database`. It replaces the H2 sample database Metabase would otherwise bundle, which cannot be a transform target. Needs Docker, so a jar instance on a machine without Docker has no sample database |
67
- | Activate your license | Optional. Paste a token, or press Enter to skip; remote sync needs one with the `remote-sync` feature |
65
+ | Activate your license | Optional. Paste a token, or press Enter to skip. The token unlocks remote sync (the `remote-sync` feature, which the git step needs), data apps (`data-apps`), and transform tests (`transforms-testing`); skipping the license goes without all three, and an activated token that lacks some is named with the ones it lacks. A token Metabase refuses is asked for again at a terminal |
68
66
  | Connect a git repository | Only with a license. Initializes or reuses a repository and points Metabase's remote sync at it, with transforms included in the sync (the Transforms row under Collections to sync), and imports the content it already holds |
69
- | Connect your databases | At a terminal, until you connect one of your own or skip it: pick the databases the imported content uses from a checklist, or, with none, paste a connection string (Enter skips); review, test, add; repeat. `--database` names them ahead of time; with `--yes` or without a terminal nothing is asked. `rde db add` starts from the same checklist, then the engine list, where the fields can also be filled one by one |
67
+ | Connect your databases | Required: `init` goes no further until a database of your own is connected, as a user that can create the tables transforms write. At a terminal: pick the databases the imported content uses from a checklist, or, with none, paste a connection string (Enter goes to the engine list); review, test, add; repeat. `--database` names them ahead of time; with `--yes` or without a terminal and none named, the step fails naming `--database` and the answers file. `rde db add` starts from the same checklist, then the engine list, where the fields can also be filled one by one |
70
68
  | Summary | URL, login email, the `mb` command for the instance, databases, repository, and the command that opens each detected agent |
71
69
 
72
70
  The second run on the same machine detects every step as done and prints the summary only:
@@ -81,43 +79,30 @@ The second run on the same machine detects every step as done and prints the sum
81
79
  ✓ Create the admin user
82
80
  ✓ Connect the Metabase CLI
83
81
  ✓ Enable transforms
84
- ✓ Connect a sample database
85
82
  – Activate your license
86
83
  – Connect a git repository
87
84
  ✓ Connect your databases
88
85
  ○ Summary
89
86
  │
90
- ◇ Your environment ─────────────────────────────────────────────────────────────────╮
91
- │ │
92
- │ Metabase: http://localhost:23000 │
93
- │ Login: admin@metabase.local (rde credentials shows the password) │
94
- │ Metabase CLI: mb <command> │
95
- │ Databases: │
96
- │ Sample Database (postgres, sync complete) │
97
- │ warehouse (postgres, syncing; `rde status` shows when it finishes) │
98
- │ Sample database: psql "postgres://metabase:metasample123@localhost:25432/sample" │
99
- │ Remote sync: not configured (no license) │
100
- │ rde skill: installed for Claude Code │
101
- │ Start working: │
102
- │ claude (Claude Code) │
103
- │ Lifecycle: rde status (--json for scripts), rde stop, rde start │
104
- │ │
105
- ├────────────────────────────────────────────────────────────────────────────────────╯
87
+ ◇ Your environment ─────────────────────────────────────────────────────╮
88
+ │ │
89
+ │ Metabase: http://localhost:23000 │
90
+ │ Login: admin@metabase.local (rde credentials shows the password) │
91
+ │ Metabase CLI: mb <command> │
92
+ │ Databases: │
93
+ │ warehouse (postgres, syncing; `rde status` shows when it finishes) │
94
+ │ Remote sync: not configured (no license) │
95
+ │ rde skill: installed for Claude Code │
96
+ │ Start working: │
97
+ │ claude (Claude Code) │
98
+ │ Lifecycle: rde status (--json for scripts), rde stop, rde start │
99
+ │ │
100
+ ├────────────────────────────────────────────────────────────────────────╯
106
101
  │
107
102
  └ rde init finished
108
103
  ```
109
104
 
110
- Ctrl-C at any prompt stops the run; `rde init` again continues from the first step that is not done. A run on an instance that already exists says so first (`Resuming instance "default" (Metabase http://localhost:23000, repository /Users/you/rde-content); steps already done are skipped.`, and that `rde uninstall` comes first to start over). A flag or answers-file section for a step that does not run, because it is already done, does not apply (a license skipped before), or is left out by `--only`, is ignored with a warning naming the flag and the step and how to get it done instead: `--database ignored: "Connect your databases" is already done. Connect another with rde db add --url <connection string>.` A skip flag for a step that is already done asks nothing of it and is not warned about. A step that fails ends the run with exit code 1 (2 for a missing answer) and a last line naming the step and the command that resumes there: `rde init stopped at "Connect a sample database": <reason>. Resume with rde init --from sample-database.` `rde init --from license` re-runs from a step on (a later step that does not apply, such as the git step without a license that has remote sync, stays skipped), `rde init --only databases` runs one step.
111
-
112
- ## The sample database
113
-
114
- Every instance gets a second container, `rde-sampledb-default`, running `metabase/qa-databases:postgres-sample-15`: the Postgres edition of Metabase's own sample data, the same tables and rows the bundled H2 sample database has (`orders`, `products`, `people`, `reviews`, `accounts`, `invoices`, `feedback`, `analytic_events`), with the user `metabase`, the password `metasample123`, and the database `sample`. `init` publishes it on `127.0.0.1` at the first free port from 25432 up (5432 is usually your own Postgres, and 15432 a common stand-in for it), connects it to Metabase as `Sample Database`, and sets `transforms-enabled`, so transforms have somewhere to write on the first run: the H2 sample database refuses to be a transform target, this one creates the target schema on demand. The `metabase` user is the cluster superuser, so any schema name works. Metabase is started with `MB_LOAD_SAMPLE_CONTENT=false`, so the H2 sample database and the example content built on it are never created and the Postgres one is the only `Sample Database`.
115
-
116
- ```sh
117
- psql "postgres://metabase:metasample123@localhost:25432/sample" # the summary and `rde status` show the port
118
- ```
119
-
120
- `rde start` and `rde stop` bring the container up and down with Metabase, `rde status` shows its state and sync, `rde doctor` checks it, and `rde uninstall` removes it (with `--remove-image`, its image too). The data lives inside the container: `stop`/`start` keep it, and a container that is removed comes back with the pristine sample data on the next `rde init`. The jar runtime gets the sample database as well whenever Docker is available; on a machine without Docker the step is `–` and there is no sample database at all (the H2 one is switched off for every instance).
105
+ Ctrl-C at any prompt stops the run; `rde init` again continues from the first step that is not done. A run on an instance that already exists says so first (`Resuming instance "default" (Metabase http://localhost:23000, repository /Users/you/rde-content); steps already done are skipped.`, and that `rde uninstall` comes first to start over). A flag or answers-file section for a step that does not run, because it is already done, does not apply (a license skipped before), or is left out by `--only`, is ignored with a warning naming the flag and the step and how to get it done instead: `--database ignored: "Connect your databases" is already done. Connect another with rde db add --url <connection string>.` A skip flag for a step that is already done asks nothing of it and is not warned about. A step that fails ends the run with exit code 1 (2 for a missing answer) and a last line naming the step and the command that resumes there: `rde init stopped at "Connect your databases": <reason>. Resume with rde init --from databases.` `rde init --from license` re-runs from a step on (a later step that does not apply, such as the git step without a license that has remote sync, stays skipped), `rde init --only databases` runs one step.
121
106
 
122
107
  ## Credentials
123
108
 
@@ -133,8 +118,6 @@ In both variants `rde` creates an API key named `rde` in the Administrators grou
133
118
 
134
119
  An instance whose state file held the public `admin@metabase.com` pair keeps working: the password and the key move to `secrets.json` the first time any `rde` command reads the state, and `rde doctor` marks the admin password `legacy-default`, because anyone who knows the default can log in. When the instance holds nothing you need, `rde uninstall` then `rde init` recreates it with a generated password.
135
120
 
136
- The sample database's own credentials (`metabase` / `metasample123`) are baked into its image and are not a secret.
137
-
138
121
  ## What lands in `~/.rde`, and what never does
139
122
 
140
123
  ```
@@ -142,7 +125,7 @@ The sample database's own credentials (`metabase` / `metasample123`) are baked i
142
125
  config.json { schemaVersion, defaultInstance }
143
126
  instances/default/ mode 0700
144
127
  state.json mode 0600, no secrets: runtime, url, Metabase version, admin email and variant,
145
- mb profile, license features, databases, sample database, git remote, step records
128
+ mb profile, license features, databases, git remote, step records
146
129
  secrets.json mode 0600: { schemaVersion, admin: { email, password } | null, apiKey }
147
130
  data/ mounted into the container as /rde, or the jar's working directory
148
131
  metabase.db/metabase.db.mv.db the H2 application database
@@ -156,7 +139,7 @@ The sample database's own credentials (`metabase` / `metasample123`) are baked i
156
139
 
157
140
  Three things are never written to disk or to a log by `rde`: the license token (it goes to Metabase, which keeps it in its own application database), a password you typed for a prompted admin user, and a git access token for a hosted remote (Metabase encrypts it on its side). The `mb` profile lives where `mb` keeps its profiles, under `$XDG_CONFIG_HOME` or `~/.config`.
158
141
 
159
- The instance listens on `127.0.0.1` only (the container's published port, or the jar's `MB_JETTY_HOST`), so it is reachable from this machine and from nothing else on the network; the sample database's container is published the same way. Two containers belong to the instance: `rde-metabase-default` (Metabase, with `data/` mounted) and `rde-sampledb-default` (Postgres, no mount). Those are the names under `~/.rde`; with `RDE_HOME` set to another directory both names end in a tag derived from that directory, such as `rde-metabase-default-3fa9c1d2`, so two homes never share a container.
142
+ The instance listens on `127.0.0.1` only (the container's published port, or the jar's `MB_JETTY_HOST`), so it is reachable from this machine and from nothing else on the network. Its container is `rde-metabase-default`, with `data/` mounted. That is the name under `~/.rde`; with `RDE_HOME` set to another directory the name ends in a tag derived from that directory, such as `rde-metabase-default-3fa9c1d2`, so two homes never share a container.
160
143
 
161
144
  ### Docker or jar
162
145
 
@@ -166,9 +149,9 @@ Docker is used whenever it is available: the image is self-contained, and the co
166
149
 
167
150
  | Command | What it does |
168
151
  | --- | --- |
169
- | `rde start` | Starts the sample database and the instance, and waits until Metabase is healthy; `--port <n>` moves the instance to another port first (see [The instance's port is taken](#troubleshooting)) |
170
- | `rde stop` | Stops both; the data stays |
171
- | `rde status` | The login email, the `mb` profile, the init checklist, whether setup is complete (or the first step `init` did not finish, with the `rde init --from` command that resumes there), runtime state, health, databases with their sync state, the sample database's container and connection string, remote sync state and the content repository's working directory (`contentRepository`); `--json` for scripts and agents (`mbProfile`, `adminEmail`, `setup`, never a secret); exit 0 whatever it reports |
152
+ | `rde start` | Starts the instance, and waits until Metabase is healthy; `--port <n>` moves the instance to another port first (see [The instance's port is taken](#troubleshooting)) |
153
+ | `rde stop` | Stops the instance; the data stays |
154
+ | `rde status` | The login email, the `mb` profile, the init checklist, whether setup is complete (or the first step `init` did not finish, with the `rde init --from` command that resumes there), runtime state, health, databases with their sync state, remote sync state and the content repository's working directory (`contentRepository`); `--json` for scripts and agents (`mbProfile`, `adminEmail`, `setup`, never a secret); exit 0 whatever it reports |
172
155
  | `rde credentials` | The Metabase URL, admin email, and password; `--json` for scripts and agents; `--api-key` for the API key alone |
173
156
  | `rde logs` | The container's log, or the jar's `metabase.log`; `-f` keeps streaming |
174
157
  | `rde open` | Opens the instance in the browser |
@@ -225,13 +208,13 @@ rde init --skip-license \
225
208
  | Flag | Answers |
226
209
  | --- | --- |
227
210
  | `--agents claude-code,codex` / `--skip-agents` | Which agents get the skill, instead of asking at a terminal or taking the ones found on the machine |
228
- | `--runtime docker\|jar`, `--image`, `--jar`, `--port` | How Metabase runs, the Docker image or the jar (`latest`, a release tag, or a `.jar` path), and the host port, instead of Docker when available, `metabase/metabase-enterprise-head:latest`, the latest release, and the first free port from 23000 that nothing else claims; `--image` implies `docker` and `--jar` implies `jar`; the sample database always runs in Docker |
211
+ | `--runtime docker\|jar`, `--image`, `--jar`, `--port` | How Metabase runs, the Docker image or the jar (`latest`, a release tag, or a `.jar` path), and the host port, instead of Docker when available, `metabase/metabase-enterprise-head:latest`, the latest release, and the first free port from 23000 that nothing else claims; `--image` implies `docker` and `--jar` implies `jar` |
229
212
  | `--admin generated\|prompted`, `--admin-email`, `--admin-password` | The admin user, `generated` unless given; an email or password implies `prompted` |
230
213
  | `--license-token` / `--skip-license` | The license |
231
- | `--database <connection string>` (repeatable) / `--skip-databases` | Your own databases, the engine read from the string; `<engine>=<connection string>` names it when the string fits several (`druid=jdbc:avatica:…`); `--skip-databases` connects none of them, and the sample database is still connected |
214
+ | `--database <connection string>` (repeatable) | Your own databases, the engine read from the string; `<engine>=<connection string>` names it when the string fits several (`druid=jdbc:avatica:…`). Without a terminal, one of them or the answers file's `databases` section is required unless the instance already has a database |
232
215
  | `--git-dir`, `--git-remote local\|hosted`, `--git-url`, `--git-token` / `--skip-git` | The content repository; a remote or URL without `--git-dir` means the current directory |
233
216
  | `--mb-profile default\|rde` | The `mb` profile when `default` already points at another Metabase; `default` (replace it) unless given |
234
- | `--yes` | Every confirmation, and the recommended choice of a question (replacing `default`); skips the question about your own databases, and the sample database is still connected. A driver's toggle (SSL, an SSH tunnel) is a setting, not a confirmation, and keeps the driver's default |
217
+ | `--yes` | Every confirmation, and the recommended choice of a question (replacing `default`); your own database then comes from `--database` or the answers file, as without a terminal. A driver's toggle (SSL, an SSH tunnel) is a setting, not a confirmation, and keeps the driver's default |
235
218
 
236
219
  A secret flag (`--admin-password`, `--license-token`, `--git-token`) takes `-` to read one line from stdin, the way `mb auth login` takes its key, or a literal `$VAR` (single-quoted, so the shell leaves it alone) to read the environment; either keeps the value out of your shell history and process listings. Only one flag can read stdin.
237
220
 
@@ -258,7 +241,7 @@ rde init --license-token '$RDE_LICENSE_TOKEN' …
258
241
  }
259
242
  ```
260
243
 
261
- `"runtime"` takes `"kind": "docker"` or `"jar"`, which `"image"` and `"jar"` imply on their own (`"runtime": { "jar": "latest" }` runs the latest release with Java). `"license": { "token": null }` skips the license, `"databases": []` connects none, `"git-sync": { "location": "skip" }` leaves the repository for later. A database is pasted as a `uri` or entered with `fields`, keyed by the driver's field names as the admin form shows them; a file field takes a path. Anything a `fields` entry leaves out is asked in the terminal, or named in the error without one. A field that engine does not ask with the others given, such as one behind the admin form's advanced options, is named in a warning and ignored.
244
+ `"runtime"` takes `"kind": "docker"` or `"jar"`, which `"image"` and `"jar"` imply on their own (`"runtime": { "jar": "latest" }` runs the latest release with Java). `"license": { "token": null }` skips the license and `"git-sync": { "location": "skip" }` leaves the repository for later. `"databases"` lists at least one database: an empty list is refused, since `init` needs one; leave the section out to be asked at a terminal. A database is pasted as a `uri` or entered with `fields`, keyed by the driver's field names as the admin form shows them; a file field takes a path. Anything a `fields` entry leaves out is asked in the terminal, or named in the error without one. A field that engine does not ask with the others given, such as one behind the admin form's advanced options, is named in a warning and ignored.
262
245
 
263
246
  ### Recording a run
264
247
 
@@ -282,22 +265,29 @@ Downgrades are refused: a target whose tag names an older release than the runni
282
265
 
283
266
  If Metabase does not become healthy on the new version, nothing is rolled back automatically, since its migrations may already have run; the command prints the last log lines, the backup path, and the steps to go back: `rde stop`, replace `data/` with the backup, set `runtime.image` (or `runtime.source`) back to the previous value in `state.json`, for Docker `docker rm -f rde-metabase-default` and `rde init --only runtime`, then `rde start`. Backups are plain directories; delete the ones you no longer need. `rde uninstall` removes them with the instance directory.
284
267
 
268
+ Ctrl-C during an upgrade says how far it got and what comes next: before the backup is whole the instance is on the version it had and the next `rde upgrade` begins again (a partial copy can go); once the switch to the new version has started, `rde init` reinstalls the instance; while Metabase starts on the new version, the next `rde upgrade` waits for it and finds it upgraded.
269
+
285
270
  ## Resetting
286
271
 
287
- `rde uninstall` returns the machine to the state before `rde init`: it stops and removes the Metabase container, or stops the jar's process, stops and removes the sample database container, forgets the `mb` profile it logged in (the one the state file records; never a profile pointing at another Metabase), and deletes the stored credentials and `~/.rde/instances/default` along with the `config.json` entry. It shows the list first and asks once; `--yes` skips the question. Your working directory and its git history are never touched, nor are the `mb` CLI, Docker, and Java themselves.
272
+ `rde uninstall` returns the machine to the state before `rde init`: it stops and removes the Metabase container, or stops the jar's process, forgets the `mb` profile it logged in (the one the state file records; never a profile pointing at another Metabase), and deletes the stored credentials and `~/.rde/instances/default` along with the `config.json` entry. It shows the list first and asks once; `--yes` skips the question. Your working directory and its git history are never touched, nor are the `mb` CLI, Docker, and Java themselves.
273
+
274
+ With the local `content.git` remote, that repository lives in the instance directory, so commits Metabase exported there and you never pulled exist nowhere else. `rde uninstall` compares it with your working directory first, without fetching into it, and lists the commits your working directory lacks along with the `git -C <workdir> pull` that brings them in; a working directory that is gone or no longer a git repository counts as lacking all of them. At a terminal the question still comes, under that list. With `--yes`, or without a terminal, the command stops with exit code 2 instead, unless `--force` is passed.
288
275
 
289
276
  ```sh
290
277
  rde uninstall # container or process, mb profile, ~/.rde/instances/default
291
278
  rde uninstall --keep-data # container or process and profile only; the data and secrets.json stay, and `rde init` reinstalls from them
292
279
  rde uninstall --remove-skill # also the rde skills from your coding agents
293
280
  rde uninstall --remove-image # also the Docker images or the downloaded jar (otherwise they stay for the next init)
281
+ rde uninstall --yes --force # also deletes commits in content.git that your working directory has not pulled
294
282
  ```
295
283
 
296
- Running it twice is a no-op. It also works with no `~/.rde` at all, so a leftover `rde-metabase-default` or `rde-sampledb-default` container, a Metabase process recorded in a stray pid file, or an `mb` profile from a half-finished run is cleaned up the same way. A container labelled with another `RDE_HOME` is left alone, and the warning names that home. Anything it could not remove is listed at the end and the command exits with 1.
284
+ A Postgres `rde-sampledb-default` container left by an older rde, which ran a sample database next to each instance, is removed by `rde uninstall`, and by `rde stop` and `rde upgrade` as well.
285
+
286
+ Running it twice is a no-op. It also works with no `~/.rde` at all, so a leftover `rde-metabase-default` container, a Metabase process recorded in a stray pid file, or an `mb` profile from a half-finished run is cleaned up the same way. A container labelled with another `RDE_HOME` is left alone, and the warning names that home. Anything it could not remove is listed at the end and the command exits with 1.
297
287
 
298
288
  ## Troubleshooting
299
289
 
300
- Start with `rde doctor`. It checks the machine (platform, Node, git, Docker, Java, every `mb` on `PATH`), the instance (the container or the jar process, port, health, Metabase version, admin user, admin password, whether Metabase accepts the API key, the secrets file's modes, no secret left in `state.json`, `mb` profile and the URL it points at, license, databases, the sample database's container, port, and Metabase record, remote sync), the `MB_PROFILE`, `MB_URL`, and `MB_API_KEY` variables when set, the other Metabases `mb` knows, the skill for each detected coding agent, and every copy of the skill, one row each with ✓, ✗, or – and a hint under every ✗. A row marked `!` is a note: nothing fails, but it changes where `mb` goes. Of Docker and Java, the one the instance does not use is `–` when missing; the one it uses is ✗.
290
+ Start with `rde doctor`. It checks the machine (platform, Node, git, Docker, Java, every `mb` on `PATH`), the instance (the container or the jar process, port, health, Metabase version, admin user, admin password, whether Metabase accepts the API key, the secrets file's modes, no secret left in `state.json`, `mb` profile and the URL it points at, license, databases, remote sync), the `MB_PROFILE`, `MB_URL`, and `MB_API_KEY` variables when set, the other Metabases `mb` knows, the skill for each detected coding agent, and every copy of the skill, one row each with ✓, ✗, or – and a hint under every ✗. A row marked `!` is a note: nothing fails, but it changes where `mb` goes. Of Docker and Java, the one the instance does not use is `–` when missing; the one it uses is ✗.
301
291
 
302
292
  ```
303
293
  ✓ container rde-metabase-default stopped (metabase/metabase-enterprise-head:latest)
@@ -332,8 +322,6 @@ Start Docker (or `colima start`), or install Java, and run `rde init` again. `rd
332
322
 
333
323
  **The instance is not on port 23000.** The runtime step takes the first free port from 23000 up and says so: `Port 23000 is in use or claimed; using 23001`. rde's ports are the standard ones plus 20000 (Metabase's 3000, Postgres's 5432), a block no common local tool uses and that Docker and the kernel never pick from on their own. A port counts as claimed when any Docker container, running or stopped, from this rde home or another, is created to publish it, or when another instance of this home uses it, because that container or instance takes it back the moment it starts. `rde status` and the summary show the URL; `--port` pins a port of your choice and refuses a busy or claimed one, naming who claims it. A container that exists with a different port or image is reported with the `docker rm -f` command that clears it.
334
324
 
335
- **The sample database is not on port 25432.** The same rule: `Port 25432 is in use or claimed; using 25433 for the sample database`. The summary, `rde status`, and the `psql` line carry the port that was taken, and Metabase's connection uses it too. A sample database container that was removed by hand comes back on the next `rde init` (`rde doctor` points at it); if another program took its port meanwhile, it moves to the next free one and `init` says which Metabase database still points at the old port.
336
-
337
325
  **The instance's port is taken.** While an instance is stopped, another program can take its port. `rde start` then refuses rather than talk to that program: `port 23000 is in use by another program, so Metabase cannot start on it; stop that program and run \`rde start\` again, or move this instance with \`rde start --port 23001\``, and `rde status` says `another program answers at http://localhost:23000` instead of reporting it healthy. Stopping the other program is enough when it is temporary. `rde start --port <n>` moves the instance for good: Metabase stops, the container is created again on the new port from the image it already runs (the data is in `~/.rde` and stays), the state and Metabase's site URL take the new address, and the `mb` profile follows once Metabase answers there (if that start fails, the next `rde start` finishes moving the profile). Anything outside rde that knows the old URL (a bookmark, a data app's config) needs the new one. A container whose port forward Docker lost, which happens when its start once failed on a taken port, is repaired by the next `rde start`, which says so in one line.
338
326
 
339
327
  **The jar's Java is wrong.** The jar runtime needs Java 21 or newer and says which one it found: `Java 17.0.9 at /usr/bin/java is too old`. Point `JAVA_HOME` at a newer runtime, or put one first on `PATH`; the next `rde start` uses it. A pid file left by a reboot is recognized as stale (the pid is free, or runs something else) and ignored.
@@ -356,4 +344,4 @@ Start Docker (or `colima start`), or install Java, and run `rde init` again. `rd
356
344
 
357
345
  **The agent follows an old copy of the skill.** The `rde skill copies` row lists every copy of the skill the `skills` CLI knows, global and in the current directory's project, with where it came from, and fails when one did not come from rde's source (the branch is read from the `skills` lock file; against a local `RDE_SKILL_SOURCE` the copy's `SKILL.md` is compared with the checkout's `skills/rde/SKILL.md`). With several copies it says which one Claude Code started in that directory loads (a personal skill wins over a project one). `rde init --only agents-skills` reinstalls the global copy; restart the agent session afterwards.
358
346
 
359
- **The license token is rejected.** Activation ends with `Metabase reports the token as invalid` (or another status Metabase returned). Check the token, and check that the container can reach `token-check.metabase.com`: activation needs outbound network access. Run `rde init --from license` to try again; press Enter at the prompt to skip the license and carry on without remote sync.
347
+ **The license token is rejected.** Metabase checks the token with `token-check.metabase.com` before it saves it. `The license token was refused: <reason>` means the store turned the token down: check that you pasted the whole token and that its subscription is active. `The instance could not reach token-check.metabase.com to check the license token` means the check never got an answer: the container (or the jar) needs outbound network access to that host. At a terminal the step asks for the token again, and Enter skips the license and carries on without remote sync, data apps, and transform tests; without a terminal the run stops, and `rde init --from license` tries again.