From otoshek-local-setup
Set up a complete Otoshek local development environment from scratch. Installs system dependencies (Homebrew, Git, SSH, mkcert, PostgreSQL, Python 3.13, Node.js), configures SSL certificates, creates databases, sets up Django backend and React frontend, and configures Stripe integration. Use when (1) setting up a new development machine for Otoshek, (2) user says "set up my local environment" or "local setup", (3) user wants to configure their machine to develop Otoshek locally. Supports macOS, Linux, and Windows. Auto-detects what is already installed and skips completed steps. Expects a Git SSH repo URL as argument, e.g. "/otoshek-local-setup [email protected]:user/repo.git".
How this skill is triggered — by the user, by Claude, or both
Slash command
/otoshek-local-setup:otoshek-local-setupThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Set up a complete local development environment for the Otoshek project.
Set up a complete local development environment for the Otoshek project.
/otoshek-local-setup [email protected]:USER/REPO.git
The user should launch Claude from the parent directory where they want the project cloned. For example, if they run Claude from ~/Projects, the repo will be cloned into ~/Projects/REPO/.
[email protected]:USER/REPO.git — use as-ishttps://github.com/USER/REPO — convert to [email protected]:USER/REPO.git~/.ssh/config for a GitHub host alias (e.g., Host github.com-work). If an alias exists, replace github.com with the alias in the SSH URL (e.g., [email protected]:USER/REPO.git).REPO_NAME from the URL (last path segment without .git).PROJECT_ROOT to <CWD>/<REPO_NAME> — this is the absolute path used for ALL file operations from step 3 onward.uname -s (Darwin = macOS, Linux = Linux). On Windows, check for C:\Windows.tail -10 to conserve context (e.g., brew install postgresql@17 2>&1 | tail -10). Always verify installation with a separate version check afterward.Each Claude Code Bash tool call runs in a fresh, non-login shell. This has critical implications:
PATH changes, virtual environment activations, environment variable exports, and cd all reset between Bash calls. You must re-establish state in every call.mkcert -install). If a step fails because a tool is missing, print the exact install command for the user to run, then wait for them to confirm before continuing.AskUserQuestion requires 2-4 options (always provide at least 2). Write and Edit tools require a Read first if the file may already exist.Every Bash command that needs brew-installed tools, PostgreSQL CLI, or the Python venv must chain the relevant prefixes:
| Variable | Value (macOS) | Needed after |
|---|---|---|
BREW_PREFIX | eval "$(/opt/homebrew/bin/brew shellenv)" && | Step 1 |
PG_PATH | export PATH="/opt/homebrew/opt/postgresql@<VERSION>/bin:$PATH" && | Step 4 |
VENV_ACTIVATE | source $PROJECT_ROOT/.venv/bin/activate && | Step 6 |
Usage pattern: BREW_PREFIX + PG_PATH + VENV_ACTIVATE + <command>
Example (Django management command):
eval "$(/opt/homebrew/bin/brew shellenv)" && export PATH="/opt/homebrew/opt/postgresql@17/bin:$PATH" && source $PROJECT_ROOT/.venv/bin/activate && python $PROJECT_ROOT/manage.py migrate
Linux note: BREW_PREFIX uses eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)". PG_PATH is not needed on Linux (apt puts psql in the system PATH).
Check: brew --version
BREW_PREFIX and continueOnce Homebrew is confirmed present, set BREW_PREFIX for all subsequent commands (eval "$(/opt/homebrew/bin/brew shellenv)" && on macOS, eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" && on Linux).
Git: Check git --version. If missing, install using OS-specific command from references/os-commands.md.
SSH for GitHub: Test the connection directly first — this is the most reliable signal:
ssh -T [email protected] 2>&1
ls ~/.ssh/*.pub — look for ANY public keys (users often have custom names like id_ed25519_work, id_ed25519_personal, etc.)cat ~/.ssh/config — check for GitHub host entries (e.g., Host github.com or aliases like github.com-work)ssh -T failed, the issue is likely agent/config, not missing keys. Debug rather than regenerate.ssh-keygen -t ed25519 -C "user_email"Only if a new key was generated — PAUSE for human action:
I've copied your SSH public key to the clipboard. Add it to GitHub:
- Go to GitHub → Settings → SSH and GPG keys
- Click "New SSH key", paste, and save
- Tell me when done.
After any path above, verify: ssh -T [email protected]
Clone: Run git clone <REPO_URL> in the current working directory. This creates <CWD>/<REPO_NAME>/. Set PROJECT_ROOT to the absolute path of this directory. Confirm by checking that $PROJECT_ROOT/manage.py exists.
From this point forward, ALL file paths are absolute using $PROJECT_ROOT:
$PROJECT_ROOT/backend/settings.py$PROJECT_ROOT/.vscode/launch.json$PROJECT_ROOT/frontend/vite.config.js$PROJECT_ROOT/.env.development$PROJECT_ROOT/requirements.txtVS Code: Check code --version
code $PROJECT_ROOTcode $PROJECT_ROOTCheck: eval "$(/opt/homebrew/bin/brew shellenv)" && mkcert -version
Install the local CA (requires password — if it fails, print the command and ask the user to run it):
eval "$(/opt/homebrew/bin/brew shellenv)" && mkcert -install 2>&1 | tail -5
Check for existing certificates before generating:
CERT_FILE=~/certs/localhost+2.pem
KEY_FILE=~/certs/localhost+2-key.pem
openssl x509 -enddate -noout -in ~/certs/localhost+2.pem
Generate certificates (only if missing or expired):
eval "$(/opt/homebrew/bin/brew shellenv)" && mkdir -p ~/certs && cd ~/certs && mkcert localhost 127.0.0.1 ::1
Get absolute cert paths:
CERT_FILE=$(realpath ~/certs/localhost+2.pem)
KEY_FILE=$(realpath ~/certs/localhost+2-key.pem)
Configure settings.json: First Read $PROJECT_ROOT/.vscode/settings.json (it may already exist). Then create or update it to prevent Python from auto-activating the venv in integrated terminals (which breaks the frontend terminal):
{
"python.terminal.activateEnvironment": false,
"python.terminal.activateEnvInCurrentTerminal": false
}
Configure launch.json: First Read $PROJECT_ROOT/.vscode/launch.json (it may already exist). Then create or update it. Include both backend and frontend configs, plus a compound to launch both with a single F5:
{
"version": "0.2.0",
"configurations": [
{
"name": "Django_server",
"type": "debugpy",
"request": "launch",
"python": "${workspaceFolder}/.venv/bin/python",
"program": "manage.py",
"args": [
"runserver_plus",
"localhost:8000",
"--cert-file",
"$CERT_FILE",
"--key-file",
"$KEY_FILE"
],
"django": true,
"justMyCode": true,
"env": { "PYTHONUNBUFFERED": "1" },
"cwd": "${workspaceFolder}",
"console": "integratedTerminal"
},
{
"name": "Frontend_Dev",
"type": "pwa-node",
"request": "launch",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "dev"],
"cwd": "${workspaceFolder}/frontend",
"console": "integratedTerminal",
"skipFiles": ["<node_internals>/**"]
}
],
"compounds": [
{
"name": "Django + Frontend",
"configurations": [
"Django_server",
"Frontend_Dev"
],
"stopAll": true
}
]
}
The user can select "Django + Frontend" from the debug dropdown to start both servers at once. Each opens in its own integrated terminal.
Configure vite.config.js: Read $PROJECT_ROOT/frontend/vite.config.js first, then Edit the https section:
https: {
key: fs.readFileSync(path.resolve(__dirname, '$KEY_FILE')),
cert: fs.readFileSync(path.resolve(__dirname, '$CERT_FILE')),
},
Check version: eval "$(/opt/homebrew/bin/brew shellenv)" && psql --version
eval "$(/opt/homebrew/bin/brew shellenv)" && brew install postgresql@17 2>&1 | tail -10
After install (or if already installed), define PG_PATH using the detected version. All subsequent psql, createdb, and pg_isready commands must be prefixed with both BREW_PREFIX and PG_PATH.
Check if already running:
eval "$(/opt/homebrew/bin/brew shellenv)" && export PATH="/opt/homebrew/opt/postgresql@<VERSION>/bin:$PATH" && pg_isready -q
eval "$(/opt/homebrew/bin/brew shellenv)" && brew services start postgresql@<INSTALLED_VERSION> 2>&1 | tail -5
sudo systemctl start postgresql (user must run manually)eval "$(/opt/homebrew/bin/brew shellenv)" && export PATH="/opt/homebrew/opt/postgresql@<VERSION>/bin:$PATH" && pg_isready -q
Replace
<VERSION>with the actual detected PostgreSQL major version throughout this step.
Create superuser:
eval "$(/opt/homebrew/bin/brew shellenv)" && export PATH="/opt/homebrew/opt/postgresql@<VERSION>/bin:$PATH" && createuser -s postgres 2>/dev/null || true
Create a fresh database. Never drop or modify existing databases. Pick a unique name by checking what already exists:
eval "$(/opt/homebrew/bin/brew shellenv)" && export PATH="/opt/homebrew/opt/postgresql@<VERSION>/bin:$PATH" && DB_NAME="local_otoshek" && while psql -U postgres -tAc "SELECT 1 FROM pg_database WHERE datname = '$DB_NAME'" | grep -q 1; do DB_NAME="local_otoshek_$((++i))"; done && createdb -U postgres -O postgres "$DB_NAME" && echo "Created database: $DB_NAME"
Remember the final DB_NAME — use it in Step 5 when configuring settings.py.
Tell the user which database name was created (especially if it wasn't the default).
eval "$(/opt/homebrew/bin/brew shellenv)" && export PATH="/opt/homebrew/opt/postgresql@<VERSION>/bin:$PATH" && psql -U postgres -tAc "SELECT datname FROM pg_database WHERE datname = '$DB_NAME'"
Read $PROJECT_ROOT/backend/settings.py first, then Edit the DATABASES section — use the $DB_NAME from Step 4:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': '$DB_NAME', # use the actual name created in Step 4
'USER': 'postgres',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '5432',
'OPTIONS': {'sslmode': 'disable'},
}
}
Check: eval "$(/opt/homebrew/bin/brew shellenv)" && python3.13 --version
Create venv and install deps:
eval "$(/opt/homebrew/bin/brew shellenv)" && python3.13 -m venv $PROJECT_ROOT/.venv
eval "$(/opt/homebrew/bin/brew shellenv)" && source $PROJECT_ROOT/.venv/bin/activate && pip install -r $PROJECT_ROOT/requirements.txt 2>&1 | tail -10
From this point forward, prepend
VENV_ACTIVATE(source $PROJECT_ROOT/.venv/bin/activate &&) to every Python/pip/Django command. On Windows use$PROJECT_ROOT\.venv\Scripts\activateinstead.
eval "$(/opt/homebrew/bin/brew shellenv)" && export PATH="/opt/homebrew/opt/postgresql@<VERSION>/bin:$PATH" && source $PROJECT_ROOT/.venv/bin/activate && python $PROJECT_ROOT/manage.py migrate
Replace
<VERSION>with the actual PostgreSQL version detected in Step 4.
This step is fully automated. Create a superuser with simple credentials for local development:
eval "$(/opt/homebrew/bin/brew shellenv)" && export PATH="/opt/homebrew/opt/postgresql@<VERSION>/bin:$PATH" && source $PROJECT_ROOT/.venv/bin/activate && python $PROJECT_ROOT/manage.py shell -c "
from django.contrib.auth import get_user_model
User = get_user_model()
if not User.objects.filter(username='admin').exists():
User.objects.create_superuser(username='admin', email='[email protected]', password='admin1234')
print('Superuser created: admin / admin1234')
else:
print('Superuser already exists')
"
Replace
<VERSION>with the actual PostgreSQL version detected in Step 4.
Tell the user: admin panel is at https://localhost:8000/admin (credentials: admin / admin1234).
PAUSE — Human action required: Ask the user to provide their credentials. They need to provide ALL of the following:
sk_test_)LLM API keys (OpenAI or Google) are optional at this stage — see the note below.
Tell the user where to find each value:
Create $PROJECT_ROOT/.env.development with their values:
# Backend and Frontend URLs
FRONTEND_URL="https://localhost:5173"
BACKEND_URL="https://localhost:8000"
# Django Superuser (local dev only)
DJANGO_SUPERUSER_USERNAME=admin
[email protected]
DJANGO_SUPERUSER_PASSWORD=admin1234
# Google OAuth
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
# Email Configuration
DEFAULT_FROM_EMAIL=
MAILJET_API_URL=https://api.mailjet.com/v3.1/
MJ_APIKEY_PUBLIC=
MJ_APIKEY_PRIVATE=
# Stripe Price IDs
STRIPE_PREMIUM_MONTHLY_PRICE_ID=
STRIPE_PREMIUM_YEARLY_PRICE_ID=
STRIPE_STANDARD_MONTHLY_PRICE_ID=
STRIPE_STANDARD_YEARLY_PRICE_ID=
STRIPE_STARTER_MONTHLY_PRICE_ID=
STRIPE_STARTER_YEARLY_PRICE_ID=
# SEO — set to true when ready for search engines to index your site
# Switches robots.txt from Disallow: / to Allow: / and adds a sitemap reference
SEO_ENABLED=
# LLM API Keys (optional — see note below)
OPENAI_API_KEY=
GOOGLE_API_KEY=
Note on LLM API keys: If neither OPENAI_API_KEY nor GOOGLE_API_KEY is set, the app's chat assistant will not work. This is intentional — the chat is designed to be grounded on information specific to the product being built, so it should be configured deliberately rather than working out of the box with a generic model. The same applies to the deployed app: no LLM key is set in production by default.
You are not limited to OpenAI or Google. The app uses LangChain, which supports a wide range of model providers (Anthropic, Mistral, Ollama, etc.). LangChain's documentation makes it straightforward to swap in any supported model. To enable the chat assistant, add the appropriate API key and update the model configuration when you're ready.
Verify .env.development is listed in $PROJECT_ROOT/.gitignore.
This step is fully automated — no human action needed.
Insert the Stripe test key into the database using the sk_test_ key from step 9. The database is always fresh (created in Step 4), so insert directly without checking:
eval "$(/opt/homebrew/bin/brew shellenv)" && export PATH="/opt/homebrew/opt/postgresql@<VERSION>/bin:$PATH" && source $PROJECT_ROOT/.venv/bin/activate && python $PROJECT_ROOT/manage.py shell -c "
from djstripe.models import APIKey
stripe_key = 'sk_test_...' # use the actual key from step 9
is_test = 'sk_test_' in stripe_key
APIKey.objects.create(
secret=stripe_key,
livemode=not is_test
)
print('API key added successfully')
"
Replace
<VERSION>with the actual PostgreSQL version detected in Step 4.
Sync Stripe data:
eval "$(/opt/homebrew/bin/brew shellenv)" && export PATH="/opt/homebrew/opt/postgresql@<VERSION>/bin:$PATH" && source $PROJECT_ROOT/.venv/bin/activate && python $PROJECT_ROOT/manage.py djstripe_sync_models price plan product customer subscription WebhookEndpoint 2>&1 | tail -5
This pulls products, prices, plans, customers, subscriptions, and webhook endpoints from Stripe test mode into the local database.
Check: node --version (v18+ recommended)
eval "$(/opt/homebrew/bin/brew shellenv)" && cd $PROJECT_ROOT/frontend && npm install
Create $PROJECT_ROOT/frontend/.env.local with the optional feature variables (commented out — uncomment when ready to use):
cat > $PROJECT_ROOT/frontend/.env.local << 'EOF'
# Analytics — Google Analytics + Microsoft Clarity via Google Tag Manager
# Get your GTM container ID from tagmanager.google.com
# Setting this activates tracking scripts and shows the cookie consent banner
# VITE_GTM_ID=GTM-XXXXXXX
# SEO — removes noindex from all pages and enables per-page titles/descriptions
# Must also set SEO_ENABLED=true in .env.development (controls robots.txt)
# VITE_SEO_ENABLED=true
EOF
Do NOT run npm run dev here — the frontend dev server is launched automatically via the "Django + Frontend" compound in launch.json (Step 3).
Tell the user:
Setup complete! To start developing:
- Open the project in VS Code:
code $PROJECT_ROOT- Important: Select "Django + Frontend" from the debug dropdown (top of the Run and Debug sidebar). By default VS Code selects "Django_server" only — you must switch to the compound once. VS Code will remember your selection for subsequent launches.
- Press F5 — this launches both the Django backend and the frontend dev server in separate integrated terminals
- Open https://localhost:5173 (must use
https://, nothttp://)- You should see the application interface
- Try signing in with Google OAuth and testing subscription features
npx claudepluginhub otoshek/otoshek-local-setup --plugin otoshek-local-setupBootstraps new Django projects or adds production components (auth, payments, async/WebSockets, Docker, CI/CD, Tailwind+DaisyUI, S3, Sentry) to existing codebases.
Guides deploying apps to Vercel, Railway, Netlify, and others; covers hosting selection, custom domains, env vars, production DBs, DNS, and going live.
Sets up Django 6.0 project with uv, direnv, HTMX, OAuth, DRF, Pydantic, pytest, mypy, ruff, Docker PostgreSQL or Supabase, custom user model, and full type annotations. Use for production-ready Django from scratch.