summaryrefslogtreecommitdiff
path: root/doc/Design.md
blob: 80b5acc76d67a125dde69de72c247e5b504baad4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
# AI Agent Sandbox MCP Server — 設計書

**文書名:** `Design.md`  
**版:** 0.1 Draft  
**上位仕様:** `Specifications.md`  
**対象:** Windows 11 x64 / C# 14 / .NET 10 LTS

---

## 1. 設計方針

### 1.1 基本原則

- 仕様で定義された性質を設計が満たすことを最優先する。
- LLMを信頼境界に置かない。決定的に検査可能なものはC#とWindows機構で検査する。
- 外部MCP Tool surfaceを2個に固定し、内部機能を外部へ漏らさない。
- Windows native security primitiveを薄く組み合わせ、独自Sandbox frameworkを作らない。
- 設定から緩和するホワイトリスト方式を採用する。
- 一時的なOS変更はtransactionとして扱い、crash recovery可能にする。
- AI生成実装が勝手に概念・層・依存を増やさないよう、語彙とmodule boundaryを固定する。
### 1.2 参照するIPAの記述観点
IPA資料が示す「構造」「機能」「振る舞い」「非機能」を、本設計では Architecture / Interface / State Transition / Quality & Invariant に対応づける。Verificationは `Specifications.md` のRequirement IDと本書の設計要素をtraceすることで行う。

---

## 2. 技術スタック
| 区分 | 採用 | 理由 |
| --- | --- | --- |
| OS | Windows 11 x64 | AppContainer、NTFS ACL、Job Object、WFPを直接利用するため |
| Language | C# 14 | Windows interopとMCP/JSON/asyncの両立 |
| Runtime | NET 10 LTS | LTS運用 |
| Editor | VS Code + C# Dev Kit | 既定開発環境 |
| Build | dotnet CLI / MSBuild | 追加build systemを不要にする |
| Package | NuGet | C#標準package管理 |
| MCP | 公式 ModelContextProtocol C# SDK | stdio/Streamable HTTP実装 |
| Win32 binding | Microsoft.Windows.CsWin32 | 必要Win32 APIだけ型付き生成 |
| Ollama | HttpClient + REST API | 専用SDK依存を避ける |
| JSON | System.Text.Json | MCP周辺・locale・audit |
| YAML | 小規模YAML parser library 1つ | 主設定のみ。追加依存はこれ以上増やさない |
| IPC | System.IO.Pipes | Sandbox worker連携 |
| Logging | Microsoft.Extensions.Logging | stderr/file sinkを統一 |
| Test | xUnit | unit/integration/security test |
### 2.1 明示的非採用
- Python
- Node.js / TypeScript
- CMake
- vcpkg
- Docker
- WSL
- ASP.NET Core application framework(MCP SDKが内部利用する部分を除く)
- Database/ORM
- 独自RPC
- 汎用Workflow engine
- 汎用Graph library
- Ollama専用SDK
- Legacy HTTP+SSE compatibility

---

## 3. 論理アーキテクチャ
```text
MCP Client
   │  stdio / Streamable HTTP(loopback)
   ▼
MCP Adapter ───────────── Localization
   │
   ▼
Agent Runtime ─── Session Store (memory)
   ├── Prompt Composer ── Skill Selector/Loader
   ├── Ollama Client ───── Ollama localhost
   ├── Token Planner ───── TaskGraph / PERT / CPM
    └── Internal Tool Dispatcher
              │
              ▼
 User Sandbox Configuration
              │
              ▼
 Sandbox Environment Resolution
   ├── Workspace / Mount / Reparse Resolution
   ├── Executable Alias / Runtime Resolution
   ├── Executable Approval Resolution
   ├── Network Resolution
   └── Resource Resolution
              │
              ▼
   Effective Sandbox Policy
              │
              ▼
         Policy Engine
             │
             ▼
        Sandbox Broker
        ├── Less Privileged AppContainer (LPAC)
        ├── NTFS ACL
        ├── Job Object
        ├── WFP
        └── Named Pipe
             │
             ▼
       Sandbox Process Tree
Audit Writer / Recovery Manager は各副作用境界を横断して記録・復旧する。
```
### 3.1 信頼境界
| 領域 | 信頼 | 備考 |
| --- | --- | --- |
| MCP Client | Untrusted | request、image、temperature、session指定を検証する |
| Ollama output | Untrusted | tool argumentもPolicy検査する |
| Skill/User Prompt | Untrusted configuration content | Fixed PromptやPolicyを上書きできない |
| Agent Runtime | Trusted | 状態管理とdeterministic guard |
| Policy Engine | Trusted | allow/deny決定 |
| Sandbox Broker | Highly Trusted | OS副作用を発生させる唯一の境界 |
| Windows Kernel Security | Trusted enforcement | ACL/AppContainer/Job/WFP |

---

## 4. Project構成
```text
src/
  Agent.App/        # Program, CLI, composition root, configuration
  Agent.Mcp/        # MCP transport and two public tools
  Agent.Core/       # Agent loop, session, prompt, ollama abstractions
  Agent.Planner/    # TaskGraph, TokenPERT, TokenCPM
  Agent.Windows/    # SandboxPolicy enforcement and Win32 interop
tests/
  Agent.Core.Tests/
  Agent.Planner.Tests/
  Agent.Windows.Tests/
config/
  agent.yaml
  locales/en.json
  locales/ja.json
prompts/
  user-system.md    # optional user prompt; fixed prompt is embedded
skills/
logs/
state/
  recovery/         # rollback journal; application-owned
```
### 4.1 dependency方向
```text
Agent.App -> Agent.Mcp -> Agent.Core -> Agent.Planner
Agent.App -------------------------> Agent.Windows
Agent.Core -> ISandbox/IToolExecutor interfaces
Agent.Windows implements those interfaces
```
`Agent.Planner` と `Agent.Core` はWin32型、HANDLE、SID、WFP型を参照してはならない。

---
## 5. MCP詳細設計
### 5.1 Transport
- defaultはstdio。stdioではstdoutをMCP専用、ログをstderrへ出す。
- Streamable HTTPは `127.0.0.1` または `::1` だけにbind可能。非loopback設定はvalidation error。
- Streamable HTTPは1つのMCP endpointを持つ。v1はJSON responseのみ使用し、SSE streamを開始しない。
- HTTP GETによるSSE listenerは提供せず、GETには405を返す。
- Legacy HTTP+SSEの旧endpoint検出・fallbackを実装しない。
- Origin headerが存在するHTTP requestはloopback originとして妥当か検査する。
### 5.2 agent_run JSON Schema
```json
{
  "type": "object",
  "properties": {
    "request": { "type": "string", "minLength": 1 },
    "session_id": { "type": "string", "format": "uuid" },
    "temperature": { "type": "number", "minimum": 0.0, "maximum": 2.0 },
    "images": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "mime_type": { "type": "string", "enum": ["image/png", "image/jpeg", "image/webp"] },
          "data_base64": { "type": "string", "minLength": 1 }
        },
        "required": ["mime_type", "data_base64"],
        "additionalProperties": false
      }
    }
  },
  "required": ["request"],
  "additionalProperties": false
}
```
### 5.3 agent_run result
MCP resultはtext content 1件とする。Machine-readable structuredContentはv1では公開しない。本文はlocale templateで次を必ず含める。
```text
task_id: <UUID>
session_id: <UUID>
status: queued
message: <localized message>
```
### 5.4 agent_status JSON Schema
```json
{
  "type": "object",
  "properties": {
    "task_id": { "type": "string", "format": "uuid" },
    "session_id": { "type": "string", "format": "uuid" }
  },
  "required": ["task_id"],
  "additionalProperties": false
}
```
### 5.5 agent_status result
```text
task_id: <UUID>
session_id: <UUID>
status: queued|planning|running|completed|failed|cancelled
completed_tasks: <n>/<total>
current_task: <localized summary or empty>
token_usage: input=<n> output=<n> total=<n>
critical_path_tokens: <n>
iterations: <n>
replans: <n>
last_error_code: <stable code or empty>
last_error: <localized message or empty>
message: <localized status>
result: <final natural-language answer; completed only>
```
`result`は選択localeで生成する。内部Tool名、policy internals、chain-of-thoughtは返さない。

### 5.6 MCP 2026-07-28 / dual-era境界

- 公式C# SDK `2.0.0`へwire処理を委譲する。独自に`server/discover`、必須`_meta`、MCP routing header、modern error codeを再実装しない。
- HTTP transportは`Stateless = true`。modern HTTP requestごとにserver contextを作成し、`Mcp-Session-Id`を使用しない。
- SDKのlegacy initialize fallbackは維持する。Legacy SSEはSDK defaultの無効状態を使い、独自GET拒否middlewareは置かない。
- Agent Sessionは`session_id`で明示的に管理するapplication stateであり、transport sessionとは独立する。

### 5.7 Tasks Extension

- `ModelContextProtocol.Extensions.Tasks 2.0.0`の`WithTasks` filterを`agent_run`だけoptional task対応として登録する。`agent_status`は同期Toolのまま維持する。
- `PersistentMcpTaskStore`は`state/mcp-tasks/<task-id>.json`へWriteThrough後のatomic moveで保存する。directoryのuser-only DACLはApp層で作成する。
- store作成IDをAgent Task IDとして使用し、Agent registryのterminal completionを待ってSDK filterへ最終結果を返す。非Tasks callは従来どおりenqueue直後に返す。
- `tasks/cancel`のrequest cancellationをAgent TaskのCancellationTokenへ接続する。restart recoveryではworking/input-requiredを`failed`、reasonを`server_restarted`とする。
- 既定TTLは24時間、poll intervalは1000 ms。期限切れfileはaccess時に削除する。

### 5.8 起動preflightとHTTP request log

- Appはtransport構築前に`WindowsPlatformCheck`を実行する。administrator/BFE/WFP probeが1つでも失敗した場合はhostをbuild/startせずfatalとする。
- `StartAsync`完了後にだけ`IMcpHostObserver.Ready`を通知するため、「起動中」と「接続可能」を区別できる。
- HTTP middlewareはsocket endpointとrouting metadataだけをbounded in-memory queueへ`TryWrite`し、専用background writerがstderr、application log、`logs/http.jsonl`へ出力する。request threadはconsole/file I/Oを待たず、queue飽和時はrequestを止めずlog entryをdropして件数を警告する。
- forwarded header、credential header、query、payloadは保存しない。
- `RollingFileWriter`をapplication/http logで共用し、同じsize/retention policyでrotationする。stdioの運用出力はstderrだけへ送る。
---
## 6. Ollama統合設計
### 6.1 APIモデル
- `HttpClient`をsingleton相当で再利用する。
- Chat APIを会話、Vision、native tool callingに使用する。
- `stream=false`をv1既定とし、Agent内部でも1call単位の完了responseを扱う。
- `prompt_eval_count` と `eval_count` を毎callで取得する。
### 6.2 Option mapping
`OllamaOptions` は既知optionをnullable typed propertyとして持つ。設定されていないpropertyはpayloadへ出さない。`extra_options` は `Dictionary<string, JsonElement>` とし、typed propertyと同名keyがある場合はtyped propertyを優先し、同名のextra optionをpayloadへ出さない。
代表的typed property:
```text
num_ctx, num_keep, num_predict, temperature, seed,
top_k, top_p, min_p, typical_p, tfs_z,
repeat_last_n, repeat_penalty, presence_penalty, frequency_penalty,
mirostat, mirostat_tau, mirostat_eta, stop
```
Chat API top-levelとして `model`, `think`, `keep_alive`, `format`, `logprobs`, `top_logprobs` を別型で管理する。`think`はbooleanまたはOllamaが定義するlevel (`low` / `medium` / `high` / `max`) を受け付ける。responseでは最終回答の`message.content`と推論過程の`message.thinking`を分離して取り込み、tool call継続時だけassistant messageの`thinking`をOllamaへ戻す。thinking本文を利用者向け結果、Conversation、Execution Result、LLM Log、Audit Logへ保存・出力しない。Ollama API変更時は既知型を更新し、未知optionは `extra_options` で一時対応できる。
### 6.3 temperature override
```text
effective_temperature = agent_run.temperature ?? config.ollama.options.temperature
```
overrideはTask objectにcopyし、global configurationを変更しない。Session内の次Taskへも継承しない。
### 6.4 Vision
- `images[]`をBase64としてOllama messageへ転送する。
- mime_type、Base64妥当性、設定上限size/countを事前検査する。
- 既定上限は4画像、1画像10 MiB、request合計20 MiBとする。
- model capability確認でVision非対応と判定した場合はOllama呼出し前にlocalized error。能力確認不能時は呼出しを行い、Ollama errorを正規化して返す。
### 6.5 Internal Tool calling
Ollamaに公開する現行Internal Tool catalogは次のとおりとする。個々のOS Executable (`grep.exe`等) をInternal Toolとして増殖させない。catalogの構成は設計事項であり、仕様上の固定数として扱わない。
| Internal Tool | 責務 | 主なoperation |
| --- | --- | --- |
| file_search | 検索 | glob / name / text / regex / tail相当 |
| file_read | 読取 | whole / range / metadata |
| file_edit | 編集 | overwrite / patch / atomic_replace / delete |
| process_run | Entry Process実行 | Executable + args + cwd + timeout |
| task_update | TaskGraph更新 | add / dependency / estimate |
| dir | ディレクトリ操作 | mkdir / rmdir / list |
---
## 7. Internal Tool Schema設計
### 7.1 file_search
```json
{"root":"string","mode":"glob|name|text|regex|tail","query":"string","max_results":100,"tail_lines":100}
```
- `root`はread許可directory/file配下でなければdeny。
- `tail`はtext file向け。binaryは拒否する。判定は先頭4 KiBのみを読み、BOM確認(UTF-8/UTF-16 LE/UTF-16 BE)→BOMなしはUTF-8 strict byte sequence検証で行う。NULバイトのみの判定はUTF-16 textを誤拒否するため使用しない。
- `max_results`にhard upper boundを設け、context爆発を防ぐ。
- `max_results`のhard upper boundは1,000件、`tail_lines`は10,000行とする。
### 7.2 file_read
```json
{"path":"string","mode":"whole|range|metadata","start":0,"length":0}
```
- wholeはsize上限を超えた場合range利用を要求する。
- whole readの既定上限は1 MiBとする。
- read前にLogical Pathをreparse resolutionし、確認済みResolved PathとEffective Filesystem Policyを検査する。
### 7.3 file_edit
```json
{
  "path":"string",
  "operation":"overwrite|patch|atomic_replace|delete|rename",
  "content":"string|null",
  "patch":"string|null",
  "expected_sha256":"string|null",
  "new_path":"string|null"
}
```
- overwrite/patch/atomic_replaceはwrite Filesystem Capabilityを要求する。
- `patch` operationの`patch` fieldは、JSON文字列化した`{"old_text":"...","new_text":"..."}`を受け取る。unified diffは受け付けない。`old_text`は対象file内で正確に1回だけ一致しなければならない。不正形式または一致数不正は再試行可能なInternal Tool failureとする。
- deleteはdelete Filesystem Capabilityを要求する。
- renameはsource/destination双方にwrite Filesystem Capabilityを要求する。destinationが既に存在する場合は拒否する(overwrite不可)。cross-volume renameは不支持でInternal Tool failureとして返す。
- rename transaction: PREPARE(source/destination検査+journal) → APPLY(File.Move) → VERIFY(source不存在/destination存在/hash一致) → COMMIT。crash recoveryはdestination hashがjournal記録と一致する場合のみdestinationからsourceへ戻す。
- `expected_sha256` 指定時はoptimistic concurrency guardとして利用する。
### 7.4 process_run
```json
{
  "executable":"string",
  "args":["string"],
  "cwd":"string",
  "timeout_seconds":300,
  "stdin":"string|null"
}
```
- Shell Command 1本ではなくExecutableとargsを分離する。
- `executable`はApproved Entry Executable/ShellのAlias、Runtime ComponentのLogical/Resolved Path、またはdevelopment Workspace ArtifactのLogical/Resolved Pathとする。Alias以外のrelative Logical Pathは`cwd`を基準に解決する。Approved Entry ExecutableのResolved PathをAliasの代用として直接指定することはできない。
- Approved Entry Executable/ShellはResolved Path + SHA-256のExecutable Approval必須。Runtime ComponentとWorkspace Artifactは分類rootによって判定する。
- External Unknown ExecutableをEntry Processとして直接起動しない。Descendant Processは個別分類せずLPAC/ACL/WFP/Job confinementを継承する。
- cwdはEffective Filesystem Policy内でなければならない。
### 7.5 task_update
```json
{
  "operation":"add|add_dependency|set_estimate",
  "task_id":"string|null",
  "description":"string|null",
  "depends_on":["string"],
  "budget_class":"1K|2K|4K|8K|16K|32K|64K|128K|null",
  "optimistic_tokens":0,
  "most_likely_tokens":0,
  "pessimistic_tokens":0,
  "requires_external_effect":"boolean|null",
  "required_tools":["file_search|file_read|file_edit|process_run|task_update|dir"]
}
```
Task状態遷移はAgent Runtimeだけが行う。`task_update` はTask追加、dependency追加、estimate変更に限定し、LLMから状態を変更するschemaを公開しない。
PlannerがDAG、不変条件、completed immutable、max_tasksを再検査してから適用する。
### 7.6 dir
```json
{"path":"string","operation":"mkdir|rmdir|list"}
```
- mkdir は Write capabilityを要求し、`Directory.CreateDirectory` で親ディレクトリも含めて作成する。
- rmdir は Delete capabilityを要求し、**空ディレクトリのみ**削除する。非空の場合は `ToolValidationException` で拒否する。内容復元の複雑さとMemoryBackupLimit超過リスクを排除するため、再帰削除は行わない。
- list は Read capabilityを要求し、直下のエントリ一覧を返す。外部効果ではない。
- 既存の `ResolvedPath` / `PathPolicy` / `TaskAclManager`(root継承ACE)/ `TaskResourceJournal` / `RecoveryManager` 枠組みを利用する。新規作成directoryは親の継承ACEを自動取得するため追加ACL操作は不要。
- mkdir後crash → ディレクトリ削除、rmdir後crash → 空ディレクトリ再作成、でRecoveryする。
### 7.7 Internal Tool error表現
既存のInternal Tool resultへ、`error_code`、`error_category`、`target_path`、`required_permission`、`retry_allowed`、`resolution`をoptional fieldとして保持する。これは独立したerror体系ではなく、既存の`SandboxPolicyException`と`ToolExecutionResult`の分類情報を失わずRuntime、Audit、localized messageへ渡す表現である。内部messageと利用者向けlocalized messageは分離し、Internal Tool名は利用者向け結果へ含めない。

### 7.8 ToolUseGuard
Taskには `requires_external_effect` をPlanner内部属性として持たせる。**Planning フェーズで LLM structured output により Task ごとに判定・設定される**(keyword heuristic ではない)。trueのTaskで、当該iteration中のInternal Tool Callが0かつ完了証拠がない場合、LLMへ「未実行」を示すsystem-generated observationを追加して再試行する。同一失敗fingerprintが5回に達したらTaskをfailedにする。ただし、Policy EngineのdenyおよびSandbox backendの`UnauthorizedAccessException`は`RetryAllowed=false`のterminal Internal Tool resultへ変換する。Runtimeはobserverへ結果を1回記録した後、同一Internal Tool Callへ再投入せず、§8.4の条件付きreplanへ遷移する。
---
## 8. Token Planner設計
### 8.1 Task model
```text
Task
  Id: UUID
  Description: string
  Dependencies: Set<TaskId>
  State: queued|planning|running|completed|failed|cancelled
  BudgetClass: TokenBudgetClass
  O, M, P: long
  ExpectedTokens: double
  ActualInputTokens: long
  ActualOutputTokens: long
  ActualTotalTokens: long
  RequiresExternalEffect: bool
  RequiredTools: set<Internal Tool name>
```
Taskは、完了に成功証跡が必要なTool名を`RequiredTools`として持つ。Planner structured outputの`required_tools`から構築し、Runtimeは集合内の全Toolが成功した場合だけTaskの操作を検証済みとする。read/search/list Taskは副作用不要でも対応Toolを持ち、純粋な説明Taskだけが空集合となる。`RequiresExternalEffect=true`では集合内の副作用Toolから外部効果も確認する。例えば`process_run`が必要なTask中の`file_edit`成功は完了根拠にしない。current Taskの集合に含まれない副作用ToolはBackendへdispatchせず、Task scope外のTool resultとしてLLMへ返してqueued Taskの先取りを決定的に防ぐ。scope外結果はAudit/LLM相関には残すが、次Taskのactive Execution Result contextへは引き継がない。

codingの編集・検証・失敗修正は同一Taskへまとめ、`file_edit`と`process_run`をRequiredToolsにする。両Toolを要求する検証Taskが、別の`file_edit` Taskへ直接または間接に依存するsplit planはこの規則に反するためPlanner validationで拒否し、具体的な理由を付けて1回だけ訂正させる。
### 8.2 PERT計算
```text
ExpectedTokens = (O + 4*M + P) / 6.0
VarianceTokens = ((P - O) / 6.0)^2   # 診断値。v1ではscheduler判断に必須ではない
```
validation: `0 < O <= M <= P <= BudgetClass.MaxTokens`.
### 8.3 CPM
topological sort後にforward passで各Taskの累積expected token costを計算し、最大経路をCritical Pathとする。時間のearliest/latest startという語をそのままUIへ出さず、`cumulative_token_cost`、`critical_path` と表記する。
### 8.4 再計画
- **Plan フェーズ**: LLM structured output により Initial TaskGraph を生成。Planner が Task ごとに `requires_external_effect` を判定。pure analysis task は `requires_external_effect=false` で少なくとも1 Task の TaskGraph を持つ。Sandbox Task Resource は Plan 時には適用しない。
- **Run フェーズ**: ready な Task (dependencies 解決済み) を critical path → creation order で順次実行。Sandbox Task Resource (BeginTask/EndTask) は RunAsync 時に適用する。
- 未完了Taskの追加/dependency追加後にDAG validationとCPMを再計算。
- completed Taskは変更しない。
- 実績がPを超過しても即失敗にはせず、remaining Taskのestimate見直しをLLMへ要求できる。
- `max_tasks=32`超過提案は拒否し、既存Taskの統合をLLMへ求める。
- Budget Classは意味的Taskを分割する唯一の理由にしない。Taskが複数独立成果物を含む場合に分割する。
- Effective Sandbox Policy denyは同一Internal Tool Callへ再投入しない。許可済みcapabilityだけで代替できる可能性がある場合、`running -> planning -> running` と遷移してreplanを最大3回まで試行できる。
- completed TaskのID、状態、usageを保持する。failed Taskをdependency解決済みとして扱わない。
- 同一deny fingerprintの再発、計画未変更、実行可能Taskなし、structured replan失敗は即Failedとする。全Taskがcompletedの場合だけAgent Taskをcompletedにする。
- structured planが空または不正な場合は、設定された`think`を維持したまま訂正instruction付きで1回だけ再試行し、それでも失敗した場合はplanning failureとする。外部効果要否が不明なfallback graphは作成しない。
- 利用者が指定したabsolute path、executable、cwd、引数配列、operation、literal値は、それを使用するTask descriptionへそのまま保持する。後続Taskの操作を先行Taskへ混在させない。
### 8.5 Ollama usage集計
1 Ollama callの `prompt_eval_count` をTask inputへ、`eval_count` をTask outputへ加算する。tool実行そのものにはtoken costを加算しない。context summary生成に使ったtokenはSession maintenance Taskとして別集計する。
---
## 9. Session・Context設計
### 9.1 In-memory store
`ConcurrentDictionary<SessionId, AgentSession>` 相当で保持する。永続化しない。Taskは必ず1 Sessionに所属する。
```text
AgentSession
  SessionId
  Conversation
  TaskGraph
  ExecutionResults
  Summary
  CreatedAt / LastAccessAt
```
### 9.2 Context assembly
実行phaseの順序を次に固定する。
1. Fixed System Prompt
2. User System Prompt
3. locale instruction
4. selected Skills (name + description一覧のみ、Progressive Disclosure Stage 1)
5. Sandbox capability summary
6. current TaskGraph / current Task
7. previous Summary
8. recent verified Execution Result
9. original MCP Task request(exact path、引数、制約、literalの参照元)
10. current Taskの`requires_external_effect`に基づく実行要件
11. recent Conversation

Planning/replanning phaseはread-onlyのTaskGraph生成契約を最初のSystem messageとして使用し、locale、Skill catalog、Sandbox capability summary、original MCP Task requestだけを組み立てる。file調査やInternal Tool実行を指示するFixed/User System PromptはPlanning契約と矛盾するため、このphaseへ混在させない。生成後のTask実行では上記1〜11の優先順位を適用する。

実行要件は、現在runningのTaskだけを実行してqueued Taskを先取りしないことをSystemおよび末尾のcurrent Task user messageで指示する。末尾messageにはoriginal MCP Task requestもexact値の参照元として併記する。外部効果が必要なTaskでは文章上の宣言、計画、JSON例を実行済みと扱わず、対応するInternal Toolを直ちに呼び出すよう指示する。成功済みのread結果はExecution Resultから再利用し、不要な再読込を避けてwrite/processへ進む。外部効果が不要なTaskにはToolを強制しない。未解決のTool失敗後にToolを呼ばない応答も同一失敗として数え、既定の同一失敗上限でfailedにする。
### 9.3 Summary policy
`num_ctx`に対する利用率が設定閾値を超えたとき、古いConversation/Execution Resultを要約する。利用率 = latest `prompt_eval_count` / `num_ctx`(累積 InputTokens ではない)。既定閾値は80%とする。次は削除・曖昧化してはならない。
- 利用者が明示した制約
- 未完了Taskとdependency
- completed Taskの重要成果
- 失敗原因と再試行回数
- 変更済fileと検証結果
- security denial
- 承認/Policyそのものではなく現在利用可能なcapability summary
raw chain-of-thoughtは保存・要約対象としない。
---
## 10. User Sandbox Configuration・Resolution・Effective Policy設計
### 10.1 schema概要
```yaml
schema_version: 2
application:
  language: en
mcp:
  transport: stdio
  http:
    host: 127.0.0.1
    port: 8080
  images:
    max_count: 4
    max_bytes_each: 10485760
    max_total_bytes: 20971520
agent:
  user_system_prompt: prompts/user-system.md
  max_iterations: 128
  same_failure_limit: 5
ollama:
  endpoint: http://localhost:11434
  model: deepseek-v4-flash:cloud
  think: true
  keep_alive: 5m
  options:
    num_ctx: 32768
    temperature: 0.4
  extra_options: {}
planner:
  max_tasks: 32
sandbox:
  profile: development
  workspaces: []
  mounts: []
  execution:
    entries: []
  network:
    access: none
    local_endpoints: []
    restricted_endpoints: []
  resources:
    profile: normal
    memory_mb:
    process_limit:
    execution_timeout_seconds:
file_edit:
  memory_backup_limit_mb: 16
limits:
  whole_read_bytes: 1048576
  search_max_results: 1000
  tail_max_lines: 10000
  context_summary_ratio: 0.8
localization:
  directory: config/locales
  fallback: en
skills:
  directory: skills
logging:
  directory: logs
```
base YAMLと同じdirectoryに`agent.local.yaml`が存在する場合、YAML nodeを読み取ってmapを再帰mergeし、scalarとsequenceはlocal nodeで置換してからtyped configurationへdeserializeする。unknown propertyを含むvalidationはmerge後に行い、全相対pathのbaseはbase YAMLのdirectoryとする。local file、そこから参照するUser System PromptおよびSkill directoryはRelease Bundleのpublish入力に含めない。
### 10.2 Workspace・Mount・Profile
- `workspaces`はLogical Path文字列のsequenceとする。`readonly`はreadのみ、`development`はread/write/delete/Artifact executeへcompileする。
- `mounts`は`path`と`access: read_only|read_write|read_write_delete`を持つ。readonly Profileではread_onlyだけを許可し、Mountにexecuteを付与しない。
- relative Logical Pathはbase YAML directory基準。実在するlocal directoryだけを許可する。
- 同一Resolved Rootはcapabilityを統合する。利用者が宣言したWorkspace/Mountについて、親の継承capabilityより狭いnested rootは拒否する。Execution EntryまたはRuntime Rootがdevelopment Workspace内にある場合、その派生rootは親Workspaceのcapabilityを継承するため別の制限境界とは扱わず、Alias/Resolved Path/SHA-256によるEntry identity検査は維持する。
### 10.3 Execution Entry・Applied Configuration Store
```yaml
execution:
  entries:
    - alias: python
      path: C:/runtime/python.exe
      runtime_root: C:/runtime
    - alias: cmd
      path: C:/Windows/System32/cmd.exe
```
- EntryはAlias、Logical Executable Path、optional Logical Runtime RootをYAML内で一体として宣言する。Runtime Root省略はRuntime Rootなしを意味する。
- apply時にExecutableをResolved Pathへ固定しSHA-256を計算する。Resolved file nameが`cmd.exe|powershell.exe|pwsh.exe`ならApproved Shell Executable、それ以外はApproved Entry Executableへ分類する。
- Aliasはcase-insensitiveに一意とする。Executableは実在file、Runtime Rootは実在directoryでなければならない。
- Store pathは`%LOCALAPPDATA%/AgentSandboxMcp/applied-configurations/<config-path-hash>.json`。user-only DACL、WriteThrough、atomic replace、schema versionを持つ。
- Storeはconfig path、YAML fingerprint、Workspace/Mount Resolution、全Execution EntryのAlias、分類、Logical/Resolved Path、SHA-256、Runtime Root、Network/Resourceを含む一つのsnapshotとする。個別Approval StoreとResolution Storeは持たない。
- applyは全項目を先に解決・検証して差分を一度表示し、承認後にsnapshot全体をatomic replaceする。YAMLから削除されたEntryは同じtransactionで適用状態から除去する。
### 10.4 Network entry
```yaml
network:
  access: restricted
  local_endpoints: []
  restricted_endpoints:
    - host: github.com
      ports: [443]
```
`none`は全deny、`local`は列挙portを`127.0.0.1`/`::1`へ展開、`restricted`はhostをTask開始時にIP snapshot化する。mode不一致または空endpointを拒否する。
### 10.5 Resource Profile
`constrained=1024 MiB/4/300秒`、`normal=4096 MiB/16/1800秒`、`extended=8192 MiB/32/3600秒`とする。`memory_mb`、`process_limit`、`execution_timeout_seconds`の正数overrideはpreset値を置換する。
### 10.6 Apply・起動・表示
- reparse chainを最終targetまで解決しcycle、missing target、非local filesystemを拒否する。
- `agent-mcp apply [config] [--yes]`だけがApplied Configuration Storeを更新する。全解決・validation完了前、または確認前にStoreを変更しない。
- `agent-mcp [config]`は現在のYAMLを再解決・再hashし、Applied Configuration snapshotとの完全一致とWindows preflightを検証してからMCP受付を開始する。個別の`serve`と`check`commandは持たない。
- `agent-mcp show [config]`はdesired/resolved/appliedの権限matrixをtext表示し、StoreやACL/WFPを変更しない。管理者権限、BFE、WFP add/deleteを伴う完全なWindows preflightはServer起動時だけ実行する。
- languageとtransportはYAMLだけから取得し、CLI overrideを持たない。

### 10.7 Effective Sandbox Policy

現在のYAMLと一致するApplied Configuration snapshotをcompileし、次を由来付きで保持する。

- Filesystem Root: `workspace`、`mount`、`approved_entry_executable`、`approved_shell_executable`、`runtime_root`、`os_runtime_root`の由来、Resolved Path、Filesystem Capability。
- Entry Executable: Alias、分類、Resolved Path、SHA-256、optional Runtime Root。
- Artifact RootとRuntime Root: Entry分類およびACL生成に使用するResolved Root。
- Network: `none|local|restricted`とTask開始時にsnapshot化するendpoint。
- Resource: Resource Profile名、override適用後のmemory/process/timeout。
- baseline capability: 固定された`registryRead`と`lpacInstrumentation`。

同じResolved RootのFilesystem Capabilityは和集合にし、由来も併記する。親rootから継承するCapabilityより狭いnested rootは表現不能としてcompileを拒否する。`show`は現在の希望状態、解決結果、hash、適用状態をtextで表示するが、Storeや設定を変更しない。
---
## 11. Windows強制設計
### 11.1 Less Privileged AppContainer
- Application Profileを固定名で作成/取得する。
- 起動時にprofile SIDを解決する。
- Taskごとにprofileを作り直さない。
- standard `CreateProcess`の`PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES`に加え、`PROC_THREAD_ATTRIBUTE_ALL_APPLICATION_PACKAGES_POLICY=PROCESS_CREATION_ALL_APPLICATION_PACKAGES_OPT_OUT`を指定してLPAC tokenを生成する。
- Experimental CreateProcessInSandbox、AppLocker、WDACへ依存しない。LPAC生成または互換性検査失敗時に通常AppContainerへfallbackしない。
- baseline capabilityは`registryRead`と、PowerShell Runtimeが起動時のETW provider登録に必要とする`lpacInstrumentation`とする。Registry writeと`lpacCom`は付与しない。Network capabilityはEffective Network Policyが必要な場合だけ付与する。`lpacInstrumentation`追加後もRegistry writeとCOM activationの実拒否をWindows Security suiteで検証する。
- capabilityはExecutable互換性の一般的なスイッチとして追加しない。採用には、(1) Microsoft公開資料またはWindows SDKで意味とSecurity Boundaryが確認できること、(2) 必要な正方向ケースが追加前に失敗し追加後に成功すること、(3) Filesystem/Registry/COM/Network/Process Treeの負方向matrixが追加後も成功すること、(4) 名称、SID、由来、適用条件をAuditへ記録できること、をすべて要求する。意味が公開されていないcapabilityは実験結果だけでbaselineへ昇格させない。
- `registryRead`は全Profileで必要なRegistry readだけに使用する。`lpacInstrumentation`はPowerShell起動互換性のための既存baselineであり、公開された意味の不足を負方向testで補う暫定互換capabilityとして扱う。`internetClient`/`privateNetworkClientServer` SIDはNetworkが`local|restricted`の場合だけ付与し、到達先はWFP hard permitでさらに制限する。`lpacCom`はv1で禁止する。`lpacAppExperience`は公開された権限範囲を確認できないため採用しない。

| capability | 根拠と用途 | 適用条件 | 必須の負方向検証 |
| --- | --- | --- | --- |
| `registryRead` | MicrosoftのLPAC起動手順に従い明示SIDとして付与し、Windows/runtimeのreadに限定 | 全Profileの固定baseline | Registry write、Broker credential環境の非継承 |
| `lpacInstrumentation` | PowerShellのETW provider登録失敗を解消した実測根拠。公開された権限範囲が不足するため暫定扱い | 全Profileの固定baseline。削除可能性を継続評価 | Registry write、COM activation、Policy外Filesystem/Network |
| `internetClient` / `privateNetworkClientServer` | Windows capability SID。WFPだけではLPAC token側のnetwork gateを通らないため使用 | Effective Network Policyが`local|restricted`のTaskだけ | `none`全deny、Policy外address/port deny、終了後WFP残留0 |
| `lpacCom` | v1がCOMを明示deny | 付与禁止 | COM activation拒否 |
| `lpacAppExperience` | 公開された権限範囲を確認できない | 付与禁止 | capability catalog/auditに出現しないこと |

根拠資料はMicrosoftの[Launch an AppContainer](https://learn.microsoft.com/en-us/windows/win32/secauthz/implementing-an-appcontainer)、[AppContainer for legacy applications](https://learn.microsoft.com/en-us/windows/win32/secauthz/appcontainer-for-legacy-applications-)、[UpdateProcThreadAttribute](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute)を正本とする。名称からSIDを導出できることだけを権限範囲の根拠にしてはならない。
- AppContainer外の通常user tokenに戻るbreakawayを許可しない。DescendantはLPAC tokenを継承する。
- `CreateProcess`へBrokerのenvironment blockをそのまま継承しない。Windows/runtime起動に必要なsystem/profile path、`ComSpec`、System32だけのPATH、Task `cwd`を指すTEMP/TMPと`DOTNET_CLI_HOME`、非対話かつnetwork非依存の.NET初回起動・telemetry・workload resolver値、Process Tree外の共有MSBuild server/node reuseを無効化する値から成る明示的なUnicode environment blockを渡し、任意のtoken、password、SSH/API credential環境変数を除外する。profile path自体はFilesystem Capabilityを付与しない。
### 11.2 NTFS ACL
- Effective Sandbox PolicyのFilesystem RootからApplication SID ACEを導出する。
- read-only directoryはdirectory traverse/list/readとfile readを別ACEとして付与し、fileのExecuteFileを含めない。execute rootだけがfile read/execute ACEを取得する。
- development Workspace/Artifact Rootはread/write/delete/execute、Runtime RootとResolved `%SystemRoot%/System32`はread/execute、Mountは指定accessのみを取得する。
- 許可pathがdirectoryの場合、rootへのinheritance ACEで既存およびTask中に作成されたdescendantを覆い、descendantごとのDACL列挙は行わない。
- 許可pathがfileの場合は、そのfileだけへ継承なしACEを追加する。異なる権限を持つnested rootは別scopeとして逆順cleanupする。
- protected DACLを持つrootまたはdescendantの継承保護は解除せず、所有権変更やDACL全体の置換も行わない。Application SID ACEをそのobjectへ安全に追加できない場合はOS拒否を維持してfail-closedにする。
- OS Runtime Root (`%SystemRoot%/System32`) はOSが管理するprotected DACLとの両立を優先し、BrokerがApplication SID ACEを追加しない。OS Runtime Root配下のApproved Entry Executable fileにも個別ACEを追加しない。LPACから観測される既存のOS accessだけを利用し、Effective Sandbox Policyの`os_runtime_root: read/execute`はDACL変更命令ではなく許容上限を表す。実際のExecutable互換性はEntry/Descendant組合せtestで確認する。
- Workspace、Mount、Runtime Rootではrootの現在のSecurity DescriptorをJournalへ保存した後、protected状態を維持したまま追加ACEを適用できる場合だけleaseを成立させる。cleanup後は元Security Descriptorとのbyte-level一致を検証する。nested protected DACLがrootの継承ACEを遮る場合、そのobjectを自動走査して保護解除せず、必要accessが得られなければその組合せを拒否する。
- rootの元security descriptorをRecovery Journalへ1件記録する。
- Task終了で追加分を除去し、元状態との整合を検査する。
### 11.3 Job Object
- TaskごとにJob Objectを1つ作成する。
- Entry ProcessをJobへ割り当て、全Descendantを同一Job chainへ継承させる。
- breakawayを許可しない。
- process count / memory limitをJobへ設定する。
- `KILL_ON_JOB_CLOSE`相当を利用し、application終了時にprocess treeを残さない。
### 11.4 Entry Process分類・Executable Approval
- Aliasは現在のApplied Configuration snapshotのApproved Entry Executable/Shellへ解決し、起動直前とsuspended生成後・resume前にResolved PathとSHA-256を再検証する。
- Runtime Componentは確認済みRuntime Root containment、Workspace Artifactはdevelopment Artifact Root containmentで分類する。MountおよびExternal Unknown Executableからの直接Entry起動は拒否する。
- Descendant Processは個別分類・Approvalを行わず、LPAC/ACL/WFP/Job confinementをSecurity Boundaryとする。`PROCESS_CREATION_CHILD_PROCESS_RESTRICTED`は使用しない。
### 11.5 WFP方針
WFP実装は複雑な汎用Firewallにしない。設計上の変換規則だけを固定する。
1. `none`ならnetwork capabilityを付与せず、Application Profile/Sandbox Process Treeへoutbound blockを作成する。
2. `local`は列挙portをIPv4/IPv6 Loopbackへ、`restricted`は列挙hostをTask開始時にIP解決する。
3. 解決したIP集合とportの組にだけallow filterを作成する。
4. Task実行中はそのIP snapshotを使用し、複雑な動的DNS追随は行わない。
5. DNS解決失敗はdeny。
6. Task終了でTask固有WFP filterを削除する。
7. LoopbackもEffective Network Policyに明示されない限り許可しない。LANをlocalへ含めない。
具体的なWFP layer、sublayer、filter condition、transaction APIは実装時にCodexがWindows SDKを確認して決定し、Security Integration Testで仕様を検証する。
### 11.6 Named Pipe
Sandbox workerとのIPCが必要な場合はtask固有Named Pipeを使用し、DACLをApplication SIDとBrokerだけに限定する。TCP localhostを内部IPCに使わない。
---
## 12. ACL / Resource Transaction設計
### 12.1 ACIDから借用する性質
| 性質 | 本システムでの意味 |
| --- | --- |
| Atomicity | Task Resource適用が途中失敗した場合、適用済み変更をrollbackする。 |
| Consistency | Effective Sandbox PolicyとSecurity Invariantを満たす状態だけを実行可能状態とする。 |
| Isolation | Task固有ResourceをTask IDで識別し、他Task cleanupで誤削除しない。 |
| Durability | Task Resource自体の永続化ではなく、cleanupに必要なjournalをcrashに耐えて保持する。 |
### 12.2 状態機械
```text
CLEAN
  -> PREPARING   journal create
  -> APPLIED     ACL/WFP/Job ready
  -> RUNNING     sandbox process start
  -> CLEANING    process stopped / task terminal
  -> CLEAN       all task resources removed
PREPARING/APPLIED/RUNNING/CLEANING --crash--> RECOVERY_REQUIRED
RECOVERY_REQUIRED -> CLEANING -> CLEAN
```
### 12.3 Recovery Journal
JournalはTaskごとのJSONとし、操作を実行する**前**にundoに必要な情報をflushする。例:
```json
{
  "schema_version": 1,
  "task_id": "...",
  "state": "APPLIED",
  "acl_changes": [{"path":"...","change_id":"..."}],
  "wfp_filter_ids": [123],
  "temp_paths": ["..."],
  "created_at": "..."
}
```
起動時にjournalが存在する場合、MCP transport開始前にRecovery Managerが逆順でcleanupし、全項目の不存在/復元を検査してからjournalを削除する。
---
## 13. File Transaction設計
### 13.1 基本フロー
```text
canonicalize + policy check
  -> read old identity/hash
  -> old content snapshot (memory or temp)
  -> edit temp representation
  -> syntax/basic validation if available
  -> atomic replace when possible
  -> post-write hash/readback validation
  -> commit: discard snapshot
failure -> rollback snapshot -> verify original hash
```
### 13.2 backup threshold
`memory_backup_limit_mb`以下はメモリsnapshot、それより大きい場合はTask専用temp directoryへbackupする。16MBをdefault候補とするが、実装時benchmarkで変更可能。これは仕様上の固定値ではない。

v1の既定値は16 MiBとし、benchmark結果を変更根拠として記録できるconfiguration defaultとして扱う。
### 13.3 Patch
patchは適用前にtarget hashまたはcontext一致を検査する。曖昧適用を禁止し、複数候補に一致する場合は失敗としてLLMへ返す。
---
## 14. Localization設計
### 14.1 Locale file
`config/locales/en.json` と `ja.json` を完全key集合として配布する。flat objectを採用する。
```json
{
  "app.starting": "Starting agent.",
  "mcp.task_queued": "Task {task} was queued.",
  "sandbox.access_denied": "Access denied: {path}",
  "ollama.vision_unsupported": "The selected model does not support image input."
}
```
### 14.2 validation
- JSON parse failure: fatal。
- baseline key集合にないunknown key: fatal。
- missing key: 起動は継続し、runtimeでenへfallback。
- enにもない場合はkey自体を表示する。
- placeholder名はen baselineと一致しなければfatal。
### 14.3 Language propagation
`LanguageContext`をrequest/sessionへ渡し、CLI/diagnostic/MCP templateだけでなくPrompt Composerのlocale instructionにも利用する。LLMに入力言語自動判定をさせない。
---
## 15. Logging・Audit設計
### 15.1 Application log
- stdio時はstderr + rolling file。
- log levelは設定可能だがCLI optionにはしない。
- stdoutへ通常ログを出すコードはtestで禁止する。
### 15.2 LLM log
call ID、session ID、task ID、Planner Task ID、phase、iteration、replan番号、model、request metadata、prompt、response、tool_calls、token usageを記録する。Planning、Skill選択、再計画、実行、context要約を同じ相関形式で記録し、Tool resultにもcall IDとiterationを付ける。秘密情報の自動継承は禁止だが、利用者入力にsecretが含まれる可能性はあるためlog directoryはuser-only ACLにする。既存rotation設定はLLM logにも適用する。
### 15.3 Audit JSONL
Auditはappend-only JSONLを採用する。1 event = 1 line。
```json
{"ts":"...","event":"process.start","session_id":"...","task_id":"...","exe":"...","sha256":"...","arguments":"redacted","argument_count":2,"decision":"allow"}
{"ts":"...","event":"file.write","task_id":"...","path":"...","before_sha256":"...","after_sha256":"..."}
{"ts":"...","event":"policy.deny","task_id":"...","kind":"network","target":"example.com:443","reason":"not_allowlisted"}
```
最低event集合: `task.start`, `task.end`, `tool.call`, `process.start`, `process.exit`, `file.write`, `file.delete`, `policy.deny`, `network.rule.apply`, `network.rule.remove`, `recovery.start`, `recovery.end`。各eventは可能な限りsession ID、task ID、内部error codeを持つ。
---
## 16. Recovery・終了設計
### 16.1 graceful stop
1. 新規agent_run受付停止。
2. 実行中Taskをcancelledへ遷移予定としてマーク。
3. Job Objectを終了しprocess tree停止。
4. File transaction rollbackが必要なら実施。
5. WFP filter/ACL/temp resource cleanup。
6. journal clean確認。
7. transport終了。
### 16.2 client disconnect
- stdio: EOFまたはparent process消失をClient切断とみなし、所有Taskをsafe stop。
- Streamable HTTP: 1回のHTTP response完了は切断ではない。MCP sessionの明示終了、session失効、server shutdownをsafe stop triggerとする。
### 16.3 Ollama retry
network/temporary errorだけを最大3回retryする。validation error、Vision unsupported、invalid model等の恒久errorは即failed。backoffは250 ms、500 ms、1,000 msに固定し、汎用retry frameworkを導入しない。
---
## 17. 状態遷移
### 17.0 実行キュー
複数Taskの受付は許可するが、`planning` / `running` およびTask Resource適用はアプリケーション全体で最大1件とする。受付順の単一キューで直列実行する。

### 17.1 Task
```text
queued -> planning -> running -> completed
                    -> planning   # replan
queued/planning/running -> failed
queued/planning/running -> cancelled
completed/failed/cancelled are terminal
```
### 17.2 Session
```text
active -> closing -> closed
```
closed Sessionは再利用しない。プロセス再起動後に以前のSession IDが指定された場合はnot found。
---
## 18. Validation / Verification設計
### 18.1 起動時validation
- YAML schema_version
- MCP transport value
- HTTP hostがloopback
- locale baseline/placeholder
- Ollama endpoint URI
- Sandbox path canonicalization
- Applied Configuration Storeのconfig path/fingerprint、Filesystem Resolution、Execution EntryのAlias/Logical Path/Resolved Path/hash format
- network host/port syntax
- resource limit range
- Fixed/User prompt file state
- Skill directory
### 18.2 deterministic verification
| 対象 | 検証 |
| --- | --- |
| TaskGraph | cycle、max_tasks、completed immutable |
| TokenPERT | O<=M<=P<=budget、式のunit test |
| TokenCPM | 既知DAGに対するcritical path unit test |
| Filesystem | allow/deny/reparse point integration test |
| Process | Alias不明、未適用、hash/Resolved Path変更、Entry分類拒否、LPAC不一致 |
| Network | noneのLoopback、local/restrictedのPolicy外address/port |
| Recovery | 各transaction stateで強制crashして再起動cleanup |
| MCP | stdio purity、Streamable HTTP loopback、GET 405 |
| Localization | fallback、unknown key fatal、placeholder validation |
---
## 19. Security Test Matrix
| ID | ケース | 期待 |
| --- | --- | --- |
| ST-01 | readonly Workspaceのread | 成功 |
| ST-02 | readonly Workspaceのwrite/delete/execute | すべて拒否 |
| ST-03 | development Workspaceのread/write/delete | 成功 |
| ST-04 | development Workspace ArtifactのEntry起動 | Approvalなしで成功 |
| ST-05 | junctionで許可外へ脱出 | 拒否 |
| ST-06 | symlink chain/cycle | 許可外は拒否、cycleはfail-closed |
| ST-07 | 承認exe/hash一致 | 成功 |
| ST-08 | exe更新/hash不一致 | 拒否 |
| ST-09 | Approved Shell分類 | cmd.exe/powershell.exe/pwsh.exeだけ直接起動可 |
| ST-10 | Descendantが個別未承認Executableを起動 | 同じLPAC identity/Job内で成功 |
| ST-11 | Job close/breakaway/process/memory/timeout | breakaway不可、制限時は全Process Tree停止 |
| ST-12 | Network noneで127.0.0.1 | 拒否 |
| ST-13 | Network local/restrictedで許可address:port | 成功 |
| ST-14 | Network local/restrictedでPolicy外port | 拒否 |
| ST-15 | MCPからpolicy変更試行 | schema/機能上不可能 |
| ST-16 | Ollama Internal Tool CallのResolved Path脱出 | Policyで拒否 |
| ST-17 | crash after ACL apply | 再起動cleanup |
| ST-18 | crash after WFP apply | 再起動cleanup |
| ST-19 | LPAC baselineでRegistry read/writeとCOM | readのみ成功、write/COM拒否 |
| ST-20 | External Unknown/System32 Executableの直接Entry | Approvalなしでは拒否 |
| ST-21 | malformed locale | 起動失敗 |
| ST-22 | non-loopback HTTP bind | 起動失敗 |
| ST-23 | Applied Configuration Store | user-only DACL、snapshot全体のatomic replace、破損record拒否 |
| ST-24 | config fingerprint/Resolved Path/hash変更 | 全体を再applyするまでfail-closed |
| ST-25 | Entry (`PowerShell`/Python/.NET/`cmd`) × Descendant (`cmd`/PowerShell/Python/.NET/System32 utility) | 個別Approvalなしで起動し、Descendantが同じLPAC SID/Jobに残る。cmd内からはPATH解決名またはWorkspace相対pathを使用する |
| ST-26 | protected DACL root/descendantと通常DACL rootのread/write/execute | protected bitを解除せず、許可ケースだけ成功。適用不能ケースは拒否し、cleanup後Security Descriptorが完全一致 |
| ST-27 | baseline/Network capabilityの追加前後 | 必要な正方向ケースに加えFilesystem、Registry write、COM、Policy外Network、Job breakawayの負方向集合をすべて検証 |
---
## 20. エラー分類
| Category | 例 | Task結果 | Retry |
| --- | --- | --- | --- |
| validation | invalid config/schema/tool args | failed | No |
| policy_denied | path/network/exe denial | LLMへobservation。回復不能ならfailed | LLM再計画のみ |
| ollama_transient | connection reset/temporary unavailable | running維持 | 最大3 |
| ollama_permanent | model not found/vision unsupported | failed | No |
| tool_failure | process nonzero/patch mismatch | running→replan | 最大同一5 |
| resource_limit | timeout/memory/process limit | failedまたはreplan | 原則No |
| recovery_failure | ACL/WFP cleanup不能 | application fatal | No |
errorは内部codeとlocalized messageを分離し、ログ/auditにはcode、MCPにはlocalized textを返す。Sandbox Configuration/Resolution/Approvalの失敗は少なくとも`configuration.invalid`、`sandbox.resolution_unconfirmed`、`sandbox.resolution_changed`、`executable.approval_missing`、`executable.resolution_changed`、`executable.hash_changed`、`executable.shell_unsupported`、`process.lpac_unsupported`を既存分類へ統合し、category、対象、解決方法を保持する。
---
## 21. 実装順序
| Phase | 実装 | 完了条件 |
| --- | --- | --- |
| 1 | Config/Locale/MCP stdio skeleton | agent_run/statusのstubが動作 |
| 2 | Session/Ollama/Prompt | text-only会話とtoken取得 |
| 3 | Planner | TaskGraph + TokenPERT/CPM unit test |
| 4 | Internal Tool dispatcher | tool schemaとToolUseGuard |
| 5 | Filesystem/Process Sandbox | ACL/AppContainer/Job integration test |
| 6 | Resource Transaction/Recovery | 強制crash recovery test |
| 7 | WFP | none/local/restricted integration test |
| 8 | Vision/Streamable HTTP | image optional、loopback HTTP |
| 9 | Audit/Hardening | security matrix全PASS |
| 10 | Release/Operational E2E | self-contained Bundle単独起動、stdio/HTTP実利用 |

### 21.1 Release設計
- `dotnet publish -c Release -r win-x64 --self-contained true` のfolder publishを配布元とする。
- Bundleはversion付きZIP、展開済みdirectory、file manifest、SHA-256 checksumから成る。
- 起動時の相対pathは実行ファイルdirectoryを基準に解決し、ソースツリーを参照しない。
- 現行Operational E2Eは配布既定の`deepseek-v4-flash:cloud`を使用する。rate limit、接続失敗、model unavailableをapplication PASSとして扱わない。
---
## 22. Codex実装制約
- 新規NuGet dependencyを勝手に追加しない。追加時は標準ライブラリで不能な理由を示す。
- MCP Toolを `agent_run` / `agent_status` 以外に増やさない。
- Internal ToolをOSコマンド名ごとに増やさず、本章のTool catalogとschemaを変更管理の単位にする。
- Legacy HTTP+SSE transport、WebSocket、独自transportを追加しない。
- Streamable HTTPをnon-loopbackへbind可能にしない。
- 認証/TLSを「便利だから」という理由でv1へ追加しない。
- SandboxPolicyをMCP/LLMから変更できるI/Fを作らない。
- Fixed System Promptを外部ファイルへ移動しない。
- AppContainer profileをTaskごとに作成・削除しない。
- WFPを汎用Firewall rule engineへ拡張しない。
- DatabaseをSession/Journal目的で導入しない。Journalは小さなfile transactionで実装する。
- Graph library/Workflow engineを導入しない。
- `Utils`, `Common`, `Infrastructure`, `Manager`等の曖昧な巨大moduleを作らない。
- 仕様語彙と異なる新名称を導入する場合はDesign.mdを先に更新する。
- セキュリティ判定をLLM出力だけに依存させない。
---
## 23. 未固定の実装詳細
次は設計方針のみを固定し、実装時にWindows SDK/APIの実状を確認して選択する。仕様変更を意味しない。
| 項目 | 固定済み方針 | 実装時に決めること |
| --- | --- | --- |
| WFP | deny/default block + hostname resolve + IP/port allow | layer/sublayer/filter condition/API sequence |
| File backup threshold | memory超過時temp rollback | default閾値benchmark |
| Process TOCTOU | path+SHA必須 | file identity handleを用いた最適API |
| Context summary | 重要情報保持 | 要約promptとthreshold |
| Retry backoff | Ollama最大3 | 具体interval |
---
## 24. 仕様トレーサビリティ
| Specifications.md | Design.md | 主検証 |
| --- | --- | --- |
| 5章 MCP | 5章 | AT-01〜06 |
| 6章 Ollama | 6〜7章 | Ollama integration tests |
| 7章 Agent | 7章/17章 | ToolUseGuard/loop tests |
| 8章 Planner | 8章 | AT-14〜17 |
| 9章 Session | 9章 | session/context tests |
| 11章 Sandbox | 10〜13章 | ST-01〜18 |
| 14章 i18n | 14章 | AT-18〜20 |
| 16〜17章 Audit/Recovery | 15〜16章 | recovery/audit tests |
| 18章 Security Invariant | 11〜19章 | Security Test Matrix |
---
## 25. 参考資料
- IPA/SEC「実務家のための形式手法 厳密な仕様記述を志すための形式手法入門 厳密な仕様記述入門」2013年。
- Model Context Protocol Specification, Transports。stdio / Streamable HTTP、旧HTTP+SSE置換、loopback推奨等を参照。
- Ollama API Reference, Chat / Generate。tools、images、options、think、keep_alive、prompt/eval token countを参照。
---
## 26. 設計変更ルール
- `Specifications.md` と矛盾する設計変更は禁止。
- Security Invariant、MCP schema、SandboxPolicy schema、Task state transitionを変える場合は仕様書も同時更新する。
- 実装時にWindows API制約が判明しても、仕様を暗黙緩和しない。実現不能なら明示的に設計レビューへ戻す。
- 語彙を追加する前に既存用語で表現できないか確認する。
---
## 27. Configuration key索引
| Key | 意味 |
| --- | --- |
| schema_version | 設定schema版 |
| application.language | 既定locale |
| mcp.transport | stdio/http |
| mcp.http.host | loopback address only |
| mcp.http.port | listen port |
| mcp.images.max_count | 画像数上限 |
| mcp.images.max_bytes_each | 1画像byte上限 |
| mcp.images.max_total_bytes | request画像合計byte上限 |
| mcp.tasks.time_to_live_hours | 永続MCP Task保持時間 |
| mcp.tasks.poll_interval_ms | Task poll間隔 |
| agent.user_system_prompt | 追加prompt path |
| agent.max_iterations | 128 default |
| agent.same_failure_limit | 5 default |
| ollama.endpoint | Ollama URL |
| ollama.model | model name |
| ollama.think | thinking option |
| ollama.keep_alive | model keep alive |
| ollama.options.* | typed runtime options |
| ollama.extra_options.* | future passthrough options |
| planner.max_tasks | 32 default |
| sandbox.profile | readonly/development Workspace preset |
| sandbox.workspaces | Workspace Logical Path list |
| sandbox.mounts | Mount Logical Path + semantic access |
| sandbox.execution.entries | Alias、Executable Logical Path、optional Runtime Rootのlist。Shell分類はResolved file nameから導出 |
| sandbox.network.access | none/local/restricted |
| sandbox.network.local_endpoints | Loopback port list |
| sandbox.network.restricted_endpoints | host/port list |
| sandbox.resources.profile | constrained/normal/extended |
| sandbox.resources.memory_mb | optional memory override |
| sandbox.resources.process_limit | optional Job process override |
| sandbox.resources.execution_timeout_seconds | optional execution timeout override |
| file_edit.memory_backup_limit_mb | memory/temp threshold |
| localization.directory | locale directory |
| localization.fallback | en |
| skills.directory | Skill directory |
| logging.directory | log directory |
| logging.level | Application log閾値 |
| logging.http_requests | HTTP request log有効化 |
| logging.max_file_bytes | rotation size |
| logging.retained_files | rotation保持数 |
| limits.whole_read_bytes | whole read上限 |
| limits.search_max_results | search結果上限 |
| limits.tail_max_lines | tail行数上限 |
| limits.context_summary_ratio | context要約開始比率 |
## 28. 主要データ型索引
- `AgentSession`
- `AgentTask`
- `TaskGraph`
- `TokenEstimate`
- `TokenBudgetClass`
- `OllamaOptions`
- `OllamaChatRequest`
- `OllamaChatResponse`
- `SandboxPolicy`
- `FilesystemPolicy`
- `ProcessPolicy`
- `NetworkPolicy`
- `ResourcePolicy`
- `ExecutableApproval`
- `TaskResourceJournal`
- `AuditEvent`
- `LanguageContext`
- `SkillDescriptor`
- `AgentSkill`
- `ToolCallRecord`
## 29. 実装レビュー用チェックリスト
- [ ] public MCP toolは2個だけか。
- [ ] Legacy SSE endpointが生成されていないか。
- [ ] HTTPはloopback検証されているか。
- [ ] Fixed Promptがresource埋め込み等で変更不能か。
- [ ] Internal Tool argumentが必ずPolicy Engineを通るか。
- [ ] pathはcanonicalize/reparse検査後に評価しているか。
- [ ] process hashは実行直前に再計算しているか。
- [ ] shell有効でもFilesystem/Network policyを迂回できないか。
- [ ] Job breakawayがないか。
- [ ] Effective Network Policy外がdefault denyか。
- [ ] WFP/ACL変更前にjournalを書いているか。
- [ ] 起動時Recoveryがserveより前か。
- [ ] file rollback後にhash検証しているか。
- [ ] completed Taskを更新するpathがないか。
- [ ] TokenPERT式がdeterministicか。
- [ ] Ollama token countsがcallごとに集計されるか。
- [ ] context summaryが重要情報を保持するか。
- [ ] locale unknown keyがfatalか。
- [ ] stdio stdoutがMCP messageだけか。
- [ ] AuditとApplication Logが分離されているか。