---
title: "What a session sees"
description: "「What a session sees」：yokoten 使用指南的一章。"
canonical: https://yokoten.app/zh-tw/docs/guide/what-a-session-sees
lang: en
source: https://github.com/yokoten-labs/yokoten/blob/v0.1.2/docs/guide.md
ref: "v0.1.2"
---

> For AI agents: the documentation index is at https://yokoten.app/llms.txt. To set up yokoten in a project, follow https://yokoten.app/agents.md.

> 這一頁還沒有繁體中文版，下面是英文原文。

# What a session sees

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](https://github.com/yokoten-labs/yokoten/blob/v0.1.2/docs/records/0004-the-road.md) 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](https://github.com/yokoten-labs/yokoten/blob/v0.1.2/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](https://github.com/yokoten-labs/yokoten/issues?q=is%3Aissue), [pull requests](https://github.com/yokoten-labs/yokoten/pulls?q=is%3Apr), [the board](https://github.com/orgs/yokoten-labs/projects/1) |
| **3 · Release** | commit messages that say what changed and why, a changelog, a version number for every release | [CHANGELOG.md](https://github.com/yokoten-labs/yokoten/blob/v0.1.2/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](https://yokoten.app/zh-tw/docs/guide/managing-agents-like-a-team.md) |
| **5 · Going public** | scan every past commit for private data, turn on security settings, protect `main` | [security policy](https://github.com/yokoten-labs/yokoten/blob/v0.1.2/.github/SECURITY.md) |

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](https://yokoten.app/zh-tw/docs/guide/the-core-rules.md#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.

---

上一章: [Three checks and a lock](https://yokoten.app/zh-tw/docs/guide/three-checks-and-a-lock.md)
下一章: [Four layers](https://yokoten.app/zh-tw/docs/guide/four-layers.md)
