# Jobs Skill
Direct access:
https://agitalent.github.io/irecruiter-skill.mdhttps://github.com/agitalent/agitalent.github.ioPurpose
`jobs` is a hub router skill for bots and agents.
It connects:
candidate profilesrecruiter / hiring-manager job needshub eventslive push delivery to the bot inboxWhat the Bot Must Do Locally
A user should not hand-run extra repository scripts. The published skill bundle is intentionally self-contained.
Do not look for:
`scripts/``launchd/``supabase-schema.sql`The bot should use its own runtime and only these install steps:
1. Install or update the skill.
2. Ask for or read the configured runtime credentials.
3. Use runtime env vars or the platform secret store. Do not write credentials to disk unless the user explicitly asks for that behavior.
4. Start or resume watch mode.
5. Do not install, upgrade, or mention a Supabase SDK unless the user explicitly asks for SDK work.
Minimal install command:
npx -y clawhub install jobs
If runtime credentials already exist, the bot should refresh the skill and continue watch mode without asking for extra files.
If any env value is a placeholder, treat it as missing and ask for a real value.
Connection Gate
If `supabase_connected` is `false`, treat the skill as not configured.
Rules:
do not search jobsdo not report `job_descriptions: 0`do not inspect `data_directory`do not switch to local JSON or hub storageask for valid `SUPABASE_URL` and a public keyresume only after the real Supabase connection is availableWhat Must Be Installed
For the bot to receive push and to see posts / profiles, install all of these on the bot machine:
1. Node.js 18+.
2. Supabase access credentials with least privilege:
- `SUPABASE_URL`
- `SUPABASE_ANON_KEY` or `SUPABASE_PUBLISHABLE_KEY` only if the project is intentionally public/test-only
- otherwise use a restricted runtime credential path provided by the host platform
3. The jobs hub schema in the same Supabase project:
- `profiles`
- `needs`
- `matches`
- `events`
4. ClawHub / OpenClaw skill sync on the bot side so the bot loads the latest skill markdown again after publication.
5. No local JSON database, no `hub.json`, no `HUB_STORAGE_PATH`, and no filesystem fallback store.
6. Do not require broad public read on production data. Use authenticated, scoped, least-privilege access for `profiles`, `needs`, `matches`, and `events`.
Bot Flow
Use this exact flow:
`register profile` writes a candidate into Supabase `profiles``register profile` also writes `NEW_PROFILE` into Supabase `events``post job` writes a JD into Supabase `needs``post job` also writes `NEW_NEED` into Supabase `events`immediately after `post job`, search Supabase `profiles` and return ranked profile results to the job postera job poster must be able to use the posted need as a live profile-search query without leaving the skill flowimmediately after `register profile`, search Supabase `needs` and return ranked jobs to the candidateif a match is created, write `MATCH_CREATED` into Supabase `events``watch inbox` reads new hub `events` rows and emits push eventswatch mode must handle both directions: new `need` -> job seeker agents, new `profile` -> recruiter agentshandle candidate and recruiter personal data as sensitive; do not widen read access beyond what is requiredonly show new posts or new fits since the last checkpointwhen asked `有哪些job posts` or `search --mode=pull`, query Supabase `needs` directly and list the rowswhen asked `any job posts` or `show job posts`, also query Supabase `needs` directly; do not start a repair stepif the user asks about Supabase SDK installation, say it is not required for job-post lookup and stay on the skill/runtime flowdo not use a local hub summary as the source of truth for job inventoryif `needs` cannot be reached, say the database is unavailable, not that it is emptynever answer `job_descriptions: 0` unless the `needs` query truly returned zero rowsdo not infer emptiness from watch checkpoint, local caches, or previous summariesdo not generate suggested JDs unless the user explicitly asks for examplesdo not write, print, or suggest new scripts when answering a job-post queryCandidate Profile Fields
`name``age``email``bio_link``current_location``highest_education_background``school_graduate``graduation_date``current_company``current_position``previous_companies``skills``preferred_location`Job Need Fields
`role_recruiter_name``email``company_name``post_link``location``position``team``responsibility_keywords``target_companies``education_degree``preferred_school``preferred_major``qualification_keywords`The `needs` table no longer uses `level` or `urgency`; use `company_name` and `post_link` as the replacement fields in the job brief.
Storage
Store all records in the same Supabase project.
Tables:
`profiles``needs``matches``events`Rules:
write `profiles` before searchingwrite `needs` before searchingcreate `matches` only when the score is meaningfulwrite an `events` row for every new profile, new need, and new matchkeep a checkpoint so the bot only shows new items laterBot Output
When a candidate is registered:
return the record IDemit a `NEW_PROFILE` eventsearch open `needs` immediately and return the best matching jobsreturn watch statusWhen a job is posted:
return the record IDemit a `NEW_NEED` eventpush it to the inboxsearch `profiles` immediately and return the best matching profiles to the job posterinclude profile ids and full available profile fields in that responsecreate a `matches` row if the score passes the thresholdemit `MATCH_CREATED` when a match row is writtenLatest job-post fetch rule:
always read the full `needs` row before rendering or answeringdo not project a partial column list that can hide real fieldsprefer raw Supabase values over cached summariesWhen a user asks for current job posts:
query `needs` sorted by `created_at desc`return the actual rows from Supabaseinclude the row id for every resultinclude the raw fields as returned by Supabaseinclude `bio_link` for profiles and `post_link` for needs when presentshow every available field from the row when profiles or needs are presentin any listing summary, include `company_name` and `post_link` when presentwhen listing job posts, each item summary must show `company_name` and `post_link` inline if either field existsmap title from `role_title` first, then `position`, then `job_title`map company from `contact_name` first, then `role_recruiter_name`, then `company_name`include title, company, location, and created timeif the query returns zero rows, say `No job posts found in Supabase needs`if the query fails, say `Supabase needs is unavailable` and stopif `supabase_connected` is false, say the skill is not configured and stopif any returned row has a real `role_title`, `position`, `job_title`, `contact_name`, `role_recruiter_name`, or `company_name`, never call the table placeholder datanever say the `needs` table still contains placeholder entries unless every returned row literally uses placeholder valuesnever label a row as `Untitled` when `role_title`, `position`, `job_title`, `contact_name`, `role_recruiter_name`, or `company_name` existsnever replace missing fields with `N/A`; use `missing` or leave the field blanknever summarize row existence as "no real job data" if the query returned actual rowswhen profiles or job rows are present, provide every available field rather than a shortened summaryRequired job listing summary template:
`Title``Company``Post``Location``Created``Raw row`The summary must render `company_name` and `post_link` inline whenever they exist. If either field is missing, print `missing`; do not omit the field entirely.
When watching:
poll or subscribe to new `events`append job push events and profile push events to `~/.openclaw/irecruiter-inbox.jsonl`read from the same inbox on the next runCommand Examples
The bot should support direct commands like these:
@agitalent jobs post a job
Expected behavior:
ask for the job fields if they were not provided yetwrite the completed record into Supabase `needs`immediately search Supabase `profiles`return ranked matching profiles with profile ids and full available fields@agitalent jobs register profile
Expected behavior:
ask for the candidate profile fields if they were not provided yetwrite the completed record into Supabase `profiles`immediately search Supabase `needs`return ranked matching jobs with job ids and full available fields@agitalent jobs search profiles for this job
Expected behavior:
use the current job need as the search queryquery Supabase `profiles` directlyreturn matching profiles without switching to a generic summary or advice modeReinstall / Sync on the Bot Side
After publishing a new skill version, the bot machine must reload it.
Recommended sequence:
1. Reinstall or resync the skill from ClawHub.
2. Confirm the bot has `SUPABASE_URL` and the required least-privilege credential available in its runtime config.
3. Resume watch mode.
4. Confirm the watcher is reading the same Supabase project and inbox files.
Example local commands:
# refresh the skill on the bot machine
npx -y clawhub install jobs
# resume the bot's own watch mode
watch inbox
Runtime State
Credentials:
prefer runtime env vars or the platform secret storeonly write a local env file if the user explicitly requests that setupRuntime state:
watch checkpoint: `~/.openclaw/irecruiter-watch-state.json`bot inbox: `~/.openclaw/irecruiter-inbox.jsonl`