accord
# accord
正本と、そこから派生する対外表現が食い違わないようにする、手元で動く MCP サーバー。
> **English:** accord is a local MCP server that keeps one source of truth (what you can do, what you have done, how you sell it) consistent with everything derived from it (profiles, applications, résumés). Run it with `uv sync`, `uv run pytest`, `uv run accord --list`. The rest of this document is written in Japanese.
## 何を解決するか
自分の仕事を売る人は、たいてい 3 つの正本を持っている。何ができるか、何をしてきたか、どう売るか。
そこからプロフィールや応募文や職務経歴書を書く。困るのは、売り方を変えたときである。
売り方の決めはその場の会話で終わり、どこにも残らない。だから、束ねた売り物の定義が 1 か月古いまま残り、
もう名乗っていない売り物を宣言した文面が何枚も残る。どれも規約には書いてある。書いてあるのに、
文面を書く瞬間には効かない。人が何往復もかけて自分で見つけるまで、誰も気づかない。
accord は、この規約を「読んで覚えておくもの」から「行動の瞬間に返ってくるもの」に変える。
決めを登記しようとすれば、欠けた欄を数えて返す。実在しない節を裏づけに挙げれば、書き込まずに近い節名を返す。
外に出す前に検査を呼べば、どのファイルのどこを何に合わせるかを一覧で返す。
文面そのものは書かない。書くのは人(または AI)の仕事で、accord がするのは、材料を渡すことと、
食い違いを行動の瞬間に止めることである。
## 動かす
Python 3.12 以上と [uv](https://docs.astral.sh/uv/) が要る。同梱の架空のサンプルだけで動くので、
設定ファイルを作る必要は無い。
```
uv sync # 依存を入れる
uv run pytest # テストが通ることを確かめる
uv run accord --list # 開く口(MCP のツール 6 本と資源 1 本。以下「口」はこの 2 つを指す)を並べる
```
引数なしで `uv run accord` を呼ぶと、標準入出力で MCP サーバーが立ち上がる。ネットワークの口は開かない。
自分のデータで動かすときは、`samples/accord.toml` を写して書き換え、次の形で指す。
```
uv run accord --config <写して書き換えた accord.toml のパス>
```
開く口は次のとおり。
| 口 | 何をするか |
|---|---|
| `get_positioning` | いまの決め(看板)を読む(媒体を省くと「全体」の決め。決めが未登記なら、先に登記することを返す) |
| `assemble_material` | 媒体向けの文面を書くための材料を取り出す(決め・束・束ねる機能・裏づけの節・媒体の規約・禁じた言い回し。公開不可の節は落として警告に書く) |
| `record_positioning` | 売り方の決めを 1 ブロック登記する |
| `register_capability` | 機能の台帳に 1 行足す |
| `revise_package` | パッケージ定義を改訂する |
| `check_consistency` | 正本を制約に当て、違反の一覧を直し先つきで返す(範囲は、全体・媒体 1 つ・提示物 1 件から選ぶ) |
| 資源 `accord://ontology` | 型・関係・制約の定義を返す(セッションの初めに読む) |
6 本とも、同梱の架空のサンプルの上でそのまま動く。読みの 2 つ(決めを読む、材料を取り出す)と
検査は正本を 1 バイトも変えない。書きの 3 つ(決めの登記、機能の登記、パッケージの改訂)は、
制約に通った入力だけを正本に書き、通らない入力は書かずに拒否して次の一手を返す。
## 設計の要点
**4 層に分ける。** 上から、MCP の口を開く薄い皮(`server/`)、制約を執行するサービス(`services/`)、
正本の在処を知るリポジトリ(`repository/`)、Markdown ファイルそのもの。依存は上から下への 1 方向だけ。
Markdown の在処と書き方を知るのはリポジトリだけなので、保管の形を変えるときに直る場所がそこに閉じる。
サービスが皮を読み込まないのは、同じ判断をコマンドの道具からも呼べる形に残すためである。
**型と制約の正本は YAML に置く。** `src/accord/ontology.yaml` が、型 7 つ・関係 6 種・制約 7 つの正本である。
Pydantic(Python の型検証ライブラリ)のモデル(`models/types.py`)と制約の宣言(`models/constraints.py`)は、そこからの生成物で、
`scripts/generate_models.py --check` が正本との一致を見る。制約を 1 か所に宣言しておくと、
同じ制約が「書きでは拒否、読みでは警告、検査では一覧」という 3 つの顔で現れても、宣言は 1 つで済む。
**語彙は設定から読む。** 媒体の名前、機能の分類の節、仮説の状態の語は、型の構造から外して設定ファイルに置く。
分類の選択肢を特定の人や会社の語で埋めると、型の定義ごと公開できなくなるからである。
正本の書き方(見出しの深さ、欄を箇条書きで書くか表で書くか、欄のラベルの言い方)も同じ理由で設定に置き、
設定ファイルの `[reading]` の節で差し替えられる。この節を書かなければ、同梱のサンプルと同じ書き方で読む。
設定を読む部分は標準ライブラリだけで動かし、型を知らない状態に保つ。
見せ方(媒体の規約・語り口の決め・禁じた言い回し)も型には持たず、置き場だけを設定に書く。
良し悪しを機械で判定しないものまで型にすると、守れない約束が増えるからである。材料の取り出しは、
その置き場から宛先の媒体の節と禁じた言い回しの節を読んで、そのまま材料に載せる。
**拒否は例外ではなく返り値。** 制約に反する入力は、例外ではなく「受け付けなかったこと」と
「次に何をすべきか」を持つ値で返す。返ってきた候補をそのまま渡し直せば通る、という形にしてある。
拒否のときは正本のファイルが 1 バイトも変わらない。書きの操作は、制約を全部見て通ると決まってから
1 度だけ書き戻す。
**公開境界を機械で守る。** このリポジトリに入る人物・会社・媒体の名前はすべて架空で、実在しないことを
確かめた結果は `samples/README.md` にある。テストもこのサンプルの写しの上で走る。実データの語
(クライアントの名前や単価)が 1 語も入っていないことは、公開の前に、語の一覧と追跡中の全ファイルを
突き合わせる検査で確かめる。語の一覧と検査は公開しない手元の置き場に持ち、コミットの前に毎回走らせる。
git の履歴に一度入れば履歴の書き換えが要るので、入る前に止める形にしてある。
## 置き場
```
src/accord/ontology.yaml 型・関係・制約の正本
src/accord/server/ MCP の口(薄い皮)
src/accord/services/ 制約を執行するサービス
src/accord/repository/ 正本の Markdown の読み書き
src/accord/models/ 型・制約・返す型
src/accord/vocabulary/ 設定から読む語彙
scripts/generate_models.py 正本からモデルと制約の宣言を生成する
samples/ 架空の設定とデータ
tests/ 受け入れ条件のテスト
```
## 作り方
この道具は、設計の文書を先に固め、受け入れ条件を仕様書として実装より先にコミットし、実装役とは別の検収役が仕様書だけを見て検収する、という手順で作った。実装と検収の多くは AI(Claude Code)に委譲し、設計の判断・仕様の確定・検収結果の検品・コミットは作者が行った。公開リポジトリには、実データの語(クライアント名・単価・担当者名)が入らないよう、コミットのたびに機械の検査を通している。同梱のサンプルは架空の人物と案件だけで作ってある。
## ライセンス
MIT License。全文は `LICENSE` にある。
TDQS
Scored across 6 tools
Each tool targets a distinct resource and action: reading or recording positioning, assembling material, registering capabilities, revising packages, and checking consistency. There is no meaningful overlap, and the descriptions leave no ambiguity about which tool to select.
All tool names follow a consistent lowercase snake_case verb_noun pattern: get_positioning, record_positioning, assemble_material, register_capability, revise_package, check_consistency. The verbs clearly indicate the action, and the nouns identify the target resource.
Six tools is well within the ideal scope for a focused domain. Each tool addresses a distinct part of the workflow—reading/writing positioning, preparing material, managing capabilities, editing packages, and validating consistency—without unnecessary redundancy or bloat.
The core positioning, package revision, and consistency-checking workflows are well covered, and the register_capability tool includes guardrails with next-step guidance. However, there is no direct tool to read or update the capability ledger, and delete operations are absent, which creates minor gaps for maintenance scenarios.