# How /add-portal Scaffolds New Job Board Skills Through Investigation and Test Runs

> Learn how the /add-portal command builds job board skills. It investigates APIs, scaffolds TypeScript CLIs, and validates live data for seamless registration.

- Repository: [Mads Lorentzen/ai-job-search](https://github.com/MadsLorentzen/ai-job-search)
- Tags: how-to-guide
- Published: 2026-07-19

---

**The `/add-portal` command is a guided wizard that creates production-ready job-portal search skills by first investigating the target site's API structure, scaffolding a TypeScript CLI with zero runtime dependencies, and mandating validation against live data before automatic registration.**

The `MadsLorentzen/ai-job-search` repository treats job boards as modular, interchangeable skills. The `/add-portal` command implements a rigorous seven-step pipeline defined in [`.claude/commands/add-portal.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/commands/add-portal.md) that ensures every generated scraper conforms to a unified contract and functions correctly on real-world data before entering the workflow.

## The Seven-Step Pipeline

The command follows a strict **investigation-first, test-run-last** methodology. Each phase is encoded in the command definition with specific line ranges governing the logic.

### Step 0: Parse Arguments

The wizard begins by detecting invocation flags. If you pass `--list`, the command globs all [`SKILL.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/SKILL.md) files under `.agents/skills/*/SKILL.md`, prints a formatted table of existing portal skills, and exits immediately【L13-L18】.

```bash
/add-portal --list

```

Otherwise, the command accepts an optional portal URL and proceeds to the interview phase.

### Step 1: Interactive Portal Interview

The wizard prompts for four critical inputs【L21-L29】:

- **Portal URL** – The root address of the job board
- **Skill name** – Kebab-case identifier ending in `-search`
- **Market and language** – Geographic and linguistic context
- **Test query** – A realistic search term for validation

```bash
/add-portal

# ❓ Portal URL: https://www.stepstone.de

# ❓ Skill name: stepstone-search

# ❓ Market: Germany (German)

# ❓ Test query: Software Engineer

```

### Step 2: Technical Investigation

Before writing code, the command performs manual reconnaissance via WebFetch or `curl` to document the portal's structure【L32-L44】. This investigation records:

- Search endpoint patterns and query parameters
- Response field mappings (id, title, company, location)
- Detail-page URL constructions
- Robots.txt restrictions and terms of service compliance

Findings are preserved in the generated [`url-reference.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/url-reference.md) for future maintenance.

### Step 3: Directory and Code Scaffolding

Using the canonical `linkedin-search` skill as a template, the wizard creates `.agents/skills/<name>/` containing【L48-L70】:

- **[`SKILL.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/SKILL.md)** – Skill definition, trigger phrases, and personal-use warnings
- **[`url-reference.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/url-reference.md)** – Endpoint documentation from Step 2
- **`cli/`** – A minimal TypeScript project with [`package.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/package.json), [`tsconfig.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tsconfig.json), source files, and tests

All generated code obeys the **portal-skill contract**【L72-L82】: standardized commands (`search`, `detail`), consistent JSON output shapes, robust error handling, and a **zero-runtime-dependency policy** (only dev types are installed).

### Step 4: Mandatory Live Testing

The pipeline enforces a real-world validation check【L94-L113】. The wizard automatically executes:

1. `bun install && bun run typecheck` – Verifies TypeScript compilation
2. `search` command with the test query – Confirms ≥1 result with non-null fields
3. `detail` command on a live ID – Validates description readability
4. `bun run test` – Executes the shipped test suite

If any check fails, you must iterate on parsers in [`cli/src/commands/search.ts`](https://github.com/MadsLorentzen/ai-job-search/blob/main/cli/src/commands/search.ts) or [`detail.ts`](https://github.com/MadsLorentzen/ai-job-search/blob/main/detail.ts) until output is clean.

```bash
cd .agents/skills/stepstone-search/cli
bun install
bun run src/cli.ts search -q "Software Engineer" --limit 5 --format table

```

### Step 5: Auto-Registration

Upon successful live testing, the skill becomes immediately discoverable by the `/scrape` command because the CLI resides under `.agents/skills/*`【L119-L128】. Optionally, you may append placeholder queries to [`.claude/skills/job-scraper/search-queries.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/job-scraper/search-queries.md).

### Step 6: Confirmation

The wizard prints a summary of the generated skill, the live test outcome, and sample commands for manual invocation【L133-L145】.

## The Portal-Skill Contract

The scaffolded skills are interchangeable because they implement a strict contract defined in the command specification. Key requirements include:

- **Standardized entry points** – Every skill exposes `search` and `detail` subcommands via [`cli/src/cli.ts`](https://github.com/MadsLorentzen/ai-job-search/blob/main/cli/src/cli.ts)
- **Uniform JSON schema** – Results must include id, title, company, location, and date fields
- **Zero runtime dependencies** – The CLI relies only on Bun/Node built-ins plus dev-only type definitions
- **Resilient fetching** – The generated [`cli/src/helpers.ts`](https://github.com/MadsLorentzen/ai-job-search/blob/main/cli/src/helpers.ts) includes back-off logic and respects robots.txt

## Summary

- **Investigation precedes scaffolding** – The `/add-portal` command documents endpoints and terms of service before generating code.
- **Live validation is mandatory** – Skills cannot register until they return real data from the target portal.
- **Strict contracts ensure interoperability** – All skills use kebab-case names ending in `-search`, share identical CLI patterns, and output consistent JSON shapes.
- **Reference-based generation** – New skills clone the structure from `linkedin-search` to guarantee best-practice patterns.

## Frequently Asked Questions

### What happens if the live test fails?

The wizard halts and reports specific errors—whether from TypeScript compilation, empty result sets, or malformed detail pages. You must fix the parsers in `cli/src/commands/` and re-run `bun run test` until the output conforms to the schema before the skill becomes discoverable.

### Why must skill names end with "-search"?

The suffix enforces a glob pattern used by `/scrape` to discover portal skills under `.agents/skills/*-search/`. This convention separates job-board integrations from other skill types while maintaining predictable directory structures.

### How does the scaffolded CLI respect rate limits?

The generated [`cli/src/helpers.ts`](https://github.com/MadsLorentzen/ai-job-search/blob/main/cli/src/helpers.ts) implements exponential back-off and observes the [`robots.txt`](https://github.com/MadsLorentzen/ai-job-search/blob/main/robots.txt) directives discovered during Step 2. This lightweight approach, part of the zero-runtime-dependency policy, prevents overwhelming target servers.

### Can I extend the generated skill after scaffolding?

Yes. The TypeScript project under `.agents/skills/<name>/cli/` is fully editable. You may add filters, custom parsers, or additional commands, provided you maintain the **portal-skill contract**—specifically the JSON output shape and error handling required by the `/scrape` workflow.