{"_id":"@arik_shemesh/yoman","_rev":"2-762699770c569f7ec3bb32024e4c7c13","name":"@arik_shemesh/yoman","dist-tags":{"latest":"0.3.0"},"versions":{"0.2.0":{"name":"@arik_shemesh/yoman","version":"0.2.0","license":"MIT","_id":"@arik_shemesh/yoman@0.2.0","maintainers":[{"name":"arik_shemesh","email":"ninelive@gmail.com"}],"homepage":"https://github.com/ArikShemesh/yoman#readme","bugs":{"url":"https://github.com/ArikShemesh/yoman/issues"},"bin":{"yoman":"cli.js"},"dist":{"shasum":"996a781d1f698a8ec5714bcb17927244b311ff82","tarball":"https://registry.npmjs.org/@arik_shemesh/yoman/-/yoman-0.2.0.tgz","fileCount":12,"integrity":"sha512-p7G5BpyU9vbZTvBgO3xSRnKyEl1wMu+boYjwWZbpjUDNn5EO6N6ckzdlytc1DxvMo5lOHAuofcnuzY4svdxT+g==","signatures":[{"sig":"MEYCIQDQtjk7TiW4uD22gSJc+gsbdcZ/JdSHTxBKkOYugGDW+gIhAL0ZRyKOAyBE7XhnM5L9zUP6KhMxttEWPMbSNaVwnqee","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":27949},"main":"cli.js","gitHead":"c3850c80112f7c556ebfe88ed3495e5ad26cfe73","scripts":{"start":"node cli.js"},"_npmUser":{"name":"arik_shemesh","email":"ninelive@gmail.com"},"repository":{"url":"git+https://github.com/ArikShemesh/yoman.git","type":"git"},"_npmVersion":"10.9.0","description":"Local-first CLI that generates engineering log entries from git history + human-provided intent, via Gemini API.","directories":{},"_nodeVersion":"22.11.0","dependencies":{"dotenv":"^16.4.5","@google/genai":"^1.0.0","@inquirer/prompts":"^7.0.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/yoman_0.2.0_1784523905354_0.31557446280162615","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@arik_shemesh/yoman","version":"0.3.0","description":"Local-first CLI that generates engineering log entries from git history + human-provided intent, via Gemini API.","main":"cli.js","bin":{"yoman":"cli.js"},"repository":{"type":"git","url":"git+https://github.com/ArikShemesh/yoman.git"},"scripts":{"start":"node cli.js","test":"node test/smoke.js"},"license":"MIT","dependencies":{"@google/genai":"^1.0.0","@inquirer/prompts":"^7.0.0","dotenv":"^16.4.5"},"_id":"@arik_shemesh/yoman@0.3.0","gitHead":"e7bf54068dd542a46e0f5e66e3c1cb532178fc40","bugs":{"url":"https://github.com/ArikShemesh/yoman/issues"},"homepage":"https://github.com/ArikShemesh/yoman#readme","_nodeVersion":"22.11.0","_npmVersion":"10.9.0","dist":{"integrity":"sha512-NJ+UoETUBJeuPPt9qeGnjOSKWD7mWG84j1WpSy/9YrHaCSLz2HjsHxKPO6W8cM1sbZmI1+ccYrG5Sq1QBBDOHg==","shasum":"7c91c4ff6508436ed9e9c8fdd6ee4076c5a0327c","tarball":"https://registry.npmjs.org/@arik_shemesh/yoman/-/yoman-0.3.0.tgz","fileCount":15,"unpackedSize":42479,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIFio+dRdLaiyKzWaIAMVkw5ffW7VeYP7fY9BggyQHnRKAiBQFs0EA8p6tim+++vAUS7u9OEJrZBrpDgzevFSS/LuVw=="}]},"_npmUser":{"name":"arik_shemesh","email":"ninelive@gmail.com"},"directories":{},"maintainers":[{"name":"arik_shemesh","email":"ninelive@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/yoman_0.3.0_1784705027605_0.6939258509276578"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-20T05:05:05.251Z","modified":"2026-07-22T07:23:47.918Z","0.2.0":"2026-07-20T05:05:05.510Z","0.3.0":"2026-07-22T07:23:47.749Z"},"bugs":{"url":"https://github.com/ArikShemesh/yoman/issues"},"license":"MIT","homepage":"https://github.com/ArikShemesh/yoman#readme","repository":{"type":"git","url":"git+https://github.com/ArikShemesh/yoman.git"},"description":"Local-first CLI that generates engineering log entries from git history + human-provided intent, via Gemini API.","maintainers":[{"name":"arik_shemesh","email":"ninelive@gmail.com"}],"readme":"# yoman\n\n[![npm](https://img.shields.io/npm/v/@arik_shemesh/yoman)](https://www.npmjs.com/package/@arik_shemesh/yoman)\n[![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n\n**A development log your team will actually trust, because the \"why\" comes from you, not a guess.**\n\nEvery \"AI changelog\" tool reads a diff and invents a reason for it. That reason is always a hallucination - a diff shows *what* changed, never *why*. yoman flips the pipeline: it asks you for your reasoning at the moment the milestone happens, captures it verbatim, and only then lets the model use the diff as supporting evidence to write up the rest.\n\nLocal-first CLI. Your repo, your `DEVELOPMENT_LOG.md`, the Gemini API doing the write-up - nothing else in the loop.\n\n## See it work\n\nThis is a real, unedited entry from this project's own log, generated by running `yoman` after a milestone:\n\n> **2026-07-19 - Flush pending queue before new runs; add README and CLAUDE.md**\n>\n> **Stated intent:** Asked what happens if a failed run is followed by plain yoman instead of retry, and found a real duplicate-entry and state-regression bug. Chose flush-first over post-run auto-flush so overlapping ranges can never form, plus a stale-item guard as cheap insurance.\n>\n> **Summary:** Implemented a flush-first mechanism in the main command flow that processes any queued items in `pending.json` before a new run is calculated. Added a stale-item check using a new git ancestry utility to drop queued entries that have already been journaled...\n\nThe first paragraph is what the human typed. Everything after it is the model, working only from that intent plus the diff. Full entry in [DEVELOPMENT_LOG.md](DEVELOPMENT_LOG.md).\n\n## How\n\n1. `yoman` shows you the commits since your last journal entry.\n2. You pick a title, then type **why** - free text, mandatory, no skipping.\n3. Your intent gets saved to disk *before* any network call, so a failed API request never loses what you typed.\n4. Gemini receives your stated intent + commit messages + a secret-filtered diff, and is explicitly told your intent is the only source of motivation - the diff is evidence of *what* changed only.\n5. You review the generated entry before it's written: accept, regenerate with a steering note, or abort.\n\n## Quickstart\n\n```\nnpm install -g @arik_shemesh/yoman\n```\n\nAdd your Gemini key next to the install (`.env`, gitignored):\n\n```\nGEMINI_API_KEY=your-key-here\n```\n\nInside the repo you want to journal:\n\n```\nyoman init   # sets up .yoman/ + DEVELOPMENT_LOG.md\nyoman        # journal commits since the last entry\n```\n\nSee [Install](#install) below for installing from source with `npm link`.\n\n## Table of contents\n\n- [Install](#install)\n- [Updating](#updating)\n- [Usage](#usage)\n- [Nag hook](#nag-hook)\n- [What gets sent to the LLM, and what doesn't](#what-gets-sent-to-the-llm-and-what-doesnt)\n- [Config](#config)\n- [Not yet included](#not-yet-included)\n- [Project layout](#project-layout)\n\n## Install\n\nFrom npm:\n\n```\nnpm install -g @arik_shemesh/yoman\n```\n\nOr from source:\n\n```\ngit clone https://github.com/ArikShemesh/yoman.git\ncd yoman\nnpm install\n```\n\nCreate a `.env` file next to `cli.js` with your Gemini API key:\n\n```\nGEMINI_API_KEY=your-key-here\n```\n\n`.env` is gitignored - never committed.\n\n### Global command\n\nRun once inside the cloned yoman folder:\n\n```\nnpm link\n```\n\nThis puts a `yoman` command on your PATH, so every command below is just `yoman`, `yoman init`, `yoman status`, etc.\n\n## Updating\n\n```\ncd /path/to/yoman\ngit pull\nnpm install   # only if dependencies changed\n```\n\nNothing else: `npm link` is a symlink to the clone, so pulled code is live everywhere immediately. New config defaults reach existing repos automatically - a `.yoman/config.json` without a newly added key just gets that key's default; add the key to the file only to override it. Installed hooks keep working untouched (they only call `yoman nag`; all logic lives in the clone).\n\n## Usage\n\nRun these from inside the git repo you want to journal (not from the yoman folder itself, unless you're journaling yoman's own history):\n\n```\nyoman init\n```\n\nCreates `.yoman/config.json` and `.yoman/state.json` in the current repo, and `DEVELOPMENT_LOG.md` if it doesn't exist yet. Safe to re-run - refuses to overwrite and prints the current state instead.\n\n```\nyoman\n```\n\nThe main command. Run it after finishing a milestone (one commit or several):\n\n1. Shows the commits since the last journal entry.\n2. Asks you to pick a title (derived from commit messages) or type your own.\n3. Asks **why** you made the change - free text, mandatory. Under ~15 words, it asks once more for more context, then accepts whatever you give it.\n4. Sends your stated intent + the commit messages + a secret-filtered diff to Gemini, and prepends a new entry to `DEVELOPMENT_LOG.md` (newest entry first).\n\nIf the API call fails (bad model name, rate limit, network), your title/why/commit-range is saved to `.yoman/pending.json` - nothing is lost. Fix whatever broke and run:\n\n```\nyoman retry\n```\n\nThis flushes everything queued in `.yoman/pending.json`.\n\nBefore anything is written, yoman shows the generated entry and asks: accept, regenerate (optionally with a steering note like \"shorter\" or \"focus on the refactor\"), or abort. Abort keeps your input queued for `yoman retry`. Set `\"preview\": false` in `.yoman/config.json` to skip the preview and write immediately.\n\nGot a weak entry into the log anyway? Fix the newest one:\n\n```\nyoman amend\n```\n\nKeep or replace the title and the stated intent, regenerate, review, accept - same SHA range, same date, older entries untouched.\n\nRebased or amended commits after journaling? `yoman` and `yoman status` will refuse with a clear message instead of guessing; run:\n\n```\nyoman reset\n```\n\nto re-anchor the journal state at the current HEAD (confirms first; skipped commits stay unjournaled).\n\n## Nag hook\n\nForgetting to journal is the default failure mode. Install a reminder per repo:\n\n```\nyoman hook\n```\n\nThis adds a `post-commit` hook that prints one line once you have `nagThreshold` (default 5) unjournaled commits - and stays silent otherwise. It never blocks or breaks a commit: any yoman error is swallowed. If your repo manages hooks via `core.hooksPath` (husky etc.), yoman refuses to touch the managed directory and prints the line to add manually.\n\n`yoman status` shows where you stand any time: model, unjournaled commits, pending queue.\n\n## What gets sent to the LLM, and what doesn't\n\n- Sent: commit subjects, a filtered diff, your stated intent, the entry date (the day the milestone was recorded).\n- Never sent: anything matching `.env`, `.env.*`, `*.pem`, `*.key`, `*credentials*`, `*secret*`, lockfiles (`package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`), the `.yoman/` directory, or the log file itself.\n- The prompt explicitly instructs the model that your stated intent is the *only* source of truth for motivation - the diff is evidence of *what* changed, never *why*. If no rationale was stated, the entry says \"Rationale not recorded\" instead of guessing.\n- The \"Stated intent\" line in every log entry is your verbatim text, assembled by the code - never something the model is trusted to reproduce or paraphrase.\n\n## Config\n\n`.yoman/config.json` (created by `init`, per-repo):\n\n```json\n{\n  \"model\": \"gemini-flash-latest\",\n  \"logFile\": \"DEVELOPMENT_LOG.md\",\n  \"minWhyWords\": 15,\n  \"diffCharLimit\": 20000,\n  \"nagThreshold\": 5,\n  \"preview\": true\n}\n```\n\nEdit freely - e.g. swap `model` if Gemini retires/renames one (this happens; the tool maps 404s to a clear \"update your config\" message instead of a stack trace).\n\n`.yoman/state.json` tracks `lastSha` - the last commit journaled. Commit both `.yoman/` and your log file to your repo so state travels with it.\n\n## Not yet included\n\nDeliberately deferred:\n\n- No npm registry publish (global command is via `npm link` only)\n- No other LLM providers (Gemini only)\n- No log splitting or cross-entry narrative continuity\n\n## Project layout\n\n```\ncli.js              entry point, command dispatch (init / run / retry / status / hook / amend / reset)\nsrc/\n  config.js          .yoman/config.json load/validate + .env key\n  state.js            .yoman/state.json (lastSha) read/write\n  git.js               commit list, filtered diff, secret-path exclusion\n  titles.js            local (non-AI) title candidates from commit subjects\n  prompt.js            hallucination-guarded prompt construction\n  llm.js               Gemini API call + friendly error mapping\n  log.js                prepend entry to DEVELOPMENT_LOG.md with SHA-range anchor\n  pending.js            save-before-call queue (.yoman/pending.json)\n  review.js             entry preview loop (accept / regenerate / abort)\n  amend.js              regenerate the latest entry (same range, same date)\n  ask.js                shared why prompt with thin-context re-ask\n```\n","readmeFilename":"README.md"}