用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/Tzeusy/butlers --skill data-organizer命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| name | data-organizer |
| description | Structured patterns for organizing collections and items in the General butler's freeform data store |
| trigger_patterns | ["organize my data","set up collections","how should I structure","clean up my items","merge duplicates","archive old data"] |
This skill provides structured patterns, conventions, and workflows for organizing freeform data in the General butler's JSONB-based item store.
The General butler stores arbitrary JSON items in named collections. Use this skill when you need to:
Collections organize items by domain or purpose. Follow these patterns for consistency:
projects, reading-list)bookmark, not bookmarks)work-project, personal-project)web-dev not web--devproject-alpha not 2026-projectpersonal-note # Personal journal entries
work-task # Work-related tasks
learning-resource # Educational materials
bookmark # Web links and references
recipe # Cooking recipes
contact # People and contact info
project # Projects and initiatives
inbox # Unsorted incoming items
active-project # Currently active projects
archive # Historical records
Start simple with top-level collections (project, note, bookmark). Add domain prefixes only when you have overlapping types across domains.
Items are freeform JSONB, but consistency helps with querying and maintenance. Here are proven templates:
Track initiatives, goals, or multi-step endeavors.
{
"title": "Build AI Agent Framework",
"status": "active",
"priority": "high",
"description": "A framework for long-running AI butlers with MCP integration",
"goals": [
"Core infrastructure complete",
"Three working butlers deployed"
],
"milestones": [
{
"name": "v1 MVP",
"due": "2026-03-01",
"status": "in_progress"
}
],
"tags": ["ai", "framework", "mcp"],
"started_at": "2026-01-15"
Key fields:
title (required): Human-readable namestatus (required): Enum-like value (active, paused, completed, archived)priority: low | medium | high | criticaltags: Array of strings for filteringstarted_at, updated_at, completed_atSave web links, articles, resources, and references.
{
"url": "https://example.com/article",
"title": "Effective AI Agent Patterns",
"description": "Deep dive into agent architecture for production systems",
"tags": ["ai", "architecture", "reference"],
"category": "technical",
"added_at": "2026-02-09",
"read": false,
"rating": null,
"notes": "Referenced in project design docs"
}
Key fields:
url (required): The linktitle (required): Page title or custom labeltags: Array for multi-dimensional categorizationcategory: Primary classification (technical, personal, news, etc.)read: Boolean flag for trackingrating: Numeric score (1-5) or nullCapture thoughts, journal entries, meeting notes, or observations.
{
"title": "Daily Standup - Feb 9",
"content": "Completed the General butler data store tools. Next: create skills for common workflows.",
"note_type": "journal",
"tags": ["standup", "progress"],
"created_at": "2026-02-09T10:00:00Z",
"related_items": [
"uuid-of-related-project"
],
"private": false
}
Key fields:
title: Optional subject linecontent (required): Main text body (markdown supported)note_type: journal | meeting | idea | reference | taskrelated_items: Array of UUIDs linking to other itemsprivate: Boolean for visibility controlOrganize items into ordered or unordered collections (shopping, reading queue, etc.).
{
"title": "2026 Reading List",
"description": "Technical books to read this year",
"list_type": "reading_queue",
"items": [
{
"title": "Designing Data-Intensive Applications",
"author": "Martin Kleppmann",
"status": "reading",
"priority": 1
},
{
"title": "The Pragmatic Programmer",
"author": "Hunt & Thomas",
"status": "pending",
"priority": 2
}
],
"tags": [
Key fields:
title (required): List namelist_type: reading_queue | shopping | todo | watchlist | generalitems (required): Array of structured items (each item can have custom fields)tags: For categorizationStore cooking recipes with ingredients and instructions.
{
"title": "Sourdough Bread",
"cuisine": "French",
"prep_time_minutes": 30,
"cook_time_minutes": 45,
"servings": 8,
"difficulty": "intermediate",
"ingredients": [
{"item": "bread flour", "amount": "500g"},
{"item": "sourdough starter", "amount": "100g"},
{"item": "water", "amount": "350ml"},
{
Key fields:
title (required): Recipe namecuisine: Type or originingredients (required): Array of objects with item and amountinstructions (required): Ordered array of stepstags: For discoveryrating: 1-5 scaleStore people, organizations, or contact information.
{
"name": "Jane Smith",
"contact_type": "professional",
"email": "jane@example.com",
"phone": "+1-555-0123",
"company": "Acme Corp",
"role": "Engineering Manager",
"tags": ["colleague", "engineering", "networking"],
"notes": "Met at conference 2025, working on similar AI projects",
"last_contact": "2026-01-15",
"social": {
"linkedin": "https://linkedin.com/in/janesmith",
"github": "https://github.com/janesmith"
}
}
Key fields:
name (required): Full name or organizationcontact_type: personal | professional | businessemail, phone: Primary contact methodstags: For grouping and filteringlast_contact: ISO date of last interactionThe General butler uses PostgreSQL's JSONB containment operator (@>) with a GIN index for efficient querying.
Find items with specific top-level fields:
# Find all active projects
await item_search(
pool,
collection_name="project",
query={"status": "active"}
)
# Find high-priority items
await item_search(
pool,
collection_name="project",
query={"priority": "high"}
)
Query nested objects using path notation:
# Find projects with specific milestone status
await item_search(
pool,
collection_name="project",
query={
"milestones": [
{"status": "in_progress"}
]
}
)
Note: JSONB containment requires exact substructure match. The query {"milestones": [{"status": "in_progress"}]} matches items where milestones contains at least one object with status: "in_progress", but it also requires other fields in that milestone object to match if present in the query.
Tags are arrays, so use array containment:
# Find items tagged with "ai"
await item_search(
pool,
collection_name="bookmark",
query={"tags": ["ai"]}
)
# Find items with multiple tags (AND logic via containment)
# This finds items where tags array contains BOTH "ai" AND "reference"
await item_search(
pool,
query={"tags": ["ai", "reference"]}
)
Limitation: The @> operator requires the queried array to be a subset of the stored array. For OR logic across tags, you'll need to run multiple queries or use a script to post-process results.
Combine multiple field queries in a single containment check:
# Find unread technical bookmarks
await item_search(
pool,
collection_name="bookmark",
query={
"read": False,
"category": "technical"
}
)
For text content searches (not supported by basic containment), consider:
collection_items.data covers all JSONB queriesOver time, item stores accumulate duplicates, stale data, and inconsistencies. Use these workflows to maintain quality.
Goal: Identify and merge duplicate items within a collection.
Steps:
Export the collection:
entities = await collection_export(pool, "bookmark")
Identify duplicates: Group by a unique key (e.g., url for bookmarks, title for projects):
from collections import defaultdict
seen = defaultdict(list)
for entity in entities:
key = entity["data"].get("url")
if key:
seen[key].append(entity)
duplicates = {k: v for k, v in seen.items() if len(v) > 1}
Merge duplicates: For each duplicate group, choose a canonical item (e.g., oldest by created_at or most complete by field count), then merge fields:
for url, dupes in duplicates.items():
# Sort by created_at to prefer oldest
dupes_sorted = sorted(dupes, key=lambda e: e["created_at"])
canonical = dupes_sorted[0]
# Merge fields from other duplicates
merged_data = canonical["data"].copy()
for dupe in dupes_sorted[1:]:
for field, value in dupe["data"].items():
if field not in merged_data:
merged_data[field] = value
# Update canonical item
await item_update(pool, canonical[], merged_data)
dupe dupes_sorted[:]:
item_delete(pool, dupe[])
Caution: This is a destructive operation. Consider exporting a backup before running.
Goal: Move old or inactive items to an archive collection to reduce active data clutter.
Steps:
Create an archive collection:
await collection_create(pool, "archive", "Historical items no longer active")
Define staleness criteria (e.g., status: "completed" and completed_at older than 6 months):
from datetime import datetime, timedelta
cutoff = datetime.now() - timedelta(days=180)
Fetch candidates:
all_projects = await item_search(pool, collection_name="project")
stale = [
e for e in all_projects
if e["data"].get("status") == "completed"
and datetime.fromisoformat(e["data"].get("completed_at", "2099-12-31")) < cutoff
]
Move to archive: Create new items in archive collection, then delete originals:
for entity in stale:
# Add source collection to metadata
archive_data = entity["data"].copy()
archive_data["_archived_from"] = "project"
archive_data["_archived_at"] = datetime.now().isoformat()
await item_create(pool, "archive", archive_data)
await item_delete(pool, entity["id"])
Alternative: Add an archived: true field instead of moving to a separate collection, then filter queries with {"archived": False}.
Goal: Ensure consistent tag naming (e.g., ai vs AI vs artificial-intelligence).
Steps:
Audit existing tags:
all_entities = await item_search(pool) # All collections
tag_set = set()
for entity in all_entities:
tags = entity["data"].get("tags", [])
tag_set.update(tags)
print(sorted(tag_set))
Define a canonical tag mapping:
tag_map = {
"AI": "ai",
"artificial-intelligence": "ai",
"ML": "machine-learning",
"web-dev": "web-development"
}
Update items:
for entity in all_entities:
tags = entity["data"].get("tags", [])
normalized = [tag_map.get(tag, tag) for tag in tags]
if normalized != tags:
await item_update(pool, entity["id"], {"tags": normalized})
Goal: Ensure all items in a collection conform to an expected schema.
Steps:
Define required fields (e.g., for project: title, status):
required_fields = ["title", "status"]
Validate items:
projects = await item_search(pool, collection_name="project")
invalid = []
for entity in projects:
missing = [f for f in required_fields if f not in entity["data"]]
if missing:
invalid.append((entity["id"], missing))
Fix or flag invalid items:
for entity_id, missing_fields in invalid:
print(f"Item {entity_id} missing: {missing_fields}")
# Option 1: Add default values
defaults = {"status": "unknown", "title": "Untitled"}
await item_update(pool, entity_id, {f: defaults[f] for f in missing_fields})
# Option 2: Tag for manual review
await item_update(pool, entity_id, {"_validation_errors": missing_fields})
Goal: Add tags to a batch of items based on criteria.
Steps:
Fetch target items (e.g., all bookmarks with category: "technical"):
technical_bookmarks = await item_search(
pool,
collection_name="bookmark",
query={"category": "technical"}
)
Add tags without overwriting existing ones:
for entity in technical_bookmarks:
existing_tags = entity["data"].get("tags", [])
new_tags = list(set(existing_tags + ["reference", "dev"]))
await item_update(pool, entity["id"], {"tags": new_tags})
Tip: Use Python's set operations to ensure no duplicate tags.
# Create collection
await collection_create(pool, "project", "Personal and work projects")
# Add first project
project_id = await item_create(
pool,
"project",
{
"title": "Learn PostgreSQL JSONB",
"status": "active",
"priority": "medium",
"goals": ["Master JSONB queries", "Build a sample app"],
"tags": ["learning", "database"],
"started_at": "2026-02-09"
}
)
# Find all active high-priority projects
active_high = await item_search(
pool,
collection_name="project",
query={"status": "active", "priority": "high"}
)
# Mark the first one as completed
if active_high:
project_id = active_high[0]["id"]
await item_update(
pool,
project_id,
{"status": "completed", "completed_at": "2026-02-09"}
)
# Export all bookmarks to JSON file
bookmarks = await collection_export(pool, "bookmark")
import json
with open("bookmarks_backup.json", "w") as f:
json.dump(bookmarks, f, indent=2, default=str) # default=str handles UUIDs/dates
item_search + loops.As you use the General butler, you may discover new item types or workflows. To extend this skill:
deduplicate.py, archive_stale.py)collection_create(name, description): Initialize a new collectioncollection_list(): View all collectionsitem_create(collection_name, data): Add a new item to a collectionitem_get(item_id): Retrieve a single itemitem_update(item_id, data): Merge updates into an item (deep merge)item_search(collection_name, query): Find items using JSONB containmentitem_delete(item_id): Remove an itemcollection_export(collection_name): Export all items from a collectionVersion: 1.0
Last Updated: 2026-02-09
Author: General Butler Team
Guide for discovering, analyzing, and pruning the Butlers test suite. Use when working on test condensation beads (Phase 1 epic bu-rhztl and Phase 2 epic bu-hg8rl both CLOSED; Phase 3 maintenance cycle underway 2026-06-21), assessing test bloat, identifying pruning targets, or rewriting tests to be contract-driven. Triggers on test reduction, test pruning, test consolidation, or condensation tasks for this project. Also use when a fresh session needs to assess test health, create new condensation beads, or resume in-progress condensation work.
Generate a weekly home energy digest with trends, top consumers, and recommendations.
Orchestrate a UX redesign of a Butlers dashboard page (or sub-page set) using /project-direction as the spec+beads engine, with redesign-specific upfront phases for vision capture, asset ingestion, impact analysis, backend-contract derivation, LLM-cost feasibility, manifesto/identity preservation, and a th-design design-bar audit. The binding design language is the Dispatch spec (openspec/specs/dashboard-design-language/spec.md); bundles live under pr/overview/ and resolve via references/bundle-registry.md. Use when asked to redesign a dashboard page, with or without a Claude Design bundle. Triggers on "redesign the X page", "plan the Y redesign", "integrate the redesign bundle", "what would it take to ship the SLUG redesign", "design language integration for AREA".
基于 SOC 职业分类