polydeukes 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/README.ko.md +30 -70
  2. package/README.md +31 -84
  3. package/dist/baseline.d.ts +37 -1
  4. package/dist/baseline.js +68 -1
  5. package/dist/bin.d.ts +3 -4
  6. package/dist/bin.js +79 -93
  7. package/dist/covenant/bash-line.d.ts +130 -0
  8. package/dist/covenant/bash-line.js +566 -0
  9. package/dist/covenant/declaration-engine.d.ts +108 -0
  10. package/dist/covenant/declaration-engine.js +415 -0
  11. package/dist/covenant/discipline.d.ts +103 -0
  12. package/dist/covenant/discipline.js +667 -0
  13. package/dist/covenant/dispatch.d.ts +153 -0
  14. package/dist/covenant/dispatch.js +237 -0
  15. package/dist/covenant/extract-steps.d.ts +122 -0
  16. package/dist/covenant/extract-steps.js +0 -0
  17. package/dist/covenant/mention.d.ts +117 -0
  18. package/dist/covenant/mention.js +209 -0
  19. package/dist/covenant/module.d.ts +25 -0
  20. package/dist/covenant/module.js +23 -0
  21. package/dist/covenant/mutation-rules.d.ts +40 -0
  22. package/dist/covenant/mutation-rules.js +146 -0
  23. package/dist/covenant/relations.d.ts +46 -0
  24. package/dist/covenant/relations.js +68 -0
  25. package/dist/covenant/run-covenant.d.ts +95 -0
  26. package/dist/covenant/run-covenant.js +164 -0
  27. package/dist/covenant/self-mod.d.ts +55 -0
  28. package/dist/covenant/self-mod.js +84 -0
  29. package/dist/covenant/shell-evidence.d.ts +38 -0
  30. package/dist/covenant/shell-evidence.js +247 -0
  31. package/dist/covenant/shell-mod.d.ts +84 -0
  32. package/dist/covenant/shell-mod.js +213 -0
  33. package/dist/covenant/supply.d.ts +54 -0
  34. package/dist/covenant/supply.js +50 -0
  35. package/dist/covenant/transcript-mod.d.ts +60 -0
  36. package/dist/covenant/transcript-mod.js +254 -0
  37. package/dist/covenant/ttl-witness.d.ts +47 -0
  38. package/dist/covenant/ttl-witness.js +80 -0
  39. package/dist/covenant-check.d.ts +72 -39
  40. package/dist/covenant-check.js +260 -121
  41. package/dist/diff-ir.d.ts +28 -0
  42. package/dist/diff-ir.js +310 -0
  43. package/dist/docs/README.ko.md +60 -0
  44. package/dist/docs/README.md +64 -0
  45. package/dist/docs/catalog.json +480 -0
  46. package/dist/docs/concepts/judgment.ko.md +113 -0
  47. package/dist/docs/concepts/judgment.md +113 -0
  48. package/dist/docs/how-to/configure-project.ko.md +99 -0
  49. package/dist/docs/how-to/configure-project.md +98 -0
  50. package/dist/docs/how-to/connect-surfaces.ko.md +120 -0
  51. package/dist/docs/how-to/connect-surfaces.md +121 -0
  52. package/dist/docs/how-to/write-disciplines.ko.md +179 -0
  53. package/dist/docs/how-to/write-disciplines.md +181 -0
  54. package/dist/docs/index.json +2280 -0
  55. package/dist/docs/reference/cli/covenant-check.ko.md +148 -0
  56. package/dist/docs/reference/cli/covenant-check.md +153 -0
  57. package/dist/docs/reference/cli/docs.ko.md +97 -0
  58. package/dist/docs/reference/cli/docs.md +95 -0
  59. package/dist/docs/reference/cli/explain.ko.md +84 -0
  60. package/dist/docs/reference/cli/explain.md +89 -0
  61. package/dist/docs/reference/cli/init.ko.md +119 -0
  62. package/dist/docs/reference/cli/init.md +119 -0
  63. package/dist/docs/reference/configuration/index.ko.md +553 -0
  64. package/dist/docs/reference/{configuration.md → configuration/index.md} +215 -90
  65. package/dist/docs/reference/packages/adapter-claude-code.ko.md +110 -0
  66. package/dist/docs/reference/{adapter-claude-code.md → packages/adapter-claude-code.md} +47 -19
  67. package/dist/docs/reference/packages/adapter-grok.ko.md +77 -0
  68. package/dist/docs/reference/packages/adapter-grok.md +79 -0
  69. package/dist/docs/reference/packages/core.ko.md +174 -0
  70. package/dist/docs/reference/{core.md → packages/core.md} +74 -12
  71. package/dist/docs/reference/packages/polydeukes.ko.md +195 -0
  72. package/dist/docs/reference/packages/polydeukes.md +204 -0
  73. package/dist/docs/reference/packages/sdk-ts.ko.md +161 -0
  74. package/dist/docs/reference/packages/sdk-ts.md +164 -0
  75. package/dist/docs/troubleshooting.ko.md +144 -0
  76. package/dist/docs/troubleshooting.md +103 -151
  77. package/dist/docs/tutorials/first-judgment.ko.md +82 -0
  78. package/dist/docs/tutorials/first-judgment.md +81 -0
  79. package/dist/docs-catalog.d.ts +25 -0
  80. package/dist/docs-catalog.js +450 -0
  81. package/dist/docs-library.d.ts +23 -0
  82. package/dist/docs-library.js +347 -0
  83. package/dist/docs-markdown.d.ts +32 -0
  84. package/dist/docs-markdown.js +150 -0
  85. package/dist/docs-query.d.ts +11 -40
  86. package/dist/docs-query.js +28 -122
  87. package/dist/docs-types.d.ts +105 -0
  88. package/dist/docs-types.js +2 -0
  89. package/dist/explain.d.ts +1 -1
  90. package/dist/explain.js +37 -22
  91. package/dist/load-config.d.ts +1 -1
  92. package/dist/load-config.js +1 -1
  93. package/dist/pre-state-reader.d.ts +1 -1
  94. package/dist/pre-state-reader.js +1 -1
  95. package/dist/scaffold-project.d.ts +2 -2
  96. package/dist/scaffold-project.js +9 -3
  97. package/dist/schema/polydeukes.schema.json +12 -0
  98. package/dist/worktree-reader.d.ts +19 -0
  99. package/dist/worktree-reader.js +30 -0
  100. package/package.json +3 -17
  101. package/dist/claude-code-hook.d.ts +0 -79
  102. package/dist/claude-code-hook.js +0 -372
  103. package/dist/claude-code.d.ts +0 -6
  104. package/dist/claude-code.js +0 -6
  105. package/dist/covenant-module.d.ts +0 -25
  106. package/dist/covenant-module.js +0 -42
  107. package/dist/docs/configuration.md +0 -103
  108. package/dist/docs/installation.md +0 -241
  109. package/dist/docs/reference/adapter-git.md +0 -100
  110. package/dist/docs/reference/covenant.md +0 -116
  111. package/dist/docs/reference/polydeukes.md +0 -315
  112. package/dist/index.d.ts +0 -22
  113. package/dist/index.js +0 -21
  114. package/dist/init-claude-code.d.ts +0 -52
  115. package/dist/init-claude-code.js +0 -469
  116. package/dist/init-grok.d.ts +0 -51
  117. package/dist/init-grok.js +0 -242
@@ -0,0 +1,310 @@
1
+ /**
2
+ * unified diff → `CovenantInput`. One pure translation, no judgment and no disk.
3
+ *
4
+ * The accepted grammar is finite: `diff --git` blocks and header-less `---`/`+++` blocks,
5
+ * covering creation, deletion, modification, mode-only changes, renames, and binary blobs.
6
+ * Anything else throws, so an unrecognised shape fails the run closed instead of translating
7
+ * to a partial observation.
8
+ *
9
+ * A modification's `pre`/`post` are the hunk's `-` and `+` lines, never the whole file: a
10
+ * unified diff carries the changed lines and the context around them, and reconstructing the
11
+ * file from them is not a translation. A creation and a deletion carry the whole text because
12
+ * every line of the file is in the hunk.
13
+ */
14
+ /** The tool name a staged write is dispatched under — telemetry and configs read it. */
15
+ export const STAGED_WRITE = 'staged-write';
16
+ /** The tool name a staged deletion is dispatched under. */
17
+ export const STAGED_DELETE = 'staged-delete';
18
+ function emptyBlock() {
19
+ return { binary: false, deletedFile: false, newFile: false, removed: [], added: [] };
20
+ }
21
+ /** A path as git prints it after `rename from` / `rename to`: quoted only when it has to be. */
22
+ function readBarePath(raw) {
23
+ return raw.startsWith('"') ? unquotePath(raw) : raw;
24
+ }
25
+ /**
26
+ * Decode git's C-quoted path form: the octal escapes are BYTES of the path, so they are
27
+ * collected and decoded as UTF-8 together — decoding each one on its own would turn every
28
+ * non-ASCII character into replacement characters.
29
+ */
30
+ function unquotePath(quoted) {
31
+ const body = quoted.slice(1, -1);
32
+ const bytes = [];
33
+ for (let at = 0; at < body.length; at += 1) {
34
+ const char = body[at];
35
+ if (char !== '\\') {
36
+ bytes.push(...Buffer.from(char, 'utf-8'));
37
+ continue;
38
+ }
39
+ const next = body[at + 1];
40
+ const octal = body.slice(at + 1, at + 4);
41
+ if (/^[0-7]{3}$/.test(octal)) {
42
+ bytes.push(Number.parseInt(octal, 8));
43
+ at += 3;
44
+ continue;
45
+ }
46
+ const simple = {
47
+ t: 0x09,
48
+ n: 0x0a,
49
+ r: 0x0d,
50
+ '"': 0x22,
51
+ '\\': 0x5c,
52
+ };
53
+ bytes.push(simple[next] ?? Buffer.from(next, 'utf-8')[0] ?? 0);
54
+ at += 1;
55
+ }
56
+ return Buffer.from(bytes).toString('utf-8');
57
+ }
58
+ /**
59
+ * The path a `---`/`+++` line names, or null for `/dev/null`. A quoted path is unquoted
60
+ * before anything is cut, because a quoted path may itself contain a tab; an unquoted one is
61
+ * cut at the tab `diff -u` puts its timestamp behind. Exactly one `a/` or `b/` level is
62
+ * stripped, so a repository directory literally named `a/` survives.
63
+ */
64
+ function readPath(rest, prefix) {
65
+ let path;
66
+ if (rest.startsWith('"')) {
67
+ const end = rest.lastIndexOf('"');
68
+ path = unquotePath(rest.slice(0, end + 1));
69
+ }
70
+ else {
71
+ const tab = rest.indexOf('\t');
72
+ path = tab === -1 ? rest : rest.slice(0, tab);
73
+ }
74
+ if (path === '/dev/null')
75
+ return null;
76
+ return path.startsWith(prefix) ? path.slice(prefix.length) : path;
77
+ }
78
+ /** The two paths of a `diff --git a/X b/Y` header, or undefined when they cannot be read. */
79
+ function readHeaderPaths(rest) {
80
+ if (rest.startsWith('"')) {
81
+ const end = rest.indexOf('" "');
82
+ if (end === -1)
83
+ return undefined;
84
+ const old = unquotePath(rest.slice(0, end + 1));
85
+ const next = unquotePath(rest.slice(end + 2));
86
+ return { old: stripOnce(old, 'a/'), new: stripOnce(next, 'b/') };
87
+ }
88
+ // Unquoted paths may contain spaces, and git writes no separator between the two. The
89
+ // halves are equal in length whenever the prefixes are, which is git's own output; the
90
+ // midpoint split is what recovers them.
91
+ const middle = rest.length % 2 === 1 ? (rest.length - 1) / 2 : -1;
92
+ if (middle > 0 && rest[middle] === ' ') {
93
+ return {
94
+ old: stripOnce(rest.slice(0, middle), 'a/'),
95
+ new: stripOnce(rest.slice(middle + 1), 'b/'),
96
+ };
97
+ }
98
+ const at = rest.indexOf(' ');
99
+ if (at === -1)
100
+ return undefined;
101
+ return { old: stripOnce(rest.slice(0, at), 'a/'), new: stripOnce(rest.slice(at + 1), 'b/') };
102
+ }
103
+ function stripOnce(path, prefix) {
104
+ return path.startsWith(prefix) ? path.slice(prefix.length) : path;
105
+ }
106
+ /** The old and new line counts a hunk header declares, or undefined when it is not one. */
107
+ function readHunkCounts(line) {
108
+ const match = /^@@ -\d+(?:,(\d+))? \+\d+(?:,(\d+))? @@/.exec(line);
109
+ if (match === null)
110
+ return undefined;
111
+ return {
112
+ old: match[1] === undefined ? 1 : Number.parseInt(match[1], 10),
113
+ new: match[2] === undefined ? 1 : Number.parseInt(match[2], 10),
114
+ };
115
+ }
116
+ /**
117
+ * Split the text into file blocks, reading hunk bodies by the line counts their headers
118
+ * declare. The counts are what keeps a removed `-- note` line (which reads as `--- note`)
119
+ * from being taken for a new file header: header lines are only recognised outside a hunk.
120
+ */
121
+ function parseBlocks(text) {
122
+ const lines = text.split('\n');
123
+ const blocks = [];
124
+ let block;
125
+ const open = () => {
126
+ if (block === undefined) {
127
+ block = emptyBlock();
128
+ blocks.push(block);
129
+ }
130
+ return block;
131
+ };
132
+ for (let at = 0; at < lines.length; at += 1) {
133
+ const line = lines[at];
134
+ if (line === '' && at === lines.length - 1)
135
+ continue;
136
+ if (line.startsWith('diff --cc ') || line.startsWith('diff --combined ')) {
137
+ throw new Error(`unified diff: combined diffs are not translatable: ${line}`);
138
+ }
139
+ if (line.startsWith('diff --git ')) {
140
+ block = emptyBlock();
141
+ blocks.push(block);
142
+ block.headerPaths = readHeaderPaths(line.slice('diff --git '.length));
143
+ continue;
144
+ }
145
+ if (line.startsWith('--- ')) {
146
+ // A second `---` outside a hunk starts a new header-less block.
147
+ if (block !== undefined && block.oldPath !== undefined)
148
+ block = undefined;
149
+ open().oldPath = readPath(line.slice(4), 'a/');
150
+ continue;
151
+ }
152
+ if (line.startsWith('+++ ')) {
153
+ const current = open();
154
+ if (current.oldPath === undefined) {
155
+ throw new Error(`unified diff: '+++' line with no '---' partner: ${line}`);
156
+ }
157
+ current.newPath = readPath(line.slice(4), 'b/');
158
+ continue;
159
+ }
160
+ const counts = readHunkCounts(line);
161
+ if (counts !== undefined) {
162
+ const current = open();
163
+ if (current.oldPath === undefined || current.newPath === undefined) {
164
+ if (current.headerPaths === undefined) {
165
+ throw new Error(`unified diff: hunk with no file header: ${line}`);
166
+ }
167
+ }
168
+ let oldLeft = counts.old;
169
+ let newLeft = counts.new;
170
+ while ((oldLeft > 0 || newLeft > 0) && at + 1 < lines.length) {
171
+ const body = lines[at + 1];
172
+ at += 1;
173
+ if (body.startsWith('\\'))
174
+ continue;
175
+ // A line the declared counts have no room for is a malformed hunk: judging the
176
+ // lines that fit and dropping the rest would be an observation smaller than the
177
+ // input, so the whole run fails closed instead.
178
+ if (body.startsWith('+') && newLeft > 0) {
179
+ current.added.push(body.slice(1));
180
+ newLeft -= 1;
181
+ continue;
182
+ }
183
+ if (body.startsWith('-') && oldLeft > 0) {
184
+ current.removed.push(body.slice(1));
185
+ oldLeft -= 1;
186
+ continue;
187
+ }
188
+ if ((body.startsWith(' ') || body === '') && oldLeft > 0 && newLeft > 0) {
189
+ oldLeft -= 1;
190
+ newLeft -= 1;
191
+ continue;
192
+ }
193
+ throw new Error(`unified diff: unknown hunk line: ${body}`);
194
+ }
195
+ continue;
196
+ }
197
+ if (line.startsWith('rename from ')) {
198
+ open().renameFrom = readBarePath(line.slice('rename from '.length));
199
+ continue;
200
+ }
201
+ if (line.startsWith('rename to ')) {
202
+ open().renameTo = readBarePath(line.slice('rename to '.length));
203
+ continue;
204
+ }
205
+ if (line.startsWith('deleted file mode ')) {
206
+ open().deletedFile = true;
207
+ continue;
208
+ }
209
+ if (line.startsWith('new file mode ')) {
210
+ open().newFile = true;
211
+ continue;
212
+ }
213
+ if (line.startsWith('Binary files ') || line === 'GIT binary patch') {
214
+ const current = open();
215
+ current.binary = true;
216
+ if (line.endsWith('and /dev/null differ'))
217
+ current.deletedFile = true;
218
+ }
219
+ // Everything else outside a hunk is an extended header line (`index`, `old mode`,
220
+ // `similarity index`, a binary patch's base85 payload) that names nothing this
221
+ // translation reads.
222
+ }
223
+ return blocks;
224
+ }
225
+ /** The toolCalls one block translates to, in the order the judgment sees them. */
226
+ function blockToolCalls(block) {
227
+ const { renameFrom, renameTo } = block;
228
+ if (renameFrom !== undefined && renameTo !== undefined) {
229
+ return [
230
+ {
231
+ name: STAGED_DELETE,
232
+ args: { file_path: renameFrom },
233
+ fileChange: { kind: 'delete', path: renameFrom },
234
+ },
235
+ {
236
+ name: STAGED_WRITE,
237
+ args: { file_path: renameTo },
238
+ fileChange: {
239
+ kind: 'modify',
240
+ path: renameTo,
241
+ pre: block.removed.join('\n'),
242
+ post: block.added.join('\n'),
243
+ },
244
+ },
245
+ ];
246
+ }
247
+ // An empty file's deletion or creation carries no `---`/`+++` pair and no hunk, so the
248
+ // mode line is the only evidence of which one it is.
249
+ const deletion = block.newPath === null || block.deletedFile;
250
+ const path = deletion
251
+ ? (block.oldPath ?? block.headerPaths?.old)
252
+ : (block.newPath ?? block.headerPaths?.new);
253
+ if (path === undefined || path === null) {
254
+ throw new Error('unified diff: a file block names no path');
255
+ }
256
+ if (block.binary) {
257
+ return [{ name: deletion ? STAGED_DELETE : STAGED_WRITE, args: { file_path: path } }];
258
+ }
259
+ if (deletion) {
260
+ return [
261
+ {
262
+ name: STAGED_DELETE,
263
+ args: { file_path: path },
264
+ fileChange: { kind: 'delete', path, pre: block.removed.join('\n') },
265
+ },
266
+ ];
267
+ }
268
+ if (block.oldPath === null || block.newFile) {
269
+ return [
270
+ {
271
+ name: STAGED_WRITE,
272
+ args: { file_path: path },
273
+ fileChange: { kind: 'create', path, post: block.added.join('\n') },
274
+ },
275
+ ];
276
+ }
277
+ return [
278
+ {
279
+ name: STAGED_WRITE,
280
+ args: { file_path: path },
281
+ fileChange: {
282
+ kind: 'modify',
283
+ path,
284
+ pre: block.removed.join('\n'),
285
+ post: block.added.join('\n'),
286
+ },
287
+ },
288
+ ];
289
+ }
290
+ /**
291
+ * Translate a unified diff into the covenant input IR: one toolCall per file block in input
292
+ * order (a rename is two, the deletion first), and no `actor` key — a diff proves no author.
293
+ */
294
+ export function covenantInputFromUnifiedDiff(spec) {
295
+ const blocks = parseBlocks(spec.text);
296
+ // Text that is not blank yet contains no block the grammar recognizes — a colored diff,
297
+ // a pager banner, anything else — must not translate to "nothing staged": an empty
298
+ // observation is a pass, and this input may describe a whole commit.
299
+ if (blocks.length === 0 && spec.text.trim() !== '') {
300
+ throw new Error('unified diff: no file block recognized in the input');
301
+ }
302
+ const toolCalls = [];
303
+ for (const block of blocks) {
304
+ if (block.oldPath !== undefined && block.newPath === undefined) {
305
+ throw new Error(`unified diff: '---' line with no '+++' partner: ${block.oldPath}`);
306
+ }
307
+ toolCalls.push(...blockToolCalls(block));
308
+ }
309
+ return { toolCalls, subagentSpawns: [], userMessages: [] };
310
+ }
@@ -0,0 +1,60 @@
1
+ # 폴리데우케스 문서
2
+
3
+ [English](./README.md) · **한국어**
4
+
5
+ > AI 코딩 파트너와 함께 개발하기 위한 규율 프레임워크입니다. 궁금한 곳부터 읽으십시오.
6
+
7
+ <a id="start-here"></a>
8
+ ## 여기서 시작하십시오
9
+
10
+ | 하려는 것 | 읽을 문서 |
11
+ |---|---|
12
+ | 첫 눈에 보이는 판정을 보고 싶다 | [첫 판정](./tutorials/first-judgment.ko.md) — 설치하고 Claude Code를 배선한 뒤 보호된 편집이 판정되는 모습을 봅니다 |
13
+ | Claude Code, Grok, git을 연결하고 싶다 | [표면 연결하기](./how-to/connect-surfaces.ko.md) — 세션과 커밋 배선, Grok 포함 |
14
+ | 프로젝트 설정을 다듬고 싶다 | [프로젝트 설정하기](./how-to/configure-project.ko.md) — 발견, IDE 지원, advise와 block의 선택 |
15
+ | 실제 규율을 쓰고 싶다 | [규율 작성하기](./how-to/write-disciplines.ko.md) — 실전 선언 예제, 특히 locale key pairing |
16
+ | 차단이나 건너뜀에서 회복하고 싶다 | [문제 해결](./troubleshooting.ko.md) — fail-closed 상태, 증인 밸브, 로그 |
17
+ | 이 프레임워크가 왜 있는지 알고 싶다 | [왜 폴리데우케스인가?](./why-polydeukes.ko.md) — 설계 백서 |
18
+ | 이 문서에 기여하고 싶다 | [문서에 기여하기](./contributing.ko.md) — 영한 쌍, 안정 ID, 카탈로그, 검사 |
19
+
20
+ <a id="reference"></a>
21
+ ## 레퍼런스
22
+
23
+ 설정 키, 하위 명령, 종료 코드를 설명합니다. 계획이 아니라 현재 동작을 기준으로 서술합니다.
24
+
25
+ | 문서 | 답하는 것 |
26
+ |---|---|
27
+ | [설정 레퍼런스](./reference/configuration/index.ko.md) | `polydeukes.config.yaml`에 무엇을 넣을 수 있고 각 키가 무엇을 하는지 |
28
+ | [`polydeukes` (`pdks` CLI)](./reference/packages/polydeukes.ko.md) | 패키지 계약과 그 안에 있는 판정기. 서브커맨드는 [`reference/cli/`](./reference/cli/covenant-check.ko.md) |
29
+ | [`@polydeukes/core`](./reference/packages/core.ko.md) | 프로토콜, 입력 IR, 설정 스키마, 텔레메트리 |
30
+ | [`@polydeukes/adapter-claude-code`](./reference/packages/adapter-claude-code.ko.md) | Claude Code 세션 표면입니다. 훅 페이로드에서 입력 IR로 |
31
+ | [`@polydeukes/adapter-grok`](./reference/packages/adapter-grok.ko.md) | Grok 세션 표면입니다. 훅 페이로드에서 입력 IR로 |
32
+
33
+ <a id="shape-of-the-thing"></a>
34
+ ## 한 페이지로 보는 구조
35
+
36
+ 폴리데우케스는 개발자나 AI 에이전트가 하려는 일을 판정하고 결과를 기록합니다.
37
+ 기본값으로는 작업을 차단하지 않습니다. 설계의 바탕은 다음 세 가지입니다.
38
+
39
+ **약속은 가두기 위한 울타리가 아닙니다.** 여기서 확인하는 규율은 개발자가 이미 스스로 지켜 온 것들입니다. AI에게만큼 사람에게도 똑같이 적용되고, 프레임워크를 만든
40
+ 사람도 매일 그 판정을 받습니다.
41
+
42
+ **판정과 차단은 별개의 결정입니다.** 선언된 규율은 적용 범위에 해당하는 호출마다 판정합니다.
43
+ 위반했을 때 호출을 차단할지는 별도로 정합니다. 기본값으로는 사유를 기록하고 호출을 계속합니다.
44
+ 작성자는 `enforce: block`으로 차단을 선택할 수 있습니다. 별도 선택 없이 차단하는 것은
45
+ 프레임워크 자체를 보호하는 경우뿐입니다.
46
+
47
+ **모든 판정은 행 하나를 남깁니다.** `.polydeukes/roi.log`가 판정 결과마다 한 줄씩, 낱말 여섯 개짜리 어휘로 담습니다. 이 프로젝트가 자기 결함을 찾는
48
+ 방법이 그 기록입니다. 백서에 적힌 결함들도 전부 코드를 읽어서가 아니라 행을 세어서 나왔습니다.
49
+
50
+ <a id="two-surfaces"></a>
51
+ ## 두 표면
52
+
53
+ | 표면 | 판정 대상 | 배선 방법 | 대상 |
54
+ |---|---|---|---|
55
+ | **세션** | 도구 호출, 실행되기 전에 | `pdks-claude-code init` 또는 `pdks-grok init` | AI 파트너와 함께 개발하는 프로젝트 |
56
+ | **커밋** | stdin의 unified diff — 스테이징 영역, 작업 트리, ref 범위 | `git diff --cached`를 파이프로 넘기는 pre-commit 훅, 또는 필요할 때 직접 실행 | 혼자 개발하는 사람, 그리고 CI |
57
+
58
+ 커밋 판정기는 필요할 때 직접 실행할 수도 있습니다. 작업 후에는 `git diff HEAD | pdks covenant check --diff`,
59
+ PR 전에는 `git diff main...HEAD | …`를 사용합니다. 같은 판정 기준을 종료 코드로 답하며 묻지
60
+ 않습니다. 관문은 그 코드를 소비하는 쪽입니다.
@@ -0,0 +1,64 @@
1
+ # Polydeukes documentation
2
+
3
+ **English** · [한국어](./README.ko.md)
4
+
5
+ > A development discipline framework for building alongside an AI coding partner. Start where your
6
+ question is.
7
+
8
+ <a id="start-here"></a>
9
+ ## Start here
10
+
11
+ | If you want to | Read |
12
+ |---|---|
13
+ | Get to a first visible judgment | [First judgment](./tutorials/first-judgment.md) — install, wire Claude Code, and watch one protected edit get judged |
14
+ | Connect Claude Code, Grok, or git | [Connect the surfaces](./how-to/connect-surfaces.md) — session and commit setup, including Grok |
15
+ | Shape the project config | [Configure the project](./how-to/configure-project.md) — discovery, IDE support, and advise versus block |
16
+ | Write a real discipline | [Write disciplines](./how-to/write-disciplines.md) — worked declarations, especially locale key pairing |
17
+ | Recover from a block or skip | [Troubleshooting](./troubleshooting.md) — the fail-closed states, the witness valve, and the log |
18
+ | Understand why the framework exists | [Why Polydeukes?](./why-polydeukes.md) — the design whitepaper |
19
+ | Contribute to these docs | [Contributing](./contributing.md) — bilingual pairs, stable IDs, catalog, and checks |
20
+
21
+ <a id="reference"></a>
22
+ ## Reference
23
+
24
+ Every key, every subcommand, every exit code. These describe the present state only — nothing here
25
+ is aspirational.
26
+
27
+ | Document | Answers |
28
+ |---|---|
29
+ | [Configuration reference](./reference/configuration/index.md) | What may go in `polydeukes.config.yaml`, and what each key does |
30
+ | [`polydeukes` (the `pdks` CLI)](./reference/packages/polydeukes.md) | Package contract, and the judge that lives inside it; subcommands live under [`reference/cli/`](./reference/cli/covenant-check.md) |
31
+ | [`@polydeukes/core`](./reference/packages/core.md) | The protocol, the input IR, the config schema, telemetry |
32
+ | [`@polydeukes/adapter-claude-code`](./reference/packages/adapter-claude-code.md) | Claude Code session surface — hook payloads become the input IR |
33
+ | [`@polydeukes/adapter-grok`](./reference/packages/adapter-grok.md) | Grok session surface — hook payloads become the input IR |
34
+
35
+ <a id="shape-of-the-thing"></a>
36
+ ## The shape of the thing, in one page
37
+
38
+ Polydeukes judges what a developer or an AI agent is about to do, records the verdict, and by
39
+ default lets the work proceed. Three ideas carry the rest.
40
+
41
+ **A covenant is a promise, not a fence.** The disciplines it enforces are the ones a good developer
42
+ already imposes on themselves. They bind the human exactly as much as the AI, and the framework's
43
+ own authors get judged by them daily.
44
+
45
+ **Judging and stopping are separate decisions.** Every declared discipline is judged on every
46
+ matching call. What a break then does is a second question: by default it is recorded with its
47
+ reason and the call continues. `enforce: block` is a promotion the author chooses. The only things
48
+ that stop a call unasked are the framework's own protections.
49
+
50
+ **Every judgment leaves a row.** `.polydeukes/roi.log` holds one line per verdict, in a vocabulary
51
+ of six words. That record is how this project finds its own defects — including the ones described
52
+ in the whitepaper, which were all found by counting rows rather than by reading code.
53
+
54
+ <a id="two-surfaces"></a>
55
+ ## Two surfaces
56
+
57
+ | Surface | Judges | Wired by | For |
58
+ |---|---|---|---|
59
+ | **Session** | A tool call, before it runs | `pdks-claude-code init` or `pdks-grok init` | A project developed with an AI partner |
60
+ | **Commit** | A unified diff on stdin — staged, the working tree, or a ref range | A pre-commit hook piping `git diff --cached`, or run on demand | A human developing alone, and CI |
61
+
62
+ The commit judge also answers on demand: `git diff HEAD | pdks covenant check --diff` after a task,
63
+ `git diff main...HEAD | …` before a PR. Same verdict a commit would receive, delivered as an exit
64
+ code with no prompt — the gate is whatever consumes that code.