# Self-Hosting

Deploy Specwright to your own Kubernetes cluster using the provided Helm chart.

## Prerequisites

- Kubernetes 1.25+
- Helm 3.x
- A GitHub App (see [GitHub App Setup](./github-app))
- An Anthropic API key
- (Optional) Jira, Linear, or GitHub Issues for ticket sync

## 1. Create Kubernetes Secrets

Create secrets before installing the chart, or let the chart create them for you.

### Option A: Let the Chart Manage Secrets

Set values directly in your `values.yaml` (not recommended for production):

```yaml
secrets:
  githubApp:
    appId: "123456"
    privateKey: |
      -----BEGIN RSA PRIVATE KEY-----
      ...
      -----END RSA PRIVATE KEY-----
    webhookSecret: "your-webhook-secret"
    installationId: "789012"
  anthropic:
    apiKey: "sk-ant-..."
```

### Option B: Use Existing Secrets (Recommended)

Create secrets manually, then reference them:

```bash
# GitHub App credentials
kubectl create secret generic specwright-github \
  --from-literal=app-id=123456 \
  --from-file=private-key=./your-app.pem \
  --from-literal=webhook-secret=$(openssl rand -hex 32) \
  --from-literal=installation-id=789012

# Anthropic API key
kubectl create secret generic specwright-anthropic \
  --from-literal=api-key=sk-ant-...

# Jira credentials (if using Jira)
kubectl create secret generic specwright-jira \
  --from-literal=host=yourcompany.atlassian.net \
  --from-literal=email=specwright@yourcompany.com \
  --from-literal=api-token=your-jira-api-token
```

Then in `values.yaml`:

```yaml
secrets:
  githubApp:
    existingSecret: "specwright-github"
  anthropic:
    existingSecret: "specwright-anthropic"
  jira:
    existingSecret: "specwright-jira"
```

### Auth0 (Optional)

If you want web login, CLI auth (`specwright login`), or role-based access control, configure an Auth0 tenant. See the [GitHub App Setup](./github-app) guide for Auth0 configuration, then create the secret:

```bash
kubectl create secret generic specwright-auth0 \
  --from-literal=domain=your-tenant.auth0.com \
  --from-literal=client-id=your-client-id \
  --from-literal=client-secret=your-client-secret \
  --from-literal=audience=https://specwright.yourcompany.com/api \
  --from-literal=device-client-id=your-device-client-id  # optional
```

`AUTH0_AUDIENCE` is **required** for JWT validation — without it, device auth (CLI login) and server-proxied ticket sync will not work.

```yaml
secrets:
  auth0:
    existingSecret: "specwright-auth0"
```

## 2. Install with Helm

Minimal install:

```bash
helm install specwright chart/specwright/ \
  --set secrets.githubApp.appId=123456 \
  --set secrets.githubApp.webhookSecret=your-secret \
  --set secrets.githubApp.installationId=789012 \
  --set secrets.anthropic.apiKey=sk-ant-... \
  --set-file secrets.githubApp.privateKey=./your-app.pem
```

Production install with custom values:

```bash
helm install specwright chart/specwright/ -f values-production.yaml
```

Example `values-production.yaml`:

```yaml
image:
  registry: ghcr.io
  repository: your-org/specwright
  tag: "latest"

ingress:
  enabled: true
  hostname: specwright.yourcompany.com
  ingressClassName: nginx
  tls: true
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod

secrets:
  githubApp:
    existingSecret: specwright-github
  anthropic:
    existingSecret: specwright-anthropic
  jira:
    existingSecret: specwright-jira

cronJob:
  enabled: true
  schedule: "*/15 * * * *"

resources:
  limits:
    cpu: 500m
    memory: 256Mi
  requests:
    cpu: 100m
    memory: 128Mi
```

## 3. Build and Push the Docker Image

```bash
# Build
docker build -t specwright:latest .

# Tag for your registry
docker tag specwright:latest ghcr.io/your-org/specwright:latest

# Push
docker push ghcr.io/your-org/specwright:latest
```

## 4. Configure Target Repos

Add a `SPECWRIGHT.yaml` to each repo you want Specwright to manage. See [Configuration](/getting-started/configuration) for the full reference.

Minimal:

```yaml
version: "1"

specs:
  paths:
    - "docs/specs/*.md"

agents:
  pr_analysis: true
```

## 5. Jira Setup

If using Jira for ticket sync:

1. Create a **service account** or use an existing Jira user
2. Generate an **API token** at `https://id.atlassian.com/manage-profile/security/api-tokens`
3. Ensure the Jira project has these workflow statuses (or map custom ones): `Backlog`, `To Do`, `In Progress`, `Done`
4. The service account needs project-level permissions to create and transition issues

## 6. Verify the Deployment

```bash
# Check pods are running
kubectl get pods -l app.kubernetes.io/name=specwright

# Check health endpoint
kubectl port-forward svc/specwright 8080:80
curl http://localhost:8080/healthz

# Check logs
kubectl logs -l app.kubernetes.io/name=specwright -f

# Run Helm tests
helm test specwright
```

## Troubleshooting

### Webhooks Not Arriving

1. Check GitHub App webhook deliveries: **App Settings > Advanced > Recent Deliveries**
2. Verify the webhook URL matches your ingress hostname + `/webhook`
3. Check the webhook secret matches what's in your K8s secret
4. Ensure the GitHub App is installed on the target org/repos

### Signature Verification Failures

- The webhook secret in K8s must exactly match the one configured in GitHub App settings
- Check for trailing newlines in the secret value

### Cron Job Not Running

```bash
# Check CronJob status
kubectl get cronjobs -l app.kubernetes.io/name=specwright

# Check recent Job runs
kubectl get jobs -l app.kubernetes.io/name=specwright

# Check Job logs
kubectl logs job/specwright-sync-status-<timestamp>
```

### Jira Connection Errors

- Verify `JIRA_HOST` doesn't include `https://` prefix (just `yourcompany.atlassian.net`)
- Test credentials: `curl -u email:api-token https://yourcompany.atlassian.net/rest/api/3/myself`
- Check the project key exists and the service account has access
