| name | jobhunt |
| description | Track job applications, analyze positions, identify skill gaps, and plan your job search strategy |
| read_strategy | On first use: read Quick Start + Job Seeker Profile.
When searching: read Discovery section (agent-driven search missions).
When ingesting: read Ingestion + Sensemaking sections.
When analyzing: read Analysis section.
Full command reference: read Commands section on demand.
|
| triggers | ["add job / ingest job / new position","search for jobs / run a search mission","analyze this job posting / make sense of","show my pipeline / skill gaps / learning plan","update status / job search","create seeker profile / set up job search"] |
| prerequisites | ["TypeDB running (make db-start)","make build-skills"] |
Job Hunting Notebook Skill
Use this skill to manage a job search as a knowledge graph. Claude acts as the career agent — browsing job boards, evaluating postings against the seeker's profile, and building structured understanding of positions, companies, and fit over time.
Key principle: The agent does the sensemaking. Scripts are tools that search APIs, store data, and run queries. The agent decides what's relevant, writes the rationale, and manages the pipeline.
Role model: The job seeker is a BFO/UFO role that inheres in a person. One person can have multiple roles (job seeker, author, evaluator). The role holds search-specific data; the person holds identity data.
1. Quick Start
Prerequisites
- TypeDB must be running:
make db-start
- Dependencies installed:
uv sync --all-extras (from project root)
- Schema loaded: run
make build-db after make build-skills
Path note: Replace .claude/skills/jobhunt below with your installation directory:
- Claude plugin install:
${CLAUDE_PLUGIN_ROOT}/skills/jobhunt (self-contained bundle at plugins/jobhunt/)
- skillful-alhazen project:
.claude/skills/jobhunt
When installed as a plugin, TypeDB starts automatically on session start (no manual init required).
Environment Variables
TYPEDB_HOST: TypeDB server (default: localhost)
TYPEDB_PORT: TypeDB port (default: 1729)
TYPEDB_DATABASE: Database name (default: alhazen_notebook)
Essential Commands
uv run python .claude/skills/jobhunt/jobhunt.py ingest-job \
--url "https://boards.greenhouse.io/anthropic/jobs/123456" \
--priority high
uv run python .claude/skills/jobhunt/jobhunt.py list-pipeline
uv run python .claude/skills/jobhunt/jobhunt.py show-position --id "position-abc123"
uv run python .claude/skills/jobhunt/jobhunt.py add-note \
--about "position-abc123" --type research \
--content "Strong AI safety focus, good culture fit"
Command Output Pattern
uv run emits a VIRTUAL_ENV warning to stderr. Always use 2>/dev/null when piping output to a JSON parser -- never 2>&1, which merges the warning into stdout and breaks JSON parsing.
2. Job Seeker Profile
The job seeker is modeled as a role (BFO/UFO pattern) that inheres in a person. The role holds search-specific data (target role, industries, salary expectations) while the person entity holds identity data (name, email, linkedin).
Create a Seeker Profile
uv run python .claude/skills/jobhunt/jobhunt.py create-seeker-profile \
--person op-f25ab4b15b0f \
--target-role "Principal AI Architect" \
--industries "AI, Biotech, Scientific Computing" \
--salary "200k-250k" \
--location "Remote / SF Bay Area" \
--focus "TypeDB-powered knowledge systems, AI for science"
This creates a jhunt-job-seeker-role entity linked to the person via alh-role-bearing. All pipeline data (opportunities, skills, candidates) scopes to this role.
Build the Skill Profile
Skills are owned by the seeker role, derived from real evidence, and use a simplified Bloom's taxonomy for proficiency levels.
Proficiency levels:
| Level | Meaning | Evidence type | Interview readiness |
|---|
expert | Can design/teach | Publications, architected systems, led teams | Can whiteboard, critique alternatives |
practiced | Hands-on experience | Projects, production use, coursework | Can walk through how you used it |
aware | Conceptual knowledge | Read papers/docs, attended talks | Can answer "what is X" questions |
none | Not known | No evidence | Cannot discuss |
Step 1: Ingest Profile Artifacts
The agent ingests the seeker's professional artifacts as sources of evidence. Each artifact is stored and linked to the seeker via alh-aboutness so skills can trace back to their proof.
uv run python .claude/skills/jobhunt/jobhunt.py ingest-job \
--url "https://linkedin.com/in/username"
The agent should fetch each source, extract the content, and store it as an artifact linked to the seeker role via alh-aboutness. This creates the evidence chain: artifact → seeker → skill.
Step 2: Sensemaking Interview
The agent reads the ingested artifacts and conducts a structured interview with the seeker:
- "Tell me about your TypeDB experience — what have you built?"
- "How deep is your AWS knowledge — have you architected solutions or followed tutorials?"
- "What's your biomedical ontology experience — which ones have you used?"
For each skill identified, the agent assesses the proficiency level based on the evidence and discussion.
Step 3: Create Skills with Evidence
uv run python .claude/skills/jobhunt/jobhunt.py add-skill \
--name "Knowledge Graphs" --level "expert" \
--evidence "Built 5000+ entity TypeDB production KG, BFO/UFO ontology design" \
--recency "daily 2026" \
--description "TypeDB 3.x, TypeQL, schema evolution, GLAV mapping"
uv run python .claude/skills/jobhunt/jobhunt.py add-skill \
--name "RAG Pipelines" --level "expert" \
--evidence "Voyage AI + Qdrant in production, hybrid ontology-filtered retrieval" \
--recency "daily 2026"
uv run python .claude/skills/jobhunt/jobhunt.py add-skill \
--name "Pharma Experience" --level "none" \
--description "No direct pharma industry experience. Biomedical informatics at CZI."
Each skill is linked to the seeker via jhunt-seeker-has-skill. The --evidence field should reference the ingested artifacts where possible.
Step 4: Gap Analysis
Once skills are populated, gap analysis joins seeker skills against position requirements:
- Position requires "RAG Pipelines" at "required" level → seeker has it at "expert" → no gap
- Position requires "Pharma Experience" at "preferred" level → seeker has "none" → gap
uv run python .claude/skills/jobhunt/jobhunt.py show-gaps
View Your Skills
uv run python .claude/skills/jobhunt/jobhunt.py list-skills
3. Discovery — Agent-Driven Search Missions
Discovery is agent-driven: Claude browses job boards, reads postings, evaluates fit against the seeker profile, and adds good matches as candidates with a written rationale. No automated scoring or LLM triage — the agent IS the sensemaker.
How a Search Mission Works
- Operator asks: "Search Anthropic for ML roles that match my profile"
- Agent reads the seeker profile (target role, industries, skills from TypeDB)
- Agent searches using the best tool for the job:
- Platform API (
search-source) for bulk listing from Greenhouse/Lever boards
- Playwright MCP (
search-source on website sources) for browsing JS-rendered job sites like hiring.cafe
- Web search (
web-search skill) for ad-hoc browsing of careers pages or niche boards
- Agent reads each posting and evaluates fit
- Agent adds good matches as candidates with rationale:
uv run python .claude/skills/jobhunt/job_forager.py add-candidate \
--title "Research Scientist, AI for Science" \
--url "https://boards.greenhouse.io/anthropic/jobs/123" \
--location "San Francisco" \
--relevance 0.85 \
--reason "Strong fit: combines AI evaluation with scientific methodology"
- Agent writes a search mission note summarizing what was found
- Operator reviews candidates in the dashboard, promotes promising ones to positions
Configure Search Sources
Three types of sources:
uv run python .claude/skills/jobhunt/job_forager.py add-source \
--name "Anthropic" --platform greenhouse --token anthropic
uv run python .claude/skills/jobhunt/job_forager.py add-source \
--name "ML Jobs" --platform linkedin --query "machine learning" --location "San Francisco"
uv run python .claude/skills/jobhunt/job_forager.py add-source \
--name "hiring.cafe" --platform website \
--url "https://hiring.cafe" \
--query "AI scientist knowledge graph biotech drug discovery"
| Platform | Type | Auth | Args |
|---|
greenhouse | Company board | None | --token (slug) |
lever | Company board | None | --token (slug) |
ashby | Company board | None | --token (slug) |
linkedin | Aggregator | None | --query, --location |
remotive | Aggregator | None | --query, --location |
adzuna | Aggregator | API key | --query, --location |
website | Job website | Playwright MCP | --url, --query |
Search a Source (Raw Listings)
Returns all job listings from a source for the agent to evaluate:
uv run python .claude/skills/jobhunt/job_forager.py search-source --source "Anthropic"
The agent reads through these, fetches interesting postings via web-fetch, and adds good matches as candidates.
Search a Website Source (Playwright MCP)
For website platform sources, search-source returns instructions instead of job listings.
The agent uses Playwright MCP tools to browse the site interactively:
- Get source info:
search-source --source "hiring.cafe" returns the URL and query
- Navigate:
browser_navigate to the source URL
- Search:
browser_type the query into the search box, submit
- Wait:
browser_snapshot or browser_take_screenshot to see rendered results
- Extract:
browser_run_code_unsafe to extract job URLs from the DOM, or read the snapshot
- Evaluate:
WebFetch each interesting job URL (individual pages usually render server-side)
- Add matches:
add-candidate with rationale for each good match
Example: hiring.cafe
hiring.cafe is a 41M+ job aggregator with AI-powered search. It uses client-side React rendering,
so API/curl cannot access search results — Playwright MCP is required.
The site auto-generates filters from natural language queries (Department, Industry, Tech Keywords).
Sometimes the auto-filters are too narrow and return zero results. If this happens, click "Reject All"
on the suggested filters and try a broader query, or remove specific filter chips.
Individual job pages (/viewjob/{id}) render server-side and can be fetched with WebFetch for full details.
Semantic Search Across Candidates
Candidates are embedded in Qdrant on creation. Search by meaning:
uv run python .claude/skills/jobhunt/job_forager.py search-candidates \
--query "knowledge graph engineering for science" --limit 10
Manage Candidates
uv run python .claude/skills/jobhunt/job_forager.py list-candidates
uv run python .claude/skills/jobhunt/job_forager.py list-candidates --status reviewed
uv run python .claude/skills/jobhunt/job_forager.py promote --id candidate-abc123
Key Principle
The agent does the sensemaking. Scripts are tools — they search APIs, store data, and run queries. The agent decides what's relevant, writes the rationale, and manages the pipeline.
4. Ingestion
From URL (ingest-job)
Triggers: "add job", "ingest job", "new position", "found a job posting", "here's a job"
uv run python .claude/skills/jobhunt/jobhunt.py ingest-job \
--url "https://boards.greenhouse.io/anthropic/jobs/123456" \
--priority high \
--tags "ai" "ml" "safety"
Options:
--url (required): Job posting URL
--priority: Set priority (high/medium/low)
--tags: Space-separated tags
Returns:
{
"success": true,
"position_id": "position-abc123",
"artifact_id": "artifact-xyz789",
"status": "raw",
"message": "Artifact stored - ask Claude to 'analyze this job posting' for sensemaking."
}
What ingestion produces:
- A
jobhunt-position entity with status researching
- A
jobhunt-job-description artifact containing the raw scraped page content
- An initial
jobhunt-application-note tracking the application status
Manual Position (add-position)
uv run python .claude/skills/jobhunt/jobhunt.py add-position \
--title "Senior ML Engineer" \
--company "Anthropic" \
--priority high
Add Company
uv run python .claude/skills/jobhunt/jobhunt.py add-company \
--name "Anthropic" \
--url "https://anthropic.com" \
--description "AI safety research company"
Add Engagement
uv run python .claude/skills/jobhunt/jobhunt.py add-engagement \
--name "Acme Corp Data Consulting" \
--company-id "company-abc123" \
--type project \
--rate "$200/hr" \
--status active \
--priority high
Engagement types: hourly | project | retainer | advisory
Add Venture
uv run python .claude/skills/jobhunt/jobhunt.py add-venture \
--name "Augura Health Advisory" \
--stage proposal-sent \
--equity-type advisor \
--priority high
Venture stages: exploring | proposal-sent | negotiating | active | paused | closed
Equity types: none | advisor | cofounder | investor
Add Lead
uv run python .claude/skills/jobhunt/jobhunt.py add-lead \
--name "Jane Smith - BigCo" \
--status warm \
--priority medium \
--description "Met at ML Summit, interested in consulting"
Lead statuses: first-contact | active | inactive | closed
5. Sensemaking
Sensemaking Workflow
When user says "analyze this job posting" or "make sense of [position]":
-
Get the artifact content
uv run python .claude/skills/jobhunt/jobhunt.py show-artifact --id "artifact-xyz"
-
Read and comprehend the content
- Look for: company name, job title, location, salary, remote policy
- Identify: requirements, responsibilities, qualifications
- Note: team info, culture signals, growth opportunities
-
Research the company and leadership online (use the web-search skill)
Search for: company mission, funding, recent news, and LinkedIn activity of key leaders.
Focus on:
- Company: founding story, funding/investors, mission statement, recent product launches
- Leadership: CEO, CTO, relevant SVPs -- what are they posting about on LinkedIn?
- Role context: Which leader is likely the hiring manager? What technical bets is the team making?
- Culture signals: hiring pace, public talks, open-source releases, AI-in-residence programs
Save findings as a research note attached to both the company and the position:
uv run python .claude/skills/jobhunt/jobhunt.py add-note \
--about "company-xyz" \
--type research \
--content "Series C, $4B raised. Mission: X. CEO recently spoke at Y conference..."
uv run python .claude/skills/jobhunt/jobhunt.py add-note \
--about "position-abc123" \
--type research \
--content "Bo Wang (SVP Biomedical AI) is likely hiring manager. Very active on LinkedIn..."
-
Create/update the company
uv run python .claude/skills/jobhunt/jobhunt.py add-company \
--name "Anthropic" \
--url "https://anthropic.com" \
--description "AI safety research company"
-
Extract requirements using the skill vocabulary
Before extracting requirements, load the skill concept vocabulary:
uv run python .claude/skills/jobhunt/jobhunt.py list-concepts
This returns the full vocabulary with your proficiency levels, alt-labels, and hierarchy.
Use canonical concept names when creating requirements so they match your skill profile.
For each skill in the posting:
- Look up the vocabulary for a matching concept (check alt-labels too)
- If match exists: use the canonical name from the vocabulary
- If no match: create a new concept first, then use it
- If the skill is not in your profile (shows as "?" in list-concepts):
ASK THE USER to self-assess their level for this skill.
Don't guess — the user knows their own capabilities. Ask:
"The posting requires [skill]. I don't have this in your profile yet.
How would you rate your proficiency: expert, practiced, aware, or none?"
Then create the skill with their assessment.
uv run python .claude/skills/jobhunt/jobhunt.py add-concept \
--name "Molecular Simulation" \
--alt-labels "MD,Molecular Dynamics,Force Fields"
uv run python .claude/skills/jobhunt/jobhunt.py add-skill \
--name "Molecular Simulation" --level "aware" \
--evidence "Read papers, understand concepts, no hands-on" \
--recency "reading 2026"
uv run python .claude/skills/jobhunt/jobhunt.py add-requirement \
--position "position-abc123" \
--skill "Molecular Simulation" \
--level "required"
Key principle: Never assume the user's skill level. If a requirement mentions
a skill not in their profile, ask them. Their self-assessment + evidence is the
ground truth, not the agent's inference.
-
Create analysis notes
Fit Analysis Note:
uv run python .claude/skills/jobhunt/jobhunt.py add-note \
--about "position-abc123" \
--type fit-analysis \
--content "Strong fit for core requirements. Gap in distributed systems." \
--fit-score 0.82 \
--fit-summary "Strong technical fit, one gap to address"
Skill Gap Note:
uv run python .claude/skills/jobhunt/jobhunt.py add-note \
--about "position-abc123" \
--type skill-gap \
--content "Distributed systems is required. Recommend: DDIA book, MIT 6.824 course."
-
Flag uncertainties
uv run python .claude/skills/jobhunt/jobhunt.py tag \
--entity "requirement-xyz" \
--tag "uncertain"
-
Report findings to user: company overview, leadership signals, fit score breakdown, key gaps, suggested next steps (including who to follow on LinkedIn)
List Artifacts Needing Analysis
uv run python .claude/skills/jobhunt/jobhunt.py list-artifacts --status raw
uv run python .claude/skills/jobhunt/jobhunt.py list-artifacts --status all
Get Artifact Content
uv run python .claude/skills/jobhunt/jobhunt.py show-artifact --id "artifact-xyz789"
Quality Checklist
Every opportunity MUST have after sensemaking:
- Clean title -- strip "Job Application for", "| LinkedIn", "hiring", and other job-board boilerplate from the name
- Short-name -- a compact display label (3-4 words, e.g. "Sr ML Eng - Anthropic")
- Company linked -- via
--company flag on add-position, auto-matched to existing jobhunt-company entities (do not create duplicates)
- Salary/compensation researched -- if not in the posting, search Levels.fyi or Glassdoor and record in
salary-range attribute
- At least one research note -- company background, leadership, role context
- Requirements extracted -- as
jobhunt-requirement entities via add-requirement
- Fit analysis note -- with
fit-score (0.0-1.0) and fit-summary
- Opportunity summary -- a
jobhunt-opp-summary-note synthesizing all notes. Regenerated after any note is added or updated.
- Embedded in map -- run
embedding_map.py embed-and-map after saving the summary so the opportunity appears on Mission Control.
Opportunity Summary
Every opportunity has exactly one jobhunt-opp-summary-note — a living markdown dossier that is overwritten each time notes change. This is the primary embedding text for the Mission Control map and the quick-read view for understanding any opportunity.
Workflow — regenerate after any note update:
uv run python .claude/skills/jobhunt/jobhunt.py regenerate-summary --about <opp-id>
uv run python .claude/skills/jobhunt/jobhunt.py upsert-summary --about <opp-id> --content "@/tmp/summary.md"
uv run python local_skills/jobhunt/embedding_map.py embed-and-map
IMPORTANT: Step 4 (re-embed) MUST be run after saving the summary. Without it, new or updated opportunities will not appear on the Mission Control map. This step re-computes embeddings for ALL opportunities and regenerates the 2D layout.
Summary templates by type:
Position:
## Role
- Title, company, location/remote policy
- Key responsibilities (2-3 bullets)
- Salary range if known
## Fit
- Overall fit score and one-line assessment
- Top strengths (2-3 bullets with specifics)
- Key gaps (1-2 bullets)
## Company
- What they do, stage/size, why interesting
- Key people (hiring manager, contacts)
## Status
- Current application status
- Key dates, next steps, or outcome
Engagement:
## Engagement
- Client, scope, type (consulting/contract/advisory)
- Rate/compensation if known
## Fit
- Why this is a good match
- Key deliverables
## Status
- Current stage (proposal/active/paused/closed)
Venture:
## Overview
- What the venture is, stage
- Your role/involvement
## Opportunity
- Why it's interesting
- Key milestones or next steps
## Status
- Current stage (seed/series-a/series-b/growth/closed)
Lead:
## Contact
- Who, title, organization
- How you met, when
## Context
- What the connection is about
- Potential opportunity or value
## Status
- Relationship state (first-contact/active/inactive/closed)
6. Application Tracking
Update Status
uv run python .claude/skills/jobhunt/jobhunt.py update-status \
--position "position-abc123" \
--status "applied" \
--date "2025-02-05"
Status values: researching | applied | phone-screen | interviewing | offer | rejected | withdrawn
Add Notes
uv run python .claude/skills/jobhunt/jobhunt.py add-note \
--about "position-abc123" \
--type interaction \
--content "Phone screen went well, moving to technical round." \
--interaction-type "call" \
--interaction-date "2025-02-05"
uv run python .claude/skills/jobhunt/jobhunt.py add-note \
--about "position-abc123" \
--type strategy \
--content "Lead with distributed systems experience from caching project."
uv run python .claude/skills/jobhunt/jobhunt.py add-note \
--about "position-abc123" \
--type cc-brief \
--content "Next session: prep for technical interview on 2025-02-10. Focus on system design questions."
uv run python .claude/skills/jobhunt/jobhunt.py add-note \
--about "position-abc123" \
--type cc-feedback \
--content "User reported phone screen went well. Interviewer asked about distributed caching. Move to next round."
Note types: research | strategy | interview | interaction | skill-gap | fit-analysis | general | cc-brief | cc-feedback
7. Analysis
Skill Gap Analysis
uv run python .claude/skills/jobhunt/jobhunt.py show-gaps
Learning Plan
uv run python .claude/skills/jobhunt/jobhunt.py learning-plan
Add Learning Resources
uv run python .claude/skills/jobhunt/jobhunt.py add-resource \
--name "Designing Data-Intensive Applications" \
--type "book" \
--url "https://dataintensive.net" \
--hours 30 \
--skills "distributed-systems" "system-design"
Link Resource to Requirement
uv run python .claude/skills/jobhunt/jobhunt.py link-resource \
--resource "<resource-id>" \
--requirement "<requirement-id>"
Cross-Skill Integration: Link Literature to Learning Plan
uv run python .claude/skills/scientific-literature/scientific_literature.py search \
--query "machine learning systems design" \
--collection "ML Systems Reading List"
uv run python .claude/skills/jobhunt/jobhunt.py link-collection \
--collection "<collection-id>" \
--skill "machine-learning"
uv run python .claude/skills/jobhunt/jobhunt.py link-paper \
--resource "<resource-id>" \
--paper "<paper-id>"
uv run python .claude/skills/jobhunt/jobhunt.py learning-plan
8. Reporting and Queries
JSON Output (programmatic)
uv run python .claude/skills/jobhunt/jobhunt.py list-pipeline
uv run python .claude/skills/jobhunt/jobhunt.py list-pipeline --status "interviewing"
uv run python .claude/skills/jobhunt/jobhunt.py list-pipeline --priority "high"
uv run python .claude/skills/jobhunt/jobhunt.py list-opportunities --type all
uv run python .claude/skills/jobhunt/jobhunt.py list-opportunities --type venture
uv run python .claude/skills/jobhunt/jobhunt.py list-opportunities --type engagement --status active
uv run python .claude/skills/jobhunt/jobhunt.py show-position --id "position-abc123"
uv run python .claude/skills/jobhunt/jobhunt.py show-opportunity --id "venture-abc123"
uv run python .claude/skills/jobhunt/jobhunt.py show-company --id "company-xyz"
uv run python .claude/skills/jobhunt/jobhunt.py show-gaps
uv run python .claude/skills/jobhunt/jobhunt.py learning-plan
Markdown Output (for display to users)
uv run python .claude/skills/jobhunt/jobhunt.py report-pipeline
uv run python .claude/skills/jobhunt/jobhunt.py report-stats
uv run python .claude/skills/jobhunt/jobhunt.py report-gaps
uv run python .claude/skills/jobhunt/jobhunt.py report-position --id "position-xyz"
Use reports (Markdown) for displaying to users in chat. Use JSON commands (list-pipeline, show-position) for programmatic processing.
Tagging
uv run python .claude/skills/jobhunt/jobhunt.py tag --entity "position-abc123" --tag "remote"
uv run python .claude/skills/jobhunt/jobhunt.py search-tag --tag "remote"
9. Opportunity Model
The jobhunt skill tracks multiple types of career opportunities via the jobhunt-opportunity hierarchy:
jobhunt-opportunity (base)
+-- jobhunt-position -- formal employment application (has application-status pipeline)
+-- jobhunt-engagement -- paid consulting/service work for a client
+-- jobhunt-venture -- startup/advisory/equity opportunity
+-- jobhunt-lead -- early-stage networking contact, role undefined
All opportunity types share: opportunity-status, priority-level, deadline, and can be linked to a jobhunt-company via opportunity-at-organization.
All opportunity types work with add-note --about <ID> -- notes attach to any identifiable-entity.
Update Any Opportunity
uv run python .claude/skills/jobhunt/jobhunt.py update-opportunity \
--id "venture-abc123" \
--status active \
--stage negotiating \
--priority high
Modeling Guide
| Situation | Entity type | Key attributes |
|---|
| Own consulting business | jobhunt-company | name, description |
| Startup advisory role | jobhunt-venture | venture-stage, equity-type |
| Consulting engagement | jobhunt-engagement | engagement-type, rate-info |
| Networking contact (no role yet) | jobhunt-lead | opportunity-status, description |
| Formal job application | jobhunt-position | job-url, application-status pipeline |
Phylo strategy pattern: Use an existing jobhunt-position as the anchor for all interactions. Add jobhunt-interaction-note entries for each meeting. Only create a separate jobhunt-lead if a genuinely new thread emerges from those conversations.
10. Data Model
Entity Types
| Type | Description |
|---|
your-skill | Your skills for gap analysis |
jobhunt-company | An employer/client organization |
jobhunt-opportunity | Base type for all opportunities |
jobhunt-position | Formal job posting (sub opportunity) |
jobhunt-engagement | Consulting engagement (sub opportunity) |
jobhunt-venture | Startup/advisory venture (sub opportunity) |
jobhunt-lead | Networking lead (sub opportunity) |
jobhunt-learning-resource | Course, book, tutorial |
jobhunt-contact | Person at a company |
jobhunt-search-source | Company board for forager |
jobhunt-candidate | Discovered posting (forager) |
Artifact Types
| Type | Description |
|---|
jobhunt-job-description | Raw HTML/text from job posting URL |
jobhunt-resume | Resume document |
jobhunt-cover-letter | Cover letter |
jobhunt-company-page | Company website snapshot |
jobhunt-proposal | Proposal or pitch deck for engagement/venture |
Note Types
| Type | Purpose |
|---|
jobhunt-application-note | Status tracking (positions) |
jobhunt-research-note | Company/opportunity research |
jobhunt-interview-note | Interview prep/feedback |
jobhunt-strategy-note | Talking points, approach |
jobhunt-skill-gap-note | Learning needs |
jobhunt-fit-analysis-note | Fit assessment |
jobhunt-interaction-note | Contact logs |
jobhunt-cc-brief-note | Claude Code brief for next session |
jobhunt-cc-feedback-note | Claude Code feedback from completed interaction |
Relations
position-at-company -- links position to employer
opportunity-at-organization -- links any opportunity type to a company
aboutness -- links notes to any entity (position, company, opportunity)
requirement-of -- links requirements to positions
Schema File
- JobHunt Schema:
local_skills/jobhunt/schema.tql
- Core Schema:
local_resources/typedb/alhazen_notebook.tql
11. Command Reference
jobhunt.py Commands
| Command | Description | Key Args |
|---|
ingest-job | Fetch job URL, store raw | --url |
add-skill | Add/update skill with Bloom's proficiency | --name, --level (expert/practiced/aware/none), --evidence, --recency |
list-skills | Show your skills | |
list-artifacts | List artifacts by status | --status |
show-artifact | Get artifact content | --id |
add-company | Add company | --name |
add-position | Add position manually | --title |
add-engagement | Add consulting engagement | --name, --type, --rate |
add-venture | Add startup/advisory venture | --name, --stage, --equity-type |
add-lead | Add networking lead | --name, --status |
update-opportunity | Update any opportunity status/stage/priority | --id |
show-opportunity | Show any opportunity details | --id |
list-opportunities | List by type/status | --type, --status, --priority |
add-requirement | Add skill requirement | --position, --skill |
update-status | Change position application status | --position, --status |
add-note | Create any note type | --about, --type, --content |
add-resource | Add learning resource | --name, --type |
link-collection | Link paper collection to skill gap | --collection, --skill |
link-resource | Link resource to a skill requirement | --resource, --requirement |
link-paper | Link learning resource to a paper | --resource, --paper |
create-seeker-profile | Create job-seeker role for a person | --person, --target-role, --industries |
list-pipeline | Show position pipeline | --status, --priority, --person |
show-position | Position details | --id |
show-company | Company details | --id |
show-gaps | Skill gap analysis | |
learning-plan | Prioritized study list | |
tag | Tag an entity | --entity, --tag |
search-tag | Find by tag | --tag |
report-pipeline | Pipeline overview (Markdown) | |
report-stats | Stats summary (Markdown) | |
report-gaps | Skill gaps report (Markdown) | |
report-position | Position detail (Markdown) | --id |
job_forager.py Commands
| Command | Description | Key Args |
|---|
add-source | Add a search source (company board or aggregator) | --name, --platform, --token/--query |
list-sources | List configured search sources | |
remove-source | Remove a source | --id, --token, or --name |
search-source | Search one source (raw listings for agent review) | --source |
add-candidate | Add a candidate with agent evaluation | --title, --url, --relevance, --reason |
search-candidates | Semantic search across candidates (Qdrant) | --query, --limit |
list-candidates | List candidates | --status, --source |
promote | Promote candidate to full position | --id |
12. Quality Checks
Declarative audit rules for data quality are defined in quality-checks.yaml.
Run Audits
uv run python .claude/skills/jobhunt/jobhunt.py audit
uv run python .claude/skills/jobhunt/jobhunt.py audit --fix
uv run python src/skillful_alhazen/utils/audit_runner.py run \
--checks local_skills/jobhunt/quality-checks.yaml
Current Checks
| Check | Severity | Description |
|---|
position-company-link | high | Positions should be linked to a company via position-at-company |
ugly-titles | medium | Position titles containing job-board boilerplate |
missing-short-name | medium | Positions without a short-name for compact display |
missing-salary | low | Positions without salary-range information |
positions-without-notes | low | Positions with no notes at all |
duplicate-companies | high | Multiple company entities with identical names |
orphaned-companies | medium | Companies with no positions or opportunities linked |
13. Dashboard
A Next.js dashboard is available for visualizing your job search pipeline. It runs in Docker (not npm run dev).
Docker Build/Run
docker compose build --no-cache dashboard
docker compose up -d dashboard
Views
- Pipeline Board (
/jobhunt) -- Kanban columns by application status
- Position Detail (
/jobhunt/position/{id}) -- Full position profile: requirements, notes, gap analysis, fit score
- Collection Detail (
/jobhunt/collection/{id}) -- Notes and resources grouped by collection
Internal Organization (for contributors)
- Pages:
dashboard/src/app/(jobhunt)/jobhunt/
- Components:
dashboard/src/components/jobhunt/
- API routes:
dashboard/src/app/api/jobhunt/
- TypeScript wrapper:
dashboard/src/lib/jobhunt.ts
14. Schema Gap Recognition
During sensemaking, if you encounter a concept, relationship, or entity type that has no place in the current TypeDB schema, that is a schema gap -- a signal for schema evolution, not a failure.
When you notice a schema gap:
- Complete as much as possible with the current schema (partial knowledge > none)
- Immediately file a gap issue:
uv run python local_resources/skilllog/skill_logger.py file-schema-gap \
--skill jobhunt \
--concept "<the concept you tried to represent>" \
--missing "<which TypeDB entity/relation/attribute is absent>" \
--suggested "<proposed TypeQL addition, or 'unknown' if unsure>"
Examples of schema gaps:
- A job posting mentions a work arrangement type that isn't in the schema
- A contact has a relationship type (e.g., "mentor") not modeled in
jobhunt-contact
- An opportunity has a compensation structure (e.g., revenue share) not covered by existing attributes
Use --dry-run first to review the issue before filing it.