Conversation
…evelopment journey Created complete blog series documenting the 12-day AI-orchestrated development of Catwalk Live: Part 1: Genesis - Building a Vercel for MCP Servers - Project vision and AI orchestration strategy - Initial tech stack decisions and architecture - First commit and setup Part 2: Foundation - Architecture & Encryption - Core three-service architecture (Analysis, Credential, Deployment) - Database schema design and Fernet encryption - Dynamic form generation and Aurora UI Part 3: The AI Analysis Engine - Prompt engineering for GitHub repo analysis - OpenRouter + Claude Haiku integration with web search - Caching strategy and the 200k token overflow fix Part 4: First Deployment - Fly.io Adventures - Dockerization challenges and PostgreSQL driver saga (asyncpg → psycopg3) - Shell script CRLF issues and missing dependencies - Database cluster failures and recovery procedures Part 5: Implementing Streamable HTTP & MCP Machines - MCP 2025-06-18 Streamable HTTP spec implementation - Fly Machines API integration and mcp-proxy architecture - Private networking challenges and session management Part 6: Building the Registry & Validation Layer - Security wake-up call: command injection vulnerability - Package validation against npm/PyPI registries - Credential validation and Glama registry integration Part 7: The Authentication Nightmare - JWT authentication implementation with NextAuth.js - The 401 error debugging saga (AUTH_SECRET vs AUTH_SYNC_SECRET) - User sync issues and final resolution Part 8: Security Hardening & Production Ready - PR #12: 51 comprehensive tests, 89% coverage - PR #13: Security hardening, access token rotation - Frontend deployment to Vercel and production polish Part 9: Reflections - AI-Orchestrated Development - Lessons learned from AI orchestration - What worked vs what didn't - The skill shift from coding to validating systems - Future of AI-assisted development Series includes: - README.md with series overview, reading paths, and topic guides - ~4,500 lines of technical narrative across 9 posts - Real commit references, code examples, and lessons learned - Honest discussion of AI successes and failures - Reproducible methodology for AI-orchestrated development This series serves as both project documentation and a case study in modern AI-assisted software development.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughThis PR adds a comprehensive 9-part blog series documenting the "Catwalk Live Development Journey," covering system architecture, encryption/credentials, AI analysis engine, Fly.io deployment, HTTP/MCP protocol implementation, registry validation, authentication, security hardening, and AI orchestration lessons learned, along with a blog README guide. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello @zenchantlive, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request establishes a foundational system specification framework by adding a comprehensive 9-part blog series. This series meticulously documents the 12-day AI-orchestrated development of 'Catwalk Live,' a platform designed to simplify the deployment of Model Context Protocol (MCP) servers. It provides an in-depth look at the project's journey from initial concept to production readiness, highlighting the strategic use of AI, architectural decisions, and critical lessons learned in building a complex full-stack application. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
PR Compliance Guide 🔍Below is a summary of compliance checks for this PR:
Compliance status legend🟢 - Fully Compliant🟡 - Partial Compliant 🔴 - Not Compliant ⚪ - Requires Further Human Verification 🏷️ - Compliance label |
||||||||||||
PR Code Suggestions ✨Explore these optional code suggestions:
|
||||||||||||||||||||
There was a problem hiding this comment.
Code Review
This pull request adds an extensive and well-written 9-part blog series documenting the AI-orchestrated development of the Catwalk Live platform. The series is a valuable case study. My review focuses on improving the technical accuracy and educational value of the content. I've provided feedback on a few security anti-patterns shown in code snippets, technical inaccuracies in the documentation, and minor formatting issues to ensure the blog posts are as clear and correct as possible for readers.
| if deployment.access_token != access_token: | ||
| raise HTTPException(401, "Invalid access token") |
There was a problem hiding this comment.
The code snippet for access token validation uses a direct string comparison (!=), which is vulnerable to timing attacks. For security-sensitive values like access tokens, a constant-time comparison function should always be used to prevent attackers from inferring the token's value by measuring response times. The blog post should be updated to use secrets.compare_digest to demonstrate secure coding practices.
| if not x_access_token or x_access_token != deployment.access_token: | ||
| raise HTTPException(401, "Invalid or missing access token") |
There was a problem hiding this comment.
In a blog post dedicated to security hardening, this code snippet for access token validation uses a direct string comparison (!=), which is vulnerable to timing attacks. It's critical to demonstrate best practices in a security context. A constant-time comparison function, like secrets.compare_digest in Python, must be used here to prevent attackers from inferring the token's value by measuring response time differences.
| **The Zod schema generation** (this was AI-generated and it's beautiful): | ||
|
|
||
| ```typescript | ||
| function generateZodSchema(envVars: EnvVar[]): z.ZodObject<any> { |
There was a problem hiding this comment.
The blog post praises the AI-generated generateZodSchema function, but the function signature z.ZodObject<any> sacrifices type safety. This contradicts the project's goal of being "type-safe throughout" and is a missed opportunity for a teaching moment. Using a more specific type like z.ZodObject<z.ZodRawShape> or letting TypeScript infer the return type would be a better practice to showcase.
| function generateZodSchema(envVars: EnvVar[]): z.ZodObject<any> { | |
| function generateZodSchema(envVars: EnvVar[]): z.ZodObject<z.ZodRawShape> { |
|
|
||
| # Start mcp-proxy with dynamic package | ||
| # MCP_PACKAGE env var set by deployment | ||
| CMD npx -y $MCP_PACKAGE | mcp-proxy http --port 8080 |
There was a problem hiding this comment.
The Docker CMD shown here uses a shell pipe (|), which makes the shell (e.g., sh) PID 1, not mcp-proxy. This can lead to improper signal handling and prevent graceful shutdowns. The actual deploy/Dockerfile uses a more robust pattern where mcp-proxy is the main process. The blog post would be more accurate and educational if it reflected this superior implementation.
| CMD npx -y $MCP_PACKAGE | mcp-proxy http --port 8080 | |
| CMD mcp-proxy http --port 8080 -- npx -y $MCP_PACKAGE |
| from functools import lru_cache | ||
|
|
||
| class RegistryService: | ||
| def __init__(self): | ||
| self.client = httpx.AsyncClient(timeout=10.0) | ||
| self._cache = {} # In-memory cache | ||
| self._cache_ttl = 300 # 5 minutes | ||
|
|
||
| async def validate_npm_package(self, package: str) -> bool: | ||
| # Check cache first | ||
| if package in self._cache: | ||
| cached_at, result = self._cache[package] | ||
| if time.time() - cached_at < self._cache_ttl: | ||
| return result | ||
|
|
||
| # Validate | ||
| result = await self._validate_npm_package_uncached(package) | ||
|
|
||
| # Cache result | ||
| self._cache[package] = (time.time(), result) | ||
| return result |
There was a problem hiding this comment.
This code snippet for caching has a couple of issues that would prevent it from running:
- It imports
lru_cachefromfunctoolsbut never uses it. - It uses
time.time()but thetimemodule is not imported, which would cause aNameError.
To make the example correct and clear for readers, the unused import should be removed and import time should be added.
| | AI Model | Recommendation | Rationale | | ||
| |----------|----------------|-----------| | ||
| | GPT-4 | asyncpg | "Modern async driver, well-maintained" | | ||
| | Claude | psycopg3 | "Better SSL parameter support" | | ||
| | Gemini | psycopg3 | "More compatible with connection strings" | |
There was a problem hiding this comment.
The markdown for this table is slightly malformed. The header and separator lines are missing the trailing |, which can cause rendering issues in some markdown parsers.
| | AI Model | Recommendation | Rationale | | |
| |----------|----------------|-----------| | |
| | GPT-4 | asyncpg | "Modern async driver, well-maintained" | | |
| | Claude | psycopg3 | "Better SSL parameter support" | | |
| | Gemini | psycopg3 | "More compatible with connection strings" | | |
| | AI Model | Recommendation | Rationale | | |
| |----------|----------------|-----------| | |
| | GPT-4 | asyncpg | "Modern async driver, well-maintained" | | |
| | Claude | psycopg3 | "Better SSL parameter support" | | |
| | Gemini | psycopg3 | "More compatible with connection strings" | |
There was a problem hiding this comment.
Actionable comments posted: 10
🧹 Nitpick comments (4)
blog/03-ai-analysis-engine.md (3)
14-23: Minor: Consider varying sentence structure for stylistic polish.The opening uses an intentional "We have X..." repetition for rhetorical effect, which works well for emphasis. If you prefer to vary it, options include combining some statements or restructuring the pivot.
39-42: Add language identifier to fenced code block.Line 39 (and also lines 52 and 166) are missing language specifiers. Add
text,json, or appropriate language after the opening```.Example fix for line 39
-``` +```text Analyze this GitHub repository and tell me what MCP server it contains:
158-158: Capitalize "Markdown" as a proper noun.Proposed fix
-**Why "ONLY valid JSON"**: Claude loves to wrap JSON in markdown code blocks. This instruction reduces that. +**Why "ONLY valid JSON"**: Claude loves to wrap JSON in Markdown code blocks. This instruction reduces that.blog/02-foundation-architecture-encryption.md (1)
144-144: Optional: Strengthen the verb choice."Storing it makes API responses faster" is clear, but a stronger verb (e.g., "improves," "optimizes," "accelerates") could add punch to the explanation.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
blog/01-genesis-building-vercel-for-mcp.mdblog/02-foundation-architecture-encryption.mdblog/03-ai-analysis-engine.mdblog/04-first-deployment-flyio.mdblog/05-streamable-http-mcp-machines.mdblog/06-registry-validation.mdblog/07-authentication-crisis.mdblog/08-security-hardening-production.mdblog/09-reflections-ai-orchestration.mdblog/README.md
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-12-23T23:36:13.808Z
Learnt from: CR
Repo: zenchantlive/catwalk PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-23T23:36:13.808Z
Learning: Use `fly deploy` for all backend changes to production and check logs with `fly logs --app <your-backend-app>`
Applied to files:
blog/04-first-deployment-flyio.md
📚 Learning: 2025-12-23T23:36:13.808Z
Learnt from: CR
Repo: zenchantlive/catwalk PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-23T23:36:13.808Z
Learning: Applies to backend/Dockerfile : Dockerfile: Avoid shell scripts and CRLF line ending issues. Use `release_command` in fly.toml for migrations; keep container CMD as uvicorn only
Applied to files:
blog/04-first-deployment-flyio.md
📚 Learning: 2025-12-23T23:36:13.808Z
Learnt from: CR
Repo: zenchantlive/catwalk PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-23T23:36:13.808Z
Learning: Applies to backend/app/api/deployments.py : After storing a deployment in the database in `app/api/deployments.py`, call `fly_deployment_service.create_machine()` to spin up the Fly.io container running the MCP server
Applied to files:
blog/04-first-deployment-flyio.mdblog/05-streamable-http-mcp-machines.md
📚 Learning: 2025-12-23T23:36:13.808Z
Learnt from: CR
Repo: zenchantlive/catwalk PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-23T23:36:13.808Z
Learning: Applies to backend/app/services/fly_deployment_service.py : When implementing Fly.io MCP server deployments, follow the pattern in `app/services/fly_deployment_service.py`: use Fly Machines API, inject environment variables from encrypted credentials, and return machine ID
Applied to files:
blog/04-first-deployment-flyio.mdblog/05-streamable-http-mcp-machines.md
📚 Learning: 2025-12-23T23:36:13.808Z
Learnt from: CR
Repo: zenchantlive/catwalk PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-23T23:36:13.808Z
Learning: Applies to frontend/.env.local : Authentication setup requires two secrets: AUTH_SECRET (JWT token signing) and AUTH_SYNC_SECRET (user sync endpoint security). Both must be set identically on frontend `.env.local` and backend Fly.io secrets
Applied to files:
blog/07-authentication-crisis.md
🪛 LanguageTool
blog/04-first-deployment-flyio.md
[style] ~41-~41: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...an fly deploy. It built. It deployed. It... crashed immediately.
2025-12...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
---
[grammar] ~139-~139: Use a hyphen to join words.
Context: ...Run Alembic migrations on startup.
AI generated:
```dockerfile
# ❌ AI's ap...
(QB_NEW_EN_HYPHEN)
</details>
<details>
<summary>blog/05-streamable-http-mcp-machines.md</summary>
[style] ~14-~14: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...d backend. We can analyze GitHub repos. We can encrypt credentials. But we can't a...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
</details>
<details>
<summary>blog/09-reflections-ai-orchestration.md</summary>
[style] ~49-~49: Consider using a different adjective in this context to strengthen your wording.
Context: ...ployment platform for MCP servers"
**Good approach**:
Build a platform that...
(GOOD_ALTERNATIVE)
[style] ~193-~193: Consider a different adjective to strengthen your wording.
Context: ...edge in training data.
Solution: Deep knowledge of infrastructure platforms s...
(DEEP_PROFOUND)
[grammar] ~199-~199: Use a hyphen to join words.
Context: ...ons
Example: Authentication
AI generated:
async signIn(...
(QB_NEW_EN_HYPHEN)
---
[style] ~420-~420: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ent failures in distributed systems?
- Can AI make architectural trade-offs (cost ...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
---
[style] ~422-~422: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...xity)?
**My intuition**: AI will get very good at **implementation** but humans will r...
(EN_WEAK_ADJECTIVE)
</details>
<details>
<summary>blog/01-genesis-building-vercel-for-mcp.md</summary>
[style] ~53-~53: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...er. I can't write FastAPI from scratch. I don't remember SQLAlchemy patterns off ...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
---
[style] ~53-~53: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...lchemy patterns off the top of my head. I've never built a Fly.io deployment pipe...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
</details>
<details>
<summary>blog/07-authentication-crisis.md</summary>
[style] ~23-~23: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...
No user accounts. No authentication. No authorization. Just... open endpoints.
...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
</details>
<details>
<summary>blog/02-foundation-architecture-encryption.md</summary>
[style] ~144-~144: Consider using a different verb to strengthen your wording.
Context: ...: Could compute from ID, but storing it makes API responses faster.
5. **`access_token` for auth**: Eac...
(MAKE_XXX_FASTER)
</details>
<details>
<summary>blog/03-ai-analysis-engine.md</summary>
[style] ~14-~14: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...We have a platform. We have a database. We have encryption. But there's a fundamen...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
---
[uncategorized] ~158-~158: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...d JSON"**: Claude loves to wrap JSON in markdown code blocks. This instruction reduces t...
(MARKDOWN_NNP)
---
[uncategorized] ~394-~394: Do not mix variants of the same word (‘analyse’ and ‘analyze’) within a single text.
Context: ...g**: ~$0.007 per cached request. At 100 analyses/day: $0.70/day saved.
## What I Lear...
(EN_WORD_COHERENCY)
</details>
<details>
<summary>blog/README.md</summary>
[uncategorized] ~82-~82: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...gy
### Part 8: [Security Hardening & Production Ready](08-security-hardening-production.md)
...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
---
[typographical] ~90-~90: Consider using an en dash here instead of a hyphen.
Context: ...ections-ai-orchestration.md)
**Dec 23, 2025 - Present** • *Lessons learned and the future*
...
(QB_NEW_EN_DASH_RULE_EN)
</details>
</details>
<details>
<summary>🪛 markdownlint-cli2 (0.18.1)</summary>
<details>
<summary>blog/04-first-deployment-flyio.md</summary>
43-43: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
72-72: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
78-78: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
83-83: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
98-98: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
157-157: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
193-193: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
<details>
<summary>blog/05-streamable-http-mcp-machines.md</summary>
48-48: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
527-527: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
<details>
<summary>blog/09-reflections-ai-orchestration.md</summary>
43-43: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
72-72: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
78-78: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
83-83: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
98-98: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
157-157: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
193-193: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
<details>
<summary>blog/06-registry-validation.md</summary>
114-114: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
198-198: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
447-447: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
<details>
<summary>blog/01-genesis-building-vercel-for-mcp.md</summary>
74-74: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
198-198: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
<details>
<summary>blog/08-security-hardening-production.md</summary>
417-417: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
609-609: Bare URL used
(MD034, no-bare-urls)
---
610-610: Bare URL used
(MD034, no-bare-urls)
</details>
<details>
<summary>blog/03-ai-analysis-engine.md</summary>
39-39: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
52-52: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
166-166: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
</details>
</details>
<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)</summary>
* GitHub Check: Greptile Review
</details>
<details>
<summary>🔇 Additional comments (3)</summary><blockquote>
<details>
<summary>blog/README.md (1)</summary><blockquote>
`1-176`: **Well-structured series index with comprehensive navigation.** The README effectively guides readers through the 9-part journey with clear reading paths and contextual summaries. All referenced blog posts exist and are properly linked.
</blockquote></details>
<details>
<summary>blog/03-ai-analysis-engine.md (1)</summary><blockquote>
`1-430`: **Excellent technical narrative with strong practical insights.**
This is a comprehensive, well-structured post that documents both the iterative learning process and the production solution. The narrative arc (naive prompt → web search integration → token overflow crisis → optimization) is authentic and instructive. Code examples are idiomatic, performance metrics are credible, and real failure modes are acknowledged. The post provides genuine value for readers trying to build similar AI-driven extraction pipelines.
Minor formatting suggestions above (code block language specifiers, Markdown capitalization), but content quality is high.
</blockquote></details>
<details>
<summary>blog/02-foundation-architecture-encryption.md (1)</summary><blockquote>
`1-369`: **Excellent foundation documentation with sound architectural and security decisions.**
This post clearly articulates the three-service architecture, justifies each design choice (Fernet for encryption, JSONB for flexible config, separate credentials table, PostgreSQL cache), and explains the security-by-design patterns well (encrypt before DB, decrypt in memory only, never log). The dynamic form generation example is particularly clever. Database schema is clean and includes appropriate constraints and indexes.
The candid "What I Learned" section—acknowledging that tests were skipped and vulnerabilities would be discovered—adds authenticity. Overall, this is high-quality technical documentation that serves both as narrative and as a useful architectural reference.
</blockquote></details>
</blockquote></details>
</details>
<!-- This is an auto-generated comment by CodeRabbit for review status -->| ``` | ||
| ┌─────────────────┐ | ||
| │ Claude Desktop │ (MCP Client) | ||
| │ (User) │ | ||
| └────────┬────────┘ | ||
| │ HTTPS (Streamable HTTP) | ||
| ↓ | ||
| ┌─────────────────┐ | ||
| │ Catwalk Live │ (Our Platform) | ||
| │ - Frontend │ Next.js 15, React 19 | ||
| │ - Backend API │ FastAPI, PostgreSQL | ||
| └────────┬────────┘ | ||
| │ Fly.io Machines API | ||
| ↓ | ||
| ┌─────────────────┐ | ||
| │ MCP Machine │ (Isolated Container) | ||
| │ - mcp-proxy │ Streamable HTTP adapter | ||
| │ - MCP Server │ User's server package | ||
| └─────────────────┘ | ||
| ``` |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Add language specifications to code blocks. Two fenced code blocks lack language identifiers (lines 74 and 198), which affects readability and syntax highlighting on rendered platforms.
🔎 Proposed fixes
Line 74, add language tag:
-```
+```text
┌─────────────────┐
Line 198, add language tag:
-```
+```text
catwalk/
├── backend/Also applies to: 198-205
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
74-74: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
In blog/01-genesis-building-vercel-for-mcp.md around lines 74 and 198-205, the
two fenced code blocks lack language identifiers; update each opening fence from
``` to ```text so the ASCII diagram and directory tree render with proper
plain-text syntax highlighting and preserve formatting.
| ``` | ||
| 2025-12-12T14:23:01Z [error] ModuleNotFoundError: No module named 'openai' |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Add language specifications to seven code blocks. Multiple error messages and configuration snippets lack language tags, affecting readability across the deployment narrative.
🔎 Proposed fixes
Line 43:
-```
+```plaintext
ModuleNotFoundError: No module named 'openai'
Line 72:
-```
+```plaintext
sqlalchemy.exc.ArgumentError:
Line 78:
-```
+```text
postgres://user:pass@db-name.internal
Line 83:
-```
+```text
postgresql+psycopg://user:pass@db-name.internal
Line 98:
-```
+```plaintext
asyncpg.exceptions.InvalidParameterValue:
Line 157:
-```
+```plaintext
/bin/sh: ./docker-entrypoint.sh: not found
Line 193:
-```
+```plaintext
psycopg.OperationalError:Also applies to: 72-75, 78-85, 98-102, 157-159, 193-197
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
43-43: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
In blog/04-first-deployment-flyio.md around lines 43-44 (and also apply to
ranges 72-75, 78-85, 98-102, 157-159, 193-197), several fenced code blocks lack
language tags which reduces readability and syntax highlighting; update each
opening triple-backtick to include the appropriate language/token (e.g.,
```plaintext, ```text) as suggested in the review for the seven blocks so the
error messages and config snippets render with proper highlighting and remain
consistent across the document.
| ``` | ||
| ┌──────────────────┐ | ||
| │ Claude Desktop │ User: "What are my TickTick tasks?" | ||
| └────────┬─────────┘ | ||
| │ POST /mcp | ||
| │ MCP-Protocol-Version: 2025-06-18 | ||
| │ MCP-Session-Id: <uuid> | ||
| │ {jsonrpc: "2.0", method: "tools/call", params: {...}} | ||
| ↓ | ||
| ┌─────────────────────────────────────┐ | ||
| │ Catwalk Backend (FastAPI) │ | ||
| │ https://backend.fly.dev/api/mcp/{id}│ | ||
| │ - Validates access token │ | ||
| │ - Retrieves deployment record │ | ||
| │ - Proxies to MCP machine │ | ||
| └────────┬────────────────────────────┘ | ||
| │ POST /mcp | ||
| │ (over Fly.io private network) | ||
| │ http://{machine_id}.vm.mcp-host.internal:8080/mcp | ||
| ↓ | ||
| ┌─────────────────────────────────────┐ | ||
| │ MCP Machine (Fly.io Container) │ | ||
| │ - mcp-proxy (HTTP ↔ stdio) │ | ||
| │ - npx @hong-hao/mcp-ticktick │ | ||
| │ - Env: TICKTICK_TOKEN=<encrypted> │ | ||
| └────────┬────────────────────────────┘ | ||
| │ stdio communication | ||
| │ JSON-RPC messages | ||
| ↓ | ||
| MCP Server executes tool | ||
| Returns result via stdout | ||
| ↓ | ||
| mcp-proxy converts to HTTP response | ||
| ↓ | ||
| Backend proxies response to Claude | ||
| ↓ | ||
| Claude synthesizes answer for user | ||
| ``` |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Add language specifications to code blocks. Two fenced code blocks lack language tags (lines 48 and 527).
🔎 Proposed fixes
Line 48:
-```
+```text
┌──────────────────┐
Line 527:
-```
+```bash
package: "; rm -rf /"Also applies to: 527-529
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
48-48: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
In blog/05-streamable-http-mcp-machines.md around lines 48 to 85 and 527 to 529,
two fenced code blocks are missing language specifiers; update the opening fence
at line 48 to use ```text for the ASCII diagram block, and update the opening
fence at lines 527-529 to use ```bash for the shell/package snippet so syntax
highlighting and content intent are explicit.
| ``` | ||
| package: "@attacker/malicious-script" | ||
| ``` | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Add language specifications to three code blocks. Incomplete code snippets and error messages lack language tags (lines 114, 198, and 447).
🔎 Proposed fixes
Line 114:
-```
+```text
package: "@attacker/malicious-script"
Line 198:
-```
+```text
package: "; rm -rf /"
Line 447:
-```
+```plaintext
ValidationError: regex pattern...Also applies to: 198-203, 447-450
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
114-114: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
In blog/06-registry-validation.md around lines 114-117, 198-203 and 447-450 the
fenced code blocks are missing language identifiers; update each opening
triple-backtick to include an appropriate language tag (e.g., use text or
plaintext for plain text/error snippets) so the blocks read like ```text or
```plaintext, ensuring the specified lines show the new tags and no other
content changes.
| ``` | ||
| POST /api/deployments | ||
| Authorization: Bearer <jwt> | ||
|
|
||
| Response: 401 Unauthorized | ||
| ``` |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Add language specifications to code blocks. Three fenced code blocks lack language identifiers (lines 61, 110, and 193).
🔎 Proposed fixes
Line 61:
-```
+```plaintext
2025-12-20T15:23:45Z [error] JWT verification failed
Line 110:
-```
+```plaintext
2025-12-20T16:05:12Z [error] User not found
Line 193:
-```
+```python
@router.post("/auth/sync-user")Also applies to: 110-114, 193-199
🤖 Prompt for AI Agents
In blog/07-authentication-crisis.md around lines 61-66, 110-114 and 193-199 the
fenced code blocks lack language identifiers; update the three fences to include
appropriate languages (e.g. ```plaintext for the log snippets at lines ~61 and
~110, and ```python for the route example at ~193) so syntax highlighting and
accessibility work correctly, ensuring you replace the opening ``` with the
language-tagged version and leave the block contents unchanged.
| ``` | ||
| Error: Cannot find module './vitest.config.mts' | ||
| ``` | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Add language specification to code block at line 417. The error output block lacks a language tag.
🔎 Proposed fix
-```
+```plaintext
Error: Cannot find module './vitest.config.mts'🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
417-417: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
In blog/08-security-hardening-production.md around lines 417 to 420, the code
block containing the error message lacks a language specifier; update the fenced
code block opening from ``` to ```plaintext so the block is explicitly marked as
plain text (i.e., change the opening fence only to include the language tag).
| - Frontend: https://catwalk.vercel.app | ||
| - Backend: https://catwalk-backend.fly.dev | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Wrap bare URLs in Markdown link syntax. Lines 609-610 contain bare URLs that should be formatted as proper Markdown links for consistency and platform compatibility.
🔎 Proposed fix
**Production URLs**:
-Frontend: https://catwalk.vercel.app
-Backend: https://catwalk-backend.fly.dev
+- Frontend: [https://catwalk.vercel.app](https://catwalk.vercel.app)
+- Backend: [https://catwalk-backend.fly.dev](https://catwalk-backend.fly.dev)🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
609-609: Bare URL used
(MD034, no-bare-urls)
610-610: Bare URL used
(MD034, no-bare-urls)
🤖 Prompt for AI Agents
In blog/08-security-hardening-production.md around lines 609 to 611, the two
production URLs are bare and need to be wrapped in Markdown link syntax; replace
the plain URLs with link format so each line reads like "Frontend:
[https://catwalk.vercel.app](https://catwalk.vercel.app)" and "Backend:
[https://catwalk-backend.fly.dev](https://catwalk-backend.fly.dev)" ensuring the
surrounding list formatting and punctuation remain consistent.
| ``` | ||
| Build a platform that: | ||
| - Accepts GitHub URLs for MCP servers | ||
| - Uses Claude API (via OpenRouter) with web search to analyze repos | ||
| - Extracts: package name (npm/PyPI), env vars, tools/resources/prompts | ||
| - Generates dynamic credential forms based on extracted requirements | ||
| - Encrypts credentials with Fernet symmetric encryption (256-bit key) | ||
| - Stores deployments in PostgreSQL with async SQLAlchemy | ||
| - Validates package names against npm/PyPI registries (prevent command injection) | ||
| - Deploys to Fly.io Machines API with isolated Firecracker VMs | ||
| - Implements MCP Streamable HTTP transport (2025-06-18 spec) | ||
| - Exposes stable HTTPS endpoints for Claude Desktop | ||
|
|
||
| Tech constraints: | ||
| - Frontend: Next.js 15 (App Router), React 19, TypeScript 5+ (no 'any' types) | ||
| - Backend: FastAPI, Python 3.12, psycopg3 (NOT asyncpg), Pydantic 2.0 | ||
| - All async (asyncio, async SQLAlchemy) | ||
| - Type-safe throughout | ||
| - Must pass ruff check with zero warnings | ||
|
|
||
| Success criteria: | ||
| - End-to-end MCP tool calling works | ||
| - Credentials never logged or exposed | ||
| - Package validation prevents command injection | ||
| - 90%+ test coverage | ||
| ``` | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Add language specifications to code blocks in the prompt refinement section. The detailed specification blocks (lines 50-76) lack proper language tags, making them harder to parse visually.
🔎 Proposed fix
Lines 50-76, add language tag:
-```
+```text
Build a platform that:
- Accepts GitHub URLs...
- Uses Claude API...🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
72-72: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
In blog/09-reflections-ai-orchestration.md around lines 50 to 76, the multi-line
specification block is missing a language tag which harms readability and
parsing; update the fenced code block opener to include a language tag such as
"text" or "markdown" (e.g., ```text) so the block is properly annotated and
renders/parses correctly in editors and markdown processors.
| ```python | ||
| env = {"MCP_PACKAGE": mcp_package} # User input, unsanitized! | ||
| ``` | ||
|
|
||
| Exploit: | ||
| ```python | ||
| mcp_package = "; rm -rf /" | ||
| # Executes: npx -y ; rm -rf / | ||
| ``` | ||
|
|
||
| **CodeRabbit flagged this** → I added package validation against registries. | ||
|
|
||
| **Human alone**: Might have missed this. | ||
| **AI alone**: Generated the vulnerability. | ||
| **AI + automated review**: Caught and fixed it. | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Add language specifications to code examples. Two code blocks in the failure modes section lack language tags (around lines 142-157).
🔎 Proposed fix
For the Python command injection example (line 142):
-```
+```python
env = {"MCP_PACKAGE": mcp_package}For the exploit example (line 148):
-```
+```python
mcp_package = "; rm -rf /"🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
157-157: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
blog/09-reflections-ai-orchestration.md lines 142-157: two fenced code blocks in
the failure modes section are missing language specifiers; add "python" after
each opening ``` so both examples are marked as Python (the env assignment block
and the exploit assignment block) to enable proper syntax highlighting and
consistency with surrounding examples.
| **Example: Fly.io private networking** | ||
|
|
||
| AI suggested: | ||
| ```python | ||
| machine_url = f"http://{machine_id}.fly.dev/mcp" | ||
| ``` | ||
|
|
||
| **Problem**: `.fly.dev` is public DNS. MCP machines don't have public IPs. | ||
|
|
||
| **Correct**: | ||
| ```python | ||
| machine_url = f"http://{machine_id}.vm.mcp-host.internal:8080/mcp" | ||
| ``` |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Add language specifications to code examples in infrastructure quirks section. Two code blocks (lines 177-189) lack language tags.
🔎 Proposed fix
For the incorrect approach (line 180):
-```
+```python
machine_url = f"http://{machine_id}.fly.dev/mcp"For the correct approach (line 187):
-```
+```python
machine_url = f"http://{machine_id}.vm.mcp-host.internal:8080/mcp"🤖 Prompt for AI Agents
In blog/09-reflections-ai-orchestration.md around lines 177 to 189, the two
fenced code blocks in the "Example: Fly.io private networking" snippet are
missing language specifiers; update both backticks to use ```python so the
blocks are highlighted as Python (one for the incorrect .fly.dev example and one
for the correct .vm.mcp-host.internal:8080 example).
User description
…evelopment journey
Created complete blog series documenting the 12-day AI-orchestrated development of Catwalk Live:
Part 1: Genesis - Building a Vercel for MCP Servers
Part 2: Foundation - Architecture & Encryption
Part 3: The AI Analysis Engine
Part 4: First Deployment - Fly.io Adventures
Part 5: Implementing Streamable HTTP & MCP Machines
Part 6: Building the Registry & Validation Layer
Part 7: The Authentication Nightmare
Part 8: Security Hardening & Production Ready
Part 9: Reflections - AI-Orchestrated Development
Series includes:
This series serves as both project documentation and a case study in modern AI-assisted software development.
PR Type
Documentation
Description
Complete 9-part blog series documenting a 12-day AI-orchestrated development journey for Catwalk Live, a Vercel-like platform for MCP server deployment
Comprehensive technical narrative covering project genesis, architecture design, AI analysis engine implementation, production deployment, security hardening, and authentication systems
Detailed posts on MCP Streamable HTTP protocol implementation, Fly.io Machines integration, package validation, and registry security
Meta-analysis of AI-orchestrated development methodology with lessons learned, reproducible patterns, and honest assessment of AI capabilities and limitations
~4,500 lines of technical documentation with real commit references, code examples, debugging narratives, and infrastructure troubleshooting procedures
Master README providing series overview, reading paths for different audiences, and links to complementary documentation
Diagram Walkthrough
File Walkthrough
8 files
05-streamable-http-mcp-machines.md
MCP Streamable HTTP Protocol Implementation and Fly MachinesDeploymentblog/05-streamable-http-mcp-machines.md
implementation (2025-06-18 spec)
Desktop through backend to Fly.io machines
negotiation and session management
containers with dynamic package installation
requirements, and end-to-end testing
07-authentication-crisis.md
JWT Authentication Implementation and Multi-System Debugging Narrativeblog/07-authentication-crisis.md
debugging process
systems
AUTH_SECRETvsAUTH_SYNC_SECRET) andsynchronization issues
cross-system authentication failures
09-reflections-ai-orchestration.md
AI-Orchestrated Development Methodology and Lessons Learnedblog/09-reflections-ai-orchestration.md
learned from 12-day development cycle
security, infrastructure, and debugging
engineering, and AI orchestration
including context files, multi-AI validation, and quality gates
predictions for AI-assisted development
04-first-deployment-flyio.md
Production Deployment on Fly.io with Infrastructure Troubleshootingblog/04-first-deployment-flyio.md
management, database driver selection, and shell script issues
parameter incompatibility
for database migrations
limitations
infrastructure on Fly.io
03-ai-analysis-engine.md
AI Analysis Engine with Prompt Engineering and Caching Strategyblog/03-ai-analysis-engine.md
search plugin
production-grade prompts with structured output
AI input scope
optimization
errors, and unexpected exceptions
02-foundation-architecture-encryption.md
Core Architecture and Encryption Foundation Documentationblog/02-foundation-architecture-encryption.md
with three-service pattern (Analysis, Credential, Deployment)
and analysis cache tables with security considerations
different MCP server configurations
TailwindCSS 4 implementation
01-genesis-building-vercel-for-mcp.md
Project Vision and AI Orchestration Methodologyblog/01-genesis-building-vercel-for-mcp.md
platform for MCP server deployment
systems with structured context files
key technology decisions
structuring AI-assisted development
README.md
Blog Series Index and Navigation Guideblog/README.md
AI-orchestrated development journey
paths for different audiences
specifications, and architecture details
for AI-assisted development
1 files
06-registry-validation.md
Security Hardening with Package and Credential Validation Layerblog/06-registry-validation.md
in package deployment
package existence before deployment
failures
1 files
08-security-hardening-production.md
Production Readiness: Testing, Security Hardening, and Deploymentblog/08-security-hardening-production.md
with 89% code coverage)
configuration, access token validation
configuration
validation, and connection pooling
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.
Greptile Summary
This PR adds a comprehensive 9-part blog series (~4,500 lines) documenting the complete 12-day AI-orchestrated development journey of Catwalk Live, from initial vision through production deployment.
What's Excellent
Technical Accuracy: All referenced commits exist (verified 215deaa, 890c67a, f1b3e68, 068dc28, 02f9346), the 86-commit count matches git history, and technical details align with the codebase (e.g., psycopg3 usage is correctly documented in
requirements.txt).Narrative Structure: The series follows a clear chronological arc with engaging storytelling that balances technical depth with accessibility. Each post builds on previous ones while remaining independently valuable.
Honest Documentation: The series doesn't shy away from failures - it documents the authentication debugging nightmare (Part 7), command injection vulnerability caught by CodeRabbit (Part 6), and the PostgreSQL driver saga (Part 4). This honesty makes the methodology more credible and valuable.
Practical Value: The series goes beyond "I built X with AI" to provide a reproducible methodology with specific prompt engineering patterns, multi-AI validation techniques, context file structures, and quality gates.
Cross-References: Excellent integration with existing documentation (
AGENTS.md,ARCHITECTURE.md,AI_ORCHESTRATION.md) and proper PR references (#12, #13) with accurate technical details.Key Highlights
Documentation Quality
The README navigation guide is excellent, providing multiple reading paths (Quick Read, Technical Deep-Dive, Specific Topics) that help different audiences find value. The series serves as both project documentation and a case study in AI-assisted development.
This is high-quality technical writing that will benefit developers exploring AI orchestration methodologies.
Confidence Score: 5/5
Important Files Changed
Sequence Diagram
sequenceDiagram participant Author as Blog Author participant Reader as Reader participant AI as AI Tools participant Code as Codebase participant Infra as Infrastructure Note over Author,Infra: 12-Day Development Journey (Dec 11-23, 2025) rect rgb(200, 220, 255) Note over Author,AI: Part 1: Genesis - Vision & Setup Author->>AI: Define project vision AI->>Author: Architectural recommendations Author->>Code: Initial commit (215deaa) Author->>Author: Create context files (AGENTS.md, ARCHITECTURE.md) end rect rgb(220, 255, 220) Note over Author,Code: Part 2: Foundation - Architecture Author->>AI: Request FastAPI backend setup AI->>Code: Generate database models AI->>Code: Implement Fernet encryption AI->>Code: Create dynamic form generation Author->>Code: Review and validate implementation end rect rgb(255, 240, 200) Note over Author,AI: Part 3: AI Analysis Engine Author->>AI: Design prompt for repo analysis AI->>AI: Iterate prompt engineering AI->>Code: Implement Claude API integration Code->>Code: Add caching (PostgreSQL) Author->>Code: Fix token overflow (200k+ → limit to 2 results) end rect rgb(255, 220, 220) Note over Author,Infra: Part 4: First Deployment Author->>Infra: Deploy to Fly.io Infra-->>Author: PostgreSQL driver error (asyncpg) Author->>Code: Switch to psycopg3 Infra-->>Author: CRLF line ending issues Author->>Code: Fix shell scripts Author->>Infra: Successful deployment end rect rgb(240, 220, 255) Note over Author,Infra: Part 5: Streamable HTTP & MCP Author->>AI: Implement MCP 2025-06-18 spec AI->>Code: Create mcp_streamable.py endpoint AI->>Code: Generate Fly Machines API integration Author->>Infra: Deploy MCP machines Infra-->>Author: 406 Not Acceptable (missing Accept header) Author->>Code: Fix header forwarding Code->>Code: End-to-end MCP tool calling works end rect rgb(255, 230, 230) Note over Author,Code: Part 6: Registry & Validation AI->>Code: Generate deployment code Code->>Code: CodeRabbit detects command injection Author->>Code: Add package validation (npm/PyPI) Author->>Code: Implement credential validation Author->>Code: Add Glama registry integration end rect rgb(255, 200, 200) Note over Author,Code: Part 7: Authentication Crisis Author->>AI: Implement NextAuth.js AI->>Code: Generate auth code (with TODOs) Author->>Infra: Deploy with authentication Code-->>Author: 401 Unauthorized (JWT signature invalid) Author->>Author: Debug for 4 hours Author->>Code: Fix AUTH_SECRET mismatch Code-->>Author: Still 401 (user sync not implemented) Author->>Code: Implement user sync endpoint Code-->>Author: Still 401 (AUTH_SECRET vs AUTH_SYNC_SECRET) Author->>Infra: Sync secrets correctly Code->>Code: Authentication works! end rect rgb(220, 255, 240) Note over Author,Code: Part 8: Security & Testing Author->>AI: Generate comprehensive test suite AI->>Code: Create 51 tests (89% coverage) Code->>Code: Tests reveal 3 critical bugs Author->>Code: Fix cache expiration bug Author->>Code: Fix credential validation Author->>Code: Fix deployment background task Code->>Code: CodeRabbit security review (PR #13) Author->>Code: Add access token rotation Author->>Code: Filter secrets from logs Author->>Code: Fix CORS configuration Author->>Infra: Deploy frontend to Vercel end rect rgb(240, 240, 240) Note over Author,Reader: Part 9: Reflections & Lessons Author->>Author: Analyze what worked vs failed Author->>Reader: Document AI orchestration methodology Author->>Reader: Share lessons learned Author->>Reader: Define reproducible process end Note over Author,Reader: Result: Production system + Complete methodology documentation