▸ Table of Contents
Foundation — Forge & the Agent Team
Intro for Forge. Forge is your coordinator — the agent you talk to. It never does the specialist work itself; it routes to three persistent teammates and reports back. In this part we set Forge's rules, create and introduce each agent, give them shared team awareness, a router with slash-commands, and an activity log.
What this does: The most important prompt — the first thing you say to Hermes' default agent. It names Forge, names you, explains in full what you're building together, introduces the teammates Forge will coordinate, and sets its operating rules.
Defines Forge's identity (orchestrator, not doer), who you work for, the full system architecture (Search → Review → Promote → Memory → Control), your team (Scout, Job Reader, CV Adapter), pipeline order, and the golden rule: never fabricate anything.
What this does: Forge is the default Hermes agent you just onboarded; now create its three persistent teammates with their exact identities — each introduces itself, states its role, and names who it works with.
Creates 3 Hermes profiles (scout, job-reader, cv-adapter) via hermes profile create <name>, writes their SOUL.md identity files, and verifies each agent responds with the correct identity before continuing.
What this does: Configures dedicated memory, fixed identity, isolated workspaces, role boundaries, and session continuity for each agent.
Five settings: (1) Dedicated memory — each stores only role-relevant data; (2) Fixed identity — never changes role; (3) Workspace isolation — writes only to own outputs folder; (4) Role boundaries — declines out-of-scope tasks; (5) Session continuity — memory persists across restarts. Includes a fixed-identity test.
What this does: Teaches every agent the full team structure and their place in it, so work goes to the right teammate.
Every agent learns: the owner, Forge as coordinator, Scout (search + rank), Job Reader (full JD extraction), CV Adapter (base CV + tailoring), and the pipeline order. Agents must redirect out-of-scope requests to the correct teammate by name.
What this does: Sets up natural-language routing and slash-command shortcuts so requests dispatch to the right agent automatically.
Routing table mapping phrases to each agent. Slash commands: /forge, /scout, /reader, /adapter for direct agent addressing; /find for free search, /promote [n] for paid tailoring, /stats for run summary. Fallback: bare messages go to Forge; ambiguous messages trigger clarification.
What this does: Builds a SQLite database and a bash logging script that records every agent action for the dashboard's analytics.
Creates ~/.hermes/agent-logs.db with schema: id (UUID), agent_name, task_description, status, model_used, created_at. Builds log-task-local.sh — accepts 4 args, auto-detects model, uses stdlib only. Tests with a one-liner verification.
What this does: Distributes the logging rule from Forge to every agent and makes it permanent, then runs a smoke test so each agent proves it logs.
Forge saves a durable rule: log every response before sending via log-task-local.sh with all 4 fields populated, description under 140 chars. Distributes to all 3 teammates. Runs smoke test and reports per-agent results.
What works now: Forge and its three teammates (Scout, Job Reader, CV Adapter) exist as persistent agents with fixed roles, shared team awareness, and an activity log.
Test: Ask Forge "who's on your team and who does what?" then send /scout who are you? — both turns should appear in the activity log. Don't move on until this passes.
The Dashboard — Forge Builds It
Forge now builds the mission-control dashboard: a private backend, the uploaded template as the design source of truth, the shell, and the Overview + agent-fleet pages — all showing live data.
What this does: Stands up a private FastAPI backend over the logs, telemetry, job memory and runs, kept alive by systemd and never exposed to the internet.
FastAPI app at 127.0.0.1:51764 (localhost only) with endpoints: /api/health, /api/overview, /api/agents, /api/activity, /api/telemetry, /api/pipeline, /api/run-detail, /api/results. Served via uvicorn, managed as forge-dashboard.service (auto-restart, boot-enabled). Backup script included.
What this does: The first design step — Forge builds an upload point and folder where you upload the prebuilt dashboard template, saves it, and locks it in as the project's visual source of truth.
Creates /design/ folder + POST /api/design-template endpoint. Serves template at GET /template. Canonical rule: from this point on, every visual component must match the template's language exactly — palette, glassmorphism, spacing, typography, proportions, radii, shadows.
What this does: Establishes the premium design system, builds the app shell (sidebar nav, sticky top bar, live clock/status), wires the hydration script, and makes the whole thing fully mobile-responsive.
Pure DOM, no framework, no build step. Design system: near-black base (#080c17), gold accent (#eac266), glass cards with backdrop blur, stat numbers with gradient fills, gold primary buttons, dark inputs with gold focus ring. CSS variables for everything.
What this does: The home screen — a hero panel, the two matching ring gauges, and the live conversion funnel. The centrepiece visuals of the whole product.
Three sections: (1) Hero panel with greeting, date, status chips, and headline naming your 4 agents; (2) Two matching ring gauges — "Tokenized Load" (vs 1M budget) and "Jobs Indexed" (with MATCH/TAILORED sub-stats) — both wired to live data; (3) Conversion funnel (found → matched → read → tailored) with proportioned bars.
What this does: The live AGENT FLEET — four glass cards, each in its own accent colour, that glow while the agent is working — plus the running activity stream and sidebar mini-fleet.
Canonical colours: Forge = gold (#eac266), Scout = sky-blue, Job Reader = teal (#00c89c), CV Adapter = coral (#ff7c68). Fleet shows avatar, role, status (LIVE/WORKING/IDLE), success rate, task count, last action. Working agents' cards GLOW in their accent colour — survives page reload.
Job Sourcing & the Core Flow
Now the engine: connect your job sources (Adzuna + Remotive), upload your CV (Forge builds your base CV and derives your search profile from it), then Scout's deterministic search + scoring + memory and Forge's free Find run that fills the dashboard — all without spending a token.
What this does: You paste your Adzuna keys to Forge and it saves them for you — no hunting through hidden files. We use Adzuna (19 countries) and Remotive (global remote) together.
Saves ADZUNA_APP_ID and ADZUNA_APP_KEY to ~/.hermes/.env (treats as secrets — never echoes values). Makes one test API call and reports success + result count. Scout will search both sources together.
What this does: Your CV enters the system — you drop in your real CV (PDF/DOCX/MD/TXT) and Forge auto-builds your structured base CV from it, so the pipeline always tailors from your document.
Drop-zone upload. On upload: saves raw file, archives previous, drops .cv-building flag, runs build_base_cv.py in background — extracts text → ONE LLM call to structure into base_cv.json schema → atomically replaces old CV. Also derives search profile from CV text.
What this does: Your CV upload already derived a starting profile. Here Forge reads it back, lets you review and refine it, and fills in the search-only settings a CV can't contain.
Forge reads profile.json + base_cv.json, proposes refinements to titles, skills, scoring_skills, seniority from CV. Asks for search-only settings: short keyword queries (1-2 word domain nouns), country, thresholds. Writes validated profile.json.
What this does: Gives Scout the deterministic fetcher that pulls Adzuna + Remotive, merges and de-dupes into one list.
Deterministic scout_search.py script: fetches Adzuna (sweeps keywords by date + relevance, probes zero-hit queries by dropping trailing words) + Remotive (global remote, strips HTML). Merges by normalized title+company, normalizes to uniform schema. Per-source graceful degradation.
What this does: Gives Scout the two-pass, DOMAIN-driven scorer. The cheap first pass is title-led but matches on distinctive domain words — not shared role nouns — and guards against off-domain junk.
Deterministic matcher_score.py: two modes — first_cut (search-time, title-led) and final (full JD, skill-led). Four components: title (distinctive tokens only + role-family conflict penalty), skill (profile scoring_skills presence), seniority (level match), location (country scope). Two guards: relevance gate and wrong-level filter.
Run a real Scout search and then score it from the command line. You should see a healthy merged list (typically 100+ listings from Adzuna + Remotive combined) and a top-10 of clearly relevant, ranked matches. If the count is 0 or the top matches look wrong, fix it here.
What this does: Remembers every job ever seen so nothing is re-read or re-tailored, and badges what's NEW.
job_store.py backed by SQLite jobs.db — schema: key (Adzuna id or normalized title+company), title, company, url, score, status, jd_json, cv_path, times_seen, first_run, last_run, user_status. Status moves forward only (seen → matched → read → tailored). NEW badges for first-time listings. Reader/tailor REUSE cached data — zero-cost repeats.
What this does: Wires Forge's free scan: Scout searches + scores, results land in the dashboard (and are reviewable in Telegram) for review. No tokens.
run_pipeline.py --find-only: runs search → score → first cut → records run → logs to agent-logs.db. Real-time progress: scanning spinner, agent glow, run-status pill. POST/GET API for runs. Live progress survives page reload.
Tailoring & Product Features
The paid, opt-in tailoring step (Job Reader + CV Adapter), CV export to Word/PDF, and the product pages that make Forge complete — the Jobs workspace, Settings control center and theme switch.
What this does: When you pick a job, Job Reader fetches the full JD and CV Adapter tailors your CV for it — for that one job only, reusing cache if seen before.
Three-step pipeline: (1) job_reader.py — fetches JD page (Playwright → HTTP fallback), ONE Hermes call for structured extraction; (2) cv_adapter.py — rewrites headline/summary/experience from base CV, strictly from facts; (3) promote_job.py — orchestrates with caching. Background API endpoint with "tailoring.." spinner.
What this does: Turns the tailored CV JSON into a polished, downloadable .docx and .pdf.
cv_docx.py renders CV JSON to .docx (python-docx). LibreOffice headless converts to PDF. API endpoints with path traversal protection. DOC/PDF buttons per tailored row.
What this does: The main workspace: ranked matches with a per-job application tracker, NEW/seen badges, and a legend.
Matches table: rank, score (green/gold pills), role, company, location, status dropdown (persisted to jobs.db), flags (NEW, xN seen, language-required, CV tailored), actions (Tailor, JD drawer, CV drawer, DOC, PDF, original posting). Scan now button + KEY legend strip.
What this does: One page to retune search depth, scoring, sources and the profile — applied on the next scan.
Edits profile.json via GET/POST /api/settings. Sections: Profile & targeting (seniority chips, editable title/skill chips), Search (keyword chips, country dropdown, number inputs), Scoring (live sliders), Job sources (on/off toggles), System (read-only). Dirty-tracking Save button. Validates: clamps numbers, rejects invalid choices.
What this does: A polished theme switch — same layout, recolored — that looks as premium light as it does dark.
CSS variable-driven. Dark = template default. Light mode recolors surfaces via html[data-theme="light"] overrides. Persists in localStorage, no-flash inline script. Deepens accent colors for white-background readability. Dark-on-accent text stays dark in both themes.
What works now: promoting a job tailors your CV (the only paid step), CVs export to Word & PDF, and the Jobs page, Settings and theme make it usable end to end.
Test: Click Tailor → download DOC/PDF (opens clean). Change job status → reload (persists). Change Setting → re-scan (results change). Toggle theme. Don't move on until each works.
Automation, Testing & Launch
Now that the full pipeline and dashboard exist, give Forge its phone controls (run everything from Telegram), put scanning on autopilot, prove every function works, and reach the dashboard securely from anywhere.
What this does: Builds the deterministic command brain that powers Telegram plus the natural-language relay so plain English works too.
forge_cmd.py — deterministic (no LLM): /find (search+rank with tappable links), /jobs (latest matches), /promote <n> (read+tailor+send PDF via Telegram API), /status (latest run + memory summary), /help (command list). Natural-language fallback rule saved to Forge's memory.
What this does: Registers every command as a REAL Hermes gateway slash command (skills + per-agent profile routing) and the "/" autocomplete menu.
Creates tiny Hermes skills for find, jobs, promote, stats. Registers per-agent slashes (/scout, /reader, /adapter) routed to correct profiles. Registers Telegram Bot API command menu. Restarts gateway. Verify every slash from Telegram returns no "Unknown command" errors.
What this does: Final messaging safety check — right person, paid steps gated, everything logged.
Three checks: (1) Only owner's user ID can command Forge; (2) /promote (the only token-spending command) requires explicit yes before running; (3) Forge logs each Telegram interaction. Final test from Telegram: send /stats, confirm reply, check logs + allow-list.
What this does: Runs Find on a schedule and pings you on Telegram only when new matches appear.
scheduled_find.py — runs find-only scan, alerts Telegram only on NEW matches (per job memory). Systemd timer with oneshot service. UI toggle for auto-scan (interval picker). Manual "Scan now" button. Dashboard schedule API. Verifies: enable → timer scheduled → manual run delivers alert.