Skip to content

feat: add Bob Shell adapter package - #6518

Open
danijel-soldo wants to merge 19 commits into
paperclipai:masterfrom
danijel-soldo:pr/bob-shell-adapter
Open

feat: add Bob Shell adapter package#6518
danijel-soldo wants to merge 19 commits into
paperclipai:masterfrom
danijel-soldo:pr/bob-shell-adapter

Conversation

@danijel-soldo

Copy link
Copy Markdown

Thinking Path

  • Bob Shell is the shell/CLI build of IBM's "Bob" coding agent — same underlying agent, exposed as a local command-line runtime suitable for orchestration by a control plane like Paperclip
  • Paperclip orchestrates AI agents and adapters decouple the control plane from any single coding-agent runtime
  • Built-in adapters today (master): Claude, Codex, Cursor (local + cloud), Gemini, Grok, OpenCode, Pi, ACPX, OpenClaw Gateway, Hermes — none for Bob Shell
  • Operators on Bob Shell currently maintain a long-running fork to use it, which drifts and blocks them from upstream releases
  • Adding bob_shell as a built-in mirrors the upstream pattern (Claude/Codex/Hermes are all built-in adapter packages registered in
    server/src/adapters/registry.ts) and removes that fork-maintenance pain
  • This PR lands the adapter as a new package @paperclipai/adapter-bob-shell and registers it in the server + UI registries
  • Benefit: parity with other CLI agents, IBM Bob users no longer need to fork, 127/127 passing tests in 0.6s, zero changes to non-bob-shell code paths

Coordination note:
No prior #dev thread — happy to pause this PR for coordination if maintainers prefer. Opening it now to make the implementation concrete and reviewable rather than describing it abstractly. The adapter is structurally identical to the existing built-in adapters and the diff is fully scoped to its own package, so the review surface is small even though the line count is large.

What Changed

  • New package packages/adapters/bob-shell/ (22 source files, 9 modules + 6 test files, ~6.5k LoC) — server execute, workspace sync, prompt cache, JSON-stream + stdout parsers, error detection + classification, retry strategy, runtime config, session management, UI selector, and 127 unit tests
  • Registry hook-up — one new entry each in server/src/adapters/registry.ts, server/src/adapters/builtin-adapter-types.ts, ui/src/adapters/registry.ts;new workspace dep in server/package.json
  • UI configui/src/adapters/bob-shell/{index.ts,config-fields.tsx} for the agent settings panel
  • Role-aware defaults — agent role auto-maps to Bob Shell mode + tool groups (engineer → read,edit,command,mcp; CEO/CTO/COO/VP → read,command,mcp; manager/CMO/CFO → read,mcp`)
  • Setup guide at packages/adapters/bob-shell/docs/SETUP.md, linked from the package README
  • .gitignore adds ._* (macOS resource-fork hygiene; cleanup from cherry-pick noise)

Total diff: 38 files, +6813 / −88, all bob-shell-scoped. No existing adapter code is modified.

Verification

pnpm install
pnpm --filter @paperclipai/adapter-bob-shell build      # tsc clean
pnpm --filter @paperclipai/adapter-bob-shell test       # 127/127 pass in ~0.6s
pnpm --filter @paperclipai/server typecheck             # tsc --noEmit clean

End-to-end smoke (set BOBSHELL_API_KEY, ensure bob on PATH): UI → Agents → New Agent → adapter Bob ShellTest Environment → green. Full setup steps in packages/adapters/bob-shell/docs/SETUP.md.

Risks

  • Low risk for non-bob-shell users. All existing adapters are unchanged; the registry change is purely additive (new entry in BUILTIN_ADAPTER_TYPES and a new module registration).
  • Bob Shell binary required at runtime. Adapter expects bob on PATH (or absolute path in agent config). Missing → clear error in Test Environment. No effect on other adapters.
  • Workspace footprint. Adapter writes a .bob/ dir into the agent's working directory at runtime (custom modes, MCP config, role-specific rules). The setup guide documents this and recommends .gitignore-ing it in user projects.
  • Test layout inconsistency. Some tests live under src/server/__tests__/, others as *.test.ts siblings of the source files. Matches the original implementation; happy to normalize in a follow-up if reviewers prefer one layout.
  • Packaging choice — built-in vs external plugin. Lands as a built-in for these reasons:
    • Upstream precedent. Claude, Codex, Cursor, Gemini, Grok, OpenCode, Pi, ACPX, OpenClaw Gateway, and Hermes are all built-in adapter packages registered in server/src/adapters/registry.ts. Hermes in particular has substantially deeper control-plane wiring (auth-token injection, prompt-template patching) and is still built-in on master. Bob Shell's integration is shallower than Hermes's.
    • No internal type coupling. Package depends only on @paperclipai/adapter-utils and @paperclipai/shared — no private server imports. If maintainers prefer the Droid model (external-only), the package is structured to convert without API changes: it already exposes ./server, ./ui, ./cli entrypoints in the same shape Droid uses.
    • Out-of-the-box UX. Built-in means no ~/.paperclip/adapter-plugins.json step for users adopting Bob Shell, matching the experience for every other first-party CLI agent.
    • Open to converting to an external plugin if maintainers want to draw the line differently — explicitly flagging this as a packaging decision for review, not a hidden choice.

Roadmap check: ROADMAP.md has no Bob-Shell-shaped item. Closest entries are "Plugin system" and "OpenClaw / claw-style agent employees" (both done). The "Cloud / Sandbox agents (Cursor / e2b)" item is about remote/sandboxed runtimes, not local CLI agents — distinct from Bob Shell.

Model Used

  • Claude Sonnet 4.5 (claude-sonnet-4-5-20250929), 200k context, extended thinking + tool use — used for cherry-pick strategy across 16 commits, conflict
    resolution in server/src/adapters/registry.ts, dry-run verification against upstream master, and authoring this PR description.
  • Original adapter implementation by @d-soldo with Claude Sonnet 4.6 (1M context) — attribution preserved in commit trailers (Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> on commits 77a41e37, 4fa3c5ff, 13c1a32f, etc.).
  • Optimization and PR preparation with Claude Opus 4.7 (1M context) — operator-attested; not pinned to a public Anthropic model ID at time of writing.

Checklist

  • I have included a thinking path that traces from project context to this change
  • I have specified the model used (with version and capability details)
  • I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work
  • I have run tests locally and they pass (127/127 adapter tests in 0.6s, server typecheck clean)
  • I have added or updated tests where applicable (6 test files, 127 cases covering parsing, caching, error detection, metadata extraction, prompt-cache lifecycle)
  • If this change affects the UI, I have included before/after screenshots — N/A: change is purely additive (new entry in adapter dropdown + new config panel
    for the new adapter); no existing UI surface is modified. Happy to add screenshots if a reviewer asks.
  • I have updated relevant documentation to reflect my changes (package README + SETUP.md)
  • I have considered and documented any risks above (including explicit built-in-vs-plugin rationale)
  • I will address all Greptile and reviewer comments before requesting merge

d-soldo and others added 15 commits May 20, 2026 23:30
Introduces the bob-shell adapter package and wires it into both the
server-side adapter registry and the UI adapter registry.

Touch points:
- packages/adapters/bob-shell/ — full adapter implementation
- server/src/adapters/registry.ts — import, definition, registration
- server/src/adapters/builtin-adapter-types.ts — "bob_shell" in Set
- ui/src/adapters/bob-shell/ — UI config fields and adapter
- ui/src/adapters/registry.ts — import and registration

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Remove macOS hidden files (._*)
- Remove dev-log markdown files (DASHBOARD_STATUS_UPDATES, DEBUG, BOB_SHELL_OUTPUT_FORMAT, MCP_TOOLS_VERIFICATION)
- Remove diagnose-mcp.sh debug script
- Remove dist/ compiled output
- Remove node_modules/
- Remove src/server/test-parse.ts (dev scratch file)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
No corresponding source file exists; dead weight before upstreaming.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The server was importing from @paperclipai/adapter-bob-shell but the
dependency was not declared in server/package.json, causing TypeScript
compilation to fail.

Added @paperclipai/adapter-bob-shell as a workspace dependency to resolve
the build error.
The adapter resolved the correct project workspace cwd but passed
promptBundle.rootDir (a content-addressed cache path) as the execution
cwd to runChildProcess, onMeta, canResumeSession, and buildBobResult.
Bob Shell therefore ran in the isolated cache directory instead of the
actual repository, blocking all code implementation tasks.

Fix: sync .bob/ workspace config into the project cwd before launch,
and use cwd everywhere promptBundle.rootDir was used as execution dir.
The prompt-cache dir retains its role as a stable key for session
bundle validation only.

Build: tsc clean. Tests: 127/127 pass.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Adds agentRole-based defaults for Bob Shell custom modes, tool groups,
and whenToUse descriptions. Roles (ceo, cto, engineer, etc.) now
automatically get appropriate tool group permissions and mode slugs
without requiring explicit config.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The wrappedOnLog handler was emitting a [paperclip] status line on
every stdout chunk, producing hundreds of lines like:
  [paperclip] I've
  [paperclip] I've been
  [paperclip] I've been assigned BOB-26

Now only emits when the summary ends with sentence-ending punctuation
(.!?), indicating Bob has completed the thought.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Avoids token-by-token log spam by gating stderr summary logging on
sentence-ending punctuation.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Step-by-step guide covering clone, build, Bob API key config, agent
creation, role-to-tool-group mapping, and troubleshooting.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Rename ANTHROPIC_API_KEY → BOBSHELL_API_KEY throughout
- Remove non-existent bobshell.ai link

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The bob-shell adapter was using stderr for Paperclip coordination messages
(session status, progressive updates, error descriptions). This caused noise
in stderr output that should be reserved for actual subprocess errors.

Changes:
- Session status messages now go to stdout (lines 435-439)
- Progressive status updates now go to stdout (lines 359-380)
- Error descriptions now go to stdout (lines 404-411)

This aligns bob-shell with the claude adapter pattern where:
- stdout = Paperclip coordination/status messages
- stderr = actual subprocess error output only

Fixes OCP-14

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Adds retry-strategy, runtime-config, session-management modules and
custom-modes/types under workspace/. Refactors execute.ts to use them.
Drops macOS resource forks (._*) accidentally committed via earlier
cherry-picks.

Cherry-picked partially from e04c0e7 (instance-only docs and .bob/
state were excluded).
BOB_SHELL_SETUP.md at repo root was non-idiomatic; Hermes and Droid
keep their setup guides inside the adapter package. Also link to it
from packages/adapters/bob-shell/README.md and fix fork-specific
clone URL to point at upstream.

Idempotent: repo root no longer has BOB_SHELL_SETUP.md after this.
@greptile-apps

greptile-apps Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds @paperclipai/adapter-bob-shell as a new built-in adapter for IBM's Bob Shell coding agent, following the same structural pattern as the existing Claude, Codex, and Hermes adapters. The integration is fully additive — no existing adapter code is modified.

  • New package (packages/adapters/bob-shell/): server executor, workspace sync, prompt-bundle cache, JSON-stream + XML parsers, error classification, retry strategy, session management, and 127 unit tests.
  • Registry hook-up: one new entry each in server/src/adapters/registry.ts, server/src/adapters/builtin-adapter-types.ts, and ui/src/adapters/registry.ts.
  • Key concern: workspace.ts writes the live PAPERCLIP_API_KEY value verbatim into {cwd}/.bob/mcp.json on every run while prompt-cache.ts correctly uses a placeholder — credentials are stored in plaintext in the project working directory.

Confidence Score: 3/5

Safe to merge for non-Bob-Shell users; Bob Shell users will have their API key written to disk in plaintext on every run, which should be resolved before production rollout.

The registry changes are purely additive and do not touch any existing adapter paths. The core concern is that workspace.ts writes the actual PAPERCLIP_API_KEY into a file in the project working directory on every run, creating a persistent credential exposure risk. There are also two independent implementations of the same workspace helper functions that will silently diverge over time, plus ROLE_GROUPS duplicated across three files.

packages/adapters/bob-shell/src/server/workspace.ts (API key written to disk) and packages/adapters/bob-shell/src/server/workspace/custom-modes.ts (dead code duplicating workspace.ts logic)

Security Review

  • Credential written to workspace directory (packages/adapters/bob-shell/src/server/workspace.ts, generatePaperclipMcpServer): the live PAPERCLIP_API_KEY bearer token is written verbatim into {cwd}/.bob/mcp.json on every run. A missed .gitignore entry or shared filesystem exposes the key. The prompt-cache.ts path correctly uses a placeholder — workspace.ts should match that approach.

Important Files Changed

Filename Overview
packages/adapters/bob-shell/src/server/workspace.ts Syncs .bob/ workspace config to project cwd; writes PAPERCLIP_API_KEY in plaintext to mcp.json on every run, and re-implements functions already in workspace/custom-modes.ts
packages/adapters/bob-shell/src/server/prompt-cache.ts Prompt bundle cache using SHA-256 content hashing; reads modeConfig.toolGroups instead of modeConfig.groups; duplicates ROLE_GROUPS/ROLE_WHEN_TO_USE constants
packages/adapters/bob-shell/src/server/workspace/custom-modes.ts Custom modes helpers never imported anywhere; workspace.ts re-implements the same functions locally making this dead code
packages/adapters/bob-shell/src/server/execute.ts Main adapter entry point; orchestrates runtime config, prompt caching, session validation, workspace sync, and retry-backed execution cleanly
server/src/adapters/registry.ts Additive registration of bob_shell adapter following exact same pattern as existing adapters; no existing code modified
Prompt To Fix All With AI
Fix the following 4 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 4
packages/adapters/bob-shell/src/server/workspace.ts:183-201
**API key written to plaintext file in project workspace**

`generatePaperclipMcpServer` resolves the live `PAPERCLIP_API_KEY` value and writes it verbatim into `{cwd}/.bob/mcp.json` on every run. Any developer who can read the workspace directory — or who accidentally runs `git add .` without the gitignore in place — will expose the bearer token. This is distinct from the `prompt-cache.ts` approach, which uses `"${PAPERCLIP_API_KEY}"` as a template placeholder and never touches the real value.

Consider aligning with `prompt-cache.ts` and using the env-var placeholder form here, relying on Bob Shell's parent-process environment to supply the value at MCP server startup rather than baking it into the file.

### Issue 2 of 4
packages/adapters/bob-shell/src/server/prompt-cache.ts:266-271
**`modeConfig.toolGroups` key does not match `modeConfig.groups` used everywhere else**

`generateCustomModesYaml` reads `modeConfig.toolGroups`, but `config-fields.tsx` stores the user's selection under `modeConfig.groups`, and both `workspace.ts` and `workspace/custom-modes.ts` also read `modeConfig.groups`. Because Bob Shell uses the files from `syncBobWorkspace` at runtime (which correctly reads `groups`), execution is unaffected today. However, the cached `custom_modes.yaml` will always silently fall through to the `ROLE_GROUPS` default, so the cache content diverges from the workspace content whenever a user customises tool groups.

### Issue 3 of 4
packages/adapters/bob-shell/src/server/workspace/custom-modes.ts:1-5
**`workspace/custom-modes.ts` is unreachable dead code**

Nothing in the package imports from `workspace/custom-modes.ts`. The `workspace.ts` file re-implements `readExistingCustomModes`, `generatePaperclipMode`, and `mergeCustomModes` directly without using this module. Having two independent implementations of the same functions will inevitably drift — any fix or enhancement to one copy won't be applied to the other. Either `workspace.ts` should delegate to `workspace/custom-modes.ts`, or `workspace/custom-modes.ts` should be removed.

### Issue 4 of 4
packages/adapters/bob-shell/src/server/prompt-cache.ts:220-239
**`ROLE_GROUPS` and `ROLE_WHEN_TO_USE` are defined three times independently**

These maps are duplicated verbatim in `prompt-cache.ts` (lines 220-239), `workspace.ts` (lines 80-100), and `workspace/types.ts` (lines 83-104). If a new role is added or an existing role's tool groups are changed, all three copies must be kept in sync. The canonical source should live in `workspace/types.ts` (where it already has JSDoc), and both `prompt-cache.ts` and `workspace.ts` should import from there.

Reviews (1): Last reviewed commit: "chore: regenerate lockfile after bob-she..." | Re-trigger Greptile

Comment on lines +183 to +201
function generatePaperclipMcpServer(env: Record<string, string>): BobMcpServer {
const apiUrl = env.PAPERCLIP_API_URL || "http://localhost:3100";
const apiKey = env.PAPERCLIP_API_KEY || "";
const companyId = env.PAPERCLIP_COMPANY_ID || "";
const agentId = env.PAPERCLIP_AGENT_ID || "";
const runId = env.PAPERCLIP_RUN_ID || "";

return {
command: "npx",
args: ["-y", "@paperclipai/mcp-server"],
env: {
PAPERCLIP_API_URL: apiUrl,
PAPERCLIP_API_KEY: apiKey,
PAPERCLIP_COMPANY_ID: companyId,
PAPERCLIP_AGENT_ID: agentId,
PAPERCLIP_RUN_ID: runId,
},
};
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security API key written to plaintext file in project workspace

generatePaperclipMcpServer resolves the live PAPERCLIP_API_KEY value and writes it verbatim into {cwd}/.bob/mcp.json on every run. Any developer who can read the workspace directory — or who accidentally runs git add . without the gitignore in place — will expose the bearer token. This is distinct from the prompt-cache.ts approach, which uses "${PAPERCLIP_API_KEY}" as a template placeholder and never touches the real value.

Consider aligning with prompt-cache.ts and using the env-var placeholder form here, relying on Bob Shell's parent-process environment to supply the value at MCP server startup rather than baking it into the file.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/adapters/bob-shell/src/server/workspace.ts
Line: 183-201

Comment:
**API key written to plaintext file in project workspace**

`generatePaperclipMcpServer` resolves the live `PAPERCLIP_API_KEY` value and writes it verbatim into `{cwd}/.bob/mcp.json` on every run. Any developer who can read the workspace directory — or who accidentally runs `git add .` without the gitignore in place — will expose the bearer token. This is distinct from the `prompt-cache.ts` approach, which uses `"${PAPERCLIP_API_KEY}"` as a template placeholder and never touches the real value.

Consider aligning with `prompt-cache.ts` and using the env-var placeholder form here, relying on Bob Shell's parent-process environment to supply the value at MCP server startup rather than baking it into the file.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +266 to +271
const toolGroups =
(Array.isArray(modeConfig.toolGroups) && modeConfig.toolGroups.length > 0
? modeConfig.toolGroups
: null) ??
ROLE_GROUPS[agentRole] ??
["read", "edit", "command", "mcp"];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 modeConfig.toolGroups key does not match modeConfig.groups used everywhere else

generateCustomModesYaml reads modeConfig.toolGroups, but config-fields.tsx stores the user's selection under modeConfig.groups, and both workspace.ts and workspace/custom-modes.ts also read modeConfig.groups. Because Bob Shell uses the files from syncBobWorkspace at runtime (which correctly reads groups), execution is unaffected today. However, the cached custom_modes.yaml will always silently fall through to the ROLE_GROUPS default, so the cache content diverges from the workspace content whenever a user customises tool groups.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/adapters/bob-shell/src/server/prompt-cache.ts
Line: 266-271

Comment:
**`modeConfig.toolGroups` key does not match `modeConfig.groups` used everywhere else**

`generateCustomModesYaml` reads `modeConfig.toolGroups`, but `config-fields.tsx` stores the user's selection under `modeConfig.groups`, and both `workspace.ts` and `workspace/custom-modes.ts` also read `modeConfig.groups`. Because Bob Shell uses the files from `syncBobWorkspace` at runtime (which correctly reads `groups`), execution is unaffected today. However, the cached `custom_modes.yaml` will always silently fall through to the `ROLE_GROUPS` default, so the cache content diverges from the workspace content whenever a user customises tool groups.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +1 to +5
import fs from "node:fs/promises";
import path from "node:path";
import yaml from "yaml";
import type { BobCustomMode, BobCustomModesConfig, ROLE_GROUPS, ROLE_WHEN_TO_USE } from "./types.js";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 workspace/custom-modes.ts is unreachable dead code

Nothing in the package imports from workspace/custom-modes.ts. The workspace.ts file re-implements readExistingCustomModes, generatePaperclipMode, and mergeCustomModes directly without using this module. Having two independent implementations of the same functions will inevitably drift — any fix or enhancement to one copy won't be applied to the other. Either workspace.ts should delegate to workspace/custom-modes.ts, or workspace/custom-modes.ts should be removed.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/adapters/bob-shell/src/server/workspace/custom-modes.ts
Line: 1-5

Comment:
**`workspace/custom-modes.ts` is unreachable dead code**

Nothing in the package imports from `workspace/custom-modes.ts`. The `workspace.ts` file re-implements `readExistingCustomModes`, `generatePaperclipMode`, and `mergeCustomModes` directly without using this module. Having two independent implementations of the same functions will inevitably drift — any fix or enhancement to one copy won't be applied to the other. Either `workspace.ts` should delegate to `workspace/custom-modes.ts`, or `workspace/custom-modes.ts` should be removed.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +220 to +239
const ROLE_GROUPS: Record<string, string[]> = {
ceo: ["read", "command", "mcp"],
cto: ["read", "command", "mcp"],
cmo: ["read", "mcp"],
cfo: ["read", "mcp"],
coo: ["read", "command", "mcp"],
vp: ["read", "command", "mcp"],
manager: ["read", "mcp"],
engineer: ["read", "edit", "command", "mcp"],
};

const ROLE_WHEN_TO_USE: Record<string, string> = {
ceo: "Strategic oversight, executive decisions, and company-level approvals.",
cto: "Architecture review, technical planning, and engineering governance.",
cmo: "Marketing strategy, content direction, and brand decisions.",
cfo: "Financial analysis, budget review, and cost decisions.",
coo: "Operations coordination, process management, and cross-team work.",
vp: "Division leadership, team management, and delivery oversight.",
manager: "Task coordination, team management, and issue triage.",
engineer: "Coding, debugging, refactoring, testing, and validation.",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 ROLE_GROUPS and ROLE_WHEN_TO_USE are defined three times independently

These maps are duplicated verbatim in prompt-cache.ts (lines 220-239), workspace.ts (lines 80-100), and workspace/types.ts (lines 83-104). If a new role is added or an existing role's tool groups are changed, all three copies must be kept in sync. The canonical source should live in workspace/types.ts (where it already has JSDoc), and both prompt-cache.ts and workspace.ts should import from there.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/adapters/bob-shell/src/server/prompt-cache.ts
Line: 220-239

Comment:
**`ROLE_GROUPS` and `ROLE_WHEN_TO_USE` are defined three times independently**

These maps are duplicated verbatim in `prompt-cache.ts` (lines 220-239), `workspace.ts` (lines 80-100), and `workspace/types.ts` (lines 83-104). If a new role is added or an existing role's tool groups are changed, all three copies must be kept in sync. The canonical source should live in `workspace/types.ts` (where it already has JSDoc), and both `prompt-cache.ts` and `workspace.ts` should import from there.

How can I resolve this? If you propose a fix, please make it concise.

Danijel Soldo added 3 commits May 22, 2026 00:23
…t plaintext

generatePaperclipMcpServer was resolving the live PAPERCLIP_API_KEY
value and writing it verbatim into {cwd}/.bob/mcp.json on every run.
Anyone with workspace read access could see the bearer token, and a
stray "git add ." before the .gitignore caught .bob/ would commit it.

Aligns with prompt-cache.ts:generateMcpJson, which already uses
"${PAPERCLIP_API_KEY}" placeholders that Bob Shell expands from its
parent-process environment at MCP server startup. The secret never
lands on disk.

Also drops the apiUrl and runId reads — those go through the same
placeholder pattern now (apiUrl was harmless but inconsistent; runId
would otherwise stale on cached files).

companyId and agentId remain inlined since they are stable per-agent
and non-sensitive, matching prompt-cache.ts.

Addresses Greptile P1 review on PR paperclipai#6518:
paperclipai#6518 (comment)

Tests: 127/127 pass. Typecheck: clean.
generateCustomModesYaml in prompt-cache.ts was reading
modeConfig.toolGroups, but the UI (config-fields.tsx) writes the
user selection under modeConfig.groups, and both workspace.ts and
workspace/custom-modes.ts read from modeConfig.groups too.

Bob Shell uses the .bob files written by syncBobWorkspace at runtime
(which reads the right key), so execution was unaffected today. But
the cached custom_modes.yaml in the prompt cache always silently fell
through to ROLE_GROUPS defaults, so the cache content diverged from
the workspace content whenever a user customised tool groups.

Aligning the key name fixes the cache drift and makes prompt-cache
match the rest of the package.

Addresses Greptile P2 review on PR paperclipai#6518:
paperclipai#6518 (comment)

Tests: 127/127 pass. Typecheck: clean.
ROLE_GROUPS and ROLE_WHEN_TO_USE were defined verbatim in three
places (prompt-cache.ts, workspace.ts, and workspace/types.ts), so
adding a role or changing a tool group required keeping three copies
in sync. The same drift risk applied to BobWorkspaceSyncInput,
BobCustomMode, BobCustomModesConfig, BobMcpServer, BobMcpConfig, and
PAPERCLIP_MCP_SERVER_NAME — all triplicated.

This commit:

- Promotes workspace/types.ts to the canonical source for the shared
  types, role maps, and PAPERCLIP_MCP_SERVER_NAME (it already had
  JSDoc and the right exports — it just was not being imported).
- workspace.ts and prompt-cache.ts now import from workspace/types
  instead of redeclaring locally.
- Deletes workspace/custom-modes.ts. Nothing in the package imported
  from it (workspace.ts re-implemented its three exported functions
  directly), so it was unreachable and just another place where the
  same logic could drift. Its only consumer of workspace/types.ts is
  removed with it.

No behavior change. The role maps and types had identical contents
across all three definitions; this is a deduplication, not a fix.

Addresses Greptile P2 reviews on PR paperclipai#6518:
- paperclipai#6518 (comment) (dead code)
- paperclipai#6518 (comment) (triplicated maps)

Tests: 127/127 pass. Typecheck: bob-shell + server clean.
@danijel-soldo

Copy link
Copy Markdown
Author

Greptile review addressed in three commits on top of bb82163:

  • 047f403 — P1 / security: write PAPERCLIP_API_KEY as ${PAPERCLIP_API_KEY} placeholder in .bob/mcp.json, matching prompt-cache.ts. Bearer token no longer lands on
    disk in the workspace. (thread)
  • 6ceb4e9 — P2: prompt-cache.ts now reads modeConfig.groups instead of modeConfig.toolGroups, matching the UI and the other readers. Cached custom_modes.yaml no longer drifts from the workspace copy when users customise tool groups. (thread)
  • 5268ae8 — P2: deleted unreachable workspace/custom-modes.ts; promoted workspace/types.ts to canonical for shared types, role maps, and PAPERCLIP_MCP_SERVER_NAME; workspace.ts and prompt-cache.ts now import instead of redeclaring. Net +11 / −219. No behavior change. (dead-code thread, triplication thread)

Verified after each commit:

  • pnpm --filter @paperclipai/adapter-bob-shell test → 127/127 pass
  • pnpm --filter @paperclipai/adapter-bob-shell typecheck → clean
  • pnpm --filter @paperclipai/server typecheck → clean

Re-requesting Greptile review.

custom_modes.yaml generation and role-derived mode selection were
removed in 5268ae8 (the refactor that hoisted shared types to
workspace/types.ts promoted a stripped-down types file, dropping
BobCustomMode, BobCustomModesConfig, ROLE_GROUPS, ROLE_WHEN_TO_USE,
and the full BobWorkspaceSyncInput along with it). The docs were never
updated.

- Remove .bob/custom_modes.yaml section from README and agentConfigurationDoc
- Rename .bob/rules-{mode}/ -> .bob/rules-paperclip/ (hardcoded in code)
- Drop mode, modeConfig.groups, modeConfig.whenToUse, modeConfig.customInstructions
  from the config table; modeConfig is now described as an opaque cache-key input
- Note that --mode must be passed explicitly via extraArgs if needed
- Update workspace sync semantics (no mode management, only mcp.json + rules-paperclip/)
@commitperclip

commitperclip Bot commented Aug 8, 2026

Copy link
Copy Markdown

Hey @danijel-soldo! Before this PR can be reviewed, a few things need attention:

Missing or incomplete:

  • No linked issue or inline issue description found — either tag an existing issue with Fixes #NNN / Closes #NNN / Refs #NNN, or describe the underlying issue inline in the PR body following one of our issue templates (https://github.com/paperclipai/paperclip/tree/master/.github/ISSUE_TEMPLATE). See CONTRIBUTING.md → "Link Issues or Describe Them In-PR".
  • Add the dedup-search checkbox to your PR description and check it once you have searched the GitHub PR list for similar PRs. See the PR template at .github/PULL_REQUEST_TEMPLATE.md and CONTRIBUTING.md → "Before You Start: Search First".
  • You have changes to pnpm-lock.yamlpr.yml will hard-fail this PR with a confusing message about lockfile edits. To fix: run pnpm install locally, exclude the lockfile from your commit, push again. The lockfile is regenerated automatically by the refresh bot on a schedule.

Informational:

  • 📦 New dependencies added: @paperclipai/adapter-acpx-local, @paperclipai/adapter-bob-shell, hermes-paperclip-adapter. Review may take longer and new dependencies are less likely to be accepted — please check if existing deps cover this need.

Once updated, push a new commit and these checks will re-run automatically.

— commitperclip

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant