diff --git a/mcp/delegation/README.md b/mcp/delegation/README.md
new file mode 100644
index 0000000..b28cd29
--- /dev/null
+++ b/mcp/delegation/README.md
@@ -0,0 +1,53 @@
+# Model Delegation Helper
+
+Spawns lower-tier Claude models via Claude CLI using your subscription.
+
+## Setup
+
+**No API key needed!** Uses Claude CLI with your existing subscription.
+
+Requirements:
+- Claude CLI at `/home/linuxbrew/.linuxbrew/bin/claude`
+- Active Claude subscription (Pro/Max)
+
+## Usage
+
+### Gmail operations (tiered)
+```bash
+PY=~/.claude/mcp/gmail/venv/bin/python
+HELPER=~/.claude/mcp/delegation/gmail_delegate.py
+
+# Haiku tier - just fetch and list (no LLM call)
+$PY $HELPER check-unread --days 7
+
+# Sonnet tier - fetch + summarize (uses claude CLI)
+$PY $HELPER summarize --query "from:github.com"
+
+# Sonnet tier - urgent triage (uses claude CLI)
+$PY $HELPER urgent
+```
+
+## Model Tiers
+
+| Tier | Model | LLM Call | Use For |
+|------|-------|----------|---------|
+| haiku | (none - just fetch) | No | List, count, group emails |
+| sonnet | claude --model sonnet | Yes | Summarize, categorize, triage |
+| opus | (PA direct) | N/A | Complex reasoning, prioritization |
+
+## How It Works
+
+1. **check-unread**: Fetches emails via Gmail API, groups by sender. No LLM needed.
+2. **summarize**: Fetches emails, then spawns `claude --print --model sonnet` to summarize.
+3. **urgent**: Fetches flagged emails, spawns Sonnet to triage by urgency.
+
+## Integration with PA
+
+The Personal Assistant (Opus) delegates gmail operations:
+
+| User Request | Delegation | Model Used |
+|--------------|------------|------------|
+| "Check my email" | `check-unread` | None (fetch only) |
+| "Summarize X emails" | `summarize` | Sonnet via CLI |
+| "What's urgent?" | `urgent` | Sonnet via CLI |
+| "What should I prioritize?" | (direct) | Opus (PA) |
diff --git a/mcp/delegation/gmail_delegate.py b/mcp/delegation/gmail_delegate.py
new file mode 100755
index 0000000..7fb3eca
--- /dev/null
+++ b/mcp/delegation/gmail_delegate.py
@@ -0,0 +1,286 @@
+#!/usr/bin/env python3
+"""
+Gmail Delegation Helper
+
+Fetches emails via Gmail API, then delegates summarization to appropriate model tier.
+
+Usage:
+ gmail_delegate.py check-unread [--days N]
+ gmail_delegate.py summarize --query "QUERY"
+ gmail_delegate.py urgent
+"""
+
+import sys
+import os
+import json
+import argparse
+import base64
+import re
+from collections import defaultdict
+from pathlib import Path
+
+# Set credentials path
+os.environ["GMAIL_CREDENTIALS_PATH"] = str(Path.home() / ".gmail-mcp" / "credentials.json")
+
+# Note: Run this script with ~/.claude/mcp/gmail/venv/bin/python
+from gmail_mcp.utils.GCP.gmail_auth import get_gmail_service
+import subprocess
+
+# Claude CLI path
+CLAUDE_CLI = "/home/linuxbrew/.linuxbrew/bin/claude"
+
+
+def delegate(model: str, system: str, prompt: str, max_tokens: int = 4096) -> dict:
+ """Delegate a task to Claude CLI using subscription."""
+ try:
+ # Build command
+ cmd = [
+ CLAUDE_CLI,
+ "--print",
+ "--model", model,
+ "--system-prompt", system,
+ "--output-format", "json",
+ prompt
+ ]
+
+ # Run claude CLI
+ result = subprocess.run(
+ cmd,
+ capture_output=True,
+ text=True,
+ timeout=120
+ )
+
+ if result.returncode != 0:
+ return {"error": f"Claude CLI error: {result.stderr}"}
+
+ # Parse JSON output
+ try:
+ output = json.loads(result.stdout)
+ # Extract text from the response
+ content = output.get("result", "")
+ return {
+ "success": True,
+ "model": model,
+ "content": content,
+ "usage": output.get("usage", {})
+ }
+ except json.JSONDecodeError:
+ # If not JSON, use raw text output
+ return {
+ "success": True,
+ "model": model,
+ "content": result.stdout.strip(),
+ "usage": {}
+ }
+
+ except subprocess.TimeoutExpired:
+ return {"error": "Claude CLI timed out"}
+ except FileNotFoundError:
+ return {"error": f"Claude CLI not found at {CLAUDE_CLI}"}
+ except Exception as e:
+ return {"error": f"Unexpected error: {e}"}
+
+
+def fetch_emails(query: str, max_results: int = 25) -> list[dict]:
+ """Fetch emails matching query, return metadata + snippets."""
+ service = get_gmail_service()
+ results = service.users().messages().list(
+ userId='me', q=query, maxResults=max_results
+ ).execute()
+
+ emails = []
+ for msg in results.get('messages', []):
+ detail = service.users().messages().get(
+ userId='me', id=msg['id'], format='metadata',
+ metadataHeaders=['From', 'Subject', 'Date']
+ ).execute()
+
+ headers = {h['name']: h['value'] for h in detail['payload']['headers']}
+ emails.append({
+ 'id': msg['id'],
+ 'from': headers.get('From', 'Unknown'),
+ 'subject': headers.get('Subject', '(no subject)'),
+ 'date': headers.get('Date', 'Unknown'),
+ 'snippet': detail.get('snippet', '')[:200]
+ })
+
+ return emails
+
+
+def fetch_email_body(msg_id: str) -> str:
+ """Fetch full email body for summarization."""
+ service = get_gmail_service()
+ detail = service.users().messages().get(
+ userId='me', id=msg_id, format='full'
+ ).execute()
+
+ payload = detail['payload']
+
+ def find_text(part):
+ if part.get('mimeType') == 'text/plain':
+ data = part['body'].get('data', '')
+ if data:
+ return base64.urlsafe_b64decode(data).decode('utf-8', errors='ignore')
+ if 'parts' in part:
+ for p in part['parts']:
+ result = find_text(p)
+ if result:
+ return result
+ return None
+
+ def find_html(part):
+ if part.get('mimeType') == 'text/html':
+ data = part['body'].get('data', '')
+ if data:
+ html = base64.urlsafe_b64decode(data).decode('utf-8', errors='ignore')
+ # Strip HTML tags
+ text = re.sub(r'', '', html, flags=re.DOTALL)
+ text = re.sub(r'', '', text, flags=re.DOTALL)
+ text = re.sub(r'<[^>]+>', ' ', text)
+ text = re.sub(r' ', ' ', text)
+ text = re.sub(r'&', '&', text)
+ text = re.sub(r'\s+', ' ', text)
+ return text.strip()
+ if 'parts' in part:
+ for p in part['parts']:
+ result = find_html(p)
+ if result:
+ return result
+ return None
+
+ text = find_text(payload) or find_html(payload) or detail.get('snippet', '')
+ return text[:3000] # Limit for context window
+
+
+def check_unread(days: int = 7) -> dict:
+ """Check unread emails - Haiku tier operation."""
+ query = f"is:unread newer_than:{days}d"
+ emails = fetch_emails(query)
+
+ # Group by sender (simple operation, no LLM needed)
+ by_sender = defaultdict(list)
+ for email in emails:
+ sender = email['from'].split('<')[0].strip().strip('"')
+ by_sender[sender].append(email['subject'][:50])
+
+ return {
+ "tier": "haiku",
+ "operation": "check_unread",
+ "total": len(emails),
+ "by_sender": dict(by_sender)
+ }
+
+
+def summarize_emails(query: str, max_results: int = 10) -> dict:
+ """Summarize emails matching query - Sonnet tier operation."""
+ emails = fetch_emails(query, max_results)
+
+ if not emails:
+ return {"tier": "sonnet", "operation": "summarize", "summary": "No emails found."}
+
+ # Build context for summarization
+ context = "Emails to summarize:\n\n"
+ for i, email in enumerate(emails, 1):
+ body = fetch_email_body(email['id'])
+ context += f"--- Email {i} ---\n"
+ context += f"From: {email['from']}\n"
+ context += f"Subject: {email['subject']}\n"
+ context += f"Date: {email['date']}\n"
+ context += f"Content: {body[:1000]}\n\n"
+
+ # Delegate to Sonnet for summarization
+ system = """You are an email summarization assistant. Provide concise, actionable summaries.
+Focus on: key points, action items, important dates, and who needs response.
+Format: Use bullet points, group by topic if multiple related emails."""
+
+ prompt = f"""Summarize these emails concisely:
+
+{context}
+
+Provide a brief summary highlighting what's important and any action items."""
+
+ result = delegate("sonnet", system, prompt, max_tokens=1024)
+
+ return {
+ "tier": "sonnet",
+ "operation": "summarize",
+ "email_count": len(emails),
+ "summary": result.get("content", result.get("error", "Failed to summarize")),
+ "usage": result.get("usage", {})
+ }
+
+
+def check_urgent() -> dict:
+ """Check for urgent emails - Haiku fetch + Sonnet analysis."""
+ query = 'is:unread newer_than:3d (subject:urgent OR subject:asap OR subject:"action required" OR is:important)'
+ emails = fetch_emails(query, max_results=15)
+
+ if not emails:
+ return {"tier": "haiku", "operation": "urgent", "message": "No urgent emails found."}
+
+ # For urgent, we want Sonnet to prioritize
+ context = "Potentially urgent emails:\n\n"
+ for email in emails:
+ context += f"- From: {email['from']}\n"
+ context += f" Subject: {email['subject']}\n"
+ context += f" Date: {email['date']}\n"
+ context += f" Preview: {email['snippet']}\n\n"
+
+ system = """You are an email triage assistant. Identify truly urgent items that need immediate attention.
+Distinguish between: actually urgent (needs response today), important (needs response soon), and FYI (can wait)."""
+
+ prompt = f"""Triage these flagged emails by urgency:
+
+{context}
+
+List any that are truly urgent first, then important, then FYI."""
+
+ result = delegate("sonnet", system, prompt, max_tokens=1024)
+
+ return {
+ "tier": "sonnet",
+ "operation": "urgent",
+ "email_count": len(emails),
+ "triage": result.get("content", result.get("error", "Failed to triage")),
+ "usage": result.get("usage", {})
+ }
+
+
+def main():
+ parser = argparse.ArgumentParser(description="Gmail operations with tiered delegation")
+ subparsers = parser.add_subparsers(dest="command", required=True)
+
+ # check-unread
+ unread = subparsers.add_parser("check-unread", help="List unread emails (Haiku tier)")
+ unread.add_argument("--days", "-d", type=int, default=7, help="Days to look back")
+
+ # summarize
+ summarize = subparsers.add_parser("summarize", help="Summarize emails (Sonnet tier)")
+ summarize.add_argument("--query", "-q", required=True, help="Gmail search query")
+ summarize.add_argument("--max", "-m", type=int, default=10, help="Max emails to summarize")
+
+ # urgent
+ subparsers.add_parser("urgent", help="Check urgent emails (Sonnet tier)")
+
+ args = parser.parse_args()
+
+ try:
+ if args.command == "check-unread":
+ result = check_unread(args.days)
+ elif args.command == "summarize":
+ result = summarize_emails(args.query, args.max)
+ elif args.command == "urgent":
+ result = check_urgent()
+ else:
+ result = {"error": f"Unknown command: {args.command}"}
+
+ print(json.dumps(result, indent=2))
+
+ except Exception as e:
+ print(json.dumps({"error": str(e)}))
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/skills/gmail/SKILL.md b/skills/gmail/SKILL.md
index 719eb0f..936140b 100644
--- a/skills/gmail/SKILL.md
+++ b/skills/gmail/SKILL.md
@@ -9,6 +9,34 @@ allowed-tools:
Access Gmail via direct Python API calls. Uses OAuth credentials at `~/.gmail-mcp/`.
+## Delegated Operations (Recommended)
+
+Use the tiered delegation helper for cost-efficient operations. Uses Claude CLI with your subscription (no API key needed):
+
+```bash
+GMAIL_PY=~/.claude/mcp/gmail/venv/bin/python
+HELPER=~/.claude/mcp/delegation/gmail_delegate.py
+
+# Haiku tier - list unread (no LLM call, just fetches)
+$GMAIL_PY $HELPER check-unread --days 7
+
+# Sonnet tier - summarize emails (spawns claude --model sonnet)
+$GMAIL_PY $HELPER summarize --query "from:github.com"
+
+# Sonnet tier - triage urgent (spawns claude --model sonnet)
+$GMAIL_PY $HELPER urgent
+```
+
+### When to Use Each Tier
+
+| Request Type | Command | Model |
+|--------------|---------|-------|
+| "Check my email" | `check-unread` | Haiku |
+| "How many unread?" | `check-unread` | Haiku |
+| "Summarize X" | `summarize --query "X"` | Sonnet |
+| "What's urgent?" | `urgent` | Sonnet |
+| "What should I prioritize?" | (PA direct) | Opus |
+
## Usage
For any Gmail request, use Bash to run the Python helper:
@@ -83,8 +111,37 @@ for msg in results.get('messages', []):
EOF
```
+## Model Selection
+
+Gmail operations use tiered delegation per `model-policy.json`:
+
+| Model | Use For | Examples |
+|-------|---------|----------|
+| **Haiku** | Fetch, count, list, simple search | "How many unread?", "List from X" |
+| **Sonnet** | Summarize, categorize, extract | "Summarize this email", "Group by topic" |
+| **Opus** | Prioritize, analyze, cross-reference | "What should I handle first?" |
+
+### Delegation Pattern
+
+When invoking gmail operations, the PA should:
+
+1. **Classify the request** — Is it fetch-only, summarization, or analysis?
+2. **Delegate appropriately**:
+ - Haiku: API calls + simple formatting
+ - Sonnet: API calls + content understanding
+ - Opus: Only for strategic reasoning
+3. **Escalate if needed** — If lower tier can't handle it, escalate
+
+### Implementation Note
+
+Until Task tool delegation is available, the PA executes gmail operations directly
+but should mentally "account" for which tier the work belongs to. This policy
+enables future cost optimization when subagent spawning is implemented.
+
## Policy
- Read-only operations only
- Summarize results (don't dump raw content)
- Report metadata, not full body unless asked
+- Start with lowest capable model tier
+- Escalate only when task complexity requires
diff --git a/state/future-considerations.json b/state/future-considerations.json
index 8418e1b..758bcc1 100644
--- a/state/future-considerations.json
+++ b/state/future-considerations.json
@@ -1 +1 @@
-{"version":"1.0.0","description":"Deferred features and decisions for future implementation","items":[{"id":"fc-001","category":"infrastructure","title":"Workstation monitoring with Prometheus","description":"Deploy node_exporter and Alertmanager for workstation metrics and alerting","priority":"medium","status":"deferred","created":"2024-12-28","notes":"Would enable proactive alerting for disk, memory, CPU issues"},{"id":"fc-002","category":"agent","title":"Network admin agent","description":"Agent for network configuration, firewall rules, VPN management","priority":"medium","status":"deferred","created":"2024-12-28","notes":"Would manage iptables/nftables, NetworkManager, WireGuard"},{"id":"fc-003","category":"agent","title":"Personal assistant agent","description":"Agent for personal tasks, reminders, scheduling","priority":"medium","status":"deferred","created":"2024-12-28","notes":"Integration with calendar, task management"},{"id":"fc-004","category":"integration","title":"External LLM integration","description":"Support for non-Claude models in the agent system","priority":"low","status":"deferred","created":"2024-12-28","notes":"For specialized tasks or cost optimization"},{"id":"fc-005","category":"optimization","title":"Model usage logging and cost tracking","description":"Track model usage across agents for cost analysis","priority":"medium","status":"deferred","created":"2024-12-28","notes":"Would help optimize model selection policy"},{"id":"fc-006","category":"design","title":"Slash commands redesign","description":"Revisit slash command architecture and user experience","priority":"low","status":"deferred","created":"2024-12-28","notes":"Current design may need refinement"},{"id":"fc-007","category":"optimization","title":"Document structure optimization","description":"Optimize agent document format for efficiency","priority":"low","status":"deferred","created":"2024-12-28","notes":"Balance between clarity and token usage"},{"id":"fc-008","category":"infrastructure","title":"ArgoCD CLI authentication","description":"Configure argocd CLI with proper authentication","priority":"medium","status":"resolved","created":"2025-12-28","resolved":"2025-12-28","notes":"Using 10-year API token (expires 2035-12-26). Token ID: e3980c6a-1c4e-4f1a-8459-a120a5c60cc5. Stored in ~/.config/argocd/config. No renewal automation needed."},{"id":"fc-009","category":"infrastructure","title":"Prometheus local port-forward","description":"Document Prometheus access patterns for agents","priority":"low","status":"identified","created":"2025-12-28","notes":"Prometheus not accessible on localhost:9090. Options: (1) use kubectl exec to query, (2) set up port-forward, (3) use ingress. Currently works via pod exec."},{"id":"fc-010","category":"infrastructure","title":"Clone homelab gitops repo locally","description":"Clone git@github.com:will666/homelab.git for git-operator access","priority":"low","status":"resolved","created":"2025-12-28","resolved":"2025-12-28","notes":"Cloned to ~/.claude/repos/homelab"},{"id":"fc-011","category":"k8s-health","title":"Address OutOfSync ArgoCD apps","description":"5 apps OutOfSync, 1 Degraded (porthole)","priority":"medium","status":"identified","created":"2025-12-28","notes":"OutOfSync: adopt-a-street, ai-stack, gitea, home-assistant, kubernetes-dashboard, speetest-tracker. Degraded: porthole"},{"id":"fc-012","category":"agent-memory","title":"PA knowledge base with session caching","description":"Local KB for infrastructure facts with lazy-load and in-session caching","priority":"medium","status":"resolved","created":"2025-12-28","resolved":"2025-12-28","notes":"Implemented. KB files at state/kb.json (shared) and state/personal-assistant/kb.json (private). PA agent updated with lazy-load behavior."},{"id":"fc-013","category":"agent-memory","title":"Vector database for agent long-term memory","description":"Semantic search over agent knowledge using embeddings","priority":"low","status":"deferred","created":"2025-12-28","notes":"Would enable fuzzy matching, semantic queries, and scalable knowledge storage. Consider: ChromaDB, Qdrant, or pgvector."},{"id":"fc-014","category":"observability","title":"Grafana predefined reports","description":"Slash command like /grafana-report services to get standard metrics from known dashboards","priority":"low","status":"deferred","created":"2025-12-29","notes":"Requires comprehensive dashboard coverage first. Revisit when observability matures."},{"id":"fc-015","category":"observability","title":"Grafana integration in diagnostics","description":"Auto-pull Grafana dashboard data during /k8s:diagnose or health checks","priority":"low","status":"deferred","created":"2025-12-29","notes":"Would make Grafana the first troubleshooting tool. Depends on fc-016 and mature observability setup."},{"id":"fc-016","category":"observability","title":"Extend prometheus-analyst with Grafana API","description":"Add Grafana API query capability to existing prometheus-analyst agent","priority":"low","status":"deferred","created":"2025-12-29","notes":"Preferred approach over creating new agent/skill. Natural extension when dashboards are comprehensive. Prerequisite for fc-014 and fc-015."}]}
+{"version":"1.0.0","description":"Deferred features and decisions for future implementation","items":[{"id":"fc-001","category":"infrastructure","title":"Workstation monitoring with Prometheus","description":"Deploy node_exporter and Alertmanager for workstation metrics and alerting","priority":"medium","status":"deferred","created":"2024-12-28","notes":"Would enable proactive alerting for disk, memory, CPU issues"},{"id":"fc-002","category":"agent","title":"Network admin agent","description":"Agent for network configuration, firewall rules, VPN management","priority":"medium","status":"deferred","created":"2024-12-28","notes":"Would manage iptables/nftables, NetworkManager, WireGuard"},{"id":"fc-003","category":"agent","title":"Personal assistant agent","description":"Agent for personal tasks, reminders, scheduling","priority":"medium","status":"deferred","created":"2024-12-28","notes":"Integration with calendar, task management"},{"id":"fc-004","category":"integration","title":"External LLM integration","description":"Support for non-Claude models in the agent system","priority":"low","status":"deferred","created":"2024-12-28","notes":"For specialized tasks or cost optimization"},{"id":"fc-005","category":"optimization","title":"Model usage logging and cost tracking","description":"Track model usage across agents for cost analysis","priority":"medium","status":"deferred","created":"2024-12-28","notes":"Would help optimize model selection policy"},{"id":"fc-006","category":"design","title":"Slash commands redesign","description":"Revisit slash command architecture and user experience","priority":"low","status":"deferred","created":"2024-12-28","notes":"Current design may need refinement"},{"id":"fc-007","category":"optimization","title":"Document structure optimization","description":"Optimize agent document format for efficiency","priority":"low","status":"deferred","created":"2024-12-28","notes":"Balance between clarity and token usage"},{"id":"fc-008","category":"infrastructure","title":"ArgoCD CLI authentication","description":"Configure argocd CLI with proper authentication","priority":"medium","status":"resolved","created":"2025-12-28","resolved":"2025-12-28","notes":"Using 10-year API token (expires 2035-12-26). Token ID: e3980c6a-1c4e-4f1a-8459-a120a5c60cc5. Stored in ~/.config/argocd/config. No renewal automation needed."},{"id":"fc-009","category":"infrastructure","title":"Prometheus local port-forward","description":"Document Prometheus access patterns for agents","priority":"low","status":"identified","created":"2025-12-28","notes":"Prometheus not accessible on localhost:9090. Options: (1) use kubectl exec to query, (2) set up port-forward, (3) use ingress. Currently works via pod exec."},{"id":"fc-010","category":"infrastructure","title":"Clone homelab gitops repo locally","description":"Clone git@github.com:will666/homelab.git for git-operator access","priority":"low","status":"resolved","created":"2025-12-28","resolved":"2025-12-28","notes":"Cloned to ~/.claude/repos/homelab"},{"id":"fc-011","category":"k8s-health","title":"Address OutOfSync ArgoCD apps","description":"5 apps OutOfSync, 1 Degraded (porthole)","priority":"medium","status":"identified","created":"2025-12-28","notes":"OutOfSync: adopt-a-street, ai-stack, gitea, home-assistant, kubernetes-dashboard, speetest-tracker. Degraded: porthole"},{"id":"fc-012","category":"agent-memory","title":"PA knowledge base with session caching","description":"Local KB for infrastructure facts with lazy-load and in-session caching","priority":"medium","status":"resolved","created":"2025-12-28","resolved":"2025-12-28","notes":"Implemented. KB files at state/kb.json (shared) and state/personal-assistant/kb.json (private). PA agent updated with lazy-load behavior."},{"id":"fc-013","category":"agent-memory","title":"Vector database for agent long-term memory","description":"Semantic search over agent knowledge using embeddings","priority":"low","status":"deferred","created":"2025-12-28","notes":"Would enable fuzzy matching, semantic queries, and scalable knowledge storage. Consider: ChromaDB, Qdrant, or pgvector."},{"id":"fc-014","category":"observability","title":"Grafana predefined reports","description":"Slash command like /grafana-report services to get standard metrics from known dashboards","priority":"low","status":"deferred","created":"2025-12-29","notes":"Requires comprehensive dashboard coverage first. Revisit when observability matures."},{"id":"fc-015","category":"observability","title":"Grafana integration in diagnostics","description":"Auto-pull Grafana dashboard data during /k8s:diagnose or health checks","priority":"low","status":"deferred","created":"2025-12-29","notes":"Would make Grafana the first troubleshooting tool. Depends on fc-016 and mature observability setup."},{"id":"fc-016","category":"observability","title":"Extend prometheus-analyst with Grafana API","description":"Add Grafana API query capability to existing prometheus-analyst agent","priority":"low","status":"deferred","created":"2025-12-29","notes":"Preferred approach over creating new agent/skill. Natural extension when dashboards are comprehensive. Prerequisite for fc-014 and fc-015."},{"id":"fc-017","category":"optimization","title":"Subagent spawning for skill delegation","description":"Implement Task tool or similar mechanism to spawn lower-tier models for specific operations","priority":"medium","status":"resolved","created":"2025-12-31","resolved":"2025-12-31","notes":"Implemented via Claude CLI subprocess. Helper at ~/.claude/mcp/delegation/gmail_delegate.py. Uses tiered delegation: fetch/list (no LLM), Sonnet for summarize/triage (via 'claude --print --model sonnet'). Uses subscription, no API key needed."}]}
diff --git a/state/model-policy.json b/state/model-policy.json
index c6014a6..bfb5e3b 100644
--- a/state/model-policy.json
+++ b/state/model-policy.json
@@ -64,5 +64,54 @@
"default_start": "lowest_capable",
"log_usage": true,
"review_frequency": "weekly"
+ },
+ "skill_delegation": {
+ "gmail": {
+ "description": "Tiered model selection for email operations",
+ "tiers": {
+ "haiku": {
+ "operations": [
+ "count_unread",
+ "list_emails",
+ "fetch_metadata",
+ "simple_search"
+ ],
+ "examples": [
+ "How many unread emails?",
+ "List emails from sender X",
+ "Any emails with attachments?"
+ ]
+ },
+ "sonnet": {
+ "operations": [
+ "summarize_email",
+ "summarize_thread",
+ "categorize_emails",
+ "extract_action_items",
+ "group_by_topic"
+ ],
+ "examples": [
+ "Summarize this email",
+ "What are the OpenAgents notifications about?",
+ "Group my emails by project"
+ ]
+ },
+ "opus": {
+ "operations": [
+ "prioritize_inbox",
+ "strategic_analysis",
+ "cross_reference_context",
+ "complex_reasoning"
+ ],
+ "examples": [
+ "What should I respond to first?",
+ "How does this relate to my current projects?",
+ "What's the sentiment across these threads?"
+ ]
+ }
+ },
+ "default": "haiku",
+ "escalate_on": ["insufficient_context", "reasoning_required", "user_dissatisfied"]
+ }
}
}