Skip to content

docs: slim specs 01-03 to remaining work + add remediation specs 04/05#5

Merged
khaliqgant merged 3 commits into
mainfrom
docs/spec-wave
May 21, 2026
Merged

docs: slim specs 01-03 to remaining work + add remediation specs 04/05#5
khaliqgant merged 3 commits into
mainfrom
docs/spec-wave

Conversation

@khaliqgant

Copy link
Copy Markdown
Member

Slims specs 01–03 to only the gaps still failing their acceptance, and adds Spec 04 (cloud-agent box endpoints in ../cloud) and Spec 05 (integrations Connect via @relayfile/sdk + account-wide RelayWorkspaceManager).

Why

A check against the in-code acceptance gates showed 01–03 are scaffolded on main but materially incomplete (e.g. cloudAgentManager.restore exists but is never called on launch; ProactiveAgentsSection is defined but never rendered; integrations Connect targets a fake random workspace id). 04 and 05 are the cross-repo remediation specs that close the gaps, and the slimmed 01–03 capture what's left after they land.

What's in this PR

  • Slimmed 01-cloud-agents.md, 02-integrations.md, 03-proactive-agents.md — only the unimplemented bits, each with grep-based acceptance gates and the worktree+PR workflow.
  • New 04-cloud-agent-box.md, 05-integrations-connect.md — full remediation specs with frozen contracts, design decisions, deterministic gates, manual verification.
  • Mandatory worktree→PR workflow on every spec, plus a "Workflow: every spec runs in a worktree and ends with a PR" section in the README.
  • New runner specs/run-remaining-work.sh that iterates in dependency order (05 → 04 → 01 → 02 → 03); removes the legacy run-overnight.sh (sorted order is wrong now that 05 must precede 04).
  • Memories under .claude/projects/.../memory/ documenting the cloud credential sources, what a "cloud agent" actually is (provider credential), and the relayfile workspace model.

Docs-only — no source changes.

🤖 Generated with Claude Code

… specs 04/05

- Slim 01/02/03 to only their unimplemented gaps (the scaffolding from prior
  ricky runs is already on main; do not redo it).
- Add Spec 04 (cloud-agent box endpoints in ../cloud) and Spec 05 (integrations
  Connect via @relayfile/sdk + account-wide RelayWorkspaceManager).
- Mandatory worktree → PR workflow on every spec; new runner
  specs/run-remaining-work.sh iterates in dependency order (05 → 04 → 01 → 02 → 03).
- Remove legacy specs/run-overnight.sh (sorted order is wrong now that 05
  precedes 04).
- Memories: cloud credential sources, cloud-agent semantics, relayfile workspace
  model.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 21, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: a31e7767-d928-47eb-9646-897288c7520d

📥 Commits

Reviewing files that changed from the base of the PR and between 132957d and 7d85019.

📒 Files selected for processing (1)
  • specs/run-remaining-work.sh

📝 Walkthrough

Walkthrough

Adds memory documents and five detailed specs plus a runner script: design foundations for cloud credentials and relayfile workspaces, and specs covering Cloud Agents, Integrations, Proactive Agents, Cloud Agent Box backend, and Integrations Connect remediation.

Changes

Cloud Agents, Integrations & Proactive Agents Wave

Layer / File(s) Summary
Design foundation & semantics
.claude/projects/.../memory/MEMORY.md, ...memory/cloud-credential-sources.md, ...memory/cloud-agent-semantics.md, ...memory/relayfile-workspace-model.md
Memory documents establish the design context: Pear's dual credential-source resolution strategy (resolveCloudAuth()), cloud agent semantics as provider credentials with missing attach/warm flow, and the account-wide relayfile workspace model for integrations (vs prior broken per-project approach).
Wave coordination & execution
specs/README.md, specs/run-remaining-work.sh
Wave README codifies scope, shared design conventions, cross-repo footprint, and acceptance criteria. Bash runner executes specs 05 → 04 → 01 → 02 → 03 in dependency order with resume support, prerequisite validation, and fast-fail semantics.
Cloud agents (Pear startup restore & conflict policy)
specs/01-cloud-agents.md
Spec 01 defines two remaining Pear tasks: wire CloudAgentManager.restore(projectId) on app startup to best-effort restore persisted cloud agents per project, and add --conflict-policy={local-wins|remote-wins} flag to relayfile-mount with file backup to .relay/conflicts/<ts>-<path> when remote-wins is selected.
Integrations UI (Pear scope pickers & visibility)
specs/02-integrations.md
Spec 02 defines Pear UI completions: per-provider scope-picker components (generic fallback), per-project IntegrationVisibilitySection in ProjectSettings, and a missing ../relayfile-cloud workspace-integrations route (connect-session, mount, disconnect handlers).
Proactive agents (Pear UI + cloud backend)
specs/03-proactive-agents.md
Spec 03 covers Pear UI wiring (mount ProactiveAgentsSection, add editor tab kind, integrate Monaco, vendor runtime types via sync script) and cloud backend: proactive-personas routes, DB schema/migration, trigger/router/runner modules, and workforce deploy cloud mode unstubbing.
Cloud agent box backend (attach/warm endpoint)
specs/04-cloud-agent-box.md
Spec 04 implements the missing POST/GET/PATCH/DELETE /cloud-agents/{cloudAgentId}/box endpoint in ../cloud. Design: treat cloudAgentId as provider_credentials.id with ownership validation, mint path-scoped relayfile tokens via mintPathScopedRelayfileToken, enforce sticky one-sandbox-per-(workspace, cloud agent) reuse with row-level locking, map Daytona states to warming/ready/stopping/stopped, and make DELETE idempotent (stops sandbox, leaves provider credential intact).
Integrations connect backend (remediation via relayfile SDK)
specs/05-integrations-connect.md
Spec 05 remedies the broken integrations connect flow: bootstrap single account-wide relayfile workspace via RelayWorkspaceManager, rewire connect/disconnect/status to call generic relayfile endpoints via WorkspaceHandle.requestJson (bypassing SDK provider allowlist), apply provider id mapping (gmailgoogle-mail), and shift visibility to mount-path scoping per project.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I nibbled notes beneath the moonlit code,
Mapped workspaces, tokens, and the warming road.
Specs stacked neat, each gate a tiny art,
Cloud agents hum while integrations start,
A rabbit cheers the wave — hop, then ship, depart!


Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands and usage tips.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 1 additional finding in Devin Review.

Open in Devin Review

Comment thread specs/run-remaining-work.sh Outdated
Comment on lines +73 to +79
if ! "${cmd[@]}"; then
rc=$?
echo
echo "==> FAILED on $name (exit $rc)"
echo " Fix the underlying issue, then resume with:"
echo " $0 ${name%%-*}"
exit "$rc"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Exit code always 0 on failure due to $? after negated if condition

On line 74, rc=$? always captures 0 because it follows if ! "${cmd[@]}". In bash, when the then branch is entered, $? reflects the exit status of the negated condition (! cmd), which is 0 (true). The actual non-zero exit code of the failed command is lost. This causes exit "$rc" on line 79 to exit with 0, making the script appear to succeed to any parent process or CI system, even when ricky fails. The printed message also incorrectly shows "exit 0".

Suggested change
if ! "${cmd[@]}"; then
rc=$?
echo
echo "==> FAILED on $name (exit $rc)"
echo " Fix the underlying issue, then resume with:"
echo " $0 ${name%%-*}"
exit "$rc"
"${cmd[@]}" && true
rc=$?
if [[ $rc -ne 0 ]]; then
echo
echo "==> FAILED on $name (exit $rc)"
echo " Fix the underlying issue, then resume with:"
echo " $0 ${name%%-*}"
exit "$rc"
fi
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

khaliqgant and others added 2 commits May 21, 2026 14:24
Adds resume support to specs/run-remaining-work.sh so a paused or partially
completed run can continue from a given spec without re-running the ones that
already landed.

  ./specs/run-remaining-work.sh                # full run, dependency order
  ./specs/run-remaining-work.sh --from 01      # resume from 01 onward
  ./specs/run-remaining-work.sh --only 04      # run only one spec

Positional NN still works for back-compat (= --only NN). On failure the script
prints the exact --from command to resume from where it stopped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Use `cmd && true; rc=$?` so the failing command's exit status is preserved.
`if ! cmd; then rc=$?` always captured 0 because bash sets $? to the negated
condition's result (0 = true), making FAILED on … (exit 0) and exiting 0 even
when ricky failed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant khaliqgant merged commit e295e7b into main May 21, 2026
2 checks passed
khaliqgant added a commit that referenced this pull request May 22, 2026
… dev

ai-hist 0.2.0 (JSONL fallback, AgentWorkforce/relayhistory#5) isn't on npm
yet. Use the local checkout so the Conversations panel picks up the
fallback before publish.

Switch back to `"ai-hist": "^0.2.0"` once #5 is merged + published.
khaliqgant added a commit that referenced this pull request May 22, 2026
… history (#20)

* feat(ai-hist): Conversations panel — browse Claude/Codex/Cursor/Relay history

Adds a "Conversations" view backed by the new ai-hist SDK
(AgentWorkforce/relayhistory#3). Matches the conversation-history UX in the
Codex and Claude apps: searchable list of recent sessions on the left,
full prompt thread on the right, source-color chips, one-click
"copy resume command" to re-launch the session in its native CLI.

- src/main/ai-hist.ts: lazy-loading manager around `openAiHist()`.
  Surfaces missing-DB / load failures via getStatus() rather than
  crashing app startup.
- src/main/ipc-handlers.ts + src/preload/index.ts: ai-hist:* IPC
  channels and a typed `pear.aiHist.*` namespace.
- src/renderer/src/components/ai-hist/ConversationsPanel.tsx:
  two-pane Allotment layout with search, source filter chips,
  session list, and per-session prompt thread.
- src/renderer/src/components/sidebar/Sidebar.tsx: "Conversations"
  button in the sidebar footer.
- src/renderer/src/stores/ui-store.ts + src/renderer/src/App.tsx:
  registers `ai-hist` as a new AppTabKind / ViewMode.

The SDK uses sql.js (WASM SQLite) under the hood — no electron-rebuild
required. ai-hist (the Python sync tool) needs to be installed
separately; the panel shows a friendly install hint when the DB isn't
present.

The SDK is consumed via `file:../ai-hist/sdk-ts` for now. Once
ai-hist#3 lands and the SDK is published to npm, swap this to a
versioned dep.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(ai-hist): switch to dynamic import() for ESM SDK

The ai-hist SDK now ships as `type: module`. require() of an ESM
package fails at runtime on older Node, so switch the lazy-load path
in src/main/ai-hist.ts to `await import('ai-hist')`. The IPC surface
is unchanged (handlers already return Promises); resumeCommand is now
async too.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(ai-hist): consume published ai-hist@^0.1.1 from npm

ai-hist@0.1.1 is now on npm. Swap the `file:../ai-hist/sdk-ts` link
to a real versioned dep so end users of pear don't need the ai-hist
repo cloned alongside.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(ai-hist): per-project Conversations + group by root + double-click resume

- ProjectSidebar: adds a "Conversations" entry under the active project
  (replaces the global sidebar footer button). Each project gets its
  own tab via `{ kind: 'ai-hist', projectId }`; the ai-hist tab id now
  includes projectId so tabs don't collide across projects.
- ConversationsPanel: reads the scoped projectId from the active tab,
  pulls a larger session window (limit 500), and groups sessions by
  which project root the session.project path matches. Without a
  scope, groups every pear project's roots + an "Other" bucket.
- Session row UX:
  - single click  → load the full prompt thread in the right pane
  - double click  → spawn the session as a pear agent in the matching
    project (broker.spawnAgent with cli + --resume <sessionId>), open
    the agents tab, focus the new agent
- Detail header: replaces the single "Copy resume command" button with
  a primary "Resume in pear" + a secondary "Copy" button.
- Broker.spawnAgent: preload + renderer PearAPI now expose the `args`
  field that SpawnPtyInput already accepted server-side, so the
  renderer can pass `['--resume', sessionId]` (claude/cursor) or
  `['resume', sessionId]` (codex) without parsing a shell string.
- Renderer ipc.ts: added the AiHist* types + the aiHist namespace
  (was preload-only before, which left the renderer's PearAPI
  untyped).

Sidebar.tsx: removed the global Conversations button since the entry
point now lives under each project.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(ai-hist): temporarily point at file:../ai-hist/sdk-ts for 0.2.0 dev

ai-hist 0.2.0 (JSONL fallback, AgentWorkforce/relayhistory#5) isn't on npm
yet. Use the local checkout so the Conversations panel picks up the
fallback before publish.

Switch back to `"ai-hist": "^0.2.0"` once #5 is merged + published.

* fix(ai-hist): surface getSession errors + empty-state in right pane

The right pane was conditionally rendering an empty <ul> when
getSession returned [] or rejected, so a failed load looked identical
to "loading complete with zero prompts" — i.e. invisible. Adds:

  - detailError state captured from the IPC promise's catch handler;
    rendered as a red error card in the right pane.
  - Explicit empty-state message including the session id so users
    can report which session id the SDK rejected.

These are diagnostic affordances, not a fix for the underlying
getSession behavior — they make any future failure visible instead
of silent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(ai-hist): bump dep to published ai-hist@^0.2.1

ai-hist 0.2.1 is now on npm with the JSONL fallback +
non-blocking loads. Swap the file: link back to a real
versioned dep.

* fix(ai-hist): replace Allotment with plain flex — right pane was invisible

Root cause of "clicking a conversation shows nothing": the Conversations
panel used `Allotment` for the two-pane split, but Allotment's required
CSS (allotment/dist/style.css) was never imported anywhere in the
renderer. Without it, the right pane rendered at zero width and the
transcript was visible to React but not to the user.

Switching to plain CSS flex (`w-[380px]` left, `flex-1` right) sidesteps
the missing-stylesheet bug and removes the Allotment dependency from
this view. Users don't need a draggable splitter for this layout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* perf(ai-hist): fast session-grouping + debounced search (codex-2)

Lifts the conversation-loading and search freeze out of the SDK by
doing the slow work in pear's main-process wrapper instead. Drafted
by codex-2 via Relaycast after Khaliq reported "search freezes".

Three changes:

1. `src/main/ai-hist.ts`: new `fastListSessions` + `fastSearchSessions`
   methods on the manager. They reach into the SDK's already-open
   sql.js DB handle, pull the raw rows matching the filters, and group
   in-memory in JS (Map keyed by source/session_id/project). Falls
   back to the SDK's slow methods on any error so we stay safe if the
   internal handle is ever unavailable. New `searchSessions` IPC
   handler exposed via `ai-hist:search-sessions`.

2. `src/preload/index.ts` + `src/renderer/src/lib/ipc.ts`: expose
   `pear.aiHist.searchSessions(query, opts)` returning
   `AiHistSession[]` so the renderer can avoid the previous two-call
   dance (`search()` followed by `listSessions(500)` to grouping by
   session_id intersection).

3. `src/renderer/src/components/ai-hist/ConversationsPanel.tsx`:
   - 150 ms debounce on the search input (was firing per keystroke).
   - When the query is non-empty, call `searchSessions` instead of
     `search + listSessions + client-side intersect`.

Benchmarks against ~91 MB / 35,857-row DB:
- old SDK `listSessions({ limit: 500 })`: ~17.1s
- new row-scan session list:                ~255ms
- new search-session path (filtered):       ~277ms

Co-Authored-By: codex-2 (via Relaycast) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(ai-hist): bump dep to ai-hist@^0.2.3

0.2.3 includes the listSessions window-function rewrite + auto-created
session_id/timestamp indexes (~68x faster on a 35K-row DB). Pear's
main-wrapper bypass (cc6a47f) still works as a safety net, but with
0.2.3 the underlying SDK is fast too — both paths agree.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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