# 작업 공간 파일 (/ko/docs/reference/workspace-files)

작업 공간은 이름이 `.echolot`로 끝나는 폴더이며, 그 안에는 일반 TOML 파일이 있습니다. 요청, 환경, MCP 서버, 모의 서버, 플로마다 파일 하나씩입니다.
Finder에서는 문서 하나로 보이고, 터미널, Git, 편집기에서는 일반 폴더입니다. Echolot은 모든 파일을 매번 같은 방식으로 기록합니다(키는 고정된 순서,
기본값인 것은 기록하지 않음). 그래서 앱에서 한 변경은 diff에서 작은 변경으로 나타납니다. [Git과 팀](/docs/workspaces/git-and-teams)을
참고하세요.

```text
Alpenglow.echolot/
  workspace.toml                     작업 공간: ID, 이름, 변수, 인증, 에이전트, 프록시, 인증서
  environments/
    staging.toml                     환경 하나
  requests/
    _folder.toml                     최상위의 순서
    _folder.pre.js                   작업 공간의 요청 전 스크립트(와 _folder.test.js)
    auth/
      _folder.toml                   폴더: 이름, 순서, 문서, 변수, 인증
      sign-in.req.toml               HTTP 요청
      sign-in.body.json              요청의 본문
      sign-in.pre.js                 요청의 요청 전 스크립트
      sign-in.test.js                요청의 테스트 스크립트
    catalog/
      search-products.gql.toml       GraphQL 요청
      search-products.graphql        요청의 쿼리
  mcp-servers/
    alpenglow-mcp.toml               MCP 서버
  specs/
    alpenglow.yaml                   OpenAPI 문서
    shop.graphql                     GraphQL 스키마
    inventory.proto                  protobuf 파일
  mocks/
    shop.toml                        모의 서버: 설정과 경로
    shop.js                          JavaScript로 작성한 경로
  flows/
    place-test-order.flow.toml       플로
  assistant/
    checking-orders.md               공유한 어시스턴트 대화(읽기용)
    checking-orders.json             같은 대화(앱에서 열기용)
```

## 모든 파일의 규칙 [#rules-for-every-file]

- 파일은 TOML 1.0이며 UTF-8입니다.
- 각 파일은 형식의 버전인 `echolot = 1`로 시작합니다. 더 높은 숫자가 있는 파일은 더 새로운 Echolot이 저장한 것이며, Echolot은 그 파일을
  열지 않고 그렇게 알려 줍니다.
- 파일 이름은 **슬러그**입니다. 소문자, 숫자, 하이픈으로 이루어지며 최대 80자이고, 항목의 이름에서 만들어집니다(`Sign in`은 `sign-in`).
  이름 자체는 `name` 키입니다.
- 항목 사이의 경로는 `/`로 이은 슬러그이며 `requests/` 기준 상대 경로입니다. `auth/sign-in`, `orders`.
- 텍스트 필드에는 `{{variables}}`와 [동적 값](/docs/reference/dynamic-values)을 넣을 수 있습니다.
- 항목의 목록은 테이블의 TOML 배열(`[[headers]]`)입니다. `enabled = false`가 있는 항목은 보관되지만 꺼져 있으며, 키가 없으면 켜져 있습니다.

## 파일에 절대 들어가지 않는 것 [#what-never-goes-in-the-files]

- **비밀 값.** 비밀 변수는 이름과 `secret = true`로 기록되며 값은 없습니다. 값은 Mac의 키체인에 있습니다. 비밀 값이 필요한 필드(암호, 프록시 암호,
  클라이언트 비밀 값)에는 비밀 변수인 `{{variable}}`을 넣어야 합니다. Echolot은 입력한 암호를 키체인으로 옮기도록 제안하며, 가져오기는
  자동으로 그렇게 합니다. [비밀 값](/docs/workspaces/secrets)을 참고하세요.
- OAuth 토큰과 MCP 로그인: 키체인에 있습니다.
- `pm.environment.set` 등으로 스크립트가 설정한 값: 윈도우나 명령이 실행되는 동안만 유지됩니다.
- 기록과 응답: Mac의 Application Support에 있으며 작업 공간마다 기록이 하나입니다. [기록](/docs/workspaces/history)을 참고하세요.
- 개인 레이아웃: 패널 레이아웃과 크기, 열려 있는 탭, 선택한 환경.

그래서 작업 공간은 커밋하고 공유해도 안전합니다. 팀원은 자신의 비밀 값을 직접 설정합니다.

## workspace.toml [#workspacetoml]

```toml
# Echolot workspace. Requests live in requests/, one file each.
echolot = 1
id = "0b7d4c1e-2f6a-4e38-9c51-7a1e3d9b5f20"
name = "Alpenglow"

[[variables]]
name = "baseURL"
value = "https://demo.echolot.dev/v1"

[[variables]]
name = "token"
secret = true
```

| 키 | 의미 |
| --- | --- |
| `id` | 작업 공간의 ID. 키체인의 비밀 값이 이 ID에 속하므로, ID가 같은 복사본은 비밀 값을 공유합니다. 내보낸 복사본은 새 ID를 받습니다. |
| `name` | 작업 공간의 이름. |
| `[[variables]]` | 작업 공간 변수. [변수](#variables)를 참고하세요. |
| `[auth]` | 상속하는 모든 요청의 인증. [인증](#auth)을 참고하세요. 기본값: 없음. |
| `[agents]` | AI 에이전트에 대한 규칙. [에이전트](#agents)를 참고하세요. |
| `[proxy]` | 앱의 프록시 대신 사용하는 작업 공간 자체의 프록시. |
| `[[certificates]]` | 신뢰할 CA 인증서와 호스트별로 보낼 클라이언트 인증서. |

### 프록시 [#proxy]

| 키 | 의미 |
| --- | --- |
| `mode` | `manual`(기본값), `system`, `environment`(`HTTPS_PROXY` 계열), `none`. |
| `url` | 프록시: `http://host:port`, `https://…`, `socks5://host:port`. |
| `username`, `password` | 프록시의 자격 증명. 암호는 비밀 `{{variable}}`로 작성하세요. |
| `bypass` | 직접 연결할 호스트(배열). |

### 인증서 [#certificates]

각 `[[certificates]]` 테이블은 호스트 하나에 대한 규칙입니다.

| 키 | 의미 |
| --- | --- |
| `host` | 규칙이 적용되는 호스트. |
| `trust` | 신뢰할 CA 인증서의 PEM 파일(배열). |
| `certificate` | 클라이언트 인증서: PEM 파일 또는 `.p12`/`.pfx` 파일. |
| `key` | 인증서 파일에 키가 없을 때 클라이언트 인증서의 PEM 키. |
| `passphrase` | 키 또는 PKCS#12 파일의 암호 문구. 비밀 `{{variable}}`로 작성하세요. |

### 에이전트 [#agents]

`[agents]`는 Echolot의 MCP 서버와 어시스턴트를 통해 AI 에이전트가 이 작업 공간에서 할 수 있는 일을 정합니다. [에이전트](/docs/ai/agents)를
참고하세요.

```toml
[agents]
allowed-hosts = ["demo.echolot.dev"]
max-requests = 200
max-requests-per-minute = 30

[agents.rules]
unsafe-send = "ask"
destructive = "refuse"
```

| 키 | 의미 |
| --- | --- |
| `enabled` | `false`이면 이 작업 공간에서 에이전트가 꺼집니다. 에이전트는 작업 공간에서 아무것도 얻지 못합니다. 기본값 `true`. |
| `allowed-hosts` | 요청이 사용하는 호스트 외에 작업 공간 자체의 호스트로 간주할 호스트. |
| `max-requests` | 에이전트 세션 하나가 전체적으로 보낼 수 있는 요청 수. |
| `max-requests-per-minute` | 에이전트 세션 하나가 분당 보낼 수 있는 요청 수. |
| `[agents.rules]` | 동작 종류별 규칙: `allow`, `ask`, `refuse`. |

동작의 종류는 `read`, `safe-send`, `unsafe-send`, `protected-send`, `new-host`, `workspace-write`, `destructive`입니다. 더 엄격한 규칙은 항상
적용됩니다. 더 느슨한 규칙은 신뢰한 후에만 적용됩니다(앱이 묻고, 명령줄에서는 `--trust-workspace-policy`가 필요합니다). `protected-send`와
`new-host`는 `allow`로 설정할 수 없습니다.

## environments/ [#environments]

환경마다 파일 하나가 있으며, 파일 이름은 `--env`가 사용하는 슬러그입니다.

```toml
echolot = 1
name = "Production"
protected = true

[[variables]]
name = "baseURL"
value = "https://api.alpenglow.example/v1"

[[variables]]
name = "password"
secret = true
```

| 키 | 의미 |
| --- | --- |
| `name` | 환경의 이름. |
| `protected` | `true`이면 [보호된 환경](/docs/workspaces/protected-environments)이 됩니다. 보낼 때마다 먼저 확인을 요청합니다. |
| `[[variables]]` | 환경의 변수. |

### 변수 [#variables]

`workspace.toml`, 환경, 폴더, 요청에서 같습니다.

| 키 | 의미 |
| --- | --- |
| `name` | 변수의 이름. `{{name}}`으로 사용합니다. |
| `value` | 변수의 값. 비밀 값에는 쓰지 않습니다. |
| `secret` | 비밀 값이면 `true`. 값은 키체인에 있습니다. |
| `enabled` | `false`이면 끕니다. |

## requests/ [#requests]

`requests` 폴더에는 사이드바에 보이는 트리가 들어 있습니다. 그 안의 각 폴더는 트리의 폴더이고, 각 요청 파일은 요청입니다. 요청의 종류는 파일의
접미사로 정해집니다.

| 접미사 | 종류 |
| --- | --- |
| `.req.toml` | HTTP(Server-Sent Events 포함) |
| `.gql.toml` | GraphQL |
| `.grpc.toml` | gRPC |
| `.ws.toml` | WebSocket |
| `.sio.toml` | Socket.IO |
| `.mqtt.toml` | MQTT |
| `.mcp.toml` | MCP 서버 호출 |

요청 옆에 같은 슬러그로 있는 파일은 다음과 같습니다.

| 파일 | 담긴 내용 |
| --- | --- |
| `<slug>.body.<ext>` | 요청의 본문을 본문 고유의 형식으로: `.json`, `.xml`, `.txt`, `.html`, `.graphql`, `.form.txt`. |
| `<slug>.graphql` | GraphQL 요청의 쿼리. |
| `<slug>.pre.js` | 요청 전 스크립트. |
| `<slug>.test.js` | 테스트 스크립트. |

### _folder.toml [#foldertoml]

모든 폴더에 있으며, 최상위를 위한 `requests/` 자체에도 있습니다.

```toml
echolot = 1
name = "Auth"
order = ["sign-in", "who-am-i", "client-credentials"]
docs = "Send \"Sign in\" first: it captures the access token into {{token}}."
```

| 키 | 의미 |
| --- | --- |
| `name` | 폴더의 이름. `requests/_folder.toml`에는 없습니다. |
| `order` | 폴더 안에 있는 항목의 슬러그로, 사이드바와 실행이 사용하는 순서입니다. 나열되지 않은 항목은 그 뒤에 슬러그 순으로 옵니다. |
| `docs` | 폴더의 문서(Markdown). |
| `spec` | 폴더가 따르는 명세. 예: `specs/alpenglow.yaml`. |
| `spec-url` | 명세가 URL에서 왔을 때 명세를 가져오는 위치. |
| `agent-tools` | `true`이면 폴더의 요청을 에이전트에 도구로 제공합니다. |
| `[[variables]]` | 폴더 안의 모든 것에 적용되는 폴더의 변수. |
| `[auth]` | 상속하는 폴더 안의 모든 것에 적용되는 폴더의 인증. 기본값: 상속. |

그 옆의 `_folder.pre.js`와 `_folder.test.js`는 폴더의 스크립트이며, `requests/`에서는 작업 공간의 스크립트입니다. 안에 있는 모든 요청에 대해
작업 공간의 스크립트부터 요청 자신의 스크립트까지 순서대로 실행됩니다. 명세를 따르는 폴더에는 명세에서 마지막으로 가져온 내용인 `_spec-lock.json`도
있습니다. Echolot이 관리하도록 두세요.

### 모든 요청의 키 [#keys-of-every-request]

```toml
echolot = 1
name = "Sign in"
method = "POST"
url = "{{baseURL}}/auth/token"

[body]
syntax = "json"
file = "sign-in.body.json"

[[headers]]
name = "Content-Type"
value = "application/json"

[[assertions]]
target = "status"
check = "equals"
expected = "200"

[[captures]]
variable = "token"
from = "json"
path = "$.access_token"
scope = "workspace"
secret = true
```

| 키 | 의미 |
| --- | --- |
| `name` | 요청의 이름. |
| `url` | 쿼리 문자열이 포함된 URL. MCP 호출을 제외한 모든 종류에 있습니다. |
| `docs` | 요청의 문서(Markdown). |
| `spec-operation` | 요청을 만든 명세의 작업. 예: `POST /auth/token`. |
| `[[headers]]` | `name`, `value`, 꺼진 헤더에는 `enabled = false`. |
| `[[disabled-params]]` | 꺼진 쿼리 매개변수: `name`, `value`. 켜져 있는 것은 URL에 있습니다. |
| `[[disabled-form-fields]]` | 꺼진 폼 필드: `name`, `value`. |
| `[[variables]]` | 요청 자신의 변수. |
| `[[assertions]]` | 요청의 검사. |
| `[[captures]]` | 응답마다 변수에 저장하는 값. |
| `[auth]` | 요청의 인증. 기본값: 폴더에서 상속. |
| `[settings]` | 앱의 설정과 다른 설정. |

### HTTP 요청(.req.toml) [#http-requests-reqtoml]

| 키 | 의미 |
| --- | --- |
| `method` | 메서드: `GET`, `POST` 또는 임의의 토큰. 기본값 `GET`. |
| `[body]` | 본문. 생략하면 없음. |

`[body]` 테이블은 세 가지 형태 중 하나를 취합니다.

| 형태 | 키 |
| --- | --- |
| 텍스트 | `syntax`: `json`, `xml`, `text`, `html`, `graphql`, `form`(URL 인코딩된 폼 필드). `file`: 요청 옆의 본문 파일. |
| 디스크에서 스트리밍하는 파일 | `stream-from`: 파일의 경로. |
| 멀티파트 | `syntax = "multipart"`와 부분마다 `[[body.parts]]` 테이블: `name`, 그리고 `value`(텍스트) 또는 `file`(경로), `content-type`, `enabled`. |

### GraphQL 요청(.gql.toml) [#graphql-requests-gqltoml]

```toml
echolot = 1
name = "Search products"
url = "{{baseURL}}/graphql"
operation = "SearchProducts"
schema = "specs/shop.graphql"
query-file = "search-products.graphql"
graphql-variables = """
{
  "text": "ultralight"
}"""
```

| 키 | 의미 |
| --- | --- |
| `query-file` | 쿼리가 들어 있는 요청 옆의 파일, `<slug>.graphql`. |
| `operation` | 쿼리에 작업이 여러 개일 때 실행할 작업. |
| `graphql-variables` | JSON 텍스트로 된 GraphQL 변수. 예전 파일에서는 `variables`라고 합니다. |
| `schema` | 요청을 검사하고 자동 완성하는 기준이 되는 스키마: `specs/`의 파일. |
| `transport` | `post`(기본값), `get`, 구독용 `websocket`. |
| `persisted-queries` | `true`이면 먼저 쿼리의 SHA-256만 보내고, 서버가 모르면 쿼리를 보냅니다(자동 영구 쿼리). |
| `batch` | `true`이면 작업이 여러 개인 문서를 작업마다 항목 하나인 배열로 보냅니다. |
| `[[uploads]]` | 파일 업로드: `variable`(파일이 들어가는 변수)과 `path`. |

### gRPC 요청(.grpc.toml) [#grpc-requests-grpctoml]

| 키 | 의미 |
| --- | --- |
| `proto` | 서비스를 설명하는 `.proto` 파일. 예: `specs/inventory.proto`. |
| `reflection` | `true`이면 서버의 리플렉션을 사용합니다. |
| `service` | 서비스. 예: `alpenglow.inventory.v1.Inventory`. |
| `rpc` | 메서드. 예: `Reserve`. |
| `message` | JSON 텍스트로 된 메시지. 클라이언트 스트리밍 메서드에서는 메시지의 배열. |
| `deadline-ms` | 밀리초 단위의 마감 시간. |
| `compression` | 보내는 메시지에 대한 `gzip` 또는 `deflate`. |

### WebSocket 요청(.ws.toml) [#websocket-requests-wstoml]

| 키 | 의미 |
| --- | --- |
| `subprotocols` | 제안할 하위 프로토콜(배열). |
| `[[messages]]` | 저장된 메시지: `name`, `text`, `enabled`. |

### Socket.IO 요청(.sio.toml) [#socketio-requests-siotoml]

| 키 | 의미 |
| --- | --- |
| `version` | 서버의 Socket.IO 버전: `4`(기본값), `3`, `2`. |
| `path` | 서버가 수신 대기하는 위치. 기본값 `/socket.io/`. |
| `namespace` | 참여할 네임스페이스. 예: `/support`. |
| `socket-auth` | JSON 텍스트로 된 인증 페이로드. |
| `[[emits]]` | 저장된 이벤트: `name`, `event`, `arguments`(JSON 텍스트), 확인 응답을 요청하는 `ack = true`, `enabled`. |

### MQTT 요청(.mqtt.toml) [#mqtt-requests-mqtttoml]

| 키 | 의미 |
| --- | --- |
| `version` | `5`(기본값) 또는 `3.1.1`. |
| `client-id` | 클라이언트 ID. 비어 있으면 무작위 값. |
| `clean-start` | `false`이면 브로커에 세션을 유지하도록 요청합니다. 기본값 `true`. |
| `keep-alive` | 핑 사이의 간격(초). 기본값 60. |
| `[will]` | 유언 메시지: `topic`, `payload`, `qos`, `retain`. |
| `[[subscriptions]]` | `filter`, `qos`(기본값 0), `no-local`, `enabled`. |
| `[[messages]]` | 게시할 저장된 메시지: `name`, `topic`, `payload`, `qos`, `retain`, `content-type`, `enabled`. |

사용자 이름과 암호는 요청의 Basic 인증입니다.

### MCP 호출(.mcp.toml) [#mcp-calls-mcptoml]

```toml
echolot = 1
name = "search_catalog"
server = "alpenglow-mcp"
tool = "search_catalog"
arguments = """
{
  "query": "ultralight tent",
  "limit": 3
}"""
```

| 키 | 의미 |
| --- | --- |
| `server` | `mcp-servers/`에 있는 서버의 슬러그. |
| `tool`, `resource`, `prompt`, `method` | 호출할 대상: 이름으로 지정하는 도구, URI로 지정하는 리소스, 이름으로 지정하는 프롬프트, 또는 원시 JSON-RPC 메서드. 이 중 하나. |
| `arguments` | JSON 텍스트로 된 인수. |

### 검사 [#assertions]

| 키 | 의미 |
| --- | --- |
| `target` | 검사 대상: `status`, `header`, `json`, `body`, `time`(밀리초), `size`(바이트), `schema`(JSON 스키마), `graphql-errors`, `mcp-error`, `mcp-output-schema`, `openapi`, `grpc-status`. |
| `name` | `header`의 경우 헤더의 이름. |
| `path` | `json`의 경우 `$.items.length` 같은 JSONPath. |
| `check` | `equals`, `not-equals`, `contains`, `not-contains`, `less-than`, `at-most`, `greater-than`, `at-least`, `exists`, `not-exists`, `matches`(정규 표현식), `is-type`, `is-one-of`, `matches-schema`. |
| `expected` | 비교할 값. 값이 필요 없는 검사에는 기록하지 않습니다. |
| `enabled` | `false`이면 끕니다. |

대상마다 어떤 검사를 제공하는지는 [스크립트와 테스트](/docs/requests/scripts-and-tests)를 참고하세요.

### 캡처 [#captures]

| 키 | 의미 |
| --- | --- |
| `variable` | 값을 저장할 변수. |
| `from` | `json`, `form`, `msgpack`, `xml`, `header`, `cookie`, `status`, `body`. |
| `path` | 값이 있는 위치: JSONPath, XPath, 헤더 또는 쿠키 이름. `status`와 `body`에는 쓰지 않습니다. |
| `scope` | `environment`(기본값: 활성 환경) 또는 `workspace`. |
| `secret` | `true`이면 값을 비밀 값으로 키체인에 저장합니다. |
| `enabled` | `false`이면 끕니다. |

응답이 400 이상이거나 값이 없으면 변수는 그대로 유지됩니다. [캡처](/docs/requests/captures)를 참고하세요.

### 설정 [#settings]

| 키 | 의미 |
| --- | --- |
| `timeout` | 교환 전체의 제한 시간(초). |
| `raw` | `true`이면 자동 헤더를 보내지 않습니다. |
| `verify-tls` | `false`이면 인증서 확인을 건너뜁니다. |
| `follow-redirects` | `false`이면 리디렉션에서 멈춥니다. |
| `max-redirects` | 따라갈 리디렉션의 최대 횟수. |
| `decompress` | `false`이면 본문을 서버가 인코딩한 그대로 둡니다. |
| `cookies` | `false`이면 쿠키를 보내지도 저장하지도 않습니다. |
| `http-version` | `automatic`, `http1`, `http2`, `http3`. |
| `stream-limit` | 이벤트 스트림이나 세션을 수신하는 시간(초). |

[요청 설정](/docs/requests/settings)을 참고하세요.

### 인증 [#auth]

`[auth]`에는 `type`과 그 타입의 키가 있습니다. `[auth]`가 없는 요청이나 폴더는 상속하며, 작업 공간의 기본값은 인증 없음입니다.

| `type` | 키 |
| --- | --- |
| `inherit` | 없음: 폴더의 인증을 사용. |
| `none` | 없음: 폴더에 인증이 있어도 인증 없음. |
| `basic`, `digest` | `username`, `password` |
| `bearer` | `token`. `Bearer`가 아니면 `prefix` |
| `api-key` | `name`, `value`, `in`(`header` 또는 `query`) |
| `oauth2` | `grant`(`authorization-code`, `client-credentials`, `device-code`), `authorization-url`, `token-url`, `device-authorization-url`, `client-id`, `client-secret`, `scope`, `audience`, `redirect-uri`. PKCE를 끄려면 `pkce = false`. 클라이언트 자격 증명을 Basic 대신 본문으로 보내려면 `client-authentication = "body"`. `Bearer`가 아니면 `header-prefix` |
| `aws-signature` | `access-key-id`, `secret-access-key`, `session-token`, `region`, `service` |
| `jwt` | `algorithm`(`HS256`, `HS384`, `HS512`, `RS256`, `RS384`, `RS512`, `PS256`, `PS384`, `PS512`, `ES256`, `ES384`), `secret`, `secret-base64`, `payload`, `header`, `iat`를 빼려면 `issued-at = false`, `expires-in`(초, 기본값 300), `in`(`header` 또는 `query`), `prefix`, `query-name`(기본값 `token`) |
| `hawk` | `id`, `key`, `algorithm`(`sha256` 또는 `sha1`), `ext`, `payload-hash` |
| `edgegrid` | `client-token`, `client-secret`, `access-token`, `max-body`(기본값 131072), `headers-to-sign` |
| `ntlm` | `username`, `password`, `domain`, `workstation` |

모든 암호, 토큰, 키는 비밀 `{{variable}}`로 작성하세요. [인증](/docs/requests/auth)을 참고하세요.

## mcp-servers/ [#mcp-servers]

MCP 서버마다 파일 하나가 있으며, 파일 이름은 MCP 호출이 지정하는 슬러그입니다.

```toml
echolot = 1
name = "Alpenglow MCP"
transport = "http"
url = "https://demo.echolot.dev/mcp"
```

| 키 | 의미 |
| --- | --- |
| `name` | 서버의 이름. |
| `transport` | `http`(Streamable HTTP) 또는 `stdio`(Echolot이 시작하는 프로그램). |
| `url` | `http`의 경우 엔드포인트. |
| `[[headers]]` | `http`의 경우: `name`, `value`, `enabled`. |
| `command` | `stdio`의 경우 시작할 프로그램. |
| `arguments` | `stdio`의 경우 프로그램의 인수(배열). |
| `working-directory` | `stdio`의 경우 프로그램을 시작할 폴더. |
| `[[environment]]` | `stdio`의 경우 환경 변수: `name`, `value`, `enabled`. |
| `[oauth]` | OAuth로 로그인하는 서버의 클라이언트 설정: `client-id`, `client-secret`, `scope`, `redirect-uri`. |

[서버 추가](/docs/mcp-servers/adding-servers)를 참고하세요.

## specs/ [#specs]

명세 파일은 있는 그대로 둡니다. OpenAPI 문서(`.yaml`, `.yml`, `.json`), GraphQL 스키마(`.graphql` SDL, 또는 JSON으로 된 인트로스펙션 결과),
protobuf 파일(`.proto`). Echolot은 서식을 유지한 채 그 자리에서 편집합니다. 요청과 모의 서버는 `specs/alpenglow.yaml`처럼 경로로 이 파일을
가리킵니다. [명세](/docs/specs)를 참고하세요.

## mocks/ [#mocks]

모의 서버마다 파일 하나가 있으며, 그 옆에 JavaScript 경로가 있습니다.

```toml
echolot = 1
name = "Shop"
spec = "specs/alpenglow.yaml"
port = 4010
delay = 200

[[scenarios]]
operation = "GET /products/{sku}"
status = "404"

[[routes]]
id = "e5f6a7b8"
method = "GET"
path = "/users/{id}"
summary = "One user"

[[routes.responses]]
name = "OK"
status = 200
content-type = "application/json"
headers = [{ name = "X-Request-Id", value = "{{$randomUUID}}" }]
body = """
{
  "id": "{{request.params.id}}",
  "name": "{{$randomFullName}}"
}"""

[[routes.responses]]
name = "Not found"
status = 404
content-type = "application/json"
rules = [{ source = "path", name = "id", value = "0" }]
body = """{ "error": "no user {{request.params.id}}" }"""
```

| 키 | 의미 |
| --- | --- |
| `name` | 모의 서버의 이름. |
| `spec` | 제공하는 명세. 없으면 모의 서버의 경로만 응답합니다. |
| `port` | 포트. 기본값 4010. |
| `share-on-network` | `true`이면 이 Mac뿐 아니라 모든 네트워크 인터페이스에서 응답합니다. |
| `delay` | 응답하기 전의 밀리초. |
| `failure-rate` | 일부러 500으로 응답하는 요청의 비율(퍼센트, 0~100). |
| `validate-requests` | `false`이면 명세를 위반하는 요청에도 응답합니다. 기본값 `true`. |
| `[[scenarios]]` | 명세의 작업에 대해 고른 응답: `operation`(예: `GET /pets`), `status`, `example`(예제의 이름). |
| `[[routes]]` | 직접 만든 경로: `id`(경로가 바뀌어도 그대로 유지됨), `method`(또는 `ANY`), `path`(매개변수는 `{id}`), `summary`, 꺼진 경로에는 `enabled = false`, `response`(기본 응답의 이름. 생략하면 첫 번째), `request-content-type`과 `request-body`(이 경로에서 만든 요청이 보내는 것). |
| `[[routes.responses]]` | 위 경로의 응답 하나: `name`, `status`, `content-type`, `headers`(`name`과 `value`), `rules`(`source`는 `path`, `query`, `header`, `body`. `name`. `value`는 아무 값이나 `*`, 없음은 빈 값), `body`. |

`mocks/<slug>.js`에는 모의 서버의 JavaScript 경로가 있으며, 직접 만든 경로와 명세보다 먼저 응답합니다. 명세의 작업에 대한 응답은 모의 서버에
저장되지 않고, 예제는 명세에 들어갑니다. [모의 서버](/docs/mocks), [경로와 가짜 데이터](/docs/mocks/routes),
[스크립트 경로](/docs/mocks/scripted-routes)를 참고하세요.

## flows/ [#flows]

플로마다 파일 하나, `<slug>.flow.toml`이 있습니다. Echolot은 블록, 연결, 메모를 고정된 순서로 기록하므로 블록을 옮기면 두 줄이 바뀝니다.

```toml
echolot = 1
name = "Place a test order"
description = "Places an order, then asks a person whether to keep it."

[mcp]
tool = "place_test_order"
description = "Places a test order on the demo shop, asking a person before keeping it."

[[blocks]]
id = "signin"
kind = "request"
title = "Sign in"
position = [330, 250]

[blocks.settings]
request = "auth/sign-in"

[[wires]]
from = "start.run"
to = "signin.run"
```

| 키 | 의미 |
| --- | --- |
| `name`, `description` | 플로의 이름과 하는 일. |
| `[mcp]` | 플로를 에이전트에 도구로 제공합니다: `tool`(이름)과 `description`. |
| `[schedule]` | 일정에 따라 실행합니다: `every-minutes` 또는 `cron`(예: `"0 6 * * *"`). |
| `[webhook]` | 요청이 도착하면 실행합니다: `method`(기본값 `POST`)와 `path`. |
| `[[inputs]]` | 플로의 입력: `name`, `type`(`any`, `text`, `number`, `bool`, `object`, `list`, `secret`), `description`, `default`, `required`. |
| `[[blocks]]` | 플로의 블록: `id`, `kind`, `title`, `position`(캔버스의 `[x, y]`), `paused`, `color`, 그리고 종류별 설정이 있는 `[blocks.settings]`. |
| `[[wires]]` | 연결: `from`과 `to`, 각각 `block.port`. |
| `[[groups]]` | 블록의 그룹: `title`, `blocks`(블록의 ID), `color`. |
| `[[notes]]` | 캔버스의 메모: `text`, `frame`(`[x, y, width, height]`). |

블록의 종류와 설정은 [블록](/docs/flows/blocks)에 있습니다.

## assistant/ [#assistant]

작업 공간에서 공유하는 [어시스턴트](/docs/ai/assistant)와의 대화입니다. 어떤 편집기에서든 읽을 수 있는 `<slug>.md`와, Echolot이 다시 열 수 있는
`<slug>.json`이 있습니다.

## 그 밖의 파일 [#other-files]

Echolot이 모르는 파일은 그대로 두므로 README, `.gitignore`, 데이터 파일을 작업 공간에 둘 수 있습니다. 에이전트나 플로가 저장하는 데이터
(`exports/products.csv` 등)는 요청받은 위치, 즉 작업 공간 안에 저장됩니다.
