Skip to content

Getting Started

Karthik P edited this page Oct 15, 2026 · 1 revision

Getting Started

This page takes you from nothing to a first set of job matches on a self-hosted Job Matcher. It covers what you need, what the one-line installers do step by step, the difference between demo and live mode, a walkthrough of the first sign-in, and how to switch modes and upgrade. For running the code from a checkout instead, see Development Setup; for the full production stack, see Deployment.

Requirements

Requirement Detail
Docker Docker Engine with Compose v2. Docker Desktop includes both on Windows, macOS and Linux.
Memory and disk About 2 GB of free memory and 3 GB of disk (self-hosting guide).
CPU architecture amd64 or arm64. Images are published for both, so Intel and Apple Silicon Macs and a Raspberry Pi 4 or 5 work.
Shell tools (macOS/Linux) curl or wget. openssl is used for secrets when present, otherwise /dev/urandom. lsof, ss or netstat is used to find a free port when present.
API keys (live mode only) An OpenRouter key for AI matching and a Firecrawl key for scraping. Demo mode needs neither.

The installer never asks for admin rights and writes only to the install folder.

Install with one command

macOS, Linux or WSL:

curl -fsSL https://raw.githubusercontent.com/Karthik-beta/AI-Job-Resume-Matcher/master/install.sh | sh

Windows PowerShell:

irm https://raw.githubusercontent.com/Karthik-beta/AI-Job-Resume-Matcher/master/install.ps1 | iex

To read the scripts before running them: install.sh and install.ps1.

What the installer does

Both scripts follow the same five steps. install.ps1 wraps everything in a script block, so iex neither leaks variables nor exits your shell.

Step What happens Failure message
1. Check Docker Checks that docker is on the path, that docker compose version works (Compose v2), and that docker info succeeds (the daemon is running). Docker is not installed, Docker Compose v2 is missing, Docker is installed but not running
2. Pick a version Uses JOB_MATCHER_VERSION when set (a leading v is stripped). Otherwise reads tag_name from https://api.github.com/repos/Karthik-beta/AI-Job-Resume-Matcher/releases/latest. The compose files are downloaded from the git ref v<version> when the version looks like X.Y.Z, from master for any other value, or from JOB_MATCHER_REF when set. Could not find the latest release on GitHub. Set JOB_MATCHER_VERSION and run this again.
3. Download the stack Creates the install folder and downloads deploy/compose.yml and deploy/.env.example from that ref into it as compose.yml and .env.example. Download error from curl, wget or Invoke-WebRequest
4. Write settings If .env already exists (an upgrade), only JOB_MATCHER_VERSION is updated; every other value is kept. Otherwise, it first refuses to continue if the Docker volume job-matcher_postgres-data exists (an earlier install's database, created with a password that is now lost). Then it copies .env.example to .env and sets POSTGRES_PASSWORD and BETTER_AUTH_SECRET to 32 random bytes in hex, finds the first free TCP port from 8080 upward and writes it to WEB_PORT and BETTER_AUTH_URL=http://localhost:<port>, and writes JOB_MATCHER_VERSION. Finally it asks for the API keys (below) and sets PROVIDERS. A database from an earlier Job Matcher install exists, but its .env is gone.
5. Start Runs docker compose -f <dir>/compose.yml up -d --pull missing --quiet-pull --remove-orphans --wait --wait-timeout 300. The explicit -f overrides any COMPOSE_FILE set in your shell. It then prints the URL, the mode, and the commands for logs, stop, upgrade and uninstall. install.ps1 also opens the URL in your browser when it runs interactively. The stack did not become healthy. See the logs with: ... docker compose logs

Key prompts. The prompts read from the terminal (/dev/tty on Unix), so they work under curl | sh. A key already present in the environment as OPENROUTER_API_KEY or FIRECRAWL_API_KEY is used instead of prompting. The Firecrawl prompt appears only after an OpenRouter key is given. With both keys the installer writes them to .env and sets PROVIDERS=live; with one or none it sets PROVIDERS=fake (printing "Live mode needs both keys; starting in demo mode." when only one was given).

File permissions. On macOS and Linux, .env is created with mode 600, and every rewrite goes through a temporary file created under umask 077, so a re-run also tightens a .env that an earlier install left world-readable. CI checks this (see CI/CD and Releases). On Windows, .env is written as UTF-8 without a BOM and with LF line endings, which Compose expects.

Installer environment overrides

Variable Default Effect
JOB_MATCHER_DIR ~/job-matcher ($HOME\job-matcher on Windows) Install folder for compose.yml, .env.example and .env.
JOB_MATCHER_VERSION Latest GitHub release Release to install, for example 1.2.0 or v1.2.0. Written to .env and used as the image tag.
JOB_MATCHER_REF v<version>, or master for a non-X.Y.Z version Git ref the compose files are downloaded from. CI uses it to test the installer against a pull request's head commit.
JOB_MATCHER_NONINTERACTIVE unset 1 skips every prompt; keys come from OPENROUTER_API_KEY and FIRECRAWL_API_KEY in the environment.
OPENROUTER_API_KEY, FIRECRAWL_API_KEY unset Used as the API keys on a fresh install, in place of the prompts.

Example of a scripted install of a pinned version:

JOB_MATCHER_NONINTERACTIVE=1 JOB_MATCHER_VERSION=1.0.0 \
  OPENROUTER_API_KEY=sk-or-... FIRECRAWL_API_KEY=fc-... \
  sh -c "$(curl -fsSL https://raw.githubusercontent.com/Karthik-beta/AI-Job-Resume-Matcher/master/install.sh)"

Installing by hand or from source

The self-hosting guide has the three manual commands (download compose.yml and .env.example, fill in the Required section, docker compose up -d --wait) and the from-source variant that builds images with deploy/compose.build.yml. Both are described in Deployment.

Demo and live mode

PROVIDERS in .env picks the mode. The API and worker read it at startup (config.ts).

Demo (PROVIDERS=fake) Live (PROVIDERS=live)
Keys None OPENROUTER_API_KEY and FIRECRAWL_API_KEY (or a self-hosted Firecrawl, see Configuration Reference)
Scraping Built-in fixture pages from apps/api/test/fixtures/. Every careers page serves the same sample board of three jobs. Firecrawl cloud by default; ATS boards through their public APIs
Resume Every resume URL serves the fixture resume The PDF or page at your resume URL
AI A scripted evaluator: a job page's Verdict: line decides the result OpenRouter, openai/gpt-6-luna:floor on the flex tier by default
Discord Logged only ("Fake Discord alert for ...") Posted to your webhook
Cost Free Firecrawl credits (the free plan has 1,000 a month) and a fraction of a cent of AI per job

The fake providers are defined in providers/fake.ts. In demo mode, add a plain careers page URL (any https:// URL that is not a Greenhouse, Lever, Ashby, SmartRecruiters or Recruitee board) or a search source. ATS boards are read over plain HTTP, which demo mode does not fake, so an ATS source fails to load there. See Glossary: fake providers.

First run walkthrough

The app's routes live in apps/web/app. Open the URL the installer printed (by default http://localhost:8080).

1. Create an account

Choose Create an account on the landing page (/), or go to /sign-up. Enter a name, email and password and press Create account. Accounts are email and password only (auth.ts); there is no email verification. Anyone who can reach the address can sign up, so do not expose an instance you do not want others to use. See Authentication.

2. The setup wizard (/welcome)

A new account lands on the setup wizard. The current step is kept in the URL as ?step= (welcome-steps.ts):

Step URL Heading What you do Required
Welcome ?step=welcome How it works Read the overview, then press Let's set up No
Resume ?step=resume Add your resume Paste a public link to a PDF (Google Drive and Dropbox share links work) or a page such as a Google Doc, then Save resume Yes
Matching ?step=preferences Matching basics Set experience, cities and title keywords, or press Use defaults No
Job sources ?step=source Add a job source Add a careers page, ATS board or search, then Next Yes
First run ?step=firstRun Start your first run Press Start first run Yes

Steps you have not unlocked cannot be opened: matching and sources need a resume, and the first run needs a resume and a source. Finish later or Skip for now goes to /home, where a "Get set up" checklist shows your progress ("N of 3 required done") with a Continue setup link back into the wizard. The checklist can be hidden and brought back from the account menu's Setup guide item.

3. Watch the run (/runs/<id>)

Starting the first run opens the run page with ?first=1, which adds a "What happens during a run" guide. The page polls the API while the worker reads your sources, filters listings, and evaluates each job. Each job shows how its text was read: From job board (ATS API, free), Saved copy (page cache, free), Read directly (self-hosted Firecrawl, free) or Read with Firecrawl (cloud, uses credits). When the run finishes, See your matches links to the matches list. The pipeline is described in Run Pipeline.

4. Settings (/settings)

Everything the wizard collects can be changed later in Settings, which has these sections: Resume, Job sources, Matching, Runs (jobs per run, title triage), Schedule & alerts (check every N minutes, Discord webhook) and Data (clear the page cache). Each field is described in Configuration Reference: user settings.

5. Analyze (/analyze)

The Analyze page lists your job sources with checkboxes and an Analyze button (Analyze again after a run), and shows the latest run and past runs. If the resume or sources are missing, it links to /settings#resume or /settings#sources. Only one run per user can be queued or running at a time; a second start returns "A run is already in progress".

6. Matches (/matches)

Matches are listed newest first, filtered by Pending or Applied. Mark applied moves a match to Applied, and Move to pending moves it back. Matches are kept per job URL, so a job matched again on a later run keeps its status.

Signed-in navigation

The header links to Home (/home), Analyze (/analyze, which also covers /runs/...), Matches (/matches) and Settings (/settings). A signed-out visitor who opens any of these is sent to /sign-in?next=<page> and returned there after signing in (proxy.ts). A signed-in visitor who opens /, /sign-in or /sign-up goes to /home.

Switching from demo to live

  1. Edit ~/job-matcher/.env (or your JOB_MATCHER_DIR):

    PROVIDERS=live
    OPENROUTER_API_KEY=sk-or-...
    FIRECRAWL_API_KEY=fc-...
  2. Apply it:

    cd ~/job-matcher && docker compose up -d

The worker validates the keys when it starts: it exits if OPENROUTER_API_KEY is empty, or if the Firecrawl mode's key or URL is missing. Each run then checks the OpenRouter key and model before scraping anything (see Glossary: preflight). Check docker compose logs worker if a run never finishes. To go back to demo mode, set PROVIDERS=fake and run the same command.

Results evaluated in demo mode stay in the database. Live runs read real pages, so they produce new job results rather than reusing demo ones.

Upgrading

Run the installer again. It downloads the newest release's compose.yml and .env.example, updates JOB_MATCHER_VERSION in .env, keeps every other setting and all data, and restarts the stack. The migrate service applies any new database migrations before the API and worker start.

Note that an upgrade does not merge new variables from the new .env.example into your .env. Compare the two files after upgrading if a release notes a new setting.

For a by-hand install, set JOB_MATCHER_VERSION in .env, download that release's compose.yml, and run docker compose up -d --wait. See Deployment.

Next steps

Clone this wiki locally