A modular, user-agnostic architecture for a personal job search assistant powered by your personal agent.
Since this is not a simple skill, but instead a combination of many skills allowing your agent to run a complex task,
I refer to this as a skill-set.
A running "claw" like nanobot, ZeroClaw, OpenClaw, PicoClaw, TinyClaw, NanoClaw or what not.
Simply move the skills inside the skills folder of your agent.
If you already have applied to jobs and have a list of the application history. You can fetch it into your
job-search project as applications_tracker.csv and the skill will use it. The entry needs to contain a URL and optionally
your user rating, user feedback, company name and company title. additional to any other information.
The user interface job-dashboard skill is set to always so it will automatically be available. You can then tell your
agent to create you a new job search project and spawn a job-setup. This will create all relevant files for the search
to start.
In order for the agent to not search blindly explain it what jobs you want to search for and what are your experience, degree, location preferences and whatever else you want to tell the agent.
Now you can run the job-manager skill. This is the entry point into the automatic pipeline. It will select whatever
phase is next (clean-up, searching, analyzing, refining search strategies, updating profile etc.).
I recommend adding it as a quite cron job in the background and let it run every few minutes to continuously search the web.
Use the cron message: "load/read the job-manager skill and run the skill. The job manager handles all logic for the job-search internally. Do not evaluate conditions. Do not add instructions or context. Do not interpret."
To keep the agent as a silent background runner you can use:
nanobot agent -m "Create a cron job running every 30 minutes. Use this exact message, do not edit it: load/read the job-manager skill and run the skill. The job manager handles all logic for the job-search internally. Do not evaluate conditions. Do not add instructions or context. Do not interpret."
This will create a cron entry that looks like this (found in workspace/cron/jobs.json):
{
"payload": {
"kind": "agent_turn",
"message": "[message from above]",
"deliver": false,
"channel": "cli",
"to": "direct"
}
}Note: Setting "channel": "cli" ensures the responses are routed to your command line interface rather than being sent as messages.
Details for understanding the design behind the skillset.
Core Design Concepts
- User-Agnostic Skills: Skills contain no hardcoded user data, names, or paths. They operate purely on the provided project context.
- Dynamic Project Context: The project name and path are retrieved dynamically from
USER.md. The following variables must be defined under a## Job Searchheader:job_search_project: Absolute path to the workspace folder.standard_searches: Number of standard queries to run per cycle.explorative_searches: Number of creative queries to run per cycle.
- Root Agent Execution: Orchestration skills (
job-manager,job-status) MUST run as a Root Agent (triggered via Cron or a direct User command). They will fail if spawned as background sub-agents due to Nanobot's tool recursion guards. - Unified Scaffolding: The system environment (directories and database) is managed via a single initialization tool, ensuring structural consistency across all deployments.
- Passive Reporting (Script-Driven): The
{project_dir}/STATUS.mddashboard is generated automatically by deterministic scripts. LLM agents focus on interpreting the results and providing strategic pivots rather than data processing. - Context Efficiency: Sub-Agents run sequentially to prevent LLM context exhaustion.
- Automated Synchronization: A daily cron job keeps the
{project_dir}/applications_tracker.csvup to date, which serves as the source of truth for the agent's feedback loop. - Word-Order Independent Matching: Deduplication uses high-precision identity matching where the order of words in a title or company name does not prevent a match (e.g., "Senior Python Developer" matches "Python Developer Senior").
- Logging & Auditing: The system maintains a high-granularity daily audit trail. Every state-changing script (Audit, Deduplication, Database) logs its specific metrics and decisions to
{project_dir}/logs/YYYY-MM-DD.logto ensure pipeline transparency.
Skill Development Standard (The Root Anchor)
All skills in this project must adhere to the Root Anchor Architecture to ensure portability across different agent environments (OpenClaw, Nanobot, ZeroClaw).
- The Hub (
job-db): Provides centralized logic (Config, Logging, DB access). - The Spokes: Specialized workers that import Hub logic directly.
- Rule: Spokes never call other Spokes. All shared truth must live in the Hub.
All SKILL.md files and internal scripts must use relative pathing based on the Current Working Directory (CWD) from which the agent is spawned.
| Target Type | Pathing Rule | Example |
|---|---|---|
| Project Data | {project_dir}/ (resolved from USER.md) |
{project_dir}/data/job_search.db |
| Internal Logic | skills/[skill-name]/scripts/ |
skills/job-db/scripts/db_io.py |
| Documentation | skills/[skill-name]/references/ |
skills/job-db/references/schema.md |
| Configuration | Root level (CWD) | USER.md |
Every SKILL.md must contain the following section to anchor itself:
## Preparation & Pathing
1. Identify the project directory `{project_dir}` via `job_search_project` in `USER.md`.
2. Environment: Your working directory is fixed at the workspace root.
3. Execution: To run scripts, use the full path from the root: `python3 skills/[skill-name]/scripts/[script].py`.- Stateless Shell: Assume directory changes (
cd) do not persist between tool calls. Always use full relative paths for execution. - Zero Subprocess Core: Functional scripts MUST use direct Python imports of Hub logic to eliminate process overhead and enable type-safe data passing.
- Fail-Fast Configuration: Scripts must terminate immediately with a JSON error if
USER.mdor thejob_search_projectpath cannot be resolved. - Audit Trails: Every state-changing script must log its actions using the Hub's
logutility with the standardized 3-argument signature.
The 9-Skill Architecture
- Manager (The Orchestrator): Coordinates the pipeline. A reactive state machine that audits environment scaffolding, raw leads, and stale evaluations to trigger the next phase. Must run as Root.
- Setup (The Janitor): Orchestrates environment initialization via the unified
inittool and syncs with the user's manual application tracker. - Researchers (The Harvesters): Modular scouts that scrape individual job listings from search results. Use "One-Shot Fetching" to ignore broken links and prevent iteration exhaustion. Handles both standard and explorative queries assigned by the Manager.
- Deduplicator (The Consolidator): Manages the Persistent Queue (
raw_listing_1.json). Resolves ambiguities that automated Tier 1/2 checks could not handle. - Analyst (The Evaluator): The intelligence core. Processes raw leads AND performs Identity Refinement, updating the database's normalized matching keys while preserving source metadata.
- Status & Audit (The Concluder): Orchestrates the automated generation of
STATUS.mdand thestrategy.jsonmanifest. Performs self-correction (Profile Drift) and market intelligence (query promotion/rotation).
- Dashboard (The Interface): The primary user-facing skill. An interactive navigator that presents findings, marks jobs as "reported," and manages career goals.
- Job Profile (The Profiler): The "Brain" of the system. Synthesizes
career_master.mdandfeedback_summary.mdinto the operationaljob_profile.md. - Job DB (The Data Layer): An auxiliary skill providing specialized database tools, including the flexible
listtool for situational awareness.
Output Ownership Map
To ensure stability and prevent state conflicts, each file in the system has a clearly defined owner and access protocol.
| File | Type | Owner | Accessor | Permissions | Role |
|---|---|---|---|---|---|
data/raw_findings/last_search.md |
Owned | Manager | Script (Audit) | Write | Discovery clock / Marker |
SETUP.md |
Owned | Setup | Script (Sync) | Write | Project health summary |
data/raw_findings/raw_listing_N.json |
Owned | Researchers | LLM (Agent) | Write | Discovery fragment (Temporary) |
data/raw_findings/raw_listing_1.json |
Shared | Deduplicator | Script (Auto) | Write | Persistent Queue (Self-cleaning) |
data/job_search.db |
Shared | Job DB | Script (db_io) | Read/Write | Centralized Data Store |
STATUS.md |
Owned | Status | Script (Report) | Write | User-facing dashboard |
logs/YYYY-MM-DD.log |
Owned | All | Script (Logger) | Append | Daily audit trail |
search/sub_agent_searches/ |
Owned | Researchers | LLM (Agent) | Write | Isolated search heartbeats |
profile/career_master.md |
Owned | Dashboard | LLM (Agent) | Write | Permanent user directives |
profile/feedback_summary.md |
Owned | Job Profile | LLM (Agent) | Write | Learned feedback patterns |
profile/job_profile.md |
Owned | Job Profile | LLM (Agent) | Write | Synthesized operational profile |
search/strategy.json |
Owned | Status | LLM (Agent) | Read/Write | Execution manifest (Hard-gate) |
search/search_history.json |
Shared | Status | Script/Tool | Write | Unified Query Vault (State-based tracking) |
applications_tracker.csv |
Input | User | Manual | Read | Application history (Source of Truth) |
Data Formats
Markdown file synthesized from memory and observations.
## User Directives
[Content from career_master.md]
## Background Observations
[Content from feedback_summary.md]Used in discovery fragments. This is a rich, evaluated subset of the database schema.
{
"title": "Exact job title",
"company": "Hiring company name",
"location": "City, Country or Remote",
"applied": false,
"tracker_data": {"header": "value"},
"priority": "high|medium|low",
"agent_notes": "Evaluation reasoning",
"match_score": 0.85,
"requirements": ["List of strings"],
"description": ["Blocks of text"],
"sources": [
{
"url": "Direct link",
"source_query": "The specific query used (or 'user')",
"is_live": 1,
"date_found": "YYYY-MM-DD"
}
]
}Every job finding follows a deterministic path from initial discovery to its final state in the archive.
A lead enters the system as a Standardized Ingestion Entry in one of several fragment files:
- Automated: Researchers write to
raw_listing_N.json. - Manual: User input via Dashboard stages to
raw_listings_manual.json. - History: Setup skill identifies unmatched rows in
applications_tracker.csvand stages toraw_listing_tracker.json.
The Deduplicator processes fragments via db_io.py --action find_candidates using a 3-tier strategy:
- Tier 1 (URL + Query): If the
urlandsource_querycombination exists, the finding is ignored. If the URL exists but the Query is new, the source is Merged into the existing record. - Resurfacing Logic: If an
archivedlead withapplied=0matches Tier 1, and it ispriority='high'or has a highuser_rating, it is moved back tostatus='active'andreported=0. - Tier 2 (Identity): If the URL is new, the system performs a Word-Order Independent match using
norm_titleandnorm_company(within an 8-week window). Successful matches are auto-merged. - Tier 3 (LLM Comparison): Ambiguous findings are moved to the Persistent Queue (
raw_listing_1.json) for manual identity comparison by the LLM agent.
Leads that pass deduplication are marked as status='raw'.
- Initial Evaluation: The Analyst fetches the full job description, scores the match (
match_score,priority), and extracts detailed requirements. - Identity Refinement: The Analyst extracts the "Clean Identity" from the description content, updating the
norm_titleandnorm_companyfields. This ensures the lead is "smart" for future Tier 2/3 deduplication. - Transition: Upon commitment, the lead moves to
status='active'.
Active leads are in the user's "Working Memory."
- Reporting: Presented by the Dashboard and marked as
reported=1. - Feedback: User provides a
user_ratingandfeedback. - Self-Evolution: User feedback triggers the Profiler to update the
job_profile.md. - Staleness: If the profile is updated, any lead without a user rating where
evaluated_atis older than the profilemtimeis considered stale and queued for Re-evaluation by the Analyst.
The generate_status_report.py script performs routine maintenance:
- Profile Drift Correction: Leads that are
status='active'andpriority='high'but have been rateduser_rating='poor'are automatically moved to the archive. This preserves the user's verdict while cleaning the dashboard. - Batch Pruning: Bulk moves expired links or low-priority leads to
archived.
A lead reaches finality in the archive but is never deleted. This ensures the system maintains a "Negative Memory" of every job ever seen.
- End States: Applied (
applied=1), Rejected (user_rating='poor'), or Expired (expired=1).
Every search phrase is a stateful entity tracked within the Unified Query Vault (search_history.json).
- Strategist Injection: The Status agent generates new explorative queries based on the
job_profile.mdand registers them via the management tool. - Autonomous Discovery: If a Researcher executes an unknown query, the Deduplicator initializes it as
explorative.
- The Brief: The automation layer categorizes queries as ACTIVE or COOLDOWN based on their
last_run_attimestamp. - The Manifest: The Status agent selects queries from the ACTIVE list and writes the
strategy.jsonmanifest. - The Hard Gate: Phase 2 (Search) is blocked unless a fresh manifest exists (newer than the last search).
- Search: The Manager spawns Researchers to execute the manifest.
- Heartbeat: Researchers record successful attempts.
- Aging: The Deduplicator merges heartbeats, updating the query's
last_run_atto the current date and incrementingrun_count. The query enters its Cooldown Period.
- Metric Sync: The automation layer maps "High Priority" leads in the database back to the query strings.
- Attribution: The
success_countin the vault is overwritten with the fresh total of high-quality leads found by that specific query.
The Status agent uses the management tool to update query states:
- Promotion: High-performing
explorativequeries becomestandard. - Retirement: Underperforming or exhausted
standardqueries are moved toretired. - Negative Memory: Retired queries remain in the vault forever to prevent redundant re-exploration of failed paths.
The system includes an Admin Module within the job-db utility for manual data surgery (e.g., the delete action).
- Restriction: Administrative actions are strictly for manual use by a human user via the CLI. LLM Agents are not authorized to use the Admin Module.