HttpApi CLI
An Effect CLI generator driven by OpenAPI metadata that groups selected HttpApi operations and executes them through the generated API client.
bunx --bun shadcn@latest add https://krakstack.net/r/httpapi-cli.jsonOverview
httpapi-cli turns operations selected by HttpApiSpec into grouped Effect CLI commands. Its command name, version, and description come from the API OpenAPI info metadata. Calls are delegated to ApiClient, so request encoding, transport customization, authentication, and response decoding stay aligned with the generated Effect HttpApiClient.
Configure OpenAPI Metadata
Annotate the API once; the CLI and MCP server use the same metadata:
export const AppApi = HttpApi.make("AppApi")
.annotateMerge(
OpenApi.annotations({
title: "App API",
version: "1.0.0",
description: "API for the App application",
}),
)
.add(/* groups */);Create A CLI Handler
Create an app-owned handler such as src/lib/cli-handler.ts. This is where the application selects exposed methods, its API origin, and any authenticated HttpClient layer:
import { Layer } from "effect";
import { FetchHttpClient } from "effect/unstable/http";
import { AppApi } from "@/api";
import { env } from "@/env";
import { HttpApiCli, runHttpApiCli } from "@/lib/httpapi-cli";
import { ApiClient } from "@/lib/httpapi-client";
import { HttpApiSpec } from "@/lib/httpapi-helpers";
const httpApiLayer = Layer.mergeAll(
HttpApiSpec.layer({
api: AppApi,
methods: ["get", "post", "put", "patch", "delete"],
}),
ApiClient.layer({
api: AppApi,
baseUrl: env.VITE_SITE_URL,
}).pipe(Layer.provide(FetchHttpClient.layer)),
);
const cliLayer = HttpApiCli.layer.pipe(Layer.provide(httpApiLayer));
export const runCli = (args = process.argv.slice(2)) =>
runHttpApiCli(cliLayer, args);
if (import.meta.main) {
runCli();
}For API keys or session forwarding, replace FetchHttpClient.layer with an app-owned layer that transforms requests before providing it to ApiClient.layer.
Create A Binary Entrypoint
#!/usr/bin/env node
import { runCli } from "@/lib/cli-handler";
runCli();Use --body, --headers, --params, and --query to pass JSON input to an operation.