@metabase/rde 0.1.17 → 0.5.0

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 +59 -28
  2. package/dist/cli.mjs +971 -497
  3. package/package.json +12 -2
package/README.md CHANGED
@@ -1,12 +1,12 @@
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`, 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.
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 `metabase-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
 
7
7
  ## Requirements
8
8
 
9
- - macOS or Linux
9
+ - macOS or Linux; Windows is not supported, and WSL is untested
10
10
  - Node 20.19 or newer
11
11
  - git
12
12
  - One way to run Metabase, either of:
@@ -22,6 +22,8 @@ npm install -g @metabase/rde
22
22
  rde init
23
23
  ```
24
24
 
25
+ To update rde itself, run `npm i -g @metabase/rde@latest`; `rde doctor` says when a newer release is out. To remove it, run `rde uninstall` first (see [Resetting](#resetting)), then `npm rm -g @metabase/rde`.
26
+
25
27
  ## What `rde init` does
26
28
 
27
29
  The wizard shows its checklist first (`✓` done, `○` to do, `↑` done but behind what is published, `–` not applicable), runs the steps still to do in order, and ends with a summary of your environment. A first run on a machine that has Docker but not yet `mb` starts like this:
@@ -30,9 +32,9 @@ The wizard shows its checklist first (`✓` done, `○` to do, `↑` done but be
30
32
  ┌ rde init
31
33
  ✓ Check this machine
32
34
  ○ Install the Metabase CLI
33
- ○ Install the rde and data-app skills for your coding agents
34
35
  ○ Install Metabase
35
36
  ○ Start Metabase
37
+ ○ Install the rde and data-app skills for your coding agents
36
38
  ○ Create the admin user
37
39
  ○ Connect the Metabase CLI
38
40
  ○ Enable transforms
@@ -41,7 +43,7 @@ The wizard shows its checklist first (`✓` done, `○` to do, `↑` done but be
41
43
  ○ Connect your databases
42
44
  ○ Summary
43
45
  │
44
- ● Running npm install -g @metabase/cli@alpha-release-65-integration-branch
46
+ ● Running npm install -g @metabase/cli@latest
45
47
  ```
46
48
 
47
49
  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.
@@ -50,21 +52,21 @@ The databases step is the one `init` cannot do without: transforms write their t
50
52
 
51
53
  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.
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
+ 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. A license can lapse after it was activated (a token expires, or Metabase stops accepting it); the license step then runs again, and skipping it records that the instance has no license. The git step asks Metabase for the license before it sets anything up, and stops with `rde init --from license` as the fix when the license lacks remote sync.
54
56
 
55
57
  | Step | What it does |
56
58
  | --- | --- |
57
59
  | Check this machine | Platform, Node version, git, and a reachable Docker daemon or a Java 21+ runtime |
58
- | Install the Metabase CLI | `@metabase/cli` (`mb`) at the `alpha-release-65-integration-branch` dist-tag, with the package manager that installed `rde`; an installed `mb` older than what the dist-tag names now is updated. `rde status` and `rde doctor` check only what is installed and ask no registry |
59
- | Install the rde and data-app skills | The data-app skills (`metabase-data-app-setup`, `-routing`, `-actions`, `-semantic-layer`, `-migrate`) from `metabase/metabase/skills#master`, then the `rde` and `rde-data-apps` skills from the `main` branch of `metabase/agent-skills` (the rde skill hands an explicit app request to `rde-data-apps`, which hands the build to the data-app skills), for the coding agents you pick at a terminal, from the ones found on this machine (Claude Code, Codex, Cursor, Gemini CLI, OpenCode, Windsurf). When none is found, the step is skipped and says how to add the skills once an agent is installed; `rde` installs no agent. Without a terminal, or with `--yes`, every agent found gets the skills; `--agents` picks a set ahead of time (the skills are installed for them whether or not they are on the machine yet), `--skip-agents` none; `RDE_SKILL_SOURCE` installs the two rde skills from another URL or a local checkout of `metabase/agent-skills`. Installed skills whose directory changed on its branch since are installed again, without a question when every detected agent already has them all |
60
- | Install Metabase | **Docker** when it is available: pulls `metabase/metabase-enterprise-head:latest` (or `--image`) and creates the container. **Jar** otherwise, or with `--runtime jar`: downloads the latest enterprise release (or the tag or `.jar` path given as `--jar`) into `~/.rde/jars/` and runs it with your Java. Either way on port 23000, or the first free port above it that nothing else claims, or `--port` |
60
+ | Install the Metabase CLI | `@metabase/cli` (`mb`) at the `latest` dist-tag, with the package manager that installed `rde`; an installed `mb` older than what the dist-tag names now is updated. `rde status` and `rde doctor` check only what is installed and ask no registry |
61
+ | Install Metabase | **Docker** when it is available: pulls the major line of the newest Metabase Enterprise release, such as `metabase/metabase-enterprise:v1.65.x` (or `--image`), and creates the container. **Jar** otherwise, or with `--runtime jar`: downloads the newest enterprise release (or the tag or `.jar` path given as `--jar`) into `~/.rde/jars/` and runs it with your Java. [Metabase versions](#metabase-versions) says how the release is found. Either way on port 23000, or the first free port above it that nothing else claims, or `--port` |
61
62
  | Start Metabase | Starts the container or the jar and waits for `/api/health`, showing Metabase's own progress |
63
+ | Install the rde and data-app skills | The `metabase-data-apps` skill, one skill with a guide per data-app task (setup, routing, actions, semantic layer, migrate), from the `skills/metabase-data-apps/v1` folder of the `main` branch of `metabase/agent-skills`, then the `metabase-rde` skill from the `skills/metabase-rde/v1` folder of the same branch (its data-app reference settles what an app needs on an rde machine and hands the build to `metabase-data-apps`), for the coding agents you pick at a terminal, from the ones found on this machine (OpenCode, Claude Code, Codex, Cursor, Gemini CLI, Windsurf). When none is found, the step is skipped and says how to add the skills once an agent is installed; `rde` installs no agent. Without a terminal, or with `--yes`, every agent found gets the skills; `--agents` picks a set ahead of time (the skills are installed for them whether or not they are on the machine yet), `--skip-agents` none; `RDE_SKILL_SOURCE` installs both from another branch URL or a local checkout of `metabase/agent-skills`. The `v1` folder of `metabase-data-apps` is the data-app contract version Metabase serves, the same whatever Metabase version the instance runs; a breaking contract change gets a folder of its own (`v2`, …), and the guide for migrating an app Metabase marks Outdated moves it to the newer one. Installed skills whose directory changed on its branch since are installed again, without a question when every detected agent already has them all, and copies of the earlier per-task data-app skills (`metabase-data-app-setup`, `-routing`, `-actions`, `-semantic-layer`, `-migrate`) that the skills lock attributes to `metabase/metabase`, whoever installed them, are removed once `metabase-data-apps` is in, so the two never compete; a copy also installed for an agent that has no `metabase-data-apps` after the run stays, with a warning naming those agents and the `rde init --only agents-skills --agents <…>` command that replaces it. Copies of `rde` and `rde-data-apps`, the two skills an earlier rde installed in place of `metabase-rde`, are removed the same way once `metabase-rde` is in, wherever they came from. The skills are installed globally, not per instance, so every instance on the machine shares one set |
62
64
  | Create the admin user | `admin@metabase.local` with a generated password that `rde credentials` shows, or your own with `--admin prompted`, see [Credentials](#credentials) |
63
65
  | 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 |
64
66
  | 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 |
65
67
  | 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 |
66
68
  | 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 |
67
- | Choose what syncs to git | Only once a repository is connected. Creates the Library (when the license has the `library` feature) and an `Analytics` collection, unless the repository already brought synced top-level collections in, and marks them for sync. Before it changes anything it asks whether to push them to the branch (default yes); without the push, or when the branch has commits Metabase has not imported, it prints the export to run instead |
69
+ | Choose what syncs to git | Only once a repository is connected, and only when the license has the `library` feature. Creates the Library unless the repository already brought one in, and marks it for sync; nothing else is created or marked. When the Library was not synced yet, it asks before it changes anything whether to push it to the branch (default yes); without the push, or when the branch has commits Metabase has not imported, it prints the export to run instead |
68
70
  | 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 |
69
71
  | Summary | URL, login email, the `mb` command for the instance, databases, repository, the export still to run when Metabase has unexported changes, and the command that opens each detected agent |
70
72
 
@@ -93,7 +95,7 @@ The second run on the same machine detects every step as done and prints the sum
93
95
  │ Databases: │
94
96
  │ warehouse (postgres, syncing; `rde status` shows when it finishes) │
95
97
  │ Remote sync: not configured (no license) │
96
- │ rde skill: installed for Claude Code │
98
+ │ metabase-rde skill: installed for Claude Code │
97
99
  │ Start working: │
98
100
  │ claude (Claude Code) │
99
101
  │ Lifecycle: rde status (--json for scripts), rde stop, rde start │
@@ -144,7 +146,13 @@ The instance listens on `127.0.0.1` only (the container's published port, or the
144
146
 
145
147
  ### Docker or jar
146
148
 
147
- Docker is used whenever it is available: the image is self-contained, and the container is the thing to look at when something is off. The jar runtime is what `init` falls back to on a machine without Docker, and what `--runtime jar` (or `--jar`) picks on purpose, for running a jar you built yourself. It runs `java -jar` detached from the terminal, with the same data directory layout, the same environment, and the same `127.0.0.1`-only listener; `rde stop` sends it SIGTERM and waits for it to exit; `rde logs` reads `metabase.log`. Java is resolved through `JAVA_HOME`, then `PATH`, at every start, so a version manager's switch is picked up without reconfiguring. Without `--jar` the latest enterprise release is used; `--jar` accepts `latest`, a release tag such as `v1.63.18` (with or without the `v`; `v0.…` is the OSS build), or the path of a `.jar` file. A release is downloaded once into `~/.rde/jars/<tag>/` and reused; a path is run from where it is. A connection string that says `localhost` reaches your own databases directly, since the jar runs on the host; no rewrite to `host.docker.internal` is needed.
149
+ Docker is used whenever it is available: the image is self-contained, and the container is the thing to look at when something is off. The jar runtime is what `init` falls back to on a machine without Docker, and what `--runtime jar` (or `--jar`) picks on purpose, for running a jar you built yourself. It runs `java -jar` detached from the terminal, with the same data directory layout, the same environment, and the same `127.0.0.1`-only listener; `rde stop` sends it SIGTERM and waits for it to exit; `rde logs` reads `metabase.log`. Java is resolved through `JAVA_HOME`, then `PATH`, at every start, so a version manager's switch is picked up without reconfiguring. Without `--jar` the newest enterprise release is used; `--jar` accepts `latest` (that same release), an enterprise release tag such as `v1.65.0` (with or without the `v`; an OSS `v0.…` tag is refused), or the path of a `.jar` file. A release is downloaded once into `~/.rde/jars/<tag>/` and reused; a path is run from where it is. A connection string that says `localhost` reaches your own databases directly, since the jar runs on the host; no rewrite to `host.docker.internal` is needed.
150
+
151
+ ### Metabase versions
152
+
153
+ rde runs Metabase Enterprise 65 or newer. Once Metabase is up, `rde init`, `rde start`, and `rde upgrade` read the version it reports and refuse the OSS edition (a `v0.…` version, which `metabase/metabase` runs), a release before 65, and a build of master (a `-SNAPSHOT` version, which `metabase/metabase-enterprise-head` runs), with exit code 2 and the way to another: `rde upgrade --to <image or release tag>` for this instance, or `rde uninstall`, then `rde init --image <image>` or `rde init --jar <release tag>`, for a new one. The refused instance is left running as it is. `--jar` refuses a `v0.…` tag before anything is downloaded. With `RDE_DEV=1`, for working on rde and Metabase themselves, every version runs.
154
+
155
+ A new instance runs the newest release that Metabase's release feed (`https://static.metabase.com/version-info-ee.json`) lists of Enterprise 65 or newer, betas and release candidates left out. The feed's own `latest`, like the Docker `:latest` tag, moves to a new major only weeks after its release, so rde reads neither. Docker gets the major line of that release, `metabase/metabase-enterprise:v1.<major>.x`, a tag Metabase moves to every build of the major: the state file records the line, and each pull of it brings the newest build. The jar gets the release itself. While the feed lists no release of 65 or newer, `init` stops with exit code 2 before it pulls or downloads anything, and names the ways out: `--image <image>`, `--jar <release tag>`, or `RDE_DEV=1` for the development build. When the feed cannot be read, `init` stops the same way, with the cause and `--image <image>` or `--jar <release tag>` as the way past it. In development mode the image is `metabase/metabase-enterprise-head:latest`, and the jar's `latest` is the feed's own `latest`.
148
156
 
149
157
  ## Everyday commands
150
158
 
@@ -187,9 +195,9 @@ With a license that includes remote sync, the step after the license connects a
187
195
 
188
196
  A fresh repository gets a first commit with a `README.md` and a `.gitignore` that keeps out what a data app built in it must not push: `.env`, `.env.local`, `.env.*.local`, `node_modules/`, `.vite/`, the rde skill's `.scratch/`, and `.DS_Store` (a data app's built `dist/` stays tracked, since that bundle is what Metabase serves); a `.gitignore` already there keeps its lines and gets the missing ones, and a repository that already has commits is left as it is. A repository that already holds Metabase content is imported on the spot; each database it names that this instance lacks becomes a stub, which the databases step offers to connect.
189
197
 
190
- Remote sync carries only what is marked for it, so the step after the repository decides what that is: the Library (published tables with their measures and segments in Data, metrics in Metrics), and one top-level collection for dashboards, questions, models, and documents; transforms already sync through the repository step. The collection is `Analytics`, created for the purpose (beside any `Analytics` of the user's, which stays out of git), unless the import brought top-level collections the repository already syncs, in which case those are used and nothing is created; the Library is created only when the import did not bring one, since a second Library would conflict with the repository's on the next import. Anything filed outside these collections stays on this instance. The step refuses to run after an import that did not finish cleanly, and names the import to run first. While remote sync is read-only, the repository decides what syncs: `rde init` skips the step, and `rde init --only sync-scope` stops and asks for read-write in Admin. `rde init --only sync-scope` runs it again; it creates nothing that is already there.
198
+ Remote sync carries only what is marked for it, so the step after the repository decides what that is: the Library, where everything for consumption goes (published tables with their measures and segments in Data, metrics in Metrics, official dashboards in Dashboards). Transforms already sync through the repository step, by setting rather than by collection, and data apps sync their own collections. The step never creates or marks any other collection; top-level collections the repository already syncs come in marked with the import and are left as they are. The Library is created only when the import did not bring one, since a second Library would conflict with the repository's on the next import, and when the import brought it already synced, the normal case for an instance cloned from a production repository, the step changes nothing and asks nothing. Anything filed outside the synced collections stays on this instance. The step refuses to run after an import that did not finish cleanly, and names the import to run first. While remote sync is read-only, the repository decides what syncs: `rde init` skips the step, and `rde init --only sync-scope` stops and asks for read-write in Admin. `rde init --only sync-scope` runs it again; it creates nothing that is already there. An instance set up by an earlier `rde` may have an `Analytics` collection that step created; it stays as it is, synced or not, and `rde` no longer tracks it.
191
199
 
192
- Marking the scope is itself a change Metabase has not exported, and until it is exported a plain `mb git-sync import` refuses ("There are unsaved changes in the Remote Sync collection"). So the step asks, before it creates or marks anything, whether to push the scope to the branch, and on yes runs `mb git-sync export` and checks that Metabase is in sync afterwards. It asks because the branch may be one others share. On no, or when the push fails, it prints `mb git-sync export -b <branch>` and the summary repeats it while Metabase has unexported changes. When the branch has commits Metabase has not imported, it asks nothing and pushes nothing: a plain export would end in a conflict, which counts the remote commit as synced, so it names `mb git-sync export-preflight` and `mb git-sync export -b <branch> --merge` instead. Afterwards:
200
+ Marking the Library is itself a change Metabase has not exported, and until it is exported a plain `mb git-sync import` refuses ("There are unsaved changes in the Remote Sync collection"). So when the Library is not synced yet, as with a fresh repository, the step asks, before it creates or marks anything, whether to push it to the branch, and on yes runs `mb git-sync export` and checks that Metabase is in sync afterwards. It asks because the branch may be one others share. On no, or when the push fails, it prints `mb git-sync export -b <branch>` and the summary repeats it while Metabase has unexported changes. When the branch has commits Metabase has not imported, it asks nothing and pushes nothing: a plain export would end in a conflict, which counts the remote commit as synced, so it names `mb git-sync export-preflight` and `mb git-sync export -b <branch> --merge` instead. Afterwards:
193
201
 
194
202
  ```sh
195
203
  cd <your working directory>
@@ -200,7 +208,7 @@ git pull # after an export, to see the YAML files
200
208
 
201
209
  ## Running `init` without a terminal
202
210
 
203
- Every prompt can be answered ahead of time, by a flag or by a JSON answers file, so an agent or a CI job can run `rde init` unattended. The choices `init` makes on its own need no answer, so a run without a terminal only has to cover the license, the databases, the git repository, and whether to push the sync scope. When stdin is not a terminal, the first prompt nothing answers fails with exit code 2 and a message naming the step, the prompt, and the flag or answers key that would have answered it; nothing hangs. A text prompt with a default (a display name) takes its default, as Enter would.
211
+ Every prompt can be answered ahead of time, by a flag or by a JSON answers file, so an agent or a CI job can run `rde init` unattended. The choices `init` makes on its own need no answer, so a run without a terminal only has to cover the license, the databases, the git repository, and whether to push the Library. When stdin is not a terminal, the first prompt nothing answers fails with exit code 2 and a message naming the step, the prompt, and the flag or answers key that would have answered it; nothing hangs. A text prompt with a default (a display name) takes its default, as Enter would.
204
212
 
205
213
  ### Flags
206
214
 
@@ -212,11 +220,12 @@ rde init --skip-license \
212
220
 
213
221
  | Flag | Answers |
214
222
  | --- | --- |
215
- | `--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 |
216
- | `--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` |
223
+ | `--agents opencode,claude-code` / `--skip-agents` | Which agents get the skill, instead of asking at a terminal or taking the ones found on the machine |
224
+ | `--runtime docker\|jar`, `--image`, `--jar`, `--port` | How Metabase runs, the Docker image or the jar (`latest`, an enterprise release tag, or a `.jar` path), and the host port, instead of Docker when available, the major line of the newest release, the newest release, and the first free port from 23000 that nothing else claims; `--image` implies `docker` and `--jar` implies `jar` |
217
225
  | `--admin generated\|prompted`, `--admin-email`, `--admin-password` | The admin user, `generated` unless given; an email or password implies `prompted` |
218
226
  | `--license-token` / `--skip-license` | The license |
219
227
  | `--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 |
228
+ | `--database-name <name>` (repeatable) | Display name of the `--database` in the same position. A name the repository's content already uses (the production Metabase's name) connects the placeholder a remote-sync import left for it instead of adding a second database |
220
229
  | `--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 |
221
230
  | `--mb-profile default\|rde` | The `mb` profile when `default` already points at another Metabase; `default` (replace it) unless given |
222
231
  | `--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,7 +244,7 @@ rde init --license-token '$RDE_LICENSE_TOKEN' …
235
244
  ```json
236
245
  {
237
246
  "agents-skills": { "agents": ["claude-code"] },
238
- "runtime": { "image": "metabase/metabase-enterprise:latest", "port": 13000 },
247
+ "runtime": { "image": "metabase/metabase-enterprise:v1.65.x", "port": 13000 },
239
248
  "admin-user": { "variant": "prompted", "email": "me@example.com", "password": "$RDE_ADMIN_PASSWORD" },
240
249
  "license": { "token": "$RDE_LICENSE_TOKEN" },
241
250
  "databases": [
@@ -247,7 +256,7 @@ rde init --license-token '$RDE_LICENSE_TOKEN' …
247
256
  }
248
257
  ```
249
258
 
250
- `"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. `"sync-scope": { "export": false }` leaves the first export of the sync scope to you. `"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.
259
+ `"runtime"` takes `"kind": "docker"` or `"jar"`, which `"image"` and `"jar"` imply on their own (`"runtime": { "jar": "latest" }` runs the newest release with Java). `"license": { "token": null }` skips the license and `"git-sync": { "location": "skip" }` leaves the repository for later. `"sync-scope": { "export": false }` leaves the first export of the Library to you. `"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.
251
260
 
252
261
  ### Recording a run
253
262
 
@@ -257,17 +266,21 @@ rde init --license-token '$RDE_LICENSE_TOKEN' …
257
266
 
258
267
  `rde upgrade` moves the instance to a newer Metabase without losing its application database. It makes sure the instance is running and reads the version it is on, fetches the target, and stops there with `Already on …` when the target is what the instance already runs. Otherwise it shows the running version, the target, and the backup path, asks once (`--yes` skips the question; without a terminal `--yes` is required), and then stops Metabase, copies the whole `data/` directory to `~/.rde/instances/default/backups/<timestamp>/`, switches the instance to the target, starts it, waits for health, and records the new version. Metabase migrates its application database forward on that first start.
259
268
 
260
- For a Docker instance the target is an image ref (`--to <image ref>`; by default the instance's own image, which for a `:latest` tag means "whatever is latest now"), the pulled image is compared by id with the one the container runs, and the container is removed and created again from the target with the same port, mount, and environment. For a jar instance the target is `latest` (the default), a release tag, or a `.jar` path; a release is downloaded into `~/.rde/jars/` before the question, and the instance's `runtime.source` is switched to it.
269
+ A move to another major version (65 to 66, say) is named before the backup with `This moves Metabase from 65 to 66`, ahead of the same question. A target that names no release shows its version only once it runs, and the plan says so: a major line (`:v1.66.x`) still names its major, so the move is named before the backup all the same, while `:latest` or a jar path names nothing, so the line comes after the start instead. Either way, once the new major runs, `rde upgrade` runs the skills step, which installs again every skill whose folder changed on its branch; at a terminal it asks which agents get them like `rde init` does, and with `--yes` every agent found gets them.
270
+
271
+ For a Docker instance the target is an image ref (`--to <image ref>`; by default, for an image of `metabase/metabase-enterprise`, `metabase/metabase-enterprise-head`, or `metabase/metabase`, the major line of the newest release, found the way `init` finds it, whatever tag the instance ran before: `:latest`, an older major line, or the same line), the pulled image is compared by id with the one the container runs, and the container is removed and created again from the target with the same port and mount and the environment rde sets now. An image from any other repository (a registry of your own, an image you built) is pulled again under its own ref, and the plan says so. The default target follows the feed rules of [Metabase versions](#metabase-versions): a feed that lists no release of 65 or newer, or cannot be read, stops the upgrade before it starts Metabase or pulls anything. With `RDE_DEV=1` the default target is the instance's own image. When the target is the image already running, a container created under another ref of it (`:latest` that names the same image as the line, say) or one that keeps variables rde sets otherwise now (the staging store of development mode, say) is still created again from that image under the target's ref, with no backup since nothing migrates; `rde doctor` names a container with such variables, with `rde upgrade` as the fix. A build of master (`metabase/metabase-enterprise-head:latest`, the development image) reports a major ahead of every release, so `rde upgrade` refuses it as a downgrade; `rde doctor` names one outside development mode, and the way onto a release is `rde uninstall`, then `rde init`, while `RDE_DEV=1` keeps running it. For a jar instance the target is `latest` (the default, the newest release), a release tag, or a `.jar` path; a release is downloaded into `~/.rde/jars/` before the question, and the instance's `runtime.source` is switched to it.
261
272
 
262
273
  ```sh
263
- rde upgrade # Docker: pull the instance's image again; jar: the latest release
264
- rde upgrade --to metabase/metabase-enterprise:v1.64.0 # Docker: a specific release
265
- rde upgrade --to v1.64.0 # jar: a specific release
274
+ rde upgrade # Docker: the major line of the newest release, pulled again; jar: the newest release
275
+ rde upgrade --to metabase/metabase-enterprise:v1.66.0 # Docker: a specific release
276
+ rde upgrade --to v1.66.0 # jar: a specific release
266
277
  rde upgrade --to ~/metabase/target/uberjar/metabase.jar # jar: a build of your own
267
- rde status # shows `Version: v1.64.0`
278
+ rde status # shows `Version: v1.66.0`
268
279
  ```
269
280
 
270
- Downgrades are refused: a target whose tag names an older release than the running one (`v1.62.0` against a running `v1.63.18`) ends with exit code 2 before anything is fetched, because those migrations only run forward. An older release needs a fresh instance (`rde uninstall`, then `rde init`). A target that carries no release tag (`latest`, a branch image, a jar path) is taken on trust.
281
+ Downgrades are refused: a target whose tag names an older release than the running one (`v1.65.0` against a running `v1.66.2`), or the major line of an older major (`v1.65.x` against the same, or against a build of master that reports `v1.67.0-SNAPSHOT`), ends with exit code 2 before anything is fetched, because those migrations only run forward. An older release needs a fresh instance (`rde uninstall`, then `rde init`). A target that carries no release tag (`latest`, a branch image, a jar path) is taken on trust.
282
+
283
+ A target rde does not run (see [Metabase versions](#metabase-versions)) is refused the same way, before anything is fetched, when its tag names the release. When its version shows only once it runs, the upgrade fails like one that never became healthy, below, with the backup path and the steps to go back. An instance already on such a version still starts for `rde upgrade`, which is how it moves to one rde runs.
271
284
 
272
285
  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.
273
286
 
@@ -282,7 +295,7 @@ With the local `content.git` remote, that repository lives in the instance direc
282
295
  ```sh
283
296
  rde uninstall # container or process, mb profile, ~/.rde/instances/default
284
297
  rde uninstall --keep-data # container or process and profile only; the data and secrets.json stay, and `rde init` reinstalls from them
285
- rde uninstall --remove-skill # also the rde skills from your coding agents
298
+ rde uninstall --remove-skill # also the metabase-rde and metabase-data-apps skills (and the older rde and rde-data-apps) from your coding agents
286
299
  rde uninstall --remove-image # also the Docker images or the downloaded jar (otherwise they stay for the next init)
287
300
  rde uninstall --yes --force # also deletes commits in content.git that your working directory has not pulled
288
301
  ```
@@ -291,12 +304,22 @@ A Postgres `rde-sampledb-default` container left by an older rde, which ran a sa
291
304
 
292
305
  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.
293
306
 
307
+ ## Environment variables
308
+
309
+ | Variable | What it does |
310
+ | --- | --- |
311
+ | `RDE_HOME` | Where rde keeps its state instead of `~/.rde`; a relative path is resolved against the working directory |
312
+ | `RDE_SKILL_SOURCE` | Development only: the `metabase/agent-skills` branch or checkout the `metabase-rde` and `metabase-data-apps` skills are installed from (from its `skills/metabase-rde/v1` and `skills/metabase-data-apps/v1` folders) instead of the `main` branch: a GitHub URL that names a branch (`…/tree/<branch>`) or the root of a local checkout, so they can be tried before they are pushed |
313
+ | `RDE_DEV` | Development only: `1` runs instances on the enterprise build of master and checks license tokens against the staging store; `bin/rde-dev` sets it |
314
+
315
+ An empty value counts as unset.
316
+
294
317
  ## Troubleshooting
295
318
 
296
- 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 ✗.
319
+ Start with `rde doctor`. It checks the machine (platform, Node, git, Docker, Java, every `mb` on `PATH`, and whether a newer rde is released, the one check that asks the npm registry and gives up after a few seconds), 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, every copy of the skill, and the data-app skills, 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 ✗.
297
320
 
298
321
  ```
299
- ✓ container rde-metabase-default stopped (metabase/metabase-enterprise-head:latest)
322
+ ✓ container rde-metabase-default stopped (metabase/metabase-enterprise:v1.65.x)
300
323
  ✓ port 23000 is free
301
324
  ✗ health unreachable
302
325
  → `rde start`
@@ -336,6 +359,8 @@ Start Docker (or `colima start`), or install Java, and run `rde init` again. `rd
336
359
 
337
360
  **An older `mb` runs first.** Another package manager installed an `mb` earlier, and its directory comes first on `PATH`. The `mb` row lists every `mb` in `PATH` order and fails when the first one is too old, or comes from another package manager while a newer one sits later; the hint names both paths and the command that removes the old one, taken from its path (`bun remove -g @metabase/cli`, `brew uninstall <formula>`, …), or the `PATH` order that puts the new one first. `rde` never edits shell profiles; open a new terminal after the change. `rde init` stops with the same list when the `mb` it installed is still not the one that runs.
338
361
 
362
+ **npm cannot install `mb`.** On a Node whose global directory belongs to root (a system or installer-package Node), `npm install -g @metabase/cli@latest` fails with `EACCES`, and `rde init` stops with `npm cannot write its global directory`. Give npm a prefix you own (`npm config set prefix ~/.npm-global`, then add `~/.npm-global/bin` to `PATH` and open a new terminal), or install Node with a version manager such as nvm, fnm, or mise, and run `rde init` again. Avoid `sudo`: it leaves root-owned files in npm's cache.
363
+
339
364
  **`mb` went to the wrong Metabase.** A plain `mb` uses the `default` profile, or the one `MB_PROFILE` names, and `MB_URL` or `MB_API_KEY` override every profile, the instance's own included. `rde doctor` shows a `!` row for each of those variables that is set, with the `unset` to run, and lists every other profile by host with whether it authenticates and which one plain `mb` uses:
340
365
 
341
366
  ```
@@ -348,6 +373,12 @@ Start Docker (or `colima start`), or install Java, and run `rde init` again. `rd
348
373
  plain `mb` uses prod (MB_PROFILE): prod.acme.example
349
374
  ```
350
375
 
351
- **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.
376
+ **The agent follows an old copy of the skill.** The `metabase-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/metabase-rde/v1/SKILL.md`), and also fails while a global copy of `rde` or `rde-data-apps`, which `metabase-rde` replaces, is still there. 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 and removes the replaced ones; restart the agent session afterwards.
377
+
378
+ **The agent follows the wrong data-app skill.** The `data-app skills` row fails when `metabase-data-apps` is missing or its copy did not come from rde's source (against a local `RDE_SKILL_SOURCE`, the checkout's `skills/metabase-data-apps/v1/SKILL.md`), or when a copy of an earlier per-task data-app skill (`metabase-data-app-setup` and the like) that the skills lock attributes to `metabase/metabase` is still there, whoever installed it. `rde init --only agents-skills` (or `rde doctor --fix`) installs the skills and removes the copies `metabase-data-apps` replaces; a copy also installed for an agent that has no `metabase-data-apps` after the run stays, and the run names the `--agents` that let it go. Restart the agent session afterwards.
352
379
 
353
380
  **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.
381
+
382
+ ## License
383
+
384
+ License: AGPL-3.0, see `package.json`.