jobissimo
AGENTS.md8 starsChanged 44 days agoMITView on GitHub
Engine operating contract. An LLM agent (built for Claude Code and Codex, runnable by any capable agent) finds postings, scores them for fit, generates truth-audited ATS-optimized applications, tracks outcomes, and improves the pipeline from its own telemetry. Plain-markdown slash commands hold the judgement; a handful of deterministic Python scripts hold anything that must be exact — lifecycle state, truth auditing, ATS scoring, export. The agent never writes SQL; the scripts never make judgement calls. All personal data and generated artefacts…
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,439 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
The file
We split this AGENTS.md into the rules it gives an agent
4 rules. About 0 are common, 0 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 11
All personal data and generated artefacts live under one gitignored workspace root, $JOBISSIMO_HOME (default ./profile, resolved by …
- Very specific: line 74
scripts/db.pyis the only write path to the pipeline DB: Never write SQL, never edit the DB file, never bypass with ad-hoc scripts. - Very specific: line 132
Every config change carries a reason (config.py set --reason).
- Very specific: line 238
Every script keeps --help.
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Jobissimo — Agent-Operated Job-Search Pipeline
Engine operating contract. An LLM agent (built for Claude Code and Codex, runnable by any capable agent) finds postings, scores them for fit, generates truth-audited ATS-optimized applications, tracks outcomes, and improves the pipeline from its own telemetry. Plain-markdown slash commands hold the judgement; a handful of deterministic Python scripts hold anything that must be exact — lifecycle state, truth auditing, ATS scoring, export. The agent never writes SQL; the scripts never make judgement calls.
All personal data and generated artefacts live under one gitignored workspace
root, $JOBISSIMO_HOME (default ./profile, resolved by scripts/paths.py).
Nothing personal is ever committed.
Pipeline map
/setup documents first → extract knowledge → minimum config → first result
↓
/hunt browse: extract JD → score → originate employer URL → record
↓ (status: shortlisted | discarded)
/prepare evidence map → drafts → audit.py (hard gate) → ats_score.py +
LLM rubric → targeted regeneration (max 2) → export.py → ready
↓
/apply assisted browser form-fill from profile + finals (stretch;
NEVER submits autonomously)
↓
/track natural-language outcome updates + mail reconciliation → db.py
→ dashboard (follow-ups live here too)
↓
/optimise events + funnel + run reports + gap_suggestions → evidence-backed
improvement diffs to config/profile/pack (user approves per item)
/enrich answer the highest-impact profile gaps in five minutes
/dashboard read-only views any time: dashboard | stats | list | get
/refresh liveness check on pre-application jobs → closed postings marked
missed (employer-source evidence only; `links` mode for manual pass)
/cycle the scheduled pass: reconcile (track + refresh) → hunt →
prepare the most perishable → one report, daily or weekly
/doctor config health, value provenance, drift detection
python3 scripts/ui.py the local UI (127.0.0.1): overview, applications,
knowledge, pipeline, analytics — reads the same
state, writes only through the scripts belowCommands live in .claude/commands/ (Claude Code slash commands) as plain
markdown — runnable by any LLM agent by reading the file. Each is
self-sufficient given this file + the referenced engine/rules/ files, and
ends with a "Stdout summary" spec. Codex runs the same files through thin
skill wrappers in .agents/skills/<name>/SKILL.md ($hunt,
$prepare <job_id>); the wrappers hold no logic — the command file is the
single source of truth. See docs/codex.md.
Lifecycle status enum
found → scored → discarded | shortlisted → generated → ready → applied →
responded → [offered →] closed (+ on_hold, missed, skipped). Transitions
are validated by db.py; closed takes an outcome
(no_response/rejected/interview/offer_accepted/offer_declined/offer_withdrawn/
withdrawn — withdrawn is the candidate pulling out, offer_withdrawn the
employer taking an offer back). Interview rounds and offer figures live in the
stage ledger (db.py stage add|resolve|list): one row per gate that can be
passed or failed, numbered with no upper limit, plus one row per offer figure.
Invariants (non-negotiable)
- Truth guardrails outrank everything — including ATS score.
engine/rules/truth_guardrails.mdis strict mode: select/rephrase source bullets fromknowledge/, never invent facts, never combine metrics across bullets, never claim unproven skills. A keyword whose evidence-map status isno_evidenceis never inserted into the CV; it goes togap_suggestions.md. scripts/db.pyis the only write path to the pipeline DB. Never write SQL, never edit the DB file, never bypass with ad-hoc scripts.discardedis permanent — it is the dedupe/no-rework record./huntchecksdb.py urls(which includes discarded) before extracting anything.- Audit failures surface to the user for
fix / bypass / halt— never silently fixed. Bypass is recorded inaudit_log.mdand stays a FAIL with override. Truth audit is a hard gate before ATS scoring and export. - No autonomous submission.
/applyhard-stops before submit: filled-form screenshot + field-by-field summary + explicit user confirmation (started from the UI: a question in the run panel; declined or unanswered never submits). Several postings in one run each get their own hard stop. Form answers come only fromapplicant_profile.yaml+ final assets +knowledge/; anything else → ask the user. /optimisenever touches the engine. It proposes changes toconfig/,profile/, and pack overrides — never toengine/,scripts/,.claude/commands/,.agents/skills/,.codex/, orAGENTS.md/CLAUDE.md— and never applies anything without per-item approval. A run that endsabortedorpartialdoes not fix itself either: it appends a proposal toreports/pending_suggestions.md(contract in that file's header) and/optimisetriages it. Runs propose,/optimisereports, the user approves.- Guardrails are engine, never config. Nothing under
config/may weaken the truth audit, make the audit non-blocking, turn a bypass into a pass, or enable autonomous submission. - Evidence-map discipline (
/preparestep 1): REQ rows with explicit_match/implicit_match/no_evidence status,<!-- src:ID -->trace comments on every CV bullet, deterministic validation before finalization.jd_wordingis the compact near-verbatim keyword, not the full sentence. - Assets speak the JD's language (
jd_languageon the job row; seeengine/rules/language_rules.md): CV content, cover letter, and recruiter message in the posting's language; section headers, dates, and skills-inventory names stay canonical English; internal artifacts stay English. Translation never changes a fact, and never exceeds the register the user declared inconfig/languages.yaml. - Workspace state travels as CSV; the database is a local artefact.
state/pipeline.dbis never committed —db.py export-csvwrites the diff-friendly CSV record (jobs/events/stages/id_reservations/meta + manifest) that is, anddb.py import-csvrebuilds the DB./syncis the only thing that commits or moves the workspace; no pipeline command syncs on its own, and divergent pipeline state is never auto-merged (show both sides, user picks). - No workspace-derived fact leaves the workspace — anonymised or not.
Issues, PRs, comments, commit messages and pack exports carry no count,
rate, date, duration, amount or company name taken from the user's
pipeline, profile or config. Stripping names does not anonymise a number:
it is still the user's. Upstream evidence is the engine
file:lineplus a reproduction on the synthetic fixture, with obviously fictional values (round numbers like100000, dates in2030). Real telemetry stays inreports/. Every outbound body goes to a file and throughscrub_check.py --outbound <file>; in Claude Code a PreToolUse hook runs that check on everyghissue/PR write and blocks on a finding. A finding is rewritten, never waived. - The local UI is a front end to the scripts, never around them.
scripts/ui.pyreads throughreadmodel.pyand writes only by callingdb.py,knowledge.pyandconfig.py. It offers no control to submit an application, bypass an audit, force a lifecycle transition, or mark knowledge verified without the user's own accept. Knowledge changes enter through the inbox (knowledge.py propose); an agent proposes, the user accepts —knowledge.py decideruns only on the user's explicit word. Every config change carries a reason (config.py set --reason). Documents the user drags in go throughintake.py --upload. The UI may start a command in the user's own Claude Code or Codex (agent_runner.py): a fixed list with validated arguments, never/sync;/applyonly in Claude Code, where its hard stop is a question in the run panel and only the user's explicit answer submits; runs that touch the same things never overlap. Where a command would ask, the question (or a permission request) goes to the user in the run panel and only the user answers it; an unanswered one times out to the safe default (halt the item, never bypass, never submit, never accept a knowledge item). Edits without asking stop at the workspace. What runs may do without asking is set by the user on the Settings page (agent_setup.py, writing Claude Code's own.claude/settings.local.json).agent_runner.py,agent_setup.py,launcher.pyandui.pyare deliberately off both allowlists, and a run asking to start an agent or change agent settings is refused without asking: an agent never launches another agent or grants itself permissions.
The four-layer config model
Resolution order, last wins. A layer is only written by its owner.
| Layer | Holds | Written by | Committed |
| Engine | scripts, command files, engine/rules/, schemas | maintainers | yes |
| Pack (shipped) | role clusters, ATS lexicons, board catalogue, locale conventions, evaluation rubric | community PR | yes |
| Pack (local) | the same, for a role family no shipped pack covers — lives in <workspace>/packs/<name> and shadows a shipped pack of that name | /setup (forks generic), then the user | no — user's private repo |
| Config | this install's identity, targets, languages, boards, capabilities | /setup, /optimise (with approval) | no — user's private repo |
| Profile | knowledge, positioning, and every generated artefact | the user and the pipeline | no — user's private repo |
A shipped pack is never edited in place. Small deltas land in config/ (same
filenames as the pack: roles.yaml, ats_keywords.yaml, ats_synonyms.yaml,
locales/<code>.yaml) and extend it per term. A whole role family the packs do
not cover becomes a local pack instead — packs.py --fork creates it,
--export scrub-gates it back toward a community PR. Config and
Profile live in the workspace ($JOBISSIMO_HOME, which contains config/) and
are versioned via /sync in the user's own private repo, never this public one;
the shipped config templates live in templates/config/ (see docs/sync.md).
Directory map
| Path | What |
.claude/commands/ | The slash commands (the pipeline logic) |
.agents/skills/ | Codex skill wrappers — one per command, each pointing at its .claude/commands/ file |
.codex/rules/ | Codex command allowlist — mirrors .claude/settings.json (test-enforced) |
engine/rules/ | truth_guardrails, style_and_ats_rules, tailoring_rules, cover_letter_playbook, language_rules, jd_analysis_schema, jd_template |
engine/adapters/ | browse (claude-in-chrome / codex-chrome / playwright / webfetch / manual), mail (gmail-mcp / imap / none), export (pandoc) |
engine/schemas/ | JSON Schema for the config files |
packs/product/ | The reference domain pack (roles, evaluation, ATS lexicons, boards, en/it locales verified + de/fr/es/nl/pt stubs) |
packs/generic/ | Minimal fallback; taxonomy generated at setup |
scripts/ | db.py, audit.py, ats_score.py, export.py, paths.py, packs.py, sync.py, intake.py, competency_map.py, coverage.py, setup_check.py, scrub_check.py, migrate.py, events.py, assets.py, knowledge.py, config.py, readmodel.py, insights.py, ui.py, agent_runner.py, agent_setup.py, launcher.py (all have --help) |
templates/ | ats_reference.docx (clean metadata), knowledge scaffolds, config/*.example.yaml (shipped config templates), workspace.gitignore (written by /sync init) |
config/ (workspace) | GITIGNORED ENTIRELY — identity, targets, languages, boards, capabilities; lives in $JOBISSIMO_HOME, resolved via $JOBISSIMO_CONFIG → <workspace>/config → legacy <repo>/config |
profile/ | GITIGNORED ENTIRELY — $JOBISSIMO_HOME (resolved via $JOBISSIMO_HOME → .jobissimo pointer → default): config/, _intake/, knowledge/, positioning/, competency_map.md, applicant_profile.yaml, setup_state.yaml, jd_texts/, applications/, runs/, reports/, state/pipeline.db (+ state/backup/*.csv, the committed record) |
ui/ | The local UI: static HTML/CSS + vanilla JS modules, no build step, served by scripts/ui.py |
install.sh | macOS/Linux installer: engine + private workspace + the Jobissimo app, then opens it |
fixtures/, tests/ | Synthetic candidate (Sam Rivera) + JDs; offline test suite |
Scripts
python3 scripts/db.py <cmd>— add-job, score, set-status, set-field, list, get, next-id, urls, run-start, log, dashboard, stats, export-csv.run-start --command <cmd>mints the run id and logsrun_start; the agent passes the printed id literally — never a$RUN_IDshell variable. Validates enums and transitions; role clusters and location-fit values validate against pack ∪ config UNION values already in the DB, so imported historical rows never fail. Refuses bad input loudly.python3 scripts/audit.py --folder <app_folder> [--write-log]— truth audit: traces resolve, skills evidenced, no metric recombination, no_evidence terms absent, contact block + date formats.--library <file>audits a generated positioning file at birth. Exit 1 = FAIL.python3 scripts/ats_score.py --folder <app_folder> --jd jd_texts/{id}.md— deterministic 0–100: evidence-map requirement coverage (25+5) and JD-vocabulary extraction (hard 20 / soft 10) via the pack'sats_keywordsats_synonyms(+ locale bridges); plus structure (10), dates (10), quantified bullets (10), title (5), length (3), contact (2). Scorescv_draft.md.
python3 scripts/export.py --folder <app_folder>— runs audit, strips traces to finals, pandoc DOCX viatemplates/ats_reference.docx(+PDF).python3 scripts/db.py runs [--orphans]/asset record|backfill/suggestion add|decide|list— run pairing (a run_start with no run_end is an orphan), asset fingerprints (variant_id= which bullets a CV cites), and the optimiser's suggestion ledger.db.py logchecks actions againstevents.py(warns;--strictrefuses).python3 scripts/knowledge.py propose|decide|list|inbox— the knowledge inbox: the only mechanical write path intoknowledge/master_experience.md. Adeprecatedbullet stays for history; audit.py fails a new CV citing it.python3 scripts/config.py get|set|apply-suggestion— change one existing setting with--reason; logsconfig_changedwith the config revision.readmodel.py(read-only JSON views),insights.py(deterministic diagnostics, Wilson intervals, n ≥ 8),ui.py(the local server),agent_runner.py(runs of a command in the user's own Claude Code / Codex for the UI — questions, permission requests and replies go to the user; transcripts instate/agent_runs/, never synced),agent_setup.py(the Settings page: agent sign-in, connectors, run permissions, tools),launcher.py(open the UI without a terminal: the generated app / app-menu entry, reuse of a running UI, start at login);install.shat the repo root installs engine + workspace + app on macOS/Linux.paths.pyresolves$JOBISSIMO_HOME;packs.pyloads packs + config;intake.pyconverts documents to text;competency_map.py/coverage.pybuild the map + strength ledger;setup_check.pyvalidates config;scrub_check.pyis the PII gate (and pre-commit hook);migrate.pyimports a pre-OSS workspace (shipped, not run).
Quality bar for changes
Every script keeps --help. Every command file ends with a stdout-summary
spec. No command requires the user to remember more than the command name and
a job_id. New ATS keywords/synonyms go through /optimise evidence or a pack
PR, and a synonym must bridge wording only — never claim a neighboring skill.
The offline test suite (tests/) must pass, and scrub_check.py --all must
report zero findings, before anything is committed. An issue or PR body must
pass scrub_check.py --outbound <file> before it is posted (invariant 11).
A change an existing install needs anything for beyond /sync pull — a
schema bump, a one-time command, a moved file — gets an entry in
docs/upgrading.md; tests/test_upgrading.py fails on a schema version
without one and on any command the notes name that no longer exists.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

