docs(spec): embedded agent — a chat pane backed by a DeepAgents agent - #33
Conversation
Adds specs/embedded-agent/{requirements,design,tasks}.md for a chat pane in
the desktop application, backed by a DeepAgents agent that reads the open
project the way a harness does and writes the wiki only through the
validated store. Enabled by adr:0019.
v1, decided at kickoff: read + write (consultation + maintenance), Groq
only (the existing credential's second purpose), execute and task
excluded (the former can't be scope-guarded; the latter is dangerous by
adr:0019), and every wiki write paused for human approve/reject/edit
before it lands. The convention (harness entry file + scaffolded skills)
is carried in unchanged.
scc validate: no findings.
Co-Authored-By: Claude <noreply@anthropic.com>
…ty-review)
Address findings from the code-review and security-review subagents on the
embedded-agent spec (the first commit). Verified against the deepagents@1.12.1
source and the @open-wiki/access API.
code-review (compile-blocking + factual):
- Origin is a string union, not { kind: "agent" }; extend it with "agent" and
write origin: "agent" at every call site (task 1.7, 1.4, R4.5).
- createDeepAgent's `tools` takes tool objects, not a string allowlist; drop
tools: ["read_file",...] and pass rename_page/delete_page as tool objects.
The fs tools auto-attach from the harness profile (task 2.1).
- "No subagents" does not disable task; createDeepAgent auto-adds a
general-purpose subagent. Register a Groq harness profile with
generalPurposeSubagent.enabled=false so task is never built; execute is
hidden by the non-sandbox backend (task 2.4, R4.4).
- No gated deletePage exists in @open-wiki/access (the desktop's calls node:fs
with a hardcoded origin); spec a new gated delete primitive, and make
rename_page refuse clobber + NON_ENTITY_PAGES (R4.2, R4.6, tasks 1.8, 2.3).
- BackendProtocol is the deprecated v1 alias; implement BackendProtocolV2.
security-review (design gaps, now stated + proved):
- replace_all interrupt shows every match site / full resulting page (R5.2, 6.9).
- The middleware's large-result eviction calls the SAME WikiGateBackend.write to
/large_tool_results/ and /conversation_history/, both outside wiki/, so the
gate rejects it — fail-closed, no disk write (6.11).
- rename/delete refuse clobber + the wiki index, changelog, and log (R4.6, 6.10).
- Risk: the system prompt itself is project-controlled for an untrusted project.
- Risk: NON_ENTITY_PAGES are gated only by human approval.
- Tracing exfiltration: disable tracing before construction (set
LANGCHAIN_TRACING_V2=false), read no LANGCHAIN_*/LANGSMITH_* env var, so
library-level LangSmith auto-init does not fire (R2.6, 2.8, 6.12).
- Prove interrupt fires before any store write (6.8); prove a junction/symlink
read escape is denied (6.6).
scc validate: no findings. Both re-reviews returned clean.
Co-Authored-By: Claude <noreply@anthropic.com>
📝 WalkthroughWalkthroughThe PR adds design, requirements, and implementation tasks for an embedded DeepAgents chat agent in the Electron desktop app. It defines Groq integration, project-confined wiki access, approval-gated writes, IPC streaming, in-memory state, and renderer chat behavior. ChangesEmbedded agent
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 12
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@specs/embedded-agent/design.md`:
- Around line 47-55: Update the agent construction flow around createDeepAgent
so systemPrompt and skills bootstrap paths are resolved beneath projectRoot
using assertWithin and real-path validation before any file reads. Reject
symlink or junction targets that resolve outside projectRoot, and only pass
validated content or paths to the agent and Groq.
- Around line 183-186: Update the reserved-page protection described by R4.6 so
agent mutation tools reject the wiki index, changelog, and log for write and
edit operations as well as rename and delete; ensure gateWrite or the shared
mutation guard does not bypass these paths through NON_ENTITY_PAGES, and add
coverage for write_file and edit_file alongside the existing rename/delete
tests.
- Around line 198-200: Update the interrupt approval flow described in the
design to store the page content hash or version with each approved effect, then
revalidate it immediately before applying the write. If the current page no
longer matches, reject the stale old_string or replace_all operation and return
a fresh proposal instead of writing.
- Around line 55-56: Update the embedded-agent design around the IPC payload
definitions and project-window lifecycle to establish stable conversation
identity: include thread_id and run_id in every request and event, define an
interrupt identifier and associate decisions with it, and scope one
agent/checkpointer pair (including MemorySaver) to each project window. Add
discriminated schemas for token, tool, interrupt, error, and done events,
including rename/delete fields and replace_all match sites.
- Around line 25-31: Update task 1.5 and the surrounding edit_file design to
define exact-string replacement as a logical edit: preserve all content outside
matched replacements, then commit the resulting full page through writePage and
atomicWrite. Remove the assertion that edit_file never rewrites the whole page;
only introduce an atomic partial-update primitive if the design requires
avoiding full-page writes.
- Around line 127-135: Update the access-layer rename/delete primitive around
deletePage and rename_page to perform a single atomic operation: snapshot every
affected page, execute all writes or removal/supersession changes, record
exactly one operation, and restore the snapshot on failure. Do not compose
writePage and supersedePage as separate operations; explicitly define and
implement deletion’s visibility and undo behavior while preserving protection
for NON_ENTITY_PAGES and deterministic target handling.
- Around line 12-23: Update the BackendProtocolV2 design description for
WikiGateBackend to include the required readRaw(filePath) method, returning
ReadRawResult and confining the path with assertWithin(projectRoot). Keep
downloadFiles and uploadFiles optional; if uploadFiles is documented, require
each upload to use gateWrite and pass decision.content to writePage.
- Around line 74-80: Ensure all LangSmith/LangChain tracing flags are set to
false before importing DeepAgents, LangChain, or LangGraph dependencies: update
startup initialization to cover LANGSMITH_TRACING, LANGSMITH_TRACING_V2,
LANGCHAIN_TRACING, and LANGCHAIN_TRACING_V2, or lazy-load the agent dependencies
only after this environment setup. Add coverage for globally enabled flags and
import order, verifying no tracing clients or requests are created.
- Around line 60-68: Update the module-load harness registration to call
registerHarnessProfile with the Groq key as its first argument and the existing
createHarnessProfile configuration disabling generalPurposeSubagent. Do not add
excludedTools for execute; retain the current FilesystemMiddleware behavior for
WikiGateBackend.
In `@specs/embedded-agent/requirements.md`:
- Around line 8-10: Update the ADR reference paragraph to replace the
grammatically incomplete sentence with wording that explicitly says the record’s
“Consequences” section calls for this spec first.
- Around line 42-47: Update R2.3 to define deterministic selection when multiple
harness entry files exist: resolve the entry file from scaffold metadata or the
active harness, and reject ambiguous projects before constructing the embedded
agent. Preserve the requirement to carry the selected scaffolded instructions
unchanged without adding a hand-written system prompt.
In `@specs/embedded-agent/tasks.md`:
- Line 21: Update task 2.6 to call agent.streamEvents with the run input as the
first argument and the version options object as the second argument:
streamEvents(input, { version: "v3" }).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 060908d8-3bbf-4c57-b985-d92419ac178a
📒 Files selected for processing (3)
specs/embedded-agent/design.mdspecs/embedded-agent/requirements.mdspecs/embedded-agent/tasks.md
| - **The wiki's index, changelog, and log are `NON_ENTITY_PAGES`.** `gateWrite` passes them | ||
| with no content validation — they are "themselves." An agent `write_file` to `wiki/index.md` | ||
| is therefore gated only by human approval, not by the gate's form checks. R4.6 keeps the | ||
| agent from deleting or renaming them; overwriting them by edit remains a human call. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Block all agent mutations of reserved pages.
R4.6 protects the index, changelog, and log only for rename and delete. The design explicitly permits write_file and edit_file to overwrite them after approval because gateWrite skips validation for NON_ENTITY_PAGES.
Reject these paths in all agent mutation tools, or explicitly narrow the reserved-file protection objective. Add tests for write and edit, not only rename and delete.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@specs/embedded-agent/design.md` around lines 183 - 186, Update the
reserved-page protection described by R4.6 so agent mutation tools reject the
wiki index, changelog, and log for write and edit operations as well as rename
and delete; ensure gateWrite or the shared mutation guard does not bypass these
paths through NON_ENTITY_PAGES, and add coverage for write_file and edit_file
alongside the existing rename/delete tests.
Fold in the substantive findings from the CodeRabbit review on PR #33. Verified the factual claims against the deepagents@1.12.1 source before writing them in; skipped the ones already correct. - readRaw is required on BackendProtocolV2 (edit is inherited from v1, delete is optional). Add WikiGateBackend.readRaw, confined with assertWithin (R3.1/R3.2, task 1.9). The backend implements ls/read/readRaw/write/edit/glob/grep; delete is not implemented. - edit_file is a logical replacement, not a partial write: read the page, apply the exact-string replace, write the full resulting page atomically through writePage — the gate validates the whole new page, not the diff. - registerHarnessProfile takes (key, profile); fix the call to registerHarnessProfile("groq", createHarnessProfile({ generalPurposeSubagent: { enabled: false } })) — the first arg is the provider key createDeepAgent resolves for the model (task 2.4). - streamEvents(input, {version:"v3"}) takes input first; restore the input arg dropped in task 2.6 (the design already had it right). - Confine the harness entry file (system prompt) read with assertWithin + real-path check in main; skills load through the backend's read_file. - Tracing disabled before the agent's dependencies are imported (start of main), not just before construction — LangChain auto-inits at import (R2.6, task 2.8). - Atomic rename/delete: new renamePage/deletePage primitives are single operations (snapshot, gate+write, one log entry, rollback on failure); deletion is supersession; no half-applied rename. - TOCTOU on approval: the interrupt stores a content hash; on resume the backend revalidates the page and re-interrupts with a fresh proposal if another writer changed it (R5.5, task 6.14). - Stable conversation identity + discriminated event schemas: IPC carries thread_id/run_id/interrupt_id; a resume references the interrupt_id; one MemorySaver per project window; events discriminated by kind (R7.2, task 3.1). - Deterministic harness-entry selection: resolve from scaffold metadata or the active harness, reject ambiguity before construction (R2.3). - Narrow R4.6's scope explicitly: reserved-page protection covers rename/delete (structural); content edits to index/changelog/log remain a human-approved agent capability — maintaining them is the agent's job. - Minor: fix the ADR reference sentence in requirements.md. scc validate: no findings. CI was green before this push. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@specs/embedded-agent/design.md`:
- Around line 130-138: Update the IPC contract around OwBridge and the chat
handlers so chat:resume and chat:cancel carry project/window identity, and
define validation that run_id, interrupt_id, and thread_id resolve only within
the originating project window. Reject cross-window or cross-project
identifiers, and dispose the project-scoped agent and MemorySaver when a project
window closes or switches projects.
- Around line 160-168: Update the resume commit flow for approved decisions to
pass the stored page hash or version into the access-layer write primitive,
which must atomically compare it before applying the edit. Remove reliance on a
separate validation-then-write sequence, and re-interrupt with a fresh proposal
when the compare-and-swap fails.
- Around line 13-25: Update the BackendProtocolV2 documentation around
WikiGateBackend to state the exact result contracts: ls, read, readRaw, grep,
and glob return LsResult, ReadResult, ReadRawResult, GrepResult, and GlobResult;
write and edit return WriteResult and EditResult, with failures using error and
successful edits including occurrences, without V1-style strings or arrays. Add
and pin the required deepagents dependency in the repository’s dependency
manifest.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: e1fac712-6d61-4a26-a439-5868f3cc3a27
📒 Files selected for processing (3)
specs/embedded-agent/design.mdspecs/embedded-agent/requirements.mdspecs/embedded-agent/tasks.md
🚧 Files skipped from review as they are similar to previous changes (2)
- specs/embedded-agent/tasks.md
- specs/embedded-agent/requirements.md
| `apps/desktop/src/main/agent/wiki-gate-backend.ts`. It implements `BackendProtocolV2`: | ||
| `ls`, `read`, `readRaw`, `write`, `glob`, and `grep` (required) and `edit` (inherited from | ||
| the v1 protocol); `delete` is optional and is not implemented (the custom `delete_page` | ||
| tool uses the access primitive below, not `backend.delete`). (The bare `BackendProtocol` | ||
| export is the deprecated v1 alias; `WikiGateBackend` implements v2.) Reads | ||
| (`ls`/`read`/`readRaw`/`glob`/`grep`) operate on the real project directory, every path | ||
| confined with `assertWithin(projectRoot)` from `@open-wiki/access`. Writes (`write`/`edit`) | ||
| accept only paths that resolve inside `<projectRoot>/wiki/` and route them through the | ||
| store: `gateWrite` to validate, then `writePage(projectRoot, pagePath, content, "agent")` to | ||
| write atomically, log the operation with origin `agent`, and leave it undoable. `edit` is a | ||
| logical replacement, not a partial write: the backend reads the page, applies the | ||
| exact-string replacement (`replace_all` supported), and writes the full resulting page | ||
| atomically through `writePage` — the gate validates the whole new page, not the diff. A |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/sh
set -eu
pnpm why deepagents
deepagents_root="$(pnpm root -w)/deepagents"
rg -n -C 8 \
'BackendProtocolV2|ReadResult|ReadRawResult|GrepResult|LsResult|GlobResult|WriteResult|EditResult' \
"$deepagents_root"Repository: protonspy/open-wiki
Length of output: 1352
🏁 Script executed:
#!/bin/sh
set -eu
printf '%s\n' '--- package declarations and lock entries ---'
rg -n -C 3 '"deepagents"|deepagents@|BackendProtocolV2' \
--glob 'package.json' \
--glob 'pnpm-lock.yaml' \
--glob 'yarn.lock' \
--glob 'package-lock.json' \
--glob 'npm-shrinkwrap.json' \
.
printf '%s\n' '--- repository files related to dependency metadata ---'
git ls-files | rg '(^|/)(package\.json|pnpm-lock\.yaml|yarn\.lock|package-lock\.json|npm-shrinkwrap\.json)$'
printf '%s\n' '--- design section ---'
cat -n specs/embedded-agent/design.md | sed -n '1,70p'Repository: protonspy/open-wiki
Length of output: 203
🌐 Web query:
DeepAgents JavaScript BackendProtocolV2 LsResult ReadResult ReadRawResult GrepResult GlobResult WriteResult EditResult
💡 Result:
BackendProtocolV2 is the current, updated protocol for pluggable memory backends in the JavaScript deepagents library, replacing the deprecated v1 protocol [1][2]. Its primary design shift is the introduction of structured result types for all operations, ensuring consistent error handling through an error field instead of throwing exceptions or returning raw values [1][3]. The result types associated with this protocol include: LsResult: Returned by the ls method, containing a list of FileInfo objects on success or an error on failure [3][4][5]. ReadResult: Returned by read, this provides paginated text content or raw Uint8Array content for binary files, along with an optional MIME type [1][3][4]. ReadRawResult: Returned by readRaw, this provides the raw FileData for a file [1][3][4]. GrepResult: Returned by grep, containing an array of GrepMatch objects on success [1][3][4]. GlobResult: Returned by glob, providing a list of FileInfo objects that match the specified glob pattern [1][3][4]. WriteResult: Returned by write, containing the path of the written file and any associated state updates (e.g., for checkpoint backends) [3][4][5]. EditResult: Returned by edit, containing the path of the edited file, the number of occurrences replaced, and associated state updates [3][4][5]. Existing v1 backends can be adapted to the BackendProtocolV2 interface using the adaptBackendProtocol utility, which wraps v1 return values into these structured result types [6][1][7].
Citations:
- 1: https://docs.langchain.com/oss/javascript/releases/changelog
- 2: https://github.com/langchain-ai/deepagentsjs/blob/main/libs/deepagents/src/backends/protocol.ts
- 3: https://docs.langchain.com/oss/javascript/deepagents/backends
- 4: https://github.com/langchain-ai/deepagentsjs/blob/ab85866549067fb9a6e93b90c543390916748c7b/libs/deepagents/src/backends/protocol.ts
- 5: https://github.com/langchain-ai/deepagentsjs/blob/0c7da26b5d552cf53ab0eb90fb151ba19ad62767/libs/deepagents/src/backends/protocol.ts
- 6: https://reference.langchain.com/javascript/deepagents/browser/adaptBackendProtocol
- 7: https://reference.langchain.com/javascript/deepagents/backends/adaptBackendProtocol
🏁 Script executed:
#!/bin/sh
set -u
printf '%s\n' '--- tracked dependency manifests ---'
git ls-files | rg '(^|/)(package\.json|pnpm-lock\.yaml|yarn\.lock|package-lock\.json|npm-shrinkwrap\.json)$' || true
printf '%s\n' '--- deepagents references in tracked files ---'
git grep -n -i -C 3 'deepagents' -- \
'*.json' '*.yaml' '*.yml' '*.lock' '*.ts' '*.tsx' '*.js' '*.md' 2>/dev/null || true
printf '%s\n' '--- design section ---'
cat -n specs/embedded-agent/design.md | sed -n '1,70p'Repository: protonspy/open-wiki
Length of output: 15076
🏁 Script executed:
#!/bin/sh
set -u
printf '%s\n' '--- root package.json ---'
cat -n package.json | sed -n '1,220p'
printf '%s\n' '--- desktop package.json ---'
cat -n apps/desktop/package.json | sed -n '1,260p'
printf '%s\n' '--- lockfile header and dependency importers ---'
cat -n pnpm-lock.yaml | sed -n '1,180p'
printf '%s\n' '--- exact protocol source for the declared ADR version ---'
curl -L --fail --silent --show-error \
https://raw.githubusercontent.com/langchain-ai/deepagentsjs/v1.12.1/libs/deepagents/src/backends/protocol.ts \
| sed -n '1,280p'Repository: protonspy/open-wiki
Length of output: 10942
🏁 Script executed:
#!/bin/sh
set -u
printf '%s\n' '--- deepagents release metadata ---'
curl -L --fail --silent --show-error \
https://registry.npmjs.org/deepagents/1.12.1 \
| python3 -c 'import json,sys; d=json.load(sys.stdin); print(json.dumps({k:d.get(k) for k in ("name","version","dist")}, indent=2))' || true
printf '%s\n' '--- repository tags matching 1.12.1 ---'
curl -L --fail --silent --show-error \
'https://api.github.com/repos/langchain-ai/deepagentsjs/tags?per_page=100' \
| python3 -c 'import json,sys; tags=json.load(sys.stdin); print("\n".join(t["name"] for t in tags if "1.12.1" in t["name"]))' || true
printf '%s\n' '--- current protocol source ---'
curl -L --fail --silent --show-error \
https://raw.githubusercontent.com/langchain-ai/deepagentsjs/main/libs/deepagents/src/backends/protocol.ts \
| sed -n '1,320p' || trueRepository: protonspy/open-wiki
Length of output: 11370
🌐 Web query:
site:github.com/langchain-ai/deepagentsjs "BackendProtocolV2" "WriteResult" "EditResult" "1.12.1"
💡 Result:
BackendProtocolV2, WriteResult, and EditResult are components of the deepagentsjs library, specifically within its backend protocol system [1][2][3]. BackendProtocolV2 is an interface that defines the contract for pluggable memory backends, providing structured access to file system operations [3][4]. It succeeds the original BackendProtocol (often referred to as V1) by introducing typed results for operations such as reading, searching, and listing files [3][4]. WriteResult and EditResult define the return structures for file modification operations within these backends [1]: WriteResult represents the outcome of a write operation [1]. It includes: - error: An optional error message if the operation failed [1]. - path: The path of the written file [1]. - filesUpdate: An optional state update dictionary used by checkpoint backends, or null for external storage [1]. - metadata: Optional metadata attached to the operation [1]. EditResult represents the outcome of an edit operation [1]. It includes: - error: An optional error message if the operation failed [1]. - path: The path of the edited file [1]. - filesUpdate: An optional state update dictionary [1]. - occurrences: The number of replacements made [1]. - metadata: Optional metadata attached to the operation [1]. These interfaces are used in implementations such as the CompositeBackend, which routes file operations to the appropriate underlying backend based on the file path [5].
Citations:
- 1: https://github.com/langchain-ai/deepagentsjs/blob/main/libs/deepagents/src/backends/protocol.ts
- 2: https://github.com/langchain-ai/deepagentsjs/blob/2442d7d0/libs/deepagents/src/backends/index.ts
- 3: https://github.com/langchain-ai/deepagentsjs/blob/ab85866549067fb9a6e93b90c543390916748c7b/libs/deepagents/src/backends/v2/protocol.ts
- 4: https://github.com/langchain-ai/deepagentsjs/blob/2442d7d0/libs/deepagents/src/backends/v2/protocol.ts
- 5: https://github.com/langchain-ai/deepagentsjs/blob/main/libs/deepagents/src/backends/composite.ts
🏁 Script executed:
#!/bin/sh
set -u
printf '%s\n' '--- current V2 protocol declarations ---'
curl -L --fail --silent --show-error \
https://raw.githubusercontent.com/langchain-ai/deepagentsjs/main/libs/deepagents/src/backends/v2/protocol.ts \
| sed -n '1,300p' || true
printf '%s\n' '--- version 1.12.1 package listing ---'
curl -L --fail --silent --show-error \
https://unpkg.com/deepagents@1.12.1/ \
| sed -n '1,180p' || trueRepository: protonspy/open-wiki
Length of output: 20280
🏁 Script executed:
#!/bin/sh
set -u
printf '%s\n' '--- current V1 protocol declarations inherited by V2 ---'
curl -L --fail --silent --show-error \
https://raw.githubusercontent.com/langchain-ai/deepagentsjs/main/libs/deepagents/src/backends/v1/protocol.ts \
| sed -n '1,280p'
printf '%s\n' '--- version 1.12.1 package metadata and exports ---'
curl -L --fail --silent --show-error \
https://unpkg.com/deepagents@1.12.1/package.json \
| python3 -c 'import json,sys; d=json.load(sys.stdin); print(json.dumps({k:d.get(k) for k in ("version","main","module","types","exports")}, indent=2))'Repository: protonspy/open-wiki
Length of output: 6348
Document the BackendProtocolV2 result contracts and pin deepagents.
The repository currently has no deepagents dependency or pin. Add the dependency, then specify that ls, read, readRaw, grep, and glob return LsResult, ReadResult, ReadRawResult, GrepResult, and GlobResult. Specify that write and edit return WriteResult and EditResult, with failures represented by error and successful edits including occurrences. Do not use V1-shaped strings or arrays.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@specs/embedded-agent/design.md` around lines 13 - 25, Update the
BackendProtocolV2 documentation around WikiGateBackend to state the exact result
contracts: ls, read, readRaw, grep, and glob return LsResult, ReadResult,
ReadRawResult, GrepResult, and GlobResult; write and edit return WriteResult and
EditResult, with failures using error and successful edits including
occurrences, without V1-style strings or arrays. Add and pin the required
deepagents dependency in the repository’s dependency manifest.
| - **IPC contract.** `chat:send({ text, thread_id })`, `chat:resume({ decisions, interrupt_id, | ||
| run_id })`, `chat:cancel({ run_id })`, and push `chat:event({ kind, thread_id, run_id, ... })` | ||
| where `kind` is `token` | `tool` | `interrupt` | `done` | `error`, each carrying the fields | ||
| its kind requires (an `interrupt` carries the tool, file path, old/new content or the full | ||
| resulting page for `replace_all`, or the rename/delete target, plus an `interrupt_id` and a | ||
| content hash of the page at interrupt time; a `tool` event carries the call and its result). | ||
| One `MemorySaver` — and one agent instance — is scoped to the project window, keyed by | ||
| `thread_id`. Typed in `bridge.ts` `OwBridge`; the preload parity check (`preload.ts:104`) and | ||
| `dispatch`'s unknown-channel throw (`ipc.ts`) enforce completeness. |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major
Bind IPC identities to the owning project window.
chat:send carries thread_id, but chat:resume and chat:cancel do not. The design also does not define how run_id and interrupt_id are bound to a projectRoot and originating window. Require window-scoped routing, reject cross-window identifiers, and dispose the project-scoped agent and MemorySaver when the window closes or changes projects. This prevents cross-project resume/cancel operations and stale conversation retention.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@specs/embedded-agent/design.md` around lines 130 - 138, Update the IPC
contract around OwBridge and the chat handlers so chat:resume and chat:cancel
carry project/window identity, and define validation that run_id, interrupt_id,
and thread_id resolve only within the originating project window. Reject
cross-window or cross-project identifiers, and dispose the project-scoped agent
and MemorySaver when a project window closes or switches projects.
| - **Interrupt payload** — the proposed write: `{ tool, file_path, old_string?, new_string?, | ||
| content? }`, rendered as a diff in the pane, plus a content hash of the page at interrupt | ||
| time. For `edit_file` with `replace_all`, the payload carries every match site (or the full | ||
| resulting page), so the human sees the complete effect of the tool call, not only the two | ||
| strings — a short `old_string` that matches in several places must not be smuggled past | ||
| review. Resume carries `decisions: [{ type: "approve" | "reject" | "edit", ... }]` and the | ||
| `interrupt_id` it answers. On resume the backend revalidates the page against the stored | ||
| hash; if another writer changed it in the window between interrupt and resume, the stale | ||
| edit is not applied — the run re-interrupts with a fresh proposal (R5.5). |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Make approval validation and commit atomic.
The design rechecks the page hash and then applies the edit. Another writer can change the page after the check and before writePage, so the approved edit can still overwrite newer content. Pass the expected hash or version into the access-layer mutation primitive and perform a compare-and-swap with the write. Re-interrupt when that atomic check fails.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@specs/embedded-agent/design.md` around lines 160 - 168, Update the resume
commit flow for approved decisions to pass the stored page hash or version into
the access-layer write primitive, which must atomically compare it before
applying the edit. Remove reliance on a separate validation-then-write sequence,
and re-interrupt with a fresh proposal when the compare-and-swap fails.
@-
Summary by CodeRabbit