⏱️ Reading time: 14 min

A Claude Code agent can refactor an entire monorepo and write the database migration on its own, but if it needs you to click through a permissions dialog, it goes silent in front of a terminal nobody is watching. Claude Code Skills solve exactly that kind of snag, and the big-arrow-on-the-screen repository, released under the MIT license, is a real case to show it: it draws a huge arrow over any macOS window to point out which button to press.

📑 En este artículo
  1. TL;DR
  2. What Are Claude Code Skills?
  3. Why It Matters: The Problem big-arrow-on-the-screen Solves
  4. How a Skill Works Under the Hood: The Anatomy of SKILL.md
    1. How the Model Decides Which One to Load
  5. Real Example: The big-arrow Skill Step by Step
  6. How to Build Your Own Agent Extension
  7. Getting Started: Installing and Testing Your Own Skill
  8. Comparison: Skills vs. MCP vs. Subagents
  9. Real-World Use Cases
  10. Common Mistakes and Best Practices
  11. Going Deeper: Permissions, Security, and the Execution Model
  12. Frequently Asked Questions
    1. Do Claude Code Skills Work the Same Way in Codex?
    2. Does a Script Need macOS Permission to Draw on the Screen?
    3. Can This Agent Extension Replace an MCP Server?
    4. Where Do Project Skills Get Installed Versus Global Ones?
    5. Do You Need to Know Swift to Write a Skill Like big-arrow’s?
  13. References

The interesting part isn’t the arrow. It’s the mechanism that connects it to the agent without touching a single line of the model’s code. This article uses that real project as a case study to explain what a skill is, how the model discovers it, and how to build your own agent extension from scratch.

TL;DR

  • A SKILL.md file with YAML frontmatter is all it takes for Claude Code to discover and activate a new skill.
  • big-arrow-on-the-screen combines a daemon-free Swift binary with a skill installable via bigarrow install-skill.
  • A vague description in the frontmatter never wins the model’s selection, no matter how useful the skill actually is.
  • A shell script or any executable binary can be the real body of a skill, no proprietary SDK required.
  • MCP connects the agent to external stateful systems; a skill solves a one-off task without spinning up a server.

What Are Claude Code Skills?

Claude Code Skills are packages of instructions, metadata, and optional scripts that extend what the agent can do without modifying its core codebase. Each skill lives in a folder with a SKILL.md file. The model reads its description first, and only loads the rest of the content if it applies to the requested task.

Think of it like a shelf of manuals on a new employee’s desk. Nobody memorizes all forty manuals on day one, but when a customer asks something specific, the employee looks up the right manual, reads it, and only then acts. Claude Code works the same way: it keeps a short list of names and descriptions, and only opens a skill’s full content when the user’s request matches that description.

This mechanism is called progressive disclosure. It keeps every installed skill from eating up context space all the time; the cost of having a hundred skills installed is, in practice, a hundred lines of name and description, not a hundred full documents loaded upfront. The folder can include, besides the SKILL.md, any script or file the instructions need. That’s the second layer of progressive disclosure: it’s not just about deciding which skill to load, but which parts of that skill are worth reading for the task at hand.

Why It Matters: The Problem big-arrow-on-the-screen Solves

An agent that automates real tasks on a computer sooner or later runs into a step that only a human can, or should, authorize: a system permissions dialog, a two-factor check, a CAPTCHA, a signature. The agent finds the right button, but it can’t and shouldn’t press it.

The project’s README lists several real cases like these: an assistant asking you to click Allow without knowing whether you’re watching the terminal; a three-step guide in Keynote; picking the right tab among fourteen open in Chrome; helping a family member save a PDF over a video call. In every case, the solution isn’t for the agent to act on your behalf. It’s for it to point you exactly where to act.

By design, this agent extension never clicks, never types, and never takes screenshots: it only draws. It’s a transparent window, overlaid on top of everything, that ignores mouse clicks and leaves your keyboard focus untouched. According to the repository, drawing that arrow requires no special macOS permission, and the whole binary is a single Swift executable with no background daemon, no menu bar icon, no account, and no telemetry.

macOS allows transparent windows that ignore clicks through the system’s Quartz API. Foto de Branko Stancevic en Unsplash

How a Skill Works Under the Hood: The Anatomy of SKILL.md

Every skill starts with a YAML block delimited by three dashes, with at least two required fields: name and description. After the second delimiter comes the Markdown body: natural-language instructions that the model follows as if they were part of its own prompt, but only once it decides that skill applies.

The simplest possible skill has two files. First, the SKILL.md:

---
name: hello-world
description: Greets the user and tells the system time. Use when asked for a greeting, the time, or to test that skills are working.
---

# Hello world

When greeted or asked for the time, run `bash greet.sh`
with no arguments and return the output as is, with no extra text.

And the script that file invokes, greet.sh, in the same folder:

#!/usr/bin/env bash
echo "Hello from your first skill. System time: $(date '+%H:%M:%S')"

If you ask Claude Code to “greet me” with that skill installed, the response includes a line like this one, with the real time of the moment it ran:

Hello from your first skill. System time: 14:32:07
flowchart TD
A["~/.claude/skills/"] --> B["hello-world/"]
B --> C["SKILL.md"]
B --> D["greet.sh"]
A --> E["big-arrow/"]
E --> F["SKILL.md"]
E --> G["bin/bigarrow"]

The two skills coexist in the same top-level folder without stepping on each other: each is an independent directory, and Claude Code scans through all of them before deciding which one to use.

How the Model Decides Which One to Load

The decision is based exclusively on the description field. The model compares the user’s request against that short phrase from each installed skill, and only after picking one does it open the full SKILL.md along with whatever scripts it needs.

sequenceDiagram
participant U as User
participant A as Agent
participant S as Skills folder
U->>A: requests something in natural language
A->>S: reads name and description of each skill
S-->>A: short list of candidates
A->>S: loads the full SKILL.md of the best candidate
S-->>A: instructions and scripts
A->>U: runs the script and responds

Real Example: The big-arrow Skill Step by Step

Installing big-arrow-on-the-screen is macOS-only, via Homebrew:

brew install franzenzenhofer/tap/bigarrow
bigarrow install-skill

The second command copies the SKILL.md and the CLI usage instructions into Claude Code’s skills folder, and into Codex’s if it’s installed, according to the repository’s description. From there, asking the agent to point at a button no longer requires typing the command by hand: the agent builds it on its own from the skill’s instructions.

An example taken from the README shows what that command looks like once built:

bigarrow point --element "Allow" --app "System Settings" \
 --text "Franz, click Allow: Ghostty may control your Mac"

That command draws an arrow pointing at the “Allow” button inside System Settings, with a text label next to it. The actual click is still yours; Big Arrow only points.

The repository stays under the MIT license, with no cloud dependencies or user account. Foto de Bernd 📷 Dittrich en Unsplash

How to Build Your Own Agent Extension

The difference between the “hello world” skill above and a genuinely useful skill usually comes down to one thing: whether the script takes arguments instead of always doing the same thing. The following example wraps the Unix wc command to count the lines and words in a file.

---
name: count-words
description: Counts the lines and words in a local text file. Use when the user asks for the size, the length, or how many words a file has.
---

# Count words

When asked for a file's size, run:

wc -l -w "$1"

wc always returns the lines first and the words second,
no matter what order you requested the flags in.

If you ask Claude Code “how many words does notes.txt have?” with that skill installed, the agent runs the command and the literal output looks like this:

  12  54 notes.txt

Twelve lines, fifty-four words. That same structure, a name, a description, and one wrapped command, works for almost any CLI you already have installed: an internal linter, a tool of your own, or the bigarrow binary with different flags depending on the case.

Getting Started: Installing and Testing Your Own Skill

The only dependency is having Claude Code installed and authenticated on your machine. No SDK or extra toolchain is needed for a shell-based skill. On macOS and Linux, the commands are identical:

mkdir -p ~/.claude/skills/hello-world
cd ~/.claude/skills/hello-world
cat > SKILL.md <<'EOF'
---
name: hello-world
description: Greets the user and tells the system time. Use when asked for a greeting or to test that skills are working.
---

# Hello world

Run `bash greet.sh` and return the output as is.
EOF
cat > greet.sh <<'EOF'
#!/usr/bin/env bash
echo "Hello from your first skill. System time: $(date '+%H:%M:%S')"
EOF
chmod +x greet.sh

On Windows, the same three elements (the folder, the SKILL.md, and the script) are created by hand from a text editor inside %USERPROFILE%\.claude\skills\hello-world, with no need for bash heredocs.

💡 Tip: write the description like an entry in an internal search index, with the synonyms a real user would actually type (“greeting”, “time”, “test skill”), because it’s the one part the model always reads, even if it never opens the rest of the file.

To confirm it worked, open a new Claude Code session and type “greet me”. If the skill loaded, the response carries the real time returned by the script; if Claude replies with a generic greeting without that time, the description wasn’t specific enough for it to get picked. There’s no command yet that lists which skills are loaded in memory at a given moment. What you can verify with certainty is that the file exists and the YAML is valid, by checking by hand that the block between the two --- markers has name and description.

Comparison: Skills vs. MCP vs. Subagents

Before writing the next skill, it’s worth placing Claude Code Skills against the other two ways to extend an agent: an MCP server and a subagent with its own context.

OptionWhen to use itAdvantageLimitation
SkillWrapping a local command or workflow with specific instructionsSimple installation, no server, progressive disclosureRuns with the same permissions as the user, with no isolation of its own
MCP serverConnecting the agent to an external stateful system (database, API, SaaS)Standard protocol, reusable across different AI clientsYou have to stand up and maintain your own process
SubagentDelegating a long task with its own context historyIsolates context, avoids polluting the main conversationDoesn’t replace a one-off tool, it’s meant for full workflows

flowchart LR
A["Agent"] -->|reads locally| B["Skill on disk"]
A -->|MCP protocol| C[("MCP server")]
C --> D[("External database or API")]
B --> E["Local script or binary"]

Real-World Use Cases

Beyond pointing at buttons, the same skill pattern works for wrapping any command-line tool in natural language.

  • Support for non-technical users: guiding a family member to save a PDF or accept a permission during a video call, without giving remote access to the machine.
  • Visual documentation: recording a tutorial that points at each control in a complex app, instead of writing “the button at the top right”.
  • Coordinate debugging: pointing at the coordinates an accessibility API returns and checking whether they land where they should, before automating a real click.
  • Internal tools wrapped in natural language: turning a linter, a deploy script, or a report generator into something the team invokes by chatting, not by memorizing flags.

Common Mistakes and Best Practices

  • Vague description: a description like “helps with files” almost never wins the selection against skills with specific descriptions; write it thinking about the exact words a real user would type.
  • Scripts without execute permission: forgetting chmod +x breaks the skill on first use, with a permission-denied error that says nothing about the SKILL.md.
  • A skill that does too much: if the body mixes five different tasks, split it into several skills with their own names; the model picks better among narrow options than among one generic one.
  • Absolute paths from the original author: a script that assumes a fixed path from the author fails on any other machine; use paths relative to the skill’s folder.
  • Assuming the dependency: big-arrow needs macOS and Homebrew; always document which operating system and which external binaries your skill expects before someone installs it blindly.

Going Deeper: Permissions, Security, and the Execution Model

A script inside a skill runs, by default, with the same permissions as the account running Claude Code. There’s no automatic sandbox separating a skill’s code from code you’d write yourself in that terminal. Installing a skill from someone else’s repository is, in terms of risk, equivalent to copying and running a script you downloaded from the internet.

The README for big-arrow-on-the-screen is insistent about what the binary doesn’t do. It doesn’t take screenshots, it doesn’t click, it doesn’t type, and it has no telemetry. These are verifiable claims because the code is open under MIT: anyone can read the Swift source and confirm the only operation is drawing an overlay window.

⚠️ Heads up: before installing a third-party skill, open the SKILL.md and the scripts it ships with; they’re plain text and Markdown, so reading them before trusting them with your user account takes less than a minute.

This also marks when this agent add-on isn’t the right tool. If several people or services without mutual trust need the same integration, with their own quota limits and authentication, an MCP server with its own access control makes more sense than a local script running with the permissions of whoever invokes it.

Your next step: create the ~/.claude/skills/hello-world folder from the “Getting Started” section, ask Claude to greet you, and then compare it with the real SKILL.md from big-arrow-on-the-screen.

📬 Get new articles by email

We only email about big articles (1-2 a month).

Frequently Asked Questions

Do Claude Code Skills Work the Same Way in Codex?

big-arrow-on-the-screen installs as a skill in both Claude Code and Codex because both read the same folder format with SKILL.md and frontmatter; what changes is the client interpreting that file, not its content.

Does a Script Need macOS Permission to Draw on the Screen?

According to the repository, drawing the arrow itself doesn’t ask for any system permission. Identifying a specific element of an app with the --element flag can require access to macOS’s accessibility API, depending on how each version of the binary implements it.

Can This Agent Extension Replace an MCP Server?

For a local, one-off task, yes. For connecting to an external system with its own state, authentication, and multiple simultaneous clients, no. There, an MCP server is still the right piece, as shown in the comparison table above.

Where Do Project Skills Get Installed Versus Global Ones?

Global skills live in ~/.claude/skills/ and are available in any project; skills specific to a repository are stored inside .claude/skills/ alongside the code, similar to how a CLAUDE.md sits with the project.

Do You Need to Know Swift to Write a Skill Like big-arrow’s?

No. big-arrow-on-the-screen uses Swift for its own binary, but the script a skill invokes can be bash, Python, Node, or any executable: all the SKILL.md needs to know is which command to run and with what arguments.

References

📱 Enjoying this content? Follow @programacion on Telegram for daily tech content in Spanish: quick summaries, fresh content every day.

Featured image: Foto de Ilya Pavlov en Unsplash

Did it work for you? Got a different error? Say so below: questions get answered and help the next reader.

Leave a comment

Andrés Morales

Developer and AI researcher. Writes about language models, frameworks, developer tooling, and open source releases. Covers ML papers, the tech startup ecosystem, and programming trends.

0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *

You can include code inside <code>…</code> or, for several lines, <pre><code>…</code></pre>.

This site uses Akismet to reduce spam. Learn how your comment data is processed.