Skip to content

Commit bd55f29

Browse files
AbhinRustagiclaude
andauthored
feat(cli): optionally install OpenUI agent skill on project creation (#384)
* feat(cli): optionally install OpenUI agent skill on project creation After scaffolding, `openui create` now prompts whether to install the OpenUI agent skill via `npx skills add`. The skill is agent-agnostic (works with Claude, Cursor, Copilot, Codex, etc.). Adds --skill and --no-skill flags for non-interactive control. Closes #382 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: move skill install to after deps, extract to lib/ Move the skill prompt and installation to run after dependency installation. Extract shouldInstallSkill and runSkillInstall into lib/install-skill.ts for cleaner separation of concerns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8462bc6 commit bd55f29

4 files changed

Lines changed: 72 additions & 7 deletions

File tree

docs/content/docs/api-reference/cli.mdx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ openui create [options]
3131
| Flag | Description |
3232
|---|---|
3333
| `-n, --name <string>` | Project name (directory to create) |
34+
| `--skill` | Install the OpenUI agent skill for AI coding assistants |
35+
| `--no-skill` | Skip installing the OpenUI agent skill |
3436
| `--no-interactive` | Fail instead of prompting for missing input |
3537

3638
When run interactively (default), the CLI prompts for any missing options. Pass `--no-interactive` in CI or scripted environments to surface missing required flags as errors instead.
@@ -41,18 +43,29 @@ When run interactively (default), the CLI prompts for any missing options. Pass
4143
2. Rewrites `workspace:*` dependency versions to `latest`
4244
3. Auto-detects your package manager (npm, pnpm, yarn, bun)
4345
4. Installs dependencies
46+
5. Optionally installs the [OpenUI agent skill](/docs/openui-lang/agent-skill) for AI coding assistants (e.g. Claude, Cursor, Copilot)
4447

4548
The generated project includes a `generate:prompt` script that runs `openui generate` as part of `dev` and `build`.
4649

50+
**Agent skill**
51+
52+
When run interactively, `openui create` asks whether to install the OpenUI agent skill. The skill teaches AI coding assistants how to build with OpenUI Lang — covering component definitions, system prompts, the Renderer, and debugging.
53+
54+
Pass `--skill` or `--no-skill` to skip the prompt. In `--no-interactive` mode the skill is skipped unless `--skill` is explicitly passed.
55+
4756
**Examples**
4857

4958
```bash
50-
# Interactive — prompts for project name
59+
# Interactive — prompts for project name and skill installation
5160
openui create
5261

5362
# Non-interactive
5463
openui create --name my-app
5564
openui create --no-interactive --name my-app
65+
66+
# Explicitly install or skip the agent skill
67+
openui create --name my-app --skill
68+
openui create --name my-app --no-skill
5669
```
5770

5871
## `openui generate`

packages/openui-cli/src/commands/create-chat-app.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import * as fs from "fs";
33
import * as path from "path";
44

55
import { detectPackageManager } from "../lib/detect-package-manager";
6+
import { runSkillInstall, shouldInstallSkill } from "../lib/install-skill";
67
import { resolveArgs } from "../lib/resolve-args";
78

89
export interface CreateChatAppOptions {
910
name?: string;
11+
skill?: boolean;
1012
noInteractive?: boolean;
1113
}
1214

@@ -93,6 +95,11 @@ export async function runCreateChatApp(options: CreateChatAppOptions): Promise<v
9395
process.exit(1);
9496
}
9597

98+
const installSkill = await shouldInstallSkill(options.skill, !options.noInteractive);
99+
if (installSkill) {
100+
runSkillInstall(targetDir);
101+
}
102+
96103
const devCmd =
97104
runner === "pnpm dlx"
98105
? "pnpm"
@@ -102,13 +109,13 @@ export async function runCreateChatApp(options: CreateChatAppOptions): Promise<v
102109
? "bun"
103110
: "npm";
104111

105-
console.info(getStartedMessage(name, devCmd));
112+
console.info(getStartedMessage(name, devCmd, installSkill));
106113
}
107114

108-
const getStartedMessage = (name: string, devCmd: string) =>
115+
const getStartedMessage = (name: string, devCmd: string, skillInstalled: boolean) =>
109116
`
110117
Done!
111-
Get started:
118+
Get started:
112119
113120
cd ${name}
114121
@@ -118,4 +125,4 @@ Add your API key to .env:
118125
OPENAI_API_KEY=sk-your-key-here
119126
120127
${devCmd} run dev
121-
`;
128+
${skillInstalled ? "\nThe OpenUI agent skill was installed.\nAI coding assistants will use it to help you build with OpenUI.\n" : ""}`;

packages/openui-cli/src/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,15 @@ program
1414
.command("create")
1515
.description("Scaffold a new Next.js app with OpenUI Chat")
1616
.option("-n, --name <string>", "Project name")
17+
.option("--skill", "Install the OpenUI agent skill for AI coding assistants")
18+
.option("--no-skill", "Skip installing the OpenUI agent skill")
1719
.option("--no-interactive", "Fail with error if required args are missing")
18-
.action(async (options: { name?: string; interactive: boolean }) => {
19-
await runCreateChatApp({ name: options.name, noInteractive: !options.interactive });
20+
.action(async (options: { name?: string; skill?: boolean; interactive: boolean }) => {
21+
await runCreateChatApp({
22+
name: options.name,
23+
skill: options.skill,
24+
noInteractive: !options.interactive,
25+
});
2026
});
2127

2228
program
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { execSync } from "child_process";
2+
3+
export async function shouldInstallSkill(
4+
option: boolean | undefined,
5+
interactive: boolean,
6+
): Promise<boolean> {
7+
if (option !== undefined) return option;
8+
if (!interactive) return false;
9+
10+
try {
11+
const { confirm } = await import("@inquirer/prompts");
12+
return await confirm({
13+
message: "Install the OpenUI agent skill for AI coding assistants?",
14+
default: true,
15+
});
16+
} catch (err) {
17+
const { ExitPromptError } = await import("@inquirer/core");
18+
if (err instanceof ExitPromptError) {
19+
process.exit(0);
20+
}
21+
throw err;
22+
}
23+
}
24+
25+
export function runSkillInstall(targetDir: string): void {
26+
console.info("\nInstalling OpenUI agent skill...\n");
27+
try {
28+
execSync("npx -y skills add thesysdev/openui --skill openui -y", {
29+
stdio: "inherit",
30+
cwd: targetDir,
31+
});
32+
} catch {
33+
console.warn(
34+
"\nCould not install the OpenUI agent skill automatically.\n" +
35+
"You can install it manually later with:\n\n" +
36+
" npx skills add thesysdev/openui --skill openui\n",
37+
);
38+
}
39+
}

0 commit comments

Comments
 (0)