harness-engineering について
リポジトリをエージェント中心の開発環境に整えるスキルです。案内文書、アーキテクチャ規則、テスト、CIによる検査を整備し、固定構成を押しつけず実際のコードベースに合わせて進めます。
主な機能
- 01リポジトリの技術スタックと構造を調査
- 02AGENTS.mdの案内マップを作成
- 03レイヤー規則と開発原則を文書化
- 04境界テストとリンタールールを設定
- 05CIと定期的な整理チェックを追加
活用シーン
- 01自律型コーディングエージェント向けにリポジトリを準備
- 02アーキテクチャ制約を機械的に適用
- 03プロジェクトの指針と開発チェックを整理
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ charlesanim/ harness-engineering --skill harness-engineeringインストール後、Claude Code で/harness-engineeringを入力して読み込まれたか確認します。
同梱ファイルREADME.md
詳細
Harness Engineering のセットアップ
OpenAI の Harness Engineering 手法に精通したエキスパートです。目標は、あらゆるリポジトリを、AI エージェント(Codex、Copilot、Claude など)が機械的に強制される境界の中で、独立してコードの調査、ビルド、テスト、検証を行える、エージェントファーストのエンジニアリング環境に変えることです。
背景
OpenAI が提唱した Harness Engineering は、人間のエンジニアの役割をコードの作成から環境の設計へと移行させます。「ハーネス」は馬具のように、強力ですが制御しにくいエージェントが安全に連携して動作できるよう導きます。主な原則は次のとおりです。
- エンジニアは環境の設計者になる — 実装ではなく制約を定めます
- エージェントには百科事典ではなく地図を渡す — AGENTS.md を通じて段階的に情報を開示します
- エージェントから見えなければ、存在しないのと同じです — すべてのナレッジをリポジトリ内に置きます
- アーキテクチャを機械的に強制する — Markdown の指示ではなく、リンターとテストを使います
- 堅実な技術が優れています — 組み合わせやすく、安定しており、十分に学習された API を選びます
- エントロピーの管理はガベージコレクションです — 定期的にクリーンアップするエージェントを用意します
- スループットの変化に応じてマージの方針を変える — ブロックするゲートは最小限にします
- エージェント同士でコードレビューする — 人間へのエスカレーションは判断が必要な場合に限ります
Phase 0: 調査
何かを生成する前に、リポジトリの内容を把握する必要があります。次の手順を実行してください。
0a. 技術スタックの検出
リポジトリを分析して、次の項目を特定します。
# Check for stack indicators
ls package.json pyproject.toml Cargo.toml go.mod Gemfile build.gradle pom.xml composer.json mix.exs 2>/dev/null
cat package.json 2>/dev/null | head -50
cat pyproject.toml 2>/dev/null | head -30
以下を特定してください。
- 言語: TypeScript、Python、Go、Rust、Ruby、Java など
- フレームワーク: React、Next.js、Django、FastAPI、Rails、Spring など
- パッケージマネージャー: npm、pnpm、yarn、pip、poetry、cargo、go mod、bundler
- ビルドツール: Vite、Webpack、tsc、setuptools、cargo、make
- テストランナー(ある場合): Vitest、Jest、pytest、go test、RSpec、JUnit
- リンター(ある場合): ESLint、Ruff、pylint、golangci-lint、RuboCop
0b. アーキテクチャの把握
# Get directory structure
find . -maxdepth 3 -type d | grep -v node_modules | grep -v .git | grep -v __pycache__ | sort
# Check for existing docs/config
ls AGENTS.md CLAUDE.md .cursorrules .github/copilot-instructions.md docs/ 2>/dev/null
# Check for existing CI
ls .github/workflows/*.yml 2>/dev/null
# Check for existing tests
find . -name "*.test.*" -o -name "*.spec.*" -o -name "test_*" -o -name "*_test.*" | grep -v node_modules | head -20
# Check for existing lint config
ls .eslintrc* eslint.config* .pylintrc pyproject.toml .rubocop.yml .golangci.yml 2>/dev/null
0c. レイヤーの特定
どのコードベースにも、明示されていないアーキテクチャ上のレイヤーがあります。それらを明確にするのが役割です。一般的なパターンは次のとおりです。
Web フロントエンド(React/Vue/Svelte/Angular):
types/ → No app imports (pure type definitions)
utils/ → No app imports (pure functions)
lib/ → types/ only (clients, configs, core utilities)
services/ → lib/, types/ (business logic, API wrappers)
hooks/states/ → lib/, services/, types/ (state management)
components/ → hooks/, lib/, types/ (UI layer)
pages/routes/ → components/, hooks/, lib/, types/ (route entry points)
バックエンド API(Express/FastAPI/Rails/Spring):
types/models/ → No app imports (data definitions)
config/ → types/ only (configuration)
db/repo/ → config/, types/ (data access layer)
services/ → db/, config/, types/ (business logic)
middleware/ → services/, config/, types/ (request processing)
routes/ → services/, middleware/, types/ (HTTP handlers)
フルスタック(Next.js/Nuxt/SvelteKit):
types/ → No app imports
lib/ → types/ only (shared utilities)
db/ → lib/, types/ (database layer)
services/ → db/, lib/, types/ (business logic)
components/ → lib/, types/ (UI primitives)
features/ → components/, services/, lib/, types/ (feature modules)
app/pages/ → features/, components/, lib/, types/ (routes)
モノレポ(Turborepo/Nx/Lerna):
packages/types/ → No internal imports
packages/config/ → types/
packages/db/ → config/, types/
packages/api/ → db/, config/, types/
packages/ui/ → types/ only
packages/web/ → ui/, api/, types/
実際のディレクトリ構造に合わせてレイヤーを調整してください。適合しない構造を無理に当てはめないでください。コードベースのインポートパターンを読み取り、実際の依存関係グラフを把握してください。
0d. 確認事項を尋ねる
作業を進める前に、ユーザーに次の点を確認してください。
- どのディレクトリをどのレイヤーとして扱いますか?
- 維持すべき特別なインポート関係はありますか?
- 希望するテストフレームワークはありますか?
- セットアップ全体を希望しますか、それとも特定のフェーズのみですか?
Phase 1: AGENTS.md — 地図
リポジトリのルートに AGENTS.md を作成します。これは最も重要なファイルです。次の要件を満たす必要があります。
- 約100行(百科事典のようにしない)
- 目次として docs/ のサブディレクトリを示す
- リポジトリで作業するすべてのエージェントの開始地点となる
テンプレート
# {Project Name} — Agent Orientation Map
> {One-line description of what this project does.}
## Stack
| Layer | Tech |
|-------|------|
| {Language} | {version} |
| {Framework} | {version} |
| {Database} | {type} |
| {Other} | {details} |
## Architecture Layers
Dependency flows **downward only**. Never import upward.
{Generate the layer diagram from Phase 0c discovery}
## Key Conventions
- {Convention 1 — brief, with pointer to docs/golden-principles/ for details}
- {Convention 2}
- {Convention 3}
## Commands
```sh
{build command}
{test command}
{lint command}
{dev command}
ドキュメントマップ
docs/
├── architecture/ Dependency graph, layer rules
├── guides/ Setup, testing, deployment how-tos
├── golden-principles/ Canonical patterns (DO/DON'T examples)
└── {other categories as needed}
最初に確認する場所
| タスク | 最初に確認する場所 |
|---|---|
| {common task 1} | {directory/file} |
| {common task 2} | {directory/file} |
| {common task 3} | {directory/file} |
## Phase 2: Documentation Structure
### 2a. Restructure docs/
If docs exist, reorganize them. If not, create the structure.
```bash
mkdir -p docs/architecture docs/guides docs/golden-principles
既存のドキュメントは、履歴を保持するために git mv を使って適切なサブディレクトリに移動します。次のカテゴリを検討してください。
architecture/— レイヤーのルール、依存関係の流れ、システム設計guides/— ローカル開発、テスト、デプロイ、オンボーディングgolden-principles/— 標準となるコーディングパターンfeatures/— 機能仕様(該当する場合)integrations/— サードパーティサービスのドキュメント(該当する場合)security/— 認証、アクセス制御のドキュメント(該当する場合)historical/— 完了した作業、移行に関するメモ(該当する場合)
リポジトリの規模に合ったサブディレクトリだけを作成してください。
2b. docs/architecture/LAYERS.md を作成する
レイヤー階層の決定版リファレンスです。以下を含めてください。
- レイヤー図 — 許可される依存関係の方向を示す ASCII 図
- 厳格なルール — 違反すると CI が失敗するルール
- 各レイヤーに含まれるもの — 責務と主要なファイル
- 修正ガイド — よくある違反ごとに、修正方法を説明する
CI のすべてのエラーメッセージから、このファイルを参照するようにしてください。
2c. Golden Principles を作成する
docs/golden-principles/ に 3〜5 個の Golden Principles ドキュメントを作成します。それぞれ 30〜60 行にし、DO と DON'T の例を含めてください。候補としては、次のようなものがあります。
- IMPORTS.md — パスエイリアス、インポート順序、深い相対インポートの禁止
- NAMING.md — ファイル名、エクスポート規則、変数名
- ERROR_HANDLING.md — エラーの処理と報告方法
- LOGGING.md — ロギング規則(カスタムロガーがある場合)
- DATA_FETCHING.md — データの取得とキャッシュ方法(フロントエンド)
- TESTING.md — テストの書き方、テスト対象、従うべきパターン
作成前に、実際のコードベースのパターンを確認してください。推測せず、調査してください。
フェーズ 3:テスト基盤
3a. 適切なテストランナーを選ぶ
| スタック | テストランナー | インストール |
|---|---|---|
| Vite/React/Vue | Vitest | npm i -D vitest @testing-library/react jsdom |
| Next.js | Vitest または Jest | npm i -D vitest @testing-library/react jsdom |
| Node.js/Express | Vitest または Jest | npm i -D vitest |
| Python | pytest | pip install pytest pytest-cov |
| Go | go test(組み込み) | インストール不要 |
| Rust | cargo test(組み込み) | インストール不要 |
| Ruby/Rails | RSpec または Minitest | gem install rspec |
3b. テスト設定を作成する
以下の設定をテストランナーに追加します。
- メインのビルド設定に合わせたパスエイリアスの解決
- カバレッジレポート
- テストファイルのパターン
- 共通のテストユーティリティ用セットアップファイル
3c. テストユーティリティを作成する
共通のテストヘルパーを作成します。
- モックファクトリー — データベースクライアント、API クライアント、認証コンテキスト用
- レンダーヘルパー — (フロントエンド)テスト用にプロバイダーでコンポーネントをラップする
- フィクスチャファクトリー — テストデータを生成する
3d. アーキテクチャ境界テストを作成する
これは機械的な強制であり、最も重要なテストです。次の処理を行います。
- プロジェクト内のすべてのソースファイルをスキャンする
- import/require 文を解析する
- 各ファイルが属するレイヤーを特定する
- import がレイヤールールに従っているか検証する
- 具体的で、対処方法がわかるエラーメッセージを表示して失敗する
主な設計上の決定事項:
- 言語のファイル I/O を使ってスキャンする(node:fs、os.walk、filepath.Walk)
- 正規表現で import を解析する(これで十分です。AST は不要です)
- 違反は次の形式で報告する:
"VIOLATION: {file} imports from {target} — {layer} cannot import from {target_layer}. {remediation}. See docs/architecture/LAYERS.md" - ラチェットとして機能する
KNOWN_VIOLATIONSリストを維持する。追加はレビューなしでは認めず、項目を削除することだけを許可する - すべての違反が既知のリストに含まれていればテストは成功し、新たな違反があれば失敗する
3e. テスト例を作成する
コードベースのテストパターンを示すテスト例を 3〜5 個作成します。
- 純粋なユーティリティ関数のテスト
- 設定/セットアップの検証テスト
- コンポーネント/ハンドラーのテスト(該当する場合)
- アーキテクチャ境界テスト
フェーズ 4:リントと境界の強制
4a. インポート制限ルールを追加する
境界を強制するには、リンターの標準機能を使用します。すべてのエラーメッセージに、必ず修正手順を含めてください。エラー出力そのものがエージェントのコンテキストになります。
ESLint(JavaScript/TypeScript):
レイヤーごとに個別の設定オブジェクトを用意し、patterns を使って no-restricted-imports を設定します。
{
files: ['src/lib/**/*.{ts,tsx}'],
rules: {
'no-restricted-imports': ['error', {
patterns: [{
group: ['@/services/*', '@/hooks/*', '@/components/*', '@/pages/*'],
message: 'lib/ is Layer 3 — cannot import from higher layers. See docs/architecture/LAYERS.md'
}]
}]
}
}
Ruff/pylint(Python):
banned-api、または [tool.ruff.lint.per-file-ignores] によるカスタムチェックを使用します。
Go:
golangci-lint 経由で depguard を使用します。
Rust:
clippy の制限、または Cargo.toml のワークスペース依存関係ルールを使用します。
4b. インポート順序を追加する(該当する場合)
一貫したインポート順序を徹底します:
- ESLint:
eslint-plugin-importのimport/order - Python: Ruff 経由の
isort - Go:
goimports(組み込み) - Rust:
rustfmt(組み込み)
フェーズ 5:CI/CD パイプライン
5a. CI ワークフローを作成する
並列ジョブを含む .github/workflows/ci.yml を作成します:
name: CI
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup {language}
# Use appropriate setup action
- run: {install_command}
- run: {lint_command}
typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup {language}
- run: {install_command}
- run: {typecheck_command}
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup {language}
- run: {install_command}
- run: {test_command}
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup {language}
- run: {install_command}
- run: {build_command}
スタックに合わせてジョブを調整します。すべてのスタックで 4 つのジョブすべてが必要とは限りません。Python では個別の build ジョブが不要な場合があります。Go では typecheck を build に統合できる場合があります。
フェーズ 6:ガベージコレクション
6a. GC チェックスクリプトを作成する
よくある違反をゴールデン原則に照らして検出する、シンプルなスクリプトを(リポジトリの主要言語またはシェルで)作成します。各スクリプトでは次の処理を行います:
- ソースディレクトリをスキャンする
- 特定のアンチパターンを探す
- 違反を file:line 形式で報告する
- 問題がなければ 0、違反が見つかった場合は 1 で終了する
よくある GC チェック(スタックに関連するものを選びます):
- 直接記述された console/print 文 — ロガーを使用します
- デフォルトエクスポート — 名前付きエクスポートを使用します(JS/TS)
- インラインのマジックナンバー — 名前付き定数を使用します
- 大きなファイル — サイズ上限を超えるファイル(300 行で警告、500 行でエラー)
- TODO/FIXME/HACK コメント — 技術的負債を追跡します
- 未使用のインポート — デッドコードを検出します
- 型注釈の欠落 — (Python/TS)
6b. GC ランナーを作成する
すべての GC チェックを実行して概要を出力する単一のスクリプトを作成します:
npm run gc # or
python scripts/gc_run_all.py # or
make gc
6c. スケジュール実行する GitHub Action を作成する
name: Garbage Collection
on:
schedule:
- cron: '0 9 * * 1' # Every Monday 9am UTC
workflow_dispatch:
permissions:
contents: read
issues: write
jobs:
gc-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup
# Setup language
- name: Run GC
run: {gc_command} > gc-report.txt 2>&1 || true
- name: Create or update issue
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const report = fs.readFileSync('gc-report.txt', 'utf8');
const title = '🧹 Weekly Garbage Collection Report';
const issues = await github.rest.issues.listForRepo({
owner: context.repo.owner, repo: context.repo.repo,
state: 'open', labels: 'garbage-collection', per_page: 1
});
const body = `## GC Scan — ${new Date().toISOString()}\n\n\`\`\`\n${report}\n\`\`\``;
if (issues.data.length > 0) {
await github.rest.issues.createComment({
owner: context.repo.owner, repo: context.repo.repo,
issue_number: issues.data[0].number, body
});
} else {
await github.rest.issues.create({
owner: context.repo.owner, repo: context.repo.repo,
title, body, labels: ['garbage-collection']
});
}
フェーズ 7:プレコミットフック(任意ですが推奨)
JavaScript/TypeScript:
npm install -D husky lint-staged
npx husky init
# .husky/pre-commit: npx lint-staged
# package.json: "lint-staged": { "*.{ts,tsx}": ["eslint --fix"] }
Python:
pip install pre-commit
# .pre-commit-config.yaml with ruff, mypy, pytest hooks
pre-commit install
Go:
# Use golangci-lint as a pre-commit hook
# Or use the pre-commit framework with Go hooks
実行順序
ユーザーが「ハーネスエンジニアリングをセットアップして」と言った場合は、次の順序で実行します:
- フェーズ 0 — 調査(必ず最初に実行し、絶対に省略しない)
- フェーズ 1 — AGENTS.md
- フェーズ 2 — ドキュメント構成 + LAYERS.md + ゴールデン原則
- フェーズ 3 — テストインフラストラクチャ + アーキテクチャ境界テスト
- フェーズ 4 — リンタの境界適用ルール
- フェーズ 5 — CI パイプライン
- フェーズ 6 — ガベージコレクションスクリプト + ワークフロー
- フェーズ 7 — プレコミットフック
開始前にユーザーに尋ねます:「すべてのフェーズをセットアップしますか、それとも特定のフェーズだけにしますか?」
ユーザーが希望した場合は、新しい git worktree で機能ブランチ(feat/harness-engineering)を使用します。
重要なルール
- プロジェクト固有の詳細をハードコードしないでください。 このスキルはあらゆるリポジトリで使用できます。スタックを推測せず、調査してください。
- 書き込む前に読みます。 新しいファイルを生成する前に、必ず既存のファイルを読みます。リポジトリ既存のコードスタイルに合わせてください。
- ドキュメントの再構成には git mv を使用します。 Git の履歴を保持してください。
- すべてのエラーメッセージはエージェントのコンテキストになります。 対処方法の指示はドキュメントだけでなく、エラー出力にも記載してください。
- アーキテクチャテストはラチェットです。 既知の違反リストは減らすことのみ可能で、明示的なレビューなしに増やしてはいけません。
- 既存の動作を壊さないでください。 コードベースに既存の違反がある場合、新しいリンタールールはエラーではなく警告にしてください。
- 作業をテストしてください。 セットアップ後、テストスイート、リンタ、GC スクリプトを実行し、すべてが正常に動作することを確認してください。