# Architecture Decision Guide

**Version:** 4.0
**Purpose:** Comprehensive guide for choosing the right architecture when creating agent skills, including directory structures, naming conventions, sizing patterns, and performance strategies.

---

## 1. Architecture Decision Framework

Before creating any skill, determine whether it should be a **Simple Skill** or a **Complex Suite**. This decision drives the entire directory structure, file organization, and whether a `marketplace.json` is needed.

### 1.1 Decision Criteria

| Factor | Simple Skill | Complex Suite |
|--------|-------------|---------------|
| **Number of workflows** | 1-2 related workflows | 3+ distinct workflows |
| **Code complexity** | <1000 lines total | >2000 lines total |
| **SKILL.md files** | 1 | Multiple (one per component) |
| **Maintenance scope** | Single developer | Team or multi-concern |
| **Domain breadth** | Single domain focus | Spans multiple sub-domains |
| **Deployment** | Install as one unit | Components may be used independently |
| **marketplace.json** | **Not needed** | Optional (official fields only) |

### 1.2 Decision Flowchart

Follow this logic sequentially:

```
START
  |
  v
How many distinct workflows does this skill address?
  |
  +-- 1-2 workflows --> Does the total code exceed 2000 lines?
  |                       |
  |                       +-- No  --> SIMPLE SKILL
  |                       +-- Yes --> Can it be split into independent sub-skills?
  |                                     |
  |                                     +-- No  --> SIMPLE SKILL (large)
  |                                     +-- Yes --> COMPLEX SUITE
  |
  +-- 3+ workflows --> Are the workflows tightly coupled?
                        |
                        +-- Yes (shared state/data) --> SIMPLE SKILL (organized)
                        +-- No  (independent concerns) --> COMPLEX SUITE
```

### 1.3 Decision Examples

| User Request | Decision | Rationale |
|-------------|----------|-----------|
| "Analyze stock prices with technical indicators" | Simple Skill | Single domain, 1-2 workflows (fetch + analyze) |
| "Format markdown tables" | Simple Skill | Single workflow, <500 lines |
| "Full-stack web dev with frontend, backend, deployment" | Complex Suite | 3 independent sub-domains |
| "USDA agriculture data with 6 analysis types" | Simple Skill (organized) | Multiple analyses but single domain, shared data pipeline |
| "Financial suite: stock analysis, portfolio tracking, tax reporting" | Complex Suite | 3 distinct workflows, each usable independently |

---

## 2. Simple Skill Structure

A Simple Skill is a single, self-contained agent skill that follows the Agent Skills Open Standard. It has one SKILL.md file and no `marketplace.json`.

### 2.1 Standard Directory Layout

```
skill-name/
├── SKILL.md          # <500 lines, spec-compliant frontmatter
├── scripts/          # Functional Python code
├── references/       # Detailed documentation (loaded on demand)
├── assets/           # Templates, schemas, data files
├── install.sh        # Cross-platform auto-detect installer
└── README.md         # Multi-platform installation instructions
```

**Key rule:** NO `.claude-plugin/marketplace.json` for simple skills. The SKILL.md file is the sole manifest and activation mechanism.

### 2.2 SKILL.md Frontmatter (Required)

```yaml
---
name: skill-name            # 1-64 chars, lowercase + hyphens, must match directory
description: >-             # 1-1024 chars, activation keywords included
  Description with domain keywords for agent discovery...
license: MIT                # or appropriate license
metadata:
  author: Author Name
  version: 1.0.0
compatibility: >-           # optional, use when platform-specific features exist
  Works on all platforms supporting the SKILL.md standard.
---
```

### 2.3 File Responsibilities

| File/Directory | Purpose | Required? |
|---------------|---------|-----------|
| `SKILL.md` | Primary skill definition, frontmatter, instructions | Yes |
| `scripts/` | Executable Python code (functional, no placeholders) | Yes (if skill has code) |
| `references/` | Detailed documentation, API guides, methodology docs | Recommended |
| `assets/` | Configuration files, templates, schemas, static data | Optional |
| `install.sh` | Cross-platform installer script | Yes |
| `README.md` | Installation instructions for 5+ platforms | Yes |

### 2.4 Why No marketplace.json for Simple Skills

Per the Agent Skills Open Standard and FR-005:

- SKILL.md is the universal discovery mechanism across all 26+ platforms
- `marketplace.json` is a Claude Code-specific plugin manifest, not part of the standard
- Simple skills activate via their SKILL.md `description` field alone
- Adding `marketplace.json` to a simple skill creates a non-standard structure that may confuse other platforms
- Skills placed in `~/.claude/skills/` or `.claude/skills/` are discovered automatically by Claude Code without `marketplace.json`

---

## 3. Complex Suite Structure

A Complex Suite bundles multiple related but independently usable skills under a single parent directory. It optionally includes a `marketplace.json` for Claude Code plugin registration.

### 3.1 Standard Directory Layout

```
suite-name/
├── .claude-plugin/
│   └── marketplace.json    # ONLY official fields (see below)
├── component-1/
│   ├── SKILL.md            # Independent skill definition
│   ├── scripts/
│   └── references/
├── component-2/
│   ├── SKILL.md            # Independent skill definition
│   ├── scripts/
│   └── references/
├── shared/                 # Shared utilities, data, config
│   ├── utils.py
│   └── config.json
├── install.sh              # Installs all components
└── README.md               # Suite-level documentation
```

### 3.2 marketplace.json Schema (Official Fields Only)

When a Complex Suite includes a `marketplace.json`, it must contain **only** the official Claude Code fields. No custom or non-standard fields are permitted.

```json
{
  "name": "suite-name",
  "plugins": [
    {
      "name": "component-1",
      "description": "What component-1 does",
      "source": "component-1/SKILL.md",
      "skills": ["component-1"]
    },
    {
      "name": "component-2",
      "description": "What component-2 does",
      "source": "component-2/SKILL.md",
      "skills": ["component-2"]
    }
  ]
}
```

**Allowed top-level fields:**
- `name` (string): The suite name
- `plugins` (array): List of plugin entries

**Allowed fields per plugin entry:**
- `name` (string): Component skill name
- `description` (string): What the component does
- `source` (string): Relative path to the component's SKILL.md
- `skills` (array of strings): Skill identifiers

**Forbidden fields** (non-standard, will cause validation failure):
- `version` -- use `metadata.version` in SKILL.md instead
- `author` -- use `metadata.author` in SKILL.md instead
- `repository` -- not part of the official schema
- `tags` -- not part of the official schema
- Any other custom fields

### 3.3 When to Use marketplace.json

| Scenario | Include marketplace.json? |
|----------|--------------------------|
| Simple skill (1 SKILL.md) | No |
| Complex suite for Claude Code distribution | Yes (optional) |
| Complex suite targeting only non-Claude platforms | No |
| Suite where components must be independently discoverable in Claude Code | Yes |

### 3.4 Component Independence

Each component in a Complex Suite should be independently functional:

- Each component has its own `SKILL.md` with valid frontmatter
- Each component can be installed separately if extracted from the suite
- Shared resources in `shared/` are optional enhancements, not hard dependencies
- Each component's `name` field matches its directory name

---

## 4. Naming Convention

All skill and suite names follow standard kebab-case per the Agent Skills Open Standard.

### 4.1 Rules

| Rule | Requirement |
|------|-------------|
| Length | 1-64 characters |
| Characters | Lowercase letters (`a-z`), numbers (`0-9`), hyphens (`-`) |
| Format | kebab-case |
| First character | Must be a letter or number (not a hyphen) |
| Last character | Must be a letter or number (not a hyphen) |
| Consecutive hyphens | Not allowed (`my--skill` is invalid) |
| Directory match | The `name` field in SKILL.md frontmatter must exactly match the parent directory name |

### 4.2 The -skill Suffix

Every generated skill name **must end with `-skill`**. This suffix makes skills instantly discoverable across GitHub and GitLab organizations — teams can search `*-skill` and find every skill in their org.

**Suites** use the `-suite` suffix instead (e.g., `financial-suite`). Suites contain skills but are not themselves invoked as skills.

The previous `-cskill` suffix convention is **deprecated**. If encountered, replace with `-skill`.

### 4.3 Naming Pattern

```
{domain}-{objective}-skill
```

**Examples:**
- `stock-analyzer-skill` -- domain: stock, objective: analyzer
- `csv-data-cleaner-skill` -- domain: csv-data, objective: cleaner
- `sales-report-skill` -- domain: sales, objective: report
- `deploy-checklist-skill` -- domain: deploy, objective: checklist
- `financial-suite` -- complex suite (uses `-suite`, not `-skill`)

**Guidelines:**
- Must end with `-skill` (or `-suite` for multi-skill suites)
- Be descriptive but concise — aim for under 30 characters
- Include the primary domain for discoverability
- Avoid generic names like `my-skill` or `tool-1`

### 4.4 Naming Validation

A valid name passes all of these checks:

```python
import re

def validate_skill_name(name: str) -> tuple[bool, list[str]]:
    errors = []
    if not name:
        errors.append("Name is required")
    if len(name) > 64:
        errors.append(f"Name exceeds 64 chars ({len(name)})")
    if name != name.lower():
        errors.append("Name must be lowercase")
    if not re.match(r'^[a-z0-9][a-z0-9-]*[a-z0-9]$', name) and len(name) > 1:
        errors.append("Name must start/end with letter or number, contain only a-z, 0-9, hyphens")
    if '--' in name:
        errors.append("Consecutive hyphens not allowed")
    if name.endswith('-cskill'):
        errors.append("The -cskill suffix is deprecated; use -skill instead")
    if not name.endswith('-skill') and not name.endswith('-suite'):
        errors.append("Name must end with '-skill' (or '-suite' for multi-skill suites)")
    return (len(errors) == 0, errors)
```

---

## 5. Directory Sizing Patterns

Choose a sizing pattern based on the skill's complexity. These patterns apply to both Simple Skills and individual components within a Complex Suite.

### 5.1 Small Agent Pattern

**When to use:** Single workflow, 1-2 scripts, <500 total lines of code.

```
skill-name/
├── SKILL.md              # <200 lines
├── scripts/
│   └── main.py           # 200-400 lines, single entry point
├── references/
│   └── guide.md          # API docs, methodology
├── assets/
│   └── config.json       # Minimal configuration
├── install.sh
└── README.md
```

**Characteristics:**
- One main script handles the entire workflow
- Minimal configuration
- Single reference document
- Estimated total: 500-800 lines across all files

**Examples:** markdown-table-formatter, url-shortener, json-validator

### 5.2 Medium Agent Pattern

**When to use:** 2-3 workflows, 3-5 scripts, 500-2000 total lines of code.

```
skill-name/
├── SKILL.md              # 200-400 lines
├── scripts/
│   ├── fetch.py          # Data acquisition (200-300 lines)
│   ├── parse.py          # Data processing (150-200 lines)
│   ├── analyze.py        # Analysis logic (300-500 lines)
│   └── utils/
│       ├── cache.py      # Cache management (100-150 lines)
│       └── validators.py # Input validation (100-150 lines)
├── references/
│   ├── api-guide.md      # ~1500 words
│   └── methodology.md    # ~2000 words
├── assets/
│   └── config.json
├── install.sh
└── README.md
```

**Characteristics:**
- Separation of concerns: fetch, parse, analyze
- Utility modules for cross-cutting concerns (caching, validation)
- Multiple reference documents
- Estimated total: 1000-2500 lines across all files

**Examples:** stock-analyzer, weather-dashboard, csv-data-cleaner

### 5.3 Large Agent Pattern

**When to use:** 3+ workflows within a single domain, 6+ scripts, 2000+ total lines of code. Still a Simple Skill if all workflows share a single domain and data pipeline.

```
skill-name/
├── SKILL.md              # 400-500 lines (at the limit)
├── scripts/
│   ├── core/
│   │   ├── fetch_source_a.py    # 200-300 lines
│   │   ├── fetch_source_b.py    # 200-300 lines
│   │   ├── parse_source_a.py    # 150-200 lines
│   │   ├── parse_source_b.py    # 150-200 lines
│   │   └── analyze.py           # 400-600 lines
│   ├── models/
│   │   ├── forecasting.py       # 200-300 lines
│   │   └── ml_models.py         # 200-300 lines
│   └── utils/
│       ├── cache_manager.py     # 100-150 lines
│       ├── rate_limiter.py      # 100-150 lines
│       └── validators.py        # 100-150 lines
├── references/
│   ├── api/
│   │   ├── source-a-guide.md
│   │   └── source-b-guide.md
│   ├── methods/
│   │   └── analysis-methods.md
│   └── troubleshooting.md
├── assets/
│   ├── config.json
│   └── metadata.json
├── install.sh
└── README.md
```

**Characteristics:**
- Sub-directories within `scripts/` for organization (core, models, utils)
- Multiple data sources with dedicated fetch/parse scripts
- Dedicated models directory for analysis/ML logic
- Organized reference documentation
- Estimated total: 2500-5000 lines across all files

**Examples:** nass-usda-agriculture, conab-crop-yield-analysis, noaa-climate-analysis

### 5.4 Sizing Comparison Table

| Aspect | Small | Medium | Large |
|--------|-------|--------|-------|
| Total code lines | <500 | 500-2000 | 2000+ |
| Script files | 1 | 3-5 | 6+ |
| Script sub-dirs | None | `utils/` | `core/`, `models/`, `utils/` |
| Reference files | 1 | 2-3 | 4+ (may use sub-dirs) |
| Asset files | 0-1 | 1 | 2+ |
| SKILL.md length | <200 lines | 200-400 lines | 400-500 lines |
| Typical domains | Formatters, validators | Data analyzers, dashboards | Multi-source analysis, forecasting |

---

## 6. Performance Strategy

All generated skills should incorporate performance considerations appropriate to their size and use case.

### 6.1 Caching Strategy

Cache API responses and computed results to avoid redundant work and reduce API usage.

**Cache TTL Decision Logic:**

| Data Type | TTL | Rationale |
|-----------|-----|-----------|
| Historical data (past years) | 365 days (effectively permanent) | Historical data does not change |
| Current-year data | 7 days | May be revised/updated |
| Metadata (lists, enums) | 365 days | Rarely changes |
| Real-time data | 1-60 minutes | Freshness required |
| User preferences | Session-scoped | Per-execution only |

**Implementation Pattern:**

```python
import json
import hashlib
from pathlib import Path
from datetime import datetime, timedelta

class FileCache:
    """Simple file-based cache with TTL support."""

    def __init__(self, cache_dir: str = "data/cache"):
        self.cache_dir = Path(cache_dir)
        self.cache_dir.mkdir(parents=True, exist_ok=True)

    def _key_path(self, key: str) -> Path:
        hashed = hashlib.sha256(key.encode()).hexdigest()[:16]
        return self.cache_dir / f"{hashed}.json"

    def get(self, key: str, ttl: timedelta) -> dict | None:
        path = self._key_path(key)
        if not path.exists():
            return None
        data = json.loads(path.read_text())
        cached_at = datetime.fromisoformat(data["cached_at"])
        if datetime.now() - cached_at > ttl:
            return None  # Expired
        return data["value"]

    def set(self, key: str, value: dict) -> None:
        path = self._key_path(key)
        path.write_text(json.dumps({
            "cached_at": datetime.now().isoformat(),
            "value": value
        }, indent=2))

    def get_or_fetch(self, key: str, ttl: timedelta, fetch_fn) -> dict:
        cached = self.get(key, ttl)
        if cached is not None:
            return cached
        value = fetch_fn()
        self.set(key, value)
        return value
```

**Cache Location:** Store cache files under `data/cache/` within the skill directory. This keeps cache local and avoids polluting system directories.

**Graceful Degradation:** If the cache file is corrupted or unreadable, log a warning and proceed without cache (fetch fresh data).

### 6.2 Rate Limiting Strategy

Protect against API rate limit exhaustion with proactive tracking.

**Rate Limiter Pattern:**

```python
import json
from pathlib import Path
from datetime import datetime, timedelta

class RateLimiter:
    """File-based rate limiter with persistent counter."""

    def __init__(
        self,
        max_requests: int,
        period: timedelta,
        counter_file: str = "data/cache/rate_limit.json"
    ):
        self.max_requests = max_requests
        self.period = period
        self.counter_file = Path(counter_file)
        self.counter_file.parent.mkdir(parents=True, exist_ok=True)

    def _load(self) -> dict:
        if not self.counter_file.exists():
            return {"requests": [], "period_start": datetime.now().isoformat()}
        return json.loads(self.counter_file.read_text())

    def _save(self, data: dict) -> None:
        self.counter_file.write_text(json.dumps(data, indent=2))

    def _prune_old(self, data: dict) -> dict:
        cutoff = (datetime.now() - self.period).isoformat()
        data["requests"] = [r for r in data["requests"] if r > cutoff]
        return data

    def allow_request(self) -> bool:
        data = self._prune_old(self._load())
        count = len(data["requests"])
        if count >= self.max_requests:
            return False
        if count > self.max_requests * 0.9:
            remaining = self.max_requests - count
            print(f"WARNING: Rate limit nearly reached ({count}/{self.max_requests}), {remaining} requests remaining")
        return True

    def record_request(self) -> None:
        data = self._prune_old(self._load())
        data["requests"].append(datetime.now().isoformat())
        self._save(data)
```

**Rate Limit Configuration:** Define rate limits in `assets/config.json` so they can be adjusted without code changes:

```json
{
  "rate_limit": {
    "max_requests_per_day": 1000,
    "warn_threshold_percent": 90
  }
}
```

### 6.3 Optimization Techniques

**For Small Agents:**
- Keep it simple. A single script with basic caching is sufficient.
- Avoid premature optimization.

**For Medium Agents:**
- File-based caching for API responses.
- Rate limiter for external APIs.
- Lazy loading of reference data (only load when a specific analysis is requested).

**For Large Agents:**
- All Medium optimizations, plus:
- Batch API requests where the API supports it.
- Parallel processing for independent data sources (use `concurrent.futures`).
- Tiered caching: in-memory for hot data, file-based for cold data.
- Progress reporting for long-running operations.

**General Rules:**
- Never make the same API call twice in a single execution -- always check cache first.
- Use exponential backoff for transient API failures (start at 1 second, max 3 retries).
- Log all API calls with timestamps for debugging rate limit issues.
- Keep cached data in `data/cache/` and provide a way to clear it (`--clear-cache` flag or a function).

### 6.4 Error Handling Strategy

Every script must handle errors gracefully:

```python
import sys
from pathlib import Path

def safe_api_call(url: str, params: dict, retries: int = 3) -> dict:
    """Make an API call with retry logic and graceful error handling."""
    import urllib.request
    import urllib.error
    import json
    import time

    for attempt in range(retries):
        try:
            query = "&".join(f"{k}={v}" for k, v in params.items())
            full_url = f"{url}?{query}" if params else url
            req = urllib.request.Request(full_url)
            with urllib.request.urlopen(req, timeout=30) as response:
                return json.loads(response.read().decode())
        except urllib.error.HTTPError as e:
            if e.code == 429:  # Rate limited
                wait = 2 ** attempt
                print(f"Rate limited. Retrying in {wait}s...")
                time.sleep(wait)
            elif e.code >= 500:  # Server error
                wait = 2 ** attempt
                print(f"Server error ({e.code}). Retrying in {wait}s...")
                time.sleep(wait)
            else:
                print(f"HTTP error {e.code}: {e.reason}")
                return {"error": str(e), "code": e.code}
        except urllib.error.URLError as e:
            print(f"Network error: {e.reason}")
            if attempt < retries - 1:
                time.sleep(2 ** attempt)
            else:
                return {"error": f"Network error after {retries} attempts: {e.reason}"}
        except Exception as e:
            return {"error": f"Unexpected error: {str(e)}"}

    return {"error": f"Failed after {retries} retries"}
```

### 6.5 SKILL.md Size Management

The SKILL.md body must stay under 500 lines. Use progressive disclosure:

| Content Type | Where It Goes |
|-------------|---------------|
| Activation triggers, overview, core workflow | `SKILL.md` body (required) |
| API documentation, endpoint details | `references/api-guide.md` |
| Analysis methodology, formulas | `references/methodology.md` |
| Troubleshooting, FAQs | `references/troubleshooting.md` |
| Domain context, terminology | `references/domain-context.md` |
| Configuration schema documentation | `references/config-guide.md` |

Reference content from SKILL.md using `See references/filename.md for details.` directives. The agent will load referenced files on demand, reducing initial context consumption.

---

## 7. When to Refactor a Growing Skill

Skills evolve. A simple skill that started at 500 lines can grow to 5000+ as the team adds analyses, data sources, and edge case handling. Recognize the signs early and refactor before the skill becomes unmaintainable.

### 7.1 Signs It's Time to Refactor

| Signal | What It Means |
|--------|--------------|
| SKILL.md approaching 500 lines | Body is stuffed — move content to references |
| Total code exceeding 3000 lines | Single-domain skill is becoming unwieldy |
| 3+ unrelated workflows emerging | The skill is doing too many different jobs |
| Different people maintaining different parts | Ownership boundaries need to be explicit |
| Users invoking the skill for fundamentally different tasks | The skill should be split into focused components |
| New data sources that don't share the existing pipeline | Independent fetch/parse/analyze chains = independent skills |

### 7.2 Refactoring Patterns

**Pattern 1: Extract to References (lightest touch)**

When the skill body is too long but the code is fine:

```
Before: SKILL.md at 480 lines with inline methodology docs
After:  SKILL.md at 250 lines, references/methodology.md with the detail
```

This is not a structural refactor — just progressive disclosure. Do this first.

**Pattern 2: Extract Utility Module**

When multiple scripts duplicate logic:

```
Before: fetch.py has cache logic, analyze.py has cache logic
After:  utils/cache.py extracted, both scripts import from it
```

**Pattern 3: Split by Domain (simple → suite)**

When the skill covers multiple independent domains:

```
Before:
  financial-analyzer/
    scripts/
      stock_analysis.py      # 800 lines
      portfolio_tracking.py   # 600 lines
      tax_reporting.py        # 500 lines

After:
  financial-suite/
    skills/
      stock-analyzer/         # Independent skill
      portfolio-tracker/      # Independent skill
      tax-reporter/           # Independent skill
    shared/
      market_data_client.py   # Shared API connection
```

**Pattern 4: Extract Shared Resources**

When converting to a suite, identify code that multiple components need:

1. API client code → `shared/api_client.py`
2. Common data models → `shared/models.py`
3. Utility functions (date handling, formatting) → `shared/utils.py`
4. Configuration → `shared/config.json`

### 7.3 Refactoring Decision Process

```
Is SKILL.md > 400 lines?
  → Yes: Extract to references (Pattern 1)
  → Still growing?
      ↓
Is total code > 3000 lines with 3+ unrelated workflows?
  → Yes: Split into suite (Pattern 3)
  → No, but code is duplicated across scripts?
      → Extract utilities (Pattern 2)
  → No: Keep as large simple skill — not everything needs to be a suite
```

**Critical rule**: Do not split prematurely. Three similar scripts in one domain is better than a suite with three trivially small components. Only split when the workflows are genuinely independent — different data sources, different users, different maintenance cadences.

### 7.4 Refactoring Checklist

- [ ] Identified which pattern applies (1-4)
- [ ] Each new component is independently functional
- [ ] Shared resources extracted to `shared/` (not duplicated)
- [ ] All SKILL.md files are <500 lines
- [ ] All component names follow kebab-case naming
- [ ] install.sh updated to handle new structure
- [ ] README.md updated with new structure
- [ ] Validation passes on all components

---

## 8. Cross-Component Communication in Suites

When a suite has multiple component skills, they need clear patterns for sharing code, data, and orchestration.

### 8.1 The shared/ Directory

The `shared/` directory contains code that multiple components use. It is **not** a component skill — it has no SKILL.md and is never invoked directly.

```
suite-name/
├── shared/
│   ├── api_client.py       # Shared API connection + authentication
│   ├── models.py           # Shared data classes and type definitions
│   ├── utils.py            # Common utilities (date formatting, etc.)
│   └── config.json         # Shared configuration
├── skills/
│   ├── component-a/
│   │   ├── SKILL.md
│   │   └── scripts/
│   │       └── analyze.py  # imports from ../../shared/api_client.py
│   └── component-b/
│       ├── SKILL.md
│       └── scripts/
│           └── report.py   # imports from ../../shared/api_client.py
```

### 8.2 Import Patterns

Components import from `shared/` using path manipulation:

```python
import sys
from pathlib import Path

# Add shared/ to path
_SUITE_ROOT = Path(__file__).resolve().parent.parent.parent
_SHARED_DIR = _SUITE_ROOT / "shared"
if str(_SHARED_DIR) not in sys.path:
    sys.path.insert(0, str(_SHARED_DIR))

from api_client import SuiteAPIClient
from utils import format_date, parse_currency
```

**Rules:**
- Always use `Path(__file__).resolve()` for reliable path resolution
- Add `shared/` to `sys.path` — do not copy files into each component
- Import specific names, not `from shared import *`
- Each component must still work if `shared/` provides enhanced functionality but is not strictly required (graceful degradation)

### 8.3 Orchestration: Suite-Level SKILL.md

The suite-level SKILL.md is the router. When a user's query could match multiple components, the suite SKILL.md tells the agent how to decide:

```markdown
# /ecommerce-suite — E-commerce Intelligence

You are an e-commerce analytics coordinator. Route user queries
to the right component skill based on intent:

## Routing Logic

| User Intent | Route To | Example Queries |
|-------------|----------|-----------------|
| Revenue, orders, conversion | /sales-monitor | "What were last week's sales?" |
| Segments, cohorts, churn | /customer-analytics | "Show customer retention by cohort" |
| Stock levels, reorder | /inventory-tracker | "Which products need reordering?" |
| Executive summary, dashboard | /executive-reports | "Generate the weekly executive report" |

## Cross-Component Workflows

Some requests require multiple components:

### Full Store Report
When the user asks for a "full report" or "store overview":
1. Invoke /sales-monitor for revenue summary
2. Invoke /customer-analytics for retention metrics
3. Invoke /inventory-tracker for stock alerts
4. Invoke /executive-reports to compile everything into a single report

### Churn Impact Analysis
When the user asks about churn's revenue impact:
1. Invoke /customer-analytics for churn rate and segments
2. Invoke /sales-monitor for revenue by customer segment
3. Combine: revenue at risk = churned segment revenue × churn rate
```

### 8.4 Data Flow Between Components

Components do not call each other's functions directly. Instead, they communicate through:

1. **Shared data files**: Component A writes to `data/sales_summary.json`, Component B reads it
2. **Shared API client**: Both components use the same `shared/api_client.py` to fetch data
3. **Agent orchestration**: The agent (LLM) reads output from Component A and passes relevant parts to Component B

**Anti-patterns to avoid:**
- Component A importing Component B's scripts directly (creates tight coupling)
- Components writing to each other's directories
- Circular dependencies between components

### 8.5 Component Independence Rule

Each component must be independently functional. This means:

- A component extracted from the suite and installed alone must still work
- `shared/` utilities enhance performance (avoid duplicate API calls, consistent formatting) but are not hard requirements
- If a component absolutely requires `shared/`, document this in its README.md
- The suite-level install.sh must install `shared/` alongside all components

---

## 9. Versioning Strategy

### 9.1 Semver for Skills

Skills follow [Semantic Versioning](https://semver.org/):

| Change Type | Version Bump | Examples |
|------------|-------------|---------|
| **Patch** (x.y.Z) | Bug fixes, typo corrections, minor doc improvements | Fix API timeout handling, correct calculation formula |
| **Minor** (x.Y.0) | New analyses, new data sources, new output formats | Add trend analysis, support CSV export, add new API endpoint |
| **Major** (X.0.0) | Breaking changes to inputs, outputs, or invocation | Change script arguments, rename skill, restructure output format |

### 9.2 What Counts as Breaking

A change is breaking if existing users of the skill would get different behavior or errors:

| Breaking | Not Breaking |
|----------|-------------|
| Changing script CLI arguments | Adding new optional arguments |
| Changing output JSON structure | Adding new fields to output |
| Removing an analysis function | Adding new analysis functions |
| Renaming the skill | Updating the description keywords |
| Changing required environment variables | Adding optional environment variables |

### 9.3 Suite Versioning

Suite versions are independent of component versions:

```
ecommerce-suite/        version: 2.0.0  (added new component)
├── sales-monitor/      version: 1.3.0  (3 minor updates since suite v1)
├── customer-analytics/  version: 1.1.0  (1 minor update)
├── inventory-tracker/   version: 2.0.0  (breaking change in its own output)
└── executive-reports/   version: 1.0.0  (unchanged)
```

**Suite version bump rules:**

| Change | Suite Version Bump |
|--------|--------------------|
| Bug fix in one component | No suite bump (component patch only) |
| New capability in one component | No suite bump (component minor only) |
| Breaking change in one component | Suite minor bump (warn users) |
| Add new component to suite | Suite minor bump |
| Remove component from suite | Suite major bump |
| Restructure shared/ | Suite major bump |

### 9.4 Version in Practice

The version lives in SKILL.md frontmatter:

```yaml
metadata:
  version: 1.2.0
```

When publishing to the registry, `skill_registry.py` reads this version. Publishing the same name+version is rejected unless `--force` is used.

**When to create a new skill vs. version an existing one:**

| Situation | Action |
|-----------|--------|
| Same domain, improved implementation | Version bump (minor or major) |
| Same domain, fundamentally different approach | New skill (e.g., `stock-analyzer-v2`) |
| Different domain entirely | New skill |
| Extending to cover adjacent domain | If tightly coupled: version bump. If independent: new skill or convert to suite |

---

## 10. Architecture Checklist

Use this checklist before proceeding to implementation (Phase 5):

### Decision

- [ ] Determined Simple Skill vs Complex Suite
- [ ] Justified the decision based on workflow count, code size, and domain scope
- [ ] If suite: identified shared resources and component boundaries
- [ ] If suite: designed orchestration logic (routing, cross-component workflows)

### Naming

- [ ] Name is 1-64 characters, kebab-case
- [ ] Name matches the parent directory
- [ ] No `-cskill` suffix
- [ ] Name is descriptive and includes the primary domain
- [ ] If suite: all component names are unique and follow kebab-case

### Structure

- [ ] Directory layout matches the chosen sizing pattern (Small/Medium/Large)
- [ ] SKILL.md planned at <500 lines
- [ ] Scripts have clear separation of concerns
- [ ] References planned for detailed content
- [ ] `install.sh` included
- [ ] `README.md` planned with multi-platform install instructions
- [ ] No `marketplace.json` for Simple Skills
- [ ] If Complex Suite with `marketplace.json`, only official fields used
- [ ] If suite: shared/ directory planned with import patterns documented
- [ ] If suite: each component is independently functional

### Performance

- [ ] Cache strategy defined (what to cache, TTL for each data type)
- [ ] Rate limiting planned for external APIs
- [ ] Error handling approach defined (retries, backoff, fallbacks)
- [ ] SKILL.md size managed via progressive disclosure to `references/`

### Dependencies

- [ ] Dependency strategy decided (stdlib-only vs. third-party)
- [ ] requirements.txt planned if third-party packages needed
- [ ] No unnecessary heavy dependencies

### Versioning

- [ ] Initial version set (1.0.0)
- [ ] Version bump rules understood (patch/minor/major)
- [ ] If suite: component versions independent of suite version

### Documentation

- [ ] Architecture decisions documented
- [ ] Script responsibilities defined (input, output, line count estimate)
- [ ] Reference files planned (topic, estimated word count)
- [ ] Asset files planned (config structure, metadata)
