Single-model, tool-using job application agent for:
- reading persistent applicant memory (
experience_skills.md) - reading a persistent master CV Typst source (
master_cv.typ) - asking for explicit applicant approval with evidence review
- asking for a specific motivation-letter addition before generation
- enforcing one output language based on the job posting
- generating Motivation Letter PDF from text + template
- generating CV PDF from full Typst source
- targeting one-page CV output with overflow warnings and retries
- writing simplified agent execution trace JSON
- Install dependencies:
uv sync- Set environment variables:
export OPENAI_API_KEY=your_key
# optional overrides
# export OPENAI_MODEL_AGENT=gpt-4.1-mini
# export OPENAI_AGENT_MAX_STEPS=30- Ensure PocketBase collections exist:
uv run python -c "from app.main import ensure_pocketbase_collections; ensure_pocketbase_collections()"- Start the backend API:
uv run uvicorn app.web.api:app --host 127.0.0.1 --port 8000- Copy environment template:
cp .env.example .env- Fill in at least:
OPENAI_API_KEYPOCKETBASE_ADMIN_EMAILPOCKETBASE_ADMIN_PASSWORDWEB_AUTH_COOKIE_SECRETNEXT_PUBLIC_API_BASE_URL(frontend -> backend URL)POCKETBASE_PUBLIC_URL(frontend -> PocketBase URL/domain)
- Start everything:
docker compose up --build -d- Access:
- App: http://localhost:3000
- Backend health: http://localhost:8000/api/health
- PocketBase health: http://localhost:8090/api/health
Notes:
- Host ports are configurable via:
FRONTEND_HOST_PORT(default3000)BACKEND_HOST_PORT(default8000)POCKETBASE_HOST_PORT(default8090)
- For an external PocketBase domain, set:
POCKETBASE_PUBLIC_URL=https://pb.your-domain.tld(used by frontend)POCKETBASE_URL=https://pb.your-domain.tld(used by backend)
Persistence:
- PocketBase data is stored in Docker volume
pocketbase_data. docker compose downkeeps data.docker compose down -vdeletes data volumes.
The repository now includes:
- FastAPI backend with SSE streaming in
app/web/api.py - Next.js chat UI in
web/(light mode, shadcn-style components)
Start backend API:
uv run uvicorn app.web.api:app --host 127.0.0.1 --port 8000Start frontend (new terminal):
cd web
npm install
NEXT_PUBLIC_API_BASE_URL=http://127.0.0.1:8000 \
NEXT_PUBLIC_POCKETBASE_URL=http://127.0.0.1:8090 \
npm run devOpen http://127.0.0.1:3000.
Web flow:
- Paste job description into the large initial textbox.
- Click
Generate documents. - Watch tool calls stream as grey hint cards in the chat timeline.
- Review/modify evidence in the approval card and choose
Accept proposalorSuggest changes. - Respond to follow-up prompts in the bottom chat composer.
- Download generated files and preview PDFs inline from the final artifacts card.
Initialize required PocketBase collections:
uv run python -c "from app.main import ensure_pocketbase_collections; ensure_pocketbase_collections()"The agent uses a strict tool flow:
- retrieve experience/skills memory document
- retrieve master CV content
- select evidence and ask applicant approval
- collect optional custom motivation-letter point from applicant
- if applicant appends evidence, update memory document
- generate motivation letter PDF
- generate CV PDF
Language and wording behavior:
- The agent detects the dominant language in the job text and uses it for both documents.
- The agent reuses key terminology from the job listing naturally (not copy-paste style).
CV one-page behavior:
- The agent targets exactly one page for CV output.
- The CV should not be over-shortened; it should still use page space effectively.
- Work experience and education are expected in reverse chronological order.
- Full education curriculum is always preserved.
- Rule of thumb: around 8 meaningful entries across major categories, plus skills/hobbies sections.
- If the CV exceeds one page, it attempts compaction (trim less relevant entries, reduce/shorten bullets) and retries.
- If still over one page, generation still completes with explicit warnings in logs and trace metadata.
Motivation letter behavior:
- Written in a natural, human, professional tone.
- Structured into 4 paragraphs (intro, relevant background, why this opportunity, goals/closing).
- 400-600 words, full paragraphs, no bullet points.
- Includes any applicant-specific motivation point collected during approval.
Generation tools are hard-gated until approval is granted.
Default outputs:
- trace:
data/applications/agent_trace.json - generated files:
data/applications/generated/<role-company-slug>/MotivationLetter.typMotivationLetter.pdfCV.typCV.pdf
- persistent memory files:
data/profile/experience_skills.mddata/profile/master_cv.typ