ai-infrastructure-hugg…
Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming,…
Modern CLI development combining oclif's command framework with Ink's React-based terminal rendering
Claude Code
$ npx -y skills add agents-inc/skills --skill cli-framework-oclif-ink --agent claude-code
Codex
$ npx skills add agents-inc/skills --skill cli-framework-oclif-ink -a codex -y
Cursor
$ npx skills add agents-inc/skills --skill cli-framework-oclif-ink -a cursor -y
Gemini CLI
$ npx skills add agents-inc/skills --skill cli-framework-oclif-ink -a gemini-cli -y
GitHub Copilot
$ npx skills add agents-inc/skills --skill cli-framework-oclif-ink -a github-copilot -y
OpenCode
$ npx skills add agents-inc/skills --skill cli-framework-oclif-ink -a opencode -y
Windsurf
$ npx skills add agents-inc/skills --skill cli-framework-oclif-ink -a windsurf -y
name: cli-framework-oclif-ink description: Modern CLI development combining oclif's command framework with Ink's React-based terminal rendering
> **Quick Guide:** Use oclif for command routing, flag/arg parsing, and plugin architecture. Use Ink for React-based interactive terminal UIs with Flexbox layout. Combine both when commands need rich stateful interfaces. Always `await waitUntilExit()` when rendering Ink from oclif commands. Use `this.log()` instead of `console.log` to preserve JSON output mode.
---
<critical_requirements>
**(You MUST `await waitUntilExit()` after `render()` in oclif commands -- without it the process exits before the UI completes)**
**(You MUST use `this.log()` / `this.warn()` / `this.error()` in commands -- `console.log` breaks `--json` mode and test capture)**
**(You MUST wrap all text in `<Text>` components in Ink -- bare strings cause rendering errors)**
**(You MUST use `useEffect` cleanup to cancel async operations -- Ink components unmount when the user presses Ctrl+C)**
</critical_requirements>
---
**Auto-detection:** oclif, @oclif/core, @oclif/test, Ink, ink, @inkjs/ui, Command class, Flags, Args, useInput, useApp, useFocus, render(), waitUntilExit, terminal UI, CLI command, ink-testing-library
**When to use:**
**When NOT to use:**
**Key patterns covered:**
---
<philosophy>
oclif and Ink solve orthogonal problems. **oclif** handles the boring-but-critical parts: command routing, flag parsing, help generation, plugin discovery, auto-updates. **Ink** handles the interactive parts: stateful terminal UIs using React's component model with Flexbox layout.
**Use oclif alone** when commands do their work and print output. **Add Ink** when a command needs real-time user interaction (wizards, dashboards, progress). The integration point is simple: the oclif command's `run()` calls `render()` and awaits `waitUntilExit()`.
**Key architectural decisions:**
</philosophy>
---
<patterns>
Commands use static properties for metadata and flag/arg definitions. The `run()` method is async and returns typed data for JSON output support.
import { Command, Flags, Args } from "@oclif/core";
const DEFAULT_RETRIES = 3;
export class Deploy extends Command {
static summary = "Deploy to target environment";
static enableJsonFlag = true; // Adds --json flag
static flags = {
env: Flags.string({
char: "e",
required: true,
options: ["staging", "production"] as const,
}),
retries: Flags.integer({
char: "r",
default: DEFAULT_RETRIES,
min: 0,
max: 10,
}),
verbose: Flags.boolean({ char: "v", default: false, allowNo: true }),
apiKey: Flags.string({ env: "MY_CLI_API_KEY" }), // From env var
};
static args = {
target: Args.string({ description: "Deploy target", required: true }),
};
async run(): Promise<{ status: string }> {
const { args, flags } = await this.parse(Deploy);
// Use this.log, this.warn, this.error -- never console.*
this.log(`Deploying ${args.target} to ${flags.env}`);
return { status: "deployed" };
}
}See [examples/core.md](examples/core.md) Pattern 1-5 for complete flag types, args, output methods, and error handling.
---
Ink components are React functional components using hooks for input, app lifecycle, and focus.
import React, { useState } from "react";
import { Box, Text, useInput, useApp } from "ink";
interface SelectorProps {
items: string[];
onSelect: (item: string) => void;
}
export const Selector: React.FC<SelectorProps> = ({ items, onSelect }) => {
const [index, setIndex] = useState(0);
const { exit } = useApp();
useInput((input, key) => {
if (key.upArrow) setIndex((i) => Math.max(0, i - 1));
if (key.downArrow) setIndex((i) => Math.min(items.length - 1, i + 1));
if (key.return) onSelect(items[index]);
if (input === "q") exit();
});
return (
<Box flexDirection="column">
{items.map((item, i) => (
<Text key={item} bold={i === index}>
{i === index ? "> " : " "}
{item}
</Text>
))}
</Box>
);
};See [examples/core.md](examples/core.md) Pattern 6-8 for styling, layout, and @inkjs/ui components.
---
The integration pattern: oclif command renders an Ink component and awaits its completion.
import { Command, Flags } from "@oclif/core";
import { render } from "ink";
import React from "react";
import { SetupWizard } from "../components/setuThe official skills marketplace for Agents Inc. 230+ skills covering everything from React and Prisma to Redis, ElevenLabs, and infrastructure tooling. Pick the skills that match your stack and install them via Claude Code. Need more control?
Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming,…
LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking,…
Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client…
Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output,…
Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning,…
Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling,…
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.