How to Create a New Job Portal Search Skill for Non‑Danish Boards Using `/add-portal`

Use the /add-portal command-line generator to scaffold a complete job-portal search skill from any public job board URL in under five minutes, following the zero-dependency contract established in the MadsLorentzen/ai-job-search repository.

The MadsLorentzen/ai-job-search repository provides a command-line generator called /add-portal that transforms any public job board—such as Seek, StepStone, or Indeed—into a fully-featured search skill compatible with the AI job search workflow. This tool is specifically designed for non-Danish boards, following a strict seven-step interview and scaffolding process that ensures consistency with existing skills like linkedin-search.

The Seven-Step /add-portal Workflow

The generator, implemented in .claude/commands/add-portal.ts and specified in .claude/commands/add-portal.md, enforces a repeatable process from URL to working CLI.

Step 1: Parse Arguments

The command accepts an optional --list flag to display existing portal skills or a portal URL to skip the initial prompt.


# List existing skills

bun run .claude/commands/add-portal.ts --list

# Start with a specific URL

bun run .claude/commands/add-portal.ts https://www.seek.com.au

If no URL is provided, the generator starts an interactive interview.

Step 2: Interview for Portal Basics

The generator prompts for four critical pieces of information:

  • Portal URL: The base domain of the job board (e.g., https://www.stepstone.de)
  • Skill name: A kebab-case identifier (e.g., seek-search, stepstone-search)
  • Market & language: The geographic region and language code (e.g., "Australia – English")
  • Test query: A realistic search term for live validation (e.g., "Data Engineer")

Step 3: Investigate the Portal Structure

The tool analyzes the target site to determine:

  • Search URL patterns and query parameters
  • HTML result fields and pagination logic
  • Detail-page URL construction
  • Access rules (robots.txt, rate limits, API availability)

This investigation is documented in url-reference.md within the generated skill folder.

Step 4: Scaffold the Skill Files

The generator copies the canonical structure from the reference skill at .agents/skills/linkedin-search/ to create:


.agents/skills/<skill-name>/
├── SKILL.md                 # Trigger phrases and description

├── url-reference.md         # Endpoint documentation from Step 3

└── cli/
    ├── package.json
    ├── tsconfig.json
    ├── README.md
    ├── src/
    │   ├── cli.ts           # Argument parsing and help

    │   ├── helpers.ts       # Fetch logic, backoff, and parsers

    │   └── commands/
    │       ├── search.ts    # Main search implementation

    │       └── detail.ts    # Job detail fetcher

    └── tests/
        └── helpers.ts       # CLI test utilities

Step 5: Enforce the Portal-Skill Contract

Every generated skill must satisfy the portal-skill contract defined in the source specification:

  • Zero-runtime-dependency policy: Only bun/node standard library; no external npm packages in production code
  • Standardized search flags: -q (query), --limit, --format (json|table|plain)
  • JSON output shape: Consistent field names (id, title, company, location, url, posted_at)
  • Error handling: Graceful degradation with exit codes 0 (success) and 1 (failure)

Step 6: Test-Run a Live Query

Before registration, you must validate the skill against the real site:

cd .agents/skills/<skill-name>/cli

# Install dev dependencies (types only)

bun install

# Type check the TypeScript

bun run typecheck

# Execute live search

bun run src/cli.ts search -q "Data Engineer" --limit 5 --format table

# Fetch a specific job detail

bun run src/cli.ts detail <job-id> --format plain

# Run unit tests

bun run test

Step 7: Register the Skill

Optionally, the generator can append the new portal to the global scrape strategy in .claude/skills/job-scraper/search-queries.md. This registration allows the /scrape command to include your new board in multi-site search workflows.

Reference Implementation Structure

When examining the generated .agents/skills/<skill-name>/cli/src/ directory, you will find:

  • cli.ts: Handles argument parsing using process.argv and routes to search or detail commands
  • helpers.ts: Contains fetchWithBackoff() for HTTP requests and HTML parsing utilities using standard Bun APIs
  • commands/search.ts: Implements the search logic, normalizing the portal's HTML structure into the required JSON contract
  • commands/detail.ts: Fetches individual job pages and extracts full descriptions

This structure mirrors the canonical linkedin-search skill, ensuring that all skills behave identically despite targeting different job boards.

To integrate your new portal into the assistant's global search capabilities, the generator updates .claude/skills/job-scraper/search-queries.md with site-specific query templates. This file contains the site-specific search strategies used by the /scrape command when running multi-portal job searches.

If you decline automatic registration during the interview phase, you can manually add an entry following the markdown format established in that file, specifying the skill name and base URL pattern.

Summary

  • Use /add-portal to scaffold job-portal skills for any non-Danish public job board through a guided seven-step process
  • Follow the zero-dependency contract by keeping runtime code free of external npm packages and adhering to standardized JSON output shapes
  • Test live queries before registration using bun run src/cli.ts search with --format table for immediate visual validation
  • Register globally by allowing the generator to append your portal to .claude/skills/job-scraper/search-queries.md
  • Reference linkedin-search in .agents/skills/ as the canonical example of a compliant portal skill implementation

Frequently Asked Questions

What job boards work with /add-portal?

Any publicly accessible job board that does not require authentication for search results works with /add-portal. The generator specifically targets non-Danish boards such as Seek (Australia), StepStone (Germany), or Indeed (global), but the scaffold works for any site with crawlable HTML job listings.

Why must generated skills have zero runtime dependencies?

The zero-runtime-dependency policy ensures that every portal skill remains lightweight and secure, relying only on the bun JavaScript runtime standard library. This design prevents dependency rot, reduces security vulnerabilities, and guarantees that skills continue functioning months after creation without maintenance updates for third-party packages.

How do I update a skill after the portal changes its HTML structure?

Navigate to .agents/skills/<skill-name>/cli/src/helpers.ts and modify the CSS selectors or parsing logic in the extractJobs() function. After editing, rerun bun run typecheck and execute the live test query (bun run src/cli.ts search -q "test") to verify the fix before committing changes to your fork.

Can I use /add-portal for private APIs or authenticated job boards?

No. The /add-portal generator and the resulting skills are designed for public HTML scraping only. The scaffold does not include authentication handlers, API key management, or OAuth flows. For authenticated sources, you would need to manually extend the generated helpers.ts with authentication logic, though this violates the zero-dependency contract maintained by the repository.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →