llm-cli-gateway 2.11.1 → 2.12.0
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.
- package/.agents/skills/async-job-orchestration/SKILL.md +288 -0
- package/.agents/skills/implement-review-fix/SKILL.md +154 -0
- package/.agents/skills/multi-llm-review/SKILL.md +174 -0
- package/.agents/skills/public-demo-session/SKILL.md +100 -0
- package/.agents/skills/secure-orchestration/SKILL.md +227 -0
- package/.agents/skills/session-workflow/SKILL.md +271 -0
- package/CHANGELOG.md +40 -0
- package/README.md +48 -19
- package/dist/acp/provider-registry.js +5 -5
- package/dist/api-provider.d.ts +7 -0
- package/dist/api-provider.js +7 -0
- package/dist/api-request.js +1 -0
- package/dist/async-job-manager.d.ts +11 -1
- package/dist/async-job-manager.js +44 -3
- package/dist/config.d.ts +2 -0
- package/dist/config.js +3 -0
- package/dist/index.d.ts +38 -2
- package/dist/index.js +609 -156
- package/dist/job-store.d.ts +48 -1
- package/dist/job-store.js +184 -0
- package/dist/provider-codegen.js +3 -0
- package/dist/provider-tool-capabilities.js +7 -7
- package/dist/upstream-contracts.d.ts +1 -0
- package/dist/upstream-contracts.js +128 -21
- package/dist/validation-orchestrator.d.ts +5 -2
- package/dist/validation-orchestrator.js +71 -5
- package/dist/validation-receipt.d.ts +68 -0
- package/dist/validation-receipt.js +245 -0
- package/dist/validation-report.d.ts +4 -2
- package/dist/validation-report.js +18 -1
- package/dist/validation-tools.js +58 -9
- package/npm-shrinkwrap.json +5 -5
- package/package.json +10 -4
- package/dist/xai-api-provider.d.ts +0 -43
- package/dist/xai-api-provider.js +0 -191
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: public-demo-session
|
|
3
|
+
description: Prepare and drive clean public llm-cli-gateway demo sessions for recordings, README demos, screenshots, or transcripts. Use when the user needs a redacted path, compact Codex output, direct provider calls, or a demo-safe Codex environment.
|
|
4
|
+
metadata:
|
|
5
|
+
author: verivus-oss
|
|
6
|
+
version: "1.0"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Public Demo Session
|
|
10
|
+
|
|
11
|
+
Use this skill when the goal is a public recording, README demo, screenshot, or clean transcript. The priority is a short, reliable demo surface, not exhaustive orchestration.
|
|
12
|
+
|
|
13
|
+
## Goals
|
|
14
|
+
|
|
15
|
+
- Show only a public-safe workspace path such as `/llm-cli-gateway`.
|
|
16
|
+
- Keep the llm-cli-gateway MCP server and workspace skills available.
|
|
17
|
+
- Prefer direct, synchronous provider calls that return compact text.
|
|
18
|
+
- Avoid validation wrappers, async polling, nested Codex, and repeated stuck-job polling unless the user explicitly asks for those features.
|
|
19
|
+
|
|
20
|
+
## Path Hygiene
|
|
21
|
+
|
|
22
|
+
Do not start Codex directly from an internal checkout path for public demos. A symlink may still leak a resolved path in some tools. Prefer a bind-mounted public path:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
bwrap \
|
|
26
|
+
--bind "$REAL_REPO" /llm-cli-gateway \
|
|
27
|
+
--chdir /llm-cli-gateway \
|
|
28
|
+
--setenv CODEX_HOME "$DEMO_CODEX_HOME" \
|
|
29
|
+
codex --dangerously-bypass-approvals-and-sandbox
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
If the host needs Codex HTTPS/WebSocket support inside the mount namespace, bind the host CA backing store too. On this host `/etc/ssl/certs` depends on `/var/lib/ca-certificates`.
|
|
33
|
+
|
|
34
|
+
The demo `CODEX_HOME` should have a minimal `config.toml` with:
|
|
35
|
+
|
|
36
|
+
```toml
|
|
37
|
+
model = "gpt-5.5"
|
|
38
|
+
model_reasoning_effort = "high"
|
|
39
|
+
project_doc_max_bytes = 0
|
|
40
|
+
|
|
41
|
+
[projects."/llm-cli-gateway"]
|
|
42
|
+
trust_level = "trusted"
|
|
43
|
+
|
|
44
|
+
[mcp_servers.llm-gateway]
|
|
45
|
+
command = "node"
|
|
46
|
+
args = ["/llm-cli-gateway/dist/index.js"]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Keep the demo home separate from the normal Codex home. Symlink `auth.json` from the normal Codex home if needed, but do not copy private history or sessions.
|
|
50
|
+
|
|
51
|
+
## Demo Dispatch Defaults
|
|
52
|
+
|
|
53
|
+
For simple “ask the other LLMs” demo prompts, use direct provider tools:
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
claude_request({prompt: "...", outputFormat: "text"})
|
|
57
|
+
gemini_request({prompt: "...", outputFormat: "text", skipTrust: true})
|
|
58
|
+
mistral_request({prompt: "...", outputFormat: "text", trust: true})
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Provider-specific notes:
|
|
62
|
+
|
|
63
|
+
- Do not pass `maxTurns` to `claude_request` unless the current schema explicitly supports it.
|
|
64
|
+
- Pass `skipTrust:true` to Gemini when the demo workspace trust prompt would interrupt the recording.
|
|
65
|
+
- Pass `trust:true` to Mistral/Vibe for the same reason.
|
|
66
|
+
- Avoid `grok_request` in demos unless the user explicitly names Grok and the local Grok CLI has been checked in this environment.
|
|
67
|
+
- Avoid `codex_request` from inside a Codex demo unless the user explicitly asks for nested Codex.
|
|
68
|
+
|
|
69
|
+
## Avoid In Demo Mode
|
|
70
|
+
|
|
71
|
+
Do not use these by default for a public demo prompt:
|
|
72
|
+
|
|
73
|
+
- `ask_model`
|
|
74
|
+
- `validate_with_models`
|
|
75
|
+
- `compare_answers`
|
|
76
|
+
- `consensus_check`
|
|
77
|
+
- `second_opinion`
|
|
78
|
+
- `red_team_review`
|
|
79
|
+
- `synthesize_validation`
|
|
80
|
+
- `*_request_async`
|
|
81
|
+
- `llm_job_status`, `llm_job_result`, `llm_job_cancel`
|
|
82
|
+
- web search, unless the user explicitly asks for live verification
|
|
83
|
+
|
|
84
|
+
If a provider fails, state that briefly and continue with useful returned outputs. Do not turn a short demo into a recovery workflow.
|
|
85
|
+
|
|
86
|
+
## Quick Verification
|
|
87
|
+
|
|
88
|
+
Before recording:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
codex doctor --summary --no-color
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Expected: MCP server present, WebSocket connected, provider endpoints reachable, and `0 warn · 0 fail`.
|
|
95
|
+
|
|
96
|
+
Confirm the opening screen shows:
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
directory: /llm-cli-gateway
|
|
100
|
+
```
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: secure-orchestration
|
|
3
|
+
description: Security-conscious LLM orchestration with approval gates across Claude, Codex, Gemini, Grok, and Mistral. Use for high-risk operations, permissions, auditing.
|
|
4
|
+
metadata:
|
|
5
|
+
author: verivus-oss
|
|
6
|
+
version: "1.6"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Secure Orchestration
|
|
10
|
+
|
|
11
|
+
Approval gate scores request risk, enforces policy thresholds. Applies uniformly to Claude, Codex, Gemini, Grok (xAI), and Mistral Vibe dispatches. Use when security matters — production codebases, sensitive data, autonomous operations.
|
|
12
|
+
|
|
13
|
+
> **Mistral Vibe note**: the gateway always emits `--agent <mode>` explicitly and defaults the programmatic mode to `auto-approve`. Set `permissionMode:"plan"` (or `chat`/`explore`) when you want stricter behaviour. Current Vibe defaults session logging on; `doctor --json` surfaces explicit `[session_logging] enabled = false` as a `next_actions` entry.
|
|
14
|
+
|
|
15
|
+
## Dispatch Defaults
|
|
16
|
+
|
|
17
|
+
Apply these on every dispatch unless the caller has explicitly overridden a rule in the current turn:
|
|
18
|
+
|
|
19
|
+
1. **Omit `model`** — let the gateway use its configured default per CLI. Nominating a model risks deprecated IDs (`o3`, `o3-pro`, `gpt-4o`, …) and capability mismatches.
|
|
20
|
+
2. **`approvalStrategy:"mcp_managed"`** is the skill dispatch default (the gateway schema default is `"legacy"`). It runs the scored gateway gate first; Claude then uses `bypassPermissions`, Gemini uses `yolo`, and Codex still needs `fullAuto:true` for autonomous file/shell work. **The `mcp_managed` auto-flip itself is not scored as raw bypass; only caller-supplied raw bypass flags incur the +3 permission-bypass penalty below.** Raw `dangerouslySkipPermissions` / `dangerouslyBypassApprovalsAndSandbox` / caller-set `approvalMode:"yolo"` remain prohibited in production because they bypass the gateway gate entirely.
|
|
21
|
+
3. **No wallclock timeout; poll every 60 s** — good security reviews take minutes to tens of minutes. `idleTimeoutMs` (no-output safeguard) remains a valid security control and is separate from wallclock timeout.
|
|
22
|
+
4. **Iterate until unconditional APPROVED** (review dispatches only) — end every review prompt with "End with APPROVED or NOT APPROVED with findings." Loop: dispatch → parse verdict → on `NOT APPROVED` or conditional approval, dispatch fixes + re-review → repeat until unconditional APPROVED. Escalate after 3 rounds. This rule does **not** apply to pure implementation or non-review analysis dispatches.
|
|
23
|
+
|
|
24
|
+
## Risk Scoring
|
|
25
|
+
|
|
26
|
+
| Factor | Points | Trigger |
|
|
27
|
+
|--------|--------|---------|
|
|
28
|
+
| Permission bypass | +3 | Raw caller-supplied bypass: `dangerouslySkipPermissions:true`, `dangerouslyBypassApprovalsAndSandbox:true`, or caller-set Gemini `approvalMode:"yolo"`. The `approvalStrategy:"mcp_managed"` auto-flip is **not** scored here. |
|
|
29
|
+
| Sensitive keywords | +3 | `delete`, `destroy`, `wipe`, `exfiltrate`, `credential`, `token`, `password`, `secret` |
|
|
30
|
+
| Full auto | +2 | `fullAuto:true` (Codex) |
|
|
31
|
+
| Bypass + full-auto | +2 | Both requested together |
|
|
32
|
+
| Weighted MCP server | varies | Per-server approval weights from the host's MCP registry (e.g. a web-search server) add to the score |
|
|
33
|
+
| Review tool suppression | +4 | Tool-suppression language detected in review context (e.g., "do not run tools") |
|
|
34
|
+
| Empty allowedTools (review) | +6 | `allowedTools:[]` in review context — reviewers need tool access |
|
|
35
|
+
| Critical tools disallowed (review) | +6 | Review context with `Read`, `Grep`, `Glob`, or `Bash` in `disallowedTools` |
|
|
36
|
+
| Ref tools MCP | +1 | Reference tools access |
|
|
37
|
+
| Empty allowedTools (non-review) | +0 | Recorded as "No tool permissions requested"; does not lower score |
|
|
38
|
+
| Explicit disallowedTools (non-critical/non-review) | +0 | Recorded as a restriction; does not lower score |
|
|
39
|
+
|
|
40
|
+
## Policy Thresholds
|
|
41
|
+
|
|
42
|
+
| Policy | Max Score | Use When |
|
|
43
|
+
|--------|-----------|----------|
|
|
44
|
+
| `strict` | 2 | Production, security-sensitive, untrusted prompts |
|
|
45
|
+
| `balanced` | 5 | Normal development, trusted prompts |
|
|
46
|
+
| `permissive` | 7 | Experimentation, sandboxed environments |
|
|
47
|
+
|
|
48
|
+
Score > threshold → **denied**. Default: `balanced` (override: `LLM_GATEWAY_APPROVAL_POLICY` env var).
|
|
49
|
+
|
|
50
|
+
## Enabling Approval Gates
|
|
51
|
+
|
|
52
|
+
### Per-request
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
claude_request({prompt:"Refactor auth module",approvalStrategy:"mcp_managed",approvalPolicy:"strict"})
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Response includes:
|
|
59
|
+
```json
|
|
60
|
+
{"approval":{"id":"appr-...","status":"approved","score":0,"policy":"strict","reasons":[]}}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Denied example
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
codex_request({prompt:"Delete all test fixtures",fullAuto:true,dangerouslyBypassApprovalsAndSandbox:true,approvalStrategy:"mcp_managed",approvalPolicy:"strict"})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Score: bypass(+3) + full-auto(+2) + combo(+2) + "delete"(+3) = **10** > strict threshold 2. Request NOT executed.
|
|
70
|
+
|
|
71
|
+
### Async requests
|
|
72
|
+
|
|
73
|
+
Approval check happens before job spawn:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
gemini_request_async({prompt:"Audit auth module for vulnerabilities. End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",approvalPolicy:"strict"})
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Approved → job starts, get `job.id` to poll (every 60s per dispatch defaults). Denied → no job created, denial returned.
|
|
80
|
+
|
|
81
|
+
### mcp_managed CLI effects
|
|
82
|
+
|
|
83
|
+
When `approvalStrategy:"mcp_managed"`:
|
|
84
|
+
- Claude: `--permission-mode bypassPermissions`
|
|
85
|
+
- Gemini: `--approval-mode yolo`
|
|
86
|
+
- Codex: no automatic bypass flag; use `fullAuto:true` for sandboxed autonomous execution. `dangerouslyBypassApprovalsAndSandbox:true` is still raw bypass. On `codex exec resume` (when `sessionId` or `resumeLatest` is set), `fullAuto` is silently dropped — the original session's approval policy is inherited, so audit the source session's approval posture before resuming.
|
|
87
|
+
- Grok: equivalent permissive flag handled by the Grok provider; raw `alwaysApprove` / `permissionMode` overrides are scored the same way as Claude/Gemini raw bypass.
|
|
88
|
+
|
|
89
|
+
Gateway approval engine becomes the gatekeeper before permissive CLI modes are applied.
|
|
90
|
+
|
|
91
|
+
## Audit Trail
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
approval_list({limit:50})
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
```json
|
|
99
|
+
{"approvals":[{"id":"appr-...","ts":"...","status":"approved","policy":"balanced","cli":"claude","operation":"claude_request","score":0,"reasons":[],"promptPreview":"Refactor the auth...","promptSha256":"a1b2c3...","requestedMcpServers":["example-server"]}]}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Filter: `approval_list({limit:50,cli:"codex"})`
|
|
103
|
+
|
|
104
|
+
Key fields: `promptPreview` (first 280 chars) | `promptSha256` (correlation) | `reasons` (score breakdown) | `bypassRequested` | `fullAuto`
|
|
105
|
+
|
|
106
|
+
## Security Guidelines
|
|
107
|
+
|
|
108
|
+
**Production:** Always strict approval:
|
|
109
|
+
```
|
|
110
|
+
claude_request({prompt:"...",approvalStrategy:"mcp_managed",approvalPolicy:"strict"})
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Development:** Balanced for trusted prompts:
|
|
114
|
+
```
|
|
115
|
+
codex_request({prompt:"...",approvalStrategy:"mcp_managed",approvalPolicy:"balanced",fullAuto:true})
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Never in production (raw CLI bypass flags — bypass the gateway gate entirely):**
|
|
119
|
+
- `dangerouslySkipPermissions:true` (Claude)
|
|
120
|
+
- `dangerouslyBypassApprovalsAndSandbox:true` (Codex)
|
|
121
|
+
- `approvalMode:"yolo"` (Gemini)
|
|
122
|
+
- Raw permissive flags on `grok_request` (e.g., caller-supplied `alwaysApprove` or permissive `permissionMode`)
|
|
123
|
+
|
|
124
|
+
Use `approvalStrategy:"mcp_managed"` instead so the gateway scores and gates the request before permissive CLI modes are applied. For Codex, include `fullAuto:true` when the task needs file or shell access (note: not honored on `codex exec resume` — the resumed session inherits its original approval policy).
|
|
125
|
+
|
|
126
|
+
## Permission Management
|
|
127
|
+
|
|
128
|
+
Before setting provider-specific tool, MCP, sandbox, or session fields, query:
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
provider_tool_capabilities({cli:"claude"})
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Repeat for `codex`, `gemini`, `grok`, or `mistral` as needed. Use the returned
|
|
135
|
+
`controls` and `unsupportedInputs`; do not infer one provider's permission
|
|
136
|
+
surface from another provider's CLI.
|
|
137
|
+
|
|
138
|
+
### Claude MCP servers
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
claude_request({prompt:"...",mcpServers:["<server-name>"],strictMcpConfig:true})
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
- `mcpServers`: the MCP server names to enable for this request (the available set depends on the host's Claude MCP configuration)
|
|
145
|
+
- `strictMcpConfig:true`: fail if a requested server is unavailable
|
|
146
|
+
|
|
147
|
+
For Codex, Grok, and Mistral Vibe, `mcpServers` is approval tracking only; each
|
|
148
|
+
provider owns its MCP configuration. For the current Gemini/Antigravity request
|
|
149
|
+
path, non-empty `mcpServers` is rejected.
|
|
150
|
+
|
|
151
|
+
### Codex sandboxing
|
|
152
|
+
|
|
153
|
+
`fullAuto:true` enables automated changes, stays sandboxed.
|
|
154
|
+
|
|
155
|
+
### Gemini approval modes
|
|
156
|
+
|
|
157
|
+
`approvalMode`: `default` (ask) | `auto_edit` (auto-approve edits) | `yolo` (dev only)
|
|
158
|
+
|
|
159
|
+
### Tool restrictions
|
|
160
|
+
|
|
161
|
+
**Claude** — allowlists + blocklists:
|
|
162
|
+
```
|
|
163
|
+
claude_request({prompt:"...",allowedTools:["Read","Grep","Glob"],disallowedTools:["Bash","Write"]})
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Gemini/Antigravity** — current path rejects non-empty allowlists:
|
|
167
|
+
```
|
|
168
|
+
gemini_request({prompt:"...",approvalStrategy:"mcp_managed"})
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Grok** — provider-native allowlists only:
|
|
172
|
+
```
|
|
173
|
+
grok_request({prompt:"...",approvalStrategy:"mcp_managed"})
|
|
174
|
+
```
|
|
175
|
+
Do not pass Claude tool names such as `Read`, `Grep`, `Glob`, or `Bash` as Grok
|
|
176
|
+
`allowedTools`; query `provider_tool_capabilities({cli:"grok"})` and use
|
|
177
|
+
discovered provider-native tool names only when you intentionally need an
|
|
178
|
+
allowlist.
|
|
179
|
+
|
|
180
|
+
**Mistral Vibe** — enabled-tool allowlist only:
|
|
181
|
+
```
|
|
182
|
+
mistral_request({prompt:"...",allowedTools:["<vibe-enabled-tool>"],approvalStrategy:"mcp_managed"})
|
|
183
|
+
```
|
|
184
|
+
`disallowedTools` is accepted for parity but ignored because Vibe has no
|
|
185
|
+
deny-list flag.
|
|
186
|
+
|
|
187
|
+
## Idle Timeout as Security Control
|
|
188
|
+
|
|
189
|
+
Tight idle timeout limits window for unintended operations:
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
claude_request({prompt:"Audit secrets module",approvalStrategy:"mcp_managed",approvalPolicy:"strict",idleTimeoutMs:120000})
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Kills process after 2min inactivity. Exit code 125 (non-transient, no retry).
|
|
196
|
+
|
|
197
|
+
**Guideline:** 60-120s for security audits. Full 10min default for large analysis only.
|
|
198
|
+
|
|
199
|
+
## Cache Observability for Audit Tracing
|
|
200
|
+
|
|
201
|
+
Three read-only MCP resources expose cache effectiveness from the flight recorder — tokens / hashes / aggregates only, **no prompt or response text**:
|
|
202
|
+
|
|
203
|
+
- `cache-state://global` — last-24h aggregate hit rate, total hits, estimated savings, per-CLI breakdown
|
|
204
|
+
- `cache-state://session/{sessionId}` — per-session aggregates (also surfaces as `session_get.cacheState` when the session has prior requests)
|
|
205
|
+
- `cache-state://prefix/{hash}` — per-stable-prefix-hash aggregates with CLI × model breakdown
|
|
206
|
+
|
|
207
|
+
The "tokens/hashes only" property is the security guarantee: these resources let an auditor reconstruct "did the model see fresh context or a cached prefix?" without ever exposing prompt or response content. Combine with `approval_list` (which already redacts to a `promptPreview` + `promptSha256`) and `llm_job_status/result` by `correlationId` to reconstruct any past dispatch fully.
|
|
208
|
+
|
|
209
|
+
For Claude sessions, `[cache_awareness] warn_on_ttl_expiry = true` in `~/.llm-cli-gateway/config.toml` adds a structured `cache_ttl_expiring_soon` warning to responses whose prior `lastRequestAt` is within 30 s of Anthropic's TTL — useful as a signal that an audit-relevant turn may have hit a cold cache and is paying full cache-creation tokens.
|
|
210
|
+
|
|
211
|
+
### `promptParts` for prompt-discipline auditing
|
|
212
|
+
|
|
213
|
+
Switching from `prompt` to the structured `promptParts` field (`{ system?, tools?, context?, task }`, mutually exclusive with `prompt`) makes the audit story stronger: the stable prefix hash is stable across calls, so reviewing an audit trail you can see at a glance whether two requests shared a system/tools/context block or genuinely differed. Identical hashes across reviewers in a parallel dispatch = same brief; differing hashes = drift to investigate.
|
|
214
|
+
|
|
215
|
+
## Tips
|
|
216
|
+
|
|
217
|
+
- Start `strict`, relax only when needed
|
|
218
|
+
- Review audit trail regularly: `approval_list`
|
|
219
|
+
- Use `correlationId` on every request for tracing
|
|
220
|
+
- `approvalStrategy:"mcp_managed"` is the skill default dispatch path — the gateway schema default is `"legacy"`, which skips the gate unless explicitly selected
|
|
221
|
+
- Denied requests return immediately without executing
|
|
222
|
+
- Gates apply equally to sync and async requests
|
|
223
|
+
- `idleTimeoutMs` is a security control (tight 60–120 s for security audits kills silent processes quickly) — this is **not** a wallclock timeout, so it does not conflict with the "no wallclock timeout, poll every 60 s" dispatch default
|
|
224
|
+
- Approval checks run before auto-deferral — denied requests reject instantly
|
|
225
|
+
- Review dispatches loop until unconditional APPROVED — the approval gate is separate from the reviewer's verdict, and both must pass
|
|
226
|
+
- **Durable audit trail**: approvals and job state are persisted (default 30 days, `LLM_GATEWAY_JOB_RETENTION_DAYS`). Combine `approval_list` with `llm_job_status/result` by `correlationId` to reconstruct any past dispatch, even across gateway restarts
|
|
227
|
+
- **Auto-dedup interacts with approvals**: an identical replayed request within the dedup window (`LLM_GATEWAY_DEDUP_WINDOW_MS`, default 1 h) reuses the original job. The **original** approval decision is the one of record; the dedup hit does not re-run the gate. Use `forceRefresh:true` to force a fresh approval evaluation when the security-relevant context (caller, prompt, flags) has actually changed
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: session-workflow
|
|
3
|
+
description: Manage conversation sessions across Claude, Codex, Gemini, Grok, and Mistral. Use for multi-turn conversations, session switching, workspace management. Covers the `session_get.cacheState` projection, cache-aware `promptParts`, and `cache-state://` MCP resources.
|
|
4
|
+
metadata:
|
|
5
|
+
author: verivus-oss
|
|
6
|
+
version: "1.6"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Session Workflow
|
|
10
|
+
|
|
11
|
+
Sessions track conversation context across requests. One active session per CLI.
|
|
12
|
+
|
|
13
|
+
## Dispatch Defaults
|
|
14
|
+
|
|
15
|
+
Apply these on every dispatch unless the caller has explicitly overridden a rule in the current turn:
|
|
16
|
+
|
|
17
|
+
1. **Omit `model`** — let the gateway use its configured default per CLI.
|
|
18
|
+
2. **`approvalStrategy:"mcp_managed"`** is the skill dispatch default (the gateway schema default is `"legacy"`). For Codex, also pass `fullAuto:true` when the task needs file/shell access.
|
|
19
|
+
3. **No wallclock timeout; poll every 60 s** — `idleTimeoutMs` is a separate no-output safeguard.
|
|
20
|
+
4. **Iterate until unconditional APPROVED** (review dispatches only) — every review prompt must end with "End with APPROVED or NOT APPROVED with findings." Loop: dispatch review → poll if deferred → parse verdict → on `NOT APPROVED` or conditional approval, dispatch fixes + re-review → repeat. Escalate after 3 rounds. This rule does **not** apply to pure implementation or non-review analysis dispatches. Sessions make the loop cheap (Claude and Gemini preserve conversation continuity).
|
|
21
|
+
|
|
22
|
+
## Key Concepts
|
|
23
|
+
|
|
24
|
+
- **Active session** — default when no `sessionId` specified
|
|
25
|
+
- **Session ID** — string identifier (UUID or arbitrary)
|
|
26
|
+
- **`gw-*` prefix** — gateway-generated Gemini bookkeeping IDs; rejected if passed back to Gemini as `sessionId`
|
|
27
|
+
- **`resumable`** — Gemini response field: `true`=user-provided ID, `false`=gateway `gw-*` ID
|
|
28
|
+
- **Session TTL** — 30 days inactivity (configurable: `SESSION_TTL` env var, seconds)
|
|
29
|
+
- Stores metadata only (id, cli, timestamps, description) — not conversation content
|
|
30
|
+
|
|
31
|
+
## Session Continuity Per CLI
|
|
32
|
+
|
|
33
|
+
| CLI | Effect | Mechanism |
|
|
34
|
+
|-----|--------|-----------|
|
|
35
|
+
| **Claude** | Real continuity | `--session-id` or `--continue` to CLI |
|
|
36
|
+
| **Codex** | Real continuity | `codex exec resume <UUID>` (`sessionId`) or `codex exec resume --last` (`resumeLatest:true`). `sessionId` must be a real Codex UUID from `~/.codex/sessions/`; gateway-generated `gw-*` IDs are rejected. `--full-auto` silently dropped on resume (approval policy inherits from the original session) |
|
|
37
|
+
| **Gemini** | Real continuity | `--resume` to CLI |
|
|
38
|
+
| **Grok** | Real continuity | `--resume` / `--continue` to CLI |
|
|
39
|
+
| **Mistral** | Real continuity | `--resume` / `--continue` to CLI; current Vibe defaults session logging on, and doctor flags explicit `[session_logging] enabled = false` |
|
|
40
|
+
|
|
41
|
+
All four CLIs now carry true multi-turn continuity. For Codex, you must either pass `resumeLatest:true` or supply a real Codex session UUID — the gateway no longer treats Codex sessions as bookkeeping-only.
|
|
42
|
+
|
|
43
|
+
## Creating Sessions
|
|
44
|
+
|
|
45
|
+
### Explicit
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
session_create({cli:"claude",description:"Refactoring auth module",setAsActive:true})
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Returns: `{success:true,session:{id,cli,description,createdAt,isActive}}`
|
|
52
|
+
|
|
53
|
+
### Via request
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
claude_request({prompt:"...",createNewSession:true,approvalStrategy:"mcp_managed"})
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Implicit active session
|
|
60
|
+
|
|
61
|
+
- **Claude** — auto-continues active session via `--continue`
|
|
62
|
+
- **Codex** — no auto-lookup; pass `resumeLatest:true` (→ `codex exec resume --last`) or `sessionId:<UUID>` (→ `codex exec resume <UUID>`) explicitly
|
|
63
|
+
- **Gemini** — no auto-lookup; use `sessionId` or `resumeLatest:true` explicitly
|
|
64
|
+
- **Grok** — pass `sessionId` (or `resumeLatest:true`) to resume via `--resume`/`--continue`
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
claude_request({prompt:"Continue where we left off",approvalStrategy:"mcp_managed"}) // auto-continues
|
|
68
|
+
codex_request({prompt:"Continue",resumeLatest:true,fullAuto:true,approvalStrategy:"mcp_managed"}) // codex exec resume --last
|
|
69
|
+
gemini_request({prompt:"Continue analysis",resumeLatest:true,approvalStrategy:"mcp_managed"}) // explicit resume
|
|
70
|
+
grok_request({prompt:"Continue",sessionId:"my-grok-session",approvalStrategy:"mcp_managed"}) // explicit resume
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Multi-Turn Patterns
|
|
74
|
+
|
|
75
|
+
### Claude (real continuity)
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
claude_request({prompt:"Implement rate limiter in src/rate-limiter.ts",createNewSession:true,approvalStrategy:"mcp_managed"})
|
|
79
|
+
// Save returned sessionId
|
|
80
|
+
|
|
81
|
+
claude_request({prompt:"Add unit tests for rate limiter",sessionId:"[saved id]",approvalStrategy:"mcp_managed"})
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Codex (real continuity via `codex exec resume`)
|
|
85
|
+
|
|
86
|
+
Pass `resumeLatest:true` to continue the most recent Codex session in cwd, or `sessionId:<UUID>` to target a specific session (UUID visible in `~/.codex/sessions/` or via `codex resume`):
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
codex_request({prompt:"Implement rate limiter with sliding window",fullAuto:true,approvalStrategy:"mcp_managed"})
|
|
90
|
+
// Subsequent turn — resume the same Codex session:
|
|
91
|
+
codex_request({prompt:"Add tests: basic limiting, burst traffic, window expiry.",resumeLatest:true,approvalStrategy:"mcp_managed"})
|
|
92
|
+
// Or target a known UUID:
|
|
93
|
+
codex_request({prompt:"Now add metrics.",sessionId:"7f9f9a2e-1b3c-4c7a-9b0e-deadbeefcafe",approvalStrategy:"mcp_managed"})
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Note: `fullAuto:true` is silently dropped on resume — the original session's approval policy is inherited. If you need a fresh approval posture, pass `createNewSession:true` and re-state the context.
|
|
97
|
+
|
|
98
|
+
### Gemini (resumable)
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
gemini_request({prompt:"Continue analysis",resumeLatest:true,approvalStrategy:"mcp_managed"})
|
|
102
|
+
gemini_request({prompt:"Continue",sessionId:"latest",approvalStrategy:"mcp_managed"})
|
|
103
|
+
gemini_request_async({prompt:"Deep analysis...",sessionId:"my-gemini-session",approvalStrategy:"mcp_managed"})
|
|
104
|
+
// Response: resumable:true
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Grok (real continuity)
|
|
108
|
+
|
|
109
|
+
Grok carries real CLI continuity via `--resume` / `--continue`. Auth must already be set up (`grok login` OAuth, or `GROK_CODE_XAI_API_KEY`):
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
grok_request({prompt:"Implement rate limiter in src/rate-limiter.ts",createNewSession:true,approvalStrategy:"mcp_managed"})
|
|
113
|
+
// Save returned sessionId
|
|
114
|
+
|
|
115
|
+
grok_request({prompt:"Add unit tests for the rate limiter",sessionId:"[saved id]",approvalStrategy:"mcp_managed"})
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Switching Sessions
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
session_list() // all sessions
|
|
122
|
+
session_list({cli:"claude"}) // filter by CLI
|
|
123
|
+
session_set_active({cli:"claude",sessionId:"..."}) // switch active
|
|
124
|
+
session_set_active({cli:"claude",sessionId:null}) // clear active
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Parallel Workflows
|
|
128
|
+
|
|
129
|
+
Separate sessions for independent workstreams:
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
session_create({cli:"claude",description:"Feature: user auth"}) // → authSessionId
|
|
133
|
+
session_create({cli:"claude",description:"Bugfix: rate limit"}) // → bugfixSessionId
|
|
134
|
+
|
|
135
|
+
claude_request({prompt:"...",sessionId:authSessionId,approvalStrategy:"mcp_managed"}) // auth context
|
|
136
|
+
claude_request({prompt:"...",sessionId:bugfixSessionId,approvalStrategy:"mcp_managed"}) // bugfix context
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Session TTL
|
|
140
|
+
|
|
141
|
+
Default: 30 days. Expired sessions silently evicted on next operation.
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
SESSION_TTL=604800 # 7 days
|
|
145
|
+
SESSION_TTL=7776000 # 90 days
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
- Based on `lastUsedAt`, not `createdAt`
|
|
149
|
+
- Active sessions stay alive with use
|
|
150
|
+
- If active session expires, active pointer cleared
|
|
151
|
+
- File-based and PostgreSQL backends both enforce TTL
|
|
152
|
+
|
|
153
|
+
## Gateway Prefix (`gw-`)
|
|
154
|
+
|
|
155
|
+
Gemini requests without explicit `sessionId` → gateway generates `gw-*` ID.
|
|
156
|
+
|
|
157
|
+
Passing `gw-*` as `sessionId` → rejected:
|
|
158
|
+
> Session ID "gw-..." uses reserved prefix "gw-".
|
|
159
|
+
|
|
160
|
+
Check `resumable` field: `true`=safe to reuse, `false`=gateway-generated.
|
|
161
|
+
|
|
162
|
+
## Cleanup
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
session_delete({sessionId:"..."}) // single
|
|
166
|
+
session_clear_all({cli:"codex"}) // per CLI
|
|
167
|
+
session_clear_all() // everything
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Inspect
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
session_get({sessionId:"..."})
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Returns: timestamps, description, CLI type, active status.
|
|
177
|
+
|
|
178
|
+
When the session has prior requests in the flight recorder, the response also includes a compact `cacheState` block (omitted entirely for fresh sessions — not null, not empty object):
|
|
179
|
+
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"cacheState": {
|
|
183
|
+
"cli": "claude",
|
|
184
|
+
"prefixDistinct": 3,
|
|
185
|
+
"totalCacheReadTokens": 14210,
|
|
186
|
+
"totalCacheCreationTokens": 8420,
|
|
187
|
+
"requestCount": 7,
|
|
188
|
+
"hitCount": 5,
|
|
189
|
+
"hitRate": 0.714,
|
|
190
|
+
"estimatedSavingsUsd": 0.0184,
|
|
191
|
+
"ttlRemainingMs": 142000
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
`ttlRemainingMs` is non-null only for Claude sessions and reflects the configured `[cache_awareness] anthropic_ttl_seconds` (default 300 = 5 min, or 3600 = 1 h). Use it to decide whether the next turn will hit a warm cache or pay full cache-creation cost. No prompt/response text is stored or returned — only tokens, hashes, and aggregates.
|
|
197
|
+
|
|
198
|
+
## Cache-Aware Prompts and Cache Observability
|
|
199
|
+
|
|
200
|
+
Sessions and cache awareness compose. The structured `promptParts` field (mutually exclusive with `prompt`) lets you keep `system` / `tools` / `context` byte-identical across turns of a session while only the `task` mutates:
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
claude_request({
|
|
204
|
+
promptParts: {
|
|
205
|
+
system: "<stable system instruction>",
|
|
206
|
+
context: "<file dump or spec — same as last turn>",
|
|
207
|
+
task: "Now add metrics."
|
|
208
|
+
},
|
|
209
|
+
sessionId: savedSessionId,
|
|
210
|
+
approvalStrategy: "mcp_managed"
|
|
211
|
+
})
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
The gateway hashes the stable prefix and writes it to the flight recorder so per-session and per-prefix cache effectiveness is queryable via MCP resources:
|
|
215
|
+
|
|
216
|
+
- `cache-state://global` — last-24h aggregate hit rate, total hits, estimated savings, with per-CLI breakdown
|
|
217
|
+
- `cache-state://session/{sessionId}` — per-session aggregates (same shape as `session_get.cacheState`)
|
|
218
|
+
- `cache-state://prefix/{hash}` — per-stable-prefix-hash aggregates with CLI × model breakdown
|
|
219
|
+
|
|
220
|
+
### Provider-specific cache direction examples
|
|
221
|
+
|
|
222
|
+
**Claude (explicit cacheControl)**
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
claude_request({
|
|
226
|
+
promptParts: {
|
|
227
|
+
system: "<stable>",
|
|
228
|
+
context: "<large stable context>",
|
|
229
|
+
task: "Now add metrics.",
|
|
230
|
+
cacheControl: { system: true, context: true }
|
|
231
|
+
},
|
|
232
|
+
outputFormat: "stream-json",
|
|
233
|
+
sessionId: savedSessionId
|
|
234
|
+
})
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Grok (compaction)**
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
grok_request({
|
|
241
|
+
promptParts: { system: "<stable>", context: "...", task: "..." },
|
|
242
|
+
compactionMode: "segments",
|
|
243
|
+
compactionDetail: "balanced",
|
|
244
|
+
sessionId: savedSessionId
|
|
245
|
+
})
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
See `docs/personal-mcp/PROVIDER_CACHE_SURFACES.md` for exact stream-json payload shape, telemetry differences, and the full matrix. Prefix discipline (`promptParts` without cacheControl) works for all CLIs.
|
|
249
|
+
|
|
250
|
+
### TTL warning (Claude, opt-in)
|
|
251
|
+
|
|
252
|
+
With `[cache_awareness] warn_on_ttl_expiry = true` in `~/.llm-cli-gateway/config.toml`, a resumed Claude turn whose prior `lastRequestAt` is within 30 s of the cache TTL returns:
|
|
253
|
+
|
|
254
|
+
```json
|
|
255
|
+
{ "warnings": [{ "code": "cache_ttl_expiring_soon", "ttlRemainingMs": 12000, "message": "..." }] }
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
That is a hint that the next turn will likely cold-miss; coalesce or accept the cost.
|
|
259
|
+
|
|
260
|
+
## Tips
|
|
261
|
+
|
|
262
|
+
- Descriptive names: "Refactoring auth module" > "Session 1"
|
|
263
|
+
- Use `createNewSession:true` for quick one-offs
|
|
264
|
+
- Clean up completed workflow sessions
|
|
265
|
+
- Each CLI tracks active session independently
|
|
266
|
+
- For Codex: real `codex exec resume <UUID>` / `--last` continuity. The gateway-tracked session ID is independent of the Codex CLI's session UUID — for resume, supply a real Codex UUID or use `resumeLatest:true`. `--full-auto` is dropped on resume (approval policy inherits from the original session)
|
|
267
|
+
- For Grok: real `--resume`/`--continue` continuity, same model as Claude — but auth must be set up first (`grok login` or `GROK_CODE_XAI_API_KEY`)
|
|
268
|
+
- Expired sessions (past TTL) silently evicted
|
|
269
|
+
- Never pass Gemini `gw-*` IDs as `sessionId` — use own IDs for resumable Gemini workflows
|
|
270
|
+
- Check Gemini's `resumable` field to know if that session can continue
|
|
271
|
+
- Sync tools may auto-defer at 45s — deferred response preserves `sessionId`. Deferred jobs and their results are now durable (default 30-day retention via `LLM_GATEWAY_JOB_RETENTION_DAYS`), so a session that auto-defers can be picked up across gateway restarts
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the llm-cli-gateway project.
|
|
4
4
|
|
|
5
|
+
## [2.12.0] - 2026-06-30: Validation receipts, API-provider parity, and a gateway usability pass
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Durable, owner-scoped receipts for cross-LLM validation runs.** A terminal validation run (every dispatched provider job terminal, and the judge if one was requested) mints exactly one immutable `validation_receipts` row enveloping the existing `validation-report.v1` structuredContent, with a deterministic `canonical_sha256` over the canonical serialization (recursively sorted object keys, preserved array order, UTF-8; the re-derived `humanReadable` is excluded). Minting is eager (the first time a run is observed terminal, via the `job_result` collection hook and `synthesize_validation`), so a receipt is captured before job rows are evicted; an explicit read is the fallback.
|
|
10
|
+
- **New `validation_receipt` tool.** Retrieves a receipt by `validationId` with own-or-not-found ownership: `minted` | `pending` | `expired_unminted` | `not_found`. `format: "json" | "markdown"` (markdown is a read-time rendering, never stored or hashed). `includeRawResponses` inlines full provider answer text as a read-time-only expansion pulled live per job under the same owner check (never persisted, never hashed).
|
|
11
|
+
- **New `validation-receipt://{validationId}` MCP resource** with the same own-or-not-found owner scoping.
|
|
12
|
+
- **Durable run identity (prerequisite).** `validation_runs` (plus a `validation_run_jobs` reverse index) persists each run's `validationId`, owner principal, and provider/judge job links at kickoff. The report and synthesis status enums gained a terminal `completed` value.
|
|
13
|
+
- The receipt tool, the resource, and the run/receipt tables exist ONLY under an implemented durable backend (today `sqlite`) with a store attached at runtime; under `memory` / `postgres` / `none` no run/receipt row is written and the tool/resource are not registered (the caller still receives a `validationId` at kickoff). Silent loss is impossible by construction.
|
|
14
|
+
- **Grok structured-output and session/worktree parity (Grok 0.2.73).** `grok_request` / `grok_request_async` gained `jsonSchema` (emits `--json-schema`, constrains output to a JSON Schema, implies json output), `forkSession` (emits `--fork-session`, forks a resumed session into a new ID), and `worktreeRef` (emits `--worktree-ref <REF>`; requires `nativeWorktree`, else rejected). Grok `--session-id` remains intentionally unwired (the gateway owns session-id lifecycle and cross-principal isolation).
|
|
15
|
+
- **Antigravity project selection (agy 1.0.13).** `gemini_request` / `gemini_request_async` gained `project` (emits `--project <ID>`) and `newProject` (emits `--new-project`); the two are mutually exclusive (rejected if both set).
|
|
16
|
+
- **API-provider unification: the generic `api_<name>_request` surface reaches CLI-tool parity (Slices 1-4b).** Telemetry parity (per-request usage/cost), schema parity (`promptParts`, `optimizePrompt`, `optimizeResponse`, `forceRefresh`, `sessionId`, `createNewSession`), capability-typed continuity with gateway sessions (`ApiContinuity` = `server-side-id` | `stateless-resend` | `none`), and server-side-id continuation on the generic handler. The legacy standalone `xai-api-provider` module was removed; the grok-api HTTP path now runs through the shared `api-provider` / `api-http` adapter (externally-observable response shape unchanged).
|
|
17
|
+
- **OpenRouter usage accounting.** New optional provider config key `usage_include` opts the OpenAI-compatible adapter into `usage: { include: true }` so token counts and end-to-end `usage.cost` (USD) are returned; off by default so strict OpenAI-compatible servers are unaffected.
|
|
18
|
+
- **Caller-facing skills now ship in the npm package.** The published gateway serves six caller skills (`async-job-orchestration`, `multi-llm-review`, `session-workflow`, `secure-orchestration`, `implement-review-fix`, `public-demo-session`); previously `.agents` was excluded from `package.json` `files`, so every install served zero skills. Operator/maintainer skills (the `provider-*` contract guides, `gateway-restart-surfaces`) stay out of the tarball, and the release tarball guard now scans shipped skills for host-internal leaks.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **Upstream contracts refreshed to the installed provider versions.** Live `--probe-installed` probes were re-run across all six provider CLIs; ACP `targetVersion` pins bumped to claude 2.1.195, codex-cli 0.142.4, agy 1.0.13, grok 0.2.73, and devin 2026.8.18 (mistral vibe 2.17.1 unchanged), kept in sync across `upstream-contracts`, `provider-tool-capabilities`, and the ACP `provider-registry`. Acknowledged newly-advertised flags (claude `--bg`/`--background`); dropped stale acknowledgements (claude `--mcp-debug`, agy `-i`/`--version`); and acknowledged grok's `ssh` subcommand inheriting the global agent flag surface.
|
|
23
|
+
- **`agy update` help-probe drift silenced.** `agy update --help` uses Go's `flag` package (prints "Usage of update:" and exits 2). A new `helpProbeExitTolerant` subcommand-contract marker treats that legitimate non-zero help exit as clean rather than reporting it as drift.
|
|
24
|
+
- **Devin is now visible across discovery.** Devin was a fully registered request tool but omitted from the server instructions and rejected by the `list_models`, `cli_versions`, `cli_upgrade`, and `provider_tool_capabilities` enums; those now include devin (pure widening), and the stale "five providers" describe/description text was refreshed.
|
|
25
|
+
- **Request tool and parameter descriptions sharpened for usability.** Clarified Codex `sandboxMode` (omit = read-only), Gemini `approvalMode`/`outputFormat` (only default/yolo and text work on the agy headless path), `approvalStrategy`/`approvalPolicy` semantics, `idleTimeoutMs` (gateway 10-min idle kill; Claude stream-json only), `jsonSchema` (set `outputFormat:json`), session-resume rules (gw-* fresh-session ids are not resumable; use `resumeLatest`), the generic API params, and the mistral/devin permission defaults.
|
|
26
|
+
|
|
27
|
+
### Reliability and error guidance
|
|
28
|
+
|
|
29
|
+
- **Result-health guards against silent success.** A Claude run that exits 0 but reports `is_error:true` (e.g. `error_max_turns`) now carries a `claude_result_error` warning and a `resultIsError` signal (the text is still returned); an exit-0 run with empty assistant output emits an `empty_output` warning. Claude `--output-format json` telemetry (usage/cost) is now parsed (it was previously dropped), and the real Codex session UUID is surfaced as `codexSessionId` so callers can resume/fork without filesystem access.
|
|
30
|
+
- **Actionable error remediation.** `createErrorResponse` now detects auth/login failures and appends per-CLI remediation (`errorCategory: auth_error`), categorizes the 50MB output overflow as `output_overflow`, adds async-retry guidance on wall-clock timeout (124) and an interactive/idle hint on idle timeout (125), enriches Codex failures from the JSONL stream when stderr is empty (with a resume-not-found hint), and adds a fallback hint when a non-zero exit captured no stderr.
|
|
31
|
+
- A whitespace-only prompt is now rejected at the prep boundary instead of being passed to the CLI.
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- **Cross-principal read hole on the validation collection tools.** `job_status` / `job_result` now apply the `principalCanAccess` owner check that the `llm_job_*` paths already enforce; a job owned by another principal is reported as not found.
|
|
36
|
+
|
|
37
|
+
### Deps
|
|
38
|
+
|
|
39
|
+
- npm-minor-patch group: `smol-toml` 1.6.1 to 1.7.0 (runtime), `pg` 8.21.0 to 8.22.0, plus devDeps `@types/node` to 26.0.1, `@typescript-eslint/{eslint-plugin,parser}` 8.61.1 to 8.62.1, `eslint` 10.5.0 to 10.6.0, `prettier` 3.8.4 to 3.9.3. CI: `zizmor` 1.25.2 to 1.26.1, github-actions group bumps. Dependabot now ignores `body-parser` 2.3.0 (it transitively pulled the Socket-flagged `type-is` 2.1.0 / `content-type` 2.0.0 that the release audit blocks).
|
|
40
|
+
|
|
41
|
+
### Not yet implemented (reserved)
|
|
42
|
+
|
|
43
|
+
- Cryptographic signing and hash chaining. The `prev_sha256` / `seq` / `signature` columns are reserved (NULL); the canonical byte definition they will build on is fixed now. Semantic enrichment (`key_points`, `evidence_cited`, `uncertainty_signals`, numeric per-model confidence) is deferred to `validation-receipt.v2` (no extraction source exists today).
|
|
44
|
+
|
|
5
45
|
## [2.11.1] - 2026-06-22: Provider contract refresh and stable upstream scans
|
|
6
46
|
|
|
7
47
|
### Changed
|