Monorepo for Aesthetic.Computer
aesthetic.computer
1# CLAUDE.md
2
3This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
5## Project Overview
6
7Aesthetic Computer (AC) is a mobile-first runtime and social network for creative computing. It's designed as a musical instrument-like interface where users discover memorizable paths through commands and published "pieces" (interactive programs). The system supports both JavaScript (.mjs) and KidLisp (.lisp) pieces.
8
9## Agent Memory (Local-First)
10
11When @jeffrey is working, Claude hook events are written to a local encrypted memory store first.
12
13- **Hook**: `.claude/settings.json` → `UserPromptSubmit` → `node memory/hook.mjs`
14- **Git hook**: `.githooks/post-commit` → commit log + Codex import + remote flush
15- **Local store**: `~/.ac-agent-memory` (overridable via `AGENT_MEMORY_HOME`)
16- **Encryption**: AES-256-GCM (`AGENT_MEMORY_KEY` optional; local key file otherwise)
17- **Redaction**: metadata and summaries are redacted before indexing/sync
18- **CLI**: `node memory/cli.mjs` (`list`, `remember`, `checkpoint`, `doctor`, `profile`, `flush-remote`)
19- **Codex import**: `node memory/codex-sync.mjs`
20
21Remote writes are optional and disabled by default:
22
23- `AGENT_MEMORY_REMOTE_ENABLED=true` + `AGENT_MEMORY_REMOTE_URL=...` enables queued remote sync
24
25`remember` continuity is represented as lineage (`remembered_from`) instead of taking over a live mutable session.
26
27## AestheticAnts & Score.md
28
29This repository uses an automated maintenance system called "AestheticAnts" (AA). The main score lives at `SCORE.md`, and ant-specific mindset/rules live in `ants/mindset-and-rules.md`. Read both before contributing.
30
31**Important:** Do not modify `ants/mindset-and-rules.md` unless you are the queen (@jeffrey).
32
33## Development Commands
34
35### Running the Development Environment
36
37The system consists of multiple servers that run concurrently:
38
39```bash
40# Run all servers (site, session, edge, stripe) - primary dev command
41npm run aesthetic
42# or shorthand:
43npm run ac
44
45# Run individual servers:
46npm run site # Main dev server (port 8888)
47npm run server:session # Session backend (port 8889)
48npm run stripe # Stripe webhook listener
49```
50
51### Testing
52
53```bash
54# Run all tests
55npm test
56
57# KidLisp tests (with auto-reload on changes)
58npm run test:kidlisp
59
60# KidLisp tests (direct, no watch)
61npm run test:kidlisp:direct
62
63# Performance tests
64npm run test:perf
65npm run test:perf:chrome
66npm run test:perf:lighthouse
67```
68
69### Creating New Pieces
70
71```bash
72# Generate a new piece from the blank.mjs template
73npm run new piece-name "Description of the piece"
74```
75
76### Working with Sessions
77
78```bash
79# List active session backends
80npm run session:alive
81
82# View logs for a specific session
83npm run server:session:logs SESSION_ID
84
85# Reset/terminate a session
86npm run session:reset SESSION_ID
87
88# Deploy session server
89npm run session:publish
90```
91
92### Assets Management
93
94```bash
95# Sync assets down from Digital Ocean Spaces
96npm run assets:sync:down
97
98# Sync assets up to Digital Ocean Spaces
99npm run assets:sync:up
100```
101
102### AC Native OS (fedac/native/)
103
104```bash
105# Full build pipeline: binary → initramfs → kernel
106ac-os build
107
108# Build + flash USB
109ac-os flash
110
111# Build + upload OTA release (ALWAYS rebuilds first)
112ac-os upload
113
114# Build + flash + upload
115ac-os flash+upload
116```
117
118**Critical:** `ac-os upload` always does a full rebuild before uploading. The kernel embeds the git hash and build name at compile time (`AC_GIT_HASH`, `AC_BUILD_NAME` in the Makefile). Uploading without rebuilding would serve a stale kernel with the wrong version string.
119
120### Notation
121
122- **compush** - commit & push
123
124## Architecture
125
126### Core Components
127
1281. **Boot System** (`system/public/aesthetic.computer/boot.mjs`)
129 - Entry point that loads the BIOS and initializes the runtime
130 - Manages service worker registration for module caching
131 - Handles WebSocket module loader for hot reloading
132 - Boot telemetry system logs to `/api/boot-log`
133
1342. **BIOS** (`system/public/aesthetic.computer/bios.mjs`)
135 - Main runtime coordinator
136 - Manages piece lifecycle (boot, act, paint, sim, etc.)
137 - Provides the API surface for pieces
138 - Handles routing and navigation
139
1403. **Disk System** (`system/public/aesthetic.computer/lib/disk.mjs`)
141 - Large module (~572KB) that provides the core API for pieces
142 - Graphics primitives, audio, input handling, UI components
143 - All pieces interact with AC through the Disk API
144
1454. **Module Loader** (`system/public/aesthetic.computer/module-loader.mjs`)
146 - WebSocket-based dynamic module loading
147 - Enables hot reloading during development
148 - Prefetches commonly used modules
149
150### Pieces
151
152Pieces are the fundamental unit of content in AC. Each piece is a single `.mjs` or `.lisp` file located in `system/public/aesthetic.computer/disks/`.
153
154#### Piece Structure (JavaScript)
155
156Pieces export lifecycle functions that receive an API object:
157
158```javascript
159// boot: runs once when the piece loads
160function boot({ wipe, screen, params, colon, api }) {
161 // Initialize state
162}
163
164// paint: runs every frame
165function paint({ wipe, ink, line, circle, screen }) {
166 // Render graphics
167}
168
169// act: handles user input and events
170function act({ event: e }) {
171 if (e.is("keyboard:down:space")) {
172 // Handle spacebar press
173 }
174}
175
176// sim: simulation/game logic that runs every frame
177function sim() {
178 // Update game state
179}
180
181export { boot, paint, act, sim };
182```
183
184Common lifecycle functions:
185- `boot` - Initialization, runs once
186- `paint` - Rendering, runs every frame
187- `act` - Event handling (input, network, etc.)
188- `sim` - Simulation/logic, runs every frame
189- `leave` - Cleanup when exiting the piece
190- `preview` - Static preview image generation
191
192#### Piece API Surface
193
194The API is provided through function parameters. Common APIs:
195- **Graphics**: `wipe`, `ink`, `line`, `box`, `circle`, `plot`, `paste`, etc.
196- **Text**: `write`, `type`, `paste`, `help`
197- **Input**: `event`, `pen`, `hand`, `gamepad`
198- **Audio**: `sound`, `speaker`, `microphone`
199- **UI**: `ui.Button`, `ui.TextInput`, `cursor`
200- **System**: `screen`, `params`, `colon`, `store`, `net`, `jump`, `send`
201
202### Servers and Services
203
2041. **System Server** (`system/` + `lith/`)
205 - Production: lith monolith (Express + Caddy on DigitalOcean VPS)
206 - Dev: `npm run site` (port 8888)
207 - Backend functions in `system/netlify/functions/`
208 - Handles piece serving, authentication, storage APIs
209
2102. **Session Server** (`session-server/`)
211 - Per-session backend using Jamsocket for ephemeral deployments
212 - WebSocket server using Geckos.io for real-time communication
213 - Manages chat, multiplayer state, and real-time features
214 - Uses Redis for state synchronization
215
2163. **Feed Server** (`dp1-feed/`)
217 - Cloudflare Worker for activity feeds
218 - Deployed separately to Cloudflare Workers
219
220### KidLisp
221
222KidLisp is a minimal Lisp dialect for generative art, with 118 built-in functions across 12 categories. See `kidlisp/README.md` for comprehensive documentation.
223
224**Key files:**
225- `system/public/aesthetic.computer/lib/kidlisp.mjs` - Main evaluator
226- `system/netlify/functions/store-kidlisp.mjs` - Storage API
227- `kidlisp/tools/` - Analysis and debugging tools
228
229**Running KidLisp tools:**
230```bash
231# Analyze piece structure (requires dev server running)
232./kidlisp/tools/source-tree.mjs $cow
233
234# Get source code
235./kidlisp/tools/get-source.mjs $piece-code
236```
237
238### Data Storage
239
240- **MongoDB**: User data, handles, chat messages, moods
241- **Redis**: Session state, real-time coordination
242- **Firebase**: Authentication, cloud messaging
243- **Digital Ocean Spaces**: Asset storage (CDN)
244
245### Routing and URLs
246
247- Pieces are URL-addressable: `https://aesthetic.computer/piece-name`
248- Parameters: `piece-name:param1:param2`
249- User pieces: `@handle/piece-name`
250- QR code sharing: `share piece-name`
251
252## Development Workflow
253
254### Local Development in Codespaces
255
256When running in GitHub Codespaces, the server is accessible at:
257```
258https://{CODESPACE_NAME}-8888.app.github.dev
259```
260
261Get your Codespace name: `echo $CODESPACE_NAME`
262
263### Hot Reloading
264
265The module loader provides hot reloading during development:
266- Piece changes are reflected immediately when saved
267- WebSocket connection shown in boot canvas
268- Use `channel custom-name` for multi-device testing
269
270### Publishing
271
272```bash
273# In the AC prompt:
274publish # Publish current piece
275publish piece-name # Publish with custom name
276source # Download blank template
277source piece-name # Fork existing piece
278```
279
280## Important Directories
281
282- `system/public/aesthetic.computer/disks/` - All pieces (.mjs and .lisp files)
283- `system/public/aesthetic.computer/lib/` - Shared libraries and utilities
284- `system/netlify/functions/` - Serverless backend functions
285- `session-server/` - Real-time session backend
286- `shared/` - Code shared between system and session servers
287- `kidlisp/` - KidLisp language documentation and tools
288- `spec/` - Jasmine tests for KidLisp
289- `ants/` - AestheticAnts automated maintenance system
290
291## Key Patterns
292
293### Event Handling in Pieces
294
295Events use a string-based pattern matching system:
296```javascript
297event.is("keyboard:down:a") // 'a' key pressed
298event.is("touch") // Any touch event
299event.is("lift") // Touch/click released
300event.is("draw") // Drag with pen down
301event.is("keyboard:down:arrowup") // Arrow key
302```
303
304### State Management
305
306Pieces maintain state in module-level variables:
307```javascript
308let score = 0;
309let enemies = [];
310
311function boot() {
312 // Initialize state
313}
314
315function sim() {
316 // Update state
317 score += 1;
318}
319```
320
321### API Requests from Pieces
322
323Use the `net` API for HTTP requests:
324```javascript
325function boot({ net }) {
326 net.pieces("@user/list").then((data) => {
327 // Handle response
328 });
329}
330```
331
332### Multiplayer Networking (Dual-Channel Pattern)
333
334Multiplayer pieces use both WebSocket (reliable) and UDP (low-latency) channels. See `squash.mjs` for the canonical implementation.
335
336```javascript
337function boot({ net: { socket, udp }, handle }) {
338 // UDP for high-frequency position sync (low latency, may drop packets)
339 udpChannel = udp((type, content) => {
340 if (type === "game:move") {
341 const d = typeof content === "string" ? JSON.parse(content) : content;
342 // Update remote player position
343 }
344 });
345
346 // WebSocket for reliable game events (join/leave, scoring, round control)
347 server = socket((id, type, content) => {
348 if (type.startsWith("connected")) { /* joined session */ }
349 if (type === "left") { /* player disconnected */ }
350 if (type === "game:join") { /* another player joined */ }
351 if (type === "game:score") { /* reliable score event */ }
352 });
353
354 // Send reliable event
355 server.send("game:join", { handle: handle() });
356 // Send low-latency position update
357 udpChannel.send("game:move", { x, y, vx, vy });
358}
359```
360
361**Session server routing:**
362- UDP handlers: add `channel.on("game:move", ...)` in geckos section of `session-server/session.mjs`
363- WebSocket: position messages use `others()` (relay to all except sender), game events use `everyone()` (catch-all relay)
364- Chat invites: typing `'piece-name'` in chat creates a clickable link to join
365
366**Reference pieces:** `squash.mjs` (2D platformer), `1v1.mjs` (3D FPS), `udp.mjs` (minimal UDP test)
367
368### UI Components
369
370```javascript
371function boot({ ui: { Button, TextInput } }) {
372 const btn = new Button("Click me", { box: [10, 10, 100, 40] });
373}
374
375function act({ event: e }) {
376 if (btn.trigger(e)) {
377 // Button was clicked
378 }
379}
380```
381
382## Notes
383
384- The codebase uses `.mjs` extension for ES modules
385- Prefer `const` destructuring for API parameters to minimize imports
386- Graphics operations are immediate-mode (no retained scene graph)
387- All coordinates are in pixels
388- Default color depth is 8-bit RGB (0-255 per channel)
389- The `wipe` function clears the screen and should be called first in `paint`
390- When making changes, consult `ants/mindset-and-rules.md` for the ant operating philosophy