Node.js security releases (October 2026): update Node to 22.23.4, 24.22.1 or 26.12.1 before you use yokoten
yokoten
Docs What a session sees

The guide

What a session sees

Source: docs/guide.md · v0.1.2

At the start of a session in a project that hasn’t adopted yokoten yet:

yokoten: stage 1 of 5, safety net

  Next      No AGENTS.md, so the agents have no written rules here.

  Why       An agent follows the rules it can read, and only those.

  Fix       `yokoten init`

Tell the user in plain words, one step at a time, and offer to do it (as-is,
lighter, or not now with a reason).

yokoten: ~/.config/yokoten/private-marks is missing or has no marks

  Why       Without your marks, the privacy check knows only email addresses, IP
            addresses and secrets.

  Fix       `yokoten marks add`, then type your name, your city or a domain; it
            is not shown.

  More      https://github.com/yokoten-labs/yokoten/blob/main/docs/guide.md#privacy

The session hears about one step only: the stage, the next step, and why it matters. The second block, about your private marks, shows only while no marks are saved. The stage is worked out from the files each time; nothing saves it. A step you marked “not now” is skipped. The order is advice: a later step done early counts as done. When every step is done or “not now”, the session hears one line that says so. A file missing here but on the default branch is named with that branch, not with init. After Claude Code compacts the context, the session hears only notes that changed. Each session keeps what it heard in ~/.config/yokoten/sessions/, and files older than 7 days are removed. The agent tells you in your own language. yokoten prints English, which agents read most reliably.

yokoten doctor shows the whole road. Each step is done, next, to do, not now (with your reason) or can’t check. Steps that yokoten can’t check yet are not listed:

Stage Steps
1 · Safety net rules, tool-hook, commit-check, runtime, tests (a test command, and CI runs it)
2 · Issues and pull requests remote (the repo is on the code host, and a branch from it is pushed), ci (CI runs check, or uses the yokoten Action), issues (no todo file), templates, labels (the standard set), milestone (an open one), no-build-output (nothing in dist/, build/ or out/, no built binaries)
3 · Release changelog, titles (CI runs check --pr, or uses the Action on pull requests without pr-check: false)
4 · A team of agents codeowners, bot, skills, sandbox (each agent may write the worktree, and nothing wider), review (a merge to the default branch needs one approval)
5 · Going public security-files (a security policy, Dependabot, a license), protection (rulesets on the default branch and v* tags), merge-settings (squash only, delete branch on merge), security-settings (secret scanning, push protection, private reporting, Dependabot alerts)

The last three are server settings. Full doctor reads them through gh api, and only reads. Without gh, a sign-in, the network or a GitHub remote, they are can’t check, never done. A session never calls the network, so there they are always can’t check.

Another host. doctor reads the host from the origin remote. On GitHub it reads the server as above. On Gitea, name the host in yokoten.json ("host": "gitea") and give the bot user a token in GITEA_TOKEN; doctor then reads the branch and tag protection, the labels, the milestones and the forgotten branches through Gitea’s API. gitea.com is recognised without the key. On another host, such as GitLab, the core works the same: the rules, the guard and the commit check. The steps that only the host can judge are tests, ci, labels, milestone, titles, codeowners, bot, review and the three server steps. There each one is can’t check, and says what it asks, so you can set it up by hand. They never hold the stage. A self-hosted server’s name is never printed: doctor calls it “this host”.

labels and milestone in stage 2 are read the same way. The standard labels are bug, feat, docs, refactor, ci, owner, incident, good first issue, hotfix, security, and the tier labels tier A, tier B and tier C. init shows which are missing, and init --github --yes adds them.

review in stage 4 reads the server the same way. It is done when the default branch’s ruleset, or its branch protection, asks for at least one approving review. GitHub does not let you approve your own pull request. So the bot opens the pull requests, and you approve and merge them. To set it up, edit the ruleset on the default branch: in “Require a pull request”, set “Required approvals” to 1. Also keep “Allow GitHub Actions to create and approve pull requests” off, in Settings, Actions, General. If it is on, a workflow the bot pushes could approve the bot’s own pull request, so review is not done. OpenSSF Scorecard should then count each change as reviewed, because the person who merges it did not write it. We read this in the Scorecard docs and have not checked it in a real Scorecard run yet. A private repo on a free plan has no rulesets, so there review is can’t check and waits for stage 5, when the repo goes public. It is not not now: that mark is only for a decision you make.

init --github --yes also adds your own areas from yokoten.json “areas” as labels, in one grey colour. It does this only for 8 areas or fewer: a longer list is noise, so make the few you use by hand. An area label that is there is kept as it is, and yokoten never deletes one.

The board is optional. init --github --yes --board makes one named after the repo and links it. Its Status field gets Todo, In progress, In review and Done. A board needs the gh token’s project scope; without it, init skips the board and says to run gh auth refresh -s project. A second run finds the board by its title and makes nothing. The API can’t set a board’s views or workflows. So when a board is linked, full doctor lists them as “by hand” lines. They never fail doctor.

After a step, yokoten doctor names the outside standard it meets, when there is one, for example ci (Scorecard: CI-Tests). The session message leaves it out.

Record 0004 says why the road looks like this.

This repo walks the same road, so you can see each stage working:

Stage You learn See it here
1 · Safety net rules your agents read, and checks that stop them when rules aren’t enough AGENTS.md
2 · Issues and pull requests every change starts as an issue and merges only when CI passes; labels, milestones, and a board keep track issues, pull requests, the board
3 · Release commit messages that say what changed and why, a changelog, a version number for every release CHANGELOG.md
4 · A team of agents a bot opens pull requests, workers take tasks, a reviewer checks them; only you merge Managing agents like a team
5 · Going public scan every past commit for private data, turn on security settings, protect main security policy

And when an agent tries to push a release tag:

yokoten stopped this: git push --tags pushes tags [release]

  Why       Only the owner decides when to release.

  Instead   Stop and tell the owner: only the owner releases, with the steps in
            How to release; do not look for another way.

  More      https://github.com/yokoten-labs/yokoten/blob/main/docs/guide.md#how-to-release

The refusal is the same for every agent: it tells the agent to stop and let the owner release. The approval way, and the command that starts each agent with it, are in How to release. Muse Code and OpenCode are not known to pass the variable to their hooks, so the owner releases outside them. If Gemini CLI’s strict environment sanitization is on, the variable is dropped, and the owner releases outside Gemini CLI.

Every refusal has the same four parts. The first line says what happened, and ends with the rule id in square brackets, as yokoten stopped this: <what> [<id>]. The Why row says why it matters. The Instead row is the fix, a command or an edit. The More row links to where the rule is explained in full. For a problem in a file, the place comes right after the title: yokoten stopped this: file:line: <what> [<id>]. A hit names the kind of thing it found, never the thing: a secret or a private mark is never printed.

To ask why a rule exists, run yokoten explain <id>. The id is the rule or step name, such as secret or commit-check. With no id, or an unknown one, it lists every id.

$ yokoten explain force-push
force-push: no plain force push (core rule 7).
Why: a plain force push can throw away work that someone else pushed.
Check: the tool-call guard stops `git push --force`, `-f` and a `+ref`; `--force-with-lease` passes; a branch ruleset on the server is the lock.
Docs: https://github.com/yokoten-labs/yokoten/blob/main/docs/guide.md#the-core-rules

Work only on this machine

A power cut, a crash or a dead disk loses work that lives only on one machine. So doctor lists that work, each item with the one command that saves it:

Note What it means The command
uncommitted-changes A worktree has changed files: how many, and how old the oldest is git add -A and git commit -m "chore: save work" there, then push; with .yokoten/, the message is chore: add yokoten, and committing the copy is the point
unpushed-commits A branch has commits that no remote has, or a detached HEAD has commits that no branch holds git push, or git push -u origin <branch> for a branch with no upstream of its own; git switch -c <name> first for a detached HEAD
stashes There are stashes. A stash is never pushed git stash branch <name>, then push it
stale-index-lock An index.lock is left from a crash, and no git process runs in the repo rm the file
repo-on-tmpfs The repo is on a tmpfs, so a restart empties it git push --all origin, then clone it again in a folder that lasts
repo-in-temp-folder The repo is under the temp folder, which the system may empty on restart git push --all origin, then clone it again in a folder that lasts
finished-worktree A worktree with no changes whose branch is merged, or whose upstream is gone, or whose detached HEAD is in the default branch git worktree remove <path>; the branch stays
missing-worktree git still lists a worktree whose folder is gone git worktree prune

A commit that is not pushed is still only on this machine. A branch made from origin/main tracks it, so its commits go to a branch of its own, never to main.

A squash merge leaves no sign in the branch’s history. So a branch whose upstream is gone counts as merged too. A worktree with uncommitted changes is never called safe to remove. A branch, or a detached HEAD, that has not moved since it was made is not called merged: it is new.

For an index.lock, doctor looks for a git process that works in the repo. On Linux it reads each process’s folder. On macOS and Windows it can’t, so any git process means “can’t tell”. Then doctor never says to delete the file. git’s long-running helpers, such as the credential cache, do not count. The tmpfs check reads /proc/mounts, so it runs on Linux only.

The temp folders are the system’s own (TMPDIR, or %TEMP% on Windows) and /tmp. WSL empties /tmp on restart, even though it is not a tmpfs. To check other folders, list them in YOKOTEN_TEMP_DIRS, split like PATH. Set it empty to turn the check off.

The repo itself in such a folder always gets a note: that is a setup problem. A worktree there is named only when it holds work at risk, and then in that work’s own note. For example: “../w has 3 uncommitted files, the oldest changed 2 days ago, and is under the temp folder (/tmp), which the system may empty on restart”. The worktrees there that hold nothing at risk get one line in full doctor, with the count, and none in a session. Each fix says to make worktrees under .worktrees/, never under a temp folder.

All of these are notes: they never fail doctor. Doctor only reads here. It changes no file, no ref and no worktree, and git runs with optional locks off. Paths show relative to the repo, or from ~.

A session hears only what is at risk, three items at most. It hears uncommitted changes only once the oldest is an hour old, because work going on now is not forgotten. Worktrees to tidy up are left to full doctor. When two or more worktrees in the temp folder hold work at risk, one line gives the count first.

A session spends at most one second on this, because a session must not wait on a cold disk. When the time is up, it shows what it read and says “doctor stopped early”. Full doctor has no time limit.