Add documentation, PreCompact hook, gcal improvements, and marketplace

Documentation:
- Add commands/README.md documenting all slash commands
- Add skills/README.md documenting skill structure and patterns
- Add .claude-plugin/marketplace.json for local dev testing

Hooks:
- Add PreCompact hook to remind about context preservation
- Update hooks/README.md with new hook

GCal improvements:
- Add scripts/next_event.py for single event lookup
- Update SKILL.md with simplified format and allowed-tools: Read

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
OpenCode Test
2026-01-01 11:52:04 -08:00
parent 01dafbecf0
commit 97497b97c2
8 changed files with 331 additions and 69 deletions

View File

@@ -0,0 +1,18 @@
{
"name": "will-homelab-dev",
"description": "Development marketplace for will-homelab plugin",
"owner": {
"name": "Will"
},
"plugins": [
{
"name": "will-homelab",
"description": "Personal assistant and multi-agent system for homelab management",
"version": "1.0.0",
"source": "./",
"author": {
"name": "Will"
}
}
]
}

81
commands/README.md Normal file
View File

@@ -0,0 +1,81 @@
# Commands
Slash commands for quick actions. User-invoked (type `/command` to trigger).
## Available Commands
### Top-Level
| Command | Aliases | Description |
|---------|---------|-------------|
| `/pa` | `/assistant`, `/ask` | Personal assistant entrypoint |
| `/programmer` | | Code development tasks |
| `/gcal` | `/calendar`, `/cal` | Google Calendar access |
| `/usage` | `/stats` | View usage statistics |
### Kubernetes (`/k8s:*`)
| Command | Description |
|---------|-------------|
| `/k8s:cluster-status` | Quick cluster health overview |
| `/k8s:deploy` | Deploy applications to cluster |
| `/k8s:diagnose` | Diagnose Kubernetes issues |
### System Admin (`/sysadmin:*`)
| Command | Description |
|---------|-------------|
| `/sysadmin:health` | System health check |
| `/sysadmin:update` | System package updates |
| `/sysadmin:autonomy` | Set autonomy level for session |
## Command Format
```yaml
---
name: command-name
description: What this command does
aliases: [alias1, alias2]
invokes: skill:skill-name # or workflow: or agent:
---
# Command Title
Instructions for Claude when command is invoked.
```
## Command vs Skill
| Aspect | Command | Skill |
|--------|---------|-------|
| **Invocation** | User types `/command` | Claude decides automatically |
| **Discovery** | Explicit | Based on description matching |
| **Use case** | Quick actions, shortcuts | Domain expertise, workflows |
## Directory Structure
```
commands/
├── README.md
├── pa.md
├── gcal.md
├── usage.md
├── programmer.md
├── k8s/
│ ├── cluster-status.md
│ ├── deploy.md
│ └── diagnose.md
└── sysadmin/
├── health.md
├── update.md
└── autonomy.md
```
Namespaced commands use subdirectories (e.g., `k8s/deploy.md``/k8s:deploy`).
## Adding Commands
1. Create `commands/name.md` (or `commands/namespace/name.md`)
2. Add YAML frontmatter with name, description, invokes
3. Write instructions in Markdown body
4. Update `component-registry.json` if needed for routing

View File

@@ -7,6 +7,7 @@ Event handlers that run automatically during Claude Code sessions.
| Event | Script | Purpose |
|-------|--------|---------|
| `SessionStart` | `scripts/session-start.sh` | Load context, check for pending items |
| `PreCompact` | `scripts/pre-compact.sh` | Remind to preserve context before compaction |
## Hook Events

View File

@@ -9,6 +9,16 @@
}
]
}
],
"PreCompact": [
{
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/scripts/pre-compact.sh"
}
]
}
]
}
}

13
hooks/scripts/pre-compact.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/bash
# Pre-compact hook - saves context before compaction
# Output reminds Claude to summarize important context
set -euo pipefail
echo "PreCompact:Callback hook success: Success"
echo "PreCompact hook additional context: <EXTREMELY_IMPORTANT>"
echo "Context compaction is about to occur. Before compacting:"
echo "1. Note any pending tasks or decisions that need to be preserved"
echo "2. Summarize key context that should persist"
echo "3. If working on a multi-step task, note current progress"
echo "</EXTREMELY_IMPORTANT>"

105
skills/README.md Normal file
View File

@@ -0,0 +1,105 @@
# Skills
Agent skills that extend Claude's capabilities. Model-invoked (Claude decides when to use them).
## Available Skills
| Skill | Description | Scripts |
|-------|-------------|---------|
| `gmail` | Gmail read access | `check_unread.py`, `check_urgent.py`, `search.py` |
| `gcal` | Google Calendar access | `agenda.py`, `next_event.py` |
| `k8s-quick-status` | Kubernetes cluster health | `quick-status.sh` |
| `sysadmin-health` | Arch Linux health check | `health-check.sh` |
| `usage` | Session usage tracking | `usage_report.py` |
| `programmer-add-project` | Register projects | (workflow only) |
## Skill Structure
Each skill uses the "Resources Pattern":
```
skills/skill-name/
├── SKILL.md # Main instructions (required)
├── scripts/ # Executable helpers
│ ├── action1.py
│ └── action2.sh
└── references/ # Documentation
└── patterns.md
```
## Skill Format
```yaml
---
name: skill-name
description: What it does. Use when [trigger conditions].
allowed-tools:
- Bash
- Read
---
# Skill Name
## Quick Commands
```bash
./scripts/main-action.py [args]
```
## Request Routing
| User Request | Action |
|--------------|--------|
| "do X" | Run script with args |
## Policy
- Read-only / Write allowed
- Model tier preferences
```
## Key Elements
### Description
Critical for discovery. Include:
- What the skill does
- When Claude should use it (trigger phrases)
### allowed-tools
Restricts which tools Claude can use:
- `Bash` - Run commands/scripts
- `Read` - Read files
- `Write` - Write files
- `Edit` - Edit files
### Scripts
Standalone executables that do the work:
- Python: `#!/usr/bin/env python3`
- Bash: `#!/bin/bash`
- Must be executable: `chmod +x`
### References
Supporting documentation:
- Query patterns
- API reference
- Examples
## Adding a Skill
1. Create `skills/name/SKILL.md`
2. Add scripts to `skills/name/scripts/`
3. Make scripts executable
4. Update `component-registry.json` with triggers
5. Test: ask Claude something that should trigger it
## Skill vs Command
| Aspect | Skill | Command |
|--------|-------|---------|
| **Invocation** | Claude decides | User types `/command` |
| **Discovery** | Based on description | Explicit |
| **Use case** | Domain expertise | Quick actions |

View File

@@ -1,48 +1,59 @@
---
name: gcal
description: Google Calendar read access — agenda overview, event details, smart summaries
description: Google Calendar read access — agenda, events, schedule. Use when asked about calendar, meetings, schedule, or what's on today/tomorrow.
allowed-tools:
- Bash
- Read
---
# Google Calendar Skill
Access Google Calendar via Python API. Uses OAuth credentials at `~/.gmail-mcp/`.
## Command Routing
## Quick Commands
### 1. Exact Subcommand Match (priority)
```bash
GCAL_PY=~/.claude/mcp/gmail/venv/bin/python
SCRIPTS=~/.claude/skills/gcal/scripts
| Input | Action |
|-------|--------|
| `today` | Today's agenda |
| `tomorrow` | Tomorrow's agenda |
| `week` | Next 7 days, grouped by day |
| `next` | Next upcoming event only |
| `summary` | Sonnet-powered week analysis |
# Today's agenda
$GCAL_PY $SCRIPTS/agenda.py today
### 2. Natural Language Fallback
# Tomorrow's agenda
$GCAL_PY $SCRIPTS/agenda.py tomorrow
| Input | Routes To |
|-------|-----------|
| "what's on today", "today's meetings" | today |
| "this week", "next 7 days" | week |
| "next meeting", "what's next" | next |
| "am I busy tomorrow", "tomorrow's schedule" | tomorrow |
| "overview", "summarize my week" | summary |
# This week (7 days)
$GCAL_PY $SCRIPTS/agenda.py week
### 3. Smart Default (no args)
# Next event only
$GCAL_PY $SCRIPTS/next_event.py
```
## Script Reference
| Script | Purpose | Args |
|--------|---------|------|
| `agenda.py` | List events for time range | `today`, `tomorrow`, `week` |
| `next_event.py` | Next upcoming event | none |
## Request Routing
| User Request | Script | Args |
|--------------|--------|------|
| "What's on today?" | `agenda.py` | `today` |
| "Tomorrow's schedule" | `agenda.py` | `tomorrow` |
| "This week" | `agenda.py` | `week` |
| "Next meeting" | `next_event.py` | none |
| "Am I free at 3pm?" | `agenda.py` | `today` (then analyze) |
### Smart Default (no args)
- Before 6pm → today
- After 6pm → tomorrow
### 4. Ambiguous Input
## Delegation Helper (Advanced)
Ask for clarification rather than guess.
## Delegated Operations
Use the delegation helper for cost-efficient operations:
For LLM-assisted operations:
```bash
GCAL_PY=~/.claude/mcp/gmail/venv/bin/python
@@ -50,27 +61,13 @@ HELPER=~/.claude/mcp/delegation/gcal_delegate.py
# Haiku tier - fetch and format
$GCAL_PY $HELPER today
$GCAL_PY $HELPER tomorrow
$GCAL_PY $HELPER week
$GCAL_PY $HELPER next
# Sonnet tier - analyze (spawns claude --model sonnet)
$GCAL_PY $HELPER summary
```
## Delegation Tiers
| Subcommand | Tier | Reason |
|------------|------|--------|
| today, tomorrow, week, next | Haiku | Fetch + format only |
| summary | Sonnet | Requires understanding/analysis |
## Output Format
The helper returns JSON. Format for user as:
### Simple List (today/tomorrow/next)
```
📅 Today — Thursday, Jan 2
@@ -83,49 +80,25 @@ The helper returns JSON. Format for user as:
No more events today.
```
### Grouped by Day (week)
```
📅 This Week — Jan 2-8
━━━ Thursday, Jan 2 ━━━
9:00 AM Team standup (30m)
2:00 PM Project review (1h)
━━━ Friday, Jan 3 ━━━
11:00 AM Client call (1h)
```
### Context Fields (show when available)
### Context Fields
- 📍 Location or meeting link
- 👥 Attendee count
- 📝 Description snippet (first ~50 chars)
- 📝 Description snippet (if relevant)
## Error Handling
### Missing Calendar Scope
If helper reports scope error:
```
Calendar access not authorized. To fix:
1. Delete cached token: rm ~/.gmail-mcp/token.json
2. Run /gcal today to re-authenticate with Calendar scope
```
### No Events
```
📅 Today — Thursday, Jan 2
No events scheduled.
```
## Policy
- Read-only operations only
- Show context (attendees, location) by default
- Summarize results, don't dump raw data
- Start with lowest capable model tier
- Escalate only when task complexity requires
- **Read-only** operations only
- Show **context** (attendees, location) by default
- **Summarize** results, don't dump raw data
- Start with **lowest capable** model tier

View File

@@ -0,0 +1,61 @@
#!/usr/bin/env python3
"""Get the next upcoming calendar event."""
import os
from datetime import datetime
# Set credentials path
os.environ.setdefault('GMAIL_CREDENTIALS_PATH', os.path.expanduser('~/.gmail-mcp/credentials.json'))
from gmail_mcp.utils.GCP.gmail_auth import get_calendar_service
def format_event(event):
"""Format a single event for display."""
start = event['start'].get('dateTime', event['start'].get('date'))
if 'T' in start:
start_dt = datetime.fromisoformat(start.replace('Z', '+00:00'))
time_str = start_dt.strftime('%I:%M %p').lstrip('0')
date_str = start_dt.strftime('%A, %b %d')
else:
time_str = "All day"
date_str = start
summary = event.get('summary', '(No title)')
location = event.get('location', '')
print(f"📅 Next Event — {date_str}")
print()
print(f" {time_str} {summary}")
if location:
print(f" 📍 {location}")
# Show attendees if available
attendees = event.get('attendees', [])
if attendees:
print(f" 👥 {len(attendees)} attendees")
def main():
service = get_calendar_service()
now = datetime.utcnow().isoformat() + 'Z'
events_result = service.events().list(
calendarId='primary',
timeMin=now,
maxResults=1,
singleEvents=True,
orderBy='startTime'
).execute()
events = events_result.get('items', [])
if not events:
print("📅 No upcoming events")
return
format_event(events[0])
if __name__ == '__main__':
main()