- Notifications
You must be signed in to change notification settings - Fork15
Command Jobs uses AI to help software engineers find the best jobs
License
nicobrenner/commandjobs
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
██████╗ ██████╗ ███╗ ███╗███╗ ███╗ █████╗ ███╗ ██╗██████╗ ██╔════╝██╔═══██╗████╗ ████║████╗ ████║██╔══██╗████╗ ██║██╔══██╗ ██║ ██║ ██║██╔████╔██║██╔████╔██║███████║██╔██╗ ██║██║ ██║ ██║ ██║ ██║██║╚██╔╝██║██║╚██╔╝██║██╔══██║██║╚██╗██║██║ ██║ ╚██████╗╚██████╔╝██║ ╚═╝ ██║██║ ╚═╝ ██║██║ ██║██║ ╚████║██████╔╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═════╝ ██╗ ██████╗ ██████╗ ███████╗ ██║██╔═══██╗██╔══██╗██╔════╝ ██║██║ ██║██████╔╝███████╗ ██ ██║██║ ██║██╔══██╗╚════██║ ╚█████╔╝╚██████╔╝██████╔╝███████║ ╚════╝ ╚═════╝ ╚═════╝ ╚══════╝
📺 Use AI to find the best jobs for your resume and preferences
🧘🏻 A distraction-free, local-first, command line interface to scrape online jobs, and filter them to your needs
Using AI, Command Jobs makes sure to find only the absolute best matches for your experience, skills and job preferences
Stop wasting your time with online tools that are not built for you, the job finder
Command Jobs is the only job searching tool that runs from where you work, the terminal. And yes, it also doesn't make you read through hundreds of job listings just to find a couple of good matches
This is just starting out! Follow along as we improve it
To get started, check outQuick Start,Configuration andUsage
🙏🏼🤗❤️
Note: If you want to add another source of job listings,go to this issue and add it as a suggested source
Added new scraper for Workday, currently scraping NVIDIA, CROWDSTRIKE, RED HAT and SALESFORCE.
- The scraper currently scrapes for all countries on posts no older than aweek back!
Building in public:
❤️ If you want to contribute to this project and want to take a crack at writing tests for it, it would be amazing! 🤗 Here's a ticket to write a new test, and a walk-through of the current test code:Request to create: Test displaying the resume text 🙏🏼
Video walkthrough, from
git clone
all the way to finding the best matchesHere's a little bit of the internals of the application. Very high level overview of the features as well as the database. If you want to see more, or would like a deeper explanation, please create an Issue, thank you
Just wrote the first test! 😅 And it's in no small part thanks to Agentic'sGlide, which they recently launched (see announcement here). I was about to switch from ncurses topython-prompt-toolkit, and failing that from python to Go, so I could build Command Jobs usingBubble Tea 🤩😍🤤
Check out the amazingancv, a tool for building a really cool ascii version of your resume on the terminal! 🤗 (love the joke with the Venn diagram). Will need to integrate it as a library with Command Jobs
Tried outShellGPT and made a small PR to highlight its chat interface in the
README
. It's a pretty cool tool to use GPT from the terminal. Next I want to try coding a bit withaiderDecided to try to build this project as openly as possible, in that spirit, I just recorded a coding session in which I go through the process of trying to resolve a bug (issue #12), and finding 3 other bugs instead!
If you are just getting started with coding, it's also a pretty good overview of a basic software project management. In the video I show the whole workflow of not only writing code, but also managing an environment, dealing with errors, documenting the process in Github, managing git and branches, commiting, pushing and merging code, updating documentation (like now), and sharing/promoting
Thank you to the Hacker News community for the encouragement, enthusiasm and support. Check out this thread:Show HN: Tech jobs on the command line
View and navigate AI-matched job listings directly from the terminal
Scrape job listings from "Ask HN: Who's hiring?" posts on Hacker News
Process listings with GPT to find the best matches for you
- The app asks GPT for each job listing, if it's a good fit for your resume
- The prompt includes the resume, the job listing, a section for json formating the results, a role description, a job preferences section, and some additional questions
- You get a filtered list of the best matches for your resume and preferences
Track job applications directly in the terminal
Scrape job listings from additional sources
Add cronjob that runs periodically to scrape
Alerts about new matches found
Anything you'd like to see? Please add a ticket
After going through the Configuration and successfully running Command Jobs
You will get a menu with the options below. To navigate the menu, just use the arrow keys and select options with Enter. You can quit at any time by pressingq
When first running the app, open the Edit Resume section and paste the text of your resume, no need to include your name or contact info (you can see an example resume onconfig/base_resume.sample
. Alternatively, you can paste your resume text directly into abase_resume.txt
file on the base folder of the code
Then, get some job listings into the app by running Scrape "Ask HN: Who's hiring?". You can see the first few listings in the Navigate jobs in the local db section (if you want to see more, you can also openjob_listings.db
directly with sqlite3 and check out the contents)
For the next step, make sure you've reviewed your.env
file and have adapted the prompts to your preferences for job matching
Once you have your Resume ready, jobs in the local db and the prompts configured, run Find best matches for resume with AI. That will run through the listings to find a match of your resume and job preferences (for now, it is limited at 5 checks per run, you can modify that through changing theLIMIT
in the query withinfetch_job_listings()
insrc/database_manager.py
)
When the GPT analysis is done, you get access to the AI found X listings match your resume option, where you can navigate the best matches found
The menu includes:
- Edit Resume: Add or replace the text of your resume for AI matching
- Scrape "Ask HN: Who's hiring?": Scrape job listings from Hacker News
- Navigate jobs in the local db: Browse listings stored locally
- Find best matches for resume with AI: Match listings to your resume using AI
- AI found X listings match your resume: Review personalized job matches
To exit the application, pressq
Video walkthrough, fromgit clone
all the way to finding the best matches
Below is the step by step
Clone the repository:
git clone https://github.com/nicobrenner/commandjobs.git
cd commandjobs
Run via Docker
Build the Docker image:
docker-compose -f docker/docker-compose.yml build
Run the Docker container (make sure you've setup your OpenAI API key in your
.env
file - seeConfiguration section below):docker-compose -f docker/docker-compose.yml run app
(if you don't want to use Docker) Run with Python in a Virtual Environment
Set up a Python virtual environment and activate it:
python3 -m venv venv
source venv/bin/activate
Install the dependencies:
pip install -r config/requirements.txt
Run the application (make sure you've setup your OpenAI API key in your
.env
file - seeConfiguration section below):python src/menu.py
Create a
.env
file in the root directory of the project by copying theconfig/sample.env
file, and adding your OpenAI API key:cp config/sample.env .env
edit the .env fileto add your OpenAI API keyOPENAI_API_KEY=your_openai_api_key_hereOPENAI_GPT_MODEL=gpt-3.5-turboBASE_RESUME_PATH=base_resume.txtHN_START_URL=https://news.ycombinator.com/item?id=40563283&p=1...
Note: the above HN_START_URL is for April 2024
If you don't have an OpenAI API key,follow these instructions to obtain one.
Modify the prompt so that it matches your preferences. The prompt has 5 sections:
COMMANDJOBS_ROLE
: list the roles that you are looking forCOMMANDJOBS_ROLE=backend engineer, or fullstack engineer, or senior engineer, or senior tech lead, or engineering manager, or senior enginering manager, or founding engineer, or founding fullstack engineer, or something similar
COMMANDJOBS_IDEAL_JOB_QUESTIONS
: explain what is a good fit for youCOMMANDJOBS_IDEAL_JOB_QUESTIONS=and the company uses either Ruby, Rails, Ruby on Rails, or Python, the position doesn't require any knowledge or experience in any of the following: {job_requirement_exclusions}, the position is remote, it's for the US and the description matches the resume? (Yes or No), justify the Yes or No about the role being a good fit for the experience of the resume in one sentence.
COMMANDJOBS_EXCLUSIONS
: list things to avoid (this takes some trial and error to get right, iterating with the matches you get each time)COMMANDJOBS_EXCLUSIONS=VMS (video management systems), computer vision systems, Java, C++, C#, Grails, ML, Machine Learning, PyTorch, training models
COMMANDJOBS_PROMPT
: the prompt includes all the other elements as well as the questions that we want answers about from GPTCOMMANDJOBS_PROMPT=Given the below job listing html, and resume text. Listing:\n{job_html}\n\nResume:\n{resume}\n\nPlease provide the following information about the listing: brief 2 sentence summary of the listing, company name, [list of available positions, with individual corresponding links if available], tech stack description, do they use rails? (Yes or No), do they use python? (Yes or No), are the positions remote (not hybrid, not onsite)? (Yes or No), are they hiring in the US? (Yes or No), how to apply to the job? (provide 1 sentence max description, include link or email address if necessary), Does the role prioritize candidates with a background in a specific industry sector (e.g., tech, finance, healthcare)?, does the job seem like a good fit for the resume (Only say Yes if the role is for {roles} {ideal_job_questions}\n\nProvide output in JSON format, use this example for reference, always with the same keys, but replace the values with the answers for the previous requests for information: \n{output_format}
COMMANDJOBS_OUTPUT_FORMAT
: this specifies the output format for the prompt, including an example to follow - it's important that the structure and fields of the format matches the questions from the promptCOMMANDJOBS_OUTPUT_FORMAT="{\n \"small_summary\": \"Wine and Open Source developers for C-language systems programming\",\n \"company_name\": \"CodeWeavers\",\n \"available_positions\": [\n {\n \"position\": \"Wine and General Open Source Developers\",\n \"link\": \"https://www.codeweavers.com/about/jobs\"\n }\n ],\n \"tech_stack_description\": \"C-language systems programming\",\n \"use_rails\": \"No\",\n \"use_python\": \"No\",\n \"remote_positions\": \"Yes\",\n \"hiring_in_us\": \"Yes\",\n \"how_to_apply\": \"Apply through our website, here is the link: https://www.codeweavers.com/about/jobs\",\n \"back_ground_with_priority\": null,\n \"fit_for_resume\": \"No\",\n \"fit_justification\": \"The position is for Wine and Open Source developers, neither of which the resume has experience with. The job is remote in the US\"\n }"
Modify the query with filters for matching jobs.
In the file
src/display_matching_table.py
, the method__init__
has a variable (self.good_match_filters
) with the following SQL conditions:json_valid(gi.answer)=1AND json_extract(gi.answer,'$.fit_for_resume')='Yes'AND json_extract(gi.answer,'$.remote_positions')='Yes'AND json_extract(gi.answer,'$.hiring_in_us')<>'No'
These 3 conditions represent the default criteria for filtering AI-found matches. Below is the breakdown of the 3 default requirements for a good match:
The AI determined the listing a good match for the resume and preferences
AND json_extract(gi.answer,'$.fit_for_resume')='Yes'
The role is, or can be, remote
AND json_extract(gi.answer,'$.remote_positions')='Yes'
The role is hiring in the US (the value can be either Yes or NULL or '', so the condition checks that the field
'$.hiring_in_us'
is not'No'
)AND json_extract(gi.answer,'$.hiring_in_us')<>'No'
Note: the database is a sqlite3 database, so you can also just open it
sqlite3 job_listings.db
and then try out a query like the one below, and then experiment to see what you find. Regardless of filtering, all the answers and prompts should be stored in thegpt_interactions
table (checkout the latest update video about the internals):SELECTCOUNT(gi.job_id)FROM gpt_interactions giJOIN job_listings jlONgi.job_id=jl.idWHERE json_valid(gi.answer)=1AND json_extract(gi.answer,'$.fit_for_resume')='Yes'AND json_extract(gi.answer,'$.remote_positions')='Yes'AND json_extract(gi.answer,'$.hiring_in_us')<>'No'
You should adjust that to your preferences and you can mix and match with the questions/answers you want to get from your prompt
Increase the limit of listings to check per batch
The option
COMMANDJOBS_LISTINGS_PER_BATCH
(which should be in your.env
file, seesample.env
) determines how many listings are processed each time the menu option "Find best matches with AI" is executed. If you are using the default of 10, it means that every time you run the option "Find best matches", Command Jobs will make 10 requests togpt
. Once you trust the app, I recommend setting the limit to 500, so that the app can process all scraped listings in one go
Priority
- ❤️ If you want to contribute to this project and want to take a crack at writing tests for it, it would be amazing! 🤗 Here's a ticket to write a new test, and a walk-through of the current test code:Request to create: Test displaying the resume text 🙏🏼
We welcome contributions, especially in improving scrapers and enhancing user experience. If you'd like to help, please file an issue or pull request onour GitHub repository
Here's an overview of some of the internals of the app
Encounter any issues? Please file them on theproject's GitHub repo. We appreciate your feedback and contributions to making Command Jobs better!
This project is open-source and available under theApache 2.0 License.
- ancv, get a fancy version of your resume in your terminal, very cool