{"id":51123437,"url":"https://github.com/joseym/aarg","last_synced_at":"2026-06-25T05:01:37.708Z","repository":{"id":365326465,"uuid":"1271359891","full_name":"joseym/aarg","owner":"joseym","description":"Local-first Rust CLI that tailors your resume to a job posting through an adversarial agent loop, and never invents experience you don't have.","archived":false,"fork":false,"pushed_at":"2026-06-16T21:20:00.000Z","size":510,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-16T22:28:03.936Z","etag":null,"topics":["ai-agents","anthropic","ats","cli","job-search","llm","local-first-ai","pdf","resume","resume-builder","rust","typst"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/joseym.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-16T15:29:14.000Z","updated_at":"2026-06-16T21:20:05.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/joseym/aarg","commit_stats":null,"previous_names":["joseym/aarg"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/joseym/aarg","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joseym%2Faarg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joseym%2Faarg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joseym%2Faarg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joseym%2Faarg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joseym","download_url":"https://codeload.github.com/joseym/aarg/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joseym%2Faarg/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34760219,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-25T02:00:05.521Z","response_time":101,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","anthropic","ats","cli","job-search","llm","local-first-ai","pdf","resume","resume-builder","rust","typst"],"created_at":"2026-06-25T05:01:36.999Z","updated_at":"2026-06-25T05:01:37.691Z","avatar_url":"https://github.com/joseym.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AARG: The Adversarial Agentic Resume Generator\n\nAARG tailors your résumé to a specific job posting and then argues with itself\nabout the result. A skeptical reviewer agent reads each draft the way a hiring\nmanager looking for reasons to pass would, files specific objections, and a\ntailoring agent revises against them under tight bounds, keeping the best draft\nit finds rather than the last. The output is two PDFs built with\n[Typst](https://typst.app): a plain, parser-safe one to upload, and a designed\none to hand a person.\n\nIt runs on your machine, against your own career data, and it will not invent\nexperience you don't have. That last part is the whole point, and it's enforced\nin three places rather than promised in one.\n\n\u003e **Status:** working end to end. Ingest, tailoring, the adversarial loop, both\n\u003e résumé variants, history/diff, and an interactive shell all work today.\n\u003e Anthropic is the supported model provider; a fully-local one is on the\n\u003e roadmap, not in the box yet.\n\n## Demo\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/demo.gif\" alt=\"aarg ingesting a resume, tailoring it to a posting through the adversarial loop, and exporting the PDFs\" width=\"820\"\u003e\n\u003c/p\u003e\n\nA full run on a fictional candidate and posting: ingest a résumé into a\nstructured dataset, then `tailor` parses the job, analyzes the gap, drafts, and\nworks the review-and-revise loop, keeping the best draft rather than the last,\nbefore rendering both PDFs and exporting them under friendly names.\n\n## The loop, briefly\n\n1. `ingest` turns an existing résumé into a structured **dataset**: roles,\n   bullets, and skills, each tied to evidence.\n2. `tailor \u003cjob\u003e` parses the posting, runs a **gap analysis** against your\n   dataset, and writes a first draft that mirrors the posting's language without\n   overstating what you've actually done.\n3. The **adversarial reviewer** scores the draft on content and on deterministic\n   keyword coverage, then files objections: no metric, vague verb, unsupported\n   claim, and so on.\n4. The tailoring agent **revises** against those objections and re-scores. A\n   revision that doesn't improve the score is discarded and the loop stops; the\n   build keeps the best draft it ever saw.\n5. The winner renders to an **ATS** PDF and a **human** PDF (same facts,\n   different presentation), and every iteration is written to disk so you can\n   inspect or diff it later.\n\nWhen an objection can't be satisfied without lying (\"this bullet states an\noutcome with no number\"), the loop stops guessing and asks you. A short\ninterview folds your real figures back into the dataset, then re-tailors. The\nmachine revises what it can revise honestly; you supply the facts it is\nforbidden to invent.\n\nThe full write-up is in [docs/design/adversarial-loop.md](docs/design/adversarial-loop.md).\n\n## It won't make things up\n\nEvery skill, date, employer, and number in the output traces to evidence in your\ndataset. This is structural, not a request the model is trusted to honor:\n\n- **At the type level.** A skill with no backing evidence fails validation and\n  never reaches a draft.\n- **In assembly.** The model speaks in evidence IDs; a number it introduces that\n  the source bullet doesn't contain is reverted, and an unbacked skill is\n  dropped. The same checks run on the first draft and on every revision, because\n  both go through the same code.\n- **At review.** The reviewer flags unsupported claims, and a separate lint\n  refuses to ship the build if the two PDFs ever diverge on what they claim.\n\nKeyword-coverage gaps, where the posting wants something you didn't surface, are\nreported to you and stop there. They never feed back into a prompt, which closes\nthe obvious backdoor where an ATS miss turns into an invented bullet.\n\n## Getting started\n\n### Prerequisites\n\n- **Rust 1.89 or newer** (2024 edition).\n- **[Typst](https://github.com/typst/typst)** on your `PATH`; rendering shells\n  out to it. A missing binary fails with install instructions, not a panic.\n- An **Anthropic API key**, or a Claude Pro/Max subscription (see\n  [Authentication](#authentication)).\n\n### Install\n\n```sh\ngit clone git@github.com:joseym/aarg.git\ncd aarg\ncargo install --path .\n```\n\n### A first run\n\n```sh\naarg init                  # set up a workspace here, store your key in the OS keychain\naarg ingest resume.pdf     # build your dataset from an existing résumé (text, Markdown, or a text-layer PDF)\naarg tailor job.txt        # parse, gap-analyze, tailor, review, revise, render\n```\n\n`tailor` writes `resume.ats.pdf` and `resume.human.pdf` into the build directory\nand prints where they landed, the reviewer's verdict, keyword coverage, and what\nthe run cost. Run `aarg` with no arguments to drop into an interactive shell that\ntakes the same commands without the prefix.\n\nYou don't have to keep job postings in files. `tailor` and `gap` also accept a\nGreenhouse/Lever URL or `-` for stdin, and with no argument at all they let you\npaste a posting in or reuse one you've already entered.\n\n## Authentication\n\nKeys live in your OS keychain, never in a config file. `aarg init` walks you\nthrough it; `aarg key add|use|remove|list` manages more than one.\n\n```sh\naarg key add work          # an Anthropic API key, filed under a label\naarg key use work\n```\n\nYou can also authenticate against a Claude **subscription** rather than\npay-as-you-go billing, either by pasting a token from `claude setup-token` or by\ndelegating to the official `ant` CLI so it refreshes for you. Subscription auth\nis **experimental**: Anthropic scopes plan credit to its own tools, so the\nAPI-key path is the supported one. For headless or CI use, set `ANTHROPIC_API_KEY`\n(or `ANTHROPIC_AUTH_TOKEN`) and skip the keychain entirely.\n\n## Commands\n\n| | |\n|---|---|\n| `aarg init` | create a workspace and store a key |\n| `aarg ingest \u003cfile\u003e` | build your dataset from a résumé (text, Markdown, or a text-layer PDF) |\n| `aarg tailor [job]` | the adversarial loop, end to end |\n| `aarg chat [job]` | ask about a posting and how your background fits it |\n| `aarg gap [job]` | compare a posting against your dataset |\n| `aarg dataset show \\| validate \\| edit` | inspect and correct your data |\n| `aarg skills verify \\| dedup` | back unverified skills, collapse duplicates |\n| `aarg roles enrich [id]` | flesh out thin roles with a short interview |\n| `aarg voice add \\| list \\| remove` | writing samples that steer phrasing |\n| `aarg cover [build]` | draft a cover letter for a past build |\n| `aarg render [build]` | re-render a build's PDFs without re-tailoring |\n| `aarg export [build] [--to \u003cdir\u003e]` | copy a build's PDFs out under friendly company names |\n| `aarg attack [build]` | re-review a saved build without re-tailoring |\n| `aarg history` / `aarg diff \u003ca\u003e \u003cb\u003e` | list past builds, compare two |\n| `aarg templates list \\| use \u003cname\u003e` | choose a résumé template |\n| `aarg trace last \\| show \u003cid\u003e` | inspect recorded agent runs |\n\nTwo ATS templates (`classic`, `minimal`) and three human ones (`modern`,\n`technical`, `editorial`) ship built-in; point `tailor --template \u003cfile.typ\u003e` at\nyour own to render the human variant however you like.\n\n## How it's built\n\n**AARG** is a Rust workspace: an `aarg` binary over an `aarg-core` library. The\nlibrary is the agent runtime, and it's the part of this repo most worth reading.\n\n```mermaid\nflowchart TB\n    subgraph bin[\"aarg · binary\"]\n        direction TB\n        CLI[\"CLI frontend\u003cbr/\u003eclap commands · reedline REPL · inquire prompts\"]\n        ORCH[\"Orchestrator\u003cbr/\u003eroutes commands · human-in-the-loop · drives the adversarial loop\"]\n        AGENTS[\"Agents\u003cbr/\u003ejd parser · gap · tailor · adversarial reviewer\u003cbr/\u003evariant adapter · voice · skill / role / metric interviews\"]\n        SERVICES[\"Services · deterministic, no LLM\u003cbr/\u003edataset store · Typst renderer · ATS coverage · readability · history / diff\"]\n        CLI --\u003e ORCH\n        ORCH --\u003e AGENTS\n        ORCH --\u003e SERVICES\n    end\n    subgraph core[\"aarg-core · library · the agent runtime\"]\n        direction TB\n        RUNTIME[\"trait Agent · AgentContext · Tool · Tracer\u003cbr/\u003evalidation-retry · cost accounting · cancellation\"]\n        CLIENTS[\"LLM clients\u003cbr/\u003eAnthropic + scripted Mock, hand-rolled on reqwest\u003cbr/\u003ebehind a two-method LlmClient trait · Ollama planned\"]\n        RUNTIME --\u003e CLIENTS\n    end\n    AGENTS --\u003e RUNTIME\n```\n\nThere's no agent framework underneath. The Anthropic client is written directly\nagainst the HTTP API, behind a small trait with a scripted mock, so the whole\nthing tests without a network or a key.\n\n### The runtime was extracted, not designed up front\n\nThis is the part the commit history is meant to show. Phase 1 shipped three\nmodel-backed features (JD parsing, gap analysis, tailoring) as plain `async`\nfunctions, with their prompt assembly, schema-validated parsing,\nretry-on-bad-output, and cost accounting honestly duplicated. By the third, what\nthey shared was obvious. Phase 2 lifted a single generic `Agent` trait out of\nthose three working cases in one reviewable diff, and the adversarial loop and\nthe keyless eval harness then came almost for free, because every agent speaks\none contract. New abstractions arrive when a second consumer does, not in\nanticipation of one.\n\nThe reasoning behind the trait, and the alternatives weighed against it, is in\n[docs/design/agent-runtime.md](docs/design/agent-runtime.md). The convergence\nproblem the loop solves, and the score-must-improve gate that keeps it from\noscillating, is in [docs/design/adversarial-loop.md](docs/design/adversarial-loop.md).\n\nDeterminism stays out of the model wherever it can. ATS keyword coverage and\nreadability are pure code, not agents, so the facts the score leans on can't be\ntalked around.\n\n## Roadmap\n\n**Done and working**: the tailor/review/revise loop, both résumé variants with the\nclaim-divergence lint, gap analysis, the skills/roles/metric interviews, voice\nrewriting, cover-letter generation (`aarg cover` or `tailor --cover`), history and\ndiff, templates, résumé ingestion from text-layer PDFs, an interactive Q\u0026A about a\nposting (`aarg chat`), exporting finished PDFs under friendly company names\n(`aarg export`), the REPL, and experimental subscription auth.\n\n**Not there yet**: a fully-local model provider (the client trait and\nper-agent model tiers are already in place for it to slot into), and an\nexperimental vision pass that reads the rendered layout the way a recruiter\nskims it.\n\n## License\n\nDual-licensed under either [Apache 2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT),\nat your option.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoseym%2Faarg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoseym%2Faarg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoseym%2Faarg/lists"}