This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Muses is an AI-powered blog article generation platform that converts various source materials (PDF, Markdown, text, conversations) into high-quality blog articles. Next.js frontend + FastAPI backend + SQLite.
./start-python.sh # Start both frontend (port 3004) and backend (port 8080)
./scripts/setup.sh # Initial setup (installs deps, creates DB)cd frontend
npm run dev # Dev server on port 3004
npm run dev:turbo # Dev server with Turbo
npm run build # Production build
npm run lint # ESLint
npx tsc --noEmit # Type checking (no test suite yet)cd backend-python
python3 start.py # Start FastAPI (auto-kills existing process on same port)
# Swagger docs at http://localhost:8080/docscd backend-python
alembic revision --autogenerate -m "description" # Create migration
alembic upgrade head # Apply migrationscd backend-python && python -m pytest # All tests
cd backend-python && python -m pytest test_unified_ai.py # Single test file- Frontend: Next.js 14 (App Router), TypeScript, Tailwind CSS, Shadcn/ui, TanStack Query, Zustand, TipTap Editor
- Backend: FastAPI, SQLAlchemy ORM, JWT auth, multi-model AI (OpenAI/Anthropic/Google)
- Database: SQLite with SQLAlchemy + Alembic migrations
- Auth: GitHub OAuth → JWT tokens
API Client (lib/api.ts): Axios instance with auto JWT injection from localStorage. Environment-aware — uses prod API for muses.ink, dev API otherwise. 30s timeout, auto-logout on 401.
State Management:
- Server state: TanStack Query (
staleTime: 60s,refetchOnWindowFocus: false) - Client state: Zustand stores in
store/(user.ts,viewMode.ts,aiAssistant.ts) - Forms: React Hook Form + Zod validation
TipTap Editor (components/NotionEditor.tsx, ~52KB): Heavy component with extensions for tables, task lists, code blocks with syntax highlighting, math (KaTeX), videos (YouTube/Bilibili), resizable images, and collapsible code blocks.
Text Actions System: useTextActions hook provides unified interface for AI text operations (improve, expand, summarize, translate, fix-grammar, brainstorm, custom-prompt). Gated by AI Assistant toggle state.
Router registration in app/main.py: auth, users, agents, agents_actions, articles, generate, upload, publish, process, proxy, image_upload, sync, import_files, knowledge, muses_config, chat_history, studio.
Startup: start.py uses psutil to kill existing processes on the port before starting uvicorn. Settings from app/config.py (env vars).
CORS: Configured to allow only settings.frontend_url. TrustedHost middleware enabled.
- Normal Mode: 3-column layout — article list sidebar + article view
- Co-Create Mode (
components/CoCreateMode.tsx): Split-screen chat + NotionEditor. Chat history persists per article via/api/chat-history/. Auto-save with 500ms debounce. Responses containing<article_edit>...</article_edit>tags replace full editor content. - Co-Read Mode: Split-screen article reader + notes editor with text quoting.
File-based writing workspace at ~/muses-workspace with Claude AI assistance.
Backend (app/api/studio.py):
POST /api/studio/chat— Stream chat via AIHubMix (aihubmix.com/v1), supports file context injectionWS /api/studio/filewatcher— WebSocket for real-time file diffs- File CRUD:
GET/POST/PUT/DELETE /api/studio/files/{filename}
Frontend (components/studio/): ChatPanel, MarkdownEditor, DiffView, DiffOverlay, FileExplorer, HistoryPanel, FloatingTOC. Implements differential sync — tracks file snapshots and computes diffs with accept/reject UI.
Agent Service (app/agent/service.py): AgentService with generate_content() and stream_generate_content(). Uses ModelFactory to instantiate models from agent config. Builds system messages from agent config (tone, audience, custom prompts).
Prompt System (app/agent/prompts/): builder.py for dynamic prompt construction, registry.py for action registry, action_prompts/ subdirectory with 16 action types.
Multi-Model Support (app/services/unified_ai.py): Unified client abstracting OpenAI, Anthropic, and Google APIs. Model definitions in app/models_config.py. Per-agent model selection.
Located in app/agent/knowledge/: chunker → embedder → retriever → storage pipeline. Per-user collections (user_{user_id}_knowledge). API at /api/knowledge/ with endpoints: /add, /search, /build, /stats.
Article Generation: Upload materials → /api/upload/ → text extraction → /api/generate/article with AgentId → AIService + unified_ai → returns title/content/summary → saves as draft.
Co-Create Chat: Open article → chat via /api/agents/chat → responses persist to /api/chat-history/save → user can select AI text to adopt into editor.
Key entities: User (GitHub OAuth, encrypted API keys), Agent (AI writing assistants), Article (content + metadata + publishing info), ChatHistory (per-article conversations), UserSettings, SyncHistory, MusesConfig.
All sensitive data (API keys, tokens) encrypted before storage.
DATABASE_URL="sqlite:///./muses.db"
JWT_SECRET="your-jwt-secret"
GITHUB_CLIENT_ID="your-github-oauth-app-id"
GITHUB_CLIENT_SECRET="your-github-oauth-app-secret"
ENCRYPTION_KEY="your-32-char-encryption-key"
OPENAI_API_KEY="your-openai-api-key"GitHub OAuth callback URL: http://localhost:8080/api/auth/github/callback
/api/auth/github/callback— GitHub OAuth/api/agents/— Agent CRUD;/api/agents/chat— AI chat;/api/agents/text-action— text operations/api/articles/— Article CRUD/api/generate/— AI article generation/api/upload/— File upload processing/api/chat-history/{article_id}— Chat history per article/api/knowledge/— RAG knowledge base operations/api/studio/— Studio mode (chat, files, filewatcher)/api/image-upload/upload-image— GitHub-based image hosting/api/publish/— Publish to GitHub repos/api/users/settings— User settings
Use conventional commits (feat:, fix:, docs:, refactor:, style:, test:, chore:). Always include attribution footer:
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- CI/CD: Push to main → GitHub Actions → Build Docker images → Deploy to Cloud Run
- Backend:
backend-python/Dockerfile→ Cloud Run + Cloud SQL PostgreSQL - Frontend:
frontend/Dockerfile→ Cloud Run (Next.js standalone) - Manual deploy:
./deploy.sh(requiresGCP_PROJECT_IDenv var) - Env config: Copy
.env.production.templateandbackend-env.yaml.template - Studio: Disabled in production (
ENABLE_STUDIO=false) — depends on local filesystem
export GCP_PROJECT_ID="your-project" DB_PASSWORD="your-pass"
./scripts/gcp-setup.sh # Creates Cloud SQL, service account, prints GitHub Secrets to setGCP_PROJECT_ID— Google Cloud project IDGCP_SA_KEY— Service account JSON key (from gcp-setup.sh)CLOUD_SQL_INSTANCE—project:region:muses-dbDATABASE_URL—postgresql://user:pass@/muses?host=/cloudsql/...JWT_SECRET,ENCRYPTION_KEY,ENCRYPTION_SALT— Security keysOAUTH_GITHUB_CLIENT_ID,OAUTH_GITHUB_CLIENT_SECRET— GitHub OAuth AppOPENAI_API_KEY,AIHUBMIX_API_KEY— AI API keys