# 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: session_id: status: queued 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: session_id: status: queued|planning|running|completed|failed|cancelled completed_tasks: / current_task: token_usage: input= output= total= critical_path_tokens: message: result: ``` `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/.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だけを`logs/http.jsonl`へJSON Linesで保存する。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` とし、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は次の5群に固定する。個々のOS command (`grep.exe`等) をtoolとして増殖させない。 | 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 / state / estimate | --- ## 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は拒否する。 - `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", "content":"string|null", "patch":"string|null", "expected_sha256":"string|null" } ``` - overwrite/patch/atomic_replaceはwrite permissionを要求する。 - deleteはdelete permissionを要求する。 - `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_state|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, "state":"queued|planning|running|completed|failed|cancelled|null" } ``` PlannerがDAG、不変条件、completed immutable、max_tasksを再検査してから適用する。 ### 7.6 ToolUseGuard Taskには `requires_external_effect` をPlanner内部属性として持たせる。trueのTaskで、当該iteration中のtool callが0かつ完了証拠がない場合、LLMへ「未実行」を示すsystem-generated observationを追加して再試行する。同一失敗fingerprintが5回に達したらTaskをfailedにする。 --- ## 8. Token Planner設計 ### 8.1 Task model ```text Task Id: UUID Description: string Dependencies: Set 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 再計画 - 未完了Taskの追加/dependency追加後にDAG validationとCPMを再計算。 - completed Taskは変更しない。 - 実績がPを超過しても即失敗にはせず、remaining Taskのestimate見直しをLLMへ要求できる。 - `max_tasks=32`超過提案は拒否し、既存Taskの統合をLLMへ求める。 - Budget Classは意味的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` 相当で保持する。永続化しない。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 5. Sandbox capability summary 6. current TaskGraph / current Task 7. previous Summary 8. recent Conversation / Execution Result ### 9.3 Summary policy `num_ctx`に対する利用率が設定閾値を超えたとき、古いConversation/Execution Resultを要約する。既定閾値は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 ``` ### 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を導出する。 - 既存DACL全体を書き換えず、アプリケーションSID向けの必要ACEだけをtransactionalに追加する。 - 元security descriptorまたは追加ACEの逆操作情報をRecovery Journalへ記録する。 - 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、model、request metadata、prompt、response、tool_calls、token usageを記録する。秘密情報の自動継承は禁止だが、利用者入力にsecretが含まれる可能性はあるためlog directoryはuser-only ACLにする。 ### 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`. --- ## 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コマンド名ごとに増やさず、定義済み5群に収める。 - 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 | | 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 | | limits.whole_read_bytes | whole read上限 | | limits.search_max_results | search結果上限 | | limits.tail_max_lines | tail行数上限 | | limits.context_summary_ratio | context要約開始比率 | | mcp.images.max_count | 画像数上限 | | mcp.images.max_bytes_each | 1画像byte上限 | | mcp.images.max_total_bytes | request画像合計byte上限 | ## 28. 主要データ型索引 - `AgentSession` - `AgentTask` - `TaskGraph` - `TokenEstimate` - `TokenBudgetClass` - `OllamaOptions` - `OllamaChatRequest` - `OllamaChatResponse` - `SandboxPolicy` - `FilesystemPolicy` - `ProcessPolicy` - `NetworkPolicy` - `ResourcePolicy` - `ExecutableApproval` - `TaskResourceJournal` - `AuditEvent` - `LanguageContext` - `SkillDescriptor` - `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が分離されているか。