This document guides the next agent on collecting relevant code and patterns from two source repositories to bootstrap the Draftwell project.
- makefour (
../makefour) - Cloudflare Pages app with auth, storage, and Monaco editor - ml-audio-codecs (
../ml-audio-codecs) - Document revision pipeline scripts
Files to study:
wrangler.toml- Cloudflare Pages config with D1, R2, KV bindingspackage.json- Build scripts, dependencies (vite, wrangler, drizzle, biome)
What to adapt:
- D1 database binding pattern (rename to
draftwell-db) - R2 bucket binding (rename to
draftwell-documents) - KV namespace for rate limiting
- Build and deploy scripts
Files to study:
functions/
├── _middleware.ts # CORS, rate limiting, error handling
├── lib/
│ ├── auth.ts # Session validation
│ ├── crypto.ts # Password hashing utilities
│ ├── rateLimit.ts # KV-based rate limiting
│ └── email.ts # Email sending (verification, password reset)
└── api/auth/
├── register.ts # User registration
├── login.ts # Session creation
├── logout.ts # Session destruction
├── me.ts # Get current user
├── forgot-password.ts # Password reset request
├── reset-password.ts # Password reset completion
├── verify-email.ts # Email verification
└── resend-verification.ts
What to adapt:
- Full auth flow (registration → verification → login → session management)
- Middleware pattern for authenticated routes
- Rate limiting configuration
- Adapt email templates for Draftwell branding
Files to study:
schema.sql- D1 schema (users, sessions tables are relevant)drizzle.config.ts- Drizzle ORM configuration
What to adapt:
- User and session tables (copy directly)
- Remove game-specific tables
- Add new tables for Draftwell:
-- Projects CREATE TABLE projects ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL REFERENCES users(id), name TEXT NOT NULL, styleguide_id TEXT, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL ); -- Documents CREATE TABLE documents ( id TEXT PRIMARY KEY, project_id TEXT NOT NULL REFERENCES projects(id), title TEXT NOT NULL, r2_key TEXT NOT NULL, -- Key in R2 bucket current_revision INTEGER DEFAULT 0, status TEXT DEFAULT 'draft', created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL ); -- Reviews CREATE TABLE reviews ( id TEXT PRIMARY KEY, document_id TEXT NOT NULL REFERENCES documents(id), revision_number INTEGER NOT NULL, r2_key TEXT NOT NULL, -- Review content in R2 model TEXT NOT NULL, created_at INTEGER NOT NULL ); -- Review items (individual issues) CREATE TABLE review_items ( id TEXT PRIMARY KEY, review_id TEXT NOT NULL REFERENCES reviews(id), category TEXT NOT NULL, severity TEXT NOT NULL, location_start INTEGER, location_end INTEGER, description TEXT NOT NULL, suggestion TEXT, status TEXT DEFAULT 'pending' ); -- Revisions CREATE TABLE revisions ( id TEXT PRIMARY KEY, document_id TEXT NOT NULL REFERENCES documents(id), revision_number INTEGER NOT NULL, parent_review_id TEXT REFERENCES reviews(id), r2_key TEXT NOT NULL, -- Revised content in R2 changes_r2_key TEXT, -- Change summary in R2 created_at INTEGER NOT NULL );
Files to study:
src/
├── main.tsx # React entry point
├── App.tsx # Router setup, auth context
├── index.css # Tailwind base styles
├── contexts/
│ └── AuthContext.tsx # Auth state management
├── hooks/
│ └── (various) # Reusable hooks pattern
├── lib/
│ └── utils.ts # cn() utility for Tailwind
└── components/
└── ui/ # shadcn/ui components
What to adapt:
- Auth context and hooks
- Tailwind configuration
- shadcn/ui component setup
- Router structure
Additional dependencies needed:
{
"@monaco-editor/react": "^4.6.0"
}Files to copy directly:
biome.json- Linting/formatting configtsconfig.jsonandtsconfig.node.jsonpostcss.config.jstailwind.config.js(adapt colors for Draftwell brand)vite.config.ts.gitignore
Files to study and adapt:
scripts/
├── utils.py # Shared utilities (ESSENTIAL)
├── section_utils.py # Section-based processing (ESSENTIAL)
├── critical-review.py # Review generation
├── generate-revision.py # Revision generation with tracking
└── summarize.py # Document summarization (optional)
Functions to port to TypeScript:
-
estimate_tokens(text)- Rough token count for chunkingfunction estimateTokens(text: string): number { return Math.ceil(text.length / 4); }
-
run_claude(prompt, model)- Call Claude API- Replace with direct Anthropic API calls in Worker
- Use raw fetch for Workers compatibility
-
detect_format(path)- Detect markdown vs LaTeX- Keep for supporting both formats
Data structures to port:
interface Section {
heading: string;
level: number; // 1 = #, 2 = ##, etc.
content: string;
startLine: number;
tokens: number;
}
interface Chunk {
sections: Section[];
chunkId: number;
content: string; // Computed: sections joined
tokens: number; // Computed: sum of section tokens
}
interface DocumentStructure {
format: 'markdown' | 'latex';
sections: Section[];
frontmatter: string;
toc: string; // Generated table of contents
overview: string; // AI-generated overview
}Functions to port:
parse_document(content, format)- Parse into sectionschunk_sections(sections, target_tokens)- Group by token budgetgenerate_overview(structure)- Create document overview for contextbuild_chunk_context(chunk, structure)- Context window for chunk processing
From critical-review.py - The review prompt structure:
- Overall Assessment
- Strengths (3-5 numbered)
- Weaknesses / Open Questions (3-5 numbered)
- Risk Assessment (table format)
- Comparison to Alternatives
- Where This Is Actually "New"
- Recommendations for Strengthening
- Bottom Line
From generate-revision.py - The revision prompt guidelines:
- Address actionable criticisms
- Preserve structure
- Maintain voice
- Minimal changes
- Be transparent about what couldn't be addressed
Output format for revisions:
## Change Summary
### Addressed
- [List each criticism addressed and how]
### Partially Addressed
- [Criticisms that could only be partially addressed, with explanation]
### Not Addressed
- [Items that couldn't be addressed, with reasoning]
---
[REVISED DOCUMENT HERE]This doesn't exist in ml-audio-codecs yet - design from scratch:
interface Styleguide {
id: string;
name: string;
voice: {
perspective: 'first-person' | 'second-person' | 'third-person';
tone: string;
audience: string;
};
antiTropes: {
bannedPhrases: string[];
bannedPatterns: Array<{
pattern: string; // Regex
replacementHint: string;
}>;
structuralRules: string[];
};
domainTerms: {
preferred: Record<string, string[]>;
};
formatting: {
maxSentenceLength?: number;
maxParagraphLength?: number;
headingStyle?: 'sentence-case' | 'title-case';
};
}Default banned phrases:
- "dive into", "delve into"
- "it's important to note", "it's worth noting"
- "at the end of the day"
- "first and foremost"
- "in conclusion"
- "leverage" (when "use" works)
- "utilize" (when "use" works)
- "robust and scalable"
- "seamlessly"
- "cutting-edge", "state-of-the-art"
- "game-changer"
- "harness the power"
-
Copy build tooling from makefour:
package.json(strip game-specific deps)biome.json,tsconfig.json, etc.vite.config.ts
-
Set up Cloudflare:
- Create
wrangler.tomlwith D1, R2, KV - Create initial
schema.sql - Set up
functions/_middleware.ts
- Create
-
Copy auth system:
functions/lib/auth.ts,crypto.ts,rateLimit.tsfunctions/api/auth/*src/contexts/AuthContext.tsx
-
Set up frontend:
- Copy Tailwind config, shadcn setup
- Create basic layout components
- Implement auth pages (login, register)
-
Add Monaco editor:
- Install
@monaco-editor/react - Create document editor component
- Add markdown syntax highlighting
- Install
-
Basic document CRUD:
- Create project/document API endpoints
- R2 storage for document content
- Document list and selection UI
-
Port Python logic to TypeScript:
section_utils.py→functions/lib/pipeline.ts- Token estimation, chunking, parsing
-
Create AI worker:
functions/api/ai/review.ts- Generate reviewfunctions/api/ai/revise.ts- Generate revisionfunctions/api/ai/refine.ts- Refine partial items
-
Review tracking UI:
- Review items panel
- Status tracking (pending/addressed/partial/rejected)
- Diff view for revisions
-
Styleguide system:
- Default styleguide with anti-tropes
- Pre/post validation of content
- LLM-ness scoring
-
PDF export:
- Evaluate Typst WASM vs external service
- Implement export endpoint
-
Preview pane:
- Live markdown rendering
- Optional PDF preview
draftwell/
├── README.md
├── BOOTSTRAP.md
├── package.json
├── wrangler.toml
├── schema.sql
├── biome.json
├── tsconfig.json
├── vite.config.ts
├── tailwind.config.js
├── index.html
├── .gitignore
├── functions/
│ ├── _middleware.ts
│ ├── lib/
│ │ ├── auth.ts
│ │ ├── crypto.ts
│ │ ├── rateLimit.ts
│ │ ├── storage.ts
│ │ ├── pipeline.ts
│ │ └── styleguide.ts
│ └── api/
│ ├── auth/
│ ├── projects/
│ ├── documents/
│ ├── reviews/
│ └── ai/
│ ├── review.ts
│ ├── revise.ts
│ └── refine.ts
├── src/
│ ├── main.tsx
│ ├── App.tsx
│ ├── index.css
│ ├── contexts/
│ │ └── AuthContext.tsx
│ ├── components/
│ │ ├── ui/
│ │ ├── Editor.tsx
│ │ ├── Preview.tsx
│ │ ├── ReviewPanel.tsx
│ │ └── DocumentList.tsx
│ └── pages/
│ ├── Home.tsx
│ ├── Login.tsx
│ ├── Register.tsx
│ ├── Projects.tsx
│ └── Editor.tsx
└── packages/
└── styleguide/
├── index.ts
├── defaults.ts
└── validator.ts
cd ../draftwell
# Initialize
pnpm init
# Core dependencies
pnpm add react react-dom react-router-dom @monaco-editor/react zod
pnpm add -D typescript vite @vitejs/plugin-react wrangler
pnpm add -D @cloudflare/workers-types @types/react @types/react-dom
pnpm add -D tailwindcss postcss autoprefixer @biomejs/biome
pnpm add -D drizzle-orm drizzle-kit
# Tailwind
pnpm dlx tailwindcss init -p
# Cloudflare setup
pnpm wrangler login
pnpm wrangler d1 create draftwell-db
pnpm wrangler r2 bucket create draftwell-documents
pnpm wrangler kv namespace create RATE_LIMIT-
Anthropic API: Use raw fetch for Workers compatibility (not the SDK)
-
PDF generation: Research Typst WASM maturity; fallback to external service if needed
-
Real-time preview: Client-side with
react-markdown(simpler than server-side) -
Figure/image blocks: Parse and validate syntax only; defer generation to future
-
Versioning: Track in D1 for queryability; store content in R2