fix(apply,rank): route matching portal URLs to installed CLI detail before WebFetch (#535) (#562)

* fix(apply,rank): route matching portal URLs to installed CLI detail before WebFetch (#535)

When given a URL belonging to an installed portal (e.g. LinkedIn, Jobnet), WebFetch frequently encounters login walls, bot-detection blocks, or 403s. Installed portal CLIs under .agents/skills/ already provide a dedicated detail command that fetches clean posting text and structured metadata directly from board APIs.

- In .claude/commands/apply.md Step 0, invoke the matching installed portal CLI's detail command first, falling back to WebFetch on failure.

- In 09-web-research.md, place the installed portal CLI detail command as the first rung of the escalation order, bumping framework_version to 1.1.2.

- In .claude/commands/rank.md Step 2, align scoring agents to use the portal CLI's detail command before WebFetch.

- In tests/test_apply_host_check.py, add spec and resolution tests ensuring portal CLI detail precedence is strictly asserted and verified.

* fix(apply,rank): route matching portal URLs to installed CLI detail before WebFetch (#535)

When given a URL belonging to an installed portal, WebFetch frequently encounters login walls, bot-detection blocks, or 403s. Installed portal CLIs under .agents/skills/ already provide a dedicated detail command that fetches clean posting text and structured metadata directly from board APIs.

- In .claude/commands/apply.md Step 0, invoke the matching installed portal CLI's detail command first, falling back to WebFetch on failure. Derive matching portal skills from board hosts in cli/src and url-reference.md.

- In 09-web-research.md, place the installed portal CLI detail command as the first rung of the escalation order, update subsequent step references, and bump framework_version to 1.1.2.

- In .claude/commands/rank.md Step 2, align scoring agents to use the portal CLI's detail command before WebFetch.

- In CHANGELOG.md, record the framework_version bump (1.1.1 -> 1.1.2) under [Unreleased] / ### Changed.

- In tests/test_apply_host_check.py, add spec and dynamic resolution tests ensuring portal CLI detail precedence is strictly asserted and verified across all discovered installed skills.
This commit is contained in:
Ahmed authored and GitHub committed 2026-10-15 18:12:33 +02:00
1 parent 7dfa3b66fd
commit e2b966d0e7
5 files changed
+118 -13

No files matched your search

+2 -2
View File
@@ -55,8 +55,8 @@ State how many jobs will be ranked and how many are deferred before proceeding.
Dispatch parallel `general-purpose` agents via the **Agent tool**, ~5 jobs per agent (a single agent is fine for ≤5 jobs). Token-efficiency rules, consistent with `/apply`:
- Pass each agent everything it needs **inline in the prompt** - the job list (title, company, URL) and a compact scoring rubric extracted from the files you read in Step 1: the strong/moderate/weak skill match areas, direct/adjacent experience domains, behavioral thrive/drain factors, career goals, deal-breakers, and the location constraints. Do **not** make agents re-read the profile files.
- Agents fetch each posting URL with WebFetch and score **only from actually fetched content**. If a URL is dead, redirects to a listing page, or the posting has expired, the agent marks that job `expired` - it never scores from the title alone and never fabricates posting content.
- **Before marking anything `expired`, the agent must exhaust the escalation order** in `.claude/skills/job-application-assistant/09-web-research.md`: a `WebFetch` 403 is a rejected *client*, not a missing page, and retrying with browser headers via curl recovers most corporate and bank domains. A stored URL ending in a `#fragment` points at a listing page rather than a posting, so the agent should search the employer's own careers site for the role by name before writing the job off. Include this instruction in every scoring agent's prompt. `expired` means "retrieval genuinely failed after retrying", not "the first fetch was unhelpful".
- Agents fetch each posting URL following the escalation order in `.claude/skills/job-application-assistant/09-web-research.md` (using the installed portal CLI's `detail` command when the URL belongs to a portal in `.agents/skills/`, or `WebFetch` otherwise) and score **only from actually fetched content**. If a URL is dead, redirects to a listing page, or the posting has expired, the agent marks that job `expired` - it never scores from the title alone and never fabricates posting content.
- **Before marking anything `expired`, the agent must exhaust the escalation order** in `09-web-research.md`: installed portal CLI first, then `WebFetch`, then curl with browser headers (if `robots.txt` permits), then search for the employer's own careers site. A `WebFetch` 403 is a rejected *client*, not a missing page, and retrying with browser headers via curl recovers most corporate and bank domains. A stored URL ending in a `#fragment` points at a listing page rather than a posting, so the agent should search the employer's own careers site for the role by name before writing the job off. Include this instruction in every scoring agent's prompt. `expired` means "retrieval genuinely failed after retrying", not "the first fetch was unhelpful".
- Scope is triage: posting text vs. rubric. **No company research, no salary lookup, no web searches** - that depth belongs to `/apply`.
Each agent returns a JSON array, one object per job: