Metadata-Version: 2.4
Name: deathstar-ai
Version: 0.19.8
Summary: Secure AWS-hosted remote AI coding workstation with a provider-agnostic local CLI.
Author: DeathStar contributors
License: AGPL-3.0-or-later
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: alembic>=1.15.0
Requires-Dist: anthropic>=0.42.0
Requires-Dist: boto3>=1.34.0
Requires-Dist: claude-agent-sdk>=0.1.0
Requires-Dist: fastapi>=0.115.0
Requires-Dist: githubkit>=0.15.0
Requires-Dist: google-auth>=2.29.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: psycopg2-binary>=2.9.10
Requires-Dist: pydantic>=2.8.0
Requires-Dist: sqlmodel>=0.0.24
Requires-Dist: typer>=0.12.0
Requires-Dist: unidiff>=0.7.0
Requires-Dist: uvicorn[standard]>=0.30.0
Provides-Extra: dev
Requires-Dist: pre-commit>=3.7.0; extra == "dev"
Requires-Dist: pytest>=8.2.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.24.0; extra == "dev"
Requires-Dist: ruff>=0.5.0; extra == "dev"
Dynamic: license-file

# DeathStar

DeathStar is an open-source, Terraform-built remote AI coding workstation for AWS — powered by Claude Code.

- AWS single-instance deployment via Terraform
- Tailscale-first private networking (no public SSH)
- Persistent EBS-backed workspace
- Python CLI for infrastructure management
- Claude Code Agent SDK for interactive AI coding sessions
- Linear and GitHub integrations with real-time event sync
- PostgreSQL-backed persistence for conversations, memories, and documents

The web UI provides an experience similar to having Claude Code in a terminal — you type prompts, see streaming output with tool use and thinking, and can respond to questions or approve permissions interactively. Different workflow modes (Chat, Code, Review, Docs, Audit, Plan) configure the agent with appropriate tools and permissions.

## What You Get

- **Remote AI workstation** — Claude Code accessible from any device over Tailscale
- **Interactive agent sessions** — real-time streaming with tool use visualization, thinking, and permission flow
- **Concurrent agent worktrees** — each session runs in an isolated git worktree so you can switch branches without affecting a running agent
- **Workflow modes** — Chat, Code, Code+PR, Review, Docs, Audit, and Plan modes with tailored tool sets and plugins
- **Structured code reviews** — severity-rated findings with inline code suggestions and one-click apply to PRs
- **Implementation planning** — phased task breakdowns with effort estimates, risks, and push-to-Linear for issue creation
- **Linear integration** — bidirectional sync between Linear issues and branches, webhook delivery via Tailscale Funnel, polling fallback
- **GitHub integration** — PR creation, branch management, webhook-driven event streaming, and a polling fallback
- **Event bus** — real-time pub/sub for repo events (push, PR, CI status, agent completion) forwarded to WebSocket clients
- **Message queue** — background processing of queued prompts via the Claude Agent SDK
- **Memory bank** — save key learnings from conversations as persistent context for future prompts
- **Documents** — tech specs, plans, and notes stored per-repo with structured distillation from conversations
- **Preview deployments** — trigger Render or Vercel previews for pull requests from the UI
- **Remote terminal** — WebSocket PTY (xterm.js) with zsh, resize, and up to 4 concurrent sessions
- **Conversation persistence** — PostgreSQL-backed conversations, memories, feedback, and documents survive restarts and device switches
- **Zero-downtime deploys** — blue/green health-checked container restarts via `deathstar redeploy`
- **Backups** — full database + config backup to S3 with `deathstar backup` and `deathstar restore`

```bash
deathstar deploy --region us-west-1
deathstar connect
deathstar status
deathstar logs
deathstar backup
deathstar restore
```

Open the web UI at `http://deathstar:8080/` over Tailscale.

## Architecture

```
Browser / Phone  ──▶  Web UI (React + Vite + Tailwind v4)
                         │
                         ▼
                    FastAPI Control API (:8080)
                         │
          ┌──────────┬───┼───┬──────────┐
          ▼          ▼   ▼   ▼          ▼
     Claude Code  Git Ops  Event   WebSocket    PostgreSQL
     Agent SDK    Service   Bus    Terminal       (SQLModel)
          │                  │
          ▼                  ▼
     Claude CLI         GitHub / Linear
  (subscription auth)   Webhooks & Pollers
```

| Layer | Path | Stack |
|---|---|---|
| CLI | `cli/deathstar_cli/` | Python 3.11+, Typer, httpx |
| Server | `server/deathstar_server/` | Python 3.11+, FastAPI, SQLModel, asyncio |
| Shared models | `shared/deathstar_shared/` | Pydantic v2 |
| Frontend | `web/` | React 19, Vite, TypeScript, Tailwind v4, Zustand |
| Infrastructure | `terraform/` | Terraform (AWS: VPC, EC2, IAM, S3) |
| Bootstrap | `bootstrap/` | Cloud-init, shell scripts (.tftpl templates) |
| Docker | `docker/` | Multi-stage Dockerfile, docker-compose (PostgreSQL 17 + app) |
| Migrations | `alembic/` | Alembic (PostgreSQL) |
| Plugins | `plugins/` | Claude Agent SDK plugins (code, review, docs, plan, audit) |
| Tests | `tests/` | Pytest, PostgreSQL test DB |

1. The local `deathstar` CLI runs Terraform for deploy and destroy.
2. The CLI discovers the instance through Terraform outputs.
3. For `run`, `status`, `logs`, `backup`, and `restore`, the CLI talks to the remote control API over Tailscale by default.
4. `connect` uses Tailscale SSH by default. AWS SSM remains available as a break-glass fallback.
5. The web UI communicates with the control API over WebSocket for interactive Claude Code sessions and over REST for repo management.
6. GitHub and Linear integrations receive events via webhooks (Tailscale Funnel) or polling, translated into the event bus for real-time forwarding to WebSocket clients.
7. Each agent session runs in an isolated git worktree — users can switch branches in the primary checkout without affecting a running agent.
8. Redeploys use a blue/green strategy — the new image builds while the old container stays live, a canary health check runs, then traffic swaps over.

## Security Posture

- No public SSH ingress by default
- Security group starts with zero inbound rules
- IMDSv2 is required
- Root and data volumes are encrypted
- All secrets (API keys, tokens, passwords) are stored in AWS SSM Parameter Store and pulled at runtime — never in `.env` or code
- Tailscale is the primary private operator network
- The control API is intended to be reached over the tailnet, not the public internet
- The control API supports bearer token authentication via `DEATHSTAR_API_TOKEN` (required when Tailscale Funnel is enabled)
- GitHub and Linear webhooks verify HMAC signatures
- Input validation enforces path traversal protection, prompt size limits, and safe workspace subpaths
- Backup restore rejects symlinks, hard links, and paths outside the workspace root
- Tool guardrails block agents from force-pushing, pushing to main/master, or running destructive operations
- Subprocess calls always use list format (no `shell=True`)
- API error responses use structured `AppError` codes — no internal paths, URLs, or stack traces are exposed

The main tradeoff is outbound internet access: the instance needs egress for package installs, container pulls, provider APIs, GitHub, Linear, and AWS APIs. The default security group keeps outbound open to stay reproducible; tighter egress control is a documented hardening step.

### Tailscale Funnel

Tailscale Funnel exposes the control API at a public HTTPS URL so external services (Linear, GitHub) can deliver webhooks without polling.

```bash
# In .env
DEATHSTAR_ENABLE_TAILSCALE_FUNNEL=true
```

**Requirements:**

1. **`DEATHSTAR_API_TOKEN` must be set.** Funnel makes the API publicly reachable — without a bearer token, all non-webhook endpoints are unauthenticated on the open internet.
2. Funnel must be enabled in your tailnet ACL policy:
   ```jsonc
   "nodeAttrs": [{ "target": ["tag:deathstar"], "attr": ["funnel"] }]
   ```
3. Run `deathstar deploy` (not `redeploy`) — Funnel is configured at the OS level during cloud-init, not inside the Docker container.

When active, the instance serves `https://<tailscale-hostname>.<tailnet>.ts.net` which proxies to the local control API on port 8080. Webhook endpoints (`/web/api/webhooks/*`) skip bearer token auth and are verified by HMAC signature instead; all other API endpoints require the bearer token.

## Quick Start

### 1. Prerequisites

| Tool | Version | How to install | How to verify |
|------|---------|----------------|---------------|
| **Python** | 3.11+ | [python.org](https://www.python.org/downloads/) or `brew install python@3.12` | `python3 --version` |
| **uv** | any | [docs.astral.sh](https://docs.astral.sh/uv/getting-started/installation/) or `brew install uv` | `uv --version` |
| **Docker** | 20+ | [docker.com](https://docs.docker.com/get-docker/) or `brew install --cask docker` | `docker --version` |
| **Terraform** | 1.6+ | [terraform.io](https://developer.hashicorp.com/terraform/install) or `brew install terraform` | `terraform --version` |
| **AWS CLI** | v2 | [AWS docs](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) or `brew install awscli` | `aws --version` |
| **Tailscale** | any | [tailscale.com](https://tailscale.com/download) | `tailscale status` |
| **Session Manager plugin** | any | [AWS docs](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html) | `session-manager-plugin` (prints usage) |

**AWS permissions required:** Your AWS credentials must be able to create and manage VPC, EC2, IAM roles/instance profiles, S3 buckets, SSM parameters, and security groups.

**Claude Code subscription:** The web UI uses your Claude Code subscription (Max or Pro plan) for AI features. No API key is required — you'll authenticate through the web UI after deploying.

### 2. Configure AWS Credentials

DeathStar uses whichever AWS credentials the AWS CLI resolves:

```bash
# Show your current identity
aws sts get-caller-identity

# List your configured profiles
aws configure list-profiles
```

If you need to use a specific profile:

```bash
# Export for the current shell session
export AWS_PROFILE=my-work-profile

# Or set it in .env (persists across sessions)
# DEATHSTAR_AWS_PROFILE=my-work-profile
```

### 3. Configure Local Defaults

```bash
cp .env.example .env
```

Open `.env` in your editor:

```bash
# --- Required: adjust these to your environment ---

DEATHSTAR_PROJECT_NAME=deathstar       # Names all AWS resources. Change if running
                                        # multiple instances in one account.
DEATHSTAR_REGION=us-west-1             # AWS region for all resources.
DEATHSTAR_AWS_PROFILE=default          # AWS CLI profile name.

# --- Instance sizing ---

DEATHSTAR_INSTANCE_TYPE=t3.large       # EC2 instance type. t3.large = 2 vCPU, 8GB RAM.
DEATHSTAR_ROOT_VOLUME_SIZE_GB=30       # OS disk. 30GB is usually enough.
DEATHSTAR_DATA_VOLUME_SIZE_GB=200      # Workspace disk mounted at /workspace.

# --- API authentication (strongly recommended) ---

DEATHSTAR_API_TOKEN=                   # Set to a random secret string.
                                        # Generate one with: openssl rand -hex 32

```

The web UI is always enabled and served at port 8080 (only accessible over Tailscale by default).

### 4. Install The CLI

**From PyPI (recommended):**

```bash
uv tool install deathstar-ai
```

**From source (for contributors):**

```bash
git clone https://github.com/Arcway-ai/deathstar.git
cd deathstar
uv tool install -e . --force
```

Verify:

```bash
deathstar version
```

### 5. Set Up Tailscale (Recommended)

DeathStar uses Tailscale as the primary private network between your devices and the EC2 instance.

**On your laptop/phone:**

1. Install Tailscale from [tailscale.com/download](https://tailscale.com/download)
2. Sign in: `tailscale up`
3. Verify: `tailscale status`

**Create a Tailscale auth key** so the EC2 instance can join automatically:

```bash
deathstar tailscale setup --region us-west-1
```

This requires a Tailscale OAuth client. To create one:

1. Go to [Tailscale admin console](https://login.tailscale.com/admin/settings/oauth) (Settings > OAuth clients)
2. Click **"Generate OAuth client..."**
3. Grant scopes: **"Auth Keys: Write"**, **"Devices: Read"**, **"Devices: Write"**
4. Copy the **client ID** and **client secret**
5. Run `deathstar tailscale setup` and paste them when prompted

**Important:** OAuth-created auth keys require at least one ACL tag. Define a tag in your [tailnet ACL policy](https://login.tailscale.com/admin/acls):

```jsonc
"tagOwners": {
  "tag:deathstar": ["autogroup:admin"]
}
```

```bash
# In .env:
DEATHSTAR_TAILSCALE_ADVERTISE_TAGS=tag:deathstar
```

### 6. Deploy

```bash
deathstar deploy --region us-west-1
```

This runs `terraform init` and `terraform apply`. Expect 3-5 minutes for the initial deploy.

**Wait a minute or two** after deploy for cloud-init to finish:

```bash
# Check if the instance appears on your tailnet
tailscale status | grep deathstar

# Verify the API is up
deathstar status
```

### 7. Connect Your Claude Account

Open the web UI at `http://deathstar:8080/` in your browser.

Click the **Claude** indicator in the top bar — it will show a red dot if not yet authenticated. Click **"Connect Claude Account"** to start the OAuth login flow:

1. The server starts `claude auth login` and returns a URL
2. Open the URL in your browser and complete authentication
3. The web UI automatically detects when auth succeeds (polls every 3 seconds)
4. The green dot appears — you're connected

Claude auth persists across container restarts (stored on the workspace volume).

### 8. Set Up GitHub Integration (Optional)

If you want DeathStar to push branches and open PRs:

```bash
deathstar github setup --region us-west-1
```

| Method | Best for | What happens |
|--------|----------|-------------|
| `auto` (default) | Laptop with `gh` CLI | Extracts token from your `gh` session |
| `pat` | Any device with a browser | Creates a PAT via github.com |
| `oauth` | Headless or phone setups | Device Flow with one-time code |

GitHub events (pushes, PRs, CI status) are picked up by the built-in poller. For real-time delivery, configure a webhook secret in `.env` and point your GitHub repo webhook to `https://<tailscale-hostname>.<tailnet>.ts.net/web/api/webhooks/github` (requires Tailscale Funnel).

### 9. Set Up Linear Integration (Optional)

Linear integration enables bidirectional sync between Linear issues and git branches. The setup command stores credentials in SSM and registers a webhook.

**Prerequisites:** Tailscale Funnel must be active for webhook delivery. Set `DEATHSTAR_ENABLE_TAILSCALE_FUNNEL=true` in `.env` and run `deathstar deploy` first (see [Tailscale Funnel](#tailscale-funnel) below).

```bash
deathstar linear setup --region us-west-1
```

This will:

1. Prompt for your Linear API key → stores it in SSM
2. List your Linear teams so you can pick one
3. Auto-generate a webhook signing secret → stores it in SSM
4. Auto-detect your Tailscale Funnel URL
5. Register the webhook with Linear pointing to `https://<tailscale-hostname>/web/api/webhooks/linear`

Check status:

```bash
deathstar linear status
```

If Funnel is not available, Linear sync falls back to polling (configurable via `LINEAR_POLL_INTERVAL` in `.env`, default 60s).

### 10. Clone Repos

SSH into the instance:

```bash
deathstar connect
```

Clone your repos:

```bash
cd /workspace/projects
git clone git@github.com:your-org/your-repo.git
```

Or clone from the web UI — use the repo picker to browse and clone GitHub repos directly.

### 11. Start Using It

Open the web UI at `http://deathstar:8080/`:

1. Select a repo from the picker
2. Choose a persona and workflow mode
3. Type a prompt and press Enter
4. Watch Claude Code work — you'll see tool use, file reads/writes, and thinking in real time
5. Approve or deny permission requests as they come up

## Web UI

The web UI provides an interactive Claude Code experience in your browser — like having a terminal session with Claude Code, but with a rich visual interface.

### Workflow Modes

| Mode | What it does | Agent tools |
|------|-------------|-------------|
| **Chat** | Read-only exploration and Q&A | Read, Glob, Grep, WebSearch, WebFetch |
| **Code** | Direct file modification | Read, Write, Edit, Bash, Glob, Grep |
| **Code + PR** | Same as Code, then creates a PR | Read, Write, Edit, Bash, Glob, Grep |
| **Review** | Structured code review with findings | Read, Glob, Grep, Bash, Agent |
| **Docs** | Documentation generation | Read, Write, Edit, Glob, Grep |
| **Audit** | Security audit (read-only) | Read, Glob, Grep, Bash |
| **Plan** | Implementation planning with phased tasks | Read, Glob, Grep |

### Features

- **Interactive streaming** — see text, thinking, tool use, and tool results stream in real time
- **Permission flow** — Claude requests permission for sensitive operations; approve or deny from the UI
- **Multi-turn conversations** — full session continuity via the Claude Agent SDK
- **Concurrent worktrees** — each agent session runs in an isolated git worktree; you can switch branches without affecting a running agent
- **Stop button** — interrupt the agent mid-stream
- **Personas** — 8 expert personas (Frontend, Full-stack, Security, DevOps, Data, Architect, Writer, Researcher) with specialized system prompts
- **Model selector** — pick Claude models with speed/price metadata
- **Structured code review** — review mode produces severity-rated findings with inline code suggestions; accept, reject, or apply them as a commit directly to the PR
- **Structured plans** — plan mode produces phased task breakdowns with complexity ratings, effort estimates, risks, and open questions; push tasks to Linear as issues
- **PR selector** — browse open pull requests and select one as context for review mode
- **Branch management** — view, switch, create, delete, and sync branches from the repo panel
- **Quick save** — commit dirty changes with one click or Cmd+S
- **Repo context** — CLAUDE.md, current branch, recent commits, and file tree are automatically injected into prompts
- **Linear panel** — link Linear projects to repos, view synced issues, trigger manual sync, create issues from plans
- **Memory bank** — thumbs-up a response to save it as persistent context for future prompts
- **Documents** — create, view, and edit tech specs, plans, and notes per-repo with structured distillation from conversations
- **Feedback** — thumbs-up and thumbs-down per message for quality tracking
- **File explorer** — collapsible directory tree with syntax-highlighted file viewer
- **Remote terminal** — WebSocket PTY terminal (xterm.js) with zsh, resize, maximize, and up to 4 sessions
- **Message queue** — enqueue prompts for background processing; the queue worker processes them headlessly via the Claude Agent SDK
- **Event stream** — real-time repo events (push, PR, CI status, agent completion) broadcast to connected WebSocket clients
- **Preview deployments** — trigger Render or Vercel preview deploys for pull requests
- **Markdown rendering** — full markdown with syntax-highlighted code blocks
- **Conversation persistence** — PostgreSQL-backed conversations, memories, documents, and feedback survive page reloads and device switches
- **Claude auth management** — connect and disconnect your Claude account from the UI
- **Multiple themes** — dark ("Imperial"), light, and system preference
- **Star Wars commit authors** — agent commits are authored by random Star Wars characters with lego-style avatars
- **Tool guardrails** — tiered safety system (hard-deny, require-approval, auto-accept) blocks irreversible operations like force-push or pushing to main/master

### API Endpoints

All web API endpoints live under `/web/api/` and require the same bearer token as `/v1/*`. Exceptions: webhook receivers (`/web/api/webhooks/*`) skip bearer auth and verify HMAC signatures instead, and static files bypass auth entirely.

| Method | Path | Purpose |
|--------|------|---------|
| **Repositories** | | |
| GET | `/web/api/repos` | List repos with branch and dirty state |
| GET | `/web/api/repos/{name}/tree` | File list for a repo |
| GET | `/web/api/repos/{name}/file?path=...` | Read a file |
| GET | `/web/api/repos/{name}/context` | Repo context (CLAUDE.md, branch, commits, tree, linked Linear projects) |
| GET | `/web/api/repos/{name}/branches` | List local branches |
| GET | `/web/api/repos/{name}/commits` | Recent commit history |
| POST | `/web/api/repos/{name}/branch` | Create a branch |
| POST | `/web/api/repos/{name}/checkout` | Switch branch |
| POST | `/web/api/repos/{name}/sync` | Sync branch with base (rebase) |
| POST | `/web/api/repos/{name}/save` | Quick-save uncommitted changes |
| DELETE | `/web/api/repos/{name}/branch` | Delete a branch |
| GET | `/web/api/repos/{name}/pulls` | List pull requests |
| GET | `/web/api/repos/{name}/branch-pr` | Get PR for current branch |
| GET | `/web/api/repos/{name}/worktrees` | List active agent worktrees |
| **Claude Auth** | | |
| GET | `/web/api/claude/auth/status` | Check Claude CLI auth status |
| POST | `/web/api/claude/auth/token` | Exchange auth token |
| POST | `/web/api/claude/auth/logout` | Disconnect Claude account |
| **GitHub** | | |
| GET | `/web/api/github/repos` | List GitHub repos |
| POST | `/web/api/github/clone` | Clone a GitHub repo |
| **Conversations** | | |
| GET | `/web/api/conversations?repo=...` | List conversations |
| GET | `/web/api/conversations/{id}` | Full conversation detail |
| DELETE | `/web/api/conversations/{id}` | Delete a conversation |
| **Memory** | | |
| GET | `/web/api/memory?repo=...` | List memory bank entries |
| POST | `/web/api/memory` | Save a memory |
| POST | `/web/api/memory/suggest` | Get suggested memories from a conversation |
| DELETE | `/web/api/memory/{id}` | Delete a memory |
| **Documents** | | |
| GET | `/web/api/documents?repo=...` | List documents |
| GET | `/web/api/documents/{id}` | Get a document |
| POST | `/web/api/documents` | Create a document |
| PUT | `/web/api/documents/{id}` | Update a document |
| DELETE | `/web/api/documents/{id}` | Delete a document |
| POST | `/web/api/documents/distill-plan` | Extract structured plan from conversation |
| **Code Review** | | |
| GET | `/web/api/reviews/comments` | Get pending review findings |
| POST | `/web/api/reviews/post-to-github` | Post review findings to a GitHub PR |
| POST | `/web/api/reviews/apply-suggestions` | Apply code suggestions as a commit |
| **Feedback** | | |
| POST | `/web/api/feedback` | Save thumbs-up/down feedback |
| GET | `/web/api/feedback` | List feedback |
| **Message Queue** | | |
| POST | `/web/api/queue` | Enqueue a message for background processing |
| GET | `/web/api/queue` | Get queue status |
| DELETE | `/web/api/queue/{id}` | Cancel a queued item |
| **Linear** | | |
| GET | `/web/api/linear/teams` | List Linear workspace teams |
| GET | `/web/api/linear/projects` | List Linear projects |
| POST | `/web/api/linear/projects/link` | Link a Linear project to a repo |
| DELETE | `/web/api/linear/projects/unlink` | Unlink a Linear project |
| GET | `/web/api/linear/issues` | List issues in a linked project |
| POST | `/web/api/linear/sync` | Trigger manual sync |
| GET | `/web/api/linear/sync/status` | Check last sync time |
| POST | `/web/api/linear/create-from-plan` | Create Linear issues from a plan |
| **Preview Deployments** | | |
| POST | `/web/api/previews` | Create a preview deployment |
| GET | `/web/api/previews` | List active previews |
| GET | `/web/api/previews/{id}` | Get preview status |
| DELETE | `/web/api/previews/{id}` | Destroy a preview |
| **Webhooks** | | |
| POST | `/web/api/webhooks/github` | GitHub webhook receiver (HMAC-verified) |
| POST | `/web/api/webhooks/linear` | Linear webhook receiver (HMAC-verified) |
| **Agent & Terminal** | | |
| GET | `/web/api/agent/sessions` | List active agent sessions |
| WS | `/web/api/agent` | WebSocket interactive agent session |
| WS | `/web/api/terminal` | WebSocket PTY terminal |

### Phone Usage

- **Laptop or desktop** — CLI for deploy/destroy/backup, web UI for coding
- **Phone or tablet** — web UI over Tailscale for chat, code, and review
- **Emergency access** — Tailscale SSH or SSM for direct shell access

## CLI Usage

The local CLI manages infrastructure and provides a command-line interface to the remote instance.

### Deploy And Destroy

```bash
deathstar deploy --region us-west-1
deathstar destroy --region us-west-1
```

### Redeploy (Code-Only Push)

Build the Docker image locally and push it to the remote instance over Tailscale SSH:

```bash
deathstar redeploy
deathstar redeploy --yes    # auto-approve
```

Steps:
1. Builds the Docker image locally (`docker build --platform linux/amd64`)
2. Pushes the image to the instance via `docker save | gzip | ssh docker load`
3. Restarts the container with a blue/green canary health check

The old container stays live until the new one passes health checks. If unhealthy, the old container stays up and the deploy is rolled back.

Use `redeploy` for frontend changes, API route updates, or any code-only change. Use `deploy` for infrastructure changes.

**Requires:** Docker Desktop running locally and Tailscale SSH ACL configured (see Tailscale setup).

### Upgrade

```bash
deathstar upgrade
```

Automatically detects your install mode:
- **PyPI install:** upgrades from PyPI (`uv tool upgrade deathstar-ai`)
- **Source install:** pulls latest code and reinstalls the editable package

Then backs up, builds the Docker image locally, pushes it to the instance via Tailscale SSH, and restarts with a health check.

```bash
deathstar upgrade --yes           # auto-approve everything
deathstar upgrade --skip-backup   # skip pre-upgrade backup
```

### Run CLI Workflows

```bash
deathstar run --provider anthropic --prompt "summarize this repo"

deathstar run \
  --workflow patch \
  --provider anthropic \
  --workspace-subpath repos/api \
  --write \
  --prompt "fix the failing tests"

deathstar run \
  --workflow review \
  --provider anthropic \
  --workspace-subpath repos/api \
  --base-branch main \
  --prompt "review these changes"
```

### Status, Logs, Backups

```bash
deathstar status
deathstar logs --tail 200
deathstar backup --label before-rebuild
deathstar restore
```

### Connect

```bash
deathstar connect                    # Tailscale SSH (default)
deathstar connect --transport ssm    # SSM break-glass fallback
```

### Repos

```bash
deathstar repos list                  # list all cloned repos on the instance
deathstar repos clone org/repo        # clone a GitHub repo to the instance
```

### GitHub

```bash
deathstar github setup --region us-west-1
```

### Linear

```bash
deathstar linear setup --region us-west-1
deathstar linear status
```

### Seed Or Rotate Secrets

```bash
deathstar secrets bootstrap --region us-west-1
deathstar secrets put --provider anthropic --region us-west-1
deathstar secrets put --integration github --region us-west-1
```

### Tailscale

```bash
deathstar tailscale setup --region us-west-1    # register instance on your tailnet
deathstar tailscale cleanup                      # remove stale devices
deathstar tailscale fix                          # troubleshoot connectivity
```

### Total Teardown (trench-run)

Wipes everything — infrastructure, SSM secrets, Terraform state:

```bash
deathstar trench-run --region us-west-1
```

No `--yes` flag; you must type the project name to confirm.

## Frontend Development

```bash
cd web
npm install
npm run dev     # Starts Vite dev server on :5173, proxies API to :8080
```

The Vite dev server proxies `/web/api/*` (including WebSocket) and `/v1/*` to `localhost:8080`.

## Deploy Previews with Render

You can configure [Render](https://render.com) to automatically spin up deploy previews for pull requests — giving reviewers a live, running instance of your changes before merging.

### 1. Configure a Render Blueprint

Add a `render.yaml` at the root of your repo to define the preview environment. The `previews.generation` field is **required** — without it, Render will not create preview instances for PRs. See the [Render Blueprint docs](https://render.com/docs/infrastructure-as-code) for the full spec.

```yaml
previews:
  generation: automatic   # creates a preview on every PR; use "manual" for on-demand

services:
  - type: web
    name: deathstar-preview
    runtime: docker
    dockerfilePath: ./docker/control-api.Dockerfile
    envVars:
      - key: DEATHSTAR_API_TOKEN
        generateValue: true
```

### 2. Connect the Render GitHub App

1. In the Render Dashboard, go to **Blueprints** and connect your repo
2. Render's [GitHub App](https://render.com/docs/github) detects new PRs and automatically spins up preview instances based on `render.yaml`
3. Each preview gets its own URL — Render posts it as a deployment status on the PR
4. Previews are torn down when the PR is closed or merged

### 3. Create a Render API Key (Optional)

An API key is **not** required for the GitHub App preview flow above. You only need one if you want to trigger deployments from CI or call the [Render REST API](https://render.com/docs/api#1-create-an-api-key) directly:

1. Go to your [Account Settings](https://dashboard.render.com/u/settings?add-api-key) in the Render Dashboard
2. Click **"Create API Key"**
3. Copy the key immediately — it is only shown once
4. Store it as a repository secret (e.g. `RENDER_API_KEY` in GitHub Actions)

> **Security:** Treat this key as a secret. Do not commit it to version control or share it publicly. If compromised, revoke it immediately in the dashboard and generate a new one.

## Testing

```bash
uv run pytest tests/ -v
```

The test suite covers the Anthropic provider, workflows, backup/restore, git operations, input validation, API routes, web UI routes, auth middleware, CLI configuration, and the Claude Agent SDK integration.

## Contributing

Contributions are welcome! Here's how to get involved:

1. **Fork** the repo and create a feature branch from `main`
2. **Make your changes** — follow the conventions in [CLAUDE.md](CLAUDE.md)
3. **Run the checks** before submitting:
   ```bash
   uv run ruff check cli server shared tests
   uv run pytest tests/ -v
   cd web && npx tsc --noEmit && npm run build
   ```
4. **Open a pull request** against `main` with a clear description of what and why

### Guidelines

- Keep PRs focused — one feature or fix per PR
- Add tests for new backend functionality
- Don't break existing tests
- Follow the existing code style (ruff for Python, TypeScript strict mode for frontend)
- Update docs if your change affects user-facing behavior

All PRs require review and approval before merging. CI must pass (lint, test, typecheck, frontend build).

## License

[AGPL-3.0](LICENSE)
