Skills now require -skill suffix for org-wide discoverability (teams search *-skill to find all skills). Suites use -suite suffix. Post-creation sharing flow: agent detects gh/glab CLI, creates repo, adds agent-skill topic, gives shareable one-liner for Slack/Teams. Supports GitHub, GitLab, Enterprise, and self-hosted instances. Updated validate.py to warn on missing -skill suffix and error on deprecated -cskill suffix. Updated architecture-guide.md naming section to match. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
34 KiB
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)
---
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.jsonis a Claude Code-specific plugin manifest, not part of the standard- Simple skills activate via their SKILL.md
descriptionfield alone - Adding
marketplace.jsonto 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 withoutmarketplace.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.
{
"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 nameplugins(array): List of plugin entries
Allowed fields per plugin entry:
name(string): Component skill namedescription(string): What the component doessource(string): Relative path to the component's SKILL.mdskills(array of strings): Skill identifiers
Forbidden fields (non-standard, will cause validation failure):
version-- usemetadata.versionin SKILL.md insteadauthor-- usemetadata.authorin SKILL.md insteadrepository-- not part of the official schematags-- 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.mdwith 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
namefield 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: analyzercsv-data-cleaner-skill-- domain: csv-data, objective: cleanersales-report-skill-- domain: sales, objective: reportdeploy-checklist-skill-- domain: deploy, objective: checklistfinancial-suite-- complex suite (uses-suite, not-skill)
Guidelines:
- Must end with
-skill(or-suitefor multi-skill suites) - Be descriptive but concise — aim for under 30 characters
- Include the primary domain for discoverability
- Avoid generic names like
my-skillortool-1
4.4 Naming Validation
A valid name passes all of these checks:
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:
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:
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:
{
"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-cacheflag or a function).
6.4 Error Handling Strategy
Every script must handle errors gracefully:
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:
- API client code →
shared/api_client.py - Common data models →
shared/models.py - Utility functions (date handling, formatting) →
shared/utils.py - 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:
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/tosys.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:
# /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:
- Shared data files: Component A writes to
data/sales_summary.json, Component B reads it - Shared API client: Both components use the same
shared/api_client.pyto fetch data - 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:
| 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:
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
-cskillsuffix - 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.shincludedREADME.mdplanned with multi-platform install instructions- No
marketplace.jsonfor 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)