pi-codemcp 1.5.0 → 1.5.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.
package/README.md CHANGED
@@ -1,95 +1,71 @@
1
1
  # pi-codemcp
2
2
 
3
- Fast, typed, sandboxed **Code Mode for every MCP server configured in Pi**.
3
+ > [!IMPORTANT]
4
+ > **Something failed? Please open an issue.**
5
+ >
6
+ > Please do not assume your failure is too specific or not worth reporting. Platform differences, strange schemas, slow startup, confusing rendering, OAuth problems, and rough edges are exactly the reports that make this project better.
7
+ >
8
+ > Open an issue at <https://github.com/yolonir/pi-codemcp/issues>, or use **Extension is broken!** in `/codemcp` → Settings to ask the agent to investigate and prepare one.
9
+ >
10
+ > You can ask your coding agent to do the work:
11
+ >
12
+ > ```text
13
+ > Reproduce this pi-codemcp problem, redact all credentials and private data,
14
+ > collect the pi-codemcp version, Pi version, OS/architecture, MCP transport,
15
+ > minimal configuration shape, exact error, and relevant logs, then open a
16
+ > GitHub issue at https://github.com/yolonir/pi-codemcp/issues.
17
+ > ```
18
+ >
19
+ > If the agent cannot create the issue, ask it to prepare the title and body for you. I would much rather receive an incomplete report than have someone hit a problem, abandon the package, and never say anything. I will read the issues and work through them.
20
+
21
+ Typed, sandboxed **Code Mode for your MCP servers in Pi**.
22
+
23
+ The agent discovers the tools it needs, writes a Python program, and runs dependent or parallel calls across MCP servers. Intermediate data stays in the sandbox; only the program's compact return value goes back to the model.
4
24
 
5
- Instead of putting every upstream MCP tool definition into the model context, pi-codemcp gives the agent a small interface for discovery, execution, and reuse:
6
-
7
- - `codemcp_search` ranks capabilities or pages through a compact inventory without loading full schemas.
8
- - Optional Jev discovery lets the agent route complete MCP tasks on demand, returning relevant calls, composition guidance, and exact contracts through bounded parallel TypeSafe requests.
9
- - `codemcp_inspect` returns exact typed SDK stubs only for selected calls.
10
- - `codemcp_execute` runs one sandboxed Python call graph across one or many MCP servers.
11
- - `codemcp_edit` applies one exact replacement to the previous execution and reruns it without resending the full code.
12
- - `codemcp_save_chain` turns a repeated call graph into a reusable native Pi tool.
13
- - `codemcp_manage_chains` lists chains or performs an explicitly confirmed enable, disable, revalidate, or delete.
14
-
15
- Intermediate results stay inside the sandbox. The model receives only the compact value returned by the program.
16
-
17
- ## Why Code Mode?
18
-
19
- MCP has an uncomfortable scaling property: the more tools an agent can use, the more tool schemas compete with the actual task for context. Multi-step work also tends to bounce every intermediate result through the model, adding tokens, latency, and opportunities for mistakes.
20
-
21
- Cloudflare described a better pattern in [Code Mode: give agents an entire API in 1,000 tokens](https://blog.cloudflare.com/code-mode-mcp/): expose a small search-and-execute surface, let the model write code against a typed SDK, and execute that code in a sandbox. Their work reports a fixed tool footprint and dramatic context savings for very large APIs. The open-source implementation lives in [`@cloudflare/codemode`](https://github.com/cloudflare/agents/tree/main/packages/codemode).
22
-
23
- pi-codemcp applies that idea on the **client side** to the MCP servers you already use in Pi:
24
-
25
- 1. Search the combined catalog or page through a compact inventory.
26
- 2. Inspect exact schemas only for the calls selected for the task.
27
- 3. Type-check a compact Python plan before any upstream call happens.
28
- 4. Execute dependent or parallel calls without model round-trips between them.
29
- 5. Return only the final data the agent actually needs.
30
- 6. Save stable plans as native tools and reuse them without rewriting the call graph.
31
-
32
- That can make complex MCP workflows faster and substantially more token-efficient. Exact savings depend on the servers, schemas, model, and task.
33
-
34
- ## Built for daily use, not a demo
35
-
36
- I built this because I care a lot about software that is genuinely fast, efficient, and predictable enough to use every day. Too many AI extensions look good in a short demo but become slow, noisy, fragile, or effectively unusable in real work.
37
-
38
- pi-codemcp is deliberately opinionated about operational quality:
25
+ ## Install
39
26
 
40
- - Pi startup does not wait for Python or MCP servers.
41
- - Each upstream connection is lazy and independent. A dead connection is evicted after the original call fails; that call is never replayed, and the next explicit call reconnects.
42
- - Upstream failures include stable `kind`, `server`, `tool`, `retryable`, `status`, and `message` fields.
43
- - Tool catalogs are cached per server and invalidated independently.
44
- - Agent-written code is type-checked before execution.
45
- - Time, memory, call count, and output size are bounded.
46
- - Failures are explicit; there are no silent retries or compatibility fallbacks.
47
- - Tool output is compact by default and expands with Pi's normal `Ctrl+O` UI.
48
- - Bounded local telemetry uses fixed rollups rather than session event logs and appears in the `/codemcp` Stats tab.
27
+ ```bash
28
+ pi install npm:pi-codemcp
29
+ ```
49
30
 
50
- There is always room to make it faster and more reliable. If something is not working well, please report it rather than silently giving up on the extension.
31
+ Reads `<agent-dir>/mcp.json`. Supports stdio, Streamable HTTP, SSE, bearer authentication, and FastMCP-managed OAuth.
51
32
 
52
- ## Saved MCP chains
33
+ Open **`/codemcp`** to manage servers, individual tools, saved chains, settings, and usage stats. Changes are saved immediately. Tool output expands with Pi's normal `Ctrl+O`.
53
34
 
54
- Any successful MCP call graph can become a reusable tool with an explicit input and output JSON Schema.
35
+ No separate Python, uv, Bun, or just installation is needed. The package bootstraps a locked Python 3.13 runtime on first use; this needs network access unless already cached. Pi startup does not wait for MCP connections.
55
36
 
56
- A saved chain is exposed in two forms from one manifest:
37
+ ## How it works
57
38
 
58
39
  ```text
59
- mcp_chain_weekly_digest(...) # native Pi tool
60
- chains.weekly_digest(...) # typed call inside Code Mode
40
+ Discover tools load selected contracts → execute a program → return compact data
61
41
  ```
62
42
 
63
- Chains can call upstream MCP tools, other saved chains, or themselves recursively. This enables reusable composition such as:
43
+ | Tool | Purpose |
44
+ | --- | --- |
45
+ | `codemcp_search` | Search capabilities or browse the compact catalog. |
46
+ | `codemcp_route` | Optional Jev routing: select tools, roles, and composition guidance. |
47
+ | `codemcp_inspect` | Load exact typed SDK contracts for selected calls. |
48
+ | `codemcp_execute` | Type-check and run a sandboxed Python program. |
49
+ | `codemcp_edit` | Patch the previous program and rerun it. |
50
+ | `codemcp_save_chain` | Save a tested program as a reusable tool, with user approval. |
51
+ | `codemcp_manage_chains` | List chains; explicitly confirm enable, disable, revalidate, or delete. |
64
52
 
65
- ```python
66
- issues = await chains.collect_open_issues({"assignee": input["assignee"]})
67
- result = await slack.post_message({
68
- "channel": input["channel"],
69
- "text": issues["summary"],
70
- })
71
- return {"posted": result["ok"], "count": issues["count"]}
72
- ```
53
+ Independent calls can use `asyncio.gather`; dependent calls pass earlier outputs into later inputs. Filtering and aggregation happen inside the sandbox, without model round trips for every intermediate result.
73
54
 
74
- Nested chains share the same deadline, cancellation signal, catalog snapshot, and total call budget. Every nested input and output is runtime-validated. Recursion is supported but bounded. Dependency fingerprints mark chains stale when a referenced contract changes.
55
+ ## Optional Jev routing
75
56
 
76
- New manifests default to project scope under `<project>/.pi/pi-codemcp/chains`; explicitly global chains live under `<agent-dir>/pi-codemcp/chains`. A project chain overrides a same-named global chain without deleting it. Manifests contain sandboxed code and schemas, never credentials or execution results. `/codemcp` labels both scopes and can revalidate, enable, disable, or delete chains.
57
+ Provide `TYPESAFE_API_KEY`, then set **Enable Jev true** in `/codemcp` Settings. This replaces `codemcp_search` with `codemcp_route` as the agent's discovery tool.
77
58
 
78
- There is deliberately no implicitsave last execution” state: the agent must submit the exact successfully tested code plus explicit input and output contracts. This keeps persistence reviewable and avoids saving the wrong attempt from a long session.
59
+ 1. The agent calls `codemcp_route` with a short `intent`, such as read staging logs to diagnose the approval error.” The extension includes the original user request and up to three preceding user/assistant messages as context. A changed subtask can be routed again with a new intent.
60
+ 2. Enabled tool names and descriptions go to Jev in parallel chunks of up to 40. Jev scores relevance to that subtask (including prerequisites), assigns workflow roles, and checks whether an intermediate model decision or user approval is needed.
61
+ 3. CodeMCP ranks and filters the answers, selects at most eight tools, derives composition guidance, and fetches their exact typed contracts.
62
+ 4. The agent writes the actual `codemcp_execute` program, keeping a checkpoint between stages when needed.
79
63
 
80
- ## Install
64
+ Jev does not execute tools or block ordinary messages. **Routing sends the intent, your request, recent context, and tool descriptions to TypeSafe**, so it is opt-in. Without a key, local search stays active; a failed route enables search as a fallback. The SDK also honors `TYPESAFE_BASE_URL` and `TYPESAFE_DEFAULT_MODEL`.
81
65
 
82
- ```bash
83
- pi install npm:pi-codemcp
84
- ```
85
-
86
- It reads Pi's existing `<agent-dir>/mcp.json` and supports stdio, Streamable HTTP, SSE, bearer authentication, and FastMCP-managed OAuth. Open `/codemcp` to manage servers, per-tool policy, saved chains, cache, and execution limits.
87
-
88
- Package users do not need Python, uv, Bun, or just. A pinned uv binary bootstraps the locked Python 3.13 runtime under Pi's writable agent directory on first use; the first bootstrap needs network access unless already cached.
66
+ ## MCP configuration
89
67
 
90
- ## MCP configuration examples
91
-
92
- `pi-codemcp` reads the same MCP config Pi uses. Either shape is accepted:
68
+ Use an `mcpServers` object or a root-level server map:
93
69
 
94
70
  ```json
95
71
  {
@@ -97,39 +73,24 @@ Package users do not need Python, uv, Bun, or just. A pinned uv binary bootstrap
97
73
  "filesystem": {
98
74
  "command": "npx",
99
75
  "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
76
+ },
77
+ "linear": {
78
+ "type": "http",
79
+ "url": "https://mcp.linear.app/mcp",
80
+ "auth": "oauth"
100
81
  }
101
82
  }
102
83
  }
103
84
  ```
104
85
 
105
- or a root server map:
86
+ Set `disabled: true` or `enabled: false` to disable a server. For stdio, only a safe base environment, comma-separated variables in `MY_PI_CHILD_ENV_ALLOWLIST` / `MY_PI_MCP_ENV_ALLOWLIST`, and explicit server `env` values are passed through. Remote `headers` can reference allowed environment variables with `${NAME}`.
106
87
 
107
- ```json
108
- {
109
- "linear": {
110
- "type": "http",
111
- "url": "https://mcp.linear.app/mcp",
112
- "auth": "oauth"
113
- },
114
- "grafana": {
115
- "type": "sse",
116
- "url": "https://grafana.example.com/sse",
117
- "headers": {
118
- "authorization": "Bearer ${GRAFANA_MCP_TOKEN}"
119
- }
120
- },
121
- "disabled-example": {
122
- "command": "example-server",
123
- "disabled": true
124
- }
125
- }
126
- ```
127
-
128
- For stdio servers, pi-codemcp passes a small safe base environment plus variables listed in `MY_PI_CHILD_ENV_ALLOWLIST` or `MY_PI_MCP_ENV_ALLOWLIST`. Explicit `env` values in `mcp.json` are also passed. Remote headers can reference allowed environment variables with `${NAME}`. Pi-only fields such as `directTools`, `lifecycle`, `idleTimeout`, `enabled`, and `disabled` are understood locally and are not forwarded to FastMCP.
88
+ ## Settings
129
89
 
130
- ## Settings JSON
90
+ Edit settings in `/codemcp` or `<agent-dir>/pi-codemcp/settings.json`. Defaults: 30-second execution and tool timeouts, 50 upstream calls, 16 KiB returned data, 50 KiB rendered output, and a 24-hour catalog cache.
131
91
 
132
- Settings live at `<agent-dir>/pi-codemcp/settings.json` and can also be edited in `/codemcp`:
92
+ <details>
93
+ <summary>Settings JSON</summary>
133
94
 
134
95
  ```json
135
96
  {
@@ -148,141 +109,68 @@ Settings live at `<agent-dir>/pi-codemcp/settings.json` and can also be edited i
148
109
  }
149
110
  ```
150
111
 
151
- The Python sidecar enforces catalog cache TTL, execution timeout, per-tool timeout, max MCP calls, result size, and disabled-tool policy. The TypeScript Pi layer uses `backgroundWarmup` and `outputLimitKiB` for session warmup and rendered-output truncation; the sidecar still validates those fields so the settings file has one strict shared schema. Version-one files are migrated when loaded, and the removed `outputLineLimit` field is omitted on the next save.
112
+ Older settings are migrated on load, including `discoveryMode` `jevEnabled`.
152
113
 
153
- ### Jev discovery mode
114
+ </details>
154
115
 
155
- Enable Jev in `/codemcp` and provide `TYPESAFE_API_KEY`. This replaces `codemcp_search` with the on-demand `codemcp_route` tool, so ordinary messages have no routing delay. When a task may need MCP, the agent sends the complete task plus every enabled MCP call's name and description to TypeSafe in bounded parallel chunks. Jev scores every call, classifies its workflow role, and checks whether an intermediate model/user checkpoint is required; pi-codemcp merges those raw answers into parallel or dependent composition guidance. The result includes exact typed contracts and directs the agent into the appropriate `codemcp_execute` program.
116
+ ## Saved chains
156
117
 
157
- Jev mode is opt-in because routed task text and enabled tool descriptions leave the machine. If the API key is missing, pi-codemcp keeps local `codemcp_search` active. If a Jev route fails, search is activated as an in-session fallback. `TYPESAFE_BASE_URL` and `TYPESAFE_DEFAULT_MODEL` are honored by the official TypeSafe SDK.
158
-
159
- ## Search and execute flow
160
-
161
- The agent searches for a capability, inspects the selected exact stub when needed, and executes a compact plan. Unscoped searches discover stale or missing server catalogs independently: available servers still return results, while `discovery_failures` explicitly reports unavailable servers. Server-scoped searches remain fail-fast.
162
-
163
- ```python
164
- issues = await linear.list_issues({"assignee": "me", "limit": 50})
165
- return {"count": len(issues), "ids": [issue["identifier"] for issue in issues]}
166
- ```
118
+ With your approval, a successfully executed program can be saved with explicit input/output JSON Schemas. One manifest exposes both:
167
119
 
168
- The same flow is available through the internal CLI for debugging:
169
-
170
- ```bash
171
- uv run --project sidecar --frozen -m sidecar.cli search "issues assigned to me"
172
- uv run --project sidecar --frozen -m sidecar.cli execute --code-file plan.py
173
- ```
174
-
175
- A direct one-shot plan can call multiple servers without model round trips between calls:
176
-
177
- ```bash
178
- uv run --project sidecar --frozen -m sidecar.cli execute --code '
179
- number = await alpha.get_number({"seed": 41})
180
- saved = await beta.save_number({"value": number["value"]})
181
- return {"number": number["value"], "identifier": saved["identifier"]}
182
- '
183
- ```
184
-
185
- Incomplete upstream schemas become recursive `JsonValue`, not `Any`; use the prebound `expect_object`, `expect_list`, `expect_string`, and `expect_integer` helpers to narrow unknown values explicitly. For unfamiliar outputs, `inspect_json(value, samples=2, max_depth=3)` returns a byte-bounded structural summary, cardinality, field sizes, and samples; `samples` is limited to 1–3 and `max_depth` to 1–6 during preflight. The generated prelude documents the sandbox surface: use `import asyncio` with `asyncio.gather`; unavailable host or stdlib APIs are rejected. Preflight type errors happen before any upstream call is made, and oversized final results fail explicitly with the same actionable inspection data.
186
-
187
- When an oversized value fits the bounded in-memory refinement cache, the failure also returns an opaque `result_ref` and expiry. Pass that reference back as `inputRef` on one follow-up `codemcp_execute`; the retained JSON is exposed as `input`, so code can filter or aggregate it without repeating upstream calls. References expire after five minutes, are valid only in the originating sidecar, and are never persisted.
188
-
189
- For a small correction, `codemcp_edit` replaces one uniquely matching `oldText` with `newText` in the most recent execution and reruns it with the same `inputRef`. The state is in-memory and disappears when the sidecar restarts. The full call graph runs again, including upstream MCP calls.
190
-
191
- ## Saved-chain CLI flow
192
-
193
- Saved chains are JSON manifests with sandboxed code plus explicit input/output JSON Schemas. Project-scoped chains live under `<project>/.pi/pi-codemcp/chains`; global chains live under `<agent-dir>/pi-codemcp/chains`.
194
-
195
- ```bash
196
- uv run --project sidecar --frozen -m sidecar.cli chain save save_number \
197
- --description "Fetch and save one generated number." \
198
- --code 'number = await alpha.get_number({"seed": input["seed"]})
199
- return await beta.save_number({"value": number["value"]})' \
200
- --input-schema '{"type":"object","properties":{"seed":{"type":"integer"}},"required":["seed"],"additionalProperties":false}' \
201
- --output-schema '{"type":"object","properties":{"saved":{"type":"boolean"},"identifier":{"type":"string"}},"required":["saved","identifier"],"additionalProperties":false}'
202
-
203
- uv run --project sidecar --frozen -m sidecar.cli chain list
204
- uv run --project sidecar --frozen -m sidecar.cli chain run save_number --input '{"seed":41}'
205
- uv run --project sidecar --frozen -m sidecar.cli chain revalidate save_number --scope project
206
- uv run --project sidecar --frozen -m sidecar.cli chain delete save_number --scope project
120
+ ```text
121
+ mcp_chain_weekly_digest(...) # native Pi tool
122
+ chains.weekly_digest(...) # typed call inside another CodeMCP program
207
123
  ```
208
124
 
209
- Revalidation checks the saved code against the current enabled catalog. Deletion refuses to remove chains still referenced by other chains. Disabling a project chain does not fall back to a same-named global chain; project scope continues to shadow global scope until the project manifest is deleted.
125
+ Chains can call MCP tools or other chains. Nested calls share time and call budgets; inputs and outputs are validated. Changed dependency contracts mark chains stale for revalidation.
210
126
 
211
- ## Output and result normalization
127
+ - **Project:** `<project>/.pi/pi-codemcp/chains` (activated in trusted projects).
128
+ - **Global:** `<agent-dir>/pi-codemcp/chains`, when explicitly requested.
212
129
 
213
- When an upstream tool declares an output schema, pi-codemcp requires `structuredContent`, validates it, dumps it back to JSON-compatible values, and preserves declared structured string fields as strings. FastMCP-wrapped `result` strings are intentionally unwrapped and parsed because those wrappers commonly carry JSON payloads as text. When no output schema exists, single text responses that look like JSON objects, arrays, `null`, `true`, or `false` are normalized into native JSON values; non-JSON text remains a string.
130
+ Project chains override same-named global chains, even when disabled. Manifests store code and schemas, not credentials or execution results. Manage them through `/codemcp`.
214
131
 
215
- Execution results report explicit stages:
132
+ ## Execution and safety
216
133
 
217
- - `preflight`: code did not run and no upstream call was made.
218
- - `runtime`: the sandbox or an upstream call failed after execution started.
219
- - `timeout` / `cancelled`: execution was stopped.
220
- - `result`: the call graph completed, but the returned value exceeded `resultLimitKiB`.
134
+ [FastMCP](https://github.com/jlowin/fastmcp) handles transports, validation, and OAuth. [Pydantic Monty](https://github.com/pydantic/monty) type-checks and executes Python without host filesystem, environment, network, or subprocess access. External access is only through the exposed MCP and saved-chain calls.
221
135
 
222
- Rendered Pi output is separately truncated by `outputLimitKiB`; the full oversized rendered value is not persisted.
136
+ - Type errors stop execution **before any upstream call**. Time, memory, call count, and output size are bounded.
137
+ - Enabled tools retain their upstream permissions. Chains cannot bypass server or per-tool policy.
138
+ - No automatic call retries or cross-service rollback: a later failure does not undo earlier side effects.
139
+ - `codemcp_edit` reruns the **whole program**, including upstream calls; it is not a continuation.
140
+ - Unscoped search returns available results plus explicit `discovery_failures`; server-scoped search fails if that server is unavailable.
223
141
 
224
- ## Safety and limits
142
+ <details>
143
+ <summary>Working with unknown or oversized results</summary>
225
144
 
226
- FastMCP owns MCP transports, runtime validation, and OAuth. [Pydantic Monty](https://github.com/pydantic/monty) type-checks and executes agent-written Python without host filesystem, environment, network, or subprocess access. Code Mode can only call the typed MCP tool and saved-chain facades exposed in the generated stubs.
145
+ Incomplete schemas use recursive `JsonValue`, not `Any`. Use the prebound `expect_object`, `expect_list`, `expect_string`, and `expect_integer` helpers to narrow values. `inspect_json(value, samples=2, max_depth=3)` returns a bounded structural summary.
227
146
 
228
- `/codemcp` configures servers, saved chains, per-tool policy, timeouts, call limits, output limits, cache TTL, and warmup, and shows bounded lifetime/recent telemetry in its Stats tab. Server, chain, tool-policy, and setting changes are persisted immediately. Discovery, revalidation, and deletion remain explicit immediate actions. The sandbox also has a fixed memory ceiling; executions are serialized per Pi session. There are no automatic retries or cross-service rollback.
147
+ Oversized results fail explicitly. If the value fits the in-memory refinement cache, the error includes a `result_ref`. Pass it as `inputRef` in a follow-up `codemcp_execute` to filter the retained value as `input` without repeating upstream calls. References expire after five minutes and are valid only in the originating sidecar.
229
148
 
230
- Enabled tools retain their upstream permissions. Saved chains never bypass server or per-tool policy and are checked against the current enabled catalog whenever they run. Preflight safety does not make upstream tools transactional: if a later call fails after earlier calls succeeded, pi-codemcp does not roll those upstream side effects back.
149
+ Failures distinguish `preflight`, `runtime`, `timeout`, `cancelled`, and oversized `result` stages. Rendered output has a separate `outputLimitKiB` cap.
231
150
 
232
- ## Something failed? Please open an issue
151
+ </details>
233
152
 
234
- Please do not assume your failure is too specific or not worth reporting. Platform differences, strange schemas, slow startup, confusing rendering, OAuth problems, and rough edges are exactly the reports that make this project better.
235
-
236
- Open an issue at <https://github.com/yolonir/pi-codemcp/issues>.
237
-
238
- You can ask your coding agent to do the work:
239
-
240
- ```text
241
- Reproduce this pi-codemcp problem, redact all credentials and private data,
242
- collect the pi-codemcp version, Pi version, OS/architecture, MCP transport,
243
- minimal configuration shape, exact error, and relevant logs, then open a
244
- GitHub issue at https://github.com/yolonir/pi-codemcp/issues.
245
- ```
246
-
247
- If the agent cannot create the issue, ask it to prepare the title and body for you. I would much rather receive an incomplete report than have someone hit a problem, abandon the package, and never say anything. I will read the issues and work through them.
248
-
249
- ## Local development
250
-
251
- ```bash
252
- just init
253
- just check
254
- just release-check
255
- ```
256
-
257
- Development and packaged runtime checks target Python 3.13. The sidecar metadata, `.python-version`, mypy, ty, and CI all align on that version.
258
-
259
- To test the checkout without loading an installed copy:
153
+ ## Development
260
154
 
261
155
  ```bash
156
+ just init # locked dependencies and hooks
157
+ just check # locks, lint, types, and tests
158
+ just release-check # also verify the packed clean-install path
262
159
  pi -ne -e . --no-session
263
160
  ```
264
161
 
265
- The sidecar also has a stable internal CLI for development, debugging, and future runtime adapters:
162
+ Uses Bun and uv with Python 3.13. For sidecar debugging:
266
163
 
267
164
  ```bash
268
- uv run --project sidecar --frozen -m sidecar.cli serve --stdio
269
- uv run --project sidecar --frozen -m sidecar.cli status --agent-dir ~/.pi/agent
165
+ uv run --project sidecar --frozen -m sidecar.cli doctor --agent-dir ~/.pi/agent
270
166
  uv run --project sidecar --frozen -m sidecar.cli search "linear issues"
271
167
  uv run --project sidecar --frozen -m sidecar.cli execute --code-file plan.py
272
- uv run --project sidecar --frozen -m sidecar.cli chain list
273
- uv run --project sidecar --frozen -m sidecar.cli doctor --agent-dir ~/.pi/agent
274
168
  ```
275
169
 
276
- `just check` runs lockfile checks, TypeScript, Biome, Bun tests, Ruff, mypy, ty, and pytest. `just release-check` additionally packs the npm artifact, installs it into a clean consumer directory, and runs the packaged sidecar without a system uv on `PATH`.
277
-
278
- ## Releases
279
-
280
- Release Please derives versions and release notes from Conventional Commit titles on `main`: `fix:` publishes a patch, `feat:` publishes a minor, and a `!` or `BREAKING CHANGE:` publishes a major. It maintains the release PR, `CHANGELOG.md`, `package.json`, version tag, and GitHub Release.
281
-
282
- Merging a release PR publishes the verified package to npm from `.github/workflows/release.yml` using trusted publishing and provenance. Quality gates the exact merge commit on Linux, macOS, and Windows; the publish job checks out its release tag, packs it with Bun, and uses npm only for the final OIDC-authenticated upload.
170
+ Conventional Commit titles drive Release Please. Feature PRs do not publish; merging the release PR triggers the verified npm release.
283
171
 
284
172
  ## Credits
285
173
 
286
- The core search-and-execute philosophy is inspired by Cloudflare's Code Mode work. pi-codemcp is an independent implementation for Pi that composes arbitrary configured MCP servers through FastMCP and a Pydantic Monty sandbox.
174
+ Inspired by [Cloudflare's Code Mode](https://blog.cloudflare.com/code-mode-mcp/). Independent implementation for Pi using FastMCP and Pydantic Monty.
287
175
 
288
176
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-codemcp",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "Typed, sandboxed Code Mode access to configured MCP servers for Pi",
5
5
  "type": "module",
6
6
  "packageManager": "bun@1.3.10",
package/src/jev-router.ts CHANGED
@@ -128,14 +128,14 @@ export class JevRouter {
128
128
  const questions: Questions = {};
129
129
  if (includeTaskQuestions) {
130
130
  questions.needs_any_tool = noul(
131
- "Does satisfying the user's request require at least one configured external-service or saved-workflow tool?",
131
+ "Does the current task (the agent's routing intent) require at least one configured external-service or saved-workflow tool? Use the original user request as context, not as a requirement that every step be explicitly named.",
132
132
  {
133
133
  true: "The request needs current, private, or external state, or asks for an external action.",
134
134
  false: "Explanation, reasoning, or local coding tools can fully satisfy the request.",
135
135
  },
136
136
  );
137
137
  questions.needs_checkpoint = noul(
138
- "Must the agent inspect an intermediate result, make a semantic decision, or obtain user approval before the next external call?",
138
+ "For the current task, must the agent inspect an intermediate result, make a semantic decision, or obtain user approval before the next external call?",
139
139
  {
140
140
  true: "A model or user decision is required between tool stages.",
141
141
  false: "One deterministic CodeMCP program can safely run the complete workflow.",
@@ -150,17 +150,17 @@ export class JevRouter {
150
150
  questions[`tool_${index}`] = noul(
151
151
  {
152
152
  question:
153
- "Is this exact tool necessary to satisfy an explicit part of the user's request?",
153
+ "Is this tool needed for the current task (the agent's routing intent), including prerequisite discovery or diagnostic calls? The user need not explicitly name each step.",
154
154
  tool: toolDescription,
155
155
  },
156
156
  {
157
- true: "The minimal correct workflow needs this capability.",
157
+ true: "The task needs this capability directly or as a prerequisite, such as finding a datasource before querying logs.",
158
158
  false: "The tool is unrelated, redundant, optional, or merely adjacent.",
159
159
  },
160
160
  );
161
161
  questions[`role_${index}`] = choice(
162
162
  {
163
- question: "What role should this tool have in the minimal requested workflow?",
163
+ question: "What role should this tool have in the minimal workflow for the current task?",
164
164
  tool: toolDescription,
165
165
  },
166
166
  {
package/src/tools.ts CHANGED
@@ -75,7 +75,14 @@ const SearchParameters = Type.Object({
75
75
  ),
76
76
  });
77
77
 
78
- const JevRouteParameters = Type.Object({});
78
+ const JevRouteParameters = Type.Object({
79
+ intent: Type.String({
80
+ minLength: 1,
81
+ pattern: "\\S",
82
+ description:
83
+ "Briefly describe the current MCP subtask and relevant service or environment, e.g. read staging logs to diagnose an approval error. Not instructions to another agent; the original user request is included automatically.",
84
+ }),
85
+ });
79
86
 
80
87
  const InspectParameters = Type.Object({
81
88
  calls: Type.Array(Type.String({ minLength: 1 }), {
@@ -174,15 +181,15 @@ export function registerJevRouteTool(
174
181
  name: "codemcp_route",
175
182
  label: "Jev MCP Route",
176
183
  description:
177
- "Use Jev to select every configured MCP call relevant to a complete task, classify each call's workflow role, recommend parallel or dependent composition, and return exact typed SDK contracts. Use when the task may require external services or saved workflows. If no configured capability applies, returns no calls.",
178
- promptSnippet: "Select and compose MCP calls for a complete task with Jev",
184
+ "Use Jev to select configured MCP calls for the agent's current subtask, including prerequisites, classify each call's workflow role, recommend parallel or dependent composition, and return exact typed SDK contracts. Use when the subtask may require external services or saved workflows. If no configured capability applies, returns no calls.",
185
+ promptSnippet: "Select MCP calls and composition guidance for the current subtask with Jev",
179
186
  promptGuidelines: [
180
- "Use codemcp_route once per distinct task when MCP capabilities may be needed; route again only if the task changes or the selected contracts cannot complete it. It reads the current request and recent conversation context automatically.",
187
+ "Use codemcp_route once per distinct MCP subtask. Provide a short intent describing what you need now, including relevant findings; the original user request and recent context are included automatically. Route again with an updated intent if the subtask changes or the selected contracts cannot complete it.",
181
188
  "After codemcp_route returns contracts, immediately write and run the recommended minimal codemcp_execute program instead of stopping to describe the plan.",
182
189
  "Follow codemcp_route composition guidance: gather independent calls, sequence dependent calls, and preserve a model turn only for semantic decisions or approvals.",
183
190
  ],
184
191
  parameters: JevRouteParameters,
185
- async execute(_toolCallId, _params, signal, onUpdate, ctx) {
192
+ async execute(_toolCallId, params, signal, onUpdate, ctx) {
186
193
  const router = getRouter();
187
194
  if (!router) throw new Error("Jev routing requires TYPESAFE_API_KEY");
188
195
  const { task, recentContext } = currentRouteTask(ctx.sessionManager.buildContextEntries());
@@ -191,7 +198,11 @@ export function registerJevRouteTool(
191
198
  details: undefined,
192
199
  });
193
200
  try {
194
- const route = await router.route(task, recentContext, signal);
201
+ const route = await router.route(
202
+ params.intent,
203
+ [`Original user request: ${task}`, recentContext].filter(Boolean).join("\n\n"),
204
+ signal,
205
+ );
195
206
  return {
196
207
  content: [{ type: "text", text: route.prompt }],
197
208
  details: {