Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .changeset/first-version.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ First version of `meili`, the Meilisearch CLI built for coding agents.
- Write commands take their body from flags, `--data '<json>'` or `--file <path>` (`-` for stdin), a flag overriding its field; `null` sends a JSON null.
- `meili schema` prints every command with its flags and examples as JSON.
- Connection through `--project-url` and `--project-api-key`, or `MEILI_PROJECT_URL` and `MEILI_PROJECT_API_KEY`; `MEILI_MANAGEMENT_TOKEN` and `MEILI_MANAGEMENT_URL` for the Management API.
- Several projects in a config file, `~/.config/meili/config.json` or `MEILI_CONFIG`, chosen with `--project` on the command line and never deduced; `meili config list`, `config add` and `config remove` manage the file.
- Several projects in a config file, `~/.config/meili/config.json` or `MEILI_CONFIG`, chosen with `--project` on the command line and never deduced; `meili config list`, `config add`, `config update` and `config remove` manage the file.
- A project's `cloudId` in the file gives its id to the management commands, `meili update projects --project prod`; `meili config sync-with-cloud` fills it from Meilisearch Cloud on the entries that have the project's URL, `meili create projects --add-to-config` adds the project it creates.
- `json` output by default, `ndjson` for lists, `--all` to follow the pagination, `--wait` and `--timeout` for asynchronous tasks.
- Structured errors on stderr with stable codes and exit codes, a "did you mean" hint on an unknown command, `--debug` HTTP traces with secrets masked.
4 changes: 2 additions & 2 deletions .claude/skills/add-command/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Work through the steps in order. Every check below is enforced by `pnpm test` th
## 1. Read before you write

- `CLAUDE.md`, fully. The non-negotiable rules are the review checklist.
- `docs/contract/commands.md`: the grammar, the eleven naming rules, the exceptions table, the shared flag groups and the commands without an API.
- `docs/contract/commands.md`: the grammar, the eleven naming rules, the exceptions table, the shared flag groups and the commands that do not derive from a route.
- `docs/contract/output.md`: output modes, pass-through, errors, exit codes, asynchronous operations, destructive commands, input, pagination. The sections that match your routes are the specification of your command.
- `docs/contract/testing.md`: what the three test levels must contain.

Expand All @@ -32,7 +32,7 @@ Compare the derived command with `$ARGUMENTS`:
- different name because the user's request contradicts the rules for no such reason: tell the user, propose the derived name, and follow what they decide; if they keep their name, it is an exception with their reason.
- no route in the document, or a parameter the user mentions that the document does not have: stop and ask the user. Do not guess a route and do not read it in Meilisearch's source code.
- a route behind an experimental feature: it is out of the contract (rule 10). Stop and tell the user; opening it is an exception they decide.
- a command that calls no API (`schema`): it must be in the "Commands without an API" table of `commands.md`; if it is not, stop and ask.
- a command that does not derive from a route (`schema`, the `config` commands): it must be in the "Commands that do not derive from a route" table of `commands.md`; if it is not, stop and ask.

From the routes, write down the flags of each: the path flags (rule 4: `--id` for the resource itself, the singular collection for a parent, `--index`), the query parameters and body fields (rule 6), the identifier flags named by what they identify and their API-spelling aliases (rule 5), and which flag combination selects which route (rule 3).

Expand Down
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Package: `@meilisearch/cli` on npm. Binary: `meili`.
- TypeScript, strict mode, `noUncheckedIndexedAccess` on. Node 22 or newer.
- oclif v5 (`@oclif/core` 5) for the command tree, topic separator is a space (`meili get indexes`). See ADR 0001.
- `meilisearch-js` for the Meilisearch API.
- `@hey-api/openapi-ts` generates the Management API client from `openapi/management.json`, downloaded by `pnpm openapi:management` and never committed, into `src/lib/clients/management/generated/`. Never edit generated files. Run `pnpm gen:management` to refresh them: it runs the generator through `pnpm dlx` with TypeScript 5 beside it, which the generator needs, and CI fails when the committed files differ. In code, commands, flags and environment variables, `management` is the name for everything that touches the Management API. `Cloud` only appears in prose, as the product name.
- `@hey-api/openapi-ts` generates the Management API client from `openapi/management.json`, downloaded by `pnpm openapi:management` and never committed, into `src/lib/clients/management/generated/`. Never edit generated files. Run `pnpm gen:management` to refresh them: it runs the generator through `pnpm dlx` with TypeScript 5 beside it, which the generator needs, and CI fails when the committed files differ. In code, flags and environment variables, `management` names the Management API itself, `--management-token`; `cloud` names the product, Meilisearch Cloud, where a command or a field speaks of it, `config sync-with-cloud`, `cloudId`.
- vitest for tests, with snapshots. `msw` mocks HTTP in unit tests. Integration tests run against a local Meilisearch and a local Management API, see `docs/contract/testing.md`.
- Biome for lint and format.
- changesets for versioning and the changelog.
Expand Down Expand Up @@ -95,9 +95,9 @@ Then read the diff of your pull request twice. Once for simplicity: in Claude Co

## Where to read more

- `docs/contract/commands.md`: the naming rules that turn an API route into a command, the exceptions, the global and shared flags, the commands without an API
- `docs/contract/commands.md`: the naming rules that turn an API route into a command, the exceptions, the global and shared flags, the commands that do not derive from a route
- `docs/contract/output.md`: output modes, error format, exit codes, async tasks, pagination
- `docs/contract/config.md`: projects, the config file, connection resolution, environment variables, secrets
- `docs/contract/config.md`: projects, the config file, connection resolution, Cloud projects, environment variables, secrets
- `openapi/`: the OpenAPI documents downloaded by `pnpm openapi`, the reference for every command name
- `docs/contract/testing.md`: test levels, how the two local APIs start, what runs in pull request CI
- `docs/adr/`: the decisions and the reasons
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,19 @@ The URL, the key and the token also exist as flags with the same name: `--projec
{
"projects": {
"local": { "url": "http://localhost:7700" },
"prod": { "url": "https://ms-abc.sfo.meilisearch.io", "apiKey": "..." }
"prod": { "url": "https://ms-abc.sfo.meilisearch.io", "apiKey": "...", "cloudId": 343 }
}
}
```

```sh
meili get indexes --project prod
meili update projects --project prod --name renamed # a management command uses the cloudId
```

With several projects in the file, `--project` is required: the CLI never guesses, and it refuses to run when the file and the `MEILI_PROJECT_URL` variable both define a project. `MEILI_CONFIG` names another file. For a coding agent, give it its own file through `MEILI_CONFIG`, read-only: the file is shared state, and an agent must not be able to change where another one's commands go. The file holds your keys: keep it readable by you alone, the CLI warns on stderr otherwise, and an agent changes nothing in it, neither a project nor its permissions, unless you asked for it explicitly. `meili config list`, `meili config add` and `meili config remove` manage the file.
With several projects in the file, `--project` is required: the CLI never guesses, and it refuses to run when the file and the `MEILI_PROJECT_URL` variable both define a project. `MEILI_CONFIG` names another file. For a coding agent, give it its own file through `MEILI_CONFIG`, read-only: the file is shared state, and an agent must not be able to change where another one's commands go. The file holds your keys: keep it readable by you alone, the CLI warns on stderr otherwise, and an agent changes nothing in it, neither a project nor its permissions, unless you asked for it explicitly. `meili config list`, `meili config add`, `meili config update` and `meili config remove` manage the file.

`cloudId` is the project's id in Meilisearch Cloud, which the dashboard does not show. `meili config sync-with-cloud` fills it on the entries whose URL is a project your token sees; `meili create projects --add-to-config` adds the project it creates, with its URL, its master key and its `cloudId`: creation is the one moment the key is returned, `sync-with-cloud` never writes one.

## Documentation

Expand Down
2 changes: 1 addition & 1 deletion docs/adr/0005-named-projects-config-file.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ADR 0005: Named projects in a config file, chosen on the command line, nothing deduced

Status: accepted. Date: 2026-10-14.
Status: accepted. Date: 2026-10-14. One point is superseded by ADR 0006: an entry is changed with `config update`, no longer with `remove` then `add`.

## Context

Expand Down
34 changes: 34 additions & 0 deletions docs/adr/0006-cloud-projects-in-the-config-file.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# ADR 0006: Cloud projects in the config file, the Management API consulted only on request

Status: accepted. Date: 2026-10-15.

## Context

A management command acts on a Meilisearch Cloud project identified by its integer `id`, `meili update projects --id 343`. That id is not shown in the Cloud dashboard, only in the URL of a page. The config file of ADR 0005 names projects for the Meilisearch commands, with a URL and a key, and `--project <name>` is the handy way to target one; on a management command it was ignored in silence, and the user had to find an id.

Many users create their projects in the dashboard and want the CLI, and the agent behind it, to act on them. ADR 0005 rejected resolving a project through the Management API because not everyone has Cloud, and because a resolution that runs before a command chooses its target in the user's back.

The Management API returns a project's master key at its creation only: `GET /projects` does not carry it.

## Decision

- **`cloudId` in the config file.** An entry has `url`, optionally `apiKey`, optionally `cloudId`, the project's `id` in Meilisearch Cloud. On a management command, `--project <name>` supplies the id from the entry: `--id` of the `projects` commands and `--project-id` of their sub-resources are optional. `--project` with `--id` is `cli_usage`; an entry without `cloudId` is `cli_config` with the ways to set it; `--project` on a command none of whose routes takes a project is `cli_usage`. The id is never resolved by the CLI itself, from the URL or otherwise.
- **The Management API is consulted only when the command line asks for it**, never to resolve the target of a command. The rule of ADR 0005 stays for the ambient resolution; explicit requests are not deduction. Three of them set `cloudId`: `create projects --add-to-config`, which adds the created project as an entry named after it; `config add` and `config update` with `--project-cloud-id`, the id by hand; `config sync-with-cloud`, which lists the projects the token sees and sets `cloudId` on the entries that have a project's URL.
- **`--add-to-config` writes the master key**, as the entry's `apiKey`: creation is the one moment the API returns it, and an entry without its key serves no Meilisearch command. `sync-with-cloud` never writes a key, the API does not return it afterwards; a key written later is the human's choice, through `config update` or the editor.
- **`sync-with-cloud` never adds or removes an entry.** A project the file does not know is ignored: without its key, which the API does not return, an entry would serve no Meilisearch command. The entries whose project it no longer sees are reported as `missing` and kept.
- **`config update`** changes the fields of an entry, replacing the `remove` then `add` of ADR 0005: `cloudId` arrives after an entry exists, and a key is corrected in place.
- **The name `cloud`** is allowed in commands and fields where the product is meant, `sync-with-cloud`, `cloudId`: the product is Meilisearch Cloud, at cloud.meilisearch.com. `management` names the API, `--management-token`. ADR 0004's rule that kept `Cloud` to prose is dropped.
- **A parent parameter of the Management API keeps its API name**, `{projectId}` is `--project-id`, because `--project` is the global flag that names an entry.

Alternatives considered:

- **Refusing `--project` on management commands.** Honest and minimal, but it gives up the one way to name a project without its id.
- **Resolving the id from the entry's URL at command time.** One hidden request before each command, a URL match that can be wrong in silence: the ambient deduction ADR 0005 refuses.
- **A `--add-to-config <name>` that names the entry.** One more thing to type; the entry is named after the project.
- **`sync-with-cloud` adding an entry for every project the file does not know**, named after the project. Rejected: without the key, those entries are of no use to the Meilisearch commands, and the file would fill with half entries.

## Consequences

- A user who created projects in the dashboard writes their entries with `config add`, URL and key, then runs `meili config sync-with-cloud` once to get their `cloudId`, and names them with `--project` on every command, Meilisearch or management.
- `--id` and `--project-id` are not required flags on the Management API, and `test/contract/api.test.ts` knows it.
- `commands.md` gains the `--add-to-config` flag, the rows of `config update` and `config sync-with-cloud`, and the `--project-id` rule; `config.md` gains the `cloudId` field and the "Cloud projects" section.
Loading
Loading