LOCAL_DEVELOPMENT.md
Rama develop · réplica de lectura del repositorio original.
# Local Development
This guide is for contributors who want to develop Roomote from a local
checkout. If you want to operate Roomote for a team, start with the public
[Self-hosting docs](https://docs.roomote.dev/self-hosting) instead.
## Prerequisites
| Tool | Version | Notes |
| -------------- | ------- | ------------------------------------------------------------------------------------------------------------ |
| macOS | Latest | This guide is optimized for macOS. Apple Silicon runs the task worker natively (no amd64 emulation). |
| Docker Desktop | Latest | Provides Docker Engine and Compose for local services. |
| mise | Latest | Manages the repository toolchain. |
| ngrok | Latest | Optional, only when `R_PUBLIC_URL` uses an ngrok domain. |
| OpenCode CLI | Latest | Required to run tasks and server-side model calls. Install with `npm install -g opencode-ai`. |
| Python 3 | Latest | Required by the server-side OpenCode CLI helper. Install with `brew install python` if `python3` is missing. |
The dev toolchain runs on Node.js 24.22.1, pinned in `.tool-versions`,
`.nvmrc`, and `.node-version`. The `package.json` `engines` field accepts
22.x from 22.23.4 or 24.x from 24.22.1, and `.npmrc` has `engine-strict=true`.
## Environment Setup
Roomote uses [mise](https://mise.jdx.dev/) to manage tool versions:
```sh
mise install
pnpm install
```
Treat the repo-managed `mise` toolchain as the default for commands like
`node`, `npm`, `pnpm`, `uv`, and `python`. If a tool is missing or resolves to
the wrong version, rerun `mise install` and retry with
`mise exec -- <command>`.
Copy the local env example only when you need to set a public callback URL or
provider credentials:
```sh
cp .env.local.example .env.local
```
Useful local values:
- `R_PUBLIC_URL` - stable public HTTPS URL for OAuth and webhook
callbacks. If this is an ngrok domain, `pnpm dev` starts and reuses
`ngrok http --url=<domain> 13000` for you.
- `R_MODEL` - required for local tasks. Use a models.dev-style
`provider/model` id and expose the matching provider API key.
- source-control provider credentials - configured during `/setup`, or
preconfigured in `.env.local` when boot-time env vars should satisfy setup.
A minimal model setup looks like this:
```sh
R_MODEL=openrouter/anthropic/claude-sonnet-4
OPENROUTER_API_KEY=...
```
For full provider setup, use the public docs:
- [Models and inference](https://docs.roomote.dev/models)
- [Communications](https://docs.roomote.dev/communications)
- [Source control](https://docs.roomote.dev/source-control)
- [Environment variables](https://docs.roomote.dev/environment-variables)
## Public Callback URLs
Local development needs a public HTTPS URL when you test auth providers,
communications providers, source-control callbacks, or Linear webhooks.
`pnpm dev` resolves one canonical public URL before starting services:
1. If `R_PUBLIC_URL` is set to an ngrok domain, Roomote starts or reuses
`ngrok http --url=<domain> 13000`.
2. If `R_PUBLIC_URL` is set to any other HTTPS URL, Roomote uses it
without starting ngrok.
3. If `R_PUBLIC_URL` is missing, startup fails before services start.
ngrok is convenient but not required. Any public HTTPS endpoint that reaches
port `13000` works, including Cloudflare Tunnel, Tailscale Funnel, a reverse
proxy in front of your own domain, or a deployed self-host URL.
Use a stable public URL for integration work. Slack, GitHub, Linear, OAuth
sign-in, and other providers store callback and webhook URLs in their own app
settings. If the URL changes, update those dashboards and restart `pnpm dev`.
If you use ngrok, install and authenticate it once:
```sh
brew install ngrok
ngrok config add-authtoken <your-ngrok-token>
```
## Database Services
Roomote uses local defaults for development services:
- Web: `http://localhost:13000`
- API/tRPC: `http://localhost:13001`
- BullMQ runtime dashboard: `http://localhost:13002/admin/queues`
- Preview proxy: `http://roomotepreview.localhost:18081`
- PostgreSQL: `postgres://postgres:password@localhost:15432/roomote_development`
- Redis: `redis://localhost:16379`
- MinIO API: `http://localhost:19000`
- MinIO console: `http://localhost:19001`
Roomote keeps server-side MinIO access on the local API port. Presigned
artifact URLs default to `R_PUBLIC_URL`, and the local Caddy edge proxies the
signed `/<bucket>/*` paths to MinIO. This lets E2B, Modal, Daytona, and other
hosted workers upload artifacts through the same public edge they use for API
callbacks. Set `S3_PRESIGN_ENDPOINT` explicitly only when using a separate
worker-reachable object-storage endpoint.
Start the database, Redis, and artifact-storage services:
```sh
pnpm db:up
```
Reset the local database:
```sh
pnpm db:reset
```
The reset leaves the database migrated but unseeded, so the setup bootstrap flow
runs from scratch. Run `pnpm db:seed` if you want the local admin identity back.
## Running the App
Start all Roomote services:
```sh
pnpm dev
```
`pnpm dev` uses PM2 to start the web app, API, preview proxy, BullMQ dashboard,
controller, and worker release watcher. It also resolves the public callback
URL, prepares the database, builds the local worker release archive, and ensures
the `roomote-worker:local` image exists.
Common options:
| Option | Default | Description |
| ----------------------------- | -------- | ------------------------------------------------------------- |
| `--reset` | `false` | Reset the database before starting services. |
| `--verbose` | `false` | Enable verbose output with stdio logging. |
| `--skip-worker-release-build` | `false` | Reuse the existing worker artifact from `./releases`. |
| `--use-release` | `false` | Use GitHub worker releases instead of the local worker build. |
| `--worker-release-channel` | `stable` | GitHub worker release channel for `--use-release`. |
| `--worker-release-version` | unset | Optional GitHub worker release version pin. |
Examples:
```sh
pnpm dev
pnpm dev --reset
pnpm dev --skip-worker-release-build
pnpm dev --use-release --worker-release-channel preview --worker-release-version 0.0.371-preview.1
pnpm dev --verbose
```
Services are managed with PM2 after startup:
```sh
pm2 status
pm2 logs
pm2 logs roomote-web
pm2 dashboard
pm2 restart roomote-web
pm2 delete roomote-api roomote-web roomote-preview-proxy roomote-bullmq roomote-controller roomote-worker-release-watcher
```
## Local Diagnostics
After `pnpm dev` starts, run:
```sh
pnpm run doctor
```
The doctor checks local Postgres, Redis, MinIO, PM2 services, web/API,
controller, preview proxy, BullMQ health, public callback URL, auth provider
configuration, model provider configuration, and optional Teams bot settings.
Use `pnpm run doctor` instead of `pnpm doctor` because `pnpm doctor` is a pnpm
built-in command.
## Development Commands
Testing:
```sh
pnpm test
pnpm exec dotenvx run -f .env.test -- pnpm --filter <package> exec vitest run path/to/file.test.ts
```
Code quality:
```sh
pnpm lint
pnpm check-types
pnpm format
pnpm lint:fast
pnpm check-types:fast
pnpm knip
pnpm check
```
Database operations:
```sh
pnpm --filter @roomote/db db:push
pnpm db:generate
pnpm db:migrate
pnpm db:reset
```
Package management:
```sh
pnpm install
pnpm --filter @roomote/web add package-name
pnpm update
```
Storybook:
```sh
pnpm storybook
```
## Troubleshooting
### Database connection errors
```sh
docker ps
pnpm db:down && pnpm db:up
```
### Local environment problems
- Start from an empty `.env.local` when debugging core local startup.
- Copy `.env.local.example` only for overrides or integration credentials.
- If `pnpm dev` fails while starting ngrok, check that `R_PUBLIC_URL`
matches your assigned ngrok domain and that ngrok has an auth token.
- If task creation hangs during classification or title generation, verify
`python3` is available and that this succeeds:
```sh
opencode run --model <provider/model> "Return ok"
```
### Package installation issues
```sh
pnpm store prune
find . -name node_modules | xargs rm -rvf
pnpm install
```
### Docker issues
Restart Docker Desktop first. If the local Docker cache is badly wedged, clean
unused Docker data:
```sh
docker system prune -a
```
## Local Environment Variables
Roomote local development reads `.env.local` for operator-owned overrides. The
file is not encrypted and should not be committed.
Use `.env.local.example` as the reference for optional keys. Core local values
such as Postgres, Redis, MinIO artifact storage, web/API URLs, signing keys,
encryption keys, and preview proxy URLs have development defaults in
`@roomote/env`.
For production or shared self-host deployments, provide real secrets through
the deployment environment instead of relying on local defaults.
## Test Recipe
Test `@roomote/api` locally:
```sh
curl -X GET "http://localhost:13001/trpc/auth.me" \
-H "Authorization: Bearer $(pnpm --silent --filter @roomote/auth development:create-auth-token local@roomote.dev local 3600000)" \
-H "Content-Type: application/json" | jq
```
### Checking staged changes with Judgement
The pre-commit hook runs Judgement after `lint-staged`, so it checks the formatted
staged snapshot. Confirmed violations and invalid policies block the commit;
incomplete checks report their status and allow the commit after a three-second
check deadline. In managed Roomote tasks, this repository hook only formats;
the worker-installed wrapper runs Judgement once through task inference, even
when the proxy is unavailable.
Run `pnpm judgement --verbose` from the Roomote checkout to check staged changes
against `.judgement/rules.json`. The command loads `.env.local` and uses the same deployment
judgment-model settings and encrypted provider credentials as the local API.
The local database must be running. Select Jev through TypeSafe, OpenRouter, or
Vercel AI Gateway in **Settings → Models**; `R_JUDGMENT_MODEL` overrides that choice.
You do not need the standalone CLI's `TYPESAFE_API_KEY` variable.
`--verbose` shows model outcomes and confidence scores. An outcome below the
rule's confidence threshold remains incomplete, including a low-confidence
violation. The command exits unsuccessfully for violations or incomplete checks.
Use `--dry-run` to inspect evidence planning without database or model access,
or `--format json` for the report as JSON. Checks are not cached because the
configured inference backend can change. Managed task hooks use the same API
inference settings through a worker-owned local proxy and retain their
three-second deadline.
Run `pnpm judgement test` to evaluate the labeled examples under
`.judgement/examples/` at their configured thresholds. Use `--rule criterion_8`
to select a rule and `--dry-run` to validate inputs without inference. To compare
thresholds, run `pnpm judgement calibrate --rule criterion_8 --thresholds 0.8,0.85,0.9`
or use `--all` to include every rule. Judgement owns the test and calibration
runner; Roomote supplies its inference adapter. Live runs make model requests.
Generated reports belong in local output or CI artifacts. See
[the agent guide](https://github.com/RooCodeInc/judgement/blob/main/docs/agents.md)
for labeling examples and interpreting results.