Skip to content
Back to skills

Cli Creator

ASecurity

Cria e refatora CLIs no ecossistema Ravi, aterrado na arquitetura REAL do runtime. Cobre as duas famílias (CLI nativo do Ravi = classe com decorators auto-descoberta; CLI standalone/domínio = binário próprio), o contrato de decorators (@Group/@Command/@Arg/@Option/@CommandAccess/@Returns/@Scope), output agent-first (mandato --json, envelopes canônicos, exit 0/1/2/3, ContractError, IDs semânticos), paginação real (páginas limitadas 50/500 + nextCommand), gate de --help padrão-ouro, e os meta-t...

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 20, 2026
ai-agentstypescriptgosqlgitapi

Works with

  • cursor
  • cli
  • api

Security analysis

A100/100

Scanned October 20, 2026

npx -y skills add filipexyz/ravi --skill cli-creator --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Cli Creator?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Cli Creator
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/filipexyz-cli-creator/badge)](https://www.skillsdirectory.com/skills/filipexyz-cli-creator)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: cli-creator
description: >-
  Cria e refatora CLIs no ecossistema Ravi, aterrado na arquitetura REAL do runtime.
  Cobre as duas famílias (CLI nativo do Ravi = classe com decorators auto-descoberta;
  CLI standalone/domínio = binário próprio), o contrato de decorators
  (@Group/@Command/@Arg/@Option/@CommandAccess/@Returns/@Scope), output agent-first
  (mandato --json, envelopes canônicos, exit 0/1/2/3, ContractError, IDs semânticos),
  paginação real (páginas limitadas 50/500 + nextCommand), gate de --help padrão-ouro,
  e os meta-testes de CI que são a lei do repo. Use quando criar nova ferramenta CLI,
  refatorar CLI existente, padronizar comandos, ou integrar CLI ao runtime com
  RAVI_CONTEXT_KEY. Skill standalone — o essencial de --help e de skill→cli está inline;
  cli-help-engineering e dissolving-skills-into-cli-help são aprofundamento opcional.
  NÃO cobre: criar a skill que ensina o CLI (use skill-creator).
---

# CLI Creator — Ciclo Completo de CLIs no Ravi

**Função:** transformar um problema operacional num CLI correto, agent-first e descobrível — usando a arquitetura REAL do runtime do Ravi, não um modelo genérico. Todo padrão aqui foi spike-testado no código vivo (`ravi-src-dev`); nada é aspiracional.

**Esta skill é STANDALONE:** o essencial das 3 capacidades (criar CLI, `--help` padrão-ouro, skill→cli) está todo inline. As companion citadas (`cli-help-engineering`, `dissolving-skills-into-cli-help`) são **aprofundamento opcional, não dependência** — um agente que só tenha esta skill consegue os 3.

> ⚠️ Antes de tudo — a armadilha nº1: **NÃO existe** no CLI `ravi` um comando `cli-manifest` por-CLI nem um `tools cli-register`. Discovery é por **reflexão automática de decorators**. Se você escrever `program.command(...)` + `cli-manifest` + registro manual, está construindo a coisa errada.

---

## 1. DECIDIR primeiro: qual das 2 famílias

| Família | Quando | Como se constrói |
|---|---|---|
| **CLI nativo do Ravi** (`ravi <grupo>`) | O comando faz parte do runtime Ravi (agents, tasks, contexto, etc.) | Classe com decorators em `src/cli/commands/<grupo>.ts` → barrel auto-descobre. **Padrão default.** |
| **CLI standalone / de domínio** (ex: `sde`, `binance-cli`) | Ferramenta externa/de negócio com binário próprio, fora do processo `ravi` | Pacote próprio em `bun + commander` clássico, seu próprio `--help`/manifest |

O resto desta skill foca no **nativo do Ravi** (o caso comum). Para standalone, valem as mesmas regras de output/erro/help, mas SEM decorators/barrel.

---

## 2. Invariantes (não-negociáveis)

1. **Problema antes do parser** — modele os dados/decisão que o CLI destrava ANTES de desenhar comandos.
2. **Ferramenta antes do agente** — o CLI nasce antes da skill que o ensina.
3. **Contrato de decorators** (nativo Ravi) — um comando só é um "tool" de primeira classe com `@Command` + `@CommandAccess` + `@Returns`.
4. **Agent-first** — o consumidor é um agente autônomo com contexto escasso: alto sinal, IDs semânticos, `--json`, erros que se autocorrigem.
5. **RAVI_CONTEXT_KEY** — CLIs que rodam dentro do Ravi usam o contexto como credencial canônica.
6. **Contrato global** — `.ravi/specs/cli/SPEC.md` é normativo para envelopes, taxonomia,
   confirmação, transportes, autorização relacional (REBAC), auditoria e
   sanitização. A spec do domínio só
   classifica as operações e registra exceções/checks próprios.

---

## 3. Fluxo canônico (7 passos)

### 1. Brainstorm
Qual problema resolve? Qual decisão melhora? Quais entidades/artefatos/lineage? O que persistir e por quê?

### 2. Mapa de implementação (GATE — apresentar à aprovação humana, HITL)
- [ ] Verifiquei se já existe (`ravi tools search "<intenção>"`, `sde --help`, `ravi skills list`)
- [ ] Li a doc da interface de programação (API) do começo ao fim (se integra API externa)
- [ ] Defini domínio de negócio (financeiro, frete, estoque…)
- [ ] Escolhi storage: SQLite por domínio se há lineage/cache/auditoria; senão stateless

Apresentar o mapa ao **aprovador humano (HITL)**. NUNCA implementar sem aprovação. *(O HITL é quem o runtime/route define como owner — pode ser o RM, o dono do agente, ou o revisor. A skill é genérica: fala HITL, nunca uma pessoa específica.)*

### 3. Escrever o comando (contrato real de decorators)
Nativo Ravi = classe `@Group` com métodos `@Command` em `src/cli/commands/<grupo>.ts`. Template REAL (de `tasks.ts`):

```typescript
import "reflect-metadata";   // OBRIGATÓRIO: 1ª linha do arquivo. Sem ele os decorators viram no-op silencioso — compila mas o comando NÃO registra (mesmo modo de falha da arquitetura fictícia antiga).

@Group({ name: "tasks", description: "Task runtime for dispatching work to Ravi agents", scope: "open" })
export class TaskCommands {
  @Command({ name: "create", description: "Create a tracked task; ..." })
  @CommandAccess({ kind: "mutate", resource: "tasks", action: "create", risk: "medium" })
  @Returns(taskCreateReturnSchema)
  async create(
    @Arg("title", { description: "Short task title" }) title: string,
    @Option({ flags: "--priority <level>", description: "low|normal|high|urgent", defaultValue: "normal" }) priority?: string,
    @Option({ flags: "--json", description: "Print raw JSON result" }) asJson?: boolean,
  ) {
    // ... lógica ...
    if (asJson) console.log(JSON.stringify(payload, null, 2));
    else console.log(/* view humana */);
    return payload;            // <- o return é o que o kit de desenvolvimento (SDK)/gateway serializa
  }
}
```

Os 8 decorators reais (`src/cli/decorators.ts`): `@Group` `@Command` `@Arg` `@Option` `@CommandAccess` `@Returns` `@Scope` `@CliOnly`.
- **`@CommandAccess({ kind, resource, action, risk })`** — obrigatório em quase todo comando; alimenta o permission-provider. `kind`: `read`|`mutate`. `risk`: `low`|`medium`|`high`|`destructive`.
- **`@Scope` / `scope` no `@Group`** — gate grosso de exposição; default é
  `admin`. Enum real (`decorators.ts`): `superadmin`|`admin`|`writeContacts`|`resource`|`open`.
  `open` não significa read-only e nunca substitui o `@CommandAccess` por operação.
- **`@Returns(zodSchema)`** — SEM isso o comando não vira tool tipado do SDK. Schema inline (como acima) ou em massa via `declareCommandReturns(Classe, { metodo: schema })`. Primitivos reutilizáveis em `src/cli/return-schemas.ts`: `cliOffsetPaginationSchema`, `cliCursorPageSchema`, `mutationAckSchema`, `jsonValueSchema`.
- **`@Returns.binary()`** — para resposta binária (blob) no lugar do schema Zod.
- **`@CliOnly()`** — exclui o comando da superfície SDK (comando só-humano).

### 4. Descoberta = automática (NÃO manual)
1. Criar `src/cli/commands/<grupo>.ts` com a classe `@Group`.
2. Rodar `bun run gen:commands` → regenera o barrel `src/cli/commands/index.ts` (auto-gerado, **NÃO editar à mão**).
3. Pronto. `registerCommands` lê os decorators e monta tudo (inclusive enforcement de scope/access). Colisão de `(grupo, comando)` **estoura no boot** — bug pego cedo.

Sem passo de "registrar manifest". A reflexão faz. Verifica com: `ravi tools show <grupo>_<comando>` e `ravi tools manifest`.

### 5. Integração runtime (RAVI_CONTEXT_KEY) — se aplicável
- Pai emite `ravi context issue <cli> --allow <cap> --ttl <dur>` → filho recebe `RAVI_CONTEXT_KEY` (única credencial, formato `rctx_*`).
- CLI valida com `ravi context whoami` / `check <perm> <objType> <objId>`.
- Capability mínima, tempo de vida (TTL) curto, audit completo. (Esta parte a skill antiga já acertava.)

### 6. Spike + testes (GATE — antes de entregar)
Rodar CADA comando com input válido / inválido / faltando. Todos os checks abaixo têm que PASSAR (senão corrigir + re-testar; NUNCA entregar com bug):
- [ ] Output correto com input válido
- [ ] Erro acionável com input inválido (com o próximo comando sugerido)
- [ ] Mensagem de uso com input faltando
- [ ] `--json` retorna JSON válido
- [ ] Exit code correto (`0` sucesso, `1` falha, `2` uso, `3` bloqueio por política)
- [ ] `--help` passa no **gate padrão-ouro** (§5 abaixo)

**A lei do repo = meta-testes de CI** (não o spike manual). O repo tem `json-coverage.test.ts` (todo comando finito DEVE expor `--json`) e `pagination-coverage.test.ts` (todo `list`/`ls` DEVE ser paginado). Teste co-locado em `src/cli/commands/<grupo>.test.ts`, roda em `bun:test` com `mock` + `await import(...)`. Se seu CLI não conformar, **a CI fica vermelha.**

### 7. Entrega (HITL + doc por domínio)
1. Perguntar ao **HITL**: "CLI implementado, testado e descoberto. Disponibilizo pra qual agente?"
2. Documentar o CLI na skill do **DOMÍNIO DE NEGÓCIO**, NUNCA por ferramenta/API. Extrato bancário → skill financeira, nunca "banco-inter".

---

## 4. Output agent-first (regras duras)

- **`stdout` = dado/envelope em JSON. `stderr` = log/progresso e erro textual.** Em
  `--json`, uma falha imprime exatamente um envelope canônico no stdout e nada
  acrescenta `Error:`, stack ou uma segunda renderização.
- **Mandato `--json`** — todo comando finito expõe `--json`, imprime `JSON.stringify(payload, null, 2)` E `return`a o payload. É CI-enforced.
- **Taxonomia = `0/1/2/3`.** `0` sucesso; `1` execução/provider/not-found;
  `2` uso inválido; `3` bloqueio seguro pela política de confirmação. Exit 3 é
  `blocked`, não uma execução `failed`.
- **Falha contratual = `contractFail(...)`.** Passe `op`, código semântico,
  `asJson`, `exitCode` e detalhes acionáveis. Ele lança `ContractError`; CLI, tool e
  gateway/SDK preservam o mesmo envelope e taxonomia. `fail()` é legado e não
  deve nascer em um CLI novo ou em um caminho declarado migrado.
- **Confirmação baseada em risco.** `contractDryRun(...)` + `--execute` só para
  publicação/envio externo, mutação relevante em provider, destruição difícil
  de recuperar, execução disparada ou custo acima de limite conhecido. Escrita
  local/reversível e custo trivial sem estimativa rodam direto.
- **Autorização ≠ confirmação.** Toda operação com efeito usa
  `@CommandAccess({ kind: "mutate" })`, mesmo sem `--execute`; leitura pura usa
  `read`. O dry-run ocorre depois da autorização/validação e antes de qualquer
  DB write, provider, recurso, evento, fila ou worker.
- **Alto sinal** — retorne os campos que informam a próxima ação (`name`, `status`, `url`); corte ruído (`uuid` cru, `mime_type`, `256px_url`) salvo se pedido.
- **IDs semânticos** — resolva UUID pra nome legível no output; melhora a precisão do agente.
- **Erros acionáveis** — RUIM: `Error: EACCES`. BOM: `Invalid priority: X. Use low|normal|high|urgent` — sempre com o COMO corrigir / o próximo comando. Retorne o contexto que o agente gastaria uma chamada pra buscar.

---

## 5. `--help` padrão-ouro (GATE — o contrato completo)

`--help` NÃO é lista de flags — é o **contrato comportamental completo** da CLI,
a fonte única de verdade (SSoT). Um agente sem contexto tem que dirigir a CLI
só lendo o help ("teste do agente cego"). **Bloqueia entrega se falhar.** **O
essencial pra escrever um `--help` padrão-ouro está inline abaixo — esta skill
é standalone.** Aprofundamento opcional (building blocks, tipologias):
`cli-help-engineering`, se disponível.

**Padrão-ouro de referência:** use o excerto autocontido abaixo. Se `sde` estiver
disponível no ambiente, rode `sde tiny pedido-montar-json --help` para comparar
a estrutura completa; a ausência desse CLI externo não bloqueia o uso desta skill.

**Mínimo por comando (todo CLI):**
- [ ] Descrição de 1 linha + Usage com `<obrigatório>`/`[opcional]`
- [ ] Cada flag: curta+longa, `<tipo>`, descrição, **default**, **choices** quando restrito
- [ ] **EXEMPLOS reais copiáveis** (2+) — o sinal mais forte pro agente
- [ ] Nota de output (`--json` + shape) + exit codes

**As 14 seções canônicas** (no `addHelpText('after', ...)` do orquestrador; leitura-pura pode omitir 5-9):
`3. USE` (quando é a escolha certa) · `4. NÃO USE` (+ pointer alternativo) · `5. REGRAS HARD` (constraints que a CLI bloqueia) · `6. HITL OBRIGATÓRIO` · `7. VALIDAÇÕES AUTOMÁTICAS` (ref arquivo:linha) · `8. LIFECYCLE` (estados+transições) · `9. HITL TEMPLATE` (mensagem literal pro humano) · `10. EXAMPLES` · `11. ON ERROR` (código→causa→fix) · `12. PIPELINE` (upstream→esta→downstream) · `13. SEE ALSO` · `14. FORMATO` (datas/IDs/valores) · `15. DEBUG` · `16. FONTES` (datas + path do source).

**Exemplo real de `--help` anotado** (excerto do padrão-ouro `sde tiny pedido-montar-json`). Repara: cada flag carrega `tipo | significado | origem | constraint | default`, e o rodapé traz as seções — não é "lista de flags", é o contrato inteiro:
```
--lista-preco <id>   enum | 629174891="SITE (+39%)" | 601762293="Oficial (+32.25%)" (default: 629174891)
--parcelas <dias>    string | intervalo em DIAS. LIMITE: <R$1k=max 2x, R$1k-3k=3x, >R$3k=4x (default: 4)

CUSTO / SEGURANÇA
  • READ-ONLY: monta o JSON, NÃO submete à API. Idempotente, seguro p/ retry.
  • Destrutivo? NÃO — o passo destrutivo do pipeline é `pedido-incluir`.
USE          ✓ Cliente existe + SKU cadastrado + balcão padrão
NÃO USE      ✗ Item sem cadastro → `pedido-incluir` direto   ✗ Marketplace → CLI dedicada
REGRAS HARD  • Atacado requer subtotal > R$2.000   • Frete=0 + subtotal<R$500 → alerta
```
Seções obrigatórias sempre: `USE`, `NÃO USE`, `EXAMPLES`, `ON ERROR`, `FONTES`.
As de risco (`REGRAS HARD`, `HITL`, `LIFECYCLE`) entram quando o efeito real exige
restrição, confirmação ou explicação de transição — não pela mera existência de escrita.

**Cristalizar a precedência NO --help** (senão agentes divergem em conflito):
```
REGRAS HARD > INPUT HUMANO > CONVENÇÕES > REGRAS AGENTS.MD
```

**Validação empírica (obrigatória):** antes de escrever o --help, rodar `--help` de TODAS as CLIs adjacentes citadas + 1 chamada real à API. Sem isso = nomes inventados + doc-IA-genérica.

---

## 6. Paginação real (contrato do repo)

NÃO é "busca todas as páginas". É paginação **limitada** com próximo passo explícito. Helpers em `src/cli/pagination.ts`:
- `parseCliListLimit` (default **50**, máx **500**), `parseCliListOffset` (default 0)
- `paginateCliItems(items, {limit, offset})` → `{ items, total, limit, offset }`
- `buildCliOffsetPagination({ baseCommand, limit, offset, returned, total })` → monta o `nextCommand`

Shape de retorno real (spike verificado — `ravi agents list --json --limit 2`):
```json
{ "total": 81,
  "pagination": { "limit": 2, "offset": 0, "returned": 2, "total": 81,
                  "hasMore": true, "nextOffset": 2,
                  "nextCommand": "ravi agents list --json --limit 2 --offset 2" },
  "items": [ ... ] }
```
Para sets grandes/temporais use cursor (`src/cli/listing.ts` + `cliCursorPageSchema`). Todo `list`/`ls` precisa de `--limit`+`--offset` OU `--cursor` (CI-enforced).

---

## 7. Anti-patterns (parar e corrigir)

1. **Arquitetura errada** — `program.command()` + `cli-manifest` + `tools cli-register` para um CLI nativo. Não existe. Use decorators + barrel.
2. **Comando sem `@Returns`** — não vira tool tipado do SDK.
3. **Comando finito sem `--json`** ou `list` sem paginação — CI vermelha.
4. **Wrap 1:1 de endpoint de API** como comando — baixo sinal, queima contexto. Consolide fluxos.
5. **Dump de dataset inteiro** — pagine/filtre; não force o agente a ler tudo token-a-token.
6. **ID críptico como output primário** (UUID cru) — degrada retrieval do agente.
7. **Output instável entre versões** (renomear campo JSON, reordenar coluna) — quebra todo consumidor.
8. **`--help` fino/sem exemplo** — falha o teste do agente cego.
9. **Segredo em flag ou env var** — vaza em `ps`/histórico/processos-filho. Use arquivo de credencial / stdin.
10. **`process.exit` cru ou `fail()` legado** num handler novo — quebra a
    paridade entre processo/tool/gateway. Use `contractFail()`/`contractDryRun()`.
11. **Editar o barrel `commands/index.ts` à mão** — é auto-gerado. Rode `gen:commands`.

---

## 8. Skill → CLI: injetar conhecimento no `--help` (ferramenta de anotação)

Quando o CLI existe e tem regra de negócio no source que o `--help` não mostra, migra-se o conhecimento tribal da skill PRA o `--help` — o CLI vira a SSoT e a skill vira **STUB** (triggers + pointer, nunca deletar). Os passos essenciais estão inline abaixo (standalone); aprofundamento opcional: `dissolving-skills-into-cli-help` (validado em 4 skills do jarvis).

**Mecanismo real (anotar o CLI), POR FAMÍLIA:** CLI **nativo Ravi** → setar a string `helpAfter` no `@Command` (o `registry.ts` chama `addHelpText('after', helpAfter)` por baixo). CLI **standalone/commander** → encadear `.addHelpText('after', ...)` direto. Nos dois, escrever as 14 seções canônicas (§5) ali — o `--help` passa a carregar REGRAS HARD, HITL template literal, lifecycle e error mapping, não só flags.

**Classificar cada pedaço da skill em 5 buckets:** **A** → AGENTS.md (roteamento/triggers) · **B** → `--help` do orquestrador (regras hard, HITL, lifecycle) · **C** → `--help` dos subcomandos (regras locais, formato) · **D** → profile de task (dispatch denso) · **E** → vault (knowledge denso, multi-fase).

**Sequência operacional (o processo completo, condensado):**
1. **ANTES:** rodar o `--help` atual (baseline) + rodar o CLI com args reais (ver o JSON de output) + ler a skill inteira + classificar cada item nos 5 buckets + rodar `--help` de TODAS as CLIs que vai citar (cross-CLI empírica — **zero invenção de nome**).
2. **APPLY:** backup do source (nativo: `git stash`/branch; standalone: `cp index.ts index.ts.bak-<ts>`) → localizar o comando (nativo: método `@Command`; standalone: `program.command('<nome>')`) → migrar buckets **B+C** pro help (nativo: string `helpAfter`; standalone: `addHelpText('after', ...)`) escrevendo as 14 seções → validar que `--help` renderiza **E** o CLI ainda executa.
3. **PÓS:** skill vira **STUB** (mantém triggers + pointer, nunca deletar) → AGENTS.md aponta `→ TODAS regras em <cli> --help` → **simulação real**: operador monta 1 output completo só com o `--help`, sem a skill → archive a skill (só após simulação verde) → delete definitivo **SÓ com "sim" explícito do HITL** (ação destrutiva).

**Fecha o triângulo:** `cli-creator` (constrói) → `cli-help-engineering` (método do `--help`) → `dissolving-skills-into-cli-help` (injeta o conhecimento como anotação). AGENTS.md do operador aponta: `→ TODAS regras em <cli> --help`.

---

## LEMBRETE FINAL
1. **Mapa antes de código, apresentado ao HITL** — genérico, nunca uma pessoa fixa. NUNCA implementar sem aprovação.
2. **Contrato real = decorators + `@Returns` + `@CommandAccess` + `bun run gen:commands`.** Esqueça manifest/register manual — é ficção pro CLI nativo.
3. **`--json` + paginação + `--help` padrão-ouro são gates de CI/entrega**, não opcionais. Cada um foi spike-testado no código vivo.
4. **Taxonomia, confirmação e transportes vêm de `.ravi/specs/cli/`.** Não
   redefina o contrato por domínio nem aplique `--execute` por verbo.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.