> For the complete documentation index, see [llms.txt](https://docs.skail.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.skail.dev/comece-aqui/use-com-ia.md).

# Use com IA

Cursor, GitHub Copilot e Claude erram muito menos em código skail quando recebem as regras certas.

Esta página dá o arquivo de regras pronto para copiar e aponta onde a documentação inteira está em texto para o assistente ler.

## A documentação em texto

[docs.skail.dev/llms.txt](https://docs.skail.dev/llms.txt) lista todas as páginas no formato que os assistentes leem. Cada página também existe em markdown puro: acrescente `.md` ao final da URL. Cole o `llms.txt` ou a URL `.md` de uma página no contexto do assistente quando quiser que ele responda com base na doc, não na memória.

{% hint style="info" %}
Assistentes que falam MCP (Claude, Claude Code, Cursor, Codex, VS Code) podem conectar esta documentação como servidor MCP: `https://docs.skail.dev/~gitbook/mcp`. Ele responde com busca e leitura das páginas publicadas.
{% endhint %}

## O arquivo de regras

Salve o bloco da linguagem do projeto na raiz do repositório como `.cursorrules` (Cursor), `.github/copilot-instructions.md` (GitHub Copilot) ou `CLAUDE.md` (Claude Code). Os três leem o arquivo automaticamente. O conteúdo resume o modelo de programação e os antipadrões que mais aparecem em revisão.

{% tabs %}
{% tab title="C#" %}

```markdown
# Regras para código skail

Este projeto usa o skail. Siga estas regras em todo código que use [SkailFunction] ou [SkailCommand].

## Modelo
- [SkailFunction] é o orquestrador. Seu corpo é reexecutado (replay) do início a cada retomada. Ele só decide e encadeia chamadas.
- [SkailCommand] é onde ficam as operações de I/O (HTTP, banco, fila, arquivo) e tudo que muda a cada execução (relógio, aleatoriedade). Ele roda uma vez e grava o resultado; no replay o resultado gravado é devolvido sem executar.
- Todo método decorado é público, de instância (nunca static), async, e retorna SkailTask ou SkailTask<T>. Nunca Task/Task<T>.
- Use sempre `await` e nunca .Result, .Wait(), .GetAwaiter().GetResult() ou .GetResult() em SkailTask.
- O runtime é configurado com `builder.UseSkail()` e o assembly precisa de `[assembly: VisibleToSkailPlatform]`.
- Não misture Task e SkailTask no caminho durável: um helper `async Task` com I/O chamado da function não grava passo nem retenta. Faça dele um [SkailCommand].
- Não guarde estado em campos da classe entre awaits: a instância é descartada na hibernação. Passe o estado por parâmetros e retornos de commands.
- Commands só são chamados de dentro de functions. Um [SkailCommand] não chama outro [SkailCommand] nem uma [SkailFunction]: quem compõe os passos é sempre a function. Se dois passos precisam ser duráveis separadamente, a function chama os dois em sequência. Dentro de um command, reaproveite lógica com métodos comuns, sem atributo.

## Determinismo (dentro de [SkailFunction])
- Proibido: DateTime.Now/UtcNow, DateTimeOffset.Now, Guid.NewGuid(), Random, Environment.TickCount, Environment.GetEnvironmentVariable, ler arquivo/config/banco/HTTP, Task.Delay, Thread.Sleep, Task.WhenAll/WhenAny, Task.Run, Parallel.*.
- Permitido: lógica pura, branching sobre argumentos e resultados de commands, laços, ILogger, SkailContext.Current.TaskId, chamadas a commands e a outras functions, e as primitivas SkailTask.*.
- Relógio: `var agora = await ObterDataAtual();` com `[SkailCommand] public async SkailTask<DateTime> ObterDataAtual() => await Task.FromResult(DateTime.UtcNow);`
- Dentro de [SkailCommand] vale tudo (HttpClient, DbContext, Task.Delay, Guid.NewGuid(), DateTime.UtcNow, ...), menos chamar outro [SkailCommand] ou uma [SkailFunction].

## Primitivas (só dentro de functions)
- SkailTask.Delay(TimeSpan), SkailTask.DelaySeconds(ulong), SkailTask.DelayMinutes(ulong): espera durável.
- SkailTask.WhenAll(params SkailTask[]), SkailTask.WhenAny(params SkailTask[]): paralelismo. Ler resultados pela posição, não pela ordem de término.
- SkailTask.WaitForEvent(string eventName, string eventInstanceId) e WaitForEvent<T>(...): hiberna até um evento externo com o mesmo nome e o mesmo eventInstanceId.
- Não existe SkailTask.FireEvent nem cliente .NET para disparar. Eventos são disparados por HTTP: POST {SKAIL_BASE_URL}/api/v1/fire/{eventName}/{instanceId} com headers skail-key e Skail-namespace e o payload em JSON. Funções são iniciadas por POST {SKAIL_BASE_URL}/trigger/{workload}/{versao}/{funcao}/{id} com os argumentos em um array JSON.
- Não existem DelayDays, SkailEvent.*, ContextHolder.*.

## Eventos e tempo
- Nomes de evento em constantes compartilhadas (public const string), MAIÚSCULAS_COM_UNDERSCORE.
- instanceId é um id de negócio estável (id do pedido, da fatura), igual nos dois lados.
- Toda espera tem prazo: `var timeout = SkailTask.Delay(prazo); var vencedor = await SkailTask.WhenAny(espera, timeout); if (vencedor == timeout) { ... }`.

## Falhas e idempotência
- Qualquer exceção em command gera nova tentativa até retryCount (default 5); a function só vê a exceção depois. Não escreva laço de retry manual na function.
- Falha de negócio (recusa, inválido) é resultado, não exceção.
- A operação externa executa "no mínimo uma vez": passe uma chave de idempotência (id de negócio) em toda chamada externa dentro de command.
- Um command por operação de I/O.
- Nunca capture SkailNonDeterministicException: ela indica que o código diverge do histórico. Corrija o código.
- Argumentos e retornos são DTOs/records pequenos e serializáveis (System.Text.Json). Nunca entidades de ORM, streams, SkailTask ou listas enormes.

## Versionamento
- Não mude ordem, quantidade ou tipo dos awaits de uma function que tem execuções em andamento. Crie um método novo com [SkailFunction(skailMethodName: "...")] ou publique nova versão do workload (SKAIL_WORKLOAD=nome:versao) e mantenha a antiga até esvaziar.

## Estilo
- Nomes em português, legíveis no Monitor: EmitirNotaFiscal, AguardarAprovacao, ObterDataAtual.
- Inclua SkailContext.Current.TaskId nos logs.
```

{% endtab %}

{% tab title="TypeScript" %}

```markdown
# Regras para código skail

Este projeto usa o skail com o SDK TypeScript (`@skail/runtime`). Siga estas regras em todo código que use @SkailFunction() ou @SkailCommand().

## Modelo
- @SkailFunction() é o orquestrador. Seu corpo é reexecutado (replay) do início a cada retomada. Ele só decide e encadeia chamadas.
- @SkailCommand() é onde ficam as operações de I/O (HTTP, banco, fila, arquivo) e tudo que muda a cada execução (relógio, aleatoriedade). Ele roda uma vez e grava o resultado; no replay o resultado gravado é devolvido sem executar.
- Todo método decorado é público, de instância (nunca static nem private), async, e retorna Promise<T>. O `skail build` rejeita o que foge disso.
- Leia todo resultado de command, function ou primitiva com `await`, direto ou por `Skail.whenAll`/`Skail.whenAny`; nunca com `.then`.
- O entry point exporta as classes com functions e commands; o `skail build` gera a partir dele o bundle e o manifest; o host é `createSkailPlatform({ ... })` com `platform.run(signal)`.
- O runtime não infere parâmetros de construtor: as dependências entram pelo array `providers` exportado no entry point (com `useFactory`) ou são instanciadas na própria classe.
- Não dependa de campos da classe para guardar estado entre awaits: na hibernação a execução sai da memória. Passe o estado por parâmetros e retornos de commands.
- Commands só são chamados de dentro de functions. Um command não chama outro command nem uma function: quem compõe os passos é sempre a function. Se dois passos precisam ser duráveis separadamente, a function chama os dois em sequência. Dentro de um command, reaproveite lógica com métodos comuns, sem decorator.

## Determinismo (dentro de @SkailFunction())
- Lançam erro na hora: new Date() sem argumento, Date.now(), Math.random(), crypto.randomUUID(), crypto.getRandomValues(), setTimeout(), setInterval(), fetch(). `process` e `require` não existem. Imports estáticos de módulos Node de I/O (fs, net, crypto, process, worker_threads) são rejeitados no build.
- Não use Promise.all, Promise.race nem .then para compor esperas: só promises do runtime entram em Skail.whenAll e Skail.whenAny.
- Permitido: lógica pura, decisões sobre argumentos e resultados de commands, laços, new Date(texto), Date.parse, getTime(), SkailContext.current.taskId, chamadas a commands e a outras functions, e as primitivas Skail.*.
- Relógio: leia a hora em um command que devolve a data como string ISO-8601, e use o valor devolvido na function.
- Dentro de @SkailCommand() vale tudo (fetch, banco, timers, crypto, Date), com os módulos de I/O carregados por `await import(...)`, menos chamar outro command ou uma function.

## Primitivas (só dentro de functions)
- Skail.delay(ms), Skail.delaySeconds(n), Skail.delayMinutes(n): espera durável. Resolvem undefined; valor negativo ou não finito rejeita com RangeError.
- Skail.whenAll(...): devolve os resultados na ordem dos argumentos. Skail.whenAny(...): devolve o valor de quem terminou primeiro.
- Skail.waitForEvent<T>(eventName, instanceId): hiberna até um evento externo com o mesmo nome e o mesmo instanceId (string).
- Eventos são disparados por HTTP: POST {SKAIL_BASE_URL}/api/v1/fire/{eventName}/{instanceId} com headers skail-key e Skail-namespace e o payload em JSON. Funções são iniciadas por POST {SKAIL_BASE_URL}/trigger/{workload}/{versao}/{funcao}/{id} com os argumentos em um array JSON.

## Eventos e tempo
- Nomes de evento em constantes compartilhadas (objeto `as const`), MAIÚSCULAS_COM_UNDERSCORE.
- instanceId é um id de negócio estável (id do pedido, da fatura), igual nos dois lados.
- Toda espera tem prazo: `const resultado = await Skail.whenAny(espera, Skail.delayMinutes(prazo)); if (resultado === undefined) { ... }`. Por isso o payload do evento nunca pode ser undefined.

## Falhas e idempotência
- Qualquer exceção em command gera nova tentativa até retryCount (default 5); a function só vê a exceção depois. Não escreva laço de retry manual na function.
- Falha de negócio (recusa, inválido) é resultado, não exceção.
- A operação externa executa "no mínimo uma vez": passe uma chave de idempotência (id de negócio) em toda chamada externa dentro de command.
- Um command por operação de I/O.
- Nunca capture SkailNonDeterministicError: ele indica que o código diverge do histórico. Corrija o código.
- Argumentos e retornos são objetos pequenos e serializáveis em JSON, com datas como string ISO-8601. Nunca streams, promises ou listas enormes.

## Versionamento
- Não mude ordem, quantidade ou tipo dos awaits de uma function que tem execuções em andamento. Crie um método novo com @SkailFunction({ uri: "imagem:versao/metodo" }) ou publique nova versão do workload (SKAIL_WORKLOAD=nome:versao) e mantenha a antiga até esvaziar.

## Estilo
- Nomes em português, legíveis no Monitor: EmitirNotaFiscal, AguardarAprovacao, ObterDataAtual.
- Inclua SkailContext.current.taskId nos logs.
```

{% endtab %}
{% endtabs %}

## Como usar no dia a dia

Peça ao assistente para "escrever uma function que..." e revise com o [Checklist de revisão de código skail](/construa/como-fazer/padroes-e-antipadroes/checklist-de-revisao-de-codigo-skail.md): os itens 1 a 5 de [Antipadrões](/construa/como-fazer/padroes-e-antipadroes/antipadroes-o-que-nao-fazer-e-por-que.md) (I/O, relógio e aleatoriedade dentro da function, pausas e concorrência da linguagem no lugar das primitivas do skail) e, em C#, o item 21 (`Task` em vez de `SkailTask`) são os que os assistentes mais erram sem as regras.

{% hint style="warning" %}
Em C#, quando o assistente sugerir `SkailTask.FireEvent`, `DelayDays` ou `SkailEvent`, ele está inventando: nenhum existe. Aponte para esta página.
{% endhint %}

## Próximos passos

[Antipadrões](/construa/como-fazer/padroes-e-antipadroes/antipadroes-o-que-nao-fazer-e-por-que.md) é a versão comentada do arquivo de regras. [Padrões recomendados](/construa/como-fazer/padroes-e-antipadroes/padroes-recomendados.md) é a versão positiva. [Quickstart](/comece-aqui/quickstart.md) para o primeiro projeto.
