
Backend systems, databases, and building with AI
Hi, I'm Rohan. I'm a CTO based in Mumbai, building B2B SaaS for small and medium businesses with a small team of dedicated engineers. Most days that means Python, FastAPI, MySQL, and a lot of monitoring dashboards.
I write about backend systems, databases, and building with AI over at Null Tensor, my newsletter. Away from the keyboard I'm a technophile who will try any new tool once, and a long-time anime fan.
Posts
View all- How to Build an MCP Server: Python, Remote and Ready for Production8 min read
- I Tried 28 Claude Code Skills. Here Are the 5 I Kept8 min read
- Claude MCP: What It Is and How to Add a Server7 min read
- Jev AI vs Logprobs vs Structured Output: We Tested TypeSafe's System One Model on Our Support Queue9 min read
- My Claude Code chief of staff: one VM, eight specialists and one Telegram chat8 min read
- Claude Code Review in Production: How Our Review Rules Evolved Over Five Months8 min read
- MCP vs API: When to Build an MCP Server, and When the API Is Enough14 min read
- If leaders want AI speed, they must share the production risk6 min read
- A 90% agent PR merge rate can still describe a weak engineering workflow6 min read
- AI in Software Testing: Why Generated Tests Miss Bugs5 min read
Notes
View allThis is the structure of the review playbook behind Claude Code Review in Production: How Our Review Rules Evolved Over Five Months, with our company-specific rules removed. Replace the rule documents with your own; the routing, severity ladder, finding format and verifier transfer as they are. In Claude Code, the orchestrator can be a slash command (
.claude/commands/review.md), the specialists and verifier are sub-agents (.claude/agents/*.md), and the same playbook can drive a GitHub Action.# Code Review Playbook (single source of truth for local /review and CI) ## 1. Scope - CI: the PR diff. Local: ask which branch this merges into; review committed, uncommitted and untracked changes against it. - Exclude data and config artefacts (.sql, .csv, .json). If nothing reviewable remains, report "No reviewable code files changed" and stop. - Review ONLY added or changed lines. Never flag pre-existing code. ## 2. Route (the orchestrator reviews nothing itself) | Specialist | Files | Rule document | |-----------------------|-------------------------------|---------------------------| | review-api | API / router files | docs/rules/api.md | | review-domain | service / domain files | docs/rules/domain.md | | review-data | repository / data-access files| docs/rules/data.md | | review-architecture | all application code | docs/rules/architecture.md| | review-db-performance | all non-test code | docs/rules/db-perf.md | | review-style | all code | style guide (caps at WARNING) | Dispatch every relevant specialist in parallel. Skip a specialist with no files. ## 3. Finding format (every specialist) ### Finding - file: <path> - line: <line in the new file> - severity: BLOCKING | WARNING | SUGGESTION - section: <rule document> §<n> <heading> - quote: <offending code, verbatim> - issue: <which rule, why it is violated> - fix: <concrete fix> Or exactly: NO FINDINGS ## 4. Severity (mechanical, no judgement calls) - BLOCKING: violates a documented blocking rule. Must cite file and section. - WARNING: violates a documented warning-level or style rule. Must cite it. - SUGGESTION: a concern no documented rule covers. Never a rule violation. - Style never blocks. ## 5. Verify (one verifier, after all specialists) Reject a finding unless ALL hold: 1. The file exists. 2. The quoted code appears within ±5 lines of the cited line. 3. That line is added or changed in this diff (not context, not removed). 4. The cited rule section exists and says what the finding claims. False positives are far worse than false negatives. Do not re-grade severity. Do not add findings. Drop rejected findings silently. ## 6. Deliver - Group approved findings by file; lead with the verdict. - CI: request changes if any approved BLOCKING, otherwise approve. - Local: print the review; never post.For the GitHub side, two settings carried most of the weight for us: run on
opened,synchronize,reopenedandready_for_reviewbut skip drafts; and skip branches where a review cannot help, such as release promotions.How we got here, and why each rule exists, is in the full post.
Properly tuning your app configurations can save you a lot of money. Check out my new post on how I saved us on cloud costs by tuning our backend stack: How I Halved My Backend Python App's Memory Usage.
Been tinkering with Claude Skills for the past 2 weeks. Here are some things I feel everyone should know: Claude Skills Might Be Bigger Than MCP.