Skip to content
Merged
6 changes: 6 additions & 0 deletions .changeset/happy-items-battle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@mixedbread/cli": minor
---

- Update config object to store multiple api keys
- Add `--saved-key` global option
4 changes: 0 additions & 4 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnPaste": true,
"editor.formatOnSave": true,
"tailwindCSS.experimental.classRegex": [
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
["clsx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
],
"typescript.tsdk": "node_modules/typescript/lib",
"prettier.enable": false
}
6 changes: 5 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@
"noUndeclaredVariables": "off",
"noUndeclaredDependencies": "off",
"useImportExtensions": "off",
"noNodejsModules": "off"
"noNodejsModules": "off",
"noUnusedImports": {
"level": "warn",
"fix": "safe"
}
},
"nursery": {
"noSecrets": "off",
Expand Down
63 changes: 55 additions & 8 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ npm install -g @mixedbread/cli
## Quick Start

```bash
# Set your API key
# Add and set your API key
mxbai config keys add mxb_xxxxx work

# Or use environment variable
export MXBAI_API_KEY=mxb_xxxxx

## Check available commands and their options
Expand Down Expand Up @@ -83,6 +86,11 @@ mxbai vs upload "My Documents" --manifest upload-manifest.yaml

- `mxbai config set <key> <value>` - Set configuration values
- `mxbai config get [key]` - Get configuration values
- `mxbai config keys add <key> [name]` - Add a new API key
- `mxbai config keys list` - List all API keys
- `mxbai config keys remove <name>` - Remove an API key
- Options: `--force` (skip confirmation)
- `mxbai config keys set-default <name>` - Set the default API key
- `mxbai completion install` - Install shell completion
- Options: `--shell <shell>` (manually specify shell: bash, zsh, fish, pwsh)
- `mxbai completion uninstall` - Uninstall shell completion
Expand Down Expand Up @@ -220,8 +228,25 @@ mxbai config set defaults.upload.parallel 10 # Concurrent operations
mxbai config set defaults.search.top_k 20 # Number of results (default: 10)
mxbai config set defaults.search.rerank true # Enable reranking (default: false)

# API key (alternative to environment variable)
mxbai config set api_key mxb_xxxxx
# API key management (alternative to environment variable)
# Add API keys with names for easy switching
mxbai config keys add mxb_xxxxx work
mxbai config keys add mxb_xxxxx personal

# List all API keys
mxbai config keys list
# Output:
# work
# * personal (default)

# Set default API key
mxbai config keys set-default work

# Remove an API key
mxbai config keys remove personal

# Remove an API key without confirmation
mxbai config keys remove personal --force

# Create aliases for frequently used vector stores
mxbai config set aliases.docs "My Documentation"
Expand All @@ -242,14 +267,35 @@ mxbai config get defaults.upload

The CLI looks for your API key in this order:

1. `--api-key` command line flag
1. `--api-key` or `--saved-key` command line flags
2. `MXBAI_API_KEY` environment variable
3. Config file (platform-specific location):
3. Default API key from config file (platform-specific location):
- **Linux/Unix**: `~/.config/mixedbread/config.json` (or `$XDG_CONFIG_HOME/mixedbread/config.json`)
- **macOS**: `~/Library/Application Support/mixedbread/config.json`
- **Windows**: `%APPDATA%\mixedbread\config.json`
- **Custom**: Set `MXBAI_CONFIG_PATH` environment variable to override

### Multi-Organization Support

The CLI supports multiple API keys for different organizations or environments:

```bash
# Add API keys with descriptive names
mxbai config keys add mxb_xxxxx work
mxbai config keys add mxb_xxxxx personal

# Use a specific saved API key for a command
mxbai vs upload "My Docs" "*.md" --saved-key work
mxbai vs search "Knowledge Base" "query" --saved-key personal

# Or use an actual API key directly
mxbai vs upload "My Docs" "*.md" --api-key mxb_xxxxx

# The last added key becomes default automatically
# Or explicitly set a default
mxbai config keys set-default personal
```

## Shell Completion

The CLI supports tab completion for commands and subcommands. To set up completion:
Expand Down Expand Up @@ -280,7 +326,8 @@ After installation, restart your shell or reload your shell configuration:

All commands support these global options:

- `--api-key <key>` - API key for authentication (must start with "mxb\_")
- `--api-key <key>` - Actual API key for authentication
- `--saved-key <name>` - Name of saved API key from config
- `--format <format>` - Output format: table, json, or csv (default: table)
- `--debug` - Enable debug output (can also set `MXBAI_DEBUG=true`)

Expand Down Expand Up @@ -315,8 +362,8 @@ This CLI is built on top of the `@mixedbread/sdk` and provides a convenient comm

```bash
export MXBAI_API_KEY=mxb_xxxxx
# Or create a config file
cd packages/cli && pnpm build && pnpm mxbai config set api_key mxb_xxxxx
# Or add to config file
cd packages/cli && pnpm build && pnpm mxbai config keys add mxb_xxxxx dev
```

#### Development Workflow
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/src/bin/mxbai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ program.action(() => {

// Global error handling
program.on("error", (error: Error) => {
console.error(chalk.red("\nError:"), error.message);
console.error(chalk.red("\n✗"), error.message);
if (process.env.MXBAI_DEBUG === "true") {
console.error(chalk.gray(error.stack));
}
Expand All @@ -68,7 +68,7 @@ program.on("error", (error: Error) => {
// Handle unknown commands
program.on("command:*", () => {
console.error(
chalk.red("\nError:"),
chalk.red("\n✗"),
`Unknown command: ${program.args.join(" ")}\n`
);
program.help();
Expand All @@ -80,7 +80,7 @@ async function main() {
await program.parseAsync(process.argv);
} catch (error) {
if (error instanceof Error) {
console.error(chalk.red("\nError:"), error.message);
console.error(chalk.red("\n✗"), error.message);
if (process.env.MXBAI_DEBUG === "true") {
console.error(chalk.gray(error.stack));
}
Expand Down
16 changes: 14 additions & 2 deletions packages/cli/src/commands/completion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function getShellInfo(options: { shell?: string }) {
shell = options.shell as SupportedShell;
installMethod = "manual";
} else {
console.error(chalk.red(`Error: Unsupported shell '${options.shell}'.`));
console.error(chalk.red("✗"), `Unsupported shell '${options.shell}'`);
console.error(
chalk.gray(`Supported shells: ${SUPPORTED_SHELLS.join(", ")}`)
);
Expand Down Expand Up @@ -216,7 +216,19 @@ export function createCompletionServerCommand(): Command {

// Config completions
if (env.prev === "config") {
return log(["get", "set"], shell, console.log);
return log(["get", "set", "keys"], shell, console.log);
}

if (env.prev === "keys") {
// Check if we're in "mxbai config keys " context
const words = env.line.trim().split(/\s+/);
if (words.length >= 3 && words[1] === "config") {
return log(
["list", "add", "remove", "set-default"],
shell,
console.log
);
}
}

// Completion completions
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/commands/config/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function createGetCommand(): Command {
current = current[currentKey];
} else {
console.error(
chalk.red("Error:"),
chalk.red(""),
`Configuration key ${chalk.cyan(key)} not found`
);
process.exit(1);
Expand All @@ -35,7 +35,7 @@ export function createGetCommand(): Command {
console.log(chalk.cyan(`${key}:`), JSON.stringify(current, null, 2));
} catch (error) {
console.error(
chalk.red("Error:"),
chalk.red(""),
"Failed to get configuration:",
error instanceof Error ? error.message : String(error)
);
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/commands/config/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Command } from "commander";
import { createGetCommand } from "./get";
import { createKeysCommand } from "./keys";
import { createSetCommand } from "./set";

export function createConfigCommand(): Command {
Expand All @@ -9,6 +10,7 @@ export function createConfigCommand(): Command {

configCommand.addCommand(createSetCommand());
configCommand.addCommand(createGetCommand());
configCommand.addCommand(createKeysCommand());

// Show help without error exit code when no subcommand provided
configCommand.action(() => {
Expand Down
Loading