How to Add a New Job Portal Skill to AI Job Search: Complete Developer Guide
AI Job Search discovers job-portal integrations as self-contained CLI skills under the .agents/skills/ directory, requiring only a SKILL.md metadata file and a cli/ executable folder to automatically register with the framework.
The AI Job Search repository (MadsLorentzen/ai-job-search) implements a modular skill system that treats each job portal integration as a standalone micro-CLI. When you add a new portal skill following the established contract, the /scrape workflow automatically detects and executes it without requiring modifications to core framework code. This article explains how to add a new job portal skill to AI Job Search using either the automated generator or manual implementation.
Understanding the Job Portal Skill Contract
Every portal skill in AI Job Search must adhere to a strict directory structure and behavioral contract. The framework automatically loads any skill matching this layout under .agents/skills/.
A valid skill requires these components:
SKILL.md– Contains human-readable description, theenabled:flag, supported commands, and usage contractcli/– Directory containing the executable TypeScript/JavaScript source code and a minimalpackage.json- Search command – The CLI must expose a
searchcommand that accepts--queryand--formatparameters - Optional detail command – Additional
detailcommand for fetching specific job postings - Offline tests – A
bun testsuite that validates the contract without network calls
The CLI must return results in the unified format used by existing Danish portal skills (jobbank-search, jobdanmark-search, jobindex-search, jobnet-search). According to the source implemented in .claude/commands/add-portal.md, the framework inspects the enabled: flag in each SKILL.md to determine whether to activate the skill during scraping operations.
Method 1: Using the Built-in /add-portal Command
The recommended approach for adding a new job portal skill uses the interactive generator available in Claude Code.
Step 1: Execute the Generator
Run the following command inside your Claude Code environment:
/add-portal
When prompted, provide the base URL of the job board you wish to integrate (for example, https://examplejobs.com).
Step 2: Review the Scaffold
The command performs several automated operations as defined in .claude/commands/add-portal.md:
- Inspects the URL to infer search-query patterns and result page structure
- Creates the directory
.agents/skills/<name>-search/ - Generates
SKILL.mdwithenabled: trueand command definitions - Scaffolds
cli/package.jsonwith zero runtime dependencies - Creates
cli/index.tswith a startersearchimplementation - Adds
__tests__/skill.test.tswith offline validation tests - Executes a live query to verify the generated CLI works
Step 3: Install Dependencies
Navigate to the generated CLI directory and install development dependencies:
cd .agents/skills/examplejobs-search/cli
bun install
The generated skill contains zero runtime dependencies; bun install only pulls type definitions for development.
Step 4: Verify the Skill
Run the test suite to confirm the skill meets the contract:
bun test
The tests must pass without performing real network I/O, as they validate the CLI argument parsing and output format compliance.
Method 2: Creating a Skill Manually
For full control over the implementation, create the skill structure manually following the template used by existing integrations.
Required Directory Structure
Create the following layout under .agents/skills/:
.agents/
└── skills/
└── myportal-search/
├── SKILL.md
└── cli/
├── package.json
├── index.ts
└── __tests__/
└── skill.test.ts
Configuring SKILL.md
The SKILL.md file must contain the enabled: flag and command documentation. Refer to the pattern used in .agents/skills/<portal>-search/SKILL.md:
---
name: examplejobs-search
enabled: true
description: |
Search integration for ExampleJobs.com (global tech job board).
commands:
- search: |
bun run cli/index.ts --query "<keywords>" --format json
- detail: |
bun run cli/index.ts --detail "<job-id>" --format json
Implementing the CLI Interface
The cli/index.ts file must implement the search contract. Here is a minimal implementation skeleton:
#!/usr/bin/env bun
import { argv } from 'bun';
async function search(query: string, format: string) {
// Implementation should fetch from the job portal API
// and output in the unified JSON/table/plain format
const results = await fetchJobResults(query);
if (format === 'json') {
console.log(JSON.stringify(results, null, 2));
} else if (format === 'table') {
console.table(results);
} else {
console.log(results.map(r => r.title).join('\n'));
}
}
async function main() {
const query = argv.find(arg => arg.startsWith('--query='))?.split('=')[1] ?? '';
const format = argv.find(arg => arg.startsWith('--format='))?.split('=')[1] ?? 'json';
if (!query) {
console.error('Missing --query argument');
process.exit(1);
}
await search(query, format);
}
main();
The CLI must support --query "<keywords>" and --format json|table|plain arguments to remain compatible with the /scrape workflow.
Testing Requirements
The __tests__/skill.test.ts file must validate the contract without network calls. Use mocking or stubbing to test argument parsing and output formatting:
bun test
As noted in the repository's README (lines 29-34), all tests must run offline to ensure CI/CD reliability.
Security Considerations for New Skills
Before running a newly generated skill, inspect the cli/package.json to verify:
- No runtime dependencies – The scaffold generates skills with zero runtime dependencies; inspect for unexpected additions
- No postinstall scripts – Ensure no lifecycle scripts execute during
bun install - Network scope verification – Confirm all network requests target only the intended job board domain
This security practice mirrors the guidance in the README section regarding borrowing portal skills from other forks.
Summary
- AI Job Search automatically discovers skills in
.agents/skills/that contain a validSKILL.mdwithenabled: true - Use
/add-portalfor automated scaffolding or create the directory structure manually for custom implementations - Each skill requires a
cli/folder with asearchcommand supporting--queryand--formatparameters - Skills must output results in the unified JSON format used by existing Danish portal integrations
- Tests must run offline using
bun testwithout performing actual network requests - Verify
package.jsonfor security issues before executing new skills
Frequently Asked Questions
What file format does the SKILL.md use?
SKILL.md uses YAML frontmatter with a markdown body. The file must contain an enabled: boolean flag (set to true to activate the skill) and a commands: section listing the available CLI operations. The framework parses this metadata to determine which skills to load during the /scrape workflow.
Can I add a job portal skill without using the /add-portal command?
Yes. You can manually create the directory structure under .agents/skills/<portal-name>/ following the contract specifications. Ensure you include SKILL.md, cli/package.json, cli/index.ts with the search implementation, and offline tests. The /scrape command will automatically detect your skill as long as the enabled: flag is set to true in the metadata file.
Why must skills have zero runtime dependencies?
The zero-dependency requirement ensures security and performance. According to the repository's security guidelines, skills should not rely on external packages that could introduce supply-chain vulnerabilities or execute postinstall scripts. The package.json should only contain devDependencies for type definitions, keeping the runtime footprint minimal and auditable.
How do I test my new job portal skill without making real API calls?
Write unit tests in __tests__/skill.test.ts that mock the fetch calls or network interfaces. Use the bun test runner to validate that your CLI correctly parses arguments (--query and --format) and produces output matching the expected schema. The test suite must pass entirely offline, validating the contract without hitting the actual job board's API.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →