mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-11-07 23:47:46 +00:00
chore: point every in-tree reference at ai-job-search-dev/ai-job-search (#776)
The repository is moving from the MadsLorentzen personal account to the ai-job-search-dev organization. GitHub redirects the old slug, but the upstream-watch guard compares github.repository against the literal slug and would start running the fork-only triage job on upstream itself, and the upstream-check tool and its tests pin the slug too. README, CONTRIBUTING, SECURITY, SETUP, the CI workflow, the issue-template config and the CHANGELOG links follow. Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
e16acee3ab
commit
7f9edf54c1
18 files changed
+94
-86
No files matched your search
@@ -23,7 +23,7 @@ export function writeError(error: string, code: string): void {
|
|||||||
// cli/src, so a github.com URL here made every github.com link classify as an
|
// cli/src, so a github.com URL here made every github.com link classify as an
|
||||||
// installed job board instead of an unverified host. The owner/project name
|
// installed job board instead of an unverified host. The owner/project name
|
||||||
// already identifies the repo on GitHub.
|
// already identifies the repo on GitHub.
|
||||||
const UA = "MadsLorentzen/ai-job-search/1.0 (freehire-search)"
|
const UA = "ai-job-search-dev/ai-job-search/1.0 (freehire-search)"
|
||||||
|
|
||||||
/** The shared API response envelope: {data, meta, error}. */
|
/** The shared API response envelope: {data, meta, error}. */
|
||||||
export interface Envelope<T> {
|
export interface Envelope<T> {
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ points users to (`?q=<role>` scopes the counts). Example:
|
|||||||
serves HTML, which `cleanHtml` (`cli/src/helpers.ts`) strips into readable text.
|
serves HTML, which `cleanHtml` (`cli/src/helpers.ts`) strips into readable text.
|
||||||
Search descriptions arrive already rendered by the API and are passed through
|
Search descriptions arrive already rendered by the API and are passed through
|
||||||
verbatim — stripping them again would undo the Markdown structure.
|
verbatim — stripping them again would undo the Markdown structure.
|
||||||
- Fetch sends `User-Agent: MadsLorentzen/ai-job-search/1.0 (freehire-search)` (no contact
|
- Fetch sends `User-Agent: ai-job-search-dev/ai-job-search/1.0 (freehire-search)` (no contact
|
||||||
URL: a host literal in `cli/src` makes `/apply` treat that host as this portal's board)
|
URL: a host literal in `cli/src` makes `/apply` treat that host as this portal's board)
|
||||||
and `Accept: application/json`, and uses exponential backoff with jitter on 429/5xx (max 6 retries). A connection error (API
|
and `Accept: application/json`, and uses exponential backoff with jitter on 429/5xx (max 6 retries). A connection error (API
|
||||||
unreachable) fails fast with a clear message — no retry, since it is not
|
unreachable) fails fast with a clear message — no retry, since it is not
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
`detail-orbis-excerpt.html` contains verbatim excerpts from the guest response for
|
`detail-orbis-excerpt.html` contains verbatim excerpts from the guest response for
|
||||||
posting `4345841651`, captured by **portapulito** through this CLI's `htmlFetch`
|
posting `4345841651`, captured by **portapulito** through this CLI's `htmlFetch`
|
||||||
on 2026-07-14 and published in [upstream PR #153](https://github.com/MadsLorentzen/ai-job-search/pull/153).
|
on 2026-07-14 and published in [upstream PR #153](https://github.com/ai-job-search-dev/ai-job-search/pull/153).
|
||||||
That PR was closed because it was accidentally submitted to upstream instead of
|
That PR was closed because it was accidentally submitted to upstream instead of
|
||||||
the author's personalized fork; it was not merged.
|
the author's personalized fork; it was not merged.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
`search-cards.json` stores the HTML string for the first two verbatim `<li>` cards from a real
|
`search-cards.json` stores the HTML string for the first two verbatim `<li>` cards from a real
|
||||||
LinkedIn guest search response captured by **portapulito** through the CLI's
|
LinkedIn guest search response captured by **portapulito** through the CLI's
|
||||||
`htmlFetch` on 2026-07-14 and published in [PR #153](https://github.com/MadsLorentzen/ai-job-search/pull/153).
|
`htmlFetch` on 2026-07-14 and published in [PR #153](https://github.com/ai-job-search-dev/ai-job-search/pull/153).
|
||||||
That PR was closed as an accidental personalized-fork submission, not merged.
|
That PR was closed as an accidental personalized-fork submission, not merged.
|
||||||
|
|
||||||
Source: `.agents/skills/linkedin-search/cli/test/__fixtures__/search-list.html`
|
Source: `.agents/skills/linkedin-search/cli/test/__fixtures__/search-list.html`
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
blank_issues_enabled: true
|
blank_issues_enabled: true
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Filing from a personalized fork? Read this first
|
- name: Filing from a personalized fork? Read this first
|
||||||
url: https://github.com/MadsLorentzen/ai-job-search/blob/master/SETUP.md#2-fork-and-clone
|
url: https://github.com/ai-job-search-dev/ai-job-search/blob/master/SETUP.md#2-fork-and-clone
|
||||||
about: >-
|
about: >-
|
||||||
The gh CLI in a fork clone targets THIS public repo by default. Personal
|
The gh CLI in a fork clone targets THIS public repo by default. Personal
|
||||||
application tracking, evaluations, and incident logs belong in your own
|
application tracking, evaluations, and incident logs belong in your own
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ jobs:
|
|||||||
- run: pip install pyyaml
|
- run: pip install pyyaml
|
||||||
- run: python tools/lint_skills.py
|
- run: python tools/lint_skills.py
|
||||||
- name: Framework version guard (upstream template only)
|
- name: Framework version guard (upstream template only)
|
||||||
if: github.repository == 'MadsLorentzen/ai-job-search'
|
if: github.repository == 'ai-job-search-dev/ai-job-search'
|
||||||
run: python tools/check_framework_version.py
|
run: python tools/check_framework_version.py
|
||||||
|
|
||||||
security-guards:
|
security-guards:
|
||||||
@@ -203,7 +203,7 @@ jobs:
|
|||||||
python3 tools/verify_pdf.py cv/main_example.pdf --min-chars 100
|
python3 tools/verify_pdf.py cv/main_example.pdf --min-chars 100
|
||||||
python3 tools/verify_pdf.py cover_letters/cover_example.pdf --min-chars 100
|
python3 tools/verify_pdf.py cover_letters/cover_example.pdf --min-chars 100
|
||||||
- name: Assert stock PDF structure (upstream template only)
|
- name: Assert stock PDF structure (upstream template only)
|
||||||
if: github.repository == 'MadsLorentzen/ai-job-search'
|
if: github.repository == 'ai-job-search-dev/ai-job-search'
|
||||||
run: |
|
run: |
|
||||||
python3 tools/verify_pdf.py cv/main_example.pdf \
|
python3 tools/verify_pdf.py cv/main_example.pdf \
|
||||||
--pages 2 \
|
--pages 2 \
|
||||||
@@ -269,7 +269,7 @@ jobs:
|
|||||||
|
|
||||||
placeholder-integrity:
|
placeholder-integrity:
|
||||||
name: Placeholder integrity (upstream template only)
|
name: Placeholder integrity (upstream template only)
|
||||||
if: github.repository == 'MadsLorentzen/ai-job-search'
|
if: github.repository == 'ai-job-search-dev/ai-job-search'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ jobs:
|
|||||||
name: Triage upstream commits
|
name: Triage upstream commits
|
||||||
# No-op on the upstream template itself. Pinned by
|
# No-op on the upstream template itself. Pinned by
|
||||||
# tests/test_upstream_triage.py so a template clone never runs it by surprise.
|
# tests/test_upstream_triage.py so a template clone never runs it by surprise.
|
||||||
if: github.repository != 'MadsLorentzen/ai-job-search'
|
if: github.repository != 'ai-job-search-dev/ai-job-search'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
# Issue write is granted to this one job, not the workflow, so a job added
|
# Issue write is granted to this one job, not the workflow, so a job added
|
||||||
# later starts read-only.
|
# later starts read-only.
|
||||||
@@ -57,7 +57,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Fetch upstream template
|
- name: Fetch upstream template
|
||||||
run: |
|
run: |
|
||||||
git remote add upstream https://github.com/MadsLorentzen/ai-job-search.git 2>/dev/null || true
|
git remote add upstream https://github.com/ai-job-search-dev/ai-job-search.git 2>/dev/null || true
|
||||||
git fetch --quiet upstream master
|
git fetch --quiet upstream master
|
||||||
|
|
||||||
- name: Build triage report
|
- name: Build triage report
|
||||||
|
|||||||
+26
-18
@@ -25,6 +25,14 @@ per-file diff commands.
|
|||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
- **The repository moved to the `ai-job-search-dev` organization** - the canonical URL is now
|
||||||
|
`https://github.com/ai-job-search-dev/ai-job-search`. GitHub redirects the old
|
||||||
|
`MadsLorentzen/ai-job-search` address for web links, `git` remotes, raw files and the API, so
|
||||||
|
existing clones and forks keep working; update your `upstream` remote when convenient:
|
||||||
|
`git remote set-url upstream https://github.com/ai-job-search-dev/ai-job-search.git`. Every
|
||||||
|
in-tree reference (README, CONTRIBUTING, SECURITY, the upstream-check tool and its tests, the
|
||||||
|
workflows' upstream guard) now points at the new slug.
|
||||||
|
|
||||||
- **`freehire-search` documents the `OR` and `title:` query operators** (#674,
|
- **`freehire-search` documents the `OR` and `title:` query operators** (#674,
|
||||||
`.agents/skills/freehire-search/SKILL.md`, `url-reference.md`, `cli/README.md`, `--help`) -
|
`.agents/skills/freehire-search/SKILL.md`, `url-reference.md`, `cli/README.md`, `--help`) -
|
||||||
freehire's search parses an uppercase `OR` between up to five alternatives and a leading `title:`
|
freehire's search parses an uppercase `OR` between up to five alternatives and a leading `title:`
|
||||||
@@ -272,7 +280,7 @@ per-file diff commands.
|
|||||||
`github.com` among them, so a "posting" published in any GitHub repo or gist classified as an
|
`github.com` among them, so a "posting" published in any GitHub repo or gist classified as an
|
||||||
installed portal instead of getting the `⚠ Unverified source host` warning. The User-Agent keeps
|
installed portal instead of getting the `⚠ Unverified source host` warning. The User-Agent keeps
|
||||||
the `owner/project/version` name freehire's API docs ask for and drops the optional URL:
|
the `owner/project/version` name freehire's API docs ask for and drops the optional URL:
|
||||||
`MadsLorentzen/ai-job-search/1.0 (freehire-search)`. The host-check test now lists `github.com` and
|
`ai-job-search-dev/ai-job-search/1.0 (freehire-search)`. The host-check test now lists `github.com` and
|
||||||
`gist.github.com` postings among the hosts that must stay unverified.
|
`gist.github.com` postings among the hosts that must stay unverified.
|
||||||
|
|
||||||
- **The `/reset` replay tests find a Bash that actually runs the script on Windows** (#671,
|
- **The `/reset` replay tests find a Bash that actually runs the script on Windows** (#671,
|
||||||
@@ -528,7 +536,7 @@ per-file diff commands.
|
|||||||
`.agents/skills/freehire-search/cli/src/helpers.ts`, `url-reference.md`) - the old
|
`.agents/skills/freehire-search/cli/src/helpers.ts`, `url-reference.md`) - the old
|
||||||
`freehire-search-skill/1.0 (+https://freehire.me)` pointed at the API itself, so freehire's
|
`freehire-search-skill/1.0 (+https://freehire.me)` pointed at the API itself, so freehire's
|
||||||
operators could not tell whose client it was. It now sends
|
operators could not tell whose client it was. It now sends
|
||||||
`MadsLorentzen/ai-job-search/1.0 (+https://github.com/MadsLorentzen/ai-job-search; freehire-search)`,
|
`ai-job-search-dev/ai-job-search/1.0 (+https://github.com/ai-job-search-dev/ai-job-search; freehire-search)`,
|
||||||
the `owner/project` form freehire's API docs ask for. Nothing behaves differently; the API does
|
the `owner/project` form freehire's API docs ask for. Nothing behaves differently; the API does
|
||||||
not gate on it.
|
not gate on it.
|
||||||
|
|
||||||
@@ -2539,7 +2547,7 @@ per-file diff commands.
|
|||||||
Step 5 and then discarded. Both arrays are now stored verbatim and replaced (never
|
Step 5 and then discarded. Both arrays are now stored verbatim and replaced (never
|
||||||
accumulated) on `--all` re-ranks, so downstream consumers of `seen_jobs.json` can read
|
accumulated) on `--all` re-ranks, so downstream consumers of `seen_jobs.json` can read
|
||||||
real triage findings instead of re-deriving them. See
|
real triage findings instead of re-deriving them. See
|
||||||
[discussion #258](https://github.com/MadsLorentzen/ai-job-search/discussions/258).
|
[discussion #258](https://github.com/ai-job-search-dev/ai-job-search/discussions/258).
|
||||||
- **`/upskill` aggregate mode now ingests `/rank`'s recorded gaps** - previously it only
|
- **`/upskill` aggregate mode now ingests `/rank`'s recorded gaps** - previously it only
|
||||||
read `job_search_tracker.csv` and *guessed* required skills from the `role`/`sector`/
|
read `job_search_tracker.csv` and *guessed* required skills from the `role`/`sector`/
|
||||||
`notes` columns, even though `/rank` had already fetched and scored postings that never
|
`notes` columns, even though `/rank` had already fetched and scored postings that never
|
||||||
@@ -2549,7 +2557,7 @@ per-file diff commands.
|
|||||||
skill list wherever both exist. The heatmap's Gap Source column now shows the
|
skill list wherever both exist. The heatmap's Gap Source column now shows the
|
||||||
recorded-vs-inferred split per skill, and the report header states how many jobs came
|
recorded-vs-inferred split per skill, and the report header states how many jobs came
|
||||||
from each source. Depends on #263 (`/rank` persisting `gaps`/`strengths`); see
|
from each source. Depends on #263 (`/rank` persisting `gaps`/`strengths`); see
|
||||||
[discussion #258](https://github.com/MadsLorentzen/ai-job-search/discussions/258).
|
[discussion #258](https://github.com/ai-job-search-dev/ai-job-search/discussions/258).
|
||||||
|
|
||||||
### Security & privacy
|
### Security & privacy
|
||||||
|
|
||||||
@@ -2559,7 +2567,7 @@ per-file diff commands.
|
|||||||
documents the safe alternative (a private repository with this repo as `upstream`), and
|
documents the safe alternative (a private repository with this repo as `upstream`), and
|
||||||
`/setup` ends with a matching privacy note the moment profile data first lands in
|
`/setup` ends with a matching privacy note the moment profile data first lands in
|
||||||
tracked files. Prompted by
|
tracked files. Prompted by
|
||||||
[discussion #266](https://github.com/MadsLorentzen/ai-job-search/discussions/266).
|
[discussion #266](https://github.com/ai-job-search-dev/ai-job-search/discussions/266).
|
||||||
- **The gitignore guard now covers two more personal-data rules** - `security_guards.py`
|
- **The gitignore guard now covers two more personal-data rules** - `security_guards.py`
|
||||||
requires `cover_letters/Cover_*.*` (the uppercase cover-letter naming variant `/apply`
|
requires `cover_letters/Cover_*.*` (the uppercase cover-letter naming variant `/apply`
|
||||||
recognizes) and `cv/*.txt` (ATS text extractions of tailored CVs) in `.gitignore`, so a
|
recognizes) and `cv/*.txt` (ATS text extractions of tailored CVs) in `.gitignore`, so a
|
||||||
@@ -2586,7 +2594,7 @@ per-file diff commands.
|
|||||||
- CONTRIBUTING's "run what CI runs" list is now complete - it previously omitted
|
- CONTRIBUTING's "run what CI runs" list is now complete - it previously omitted
|
||||||
`tools/security_guards.py` and the exact `unittest` invocation, the precise checks a
|
`tools/security_guards.py` and the exact `unittest` invocation, the precise checks a
|
||||||
contributor PR had already failed on. Prompted by
|
contributor PR had already failed on. Prompted by
|
||||||
[issue #262](https://github.com/MadsLorentzen/ai-job-search/issues/262).
|
[issue #262](https://github.com/ai-job-search-dev/ai-job-search/issues/262).
|
||||||
|
|
||||||
## [1.1.0] - 2026-07-30
|
## [1.1.0] - 2026-07-30
|
||||||
|
|
||||||
@@ -2677,15 +2685,15 @@ At this baseline the framework provides:
|
|||||||
- **Cross-runtime support** - a root `AGENTS.md` pointer so Codex and Antigravity can
|
- **Cross-runtime support** - a root `AGENTS.md` pointer so Codex and Antigravity can
|
||||||
discover the portable portal skills, with Claude Code as the reference runtime.
|
discover the portable portal skills, with Claude Code as the reference runtime.
|
||||||
|
|
||||||
[Unreleased]: https://github.com/MadsLorentzen/ai-job-search/compare/v1.7.3...HEAD
|
[Unreleased]: https://github.com/ai-job-search-dev/ai-job-search/compare/v1.7.3...HEAD
|
||||||
[1.7.3]: https://github.com/MadsLorentzen/ai-job-search/compare/v1.7.2...v1.7.3
|
[1.7.3]: https://github.com/ai-job-search-dev/ai-job-search/compare/v1.7.2...v1.7.3
|
||||||
[1.7.2]: https://github.com/MadsLorentzen/ai-job-search/compare/v1.7.1...v1.7.2
|
[1.7.2]: https://github.com/ai-job-search-dev/ai-job-search/compare/v1.7.1...v1.7.2
|
||||||
[1.7.1]: https://github.com/MadsLorentzen/ai-job-search/compare/v1.7.0...v1.7.1
|
[1.7.1]: https://github.com/ai-job-search-dev/ai-job-search/compare/v1.7.0...v1.7.1
|
||||||
[1.7.0]: https://github.com/MadsLorentzen/ai-job-search/compare/v1.6.0...v1.7.0
|
[1.7.0]: https://github.com/ai-job-search-dev/ai-job-search/compare/v1.6.0...v1.7.0
|
||||||
[1.6.0]: https://github.com/MadsLorentzen/ai-job-search/compare/v1.5.0...v1.6.0
|
[1.6.0]: https://github.com/ai-job-search-dev/ai-job-search/compare/v1.5.0...v1.6.0
|
||||||
[1.5.0]: https://github.com/MadsLorentzen/ai-job-search/compare/v1.4.0...v1.5.0
|
[1.5.0]: https://github.com/ai-job-search-dev/ai-job-search/compare/v1.4.0...v1.5.0
|
||||||
[1.4.0]: https://github.com/MadsLorentzen/ai-job-search/compare/v1.3.0...v1.4.0
|
[1.4.0]: https://github.com/ai-job-search-dev/ai-job-search/compare/v1.3.0...v1.4.0
|
||||||
[1.3.0]: https://github.com/MadsLorentzen/ai-job-search/compare/v1.2.0...v1.3.0
|
[1.3.0]: https://github.com/ai-job-search-dev/ai-job-search/compare/v1.2.0...v1.3.0
|
||||||
[1.2.0]: https://github.com/MadsLorentzen/ai-job-search/compare/v1.1.0...v1.2.0
|
[1.2.0]: https://github.com/ai-job-search-dev/ai-job-search/compare/v1.1.0...v1.2.0
|
||||||
[1.1.0]: https://github.com/MadsLorentzen/ai-job-search/compare/v1.0.0...v1.1.0
|
[1.1.0]: https://github.com/ai-job-search-dev/ai-job-search/compare/v1.0.0...v1.1.0
|
||||||
[1.0.0]: https://github.com/MadsLorentzen/ai-job-search/releases/tag/v1.0.0
|
[1.0.0]: https://github.com/ai-job-search-dev/ai-job-search/releases/tag/v1.0.0
|
||||||
+33
-33
@@ -43,7 +43,7 @@ Reviews here are empirical. Bug reports are reproduced on master before the fix
|
|||||||
## Building for your own market? Do this instead
|
## Building for your own market? Do this instead
|
||||||
|
|
||||||
1. Fork the repo and run `/add-portal` with your local job board - it scaffolds a portal skill matching the shipped contract, and `/scrape` picks it up automatically.
|
1. Fork the repo and run `/add-portal` with your local job board - it scaffolds a portal skill matching the shipped contract, and `/scrape` picks it up automatically.
|
||||||
2. Announce your fork in the pinned [Community forks & adaptations](https://github.com/MadsLorentzen/ai-job-search/discussions/78) discussion so others can find it.
|
2. Announce your fork in the pinned [Community forks & adaptations](https://github.com/ai-job-search-dev/ai-job-search/discussions/78) discussion so others can find it.
|
||||||
3. Run the framework update checker (`python3 tools/check_upstream_updates.py`) in your fork to check if upstream has updated any framework files and compare them with your personalized variants.
|
3. Run the framework update checker (`python3 tools/check_upstream_updates.py`) in your fork to check if upstream has updated any framework files and compare them with your personalized variants.
|
||||||
|
|
||||||
Market-specific skills are genuinely valuable - they just live in forks, where their maintainers can test them and their users can find them.
|
Market-specific skills are genuinely valuable - they just live in forks, where their maintainers can test them and their users can find them.
|
||||||
@@ -60,9 +60,9 @@ What upstream maintains for other runtimes instead:
|
|||||||
- The root `AGENTS.md` points any agent at the canonical workflow specs and the profile entry point.
|
- The root `AGENTS.md` points any agent at the canonical workflow specs and the profile entry point.
|
||||||
- Framework instruction files carry `framework_version` markers, so a runtime fork can track methodology changes precisely (`python3 tools/check_upstream_updates.py`).
|
- Framework instruction files carry `framework_version` markers, so a runtime fork can track methodology changes precisely (`python3 tools/check_upstream_updates.py`).
|
||||||
|
|
||||||
Announce your runtime fork in the pinned [Community forks & adaptations](https://github.com/MadsLorentzen/ai-job-search/discussions/78) discussion and it gets listed alongside the market adaptations. The proven shape is a thin pointer: reference the specs here instead of copying them, so upstream improvements reach your fork on rebase.
|
Announce your runtime fork in the pinned [Community forks & adaptations](https://github.com/ai-job-search-dev/ai-job-search/discussions/78) discussion and it gets listed alongside the market adaptations. The proven shape is a thin pointer: reference the specs here instead of copying them, so upstream improvements reach your fork on rebase.
|
||||||
|
|
||||||
This is a decision, not a dogma: if cross-runtime standards mature to the point where these specs run unmodified elsewhere, or the community's center of gravity moves to runtime forks, the trade-off gets re-evaluated. Background: the architecture thread in [Community forks & adaptations](https://github.com/MadsLorentzen/ai-job-search/discussions/78).
|
This is a decision, not a dogma: if cross-runtime standards mature to the point where these specs run unmodified elsewhere, or the community's center of gravity moves to runtime forks, the trade-off gets re-evaluated. Background: the architecture thread in [Community forks & adaptations](https://github.com/ai-job-search-dev/ai-job-search/discussions/78).
|
||||||
|
|
||||||
## Practical notes
|
## Practical notes
|
||||||
|
|
||||||
@@ -70,34 +70,34 @@ This is a decision, not a dogma: if cross-runtime standards mature to the point
|
|||||||
- **Personal-use boundaries**: portal skills that touch ToS-restricted sources carry a prominent personal-use-only warning, and CI deliberately makes no live portal requests. Don't "fix" that.
|
- **Personal-use boundaries**: portal skills that touch ToS-restricted sources carry a prominent personal-use-only warning, and CI deliberately makes no live portal requests. Don't "fix" that.
|
||||||
- **LaTeX changes**: both templates must compile (`lualatex` for the CV, `xelatex` for the cover letter) and hold their exact page counts. CI smoke-checks this.
|
- **LaTeX changes**: both templates must compile (`lualatex` for the CV, `xelatex` for the cover letter) and hold their exact page counts. CI smoke-checks this.
|
||||||
|
|
||||||
Questions and proposals are welcome in [Discussions](https://github.com/MadsLorentzen/ai-job-search/discussions) - an Idea thread costs nothing and can save you building the wrong thing :-)
|
Questions and proposals are welcome in [Discussions](https://github.com/ai-job-search-dev/ai-job-search/discussions) - an Idea thread costs nothing and can save you building the wrong thing :-)
|
||||||
|
|
||||||
[#17]: https://github.com/MadsLorentzen/ai-job-search/issues/17
|
[#17]: https://github.com/ai-job-search-dev/ai-job-search/issues/17
|
||||||
[#30]: https://github.com/MadsLorentzen/ai-job-search/issues/30
|
[#30]: https://github.com/ai-job-search-dev/ai-job-search/issues/30
|
||||||
[#31]: https://github.com/MadsLorentzen/ai-job-search/issues/31
|
[#31]: https://github.com/ai-job-search-dev/ai-job-search/issues/31
|
||||||
[#35]: https://github.com/MadsLorentzen/ai-job-search/issues/35
|
[#35]: https://github.com/ai-job-search-dev/ai-job-search/issues/35
|
||||||
[#36]: https://github.com/MadsLorentzen/ai-job-search/issues/36
|
[#36]: https://github.com/ai-job-search-dev/ai-job-search/issues/36
|
||||||
[#37]: https://github.com/MadsLorentzen/ai-job-search/issues/37
|
[#37]: https://github.com/ai-job-search-dev/ai-job-search/issues/37
|
||||||
[#39]: https://github.com/MadsLorentzen/ai-job-search/issues/39
|
[#39]: https://github.com/ai-job-search-dev/ai-job-search/issues/39
|
||||||
[#41]: https://github.com/MadsLorentzen/ai-job-search/issues/41
|
[#41]: https://github.com/ai-job-search-dev/ai-job-search/issues/41
|
||||||
[#43]: https://github.com/MadsLorentzen/ai-job-search/issues/43
|
[#43]: https://github.com/ai-job-search-dev/ai-job-search/issues/43
|
||||||
[#44]: https://github.com/MadsLorentzen/ai-job-search/issues/44
|
[#44]: https://github.com/ai-job-search-dev/ai-job-search/issues/44
|
||||||
[#49]: https://github.com/MadsLorentzen/ai-job-search/issues/49
|
[#49]: https://github.com/ai-job-search-dev/ai-job-search/issues/49
|
||||||
[#52]: https://github.com/MadsLorentzen/ai-job-search/issues/52
|
[#52]: https://github.com/ai-job-search-dev/ai-job-search/issues/52
|
||||||
[#54]: https://github.com/MadsLorentzen/ai-job-search/issues/54
|
[#54]: https://github.com/ai-job-search-dev/ai-job-search/issues/54
|
||||||
[#55]: https://github.com/MadsLorentzen/ai-job-search/issues/55
|
[#55]: https://github.com/ai-job-search-dev/ai-job-search/issues/55
|
||||||
[#56]: https://github.com/MadsLorentzen/ai-job-search/issues/56
|
[#56]: https://github.com/ai-job-search-dev/ai-job-search/issues/56
|
||||||
[#59]: https://github.com/MadsLorentzen/ai-job-search/issues/59
|
[#59]: https://github.com/ai-job-search-dev/ai-job-search/issues/59
|
||||||
[#60]: https://github.com/MadsLorentzen/ai-job-search/issues/60
|
[#60]: https://github.com/ai-job-search-dev/ai-job-search/issues/60
|
||||||
[#63]: https://github.com/MadsLorentzen/ai-job-search/issues/63
|
[#63]: https://github.com/ai-job-search-dev/ai-job-search/issues/63
|
||||||
[#64]: https://github.com/MadsLorentzen/ai-job-search/issues/64
|
[#64]: https://github.com/ai-job-search-dev/ai-job-search/issues/64
|
||||||
[#66]: https://github.com/MadsLorentzen/ai-job-search/issues/66
|
[#66]: https://github.com/ai-job-search-dev/ai-job-search/issues/66
|
||||||
[#67]: https://github.com/MadsLorentzen/ai-job-search/issues/67
|
[#67]: https://github.com/ai-job-search-dev/ai-job-search/issues/67
|
||||||
[#68]: https://github.com/MadsLorentzen/ai-job-search/issues/68
|
[#68]: https://github.com/ai-job-search-dev/ai-job-search/issues/68
|
||||||
[#72]: https://github.com/MadsLorentzen/ai-job-search/issues/72
|
[#72]: https://github.com/ai-job-search-dev/ai-job-search/issues/72
|
||||||
[#73]: https://github.com/MadsLorentzen/ai-job-search/issues/73
|
[#73]: https://github.com/ai-job-search-dev/ai-job-search/issues/73
|
||||||
[#75]: https://github.com/MadsLorentzen/ai-job-search/issues/75
|
[#75]: https://github.com/ai-job-search-dev/ai-job-search/issues/75
|
||||||
[#76]: https://github.com/MadsLorentzen/ai-job-search/issues/76
|
[#76]: https://github.com/ai-job-search-dev/ai-job-search/issues/76
|
||||||
[#155]: https://github.com/MadsLorentzen/ai-job-search/pull/155
|
[#155]: https://github.com/ai-job-search-dev/ai-job-search/pull/155
|
||||||
[#162]: https://github.com/MadsLorentzen/ai-job-search/pull/162
|
[#162]: https://github.com/ai-job-search-dev/ai-job-search/pull/162
|
||||||
[#165]: https://github.com/MadsLorentzen/ai-job-search/pull/165
|
[#165]: https://github.com/ai-job-search-dev/ai-job-search/pull/165
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
<a href="https://trendshift.io/repositories/43622?utm_source=trendshift-badge&utm_medium=badge&utm_campaign=badge-trendshift-43622" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/trendshift/repositories/43622/daily" alt="MadsLorentzen%2Fai-job-search | Trendshift" width="250" height="55"/></a>
|
<a href="https://trendshift.io/repositories/43622?utm_source=trendshift-badge&utm_medium=badge&utm_campaign=badge-trendshift-43622" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/trendshift/repositories/43622/daily" alt="MadsLorentzen%2Fai-job-search | Trendshift" width="250" height="55"/></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
[](https://github.com/MadsLorentzen/ai-job-search/actions/workflows/ci.yml)
|
[](https://github.com/ai-job-search-dev/ai-job-search/actions/workflows/ci.yml)
|
||||||
|
|
||||||
An AI-powered job application framework built on [Claude Code](https://claude.com/claude-code). Fork it, fill in your profile, and let Claude evaluate job postings, tailor your CV, write cover letters, and prepare you for interviews.
|
An AI-powered job application framework built on [Claude Code](https://claude.com/claude-code). Fork it, fill in your profile, and let Claude evaluate job postings, tailor your CV, write cover letters, and prepare you for interviews.
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ The framework encodes career guidance best practices, including structured evalu
|
|||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- [Claude Code](https://claude.com/claude-code) (CLI). Claude Code has no free tier: you need a Claude Pro/Max/Team subscription or Anthropic API credits (pay-per-token, usually cheaper for occasional use). Using a different agent tool (Codex, Antigravity, Gemini CLI)? Start at [`AGENTS.md`](AGENTS.md) - the portal search skills work there out of the box, and [community forks](https://github.com/MadsLorentzen/ai-job-search/discussions/78) adapt the full workflow.
|
- [Claude Code](https://claude.com/claude-code) (CLI). Claude Code has no free tier: you need a Claude Pro/Max/Team subscription or Anthropic API credits (pay-per-token, usually cheaper for occasional use). Using a different agent tool (Codex, Antigravity, Gemini CLI)? Start at [`AGENTS.md`](AGENTS.md) - the portal search skills work there out of the box, and [community forks](https://github.com/ai-job-search-dev/ai-job-search/discussions/78) adapt the full workflow.
|
||||||
- Python 3.10+
|
- Python 3.10+
|
||||||
- [Bun](https://bun.sh) (for job search CLI tools)
|
- [Bun](https://bun.sh) (for job search CLI tools)
|
||||||
- LaTeX distribution with `lualatex` and `xelatex`: [TeX Live](https://tug.org/texlive/), [MacTeX](https://tug.org/mactex/), [TinyTeX](https://yihui.org/tinytex/), or [MiKTeX](https://miktex.org/). The CV compiles with `lualatex` (pdflatex often fails on modern MiKTeX installs with `fontawesome5` font-expansion errors); the cover letter compiles with `xelatex` because `cover.cls` requires `fontspec`. If using a minimal TeX install such as TinyTeX or BasicTeX, install the extra packages listed in [SETUP.md](SETUP.md#minimal-tex-install-tinytexbasictex).
|
- LaTeX distribution with `lualatex` and `xelatex`: [TeX Live](https://tug.org/texlive/), [MacTeX](https://tug.org/mactex/), [TinyTeX](https://yihui.org/tinytex/), or [MiKTeX](https://miktex.org/). The CV compiles with `lualatex` (pdflatex often fails on modern MiKTeX installs with `fontawesome5` font-expansion errors); the cover letter compiles with `xelatex` because `cover.cls` requires `fontspec`. If using a minimal TeX install such as TinyTeX or BasicTeX, install the extra packages listed in [SETUP.md](SETUP.md#minimal-tex-install-tinytexbasictex).
|
||||||
@@ -74,7 +74,7 @@ The framework encodes career guidance best practices, including structured evalu
|
|||||||
### 1. Fork and clone
|
### 1. Fork and clone
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gh repo fork MadsLorentzen/ai-job-search --clone
|
gh repo fork ai-job-search-dev/ai-job-search --clone
|
||||||
cd ai-job-search
|
cd ai-job-search
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -302,7 +302,7 @@ The four Danish CLI tools in `.agents/skills/` (Jobbank, Jobdanmark, Jobindex, J
|
|||||||
|
|
||||||
Give it your local job board's URL. The command investigates the portal (search-URL pattern, result-page structure, robots.txt/access rules), scaffolds a CLI skill with the same structure, commands, and output contract as the shipped ones, and test-runs a live query before registering anything. Auth-walled portals are declined, and portals with restrictive terms get a prominent personal-use-only warning in the generated skill. The generated skill is market-specific and lives in your fork; the generator itself is the universal part.
|
Give it your local job board's URL. The command investigates the portal (search-URL pattern, result-page structure, robots.txt/access rules), scaffolds a CLI skill with the same structure, commands, and output contract as the shipped ones, and test-runs a live query before registering anything. Auth-walled portals are declined, and portals with restrictive terms get a prominent personal-use-only warning in the generated skill. The generated skill is market-specific and lives in your fork; the generator itself is the universal part.
|
||||||
|
|
||||||
Maintaining a fork adapted to your market or language? Add it to the [Community forks & adaptations](https://github.com/MadsLorentzen/ai-job-search/discussions/78) thread so others can find it.
|
Maintaining a fork adapted to your market or language? Add it to the [Community forks & adaptations](https://github.com/ai-job-search-dev/ai-job-search/discussions/78) thread so others can find it.
|
||||||
|
|
||||||
For **country-agnostic** starting points outside Denmark, the repo ships two portal skills alongside the Danish demos:
|
For **country-agnostic** starting points outside Denmark, the repo ships two portal skills alongside the Danish demos:
|
||||||
|
|
||||||
@@ -313,11 +313,11 @@ For **country-agnostic** starting points outside Denmark, the repo ships two por
|
|||||||
|
|
||||||
Everything above adds up to an extension model, so here it is stated plainly. The framework has three extension points, and none of them require touching upstream:
|
Everything above adds up to an extension model, so here it is stated plainly. The framework has three extension points, and none of them require touching upstream:
|
||||||
|
|
||||||
1. **Portal skills** - the module system for job boards. Every `*-search` skill is a self-contained folder under `.agents/skills/` with the same contract (a `search`/`detail` CLI, `--format json|table|plain` output, an `enabled:` flag in its `SKILL.md`, its own tests). `/scrape` auto-discovers any installed skill that follows the contract - nothing to register, nothing to wire up. `/add-portal` generates new ones; the [community portal index](https://github.com/MadsLorentzen/ai-job-search/discussions/78) catalogs the ones other forks have built.
|
1. **Portal skills** - the module system for job boards. Every `*-search` skill is a self-contained folder under `.agents/skills/` with the same contract (a `search`/`detail` CLI, `--format json|table|plain` output, an `enabled:` flag in its `SKILL.md`, its own tests). `/scrape` auto-discovers any installed skill that follows the contract - nothing to register, nothing to wire up. `/add-portal` generates new ones; the [community portal index](https://github.com/ai-job-search-dev/ai-job-search/discussions/78) catalogs the ones other forks have built.
|
||||||
2. **Document templates** - `/add-template` registers any CV or cover-letter toolchain that compiles to PDF from the command line, LaTeX or otherwise.
|
2. **Document templates** - `/add-template` registers any CV or cover-letter toolchain that compiles to PDF from the command line, LaTeX or otherwise.
|
||||||
3. **Evaluation criteria** - deal-breakers and preferences in your profile are free-form, and the evaluation rubric scores against whatever you put there. "Strong parental-leave terms", "minimum salary X per my union's scale", "no on-call" - each is one profile line, no code, and it carries real weight in `/rank` and `/apply` fit evaluations. Language is the one deal-breaker type with dedicated, structured handling: `/setup` captures every language you work in and your level (asked directly, or inferred from your CV/LinkedIn export) into a `Languages` table, and the Language Gate (`04-job-evaluation.md`) hard-rejects a posting that requires a language you haven't declared at all, while flagging - not auto-rejecting - one that asks for a higher level than you declared in a language you do work in, so a borderline case (a strict "fluent" bar against your own B1/B2, say) gets your judgment instead of a silent drop.
|
3. **Evaluation criteria** - deal-breakers and preferences in your profile are free-form, and the evaluation rubric scores against whatever you put there. "Strong parental-leave terms", "minimum salary X per my union's scale", "no on-call" - each is one profile line, no code, and it carries real weight in `/rank` and `/apply` fit evaluations. Language is the one deal-breaker type with dedicated, structured handling: `/setup` captures every language you work in and your level (asked directly, or inferred from your CV/LinkedIn export) into a `Languages` table, and the Language Gate (`04-job-evaluation.md`) hard-rejects a posting that requires a language you haven't declared at all, while flagging - not auto-rejecting - one that asks for a higher level than you declared in a language you do work in, so a borderline case (a strict "fluent" bar against your own B1/B2, say) gets your judgment instead of a silent drop.
|
||||||
|
|
||||||
**Borrowing a portal skill from another fork** is the intended way to get a board that upstream doesn't ship: find it in the [portal index](https://github.com/MadsLorentzen/ai-job-search/discussions/78), open that fork, and copy the one folder into your own `.agents/skills/`. Before you run it:
|
**Borrowing a portal skill from another fork** is the intended way to get a board that upstream doesn't ship: find it in the [portal index](https://github.com/ai-job-search-dev/ai-job-search/discussions/78), open that fork, and copy the one folder into your own `.agents/skills/`. Before you run it:
|
||||||
|
|
||||||
- **Read the code.** All of it - these CLIs run pre-approved on your machine (`.claude/settings.json` allowlists them) against your career data. Check that the only network calls go to the job board it claims to search, that `package.json` has no `dependencies` and no lifecycle scripts (`postinstall` etc.), and that nothing reads or writes outside its own folder.
|
- **Read the code.** All of it - these CLIs run pre-approved on your machine (`.claude/settings.json` allowlists them) against your career data. Check that the only network calls go to the job board it claims to search, that `package.json` has no `dependencies` and no lifecycle scripts (`postinstall` etc.), and that nothing reads or writes outside its own folder.
|
||||||
- **Run its tests offline** (`bun test` in the skill's `cli/` directory) - a well-built skill's tests pass with no network access.
|
- **Run its tests offline** (`bun test` in the skill's `cli/` directory) - a well-built skill's tests pass with no network access.
|
||||||
@@ -325,7 +325,7 @@ Everything above adds up to an extension model, so here it is stated plainly. Th
|
|||||||
|
|
||||||
The copy step is manual on purpose. Your settings already allow installed portal skills to run without asking each time - so an installer that fetched them from third-party repos for you would skip the one check that matters: you, reading the code first. There isn't one, and that's a security decision rather than a missing feature.
|
The copy step is manual on purpose. Your settings already allow installed portal skills to run without asking each time - so an installer that fetched them from third-party repos for you would skip the one check that matters: you, reading the code first. There isn't one, and that's a security decision rather than a missing feature.
|
||||||
|
|
||||||
Market-specific *data sources* (a national salary database, local award-rate tables) follow the same pattern as portals: they belong in a market fork, shared via [#78](https://github.com/MadsLorentzen/ai-job-search/discussions/78), not upstream.
|
Market-specific *data sources* (a national salary database, local award-rate tables) follow the same pattern as portals: they belong in a market fork, shared via [#78](https://github.com/ai-job-search-dev/ai-job-search/discussions/78), not upstream.
|
||||||
|
|
||||||
### Salary benchmarking
|
### Salary benchmarking
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Reporting a vulnerability
|
## Reporting a vulnerability
|
||||||
|
|
||||||
Please report security findings privately via **[GitHub private vulnerability reporting](https://github.com/MadsLorentzen/ai-job-search/security/advisories/new)** rather than a public issue. You will get a response within a few days, credit in the fix unless you prefer otherwise, and public disclosure coordinated with the patch.
|
Please report security findings privately via **[GitHub private vulnerability reporting](https://github.com/ai-job-search-dev/ai-job-search/security/advisories/new)** rather than a public issue. You will get a response within a few days, credit in the fix unless you prefer otherwise, and public disclosure coordinated with the patch.
|
||||||
|
|
||||||
If the private form is unavailable, open a public issue that describes the *class* of problem without a working recipe, and note that you have details to share privately.
|
If the private form is unavailable, open a public issue that describes the *class* of problem without a working recipe, and note that you have details to share privately.
|
||||||
|
|
||||||
@@ -47,4 +47,4 @@ Instruction-level defenses raise the bar; permission-level defenses bound the da
|
|||||||
## Scope notes
|
## Scope notes
|
||||||
|
|
||||||
- Portal CLI skills make live requests only when you run them; CI never does.
|
- Portal CLI skills make live requests only when you run them; CI never does.
|
||||||
- Community fork skills listed in the [forks index](https://github.com/MadsLorentzen/ai-job-search/discussions/78) are **not** covered by this policy - review the code you copy, as the index itself says.
|
- Community fork skills listed in the [forks index](https://github.com/ai-job-search-dev/ai-job-search/discussions/78) are **not** covered by this policy - review the code you copy, as the index itself says.
|
||||||
@@ -166,7 +166,7 @@ If a command still uses `pdftotext -layout`, it must pass `-enc UTF-8` as well.
|
|||||||
## 2. Fork and clone
|
## 2. Fork and clone
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gh repo fork MadsLorentzen/ai-job-search --clone
|
gh repo fork ai-job-search-dev/ai-job-search --clone
|
||||||
cd ai-job-search
|
cd ai-job-search
|
||||||
gh repo set-default <your-github-username>/ai-job-search
|
gh repo set-default <your-github-username>/ai-job-search
|
||||||
```
|
```
|
||||||
@@ -307,10 +307,10 @@ Upstream keeps improving the methodology files your fork has personalized, so pl
|
|||||||
|
|
||||||
**Prefer releases over raw `master`.** Tagged [releases](../../releases) are vetted checkpoints, each described in [CHANGELOG.md](CHANGELOG.md). Updating to a tag pulls a stable, documented state instead of whatever `master` happens to be mid-review. Fetch tags with `git fetch upstream --tags` and merge a release (for example `git merge v1.0.0`) when you want stability; pull `master` directly only when you specifically want the latest unreleased changes. The steps below apply either way - substitute the release tag for `upstream/master` where you see it.
|
**Prefer releases over raw `master`.** Tagged [releases](../../releases) are vetted checkpoints, each described in [CHANGELOG.md](CHANGELOG.md). Updating to a tag pulls a stable, documented state instead of whatever `master` happens to be mid-review. Fetch tags with `git fetch upstream --tags` and merge a release (for example `git merge v1.0.0`) when you want stability; pull `master` directly only when you specifically want the latest unreleased changes. The steps below apply either way - substitute the release tag for `upstream/master` where you see it.
|
||||||
|
|
||||||
1. **Commit your personalization - but know where those commits land.** `/setup` edits CLAUDE.md and the profile skill files in place; those edits are *yours*, and committing them is what lets updates merge cleanly. But a GitHub **fork of this repo is public** - forks of public repositories cannot be made private - so anything you commit *and push to a fork* is visible to anyone. If you want your profile in a remote at all, don't push it to a fork: create a **private** repository, push there, and add this repo as the `upstream` remote (`git remote add upstream https://github.com/MadsLorentzen/ai-job-search.git`) to keep receiving updates. Committing locally without pushing is also fine. The genuinely sensitive files (tracker, salary data, `documents/`, application archives) are gitignored and never enter git either way. An uncommitted working tree is the most common reason `git pull` refuses to merge at all (`Your local changes ... would be overwritten`).
|
1. **Commit your personalization - but know where those commits land.** `/setup` edits CLAUDE.md and the profile skill files in place; those edits are *yours*, and committing them is what lets updates merge cleanly. But a GitHub **fork of this repo is public** - forks of public repositories cannot be made private - so anything you commit *and push to a fork* is visible to anyone. If you want your profile in a remote at all, don't push it to a fork: create a **private** repository, push there, and add this repo as the `upstream` remote (`git remote add upstream https://github.com/ai-job-search-dev/ai-job-search.git`) to keep receiving updates. Committing locally without pushing is also fine. The genuinely sensitive files (tracker, salary data, `documents/`, application archives) are gitignored and never enter git either way. An uncommitted working tree is the most common reason `git pull` refuses to merge at all (`Your local changes ... would be overwritten`).
|
||||||
2. **Preview what changed before pulling:**
|
2. **Preview what changed before pulling:**
|
||||||
```bash
|
```bash
|
||||||
git remote add upstream https://github.com/MadsLorentzen/ai-job-search.git # first time only, if you cloned your own fork
|
git remote add upstream https://github.com/ai-job-search-dev/ai-job-search.git # first time only, if you cloned your own fork
|
||||||
git fetch upstream # or origin, if you cloned the template directly
|
git fetch upstream # or origin, if you cloned the template directly
|
||||||
python3 tools/check_upstream_updates.py
|
python3 tools/check_upstream_updates.py
|
||||||
```
|
```
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ import os
|
|||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
UPSTREAM = "MadsLorentzen/ai-job-search"
|
UPSTREAM = "ai-job-search-dev/ai-job-search"
|
||||||
|
|
||||||
REPO = Path(__file__).resolve().parent.parent
|
REPO = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from pathlib import Path
|
|||||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||||
SCRIPT = REPO_ROOT / "tools" / "check_upstream_updates.py"
|
SCRIPT = REPO_ROOT / "tools" / "check_upstream_updates.py"
|
||||||
|
|
||||||
TEMPLATE_URL = "https://github.com/MadsLorentzen/ai-job-search.git"
|
TEMPLATE_URL = "https://github.com/ai-job-search-dev/ai-job-search.git"
|
||||||
FORK_URL = "https://github.com/octocat/ai-job-search.git"
|
FORK_URL = "https://github.com/octocat/ai-job-search.git"
|
||||||
|
|
||||||
FRAMEWORK_FILES = [
|
FRAMEWORK_FILES = [
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ class ToolsWriteUtf8(unittest.TestCase):
|
|||||||
subprocess.run(["git", "init", "-b", "master"], cwd=repo, check=True, capture_output=True)
|
subprocess.run(["git", "init", "-b", "master"], cwd=repo, check=True, capture_output=True)
|
||||||
subprocess.run(["git", "config", "user.name", "Test"], cwd=repo, check=True, capture_output=True)
|
subprocess.run(["git", "config", "user.name", "Test"], cwd=repo, check=True, capture_output=True)
|
||||||
subprocess.run(["git", "config", "user.email", "test@example.com"], cwd=repo, check=True, capture_output=True)
|
subprocess.run(["git", "config", "user.email", "test@example.com"], cwd=repo, check=True, capture_output=True)
|
||||||
subprocess.run(["git", "remote", "add", "upstream", "https://github.com/MadsLorentzen/ai-job-search.git"], cwd=repo, check=True, capture_output=True)
|
subprocess.run(["git", "remote", "add", "upstream", "https://github.com/ai-job-search-dev/ai-job-search.git"], cwd=repo, check=True, capture_output=True)
|
||||||
(repo / "file.txt").write_text("hello\n", encoding="utf-8")
|
(repo / "file.txt").write_text("hello\n", encoding="utf-8")
|
||||||
subprocess.run(["git", "add", "file.txt"], cwd=repo, check=True, capture_output=True)
|
subprocess.run(["git", "add", "file.txt"], cwd=repo, check=True, capture_output=True)
|
||||||
subprocess.run(["git", "commit", "-m", "init"], cwd=repo, check=True, capture_output=True)
|
subprocess.run(["git", "commit", "-m", "init"], cwd=repo, check=True, capture_output=True)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ except ImportError: # `python -m unittest discover -s tests` imports test modul
|
|||||||
import _upstream
|
import _upstream
|
||||||
from _upstream import is_upstream_checkout
|
from _upstream import is_upstream_checkout
|
||||||
|
|
||||||
UPSTREAM = "MadsLorentzen/ai-job-search"
|
UPSTREAM = "ai-job-search-dev/ai-job-search"
|
||||||
|
|
||||||
|
|
||||||
def _no_github_env(testcase):
|
def _no_github_env(testcase):
|
||||||
@@ -81,16 +81,16 @@ class UpstreamCheckoutTests(unittest.TestCase):
|
|||||||
|
|
||||||
def test_origin_url_forms(self):
|
def test_origin_url_forms(self):
|
||||||
cases = [
|
cases = [
|
||||||
("https://github.com/MadsLorentzen/ai-job-search", True),
|
("https://github.com/ai-job-search-dev/ai-job-search", True),
|
||||||
("https://github.com/MadsLorentzen/ai-job-search.git", True),
|
("https://github.com/ai-job-search-dev/ai-job-search.git", True),
|
||||||
("git@github.com:MadsLorentzen/ai-job-search", True),
|
("git@github.com:ai-job-search-dev/ai-job-search", True),
|
||||||
("git@github.com:MadsLorentzen/ai-job-search.git", True),
|
("git@github.com:ai-job-search-dev/ai-job-search.git", True),
|
||||||
("ssh://git@github.com/MadsLorentzen/ai-job-search.git", True),
|
("ssh://git@github.com/ai-job-search-dev/ai-job-search.git", True),
|
||||||
("ssh://git@github.com/MadsLorentzen/ai-job-search", True),
|
("ssh://git@github.com/ai-job-search-dev/ai-job-search", True),
|
||||||
("ssh://git@github.com/someone-else/ai-job-search.git", False),
|
("ssh://git@github.com/someone-else/ai-job-search.git", False),
|
||||||
("https://github.com/someone-else/ai-job-search.git", False),
|
("https://github.com/someone-else/ai-job-search.git", False),
|
||||||
("git@github.com:someone-else/ai-job-search", False),
|
("git@github.com:someone-else/ai-job-search", False),
|
||||||
("https://gitlab.com/MadsLorentzen/ai-job-search.git", False),
|
("https://gitlab.com/ai-job-search-dev/ai-job-search.git", False),
|
||||||
]
|
]
|
||||||
for url, expected in cases:
|
for url, expected in cases:
|
||||||
with self.subTest(url=url):
|
with self.subTest(url=url):
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from pathlib import Path
|
|||||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||||
SCRIPT = REPO_ROOT / "tools" / "upstream_triage.py"
|
SCRIPT = REPO_ROOT / "tools" / "upstream_triage.py"
|
||||||
WORKFLOW = REPO_ROOT / ".github" / "workflows" / "upstream-watch.yml"
|
WORKFLOW = REPO_ROOT / ".github" / "workflows" / "upstream-watch.yml"
|
||||||
UPSTREAM_SLUG = "MadsLorentzen/ai-job-search"
|
UPSTREAM_SLUG = "ai-job-search-dev/ai-job-search"
|
||||||
|
|
||||||
|
|
||||||
def git(root: Path, *args: str) -> str:
|
def git(root: Path, *args: str) -> str:
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ FRAMEWORK_FILES = [
|
|||||||
"AGENTS.md",
|
"AGENTS.md",
|
||||||
]
|
]
|
||||||
|
|
||||||
UPSTREAM_REPO_SLUG = "MadsLorentzen/ai-job-search"
|
UPSTREAM_REPO_SLUG = "ai-job-search-dev/ai-job-search"
|
||||||
|
|
||||||
def run_git(args: list[str]) -> tuple[int, str, str]:
|
def run_git(args: list[str]) -> tuple[int, str, str]:
|
||||||
res = subprocess.run(
|
res = subprocess.run(
|
||||||
|
|||||||
Reference in new issue
Block a user