Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
b8a6ebd
wip
ryanatkn Feb 21, 2026
539f690
wip
ryanatkn Feb 21, 2026
e67dd44
wip
ryanatkn Feb 21, 2026
64abc74
wip
ryanatkn Feb 21, 2026
8248c94
wip
ryanatkn Feb 21, 2026
c99056b
wip
ryanatkn Feb 21, 2026
696a54b
wip
ryanatkn Feb 22, 2026
750ffd3
wip
ryanatkn Feb 22, 2026
32c8fb4
wip
ryanatkn Feb 23, 2026
9a4c36b
wip
ryanatkn Feb 23, 2026
da9b473
wip
ryanatkn Feb 23, 2026
a4b1053
wip
ryanatkn Feb 23, 2026
ce873fa
wip
ryanatkn Feb 24, 2026
682524b
wip
ryanatkn Feb 24, 2026
75de40d
wip
ryanatkn Feb 24, 2026
86f998c
wip
ryanatkn Feb 24, 2026
1b72fce
wip
ryanatkn Feb 24, 2026
852ade8
wip
ryanatkn Feb 24, 2026
f3e0efc
wip
ryanatkn Feb 24, 2026
7a326dd
wip
ryanatkn Feb 24, 2026
401e05c
wip
ryanatkn Feb 25, 2026
ae905da
wip
ryanatkn Feb 28, 2026
f3c0238
wip
ryanatkn Feb 28, 2026
a7b82ae
wip
ryanatkn Feb 28, 2026
0cc5084
wip
ryanatkn Feb 28, 2026
9ce0ee0
wip
ryanatkn Feb 28, 2026
48ecf48
wip
ryanatkn Feb 28, 2026
664debf
wip
ryanatkn Feb 28, 2026
9d99266
wip
ryanatkn Feb 28, 2026
c6c7c58
wip
ryanatkn Feb 28, 2026
6c400f4
wip
ryanatkn Feb 28, 2026
7b24362
wip
ryanatkn Feb 28, 2026
52c0e97
wip
ryanatkn Mar 2, 2026
2378d22
wip
ryanatkn Mar 3, 2026
9c2b12b
wip
ryanatkn Mar 3, 2026
82464e2
wip
ryanatkn Mar 3, 2026
2e98abc
wip
ryanatkn Mar 4, 2026
bd26255
Merge branch 'main' into fuz-app
ryanatkn Mar 4, 2026
ee4573e
wip
ryanatkn Mar 4, 2026
982ef3a
wip
ryanatkn Mar 5, 2026
c734081
wip
ryanatkn Mar 6, 2026
7d3774d
wip
ryanatkn Mar 6, 2026
c02ba10
wip
ryanatkn Mar 6, 2026
65ff52e
wip
ryanatkn Mar 6, 2026
dd6c71d
wip
ryanatkn Mar 8, 2026
9a60a22
wip
ryanatkn Mar 8, 2026
80dd11c
wip
ryanatkn Mar 9, 2026
78c388d
wip
ryanatkn Mar 10, 2026
50f4724
wip
ryanatkn Mar 10, 2026
ebaf102
wip
ryanatkn Mar 10, 2026
777ddf1
wip
ryanatkn Mar 10, 2026
1e1f905
wip
ryanatkn Mar 10, 2026
480a6b8
wip
ryanatkn Mar 10, 2026
e809d87
wip
ryanatkn Mar 11, 2026
f2874f8
wip
ryanatkn Mar 11, 2026
727316b
wip
ryanatkn Mar 11, 2026
1bc5721
wip
ryanatkn Mar 12, 2026
000946a
wip
ryanatkn Mar 12, 2026
0c17d80
wip
ryanatkn Mar 12, 2026
ac1c68c
wip
ryanatkn Mar 12, 2026
86b0cf1
wip
ryanatkn Mar 12, 2026
73d909c
wip
ryanatkn Mar 13, 2026
ab56de6
wip
ryanatkn Mar 16, 2026
ac9a09b
wip
ryanatkn Mar 16, 2026
ddafab8
wip
ryanatkn Mar 16, 2026
0899b8a
wip
ryanatkn Mar 16, 2026
4833a89
wip
ryanatkn Mar 16, 2026
ed4c3e2
wip
ryanatkn Mar 16, 2026
a4ee29e
wip
ryanatkn Mar 16, 2026
a95bd2e
wip
ryanatkn Mar 16, 2026
2fae2ab
wip
ryanatkn Mar 16, 2026
cf25fef
wip
ryanatkn Mar 17, 2026
182abba
wip
ryanatkn Mar 17, 2026
a712a79
wip
ryanatkn Mar 17, 2026
dce0e54
wip
ryanatkn Mar 17, 2026
65579b5
wip
ryanatkn Mar 19, 2026
c2a96ce
wip
ryanatkn Mar 19, 2026
12bbe14
wip
ryanatkn Mar 21, 2026
6254b7b
wip
ryanatkn Mar 22, 2026
12500da
wip
ryanatkn Mar 22, 2026
ef31b01
wip
ryanatkn Mar 22, 2026
12f9bbe
wip
ryanatkn Mar 22, 2026
17c1181
wip
ryanatkn Mar 23, 2026
3ebfb03
wip
ryanatkn Mar 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 130 additions & 17 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

> nice web things for the tired

`@fuzdev/zzz` — local-first AI forge: chat + files + prompts in one app.
SvelteKit frontend, Hono/Node.js backend, Svelte 5 runes, Zod schemas.
v0.0.1, no auth, no database yet. 26 cell classes, 20 action specs, 4 AI providers.
`@fuzdev/zzz` — local-first AI forge: chat + files + prompts + terminals in one app.
SvelteKit frontend, Hono/Deno backend, Svelte 5 runes, Zod schemas.
v0.0.1, no auth, no database yet. 28 cell classes, 25 action specs, 4 AI providers.

For coding conventions, see [`fuz-stack`](../fuz-stack/CLAUDE.md).

Expand All @@ -14,7 +14,8 @@ For coding conventions, see [`fuz-stack`](../fuz-stack/CLAUDE.md).
2. **Edit files** on disk — scoped filesystem, syntax highlighting, multi-tab editor
3. **Build prompts** — reusable content templates composed from text parts and file references
4. **Manage models** — Ollama local models + Claude/ChatGPT/Gemini via BYOK API keys
5. **Symmetric actions** — JSON-RPC 2.0 between frontend and backend, same ActionPeer on both sides
5. **Run terminals** — interactive PTY terminals via xterm.js with preset commands, contextmenu copy, and restart
6. **Symmetric actions** — JSON-RPC 2.0 between frontend and backend, same ActionPeer on both sides

## Key Principles

Expand All @@ -25,34 +26,60 @@ For coding conventions, see [`fuz-stack`](../fuz-stack/CLAUDE.md).

## Development Stage

Early development, v0.0.1. Breaking changes are expected and welcome. No authentication — development use only. All state is in-memory (no database yet). The Hono/Node.js backend is a reference implementation that may be replaced by a Rust daemon (`fuzd`).
Early development, v0.0.1. Breaking changes are expected and welcome. No authentication — development use only. All state is in-memory (no database yet). The Hono/Deno backend is a reference implementation that may be replaced by a Rust daemon (`fuzd`). Deno is a shortcut — long-term the CLI and daemon migrate to Rust fuz/fuzd.

See [GitHub issues](https://github.com/fuzdev/zzz/issues) for planned work.

## CLI

zzz has a Deno-compiled CLI binary for daemon management and browser launching.
See [src/lib/zzz/CLAUDE.md](src/lib/zzz/CLAUDE.md) for full CLI architecture.

```bash
zzz # start daemon if needed, open browser
zzz ~/dev/ # open workspace at ~/dev/
zzz daemon start # start daemon (foreground)
zzz daemon status # show daemon info
zzz init # initialize ~/.zzz/
```

The global daemon runs on port 4460 with state at `~/.zzz/`. Built via
`gro_plugin_deno_compile` (see `gro.config.ts` and `deno.json`).

## Docs

- [docs/architecture.md](docs/architecture.md) — Action system, Cell system, content model, data flow
- [docs/development.md](docs/development.md) — Development workflow, extension points, patterns
- [docs/providers.md](docs/providers.md) — AI provider integration, adding new providers
- [src/lib/server/CLAUDE.md](src/lib/server/CLAUDE.md) — Backend server architecture, providers, security
- [src/lib/zzz/CLAUDE.md](src/lib/zzz/CLAUDE.md) — CLI architecture, commands, runtime abstraction

## Repository Structure

```
src/
├── lib/ # Published as @fuzdev/zzz
│ ├── server/ # Backend (Hono/Node.js reference impl)
│ ├── server/ # Backend (Hono/Deno reference impl)
│ │ ├── backend.ts
│ │ ├── server.ts
│ │ ├── server.ts # Deno server entry (dev + production)
│ │ ├── backend_action_handlers.ts
│ │ ├── backend_provider_*.ts # Ollama, Claude, ChatGPT, Gemini
│ │ ├── pty_ffi.ts # Deno FFI bindings for libfuz_pty.so
│ │ ├── backend_pty_manager.ts # PTY process management (FFI or fallback)
│ │ ├── scoped_fs.ts
│ │ ├── security.ts
│ │ └── backend_action_types.gen.ts
│ │
│ ├── *.svelte.ts # Cell state classes (26 classes)
│ ├── action_specs.ts # All 20 action spec definitions
│ ├── action_spec.ts # ActionSpec schema
│ ├── zzz/ # CLI (Deno compiled binary)
│ │ ├── main.ts # Entry point (deno compile target)
│ │ ├── cli.ts # Arg parsing wrapper
│ │ ├── cli_config.ts # ~/.zzz/config.json
│ │ ├── runtime/ # ZzzRuntime abstraction
│ │ ├── cli/ # CLI infrastructure
│ │ └── commands/ # init, daemon, open, status
│ │
│ ├── *.svelte.ts # Cell state classes (28 classes)
│ ├── action_specs.ts # All 25 action spec definitions
│ ├── action_event.ts # Action lifecycle state machine
│ ├── action_peer.ts # Symmetric send/receive
│ ├── cell.svelte.ts # Base Cell class
Expand All @@ -64,7 +91,7 @@ src/
│ ├── frontend_action_types.gen.ts
│ └── action_metatypes.gen.ts
├── routes/ # SvelteKit routes (16 dirs)
├── routes/ # SvelteKit routes (17 dirs)
│ ├── about/
│ ├── actions/
│ ├── bots/
Expand All @@ -80,6 +107,7 @@ src/
│ ├── repos/
│ ├── settings/
│ ├── tabs/
│ ├── terminals/
│ └── views/
├── test/ # Tests (not co-located)
Expand All @@ -101,7 +129,7 @@ See [docs/architecture.md](docs/architecture.md) for detailed data flow, content

## Cell Classes

26 registered classes in `src/lib/cell_classes.ts`:
28 registered classes in `src/lib/cell_classes.ts`:

| Class | Source file | Purpose |
| ---------------- | ------------------------------ | ------------------------------------ |
Expand Down Expand Up @@ -129,12 +157,14 @@ See [docs/architecture.md](docs/architecture.md) for detailed data flow, content
| `Turn` | `turn.svelte.ts` | Single conversation message |
| `Thread` | `thread.svelte.ts` | Linear conversation with one model |
| `Threads` | `threads.svelte.ts` | Collection of threads |
| `Terminal` | `terminal.svelte.ts` | PTY terminal process state |
| `TerminalPreset` | `terminal_preset.svelte.ts` | Saved terminal command config |
| `Time` | `time.svelte.ts` | Reactive time state |
| `Ui` | `ui.svelte.ts` | UI state (menus, layout) |

## Action Specs

20 specs in `src/lib/action_specs.ts`:
25 specs in `src/lib/action_specs.ts`:

| Method | Kind | Initiator | Purpose |
| ------------------------ | --------------------- | ---------- | -------------------------------- |
Expand All @@ -158,6 +188,11 @@ See [docs/architecture.md](docs/architecture.md) for detailed data flow, content
| `ollama_unload` | `request_response` | `frontend` | Unload Ollama model from memory |
| `provider_load_status` | `request_response` | `frontend` | Check provider availability |
| `provider_update_api_key`| `request_response` | `frontend` | Update provider API key |
| `terminal_create` | `request_response` | `frontend` | Spawn PTY terminal process |
| `terminal_data_send` | `request_response` | `frontend` | Send stdin to terminal |
| `terminal_data` | `remote_notification` | `backend` | Stream stdout/stderr to frontend |
| `terminal_resize` | `request_response` | `frontend` | Update PTY dimensions |
| `terminal_close` | `request_response` | `frontend` | Kill terminal process |

## Development Workflow

Expand All @@ -166,6 +201,10 @@ See [docs/architecture.md](docs/architecture.md) for detailed data flow, content
```bash
cp src/lib/server/.env.development.example .env.development
npm install

# Optional: build fuz_pty for real PTY support (echo, prompts, colors, resize)
# Without this, terminals fall back to Deno.Command pipes (no interactivity)
cd ~/dev/private_fuz && cargo build -p fuz_pty --release
```

### Daily Commands
Expand Down Expand Up @@ -233,6 +272,7 @@ Each action is a plain object with Zod schemas for input/output:
```typescript
export const diskfile_update_action_spec = {
method: 'diskfile_update',
description: 'Write content to a file on disk',
kind: 'request_response',
initiator: 'frontend',
auth: 'public',
Expand All @@ -254,6 +294,71 @@ Action kinds:
| `remote_notification` | WebSocket only | Backend pushes to frontend |
| `local_call` | None (in-process) | Frontend-only |

### Adding an Action (End-to-End)

Adding a new action touches up to 6 files. Here's the full workflow:

**1. Define the spec** in `src/lib/action_specs.ts`:

```typescript
export const my_action_spec = {
method: 'my_action',
kind: 'request_response', // or 'remote_notification', 'local_call'
initiator: 'frontend', // or 'backend', 'both'
auth: 'public',
side_effects: true, // or null for read-only
input: z.strictObject({ foo: z.string() }),
output: z.strictObject({ bar: z.number() }),
async: true,
description: 'What this action does.',
} satisfies ActionSpecUnion;
```

Add it to the `all_action_specs` array at the bottom of the file.

**2. Run `gro gen`** — regenerates 4 files:
- `action_collections.ts` — `ActionInputs`/`ActionOutputs` type maps
- `action_metatypes.ts` — `ActionMethod` union, `ActionsApi` interface
- `frontend_action_types.ts` — `FrontendActionHandlers` type
- `server/backend_action_types.ts` — `BackendActionHandlers` type

**3. Add backend handler** in `src/lib/server/backend_action_handlers.ts`:

```typescript
my_action: {
receive_request: async ({backend, data: {input}}) => {
// input is typed from the spec's input schema
return {bar: 42}; // must match spec's output schema
},
},
```

**4. Add frontend handler** in `src/lib/frontend_action_handlers.ts`:

```typescript
my_action: {
// For request_response:
receive_response: ({app, data: {output}}) => { /* handle success */ },
receive_error: ({data: {error}}) => { /* handle error */ },
// For remote_notification:
receive: ({app, data: {input}}) => { /* handle notification */ },
},
```

**5. Call from frontend** via `app.api`:

```typescript
// Returns Result<{value: OutputType}, {error: JsonrpcError}>
const result = await app.api.my_action({foo: 'hello'});
if (result.ok) {
console.log(result.value.bar); // 42
}
```

**6. For `remote_notification` actions**, also add to `BackendActionsApi`
in `src/lib/server/backend_actions_api.ts` — follow the `terminal_data`
or `completion_progress` pattern.

### Zod Schema Conventions

- Always use `z.strictObject()` (not `z.object()`) for action specs — unknown keys are rejected
Expand Down Expand Up @@ -285,7 +390,7 @@ The `.zzz/` directory stores app data. Configured via `PUBLIC_ZZZ_DIR`.
| ------------ | -------------------------------------- |
| `state/` | Persistent data (completions logs) |
| `cache/` | Regenerable data, safe to delete |
| `run/` | Runtime ephemeral (server.json: PID, port) |
| `run/` | Runtime ephemeral (daemon.json: PID, port) |

All filesystem access goes through `ScopedFs` — path validation, no symlinks, absolute paths only.

Expand Down Expand Up @@ -325,13 +430,21 @@ From `src/lib/server/.env.development.example`:
- **No authentication** — development use only, anyone with network access can use it
- **No database** — all state is in-memory, lost on restart (pglite planned)
- **No undo/history** — file edits are permanent
- **No terminal integration** — no shell access from the UI
- **PTY via FFI** — real PTY support via `fuz_pty` Rust crate loaded through Deno FFI (`forkpty()`). Requires `cargo build -p fuz_pty --release` in `~/dev/private_fuz/`. For bundled binaries, place `libfuz_pty.so` next to the `zzz` executable. Falls back to `Deno.Command` pipes (no echo, no prompt) if `.so` not found
- **No git integration** — no commit/push/pull from the UI
- **No MCP/A2A** — protocol support planned but not implemented
- **Backend is reference impl** — may be replaced by Rust daemon (`fuzd`)

## fuz_app

zzz is the primary source for the Cell and Action patterns that will become the `fuz_app` package — a shared foundation for Fuz ecosystem apps.
zzz is the reference implementation for Cell and Action patterns. ActionSpec
types have been extracted to `@fuzdev/fuz_app` — zzz imports them from
`@fuzdev/fuz_app/actions/action_spec.js` and `@fuzdev/fuz_app/actions/action_registry.js`.
Cell patterns and the full SAES runtime (ActionEvent, ActionPeer, transports)
remain in zzz until a second consumer needs them (DA-5).

The CLI and daemon lifecycle use `@fuzdev/fuz_app/cli/*` helpers: `DaemonInfo`
schema, `write_daemon_info`, `read_daemon_info`, `is_daemon_running`,
`stop_daemon`. The server writes `~/.zzz/run/daemon.json` (not `server.json`).

Last updated: 2026-02-10
Last updated: 2026-03-16
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Zzz builds on a great deal of software.
- I started using [Claude](https://claude.ai/) in late 2024 after making the initial prototype,
and in late 2025 I started doing much of the coding with Claude Code, Opus 4.5
being the first over some threshold for me for this project
- see `⚠️ AI generated` and similar disclaimers
- see `NOTE: AI-generated` and similar disclaimers

## License 🐦

Expand Down
31 changes: 31 additions & 0 deletions deno.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"unstable": ["sloppy-imports"],
"exclude": ["**/*.test.ts", "**/*.svelte.ts", "**/*.gen.ts", "src/test/"],
"tasks": {
"dev:start": "NODE_ENV=development deno run --allow-all src/lib/zzz/main.ts daemon start",
"install": "gro build && mkdir -p ~/.zzz/bin && cp dist_cli/zzz ~/.zzz/bin/zzz",
"check": "deno check src/lib/zzz/**/*.ts"
},
"imports": {
"@std/": "jsr:@std/",
"esm-env": "npm:esm-env@^1",
"hono": "npm:hono@^4",
"svelte": "npm:svelte@^5",
"zod": "npm:zod@^4",
"@electric-sql/pglite": "npm:@electric-sql/pglite@^0.3",
"@fuzdev/blake3_wasm": "npm:@fuzdev/blake3_wasm@^0.1.0",
"@fuzdev/fuz_app/": "../fuz_app/src/lib/",
"@fuzdev/fuz_util/": "npm:/@fuzdev/fuz_util@^0.53.4/",
"@fuzdev/gro/": "npm:/@fuzdev/gro@^0.197.0/",
"ollama": "npm:ollama@^0.6",
"@anthropic-ai/sdk": "npm:@anthropic-ai/sdk@^0.71.2",
"openai": "npm:openai@^6.10.0",
"@google/generative-ai": "npm:@google/generative-ai@^0.24.1"
},
"fmt": {
"useTabs": true,
"lineWidth": 100,
"indentWidth": 2,
"singleQuote": true
}
}
Loading
Loading