Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,42 @@ jobs:
- name: Build
run: pnpm run build

standards:
name: format / lint / architecture (Node 22)
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 11.18.0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Format check
run: pnpm run format:check

- name: Lint
run: pnpm run lint

- name: Architecture validator tests
run: pnpm run architecture:test

- name: Architecture/static validation
run: pnpm run architecture:check

init-test-windows:
name: init.test.ts (Windows, Node ${{ matrix.node-version }})
runs-on: windows-latest
Expand Down
11 changes: 9 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ lockfile は `pnpm-lock.yaml`。他のパッケージマネージャの lockfile

`tree-sitter` 系はネイティブビルドが必要(`pnpm approve-builds`)。初回 `pnpm install` 時に `ERR_PNPM_IGNORED_BUILDS` が出たら実行する。

CI は `.github/workflows/ci.yml`(install → typecheck → test → build、Node 22/24)。デプロイ系ワークフローは追加提案しない。
CI は `.github/workflows/ci.yml`(Node 22/24 の install → typecheck → test → build、Node 22 の format / lint / architecture)。デプロイ系ワークフローは追加提案しない。

---

Expand Down Expand Up @@ -208,7 +208,7 @@ Claude Code 側へ反映するときは `/mcp reconnect mottainai`、または

## 7. コード規約

`src/` の既存スタイルに合わせる。lint / formatter は未導入なので、**周囲のコードを模倣する**のが基準
`src/` の既存スタイルに合わせる。実行可能な規則は `scripts/architecture-check.mjs` / `eslint.config.mjs` / `prettier.config.mjs` を正本とし、周囲のコード模倣は人間レビュー規則として残す

- TypeScript strict / ESM(`module: NodeNext`)。相対 import は `.js` 拡張子付き(`./config.js`)
- 命名は完全語。略語を作らない(`config` は既存だが `cfg` / `impl` / `res` を新規に増やさない)
Expand All @@ -217,6 +217,12 @@ Claude Code 側へ反映するときは `/mcp reconnect mottainai`、または
- テストは `node:test` + `node:assert/strict`。対象ファイルと同階層に `<name>.test.ts`
- 例外は `throw new Error("<lowercase message>")` で引数検証エラーを返す既存パターンに合わせる

### 実行可能規則(Issue #25)

正本は設定ファイル自体(`scripts/architecture-check.mjs`、`eslint.config.mjs`、`prettier.config.mjs`、`package.json` scripts)。コマンド一覧・検証内容は `docs/coding-standards.md` 参照。ドキュメント側に規則を二重列挙しない(`CONTRIBUTING.md` 第9項)。

人間レビュー専用: 完全語identifier、whyコメント、圧縮意味保存、behavior invariant、subjective architecture taste。これらをlint failureへ追加しない。

---

## 8. トークン規律
Expand All @@ -236,6 +242,7 @@ Claude Code 側へ反映するときは `/mcp reconnect mottainai`、または
| 応答スタイル | `CLAUDE.md` |
| 探索 hook | `.claude/hooks/warn-grep.sh` |
| Issue and PR contract | `docs/governance.md` |
| Executable coding standard | `docs/coding-standards.md` / `scripts/architecture-check.mjs` |

機能別の詳細ドキュメント(`docs/*.md`)は整理中。Issue・PR・差分連動規則の正本は`docs/governance.md`と`scripts/governance-rules.json`。

Expand Down
22 changes: 19 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,18 @@ pnpm approve-builds
pnpm run build
pnpm test
pnpm run typecheck
pnpm run format:check
pnpm run lint
pnpm run architecture:test
pnpm run architecture:check
pnpm run verify:standards
```

There is no separate lint/format tool configured yet — match the existing
style in the file you're editing (see [Code conventions](#code-conventions)
below).
The executable standard is defined by `eslint.config.mjs`,
`prettier.config.mjs`, and `scripts/architecture-check.mjs`. The formatter
currently checks the new standard-tooling files only; broad reformatting of
legacy production code stays out of this Issue. Use `pnpm run verify:standards`
before submitting a change.

## Making changes

Expand Down Expand Up @@ -68,6 +75,9 @@ below).
8. Update relevant docs in the same commit/PR as the behavior change
(`README.md`, `docs/*.md`) — stale docs are worse than no docs.

9. Keep executable rules in the formatter/lint/architecture configuration.
Do not duplicate those rules as a second normative list in documentation.

## Commit messages

This repo uses [Conventional Commits](https://www.conventionalcommits.org/):
Expand All @@ -92,6 +102,12 @@ for examples from this repository.
- MCP tool `annotations` (`readOnlyHint`, `destructiveHint`, etc.) must match
real behavior. Don't add side effects to a tool annotated read-only.

Executable checks enforce import/runtime safety, protocol stdout purity,
process/global boundaries, dependency direction, unsafe type escapes, and the
shared local-tool output envelope. Human review remains responsible for naming,
why-comments, compression semantics, behavioral invariants, and subjective
architecture judgment.

## Pull requests

- Describe what changed and why, not just what.
Expand Down
70 changes: 70 additions & 0 deletions docs/coding-standards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Executable coding standard

Issue #25 turns the high-value repository boundaries into local and CI checks.
The check configuration and AST validator are the normative sources; this
document explains scope and intent without duplicating their rule tables.

## Commands

```bash
pnpm run format:check
pnpm run lint
pnpm run architecture:test
pnpm run architecture:check
pnpm run verify:standards
```

`verify:standards` runs the four checks together. CI runs the same checks as
separate steps so format, lint, validator fixtures, and project validation have
distinct failure causes.

## Tool selection

- Prettier `3.6.2` provides deterministic formatting for the ESM/TypeScript
tool files and has no runtime dependency on the gateway.
- ESLint `9.29.0` with `typescript-eslint` `8.66.0` provides the pinned flat
configuration and a small safety rule set for Node 22/24.
- `scripts/architecture-check.mjs` uses the repository's pinned TypeScript
compiler API. It parses ASTs, resolves relative modules with NodeNext
resolution, and builds a production import graph; it does not implement
semantic rules with grep.

The formatter scope is intentionally limited to the new standard-tooling files
and `package.json`. Reformatting the existing production tree would create a
large mechanical diff and belongs in a separate change.

## Boundary model

The validator enforces runtime dependency edges in this direction:

```text
entry -> upstream / adaptive / compression -> persistence / shared / utility
```

`src/config.ts`, `src/envelope.ts`, `src/logging.ts`, and `src/telemetry.ts`
are shared boundaries. The existing `config.ts -> adaptive/metadata.ts` edge is
the documented metadata exception. Type-only imports are checked for extension
and resolution but are excluded from runtime cycle detection.

The executable boundaries are `src/index.ts` and `src/cli.ts`; `src/server.ts`
owns MCP signal lifecycle registration. `src/workflow/domain/identity-resolve-worker.mjs`
and `src/workflow/domain/task-start-worker.mjs` are separate executable workers.
The task worker may read argv and write its JSON result to stdout. Environment
reads remain limited to the allowlisted configuration, telemetry, policy,
upstream, CLI, persistence, and workflow bootstrap boundaries in the validator.

## Suppressions

Production exceptions require a local marker with a reason, for example:

```ts
// architecture-check allow: double-assertion -- validated native interop boundary
```

Broad disable comments are not an accepted way to pass CI. New exceptions must
be narrow, explain the boundary, and update the validator allowlist or marker
contract when needed.

Human-only conventions remain outside CI: full-word identifiers, why-comments,
compression meaning preservation, behavioral invariants, and subjective
architecture judgment.
33 changes: 33 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import tseslint from "typescript-eslint";

export default tseslint.config(
{
ignores: [".codegraph/**", ".mottainai/**", "dist/**", "node_modules/**"],
},
{
files: ["src/**/*.ts", "src/**/*.mjs", "scripts/**/*.mjs", "eslint.config.mjs"],
languageOptions: {
parser: tseslint.parser,
parserOptions: { ecmaVersion: "latest", sourceType: "module" },
},
linterOptions: {
noInlineConfig: true,
reportUnusedDisableDirectives: "error",
},
plugins: { "@typescript-eslint": tseslint.plugin },
rules: {
"no-constant-binary-expression": "error",
"no-unreachable": "error",
"@typescript-eslint/ban-ts-comment": [
"error",
{
"ts-check": false,
"ts-expect-error": "allow-with-description",
"ts-ignore": "allow-with-description",
"ts-nocheck": "allow-with-description",
},
],
"@typescript-eslint/no-explicit-any": "error",
},
},
);
11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
"governance:issue": "node scripts/validate-issue.mjs",
"governance:branch": "node scripts/validate-branch-name.mjs",
"governance:test": "node --test scripts/governance.test.mjs",
"format": "prettier --write 'scripts/architecture-check.mjs' 'scripts/architecture-check.test.mjs' 'eslint.config.mjs' 'prettier.config.mjs' 'package.json'",
"format:check": "prettier --check 'scripts/architecture-check.mjs' 'scripts/architecture-check.test.mjs' 'eslint.config.mjs' 'prettier.config.mjs' 'package.json'",
"lint": "eslint 'src/**/*.ts' 'src/**/*.mjs' 'scripts/**/*.mjs' 'eslint.config.mjs'",
"architecture:test": "node --test scripts/architecture-check.test.mjs",
"architecture:check": "node scripts/architecture-check.mjs",
"verify:standards": "pnpm run format:check && pnpm run lint && pnpm run architecture:test && pnpm run architecture:check",
"typecheck": "tsc --noEmit",
"smoke-test": "node scripts/smoke-test.mjs",
"prepack": "pnpm run build",
Expand All @@ -38,8 +44,11 @@
},
"devDependencies": {
"@types/node": "^22.15.3",
"eslint": "9.29.0",
"prettier": "3.6.2",
"tsx": "^4.19.4",
"typescript": "^5.8.3"
"typescript": "^5.8.3",
"typescript-eslint": "8.66.0"
},
"engines": {
"node": ">=22.13"
Expand Down
Loading
Loading