Skip to content

Repo layout

.
├── server/                  # Go module; the backend
│   ├── main.go              # entrypoint; flag parsing; mux registration; signal handling
│   ├── handlers.go          # POST /api/chat + helpers (statelessChat, statefulChat)
│   ├── *_handlers.go        # one file per route group (connections, conversations, ...)
│   ├── store.go             # conversation persistence (encrypted)
│   ├── cryptostore.go       # the AEAD layer; every persistent write goes through here
│   ├── auth.go              # WebAuthn ceremony + session signing
│   ├── tokens.go            # bearer-token mint + storage
│   ├── connections.go       # ConnectionManager (LLM profiles)
│   ├── image_connections.go # ImageConnectionManager (SD profiles)
│   ├── characters.go        # Tavern card store + PNG chunk read/write
│   ├── characters_external.go  # read-only cards from card_dirs
│   ├── personas.go          # persona store (Tavern v2 with persona extension)
│   ├── builtin_character.go # the embedded Pluma card
│   ├── builtin_workflows.go # ComfyUI workflows that ship with the binary
│   ├── tsnet.go             # embedded Tailscale node controller
│   ├── tsnet_handlers.go    # POST /api/tailscale/{enable,disable} + status
│   ├── config.go            # config.toml read/write + comment-preserving renderer
│   ├── limits.go            # body-size caps
│   ├── ssrf.go              # restricted HTTP client + dial guard
│   ├── voice_library.go     # voice-clone sample storage
│   ├── voice_library_handlers.go
│   ├── voice_library_import.go  # yt-dlp + direct-fetch URL import
│   ├── tts.go               # OpenAI-compat TTS provider
│   ├── tts_handlers.go      # POST /api/tts/{speak,config,voices,models}
│   ├── tts_voice_discovery.go   # filesystem + curated catalogue voice fallback
│   ├── cli.go               # cobra root command
│   ├── cli_auth.go          # pluma auth {login,logout,whoami}
│   ├── embed.go             # //go:embed embedded
│   ├── embedded/            # vite build output (gitignored)
│   ├── embedded_chars/      # built-in character PNG (Pluma)
│   └── *_test.go            # unit tests
├── web/                     # Svelte SPA
│   ├── src/
│   │   ├── App.svelte       # root component; layout, modals, routing
│   │   ├── main.ts          # mount point; theme registration
│   │   ├── app.css          # base styles; theme CSS-variable seeds
│   │   ├── components/      # everything visible
│   │   ├── lib/             # state stores + helpers (api.ts, *.svelte.ts)
│   │   ├── themes/          # pluma-teal, pluma-rose, the Theme abstraction
│   │   └── *.test.ts        # vitest unit tests
│   ├── package.json
│   ├── tsconfig.json
│   └── vite.config.ts
├── docs/                    # MkDocs Material source for plumachat.app
├── scripts/
│   └── dev-watch.sh         # auto-rebuild + bounce loop
├── specs/                   # design docs + upstream-issue specs
├── Formula/
│   └── pluma.rb             # Homebrew formula template
├── .github/
│   ├── workflows/           # ci, release, docs
│   ├── ISSUE_TEMPLATE/
│   └── PULL_REQUEST_TEMPLATE.md
├── .beads/                  # local bd (beads) issue tracker state
├── README.md
├── CHANGELOG.md
├── CONTRIBUTING.md
├── CODE_OF_CONDUCT.md
├── SECURITY.md
├── SECURITY_REVIEW.md       # archive of the security-audit pass
├── LICENSE                  # MIT
├── Makefile
└── mkdocs.yml               # docs config

File naming

  • Go handlers cluster by route group: <thing>_handlers.go for the HTTP layer, <thing>.go for the storage / logic layer.
  • Tests share the base file name with _test.go.
  • Svelte components are PascalCase (MessageView.svelte); stores are kebab-case-suffixed *.svelte.ts (store.svelte.ts).

Module boundary

server/ is the Go module root (go.mod lives there). Imports inside the binary are bare ("pluma" is the module path; everything's package main). External deps are listed in server/go.mod.

The frontend is an entirely separate concern: web/package.json is the npm root. Nothing in server/ reads anything in web/ except the built embedded/ directory at compile time.