# How to Contribute to the ai-job-search Project: A Complete Guide

> Contribute to the ai-job-search project by submitting features, fixes, or docs. Learn how to add value while respecting the project's architecture in this complete guide.

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

---

**You can contribute to ai-job-search by submitting universal customization features, robustness fixes, or documentation improvements, following the three contribution buckets defined in [`CONTRIBUTING.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CONTRIBUTING.md) while maintaining the repository's thin-pointer architecture.**

The ai-job-search repository by MadsLorentzen is a thin-pointer framework designed for AI-assisted job searching that remains market-agnostic and Claude-Code-native. To contribute effectively, you must understand its modular architecture and adhere to the universal-template rule that preserves the codebase's fork-friendly design.

## Understanding the Repository Architecture

The project organizes functionality into three distinct layers to separate concerns and maintain portability.

### Canonical Workflow Definitions

Core candidate profiles, evaluation criteria, and command specifications reside under the `.claude/` directory. For example, the `/apply` workflow is defined in [`.claude/commands/apply.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/commands/apply.md)【/cache/repos/github.com/MadsLorentzen/ai-job-search/master/README.md#L371-L382】. These markdown files define the CLI commands that users invoke during their job search workflows.

### Portal-Search Skills

Each job-board integration lives as a standalone skill in `.agents/skills/<portal>/cli`. The contract specifying search commands, detail retrieval, JSON output formats, and error handling is documented in each skill's [`SKILL.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/SKILL.md) file. For instance, the LinkedIn integration is defined at [`.agents/skills/linkedin-search/SKILL.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.agents/skills/linkedin-search/SKILL.md)【/cache/repos/github.com/MadsLorentzen/ai-job-search/master/README.md#L196-L202】.

### Utility Scripts and CI Helpers

Scripts such as [`tools/lint_skills.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/lint_skills.py) and [`tools/check_upstream_updates.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/check_upstream_updates.py) enforce code quality and help contributors preview upstream changes before submitting【/cache/repos/github.com/MadsLorentzen/ai-job-search/master/README.md#L218-L226】.

## Contribution Categories

According to the source code in [`CONTRIBUTING.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CONTRIBUTING.md), contributions must fall into one of three specific buckets【/cache/repos/github.com/MadsLorentzen/ai-job-search/master/CONTRIBUTING.md#L9-L13】:

**Universal customization features** add new commands like `/add-template` or `/add-portal` that benefit every fork of the repository. These belong in `/.claude/commands/` as new command markdown files, or as new skill folders under `.agents/skills/`.

**Robustness and correctness fixes** address reproducible bugs on the master branch, such as NaN validation failures or HTML entity decoding issues. These changes belong in the relevant source file (Python, TypeScript, or LaTeX) accompanied by unit tests in the appropriate `tests/` or `cli/tests/` directory.

**Documentation improvements** include clarifications for setup procedures, platform-specific instructions, or corrections to stale links. These modifications target [`README.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/README.md), [`SETUP.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/SETUP.md), [`SECURITY.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/SECURITY.md), or other root-level markdown files.

## Step-by-Step Contribution Workflow

Follow this standardized process to ensure your pull request meets the acceptance criteria:

1. **Fork the repository** on GitHub and create a feature branch for your changes.

2. **Implement your changes** following the architectural guidelines above.

3. **Run the CI suite locally** to validate your modifications:

   ```bash
   python3 tools/lint_skills.py
   python3 tools/check_framework_version.py
   python3 tools/security_guards.py
   python3 -m unittest discover -s tests
   ```

4. **Test skill-specific changes** if you modified or added a job board CLI:

   ```bash
   cd .agents/skills/<portal-name>/cli
   bun run typecheck
   bun test
   ```

5. **Open a Pull Request** against the upstream `master` branch, referencing relevant issue numbers and including a concise description of what changed and why it matters. The PR will be evaluated first for compliance with the universal-template rule, then for correctness and test coverage.

## Adding New Portal Skills

To integrate a new job board, use the interactive scaffolding command:

```bash
/ add-portal

```

This CLI wizard generates the skill folder structure under `.agents/skills/`. After scaffolding, validate your implementation:

```bash
cd .agents/skills/<my-portal>/cli
bun test

```

## Adding New Templates

For new CV or cover letter templates, use the template wizard:

```bash
/ add-template

```

This interactive command registers your template under `templates/`. Verify compilation works correctly:

```bash
lualatex templates/<my-template>/my-cv.tex
xelatex templates/<my-template>/my-cover.tex

```

## Testing Requirements

All contributions must include automated tests that exercise real code paths, not synthetic inputs, as mandated by the test-reproduction rule in [`CONTRIBUTING.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CONTRIBUTING.md)【/cache/repos/github.com/MadsLorentzen/ai-job-search/master/CONTRIBUTING.md#L30-L36】.

- Use **Python `unittest`** for framework-level changes
- Use **`bun test`** for TypeScript skill CLIs
- Place tests in the appropriate `tests/` or `cli/tests/` directory corresponding to your modified code

## Summary

- **Fork** the repository and work on a dedicated branch to contribute to ai-job-search.
- **Target one of three buckets**: universal features, robustness fixes, or documentation improvements.
- **Respect the architecture**: Place CLI commands in `.claude/commands/`, job board skills in `.agents/skills/<portal>/`, and templates in `templates/`.
- **Validate locally** using [`tools/lint_skills.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/lint_skills.py), [`tools/security_guards.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/security_guards.py), and the appropriate test suite (`unittest` or `bun test`).
- **Follow the universal-template rule** to ensure your changes remain market-agnostic and benefit all forks.

## Frequently Asked Questions

### What types of contributions does ai-job-search accept?

The project accepts contributions in three categories only: universal customization features (new commands or portals), robustness and correctness fixes (reproducible bugs with tests), and documentation improvements (setup guides or corrections). All changes must comply with the universal-template rule to maintain market agnosticism.

### How do I test my changes before submitting a PR?

Run the local CI suite using `python3 tools/lint_skills.py`, `python3 tools/security_guards.py`, and `python3 -m unittest discover -s tests`. For TypeScript skill CLIs, execute `bun run typecheck` and `bun test` within the specific skill directory. All tests must exercise real code paths rather than synthetic inputs.

### Where should I place new job board integrations?

Create new job board skills under `.agents/skills/<portal-name>/` with a corresponding [`SKILL.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/SKILL.md) defining the search and detail command contracts. Use the `/add-portal` interactive command to scaffold the directory structure correctly, then implement the CLI in the `cli/` subdirectory with TypeScript.

### What is the universal-template rule?

The universal-template rule requires that all contributions remain market-agnostic and Claude-Code-native, ensuring the repository functions as a thin-pointer framework that any user can fork for their local market without breaking upstream compatibility. Avoid hardcoding market-specific logic that cannot be generalized to other regions or job boards.