# Contas, repositórios e publicação por API

Crie sua conta em https://aiskills.bonorasw.com.br/auth/register/ ou entre em `/auth/login/`. O nome de usuário é público, permanente e usa 3 a 39 letras minúsculas, números e hífens.

Cada usuário tem um espaço `/user/{usuario}/`. Cada skill é um repositório `/user/{usuario}/{skill}/`, com histórico de versões. Dois usuários podem publicar o mesmo identificador em espaços diferentes. O formato Agent Skills usa apenas o identificador da skill no ZIP; o instalador recusa sobrescrever uma pasta de mesmo nome já instalada.

## Publicação pelo site

Em **Minha conta → Publicar skill**, envie um ZIP ou use o formulário. A primeira publicação cria o repositório. Para atualizar, mantenha o identificador e aumente a versão. Versões já publicadas são imutáveis. O proprietário pode retirar uma versão com um motivo; os pacotes históricos continuam disponíveis.

As publicações da comunidade passam por validação de formato, tamanho e caminhos. Elas ficam disponíveis imediatamente no perfil e no catálogo, identificadas pelo autor. Isso não equivale a revisão humana ou auditoria de segurança do conteúdo. Publique apenas material que tem direito de distribuir e inclua sua licença.

## Token de publicação

Em `/account/`, crie um token. Ele aparece uma única vez, tem validade de 90 dias e permite publicar e retirar versões **somente no seu espaço**. Revogue-o pelo painel. O servidor armazena apenas o hash. Senhas usam Argon2, sessões usam cookies HttpOnly e formulários exigem CSRF.

Não coloque o token no pacote ou na URL. Forneça-o ao agente por variável de ambiente ou gerenciador de segredos.

## Publicar um ZIP

```bash
curl --fail-with-body \
  -H "Authorization: Bearer $AISKILLS_TOKEN" \
  -F "package=@minha-skill.zip" \
  https://aiskills.bonorasw.com.br/api/v1/skills/publish
```

O ZIP deve conter uma pasta `minha-skill/` com `skill.json`, `SKILL.md` e `LICENSE`, além dos recursos necessários. O contrato de metadados é `schemas/skill.schema.json`. O campo `author` é substituído pelo usuário autenticado. Scripts enviados são distribuídos como arquivos, nunca executados pelo servidor.

## Publicar JSON

Envie `Content-Type: application/json` no mesmo endpoint:

```json
{
  "metadata": {
    "id": "minha-skill",
    "name": "Minha skill",
    "description": "Revisa o material informado pelo usuário.",
    "version": "1.0.0",
    "license": "MIT",
    "category": "produtividade",
    "tags": ["revisão"],
    "compatibility": ["agent-skills"],
    "dependencies": [],
    "permissions": [],
    "changelog": "Primeira publicação."
  },
  "skill_md": "---\nname: minha-skill\ndescription: Revisa o material informado pelo usuário.\n---\n\n# Minha skill\n\nInstruções completas aqui.",
  "license_text": "Inclua o texto integral da licença escolhida.",
  "files": {"references/exemplo.md": "Recurso de apoio opcional."}
}
```

`files` aceita arquivos de texto UTF-8. Para binários, envie um ZIP. O retorno `201` contém `owner`, `namespace`, `page_url`, `manifest_url`, `download_url`, `skill_url` e checksum. Links retornados são relativos à raiz do site.

## Endpoints

| Método | Caminho | Uso |
| --- | --- | --- |
| POST | `/api/v1/skills/publish` | Publicar no espaço do usuário autenticado |
| POST | `/api/v1/users/{usuario}/skills/{skill}/versions` | Publicar no repositório indicado; exige ser o dono |
| GET | `/api/v1/users/{usuario}/skills` | Listar repositórios do usuário |
| GET | `/api/v1/users/{usuario}/skills/{skill}/index.json` | Versões e disponibilidade |
| GET / HEAD | `/api/v1/users/{usuario}/skills/{skill}/versions/{versao}/manifest.json` | Manifesto imutável |
| GET / HEAD | `/api/v1/users/{usuario}/skills/{skill}/versions/{versao}/SKILL.md` | Instruções |
| GET / HEAD | `/api/v1/users/{usuario}/skills/{skill}/versions/{versao}/download.zip` | Pacote |
| POST | `/api/v1/users/{usuario}/skills/{skill}/versions/{versao}/withdraw` | Retirar versão: `{"reason":"motivo"}` |

`GET /api/v1/catalog.json` combina as skills mantidas pelo catálogo e as publicações da comunidade. Os caminhos antigos `/api/v1/skills/{id}/...` permanecem estáticos e preservados.

Erros: `400` pacote inválido; `401` autenticação ausente ou token inválido; `403` falta de permissão ou CSRF inválido; `409` versão já existente; `413` envio excede o limite HTTP; `429` limite de tentativas/publicações.

Limites: 2 MiB de conteúdo por pacote, 100 arquivos, 50 repositórios e 100 MiB por usuário, 100 versões por repositório, 30 publicações por hora, 10 tokens ativos. O proxy limita o corpo HTTP a 4 MiB. Versões retiradas continuam contando para armazenamento.

## Login de API com senha

Prefira tokens para agentes. Para clientes que usam sessão, primeiro faça `GET /api/v1/auth/session`, preserve os cookies e o `csrf_token`. Depois envie `POST /api/v1/auth/login` com JSON `username` e `password`, cookies e cabeçalho `X-CSRFToken`. Use o novo `csrf_token` retornado após o login para operações seguintes. Faça logout por `POST /api/v1/auth/logout` com CSRF. Não há autenticação Basic.

## GitHub

O login GitHub está habilitado no site. Contas GitHub são identificadas pelo ID numérico do provedor, nunca por coincidência de nome ou e-mail. No primeiro acesso, o usuário escolhe um nome livre no catálogo. Não há importação de repositórios GitHub, acesso a repositórios privados, Git push ou vinculação automática a contas locais existentes.
