# Multi Agent Job Search

> 🤖 多Agent求职系统 | Multi-Agent Job-Search Pipeline — 独立 Python 实现，3 个 AI Agent + 5 道安全护栏 + 工作流编排。支持 MCP 协议接入 OpenCode / Codex / Claude Code。Standalone Python pipeline with 3 LLM agents, 5 guardrails, MCP integration, and dashboard.

- **Type:** MCP server
- **Install:** `agentstack add mcp-djh-001-multi-agent-job-search`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [DJH-001](https://agentstack.voostack.com/s/djh-001)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [DJH-001](https://github.com/DJH-001)
- **Source:** https://github.com/DJH-001/multi-agent-job-search
- **Website:** https://github.com/DJH-001/multi-agent-job-search

## Install

```sh
agentstack add mcp-djh-001-multi-agent-job-search
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# multi-agent-job-search

[English](README.md) | [中文](README.zh.md)

A standalone Python multi-agent system for job search, featuring 3 AI agents, 5 safety guardrails, and workflow orchestration.

---

## What This Is

This repository contains a **self-contained Python multi-agent pipeline** that automates job-search preparation: triaging positions, tailoring resumes, and generating interview prep. It runs independently with no external platform dependencies beyond a Python environment and an LLM API key.

The project originated as a design-validated domain Skill on OpenCode (~400 lines of Markdown rules defining agent behavior, safety constraints, and workflows). That original design was battle-tested across 16+ real job applications and iteratively improved based on actual AI failure modes. The SKILL.md is preserved in `docs/SKILL.md` as design documentation.

This Python implementation translates those design rules into executable code:

- **3 agents** (triage, resume, interview) calling an LLM via the OpenAI-compatible API
- **5 guardrails** (G1-G5), 3 blocking and 2 advisory, checked deterministically after every agent step
- **Workflow orchestrator** coordinating the full pipeline with retry logic and state persistence
- **State dual-write**: every position update is saved to both a position-level JSON tracker and an aggregate dashboard

The system is self-contained: `pip install -r requirements.txt`, set an API key, and run `python main.py apply --jd demo/jd.txt --profile demo/candidate-profile.md`. No OpenCode installation is needed.

---

## Architecture

```mermaid
flowchart LR
    subgraph Input["Input"]
        A["JD file + Candidate profile"]
        B["parse_jd() / parse_profile()"]
        A --> B
    end

    subgraph Pipeline["Agent Pipeline"]
        C["TriageAgent"]
        D["Track label:Safety / Stretch/ Boundary"]
        F["ResumeAgent"]
        G["Tailored markdownresume + ATS score"]
        I["InterviewAgent"]
        J["Predicted questions+ chase trees+ draft answers"]
        L["StateTracker"]
        C --> D
        F --> G
        I --> J
    end

    subgraph Guardrails["Guardrails"]
        E["G1 (skipped)G2 (advisory)G3 (blocking)"]
        H["G1 (blocking)G2 (advisory)G3 (blocking)G4 (advisory)"]
        K["G1 (blocking)G2 (advisory)G3 (blocking)G5 (advisory)"]
    end

    subgraph Output["Output"]
        M["Dual-write:position.json+ dashboard.json"]
    end

    subgraph Legend["Legend"]
        L1["Input"]:::inputClass
        L2["Triage"]:::triageClass
        L3["Resume"]:::resumeClass
        L4["Interview"]:::interviewClass
        L5["State"]:::stateClass
        L6["Blocking GR"]:::blockingClass
        L7["Advisory GR"]:::advisoryClass
        L8["Output"]:::outputClass
    end

    B --> C
    D --> E
    E --> F
    G --> H
    H --> I
    J --> K
    K --> L
    L --> M

    classDef inputClass fill:#d5d8dc,stroke:#839192,color:#1c2833
    classDef triageClass fill:#d7bde2,stroke:#7d3c98,color:#1c2833
    classDef resumeClass fill:#aed6f1,stroke:#2471a3,color:#1c2833
    classDef interviewClass fill:#a9dfbf,stroke:#1e8449,color:#1c2833
    classDef stateClass fill:#f9e79f,stroke:#b7950b,color:#1c2833
    classDef blockingClass fill:#e74c3c,stroke:#c0392b,color:#fff
    classDef advisoryClass fill:#f39c12,stroke:#d35400,color:#fff
    classDef outputClass fill:#82e0aa,stroke:#27ae60,color:#1c2833
    classDef guardrailClass fill:#f5cba7,stroke:#e67e22,color:#1c2833

    class A,B inputClass
    class C,D triageClass
    class F,G resumeClass
    class I,J interviewClass
    class L stateClass
    class E,H,K guardrailClass
    class M outputClass
```

**Pipeline steps:**

1. **Parse inputs**: `parse_jd()` extracts title, company, responsibilities, requirements, and preferred qualifications from a markdown or plain-text JD file. `parse_profile()` reads a YAML, JSON, or markdown candidate profile into a typed `CandidateProfile` dataclass.

2. **TriageAgent** evaluates the JD against the candidate profile along three dimensions -- hard-skill match, hold-ability (can the candidate pass now?), and salary/level gap -- and outputs a track label: 保底 (safety), 冲刺 (stretch), or 边界 (boundary).

3. **ResumeAgent** extracts JD keywords, selects track-appropriate bullets from the master CV, and generates a tailored resume with an AI-estimated ATS score. The output is plain markdown, no proprietary format.

4. **InterviewAgent** predicts round-by-round interview questions, drafts answers from verified profile facts only, and builds chase trees (2-3 follow-up questions per concept).

5. **StateTracker** writes two files after every step: a position-level JSON file (`_.json`) and an aggregate dashboard (`dashboard.json`), maintaining consistency without a database.

**Guardrails (G1-G5) wrap every agent step:**

| Guardrail | Stage | Severity | What It Prevents |
|:---|:---|:---|:---|
| **G1** Pre-promotion content firewall | Resume, Interview | Blocking | AI from writing unverified skills into resumes |
| **G2** Truth-source hierarchy | All stages | Advisory | Master CV from drifting away from verified facts |
| **G3** Real numbers only | All stages | Blocking | AI from inventing numbers to "strengthen" bullet points |
| **G4** Cross-track contamination | Resume | Advisory | Stretch-track framing from leaking into safety-track resumes |
| **G5** Rumor-vs-fact separation | Interview | Advisory | Scraped interview experiences from being treated as confirmed facts |

G1-G3 are blocking: a violation raises `GuardrailViolation` and halts the pipeline. G4-G5 are advisory: violations are logged as warnings but never block execution.

---

## Quickstart

```bash
# Clone the repository
git clone https://github.com/DJH-001/multi-agent-job-search.git
cd multi-agent-job-search

# Create and activate a virtual environment
python -m venv .venv
.venv\Scripts\activate

# Install dependencies
pip install -r requirements.txt

# Configure your API key
copy .env.example .env
# Edit .env with your OpenAI-compatible API key and optional base URL

# Run the full pipeline with demo data
python main.py apply --jd demo/jd.txt --profile demo/candidate-profile.md

# Check pipeline status
python main.py status --output output

# Run the test suite
python -m pytest tests/ -v
```

**Requirements:** Python 3.9+, an OpenAI-compatible API key (tested with OpenAI and DeepSeek).

The `.env.example` file documents all configuration options:
- `OPENAI_API_KEY` -- your API key (required)
- `OPENAI_BASE_URL` -- base URL for the API (defaults to `https://api.openai.com/v1`)
- `LLM_MODEL` -- model name (defaults to `gpt-4o`, also tested with `deepseek-chat`)

---

## Project Structure

```
multi-agent-job-search/
├── main.py                         # CLI entry point (argparse: apply, status, mcp)
├── requirements.txt                # openai, rich, python-dotenv, pytest, mcp
├── .env.example                    # API key and model configuration template
├── LICENSE                         # MIT
│
├── src/
│   ├── __init__.py
│   ├── config.py                   # Loads OPENAI_API_KEY, OPENAI_BASE_URL, LLM_MODEL from env
│   ├── schema.py                   # Dataclass contracts: CandidateProfile, JobDescription,
│   │                               #   TriageResult, ResumeOutput, InterviewPrep
│   ├── orchestrator.py             # JobSearchOrchestrator: 5 workflows (A-E),
│   │                               #   guardrail runner, retry logic, JD/profile parsers
│   ├── mcp_server.py               # MCP stdio server: 3 read-only tools for agent integration
│   ├── agents/
│   │   ├── __init__.py
│   │   ├── triage.py               # TriageAgent: JD vs profile assessment, track label output
│   │   ├── resume.py               # ResumeAgent: keyword extraction, bullet selection,
│   │   │                           #   ATS scoring, banned-word detection
│   │   └── interview.py            # InterviewAgent: question prediction, draft answers,
│   │                               #   chase trees, round-by-round prep
│   ├── guardrails/
│   │   ├── __init__.py
│   │   ├── g1_pre_promotion.py     # G1: deterministic skill whitelist check (blocking)
│   │   ├── g2_source_hierarchy.py  # G2: [source:] annotation check (advisory)
│   │   ├── g3_real_numbers.py      # G3: invented-number detection (blocking)
│   │   ├── g4_cross_track.py       # G4: cross-track contamination via LLM + regex (advisory)
│   │   └── g5_rumor_vs_fact.py     # G5: rumor-vs-fact firewall via LLM + regex (advisory)
│   └── state/
│       ├── __init__.py
│       └── tracker.py              # StateTracker: dual-write JSON persistence,
│                                   #   JobState dataclass, dashboard aggregation
│
├── tests/
│   ├── __init__.py
│   ├── test_guardrails_g1_g3.py    # 28 tests: G1 (skill whitelist), G3 (fake numbers)
│   ├── test_guardrails_g4_g5.py    # 14 tests: G4 (cross-track), G5 (rumor-vs-fact)
│   ├── test_tracker.py             # 6 tests: save/load roundtrip, dual-write, dashboard
│   └── test_mcp.py                 # MCP server: tool registration, parsing, error handling, LLM skipif
│
├── demo/
│   ├── jd.txt                      # Sample JD: Senior Camera Hardware Engineer
│   ├── candidate-profile.md        # Sample profile: fictional hardware engineer
│   └── 示例-某相机公司-硬件工程师/  # Example output from a completed pipeline run
│       ├── resume.md
│       ├── interview_prep_round1.json
│       └── position.json
│
├── docs/
│   ├── SKILL.md                    # Original OpenCode Skill design (~400 lines Markdown)
│   │                               #   Documents the design phase: 5 core principles,
│   │                               #   5 guardrails, dual-track engine, promotion gate,
│   │                               #   workflows A-E, and writing rules
│   └── architecture.md             # Detailed architecture documentation
│
├── config/
│   └── skill.md                    # Copy of docs/SKILL.md (for OpenCode compatibility)
│
├── scripts/
│   └── verify_guardrails.py        # Standalone guardrail compliance verification
│
├── templates/
│   ├── position-analysis.md        # Position analysis template
│   ├── interview-prepare.md        # Interview prep template
│   └── interview-review.md         # Interview review template
│
└── output/                         # Created at runtime -- pipeline output directory
```

---

## Platform vs My Work

This project has two layers: a **design layer** (the SKILL.md rules and methodology) and an **implementation layer** (the Python code). The table below separates what the OpenCode platform provided during the original deployment from what was designed and built independently.

| Capability | Provided by OpenCode Platform | Designed & Built |
|:---|:---|:---|
| **Agent runtime** (LLM calls, parallel dispatch, session management) | Built-in. OpenCode handles agent lifecycle, tool dispatch, and state persistence across sessions. | I designed which agent roles to dispatch for each workflow step and when to run them sequentially vs in parallel. |
| **SKILL.md rules (~400 lines)** | Not provided. | **Core design output.** Domain rules: 5 principles, 5 guardrails, dual-track engine, promotion gate, workflows A-E, AI-slop ban lists. |
| **G1-G5 guardrails** | Not provided. | **Design:** each guardrail addresses a real AI failure observed in practice. **Implementation:** `src/guardrails/g1_*.py` through `g5_*.py` -- deterministic checks with LLM assistance where needed. |
| **Dual-track engine** | Not provided. | Three-track triage (保底/冲刺/边界) with distinct governance strategies per track. |
| **Promotion gate** | Not provided. | 5-step human-in-the-loop mechanism: learn, challenge list, self-certify, register, backflow. |
| **Python implementation** | Not provided. | **Entirely self-built.** `main.py` (CLI), `src/orchestrator.py` (900 lines, 5 workflows), `src/agents/` (3 agent files), `src/guardrails/` (5 guardrail files), `src/state/tracker.py` (dual-write persistence), `src/schema.py` (dataclass contracts), `src/config.py` (env-based config). |
| **Test suite** | Not provided. | **Entirely self-built.** 44 pytest tests across 3 test files covering G1-G5 guardrails and state management. |
| **State dual-write** | Not provided. | **Design:** every update writes to two locations for distributed consistency. **Implementation:** `StateTracker` in `src/state/tracker.py` with atomic dual-write logic. |
| **File system architecture** | Not provided. | Three-layer structure: truth-source (immutable facts), company/position (per-position isolation), market-research (cross-company intelligence). |
| **Workflows A-E** | Not provided. | Five standard workflows with explicit step sequences: A (new position), B (update existing), C (re-derive all), D (detect source changes), E (interview iteration). |
| **Writing rules & ban lists** | Not provided. | Specific rules for AI-generated professional text: banned AI-slop words, plain alternatives, bullet structure constraints. |

**Bottom line:** The OpenCode platform provided the agent runtime environment for the original deployment. The domain architecture, safety system, workflow definitions, and the complete Python reimplementation were designed and built independently. The Python system is fully standalone -- it requires no OpenCode installation to run.

---

## Design Highlights

### Five Core Principles

1. **Truth-source first.** Every output (resume, cover letter, interview answer) must be traceable to verified personal data. The agent cannot invent or embellish.
2. **Position isolation.** Preparing for one position does not give the agent access to another position's folder. No cross-contamination.
3. **Optional reference.** If one position's output could help another, the agent must explicitly ask for permission before referencing it. No silent copying.
4. **State dual-write.** Every progress update writes to two locations: the position-level tracker (detail) and the aggregate dashboard (summary). This is a distributed consistency problem solved through rule constraints.
5. **Completeness check.** Before producing any material for a new position, the agent must cross-reference against the full verified facts inventory to prevent omissions.

### Dual-Track Engine

Every incoming position is triaged into one of three governance tracks:

- **Safety track (保底轨):** Candidate can interview now and likely pass. Strategy: fast application, stable messaging, no over-packaging.
- **Stretch track (冲刺轨):** Candidate wants the role but has a clear skill gap. Strategy: identify gaps explicitly, record genuine growth, gate new skills behind the promotion mechanism before they appear in materials.
- **Boundary track (边界轨):** Unclear fit. Strategy: default to conservative messaging, treat any new capability claims through the stretch-track promotion gate.

Tracks are determined through a 3-step evaluation (read JD, natural-language assessment, single label output) with strict rules against formulaic scoring and silent label rewriting. Label changes are append-only in a change log.

### Promotion Gate

Content learned after the initial profile cannot appear in application materials until it passes the promotion gate:

1. **Record learning** in the growth timeline (facts only, no future plans).
2. **AI generates a challenge list:** hard questions interviewers might ask, evidence gaps, reproducibility challenges, statements that would fail under pressure.
3. **Human self-certifies:** the candidate checks each item and confirms they can explain, reproduce, and handle pushback.
4. **Register the promotion:** date, content, linked evidence, and the candidate's explicit confirmation statement.
5. **回流 (backflow):** promoted content flows back into the truth-source materials and master CV.

The AI never decides what is "ready." It only generates the challenge list and records the human's confirmation. This is a human-in-the-loop safety mechanism, not an AI evaluation

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [DJH-001](https://github.com/DJH-001)
- **Source:** [DJH-001/multi-agent-job-search](https://github.com/DJH-001/multi-agent-job-search)
- **License:** MIT
- **Homepage:** https://github.com/DJH-001/multi-agent-job-search

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-djh-001-multi-agent-job-search
- Seller: https://agentstack.voostack.com/s/djh-001
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
