Skip to content

Commit 5c48669

Browse files
authored
docs: garden repository notes (#48)
* docs: record R graphics device decision * docs: add plugin skill bundle futurework * Add Glossary to AGENTS.md * futurework: server-worker boundary * Add Codex install network defaults futurework * Add project-local mcp-repl config futurework * Refine client config futurework notes * docs: add futurework notes for sessions
1 parent 8dac42a commit 5c48669

16 files changed

Lines changed: 1089 additions & 69 deletions

AGENTS.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,38 @@ Keep this file short. It is a table of contents, not the full manual.
2222
- `docs/sandbox.md`: sandbox modes and writable-root policy.
2323
- `docs/plans/AGENTS.md`: when to create checked-in execution plans.
2424

25+
## Glossary
26+
27+
- Agent: The model-facing actor using an MCP client to call `repl` or `repl_reset`.
28+
- MCP client: Codex, Claude, or another app that starts `mcp-repl` over MCP stdio and sends tool calls.
29+
- Server: The main `mcp-repl` Rust process in MCP server mode. It owns the MCP surface, worker lifecycle, sandbox application, timeout policy, stdout/stderr capture, sideband interpretation, and response finalization.
30+
- Worker: The child process spawned by the server to run the selected R or Python REPL. It runs inside the effective sandbox and owns the worker-side endpoint of sideband IPC.
31+
- Worker child process: Any direct or indirect process spawned by user code or the backend under the worker. It may inherit stdout/stderr, but it must not own sideband IPC.
32+
- Backend / interpreter: `backend` is the worker-side implementation that presents a selected REPL runtime to the server and MCP client. `interpreter` is the user-facing selector for that presented runtime, currently `r` or `python`; it does not describe the implementation language of the worker binary.
33+
- Runtime: The live R or Python execution environment inside the worker. This is where client-submitted code via `repl` is evaluated.
34+
- REPL session: The stateful runtime in the active worker. One session per worker process instance.
35+
- Tool call: One MCP client invocation of `repl` or `repl_reset`.
36+
- Request: The unit of input accepted by the server for the worker to execute. A request may outlive the initial tool call when it times out and later polls drain output.
37+
- Reply: The MCP tool result returned to the client. Reply finalization is server-owned and may combine worker-originated content with server-only status notices.
38+
- Poll: An empty `repl` input used to drain pending output, wait again on a previously timed-out request, return idle status, or advance pager mode.
39+
- Host: The user's machine and OS environment outside the worker sandbox. Avoid `host-owned` unless the owner is explicitly distinguished from the MCP client, server, worker, and OS/user.
40+
- Sandbox policy: The effective OS-level permissions applied to the worker: `read-only`, `workspace-write`, `danger-full-access`, or `external-sandbox`.
41+
- Sandbox metadata: Codex per-tool-call `_meta["codex/sandbox-state-meta"]` used by `--sandbox inherit` to choose the effective worker sandbox for that call.
42+
- Writable root: An absolute path that a `workspace-write` worker may write, subject to forced read-only subpaths like `.git`, `.codex`, and `.agents`.
43+
- Session temp directory: The server-allocated per-session temp path exposed to the worker as `TMPDIR` and `MCP_REPL_R_SESSION_TMPDIR`.
44+
- Sideband IPC: The JSON-lines server/worker pipe for structural facts such as `readline_start`, `readline_result`, `plot_image`, `request_end`, and `session_end`.
45+
- stdout/stderr pipes: The normal process output streams captured by the server. They are the authoritative visible text source; sideband only helps interpret them.
46+
- Output timeline: The server-side reconstruction of visible output order from captured stdout/stderr plus sideband facts.
47+
- Server-owned: State, files, or notices created and retained by the main server process, not by the runtime or the worker. Use this for output bundles, response finalization, debug logs, and server temp roots.
48+
- Worker-originated text: Text that came from the worker REPL or worker child processes and can be written to `transcript.txt`.
49+
- Server-originated text: Status text synthesized by the server, such as timeout, busy, restart, sandbox, or bundle notices. Also called server-only text when contrasting with worker-originated transcript text.
50+
- Output bundle: A server-owned directory for oversized (potentially mixed text/image) output in files mode, with a bounded inline preview plus inspectable files.
51+
- `transcript.txt`: Bundle file containing worker-originated REPL text only, including echoed input, prompts, stdout, and rendered stderr text.
52+
- `events.log`: Bundle index for mixed text/image history. `T` rows point into `transcript.txt`, `I` rows point to image history, and `S` rows are server-originated omission notices.
53+
- Files mode / pager mode: `--oversized-output files` spills large replies into output bundles; `--oversized-output pager` keeps oversized text in an interactive pager that consumes tool-call input locally instead of forwarding it to the worker until the pager exits or reaches the end.
54+
- Debug REPL: `--debug-repl`, a local interactive driver for the worker that bypasses MCP client/server traffic.
55+
- Wire trace: The external stdio proxy log of exact bytes between an MCP client and the `mcp-repl` server.
56+
2557
## Snapshot Workflow
2658

2759
- Preferred loop:
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Claude Sandbox Inherit
2+
3+
## Motivation
4+
5+
Claude users should not have to describe the same sandbox policy twice. If a
6+
project already has Claude sandbox settings, `mcp-repl` should be able to use
7+
the equivalent policy for its worker when Claude starts the MCP server.
8+
9+
Minimal task:
10+
11+
1. A project has Claude settings in `.claude/settings.json` or
12+
`.claude/settings.local.json`.
13+
2. The user runs `mcp-repl install --client claude`.
14+
3. The generated MCP config starts `mcp-repl` in a Claude-inherit mode.
15+
4. The server reads the effective Claude sandbox shape for the active project.
16+
5. The worker uses the corresponding `mcp-repl` sandbox and managed-network
17+
policy, or fails closed when the shape cannot be represented safely.
18+
19+
## Current Shape
20+
21+
- Claude install currently writes `.claude.json` MCP server entries and updates
22+
`.claude/settings.json` permissions so Claude can call the generated tools.
23+
- Claude install uses an explicit `mcp-repl` sandbox mode because Claude does
24+
not send Codex-style per-tool-call sandbox metadata to MCP servers.
25+
- Claude's public settings shape is JSON, not TOML. Project settings live under
26+
`.claude/settings.json` and `.claude/settings.local.json`, and sandbox options
27+
are nested under `sandbox`.
28+
- Claude sandbox settings include network-related fields such as local binding
29+
and proxy ports. Filesystem and network intent may also interact with Claude
30+
permission rules.
31+
32+
Reference: <https://docs.claude.com/en/docs/claude-code/settings>
33+
34+
## Notes
35+
36+
- This should be a separate feature from managed-network install defaults.
37+
- Claude's sandbox implementation and documentation are useful prior art for
38+
this feature. Re-inspect the current Claude source or docs when implementing
39+
instead of preserving stale assumptions about settings shape or permission
40+
semantics.
41+
- Decide whether to add a Claude-specific inherit mode, for example
42+
`--sandbox inherit-claude`, or to extend `--sandbox inherit` with a documented
43+
client source.
44+
- Claude inheritance is likely startup/project scoped, not per-tool-call scoped,
45+
unless Claude later sends sandbox metadata with MCP tool calls.
46+
- Do not silently broaden permissions. If the Claude settings shape cannot be
47+
mapped to `mcp-repl` sandbox state, fail closed or require explicit
48+
`mcp-repl` config.
49+
- Preserve Claude settings precedence. If implementation reads settings files
50+
directly, it needs a tested merge order for user, project, local project, and
51+
managed settings, or it needs to consume an already-resolved Claude-provided
52+
shape.
53+
- Keep the first slice small. A reasonable first pass could map sandbox enabled
54+
state, local binding, and managed proxy ports before attempting full
55+
permission-rule parity.
56+
57+
## Acceptance Shape
58+
59+
- Add fixture tests for representative Claude settings files.
60+
- Add an install test showing `mcp-repl install --client claude` can write the
61+
selected Claude-inherit mode.
62+
- Add a sandbox test proving unsupported or broader-than-representable Claude
63+
settings fail closed.
64+
- Add a runtime smoke test showing a supported Claude sandbox setting affects
65+
the worker sandbox as expected.
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Claude Session Lifecycle And Integration
2+
3+
## Motivation
4+
5+
`mcp-repl` should behave predictably in Claude Code even though Claude does not
6+
currently expose all client lifecycle events or agent identities through MCP.
7+
The important workflows are session reset on `/clear`, reliable install/tool
8+
visibility, and clear documentation of shared-session behavior for subagents.
9+
10+
## Target Scenarios
11+
12+
### `/clear` Resets The Runtime
13+
14+
Minimal task:
15+
16+
1. A user starts Claude Code with `mcp-repl` installed.
17+
2. The agent creates runtime state through the `repl` tool.
18+
3. The user runs `/clear` in Claude Code.
19+
4. The next `repl` call uses a fresh worker session.
20+
21+
MCP does not define a `/clear` notification, and Claude does not currently send
22+
one to MCP servers. A Claude-specific implementation would need to use Claude
23+
hooks:
24+
25+
- a `SessionStart` hook injects the Claude session ID into the environment,
26+
- `mcp-repl` records the active REPL control endpoint for that session ID,
27+
- a `SessionEnd` hook looks up that endpoint and asks `mcp-repl` to restart the
28+
worker externally.
29+
30+
Codex already closes and restarts MCP connections on `/clear`, so this is a
31+
Claude-specific lifecycle bridge rather than a general MCP requirement.
32+
33+
### Claude Subagents Share A REPL Session
34+
35+
Current Claude subagents share the same MCP connection as the main agent. Since
36+
`mcp-repl` owns one long-lived runtime per MCP server connection, those subagents
37+
also share the same REPL session.
38+
39+
There is no clean server-side fix under the current Claude MCP shape. Tool calls
40+
do not include a stable agent or subagent ID. `toolUseId` might be correlated by
41+
polling Claude transcript files, but that would be brittle and should not be
42+
implemented as the happy path.
43+
44+
If Claude later sends a stable agent identity on MCP tool calls, revisit
45+
per-agent worker routing. Until then, document the shared session in installer
46+
output, the plugin skill, or Claude-specific guidance.
47+
48+
### Install And Protocol Drift Stay Covered
49+
50+
Minimal task:
51+
52+
1. A user runs `mcp-repl install --client claude`.
53+
2. A fresh Claude Code session shows the installed R and Python tools.
54+
3. A one-call smoke test succeeds for each installed interpreter.
55+
4. A raw MCP `initialize` request with normal JSON-RPC shape succeeds.
56+
57+
The March 2026 install regression and initialize-handshake bug were both caused
58+
by client/protocol drift not being covered by the same integration surface as
59+
Codex. Future changes to install code, server initialization, and tool
60+
description registration should include Claude coverage when practical.
61+
62+
### Claude Permission Snippets Stay Current
63+
64+
Claude Code permission syntax can change independently of `mcp-repl`. Generated
65+
or documented Claude permission snippets should avoid known-deprecated patterns
66+
such as the old `:*` suffix and should be checked against the current Claude
67+
syntax when touched.
68+
69+
## Current Public Reset Surface
70+
71+
- `repl_reset` explicitly restarts the runtime.
72+
- `\u0003` interrupts the current runtime request.
73+
- `\u0004` resets the runtime and runs any remaining input in the fresh
74+
session.
75+
- `q()` or EOF exits the runtime; the next request starts a fresh worker.
76+
- Claude's `/mcp reconnect` exists as a user command, but there is no known
77+
programmatic hook for an MCP server to trigger it.
78+
79+
## Constraints
80+
81+
- Do not depend on MCP behavior that is not in the spec unless the feature is
82+
clearly Claude-specific and tested as such.
83+
- Do not implement transcript polling to infer subagent identity.
84+
- Do not broaden sandbox or network policy as part of lifecycle handling.
85+
- Keep the runtime reset action server-owned. Hook scripts should only signal
86+
the already-running `mcp-repl` instance.
87+
88+
## Acceptance Shape
89+
90+
- Add install tests or smoke coverage showing Claude config generation still
91+
exposes the expected tools.
92+
- Add a protocol test for the raw `initialize` request shape that previously
93+
failed.
94+
- If `/clear` support is implemented, add hook fixture tests and a manual smoke
95+
scenario for Claude Code.
96+
- Add skill or installer text that states Claude subagents share one REPL
97+
session under the current client behavior.
98+
99+
## Non-Goals
100+
101+
- Per-subagent REPL sessions for Claude before Claude exposes stable agent IDs.
102+
- A generic MCP `/clear` protocol extension.
103+
- Programmatically driving Claude's `/mcp reconnect` command from `mcp-repl`.

docs/futurework/external-mcp-console-config.md

Lines changed: 0 additions & 43 deletions
This file was deleted.

docs/futurework/managed-network-follow-up.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ The important future tasks are:
2020
- Let the runtime call an explicitly allowed local service, such as a local API
2121
used by tests or examples, without also allowing arbitrary remote network
2222
access.
23+
- Support a restricted read-only web/data-fetching shape where the runtime can
24+
perform HTTP GET requests to allowed hosts but cannot make state-changing
25+
requests such as POST.
2326

2427
This note is not a final design. It records the target scenarios, current
2528
constraints, and implementation tradeoffs so the next slice can choose an
@@ -84,6 +87,24 @@ Minimal task:
8487
This needs explicit loopback connect permission. It is separate from Shiny app
8588
iteration, where the worker binds a port and a browser tool connects to it.
8689

90+
### GET-Only Web Access
91+
92+
Minimal task:
93+
94+
1. Start `mcp-repl` with a policy that allows HTTP(S) access to a specific host
95+
for read-only retrieval.
96+
2. The agent asks the runtime to download or inspect a public data resource.
97+
3. GET requests to the allowed host succeed.
98+
4. POST, PUT, DELETE, and other non-GET methods fail closed.
99+
5. Requests to unrelated hosts still fail closed.
100+
101+
This is a distinct policy from domain allowlisting. For plain HTTP proxy
102+
requests, the proxy can see and enforce the method. For ordinary HTTPS
103+
`CONNECT`, the proxy sees only the tunnel endpoint, not the inner HTTP method.
104+
Enforcing GET-only semantics for HTTPS would require TLS interception,
105+
package/client-specific integration, a controlled mirror, or another design
106+
that makes request methods visible.
107+
87108
## Current Shape
88109

89110
- The server starts a server-owned HTTP/SOCKS proxy when domain allow/deny rules
@@ -138,6 +159,9 @@ Open boundaries found during the same investigation:
138159
- Managed package/web access, explicit TCP connect, and local app serving are
139160
different capabilities. They may need different policy fields and different
140161
enforcement paths.
162+
- HTTP method restrictions, such as GET-only web access, are a separate
163+
capability from host/domain allowlisting. Do not imply method-level
164+
enforcement for HTTPS until the implementation can actually see the method.
141165
- Tools that honor proxy environment variables should work transparently.
142166
Tools that ignore them must still be constrained by the OS sandbox.
143167
- Local database connect does not imply local app bind. Local app bind does not
@@ -232,6 +256,8 @@ These are implementation options, not a prescribed roadmap.
232256
example `db.example.com:5432`.
233257
- Split local loopback connect from local loopback bind/inbound permissions, so
234258
database workflows and Shiny workflows can be enabled independently.
259+
- Add GET-only enforcement for visible HTTP proxy requests, with HTTPS support
260+
deferred until there is a concrete TLS-visibility or controlled-mirror design.
235261
- Restrict HTTP `CONNECT` to package-repository-shaped traffic, such as port
236262
443 by default, unless an explicit TCP policy grants a different port.
237263
- Add TLS ClientHello SNI validation for `CONNECT` to reduce host/SNI mismatch
@@ -251,6 +277,7 @@ Choose the next design by starting from one concrete task. Good first slices are
251277
- explicit TCP connect for one database endpoint,
252278
- explicit loopback bind/inbound for Shiny app iteration,
253279
- explicit loopback connect for one local service endpoint,
280+
- GET-only enforcement for plain HTTP plus a documented HTTPS limitation,
254281
- TLS SNI gating for the existing package-repository proxy path.
255282

256283
Each slice should include a minimal end-to-end scenario that proves the intended

0 commit comments

Comments
 (0)