diff --git a/README.en.md b/README.en.md index 0500da7..65128e9 100644 --- a/README.en.md +++ b/README.en.md @@ -4,52 +4,81 @@ [![CI](https://github.com/yktsnet/dotfiles-public/actions/workflows/ci.yml/badge.svg)](https://github.com/yktsnet/dotfiles-public/actions/workflows/ci.yml) -This repository is a personal development environment for handing development to AI agents, published with its full configuration as a working example of placing the rules to be followed in the environment (Nix, Claude Code deny rules and hooks, skills) rather than in documents. +When developing with AI agents, the bottleneck moves from generating code to verification and conveying intent. +This repository publishes the personal development platform built on that premise, as code, together with its Nix configuration, the machinery that separates roles, and its skills. The rules to be followed are not left to documents but placed in the environment (Nix, Claude Code deny rules and hooks, skills). The parts that carry over to team repositories are packaged separately in [sdlc-kit](https://github.com/yktsnet/sdlc-kit); this is the environment where those practices actually run. --- ## Why -Now that AI writes the code, the time goes not into writing but into confirming that what was written can be trusted. Agents are confidently and quietly wrong, and left alone they carry destructive operations and secret leaks straight into production. A promise that people will be careful eventually becomes an empty formality. +Now that AI writes the code, writing is no longer where the time goes. Two things remain. -So removing environment differences, blocking destructive commands, and isolating secrets are fixed in code and configuration, with a human merge as the final gate. Only "what must not break" is decided by a human and approved in writing; implementation and tests are left to the agents. When a promise is broken, a machine detects it and stops, so nobody has to sit and watch. +The first is **verification**: it takes time to confirm that what was written can be trusted. Agents are confidently and quietly wrong, and left alone they carry destructive operations and secret leaks straight into production. A promise that people will be careful eventually becomes an empty formality. + +The second is **conveying intent**: conditions missing from a request get filled in by the agent's own inference, and it still finishes something that runs. Because it runs, the gap is easy to miss. Decisions that used to be made inside the implementer's head now have to be written down outside the code and handed over before implementation starts. + +So this platform **does not assume a human who stays attentive**. Removing environment differences, blocking destructive commands, and isolating secrets are fixed in code and configuration, with a human merge as the final gate. The human decides only "what must not break" and approves it in writing; implementation and tests are left to the agents. When a promise is broken, a machine detects it and stops, so nobody has to sit and watch. The human's job moves from writing code to approving promises. --- -## Design +## Principles -Rules are sorted by where they live. Rules that apply every time go in CLAUDE.md, procedures and criteria whose trigger can be stated as "when doing X" go in skills, and anything that must not be crossed goes in the `settings.json` deny list and hooks. All of it is then distributed through Nix, so the same rules apply in any repository on any machine. +The machinery is stacked in the following order. -### One Toolchain on Every Machine +1. **Decide the type before building** +2. **Put prohibitions in mechanisms, not requests** +3. **Place knowledge where it is read** +4. **Approve the promises first** +5. **Separate deciding from building** -One flake manages the macOS and Linux development machines. When tools or versions differ between machines, agents stall on commands that are not found or fail at runtime. +The order has dependencies. Until the type is decided, what to block cannot be decided. Adding knowledge without blocks only speeds up accidents. Splitting the work before the guarantees are settled leaves the executor running without knowing what it must not break. -| Configuration | OS | Role | -|---|---|---| -| `linux-desktop` | NixOS (disko / SSD) | Primary dev machine. Where consultant chat and `issue` are launched | -| `macbook` | macOS (nix-darwin) | Shares the home-manager layer with the Linux machine | +**The minimum is steps 1–3**, needed regardless of whether anything is published or how large the team is. Steps 4–5 are added when there is something published, or when several sessions start running in parallel. -OS differences are confined to `pkgs.stdenv.isDarwin` on the Nix side and to the shims in `os.sh` (`_is_darwin`, `_sed_i`, `_open`, `_linux_only`) on the shell side; everything else is the same file on both. When an agent reaches for `brew` or `npm -g`, `block-non-nix-install.sh` stops it and points to the Nix procedure ([nix-tool-install](.claude/skills/nix-tool-install/SKILL.md)). +--- + +## Design + +### 1. Decide the Type Before Building -### Blocks Are Mechanisms, Not Requests +A new repository is classified before anything is written. [repo-standardize](.claude/skills/repo-standardize/SKILL.md) decides the repository type and its verification means, `settings.json`, and the CLAUDE.md skeleton; [repo-readme](.claude/skills/repo-readme/SKILL.md) decides the kind of README (a demonstration to show, an experiment to measure, or a tool to use); [module-dev](.claude/skills/module-dev/SKILL.md) decides the boundaries and demo approach of a module-type repository. + +The type comes first so that later rules can be derived from it. Once the verification means are fixed, the contents of CI and the deny list follow; once the kind of README is fixed, the minimum set of sections follows. + +### 2. Put Prohibitions in Mechanisms, Not Requests `rebuild` commands, edits to `flake.lock`, `ssh`, and reading or writing the secrets mapping are closed off by deny rules. Deny rules only match string prefixes, so anything that has to be judged as an action, such as a path-qualified `/tmp/venv/bin/pip install` or rewriting `~/.claude` through `sed -i`, is handled by [PreToolUse hooks](.claude/hooks/). Each hook's rejection message states both why it stopped and the correct route. A rejected agent tries something else, and what it tries comes from the message, so it takes the route written there. `static-check.sh`, which syntax-checks the single file right after each edit, follows the same idea: it takes a check that nobody would notice being skipped out of the model's discretion. -### One Source for Every Session +### 3. Place Knowledge Where It Is Read + +Rules are placed according to when they are read. Rules that apply every time go in CLAUDE.md, procedures and criteria whose trigger can be stated as "when doing X" go in skills, and anything that must not be crossed goes in deny rules and hooks. If "which file to give the AI, and when" stays as someone's tacit knowledge, the AI cannot reproduce the operation on its own. So procedures become skills, each declaring its trigger in its description. The workflows covered in the following sections (`new-issue`, `guarantee-audit`, and others) are committed in this same form. The placement criteria live in [skill-dev](.claude/skills/skill-dev/SKILL.md). + +Skills split into those that carry **judgment**, whose answer changes per repository, and those that carry **routine**, which can be applied mechanically once decided. How to write a README, how to cut a module, and whether to draw a diagram are the former; scaffolding, CI, the guarantee ledger, and the Issue format are the latter. When many repositories run in parallel, the cost paid on judgment governs throughput. Whatever can be turned into routine is moved there, leaving human time only where judgment is needed. + +As rules accumulate, they start to contradict each other. CLAUDE.md, skills, and persistent memory are all "rules written by people and read by AI," with no way to detect their own contradictions. [consolidate-rules](.claude/skills/consolidate-rules/SKILL.md) periodically audits only what changed since the last inventory point (a one-line anchor in `.claude/RULES.md`), and when the model generation changes it also checks for model-specific rules that have gone stale. Persistent memory has no index; it lives directly under `~/memory/`, one fact per file (kept at a granularity where `ls` is the index). + +### 4. Approve the Promises First -The settings, hooks, and skills in `.claude/`, together with `home-manager/config/claude/common.md`, are the source of truth. `home-manager/modules/claude.nix` copies them into `~/.claude` on every rebuild. Since `~/.claude` is a generated artifact, `block-live-claude-config-edit.sh` rejects direct edits there and returns the source path instead. +Tests are the device by which the executor notices on its own that it broke something. What must not break (the guarantees) is approved by a human in the Issue's guarantee section, and the tests that turn it into something executable are written by the executor. This division of labor is called **Guarantee-Driven Development (GDD)**. If TDD is the discipline of writing tests first, GDD is the discipline of approving the promises first. -As rules accumulate, they start to contradict each other. [consolidate-rules](.claude/skills/consolidate-rules/SKILL.md) audits only what changed since the last inventory point (a one-line anchor in `.claude/RULES.md`). Persistent memory lives directly under `~/memory/`, one fact per file, and `memory.nix` puts it on the git path so every machine sees the same set. +Approved guarantees accumulate in each repository's guarantee ledger, `docs/guarantees.md`. The ledger lists only contract-surface guarantees (public API, CLI, externally observable behavior) that tests back up. Behavior not in the ledger is not a promise and may change without notice. The ledger is maintained as follows. -### Deciding and Building Are Separate +- **Laying it down**: [guarantee-audit](.claude/skills/guarantee-audit/SKILL.md) extracts guarantees from existing tests and lays down the ledger after the user approves it. Guarantees that should exist but have no test are recorded separately in a Gaps section +- **Keeping up**: from then on, tests and ledger are updated in the same PR as the Issue's guarantee section. The executor's procedure ([pr-workflow](.claude/skills/pr-workflow/SKILL.md)) treats a missing ledger update as unfinished work +- **Matching the scope**: before committing, the executor confirms that the list of staged files exactly matches the Issue's `対象` (targets) field. A change that strays outside the declared scope never reaches a commit +- **Seeing it all**: the ledger stays in each repository as the source of truth, while a scheduled job gathers links to every repository that has one into a single index, so whoever approves can see what is being promised across the board + +Development runs in two phases, handing over the driving documents. In the launch phase, before the direction is settled, work is implemented directly while PLAN.md (remaining work) and JUDGE.md (design decisions) grow alongside it ([mvp-docs](.claude/skills/mvp-docs/SKILL.md)). Once the guarantee ledger goes into formal use, the repository moves to the Issue-driven phase and is run on the ledger and tests from then on. Each repository declares its phase in its CLAUDE.md. The full idea is in sdlc-kit's [docs/lifecycle.md](https://github.com/yktsnet/sdlc-kit/blob/main/docs/lifecycle.md). + +### 5. Separate Deciding from Building When the same model both decides and builds, it cannot notice on its own that it has gone off course. The work is split into three roles. -- **Consultant**: designs the spec and the Issue in dialogue with the user. Does not implement ([new-issue](.claude/skills/new-issue/SKILL.md)) -- **Executor**: takes an Issue and carries it through implementation, tests, and a local commit. Never touches the remote ([pr-workflow](.claude/skills/pr-workflow/SKILL.md)) +- **Consultant**: investigates and designs the Issue in dialogue with the user. Does not implement ([new-issue](.claude/skills/new-issue/SKILL.md)) +- **Executor**: takes an Issue and carries it through implementation, tests, static checks, and a local commit. Never touches the remote ([pr-workflow](.claude/skills/pr-workflow/SKILL.md)) - **User**: approves the Issue's guarantee section, reviews the commits, and publishes them ```mermaid @@ -68,9 +97,37 @@ flowchart TD R -->|issue-finish| P ``` -The executor stops at a local commit, and the only way out to the remote is the user's `issue-finish`. `issue` creates a worktree and launches the executor, so several Issues can run in parallel. The executor's changes are reviewed line by line in [crit](https://github.com/tomasz-tomczyk/crit). +Role boundaries are handed over through zsh functions. + +- **`issue-open`**: moves an Issue whose guarantee section has been approved from `draft` to `open` +- **`issue`**: picks an `open` Issue, creates a worktree, and launches the executor, leaving the main checkout untouched +- **`issue-abort`**: discards an in-progress worktree together with its branch +- **`issue-finish`**: pushes the reviewed branch, opens the PR, merges it, and cleans up in one go + +The only way out to the remote is the user's `issue-finish`. The executor's changes are reviewed line by line by opening [crit](https://github.com/tomasz-tomczyk/crit) inside the executor's own session, and review comments go back to that session to be fixed. Worktrees are isolated, so the machinery could run Issues in parallel, but they are implemented one at a time: working in series is what makes the user's review and approval hold. + +Three exceptions keep the separation from becoming rigid: incident response that cannot be designed as an Issue in advance, one-off exceptions the user explicitly declares, and a lightweight path that lets small changes touching neither logic nor the guarantee ledger through without an Issue. + +In practice, several consultant sessions and worktrees run at once, and none of them can notice its own drift, for the same reason. The reader standing outside them is [session-nudge](.claude/skills/session-nudge/SKILL.md), launched with `M-m`. It reads another session's exchange and drafts advice, which is sent only after the user approves the draft. It never intervenes in another session automatically. -[session-nudge](.claude/skills/session-nudge/SKILL.md) provides a reader standing outside the parallel sessions; it sends advice to another session only after the user approves the draft. Real-time work such as incident response, one-off exceptions the user declares, and small changes that do not touch logic go through without an Issue. +--- + +## Foundation + +### One Toolchain on Every Machine + +One flake manages the macOS and Linux development machines. When tools or versions differ between machines, agents stall on commands that are not found or fail at runtime. + +| Configuration | OS | Role | +|---|---|---| +| `linux-desktop` | NixOS (disko / SSD) | Primary dev machine. Where consultant chat and `issue` are launched | +| `macbook` | macOS (nix-darwin) | Shares the home-manager layer with the Linux machine | + +OS differences are confined to `pkgs.stdenv.isDarwin` on the Nix side and to the shims in `os.sh` (`_is_darwin`, `_sed_i`, `_open`, `_linux_only`) on the shell side; everything else is the same file on both. When an agent reaches for `brew` or `npm -g`, `block-non-nix-install.sh` stops it and points to the Nix procedure ([nix-tool-install](.claude/skills/nix-tool-install/SKILL.md)). + +### One Source for Every Session + +The settings, hooks, and skills in `.claude/`, together with `home-manager/config/claude/common.md`, are the source of truth. `home-manager/modules/claude.nix` copies them into `~/.claude` on every rebuild, so the same rules apply whichever repository or machine Claude Code is opened on. Since `~/.claude` is a generated artifact, `block-live-claude-config-edit.sh` rejects direct edits there and returns the source path instead. Persistent memory is put on the git path by `memory.nix` so every machine sees the same set. ### Secrets Stay Out of the Prose @@ -80,6 +137,30 @@ If the mapping existed on only one machine, writing on any other machine would m --- +## Skills + +Criteria and procedures are owned by the skill that uses them. The criteria for what gets published are in [.claude/skills/README.md](.claude/skills/README.md). + +| Step | Skill | Owns | +|---|---|---| +| 1. Type | [repo-standardize](.claude/skills/repo-standardize/SKILL.md) | Repository type and verification means, settings.json, CLAUDE.md and context/, file hygiene. CI/CD in [reference/cicd.md](.claude/skills/repo-standardize/reference/cicd.md) | +| | [repo-readme](.claude/skills/repo-readme/SKILL.md) | README kind, minimum sections, core message, outline | +| | [module-dev](.claude/skills/module-dev/SKILL.md) | Module-type repository shape, boundaries, demos | +| | [mermaid-diagram](.claude/skills/mermaid-diagram/SKILL.md) | Whether to draw, width limits, shapes and line styles | +| 3. Knowledge | [skill-dev](.claude/skills/skill-dev/SKILL.md) | Placement criteria, narrowing auto-invocation, splitting exploration | +| | [consolidate-rules](.claude/skills/consolidate-rules/SKILL.md) | Inventory of contradictory or stale rules | +| 4. Promises | [guarantee-audit](.claude/skills/guarantee-audit/SKILL.md) | Test policy (GDD), laying down and auditing the guarantee ledger | +| | [mvp-docs](.claude/skills/mvp-docs/SKILL.md) | PLAN.md / JUDGE.md for the launch phase | +| 5. Roles | [new-issue](.claude/skills/new-issue/SKILL.md) | Phases, role separation, the three exceptions, Issue design | +| | [pr-workflow](.claude/skills/pr-workflow/SKILL.md) | The executor's work from implementation to local commit | +| | [session-nudge](.claude/skills/session-nudge/SKILL.md) | Consulting on another session from the outside | +| Publishing | [readme-i18n](.claude/skills/readme-i18n/SKILL.md), [repo-publish](.claude/skills/repo-publish/SKILL.md), [repo-about](.claude/skills/repo-about/SKILL.md) | English README, publishing, About and topics | +| Foundation | [nix-tool-install](.claude/skills/nix-tool-install/SKILL.md), [sops-secrets](.claude/skills/sops-secrets/SKILL.md), [jp-writing](.claude/skills/jp-writing/SKILL.md) | Installing through Nix, encrypting secrets, Japanese writing rules | + +Step 2 (putting prohibitions in mechanisms) is owned not by a skill but by `.claude/settings.json` and [`.claude/hooks/`](.claude/hooks/). How to write hooks is in [.claude/hooks/README.md](.claude/hooks/README.md). + +--- + ## Tech Stack | Layer | Technology | Reason | @@ -95,17 +176,9 @@ If the mapping existed on only one machine, writing on any other machine would m --- -## sdlc-kit - -Of the practices running here, the ones that carry over to team repositories are packaged in [sdlc-kit](https://github.com/yktsnet/sdlc-kit). Only practices that meet at least one of three conditions go in: they keep a human decision from being skipped, they have to survive across sessions, or they have to come out the same when the person changes. That covers the task flows, PLAN.md / JUDGE.md for the launch phase, the guarantee ledger after release, and the guards that protect main. The idea of running development on two driving documents is in sdlc-kit's [docs/lifecycle.md](https://github.com/yktsnet/sdlc-kit/blob/main/docs/lifecycle.md). - -Unifying tools through Nix, distributing `~/.claude`, decrypting the mapping, and persistent memory are tied to the machine, so a team repository cannot enforce them. They stay in this repository. - ---- - ## Scope -Only the layers involved in developing with agents (Claude Code, memory, secrets, review, and tmux session management) are extracted from the working dotfiles. Editor and desktop settings and server configurations are not included. This is an extract, not a mirror, so some things in the working environment are absent here. The criteria for what gets published are in [.claude/skills/README.md](.claude/skills/README.md). +Only the layers involved in developing with agents (Claude Code, memory, secrets, review, and tmux session management) are extracted from the working dotfiles. Besides the two machines shown here, the working flake also covers headless servers and WSL, and holds editor and desktop settings and fleet status checks; none of those are included. Unifying tools through Nix, distributing `~/.claude`, decrypting the mapping, and persistent memory are tied to the machine and cannot be enforced from a team repository, so they are kept here rather than in sdlc-kit. The repository is not meant to be cloned and applied to your own machines, so no setup steps are given. The device configurations assume the actual hardware and keys, and the encrypted contents of `secrets/` are not included. CI's `nix flake check` confirms that the published configuration still evaluates. @@ -115,9 +188,9 @@ The repository is not meant to be cloned and applied to your own machines, so no | Path | Contents | Section | |---|---|---| +| `.claude/skills/` | Procedures and criteria. Index in [Skills](#skills) | All of Design | +| `.claude/settings.json`, `.claude/hooks/` | Deny rules and hooks | 2. Prohibitions in Mechanisms | +| `home-manager/modules/` | Claude Code distribution, memory, secrets, tmux, crit. Issue-driven functions in `zsh/` | 5. Separate Deciding from Building, One Source | +| `issues/` | This repository's own Issues and PR records | 5. Separate Deciding from Building | | `flake.nix`, `devices/` | NixOS / nix-darwin configurations for the dev machines. Shared parts in `devices/common/` | One Toolchain | -| `home-manager/modules/` | Claude Code distribution, memory, secrets, tmux, crit. Issue-driven functions in `zsh/` | One Source, Deciding and Building | -| `.claude/settings.json`, `.claude/hooks/` | Deny rules and hooks | Blocks Are Mechanisms | -| `.claude/skills/` | Procedures and criteria. Index in [.claude/skills/README.md](.claude/skills/README.md) | All sections | | `secrets-agents/` | Where the mapping is decrypted (`example.md` is a sample) | Secrets | -| `issues/` | This repository's own Issues and PR records | Deciding and Building | diff --git a/README.md b/README.md index 9e2b300..80daf7f 100644 --- a/README.md +++ b/README.md @@ -4,52 +4,81 @@ [![CI](https://github.com/yktsnet/dotfiles-public/actions/workflows/ci.yml/badge.svg)](https://github.com/yktsnet/dotfiles-public/actions/workflows/ci.yml) -本リポジトリは、AI エージェントに開発を任せる個人の開発環境で、守らせたい規則を文書ではなく環境(Nix・Claude Code の deny とフック・skill)に置く形を、構成ごと公開する実例である。 +AI エージェントとの開発では、ボトルネックはコードの生成から、検証と意図伝達へ移る。 +本リポジトリは、その前提で組んだ個人の開発基盤を、Nix 構成・役割分離の実行機構・skill 群ごとコードとして公開する実例である。守らせたい規則は文書に頼まず、環境(Nix・Claude Code の deny とフック・skill)に置いている。 チームのリポジトリへ持ち込める分は [sdlc-kit](https://github.com/yktsnet/sdlc-kit) に切り出しており、ここはその型を実際に回している環境にあたる。 --- ## Why -AI がコードを書くようになって、時間がかかるのは書くことではなく、書かれたものを信じられるか確かめることに変わった。エージェントは自信を持ったまま静かに間違え、放っておけば破壊的な操作や機密の漏洩をそのまま本番へ通す。人が気をつけるという約束は、いずれ形骸化する。 +AI がコードを書くようになって、時間がかかるのは書くことではなくなった。残ったのは2つである。 -そのため、環境差の排除・破壊的なコマンドの遮断・機密の隔離はコードと設定で固定し、人間のマージを最後の関門に置いた。「何が壊れてはいけないか」だけは人間が決めて文書で承認し、実装とテストはエージェントに任せる。約束が破られれば機械が検知して止まるので、張り付いて見張らずに済む。 +1つは**検証**である。書かれたものを信じてよいか確かめることに時間がかかる。エージェントは自信を持ったまま静かに間違え、放っておけば破壊的な操作や機密の漏洩をそのまま本番へ通す。人が気をつけるという約束は、いずれ形骸化する。 + +もう1つは**意図伝達**である。依頼に書かれていない条件は、エージェントが推論で埋めて、動くものを仕上げてしまう。動くので、空白があったことに気づきにくい。これまで実装者の頭の中で下されていた判断を、実装の前にコードの外へ書き出して渡す必要がある。 + +そのため、この基盤は**注意し続ける人間を前提にしない**。環境差の排除・破壊的なコマンドの遮断・機密の隔離はコードと設定で固定し、人間のマージを最後の関門に置く。人間は「何が壊れてはいけないか」だけを決めて文書で裁可し、実装とテストはエージェントに任せる。約束が破られれば機械が検知して止まるので、張り付いて見張らずに済む。人間の仕事は、コードを書くことから約束を裁可することへ移る。 --- -## Design +## Principles -規則は置き場で分けている。毎回守らせる規則は CLAUDE.md、「〜するとき」と条件を言える手順と基準は skill、外れてはいけないものは `settings.json` の deny とフックに置く。そのうえで、どのリポジトリ、どの端末で開いても同じものが効くよう、全部を Nix で配る。 +仕組みは次の順で積む。 -### 全端末で道具を揃える +1. **作る前に型を決める** +2. **禁止は頼まず仕組みに置く** +3. **読まれる場面ごとに知識を置く** +4. **守る約束を先に裁可する** +5. **決める役と作る役を分ける** -macOS と Linux の開発機を1つの Flake で管理する。端末ごとに道具の有無や版が違うと、エージェントはコマンドが見つからない、実行時に失敗する、といった形で止まる。 +順序には依存がある。型が決まらないと、何を遮断すべきかが決まらない。遮断が無いまま知識を増やすと、事故の速度だけが上がる。保証が固まる前に分業すると、実行者は何を壊してはいけないか分からないまま走る。 -| 構成 | OS | 役割 | -|---|---|---| -| `linux-desktop` | NixOS(disko / SSD) | 主開発機。相談者チャットと `issue` の起動元 | -| `macbook` | macOS(nix-darwin) | home-manager 層を Linux 機と共有する | +**最小構成は 1〜3** で、公開の有無やチームの規模に関わらず要る。4〜5 は、公開物を持つとき、または複数のセッションを並行して回し始めたときに足す。 -OS の差は、Nix 側では `pkgs.stdenv.isDarwin`、シェル側では `os.sh` のシム(`_is_darwin` / `_sed_i` / `_open` / `_linux_only`)に閉じ込め、それ以外は両 OS が同じファイルを読む。エージェントが `brew` や `npm -g` に手を伸ばすと `block-non-nix-install.sh` が止め、Nix で入れる手順([nix-tool-install](.claude/skills/nix-tool-install/SKILL.md))へ案内する。 +--- + +## Design + +### 1. 作る前に型を決める -### 禁止は頼まず仕組みに置く +新しいリポは、書き始める前に型を判定する。[repo-standardize](.claude/skills/repo-standardize/SKILL.md) がリポの類型と検証手段・`settings.json`・CLAUDE.md の骨組みを、[repo-readme](.claude/skills/repo-readme/SKILL.md) が README の種別(見せる実証型・測る実験型・使わせる利用保証型)を、[module-dev](.claude/skills/module-dev/SKILL.md) がモジュール型リポの境界とデモ方式を決める。 + +型を先に決めるのは、以降の規則をそこから導けるようにするためである。検証手段が決まれば CI と deny の中身が決まり、README の種別が決まれば必要な節の下限が決まる。 + +### 2. 禁止は頼まず仕組みに置く `rebuild` 系・`flake.lock` の編集・`ssh`・機密の対応表の読み書きは deny で塞ぐ。deny は文字列の前方一致しか見ないので、`/tmp/venv/bin/pip install` のようなパス付きの実行や、`~/.claude` を `sed -i` で書き換えるような、行為として判定が要るものは [PreToolUse フック](.claude/hooks/)が受け持つ。 フックの拒否文には、止めた理由と正しい経路を両方書く。エージェントは拒否されると別の手を試し、何を試すかは拒否文で決まるので、書いた経路へそのまま進む。編集直後に1ファイルだけ構文検査する `static-check.sh` も同じ考えで作った。忘れても誰も気づかない確認を、モデルの裁量から外している。 -### 規則を1か所から全セッションへ配る +### 3. 読まれる場面ごとに知識を置く + +規則は、読まれる場面で置き場を分ける。毎回守らせる規則は CLAUDE.md、「〜するとき」と条件を言える手順と基準は skill、外れてはいけないものは deny とフックに置く。「どのファイルをいつ AI に渡すか」が人の暗黙知に残っていると、AI 単独では運用を再現できない。そのため手順は skill にし、description に起動条件を宣言する。この先の節で扱うワークフロー自体(`new-issue`・`guarantee-audit` 等)も、この形でコミットされている。置き場の基準は [skill-dev](.claude/skills/skill-dev/SKILL.md) が持つ。 + +skill は、リポごとに答えが変わる**判断**を担うものと、一度決めれば機械的に当てはめられる**定型**を担うものに分かれる。README の書き方・モジュールの切り方・図を描くかは前者、足場・CI・保証台帳・Issue の型は後者である。多数のリポを並行して回す運用では、判断に払うコストがスループットを左右する。定型に落とせるものは定型へ寄せ、判断が要る場面にだけ人の時間を残す。 + +規則が増えると、規則同士が食い違い始める。CLAUDE.md も skill も永続メモリも「人が書いた規則を AI が読む」構造で、矛盾を自分では検出できない。[consolidate-rules](.claude/skills/consolidate-rules/SKILL.md) が、前回の棚卸し地点(`.claude/RULES.md` のアンカー1行)からの差分だけを定期的に監査し、モデルの世代が変わったときはモデルに特化した規則の陳腐化も見る。永続メモリは索引を持たせず、`~/memory/` 直下に1ファイル1事実で置く(`ls` が索引になる粒度に保つ)。 + +### 4. 守る約束を先に裁可する -`.claude/` の settings・hooks・skills と `home-manager/config/claude/common.md` が正本で、`home-manager/modules/claude.nix` が rebuild のたびに `~/.claude` へ実体コピーする。`~/.claude` 側は生成物になるので、そこを直接編集しようとすると `block-live-claude-config-edit.sh` が止め、正本のパスを返す。 +テストは、実行者が壊したことに自分で気づくための装置である。何が壊れてはいけないか(保証)は人間が Issue の保証節で裁可し、それを実行可能な形に書き下ろすテストは実行者が書く。この分業を **Guarantee-Driven Development(GDD)** と呼んでいる。TDD がテストを先に書く規律だとすれば、GDD は約束の裁可を先に行う規律である。 -規則が増えると、規則同士が食い違い始める。[consolidate-rules](.claude/skills/consolidate-rules/SKILL.md) が、前回の棚卸し地点(`.claude/RULES.md` のアンカー1行)からの差分だけを監査する。永続メモリは `~/memory/` 直下に1ファイル1事実で置き、`memory.nix` で git の経路に乗せて端末間で揃える。 +裁可された保証は、各リポの保証台帳 `docs/guarantees.md` に積み上がる。台帳に載せるのは、テストに裏付けられた契約面(公開 API・CLI・外から観測できる振る舞い)の保証だけである。載っていない振る舞いは約束ではなく、予告なく変わりうる。台帳は次のように保守する。 -### 決める役と作る役を分ける +- **敷設**: [guarantee-audit](.claude/skills/guarantee-audit/SKILL.md) が既存テストから保証を抽出し、user の裁可を経て敷く。保証すべきなのにテストが無いものは Gaps 節に分けて記録する +- **追従**: 以後は、Issue の保証節と同じ PR でテストと台帳を更新する。実行者の手順([pr-workflow](.claude/skills/pr-workflow/SKILL.md))は、台帳の更新漏れを実装未完了として扱う +- **範囲の一致**: 実行者はコミット前に、ステージした差分のファイル一覧が Issue の `対象` と完全に一致することを確かめる。宣言した範囲の外へ出た変更は、コミットまで届かない +- **一望**: 台帳の正本は各リポに置いたまま、台帳を持つリポへのリンクを定期実行で1枚の索引に束ねる。裁可する側が、全体で何を約束しているかを見渡せる + +開発は2つのフェーズに分け、駆動文書を交代させる。方向性が固まっていない立ち上げ期は、PLAN.md(残作業)と JUDGE.md(設計判断)を育てながら直接実装する([mvp-docs](.claude/skills/mvp-docs/SKILL.md))。保証台帳が正式運用に上がった時点で Issue 駆動期へ移り、以後は台帳とテストで回す。フェーズは各リポの CLAUDE.md で宣言する。考え方の全体は sdlc-kit の [docs/lifecycle.md](https://github.com/yktsnet/sdlc-kit/blob/main/docs/lifecycle.md) にある。 + +### 5. 決める役と作る役を分ける 同じモデルが決めて作ると、方向を外したことに自分では気づけない。そのため役割を3つに分ける。 -- **相談者**: user と対話して仕様と Issue を設計する。実装はしない([new-issue](.claude/skills/new-issue/SKILL.md)) -- **実行者**: Issue を入力に、実装・テスト・ローカルコミットまでを進める。リモートには触れない([pr-workflow](.claude/skills/pr-workflow/SKILL.md)) +- **相談者**: user と対話して調査し、Issue を設計する。実装はしない([new-issue](.claude/skills/new-issue/SKILL.md)) +- **実行者**: Issue を入力に、実装・テスト・静的確認・ローカルコミットまでを進める。リモートには触れない([pr-workflow](.claude/skills/pr-workflow/SKILL.md)) - **user**: Issue の保証節を裁可し、コミットをレビューして公開する ```mermaid @@ -68,9 +97,37 @@ flowchart TD R -->|issue-finish| P ``` -実行者はローカルコミットで止まり、リモートへ出る経路は user の `issue-finish` しかない。`issue` は worktree を切って実行者を起動するので、複数の Issue を並行して走らせられる。実行者の変更は [crit](https://github.com/tomasz-tomczyk/crit) で行単位にレビューする。 +役割の境目は zsh の関数で渡す。 + +- **`issue-open`**: 保証節を裁可した Issue を `draft` から `open` に上げる +- **`issue`**: `open` の Issue を選び、worktree を切って実行者を起動する。main のチェックアウトを汚さない +- **`issue-abort`**: 進行中の worktree を作業ブランチごと破棄する +- **`issue-finish`**: レビューを通ったブランチの push → PR 作成 → マージ → 後片付けを一括で行う + +リモートへ出る経路は user の `issue-finish` しかない。実行者の変更は、実行者のセッションの中で [crit](https://github.com/tomasz-tomczyk/crit) を開いて行単位でレビューし、指摘はそのセッションへ戻して直させる。worktree は隔離されているので機構上は並列にも回せるが、Issue は1本ずつ実装する。直列であることが、user のレビューと裁可が成り立つ条件だからである。 + +分離を硬直させないための例外が3つある。事前に Issue を設計できない障害対応、user が明示した単発の例外、そしてロジックにも保証台帳にも触れない小さな変更を Issue にせず通す軽量経路である。 + +実際には複数の相談者セッションと worktree が同時に走り、どのセッションも同じ理由で自分の逸脱に気づけない。その外に立つ読み手が、`M-m` で起動する [session-nudge](.claude/skills/session-nudge/SKILL.md) である。別セッションのやり取りを読んで助言を起こし、文案を user が承認してから送る。自動で他セッションへ介入はしない。 -並行するセッションの外に立つ読み手として [session-nudge](.claude/skills/session-nudge/SKILL.md) があり、別セッションへの助言は、文案を user が承認してから送る。障害対応のような即時の作業、user が明示した単発の例外、ロジックに触れない小さな変更は、Issue を立てずに通す。 +--- + +## Foundation + +### 全端末で道具を揃える + +macOS と Linux の開発機を1つの Flake で管理する。端末ごとに道具の有無や版が違うと、エージェントはコマンドが見つからない、実行時に失敗する、といった形で止まる。 + +| 構成 | OS | 役割 | +|---|---|---| +| `linux-desktop` | NixOS(disko / SSD) | 主開発機。相談者チャットと `issue` の起動元 | +| `macbook` | macOS(nix-darwin) | home-manager 層を Linux 機と共有する | + +OS の差は、Nix 側では `pkgs.stdenv.isDarwin`、シェル側では `os.sh` のシム(`_is_darwin` / `_sed_i` / `_open` / `_linux_only`)に閉じ込め、それ以外は両 OS が同じファイルを読む。エージェントが `brew` や `npm -g` に手を伸ばすと `block-non-nix-install.sh` が止め、Nix で入れる手順([nix-tool-install](.claude/skills/nix-tool-install/SKILL.md))へ案内する。 + +### 規則を1か所から全セッションへ配る + +`.claude/` の settings・hooks・skills と `home-manager/config/claude/common.md` が正本で、`home-manager/modules/claude.nix` が rebuild のたびに `~/.claude` へ実体コピーする。どのリポジトリ、どの端末で Claude Code を開いても、同じ規則が効く。`~/.claude` 側は生成物になるので、そこを直接編集しようとすると `block-live-claude-config-edit.sh` が止め、正本のパスを返す。永続メモリは `memory.nix` で git の経路に乗せ、端末間で揃える。 ### 機密を地の文に出さない @@ -80,6 +137,30 @@ Issue・PR・コミットの地の文には、IP・ポート・実ホスト名 --- +## Skills + +基準と手順は、それを使う skill が持つ。何を公開するかの基準は [.claude/skills/README.md](.claude/skills/README.md) にある。 + +| 段 | skill | 持つもの | +|---|---|---| +| 1. 型を決める | [repo-standardize](.claude/skills/repo-standardize/SKILL.md) | リポ類型と検証手段・settings.json・CLAUDE.md と context/・ファイル衛生。CI/CD は [reference/cicd.md](.claude/skills/repo-standardize/reference/cicd.md) | +| | [repo-readme](.claude/skills/repo-readme/SKILL.md) | README の種別判定・下限・コアメッセージ・アウトライン | +| | [module-dev](.claude/skills/module-dev/SKILL.md) | モジュール型リポの型・境界・デモ | +| | [mermaid-diagram](.claude/skills/mermaid-diagram/SKILL.md) | 図を描くかの判断・幅の制約・形と線種 | +| 3. 知識の置き場 | [skill-dev](.claude/skills/skill-dev/SKILL.md) | 置き場の基準・自動発火の絞り方・探索の分け方 | +| | [consolidate-rules](.claude/skills/consolidate-rules/SKILL.md) | 規則同士の矛盾・陳腐化の棚卸し | +| 4. 約束の裁可 | [guarantee-audit](.claude/skills/guarantee-audit/SKILL.md) | テスト方針(GDD)・保証台帳の敷設と棚卸し | +| | [mvp-docs](.claude/skills/mvp-docs/SKILL.md) | 立ち上げ期の PLAN.md / JUDGE.md | +| 5. 分業 | [new-issue](.claude/skills/new-issue/SKILL.md) | フェーズ・担当分離・例外の3経路・Issue の設計 | +| | [pr-workflow](.claude/skills/pr-workflow/SKILL.md) | 実行者の実装からローカルコミットまで | +| | [session-nudge](.claude/skills/session-nudge/SKILL.md) | 別セッションを外から客観視する相談 | +| 公開 | [readme-i18n](.claude/skills/readme-i18n/SKILL.md)・[repo-publish](.claude/skills/repo-publish/SKILL.md)・[repo-about](.claude/skills/repo-about/SKILL.md) | 英語版 README・公開手続き・About と topics | +| Foundation | [nix-tool-install](.claude/skills/nix-tool-install/SKILL.md)・[sops-secrets](.claude/skills/sops-secrets/SKILL.md)・[jp-writing](.claude/skills/jp-writing/SKILL.md) | Nix 経由の導入・機密の暗号化・日本語の文章規範 | + +段 2(禁止を仕組みに置く)は skill ではなく、`.claude/settings.json` と [`.claude/hooks/`](.claude/hooks/) が持つ。フックの書き方は [.claude/hooks/README.md](.claude/hooks/README.md) にある。 + +--- + ## Tech Stack | Layer | Technology | Reason | @@ -95,17 +176,9 @@ Issue・PR・コミットの地の文には、IP・ポート・実ホスト名 --- -## sdlc-kit - -ここで回している型のうち、チームのリポジトリへ持ち込めるものを [sdlc-kit](https://github.com/yktsnet/sdlc-kit) に切り出している。持ち込むのは、人の判断を省かせない、セッションを超えて残す、担当者が替わっても揃う、のどれかに当たるものだけで、作業フロー、立ち上げ期の PLAN.md / JUDGE.md、リリース後の保証台帳、main を守るガードがこれにあたる。開発を2つの駆動文書で回す考え方は sdlc-kit の [docs/lifecycle.md](https://github.com/yktsnet/sdlc-kit/blob/main/docs/lifecycle.md) にある。 - -Nix による道具の統一、`~/.claude` の配布、対応表の復号、永続メモリは端末に紐づくので、チームのリポジトリからは効かせられない。これらはこのリポジトリに残る。 - ---- - ## Scope -稼働中の dotfiles から、エージェントとの開発に関わる層(Claude Code・メモリ・機密・レビュー・tmux のセッション管理)だけを抜き出している。エディタやデスクトップの設定、サーバー類の構成は含めていない。抜き出しであって写しではないので、稼働側にあってここに無いものがある。何を公開するかの基準は [.claude/skills/README.md](.claude/skills/README.md) に置いた。 +稼働中の dotfiles から、エージェントとの開発に関わる層(Claude Code・メモリ・機密・レビュー・tmux のセッション管理)だけを抜き出している。稼働側の Flake は、ここに載せた2台のほかに headless のサーバーや WSL も束ね、エディタ・デスクトップの設定やフリートの状態確認も持つが、それらは含めていない。Nix による道具の統一・`~/.claude` の配布・対応表の復号・永続メモリは端末に紐づき、チームのリポジトリからは効かせられないので、sdlc-kit には入れずここに残している。 clone して各自の端末へ適用することは想定しておらず、動かす手順も載せていない。デバイス構成は実機のハードウェアと鍵を前提にしていて、`secrets/` の暗号文も含めていないためである。CI の `nix flake check` は、公開している構成が評価できる状態にあることを確かめている。 @@ -115,9 +188,9 @@ clone して各自の端末へ適用することは想定しておらず、動 | パス | 中身 | 対応する節 | |---|---|---| +| `.claude/skills/` | 手順と基準。一覧は [Skills](#skills) | Design 全体 | +| `.claude/settings.json`・`.claude/hooks/` | deny とフック | 2. 禁止は頼まず仕組みに置く | +| `home-manager/modules/` | Claude Code の配布・メモリ・機密・tmux・crit。`zsh/` に Issue 駆動の関数 | 5. 決める役と作る役を分ける・規則を1か所から全セッションへ配る | +| `issues/` | このリポジトリ自身の Issue と PR の控え | 5. 決める役と作る役を分ける | | `flake.nix`・`devices/` | 開発機の NixOS / nix-darwin 構成。共通部分は `devices/common/` | 全端末で道具を揃える | -| `home-manager/modules/` | Claude Code の配布・メモリ・機密・tmux・crit。`zsh/` に Issue 駆動の関数 | 規則を1か所から全セッションへ配る・決める役と作る役を分ける | -| `.claude/settings.json`・`.claude/hooks/` | deny とフック | 禁止は頼まず仕組みに置く | -| `.claude/skills/` | 手順と基準。一覧は [.claude/skills/README.md](.claude/skills/README.md) | Design 全体 | | `secrets-agents/` | 対応表の復号先(`example.md` はサンプル) | 機密を地の文に出さない | -| `issues/` | このリポジトリ自身の Issue と PR の控え | 決める役と作る役を分ける |