CLAUDE.md
Rama main · réplica de lectura del repositorio original.
# CLAUDE.md
# Agent Instructions
## Landing the Plane (Session Completion)
**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
**MANDATORY WORKFLOW:**
1. **Run quality gates** (if code changed) - Tests, linters, builds
2. **PUSH TO REMOTE** - This is MANDATORY:
```bash
git pull --rebase
git push
git status # MUST show "up to date with origin"
```
3. **Clean up** - Clear stashes, prune remote branches
4. **Verify** - All changes committed AND pushed
5. **Hand off** - Provide context for next session
**CRITICAL RULES:**
- Work is NOT complete until `git push` succeeds
- NEVER stop before pushing - that leaves work stranded locally
- NEVER say "ready to push when you are" - YOU must push
- If push fails, resolve and retry until it succeeds
## What is siteio?
A self-hosted deployment platform for **websites** and **Docker containers** with automatic HTTPS via Traefik.
### Features
- **Sites**: Deploy folders as websites (`siteio sites deploy ./folder`). Every site runs in its own PocketBase container: static frontend plus optional backend (auth, database, file storage, realtime) at `/api`; env vars and secrets for its hooks via `siteio sites set|unset`
- **Local dev**: `siteio sites dev` runs a site + backend locally without Docker
- **Container apps**: Deploy Docker images (`siteio apps create myapp -i nginx -p 80`)
- **Git deployments**: Build from Git repos (`siteio apps create myapp --git <url> -p 3000`)
- **Monorepo support**: Specify build context with `--context <path>`
- **Custom domains, history/rollback, rename**: `siteio sites domain|history|rollback|rename`
- **Stop / start**: `siteio sites stop|start`, `siteio apps stop|start|restart` take a site or app offline (404, data kept; site containers removed, app containers stopped with their restart policy off) and bring it back as it was; a stopped item refuses deploys until started
- **Users**: a bootstrap admin per server (`siteio agent password` on the box, also set by `agent install`); admins can add other admins (`siteio users add <name> --role admin`), tenant owners and members (`siteio users add|list|remove|reset-password`); `--password` sets a chosen password instead of a generated one. Each user logs in to the admin UI with a password and has its own revocable keys (`siteio users keys|revoke-key`); the god key, tenant keys and share codes are unchanged
- **Automatic HTTPS**: Traefik handles Let's Encrypt certificates
- **Two modes**: CLI client talks to a remote agent server
### Not Yet Supported
- Private Git repository credentials (public repos only)
## Development Commands
```bash
bun run dev # Run CLI with --watch
bun run start # Run CLI directly
bun run typecheck # TypeScript type checking
bun test # Run all tests
bun test src/__tests__/deploy.test.ts # Single test file
```
## Testing Conventions
- Tests use `skipTraefik: true` to run without Traefik
- E2E tests spin up a real `AgentServer` on a random port
- Use `bun test` - the project uses Bun's built-in test runner
## Key Patterns to Follow
- **Dual output**: Commands output JSON to stdout (for scripting), human-readable to stderr
- **Error handling**: Use error classes from `utils/errors.ts` (ValidationError, ApiError, ConfigError)
- **CLI output**: Use helpers from `utils/output.ts` for consistent formatting
## Environment Variables (Agent Mode)
Required:
- `SITEIO_DOMAIN` - Base domain (e.g., `myserver.example.com`)
Optional:
- `SITEIO_API_KEY` - API key (auto-generated if not set)
- `SITEIO_DATA_DIR` - Data directory (default: `/data`)
- `SITEIO_EMAIL` - Email for Let's Encrypt
- `PAGERIO_URL` - [pagerio](https://pagerio.chuut.com) URL; when set, the agent pages it on every app/site deploy (success or failure), app restart and agent start. Can also be persisted with `siteio agent config set pagerUrl <url>` (env var wins; restart the agent after changing it)
- `RANKING_URL` - ranking dashboard URL, separate from `PAGERIO_URL`; when set, the agent POSTs `{"user","version","url"}` (JSON) after every successful app/site deploy. Deploys with no known user are skipped (the endpoint requires one). Site version = version number; app version = short commit hash, else the image. Can also be persisted with `siteio agent config set rankingUrl <url>`
- `ANALYTICS_URL` - traffic analytics endpoint, separate from `PAGERIO_URL` and `RANKING_URL`; when set, Traefik writes a JSON access log and the agent POSTs a batch of pageviews + per-site/app traffic counters every minute (format: `docs/superpowers/plans/2026-10-10-traffic-analytics-hook.md`). Best-effort: a failed batch is dropped. Can also be persisted with `siteio agent config set analyticsUrl <url>` (env var wins; restart the agent after changing it). Traefik's access log is `<dataDir>/traefik-logs/access.log`
AI site-chat editor (optional; enables the "Chat" tab on a site — edit a site by
chatting with an LLM that redeploys it — plus the **in-site live editor**: run
`siteio sites edit <site>` to mint a one-time link that opens an Intercom-style
chat bubble *on the deployed site itself* (`<site>.<domain>/_siteio/edit`), where
edits land in place. Phase 1 is owner-only. Configured iff a credential is set:
- `SITEIO_LLM_OAUTH_TOKEN` - Claude subscription token from `claude setup-token` (preferred), or `CLAUDE_CODE_OAUTH_TOKEN`
- `SITEIO_LLM_API_KEY` - Anthropic API key (alternative to a subscription token)
- `SITEIO_LLM_MODEL` - optional model override (e.g. `claude-sonnet-5`)
- `SITEIO_CHAT_SANDBOX` - run the agent in a throwaway container (default `true`; set `false` only for trusted single-tenant/dev). Sandbox needs the image: `docker build -t siteio-chat-sandbox:latest docker/chat-sandbox`
- `SITEIO_CHAT_SANDBOX_IMAGE` / `SITEIO_CHAT_SANDBOX_NETWORK` / `SITEIO_CHAT_MAX_TURNS` / `SITEIO_CHAT_TIMEOUT_MS` - sandbox/limit overrides
The credential/model can also be persisted (instead of env) via the agent config CLI, which writes to `agent-config.json` (0600; credentials masked in `config list`): `siteio agent config set llmOauthToken <token>` (or `llmApiKey`, `llmModel`, `llmProvider`). Env vars win over persisted values; restart the agent after changing either.
## Releasing
Follow this when the user asks to "release a new version" or mentions "bump the version"
### Version Bumping (Semver)
- **Patch** (1.0.x): Bug fixes, minor tweaks
- **Minor** (1.x.0): New features, backward compatible
- **Major** (x.0.0): Breaking changes
### Release Steps
1. Bump version in `package.json`
2. Commit: `git commit -am "Bump version to X.Y.Z"`
3. Push: `git push`
4. Tag: `git tag vX.Y.Z && git push origin vX.Y.Z`
5. Share the Actions link so user can follow build progress:
https://github.com/plosson/siteio/actions
GitHub Actions builds binaries and creates a release when a tag is pushed.
### Update SiteIO.me server
1. Run on the remote server accessible through `ssh siteio`:
```bash
ssh siteio "/root/.local/bin/siteio update -y && /root/.local/bin/siteio agent restart"
```