Skip to content

toolcraft-openapi: generate a complete high-level command entrypoint #424

@kamilio

Description

@kamilio

Problem

poe-agent-tools is a canary for the real OpenAPI spec and toolcraft-openapi behavior. After updating to toolcraft-openapi@0.0.62 and regenerating, the generator emitted all expected command groups in src/generated/index.ts, including generatedCommands:

export const generatedCommands = [
  agent,
  apiBots,
  botActions,
  botAssets,
  botCostTelemetry,
  botWorkflowControls,
  bots,
  costUnitPrices,
  handles,
  llms,
  modelPricing,
  officialBots,
  users,
] as const;

But the package-level client still has to manually import and wire commands:

import { botActions, bots, users } from "./generated/index.js";
import { agentWhoamiCommand } from "./generated/agent/whoami.js";

export const client = defineClient({
  name: "poe-agent-tools",
  baseUrl,
  auth,
  commands: [agentWhoamiCommand, botActions, bots, users],
});

That hand-maintained list caused most generated actions to be omitted from the installed CLI/MCP surface. poe-agent-tools --help currently exposes only:

whoami
bot-actions
bots
users

while generated groups also include agent, api-bots, bot-assets, bot-cost-telemetry, bot-workflow-controls, cost-unit-prices, handles, llms, model-pricing, and official-bots.

Required behavior

toolcraft-openapi should generate the package-level OpenAPI client wrapper, not just the leaf commands and groups.

The default generated command structure must reflect the OpenAPI-derived generated output exactly. Downstream packages should not need to flatten, reshape, rename, filter, or manually rewire generated commands to get a complete client. If the generator emits an agent group containing whoami, the default generated client surface should expose agent whoami, not a locally flattened root whoami command.

Downstream code should not import individual generated operations, enumerate generated groups, or pass a generated command array manually for the default full client. The consumer should provide only host-specific configuration:

import { defineGeneratedClient } from "./generated/client.js";
import { envBearerTokenAuth } from "./auth.js";

const BASE_URL = "https://www.i.quora.com/api/internal_agent";

export const client = defineGeneratedClient({
  name: "poe-agent-tools",
  baseUrl: BASE_URL,
  auth: envBearerTokenAuth("POE_API_KEY"),
});

The generated wrapper owns the complete generated command surface:

// generated/client.ts
import { defineClient } from "toolcraft-openapi";
import { generatedCommands } from "./index.js";

export function defineGeneratedClient(options: GeneratedClientOptions) {
  return defineClient({
    ...options,
    commands: generatedCommands,
  });
}

Exact naming can change, but the contract should be:

  • one generated client factory is the primary public entrypoint for consumers;
  • it includes every generated operation exactly once;
  • it preserves the OpenAPI-derived generated grouping exactly;
  • it is shared by CLI, MCP, and SDK/client usage;
  • app code supplies only deployment/configuration concerns such as name, baseUrl, auth, optional docsUrl, and optional fetch;
  • lower-level exports remain available for consumers that intentionally want a custom command surface.

Advanced customization escape hatch

The generator should still emit lower-level files/exports for advanced consumers. If a consumer really wants to curate the CLI shape, flatten a group, hide commands, rename groups, or expose only a subset, that should be possible by explicitly importing generated groups or leaf commands and calling defineClient directly.

Example advanced/manual wiring:

import { defineClient } from "toolcraft-openapi";
import { botActions, bots } from "./generated/index.js";
import { agentWhoamiCommand } from "./generated/agent/whoami.js";

export const client = defineClient({
  name: "custom-cli",
  baseUrl,
  auth,
  commands: [agentWhoamiCommand, botActions, bots],
});

That escape hatch is useful, but it should be opt-in. The default generated integration path should be complete and spec-shaped by construction.

Generated CLI/MCP shape

Generated CLI and MCP entrypoints should consume the same generated client/root surface, so all surfaces agree by construction.

Example:

import { runCLI } from "toolcraft/cli";
import { client } from "./client.js";

await runCLI(client.root, { services: client.services });

or, if the generated output owns the runnable entrypoint directly:

import { runGeneratedCLI } from "./generated/cli.js";
import { envBearerTokenAuth } from "./auth.js";

await runGeneratedCLI({
  name: "poe-agent-tools",
  baseUrl: "https://www.i.quora.com/api/internal_agent",
  auth: envBearerTokenAuth("POE_API_KEY"),
});

The key invariant is that CLI, MCP, and SDK clients cannot drift because they all use the same generated root/client definition by default.

Acceptance criteria

  • toolcraft-openapi-generate emits a generated client factory, e.g. defineGeneratedClient, that owns the complete command/root surface.
  • The generated client factory includes every generated operation exactly once.
  • The generated client factory preserves the OpenAPI-derived generated grouping exactly; no local flattening or reshaping in downstream packages is needed for the default full client.
  • Generated CLI and MCP entrypoints use the same generated client/root surface as SDK/client consumers.
  • Downstream packages do not need to import individual operation files or manually enumerate generated groups for the default full client.
  • Lower-level generated exports remain available for explicit advanced customization, and docs distinguish this from the default integration path.
  • Docs/readme/template should point consumers at the generated client factory as the default integration path.
  • Add a regression test in packages/toolcraft-openapi using a fixture spec with multiple groups; assert the generated client/root includes every operation and preserves the generated grouping.
  • Add a regression/compile test showing an advanced consumer can still import a generated group or leaf command and call defineClient manually.
  • Update poe-agent-tools to consume the generated client factory with no local compatibility shim and verify poe-agent-tools --help lists all generated groups/actions after regeneration.

Why this belongs upstream

Per poe-agent-tools/AGENTS.md, this repo should not patch generated files, normalize generator behavior locally, or add compatibility shims that hide upstream failures. Missing command wiring is a toolcraft-openapi ergonomics/contract issue: the generator already knows the full operation graph and should emit the complete high-level client integration point.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is not workingstatus:draftMaestro bug intake awaiting triage

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions