> ## Documentation Index
> Fetch the complete documentation index at: https://docs.causeloop.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Local Development

> Run Causeloop on your machine in minutes — with or without a database.

You do not need a database to run Causeloop locally. When `DATABASE_URL` is unset, the app uses a fast in-memory store that is seeded with demo data. Add an LLM key only if you want real AI responses; the offline mock works for everything else.

## Option A — Python virtualenv (recommended)

<Steps>
  <Step title="Clone the repository">
    ```bash theme={null}
    git clone https://github.com/your-org/causeloop-backend.git
    cd causeloop-backend
    ```
  </Step>

  <Step title="Create a virtualenv and install dependencies">
    ```bash theme={null}
    python3 -m venv .venv
    .venv/bin/pip install --upgrade pip
    .venv/bin/pip install -r requirements.txt
    ```

    Or use the `make` shortcut:

    ```bash theme={null}
    make install
    ```
  </Step>

  <Step title="Configure your environment">
    ```bash theme={null}
    cp .env.example .env
    ```

    Open `.env`. For local development the defaults are fine — you only need to change values if you want a real database or real LLM responses:

    ```env theme={null}
    PORT=4000
    JWT_SECRET=dev-secret-change-me   # OK for local only
    CORS_ORIGINS=http://localhost:3000

    # Optionally add a key for real AI responses:
    # ANTHROPIC_API_KEY=sk-ant-...

    # Optionally point at a local Postgres:
    # DATABASE_URL=postgresql://localhost:5432/causeloop
    # CAUSELOOP_MASTER_KEY=<base64-32-bytes>
    ```
  </Step>

  <Step title="Start the dev server">
    ```bash theme={null}
    .venv/bin/uvicorn app.main:app --port 4000 --reload
    ```

    Or with `make`:

    ```bash theme={null}
    make dev
    ```

    The server starts on `http://localhost:4000`. Hot-reload is on by default with `--reload`.
  </Step>

  <Step title="Explore the API">
    Open the interactive docs in your browser:

    * **Swagger UI:** `http://localhost:4000/docs`
    * **OpenAPI schema:** `http://localhost:4000/openapi.json`
    * **Health check:** `http://localhost:4000/health`
  </Step>
</Steps>

## Option B — Docker (no Python install required)

<Steps>
  <Step title="Build the image">
    ```bash theme={null}
    docker build -t causeloop-backend .
    ```
  </Step>

  <Step title="Run the container">
    ```bash theme={null}
    docker run -p 4000:4000 --env-file .env causeloop-backend
    ```

    To run in mock LLM mode without an `.env` file:

    ```bash theme={null}
    make docker-run-mock
    # equivalent to:
    docker run --rm -p 4000:4000 \
      -e JWT_SECRET=dev-secret \
      -e USE_MOCK_LLM=true \
      -e CORS_ORIGINS=http://localhost:3000 \
      causeloop-backend:latest
    ```
  </Step>
</Steps>

## Available `make` targets

Run `make help` to see all targets:

| Target                 | Description                                                 |
| ---------------------- | ----------------------------------------------------------- |
| `make install`         | Create `.venv` and install `requirements.txt`               |
| `make dev`             | Start dev server with hot reload on `$PORT` (default 4000)  |
| `make dev-log`         | Dev server with JSON access logs enabled                    |
| `make test`            | Run pytest test suite                                       |
| `make lint`            | Lint with ruff                                              |
| `make typecheck`       | Type-check with mypy                                        |
| `make migrate`         | Apply forward-only SQL migrations (requires `DATABASE_URL`) |
| `make docker-build`    | Build the Docker image as `causeloop-backend:latest`        |
| `make docker-run`      | Run the Docker image using `.env`                           |
| `make docker-run-mock` | Run in mock LLM mode (no `.env` needed)                     |
| `make clean`           | Remove `.venv` and cache directories                        |

## Getting a token without an identity provider

For local development you don't need a WorkOS (or any) account. Two options, both requiring `ENVIRONMENT` to not be `production`:

**Option 1 — mint a token directly.** `scripts/mint_dev_token.py` signs a scoped Causeloop JWT for a given `workspace_id` and `user_id`, bypassing `/auth/exchange` entirely:

```bash theme={null}
TOKEN=$(.venv/bin/python -m scripts.mint_dev_token ws_01 usr_01)
curl -s http://localhost:4000/v1/issues -H "Authorization: Bearer $TOKEN"
```

**Option 2 — exercise the real exchange endpoint.** With `AUTH_PROVIDER=none` (or unset, since `WORKOS_CLIENT_ID` is empty by default) set in the launch env, `POST /v1/auth/exchange` accepts any non-empty `subject_token` and returns a token for the first seed user — this path does not run admission, so it works without any provisioning data:

```bash theme={null}
curl -s -X POST http://localhost:4000/v1/auth/exchange \
  -H "Content-Type: application/json" \
  -d '{"subject_token": "dev"}'
```

<Note>
  A repo `.env` that pins `ENVIRONMENT=production` will shadow your shell — process env beats `.env`, so export `ENVIRONMENT=development AUTH_PROVIDER=none` explicitly in your launch env if the server refuses to start or exchange returns `503`.
</Note>

## Connecting a local database

If you want to run against a real Postgres instance during development:

<Steps>
  <Step title="Start Postgres">
    ```bash theme={null}
    # macOS with Homebrew
    brew services start postgresql@16

    # or Docker
    docker run -d -e POSTGRES_DB=causeloop -e POSTGRES_USER=causeloop \
      -e POSTGRES_PASSWORD=localpass -p 5432:5432 postgres:16-alpine
    ```
  </Step>

  <Step title="Set DATABASE_URL and master key">
    In your `.env`:

    ```env theme={null}
    DATABASE_URL=postgresql://causeloop:localpass@localhost:5432/causeloop
    CAUSELOOP_MASTER_KEY=<output of: python3 -c "import os,base64;print(base64.b64encode(os.urandom(32)).decode())">
    ```
  </Step>

  <Step title="Load the schema and reference data">
    ```bash theme={null}
    psql "$DATABASE_URL" -f db/schema.sql
    psql "$DATABASE_URL" -f db/seed_reference.sql
    psql "$DATABASE_URL" -f db/onboard_client.sql
    ```

    See [Database setup](/deploy-security/database) for the full guide including migrations and RLS role requirements.
  </Step>

  <Step title="Apply migrations">
    ```bash theme={null}
    make migrate
    ```
  </Step>
</Steps>
