Applire

mcp
Security Audit
Fail
Health Warn
  • License — License: AGPL-3.0
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 5 GitHub stars
Code Fail
  • rm -rf — Recursive force deletion command in .github/workflows/test.yml
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Open-source AI-powered CV tailoring platform for the DACH job market

README.md

Applire

Applire

The open-source, agent-ready job application tool for Europe — DACH-native first

Transform hours of CV tailoring into seconds. Upload your CVs, paste a job description, and let AI guide you through an intelligent interview to create perfectly matched application documents.

License
Python
FastAPI
Next.js
Docker
GitHub Stars

🌐 applire.de🚀 Quick Start📖 Documentation💬 Community🐛 Report Bug

🌐 English · Deutsch


📸 See it in action

From a CV and a job ad to a complete application package — in minutes.

1. Upload your CVs & paste the job ad

Upload your CVs and paste the job description

Drop in one or more CVs and add the job posting as text or URL. Applire merges them into a Master Profile, scores your fit for the role, and groups what's missing into a handful of themes.

2. A short, targeted AI interview closes the gaps

A targeted AI interview that closes the gaps

A job-specific interview fills the gaps and sharpens your story — with editable answer starters, progress tracking, and a live role-requirements checklist on the side.

3. Pick a template — get a tailored CV & matching cover letter

Choose from seven DACH-ready CV templates

Generate a DACH-ready Lebenslauf in seven templates (Classic German, Modern Swiss, Executive, Tech, Academic, and more) and colour variants — plus, on request, a matching cover letter (Anschreiben) in the same design, with recipient and subject auto-extracted from the job ad.

Screenshots use synthetic demo data (example profile "Milan Novak"). Applire ships in German and English — see the German README for German-UI screenshots. Output documents follow the job ad's language, so an English source CV becomes a German Lebenslauf for a German posting.


💡 What is Applire?

Applire is the open-source, agent-ready job application tool for Europe. It turns your entire career history into truthful, perfectly tailored application documents — DACH conventions built in, further countries planned as community-contributable packs.

Built for all job seekers — from career changers consolidating years of CV versions to international professionals adapting to German application conventions. Runs on your own hardware; your AI agent can drive it — and if you don't have one, the built-in assistant has you covered.

Unlike generic CV builders, Applire:

  • 🧠 Learns from you: Builds a persistent Master Profile that gets smarter with every CV you upload — every claim traceable to where it came from
  • 💬 Interviews you intelligently: Asks targeted questions to fill gaps between your experience and job requirements
  • Tailors with precision: Generates culturally appropriate CVs optimized for DACH recruiters and ATS systems
  • Keeps you truthful: Every job-ad keyword is classified as backed, claimable, or an honest gap — the system never claims what your profile can't back. Every generated document also ships a per-claim truthfulness report grading each statement against your profile
  • 🤖 Agent-ready: Your AI assistant can run the whole loop via the Model Context Protocol (MCP)
  • 🔒 Privacy by design: GDPR-compliant, self-hosted, full data sovereignty

In 3 simple steps:

  1. 📄 Upload 2-4 versions of your CV
  2. 🔗 Paste the job description
  3. 💬 Answer a few intelligent questions → ✨ Get a perfectly tailored CV

👥 Who is Applire for?

Applire is built around two everyday problems job seekers actually have — plus a third, agent-ready way to solve them.

📚 "I have five versions of my CV and I'm afraid of copy-paste mistakes"

Most professionals keep several CVs — some in English, some in their native language — and every new application means copy-pasting fragments between them, rebuilding the layout, and hoping nothing important slipped through. Applire stores every fact about your career in one place, retrieves exactly the parts that fit a specific job, and interviews you to close the remaining gaps as well as possible — so each CV is complete, consistent, and tailored without the manual shuffle.

🌍 "I want to apply in the DACH region, but my CV is from somewhere else"

You have your existing CV — say, an Indian one — but how do you turn it into something a German, Austrian, or Swiss recruiter expects? Applire converts your profile into a CV fine-tuned for DACH conventions (Lebenslauf structure, expected sections, cultural signals), so you compete on equal footing.

🤖 "Let my AI agent handle it"

Applire is agent-ready. Connect your AI agent — Claude, ChatGPT, or any MCP-capable assistant — and have it run the whole loop for you interactively over the Model Context Protocol: import your CVs, analyse the job ad, fill gaps, and generate the finished CV. No UI required. And if your agent writes better than our built-in generator, good — Applire's job is to enable it: your agent stays the strategist, Applire provides the career vault, the gap evidence, the DACH norms, and the rendering.


✨ Key Features

🧠 Intelligent Master Profile

  • Multi-CV Consolidation: Upload multiple CVs and automatically merge them into a rich, conflict-aware Master Profile
  • Additive Enrichment: Every CV upload, interview session, and edit enriches your profile — it never overwrites, only accumulates
  • Source Tracking: Full audit trail of where every piece of information came from
  • Conflict Resolution: Smart detection of factual contradictions (dates, degrees) with user-controlled resolution

🎯 Job-First Analysis & Gap Detection

  • Deep JD Analysis: Extracts requirements, skills, cultural signals, and industry context from job descriptions
  • Transparent Gap Scoring: 0-100% match score with detailed explanations of what's missing
  • Categorized Gaps:
    • Category A (Hard blockers): Must-have requirements you don't meet
    • Category B (Confirmation needed): You likely have this, but it's not stated clearly
    • Category C (Exploratory): Soft requirements worth discussing

💬 Conversational Interview Orchestrator

  • Three Modes:
    • Targeted (for experienced users): Focuses on filling specific gaps identified in your profile
    • Guided (for new users): Systematically builds your profile section by section
    • Profile enrichment (no job ad needed): Improves your Master Profile on its own, outside any application
  • Stateful Backend: Pause and resume anytime — your progress is saved server-side
  • Smart Completion: Automatically detects when you're done or when all gaps are resolved
  • Profile Updates: Every answer enriches your Master Profile in real-time

📄 CV Generation & Fine-Tuning

  • ATS-Optimized PDFs: Generated via Playwright/Chromium with CSS-based themes
  • Live Browser Preview: See exactly what your CV will look like before downloading
  • Section-Level Editing: Fine-tune individual sections (introduction, positions, skills) with live re-rendering
  • Dual Save Path: Save edits to your Master Profile (permanent) or just to this CV (one-time)
  • AI-Assisted Editing: Optional "Let Kaile help" for targeted gap completion within the editor
  • Cover Letter Generation: AI-powered cover letter creation based on JD and Master Profile
  • Cultural Adaptation: Automatic detection and formatting for German, Austrian, and Swiss CV conventions

🗺️ DACH Cultural Intelligence

  • Market-Specific Formatting: Lebenslauf vs. international CV formats
  • Cultural Signal Detection: Identifies when a CV needs adaptation (e.g., Indian-format CV → German Lebenslauf conventions)
  • Multilingual Support: German and English UI (English by default, switchable in Settings). Interview questions follow your UI language, while the generated CV and cover letter follow the language the job ad is written in — detected from the ad itself, so an English source CV becomes a German Lebenslauf for a German posting. French and Spanish planned.

🔒 Privacy & GDPR Compliance

  • Privacy by Design (GDPR Art. 25): Data minimisation throughout — the LLM provider you choose is the only third party your data reaches, and Applire sends it the least it can
  • Automated Retention: A daily worker enforces TTLs, all configurable via environment variables:
    • Uploaded files: 7 days (UPLOAD_TTL_DAYS)
    • Interview sessions: 30 days (INTERVIEW_SESSION_TTL_DAYS)
    • Generated CVs and cover letters: 90 days (GENERATED_DOCUMENTS_TTL_DAYS)
    • Cancelled applications: 7 days (CANCELLED_APPLICATION_TTL_DAYS)
    • Master Profile after inactivity: 730 days (PROFILE_INACTIVITY_TTL_DAYS)
  • Right to Erasure (GDPR Art. 17): One-click full data deletion
  • Self-Hosted: Your data never leaves your infrastructure
  • Encryption at rest is yours to provide. Applire adds no plaintext store of its own beyond PostgreSQL, and it does not encrypt the database for you — run it on an encrypted volume or a full-disk-encrypted host if your context requires it

🤖 Built for the AI Agent Era

Applire is the first CV tool built for AI agents as first-class users — under a simple doctrine: bring your own intelligence. Your agent is the strategist and, if it's strong, the writer; Applire supplies what an agent structurally cannot give itself:

  • State that can't silently drift — the Master Profile is a reconciled vault where every change is recorded with its source, not a lossy notes file
  • Checks it can't fake — deterministic keyword-coverage and ATS checks, plus audit_document: a per-claim document-vs-profile truthfulness audit (grounded / inflated / misattributed / unbacked / unverifiable / not applicable, with profile evidence) that also accepts documents your agent wrote itself. Limit stated openly: it verifies document ↔ profile consistency; it cannot prove the profile itself
  • A renderer it doesn't have to fightrender_document: your agent's structured content (public versioned schemas, served as MCP resources) through Applire's templates and DACH norms checks — PDF plus ATS and truthfulness reports out, and Applire never rewrites your content
  • Rules it only half-remembers — DACH application norms enforced as tested, reviewable data, not vague model recall
  • A campaign, not one document — applications, versions, staleness, and follow-ups tracked across the whole search
  • Compounding memory — facts surfaced in interviews land in the profile with receipts and benefit every future application. If your agent runs the interview itself, submit_claims records the elicited facts with agent-interview provenance — your agent asks, Applire notarises: only what the candidate actually said can land, ambiguities go to the profile Health hub instead of being silently applied

The weaker your agent's model, the more of Applire's built-in pipeline you can lean on — the generation tools remain available end-to-end.

Model Context Protocol (MCP)

  • Seamless Integration: First-class support for Claude Desktop, ChatGPT, Cursor, and custom AI agents
  • Agent-supplied documents: Agents can ingest CVs (base64-encoded PDF, with a plain-text fallback) and job descriptions (raw text or a URL scraped server-side) directly over stdio — no UI required
  • Stateful Sessions: Agents can pause, resume, and recover from interruptions via a stable flow_id
  • Flow Orchestrator: Guides agents through the correct sequence (JD analysis → CV import → gap analysis → interview → generation)
  • Data-minimal by default: Write and ingest tools return summaries and receipts, not the profile — import_cv reports what it extracted rather than echoing the vault back. The full profile is available when an agent actually needs it, deliberately and by name: get_profile() and the profile://current resource
  • Async Generation: Non-blocking CV generation with polling-based status checks

REST API

  • Full HTTP API: Programmatic access for remote integrations
  • OpenAPI Documentation: Interactive Swagger UI at /docs

Agent Workflow Example

# Start MCP server (stdio transport)
python -m applire.mcp

# A typical agent session:
1. start_flow()                              → flow_id  (stable recovery handle)
2. import_cv(file_base64="<base64 PDF>")     → profile summary
3. analyze_jd(url="https://.../job-posting") → job_id
4. analyze_gaps(job_id)                      → gap_report
5. run_interview(job_id)                     → session_id + first question
6. send_message(session_id, "I have 5 yrs…") → next question / {complete: true}
7. generate_cv(job_id)                       → cv_id  (async)
8. get_cv_status(cv_id)                      → {status: "ready", pdf_url: "…"}
9. create_application(job_id)                → application logged to pipeline

🏗️ Architecture & Tech Stack

Backend

  • Python 3.12+: Modern async Python with type hints
  • FastAPI: High-performance async web framework
  • PostgreSQL 16: JSONB for flexible Master Profile schema
  • Pydantic: Type-safe data validation and serialization
  • SQLAlchemy 2.0: Async ORM with full type support
  • Alembic: Database migrations

Frontend

  • Next.js 15: React framework with App Router
  • TypeScript: Type-safe JavaScript
  • ShadCN/UI: Accessible component library
  • Tailwind CSS v4: Utility-first styling

AI/ML

  • Bring your own key: You choose the LLM provider and supply the API key — your data goes only where you point it
  • LLM Provider Abstraction: Pluggable backends — Mistral (EU-hosted), Requesty (EU-hosted gateway), OpenRouter, Anthropic (Claude, BYO-API-key), OpenAI (or any OpenAI-compatible endpoint), and Ollama (fully offline, self-hosted)
  • Custom State Machine: Async interview orchestrator (no LangGraph dependency)
  • Playwright: Headless Chromium for PDF generation

Infrastructure

  • Docker & Docker Compose: Containerized deployment
  • PostgreSQL 16: Primary database with JSONB support
  • Retention Worker: Daily cron for GDPR TTL enforcement
  • GitHub Actions: CI/CD pipeline with pytest and Playwright E2E tests

Agent Integration

  • Model Context Protocol (MCP): stdio transport for local AI agents
  • REST API: Full HTTP API for remote integrations
  • Flow Orchestrator: State machine for multi-step agent workflows
  • Session Recovery: Agents can resume interrupted sessions via flow_id

🚀 Installation

Prerequisites

  • Docker & Docker Compose
  • An LLM provider of your choice (bring your own key): Mistral, Requesty, OpenRouter, Anthropic, OpenAI (or any OpenAI-compatible endpoint), or Ollama (local/free, no key needed)

Self-hosting (no clone required)

Which version does this install? These commands always fetch the newest published
release
— the same one Docker's :latest resolves to, so the compose file, the env
template and the images are one matching set, with no version number for you to look
up. This page describes the development version; for documentation that matches what
you just installed, open the
latest release.

# 1. Download the two files you need, straight from the newest release
curl -LO https://github.com/Applire/Applire/releases/latest/download/docker-compose.yml
curl -L -o .env.example https://github.com/Applire/Applire/releases/latest/download/env.example

# 2. Configure your environment
cp .env.example .env
# Edit .env: set LLM_PROVIDER and the matching API key (see Configuration below)

# 3. Fetch the images, then start all services.
#    The explicit `pull` matters: `up -d` on its own reuses an older `:latest`
#    that is already cached locally. Database migrations run automatically on
#    backend startup — there is no separate migration step.
docker compose pull && docker compose up -d

Every service — including the reverse proxy, whose config is baked into the applire-nginx image — is a pre-built image, so docker compose pull fetches a complete, working stack with no config files to place on the host.

Access the application at http://localhost — the bundled nginx reverse proxy serves the frontend and routes /api/* to the backend. Port 80 is the only one you need to publish; the backend and frontend containers stay internal. For the full entry-point and port topology, see docs/ARCHITECTURE.md.

Custom domain or TLS? The image ships a sensible default proxy config. To override it, bind-mount your own file over the baked one — add to the nginx service in docker-compose.yml:

    volumes:
      - ./my-nginx.conf:/etc/nginx/conf.d/default.conf:ro

To update to the latest release:

docker compose pull && docker compose up -d

Updating from a release older than v0.37.0-beta? Step through
v0.37.2-beta first. Profiles imported before the reconciliation engine
(E035) can hold flat duplicate employers and orphaned projects, and the
one-time scripts/migrate_flat_duplicates.py pass that folds them into the
typed model shipped only in v0.37.0-betav0.37.2-beta. It is data
hygiene, not schema — Alembic migrations still run automatically on startup,
so a direct jump upgrades cleanly, it just leaves those duplicates in place.

Self-hosting from source

Prefer to build what you run (or can't reach GHCR)? Clone the repo and build the same
three images locally, then start the same production topology:

git clone https://github.com/Applire/Applire.git && cd Applire
cp .env.example .env   # set LLM_PROVIDER and the matching API key

docker build -t ghcr.io/applire/applire-backend:latest ./backend
docker build --target runner -t ghcr.io/applire/applire-frontend:latest ./frontend
docker build -t ghcr.io/applire/applire-nginx:latest ./nginx

docker compose -f docker-compose.yml up -d

Note the explicit -f docker-compose.yml. Inside a clone, a plain
docker compose up -d also applies docker-compose.override.yml — the
development stack (hot-reload servers, source bind mounts, extra published
ports including the database). Great for hacking on Applire, not for serving
real users.

Contributing? See CONTRIBUTING.md for the build-from-source developer setup.


⚙️ Configuration

Environment Variables

Applire is bring-your-own-key: pick any supported provider and supply its key — your data goes only to the provider you choose. Copy .env.example to .env and configure:

# Database
DATABASE_URL=postgresql+asyncpg://applire:applire@postgres:5432/applire

# LLM Provider — choose one: mistral | requesty | openrouter | anthropic | openai | ollama
LLM_PROVIDER=mistral

# Mistral AI — EU-hosted, strong German proficiency
MISTRAL_API_KEY=your-mistral-api-key-here
MISTRAL_MODEL=mistral-medium-latest

# Requesty — EU-hosted gateway (Frankfurt); also an EU-resident path to Claude/GPT/Gemini
REQUESTY_API_KEY=your-requesty-api-key-here
REQUESTY_MODEL=mistralai/mistral-large-latest   # EU-region model for full residency

# OpenRouter — multi-model gateway: one key for Mistral, Claude, and more (not EU-hosted)
# Get a key at https://openrouter.ai/keys
OPENROUTER_API_KEY=your-openrouter-api-key-here
OPENROUTER_MODEL=mistralai/mistral-medium-3

# Anthropic (Claude) — native API, BYO-API-key only (a Claude subscription cannot be used)
# Model names move fast: take a current id from Anthropic's model list rather than
# copying one from a README. See docs/llm-models.md for how to choose.
ANTHROPIC_API_KEY=your-anthropic-api-key-here
#ANTHROPIC_MODEL=<current-claude-model-id>

# OpenAI or any OpenAI-compatible server (e.g. LM Studio)
OPENAI_API_KEY=your-openai-api-key-here
#OPENAI_MODEL=gpt-4o
#OPENAI_BASE_URL=http://host.docker.internal:1234/v1

# Ollama — fully offline (docker compose --profile ollama up)
OLLAMA_BASE_URL=http://ollama:11434
OLLAMA_MODEL=llama3.2

# LLM timeout in seconds (raise for reasoning models)
LLM_TIMEOUT=180

# Auth (none for Community Edition single-user mode)
AUTH_PROVIDER=none

# CORS — comma-separated list of allowed origins
# Default "*" (allow all) is fine for single-user self-hosting with AUTH_PROVIDER=none
#CORS_ORIGINS=*

# nginx proxy timeout — must be greater than LLM_TIMEOUT
#NGINX_PROXY_TIMEOUT=300

# Frontend API URL
# docker compose: leave empty — nginx at :80 routes /api/* to the backend
# standalone dev: set to http://localhost:8001
#NEXT_PUBLIC_API_URL=http://localhost:8001

LLM Provider Options

Applire is bring-your-own-key — no provider is privileged. Pick whichever fits your needs and supply the matching key via a pluggable abstraction layer:

Provider Configuration Use Case
Mistral AI LLM_PROVIDER=mistral
MISTRAL_API_KEY=...
EU-hosted, strong German proficiency
Requesty LLM_PROVIDER=requesty
REQUESTY_API_KEY=...
EU-hosted gateway (Frankfurt, zero-retention); an EU-resident path to Claude/GPT/Gemini via EU-region deployments
OpenRouter LLM_PROVIDER=openrouter
OPENROUTER_API_KEY=...
Multi-model gateway; access Mistral, Claude, and others with one key (not EU-hosted)
Anthropic (Claude) LLM_PROVIDER=anthropic
ANTHROPIC_API_KEY=...
Claude via a Console API key (BYO-key) — a Claude Pro/Max subscription cannot be used. US-hosted
OpenAI LLM_PROVIDER=openai
OPENAI_API_KEY=...
High quality, widely available; also supports LM Studio via OPENAI_BASE_URL
Ollama (local) LLM_PROVIDER=ollama
OLLAMA_BASE_URL=http://localhost:11434
Fully offline, no API costs, no key required

📖 API Documentation

REST API

In the Docker stack the REST API is reached through nginx at http://localhost/api/*; the interactive Swagger UI is available when running the backend standalone in development. See docs/ARCHITECTURE.md for the entry-point and port topology.

Core Endpoints

# Job Description Analysis
POST /api/job/analyze
{
  "text": "Senior Software Engineer role...",
  "url": "https://example.com/job"  # Optional
}

# CV Upload & Profile Enrichment (async job — poll until done)
POST /api/profile/import-jobs
Content-Type: multipart/form-data
files: [cv1.pdf, cv2.pdf]
GET  /api/profile/import-jobs/{job_id}

# Gap Analysis (session-scoped)
POST /api/session/{session_id}/analyze-gaps

# Start Interview Session
POST /api/session
{ "job_id": "uuid", "mode": "targeted" }

# Send Interview Message
POST /api/session/{session_id}/message
{ "message": "I have 5 years of experience with Python..." }

# Generate CV
POST /api/cv/generate
{ "job_id": "uuid", "template": "classic_german", "target_pages": 2 }
# template and target_pages are optional; target_pages falls back to your
# settings, then the region standard

# Check CV Generation Status
GET /api/cv/{cv_id}/status
# Returns: { "status": "pending" | "ready" | "failed" }

# Download CV
GET /api/cv/{cv_id}/pdf

Model Context Protocol (MCP)

# Start MCP server (stdio transport)
python -m applire.mcp

Set APPLIRE_BASE_URL to the externally-reachable scheme://host:port of your
reverse proxy for any deployment other than local/unproxied dev — it's what
generate_cv/get_cv_status/generate_cover_letter use to build html_url/
pdf_url. It defaults to http://localhost:8001, which is wrong behind
nginx/Caddy; the server logs a startup warning when it's unset. See
.env.example.

First call: after connecting, have your agent call get_guide — it returns
the agent-usage guide and Applire's honesty contract (tool flow, à-la-carte
paths, grounding rules). The canonical file is
backend/applire/mcp/AGENT_GUIDE.md.

MCP Tools

Guidance

Tool Description
get_guide() Returns the agent-usage guide + honesty contract — call before your first application run

Ingestion & profile

Tool Description
import_cv(file_base64?, filename?, text?) Seed or extend the Master Profile from a CV. Primary: base64-encoded PDF (≤10 MB); fallback: pre-extracted text. Returns an extraction summary (never the raw profile)
analyze_jd(text?, url?) Analyze a job description. Provide exactly one of text (JD body) or url (scraped server-side); reposts of jobs already in the pipeline carry a duplicate_of hint
get_profile() Return the current Master Profile
update_profile(section, data) Patch one section (personal_info, professional_summary, work_experience, education, certifications, skills, languages, publications, volunteer_activities, signature_stories)
add_role(title, company, start_date, location?, industry?, close_role_ids?) Add a new ongoing role (post-hire update); close_role_ids closes prior open roles

Flow & interview

Tool Description
start_flow(job_id?) Create or resume a flow session (idempotent per user+job); returns flow_id + state
advance_flow(flow_id, step, artifact_id?) Advance to the next step; artifact-producing steps require artifact_id
get_flow_state(flow_id) Get current flow state and available actions
analyze_gaps(job_id) Detect gaps between profile and JD
run_interview(job_id) Start a gap-fill interview; returns session_id + first question
send_message(session_id, message) Send a message in an active interview; returns next question or {complete: true}
resolve_gap(job_id, gap_id, answer) Resolve ONE gap cluster in a single call — the agent-channel form of the UI's targeted gap fill. Stateless: for agents that would rather ask their own questions than run a full interview session. gap_id comes from analyze_gaps' gap_clusters

Built-in generation

Tool Description
generate_cv(job_id, target_pages?) Initiate async CV generation; optional target_pages pins the page count for this run; returns cv_id, html_url, pdf_url
get_cv_status(cv_id) Poll CV generation status (pending / generating / ready / failed)
get_cv_ats_report(cv_id) Persisted ATS audit report for a generated CV — named pass/fail checks + present/missing keywords, no aggregate score
generate_cover_letter(job_id) Generate a cover letter (requires an existing flow session for the job); returns cover_letter_id, html_url, pdf_url
get_cover_letter_status(cover_letter_id) Poll cover-letter generation status (pending / generating / ready / failed)
get_cover_letter_ats_report(cover_letter_id) Persisted ATS audit report for a generated cover letter

Bring your own intelligence (ADR-054) — à la carte, no prior generate_* call needed

Tool Description
submit_claims(claims, job_id?) Submit facts your agent elicited from the candidate as itemized claims; Applire reconciles them into the profile with agent-interview provenance (agent = interviewer, Applire = notary). Contract: schema://claims
submit_testimony(text) Reconcile ONE whole free-text testimony document into the profile with receipts — the unstructured counterpart to submit_claims. Contract: schema://testimony
audit_document(document_id?, document_text?) Truthfulness Oracle: per-claim truthfulness report — for a generated document by id, or raw text of a document your agent wrote itself
render_document(document_kind, content, job_id, template?, target_pages?) Render your agent-authored structured content (contracts: schema://cv / schema://cover-letter) into a norms-checked, templated PDF with ATS + truthfulness reports — never rewritten

Applications

Tool Description
create_application(job_id, start_workflow?, company_name?, role_title?, deadline?, source_url?) Log an application to the pipeline; start_workflow=true atomically creates the flow session
list_applications(status_filter?) List the application pipeline (tracking, applied, rejected, offer)
get_application(application_id) Get details for a specific application (incl. a stale_cv re-tailor hint)
update_application(application_id, ...) Update user-managed fields (status, notes, deadline, source URL), pin the submitted CV/letter, or dismiss the stale-CV hint

MCP Resources

  • profile://current — Current Master Profile (JSON)
  • job://{job_id} — Job analysis
  • cv://{cv_id} — Generated CV metadata
  • flow://{flow_id} — Flow session state
  • schema://cv — Versioned tailored-CV content contract for render_document ({schema_version, json_schema})
  • schema://cover-letter — Versioned cover-letter content contract for render_document
  • schema://claims — Versioned itemized-claims contract for submit_claims
  • schema://testimony — Versioned free-text testimony contract for submit_testimony
  • guide://usage — The agent-usage guide + honesty contract (same content as get_guide)

🧪 Testing

Backend Tests

# Run all tests
pytest

# Run with coverage (enforces ≥75% threshold)
pytest --cov=applire --cov-fail-under=75

# Generate HTML coverage report
pytest --cov=applire --cov-report=html

Frontend Tests

# Run unit tests
npm test

# Run E2E tests (Playwright)
npm run test:e2e

# Run E2E tests in UI mode
npm run test:e2e:ui

CI/CD Pipeline

GitHub Actions runs, against a mocked LLM provider throughout:

  1. ATS round-trip render guarantee (Playwright)
  2. Backend unit tests (pytest, ≥75% coverage)
  3. Backend integration tests (Docker stack)
  4. MCP stdio tests (the agent channel)
  5. Playwright IQ, OQ (desktop + mobile), and PQ suites — Chromium
  6. Frontend unit tests (Vitest), lint (ESLint + i18n parity), and a production build
  7. A module-system check

All tiers must pass before merge.


📁 Project Structure

Applire/
├── backend/
│   ├── applire/
│   │   ├── main.py              # FastAPI application entry point
│   │   ├── models/              # SQLAlchemy ORM models
│   │   ├── schemas/             # Pydantic request/response schemas
│   │   ├── routers/             # FastAPI route handlers
│   │   ├── services/            # Business logic layer
│   │   │   ├── interview/       # Interview Orchestrator (state machine)
│   │   │   ├── flow/            # Flow Orchestrator
│   │   │   ├── profile/         # Master Profile merge logic
│   │   │   ├── cv/              # CV generation & section editing
│   │   │   └── gap/             # Gap analysis
│   │   ├── providers/           # LLM, Auth, Storage abstractions
│   │   ├── mcp/                 # Model Context Protocol server
│   │   ├── retention/           # GDPR retention worker
│   │   └── templates/           # Jinja2 CV templates
│   ├── alembic/                 # Database migrations
│   ├── tests/                   # Pytest test suite
│   └── requirements.txt
├── frontend/
│   ├── app/                     # Next.js App Router pages
│   ├── components/              # React components
│   ├── lib/                     # Utilities and API clients
│   └── public/
├── docs/
│   ├── TESTING.md               # Testing strategy and commands
│   └── CI_CD_GUIDE.md           # CI/CD pipeline documentation
├── tests/                       # Integration and E2E tests
├── docker-compose.yml
├── .env.example
└── README.md

🗺️ Roadmap

✅ Current Release (v0.40.0-beta)

  • The document language is your decision, not a detection: a per-application DE/EN control governs every generated document, each document pins its own language, and switching later never repaints an existing one
  • Structured profile editors for work experience, education, skills, languages, certifications and projects — the JSON text field is gone, and an edit made on stale data can be refused instead of silently overwriting
  • Fact pins: mark a fact as required for one application and it keeps its place in the document's budget, with attribution in the review report
  • One vault write path: every writer — interview, import, section editor, conflict resolution, role lifecycle — commits through commit_ops with per-entry receipts; no ad-hoc profile writes remain
  • Terminal document review closes over the CV and cover letter as composed, with bounded re-entry and ship-and-report semantics
  • Letter review treats presence as a fact it is told, not a question it asks — false demands and false-presence findings driven to near zero
  • CV prose custody: the writer emits prose only; facts join deterministically, and the deterministic tail can never silently delete evidence
  • Honestly bounded partials (assisted-not-independent, in-progress) are deliverable data instead of dropped claims
  • Outcome critic: a persisted advisory report for every generated CV and cover letter, including dropped-citation accounting
  • Truthfulness stance guard: an interview answer that denies experience can never become a CV claim — the reconciler's own denial verdicts deterministically outrank its edits
  • Document-language enforcement covers project bullets — nothing prose-shaped enters a generated CV after the language pass
  • Claimable keyword coverage self-heals inside the generation pipeline — the deterministic check that grades the document also gates every writer, including the output-language pass
  • Truthful keyword ledger: every job-ad keyword classified present / claimable / honest gap — one consistent source for match score, ATS panel, generators, and interview
  • Profile Reconciliation Engine: typed, deterministic merge of CV imports and interview answers with conflict resolution and enrichment history
  • Master Profile Health hub with snapshots/undo and no-JD interviews
  • ATS parseability checks on every generated document (panel + REST + MCP)
  • Unified CV + cover-letter document workspace per application
  • Async import/gap/letter jobs — long LLM steps survive refresh and proxies
  • Cap-safe segmented CV generation (no truncated documents on verbose models)
  • Multi-CV upload and parsing (PDF, DOCX, images via OCR)
  • Master Profile consolidation with conflict resolution
  • Job description analysis (text + URL scraping)
  • Gap detection and match scoring
  • Conversational interview flow (Targeted + Guided modes)
  • CV generation (PDF via Playwright, multiple templates)
  • CV Section Editor (Finetuner) with live preview and AI-assisted editing
  • Cover letter generation
  • Photo management (upload, crop, remove)
  • Cultural adaptation detection (DACH-specific)
  • MCP Server (stdio transport for AI agents)
  • Flow Orchestrator (state machine for user journey)
  • GDPR Retention Worker (automated TTL enforcement)
  • Multilingual UI (de/en via next-intl)

⏳ Next Up

Applire ships in dessert-named releases, each tracked as a public milestone — follow along on the blog:

  • Spaghettieis — shipped with v0.38.0-beta (milestone closed, 27 issues). Parallel applications became first-class: an application dashboard with status tracking, one-click re-tailoring across multiple jobs, refreshed job-ad analysis, and better progress feedback on long-running steps
  • Tiramisu — shipped with v0.39.0-beta. Truthfulness Oracle: every generated document ships with a deterministic truthfulness report — is each claim grounded in your profile, is every number backed, did a "targets 70%" quietly become "achieved 70%"? In the UI and as the audit_document MCP tool, which also audits documents your agent wrote itself; likewise render_document (your agent's own content through Applire's norms-checked renderer, never rewritten), submit_claims / submit_testimony (agent-run interviews landing in the profile with receipts) and resolve_gap. The flavour closed on evidence selection: one write path into the profile, and a review loop whose verdict covers the document as composed
  • Stracciatella — Felix takes the controls: choose the leading document language per application (detection becomes a default, not a law), structured Master-Profile editors replacing the raw-JSON view, and pinning must-appear facts to a document — plus hardening of the delivered documents (the v0.39 ship-gate findings and the prompt-injection defence)
  • Strawberry — Multi-user capability: user roles, sign-in UI, an admin panel for user management, and operator controls

Beyond that, without dates: country packs beyond DACH as a community contribution surface. The hosted demo and Applire Cloud (SaaS) are paused while we focus on the open-source core and the agent channel — the waitlist hears first when that changes.

🔭 Future Vision

  • Mock Interview Preparation: AI-powered practice sessions with role-specific questions
  • Career Path Advisory: Skill gap analysis and training recommendations
  • Job Search & Recommendation: Curated job suggestions based on Master Profile
  • MCP Marketplace Listings: Distribution via agent marketplaces

🤝 Contributing

We welcome contributions! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Commit your changes: git commit -m 'feat: add amazing feature'
  4. Push to the branch: git push origin feature/amazing-feature
  5. Open a Pull Request

Development Guidelines

  • Follow PEP 8 for Python code (enforced by black)
  • Use TypeScript for all frontend code (strict mode, no any)
  • Write tests for new features (≥75% backend coverage)
  • Keep commits atomic and use Conventional Commits
  • All schema changes go through Alembic migrations — never raw DDL

Code Style

# Backend: Format with Black
black .

# Frontend: Lint with ESLint
npm run lint

Contributor License Agreement

By submitting a pull request you agree to the Applire CLA. This allows us to maintain the open-core model while keeping the Community Edition fully open-source. See CONTRIBUTING.md for details.


💛 Support the project

Applire is built part-time by a solo founder and stays fully open source (AGPL-3.0, no feature held back). Every feature and every release is checked against real LLM providers before it ships — adversarial passes, blind hiring-panel reviews, agent-channel journeys — and Applire is built in public together with AI coding agents. Sponsorship pays for exactly that: the API credits, the AI coding tools, and the infrastructure behind applire.de and the release images.

If Applire saves you an evening of CV tailoring, consider sponsoring the project on GitHub. Sponsors are named in the release notes and here in the README, and every release post states what sponsorship paid for in that cycle.


💬 Community & Support

Get Help


📄 License

This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0) — see the LICENSE file for details.

Why AGPL?

We chose AGPL to ensure that:

  • The software remains free and open source — Always accessible to everyone
  • Modifications must be shared — Even when used as a service (SaaS)
  • The community benefits — All improvements flow back to the project
  • Your privacy is protected — Full transparency in how your data is processed
  • No vendor lock-in — You control your data and infrastructure

Commercial Licensing

For organizations that cannot comply with AGPL requirements (e.g., proprietary SaaS offerings), commercial licenses are available. Contact [email protected] for details.


🙏 Acknowledgments

  • Mistral AI for EU-hosted LLM infrastructure
  • FastAPI and Next.js communities
  • All contributors and early adopters
  • DACH industry professionals who provided domain expertise
  • The open-source community for inspiration and tools

📬 Contact


Built with ❤️ for job seekers in the DACH market

Open source. Privacy-first. Agent-ready. Truthful by design.

⭐ Star us on GitHub

Reviews (0)

No results found