Complete guide for deploying Writeo to production.
- Test locally:
wrangler devandnpm run dev - Choose operational mode coverage: Production (Recommended) or Legacy/Minimal
- Verify all secrets are set (see Step 3)
- Run tests:
npm run test:all(or let pre-push hook handle it) - Code is formatted:
npm run format:check - Type checking passes:
npm run type-check
Writeo's architecture has evolved to use specialized models for different tasks.
Uses the full suite of high-performance models for maximum accuracy:
- AES-DEBERTA: Primary assessor (Dimensional scoring, DeBERTa-v3-large)
- GEC-SEQ2SEQ: High-precision grammar correction (Flan-T5-base)
- GEC-GECTOR: Low-latency grammar correction (RoBERTa-base)
Cost: Variable based on usage (Modal GPU time + LLM tokens). Performance: High accuracy, parallel execution of scoring and correction.
Uses fewer models to save costs:
- LanguageTool: Rule-based grammar checking (CPU-only)
- AES-DEBERTA: (Optional) Can be disabled for CPU-only operation, but scoring will be skipped.
Note: The application is configured to prefer the Production models (AES-DEBERTA) by default. Running in minimal mode requires adjusting apps/api-worker/src/config/assessors.json.
Tip
Use the automated scripts (./scripts/deploy-all.sh, ./scripts/deploy-modal.sh) for a quick start. For a full manual deployment, follow the Step-by-Step Deployment below.
Run the setup script (creates R2 bucket and KV namespace):
./scripts/setup.shOr manually:
wrangler r2 bucket create writeo-data-1
wrangler kv:namespace create "WRITEO_RESULTS" # Copy ID to wrangler.toml
wrangler kv:namespace create "WRITEO_RESULTS" --preview # Copy preview_idDeploy the services required for your chosen operational mode.
Prerequisites:
- Install Modal:
uv pip install modal - Authenticate:
modal token new
Dimensional scoring model (DeBERTa-v3-large).
cd services/modal-deberta
modal deploy app.py
# Copy the endpoint URLHigh-precision grammar correction (Flan-T5).
cd services/modal-gec
modal deploy main.py
# Copy the endpoint URLFast, token-classification based correction.
cd services/modal-gector
modal deploy main.py
# Copy the endpoint URLExperimental model for span-level feedback.
cd services/modal-feedback
modal deploy app.py
# Copy the endpoint URLRule-based grammar checking.
cd services/modal-lt
modal deploy app.py
# Copy the endpoint URLSet the secrets in Cloudflare Workers to connect your API to the deployed services.
cd apps/api-worker
# --- Service URLs ---
# Primary Scorer (DeBERTa)
wrangler secret put MODAL_DEBERTA_URL
# Paste modal-deberta URL
# Grammar Correction (Seq2Seq)
wrangler secret put MODAL_GEC_URL
# Paste modal-gec URL
# Fast Grammar Correction (GECToR)
wrangler secret put MODAL_GECTOR_URL
# Paste modal-gector URL
# Feedback Model (Optional)
wrangler secret put MODAL_FEEDBACK_URL
# Paste modal-feedback URL
# LanguageTool (Optional)
wrangler secret put MODAL_LT_URL
# Paste modal-lt URL
# --- API Configuration ---
# Set API authentication key
wrangler secret put API_KEY
# Paste your API key (generate a secure random string)
# Test API Key (Optional, for higher rate limits)
wrangler secret put TEST_API_KEY
# Paste a secondary key
# --- LLM Provider ---
# Helper: Set provider ("openai" or "groq")
wrangler secret put LLM_PROVIDER
# If using OpenAI:
wrangler secret put OPENAI_API_KEY
# Paste OpenAI Key
# If using Groq:
wrangler secret put GROQ_API_KEY
# Paste Groq Key- Check
apps/api-worker/wrangler.toml:- R2 bucket:
writeo-data-1 - KV namespace IDs present
- R2 bucket:
- Check
apps/api-worker/src/config/assessors.json:- Ensure the flags (e.g.,
"deberta": true) match the services you deployed. Disable any services you didn't deploy to prevent errors.
- Ensure the flags (e.g.,
cd apps/api-worker
wrangler deployTest health: curl https://your-worker.workers.dev/health
cd apps/web
npm run deployThe repository includes .github/workflows/deploy-and-test.yml.
Ensure you add the following secrets to your GitHub repository for it to work:
CLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_IDAPI_KEY
Note: The GitHub Action currently deploys the Worker and Web App. It does not automatically deploy Modal services. You must deploy those manually using the steps above.
- Check
apps/api-workerlogs:wrangler tail - Verify the specific
MODAL_*_URLsecret is correct. - Ensure the service is running in Modal dashboard.
- If a service is missing, disable it in
assessors.jsonand redeploy the worker.
- Ensure you set the
MODAL_API_KEYsecret within Modal if your services require it (check individual serviceapp.py/main.py). Not all services enforce this at the Modal layer, but it's best practice.
- Use
assessors.jsonto disable expensive models (e.g.,deberta,gecSeq2seq) if not needed for development. - Adjust
SCALEDOWN_WINDOW_SECONDSin each Modal app file to control keep-warm costs.