CLAUDE.md
Rama main · réplica de lectura del repositorio original.
# CLAUDE.md
Guidance for AI coding agents working on Writers Guild. Everything in "The CI
gate" below is enforced by GitHub Actions on every PR to `main`.
Writers Guild is a self-hosted, AI-powered short story writing app: an Express
server (plain JavaScript, ESM) with SQLite storage, plus a Vue 3 + Vite client.
## Layout
- `server/` — Express routes (`src/routes/`), services (`src/services/`,
including the LLM provider adapters in `services/providers/`), SQLite storage
- `vue_client/` — Vue 3 SPA (components, views, composables)
- `shared/` — code imported by both server and client
- `data/` — runtime user data; never read or write it from tests or tooling
- Tests are Vitest, colocated in `__tests__/` directories next to the code
## The CI gate — run before every PR
| Command | What it is |
| ---------------------- | ------------------------------------------- |
| `npm run lint` | **oxlint** — errors fail CI, warnings don't |
| `npm run format:check` | **oxfmt** |
| `npm test` | **Vitest**, server + client suites |
All three must pass before opening a PR. `npm run format` writes formatting
fixes; `npm run lint:fix` applies safe lint fixes.
## Code style
- **Formatter is `oxfmt`, NOT Prettier; linter is `oxlint`, NOT ESLint.** Do
not run or configure Prettier/ESLint — they fight the house style (single
quotes, 100-col width, trailing commas).
- Tooling conventions mirror
[amiantos/lurker](https://github.com/amiantos/lurker): keep `.oxfmtrc.json`
and `.oxlintrc.json` minimal, stating only non-default choices.
- **Unused vars/params:** prefix with `_` to satisfy the lint rule. For Express
error middleware that means `(err, req, res, _next)` — keep the 4-arg arity,
Express uses it to detect error handlers.
- Match the surrounding code's naming, comment density, and idiom.
## Users
- Each row of `OWNED_TABLES` (`server/src/services/database.js`) belongs to a user. **Every query
on one must keep to the current user**: `AND ${MINE}` (`user_id = current_user_id()`), or
`mineThrough()` for a table that hangs off one, and inserts set `user_id` to
`current_user_id()`. See `server/src/services/user-context.js`.
- `current_user_id()` reads the user from AsyncLocalStorage, set per request by
`middleware/authenticate.js`, and throws outside one. Work outside a request runs inside
`runAsUser()`. Tests fall back to the admin (`src/__tests__/setup.js`); isolation tests turn
that off with `setFallbackUserId(null)`.
## Testing
- `npm run test:server` / `npm run test:client` run one side on its own.
- Tests create their own temporary directories; never point them at `data/`.