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
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1434,7 +1434,7 @@ When the embedded query (`card.dataset_query`, `transform.source.query` for `sou

Pass `--skip-validate` to bypass the pre-flight on any of `card create`, `card update`, `transform create`, `transform update`, `measure create`, `measure update`, `segment create`, or `segment update` — the body is sent as-is and the server is the authority. Same escape hatch as on `mb query`; use only when the bundled schema disagrees with what the server actually accepts.

Agent discovery path: `mb <command> --help --json` lists a command's args and output schema; the description for `card create`/`update`, `transform create`/`update`, `measure create`/`update`, and `segment create`/`update` references `mb query --print-schema` so an agent can fetch the validating schema directly.
Agent discovery path: `mb <command> --help --json` lists a command's args, JSON-body input schema, and output schema; the description for `card create`/`update`, `transform create`/`update`, `measure create`/`update`, and `segment create`/`update` references `mb query --print-schema` so an agent can fetch the validating schema directly.

The bundled query schema is synced from a pinned `@metabase/representations` release via `bun run sync:representations`; CI guards against drift.

Expand Down Expand Up @@ -1566,12 +1566,13 @@ The former `METABASE_`-prefixed names (`METABASE_URL`, `METABASE_API_KEY`, `META

Every node of the command tree answers `--help --json` with machine-readable help, mirroring what text help shows at that level:

- A leaf command emits its full entry — name, description, `details`, examples, citty args with types/defaults/enums, `capabilities` (min server version / token feature), and the output Zod schema rendered as JSON Schema.
- A leaf command emits its full entry — name, description, `details`, examples, citty args with types/defaults/enums, `capabilities` (min server version / token feature), and the input and output Zod schemas rendered as JSON Schema (`inputSchema` is the exact validator `readBody` enforces on the JSON body, `null` for commands that take none).
- A command group (and the root) emits a flat `{ commands: [{ command, description }] }` index of every leaf in its subtree, with full-path names.

```sh
mb --help --json | jq -r '.commands[].command' # every command
mb card query --help --json | jq .outputSchema # one command's output schema
mb card create --help --json | jq .inputSchema # the JSON-body contract it validates
```

The entry and index schemas (`CommandHelpEntry`, `CommandHelpIndex`) are exported from `src/runtime/command-help.ts`.
Expand Down
3 changes: 2 additions & 1 deletion skill-data/core/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,12 @@ Cheapest source that answers the question wins:

- What groups/verbs exist? → `mb --help`, then `mb <group> --help`. Add `--json` for a machine-readable `{command, description}` index (`mb --help --json` lists every command).
- What flags does a command take? → `mb <command> --help` — flags with enums and defaults, examples, ~1 KB.
- Output JSON Schema before parsing, machine-readable arg types, min server version? → `mb <command> --help --json` — that command's full entry.
- Output JSON Schema before parsing, JSON-body input schema before authoring, machine-readable arg types, min server version? → `mb <command> --help --json` — that command's full entry (`inputSchema` is the exact validator the command runs on the body; `null` when it takes none).

```bash
mb card query --help # flags, enums, defaults, examples
mb card list --help --json | jq .outputSchema # output schema before parsing
mb card create --help --json | jq .inputSchema # body schema before authoring
mb transform --help --json | jq -r '.commands[].command' # verbs under "transform"
```

Expand Down
1 change: 1 addition & 0 deletions src/commands/card/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export default defineMetabaseCommand({
...bodyInputFlags,
...skipValidateFlag,
},
inputSchema: CardCreateInput,
outputSchema: Card,
examples: [
"cat card.json | mb card create",
Expand Down
1 change: 1 addition & 0 deletions src/commands/card/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default defineMetabaseCommand({
...skipValidateFlag,
id: { type: "positional", description: "Card id", required: true },
},
inputSchema: CardUpdateInput,
outputSchema: Card,
examples: [
"cat patch.json | mb card update 1",
Expand Down
1 change: 1 addition & 0 deletions src/commands/collection/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default defineMetabaseCommand({
description: `Collection namespace: ${CollectionNamespace.options.join("|")} (omit for a normal collection)`,
},
},
inputSchema: CollectionCreateInput,
outputSchema: Collection,
examples: [
"cat collection.json | mb collection create",
Expand Down
1 change: 1 addition & 0 deletions src/commands/dashboard/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export default defineMetabaseCommand({
...connectionFlags,
...bodyInputFlags,
},
inputSchema: DashboardCreateInput,
outputSchema: Dashboard,
examples: [
"cat dashboard.json | mb dashboard create",
Expand Down
6 changes: 3 additions & 3 deletions src/commands/dashboard/preflight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ interface CardReference {
type CardCheck = { status: "ok" } | { status: "error"; message: string };

export function collectDashcardCardReferences(
dashcards: ReadonlyArray<unknown> | undefined,
dashcards: ReadonlyArray<unknown> | null | undefined,
): CardReference[] {
if (dashcards === undefined) {
if (dashcards === undefined || dashcards === null) {
return [];
}
const refs: CardReference[] = [];
Expand All @@ -40,7 +40,7 @@ export function collectDashcardCardReferences(

export async function preflightDashcardCardReferences(
client: Client,
dashcards: ReadonlyArray<unknown> | undefined,
dashcards: ReadonlyArray<unknown> | null | undefined,
): Promise<void> {
const references = collectDashcardCardReferences(dashcards);
if (references.length === 0) {
Expand Down
1 change: 1 addition & 0 deletions src/commands/dashboard/update-dashcard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default defineMetabaseCommand({
"dashboard-id": { type: "positional", description: "Dashboard id", required: true },
"dashcard-id": { type: "positional", description: "Dashcard id", required: true },
},
inputSchema: DashcardPatchInput,
outputSchema: Dashcard,
examples: [
'mb dashboard update-dashcard 1 5 --body \'{"row":2,"col":0}\'',
Expand Down
1 change: 1 addition & 0 deletions src/commands/dashboard/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export default defineMetabaseCommand({
...bodyInputFlags,
id: { type: "positional", description: "Dashboard id", required: true },
},
inputSchema: DashboardUpdateInput,
outputSchema: DashboardDetail,
examples: [
"cat patch.json | mb dashboard update 1",
Expand Down
1 change: 1 addition & 0 deletions src/commands/document/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default defineMetabaseCommand({
meta: { name: "create", description: "Create a document" },
capabilities: { minVersion: 58 },
args: { ...outputFlags, ...profileFlag, ...connectionFlags, ...bodyInputFlags },
inputSchema: DocumentCreateInput,
outputSchema: Document,
examples: [
"cat doc.json | mb document create",
Expand Down
1 change: 1 addition & 0 deletions src/commands/document/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default defineMetabaseCommand({
...bodyInputFlags,
id: { type: "positional", description: "Document id", required: true },
},
inputSchema: DocumentUpdateInput,
outputSchema: Document,
examples: [
"cat patch.json | mb document update 1",
Expand Down
5 changes: 3 additions & 2 deletions src/commands/eid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@ export default defineMetabaseCommand({
description: "Comma-separated EIDs to translate (used with --model)",
},
},
inputSchema: EidTranslateInput,
outputSchema: EidTranslateResult,
examples: [
"mb eid --model card abc123XYZ,def456ABC",
"mb eid --model card Ss3mHTaWs8T-VLPYEeraG,5oQpn8LO4qXBRZ1Wq3jIp",
"mb eid --file translate.json",
'mb eid --body \'{"entity_ids":{"card":["abc123XYZ"]}}\'',
'mb eid --body \'{"entity_ids":{"card":["Ss3mHTaWs8T-VLPYEeraG"]}}\'',
],
async run({ args, ctx, getClient }) {
const pair = requireBothOrNeither(
Expand Down
1 change: 1 addition & 0 deletions src/commands/field/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default defineMetabaseCommand({
...bodyInputFlags,
id: { type: "positional", description: "Field id", required: true },
},
inputSchema: FieldUpdateInput,
outputSchema: Field,
examples: [
'mb field update 100 --body \'{"description":"customer email"}\'',
Expand Down
1 change: 1 addition & 0 deletions src/commands/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export function defineCommandGroup(def: CommandGroupDef): CommandDef {
examples: [],
details: null,
skills: def.skills ?? [],
inputSchema: null,
outputSchema: null,
capabilities: null,
});
Expand Down
1 change: 1 addition & 0 deletions src/commands/measure/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default defineMetabaseCommand({
...bodyInputFlags,
...skipValidateFlag,
},
inputSchema: MeasureCreateInput,
outputSchema: Measure,
examples: [
"cat measure.json | mb measure create",
Expand Down
1 change: 1 addition & 0 deletions src/commands/measure/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default defineMetabaseCommand({
...skipValidateFlag,
id: { type: "positional", description: "Measure id", required: true },
},
inputSchema: MeasureUpdateInput,
outputSchema: Measure,
examples: [
"cat patch.json | mb measure update 1",
Expand Down
7 changes: 6 additions & 1 deletion src/commands/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ import { connectionFlags, outputFlags, profileFlag } from "./flags";
import { defineMetabaseCommand } from "./runtime";
import { skipValidateFlag } from "./validate-query";

const QueryBody = z.unknown();
const QueryBody = z
.unknown()
.describe(
"MBQL 5, legacy MBQL, or native query body — full MBQL 5 schema: mb query --print-schema",
);

const QUERY_ENDPOINT = "/api/dataset";

Expand Down Expand Up @@ -45,6 +49,7 @@ export default defineMetabaseCommand({
},
...skipValidateFlag,
},
inputSchema: QueryBody,
outputSchema: CardQueryResult,
examples: [
"mb query --print-schema",
Expand Down
2 changes: 2 additions & 0 deletions src/commands/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export interface MetabaseCommandDef<A extends ArgsDef> {
examples?: readonly string[];
details?: string;
skills?: readonly SkillPointer[];
inputSchema?: ZodType;
outputSchema?: ZodType;
capabilities?: Partial<Capabilities> | null;
run: (context: MetabaseCommandContext<A>) => Promise<void> | void;
Expand Down Expand Up @@ -125,6 +126,7 @@ export function defineMetabaseCommand<const A extends ArgsDef>(
examples: def.examples ?? [],
details: def.details ? def.details : null,
skills: def.skills ?? [],
inputSchema: def.inputSchema ?? null,
outputSchema: def.outputSchema ?? null,
capabilities: required,
});
Expand Down
1 change: 1 addition & 0 deletions src/commands/segment/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default defineMetabaseCommand({
...bodyInputFlags,
...skipValidateFlag,
},
inputSchema: SegmentCreateInput,
outputSchema: Segment,
examples: [
"cat segment.json | mb segment create",
Expand Down
1 change: 1 addition & 0 deletions src/commands/segment/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default defineMetabaseCommand({
...skipValidateFlag,
id: { type: "positional", description: "Segment id", required: true },
},
inputSchema: SegmentUpdateInput,
outputSchema: Segment,
examples: [
"cat patch.json | mb segment update 1",
Expand Down
7 changes: 6 additions & 1 deletion src/commands/setting/set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import { defineMetabaseCommand } from "../runtime";

import { parseSettingKey, rethrowSettingError } from "./key";

const SettingValueInput = z
.unknown()
.describe("Any JSON value; the setting's own type constraints are enforced server-side");

export default defineMetabaseCommand({
meta: { name: "set", description: "Set a setting value (parsed strictly as JSON)" },
capabilities: { minVersion: 58 },
Expand All @@ -19,6 +23,7 @@ export default defineMetabaseCommand({
key: { type: "positional", description: "Setting key", required: true },
value: { type: "positional", description: "JSON-encoded value", required: false },
},
inputSchema: SettingValueInput,
outputSchema: SettingValue,
examples: [
`mb setting set remote-sync-branch '"main"'`,
Expand All @@ -31,7 +36,7 @@ export default defineMetabaseCommand({
const key = parseSettingKey(args.key);
const value = await readBody(
{ file: args.file, positional: args.value, source: `setting ${key} value` },
z.unknown(),
SettingValueInput,
);
const client = await getClient();
await client
Expand Down
1 change: 1 addition & 0 deletions src/commands/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default defineMetabaseCommand({
...connectionFlags,
...bodyInputFlags,
},
inputSchema: SetupInput,
outputSchema: SetupResult,
examples: [
"cat setup.json | mb setup",
Expand Down
1 change: 1 addition & 0 deletions src/commands/snippet/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export default defineMetabaseCommand({
...connectionFlags,
...bodyInputFlags,
},
inputSchema: SnippetCreateInput,
outputSchema: Snippet,
examples: [
"cat snippet.json | mb snippet create",
Expand Down
1 change: 1 addition & 0 deletions src/commands/snippet/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default defineMetabaseCommand({
...bodyInputFlags,
id: { type: "positional", description: "Snippet id", required: true },
},
inputSchema: SnippetUpdateInput,
outputSchema: Snippet,
examples: [
"cat patch.json | mb snippet update 1",
Expand Down
1 change: 1 addition & 0 deletions src/commands/table/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default defineMetabaseCommand({
...bodyInputFlags,
id: { type: "positional", description: "Table id", required: true },
},
inputSchema: TableUpdateInput,
outputSchema: Table,
examples: [
'mb table update 42 --body \'{"display_name":"Customers"}\'',
Expand Down
1 change: 1 addition & 0 deletions src/commands/transform-job/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export default defineMetabaseCommand({
meta: { name: "create", description: "Create a transform job" },
capabilities: { minVersion: 59 },
args: { ...outputFlags, ...profileFlag, ...connectionFlags, ...bodyInputFlags },
inputSchema: TransformJobCreateInput,
outputSchema: TransformJob,
examples: [
"cat job.json | mb transform-job create",
Expand Down
1 change: 1 addition & 0 deletions src/commands/transform-job/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default defineMetabaseCommand({
...bodyInputFlags,
id: { type: "positional", description: "Transform job id", required: true },
},
inputSchema: TransformJobUpdateInput,
outputSchema: TransformJob,
examples: [
"cat patch.json | mb transform-job update 1",
Expand Down
1 change: 1 addition & 0 deletions src/commands/transform-tag/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export default defineMetabaseCommand({
meta: { name: "create", description: "Create a transform tag" },
capabilities: { minVersion: 59 },
args: { ...outputFlags, ...profileFlag, ...connectionFlags, ...bodyInputFlags },
inputSchema: TransformTagCreateInput,
outputSchema: TransformTag,
examples: [
'mb transform-tag create --body \'{"name":"nightly"}\'',
Expand Down
1 change: 1 addition & 0 deletions src/commands/transform-tag/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default defineMetabaseCommand({
...bodyInputFlags,
id: { type: "positional", description: "Transform tag id", required: true },
},
inputSchema: TransformTagUpdateInput,
outputSchema: TransformTag,
examples: [
'mb transform-tag update 5 --body \'{"name":"renamed"}\'',
Expand Down
1 change: 1 addition & 0 deletions src/commands/transform/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default defineMetabaseCommand({
...bodyInputFlags,
...skipValidateFlag,
},
inputSchema: TransformCreateInput,
outputSchema: Transform,
examples: [
"cat transform.json | mb transform create",
Expand Down
1 change: 1 addition & 0 deletions src/commands/transform/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export default defineMetabaseCommand({
id: { type: "positional", description: "Transform id", required: true },
...skipValidateFlag,
},
inputSchema: TransformUpdateInput,
outputSchema: Transform,
examples: [
"cat patch.json | mb transform update 1",
Expand Down
Loading
Loading