Skip to content
← All writing
Article · 3 min read Agents & MCP By Abidh Muhsin

Agent Skills That Grow: The Wrapper Pattern for Minting New Scripts

Most skills ship with a fixed set of scripts. Here's a pattern that lets the agent create new scripts on the fly, using wrapper libraries as building blocks.

Self Expanding Skills

Fixed Skills vs. Expanding Skills

Most AI agent skills ship with a fixed set of scripts. If a task isn’t covered, the user waits for the author to add it. The skill can’t grow on its own.

The alternative: design the skill so the agent can create new scripts itself using the same building blocks the existing scripts use.

The Wrapper Library Pattern

The foundation is a thin wrapper library that handles the hard parts. Here’s the pattern in action: a Jira wrapper as the core building block every script imports.

// scripts/lib/jira.mjs
export async function jiraRequest(endpoint, { method = 'GET', body = undefined } = {}) {
  const baseUrl = getBaseUrl(); // appends /rest/api/2 to JIRA_BASE_URL
  const token = getJiraToken(); // reads JIRA_TOKEN env var

  const headers = {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json',
    Accept: 'application/json',
  };

  if (method === 'POST' || method === 'PUT') {
    headers['X-Atlassian-Token'] = 'no-check';
  }

  const res = await fetch(`${baseUrl}${endpoint}`, { method, headers, body });

  if (!res.ok) {
    console.error(`Jira API error ${res.status}: ${await res.text()}`);
    process.exit(1);
  }
  return res.json();
}

One function handles auth (always Bearer for Jira), base URL construction, CSRF headers for mutations, and error formatting. It also exports parseArgs() for CLI flag parsing and getJiraToken() for explicit token access.

Every tool script in the skill is a thin layer on top: import the wrapper, call jiraRequest() with an endpoint, format the output. The wrapper owns the complexity. The scripts own the logic.

This separation is what makes expansion possible.

The Ad-Hoc → Reusable Pipeline

The expansion happens in three stages:

Stage 1: Ad-Hoc Query

The agent runs a one-liner using the wrapper directly. No new file needed:

node --input-type=module <<'EOF'
import { jiraRequest } from './scripts/lib/jira.mjs';
const data = await jiraRequest('/project?maxResults=200');
data.forEach(p => console.log(p.key, p.name));
EOF

The wrapper handles auth, URL construction, CSRF tokens. The agent just writes the query logic.

Stage 2: Promote to Script

If the query keeps coming up, the agent creates a new script file. Here’s a real example, a search script built on the wrapper:

// scripts/jira/search-issues.mjs
import { jiraRequest, parseArgs } from '../lib/jira.mjs';

const args = parseArgs();
if (!args.jql) {
  console.error('Missing required argument: --jql "<JQL query>"');
  process.exit(1);
}

const data = await jiraRequest('/search', {
  method: 'POST',
  body: JSON.stringify({
    jql: args.jql,
    maxResults: parseInt(args.maxResults || 50, 10),
    fields: (args.fields || 'summary,status,assignee,priority').split(','),
  }),
});

for (const issue of data.issues) {
  const f = issue.fields;
  console.log(`${issue.key}: ${f.summary} [${f.status?.name}]`);
}

The entire script is: import wrapper, parse args, call API, format output. No auth logic, no URL construction, no CSRF handling. The wrapper handles all of that.

Stage 3: Register It

The skill file itself documents how to expand. Here’s the actual extension section from the skill:

## Extending the Skill

Ask user if an ad-hoc query proves useful or a recurring task is not
covered by an existing script:

1. Create a new script under `scripts/jira/` so the
   operation is reusable.
2. Add a row for it to the Script Routing table in this file.
3. Update the `description` trigger phrases in the frontmatter
   if the new script covers a new category of user request.

And the routing table the script gets added to:

## Script Routing

| Goal                     | Script                           |
|--------------------------|----------------------------------|
| Get issue details        | scripts/jira/get-jira-issue.mjs  |
| Search issues with JQL   | scripts/jira/search-issues.mjs   |
| Create a new issue       | scripts/jira/create-issue.mjs    |
| Update issue fields      | scripts/jira/update-issue.mjs    |
| Add a comment            | scripts/jira/add-comment.mjs     |
| Transition issue status  | scripts/jira/transition-issue.mjs|
| Assign or unassign issue | scripts/jira/assign-issue.mjs    |
| List projects            | scripts/jira/list-projects.mjs   |

When the agent creates a new script, it adds a row to this table and updates the frontmatter trigger phrases. The skill file is both the instruction manual and the registry. It tells the agent how to expand and tracks what’s been added.

The skill now has a new capability. No core architecture changed.

Building What Doesn’t Exist

The real power of this pattern isn’t that the skill starts with a set of scripts. It’s that the skill can grow mid-session.

A user asks: “Can you link PROJ-123 as blocked by PROJ-456?” The agent checks the routing table, no script for linking issues. In a fixed skill, that’s a dead end. With the wrapper pattern, the agent runs an ad-hoc query:

node --input-type=module <<'EOF'
import { jiraRequest } from './scripts/lib/jira.mjs';
const res = await jiraRequest('/issueLink', {
  method: 'POST',
  body: JSON.stringify({
    type: { name: 'Blocks' },
    inwardIssue: { key: 'PROJ-456' },
    outwardIssue: { key: 'PROJ-123' },
  }),
});
console.log('Linked PROJ-123 ← Blocks ← PROJ-456');
EOF

It works. The query proves useful, and the agent promotes it into scripts/jira/link-issues.mjs, adds a row to the routing table:

| Link two issues          | scripts/jira/link-issues.mjs     |

The skill now has a new capability. No manual wiring needed.

The wrapper functions as a stable contract: every generated script can assume auth, pagination, error handling, and output formatting exist. That dramatically reduces the complexity of generated code. The agent doesn’t need to reason about authentication flows or error responses every time it writes a script. The wrapper has already solved those problems.

The agent generates the business logic. The wrapper provides the infrastructure. That’s the separation that makes expansion reliable.

The Author’s Role Shifts

Without this pattern, the author writes every script. With it, the author designs two things:

  1. The wrapper library: auth, request handling, CSRF headers, pagination, error formatting
  2. The extension rules: how to register new scripts, how to update the routing table, what trigger phrases to add

The skill grows based on what users actually need, not what the author anticipated.

Limitations

This pattern isn’t universal. A few things to keep in mind:

Wrapper quality is everything: If the wrapper is poorly designed, every generated script inherits those flaws. Bad error messages, missing edge cases, inconsistent auth, all of it compounds.

Complexity ceiling: This pattern works exceptionally well for REST APIs, CRUD operations, and infrastructure/DevOps tooling. It’s less suited for complex reasoning workflows, multi-agent orchestration, long-running business processes, or tasks requiring significant state management. Know where the boundary is.

No guardrails by default: An agent could write a bulk-delete or mass-update script without thinking twice. The wrapper should enforce read-only defaults and require explicit opt-in for destructive mutations.

No testing layer: Agent-generated scripts aren’t validated. A broken script gets registered and used until someone notices. If reliability matters, you need a validation step before registration.

Takeaway

Design the abstraction layer, not the capability catalog. A well-designed wrapper becomes a stable contract that lets agents create new capabilities safely and consistently. The scripts are disposable; the wrapper is the real product.


I used this pattern in my atlassian-jira-skill and bitbucket-datacenter-skill, where wrapper libraries let the agent mint new API scripts on demand and evolve each skill with new capabilities as needs arise.

Try It Yourself

npx skills add abidhmuhsin/skilladi@jira
npx skills add abidhmuhsin/skilladi@bitbucket-datacenter

Read next

Closest to this one
  1. 01Wiring Feedback Loops Into Agent SkillsArticle · 4 min
  2. 02agent-skills ↗Open source · 2026
  3. 03Building dockyard: A Zero-Dependency Docker Dashboard for Developer MachinesArticle · 6 min