AGENTS.md - Article Writing Guidelines
Article File Naming Conventions
Core Principle
Filename MUST match the article title exactly.
- Use lowercase letters
- Use hyphens (-) to separate words
- The filename should be a direct transformation of the title
Examples:
- ✅ Title:
# Avoid Database Queries in Large Data Loops- Filename:
avoid-database-queries-in-large-data-loops.md
- Filename:
- ✅ Title:
# Optimize Data Sync Script Performance- Filename:
optimize-data-sync-script-performance.md
- Filename:
- ❌
Optimization_Summary.md(doesn't match title) - ❌
perf.md(doesn't match title)
Keep the Filename Consistent with the Content
If the title or content changes, rename the file so the filename stays consistent with it.
- Do NOT keep working or placeholder names once the final title is known
- The filename drives the generated nav/sidebar link, so a stale name results in an incorrect link
Example:
- ❌
idea-to-a-product.md(placeholder, does not match the post content) - ✅
anyone-can-be-a-full-stack-developer.md
Keep Filenames Short
Prefer a short filename (roughly 60 characters or fewer) that still captures the post content.
- Don't copy a long title verbatim — summarize its core idea
- Long filenames are hard to read and produce unwieldy URLs
Example:
- ❌
anyone-can-be-a-full-stack-developer-now-cli-skill-become-a-programmer-without-writing-code.md(too long) - ✅
anyone-can-be-a-full-stack-developer.md
Frontmatter Description
Every content page MUST keep its frontmatter description in sync with the page content.
- The
descriptionis rendered into<meta name="description">, so it drives search results and link previews - Whenever the visible content of a page changes (sections added, removed, or rewritten), update the
descriptionin the same change - Describe what the page actually offers now — do not keep outdated wording about anything that was removed
- Keep it to a single sentence of roughly 120–160 characters, written in the same language as the page
- Base it only on content that exists on the page — never invent services, prices, or claims
Example:
- ❌
description: Web and mobile app development.(generic, and stale once new services were added) - ✅
description: "Fixed-price custom software: web apps, backend APIs, AI automation, 3D and GIS development — scoped and priced in writing before any work starts."
Note: Quote the value when it contains : , #, or other YAML-special characters.
Service Consistency
services/index.md is the single source of truth for what is offered.
- Every page — Home, Projects, Contact, nav, and meta descriptions — must describe only services that are actually listed on the Services page. Never invent a service, price, or capability
- When a service is added, renamed, or removed on the Services page, update every page that lists or summarises services in the same change
- The Home feature cards MUST mirror the primary service categories on the Services page (the H3 sections under "Full Service List"), reusing the same naming and scope. Benefit-driven wording is fine, but the scope must trace back to a listed service
- Supplementary items (cloud deployment, documentation, training) live under "Additional Implementation Services" and are not given their own Home card
- Every other place that lists or offers a service — the Contact page's "What do you need?" dropdown and any select/form field, CTA copy, nav labels, and meta descriptions — MUST enumerate the same primary service categories, in the same order, with the same names or a clear paraphrase. Add a single catch-all option at the end (e.g. "Something else") rather than inventing extra services
- Treat form dropdowns as service lists, not free-form UI: when a service is added, renamed, or removed on the Services page, update the form options in the same change
Example:
- ❌ Home shows a "Backend & API Development" card, but the Services page only offers backend APIs as part of "Custom Business Software Solutions"
- ❌ The Contact "What do you need?" dropdown offers "Game development" and "Server maintenance", which are not listed on the Services page
- ✅ Home and Services both present the same categories: Custom Business Software, AI Business Automation, 3D Interactive Experiences, and GIS & Map Solutions
- ✅ The Contact dropdown offers one option per Services page section — Custom business software, AI business automation, 3D interactive experiences, GIS & map solutions, and Deployment/documentation/training — plus "Something else"
Clients & Logo Consistency
clients-cases/index.md is the single source of truth for client claims.
- List only companies the owner has actually delivered work for. Never invent a client, and never add a company's logo to imply a relationship that does not exist
- Display official brand marks only — download them from the client's own website or brand/CDN and store them under
public/assets/clients/. Never redraw, recolor, crop, or AI-generate a third-party logo - Reference a logo as
/assets/clients/<file>with descriptivealttext (e.g.alt="Haier logo") - Use the exact public brand name. Add a country or entity qualifier only when it identifies the real contracting entity (e.g.
Haier Thailand) - Never publish a client's commercial details — contract size, rates, timelines, or internal metrics — unless the client has agreed to it
- Never name a client who is under NDA. Describe that work by capability and sector only — no name, no logo, no detail specific enough to identify the client — and say the details are available on a call. Anonymised claims must still trace to real work
- Case studies are titled by capability and stay unattributed until the owner confirms which engagement belongs to which client
Markup: render clients in the pf-grid pf-grid-3 grid — three per row, collapsing to two below 960px and one below 640px:
<div class="pf-grid pf-grid-3">
<div class="pf-card">
<div class="pf-client-logo">
<img src="/assets/clients/haier.png" alt="Haier logo" loading="lazy" />
</div>
<h3>Haier Thailand</h3>
</div>
</div>To signal that more clients exist without naming them, use the pf-nda block — a bordered note with a .pf-nda heading, a short explanation and a pf-btn link to the contact page. List the withheld engagements as capability plus sector, never as a named or identifiable client.
.pf-client-logokeeps a white tile behind the mark so dark or transparent logos stay legible in both light and dark themes. Do not remove it- When a client is added, renamed, or removed, update the
descriptioninclients-cases/index.mdin the same change
Example:
- ❌ Adding "Acme Corp" with a logo pulled from a random search result, because the page looks sparse
- ❌ Redrawing a client's wordmark as inline SVG to match the site palette
- ❌ Writing "cut their export time by 60%" for a client that never approved that number
- ✅ Adding a client only after the engagement is real, using the official mark downloaded from their own site, with the name matching their own branding
Case Study Pages
Case detail pages are flat files, not folders.
- Each case lives at
clients-cases/<case-name>.md— neverclients-cases/<case-name>/index.md - Each card's
data-case-studymust be/clients-cases/<case-name>— no trailing slash, no.html; the content loader strips.htmlso the popup's exact-match lookup succeeds - The listing page
clients-cases/index.mdmust stay out of the popup payload
A case has exactly one cover image, shared by every surface.
- The home page card, the Clients & Cases grid card and the detail page must all point at the same local file under
public/assets/clients-cases/ - Never reference an external image URL (the generation API, a CDN, a stock site) from a page — download or author the asset and commit it to the repo
- Use the same
alttext on all three surfaces, describing what the image actually shows rather than the service offered - When a cover is replaced, swap the file in place or update all three references in the same change; remove the old file so unused assets don't linger
- Prefer a vector
.svgcover when the image is an illustrated mockup — it stays sharp at card and detail-page sizes
Prefer a real cover source; illustrate it only when there is none.
- If a real source exists — a screenshot, or a frame captured from a supplied video or recording — use it. Capture the frame, commit it under
public/assets/clients-cases/, and crop it to 16:9 so it lines up with the sibling covers - If no real source exists, create an illustration that matches the case — a vector
.svgmockup of the case's own subject. Do not fabricate a photorealistic screenshot of software that does not exist - Whichever route is taken, the result still follows the cover rule above: one local file, one
alttext, shared by every surface, with unused assets removed
If a case is a video, the detail page contains only the video.
- A video case page shows exactly: the page title, the
<video>block and the back link — nothing else - No intro paragraph and no text sections (challenge, result, write-up) on a video case page
- Image-based case pages follow the normal structure: intro, media, The challenge, Result
An image case has exactly two sections: The challenge and Result.
- Every image case page is: intro paragraph, cover media,
## The challenge, then## Result— nothing in between - Never add a "What we built" or feature-list section — the case states the problem and the outcome, not an inventory of features
## The challengelists the concrete problems in the client's situation;## Resultlists what changed, each point traceable to a challenge above- Keep the intro to one short paragraph and finish with the
← Back to Clients & Casespf-btnlink
The home page features exactly three cases.
clients-cases/index.mdlists every case; the home page (index.md) shows only three, as a curated selection- Never let the home page grow past three case cards — when a case is added, swap one out rather than appending
- Keep the trio spread across different service categories, and reuse the same cover (image or video) and the same
data-case-studypath as the listing page - When a case is added, renamed, or removed, update the home page trio in the same change
Post Illustrations
Every post gets its own image folder mirroring its article path: public/assets/posts/<category path...>/<post-slug>/.
- The image folder must mirror the article's full folder chain under
posts/, then add the post slug: every category layer the article sits in becomes a folder layer here tooposts/ai/avoid-database-queries-in-loops.md→public/assets/posts/ai/avoid-database-queries-in-loops/01-shared-query-layer.svgposts/ai/agents/<post-slug>.md→public/assets/posts/ai/agents/<post-slug>/01-....svgposts/backend/database/indexing/<post-slug>.md→public/assets/posts/backend/database/indexing/<post-slug>/01-....svg
- Never flatten the chain: no images sitting directly in
public/assets/posts/, none in a category folder without the post slug (e.g.public/assets/ai/), and no collapsed multi-level categories (e.g.ai-agents/) - Always write the whole path, file included, so the file's real location is unambiguous
- Reference the same whole path from the article, minus
public, as an absolute public URL:public/assets/posts/<category path...>/<post-slug>/<file>→/assets/posts/<category path...>/<post-slug>/<file>. A relative path breaks once the file leaves the article folder - Name each file after what it shows, with a zero-padded prefix that matches its order in the article (e.g.
01-idea-to-working-product.svg) - Place each illustration directly under the heading it belongs to — one image per section, not stacked in a gallery at the end
- Write
alttext in the same language as the article and describe what the picture actually shows, not the point you wish it made - Prefer
.svgfor flat vector artwork so it stays sharp at any width; screenshots and screen recordings stay.png/.gif - Never reference an external image URL from an article — download or author the asset, commit it, then link the local file
- Delete the asset (and its folder once empty) in the same change that removes its last reference, so unused files don't linger
Examples:
- ❌
public/assets/posts/03-prompt-to-app.svg(loose file, not grouped per post) - ❌
public/assets/ai/prompt-to-app.svg(category folder, no post slug) - ❌
public/assets/posts/ai-agents/<post-slug>/03-prompt-to-app.svg(collapsed a two-level category into one folder) - ❌
posts/ai/illustrations/03-prompt-to-app.svgreferenced asillustrations/03-prompt-to-app.svg - ✅
public/assets/posts/ai/become-a-full-stack-developer-without-writing-code/03-prompt-to-app.svgreferenced as/assets/posts/ai/become-a-full-stack-developer-without-writing-code/03-prompt-to-app.svg - ✅
posts/backend/database/indexing/<post-slug>.md→public/assets/posts/backend/database/indexing/<post-slug>/01-....svgreferenced as/assets/posts/backend/database/indexing/<post-slug>/01-....svg
<!-- posts/ai/<post-slug>.md -->

<!-- posts/ai/agents/<post-slug>.md -->
Article Structure Standards
1. Title Format
# [Action-Oriented Title]
[Brief introduction - 1-2 sentences explaining the problem and solution]Examples:
- ✅
# Avoid Database Queries in Large Data Loops - ✅
# Fix N+1 Query Problem in JPA/Hibernate - ❌
# Database Queries(too vague) - ❌
# How to Optimize(not specific enough)
2. Section Hierarchy
## [Main Section]
### [Subsection]
#### [Sub-subsection] (use sparingly)Rules:
- Use
##for main sections (Problem, Solution, Examples) - Use
###for subsections - Avoid
####unless necessary - Maximum 3 levels deep
3. Problem-Solution Pattern
Standard Structure:
## The Problem
[Describe the scenario and why it's a problem]
### ❌ Bad Practice: [Name]
```java
// Code showing the bad practicePerformance Impact:
- [Impact 1]
- [Impact 2]
- [Critical impact in bold]
✅ Good Practice: [Name]
// Code showing the good practicePerformance Impact:
- [Benefit 1]
- [Benefit 2]
- [Key benefit in bold]
---
### 4. Code Examples
**Format:**
```markdown
### [Descriptive Title]
```java
// ✅ Good code with comment explaining why
List<Entity> result = repository.selectByIds(ids);
// ❌ Bad code with comment explaining why not
for (Entity e : entities) {
repository.selectById(e.getId()); // N queries!
}
**Rules:**
- Always use language identifier (`java`, `sql`, `yaml`, etc.)
- Use `✅` for good practices
- Use `❌` for bad practices
- Add inline comments explaining the code
- Keep examples focused and minimal
---
### 5. Performance Comparison Tables
**Format:**
```markdown
## Performance Comparison
| Approach | Metric 1 | Metric 2 | Metric 3 |
|----------|----------|----------|----------|
| Bad Way | Value | Value | **Critical** |
| Good Way | Value | Value | Normal |
| **Improvement** | **Xx** | **Yx** | **Z%** |Rules:
- Always include comparison table when discussing performance
- Use
**bold**for critical values - Show improvement multiplier/factor
- Include both quantitative and qualitative metrics
6. Best Practices Section
Format:
## Best Practices
### 1. [Practice Name]
```java
// Example codeExplanation:
- [Why this is important]
- [When to apply]
2. [Practice Name]
...
**Rules:**
- Number the practices (1, 2, 3...)
- Each practice has: Title + Code + Explanation
- Keep explanations concise (2-3 bullet points)
---
### 7. Common Pitfalls Section
**Format:**
```markdown
## Common Pitfalls to Avoid
### ❌ Pitfall 1: [Pitfall Name]
```java
// Bad code// Good codeWhy it's bad: [Explanation]
**Rules:**
- Use `❌ Pitfall N:` format
- Show both bad and good code
- Explain why the bad approach is problematic
- Number pitfalls for easy reference
---
### 8. Advanced Techniques (Optional)
**Format:**
```markdown
## Advanced Techniques
### 1. [Technique Name]
```java
// Advanced exampleWhen to use: [Scenario]
Trade-offs: [Pros and cons]
---
### 9. Real-World Case Studies (Optional)
**Format:**
```markdown
## Real-World Case Studies
### Case 1: [Case Name]
**Problem:** [Description]
**Root Cause:** [Analysis]
**Solution:**
1. [Step 1]
2. [Step 2]
**Result:** [Quantitative improvement]10. Summary Section
Format:
## Summary
When [scenario]:
1. **[Key point 1]** - [Brief explanation]
2. **[Key point 2]** - [Brief explanation]
3. **[Key point 3]** - [Brief explanation]
**Remember:** [One-sentence takeaway]Rules:
- Number the key points
- Bold the key phrase, add brief explanation
- End with memorable "Remember" statement
11. Quick Checklist (Optional)
Format:
## Quick Checklist
Before [action]:
- [ ] [Check item 1]
- [ ] [Check item 2]
- [ ] [Check item 3]Writing Style Guidelines
Language
- Use English for all technical articles
- Keep sentences concise and direct
- Use active voice: "Query the database" not "The database is queried"
Tone
- Professional but accessible
- Focus on practical solutions
- Avoid jargon without explanation
Formatting
- Use
**bold**for emphasis on key points - Use
inline codefor technical terms - Use emoji sparingly (✅ ❌ ⚠️ only)
Code Comments
- Explain why, not what
- Use
// ✅for good practices - Use
// ❌for bad practices - Use
// TRIGGER WARNINGfor anti-patterns
Article Template
# [Action-Oriented Title]
[1-2 sentence introduction]
## The Problem
[Scenario description]
### ❌ Bad Practice: [Name]
```java
// Bad codePerformance Impact:
- [Impacts]
✅ Good Practice: [Name]
// Good codePerformance Impact:
- [Benefits]
Implementation Examples
[Example 1]
// CodePerformance Comparison
| Approach | Metric | Result |
|---|---|---|
| Bad | X | Slow |
| Good | Y | Fast |
Best Practices
1. [Practice]
// CodeCommon Pitfalls to Avoid
❌ Pitfall 1: [Name]
// Bad// GoodSummary
- [Point 1] - [Explanation]
- [Point 2] - [Explanation]
Remember: [Takeaway]
---
## Quality Checklist
Before publishing, verify:
- [ ] Title is action-oriented and specific
- [ ] Filename follows naming conventions (lowercase, hyphens, descriptive)
- [ ] Introduction clearly states the problem
- [ ] All code examples have language identifiers
- [ ] Good practices marked with ✅
- [ ] Bad practices marked with ❌
- [ ] Performance comparison table included
- [ ] Summary has numbered key points
- [ ] "Remember" statement is memorable
- [ ] No emoji overuse (only ✅ ❌ ⚠️)
- [ ] All code is syntactically correct
- [ ] Links to related articles (if any)
```java
// Bad// GoodSummary
- [Point 1] - [Explanation]
- [Point 2] - [Explanation]
Remember: [Takeaway]
---
## Quality Checklist
Before publishing, verify:
- [ ] Title is action-oriented and specific
- [ ] Filename follows naming conventions (lowercase, hyphens, descriptive)
- [ ] Introduction clearly states the problem
- [ ] All code examples have language identifiers
- [ ] Good practices marked with ✅
- [ ] Bad practices marked with ❌
- [ ] Performance comparison table included
- [ ] Summary has numbered key points
- [ ] "Remember" statement is memorable
- [ ] No emoji overuse (only ✅ ❌ ⚠️)
- [ ] All code is syntactically correct
- [ ] Links to related articles (if any)