Skip to content
Open
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
1 change: 1 addition & 0 deletions .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.
- Documents: `meili get documents --index <index>`, narrowed by `--ids` or `--filter`; `meili add documents --index <index> --file <path>` and `meili update documents --index <index> --file <path>`, which read the documents from a file, from stdin with `--file -` or from `--data`; `meili delete documents --index <index> (--ids <ids> | --filter <filter> | --all) --yes`.
- Indexes: `meili get indexes [--id <index>]`; `meili add indexes --id <index> [--primary-key <field>]`, `meili update indexes --id <index> [--primary-key <field>] [--new-id <index>]`, which renames the index, and `meili delete indexes --id <index> --yes`.
- Tasks: `meili get tasks`, narrowed by `--ids`, `--statuses`, `--types`, `--index-ids`, `--batch-ids`, `--canceled-by` and the date filters of the route, paging with `--limit` and `--from` and following the `next` cursor with `--all`; `meili cancel tasks` and `meili delete tasks --yes`, which take the same filters and answer a task.
- API keys: `meili get keys [--id <key>]`, which lists the keys of the instance or gets one by its uid or by its key value; `meili add keys --actions <actions> --indexes <indexes> --expires-at <date>`, where `--expires-at null` creates a key that never expires; `meili update keys --id <key>`, which changes the `--name` and the `--description` the route takes, `null` removing one; `meili delete keys --id <key> --yes`, which answers nothing, the route returning 204. The `key` field reaches stdout as the API returns it: a credential an API answers is data, and the CLI hides nothing from the agent it works for.
- Search: `meili search --index <index> --q <query>`, on `POST /indexes/{index_uid}/search`, with every non-experimental search parameter of the route as a flag, from `--filter` and `--sort` to `--hybrid` and `--vector`; `--data` or `--file` carries a whole search body, which a flag of the same field overrides. `meili multi-search --queries '<json>'`, on `POST /multi-search`, runs several queries in one request, each naming its index, answered side by side or merged into one ranked list with `--federation`.
- Similar documents: `meili similar --index <index> --id <document> --embedder <embedder>`, on `POST /indexes/{index_uid}/similar`, returns the documents of the index closest to one of them, narrowed by `--filter`, `--limit` and `--offset`; `--data` or `--file` carries a whole body, which a flag of the same field overrides.
- Facet values: `meili facet-search --index <index> --facet-name <attribute>`, on `POST /indexes/{index_uid}/facet-search`, searches the values of one filterable attribute with `--facet-query` and counts them on the documents `--q` and `--filter` keep; `--data` or `--file` carries a whole body, which a flag of the same field overrides.
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Package: `@meilisearch/cli` on npm. Binary: `meili`.
5. Never open `$EDITOR`. Every input comes from a flag, an environment variable, a file (`--file`), stdin (`--file -`) or the config file of `docs/contract/config.md`, from which nothing is deduced.
6. Command and flag names derive from the API routes by the rules of `docs/contract/commands.md`: verb first, resource plural, `meili get indexes --id movies`. The resource's own identifier is `--id`, or `--ids` when the list route filters by identifiers; a parent in the path is a flag named after its collection, `--index`; a query or body parameter keeps its API name in kebab-case, `primaryKey` is `--primary-key`. No positional argument, and no synonym beyond the aliases the contract lists.
7. Errors are structured. Use `MeiliCliError` from `src/lib/errors.ts` with a code and an exit code from the table in `docs/contract/output.md`. Never `throw new Error("...")`.
8. Secrets never appear in output, logs or debug traces. Use the redaction helpers in `src/lib/config.ts`.
8. The credentials the CLI holds to reach an API never appear in output, logs or debug traces. Use the redaction helpers in `src/lib/config.ts`. A credential an API returns is data: it goes to stdout unchanged, like the `key` of `get keys`. See the Secrets section of `docs/contract/config.md`.
9. No new dependency without a one line justification in the pull request. Prefer the standard library.
10. One command per pull request, or the commands of one resource when they ship together and complete: the `get`, `add`, `update` and `delete` of `documents` are one change. One file per command, covering every route of its verb and resource. Every command has a snapshot test.
11. Every command declares the API it uses with `static api = "meilisearch" | "management" | "none"`. `BaseCommand` resolves credentials and builds the client. Never resolve credentials or build a client in a command.
Expand Down
5 changes: 4 additions & 1 deletion docs/contract/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ Every API command declares its routes, `static routes = ["GET /indexes", "GET /i
| `GET /tasks` | `meili get tasks [--ids <uids>] [--statuses <statuses>]` |
| `POST /tasks/cancel` | `meili cancel tasks --ids <uids>` |
| `DELETE /tasks` | `meili delete tasks --ids <uids> --yes` |
| `GET /keys`, `GET /keys/{key}` | `meili get keys [--id <uid>]` |
| `GET /keys`, `GET /keys/{key}` | `meili get keys [--id <key>]` |
| `POST /keys` | `meili add keys --actions <actions> --indexes <indexes> --expires-at <date>` |
| `PATCH /keys/{key}` | `meili update keys --id <key> [--name <name>] [--description <text>]` |
| `DELETE /keys/{key}` | `meili delete keys --id <key> --yes` |
| `POST /dumps` | `meili add dumps` |
| `GET /api/v2/projects`, `GET /api/v2/projects/{id}` | `meili get projects [--id <id>] [--team-id <id>]` |
| `POST /api/v2/projects` | `meili add projects --name <name> --team-id <id> --resource-id <id>` |
Expand Down
3 changes: 2 additions & 1 deletion docs/contract/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ A variable that doubles a flag takes its name from the flag: `MEILI_` followed b

## Secrets

- API keys and tokens never appear on stdout, on stderr, in `--debug` traces, in error messages or in snapshots. When a secret must be shown at all, only its last four characters are: `****1a2b`. `meili config list` masks keys the same way.
- The credentials the CLI holds to reach an API, the keys of the config file and the tokens of the credentials file, never appear on stdout, on stderr, in `--debug` traces, in error messages or in snapshots. When one must be shown at all, only its last four characters are: `****1a2b`. `meili config list` masks keys the same way.
- A credential an API *returns* is data, not one of those: the `keys` commands print the `key` field as the API answers it, like every field of every other response (`output.md`, Pass-through). The CLI hides nothing from the agent it works for; redaction applies to the connection the CLI was given, and to stderr, `--debug` traces and logs, never to the data stream.
- `--debug` redacts the `Authorization`, `Cookie` and `Set-Cookie` headers, a session cookie of the authorization server being a credential like any other, and every field named `apiKey`, `apikey`, `key`, `token`, `access_token`, `refresh_token` in request and response bodies. `apikey` is the Management API's spelling of a project's master key, `access_token` and `refresh_token` the spelling of the authorization server. A form-encoded body, which is what the token endpoint takes, is never printed. The redaction lives in `src/lib/config.ts` and is tested.
- The CLI reads keys from the config file, and from nowhere else on disk, and warns when the file is readable by others. Passing a key in a flag is allowed and documented as visible in the process list and in the shell history; `--project-api-key -` reads it from stdin instead.
Loading
Loading