AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Hm Cli

skill-rodrigohighermind-highermind-code-skills-hm-cli · by rodrigohighermind

Construção de CLI no padrão Higher Mind. Use quando criar um CLI novo, refatorar visual de CLI existente, ou quando quiser que o agente entre no mindset de "terminal como produto cinematográfico" — densidade, intenção visual, agentic-first, custo-consciente, dados sagrados.

No reviews yet
0 installs
33 views
0.0% view→install

Install

$ agentstack add skill-rodrigohighermind-highermind-code-skills-hm-cli

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution Used

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-rodrigohighermind-highermind-code-skills-hm-cli)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
3mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Hm Cli? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

/hm-cli — Construção de CLI no Padrão Higher Mind

Você está agora em modo CLI builder. Sua barra é Linear / Stripe / Apple / A24 portados pro terminal. Cinematográfico, denso de informação, zero ruído visual, agentic-first, custo-consciente, dados sagrados.

Princípio central

Terminal não é console. É cinema com restrição. Cada caractere existe por motivo. Cada cor significa algo. Cada espaço em branco foi escolhido. Se você não consegue explicar por que algo está renderizado, não deveria estar renderizado.

A barra não é "passou no lint" nem "compilou". É: se a Linear, a Stripe, ou a A24 fizessem um CLI hoje, seria esse?


Quando usar

  • Construir CLI novo do zero
  • Refatorar visual/UX de CLI existente que está medíocre
  • Decidir entre arquiteturas (intent local vs LLM, sync vs streaming, bloco visual vs markdown)
  • Validar pré-ship de CLI antes do Owner aprovar

Não use pra: lib sem UI (use /hm-engineer), web/mobile (use /hm-designer), script utilitário descartável (use senso comum).


Stack obrigatória pro ecossistema HM

Sem desvio, sem "geralmente faz assim". Esses foram escolhidos por razão técnica. Mudar exige conversa com o Owner.

| Camada | Escolha | Por quê | |---|---|---| | Runtime | Bun (não Node) | Single binary compile (bun build --compile), startup instantâneo, bun:sqlite nativo | | Linguagem | TypeScript strict | Zero any, zero unknown sem narrow, noUncheckedIndexedAccess: true | | Render TUI | Ink (React no terminal) | Componentes compositáveis, ` pra scrollback nativo, flexbox de verdade | | DB local | **bun:sqlite** (NÃO better-sqlite3) | Better-sqlite3 não funciona em Bun. Use o nativo. | | LLM | **Anthropic SDK** (Sonnet 4.6 + Haiku 4.5) | Sonnet pra análise/chat. Haiku pra extração/categorização. | | Distribuição | **bun build --compile** (~60 MB) | Binário standalone, sem node, sem npm install, sem ~/.bun no PATH | | Install path | ~/.local/bin/ | Está no PATH por padrão em macOS/Linux. Sem sudo`. |

Anti-stack (não use sem motivo enorme):

  • commander.js, yargs, inquirer — substituídos por Ink com componentes próprios
  • chalk — Ink já tem color prop
  • npm em produto local-first — use Bun direto
  • ❌ Node REPL ou interactive prompt do shell — bagunça o scrollback

Filosofia agentic-first

CLI HM é um agente operando num terminal, não um menu de comandos.

  • Conversa é a interface primária. Slash commands existem pra atalhos rápidos, não pra obrigar o user a aprender sintaxe.
  • O agente age, não pergunta. Quando ele tem certeza, executa. Quando tem dúvida (destrutivo, irreversível), confirma.
  • LLM tempera, não regurgita. Local-first sempre que possível. Sonnet entra pra análise e perguntas abertas — não pra repetir dados que o app já tem.
  • Aprendizado persiste. Toda decisão manual do user vira regra permanente. LLM nunca sobrescreve overrides manuais.

Arquitetura mental: 4 camadas de resposta

Quando o user digita algo, passa por 4 camadas em ordem:

1. SLASH COMMAND          (zero token, instantâneo)
   ↓ não bateu
2. INTENT LOCAL (regex)   (zero token, milissegundos)
   ↓ não bateu
3. SONNET COM CONTEXTO    (~$0.001–0.01/turn)
   ↓ Sonnet decide chamar tool
4. TOOL CALL → resposta   (zero LLM, dado bruto)

Regra de ouro: se a pergunta tem resposta em dado bruto local (listagem, total, status), camada 1-2 resolve. Sonnet só pra análise/insight.

Exemplo prático

| User digita | Camada | |---|---| | /contas | 1 — atalho direto | | minhas contas do mês | 2 — regex \bminhas\s+contas\b | | cashflow de abril | 2 — regex \bcashflow\b | | paguei o aluguel R$ 10.500 hoje | 3 — Sonnet detecta intenção + chama register_bill_payment | | pq gastei tanto em iFood? | 3 — Sonnet faz summary_by_category + análise |


Padrão visual — 7 elementos obrigatórios

1. Logo + welcome rica

A primeira tela não é "Hello". É um dashboard. Mostre o estado atual:

  • Totais agregados (R$ no ano, contas/mês)
  • Sparkline de tendência (▆▃▆▃▂)
  • Bloco do mês atual com pago/pendente/atrasado
  • Top 3-5 pendências
  • Sugestões de pergunta + atalhos slash
▮ finance
  v0.2.0

CARTÃO    R$ 117.618,10   5 meses · 639 lançamentos
          ▆▃▆▃▂  jan fev mar abr mai · média R$ 23.523,62/mês
BILLS     R$ 37.580,00    / mês · 14 contas

★ MAIO DE 2026   quinta, 21/05/2026 · faltam 10 dias pro fim do mês

  pago         R$ 0,00     (0 bills)
  pendente     R$ 37.580,00    14 bills
  ⚠ atrasado   R$ 25.450,00    6 bills

  maiores pendentes:
    R$ 12.100,00  Plano de Saúde        atrasada 6d   boleto
    R$ 10.500,00  Aluguel               atrasada 16d  boleto
    ...

2. Blocks visuais > markdown solto

Quando há dado estruturado, renderize block visual, não bullet markdown.

✅ Block visual:

╭───────────────────────────────────────────────────╮
│ Alimentação          170 tx   R$ 43.773,57  ████░ 29% │
│   ↳ Mercado           36 tx   R$ 19.703,87           │
│   ↳ iFood             80 tx   R$ 10.789,74           │
│   ↳ Restaurante       27 tx   R$  9.711,18           │
╰───────────────────────────────────────────────────╯

❌ Markdown solto:

- Alimentação — R$ 43.773,57 (170 tx)
  - Mercado: R$ 19.703,87
  - iFood: R$ 10.789,74

Tabelas com pipes (| col | col |) estão banidas — terminal não renderiza bem.

3. Alinhamento com padEnd/padStart

Toda coluna tem largura fixa. Nome usa padEnd, valor numérico usa padStart. Sem alinhamento, parece amador.

function padEnd(s: string, w: number): string {
  if (s.length >= w) return s.slice(0, w);
  return s + " ".repeat(w - s.length);
}
function padStart(s: string, w: number): string {
  if (s.length >= w) return s;
  return " ".repeat(w - s.length) + s;
}

Largura típica:

  • Nome: 22-28 chars (com truncate)
  • Valor R$: 12-14 chars right-aligned
  • Status/label: 14 chars left-aligned
  • Tag/method: 7-8 chars

4. Bars de proporção e sparklines

Bars (█░) pra proporção entre categorias. Sparklines (▁▂▃▄▅▆▇█) pra séries temporais.

const BAR_W = 14;
function bar(pct: number): string {
  const filled = Math.round((pct / 100) * BAR_W);
  return "█".repeat(filled) + "░".repeat(BAR_W - filled);
}

const SPARK = ["▁","▂","▃","▄","▅","▆","▇","█"];
function sparkline(values: number[]): string {
  const max = Math.max(...values);
  if (max === 0) return SPARK[0]!.repeat(values.length);
  return values.map((v) => {
    const idx = Math.round((v / max) * (SPARK.length - 1));
    return SPARK[idx]!;
  }).join("");
}

5. Glifos discretos com cor semântica

Um caractere conta uma história. Não use ASCII art.

| Glifo | Significado | Cor | |---|---|---| | | Destaque, foco do momento | accent | | | Concluído, sucesso | positive | | | Atrasado, anomalia | danger | | | Vence hoje, em ação | warning | | | Pendente, no prazo | textDim | | | Histórico, parcela antiga | textDim | | | Subitem, drill-down | textDim | | | Prompt do user, sugestão | accent | | ou | Aviso suave | warning |

6. Cores sóbrias com restrição

Off-white como base, accent verde como signature. Nunca arco-íris.

const COLORS = {
  textPrimary: "#E8E6E1",   // off-white principal
  textSecondary: "#B8B5AD",
  textDim: "#7A7770",
  accent: "#4ADE80",        // verde signature
  positive: "#65BB7D",
  warning: "#E0A85C",
  danger: "#D4675E",
  separator: "#3A3833",
};

A regra: 80% do texto em textPrimary + textSecondary + textDim. Accent verde é signature, usa com restrição.

7. Slash command suggester estilo Claude Code

Quando user digita /, abrir menu filtrado.

╭───────────────────────────────────────────╮
│ › /contas          contas do mês a pagar  │
│   /resumo [mês]    panorama por categoria │
│   /top [N]         top N maiores gastos   │
│                                           │
│   ↑↓ navega · Tab completa · Enter exec   │
╰───────────────────────────────────────────╯
╭───────────────────────────────────────────╮
│ › /co                                      │
╰───────────────────────────────────────────╯

Controles obrigatórios:

  • ↑↓ navega
  • Tab completa (não executa — deixa cursor pronto pra args)
  • Enter executa (ou autocompleta + espera args, se há args)
  • Esc fecha menu

Tom de voz — banker/CFO pt-BR

Zero jargão técnico. O agente fala como um CFO falaria com o founder, não como um dev falaria com outro dev.

✅ "Plano de Saúde levou 32% do mês — vale conferir se tem algum adicional." ❌ "A categoria 'plano_saude' teve valor agregado 32% do total."

✅ "Você tem 6 contas atrasadas. A maior é o Aluguel — 16 dias." ❌ "Existem 6 itens com status 'overdue'. O top item é 'aluguel' com days_to_due = -16."

✅ "Cartão de abril ficou em R$ 21.612. Bills, R$ 37.580. Total: R$ 59.192." ❌ "Sum de transactions where mês=04 retornou 21612.84..."

Proibido no output ao user:

  • API, tool, function, JSON, array, null, undefined
  • categoria, status, flag (no sentido técnico) — usar termos em PT
  • consulta, filtrado, agregado, ordenado
  • ---, ___, *** como separador (vira lixo no terminal — use linha em branco)
  • "Como posso ajudar?" — vá direto
  • "Primeira vez que a gente fala" — vocês já se conheciam
  • Tabelas markdown com pipes
  • Emoji (a menos que explícito pedido)

Obrigatório:

  • PT-BR com todos os acentos (Alimentação, Saúde, Móveis, Doceria, Família)
  • Datas em dd/MM/yyyy (08/05/2026, não 2026-05-08)
  • Meses por extenso em prosa (abril de 2026, não abr/26)
  • Valores em R$ X.XXX,XX (ponto milhar, vírgula decimal)
  • Direto, sem softening

Custo-consciência — token economy

Cada chamada custa. Cada token de contexto custa. Pensar custo é pensar produto.

Hierarquia de custo (do mais barato pro mais caro):

  1. Atalho local (regex) — $0
  2. Cache de descrição (descrição → categoria) — $0
  3. Haiku 4.5 (categorização, extração) — ~$0.001
  4. Sonnet 4.6 sem tool (análise curta) — ~$0.003
  5. Sonnet 4.6 com tool calls (análise complexa) — ~$0.01–0.05

Decisões cravadas:

  • Listagens factuais (fatura, contas, top N): sempre local. Nunca Sonnet.
  • Categorização: Haiku com confidence ≥ 0.85. Override manual fica source='manual' (Haiku nunca sobrescreve).
  • Cache permanente de (description, category) pra reuso entre runs.
  • Working memory truncate: histórico do chat com Sonnet limitado a últimos 15 turnos (não 50+).
  • Prompt cache quando aplicável (Anthropic suporta cache de 5 min).

> Pra catálogo completo de patterns LLM em produção (sliding window com summary, lazy client factory, in-flight dedupe, streaming abort/retry, schema validation no response, cross-channel safety, cost tracking), usar /hm-llm-guardrails.

Quando vale gastar:

  • Auditoria do mês: análise CFO completa
  • "Compara março com abril": diff inteligente
  • "Pq gastei tanto em X": insight + sugestão de ação
  • Comprovante de pagamento: extração de valor real

Quando NÃO vale:

  • Listar transações: local
  • Mostrar status do mês: local
  • Repetir dado que o block visual já mostrou

Dados sagrados — never lose

Toda operação destrutiva ou de import passa por 3 portões:

1. Idempotência

Import com hash SHA-256 do arquivo. Re-import do mesmo arquivo é no-op.

const hash = crypto.createHash("sha256").update(buffer).digest("hex");
const existing = db.prepare(
  "SELECT id FROM statements WHERE source_file_hash = ?"
).get(hash);
if (existing) return { skipped: true, reason: "already imported" };

2. Migrations versionadas

Schema mudou? Migration explícita, idempotente, reversível quando possível.

const SCHEMA = `
CREATE TABLE IF NOT EXISTS ...
ALTER TABLE ... -- só quando necessário, dentro de tryExec wrapper
`;

Pra schemas com UNIQUE composto, use PRAGMA foreign_keys = OFF + rename + recreate + reattach.

3. Confirmação destrutiva

Antes de DELETE em massa, DROP, ou sobrescrever arquivo importante: pedir confirmação.

if (operação.destrutivo) {
  push({ type: "system", text: "vai apagar X. confirma? [y/n]" });
  pendingConfirmation.current = operação;
  return;
}

Nunca:

  • docker compose down -v em banco com dados produtivos
  • git push --force sem aviso
  • rm -rf em path não temporário
  • DELETE FROM table sem WHERE específico

Aprendizado persistente

CLI HM aprende com o user. Toda decisão manual vira regra permanente.

3 tipos de memória:

1. Cache de classificação (description_categories)

INSERT INTO description_categories (description, category_id, confidence, source)
VALUES (?, ?, 1.0, 'manual')
ON CONFLICT(description) DO UPDATE SET
  category_id = excluded.category_id,
  confidence = 1.0,
  source = 'manual',
  updated_at = datetime('now');

source='manual' com confidence=1.0 sobrescreve qualquer tentativa de LLM. Regra cravada.

2. Memórias contextuais (agent_memories) Tipos:

  • fact — verdade objetiva ("Carter's = roupa infantil, provavelmente Manuela")
  • preference — regra geral ("Mercado Livre/Amazon = Compras sempre")
  • decision — escolha do user ("OPAQUE = revisar depois, não lembro")
  • context — situação atual ("Renata vai categorizar os 10 dela")
  • goal — meta declarada ("quero gastar menos em iFood")

3. Padrões detectados (patterns) Recorrências detectadas automaticamente (Netflix, Spotify, Anthropic todo mês). User pode marcar como expected/ignored.

Loop de aprendizado:

  1. User executa ação manual → vira regra/memória
  2. Próxima vez que descrição/contexto similar aparecer → regra aplicada automaticamente
  3. LLM consulta memórias antes de responder → contexto enriquecido sem custo recorrente

Padrões técnicos Ink (truques específicos)

Scrollback nativo com ``

Pra que o terminal nativo gerencie scroll (sem viewport interno), use ``. Cada item renderiza uma vez e fica no scrollback.


  {(item, i) => {
    if (item.kind === "logo") return ;
    if (item.kind === "greeting") return ;
    if (item.kind === "msg") return ;
  }}

Não use height fixo + overflow="hidden" — fica preso ao viewport e bagunça scroll.

ANSI inline > Box+Text nesting

Pra renderizar markdown inline (bold, italic, código), use ANSI escape codes num único `. Aninhar + ` quebra a primeira coluna do output em alguns terminais.

const BOLD = "";
const RESET = "";
const DIM = "";

function inlineToAnsi(text: string): string {
  return text
    .replace(/\*\*(.+?)\*\*/g, `${BOLD}$1${RESET}`)
    .replace(/`(.+?)`/g, `${DIM}$1${RESET}`);
}

{inlineToAnsi(content)}

AbortController pra Esc cancel

Toda chamada async (LLM, fetch, query longa) precisa de AbortController. Esc cancela.

const abortRef = useRef(null);

useInput((input, key) => {
  if (key.escape && abortRef.current) {
    abortRef.current.abort();
    setState("cancelled");
  }
});

useEffect(() => {
  if (!pendingTurn) return;
  const ctrl = new AbortController();
  abortRef.current = ctrl;
  chat({ ...args, signal: ctrl.signal }).then(...);
  return () => ctrl.abort();
}, [pendingTurn]);

useEffect pra side effects async

Nunca chame async dentro de event handlers que mudam state durante render. Sempre useEffect.

❌ Ruim:

onSubmit={async (v) => {
  setState("loading");
  const r = await chat(v);  // perde re-render entre setState e await
  setResult(r);
}}

✅ Bom:

onSubmit={(v) => {
  setPendingTurn(v);
}}

useEffect(() => {
  if (!pendingTurn) return;
  setState("loading");
  chat(pendingTurn).then(setResult);
}, [pendingTurn]);

Estrutura de pastas

src/
  cli.ts                  — entrypoint Bun
  agent/
    app.tsx               — root React component, orchestra tudo
    llm.ts                — system prompt + tools + chat()
    tools.ts              — funções TS expostas como tools pro Sonn

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [rodrigohighermind](https://github.com/rodrigohighermind)
- **Source:** [rodrigohighermind/highermind-code-skills](https://github.com/rodrigohighermind/highermind-code-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.