@metabase/rde 0.1.3 → 0.1.5

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 +84 -43
  2. package/dist/cli.mjs +1791 -766
  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, and with one, 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`, 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.
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
 
@@ -41,27 +41,29 @@ The wizard shows its checklist first (`✓` done, `○` to do, `–` not applica
41
41
  – Connect a git repository
42
42
  ○ Summary
43
43
  │
44
- ● Running npm install -g @metabase/cli@alpha-transform-tests
44
+ ● Running npm install -g @metabase/cli@alpha-fix-transform-test-ee-path
45
45
  ```
46
46
 
47
- The steps up to the license run without a question: `mb` is installed with the package manager that installed `rde`, the skill goes to every coding agent found on the machine, Metabase runs in Docker when Docker is there (the jar with your Java otherwise), on the first free port from 3100 up, with the default admin credentials, 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) and, with a license that includes remote sync, where the git repository lives and which remote it uses. The databases step asks nothing while the sample database is the only one: pass `--database` to connect your own during `init`, or run `rde db add` afterwards.
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 3100 up, 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), a connection string for your own database (Enter skips it), and, with a license that includes remote sync, where the git repository lives and which remote it uses.
48
+
49
+ 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.
48
50
 
49
51
  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.
50
52
 
51
53
  | Step | What it does |
52
54
  | --- | --- |
53
55
  | Check this machine | Platform, Node version, git, and a reachable Docker daemon or a Java 21+ runtime |
54
- | Install the Metabase CLI | `@metabase/cli` (`mb`) at the `alpha-transform-tests` dist-tag, with the package manager that installed `rde` |
55
- | Install the rde skill | The `rde` skill from `metabase/agent-skills` for every coding agent found on this machine (Claude Code, Codex, Cursor, Gemini CLI, OpenCode, Windsurf); `--agents` picks a different set, `--skip-agents` none |
56
+ | Install the Metabase CLI | `@metabase/cli` (`mb`) at the `alpha-fix-transform-test-ee-path` dist-tag, with the package manager that installed `rde` |
57
+ | Install the rde skill | The `rde` skill from the `rde-skill` branch of `metabase/agent-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) plus OpenCode, which is always offered: picked while missing, it is installed first (`opencode-ai` with the package manager that installed `rde`). Without a terminal, or with `--yes`, every agent found gets the skill; `--agents` picks a set ahead of time (`opencode` in it is installed when missing), `--skip-agents` none; `RDE_SKILL_SOURCE` installs it from another URL or a local directory |
56
58
  | 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 3100, or the first free port above it, or `--port` |
57
59
  | Start Metabase | Starts the container or the jar and waits for `/api/health`, showing Metabase's own progress |
58
- | Create the admin user | `admin@metabase.com` / `metabase123`, or your own with `--admin prompted`, see below |
59
- | 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; if `default` already points at another Metabase, offers the named profile `rde` instead |
60
+ | Create the admin user | `admin@metabase.local` with a generated password that `rde credentials` shows, or your own with `--admin prompted`, see [Credentials](#credentials) |
61
+ | 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 |
60
62
  | 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 15432, connects it as `Sample Database`, and switches transforms on. 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 keeps the H2 one instead |
61
63
  | Activate your license | Optional. Paste a token, or press Enter to skip; remote sync needs one with the `remote-sync` feature |
62
- | Connect your databases | Only when `--database` names one or `rde db add` runs: paste a connection string (or fill the fields one by one), review, test, add; repeat |
64
+ | Connect your databases | At a terminal, until you connect one of your own or skip it: 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 engine list, where the fields can also be filled one by one |
63
65
  | Connect a git repository | Only with a license. Initializes or reuses a repository and points Metabase's remote sync at it |
64
- | Summary | URL, login, `mb` profile, databases, repository, and the command that opens each detected agent |
66
+ | Summary | URL, login email, the `mb` command for the instance, databases, repository, and the command that opens each detected agent |
65
67
 
66
68
  The second run on the same machine detects every step as done and prints the summary only:
67
69
 
@@ -81,21 +83,21 @@ The second run on the same machine detects every step as done and prints the sum
81
83
  ○ Summary
82
84
  │
83
85
  ◇ Your environment ─────────────────────────────────────────────────────────────────╮
84
- │ │
85
- │ Metabase: http://localhost:3100 │
86
- │ Login: admin@metabase.com / metabase123 │
87
- │ Metabase CLI: mb <command> │
88
- │ Databases: │
89
- │ Sample Database (postgres, sync complete) │
90
- │ warehouse (postgres, sync complete) │
91
- │ Sample database: psql "postgres://metabase:metasample123@localhost:15432/sample" │
92
- │ Remote sync: not configured (no license) │
93
- │ rde skill: installed for Claude Code │
94
- │ Start working: │
95
- │ claude (Claude Code) │
96
- │ Lifecycle: rde status, rde stop, rde start │
97
- │ │
98
- ├─────────────────────────────────────────────────────────────────────────────────────╯
86
+ │ │
87
+ │ Metabase: http://localhost:3100 │
88
+ │ Login: admin@metabase.local (rde credentials shows the password) │
89
+ │ Metabase CLI: mb <command> │
90
+ │ Databases: │
91
+ │ Sample Database (postgres, sync complete) │
92
+ │ warehouse (postgres, sync complete) │
93
+ │ Sample database: psql "postgres://metabase:metasample123@localhost:15432/sample" │
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, rde stop, rde start │
99
+ │ │
100
+ ├────────────────────────────────────────────────────────────────────────────────────╯
99
101
  │
100
102
  └ rde init finished
101
103
  ```
@@ -114,18 +116,29 @@ psql "postgres://metabase:metasample123@localhost:15432/sample" # the summary
114
116
 
115
117
  ## Credentials
116
118
 
117
- The admin user is created with the default credentials `admin@metabase.com` / `metabase123`. Both are written to `~/.rde` and shown in the summary and in `rde status`, so agents and scripts can log in without asking you; the instance listens on this machine only, so nobody else can reach it. To use your own instead, run `rde init --admin prompted` (or pass `--admin-email` / `--admin-password`, or an `admin-user` section in the answers file): the email and password are asked once, sent to Metabase, and never written anywhere by `rde`.
119
+ The admin user is `admin@metabase.local` with a password `rde` generates: 32 random URL-safe characters, kept in `~/.rde/instances/default/secrets.json` (mode `0600`, in a `0700` directory) and nowhere else. The summary and `rde status` show only the email:
120
+
121
+ ```
122
+ Login: admin@metabase.local (rde credentials shows the password)
123
+ ```
124
+
125
+ `rde credentials` prints the Metabase URL, the email, and the password, wherever its output goes, so a coding agent you ask for the login can run it and tell you; `rde credentials --json` prints the same as an object (`url`, `email`, `password`, and a `note`). Nothing else prints the password: not the summary, `rde status` (text or `--json`), `rde doctor`, a log, or an error message. To use your own login instead, run `rde init --admin prompted` (or pass `--admin-email` / `--admin-password`, or an `admin-user` section in the answers file): the email and password are asked once, sent to Metabase, and never written anywhere by `rde`, and `rde credentials` says so.
118
126
 
119
- In both variants `rde` creates an API key named `rde` in the Administrators group and stores it in the instance's state file with mode `0600`. That key is what `mb` and `rde` itself use afterwards. The sample database's own credentials (`metabase` / `metasample123`) are baked into its image and are not a secret.
127
+ In both variants `rde` creates an API key named `rde` in the Administrators group and keeps it in the same secrets file. That key is what `mb` and `rde` itself use afterwards; `state.json` and `rde status --json` never carry it. If Metabase stops accepting it (someone regenerated or revoked it in the admin settings), `rde init --only api-key` or `rde doctor --fix` makes a new one with the stored admin login and logs `mb` in again, asking nothing; with a prompted admin it asks for the password once.
128
+
129
+ 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.
130
+
131
+ The sample database's own credentials (`metabase` / `metasample123`) are baked into its image and are not a secret.
120
132
 
121
133
  ## What lands in `~/.rde`, and what never does
122
134
 
123
135
  ```
124
136
  ~/.rde/
125
137
  config.json { schemaVersion, defaultInstance }
126
- instances/default/
127
- state.json mode 0600: runtime, url, Metabase version, admin credentials variant,
128
- API key, license features, databases, sample database, git remote, step records
138
+ instances/default/ mode 0700
139
+ state.json mode 0600, no secrets: runtime, url, Metabase version, admin email and variant,
140
+ mb profile, license features, databases, sample database, git remote, step records
141
+ secrets.json mode 0600: { schemaVersion, admin: { email, password } | null, apiKey }
129
142
  data/ mounted into the container as /rde, or the jar's working directory
130
143
  metabase.db/metabase.db.mv.db the H2 application database
131
144
  plugins/ driver jars (Oracle, Vertica) go here
@@ -136,7 +149,7 @@ In both variants `rde` creates an API key named `rde` in the Administrators grou
136
149
  jars/<release tag>/metabase.jar downloaded releases, shared by every instance
137
150
  ```
138
151
 
139
- 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 `rde` lives where `mb` keeps its profiles, under `$XDG_CONFIG_HOME` or `~/.config`.
152
+ 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`.
140
153
 
141
154
  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).
142
155
 
@@ -150,23 +163,31 @@ Docker is used whenever it is available: the image is self-contained, and the co
150
163
  | --- | --- |
151
164
  | `rde start` | Starts the sample database and the instance, and waits until Metabase is healthy |
152
165
  | `rde stop` | Stops both; the data stays |
153
- | `rde status` | The init checklist, runtime state, health, databases with their sync state, the sample database's container and connection string, remote sync state; `--json` for scripts |
166
+ | `rde status` | The login email, the `mb` profile, the init checklist, runtime state, health, databases with their sync state, the sample database's container and connection string, remote sync state; `--json` for scripts and agents (`mbProfile`, `adminEmail`, never a secret) |
167
+ | `rde credentials` | The Metabase URL, admin email, and password; `--json` for scripts and agents |
154
168
  | `rde logs` | The container's log, or the jar's `metabase.log`; `-f` keeps streaming |
155
169
  | `rde open` | Opens the instance in the browser |
156
- | `rde db add` | The same database wizard as in `init` |
170
+ | `rde db add` | The database wizard: pick the engine, paste a connection string or fill the fields, review, test, add |
157
171
  | `rde db list` | The connected databases; `--json` for scripts |
158
- | `rde doctor` | One table of checks with a fix hint per failure; `--fix` re-runs the init steps behind them; `--json` for scripts; exit 1 while anything fails |
172
+ | `rde doctor` | One table of checks with a fix hint per failure; `--fix` re-runs the init steps behind them; `--json` for scripts and the rde skill (every row's `id`, `status`, `detail`, `hint`, and `fix`: the `rde` command that repairs it, or null when you have to act); exit 1 while anything fails |
159
173
  | `rde upgrade` | Moves the instance to a newer Metabase after backing up its data; see [Upgrading](#upgrading) |
160
174
  | `rde uninstall` | Removes the instance, its data, and the `mb` profile; see [Resetting](#resetting) |
161
175
 
162
- Everything else goes through the Metabase CLI, logged in as the profile `default`, so plain `mb …` talks to the instance:
176
+ Everything else goes through the Metabase CLI, logged in as the profile `default`, so a plain `mb` reaches the instance:
163
177
 
164
178
  ```sh
165
179
  mb db list
166
180
  mb git-sync status
167
181
  ```
168
182
 
169
- If your `default` profile already pointed at another Metabase when `init` ran, it was left alone and the instance was connected as the profile `rde` (`init` asks; `--mb-profile default|rde` answers without a terminal). Then it is `mb --profile rde …`, or `export MB_PROFILE=rde` once per shell; the summary and `rde status` say which.
183
+ ### The `mb` profile
184
+
185
+ `rde init` logs `mb` in under `default`, the profile a plain `mb` uses. When `mb` has no `default` profile yet, or it already points at this instance, nothing is asked. When `default` points at another Metabase, `init` asks which profile to use, with the URL `default` points at today in the first choice:
186
+
187
+ - `default, replacing it (recommended; it points at <url> today)`: pre-selected, and what `--yes` and a run without a terminal take. `init` prints `Replacing mb profile default, which pointed at <url>`, so the old URL is on screen if you want to log it in again under another name (`mb auth login --profile <name> --url <url>`).
188
+ - `rde, and leave default alone`: the instance gets the profile `rde`, and every command reads `mb --profile rde <command>`, or plain `mb` after `export MB_PROFILE=rde`.
189
+
190
+ `--mb-profile default|rde`, or `"api-key": { "profile": "rde" }` in the answers file, answers the question ahead of time. An instance not named `default` always uses `rde-<name>` and asks nothing, and an instance keeps the profile its state file records; the summary and `rde status` say which, with the command to use.
170
191
 
171
192
  ## The git repository
172
193
 
@@ -198,13 +219,14 @@ rde init --skip-license \
198
219
 
199
220
  | Flag | Answers |
200
221
  | --- | --- |
201
- | `--agents claude-code,codex` / `--skip-agents` | Which agents get the skill, instead of the ones found on the machine |
222
+ | `--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; a missing `opencode` is installed |
202
223
  | `--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 3100; `--image` implies `docker` and `--jar` implies `jar` |
203
- | `--admin default\|prompted`, `--admin-email`, `--admin-password` | The admin user, `default` unless given; an email or password implies `prompted` |
224
+ | `--admin generated\|prompted`, `--admin-email`, `--admin-password` | The admin user, `generated` unless given; an email or password implies `prompted` |
204
225
  | `--license-token` / `--skip-license` | The license |
205
226
  | `--database <engine>=<connection string>` (repeatable) / `--skip-databases` | The warehouses |
206
227
  | `--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 |
207
- | `--yes` | Every confirmation (skipping databases) |
228
+ | `--mb-profile default\|rde` | The `mb` profile when `default` already points at another Metabase; `default` (replace it) unless given |
229
+ | `--yes` | Every confirmation (skipping databases), and the recommended choice of a question (replacing `default`) |
208
230
 
209
231
  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.
210
232
 
@@ -257,11 +279,11 @@ If Metabase does not become healthy on the new version, nothing is rolled back a
257
279
 
258
280
  ## Resetting
259
281
 
260
- `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 (`default`, or `rde`; never a profile pointing at another Metabase), and deletes `~/.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.
282
+ `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.
261
283
 
262
284
  ```sh
263
285
  rde uninstall # container or process, mb profile, ~/.rde/instances/default
264
- rde uninstall --keep-data # container or process and profile only; `rde init` reinstalls from the kept data
286
+ rde uninstall --keep-data # container or process and profile only; the data and secrets.json stay, and `rde init` reinstalls from them
265
287
  rde uninstall --remove-skill # also the rde skill from your coding agents
266
288
  rde uninstall --remove-image # also the Docker images or the downloaded jar (otherwise they stay for the next init)
267
289
  ```
@@ -270,7 +292,7 @@ Running it twice is a no-op. It also works with no `~/.rde` at all, so a leftove
270
292
 
271
293
  ## Troubleshooting
272
294
 
273
- Start with `rde doctor`. It checks the machine (platform, Node, git, Docker, Java, `mb`), the instance (the container or the jar process, port, health, Metabase version, admin user, API key, `mb` profile, license, databases, the sample database's container, port, and Metabase record, remote sync), and the skill for each detected coding agent, one row each with ✓, ✗, or – and a hint under every ✗. Of Docker and Java, the one the instance does not use is `–` when missing; the one it uses is ✗.
295
+ 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 ✗.
274
296
 
275
297
  ```
276
298
  ✓ container rde-metabase-default stopped (metabase/metabase-enterprise-head:latest)
@@ -280,7 +302,7 @@ Start with `rde doctor`. It checks the machine (platform, Node, git, Docker, Jav
280
302
  – admin user Metabase is not healthy
281
303
  ```
282
304
 
283
- `rde doctor --fix` lists the init steps that repair the failed rows, asks once (`--yes` skips the question), re-runs them, and prints the table again. A failure with no automatic fix, such as a port held by another program, keeps its hint and the exit code stays 1 until it is resolved.
305
+ `rde doctor --fix` lists the init steps that repair the failed rows, asks once (`--yes` skips the question), re-runs them, and prints the table again; a step that asks takes its recommended answer with `--yes` or without a terminal. A failure with no automatic fix, such as a port held by another program, keeps its hint and the exit code stays 1 until it is resolved.
284
306
 
285
307
  **Neither Docker nor Java is available.** The first step prints the checks that failed, with what Docker said and what to do, and exits with code 2; with Java 21+ installed the Docker line is `–` instead and the wizard runs Metabase as a jar:
286
308
 
@@ -309,6 +331,24 @@ Start Docker (or `colima start`), or install Java, and run `rde init` again. `rd
309
331
 
310
332
  **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.
311
333
 
334
+ **`mb` says the API key is invalid.** The key was regenerated or revoked in Metabase's admin settings. `rde doctor` shows `✗ API key in the secrets file, but Metabase rejects it`; `rde init --only api-key` (or `rde doctor --fix`) replaces it with the stored admin login and logs `mb` in again.
335
+
336
+ **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.
337
+
338
+ **`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:
339
+
340
+ ```
341
+ ✗ mb profile rde points at http://127.0.0.1:3101, not at this instance (http://localhost:3101)
342
+ → `rde init --only api-key` logs it back in against the instance
343
+ ! MB_PROFILE prod: `mb` and the rde skill will use profile prod (prod.acme.example) instead of rde's (rde)
344
+ → `unset MB_PROFILE`, remove it from your shell profile if it is exported there, then restart the agent session
345
+ ✓ other Metabases default: metabase.acme.example, not answering
346
+ staging: localhost:3101, login rejected
347
+ plain `mb` uses prod (MB_PROFILE): prod.acme.example
348
+ ```
349
+
350
+ **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 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.
351
+
312
352
  **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.
313
353
 
314
354
  ## Development
@@ -317,9 +357,10 @@ Start Docker (or `colima start`), or install Java, and run `rde init` again. `rd
317
357
  bun install
318
358
  bun run check # tsc, oxlint + boundary linter, oxfmt, unit tests
319
359
  bin/rde-dev init # runs from source with RDE_HOME and the mb config under .dev-state/
360
+ RDE_SKILL_SOURCE=~/agent-skills/skills/rde bin/rde-dev init --only agents-skills # the skill from a local checkout
320
361
  ```
321
362
 
322
- The end-to-end lane runs the built binary against real Docker: a seeded Postgres 16 sidecar on `127.0.0.1:15432` (`RDE_E2E_PG_PORT` to change it) and a fresh instance under `.e2e-state/`, with a fake `HOME` so the skill installer never touches your agents. `bun run build` must precede `bun run test:e2e`. With `RDE_E2E_JAR` pointing at a Metabase jar (a local build) the lane also runs the jar runtime through init, doctor, stop, start, and uninstall with the host's Java; without it those tests are reported as skipped.
363
+ The end-to-end lane runs the built binary against real Docker: a seeded Postgres 16 sidecar on `127.0.0.1:15432` (`RDE_E2E_PG_PORT` to change it) and a fresh instance under `.e2e-state/`, with a fake `HOME` so the skill installer never touches your agents. `bun run build` must precede `bun run test:e2e`, and `python3` must be on `PATH`: the lane answers one `init` question through a pseudo-terminal it opens with Python's `pty` module. With `RDE_E2E_JAR` pointing at a Metabase jar (a local build) the lane also runs the jar runtime through init, doctor, stop, start, and uninstall with the host's Java; without it those tests are reported as skipped.
323
364
 
324
365
  ```sh
325
366
  bun run build && bun run e2e:up && bun run test:e2e