@newsails/veil-cli 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/.veil/agents/analyst/AGENT.md +21 -0
  2. package/.veil/agents/analyst/agent.json +23 -0
  3. package/.veil/agents/assistant/AGENT.md +15 -0
  4. package/.veil/agents/assistant/agent.json +19 -0
  5. package/.veil/agents/coder/AGENT.md +18 -0
  6. package/.veil/agents/coder/agent.json +19 -0
  7. package/.veil/agents/hello/AGENT.md +5 -0
  8. package/.veil/agents/hello/agent.json +13 -0
  9. package/.veil/agents/writer/AGENT.md +12 -0
  10. package/.veil/agents/writer/agent.json +17 -0
  11. package/.veil/memory/MEMORY.md +343 -0
  12. package/.veil/memory/agents/analyst/MEMORY.md +55 -0
  13. package/.veil/memory/agents/hello/MEMORY.md +12 -0
  14. package/.veil/runtime.pid +1 -0
  15. package/.veil/settings.json +10 -0
  16. package/.veil-studio/studio.db +0 -0
  17. package/.veil-studio/studio.db-shm +0 -0
  18. package/.veil-studio/studio.db-wal +0 -0
  19. package/PLAN/01-vision.md +26 -0
  20. package/PLAN/02-tech-stack.md +94 -0
  21. package/PLAN/03-agents.md +232 -0
  22. package/PLAN/04-runtime.md +171 -0
  23. package/PLAN/05-tools.md +211 -0
  24. package/PLAN/06-communication.md +243 -0
  25. package/PLAN/07-storage.md +218 -0
  26. package/PLAN/08-api-cli.md +153 -0
  27. package/PLAN/09-permissions.md +108 -0
  28. package/PLAN/10-ably.md +105 -0
  29. package/PLAN/11-file-formats.md +442 -0
  30. package/PLAN/12-folder-structure.md +205 -0
  31. package/PLAN/13-operations.md +212 -0
  32. package/PLAN/README.md +23 -0
  33. package/README.md +128 -0
  34. package/REPORT.md +174 -0
  35. package/TODO.md +45 -0
  36. package/ai-tests/FRONTEND_PROMPT.md +220 -0
  37. package/ai-tests/Research & Planning.md +814 -0
  38. package/ai-tests/prompt-001-basic-api.md +230 -0
  39. package/ai-tests/prompt-002-basic-flows.md +230 -0
  40. package/ai-tests/prompt-003-agent-behaviors.md +220 -0
  41. package/api/middleware.js +60 -0
  42. package/api/routes/agents.js +193 -0
  43. package/api/routes/chat.js +93 -0
  44. package/api/routes/completions.js +122 -0
  45. package/api/routes/daemons.js +80 -0
  46. package/api/routes/memory.js +169 -0
  47. package/api/routes/models.js +40 -0
  48. package/api/routes/remote-methods.js +74 -0
  49. package/api/routes/sessions.js +208 -0
  50. package/api/routes/settings.js +108 -0
  51. package/api/routes/system.js +50 -0
  52. package/api/routes/tasks.js +270 -0
  53. package/api/server.js +120 -0
  54. package/cli/formatter.js +70 -0
  55. package/cli/index.js +443 -0
  56. package/cli/parser.js +113 -0
  57. package/config/config.json +10 -0
  58. package/config/models.json +6826 -0
  59. package/core/agent.js +329 -0
  60. package/core/cancel.js +38 -0
  61. package/core/compaction.js +176 -0
  62. package/core/events.js +13 -0
  63. package/core/loop.js +564 -0
  64. package/core/memory.js +51 -0
  65. package/core/prompt.js +185 -0
  66. package/core/queue.js +96 -0
  67. package/core/registry.js +291 -0
  68. package/core/remote-methods.js +124 -0
  69. package/core/router.js +386 -0
  70. package/core/running-sessions.js +18 -0
  71. package/docs/api/01-system.md +84 -0
  72. package/docs/api/02-agents.md +374 -0
  73. package/docs/api/03-chat.md +269 -0
  74. package/docs/api/04-tasks.md +470 -0
  75. package/docs/api/05-sessions.md +444 -0
  76. package/docs/api/06-daemons.md +142 -0
  77. package/docs/api/07-memory.md +186 -0
  78. package/docs/api/08-settings.md +133 -0
  79. package/docs/api/09-models.md +119 -0
  80. package/docs/api/09-websocket.md +350 -0
  81. package/docs/api/10-completions.md +134 -0
  82. package/docs/api/README.md +116 -0
  83. package/docs/guide/01-quickstart.md +220 -0
  84. package/docs/guide/02-folder-structure.md +185 -0
  85. package/docs/guide/03-configuration.md +252 -0
  86. package/docs/guide/04-agents.md +267 -0
  87. package/docs/guide/05-cli.md +290 -0
  88. package/docs/guide/06-tools.md +643 -0
  89. package/docs/guide/07-permissions.md +236 -0
  90. package/docs/guide/08-memory.md +139 -0
  91. package/docs/guide/09-multi-agent.md +271 -0
  92. package/docs/guide/10-daemons.md +226 -0
  93. package/docs/guide/README.md +53 -0
  94. package/docs/index.html +623 -0
  95. package/examples/README.md +151 -0
  96. package/examples/agents/assistant/AGENT.md +31 -0
  97. package/examples/agents/assistant/SOUL.md +9 -0
  98. package/examples/agents/assistant/agent.json +74 -0
  99. package/examples/agents/hello/AGENT.md +15 -0
  100. package/examples/agents/hello/agent.json +14 -0
  101. package/examples/agents/monitor/AGENT.md +51 -0
  102. package/examples/agents/monitor/agent.json +33 -0
  103. package/examples/agents/monitor/heartbeats/monitor.md +24 -0
  104. package/examples/agents/orchestrator/AGENT.md +70 -0
  105. package/examples/agents/orchestrator/agent.json +30 -0
  106. package/examples/agents/researcher/AGENT.md +52 -0
  107. package/examples/agents/researcher/agent.json +49 -0
  108. package/examples/agents/researcher/skills/web-research.md +28 -0
  109. package/examples/skills/code-review.md +72 -0
  110. package/examples/skills/summarise.md +59 -0
  111. package/examples/skills/web-research.md +42 -0
  112. package/examples/tools/word-count/index.js +27 -0
  113. package/examples/tools/word-count/tool.json +18 -0
  114. package/infrastructure/database.js +563 -0
  115. package/infrastructure/scheduler.js +122 -0
  116. package/llm/client.js +206 -0
  117. package/migrations/001-initial.sql +121 -0
  118. package/migrations/002-debuggability.sql +13 -0
  119. package/migrations/003-drop-orphaned-columns.sql +72 -0
  120. package/migrations/004-session-message-token-fields.sql +78 -0
  121. package/migrations/005-session-thinking.sql +5 -0
  122. package/package.json +30 -0
  123. package/schemas/agent.json +143 -0
  124. package/schemas/settings.json +111 -0
  125. package/scripts/fetch-models.js +93 -0
  126. package/session-debug-scenario.md +248 -0
  127. package/settings/fields.js +52 -0
  128. package/system-prompts/base-core.md +7 -0
  129. package/system-prompts/environment.md +13 -0
  130. package/system-prompts/reminders/anti-drift.md +6 -0
  131. package/system-prompts/reminders/stall-recovery.md +10 -0
  132. package/system-prompts/safety-rules.md +25 -0
  133. package/system-prompts/task-heuristics.md +27 -0
  134. package/test/client.js +71 -0
  135. package/test/integration/01-health.test.js +25 -0
  136. package/test/integration/02-agents.test.js +80 -0
  137. package/test/integration/03-chat-hello.test.js +48 -0
  138. package/test/integration/04-chat-multiturn.test.js +61 -0
  139. package/test/integration/05-chat-writer.test.js +48 -0
  140. package/test/integration/06-task-basic.test.js +68 -0
  141. package/test/integration/07-task-tools.test.js +74 -0
  142. package/test/integration/08-task-code-analysis.test.js +69 -0
  143. package/test/integration/09-memory-analyst.test.js +63 -0
  144. package/test/integration/10-task-advanced.test.js +85 -0
  145. package/test/integration/11-sessions-advanced.test.js +84 -0
  146. package/test/integration/12-assistant-chat-tools.test.js +75 -0
  147. package/test/integration/13-edge-cases.test.js +99 -0
  148. package/test/integration/14-cancel.test.js +62 -0
  149. package/test/integration/15-debug.test.js +106 -0
  150. package/test/integration/16-memory-api.test.js +83 -0
  151. package/test/integration/17-settings-api.test.js +41 -0
  152. package/test/integration/18-tool-search-activation.test.js +119 -0
  153. package/test/results/.gitkeep +0 -0
  154. package/test/runner.js +206 -0
  155. package/test/smoke.js +216 -0
  156. package/tools/agent_message.js +85 -0
  157. package/tools/agent_send.js +80 -0
  158. package/tools/agent_spawn.js +44 -0
  159. package/tools/bash.js +49 -0
  160. package/tools/edit_file.js +41 -0
  161. package/tools/glob.js +64 -0
  162. package/tools/grep.js +82 -0
  163. package/tools/list_dir.js +63 -0
  164. package/tools/log_write.js +31 -0
  165. package/tools/memory_read.js +38 -0
  166. package/tools/memory_search.js +65 -0
  167. package/tools/memory_write.js +42 -0
  168. package/tools/read_file.js +48 -0
  169. package/tools/sleep.js +22 -0
  170. package/tools/task_create.js +41 -0
  171. package/tools/task_respond.js +37 -0
  172. package/tools/task_spawn.js +64 -0
  173. package/tools/task_status.js +39 -0
  174. package/tools/task_subscribe.js +37 -0
  175. package/tools/todo_read.js +26 -0
  176. package/tools/todo_write.js +38 -0
  177. package/tools/tool_activate.js +24 -0
  178. package/tools/tool_search.js +24 -0
  179. package/tools/web_fetch.js +50 -0
  180. package/tools/web_search.js +52 -0
  181. package/tools/write_file.js +28 -0
  182. package/ui/api.js +190 -0
  183. package/ui/app.js +281 -0
  184. package/ui/index.html +382 -0
  185. package/ui/views/agents.js +377 -0
  186. package/ui/views/chat.js +610 -0
  187. package/ui/views/connection.js +96 -0
  188. package/ui/views/daemons.js +129 -0
  189. package/ui/views/feed.js +194 -0
  190. package/ui/views/memory.js +263 -0
  191. package/ui/views/models.js +146 -0
  192. package/ui/views/sessions.js +314 -0
  193. package/ui/views/settings.js +142 -0
  194. package/ui/views/tasks.js +415 -0
  195. package/utils/context.js +49 -0
  196. package/utils/id.js +16 -0
  197. package/utils/models.js +88 -0
  198. package/utils/paths.js +213 -0
  199. package/utils/settings.js +172 -0
@@ -0,0 +1,153 @@
1
+ # 08 — API & CLI
2
+
3
+ ## REST API
4
+
5
+ **Base URL:** `http://localhost:5050` (configurable)
6
+ **Auth:** Optional `X-Veil-Secret` header
7
+ **Format:** JSON request/response. No streaming. No WebSocket. Chat requests block until the agent responds (HTTP long-poll). Clients should set appropriate timeouts.
8
+ **Pagination:** Cursor-based for list endpoints (`?cursor=<id>&limit=20`)
9
+ **Errors:** Standard format: `{ "error": { "code": "ERROR_CODE", "message": "..." } }`
10
+
11
+ > **CWD in routes:** Routes never call `process.cwd()`. The project working directory is passed from the CLI at startup and stored in `src/utils/context.js`. Routes call `context.getCwd()` to get the correct project directory. This prevents routes from silently scanning the wrong folder when the server is started from a different directory.
12
+
13
+ ### Endpoints
14
+
15
+ #### Agents
16
+ | Method | Path | Description |
17
+ |--------|------|-------------|
18
+ | GET | `/agents` | List all discovered agents |
19
+ | GET | `/agents/:name` | Get agent details (config, modes, skills, tools) |
20
+
21
+ #### Chat Mode
22
+ | Method | Path | Description |
23
+ |--------|------|-------------|
24
+ | POST | `/agents/:name/chat` | Send message (creates session or resumes) |
25
+
26
+ **Request:**
27
+ ```json
28
+ {
29
+ "message": "Hello, agent!",
30
+ "sessionId": "sess_abc123",
31
+ "files": [{ "path": "./src/auth.js" }]
32
+ }
33
+ ```
34
+ **Response:**
35
+ ```json
36
+ {
37
+ "sessionId": "sess_abc123",
38
+ "message": { "role": "assistant", "content": "..." },
39
+ "tokenUsage": { "input": 1500, "output": 300, "cache": 0 }
40
+ }
41
+ ```
42
+
43
+ #### Task Mode
44
+ | Method | Path | Description |
45
+ |--------|------|-------------|
46
+ | POST | `/agents/:name/task` | Create a new task |
47
+ | GET | `/tasks` | List tasks (filter: agent, status, priority, tags) |
48
+ | GET | `/tasks/:id` | Get task details |
49
+ | GET | `/tasks/:id/events` | Get task progress events |
50
+ | POST | `/tasks/:id/respond` | Respond to a waiting task |
51
+ | POST | `/tasks/:id/cancel` | Cancel a task |
52
+
53
+ **Create task request:**
54
+ ```json
55
+ {
56
+ "input": "Research the best auth libraries for Node.js",
57
+ "priority": "high",
58
+ "tags": ["research", "auth"],
59
+ "files": [{ "path": "./requirements.md" }],
60
+ "maxIterations": 30,
61
+ "maxDurationSeconds": 600
62
+ }
63
+ ```
64
+ **Create task response:**
65
+ ```json
66
+ {
67
+ "taskId": "task_xyz789",
68
+ "status": "pending"
69
+ }
70
+ ```
71
+
72
+ #### Daemon Mode
73
+ | Method | Path | Description |
74
+ |--------|------|-------------|
75
+ | GET | `/daemons` | List active daemons (status, next tick, last result). State is in-memory, rebuilt from agent.json on restart. |
76
+ | POST | `/agents/:name/daemon/trigger` | Trigger a daemon tick manually |
77
+ | POST | `/agents/:name/daemon/start` | Start a daemon |
78
+ | POST | `/agents/:name/daemon/stop` | Stop a daemon |
79
+
80
+ #### Sessions
81
+ | Method | Path | Description |
82
+ |--------|------|-------------|
83
+ | GET | `/sessions` | List sessions (filter: agent, mode, status) |
84
+ | GET | `/sessions/:id` | Get session details |
85
+ | GET | `/sessions/:id/messages` | Get messages (paginated) |
86
+ | DELETE | `/sessions/:id` | Close/delete session |
87
+
88
+ #### System
89
+ | Method | Path | Description |
90
+ |--------|------|-------------|
91
+ | GET | `/health` | Health check |
92
+ | GET | `/status` | System status (uptime, agents, sessions, tasks, daemons) |
93
+ | POST | `/shutdown` | Graceful shutdown |
94
+
95
+ ### Error Codes
96
+
97
+ | Code | HTTP Status | Description |
98
+ |------|-------------|-------------|
99
+ | `AGENT_NOT_FOUND` | 404 | Agent doesn't exist |
100
+ | `MODE_NOT_SUPPORTED` | 400 | Agent doesn't support requested mode |
101
+ | `TASK_NOT_FOUND` | 404 | Task doesn't exist |
102
+ | `SESSION_NOT_FOUND` | 404 | Session doesn't exist |
103
+ | `SESSION_CLOSED` | 400 | Session is closed |
104
+ | `TASK_NOT_WAITING` | 400 | Task is not in waiting status |
105
+ | `PERMISSION_DENIED` | 403 | Invalid or missing secret |
106
+ | `VALIDATION_ERROR` | 400 | Invalid request body |
107
+ | `INTERNAL_ERROR` | 500 | Unexpected error |
108
+
109
+ ---
110
+
111
+ ## CLI
112
+
113
+ ### Server Mode
114
+ ```
115
+ veil start [--port <n>] [--folder <path>] [--secret <s>] [--ably]
116
+ ```
117
+ - Loads all agent definitions, auto-starts daemons, exposes REST API
118
+ - Writes PID file to `.veil/runtime.pid`
119
+ - Sets `context.setCwd(cwd)` at startup — used by all routes and agents internally
120
+
121
+ > **Settings location:** Project settings must be in `.veil/settings.json`, NOT `./settings.json` at the project root. The root-level `settings.json` is never read. This is a common mistake when setting up a new project.
122
+
123
+ ### One-Shot Mode
124
+ ```
125
+ veil run --agent <name> --input "..." [--input-file <path>] [--output-file <path>] [--timeout <s>]
126
+ ```
127
+ - Creates a task, runs to completion, exits
128
+ - Progress to stdout: `VEIL_PROGRESS={"type":"tool.end","name":"grep","duration":120}`
129
+ - Exit 0 on success (result JSON to stdout), exit 1 on failure (error JSON to stderr)
130
+ - Multiple one-shot instances can run in parallel (shared SQLite via WAL)
131
+
132
+ ### Management Commands
133
+ ```
134
+ veil stop # Graceful shutdown
135
+ veil status # Show running server info
136
+ veil agents list # List all discovered agents
137
+ veil agents inspect <name> # Show agent details
138
+ veil agents create # Interactive agent creation wizard
139
+ ```
140
+
141
+ ### Import
142
+ ```
143
+ veil import --type=claude-code|openclaw|raw --source <path>
144
+ ```
145
+ - Transforms source format to VeilCLI format
146
+ - Interactive: asks follow-up questions to configure agent modes
147
+ - Extensible adapter system
148
+
149
+ ### Login
150
+ ```
151
+ veil login --key <token> [--global]
152
+ ```
153
+ - Default: stores in project `.veil/auth.json`. With `--global`: stores in `~/.veil/auth.json`.
@@ -0,0 +1,108 @@
1
+ # 09 — Permissions & Hooks
2
+
3
+ ## Permission System
4
+
5
+ Adopted from Claude Code. Evaluated in order: **deny → ask → allow**.
6
+
7
+ ### Permission Format
8
+ ```
9
+ tool_name(pattern)
10
+
11
+ Examples:
12
+ bash(npm run *) ← bash commands starting with "npm run"
13
+ read_file(**) ← read any file recursively
14
+ write_file(./src/**) ← write anywhere in src/
15
+ edit_file(./src/**) ← edit anywhere in src/
16
+ web_fetch(https://api.*) ← fetch from api.* domains
17
+ ```
18
+
19
+ **Tool names are snake_case** — must match exactly. All built-in tools use snake_case (`bash`, `read_file`, `write_file`, `web_fetch`, etc.).
20
+
21
+ ### MCP Tool Permissions
22
+
23
+ MCP tools use the format `mcp:<server>.<tool>`:
24
+ ```
25
+ mcp:filesystem.read_file(**) ← MCP filesystem server's read_file
26
+ mcp:database.query(SELECT *) ← MCP database server's query tool
27
+ mcp:*.*(**) ← all MCP tools (wildcard)
28
+ ```
29
+
30
+ ### Defaults
31
+ - **Always denied:** `read_file(./.veil/auth.json)`, `read_file(~/.veil/auth.json)`
32
+ - **Interactive mode (chat):** default `ask` — agent requests permission, user approves
33
+ - **Non-interactive mode (task, daemon, subagent, one-shot):** default `deny` — must be explicitly allowed
34
+
35
+ ### Configuration Layers
36
+
37
+ Permissions resolved in order (last wins):
38
+ ```
39
+ 1. Built-in defaults (auth.json always denied)
40
+ 2. ~/.veil/settings.json → permissions
41
+ 3. ./.veil/settings.json → permissions
42
+ 4. ./.veil/settings.local.json → permissions
43
+ 5. agent.json → modes.<mode>.permissions ← per-agent, per-mode overrides
44
+ ```
45
+
46
+ ### Interaction with `disallowedTools`
47
+
48
+ The permission system and `disallowedTools` in agent.json are complementary:
49
+ - **`disallowedTools`** — removes the tool entirely from the agent's toolset (LLM never sees it)
50
+ - **Permissions** — controls whether a visible tool can actually execute (deny/ask/allow)
51
+
52
+ Resolution order: `disallowedTools` checked first (tool removed) → then permissions checked (tool allowed/denied).
53
+
54
+ Per-agent, per-mode permissions in agent.json support `allow` and `deny` only. The `ask` level is only available in settings.json because it requires interactive user approval, which is a global behavior — not agent-specific.
55
+
56
+ Example:
57
+ ```json
58
+ {
59
+ "modes": {
60
+ "task": {
61
+ "permissions": {
62
+ "allow": ["bash(npm run *)", "read_file(**)", "write_file(./src/**)"],
63
+ "deny": ["bash(rm *)"]
64
+ }
65
+ }
66
+ }
67
+ }
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Hooks
73
+
74
+ Two hooks only: **PreToolUse** and **PostToolUse**. Shell commands defined in settings.json.
75
+
76
+ ### Configuration
77
+ ```json
78
+ {
79
+ "hooks": {
80
+ "PreToolUse": "node .veil/hooks/pre-tool.js",
81
+ "PostToolUse": "node .veil/hooks/post-tool.js"
82
+ }
83
+ }
84
+ ```
85
+
86
+ ### Environment Variables
87
+ Hooks receive context via environment variables:
88
+
89
+ | Variable | Description |
90
+ |----------|-------------|
91
+ | `VEIL_TOOL_NAME` | Tool being called (e.g., `bash`, `write_file`) |
92
+ | `VEIL_TOOL_INPUT` | JSON-encoded tool input |
93
+ | `VEIL_TOOL_OUTPUT` | JSON-encoded tool output (PostToolUse only) |
94
+ | `VEIL_AGENT_NAME` | Agent calling the tool |
95
+ | `VEIL_SESSION_ID` | Current session ID |
96
+ | `VEIL_TASK_ID` | Current task ID (if in task mode) |
97
+ | `VEIL_MODE` | Current mode: chat/task/daemon/subagent |
98
+ | `VEIL_AGENT_FOLDER` | Absolute path to agent's folder |
99
+
100
+ ### Behavior
101
+ - **PreToolUse:** Exit 0 → allow tool execution. Exit 1 → block (tool returns error to LLM).
102
+ - **PostToolUse:** Exit 0 → continue. Exit 1 → log warning (tool already executed).
103
+ - **Timeout:** 10s default. Hook killed on timeout, tool proceeds.
104
+
105
+ ### Use Cases
106
+ - `PreToolUse` where `VEIL_TOOL_NAME=bash` → validate bash commands before execution
107
+ - `PostToolUse` where `VEIL_TOOL_NAME=write_file` → trigger lint/format after file write
108
+ - `PreToolUse` → log all tool calls to external audit system
@@ -0,0 +1,105 @@
1
+ # 10 — Ably Remote Access
2
+
3
+ ## Overview
4
+
5
+ When enabled, VeilCLI subscribes to an Ably channel and relays REST API calls over it. This allows remote consumers (web app, mobile app, Veil.com dashboard) to interact with a local VeilCLI instance without port forwarding.
6
+
7
+ ```
8
+ [Remote Client] → [Veil.com] → [Ably Channel] → [VeilCLI (local)]
9
+
10
+ REST API handler
11
+
12
+ [Ably Channel] → [Veil.com] → [Remote Client]
13
+ ```
14
+
15
+ ## Channel Architecture
16
+
17
+ **One channel per VeilCLI instance** (not per agent or session).
18
+
19
+ - Channel name: `veil:instance:<instanceId>`
20
+ - `instanceId` assigned by Veil.com on registration
21
+ - Namespace `veil:` allows applying Ably channel rules globally
22
+
23
+ **Message name routing** on the single channel:
24
+ - `api:request` — remote client → VeilCLI
25
+ - `api:response` — VeilCLI → remote client
26
+ - `task:progress` — VeilCLI pushes task progress events
27
+ - `system:ping` / `system:pong` — health checks
28
+
29
+ ## Message Format (RPC over Pub/Sub)
30
+
31
+ Request/response via **correlation IDs** (`requestId`).
32
+
33
+ **Request:**
34
+ ```json
35
+ {
36
+ "requestId": "req_a1b2c3d4",
37
+ "method": "POST",
38
+ "path": "/agents/researcher/task",
39
+ "headers": { "X-Veil-Secret": "mysecret" },
40
+ "body": { "input": "Research topic X" },
41
+ "timestamp": 1740793200000,
42
+ "timeout": 30000
43
+ }
44
+ ```
45
+
46
+ **Response:**
47
+ ```json
48
+ {
49
+ "requestId": "req_a1b2c3d4",
50
+ "status": 200,
51
+ "body": { "taskId": "task_xyz789", "status": "pending" },
52
+ "timestamp": 1740793201500,
53
+ "duration": 1500
54
+ }
55
+ ```
56
+
57
+ ## Authentication Flow
58
+
59
+ 1. VeilCLI starts with `ably.enabled: true`
60
+ 2. Creates Ably Realtime client with `authCallback`
61
+ 3. `authCallback` calls Veil.com: `POST /api/v1/ably/token` with `veil_token`
62
+ 4. Veil.com validates token, issues scoped Ably TokenRequest (1h TTL)
63
+ 5. Ably SDK handles automatic token refresh before expiry
64
+ 6. VeilCLI enters presence on its channel to signal "online"
65
+
66
+ **Remote clients never connect to Ably directly.** Veil.com relays on their behalf.
67
+
68
+ ## Reliability
69
+
70
+ | Offline Duration | Ably State | Behavior |
71
+ |-----------------|------------|----------|
72
+ | 0–2 min | `disconnected` | Auto-reconnect. Missed messages replayed. |
73
+ | >2 min | `suspended` | Messages during gap are lost. Re-enter presence on reconnect. |
74
+ | Extended | `failed` | Auth token expired. Log error, await manual reconnect. |
75
+
76
+ **Stale request handling:** Requests with `timestamp` older than `timeout` are skipped — remote client already timed out.
77
+
78
+ ## Limits
79
+
80
+ - **Message size:** 64 KiB. Responses >60 KiB truncated with `{ "truncated": true, "fetchUrl": "/messages/msg_xyz/full" }`.
81
+ - **Rate:** 50 msg/s per channel (sufficient for VeilCLI's use case).
82
+ - **Latency overhead:** ~100-300ms round-trip. Negligible vs LLM call time.
83
+
84
+ ## Security
85
+
86
+ Even though VeilCLI trusts Veil.com:
87
+ - Validate incoming message schema (required fields, method whitelist)
88
+ - Local `X-Veil-Secret` still required in relayed requests
89
+ - Track recent `requestId`s to reject duplicates
90
+ - Permission system still applies to all tool calls via Ably
91
+ - Optional: AES-256-CBC per-channel encryption for high-security deployments
92
+
93
+ ## Settings
94
+
95
+ ```json
96
+ {
97
+ "ably": {
98
+ "enabled": false,
99
+ "instanceId": "",
100
+ "tokenEndpoint": "https://veil.com/api/v1/ably/token",
101
+ "requestTimeout": 30000,
102
+ "maxRequestAge": 60000
103
+ }
104
+ }
105
+ ```