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
|
# 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
│
▼
Policy Engine
│
▼
Sandbox Broker
├── AppContainer
├── NTFS ACL
├── Job Object
├── WFP
└── Named Pipe
│
▼
Sandboxed 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` を別型で管理する。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 Tool calling
Ollamaに公開する現行Internal Tool catalogは次のとおりとする。個々のOS command (`grep.exe`等) をtoolとして増殖させない。catalogの構成は設計事項であり、仕様上の固定数として扱わない。
| Tool | 責務 | 主なoperation |
| --- | --- | --- |
| file_search | 検索 | glob / name / text / regex / tail相当 |
| file_read | 読取 | whole / range / metadata |
| file_edit | 編集 | overwrite / patch / atomic_replace / delete |
| process_run | 承認済Process実行 | exe + 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前にcanonical pathとreparse pointを検査する。
### 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 permissionを要求する。
- deleteはdelete permissionを要求する。
- renameはsource/destination双方にwrite permissionを要求する。destinationが既に存在する場合は拒否する(overwrite不可)。cross-volume renameは不支持で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 line 1本ではなくexeとargsを分離する。
- executableはcanonical path + SHA-256 approval必須。
- shell category disabled時はcmd/powershell/pwshを拒否する。
- cwdは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
}
```
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を要求し、直下のエントリ一覧を返す。外部効果ではない。
- 既存の PathPolicy / CanonicalPath / TaskAclManager (root継承ACE) / TaskResourceJournal / RecoveryManager 枠組みを利用する。新規作成ディレクトリは親の継承ACEを自動取得するため追加ACL操作は不要。
- mkdir後crash → ディレクトリ削除、rmdir後crash → 空ディレクトリ再作成、でRecoveryする。
### 7.7 Tool error表現
既存の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は分離し、内部Tool名は利用者向け結果へ含めない。
### 7.8 ToolUseGuard
Taskには `requires_external_effect` をPlanner内部属性として持たせる。**Planning フェーズで LLM structured output により Task ごとに判定・設定される**(keyword heuristic ではない)。trueのTaskで、当該iteration中のtool callが0かつ完了証拠がない場合、LLMへ「未実行」を示すsystem-generated observationを追加して再試行する。同一失敗fingerprintが5回に達したらTaskをfailedにする。ただし、Policy EngineのdenyおよびSandbox backendの`UnauthorizedAccessException`は`RetryAllowed=false`のterminal Tool resultへ変換する。Runtimeはobserverへ結果を1回記録した後、同一Tool呼出しへ再投入せず、§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
```
### 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が複数独立成果物を含む場合に分割する。
- Policy denyは同一Tool呼出しへ再投入しない。許可済み能力だけで代替できる可能性がある場合、`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=false`で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
順序を次に固定する。
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
実行要件は、現在runningのTaskだけを実行してqueued Taskを先取りしないことを指示する。外部効果が必要な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. SandboxPolicy YAML設計
### 10.1 schema概要
```yaml
schema_version: 1
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: qwen3-coder
think: true
keep_alive: 5m
options:
num_ctx: 32768
temperature: 0.4
extra_options: {}
planner:
max_tasks: 32
sandbox:
filesystem:
read: []
write: []
execute: []
delete: []
process:
allow_shell: true
approvals: []
max_processes: 16
network:
mode: deny
allow: []
resources:
memory_mb: 4096
process_timeout_seconds: 1800
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 Filesystem entry
各list itemはpath文字列とする。起動時に絶対canonical pathへ正規化して保持する。file/directoryは実在時に種別を記録し、未作成write targetは最も近い既存親directoryまで検査する。
### 10.3 Process approval entry
```yaml
approvals:
- path: C:/Program Files/Git/cmd/git.exe
sha256: "<64 hex chars>"
- path: C:/Windows/System32/WindowsPowerShell/v1.0/powershell.exe
sha256: "<64 hex chars>"
```
署名はaudit metadataとして取得可能だが、v1のallow判定はpath + SHA-256を必須条件とする。
### 10.4 Network entry
```yaml
network:
mode: allow
allow:
- host: github.com
ports: [443]
- host: api.github.com
ports: [443]
```
`allow` modeでもlist外はdeny。`deny`ではlistを無視して全denyする。localhostも特別扱いしない。
---
## 11. Windows強制設計
### 11.1 AppContainer
- Application Profileを固定名で作成/取得する。
- 起動時にprofile SIDを解決する。
- Taskごとにprofileを作り直さない。
- AppContainer外の通常user tokenに戻るbreakawayを許可しない。
### 11.2 NTFS ACL
- Policy Engineが許可pathから必要ACEを導出する。
- 許可pathがdirectoryの場合、そのrootへ`ContainerInherit | ObjectInherit`付きのApplication SID ACEを1件だけtransactionalに追加し、既存およびTask中に作成されたdescendantへ継承させる。descendantごとのDACL列挙・snapshot・明示ACE追加は行わない。
- 許可pathがfileの場合は、そのfileだけへ継承なしACEを追加する。異なる権限を持つnested rootは別scopeとして逆順cleanupする。
- protected DACLを持つdescendantの継承保護は解除しない。そのpathはOS拒否のままとし、Sandbox権限を暗黙に拡張しない。
- rootの元security descriptorをRecovery Journalへ1件記録する。
- Task終了で追加分を除去し、元状態との整合を検査する。
### 11.3 Job Object
- TaskごとにJob Objectを1つ作成する。
- root sandbox processをJobへ割り当てる。descendantを同一Jobへ継承させる。
- breakawayを許可しない。
- process count / memory limitをJobへ設定する。
- `KILL_ON_JOB_CLOSE`相当を利用し、application終了時にprocess treeを残さない。
### 11.4 Process approval
Sandbox Brokerは実行直前にcanonical pathを取得し、ファイルを開いた状態でSHA-256を計算し、approvalと一致確認してから起動する。TOCTOU低減のため、検証対象と実行対象のpath解決がずれないよう実装時にWin32のfile identity確認を追加する。具体API選択は実装時に確定する。
### 11.5 WFP方針
WFP実装は複雑な汎用Firewallにしない。設計上の変換規則だけを固定する。
1. `deny`ならApplication Profile/Task processに対するoutbound blockを作成する。
2. `allow`ならdefault blockを置き、列挙hostをTask開始時にDNS解決する。
3. 解決したIP集合とportの組にだけallow filterを作成する。
4. Task実行中はそのIP snapshotを使用し、複雑な動的DNS追随は行わない。
5. DNS解決失敗はdeny。
6. Task終了でTask固有WFP filterを削除する。
7. localhostはallow-listに明示されない限り許可しない。
具体的な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 | SandboxPolicyと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":"...","args":["..."],"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
- process approval 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 | hash mismatch、path mismatch、shell toggle |
| Network | deny loopback、allow-list host/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 | read許可file | 成功 |
| ST-02 | read未許可file | ACCESS_DENIED |
| ST-03 | write許可file | 成功 |
| ST-04 | delete権限なしdelete | 拒否 |
| ST-05 | junctionで許可外へ脱出 | 拒否 |
| ST-06 | symlink chainで許可外へ脱出 | 拒否 |
| ST-07 | 承認exe/hash一致 | 成功 |
| ST-08 | exe更新/hash不一致 | 拒否 |
| ST-09 | shell disabledでPowerShell | 拒否 |
| ST-10 | 子が未承認exe起動 | 拒否 |
| ST-11 | Job close | 全descendant終了 |
| ST-12 | network denyで127.0.0.1 | 拒否 |
| ST-13 | network allowで許可host:port | 成功 |
| ST-14 | network allowで未許可port | 拒否 |
| ST-15 | MCPからpolicy変更試行 | schema/機能上不可能 |
| ST-16 | Ollama tool arg path脱出 | Policyで拒否 |
| ST-17 | crash after ACL apply | 再起動cleanup |
| ST-18 | crash after WFP apply | 再起動cleanup |
| ST-19 | malformed locale | 起動失敗 |
| ST-20 | non-loopback HTTP bind | 起動失敗 |
---
## 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を返す。
---
## 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 | deny/allow-list 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を基準に解決し、ソースツリーを参照しない。
- 必須Gateはlocal Ollamaだけで実行し、cloud modelは任意互換試験に限定する。
---
## 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.filesystem.read | read allow-list |
| sandbox.filesystem.write | write allow-list |
| sandbox.filesystem.execute | execute path allow-list |
| sandbox.filesystem.delete | delete allow-list |
| sandbox.process.allow_shell | shell toggle |
| sandbox.process.approvals | path+sha256 approvals |
| sandbox.process.max_processes | Job process limit |
| sandbox.network.mode | deny/allow |
| sandbox.network.allow | host/port list |
| sandbox.resources.memory_mb | Job memory limit |
| sandbox.resources.process_timeout_seconds | process timeout |
| 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がないか。
- [ ] Network allow-list外が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が分離されているか。
|