119 Commits

Author SHA1 Message Date
kennethreitz f4730575d5 Use responder 3.6.1 built-in GZip instead of manual middleware
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 17:56:44 -04:00
kennethreitz 8267a8e646 Performance: add GZip compression, externalize CSS, bump cache, reduce workers
- Add Starlette GZipMiddleware for response compression (~60% smaller HTML)
- Extract 290 lines of inline CSS to /static/site.css (browser-cacheable)
- Bump HTML Cache-Control from 5min to 1hr
- Reduce Granian workers from 4 to 2 (matches shared-cpu-2x)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 17:43:17 -04:00
kennethreitz 33ea221a12 Add GitHub corner link to source files
Octocat banner in the upper right links to the .md source file for each
page. Directory indexes link to index.md, regular pages to their .md,
and the homepage falls back to the repo root.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:41:30 -04:00
kennethreitz d44bdeb36c Add oEmbed proxy route to Responder engine (production server)
The Flask blueprints aren't used in production — engine.py with
Responder is what Fly actually runs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 10:01:18 -04:00
kennethreitz 8f19cd63c0 Only include /api routes in OpenAPI schema
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 05:33:47 -04:00
kennethreitz 9b5e430b9c Add response definitions and query params to OpenAPI schema
Swagger UI Execute needs responses defined to display results.
Auto-detect search query params for /api/search routes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 05:32:49 -04:00
kennethreitz 51238dcddb Switch API docs to Swagger UI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 05:31:36 -04:00
kennethreitz 9d98ca4be6 Auto-generate OpenAPI schema from registered routes
Schema at /api/schema now introspects api.router.routes for paths
and docstrings instead of maintaining a static dict. Skips catch-all
and internal routes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 05:30:34 -04:00
kennethreitz cde3097b02 Switch API docs to RapiDoc — dark theme, focused layout
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 05:29:36 -04:00
kennethreitz a80e0c81a8 Redoc API docs with separate schema endpoint
Schema served as JSON at /api/schema, docs rendered with Redoc at /api.
No more inline YAML — clean separation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 05:29:20 -04:00
kennethreitz eb8bdc76d7 Self-hosted API docs at /api with Stoplight Elements
Inline OpenAPI spec avoids catch-all route conflict. Elements UI
with sidebar layout, no external schema fetch needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 05:27:16 -04:00
kennethreitz 69554471d3 Switch to Elements theme, serve docs at /api
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 05:25:28 -04:00
kennethreitz 29b290cb4c Move OpenAPI schema and docs under /api/ prefix
Avoids catch-all route intercepting /schema.yml.
Swagger UI at /api/docs, schema at /api/schema.yml.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 05:24:49 -04:00
kennethreitz 11dd894555 Add Swagger UI at /api via responder's built-in OpenAPI support
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 05:23:19 -04:00
kennethreitz 02930ccff6 Fix icon API route — use path parameter to capture slashes
/api/icon/{article_path} didn't match paths with slashes like
essays/2026-03-25-foo. Changed to {article_path:path}.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 20:52:07 -04:00
kennethreitz bda48b9c25 Bump rate limit to 600/min for load testing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 03:58:20 -04:00
kennethreitz 8f1fc2a366 Add rate limiting — 120 requests per minute per IP
Uses responder's built-in RateLimiter. Returns 429 with Retry-After
header when exceeded. Adds X-RateLimit-Limit and X-RateLimit-Remaining
headers to all responses.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 03:36:47 -04:00
kennethreitz e15b83e316 Remove unused find_adjacent_posts, add markdown render cache
find_adjacent_posts result was never used in template (like
find_related_posts before it). Added _cached_render() to cache
parsed markdown in memory — content only changes on deploy so
there's no reason to re-parse on every request.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 03:28:38 -04:00
kennethreitz f8d807fe9e Remove unused find_related_posts — 5.6x essay speedup
find_related_posts was doing TF-IDF comparison against all 250+ essays
on every request (1 second each) but the result was never rendered in
the template. Essays now serve at 105 req/s instead of 19.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 03:24:50 -04:00
kennethreitz 93f6a4be29 Sort theme groups alphabetically instead of by size
More stable ordering — won't shuffle when new essays are tagged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 21:29:56 -04:00
kennethreitz 2b2553c9d1 Restore theme badges on essay pages
The catch-all route wasn't passing article_themes to the post template.
Now looks up detected themes from the themes cache for each essay.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 21:26:25 -04:00
kennethreitz 9d297988e4 Search overhaul, AI index files, Lumina poetry index cleanup
Search:
- Build search index at startup instead of scanning 727 files per query
- Add /api/search/autocomplete for whole-site title matching
- Autocomplete now server-side, covers all content not just essays
- Remove client-side /api/blog preload from search page

AI section:
- Create 5 missing index.md files for navigational orphan directories
- Update "277 file" count to actual 352 across all references
- Tone down Lumina poetry index to match actual content quality

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 18:19:50 -04:00
kennethreitz cc1c585c57 Security, performance, and quality improvements across the site
Security:
- Add path traversal protection to serve_data_file and og_image routes
- Bound OG image cache to 256 entries to prevent memory growth

Performance:
- Pre-build legacy URL lookup tables at startup instead of rglob on every 404
- Extract _generate_pdf helper, eliminating duplicate PDF code

Templates:
- Add dark mode support to graph.html and error.html

Content:
- Remove third-person sidenotes from yoga-meditation.md, great-music.md,
  and idea_amplification essay
- Fix sidenote formatting in yoga-meditation.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 17:45:56 -04:00
kennethreitz 4fd4e65c7e Warm up homepage — dynamic posts, cleaner layout, muted accents
- Recent writing now pulls 5 latest posts dynamically with icons
- Collapsed theme/beyond sections into flowing Threads paragraph
- Added .muted class for subtle text styling with dark mode support
- Removed redundant footer nav links
- Simplified subtitle styling

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 17:39:26 -04:00
kennethreitz 9442a4275b Use folder icons for index.md results in search
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 17:04:01 -04:00
kennethreitz 8181bba75d Add unique icons to search results
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 17:03:14 -04:00
kennethreitz ba85249cbb Expand search to cover entire site, not just essays
- Search endpoint now scans all markdown files in data/ directory
- Results show section labels (Essays, Software, Themes, etc.) instead
  of hardcoded "Essay" type
- Updated placeholder text to reflect whole-site search

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 17:02:19 -04:00
kennethreitz 1ce6b8712a Add Themes and Search to top nav, Themes as dropdown with icons
- Themes dropdown mirrors Browse structure with tree-item icons
- Populated from data/themes/ directory via /api/themes endpoint
- Search link added between Archive and Themes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 16:53:58 -04:00
kennethreitz 9908c6e184 Suppress static asset access logs and fontTools.subset noise
Keep logs focused on meaningful requests — static assets (.js, .css,
.ico, .png, .woff2) and fontTools subset chatter are filtered out.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 16:45:07 -04:00
kennethreitz 20c2ea2f7b Add structured logging, legacy URL redirects, bot detection, and 404 page
- Enable responder 3.6 structured logging with request-scoped context
- Replace print() calls with api.log in cache warming
- Add logging across key routes (content serving, PDFs, search, redirects)
- Add legacy URL resolver for old date-path patterns and bare slugs (301 redirects)
- Add bot/scraper detection with logging on robots.txt and content routes
- Fix 404 page template variable mismatch and add helpful navigation links
- Bump responder dependency to >=3.6.0

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 16:38:02 -04:00
kennethreitz 0bf0e5d823 Use Responder startup event for cache warming
Warms all caches (blog, sidenotes, outlines, quotes, connections,
terms, themes) in background thread on startup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 14:40:07 -04:00
kennethreitz ffdfbfada3 Fix .md and .pdf routes, add pdf_available to template context
Handle .md and .pdf extensions inside catch-all since path:path
is greedy. Add WeasyPrint availability check for PDF button.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 14:36:19 -04:00
kennethreitz efced60c35 Serve raw files (images, etc.) from data directory in catch-all
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 14:20:35 -04:00
kennethreitz dd751105ec Fix data file serving for nested paths (images in galleries)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 14:18:58 -04:00
kennethreitz 029083d526 Fix static file serving — add explicit route before catch-all
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 14:10:35 -04:00
kennethreitz 5cd48abb90 Port site to Responder (#8)
* Initial Responder port — core content serving working

Homepage, markdown pages, directory listings, image galleries
all rendering. Flask template compatibility via RequestWrapper
and FakeConfig shims.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Complete Responder port — all routes working

Ported all routes from Flask blueprints: archive, search, OG images,
RSS, sitemap, robots.txt, API endpoints, directory browser.
All 25+ routes returning 200.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Update Dockerfile for Responder, warm caches on import

CMD now runs engine_responder:api via uvicorn.
Cache warming happens on module import for production.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Rename engine_responder.py to engine.py

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Update colophon for Responder

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix essay pages, OG images, and PDF export

- Fix find_related_posts and find_adjacent_posts call signatures
- Fix OG image route to use path:path for nested paths
- Add PDF export route with WeasyPrint
- All test plan items passing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 14:03:05 -04:00
kennethreitz f50dad4574 Switch to uvicorn, fix breadcrumbs for all content pages
- Replace gunicorn/gevent with uvicorn for ASGI support
- Add asgiref to wrap Flask WSGI app for uvicorn compatibility
- Enable auto-reload in docker-compose for development
- Add current_path to all content render_template calls
- Simplify breadcrumb template to exclude current page
- Only show breadcrumbs for nested paths (> 1 segment)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 16:58:17 -05:00
kennethreitz 60f1046204 Refactor search functionality and enhance caching mechanisms
- Removed the engine_new.py file as part of restructuring.
- Implemented actual search functionality in api.py, allowing for searching through blog posts with relevance scoring and snippet extraction.
- Enhanced caching in cache.py with a clear_cache function and improved content cleaning for search indexing.
- Deleted outdated homepage-revised.html template and ensured search.html template displays search results with additional metadata such as date and matches found.
2025-09-26 13:05:29 -04:00
kennethreitz c677b8fc98 all working / black 2025-09-26 12:34:57 -04:00
kennethreitz a353ccfaa7 Add folder icon support for directory links in icon API
- Detect directory paths (ending with / or pointing to directories)
- Use generate_folder_icon() for directories instead of regular article icons
- Read index.md files for directory titles when available
- Fallback to directory name for folder icon generation
- Fixes AI personalities link and other directory links to show proper folder icons

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-18 15:06:05 -04:00
kennethreitz bd62ba8550 Enhance icon system for themes and improve positioning
- Add themes directory to content cache for proper icon generation
- Remove colored dots from themes/index.md to enable icon display
- Fix JavaScript to handle links wrapped in strong tags
- Improve icon positioning with refined margins and alignment
- Prevent icons from loading on index/archive pages
- Fix navigation link to point to /themes instead of /themes/
- Optimize icon spacing and vertical alignment across devices

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-18 14:45:14 -04:00
kennethreitz 5f126491f9 Fix article link icons and improve icon generation system
- Fix data URL display issue by using inline SVG instead of img src
- Add LRU cache to icon API for better performance
- Expand icon coverage to all internal links (not just essays)
- Add software, poetry, and talks directories to content cache
- Implement fallback logic to read files directly when not in blog cache
- Fix Requests icon to use full title "Requests: HTTP for Humans"
- Improve icon positioning with negative margins and vertical alignment
- Add graceful fallback icons for missing content

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-18 14:18:00 -04:00
kennethreitz e4fb17097a Fix archive excerpts - remove all markdown images and improve filtering
- Enhanced simple_extract_excerpt() function to filter markdown images
- Added support for linked images [![](url)](url)
- Improved line-by-line filtering to find meaningful content
- Reduced excerpt length to 150 characters for better display
- Removed prebuild cache system to simplify architecture
- Fixed markdown filtering in all excerpt generation functions
2025-09-17 10:32:00 -04:00
kennethreitz 77e5ef9623 Fix major performance bottleneck in directory listings
- Add cached markdown title extraction with @lru_cache(maxsize=1000)
- Replace expensive render_markdown_file() calls with fast regex title extraction
- Only read first 1000 chars instead of full file content for title extraction
- Essays directory and other large directories now load significantly faster
- First load: fast title extraction, subsequent loads: instant cache lookup

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-17 10:07:03 -04:00
kennethreitz 6491c26ac1 Add memoization to SVG icon generation for significant performance improvement
- Add @lru_cache(maxsize=1000) to generate_unique_svg_icon() in svg_icon_generator.py
- Add @lru_cache(maxsize=500) to generate_folder_icon() in engine.py
- Import functools.lru_cache in both files
- Directory pages with many items (like /essays) now load much faster on repeat visits
- Icons generated once per unique title, then served from memory cache

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-17 10:00:57 -04:00
kennethreitz 7f51a2a028 Add support for .bak files in directory structure filtering 2025-09-17 09:25:29 -04:00
kennethreitz 3640827e5b Add folder icon generation for themes and update navigation links 2025-09-17 09:15:19 -04:00
kennethreitz 37f580a345 Add performance optimizations: lazy loading and caching
- Implement lazy loading for images using IntersectionObserver
- Add HTTP caching headers for static assets (images: 7 days, others: 1 hour)
- Preload critical CSS resources for faster initial page load

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-17 08:37:44 -04:00
kennethreitz 2cce051bc8 Add reading progress indicator and enhance search with result highlighting
- Add reading progress bar for longer essays with smooth animation
- Implement search result snippets with highlighted query terms
- Tighten directory listing styles for better compactness
- Add back-to-parent navigation links in directory views

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-17 08:36:43 -04:00
kennethreitz 3287eed5ac Add parent directory navigation with icon in directory view 2025-09-17 08:31:25 -04:00