Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ concurrency:

jobs:
quality-gates:
runs-on: ubuntu-latest
runs-on: ci_runner
steps:
- uses: actions/checkout@v4

Expand Down
40 changes: 20 additions & 20 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ jobs:
matrix:
include:
- target: linux-x86_64
runner: ubuntu-latest
runner: ci_runner
bazel_args: "--platforms=//bazel/config/platform/rust:linux_x86_64"
asset: crab-linux-x86_64
asset: work-linux-x86_64
- target: macos-aarch64
runner: macos-latest
runner: ci_runner
bazel_args: ""
asset: crab-macos-aarch64
asset: work-macos-aarch64

runs-on: ${{ matrix.runner }}
steps:
Expand All @@ -38,28 +38,28 @@ jobs:
uses: actions/cache@v4
with:
path: ~/.cache/bazel-disk-cache
key: bazel-disk-${{ matrix.target }}-${{ hashFiles('MODULE.bazel', 'Cargo.lock', 'packages/crab_city_ui/pnpm-lock.yaml', 'packages/crab_city_ui/src/**') }}
key: bazel-disk-${{ matrix.target }}-${{ hashFiles('MODULE.bazel', 'Cargo.lock', 'packages/workshop_ui/pnpm-lock.yaml', 'packages/workshop_ui/src/**') }}
restore-keys: |
bazel-disk-${{ matrix.target }}-

- name: Build
run: >
bazel build //packages/crab_city:crab_embedded
bazel build //packages/workshop:work_embedded
--compilation_mode opt
${{ matrix.bazel_args }}
--disk_cache=~/.cache/bazel-disk-cache
--repository_cache=~/.cache/bazel-repo-cache

- name: Verify embedded UI assets
run: >
bazel test //packages/crab_city_ui/crate:embed_test
bazel test //packages/workshop_ui/crate:embed_test
--compilation_mode opt
${{ matrix.bazel_args }}
--disk_cache=~/.cache/bazel-disk-cache
--repository_cache=~/.cache/bazel-repo-cache

- name: Prepare artifact
run: cp bazel-bin/packages/crab_city/crab_embedded ${{ matrix.asset }}
run: cp bazel-bin/packages/workshop/work_embedded ${{ matrix.asset }}

- name: Upload artifact
uses: actions/upload-artifact@v4
Expand All @@ -69,7 +69,7 @@ jobs:

release:
needs: build
runs-on: ubuntu-latest
runs-on: ci_runner
steps:
- uses: actions/checkout@v4

Expand All @@ -81,13 +81,13 @@ jobs:
- name: Prepare release assets
run: |
mkdir -p release
for dir in artifacts/crab-*/; do
for dir in artifacts/work-*/; do
name=$(basename "$dir")
cp "$dir/$name" "release/$name"
done
cp scripts/install.sh release/install.sh
cd release
sha256sum crab-* install.sh > checksums-sha256.txt
sha256sum work-* install.sh > checksums-sha256.txt

- name: Determine prerelease
id: meta
Expand All @@ -109,31 +109,31 @@ jobs:
## Install

```sh
curl -fsSL https://github.com/crabcity/crabcity/releases/latest/download/install.sh | bash
curl -fsSL https://github.com/empathic/workshop/releases/latest/download/install.sh | bash
```

Or install a specific version:

```sh
curl -fsSL https://github.com/crabcity/crabcity/releases/latest/download/install.sh | bash -s -- --version ${{ github.ref_name }}
curl -fsSL https://github.com/empathic/workshop/releases/latest/download/install.sh | bash -s -- --version ${{ github.ref_name }}
```

## Downloads

| Platform | Binary |
|----------|--------|
| Linux x86_64 | [`crab-linux-x86_64`](https://github.com/crabcity/crabcity/releases/download/${{ github.ref_name }}/crab-linux-x86_64) |
| macOS (Apple Silicon) | [`crab-macos-aarch64`](https://github.com/crabcity/crabcity/releases/download/${{ github.ref_name }}/crab-macos-aarch64) |
| Linux x86_64 | [`work-linux-x86_64`](https://github.com/empathic/workshop/releases/download/${{ github.ref_name }}/work-linux-x86_64) |
| macOS (Apple Silicon) | [`work-macos-aarch64`](https://github.com/empathic/workshop/releases/download/${{ github.ref_name }}/work-macos-aarch64) |

## Manual install

```sh
# Download the binary for your platform (adjust the asset name as needed)
# Linux x86_64: crab-linux-x86_64
# macOS Apple Silicon: crab-macos-aarch64
curl -fsSL https://github.com/crabcity/crabcity/releases/download/${{ github.ref_name }}/crab-PLATFORM -o crab
chmod +x crab
mv crab ~/.local/bin/crab
# Linux x86_64: work-linux-x86_64
# macOS Apple Silicon: work-macos-aarch64
curl -fsSL https://github.com/empathic/workshop/releases/download/${{ github.ref_name }}/work-PLATFORM -o work
chmod +x work
mv work ~/.local/bin/work
```

## SHA256 Checksums
Expand Down
44 changes: 22 additions & 22 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Documentation

When changing code, **update the associated docs in the same change**. Key files: `docs/architecture.md` (system design), `docs/web-terminal.md` (client terminal), `docs/configuration.md` (config), `packages/crab_city_ui/CLAUDE.md` (frontend conventions), this file (build/architecture notes). Stale docs are worse than no docs.
When changing code, **update the associated docs in the same change**. Key files: `docs/architecture.md` (system design), `docs/web-terminal.md` (client terminal), `docs/configuration.md` (config), `packages/workshop_ui/CLAUDE.md` (frontend conventions), this file (build/architecture notes). Stale docs are worse than no docs.

## Build System

Expand Down Expand Up @@ -30,32 +30,32 @@ All Rust code uses edition 2024. Cargo defaults to edition 2021 for `cargo check

### Build Commands

- `cargo check -p crab_city` — quick compile check
- `cargo test -p crab_city` — run unit tests for the server
- `cargo check -p workshop` — quick compile check
- `cargo test -p workshop` — run unit tests for the server
- `cargo test -p <package>` — run unit tests for any workspace crate
- `bazel test //...` — full CI-equivalent (includes format check, edition 2024)
- `CRAB_CITY_UI_PATH=packages/crab_city_ui/build cargo build -p crab_city_ui` — build embedded UI crate
- `WORKSHOP_UI_PATH=packages/workshop_ui/build cargo build -p workshop_ui` — build embedded UI crate

### Desktop App (Tauri)

- `cargo check -p crab_city_desktop` — quick compile check
- `cargo test -p crab_city_desktop` — run unit tests
- `cd packages/crab_city_desktop && cargo tauri dev --config tauri.dev.conf.json` — launch desktop app with embedded server (auto-starts Vite dev server)
- `bazel build //packages/crab_city_desktop:macos_app` — build macOS `.app` bundle (debug)
- `bazel build --config=opt //packages/crab_city_desktop:macos_app` — build optimized `.app` bundle
- `cargo check -p workshop_desktop` — quick compile check
- `cargo test -p workshop_desktop` — run unit tests
- `cd packages/workshop_desktop && cargo tauri dev --config tauri.dev.conf.json` — launch desktop app with embedded server (auto-starts Vite dev server)
- `bazel build //packages/workshop_desktop:macos_app` — build macOS `.app` bundle (debug)
- `bazel build --config=opt //packages/workshop_desktop:macos_app` — build optimized `.app` bundle

**Dev workflow** (single terminal): `cd packages/crab_city_desktop && cargo tauri dev --config tauri.dev.conf.json` — the Tauri app starts an embedded server in-process, and Vite's dev proxy discovers it automatically via the `daemon.port` file. The `--config` flag merges `tauri.dev.conf.json` (devUrl + beforeDevCommand) into the base config. The base `tauri.conf.json` has no dev URL — production builds never reference external dev servers.
**Dev workflow** (single terminal): `cd packages/workshop_desktop && cargo tauri dev --config tauri.dev.conf.json` — the Tauri app starts an embedded server in-process, and Vite's dev proxy discovers it automatically via the `daemon.port` file. The `--config` flag merges `tauri.dev.conf.json` (devUrl + beforeDevCommand) into the base config. The base `tauri.conf.json` has no dev URL — production builds never reference external dev servers.

**Custom data directory**: `crab_city_desktop --data-dir /path/to/data` (defaults to `~/.crabcity`).
**Custom data directory**: `workshop_desktop --data-dir /path/to/data` (defaults to `~/.workshop`).

Note: `crab_city_desktop` is in workspace `members` but NOT in `default-members` (requires Tauri system deps). The desktop app depends on the `crab_city` library crate (with `embedded-ui` feature) — no separate daemon process.
Note: `workshop_desktop` is in workspace `members` but NOT in `default-members` (requires Tauri system deps). The desktop app depends on the `workshop` library crate (with `embedded-ui` feature) — no separate daemon process.

### Frontend (SvelteKit)

- `cd packages/crab_city_ui && pnpm install && pnpm build` — build the web UI
- `cd packages/crab_city_ui && pnpm dev` — dev server with hot reload
- `cd packages/crab_city_ui && pnpm test` — run Jest tests
- `cd packages/crab_city_ui && pnpm format` — format TS/Svelte with Prettier (also runs via `bazel run //tools/format`)
- `cd packages/workshop_ui && pnpm install && pnpm build` — build the web UI
- `cd packages/workshop_ui && pnpm dev` — dev server with hot reload
- `cd packages/workshop_ui && pnpm test` — run Jest tests
- `cd packages/workshop_ui && pnpm format` — format TS/Svelte with Prettier (also runs via `bazel run //tools/format`)

## TUI Styling

Expand All @@ -69,15 +69,15 @@ The terminal theme is solarized. Hardcoded ANSI colors are invisible or clash:
### Package Dependency Graph

```
crab_city (lib: server core, config, handlers, WS | bin: CLI + TUI)
workshop (lib: server core, config, handlers, WS | bin "work": CLI + TUI)
├── claude_convo (conversation log reader)
├── pty_manager (PTY lifecycle)
└── virtual_terminal (screen buffer + viewport negotiation)

tty_wrapper (standalone HTTP-controlled PTY — not depended on by crab_city)
crab_city_ui (SvelteKit frontend — embedded via rust-embed feature flag)
crab_city_desktop (Tauri native desktop app — embeds crab_city server in-process)
└── crab_city (lib, with embedded-ui feature)
tty_wrapper (standalone HTTP-controlled PTY — not depended on by workshop)
workshop_ui (SvelteKit frontend — embedded via rust-embed feature flag)
workshop_desktop (Tauri native desktop app — embeds workshop server in-process)
└── workshop (lib, with embedded-ui feature)
```

### Daemon Lifecycle
Expand All @@ -88,7 +88,7 @@ One server per data directory, enforced by advisory file lock (`daemon.lock`). T
- **`check_existing_server()`** — reads `daemon.pid`/`daemon.port`, verifies process alive via `kill(pid, 0)`, then health-checks `GET /health`
- **`release_daemon_files()`** — PID-aware cleanup: only deletes state files if `daemon.pid` matches current process
- **`DaemonLock`** — RAII guard; `Drop` calls `release_daemon_files()`, then releases the flock
- Both `crab server` and `EmbeddedServer::start()` acquire the lock before initializing
- Both `work server` and `EmbeddedServer::start()` acquire the lock before initializing
- Desktop app calls `check_existing_server()` first — connects to existing daemon if healthy, otherwise starts embedded

### Server Internals
Expand Down
26 changes: 13 additions & 13 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Contributing to Crab City
# Contributing to Workshop

## Prerequisites

Expand All @@ -10,34 +10,34 @@
## Clone and Build

```sh
git clone https://github.com/anthropics/crab-city && cd crab-city
git clone https://github.com/anthropics/workshop && cd workshop

# Cargo for development (fast iteration)
cargo build -p crab_city
cargo build -p workshop

# Bazel for CI-equivalent builds (includes format checks, edition 2024 enforcement)
bazel build //packages/crab_city:crab
bazel build //packages/workshop:work
```

## Running the Server

```sh
# Start server + TUI picker
cargo run -p crab_city
cargo run -p workshop

# Start server only (for web UI development)
cargo run -p crab_city -- server --debug
cargo run -p workshop -- server --debug
```

The server starts on a random port on `127.0.0.1`. The port is printed on startup.

## Web UI Development

The frontend is a SvelteKit app in `packages/crab_city_ui/`.
The frontend is a SvelteKit app in `packages/workshop_ui/`.

```sh
# Install dependencies
cd packages/crab_city_ui
cd packages/workshop_ui
pnpm install

# Start dev server with hot reload
Expand All @@ -55,28 +55,28 @@ pnpm test
In development, the server runs without the embedded UI. To build a binary with the UI baked in:

```sh
CRAB_CITY_UI_PATH=packages/crab_city_ui/build cargo build -p crab_city --features embedded-ui
WORKSHOP_UI_PATH=packages/workshop_ui/build cargo build -p workshop --features embedded-ui
```

Or use Bazel, which handles the frontend build automatically:

```sh
bazel build //packages/crab_city:crab
bazel build //packages/workshop:work
```

## Testing

```sh
# Unit tests for any package
cargo test -p crab_city
cargo test -p workshop
cargo test -p virtual_terminal
cargo test -p <package>

# Full CI suite (all packages, format check, edition 2024)
bazel test //...

# Frontend tests
cd packages/crab_city_ui && pnpm test
cd packages/workshop_ui && pnpm test
```

## Formatting
Expand Down Expand Up @@ -119,7 +119,7 @@ These must stay in sync.
See the [architecture doc](docs/architecture.md) for system design details, or the CLAUDE.md files in each package for module-level maps and patterns:

- [`CLAUDE.md`](CLAUDE.md) — top-level build system and architecture notes
- [`packages/crab_city/CLAUDE.md`](packages/crab_city/CLAUDE.md) — server module map, key patterns, testing
- [`packages/workshop/CLAUDE.md`](packages/workshop/CLAUDE.md) — server module map, key patterns, testing

## Documentation

Expand Down
Loading
Loading