소스 정보
- 저장소
- artofrawr/claude-control
- 최근 소스 활동
- 2026년 4월 9일 21:38
- 감지된 SKILL.md 언어
- 영어
- 스타
- 1
- 포크
- 0
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/artofrawr/claude-control --skill site-architecture명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | site-architecture |
| description | Technical SEO - robots.txt, sitemap, meta tags, Core Web Vitals |
| disable-model-invocation | false |
Load with: base.md + web-content.md
For technical website structure that enables discovery by search engines AND AI crawlers (GPTBot, ClaudeBot, PerplexityBot).
Content is king. Architecture is the kingdom.
Great content buried in poor architecture won't be discovered. This skill covers the technical foundation that makes your content findable by:
# robots.txt
# Allow all crawlers by default
User-agent: *
Allow: /
Disallow: /api/
Disallow: /admin/
Disallow: /private/
Disallow: /_next/
Disallow: /cdn-cgi/
# Sitemap location
Sitemap: https://yoursite.com/sitemap.xml
# Crawl delay (optional - be careful, not all bots respect this)
# Crawl-delay: 1
# robots.txt with AI bot rules
# === SEARCH ENGINES ===
User-agent: Googlebot
Allow: /
User-agent: Bingbot
Allow: /
# === AI ASSISTANTS (Allow for discovery) ===
User-agent: GPTBot
Allow: /
User-agent: ChatGPT-User
Allow: /
User-agent: Claude-Web
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: Amazonbot
Allow: /
User-agent: anthropic-ai
Allow: /
User-agent: Google-Extended
Allow: /
# === BLOCK AI TRAINING (Optional - block training, allow chat) ===
# Uncomment these if you want to be cited but not used for training
# User-agent: CCBot
# Disallow: /
# User-agent: GPTBot
# Disallow: / # Blocks both chat and training
# === BLOCK SCRAPERS ===
User-agent: AhrefsBot
Disallow: /
User-agent: SemrushBot
Disallow: /
User-agent: MJ12bot
Disallow: /
# === DEFAULT ===
User-agent: *
Allow: /
Disallow: /api/
Disallow: /admin/
Disallow: /auth/
Disallow: /private/
Disallow: /*.json$
Disallow: /*?*
Sitemap: https://yoursite.com/sitemap.xml
// app/robots.ts
import { MetadataRoute } from 'next';
export default function robots(): MetadataRoute.Robots {
const baseUrl = process.env.NEXT_PUBLIC_URL || 'https://yoursite.com';
return {
rules: [
{
userAgent: '*',
allow: '/',
disallow: ['/api/', '/admin/', '/private/', '/_next/'],
},
{
userAgent: 'GPTBot',
allow: '/',
},
{
userAgent: 'ClaudeBot',
allow: '/',
},
{
userAgent: 'PerplexityBot',
allow: '/',
},
],
sitemap: `${baseUrl}/sitemap.xml`,
};
}
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
<url>
<loc>https://yoursite.com/</loc>
<lastmod>2025-01-15</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://yoursite.com/pricing</loc>
<lastmod>2025-01-10</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://yoursite.com/blog/article-slug</loc>
<lastmod>2025-01-12
monthly
0.8
https://yoursite.com/images/article-image.jpg
// app/sitemap.ts
import { MetadataRoute } from 'next';
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = process.env.NEXT_PUBLIC_URL || 'https://yoursite.com';
// Static pages
const staticPages = [
{ url: '/', priority: 1.0, changeFrequency: 'weekly' as const },
{ url: '/pricing', priority: 0.9, changeFrequency: 'monthly' as const },
{ url: '/about', priority: 0.8, changeFrequency: 'monthly' as const },
{ url: '/contact', priority: 0.7, changeFrequency: 'yearly' as const },
];
// Dynamic pages (e.g., blog posts)
const posts = ();
blogPages = posts.( ({
: ,
: (post.),
: ,
: ,
}));
[
...staticPages.( ({
: ,
: (),
: page.,
: page.,
})),
...blogPages.( ({
: ,
: page.,
: page.,
: page.,
})),
];
}
<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>https://yoursite.com/sitemap-pages.xml</loc>
<lastmod>2025-01-15</lastmod>
</sitemap>
<sitemap>
<loc>https://yoursite.com/sitemap-blog.xml</loc>
<lastmod>2025-01-14</lastmod>
</sitemap>
<sitemap>
<loc>https://yoursite.com/sitemap-products.xml</loc>
<lastmod>2025-01-13</lastmod>
</sitemap>
</sitemapindex>
<head>
<!-- Basic -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Page Title | Brand Name</title>
<meta name="description" content="Compelling 150-160 character description with keywords and CTA.">
<!-- Canonical (prevent duplicate content) -->
<link rel="canonical" href="https://yoursite.com/current-page">
<!-- Language -->
<html lang="en">
<meta name="language" content="English">
<!-- Robots -->
<meta name="robots" content="index, follow">
<meta name="googlebot" content="index, follow">
<!-- Author -->
<meta name="author" =>
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://yoursite.com/page">
<meta property="og:title" content="Page Title - Brand">
<meta property="og:description" content="Description for social sharing (can be longer).">
<meta property="og:image" content="https://yoursite.com/og-image.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:site_name" content="Brand Name">
<meta property="og:locale" content="en_US">
<!-- Article-specific (for blog posts) -->
<meta property= =>
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@yourbrand">
<meta name="twitter:creator" content="@authorhandle">
<meta name="twitter:title" content="Page Title">
<meta name="twitter:description" content="Description for Twitter (max 200 chars).">
<meta name="twitter:image" content="https://yoursite.com/twitter-image.jpg">
// app/layout.tsx
import { Metadata } from 'next';
export const metadata: Metadata = {
metadataBase: new URL('https://yoursite.com'),
title: {
default: 'Brand Name',
template: '%s | Brand Name',
},
description: 'Your default site description.',
keywords: ['keyword1', 'keyword2', 'keyword3'],
authors: [{ name: 'Brand Name', url: 'https://yoursite.com' }],
creator: 'Brand Name',
publisher: 'Brand Name',
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
},
openGraph: {
type: 'website',
locale: ,
: ,
: ,
: ,
: ,
: [
{
: ,
: ,
: ,
: ,
},
],
},
: {
: ,
: ,
: ,
},
: {
: ,
: ,
},
};
(): <> {
post = (params.);
{
: post.,
: post.,
: {
: post.,
: post.,
: ,
: post.,
: post.,
: [post..],
: [post.],
},
};
}
✅ GOOD URLs:
/blog/ai-seo-best-practices
/products/pro-plan
/pricing
/about/team
❌ BAD URLs:
/blog?id=123
/p/12345
/index.php?page=about
/Products/Pro_Plan (inconsistent casing)
| Rule | Example |
|---|---|
| Lowercase only | /blog/my-post not /Blog/My-Post |
| Hyphens not underscores | /my-page not /my_page |
| No trailing slashes | /about not /about/ |
| Descriptive slugs | /pricing not /p |
| No query params for content | /blog/post-title not /blog?id=123 |
| Max 3-4 levels deep | /blog/category/post |
// next.config.js
module.exports = {
async redirects() {
return [
// Redirect old URLs to new
{
source: '/old-page',
destination: '/new-page',
permanent: true, // 301 redirect
},
// Redirect with wildcard
{
source: '/blog/old/:slug',
destination: '/articles/:slug',
permanent: true,
},
// Trailing slash redirect
{
source: '/:path+/',
destination: '/:path+',
permanent: true,
},
];
},
};
<!-- Always include canonical, even for primary URL -->
<link rel="canonical" href="https://yoursite.com/current-page">
✅ USE CANONICAL:
- Every page (even if only version exists)
- Paginated content (point to page 1 or use rel=prev/next)
- URL parameters that don't change content (?utm_source=...)
- HTTP vs HTTPS (canonical to HTTPS)
- www vs non-www (pick one, canonical to it)
Example: /products?sort=price should canonical to /products
// Automatic in metadata
export const metadata: Metadata = {
alternates: {
canonical: '/current-page',
},
};
// next.config.js
const securityHeaders = [
{
key: 'X-DNS-Prefetch-Control',
value: 'on',
},
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload',
},
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN',
},
{
key: 'X-Content-Type-Options',
value: 'nosniff',
},
{
key: 'Referrer-Policy',
value: 'strict-origin-when-cross-origin',
},
{
key: 'Permissions-Policy',
value: 'camera=(), microphone=(), geolocation=()',
},
];
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: securityHeaders,
},
];
},
};
| Metric | Good | Needs Improvement | Poor |
|---|---|---|---|
| LCP (Largest Contentful Paint) | ≤2.5s | ≤4.0s | >4.0s |
| INP (Interaction to Next Paint) | ≤200ms | ≤500ms | >500ms |
| CLS (Cumulative Layout Shift) | ≤0.1 | ≤0.25 | >0.25 |
## LCP (Loading)
- [ ] Optimize largest image (WebP, proper sizing)
- [ ] Preload critical assets
- [ ] Use CDN for static assets
- [ ] Enable compression (gzip/brotli)
- [ ] Minimize render-blocking resources
## INP (Interactivity)
- [ ] Minimize JavaScript execution time
- [ ] Break up long tasks
- [ ] Use web workers for heavy computation
- [ ] Optimize event handlers
- [ ] Lazy load non-critical JS
## CLS (Visual Stability)
- [ ] Set dimensions on images/videos
- [ ] Reserve space for dynamic content
- [ ] Avoid inserting content above existing
- [ ] Use transform for animations
- [ ] Preload fonts
// Image optimization
import Image from 'next/image';
<Image
src="/hero.jpg"
alt="Hero image"
width={1200}
height={630}
priority // Preload for LCP
placeholder="blur"
blurDataURL={blurDataUrl}
/>
// Font optimization
import { Inter } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
display: 'swap', // Prevent FOIT
});
// Dynamic imports
import dynamic from 'next/dynamic';
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
loading: () => <Skeleton />,
ssr: false, // Client-only if needed
});
## Link Architecture
Homepage
├── /pricing (1 click)
├── /features (1 click)
├── /blog (1 click)
│ ├── /blog/category-1 (2 clicks)
│ │ └── /blog/category-1/post (3 clicks)
│ └── /blog/category-2 (2 clicks)
└── /about (1 click)
Rule: Every page within 3 clicks of homepage
✅ DO:
- Use descriptive anchor text
- Link contextually within content
- Create hub pages for topics
- Link to related content at end of posts
- Use breadcrumbs for navigation
❌ AVOID:
- "Click here" as anchor text
- Orphan pages (no internal links)
- Too many links per page (>100)
- Broken internal links
- Redirect chains
// components/Breadcrumbs.tsx
import Link from 'next/link';
interface BreadcrumbItem {
name: string;
href: string;
}
export function Breadcrumbs({ items }: { items: BreadcrumbItem[] }) {
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: `https://yoursite.com${item.href}`,
})),
};
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<nav aria-label="Breadcrumb">
<ol className="flex gap-2">
{items.map((item, index) => (
{index > 0 && /}
{item.name}
))}
);
}
| Bot | User Agent | Purpose |
|---|---|---|
| GPTBot | GPTBot | ChatGPT web browsing |
| ChatGPT-User | ChatGPT-User | ChatGPT user browsing |
| ClaudeBot | ClaudeBot | Claude web access |
| Claude-Web | Claude-Web | Claude web features |
| PerplexityBot | PerplexityBot | Perplexity search |
| Google-Extended | Google-Extended | Gemini/Bard training |
| Amazonbot | Amazonbot | Alexa/Amazon AI |
| CCBot | CCBot | Common Crawl (AI training) |
# robots.txt
# Allow GPTBot for ChatGPT browsing
User-agent: GPTBot
Allow: /
# Block CCBot (used for training datasets)
User-agent: CCBot
Disallow: /
# Block Google AI training, allow search
User-agent: Google-Extended
Disallow: /
<!-- Block AI training but allow indexing -->
<meta name="robots" content="index, follow, max-image-preview:large">
<!-- Opt out of AI training (proposed standard) -->
<meta name="ai-training" content="disallow">
<!-- Option 1: In <head> with JSON-LD (recommended) -->
<head>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Your Company"
}
</script>
</head>
<!-- Option 2: Before closing </body> -->
<body>
<!-- Page content -->
<script type="application/ld+json">
{ "@context": "https://schema.org", ... }
</script>
</body>
<head>
<!-- Organization (site-wide) -->
<script type="application/ld+json">
{ "@context": "https://schema.org", "@type": "Organization", ... }
</script>
<!-- BreadcrumbList (navigation) -->
<script type="application/ld+json">
{ "@context": "https://schema.org", "@type": "BreadcrumbList", ... }
</script>
<!-- Article (page-specific) -->
<script type="application/ld+json">
{ "@context": "https://schema.org", "@type": "Article", ... }
</script>
<!-- FAQPage (if FAQ section exists) -->
<script type="application/ld+json">
{ "@context": "https://schema.org", "@type": "FAQPage", ... }
</script>
</head>
project/
├── public/
│ ├── robots.txt # Or generate dynamically
│ ├── sitemap.xml # Or generate dynamically
│ ├── favicon.ico
│ ├── icon.svg
│ ├── apple-touch-icon.png
│ ├── og-image.jpg # Default OG image (1200x630)
│ └── manifest.webmanifest
├── app/
│ ├── layout.tsx # Global metadata
│ ├── robots.ts # Dynamic robots.txt
│ ├── sitemap.ts # Dynamic sitemap
│ └── [page]/
│ └── page.tsx # Page-specific metadata
├── components/
│ ├── SchemaMarkup.tsx
│ ├── Breadcrumbs.tsx
│ └── MetaTags.tsx
└── lib/
├── schema.ts # Schema generators
└── seo.ts # SEO utilities
# Verify ownership methods
1. HTML file upload (google*.html to public/)
2. Meta tag (add to <head>)
3. DNS TXT record
4. Google Analytics (if already installed)
1. Google Search Console
- Sitemaps → Add new sitemap → yoursite.com/sitemap.xml
2. Bing Webmaster Tools
- Sitemaps → Submit sitemap
3. Yandex Webmaster (if relevant)
- Indexing → Sitemap files
## Technical SEO Checklist
### robots.txt
- [ ] Allow search engines
- [ ] Allow AI bots (GPTBot, ClaudeBot, PerplexityBot)
- [ ] Block admin/private areas
- [ ] Include sitemap reference
- [ ] Test with Google's robots.txt tester
### Sitemap
- [ ] Include all indexable pages
- [ ] Exclude noindex pages
- [ ] Include lastmod dates
- [ ] Submit to Search Console
- [ ] Auto-update on content changes
### Meta Tags
- [ ] Unique title per page (50-60 chars)
- [ ] Unique description per page (150-160 chars)
- [ ] Canonical URL on every page
- [ ] Open Graph tags
- [ ] Twitter Card tags
### URL Structure
- [ ] Lowercase, hyphenated
- [ ] Descriptive slugs
- [ ] No query params for content
- [ ] 301 redirects for moved content
- [ ] No broken links
### Performance
- [ ] LCP < 2.5s
- [ ] INP < 200ms
- [ ] CLS < 0.1
- [ ] HTTPS enabled
- [ ] Security headers configured
### Structured Data
- [ ] Organization schema (homepage)
- [ ] BreadcrumbList (all pages)
- [ ] Article schema (blog posts)
- [ ] FAQ schema (FAQ sections)
- [ ] Validate with Rich Results Test
public/
├── robots.txt ✓ Required
├── sitemap.xml ✓ Required
├── favicon.ico ✓ Required
├── og-image.jpg ✓ Required (1200x630)
└── manifest.json ○ Recommended
| Tag | Length |
|---|---|
| Title | 50-60 characters |
| Description | 150-160 characters |
| OG Title | 60-90 characters |
| OG Description | 200 characters |
| Twitter Description | 200 characters |
| Image | Dimensions |
|---|---|
| OG Image | 1200 x 630 |
| Twitter Image | 1200 x 628 |
| Favicon | 32 x 32 |
| Apple Touch Icon | 180 x 180 |