European Tech Opportunities 2027 Search Registry Guide¶
← Documentation hub · CLI reference · Configuration · Architecture · Contributing · Security policy
This is the canonical search-registry guide for the project. The registry controls discovery, not publication. Every new candidate found through LinkedIn guest search must still pass deterministic employment-type, seniority, cycle, technology, and European-location checks before entering canonical SQLite state. When the title and description do not establish the target cycle, eligible posting-date evidence is required; an explicitly eligible cycle does not require a posting age.
A search establishes provenance and defines where the pipeline looks. It never proves that a listing is eligible.
Contents¶
- Registry layout
- Search groups
- YAML schema
- Validation rules
- Query identity
- Pagination and prefiltering
- Limit tiers
- Add a role search
- Add an employer search
- Add a country search
- Review a change
Registry layout¶
The loader scans configs/searches/ recursively:
configs/searches/
├── roles/ # 23 technology paths
├── companies/ # 33 targeted employers
└── countries/ # 33 country partitions
Generated documentation displays the current YAML-file count for each group. opportunities render refreshes the owned layout block, and opportunities validate compares those counts with configs/searches/.
Do not edit the generated layout counts manually; change the registry files and run the owning render path instead.
Search groups¶
| Group | Purpose |
|---|---|
| Roles | Discover coherent technology disciplines such as software engineering, cybersecurity, data, AI/ML, hardware, robotics, and quantitative technology |
| Companies | Add a targeted discovery path for selected employers |
| Countries | Partition discovery across explicitly supported European countries |
Coverage is intentionally explicit and bounded. Prefer a focused missing partition over many overlapping searches that increase request cost without meaningful discovery value.
A listing discovered by several searches keeps each provenance association but remains one canonical job identified by its numeric LinkedIn job ID.
YAML schema¶
Example role search:
name: European software testing internships and New Grad roles 2027
slug: software-testing
keywords: 'software test (intern OR "new grad" OR graduate OR "early career" OR "entry level")'
location: Europe
geo_id: "91000000"
company_names: []
workplace: any
date_posted: cycle
max_pages: 3
max_results: 75
max_rechecks: 15
enabled: true
verified_at: 2026-07-17
notes: Medium role tier covering QA and test automation.
| Field | Type or allowed values | Meaning |
|---|---|---|
name |
String, 1–200 characters | Human-readable search name; placeholders are rejected |
slug |
Lowercase kebab-case, at most 100 characters | Stable persisted search identity |
keywords |
String, 2–300 characters | LinkedIn keyword query |
location |
String, 1–200 characters | Europe or explicit country location text |
geo_id |
Numeric string or null |
Optional independently verified LinkedIn geography ID |
company_names |
Up to 50 strings, each 1–200 characters | Exact normalized employer allowlist |
workplace |
any, on-site, remote, hybrid |
Optional workplace filter |
date_posted |
any, day, week, month, cycle |
Listing-age filter; cycle requests postings from May 1, 2026 onward; ranking and page limits still bound discovery |
max_pages |
Integer, 1–10 | Maximum number of 25-card result pages |
max_results |
Integer, 1–250 | Maximum eligible detail candidates; no greater than pages × 25 |
max_rechecks |
Integer, 0–250 | Absent known jobs that may receive bounded detail rechecks |
enabled |
Boolean | Whether normal collection selects the search |
verified_at |
ISO date or null |
Date the configuration itself was reviewed |
notes |
String or null, at most 500 characters |
Scope, tier, and tuning rationale |
Unknown fields are rejected.
verified_at documents configuration review. It does not prove that LinkedIn currently returns results, that the search remains productive, or that collection is authorized.
Validation rules¶
Before network access, the registry loader requires:
- an existing search directory;
- mapping-shaped YAML files;
- valid
LinkedInSearchConfigfields; - globally unique slugs;
- globally unique effective query identities;
- result limits within page capacity.
It returns searches in deterministic slug order. The production configuration test additionally requires role filenames to map to OpportunityCategory and enforces the repository conventions below.
Repository production conventions are stricter than the model-level field limits:
- filenames and slugs remain stable lowercase kebab-case;
- role filenames map to
OpportunityCategory; - every production search is enabled;
- every query requests
intern,new grad, andgraduateterminology without requiring a year; - every production search uses the dynamic
cycleposting filter, covering May 1, 2026 through collection time; - production searches use 1–4 pages,
max_results == max_pages × 25, and 5–25 rechecks; - Europe-wide searches use the verified Europe geography ID
91000000; - employer searches use non-empty exact normalized
company_names; - country searches use explicit country location text and
geo_id: null; - numeric geography IDs are never invented;
notesexplain scope and tuning without unsupported coverage claims.
Validate locally:
Contribution requirements are defined in CONTRIBUTING.md.
Query identity¶
An effective query identity combines the normalized request-defining values of:
Two files cannot issue the same effective request under different filenames or slugs. Company allowlist order does not affect identity, and duplicate identities are rejected even when one of the searches is disabled.
The slug is persisted as the search identity. Prefer changing tunable fields without renaming an existing slug.
Disabling or deleting a search:
- preserves its historical run records and provenance;
- prevents future selection;
- is synchronized into persisted search state on the next collection run;
- does not directly close associated jobs.
Collection-driven job closure depends on repeated explicit detail-page unavailability across every active association, not registry deletion. The separate full-state availability audit follows its own explicit deletion rules.
Pagination and prefiltering¶
LinkedIn guest search uses 25-card offsets.
Collection stops when:
- the page is empty;
- the page contains no unseen raw job IDs;
- the eligible-card limit (
max_results) is reached; - the page limit is reached.
A page containing cards but no title-explicit internship or New Grad matches does not stop pagination.
Before detail requests, search cards pass two low-cost checks:
- exact normalized employer allowlist matching, when configured;
- explicit internship or New Grad terminology in the title.
These checks reduce unnecessary detail requests and do not constitute publication acceptance. Final acceptance occurs only after detail parsing, normalization, and deterministic classification.
Limit tiers¶
opportunities searches displays limits as:
Where:
P= maximum pages;R= maximum eligible detail results;C= maximum absent known-job rechecks.
| Tier | Pages | Results | Rechecks | Intended use |
|---|---|---|---|---|
| High | 4 | 100 | 20–25 | Repeatedly demonstrated yield |
| Medium | 3 | 75 | 15–20 | Broad market or employer programme |
| Specialized | 2 | 50 | 10 | Narrow role or employer |
| Minimal | 1 | 25 | 5 | New, unobserved, or low-volume partition |
Limits control request cost, not listing quality.
Start with the smallest defensible tier. Tune only after several successful authorized runs; do not raise all searches because of one low-yield snapshot.
Global diagnostic overrides belong to Configuration.
Add a role search¶
- Create
configs/searches/roles/<slug>.yml. - Choose one coherent technology discipline.
- Include the standard internship/New Grad Boolean terms without a year restriction.
- Use the verified Europe geography configuration for Europe-wide discovery.
- Start with the smallest defensible tier within the production 1–4 page policy.
- Explain role scope and tuning in
notes. - Ensure the filename maps to
OpportunityCategory; when introducing a category, update the classification configuration and tests as well. - Add or update registry and classifier tests.
Example path:
Do not create several near-identical searches only to broaden wording. Prefer one focused query plus classifier improvements supported by tests.
Add an employer search¶
Place employer searches under configs/searches/companies/. For example, the existing company-amazon slug is defined in configs/searches/companies/amazon.yml; the filename does not need the company- prefix.
Requirements:
- prefix the slug with
company-; - use broad but explicit keywords that include both internship and New Grad terms;
- omit
2027so current yearless vacancies are discoverable, and usedate_posted: cycleto request the May 1 publication window without implying complete search-result coverage; - use the verified Europe geography ID
91000000for Europe-wide discovery; - list legitimate LinkedIn employer-name variants in
company_names; - retain exact matching after normalization;
- do not use substring matching;
- start conservatively and increase limits only after repeated evidence.
Example:
name: Amazon internships and New Grad roles 2027
slug: company-amazon
keywords: 'Amazon (intern OR "new grad" OR graduate OR "early career" OR "entry level")'
location: Europe
geo_id: "91000000"
company_names:
- Amazon
- Amazon Web Services
workplace: any
date_posted: cycle
max_pages: 2
max_results: 50
max_rechecks: 10
enabled: true
verified_at: 2026-07-17
notes: Targeted employer discovery with exact normalized company matching.
The allowlist restricts discovery. It does not bypass classification. Listings must be discovered from search results and pass every publication check.
Add a country search¶
Place country searches under configs/searches/countries/. For example, the existing country-portugal slug is defined in configs/searches/countries/portugal.yml; the filename does not need the country- prefix.
Requirements:
- prefix the slug with
country-; - use the explicit country name as
location; - set
geo_id: null; current production country partitions use explicit country text rather than geography IDs; - include both internship and New Grad terminology without a year restriction;
- start unobserved or low-volume countries at the minimal tier;
- avoid claiming complete national coverage.
Example:
name: Portugal technology internships and New Grad roles 2027
slug: country-portugal
keywords: 'software (intern OR "new grad" OR graduate OR "early career" OR "entry level")'
location: Portugal
geo_id: null
company_names: []
workplace: any
date_posted: cycle
max_pages: 1
max_results: 25
max_rechecks: 5
enabled: true
verified_at: 2026-07-17
notes: Initial low-volume country partition.
Country candidates remain subject to the same European-location and technology-role classifier rules.
Review a change¶
Run:
Only with express authorization, preview one search without persistence:
Confirm that the slug and effective query identity are unique, geography and employer values follow the production policy, limits use the smallest defensible tier, the review date is accurate, generated registry counts are refreshed when needed, and relevant tests pass.
Do not require reviewers or CI to contact LinkedIn. Search files do not grant authorization, and an access block or challenge is a stop condition.