<a id="tool-contract"></a>
# 도구, 권한과 외부 효과

상위 경로: [Norma 시스템 지도](../README.md#system-map) → [기능 지도](../features/README.md#feature-map) → Tool action

`CoreTool`은 이름·설명·prompt·input schema, read-only/concurrency 판정, 자체 permission decision과 `Call`을 제공한다. `tool.Build`에서 생략한 보안 metadata는 mutating, exclusive, approval-required로 닫힌다. registry의 duplicate name은 교체이고, schema를 provider에 노출하는 목록과 name lookup 실행 경로는 별도다. [tool 근거](evidence:tool-contract) [registry 근거](evidence:tool-registry)

<a id="permission-pipeline"></a>
## Direct tool call의 실행 순서

```mermaid
flowchart TD
  U[tool_use name + raw input] --> R{registry lookup}
  R -->|missing| ER[error tool_result]
  R -->|found| S{schema validation}
  S -->|fail| ER
  S -->|pass or RawInput| P[permission Evaluate]
  P -->|deny| ER
  P -->|allow + optional input rewrite| H[PreToolUse hooks]
  H -->|block| ER
  H -->|last input rewrite| C[CoreTool.Call]
  C --> O[global output cap/spill]
  O --> PH[PostToolUse hooks]
  PH --> RT[paired tool_result + optional Extra messages]

  click S "#schema-validation" "Schema validation"
  click P "#permission-stages" "Permission stages"
  click H "#hooks" "Hook 경계"
  click O "#output-capture" "Output 제한"
```

permission callback이 `UpdatedInput`을 반환하면 그 값을 PreToolUse에 보낸다. PreToolUse가 다시 input을 바꿀 수 있지만 schema와 permission을 재실행하지 않는다. 따라서 hook은 이미 승인된 capability보다 넓은 resource/command로 rewrite하지 않아야 한다. [실행 근거](evidence:harness-tools)

<a id="schema-validation"></a>
### Schema validation

중앙 validator는 object의 `required`와 string/number/integer/boolean/array/object 같은 기본 JSON type을 검사한다. enum, numeric bounds, pattern, additionalProperties를 포함한 전체 JSON Schema 구현은 아니다. `required`를 `[]any`로 작성한 built-in schema와 달리 다른 Go 표현은 검사에서 누락될 수 있다. `RawInput` tool은 model 안내용 schema를 계속 노출하지만 중앙 validation을 건너뛰고 자체 parser가 책임진다. [schema 근거](evidence:tool-schema)

<a id="permission-stages"></a>
### Permission stages

```text
1. DisallowedTools name rule 또는 tool hard-deny → deny
2. bypass → allow / plan + mutating → deny / plan + read-only → allow
3. AllowedTools, acceptEdits file edit, read-only, tool self-allow → allow
4. dontAsk/auto → deny, 그 밖에는 CanUseTool callback 또는 deny
```

rule match는 `*`, exact name, `Name(...)`의 name 부분만 본다. argument, path, host, URL, tenant를 평가하지 않는다. `ModeBypass`도 explicit deny rule과 tool hard-deny를 넘지 못한다. `ModeAuto`는 tool 자체 allow를 인정하지만 approval-required action을 묻지 않고 거부한다. [permission 근거](evidence:permission)

<a id="hooks"></a>
## Hook 경계

`hook.Registry`는 PreToolUse, PostToolUse, PostToolUseFailure, UserPromptSubmit, SessionStart, SessionEnd, Stop, SubagentStart를 선언한다. callback은 등록 순서로 실행하며 PreToolUse의 첫 block이 중단하고 마지막 non-empty rewrite가 이긴다. Stop은 hard prevent와 blocking continuation을 구분한다. [hook 근거](evidence:hooks)

현재 `SessionStart`, `UserPromptSubmit`, tool hooks, Stop, SubagentStart 호출은 확인했지만 `SessionEnd`의 agentcore 호출처는 확인되지 않았다. callback timeout·panic recovery·thread safety도 제공하지 않는다. hook은 audit trail이나 외부 policy broker를 자동 구성하지 않는다.

<a id="builtin-boundaries"></a>
## 기본·선택 도구의 capability 경계

아래는 도구군 요약이다. 30개 정적 이름의 설치 조건, read-only/concurrency/permission metadata와 effect는 [Tool 전수 색인](../reference/tools.md#static-tools)에 있다.

| 도구군 | 설치 조건 | 외부 효과와 핵심 경계 |
|---|---|---|
| Read/Write/Edit/MultiEdit/LS/Glob/Grep/Bash | `Tools == nil` 기본 | WorkingDir 기반 편의 처리이며 path sandbox가 아님 |
| TaskOutput/TaskStop/TaskList/Monitor | background disable이 아니면 자동 추가 | session temp file/process와 notification; Prompt 종료 뒤에도 process 가능 |
| PTY shell five tools | host가 `ShellSessionTools()` 추가 | persistent process/TTY; Bash deny parser를 공유하지 않음 |
| WebFetch | option | redirect/DNS/IP allowlist 없음; proxy 실패 시 direct-intended fallback, default transport가 환경 proxy를 재상속할 수 있음 |
| WebSearch | option과 backend config | provider endpoint로 outbound; query target scope 없음 |
| Todo/AskUser | store/callback option | in-memory state 또는 host interaction |
| plan/memory/skill/deferred | 해당 option | mode/file/instruction/unlock 상태 변경 |

Bash는 일부 command deny pattern, foreground timeout과 background 전환을 제공하지만 command sandbox, egress, credential isolation은 아니다. Task manager path에는 SessionID가 들어가므로 host가 trusted identifier를 제공해야 한다. `Session.Close`는 task manager cleanup을 호출한다. [Bash 근거](evidence:bash-tool) [task 근거](evidence:background-tasks) [PTY 근거](evidence:shell-tools)

<a id="output-capture"></a>
## Tool output 제한

모든 direct tool result의 text block은 `execOne`의 공통 `capOutput`을 거친다. 기본 head cap은 30,000 characters다. `ToolOutputDir`가 있으면 full output을 파일에 쓰고 model에는 head와 pointer를 주며, 없으면 잘린 marker를 준다. 이미 marker가 있는 값은 idempotent하게 다시 처리하지 않는다. [capture 근거](evidence:tool-capture)

spill file은 편의상 원문을 보존하지만 evidence store는 아니다. integrity digest, action provenance, retention, encryption과 atomic coupling이 없고 marker-like 원문은 이미 처리된 값으로 오인될 수 있다.

<a id="deferred-tools"></a>
## Deferred tool의 노출과 실행

`DeferredTools`가 있으면 provider schema에서 이름들을 숨기고 `SearchExtraTools`, `ExecuteExtraTool`을 추가한다. `UnlockSet`은 wrapper가 실제 inner name을 호출할지 결정한다. [deferred 근거](evidence:deferred-tools)

- 숨긴 schema는 original registry에 남아 있어 model/provider가 name을 직접 만들면 direct `execOne`으로 실행될 수 있다.
- `ExecuteExtraTool` wrapper의 permission/hook는 적용되지만 inner tool의 `CheckPermissions`와 inner name hook는 다시 호출되지 않는다.
- skill invocation이 unlock set을 바꿀 수 있으나 일반 resume은 그 상태를 durable하게 복원하지 않는다.
- subagent가 parent registry를 공유하면 parent의 schema filter 설정은 별도로 상속되지 않는다.

따라서 deferred 기능은 context 절약/UX primitive이며 capability admission 경계로 단독 사용하면 안 된다.

<a id="network-tools"></a>
## Web, search와 MCP outbound

WebFetch는 optional proxy/CA/insecure TLS를 지원하고 response cap과 HTML-to-text 변환을 수행한다. configured proxy request가 실패하면 direct-intended client로 fallback해 recording/scope 경계를 이탈할 수 있다. `InsecureTLS=false`인 fallback client는 nil Transport라 proxy environment를 다시 상속할 수 있으므로 실제 direct 연결도 보장하지 않는다. redirect마다 scope를 재검사하거나 DNS/IP를 pin하지 않는다. [WebFetch 근거](evidence:webfetch-runner)

WebSearch는 `ddgs`, `brave-free`, `tavily`, `deepseek` backend를 조립한다. 잘못된 설정은 NewSession에서 오류나 warning 없이 tool 생략으로 이어진다. `WebSearchProbe` 같은 host helper는 agent permission pipeline 밖에서 직접 호출할 수 있다. [WebSearch 근거](evidence:websearch-operations)

MCP stdio child는 host environment로 실행되고 tool을 Norma registry에 감싼다. MCP와 web 모두 host-owned egress broker, endpoint allowlist, request/response evidence capture가 있어야 승인된 target 범위를 강제할 수 있다. HTTP method/header/result/retry/timeout과 MCP method별 fidelity는 [소비 operation 계약](../reference/external-operations.md#overview)에 있다. [MCP 상세](extensions-and-coordination.md#mcp)
