How to Add a New Job Portal to the ai-job-search CLI: The Complete Guide

Adding a new job portal to the ai-job-search CLI requires running the /add-portal command to scaffold a zero-dependency portal skill in .agents/skills/ that implements the required search and detail commands, passes a live query test, and automatically integrates into the /scrape workflow.

The ai-job-search framework by MadsLorentzen discovers job listings through modular portal skills—self-contained CLIs located in .agents/skills/. Each portal skill follows a strict contract defined in .claude/commands/add-portal.md so that the core workflow can invoke any job portal transparently without modifying the underlying scraper code.

Understanding the Portal-Skill Contract

Every portal skill must conform to a strict interface contract documented in the Add-Portal command specification. This contract ensures that the core /scrape workflow can discover and execute any portal skill uniformly.

Required CLI Commands and Flags

Each portal skill must expose two primary commands: search and detail. Both commands must support the following flag set:

  • --query (search term)
  • --jobage (maximum age of postings)
  • --page (pagination)
  • --limit (results per page)
  • --format (output format)

According to the contract in .claude/commands/add-portal.md, these flags enable the generic scraper to pass consistent parameters across all portals.

JSON Output Specification

The search command must emit JSON shaped exactly as { "meta":…, "results":[…] }, where each result object contains the fields id, title, company, location, date, and url. Errors must be written to stderr as JSON with exit code 1. This standardized output allows the generic scraper in .claude/skills/job-scraper/SKILL.md to parse results from any portal without custom adapters.

Step-by-Step Guide to Adding a New Portal

The /add-portal command orchestrates a guided interview process to scaffold a new portal skill. The workflow copies the canonical structure from the reference linkedin-search skill, which serves as the zero-dependency example implementation.

Step 1: Initialize the Interview

Run the /add-portal command with a target URL to begin the guided process:

claude /add-portal https://www.seek.com.au

If you omit the URL, the command starts an interactive interview. During this phase, you provide:

  • A kebab-case skill name ending in -search (e.g., seek-search)
  • Market and language (e.g., Australia (English))
  • A realistic test query for validation

Step 2: Investigate the Portal Structure

The command prompts you to investigate the portal's architecture using WebFetch or curl. You must document:

  • The search URL pattern and query parameters
  • Result field mappings (id, title, company, location, date, url)
  • The detail page URL pattern
  • Access constraints (robots.txt, authentication requirements, ToS)

These findings are recorded in url-reference.md for later reference during implementation.

Step 3: Scaffold the Skill Files

The generator creates the directory .agents/skills/<name>/ with the following structure:

.agents/skills/<name>/
├── SKILL.md                # Skill definition and trigger phrases

├── url-reference.md        # Endpoint documentation

└── cli/
    ├── package.json
    ├── tsconfig.json
    ├── README.md
    ├── src/
    │   ├── cli.ts         # Entry point and argument dispatch

    │   ├── helpers.ts     # Fetching with exponential back-off

    │   └── commands/
    │       ├── search.ts  # Implements search logic

    │       └── detail.ts  # Implements detail fetching

    └── tests/
        └── helpers.ts

This scaffold includes a full TypeScript CLI skeleton with zero runtime dependencies, mirroring the linkedin-search reference implementation.

Step 4: Run Live Tests

After scaffolding, install dev dependencies and type-check the code:

cd .agents/skills/seek-search/cli
bun install
bun run typecheck

Execute a live search using your test query to verify the implementation:

bun run src/cli.ts search -q "software engineer" --limit 5 --format table

The result set must contain non-null values for id, title, and url. Next, verify the detail command:

bun run src/cli.ts detail 12345678 --format plain

Finally, run the generated test suite:

bun run test

Step 5: Register the Portal

Once the live test passes, append the portal's domain to .claude/skills/job-scraper/search-queries.md so that /scrape includes it in future searches:

echo "seek.com.au" >> .claude/skills/job-scraper/search-queries.md

The core scraper automatically discovers installed portal skills by reading every SKILL.md under .agents/skills/*/, requiring no further code changes.

Testing Requirements and Validation

The ai-job-search framework enforces strict validation before a portal skill can be used in production. The live query test in Step 4 is mandatory and validates that:

  1. The search command returns at least one result with valid id, title, and url fields
  2. The detail command successfully retrieves full posting information
  3. Error handling writes JSON to stderr with exit code 1
  4. Zero runtime dependencies are maintained (only dev types allowed)

These requirements ensure that the core scraper in .claude/skills/job-scraper/SKILL.md can orchestrate parallel searches across all portals without compatibility issues.

Integration with the Core Scraper

Once registered, the portal skill integrates automatically with the main workflow. The core scraper reads the declarative SKILL.md files from .agents/skills/*/ to discover available portals. When you invoke claude /scrape, the system:

  1. Identifies all installed portal skills
  2. Invokes their search commands with the appropriate flags
  3. Aggregates the standardized JSON outputs
  4. Executes detail commands for specific postings when needed

This architecture means that adding a new job portal requires no modifications to the core scraper code—only the creation of a conforming portal skill in .agents/skills/.

Summary

  • Run /add-portal to start the guided interview process for creating a new job portal skill
  • Portal skills must implement search and detail commands with specific flags (--query, --jobage, --page, --limit, --format) and JSON output
  • The scaffold generates a zero-dependency TypeScript CLI in .agents/skills/<name>/ based on the linkedin-search reference
  • Mandatory live testing ensures the portal returns valid id, title, and url fields before registration
  • Register the portal by adding its domain to .claude/skills/job-scraper/search-queries.md for automatic inclusion in /scrape workflows

Frequently Asked Questions

The portal-skill contract is a strict interface specification defined in .claude/commands/add-portal.md that requires every portal skill to expose search and detail commands with standardized flags (--query, --jobage, --page, --limit, --format). The contract mandates JSON output shaped as { "meta":…, "results":[…] } containing fields id, title, company, location, date, and url, with errors written to stderr as JSON. This standardization allows the core scraper to invoke any portal skill transparently.

Where are portal skills stored in the ai-job-search repository?

Portal skills are stored in the .agents/skills/ directory, with each skill residing in its own subdirectory named using kebab-case (e.g., .agents/skills/linkedin-search/). Each skill directory contains a SKILL.md file defining its capabilities, a url-reference.md documenting the portal's endpoints, and a cli/ subdirectory containing the TypeScript implementation with src/commands/search.ts and src/commands/detail.ts.

How does the core scraper discover new portal skills?

The core scraper, defined in .claude/skills/job-scraper/SKILL.md, automatically discovers portal skills by reading the SKILL.md files in every subdirectory of .agents/skills/*/. It uses the declarative metadata in these files to determine available trigger phrases and invokes the respective CLI commands with the standardized flag set. No manual registration in the scraper code is required—only adding the domain to search-queries.md and ensuring the skill exists in .agents/skills/.

What are the testing requirements for a new job portal skill?

Every new portal skill must pass a mandatory live query test before integration. You must run a real search using bun run src/cli.ts search -q "<query>" and verify that the returned JSON contains non-null values for id, title, and url. Additionally, you must test the detail command with a specific job ID and run the full test suite with bun run test. The skill must maintain zero runtime dependencies and handle errors by writing JSON to stderr with exit code 1.

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 →