{"id":264,"date":"2026-06-14T19:57:19","date_gmt":"2026-06-14T23:57:19","guid":{"rendered":"https:\/\/www.parhammofidi.com\/blog\/?p=264"},"modified":"2026-06-14T19:57:19","modified_gmt":"2026-06-14T23:57:19","slug":"code-reviews-with-cursor","status":"publish","type":"post","link":"https:\/\/www.parhammofidi.com\/blog\/index.php\/2026\/06\/14\/code-reviews-with-cursor\/","title":{"rendered":"Code Reviews with Cursor"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">I spend a lot of time doing code reviews. It&#8217;s one of those things everyone agrees is important and it&#8217;s always a scramble to get them done. It&#8217;s probably the number one thing that slows down merges because context-switching is difficult especially when you have your own priorities and work to get done. Using Cursor to help with code reviews doesn&#8217;t excuse going through a PR\/MR manually and certainly pairing on code reviews with the code creator helps immensely, but it does help speed things up.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">The Setup: Give Cursor a Way to Fetch the Diff<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Cursor lets you enable terminal command execution, which means you can point it straight at a pull request. I use the GitHub CLI for this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>gh pr diff https:\/\/github.com\/account\/project\/pull\/1234<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This pulls the full unified diff of the PR directly into Cursor&#8217;s context. No copy-pasting, no switching tabs, no losing your place.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Alternatively, you can ask the AI to run the command directly without the need to switch your working branch.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Either way, once you&#8217;ve run that command and the diff is loaded, the model you end up using for the code review now has the context it needs to do what it needs to do.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">The Prompt<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s the prompt:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Please do a code review. Concentrate on functionality, syntax errors, \nand possible security issues.<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s genuinely it. The simplicity is the point. I&#8217;m trying to make my life easier to utilizing AI, so I&#8217;m not trying to throw a ton of instructions at it .<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">What the Output Looks Like<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s a sample of what Cursor might return after reviewing a PR\/MR that adds a new API endpoint:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Code Review \u2014 PR #1234<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Functionality<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>getUserById()<\/code> on line 42 is called without awaiting the result. The downstream handler assumes a resolved user object, so any request hitting this path will likely return <code>undefined<\/code> data rather than throwing \u2014 making this silent and hard to catch in testing.<\/li>\n\n\n\n<li>The pagination logic in <code>listOrders()<\/code> applies the <code>limit<\/code> before filtering by <code>status<\/code>, which means pages can return fewer items than expected when most records are filtered out. The filter should run first.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Syntax \/ Code Quality<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Line 87: unused import <code>parseDate<\/code> from <code>date-fns<\/code>. Minor, but worth cleaning up to avoid confusion.<\/li>\n\n\n\n<li>The <code>switch<\/code> statement in <code>routeAction()<\/code> is missing a <code>default<\/code> case. If an unrecognized action string is passed, the function returns <code>undefined<\/code> silently rather than throwing or logging.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Security<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The <code>userId<\/code> parameter on line 61 is interpolated directly into a raw SQL string. This is a SQL injection risk \u2014 use parameterized queries or your ORM&#8217;s query builder instead.<\/li>\n\n\n\n<li>The error handler on line 114 returns the full stack trace in the response body. In production this leaks internal implementation details. Sanitize error responses before they leave the server.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Summary<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Two issues worth fixing before merge: the missing <code>await<\/code> on <code>getUserById()<\/code> and the SQL injection vector. The rest are improvements worth a follow-up ticket.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">That kind of output with specific line numbers, concrete problems, actionable fixes is what makes this actually useful rather than just a vibe check.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Make It Even Smarter: The Cursor Rules File<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">A <code>.cursor\/rules<\/code> file (or a <code>CURSOR.md<\/code> at the root of your repo) helps even more. This is where you teach Cursor about <em>your<\/em> project specifically.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s what that file might look like:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Cursor Rules \u2014 MyProject\n\n## Build &amp; Run\n- `npm run build` to compile\n- `npm run dev` to start the dev server (port 3000)\n- `npm test` to run the full test suite (Jest)\n\n## Linting &amp; Formatting\n- ESLint config: `.eslintrc.js` \u2014 no unused variables, no `console.log` in production code\n- Prettier is enforced on commit via Husky\n- Run `npm run lint:fix` before raising a PR\n\n## Code Conventions\n- All API routes live in `\/src\/routes` \u2014 one file per resource\n- Database queries go through the repository layer in `\/src\/repositories` \u2014 never query directly from a controller\n- Use parameterized queries only \u2014 no raw string interpolation in SQL\n- Error responses must use the shared `ApiError` class from `\/src\/utils\/errors`\n\n## Security Notes\n- Never log request bodies \u2014 they may contain PII\n- All user-supplied IDs must be validated with `validateUUID()` before use\n- Auth middleware is applied globally; routes that bypass it must be explicitly listed in `PUBLIC_ROUTES`\n\n## PR Checklist\n- Tests added or updated for any changed behavior\n- No new `any` types in TypeScript without a comment explaining why\n- Migration files named `YYYYMMDD_description.sql`\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When Cursor reads this file alongside the diff, it knows your conventions. You can always type out a lot of these in the AI chat area, but having this file will save you from having to repeat these. The review now becomes a reflection of your team&#8217;s actual standards and not an inferred one or a generic checklist.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Why This Works<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">All this turns Cursor into something close to a knowledgeable teammate doing a first-pass review. It&#8217;s important to remember that none of this is meant to replace human judgment on architecture decisions or product tradeoffs, but it can reliably catch stuff that is also easy to miss like syntax, injection risks, unused imports, violated conventions. That&#8217;s exactly the category of issue that&#8217;s easy to miss. The rules file is the part that makes the biggest difference. Spend a few minutes writing it once, and every review after that is better because of it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I spend a lot of time doing code reviews. It&#8217;s one of those things everyone agrees is important and it&#8217;s always a scramble to get them done. It&#8217;s probably the number one thing that slows down merges because context-switching is difficult especially when you have your own priorities and work to get done. Using Cursor [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":265,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[165],"tags":[10,25,81,14,187,8,27,7],"class_list":["post-264","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai","tag-agile","tag-ai","tag-codereviews","tag-development","tag-llm","tag-productivity","tag-software","tag-softwaredevelopment"],"_links":{"self":[{"href":"https:\/\/www.parhammofidi.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/264","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.parhammofidi.com\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.parhammofidi.com\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.parhammofidi.com\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.parhammofidi.com\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=264"}],"version-history":[{"count":1,"href":"https:\/\/www.parhammofidi.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/264\/revisions"}],"predecessor-version":[{"id":266,"href":"https:\/\/www.parhammofidi.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/264\/revisions\/266"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.parhammofidi.com\/blog\/index.php\/wp-json\/wp\/v2\/media\/265"}],"wp:attachment":[{"href":"https:\/\/www.parhammofidi.com\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=264"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.parhammofidi.com\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=264"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.parhammofidi.com\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=264"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}