What Is the Skill Contract for Job Portal Skills in the AI Job Search Framework?

The AI Job Search framework enforces a strict portal-skill contract that requires every job portal CLI to expose search and detail sub-commands with standardized JSON output, specific error handling to stderr, and zero runtime dependencies to ensure seamless interchangeability across the /scrape workflow.

The MadsLorentzen/ai-job-search repository establishes a rigorous skill contract for job portal skills that governs how automated scraping tools must behave within the ecosystem. This contract ensures all portal skills remain interchangeable for the /scrape workflow while maintaining consistent behavior for both local users and CI pipelines. Every generated CLI must adhere to specifications documented in .claude/commands/add-portal.md and summarized in CONTRIBUTING.md to pass automated validation.

Required CLI Commands and Interface

Every portal skill must expose exactly two sub-commands via its CLI entry point to maintain compatibility with the framework's orchestration layer.

The search Command

The search command must accept standardized flags and return paginated job listings. According to .claude/commands/add-portal.md, implementations must support:

  • --query or -q for search terms
  • --jobage <days> to filter by posting recency
  • --page <n> using 1-indexed pagination
  • --limit <n> as a client-side cap on results returned
  • --format json|table|plain with json as the default output format
  • --location or -l (optional, only if the portal supports geographic filtering)

The detail Command

The detail <id|url> command retrieves comprehensive information about a specific job posting. This command accepts a positional identifier argument and supports the same --format flag available in the search command.

Standardized JSON Output Schema

Portal skills must emit structured JSON matching a strict schema to ensure downstream parsers can process results uniformly across different job portals.

Search Results Format

The search command must output JSON adhering to this exact structure:

{
  "meta": {
    "count": 42,
    "page": 1
  },
  "results": [
    {
      "id": "12345",
      "title": "Software Engineer",
      "company": "Acme Corp",
      "location": "Copenhagen",
      "date": "2024-08-28",
      "url": "https://example.com/job/12345"
    }
  ]
}

Missing values must be set to null rather than omitted entirely to maintain schema consistency.

Error Output Format

Errors are printed to stderr as JSON objects containing error and code fields, and the process must exit with code 1. No error text is ever written to stdout.

bun run .agents/skills/example-portal/cli/src/cli.ts detail 12345 --format plain

Typical error output:

{
  "error": "Missing required flag --query",
  "code": "MISSING_FLAG"
}

HTTP Conventions and Resilience

Portal skills must implement robust fetching behavior that respects web infrastructure while maintaining reliability under failure conditions.

User-Agent and Retry Logic

Use an honest user-agent string formatted as Mozilla/5.0 (compatible; <portal>-cli/1.0). When encountering HTTP 429 or 5xx status codes, implement exponential back-off with jitter for a maximum of approximately six retries. Return empty strings or null for 404 responses rather than crashing.

Credential Management

If a portal requires an API token, read it only from an environment variable named <SERVICE>_API_TOKEN. Abort with a JSON error using code: "MISSING_CREDENTIALS" if the variable is unset. Never expose tokens in documentation, tests, or source code.

Implementation Constraints

The contract imposes strict technical limitations to ensure portability, security, and maintainability across the skill ecosystem.

Zero Runtime Dependencies

Skills should default to zero runtime dependencies, utilizing only bun, native fetch, and regex for parsing. Add a parsing library only if markup cannot be handled with regex, and document this architectural decision in the skill's SKILL.md file.

Fault-Tolerant HTML Parsing

Parse each result independently so malformed cards do not break the entire response. The reference implementation in .agents/skills/linkedin-search/cli/src/helpers.ts demonstrates this defensive pattern via the parseJobCards function.

When robots.txt or Terms of Service restrict automated access, the generated SKILL.md must include a prominent "⚠️ Personal use only" notice, mirroring the linkedin-search skill's approach documented in CONTRIBUTING.md.

CI Enforcement and Validation

The framework automatically enforces the skill contract for job portal skills through continuous integration. The cli-checks job in .github/workflows/ci.yml discovers every .agents/skills/*/cli/package.json and executes the skill's typecheck and test scripts on each push. This ensures that new portal implementations maintain compatibility with the contract before merging into the repository.

Summary

  • Every portal skill must implement search and detail <id|url> sub-commands with specific flags including --query, --jobage, and --format.
  • Output must conform to a strict JSON schema with meta and results fields, while errors go to stderr as JSON with exit code 1.
  • Implement exponential back-off with jitter for retries, use honest user-agents, and return null for 404s rather than crashing.
  • Maintain zero runtime dependencies where possible, parse HTML defensively using patterns like parseJobCards, and never hardcode API credentials.
  • Include "Personal use only" warnings when scraping restrictions apply, and validate all implementations via the automated cli-checks CI workflow.

Frequently Asked Questions

What happens if a portal skill violates the contract?

The CI pipeline will reject the contribution. The cli-checks job automatically validates every portal skill against the contract requirements by running typecheck and test scripts defined in each skill's package.json, ensuring non-compliant code cannot merge into the repository.

Why does the contract mandate zero runtime dependencies?

This constraint maximizes portability and minimizes security surface area. By relying only on bun, native fetch, and regex, skills remain lightweight and avoid dependency drift or supply-chain vulnerabilities while maintaining fast installation times across different environments.

How should portal skills handle missing API tokens?

Skills must check for the <SERVICE>_API_TOKEN environment variable and exit with code 1, printing a JSON error to stderr with code: "MISSING_CREDENTIALS". This standardized error format allows orchestration tools to detect authentication failures programmatically without parsing stdout.

Where is the portal-skill contract documented?

The complete specification lives in .claude/commands/add-portal.md, while CONTRIBUTING.md provides a concise summary for contributors. Reference implementations demonstrating compliant HTML parsing and CLI structure are available in .agents/skills/linkedin-search/cli/.

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 →