168 lines
4.2 KiB
Markdown
168 lines
4.2 KiB
Markdown
# Toes - Claude Code Guide
|
|
|
|
## What It Is
|
|
|
|
Personal web appliance that auto-discovers and runs multiple web apps on your home network.
|
|
|
|
"Plug it in, turn it on, and forget about the cloud."
|
|
|
|
## How It Works
|
|
|
|
1. Host server scans `/apps` directory for valid apps
|
|
2. Valid app = has `package.json` with `scripts.toes` entry
|
|
3. Each app spawned as child process with unique port (3001+)
|
|
4. Dashboard UI shows all apps with current status, logs, and links
|
|
|
|
## Key Files
|
|
|
|
### Server (`src/server/`)
|
|
- `apps.ts` - **The heart**: app discovery, process management, health checks, auto-restart
|
|
- `api/apps.ts` - REST API for app lifecycle (start/stop/restart, logs, icons, rename)
|
|
- `api/sync.ts` - File sync protocol (manifest, push/pull, watch)
|
|
- `index.tsx` - Entry point (minimal, initializes Hype)
|
|
- `shell.tsx` - HTML shell for web UI
|
|
|
|
### Client (`src/client/`)
|
|
- `components/` - Dashboard, Sidebar, AppDetail, Nav
|
|
- `modals/` - NewApp, RenameApp, DeleteApp dialogs
|
|
- `styles/` - Forge CSS-in-JS (themes, buttons, forms, layout)
|
|
- `state.ts` - Client state management
|
|
- `api.ts` - API client
|
|
|
|
### CLI (`src/cli/`)
|
|
- `commands/manage.ts` - list, start, stop, restart, info, new, rename, delete, open
|
|
- `commands/sync.ts` - push, pull, sync
|
|
- `commands/logs.ts` - log viewing with tail support
|
|
|
|
### Shared (`src/shared/`)
|
|
- Code shared between frontend (browser) and backend (server)
|
|
- `types.ts` - App, AppState, Manifest interfaces
|
|
- IMPORTANT: Cannot use filesystem or Node APIs (runs in browser)
|
|
|
|
### Lib (`src/lib/`)
|
|
- Code shared between CLI and server (server-side only)
|
|
- `templates.ts` - Template generation for new apps
|
|
- Can use filesystem and Node APIs (never runs in browser)
|
|
|
|
### Other
|
|
- `apps/*/package.json` - Must have `"toes": "bun run --watch index.tsx"` script
|
|
- `TODO.txt` - Task list
|
|
|
|
## Tech Stack
|
|
|
|
- **Bun** runtime (not Node)
|
|
- **Hype** (custom HTTP framework wrapping Hono) from git+https://git.nose.space/defunkt/hype
|
|
- **Forge** (typed CSS-in-JS) from git+https://git.nose.space/defunkt/forge
|
|
- **Commander** + **kleur** for CLI
|
|
- TypeScript + Hono JSX
|
|
|
|
## Running
|
|
|
|
```bash
|
|
bun run --hot src/server/index.tsx # Dev mode with hot reload
|
|
```
|
|
|
|
## App Structure
|
|
|
|
```tsx
|
|
// apps/example/index.tsx
|
|
import { Hype } from "@because/hype"
|
|
const app = new Hype()
|
|
app.get("/", (c) => c.html(<h1>Content</h1>))
|
|
export default app.defaults
|
|
```
|
|
|
|
## Conventions
|
|
|
|
- Apps get `PORT` env var from host
|
|
- Each app is isolated process with own dependencies
|
|
- No path-based routing - apps run on separate ports
|
|
- `DATA_DIR` env controls where apps are discovered
|
|
- Path aliases: `$` → server, `@` → shared, `%` → lib
|
|
|
|
## Current State
|
|
|
|
### Infrastructure (Complete)
|
|
- App discovery, spawn, watch, auto-restart with exponential backoff
|
|
- Health checks every 30s (3 failures trigger restart)
|
|
- Port pool (3001-3100), sticky allocation per app
|
|
- SSE streams for real-time app state and log updates
|
|
- File sync protocol with hash-based manifests
|
|
|
|
### CLI
|
|
- Full management: `toes list|start|stop|restart|info|new|rename|delete|open`
|
|
- File sync: `toes push|pull|sync`
|
|
- Logs: `toes logs [-f] <app>`
|
|
|
|
Check `TODO.txt` for planned features
|
|
|
|
## Coding Guidelines
|
|
|
|
TS files should be organized in the following way:
|
|
|
|
- imports
|
|
- re-exports
|
|
- const/lets
|
|
- enums
|
|
- interfaces
|
|
- types
|
|
- classes
|
|
- functions
|
|
- module init (top level function calls)
|
|
|
|
In each section, put the `export`s first, in alphabetical order.
|
|
|
|
Then, after the `export`s (if there were any), put everything else,
|
|
also in alphabetical order.
|
|
|
|
For single-line functions, use `const fn = () => {}` and put them in the
|
|
"functions" section of the file.
|
|
|
|
All other functions use the `function blah(){}` format.
|
|
|
|
Example:
|
|
|
|
```ts
|
|
import { code } from "coders"
|
|
import { something } from "somewhere"
|
|
|
|
export type { SomeType }
|
|
|
|
const RETRY_TIMES = 5
|
|
const WIDTH = 480
|
|
|
|
enum State {
|
|
Stopped,
|
|
Starting,
|
|
Running,
|
|
}
|
|
|
|
interface Config {
|
|
name: string
|
|
port: number
|
|
}
|
|
|
|
type Handler = (req: Request) => Response
|
|
|
|
class App {
|
|
config: Config
|
|
|
|
constructor(config: Config) {
|
|
this.config = config
|
|
}
|
|
}
|
|
|
|
const isApp = (name: string) =>
|
|
apps.has(name)
|
|
|
|
function createApp(name: string): App {
|
|
const app = new App({ name, port: 3000 })
|
|
apps.set(name, app)
|
|
return app
|
|
}
|
|
|
|
function start(app: App): void {
|
|
console.log(`Starting ${app.config.name}`)
|
|
}
|
|
```
|