After the setup wizard: tuning what you get
Start here: run docker compose up -d --build in the project directory and open http://127.0.0.1:3000; the setup wizard (/setup) asks for your language, market, profile, targets, sources, AI and Telegram and writes the files for you (see setup.md). This guide is for after the wizard: it explains the same settings page by page, so you can tune them later. Each step says which page to use, what to fill in, and how to confirm it took effect. The mock-ups use example values (a Berlin / Germany setup); yours will show your own market, cities and currency.
How it works
By default a cycle runs automatically on weekdays at 07:00 and 17:00 and at 09:00 on weekends, in your configured time zone (schedule.yaml). Each cycle goes through 6 stages, and each condition you set affects exactly one of them. Click a block to jump to the matching setup step.
Where do I set the roles I want and my filters?
There are two kinds, and the first two cards are the easiest to mix up: "What to search" decides which jobs get pulled from the sites; "What I want" decides which of the pulled jobs stay and how they are scored.
My profile → What I want /me
- Target roles (also used for scoring)
- Location, work mode, remote scope, seniority
- Salary floor, contract type
- Exclude student roles, companies, keywords
Settings → Search /settings
- Keyword groups (each group is OR-ed into one query)
- Cities (each group is queried once per city), remote scope
- Look-back hours per cycle, max results per group per city
My profile → About me /me
- Languages and levels, skills and years, years of experience
- Home city, whether you need visa sponsorship, a summary for the AI
Interests + notifications /interests /settings
- Compensation / benefit signal words and bonus weights, watched companies
- Notification threshold (default 70, 60 with a salary or equity signal), quiet hours
- Saved filter views (switch at the top of the Today page)
1Open the web UI and confirm the system is healthy
- Open
http://127.0.0.1:3000in a browser (on a phone, first connect with the Tailscale app, then open the Tailscale address). Left navigation: Today, Jobs, Favorites, Pipeline, Sources, Insights, Settings, My profile, Interests. - Run a health check in the project directory and read the summary on the last line:
cd <your project directory>
pnpm run doctor
Write pnpm run doctor, not just pnpm doctor (the latter is a built-in pnpm command). doctor is read-only: it sends no messages, calls no AI and costs nothing. The Sources page in the web UI shows the same information: each channel's status, usage and latest run, plus the heartbeats of the runner and ai-worker.
2Write "About me" — the basis for AI scoring
This part is sent to the AI as a summary for scoring. Fill in at least skills or the summary, otherwise scoring pauses (a banner appears at the top of the Today page).
3Write "What I want" — roles and filters
These conditions drive the hard filter (non-matching jobs are filtered out directly, not scored or notified), and target roles also make up 40% of the pre-score.
How each item takes effect
| # | Condition | When it does not match | Advice |
|---|---|---|---|
| 1 | Target roles | No filtering, only affects the score | List every synonymous title (AI Engineer / Applied AI Engineer…) |
| 2–4 | Location, work mode, remote scope | Filtered, with a reason such as "location outside target area" | If you only want remote, remove "On-site" and "Hybrid"; if you do not want remote at all, choose "Not accepted" |
| 5 | Seniority | Filtered, reason "level mismatch" | If unsure, leave "Any" and let the AI judge |
| 6 | Salary floor | Filtered only when a stated ceiling is below the floor | Most German JDs state no salary, so nothing is wrongly dropped |
| 7 | Contract type | "Exclude" is filtered directly; anything not in "accept" is also filtered; JDs that state no contract type are kept | Choose "exclude" for temp agencies (Zeitarbeit) |
| 8 | Student roles, company and keyword blocklists | Filtered | Keywords match whole words in the title and body, so be careful with very broad words |
pnpm refilter --dry-run in the project directory to see a before/after comparison, then run it again without --dry-run to apply (no fetching, no AI calls).4Set the search criteria — where and what to search
How the query count works
Queries per channel per cycle ≈ number of keyword groups × number of cities (plus one more for remote). 3 groups × 2 cities = 6 queries. More groups give better coverage, but paid channels cost more and free sites are more likely to rate-limit you.
When a save takes effect
On save, the settings are validated with the same rules as the runner; the runner hot-reloads within a few seconds, and "runner loaded" appears next to the button. The next collection uses the new criteria, with no restart needed.
5Confirm the collection channels — which sites to pull from
Channels are the data sources. Switch them on and off and set budgets in /settings → Channels; see each channel's status and test it in /sources.
| Type | Channels | What to prepare |
|---|---|---|
| Official APIs and public company feeds, on by default | Greenhouse, Lever, Ashby, Personio, SmartRecruiters; Federal Employment Agency (Germany market only) | Nothing to do; add the companies you care about under ats_boards |
| Scraping, off by default | Indeed, StepStone (Germany pack), LinkedIn guest, XING | Their terms of service may forbid automated access. Switch one on only after reading Scraping; the wizard and /sources/registry ask you to confirm |
| Paid (monthly budget) | LinkedIn Bright Data, Apify, JSearch | Put the key in the .env file in the project directory and set a monthly budget in /settings; switch the channel off if you do not want it |
| Discover new companies | Tavily (default) / Brave | TAVILY_API_KEY, 1000 free calls per month |
| Needs login | LinkedIn session (off by default, uses your own account), Gmail alert emails | See the LinkedIn session and Gmail alerts guides; optional |
.env file in the project directory with a text editor and fill them in; after saving, run docker compose up -d runner so the runner picks up the new values. .env is not in git, and never paste keys into a chat.6Set up notifications — which jobs go to your phone
Each job pushed to Telegram looks like this, and the buttons write straight into your application records:
Example GmbH · Berlin · Hybrid
T1 €85–100kEnglish role
Match: LLM application experience, customer delivery…
TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID into .env; then click Send Telegram test message in /settings → Manual actions. If it arrives on your phone, setup is done.7Tune the ranking: signal bonuses, watched companies, views
💶 Signal words and weights
These phrases in a JD earn a bonus: T1 a stated amount, T2 equity / options, T3 salary description, T4 other. You can adjust each tier's weight and the bonus cap; after saving, rank values are recomputed immediately without calling the AI.
👀 Watched companies
Add companies you especially want to join. Any new job from them is pushed on its own, regardless of the score threshold and filters. You can add a company before it appears in the database.
👁️ Saved views
After setting filters in /jobs (score, city, remote, German requirement…), click "Save current filters as a view" and you can switch to it with one click at the top of the Today page; you can set one default view.
8Run a cycle by hand and look at the results
- In /settings → Manual actions click Run a cycle now (you can tick only a few channels). Live progress shows under the button: "Cycle N: x / y queries finished, z fetched". You can also run
pnpm cycle:runin a terminal. - After collection, the ai-worker starts scoring; scores usually trickle in within a few minutes.
- Open Today: new jobs are sorted by rank value, with per-source counts at the top.
- Click a title to open the detail page: the original JD / translation, the AI's match reasons and gaps, compensation signals, German requirement, and the "View original post" link (to record that you applied, click "Mark as applied"; opening the original post does not change the status).
- If you want to apply, click "Interested", then drag the status in the Pipeline board.
What to check when results look wrong
| Symptom | Where to look first |
|---|---|
| A job you wanted did not appear | In /jobs turn on "Show filtered" and search for it: the top of the detail page states the filter reason (for example "location outside target area"). You can click "Keep anyway", or go back to Step 3 and loosen the conditions |
| Jobs of this kind were never fetched | Whether the Step 4 keyword groups contain that title; whether the Step 5 channels are healthy |
| Scores stay empty | Whether /me has skills or a summary; the "AI has no backlog" and "ai-worker heartbeat fresh" items in pnpm run doctor |
| Scores are all low | Whether the Step 2 summary and skills are specific enough; whether the Step 3 target roles cover the common titles |
| No notification on your phone | Whether it is quiet hours; whether the rank value reaches the threshold; send a Telegram test message from /settings |
✓Every day after
- Nothing to start: once the host is set up as in the deployment guide, Docker and the ai-worker start automatically at boot, and 3 cycles run on their own every day.
- Watch Telegram: qualified new jobs arrive one by one; handle them with 👍 / 🚫 directly, and tap ⭐ to save ones for later.
- When you have time, open Today or Jobs to browse what was not pushed; follow progress on the Pipeline board, which reminds you when a reply is overdue.
- On Monday, check the AI's suggested adjustments on /interests and approve or reject them.
- When something feels off, run
pnpm run doctor; Telegram also sends proactive alerts (channel circuit-breaker, budget at 80%, ai-worker offline, etc.).