Agent Skills, working: a guide with 6 real Atlassian examples
Mihai Perdum
Author
12 min readMay 19, 2026
Your coding agent just made up an API again
Your agent just confidently wrote a Forge manifest with a jira:workflowValidator module that doesn't compile, paginated /rest/api/3/search with startAt (which Atlassian removed in August 2025), and edited a Confluence page without bumping version.number — silent 409 forever. None of these are obscure. All three are common knowledge in the heads of Atlassian developers, and missing knowledge in every coding agent shipped today.
This isn't a model-quality problem. It's a knowledge-loading problem. And it's exactly what Agent Skills were built to fix.
This tutorial covers the mechanics — how skills load, how to write one, how to install one — and uses six open-source skills we maintain at LeanZero as the worked examples. By the end, your agent will know the things it should already know.
Why pasting docs into the prompt doesn't work
The instinct, when an agent hallucinates, is to paste more documentation into the system prompt. This works for one task and breaks every other:
Token bloat. Every token in the system prompt is paid for on every turn, for the whole session. The Confluence REST API reference alone is ~80,000 tokens. Multiply by the four other Atlassian surfaces and you've burned a whole context window before the user has said anything.
Context dilution. Long system prompts measurably reduce instruction-following. The agent stops attending to your actual task instructions because they're buried.
No selection. Even if you could paste it all, the agent reads the entire thing every time. You're paying full price for the JQL section while editing a Confluence page.
The other workarounds have their own problems. retrieves relevant chunks, but the agent still has to reason about which chunk applies — and you're back to hallucinations when the retrieval is fuzzy. bakes knowledge into weights, which is expensive, slow to update, and locks you to one model.
Skills are reusable, filesystem-based resources that provide Claude with domain-specific expertise: workflows, context, and best practices that transform general-purpose agents into specialists. Unlike prompts (conversation-level instructions for one-off tasks), Skills load on-demand and eliminate the need to repeatedly provide the same guidance across multiple conversations.
A Skill is a directory on disk with a SKILL.md file at its root. That SKILL.md has YAML frontmatter (a name and a description) and a markdown body with instructions. The directory can also contain supporting files: reference docs, templates, scripts the agent can execute via bash.
The mental model from the docs is good: Skills are onboarding materials for a new team member. You wouldn't paste your entire engineering wiki into a new hire's onboarding doc. You'd give them a map: "here's the Forge module reference, here's the JQL gotchas list, here's how we structure migration scripts." The new hire reads the relevant page when they need it.
That's exactly what an agent does with a skill.
The minimum viable SKILL.md
1---2name: my-skill-name
3description: Brief description of what this skill does and when Claude should use it.
4---5# My Skill67## Instructions8Step-by-step guidance for the agent here.
910## Examples11Concrete examples here.
That's the whole format. Two required fields in the frontmatter, free-form markdown below. The format is an open standard at agentskills.io — the same SKILL.md works in Claude Code, Cline, Qwen Code, and any other agent that implements the spec.
Progressive disclosure — the trick that makes skills cheap
Here's the part that turns "another way to load context" into something genuinely new.
A skill loads in three levels, each at a different time:
Level
When loaded
Token cost
What
Level 1: Metadata
Always (at startup)
~100 tokens per skill
name and description from frontmatter
Level 2: Instructions
When the skill is triggered
Under 5k tokens
The full SKILL.md body
Level 3: Resources
On demand, via bash
Effectively unlimited
Bundled files the agent reads only when referenced
4 rows × 4 columns
This is progressive disclosure, and it's the architectural decision that makes skills work.
At startup, your agent loads the descriptions of every installed skill — about 100 tokens each. You can install 50 skills for ~5,000 tokens, and the agent now knows it has a skill for Forge manifests, a skill for JQL, a skill for migrations, and 47 others. But none of their bodies are loaded yet.
When you ask "write me a Forge workflow validator," the agent matches your request to the atlassian-jira-forge-skill description, reads that one skill's body into context via bash, and proceeds. The other 49 stay on disk, costing nothing.
When the Forge skill references forge-manifest-reference.md, the agent reads that one file — and only that file. The bundled scripts in the same directory? Their source code never enters context. The agent just runs them and reads the output.
The practical consequence: you can ship a skill with 50,000 words of reference material and the agent pays nothing for it until the moment it's needed. This is impossible with a system prompt and clumsy with RAG. With skills, it's the default.
How a skill gets triggered
Two ways: automatically (the agent decides) or manually (you decide).
Auto-trigger via description
Every skill's description is always in the agent's context. When you make a request, the agent matches your intent against those descriptions and loads the most relevant skill. This is why the description field is the most important line in your SKILL.md.
A bad description:
1description: Helps with Atlassian stuff.
A good description (this is one of ours, verbatim):
1description: Scaffold idempotent, resumable Atlassian migration scripts in Node.js — Data Center to Cloud or Cloud to Cloud — using the Plan/Sync/Audit triad, native-https clients with 429/5xx retry, post-JCMA ID mapping, identity resolution, seeded-sample audits with CSV spot-check outputs, and Forge KVS remote app-data mending. Use when migrating Jira issues or Confluence pages in bulk, mending Forge app data after JCMA, backfilling custom fields, security levels, or content properties, rewriting macros at scale, fixing broken filter JQL after a tenant move, or building any two-phase Atlassian sync job with audit verification and human-reviewable CSVs.
The first half says what the skill does. The second half says when to use it — with concrete trigger phrases like "after JCMA," "broken filter JQL," "bulk-mutate." The agent matches those phrases against the user's request and decides whether to load.
Constraint: the description has a 1,024-character cap (Claude API) and gets truncated at 1,536 characters in the skill listing (Claude Code). Put the key use case first.
Manual invocation via /skill-name
You can also trigger a skill directly. In Claude Code, type:
1/atlassian-migration-scripts-skill
…and the skill loads regardless of whether the agent thought it was relevant. Useful when you know exactly what you need and don't want to waste a turn on the agent's auto-selection.
You can also pre-empt auto-loading entirely with disable-model-invocation: true in the frontmatter — useful for skills with side effects like /deploy or /commit where you don't want the agent deciding for you.
Installing a skill in Claude Code
Claude Code reads skills from three locations:
LocationPathScopePersonal~/.claude/skills/<skill-name>/SKILL.mdAll your projectsProject.claude/skills/<skill-name>/SKILL.mdOne repo (commit to share with team)Plugin<plugin>/skills/<skill-name>/SKILL.mdBundled with a plugin
If you put a skill at all three levels with the same name, project wins over personal wins over plugin.
The install script symlinks each skill into ~/.claude/skills/ so updates are pulled with git pull. Same script works for Cline and Qwen Code — pass --target=cline or --target=qwen.
Six worked examples — the leanzero-forge-skills set
We forged these against two production Atlassian apps over 18 months (CogniRunner and Sentinel Vault, both on the Atlassian Marketplace). Each one closes a specific class of hallucination we caught coding agents committing — repeatedly, on real tasks.
The full set lives at github.com/leanzero-srl/leanzero-forge-skills. Below, one paragraph each on what they teach an agent.
1. atlassian-jira-forge-skill
For Forge code running inside Jira. Teaches the workflow trio (workflowValidator, workflowCondition, workflowPostFunction) — the doc that finally kills the long-stale myth that workflow validators are Connect-only. Includes async-event handlers with timeoutSeconds: 900 to escape Forge's 25-second function ceiling, KVS sharding patterns for hot keys lifted from a real PPM app, and capability-token webtriggers done right (public HTTPS endpoints with bearer auth). 16 templates, 30 docs.
2. atlassian-confluence-forge-skill
The Confluence counterpart. pageBanner, contentAction, contextMenu, custom content, macros. The headliner is ADF tree surgery — patterns for idempotent edits to Confluence's Atlas Document Format JSON without breaking pages. Also includes the three-level Confluence authorization model (requestConfluence in the bridge, asApp vs asUser in resolvers) which is the #1 source of mysterious 401s. And the GET → bump version.number → PUT dance that kills the silent 409 Conflict cycle on every page update. 14 templates, 30 docs.
3. atlassian-organizations-api-skill
The cross-product admin surface at api.atlassian.com/admin — orgs, users, groups, audit events, SAML/MFA policies, DLP, API tokens. Four sub-APIs covered with their distinct auth boundaries (the Bearer-only-on-DLP/Admin-Control gotcha that silently breaks OAuth integrations is the kind of thing nobody tells you until you've burned an afternoon on it). Cursor-paginated audit-event polling for what is reliably the strictest rate-limited Atlassian surface. 5 templates, 14 docs.
4. jira-api-skill
External Node, Python, or CI services calling Jira Cloud over HTTPS. The big one here: POST /rest/api/3/search/jql with nextPageToken. The old startAt-based pagination is gone as of August 2025, and most agents still write it. The skill also covers OAuth 2.0 3LO end-to-end (authorize → token exchange → /accessible-resources → gateway calls), ADF construction for descriptions and comments (it's a JSON tree, not Markdown), and a hard "no, you cannot sign your own JWT for Cloud REST" disclaimer for anyone half-remembering Connect. 4 templates, 10 docs.
5. confluence-api-skill
External services calling Confluence Cloud — v2 pages with ADF, the same GET → bump → PUT version dance (this one bites you twice if you don't have it), v1 fallback for CQL search. v2 cursor pagination for /spaces and /pages with the actually-working ?cursor= shape. The note that body.atlas_doc_format.value is stringified JSON (you have to JSON.parse before traversing) — agents miss this every time. 5 templates, 10 docs.
6. atlassian-migration-scripts-skill
The newest of the six. Idempotent, resumable Atlassian migration scripts using the Plan→Sync→Audit triad: plan-script discovers, sync-script applies, audit-script verifies. Two-gate safety (--dry-run for preview, --confirm for the real thing) means you can't accidentally mutate the wrong tenant. Built for the work nobody plans for — post-JCMA cleanup, Cloud-to-Cloud tenant consolidation, rewriting broken filter JQL after IDs shift, mending Forge KVS app data from outside the app. 29 templates, 21 docs.
Writing your own skill
The fastest path is to crib from one of ours and replace the body. The pattern:
Pick something specific. Skills are for one thing done well, not "everything about Jira." Each of our six closes a defined boundary (Forge vs REST, Jira vs Confluence, runtime vs migration).
Write the description first. What does it do? When should the agent use it? Read it aloud — if it sounds vague, it'll trigger on the wrong tasks or fail to trigger on the right ones.
KeepSKILL.mdunder 500 lines. Move detailed reference into supporting files in the same directory. The skill body should be a map; the reference is the territory.
Test by asking, not invoking. Don't type /your-skill — ask the question your skill is supposed to answer and see if the agent picks it up. If it doesn't, your description is wrong.
Ship it. Drop it in ~/.claude/skills/ and use it. The feedback loop is short.
A minimum viable skill, end-to-end:
1mkdir-p ~/.claude/skills/my-skill
1---2name: my-skill
3description: Does X for the user. Use when the user mentions X, Y, or Z. ---
45# My Skill67## Instructions81. Do this.
92. Then do that.
1011## Examples12Concrete example here.
That's it. Restart Claude Code (or wait — it auto-detects new skills), and you're done.
2: A note on security
The official docs put this in a warning box and we'll echo it: only install skills from sources you trust. A skill can give the agent new bash commands to run and new tools to invoke; a malicious skill is functionally indistinguishable from any other piece of executable code on your machine. Treat skill installation like installing a package.
Our leanzero-forge-skills repo is MIT-licensed, public, and audit-friendly — every skill is a flat directory of markdown and .js templates with no install-time scripts. Read what you install.
TL;DR
Question
Short answer
What's a skill?
A directory with SKILL.md that gives an agent specialist knowledge on demand.
What problem does it solve?
Agent hallucination on framework-specific work without burning context on docs.
How does it stay cheap?
Progressive disclosure: only the description (~100 tokens) is always loaded; the body loads when triggered.
How does the agent know when to use one?
Auto-match against the description field, or manual invocation via /skill-name.
Where do they live?
~/.claude/skills/ (personal) or .claude/skills/ (project) in Claude Code.
Cross-agent?
Yes — agentskills.io is an open standard. Same SKILL.md works in Claude Code, Cline, Qwen Code.
Where to get started?
Clone leanzero-forge-skills, run ./scripts/install-skills.sh, ask your agent to write a Forge workflow validator.
8 rows × 2 columns
If you've ever lost an afternoon to an agent confidently producing JQL that 400s, a Forge manifest that doesn't compile, or a Confluence edit that silently 409s — that's the friction skills exist to remove. The six above remove it for Atlassian. Write your own for whatever framework keeps tripping yours up.