Skill79 repo starsupdated 2mo ago
cybrix-deploy
cybrix-deploy automates deployment of static web projects to Cybrix hosting by detecting project type through configuration files and build artifacts, retrieving an API token from environment variables or local files, and uploading the compiled output directory. Use this skill when deploying front-end applications like Next.js static exports, Vue, React, Hugo, Jekyll, or other static site generators to Cybrix infrastructure.
Install in Claude Code
Copygit 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-deployThen start a new Claude Code session; the skill loads automatically.
Definition
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