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/nodestandard 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 usingprocess.argvand routes tosearchordetailcommandshelpers.ts: ContainsfetchWithBackoff()for HTTP requests and HTML parsing utilities using standardBunAPIscommands/search.ts: Implements the search logic, normalizing the portal's HTML structure into the required JSON contractcommands/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.
Adding Non-Danish Boards to Global Search
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-portalto 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 searchwith--format tablefor immediate visual validation - Register globally by allowing the generator to append your portal to
.claude/skills/job-scraper/search-queries.md - Reference
linkedin-searchin.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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →