Skip to the content.

Development

Getting Started

To set up PuTTrY for local development:

# Clone the repository
git clone <repo-url>
cd puttry

# Install dependencies
npm install

# Start the dev server
npm run dev

The dev server will start on http://localhost:5175 and display the session password in the terminal. Open the URL in your browser and authenticate with the password.

Project Structure

puttry/
├── src/
│   ├── client/                 # React frontend
│   │   ├── components/         # UI components (sessions, terminal, auth, settings)
│   │   ├── hooks/              # React hooks (auth, WebSocket, terminal state)
│   │   ├── App.tsx             # Main app component
│   │   └── main.tsx            # Entry point
│   │
│   ├── server/                 # Express backend
│   │   ├── server.ts           # Express app setup
│   │   ├── cli.ts              # CLI entry point (puttry command)
│   │   ├── vite-plugin.ts      # Vite dev server integration
│   │   ├── pty-manager.ts      # PTY session management
│   │   ├── terminal-routes.ts  # Session API endpoints
│   │   ├── auth-state.ts       # Password & 2FA persistence
│   │   ├── passkey-state.ts    # Passkey storage
│   │   ├── sync-bus.ts         # WebSocket broadcast for session sync
│   │   ├── rate-limit.ts       # Rate limiting middleware
│   │   ├── settings-api.ts     # Configuration management
│   │   └── logger.ts           # Structured logging
│   │
│   ├── lib/                    # Shared utilities
│   │   ├── utils.ts            # Common helpers
│   │   └── password-gen.ts     # Session password generation
│   │
│   └── vite-env.d.ts           # Vite type definitions
│
├── vite.config.ts              # Vite configuration
├── tsconfig.json               # TypeScript configuration
├── package.json                # Dependencies and scripts
└── README.md                   # This file

Development Scripts

npm run dev – Start Vite dev server with HMR (Hot Module Replacement)

npm run build – Build for production

npm run build:server – Bundle backend with esbuild

npm run build:cli – Bundle CLI with esbuild

npm run lint – Run ESLint

npm run preview – Preview production build locally

How Vite Dev Server Works

PuTTrY uses a custom Vite plugin (vite-plugin.ts) to integrate the Express backend with Vite’s dev server:

Frontend (Vite with HMR)

When you run npm run dev, Vite starts a dev server on port 5175. The frontend is served with Hot Module Replacement (HMR):

Backend (Express Integration)

The custom webTerminalPlugin() Vite plugin does two things:

1. Mounts Express as Vite Middleware

configureServer(server) {
  server.middlewares.use(app)  // Mount Express on Vite's middleware stack
}

This means:

2. Handles WebSocket Upgrades

server.httpServer?.on("upgrade", (req, socket, head) => {
  // /sync WebSocket (session synchronization)
  // /terminal/:sessionId WebSocket (PTY I/O)
})

The plugin intercepts HTTP upgrade requests for:

This allows real-time terminal I/O and multi-tab synchronization during development.

Development Flow

1. Browser connects to http://localhost:5175
   ↓
2. Vite serves index.html with React app
   ↓
3. React app loads and makes API calls:
   - POST /api/auth/login
   - GET /api/sessions
   - WebSocket /sync
   ↓
4. Vite's middleware stack catches these requests
   ↓
5. Express handles them (auth, session management, etc.)
   ↓
6. PTY shell runs on the backend; output streams via /terminal/:sessionId WS
   ↓
7. React receives updates and renders the terminal in real-time

No Separate Backend Server Needed

Unlike some full-stack setups, you don’t need to run a separate backend server in dev. The Vite plugin ensures:

If you modify backend code and it doesn’t reflect, refresh your browser. For full isolation, you can restart the Vite dev server.

Environment Variables

Dev mode loads .env.local from the project root (for development settings) and ~/.puttry/.env (for production-like configs):

# .env.local (development overrides)
PORT=5175
AUTH_DISABLED=0
LOG_SESSION_PASSWORD=1
TOTP_ENABLED=0

See the startup logs for which env file was loaded and current settings.

Debugging

Browser DevTools

Server Logging

WebSocket Debugging

Common Development Tasks

Run with Auth Disabled (for testing)

AUTH_DISABLED=1 npm run dev

Run with Custom Port

PORT=3000 npm run dev

Enable TOTP in Dev

TOTP_ENABLED=1 npm run dev

Build and Test Production Bundle

npm run build:all
npm start  # Starts dist-server/server.js

Lint Code

npm run lint

Testing the Terminal

Once the dev server is running:

  1. Open http://localhost:5175 in your browser
  2. Enter the session password (shown in the terminal output)
  3. Create a new session via the Web UI
  4. Type commands in the terminal (e.g., ls, echo "hello")
  5. Try switching browsers/tabs to test write lock and synchronization
  6. Check browser DevTools Network tab to see WebSocket activity

Building for Production

To create a production build:

npm run build:all

This produces:

To test the production build locally:

npm run build:all
npm start

The server will start on port 3000 (or your configured PORT). Open http://localhost:3000 to verify.

Performance Considerations