Documentation
Skills
CopyCopy understands what you copy and where you copied it from, then shows the right next action. Skills define the available actions — both the built-in ones and any you create yourself. For a visual walkthrough, see Default Skills.
When you double-press ⌘C, CopyCopy:
- Captures the clipboard content.
- Detects the top-level content type locally: text, URL, image, files, rich text, or unknown.
- Detects entities inside text locally: JSON, Base64, URL-encoded text, HTML, Markdown, code, file path, foreign language, and more.
- Identifies the source app context: browser, email, chat, IDE, terminal, notes, or other.
- Optionally asks the local LLM to add semantic labels for plain text, such as
emailDraft,slackDraft,shellCommand,logOutput, orsql. - Loads skills whose filters match the content type, entities, and source context.
- Ranks actions using source boosts, entity boosts, text length, and usage history.
- Shows the best actions in the floating panel.
After an action runs, CopyCopy creates a new context from the result, excludes redundant actions, shows immediate heuristic follow-ups, and optionally uses the local LLM plus memory to reorder follow-ups.
Source context and entities strongly influence ranking: copying JSON surfaces Format JSON; copying a terminal error surfaces Explain Error; copying from chat surfaces Draft Reply or Action Items; copying article HTML surfaces Smart Markdown.
Quick start
Create a folder under ~/.copycopy/skills/ and put a SKILL.md file inside it:
mkdir -p ~/.copycopy/skills/my-skill
open ~/.copycopy/skills/my-skillThen create:
~/.copycopy/skills/my-skill/SKILL.mdRestart CopyCopy after editing a skill. If your folder name matches a built-in skill id such as summarize or explain-code, your file overrides the bundled one.
SKILL.md format
The recommended format is YAML frontmatter plus a body.
- If the body is
toolName(args), the skill runs a safe built-in function. - Otherwise, the body is treated as an on-device LLM system prompt.
If you are starting from scratch, copy one of the built-in exported skill files and modify it.
Minimal skill example
LLM prompt skill
---
name: Fix Grammar
description: Fix grammar
icon: checkmark.bubble
content-types: text
text-source: clipboardChatCleaned
temperature: 0
source-boosts:
email: 80
notes: 80
---
Fix grammar, spelling, and punctuation.
Rules:
- Preserve meaning, tone, formatting, and language
- Do not rewrite correct sentences
- Output only the corrected textFunction skill
---
name: Format JSON
description: Pretty-print JSON
icon: curlybraces
content-types: text
entity-types: json
---
formatJSON({clipboardTrimmed})Frontmatter
Every skill needs YAML frontmatter at the top.
Required
namedescription
Optional
iconcontent-typesentity-typessource-contextstext-sourceminimum-charsmaximum-charstemperaturesource-boosts
Metadata filters
You can filter when a skill activates using content-types, entity-types, and source-contexts.
content-types: text
entity-types: json, base64
source-contexts: terminalLegacy metadata keys are still accepted for backward compatibility:
metadata:
content_types: [ text ]
entity_types: [ json, base64 ]
source_contexts: [ terminal ]Content types
texturlimagefiles
If you omit content-types, the skill can match any clipboard kind.
Source contexts
browserideterminalemailchatnotes
Source context determines the app where you pressed ⌘C. It influences ranking: actions scoped to the current source appear first, but all matching actions remain available. If you omit source-contexts, the skill can match any app source.
Common entity types
json,base64,urlEncoded,html,markdown,codeSnippetemail,phoneNumber,address,placeName,coordinatesfilePath,gitSha,ipAddress,currencyforeignLanguage,emailDraft,slackDraftshellCommand,logOutput,sql
Legacy ## Actions format
CopyCopy still supports the older readable ## Actions format, but new skills should use the frontmatter+body format shown above. Each action starts with a ### action-id block.
Prompt action
Use this for AI-powered actions — rewriting, summarization, translation, grammar fixes, and code explanation. These run on the on-device Gemma 4 E2B model. The result is copied to the clipboard automatically.
### summarize
type: prompt
prompt: Summarize the clipboard text into 3-5 bullet points. Preserve the main point and the most important supporting details. Omit filler and repetition. Return only the summary.
icon: text.redaction
description: Summarize ContentYou can scope prompt actions to a source context or an entity type:
### explain-code
type: prompt
prompt: Explain what this code does in plain language. Be brief and focus on the purpose, not line-by-line detail.
icon: doc.text.magnifyingglass
description: Explain Code
entity_types: [codeSnippet]Function action
Use this for URL opening, built-in transforms, file actions, and similar non-prompt tools:
### decode-base64
type: function
function: decodeBase64
icon: arrow.down.doc
description: Decode Base64
entity_types: [base64]Supported function: values
openURLcopyToClipboardrevealInFinderopenFilesaveImagesaveTempFilestripANSIhtmlToMarkdownformatJSONdecodeBase64decodeURL
Template variables
The readable format supports these variables in template: fields:
{text}{text:encoded}{text:trimmed}{path}{charcount}{linecount}
Structured ## Tools JSON format
This format is stricter and maps directly to CopyCopy's internal tool schema.
[
{
"id": "pretty-json",
"name": "Pretty Print JSON",
"description": "Pretty Print JSON",
"icon": "curlybraces",
"execute": "formatJSON",
"parameters": {
"type": "object",
"properties": {
"json": {
"type": "string",
"description": "Clipboard JSON",
"source": "clipboard"
}
},
"required": ["json"]
},
"entityTypes": ["json"]
}
]Tool fields
id: stable identifier inside the skillname: human-readable namedescription: menu title shown to the usericon: SF Symbol nameexecute: built-in function nameparameters: JSON schema-like object definitionentityTypes: optional action-level entity filtersourceContexts: optional action-level source-app filter
Supported parameter source values
literal— uses the property's ownvalueclipboard— raw clipboard textclipboardLLM— preprocessed clipboard text for LLM input (HTML extraction, chrome stripping, sanitization). Use this for all prompt actions.clipboardHTML— raw clipboard HTML, falls back to plain textclipboardURL— clipboard URL as a stringclipboardTrimmed— clipboard text with leading/trailing whitespace removedfilePaths— newline-joined file pathscharCount— character count as a stringlineCount— line count as a string
Available execute functions
URLs and apps
openURL— Open a validated clipboard URL directly.openURLTemplate— Build a URL frombaseURL,path, query parameters, andfragment.openStaticURL— Open a fixed URL from parameters.openApp— Open an allowlisted app and optionally copy prepared text. Supported apps include ChatGPT, Claude, Cursor, Copilot, and Safari.
Files and clipboard
openFilerevealInFindersaveImagesaveTempFilecopyToClipboard
Local transforms
formatJSON— Validate and pretty-print JSON.decodeBase64— Decode Base64 and copy the result.decodeURL— Decode percent-encoded text and copy the result.stripANSI— Remove ANSI escape codes and copy the result.htmlToMarkdown— Convert clipboard HTML to Markdown using the content extraction pipeline.htmlToMarkdownLLM— Convert clipboard HTML to Markdown, then clean it with the local model.
Path utilities
revealPath— Resolve and validate a file path, then reveal it in Finder.openInTerminal— Resolve and validate a file path, then open it in Terminal.
AI tools
llmPrompt— Run a prompt against the on-device Gemma 4 E2B model with separate system and user roles. The result is copied to the clipboard. UseclipboardLLMas the prompt source for code andclipboardChatCleanedfor chat/email.
Function reference
llmPrompt
The primary AI tool. Use this for summarization, translation, rewriting, grammar fixes, code explanation, and any other prompt-based transformation.
{
"execute": "llmPrompt",
"parameters": {
"type": "object",
"properties": {
"systemPrompt": {
"type": "string",
"description": "Instruction for the model",
"source": "literal",
"value": "Fix the grammar and spelling in the clipboard text. Preserve the original meaning and tone. Return only the corrected text."
},
"prompt": {
"type": "string",
"description": "Clipboard text",
"source": "clipboardLLM"
}
},
"required": ["systemPrompt", "prompt"]
}
}Tips for writing system prompts
- Be direct: "Fix grammar" not "You are a grammar assistant who..."
- Specify what to return: "Return only the corrected text" prevents the model from adding commentary.
- Keep it short: the on-device model responds better to concise instructions.
- The input is truncated at ~3000 characters. For longer content, summarization works better than detailed rewriting.
openURLTemplate
Build a URL safely from baseURL, path, query parameters, and fragment.
{
"execute": "openURLTemplate",
"parameters": {
"type": "object",
"properties": {
"baseURL": { "type": "string", "description": "Search URL", "source": "literal", "value": "https://duckduckgo.com/" },
"q": { "type": "string", "description": "Search query", "source": "clipboard" }
},
"required": ["baseURL", "q"]
}
}htmlToMarkdown
Convert clipboard HTML to Markdown. Uses the content extraction pipeline to strip navigation, ads, and boilerplate before converting.
{
"execute": "htmlToMarkdown",
"parameters": {
"type": "object",
"properties": {
"html": { "type": "string", "description": "Clipboard HTML", "source": "clipboardHTML" }
},
"required": ["html"]
}
}Copy-paste examples
1 · Fix grammar (prompt)
---
name: writing
description: Fix and improve copied text
metadata:
content_types: [ text ]
---
# Writing
## Actions
### fix-grammar
type: prompt
prompt: Fix the grammar and spelling in the clipboard text. Preserve the original meaning and tone. Return only the corrected text.
icon: textformat.abc
description: Fix Grammar2 · Rewrite email draft (prompt, scoped to email apps)
---
name: email
description: Polish email drafts
metadata:
content_types: [ text ]
source_contexts: [ email ]
---
# Email
## Actions
### rewrite-email
type: prompt
prompt: Rewrite the clipboard text as a polished email reply draft. Preserve the original intent and key facts. Improve clarity, tone, and grammar. Return only the rewritten email body.
icon: envelope.badge
description: Polish email draft3 · Strip ANSI codes (function, scoped to terminal)
---
name: terminal-tools
description: Clean up terminal output
metadata:
content_types: [ text ]
source_contexts: [ terminal ]
---
# Terminal Tools
## Actions
### strip-ansi
type: function
function: stripANSI
icon: textformat
description: Remove terminal colorsBuilt-in skills
CopyCopy ships with focused built-in skills:
open-url— Open copied URLs.read-article— Fetch a URL and extract readable article content.clean-text— Normalize copied text locally.smart-markdown— Convert article HTML to clean Markdown with local AI cleanup.format-json,decode-base64,decode-url,strip-ansi— Deterministic local transforms.fix-grammar,summarize,translate,rewrite-email— On-device AI text transforms.draft-chat-reply,extract-action-items— Contextual chat/email/notes actions.explain-terminal-error,explain-code— Developer and terminal helpers.open-file,reveal-in-finder,reveal-path,open-terminal— File and path actions.
On startup, built-ins are exported to ~/.copycopy/skills/ as editable Markdown files. A custom folder with the same id overrides the bundled skill.
Tips
- Start from an exported built-in skill instead of writing one from scratch.
- Use
type: promptfor AI-powered actions. Usetype: functionfor everything else. - Use
source_contextsto surface actions in the right app context. - Use
entity_typesto keep the action panel clean. - Use
clipboardLLMas the source for prompt actions — it preprocesses the input. - Keep system prompts short and direct.
- Restart CopyCopy after changing
SKILL.md.
Troubleshooting
My skill does not show up
- the folder is under
~/.copycopy/skills/ - the file is named exactly
SKILL.md - frontmatter has both
nameanddescription - JSON under
## Toolsis valid - your filters actually match the current clipboard content
My tool shows but does nothing
- the URL scheme is not allowlisted
- the app name is not allowlisted for
openApp - the path does not exist for
revealPathoropenInTerminal - the clipboard content does not match the expected source
Debugging
Enable the Debug tab:
defaults write com.copycopy.app debugMenuEnabled -bool trueThen relaunch CopyCopy and inspect the current clipboard kind, detected entity, source context, and event-tap state.