Instalar en Claude Code
Copiargit clone --depth 1 https://github.com/cybrixcc/cybrix-skills /tmp/cybrix-deploy && cp -r /tmp/cybrix-deploy/plugins/cybrix-deploy/skills/cybrix-deploy ~/.claude/skills/cybrix-deployDespués abre una sesión nueva de Claude Code; el skill carga automáticamente.
Definición
SKILL.md
# cybrix-deploy
## Prerequisites
Before deploying, ensure the user has an API token. Check in this order:
1. `CYBRIX_DEPLOY_TOKEN` — set automatically by Claude Code from userConfig keychain (no action needed).
2. Environment variable `CYBRIX_TOKEN`.
3. File `~/.config/cybrix/token`.
4. File `.cybrix/token` in the project (gitignored).
If none exist, instruct the user exactly like this:
> No Cybrix token found. Get one free at **https://app.cybrix.cc/dashboard**
> (Step 3 — "Save your API token" → Generate).
>
> Once you have it, you can either:
> - **Paste it here** and I'll use it for this deploy (easiest)
> - Run `export CYBRIX_TOKEN=<token>` in your terminal to set it for this session
> - Run `echo <token> > ~/.config/cybrix/token` to save it permanently
Then wait for the user to provide the token. If they paste it directly in
chat, use it immediately — do not require them to re-run any command.
The project is ready to deploy once the token is available.
## Deployment workflow
### Step 1 — Detect project type (heuristic)
Do not rely on a framework whitelist. Instead, look for signals and
classify the project as **static**, **server**, or **unknown**.
**Static signals** (proceed with deploy):
- `package.json` has a `build` script AND output lands in `dist/`, `out/`,
`build/`, `public/`, `_site/`, or `.output/public/`
- `next.config.{js,ts,mjs}` with `output: 'export'` or `output: 'static'`
- `astro.config.{js,ts,mjs}` present (default mode is static)
- `vite.config.{js,ts}` without SSR plugins
- `_config.yml` (Jekyll), `config.toml` or `hugo.toml` (Hugo),
`.eleventy.js` / `eleventy.config.js` (Eleventy),
`zola.toml` (Zola)
- Only HTML/CSS/JS files at root, no server entry point
**Server signals** (refuse — see below):
- `Dockerfile` or `docker-compose.yml` (unless it only copies a static
`dist/`)
- `main.go`, `server.go`, or any `*.go` containing `net/http` or
`ListenAndServe`
- `main.py`, `app.py`, `server.py` with `uvicorn`, `gunicorn`, `flask`,
`fastapi` imports, or a `if __name__ == '__main__'` block calling
`app.run` / `serve` / `asyncio.run`
- `main.rs` or `server.rs` with `actix`, `axum`, `rocket`, `warp`,
or `tokio::main`
- `package.json` with a `start` script that runs `node`/`tsx`/`bun` on a
server file (NOT `next start` in a static-export config)
- `Gemfile` with `puma`, `unicorn`, `rails`, or `sinatra`
- `pom.xml` or `build.gradle` with `spring-boot`
- `.csproj` with ASP.NET
**Database signals** (warn but allow if everything else is static):
- `*.sql` files, `migrations/` folder, `prisma/schema.prisma`,
`drizzle.config.*`, `DATABASE_URL` referenced in source
- A static site hitting a hosted DB from the browser is unusual but valid.
Warn the user, don't refuse.
**When refusing** (server signals detected):
> This looks like a project that needs a server runtime — I detected
> `<specific signal, e.g. "main.go with net/http" or "Dockerfile with EXPOSE">`.
>
> Cybrix currently supports static sites only. Your options:
> 1. Convert to a static export (e.g. Next.js `output: 'export'`, Astro,
> Hugo).
> 2. Use a service that supports backends: Railway, Fly.io, Render.
> 3. Tell me to deploy anyway if you think the detection is wrong.
Always allow option 3 — heuristics are imperfect and the user knows
their project.
**Static output directories** to check, in order: `dist`, `out`, `public`,
`_site`, `build`, `.output/public`.
### Step 2 — Scan environment variables
After confirming the project is static but BEFORE running the build, scan
for environment variables the build will need.
**2a. Read .env files** — parse `KEY=value` format, skip comments (`#`)
and blank lines. Files to check: `.env`, `.env.local`, `.env.production`,
`.env.example`.
**2b. Grep source code** for build-time env var references:
- JS/TS: `process.env.X`, `import.meta.env.X`
- Look in `src/`, `app/`, `pages/`, `components/` — any
`*.{js,jsx,ts,tsx,vue,svelte}`
- Pay extra attention to `NEXT_PUBLIC_*`, `VITE_*`, `PUBLIC_*`,
`REACT_APP_*` — these are baked into the bundle at build time
**2c. Cross-reference** keys found in code against keys present in .env
files to find what the build needs.
**2d. Show the user:**
> I detected the following environment variables your build needs:
>
> NEXT_PUBLIC_API_URL (in .env.local, used in 3 files)
> VITE_STRIPE_KEY (in .env.local, used in src/checkout.ts)
>
> These need to be set before the build. How would you like to provide
> them?
>
> 1. Paste them here (sent encrypted with the deploy)
> 2. Set them later in the dashboard
> 3. Skip (build may fail or site may not work correctly)
If the user picks **option 1**, ask for each value one at a time. Include
them in the multipart POST to `/v1/deploys` as an `env_vars` field
(JSON map: `{"KEY": "value", ...}`).
**2e. Warn about missing variables** — if a var is referenced in code but
not in any .env file:
> ⚠ `AUTH_SECRET` is referenced in your code but not in any .env file.
> Provide it now or the build may fail.
**2f. Refuse to forward secrets in client-exposed vars** — if a key with
a client prefix (`NEXT_PUBLIC_*`, `VITE_*`, `REACT_APP_*`, `PUBLIC_*`)
looks like a secret (`*_SECRET`, `*_PRIVATE_KEY`, `DATABASE_URL`,
`JWT_SECRET`):
> ⚠ `NEXT_PUBLIC_JWT_SECRET` looks like a private secret but has a
> client-bundle prefix — it will be visible to anyone who opens your
> site's source. Are you sure you want to include it?
Do not send it without explicit confirmation.
### Step 3 — Choose project name and confirm
**3a. Infer a default name** from the current folder name, slugified
(lowercase, hyphens, max 32 chars). Example: `my-portfolio-site`.
**3b. Check availability** by calling:
```
GET https://api.cybrix.cc/v1/slugs/<name>/available
```
Response: `{"available": true, "slug": "my-portfolio-site"}`
- If `available: true` — use it as the default.
- If `available: false` — do NOT use it. Tell the user:
> The name `<name>` is already taken. Wh