Installs into .claude/skills of the current project.
Are you the author of Setup?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/mubit-ai-setup-plugins)
---
name: setup
description: "First-run setup: check the endpoint, the key and that the instance answers; use when freshly installed or reporting auth_failed."
---
**This skill never installs anything.** It writes two configuration files the user already
owns, tells them exactly what it is about to write, and confirms the instance answers. It does
not install packages, start services, or touch the user's shell profile. A memory plugin that
runs installers is a trust failure.
It does have more to do under Codex than under Claude Code, and the reason is worth stating
before you start, because it decides the whole shape of the work:
> **Codex does not read the `hooks.json` this plugin ships, and cannot resolve a plugin's
> `.mcp.json` entry point.** A bare `hooks.json` at a plugin's root is copied into the install
> cache and then ignored — the manifest has to name it (`"hooks": "./hooks.json"`), or it has
> to be at `hooks/hooks.json`, and this plugin's is neither. And a plugin-declared MCP server
> gets no path substitution of any kind: `${CLAUDE_PLUGIN_ROOT}/x.mjs`, `./x.mjs` and `x.mjs`
> all fail to start, because a relative path resolves against the *project* directory and
> there is no variable layer at all.
So the file this plugin ships is **data**, and this skill installs it into the user layer,
where `hooks/list` reports it as `source: "user"` with `pluginId: null`. (A plugin whose
manifest *did* declare its hooks is discovered and reported against its own `pluginId`;
`test/codex-oracle.test.mjs` pins that, and changing this plugin to that shape is a change
nobody has made yet. Until someone does, the procedure below is the one that works.)
So the plugin ships both files as **templates** and this skill installs them into the user
layer with the paths resolved. Skipping this step gives a plugin that installs perfectly, lists
its skills, and captures nothing.
## Step 0 — find the plugin root
Everything below needs this plugin's absolute install path, and no environment variable
carries it. Codex lists each skill with the absolute path of its `SKILL.md`; this file is at
`<plugin-root>/skills/setup/SKILL.md`, so the root is two directories above this file. Resolve
it once and use it throughout. Verify before continuing:
```bash
ls "<plugin-root>/hooks/dist/capture.mjs" "<plugin-root>/mcp/dist/index.js"
```
Both must exist. They are committed artifacts — there is no build step at install time — so if
either is missing the install is damaged and reinstalling is the fix, not anything below.
## Steps 1-3, as one command
The mechanical half of this — substitute, merge, register, trust — is
`<plugin-root>/scripts/setup.mjs`, so you do not have to hand-roll a JSON-RPC handshake to
read the trust hashes:
```bash
node "<plugin-root>/scripts/setup.mjs" "<plugin-root>"
```
**Read step 3 before you run it**, because that command records hook trust and that is the
user's decision, not yours. Pass `--no-trust` to do everything except that, and
`--with-pre-tool` to include the `PreToolUse` registration. The script merges rather than
overwrites, backs up both files it touches, and trusts only hooks under this plugin root.
What follows is what it does, and what to tell the user about each part. If the script is
missing — an older install — do it by hand as described. It is the same install, with one
thing that is easy to leave out and has no fallback: **the `MUBIT_CC_DATA_DIR` pin in step
0a**, which both later steps carry. The MCP bundle gets no `boot.mjs`, so if you omit it there
is nothing downstream to recover it from.
## Step 0a — resolve the data directory, and pin it
Both halves below need one answer: which directory holds this user's Mubit state. Get it wrong
and `/mubit-memory:remember` writes into a run that recall never reads, or fails auth on a
machine that is already authenticated.
It is **not** reliably `~/.claude/plugins/data/mubit-memory`. Claude Code suffixes that name
with the marketplace it installed from — `mubit-memory-<marketplace>`, or `-inline` for
`--plugin-dir` — so the bare name is only one of several. Look:
```bash
ls -d ~/.claude/plugins/data/mubit-memory*
```
Prefer the one holding `credentials.json`: that is the user's existing Claude Code memory, and
sharing it is the point — a Codex session and a Claude Code session in one project derive the
same run id on purpose. Tell the user which you chose. Every command below carries it as
`MUBIT_CC_DATA_DIR`, which outranks every other input on both hosts.
## Step 1 — merge the hook registrations
Read `<plugin-root>/hooks.json`, replace every `{{PLUGIN_ROOT}}` with the resolved path, prefix
each command with the pin from step 0a, and merge the result into `$CODEX_HOME/hooks.json`
(`~/.codex/hooks.json` unless `CODEX_HOME` says otherwise). A command ends up looking like:
```
MUBIT_CC_DATA_DIR="/Users/you/.claude/plugins/data/mubit-memory-mubit" node "<plugin-root>/hooks/dist/capture.mjs"
```
Codex runs a hook command as a shell string, which is what makes that prefix work — and why the
path is quoted: a data directory with a space in it is otherwise two arguments.
**Merge, do not overwrite.** That file is the user's, and other tools register there too.
Read what is present, keep every entry that is not Mubit's, and replace only the handlers whose
command names **this plugin's own** `hooks/dist/` — the absolute path resolved in step 0, not
the bare substring `/hooks/dist/`. Other vendors lay their bundles out the same way, and
matching on the substring deletes their registrations from the user's file.
Two things about that file that will bite otherwise:
- It accepts exactly two top-level fields, `description` and `hooks`. Any other key is a hard
parse error that takes **every** registration in the file down, not just the offending one.
- Codex clamps the `SessionEnd` timeout to 3 seconds whatever the file says, and prints a
warning on stderr. The shipped template already asks for 3.
One registration is conditional. `PreToolUse` exists only to show a stored Mubit rule in front
of a matching tool call, and that feature (`MUBIT_CC_PRE_TOOL_WARNINGS`) is **off by default**.
Codex has no `if:` predicate, so a registered `PreToolUse` costs a process spawn on every shell
command whether the feature is on or not. **Omit the `PreToolUse` block unless the user has
turned the warnings on**, and say that you did.
## Step 2 — register the MCP server
```bash
codex mcp add mubit \
--env MUBIT_CC_DATA_DIR="<data-dir from step 0a>" \
-- node "<plugin-root>/mcp/dist/index.js"
```
`--env` is not optional. The server derives the run id itself, with the same strategy the hooks
use, so a server reading a different data directory writes `/mubit-memory:remember` into a run
that pre-prompt recall never reads — and on an authenticated machine it fails auth instead,
because the credentials live in that directory too. Nothing else supplies it: unlike a hook,
the MCP bundle has no `boot.mjs` to synthesise it.
The server must be named `mubit`: the model sees each tool as `mcp__<server>__<tool>`, and
every skill in this plugin names `mcp__mubit__…`. Confirm with `codex mcp list`.
## Step 3 — trust the hooks, and ask first
A registered hook does not run until it is trusted. Under `codex exec` an untrusted hook is
skipped **silently** — no prompt, no warning, exit 0 — which is why this step is not optional
and why its absence is so hard to diagnose.
Trust is normally granted by a human in the `/hooks` screen. It can also be written directly:
each hook's `key` and `currentHash` come from the app server's `hooks/list`, and the pair goes
into `$CODEX_HOME/config.toml` as
```toml
[hooks.state."<key>"]
trusted_hash = "<currentHash>"
```
**Ask before writing it.** That entry is the control Codex uses to stop a hook running
unreviewed, and answering it on the user's behalf defeats the control however good the
intentions. Show them the exact commands you are about to trust — all of them, in full — and
get a yes. If they would rather do it themselves, tell them to run `/hooks` in the Codex TUI
and approve the Mubit entries there; the result is identical.
Editing any registration changes its hash and returns it to untrusted, so this step has to be
repeated after every upgrade or edit. Say that too.
## Step 4 — confirm the endpoint and key
Two values, and nothing else:
| Setting | Value |
| --- | --- |
| `endpoint` | the user's Mubit instance URL, e.g. `https://api.mubit.ai` |
| `apiKey` | a key of the form `mbt_...` |
Precedence, highest first: `MUBIT_ENDPOINT` / `MUBIT_API_KEY` in the environment, then
`<data-dir>/credentials.json` (what `mubit-memory:auth` writes), then
`<project>/.mubit-cc.json`.
Codex has no plugin settings UI and no `CODEX_PLUGIN_OPTION_*` variables — the strings
`PLUGIN_OPTION` and `userConfig` appear nowhere in its binary — so those three rungs are the
whole ladder. Do not send a Codex user to a `/plugin` configure screen; it does not exist here.
**If either value is missing, run `node <root>/scripts/login.mjs`.** It prompts for a key
without echoing it, checks it against the instance, and writes it to the directory Step 3
pinned as `MUBIT_CC_DATA_DIR` — and prints which directory that was and how it decided.
`mubit-memory:auth` runs `bin/auth.mjs`, which resolves the same directory the same way — the
pin in `$CODEX_HOME/hooks.json` first, then a search — so the two agree on a set-up install; the
script is the one that says so out loud, which is what you want when the answer might be wrong.
```
node <root>/scripts/login.mjs # prompts; add --status to check without dialing
node <root>/scripts/login.mjs --key=mbt_… --endpoint=https://api.mubit.ai
```
It prints the directory it wrote to and how it decided, so a wrong answer is visible rather
than silent. `--json` gives the same as a machine-readable object.
## Step 5 — confirm with `mcp__mubit__mubit_status`
A `ready` state, the expected endpoint echoed back, and a run id is a finished setup. Report
those three things and stop.
Anything else maps to one cause:
| Result | What it means | What to tell the user |
| --- | --- | --- |
| `auth_failed` | The key is missing, wrong, or revoked. Not a network problem. | Run `mubit-memory:auth` to sign in again. Nothing else in this skill helps. |
| `unreachable` | Nothing is listening at that address. | The endpoint is wrong, or the instance is not running. Check both in the console. |
| `warming` | The instance is still starting. | Wait and retry — this is not a failure. |
| `server_error` | The instance is up and failing. | Retry once, then check the instance's status in the console. The client cannot fix it. |
| `not_responding` | Three or more consecutive timeouts. | Usually load, not death. Retry before concluding anything. |
## Step 6 — the session boundary
None of the above reaches a session that is already running: hooks are read at session start,
and the MCP server is launched then too. **Start a new Codex session before testing.** This is
the single most common "it's broken" report and it is not a fault. Say it explicitly whenever
setup is run in the session that installed the plugin.
## Finish
End with `mcp__mubit__mubit_status`. A `ready` state, the expected endpoint, and the run id the
hooks derived is a working install. Anything else is a job for `mubit-memory:doctor`, whose
step 0 is the Codex-specific one this skill just tried to prevent.