rayfin-cli-ux
Skill646 starsChanged 25 days agoMITView on GitHub
Mandatory for Rayfin CLI UX work. Load before designing, speccing, implementing, or reviewing CLI commands, flags, output, or errors.
- Reads credentials
We split this skill into the rules it gives an agent
12 rules. About 0 are common, 3 are distinctive, and 9 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 19
New or migrated commands: use a common/src/workflows/<name>/ workflow returning a typed Result<T>, with a thin Layer-1 Commander wrapper …
- Very specific: line 20
Legacy (un-migrated) commands: use output-mode.ts (modeLog/emitJson/resolveOutputMode).
- Distinctive: line 21
When this skill and the architecture RFC disagree, the RFC wins.
- Very specific: line 106
Create command file in packages/tools/cli/src/commands/.
- Very specific: line 107
Import utilities from ../utils/output-mode.js.
- Very specific: line 108
Add --json, -y/--yes, --verbose options.
- Very specific: line 109
Add --dry-run/--force when applicable.
- Distinctive: line 111
Follow the standard action handler skeleton above.
- Very specific: line 143
Every tasks.md for a CLI-touching OpenSpec change MUST begin with this block:
- Distinctive: line 160
Before submitting, verify none of the NEVER/ALWAYS rules are violated:
- Very specific: line 162
NEVER: bare console.log (R2), prompt when non-interactive (R5), partial/multiple JSON (R6), error without recovery (R3), destructive …
- Very specific: line 163
ALWAYS: action-oriented progress text (R8), standard flag names (R7), mirror dev/up nouns, regenerate .env.local after lifecycle commands.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Rayfin CLI UX Guidelines
Standards for consistent, high-quality CLI experiences in @microsoft/rayfin-cli.
Full reference: references/cli-ux-guidelines.md — load on demand for depth, examples, and rationale.
Architecture Status
These rules define what a good CLI experience must deliver — they stay in force regardless of wiring.
How output is wired is mid-migration to the workflow + adapter architecture (docs/rfc/rayfin-tools-architecture.md, tracked in rayfin-tools-architecture-migration.md).
- New or migrated commands use a
common/src/workflows/<name>/workflow returning a typedResult<T>, with a thin Layer-1 Commander wrapper rendering viaLogger/Progressadapters selected from--output <mode>. Do not importoutput-mode.ts, branch on raw--json/--verbose, or useCliHandledError/process.exit. - Legacy (un-migrated) commands use
output-mode.ts(modeLog/emitJson/resolveOutputMode). This machinery is scheduled for removal in Phase 6. - When this skill and the architecture RFC disagree, the RFC wins.
Constitutional Rules
Non-negotiable for every CLI command. Each rule has a stable ID (R1–R12) for cross-referencing.
| ID | Rule | One-liner |
| R1 | Three output modes | Every command supports interactive, plain, and json. See reference §1. |
| R2 | No console.log | All output goes through mode-aware utilities (or v2 Logger/Progress adapters). |
| R3 | Recovery hints | Every ❌ error includes an indented next-step action. |
| R4 | --force for destructive ops | Operations risking data loss fail by default; --force opts in. |
| R5 | Respect non-interactive | No prompts when --yes, non-TTY stdin, or CI=true. |
| R6 | Valid JSON output | --json → exactly one JSON object on stdout, no ANSI/emoji. --verbose + --json → reject with error. |
| R7 | Standard flags | --output <mode> (canonical), --json (shorthand), -y/--yes, --verbose, --dry-run, --force, --env-file <path>. |
| R8 | Clear progress text | Every step uses ProgressIndicator with action-oriented text. |
| R9 | No credentials/PII | Truncate tokens, use boolean indicators, never log emails/OIDs. |
| R10 | --dry-run explains | Lists planned ops without mutations; viable previews exit 0, validation failures exit nonzero. |
| R11 | --help everywhere | .description() on every command/option/argument. See reference §5 for canonical descriptions. |
| R12 | Semantic exit codes | 0 = success, 1 = error, 2 = cancelled. |
Decision Shortcuts
- "Command or flag?" → Changes what = command. Changes how = flag.
- "
devorup?" → Local Docker / no auth →dev. Authenticated cloud →up. - "Child service or connector?" → Owned/deployed with app →
rayfin <service> init. External →rayfin connector add. - "
initcreate this?" → Only minimal base app (auth, data, static). Otherwise explicit follow-up command. - "Implicit?" → Only required system actions in
dev/up. User-facing = explicit.
Common Patterns (keep — action-oriented)
Standard action handler (legacy path)
.action(async (cmdOptions) => {
const mode = resolveOutputMode({ json: cmdOptions.json });
const interactive = isInteractive({ yes: cmdOptions.yes });
const verbose = createVerboseLogger(cmdOptions.verbose);
try {
// ...work...
if (mode === 'json') {
emitJson({ status: 'success', ...result });
}
} catch (err) {
if (mode === 'json') {
emitJsonError(mode, (err as Error).message);
}
modeError(mode, `❌ ${(err as Error).message}`);
modeError(mode, ' <recovery hint>');
throw new CliHandledError(err);
}
})Error with recovery hint
modeError(mode, '❌ Project name not found in rayfin.yml configuration');
modeError(mode, " Run 'rayfin init' to create a new project configuration");
throw new CliHandledError(new Error('...'));Progress step
const spinner = showProgress('Deploying configuration', '🔄', mode);
try {
await doWork();
spinner.succeed('Configuration deployed');
} catch (err) {
spinner.fail('Configuration deployment failed');
throw err;
}Implementing a New Command
First decide: v2 workflow or legacy path? New commands target the workflow + adapter architecture (see migration plan). The legacy steps below are for un-migrated commands only.
V2 command (preferred): orchestration in common/src/workflows/<name>/, Commander .action() is a thin wrapper that parses → builds deps → calls workflow → renders Result via adapters → maps exit code.
Legacy path (un-migrated commands):
- Create command file in
packages/tools/cli/src/commands/. - Import utilities from
../utils/output-mode.js. - Add
--json,-y/--yes,--verboseoptions. - Add
--dry-run/--forcewhen applicable. - Wrap progress in
ProgressIndicator. - Follow the standard action handler skeleton above.
- Register in parent
index.ts.
Reviewing a Command (checklist by rule ID)
- R1 — supports interactive, plain, json modes
- R2 — no bare
console.log - R3 — every
❌has a recovery hint - R6 —
--jsonemits valid JSON only; no ANSI/emoji - R4 — destructive ops gated on
--force - R5 — prompts respect
isInteractive() - R8 — progress uses
ProgressIndicatorwith action text - R10 —
--dry-runlists ops without mutations and uses a semantic exit code - R9 — no PII in verbose output
- R11 —
--helpdescriptions present, canonical wording for standard flags - R12 — exit codes are semantic
- Spec includes user intent, behavior contract, validation/failures, error wording, examples, cross-cutting impacts
Command Topology: dev vs up
See reference §12 for full rationale and patterns.
Key rules:
- Mirror nouns under both
devandupwhen capability exists in both worlds. dev= local Docker, offline, single env, lifecycle via flags (--stop,--down, etc.).up= Fabric cloud, requires auth (except inspection), multi-env via subcommands.devnever authenticates. Inspection commands (status,list) never block on auth.--forcemeans "allow destructive schema changes" — not "skip prompt" (that's--yes).
Pre-flight Checklist (OpenSpec CLI changes)
Every tasks.md for a CLI-touching OpenSpec change MUST begin with this block:
## Pre-flight
- [ ] Loaded `.github/skills/rayfin-cli-ux/SKILL.md`. Cite one rule applied: <ID and restatement>.
- [ ] Loaded `.github/skills/rayfin-cli-ux/references/cli-ux-guidelines.md`. Cite one section: <name>.
- [ ] Every new/changed command, option, argument has a `.description()` (R11).
- [ ] Every `❌` error has a recovery hint (R3).
- [ ] All three output modes covered in scenarios (R1).
- [ ] Destructive ops gated on `--force` (R4).
- [ ] Non-interactive behavior preserved (R5).
- [ ] `dev` vs `up` topology rules respected if adding lifecycle commands.Final Scan (Guardrails)
Before submitting, verify none of the NEVER/ALWAYS rules are violated:
- NEVER: bare
console.log(R2), prompt when non-interactive (R5), partial/multiple JSON (R6), error without recovery (R3), destructive without--force(R4), PII in logs (R9), emoji outside interactive (R1), mutating API calls in dry-run (R10), auth indevcommands. - ALWAYS: action-oriented progress text (R8), standard flag names (R7), mirror
dev/upnouns, regenerate.env.localafter lifecycle commands.
Dry-run reads require an explicit documented contract.
rayfin up authenticates and reads workspace metadata so its preview can identify the resolved target; it validates local static inputs first and never runs builds or deployment writes.
See reference section 7 for this exception to the otherwise offline dry-run contract.
In this repository76 other files it gives its agents.
- common/config/typedoc/AGENTS.mdAGENTS.md
- docs/site/AGENTS.mdAGENTS.md
- .github/skills/react-best-practices/AGENTS.mdAGENTS.md
- packages/docgen/AGENTS.mdAGENTS.md
- packages/guide/AGENTS.mdAGENTS.md
- packages/host-docs/AGENTS.mdAGENTS.md
- packages/tools/AGENTS.mdAGENTS.md
- packages/tools/cli/AGENTS.mdAGENTS.md
- packages/tools/cli/assets/agent-files/AGENTS.mdAGENTS.md
- packages/tools/common/AGENTS.mdAGENTS.md
- packages/tools/docs-lib/AGENTS.mdAGENTS.md
- packages/tools/mcp/AGENTS.mdAGENTS.md
- packages/tools/vscode/AGENTS.mdAGENTS.md
- packages/typescript-sdk/AGENTS.mdAGENTS.md
- packages/typescript-sdk/auth/AGENTS.mdAGENTS.md
- packages/typescript-sdk/core/AGENTS.mdAGENTS.md
- packages/typescript-sdk/data/AGENTS.mdAGENTS.md
- packages/typescript-sdk/storage/AGENTS.mdAGENTS.md
- packages/udf/udf-worker-extension/AGENTS.mdAGENTS.md
- samples/data-app/AGENTS.mdAGENTS.md
- samples/getting-started-auth/AGENTS.mdAGENTS.md
- samples/notes-app/AGENTS.mdAGENTS.md
- samples/todo-app/AGENTS.mdAGENTS.md
- samples/universal-app/template/AGENTS.mdAGENTS.md
- samples/welcome-app-react-auth/AGENTS.mdAGENTS.md
- samples/welcome-app-react-no-auth/AGENTS.mdAGENTS.md
- samples/welcome-app-typescript/AGENTS.mdAGENTS.md
- hotfix-releaseSkill
- launch-vscode-extensionSkill
- openspec-apply-changeSkill
- openspec-archive-changeSkill
- openspec-bulk-archive-changeSkill
- openspec-continue-changeSkill
- openspec-exploreSkill
- openspec-ff-changeSkill
- openspec-new-changeSkill
- openspec-onboardSkill
- openspec-sync-specsSkill
- openspec-verify-changeSkill
- privacy-dfdSkill
- vercel-react-best-practicesSkill
- react-clean-architectureSkill
- run-cli-e2e-locallySkill
- vscode-react-webview-architectureSkill
- vscode-webview-trpc-messagingSkill
- rayfin-connectorsSkill
- rayfin-functionsSkill
- rayfinSkill
- rayfin-storageSkill
- rayfin-getting-startedSkill
- app-designSkill
- app-validationSkill
- dax-authoringSkill
- fabric-cliSkill
- fabric-sdkSkill
- playwright-cliSkill
- query-designSkill
- schema-discoverySkill
- visualsSkill
- analyticsSkill
- The first 60 shown.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

