Skip to content
Learn Agentic AI
Learn Agentic AI13 min read3 views

Building an Internal Mobility Agent: Job Posting, Skill Matching, and Transfer Assistance

Create an AI agent that powers internal job boards, matches employees to open positions based on skill profiles, supports transfer applications, and facilitates transition planning between teams.

Why Internal Mobility Matters

Employees who see no growth path within their organization leave. Research shows that internal mobility increases retention by 2x, yet most companies have opaque internal job markets where opportunities are shared through informal networks rather than equitable systems. An AI internal mobility agent democratizes access to opportunities by matching employee skills to open positions, identifying development gaps, and facilitating the transfer process.

Employee Profile and Job Posting Models

The mobility agent works at the intersection of employee skill profiles and internal job postings. Both data models must be rich enough to support meaningful matching.

flowchart TD
    START["Building an Internal Mobility Agent: Job Posting,…"] --> A
    A["Why Internal Mobility Matters"]
    A --> B
    B["Employee Profile and Job Posting Models"]
    B --> C
    C["Skill Matching Engine"]
    C --> D
    D["Gap Analysis and Development Planning"]
    D --> E
    E["Transfer Application Tool"]
    E --> F
    F["FAQ"]
    F --> DONE["Key Takeaways"]
    style START fill:#4f46e5,stroke:#4338ca,color:#fff
    style DONE fill:#059669,stroke:#047857,color:#fff
from dataclasses import dataclass, field
from datetime import date
from typing import Optional
from agents import Agent, Runner, function_tool
import json

@dataclass
class EmployeeProfile:
    employee_id: str
    name: str
    current_role: str
    current_department: str
    tenure_years: float
    skills: list[str]
    skill_levels: dict[str, str]  # skill -> "beginner"|"intermediate"|"expert"
    interests: list[str]
    career_goals: list[str]
    willing_to_relocate: bool = False
    manager_approved_mobility: bool = True

@dataclass
class InternalPosting:
    posting_id: str
    title: str
    department: str
    hiring_manager: str
    location: str
    required_skills: list[str]
    preferred_skills: list[str]
    min_tenure_months: int  # minimum company tenure to apply
    description: str
    status: str = "open"

EMPLOYEE_DB: dict[str, EmployeeProfile] = {}
INTERNAL_POSTINGS: dict[str, InternalPosting] = {}

Skill Matching Engine

The matching engine goes beyond simple keyword overlap. It considers skill levels, career interests, and development potential — not just current qualifications.

@function_tool
def find_internal_opportunities(employee_id: str) -> str:
    """Find internal job postings matching an employee's skills and interests."""
    emp = EMPLOYEE_DB.get(employee_id)
    if not emp:
        return json.dumps({"error": "Employee not found"})

    matches = []
    for posting in INTERNAL_POSTINGS.values():
        if posting.status != "open":
            continue
        if posting.department == emp.current_department:
            continue  # exclude same-department lateral moves by default
        if emp.tenure_years * 12 < posting.min_tenure_months:
            continue

        # Skill match scoring
        emp_skills_lower = {s.lower() for s in emp.skills}
        required_lower = {s.lower() for s in posting.required_skills}
        preferred_lower = {s.lower() for s in posting.preferred_skills}

        required_match = emp_skills_lower & required_lower
        preferred_match = emp_skills_lower & preferred_lower
        skill_gaps = required_lower - emp_skills_lower

        if not required_lower:
            skill_score = 0.5
        else:
            skill_score = len(required_match) / len(required_lower)

        # Interest alignment bonus
        interest_overlap = set(i.lower() for i in emp.interests) & {
            posting.department.lower(), posting.title.lower()
        }
        interest_bonus = 0.1 if interest_overlap else 0.0

        total_score = min(skill_score + interest_bonus, 1.0)

        if total_score >= 0.4:
            matches.append({
                "posting_id": posting.posting_id,
                "title": posting.title,
                "department": posting.department,
                "match_score": round(total_score * 100),
                "matched_skills": list(required_match | preferred_match),
                "skill_gaps": list(skill_gaps),
                "development_needed": len(skill_gaps) > 0,
            })

    matches.sort(key=lambda x: x["match_score"], reverse=True)
    return json.dumps(matches[:10])

Gap Analysis and Development Planning

When an employee is interested in a role but lacks some skills, the agent generates a development plan to bridge the gap.

See AI Voice Agents Handle Real Calls

Book a free demo or calculate how much you can save with AI voice automation.

LEARNING_CATALOG = {
    "python": {"course": "Python Mastery", "duration_weeks": 8, "format": "online"},
    "data analysis": {"course": "Data Analytics Bootcamp", "duration_weeks": 6, "format": "hybrid"},
    "project management": {"course": "PMP Preparation", "duration_weeks": 12, "format": "online"},
    "machine learning": {"course": "ML Fundamentals", "duration_weeks": 10, "format": "online"},
    "leadership": {"course": "Leadership Essentials", "duration_weeks": 4, "format": "workshop"},
}

@function_tool
def generate_development_plan(employee_id: str, posting_id: str) -> str:
    """Create a development plan to bridge skill gaps for a target role."""
    emp = EMPLOYEE_DB.get(employee_id)
    posting = INTERNAL_POSTINGS.get(posting_id)

    if not emp or not posting:
        return json.dumps({"error": "Employee or posting not found"})

    emp_skills_lower = {s.lower() for s in emp.skills}
    required_lower = {s.lower() for s in posting.required_skills}
    gaps = required_lower - emp_skills_lower

    if not gaps:
        return json.dumps({
            "message": "No skill gaps detected. You are ready to apply.",
            "recommendation": "Submit your application directly.",
        })

    plan_items = []
    total_weeks = 0
    for gap in gaps:
        course = LEARNING_CATALOG.get(gap)
        if course:
            plan_items.append({
                "skill": gap,
                "course": course["course"],
                "duration": f"{course['duration_weeks']} weeks",
                "format": course["format"],
            })
            total_weeks += course["duration_weeks"]
        else:
            plan_items.append({
                "skill": gap,
                "suggestion": "Seek mentorship or job shadowing opportunity",
                "duration": "Ongoing",
            })

    return json.dumps({
        "target_role": posting.title,
        "gaps_identified": len(gaps),
        "development_plan": plan_items,
        "estimated_timeline": f"{total_weeks} weeks to address all gaps",
        "next_step": "Discuss this plan with your manager for approval and time allocation.",
    })

Transfer Application Tool

@function_tool
def submit_transfer_application(
    employee_id: str,
    posting_id: str,
    motivation: str,
) -> str:
    """Submit an internal transfer application."""
    emp = EMPLOYEE_DB.get(employee_id)
    posting = INTERNAL_POSTINGS.get(posting_id)

    if not emp or not posting:
        return json.dumps({"error": "Employee or posting not found"})

    if not emp.manager_approved_mobility:
        return json.dumps({
            "status": "blocked",
            "reason": "Manager approval for internal mobility is required. "
                      "Please discuss with your manager first.",
        })

    return json.dumps({
        "status": "submitted",
        "application_id": f"INT-{employee_id[:4]}-{posting_id[:4]}",
        "current_role": emp.current_role,
        "target_role": posting.title,
        "hiring_manager_notified": posting.hiring_manager,
        "next_steps": "The hiring manager will review your application "
                      "and reach out to schedule a conversation.",
    })

mobility_agent = Agent(
    name="MobilityBot",
    instructions="""You are MobilityBot, an internal career mobility assistant.
Help employees discover internal opportunities that match their skills and goals.
When skill gaps exist, create actionable development plans rather than discouraging.
Maintain confidentiality — do not reveal who else has applied for a role.
Encourage employees to discuss mobility plans with their managers openly.""",
    tools=[find_internal_opportunities, generate_development_plan, submit_transfer_application],
)

FAQ

Should the agent notify the employee's current manager when they explore internal moves?

This is a design decision that depends on company culture. Some organizations require manager approval before applying, while others allow confidential exploration. A common middle ground is allowing browsing and gap analysis without notification, but requiring manager acknowledgment before a formal application is submitted.

How do you prevent skill inflation in employee profiles?

Pair self-reported skills with evidence: certifications, project contributions (from version control or project management tools), and peer endorsements. The agent can cross-reference claimed skills with actual project history to flag discrepancies.

What about lateral moves within the same department?

The default configuration excludes same-department postings to focus on cross-functional mobility. However, the filter is configurable. Some roles — like moving from individual contributor to team lead within engineering — are valid lateral moves that the agent should surface when the employee's career goals include leadership.


#InternalMobility #SkillMatching #CareerDevelopment #TalentRetention #AgenticAI #LearnAI #AIEngineering

Share
C

Written by

CallSphere Team

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.

Related Articles You May Like

Learn Agentic AI

Fine-Tuning LLMs for Agentic Tasks: When and How to Customize Foundation Models

When fine-tuning beats prompting for AI agents: dataset creation from agent traces, SFT and DPO training approaches, evaluation methodology, and cost-benefit analysis for agentic fine-tuning.

AI Interview Prep

7 Agentic AI & Multi-Agent System Interview Questions for 2026

Real agentic AI and multi-agent system interview questions from Anthropic, OpenAI, and Microsoft in 2026. Covers agent design patterns, memory systems, safety, orchestration frameworks, tool calling, and evaluation.

Learn Agentic AI

Adaptive Thinking in Claude 4.6: How AI Agents Decide When and How Much to Reason

Technical exploration of adaptive thinking in Claude 4.6 — how the model dynamically adjusts reasoning depth, its impact on agent architectures, and practical implementation patterns.

Learn Agentic AI

How NVIDIA Vera CPU Solves the Agentic AI Bottleneck: Architecture Deep Dive

Technical analysis of NVIDIA's Vera CPU designed for agentic AI workloads — why the CPU is the bottleneck, how Vera's architecture addresses it, and what it means for agent performance.

Learn Agentic AI

Claude Opus 4.6 with 1M Context Window: Complete Developer Guide for Agentic AI

Complete guide to Claude Opus 4.6 GA — 1M context at standard pricing, 128K output tokens, adaptive thinking, and production patterns for building agentic AI systems.

Large Language Models

Why Enterprises Need Custom LLMs: Base vs Fine-Tuned Models in 2026

Custom LLMs outperform base models for enterprise use cases by 40-65%. Learn when to fine-tune, RAG, or build custom models — with architecture patterns and ROI data.