AGENTS.md - AI Coding Agent Guidelines

This is a Jekyll static site blog hosted on GitHub Pages at sameerbajaj.com. Primary Focus: SEO & organic search traffic.

Build Commands

# Development server (user runs this - agents should NOT start the server)
bundle exec jekyll serve --livereload --config _config.yml,_config-dev.yml

# Production build
bundle exec jekyll build

# Clean build cache
bundle exec jekyll clean

# Check configuration
bundle exec jekyll doctor

# HTML validation (after building _site/)
bundle exec rake

Testing & Validation

There are no unit tests. Validation is done via:

bundle exec rake                 # Runs HTMLProofer on _site/
bundle exec jekyll doctor        # Configuration checks

SEO Submission Scripts (Node.js)

npm run submit:google    # Submit URLs to Google Indexing API
npm run submit:bing      # Submit URLs to Bing IndexNow
npm run submit:all       # Bulk submission to both
npm run urls:list        # List all site URLs
npm run check:status     # Check indexing status

Requires GOOGLE_SERVICE_ACCOUNT_JSON environment variable for Google API.

Project Structure

_config.yml          # Production config
_config-dev.yml      # Development overrides (incremental builds, no minification)
_posts/              # Blog posts (YYYY-MM-DD-slug.md)
_layouts/            # HTML templates (post.html, book_notes.html, page.html)
_includes/           # Reusable components (head.html, nav.html, etc.)
_sass/               # SCSS partials (compiled via jekyll-minifier)
_data/               # YAML data files (fiction_books.yml, tools.yml)
assets/js/           # JavaScript (source .js and minified .min.js)
assets/images/       # Post images
scripts/             # Node.js SEO submission utilities
docs/                # Internal documentation

Code Style Guidelines

JavaScript Conventions

// Use DOMContentLoaded for DOM-dependent code
document.addEventListener('DOMContentLoaded', function () {
    // Code here
});

// IIFE pattern for isolation
(function () {
    // Self-contained logic
})();

// Early returns for guard clauses
if (!element || !container) {
    return;
}

// Function declarations over expressions for named functions
function setDarkMode(isDarkMode) { }
function toggleDarkMode() { }

// Arrow functions for callbacks and event handlers
prefersDarkMode.addEventListener('change', (e) => {
    setDarkMode(e.matches);
});

// LocalStorage for persistence
localStorage.getItem('darkMode');
localStorage.setItem('darkMode', isDarkMode);

Important: Production serves .min.js files. When editing JavaScript in assets/js/, update both source and minified versions.

SCSS/CSS Conventions

// Component-based naming (BEM-like)
.toc { }
.toc h2 { }
.toc a.active { }

// CSS custom properties for theming
color: var(--signature-color);
background: var(--background-color);

// Dark mode via body class
body.dark-mode .component { }

// Responsive breakpoints
@media (max-width: 768px) { }
@media (max-width: 1360px) { }

// Modern CSS features encouraged
clamp(), min(), max(), transform, transition

SCSS partials use underscore prefix: _toc.scss, _newsletter.scss.

Liquid Template Patterns







<!-- Simple Feedback Widget - One-click reactions -->
<div class="feedback-widget" data-post-title="AGENTS.md - AI Coding Agent Guidelines" data-post-url="/AGENTS/">
    <div class="feedback-section" id="feedbackSection">
        <p class="feedback-question">Was this helpful?</p>
        
        <!-- Reaction Buttons -->
        <div class="reaction-buttons">
            <button class="reaction-btn" data-reaction="loved" title="Loved it!">
                <span class="emoji">❤️</span>
                <span class="reaction-label">Loved it</span>
            </button>
            <button class="reaction-btn" data-reaction="helpful" title="Helpful">
                <span class="emoji">👍</span>
                <span class="reaction-label">Helpful</span>
            </button>
            <button class="reaction-btn" data-reaction="interesting" title="Interesting">
                <span class="emoji">🤔</span>
                <span class="reaction-label">Interesting</span>
            </button>
            <button class="reaction-btn" data-reaction="meh" title="Meh">
                <span class="emoji">😐</span>
                <span class="reaction-label">Meh</span>
            </button>
        </div>

        <!-- Thank you message (shown inline after click) -->
        <p class="feedback-thanks" id="thanksMessage" style="display: none;">
            Thanks! ✨
        </p>

        <!-- Optional comment section (shown after reaction click) -->
        <div class="feedback-comment-section" id="commentSection" style="display: none;">
            <p class="comment-prompt">Want to add a quick comment? (optional)</p>
            <textarea 
                class="comment-input" 
                id="commentInput" 
                placeholder="What did you think?"
                maxlength="500"
                rows="3"
            ></textarea>
            <div class="comment-buttons">
                <button class="comment-btn comment-submit" id="submitComment">Send</button>
                <button class="comment-btn comment-skip" id="skipComment">Skip</button>
            </div>
        </div>
    </div>
</div>

<style>
.feedback-widget {
    margin: 2.4rem 0 1.6rem 0;
    padding: 2rem 1.6rem;
    border-top: 1px solid var(--border-color);
    border-bottom: 1px solid var(--border-color);
    text-align: center;
    background: var(--background-color);
}

.feedback-question {
    margin: 0 0 1.6rem 0;
    font-size: 1.8rem;
    font-family: 'signifier', serif;
    color: var(--heading-color);
    font-weight: 400;
    line-height: 1.4;
}

.reaction-buttons {
    display: flex;
    justify-content: center;
    gap: 1.2rem;
    flex-wrap: wrap;
    margin-bottom: 0.8rem;
}

.reaction-btn {
    background: var(--background-elevated);
    border: 1.5px solid var(--border-color);
    border-radius: 12px;
    width: 72px;
    height: 72px;
    cursor: pointer;
    transition: all 0.25s ease;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    position: relative;
    box-shadow: 0 1px 3px rgba(0,0,0,0.08);
}

.reaction-btn:hover {
    transform: translateY(-3px);
    border-color: var(--signature-color);
    box-shadow: 0 3px 10px rgba(0,0,0,0.12);
}

.reaction-btn:hover .reaction-label {
    opacity: 1;
    color: var(--signature-color);
}

.reaction-btn.clicked {
    transform: scale(0.95);
    background: var(--background-hover);
    border-color: var(--signature-color);
}

.reaction-btn .emoji {
    font-size: 2.2rem;
    display: block;
    line-height: 1;
}

.reaction-label {
    font-size: 1.1rem;
    font-family: 'signifier', serif;
    color: var(--text-muted);
    font-weight: 400;
    opacity: 0.85;
    transition: all 0.25s ease;
    text-transform: capitalize;
}

.feedback-thanks {
    margin-top: 1.2rem;
    color: var(--success-color);
    font-size: 1.6rem;
    font-family: 'signifier', serif;
    font-weight: 400;
    animation: fadeIn 0.5s ease;
}

@keyframes fadeIn {
    from { opacity: 0; transform: translateY(-8px); }
    to { opacity: 1; transform: translateY(0); }
}

.feedback-comment-section {
    margin-top: 1.6rem;
    animation: fadeIn 0.5s ease;
}

.comment-prompt {
    margin: 0 0 1.2rem 0;
    font-size: 1.5rem;
    font-family: 'signifier', serif;
    color: var(--text-muted);
    font-weight: 400;
}

.comment-input {
    width: 100%;
    max-width: 480px;
    padding: 1rem;
    border: 1.5px solid var(--border-color);
    border-radius: 10px;
    font-family: 'signifier', serif;
    font-size: 1.4rem;
    line-height: 1.6;
    resize: vertical;
    transition: all 0.25s ease;
    background: var(--background-color);
    color: var(--text-color);
}

.comment-input:focus {
    outline: none;
    border-color: var(--signature-color);
    box-shadow: 0 0 0 2.5px rgba(0,0,0,0.05);
}

.comment-input::placeholder {
    color: var(--text-muted-light);
    opacity: 0.8;
}

.comment-buttons {
    display: flex;
    gap: 0.8rem;
    justify-content: center;
    margin-top: 1.2rem;
}

.comment-btn {
    padding: 0.8rem 2rem;
    border: none;
    border-radius: 6px;
    font-size: 1.4rem;
    font-family: 'signifier', serif;
    font-weight: 400;
    cursor: pointer;
    transition: all 0.25s ease;
    text-decoration: none;
}

.comment-submit {
    background: var(--signature-color);
    color: white;
}

.comment-submit:hover {
    background: var(--signature-color-hover);
    transform: translateY(-1.5px);
    box-shadow: 0 3px 10px rgba(245, 158, 11, 0.3);
}

.comment-skip {
    background: transparent;
    color: var(--text-muted);
    border: 1.5px solid var(--border-color);
}

.comment-skip:hover {
    background: var(--background-hover);
    border-color: var(--border-color-hover);
}

@media only screen and (max-width: 780px) {
    .feedback-widget {
        padding: 1.6rem 0.8rem;
    }
    
    .feedback-question {
        font-size: 1.45rem;
    }
    
    .reaction-buttons {
        gap: 0.8rem;
    }
    
    .reaction-btn {
        width: 60px;
        height: 60px;
    }
    
    .reaction-btn .emoji {
        font-size: 1.9rem;
    }
    
    .reaction-label {
        font-size: 0.95rem;
    }
    
    .comment-prompt {
        font-size: 1.3rem;
    }
    
    .comment-input {
        font-size: 1.2rem;
    }
    
    .comment-btn {
        padding: 0.7rem 1.6rem;
        font-size: 1.2rem;
    }
}
</style>


/assets/js/file.js?v=1793392977

Markdown Conventions

Front Matter Standards

Blog Post

---
title: "Post Title"
layout: post
date: 2024-03-08 00:00
image: /assets/images/image.jpg
description: "Brief summary (150 chars)"
tags: [tag1, tag2]
category: blog
author: sameerbajaj
last_modified_at: 2024-01-02 12:00  # Update when revising content
---

Book Notes

---
title: "Book Title by Author - Summary and Notes"
layout: book_notes
date: 2024-03-08 00:00
image_url: https://m.media-amazon.com/...
book_title: "Book Title"
book_author: "Author Name"
book_url: https://amzn.to/...
book_thoughts: "One-liner recommendation"
rating: 7
date_read: 2024-01-27 00:00
star: false
tags: [book-notes]
category: blog
---

File Naming

SEO Best Practices (Critical)

OG Image Fallback Logic

  1. Use image (relative path)
  2. Fallback to image_url (absolute URL)
  3. Auto-extract first <img> from content
  4. Last resort: site avatar

Development Workflow

IMPORTANT: The user runs the Jekyll dev server themselves. Never start the server or run bundle exec jekyll serve. If you need the user to check changes, ask them to review it.

  1. Edit files as needed
  2. Ask user to verify changes in browser (they’re running dev server)
  3. For significant revisions, update last_modified_at
  4. After commit/push, consider npm run submit:google for faster indexing

Ruby Environment

Error Handling

Performance Patterns

Author & Submissions Identity Standards

To prevent spammy, low-taste, or mismatched outreach, every prospective link target must pass all 4 gates:

  1. Exact Form Factor Match:
    • macOS Desktop Apps (MacYT, EnhancedSkills) ➔ ONLY macOS app showcases (awesome-mac, open-source-mac-os-apps). NEVER submit desktop apps to CLI lists or generic software directories.
    • Essays & Case Studies ➔ ONLY technical/product publications (Dev.to with canonical tags, HackerNoon, Mind the Product).
    • Personal Blog & Reading Notes ➔ ONLY authentic indie webrings (uses.tech, personalsit.es, blogroll.org).
  2. Objective Prerequisite Verification:
    • Pre-audit star counts, repository age, and automated maintainer bots before proposing. Never propose a list requiring >4 stars if the repo currently has fewer.
    • Immediately disqualify any directory requiring revenue, MRR, or payment processor sync (e.g. TrustMRR). All tools are 100% free open-source software.
  3. Taste & Reputation Invariant (“Proud to Showcase” Test):
    • Zero SEO link farms, low-rent directories, throwaway profile aggregators, or paid listing networks (e.g. Carrd hubs, Linktree spam, Dodo, TinyLaunch).
    • If the author would not proudly display the listing on their portfolio, do not pursue it.
  4. Editorial & Peer Recognition Over Directory Volume:
    • Prioritize high-signal, earned editorial mentions (canonical syndication on Dev.to, guest technical breakdowns, mutual /friends blogroll links) over arbitrary directory submissions.

Technical SEO Architecture & Crawl Resolutions (September 2026 Audit)

rss facebook twitter github gitlab youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora