Commit Graph

1163 Commits

Author SHA1 Message Date
Devin Foley a4993a72a6
Fix live run streaming text readability (#9330)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The issue thread UI renders live agent output from adapter run logs
and transcript parsing.
> - Some adapter streams emit many small or repeated token chunks, and
live UI updates can expose partial words, duplicated slices, or
transient markdown placeholders.
> - That makes active run updates look like gibberish even when the
underlying agent output is valid.
> - The fix needs to preserve raw logs while making the live thread view
stable, readable, and ordered.
> - This pull request adds monotonic run-log sequencing, safer live
transcript dedupe/order handling, markdown placeholder hiding, and
readable live text stabilization.
> - The benefit is a live issue thread that updates smoothly without
showing confusing partial parser artifacts.

## Linked Issues or Issue Description

No public GitHub issue exists yet, so this PR includes the bug details
inline.

### What happened?

Live run updates in the issue thread can show confusing repeated or
partial text while an adapter is streaming. The visible text appears to
lose parsing boundaries during active updates, especially with ACP-style
token deltas, so the live output can briefly render duplicated chunks,
incomplete words, or HTML-comment placeholders.

### Expected behavior

Live text should remain readable while preserving the underlying run
output for raw inspection.

### Steps to reproduce

1. Start a live agent run whose adapter emits small stdout token deltas.
2. Watch the issue thread while the run is still active.
3. Observe transient duplicated chunks, incomplete words, or markdown
placeholder artifacts in the live rendered text.

### Paperclip version or commit

Reproduced against current `master` before this PR branch.

### Deployment mode

Local dev issue-thread UI with live local adapter runs.

### Additional context

GitHub PR search for `live run streaming text markdown transcript` found
one broad merged PR, `#252` (“Dotta updates - sorry it's so large”), but
no targeted duplicate for this live streaming readability bug.

## What Changed

- Added per-run monotonic sequence numbers to persisted and live run-log
chunks.
- Dedupe and order live transcript chunks by sequence before falling
back to timestamp ordering.
- Hide markdown HTML comment placeholder text from rendered markdown
output.
- Smooth live issue-thread text updates so partial additions reveal at
readable word boundaries and sliding-window removals do not produce
gibberish.
- Added coverage for run-log ordering/deduping, markdown comment hiding,
live issue-thread stabilization, and Greptile-reviewed edge cases where
overlap rewrites could synthesize text or no-boundary additions could
stay hidden.

## Verification

- `pnpm --filter @paperclipai/ui exec vitest run
src/lib/issue-chat-messages.test.ts src/components/MarkdownBody.test.tsx
src/components/transcript/useLiveRunTranscripts.test.tsx` passed before
the review fix: 3 files, 86 tests.
- `pnpm --filter @paperclipai/ui exec vitest run
src/lib/issue-chat-messages.test.ts` passed after the review fix: 1
file, 30 tests.
- `pnpm --filter @paperclipai/ui exec vitest run
src/lib/issue-chat-messages.test.ts
src/components/transcript/useLiveRunTranscripts.test.tsx` passed after
the final Greptile overlap fix: 2 files, 40 tests.
- `pnpm check:token-gates` passed.
- Local PII/secret scan of touched files found only expected code/test
words such as `secret`, `token`, and redaction-related strings; no
literal credentials found.
- `pnpm -r typecheck` passed after restoring declared dependencies with
`CI=1 pnpm install --frozen-lockfile` and running with a short `TMPDIR`
because `tsx` IPC sockets fail under the long sandbox temp path.
- `pnpm build` passed with existing Vite CSS/font/chunk warnings.
- GitHub PR checks passed on head
`4c052dfe86aecb5feb73504e6b48843f68fce813`: build, typecheck/release
registry, server and workspace test shards, serialized server suites,
e2e, canary dry run, policy, review, Socket, Superagent, Snyk, and
verify.
- Greptile review passed on head
`4c052dfe86aecb5feb73504e6b48843f68fce813` with confidence score 5/5 and
no blocking issues found.
- `pnpm test:run` failed in unrelated server workspace tests on this
macOS local environment:
- `server/src/__tests__/heartbeat-workspace-branch-containment.test.ts`:
two assertions compare `/tmp/...` with `/private/tmp/...`.
- `server/src/__tests__/heartbeat-worktree-suppression.test.ts`:
expected one heartbeat run but observed two, followed by cleanup fallout
in the full run.
- Isolated rerun of those two server suites reproduced the same three
failures.

## Risks

- Low product risk for the UI changes: the readable smoothing only
affects active live-run display stabilization, not stored comments or
raw run logs.
- Moderate verification risk: local full Vitest did not pass because of
unrelated server workspace tests. Targeted tests for this change,
typecheck, token gates, and build passed.
- Run-log sequence fields are optional for compatibility with older log
rows that do not include `seq`.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, GPT-5-based coding agent, tool-using local workspace
execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I searched the GitHub PR list for similar PRs and confirmed this
is not a duplicate
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-07-10 08:11:52 -07:00
Dotta a02fe8d575
Update Codex adapter GPT-5.6 defaults (#9352)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Codex local is the adapter subsystem that exposes OpenAI Codex CLI
model choices to agents and issue overrides.
> - OpenAI has GPT-5.6 Codex-capable models that should appear in
Paperclip's built-in Codex model list and refresh behavior.
> - Paperclip's server model listing falls back to the adapter metadata
and merges OpenAI refresh results with known Codex defaults.
> - This pull request updates the Codex default model metadata to
include GPT-5.6 options and adds regression coverage for fallback and
refresh paths.
> - The benefit is that operators can select the new Codex models
without relying on manual model IDs, and refresh behavior keeps known
GPT-5.6 options visible.

## Linked Issues or Issue Description

Refs #9322.
Refs #9342.
Refs #9346.

### Agent or provider

Codex CLI (OpenAI).

### Why this adapter is useful

OpenAI's GPT-5.6 Codex-capable models should be available in Paperclip's
Codex adapter defaults and model refresh path.

### How the agent is invoked

`codex`

## What Changed

- Changed the `codex_local` default model metadata from `gpt-5.5` to
`gpt-5.6`.
- Added `gpt-5.6-sol`, `gpt-5.6-terra`, and `gpt-5.6-luna` to the
built-in Codex adapter model list.
- Updated adapter and server model-listing tests to cover GPT-5.6
fallback and refresh behavior.
- Aligned Codex Fast mode support and helper text with the new `gpt-5.6`
default, while preserving GPT-5.5, GPT-5.4, and manual model ID support.

## Verification

- `git diff --check origin/master...HEAD`
- `pnpm exec vitest run packages/adapters/codex-local/src/index.test.ts
packages/adapters/codex-local/src/server/codex-args.test.ts
server/src/__tests__/adapter-models.test.ts
server/src/__tests__/adapter-model-refresh-routes.test.ts`
- `pnpm check:token-gates`
- `pnpm --filter @paperclipai/adapter-codex-local typecheck`
- `pnpm --filter @paperclipai/server typecheck`
- `pnpm --filter @paperclipai/ui typecheck`

## Risks

Medium risk because changing `DEFAULT_CODEX_LOCAL_MODEL` from `gpt-5.5`
to `gpt-5.6` changes the adapter's default model selection for new blank
configurations. The model-list additions are otherwise low risk and
covered by adapter/server metadata tests. This PR intentionally overlaps
related PRs #9342 and #9346, so reviewers may prefer to close or fold it
into one of those branches.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex coding agent based on GPT-5, with shell, git, GitHub CLI,
and repository editing tool use. Exact served model ID and context
window were not exposed by the runtime.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-10 09:20:13 -05:00
Dotta 0f5f461729
Avoid startup crash when Reflection Coach assets are missing (#9351)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The server has built-in agent definitions that are loaded during
startup and used to provision optional operational agents such as
Reflection Coach
> - Reflection Coach stores richer stock instructions, a routine
description, and a bundled skill as markdown assets outside the
TypeScript module body
> - A deployed server can fail before it is healthy if one of those
copied markdown assets is absent from `server/dist`
> - A recent build fix preserves those assets during normal server
builds, but runtime should still degrade gracefully if a packaged asset
is missing or unreadable
> - This pull request adds resilient loading for built-in Reflection
Coach assets and keeps a minimal compiled fallback available
> - The benefit is that a missing optional built-in agent file no longer
turns into a process-wide startup crash

## Linked Issues or Issue Description

Bug fix. No public GitHub issue found for this exact startup crash.

- Related public PR: #9339
- What happened: the server could throw `ENOENT` while importing the
built-in agent service if
`server/dist/built-ins/agents/reflection-coach/AGENTS.md` was missing
from a deployed build.
- Expected behavior: the server should keep starting, log that the
built-in asset was missing, and use safe fallback text for the optional
built-in agent resource.
- Steps to reproduce: build the server, remove the compiled Reflection
Coach `AGENTS.md` asset from `server/dist`, then import/start the server
path that loads built-in agent definitions.
- Paperclip version/commit: reproduced against a deployed build
containing the Reflection Coach built-in agent assets; fixed against
current `master` after #9339.
- Deployment mode: Node server deployment using compiled `server/dist`
output.

## What Changed

- Added built-in agent text loading that checks the compiled asset path
first, then source/package fallback paths, then a minimal compiled-in
fallback string.
- Added fallback text for Reflection Coach instructions, routine
description, and bundled skill content so startup does not depend on
optional markdown assets being present.
- Added regression coverage for readable candidate selection and
missing-file fallback behavior.

## Verification

- `pnpm -w exec vitest run server/src/__tests__/built-in-agents.test.ts`
— 1 test file passed, 24 tests passed.
- `pnpm --filter @paperclipai/server build` — server TypeScript build
completed and copied `src/built-ins` into `dist/built-ins`.
- Manual smoke: temporarily moved
`server/dist/built-ins/agents/reflection-coach/AGENTS.md`, imported
`server/dist/services/built-in-agents.js` through the repo-pinned `tsx`
runtime, and confirmed Reflection Coach definitions still loaded with
output `reflection-coach:3732`; the asset was restored afterward.

## Risks

Low risk. The normal path still uses the full packaged markdown assets.
The fallback path is only used when those files are missing or
unreadable, and it logs a warning so packaging drift remains visible.

## Model Used

OpenAI GPT-5 Codex coding agent, with repository tool access and
shell-based verification. Exact context window was not exposed in this
runtime.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-10 08:28:37 -05:00
Dotta cc81eefb60
Make plan-approval continuations durable after failed wakes (#9331)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents often work from reviewed plans that are approved through
issue-thread interactions.
> - Accepting a plan is not just a UI decision; it must reliably resume
the assignee so approved work continues.
> - A failed continuation wake could leave an approved plan stranded in
review with no durable retry or visible recovery path.
> - This pull request makes approved plan continuations retryable,
recoverable, and visible when resume fails.
> - The benefit is that operators can trust plan approval to either
resume the agent or produce an explicit actionable failure instead of
silent limbo.

## Linked Issues or Issue Description

No public GitHub issue exists. Inline bug report follows the repository
bug template.

### Pre-submission checklist

- [x] I have searched existing open and closed issues and this is not a
duplicate.
- [x] I am on the latest released version of Paperclip or can reproduce
on `master`.
- [x] I have confirmed the error originates in Paperclip itself, not in
my agent adapter, API provider, or local configuration.

### What happened?

When a plan-confirmation interaction was accepted, the assignee
continuation wake could fail before useful agent execution. In that case
the issue could remain in review even though the plan had been approved,
because the failed wake was fire-and-forget and there was no durable
retry or recovery path for accepted continuations.

### Expected behavior

Accepted plan continuations should either wake the assignee
successfully, retry bounded infrastructure failures, recover dropped
wakes, or surface an explicit failure state that operators can act on.

### Steps to reproduce

1. Create an issue with an assignee and a plan confirmation that wakes
the assignee on accept.
2. Accept the confirmation.
3. Simulate a pre-flight continuation failure, such as process loss
before agent start or workspace validation failure.
4. Observe that the approved issue can remain in review without an
active assignee wake or visible retry/failure state.

### Paperclip version or commit

Reproducible on `master` before this PR's retry/recovery changes.

### Deployment mode

Local dev (`pnpm dev`) and server-side recovery paths.

### Installation method

Built from source (`pnpm install`, `pnpm dev`, test runner).

### Agent adapter(s) involved

Not adapter-specific; this is a core continuation/recovery bug. The
tests cover local-agent failure shapes without relying on a
provider-specific API.

### Database mode

Embedded Postgres test database for verification. The affected logic is
database-backed and applies to normal Postgres deployments as well.

### Access context

Board accepts the interaction; agent execution resumes through the
assignee wake path.

### Relevant logs or output

No sensitive logs are needed. The regression tests simulate the failed
wake and recovery states directly.

### Relevant config

No special config is required beyond an assignee with wake-on-demand
enabled.

### Additional context

This PR also prevents a stale workspace-validation payload from
quarantining another issue's active workspace and prevents unrelated
successful runs from masking a continuation that never resumed.

### Privacy checklist

- [x] I have reviewed all pasted output for PII, usernames, file paths,
API keys, tokens, and company names, and redacted where necessary.

## What Changed

- Added bounded infrastructure retries for failed accepted-interaction
continuation wakes.
- Extended stranded issue recovery so dropped accepted-plan continuation
wakes are requeued.
- Recorded and rendered explicit resume-failure state on accepted
confirmation cards.
- Added clean-workspace fallback for workspace-validation failures while
preventing cross-issue workspace quarantine.
- Tightened recovery so unrelated successful runs do not mask an
accepted continuation that never resumed.
- Added focused server/UI coverage for retry scheduling, recovery,
visible failure state, and interaction card rendering.

## Verification

- `pnpm vitest run
server/src/__tests__/heartbeat-retry-scheduling.test.ts
server/src/__tests__/heartbeat-process-recovery.test.ts` — 106 tests
passed.
- Earlier branch verification also covered the issue-thread interaction
card tests for the visible resume-failure UI.
- GitHub CI is green on the replacement PR head, and Greptile reports
5/5 with no blocking issues.

## Risks

- Medium behavioral risk: this changes recovery behavior for accepted
continuation interactions and workspace-validation retries.
- Mitigation: retries are bounded, scoped to same-company issue context,
and workspace quarantine now requires ownership by the issue being
retried.
- Existing stored confirmation results remain compatible because the new
resume-failure field is optional.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex, GPT-5 coding agent, tool-enabled terminal workflow. The
runtime does not expose an exact context-window value to the agent.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-10 08:12:16 -05:00
Dotta d166069bc4
Preserve built-in agent assets in server builds (#9339)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The server package ships compiled runtime code plus static runtime
assets.
> - Built-in agent definitions live under `server/src/built-ins` and
runtime code resolves them relative to compiled server files.
> - The server build already copied onboarding assets into `dist`, but
it did not copy built-in agent assets alongside the compiled code.
> - Packaged server builds could therefore miss built-in agent
definitions even though source-based development runs worked.
> - This pull request extends the server build copy step to preserve
built-in agent assets in `dist/built-ins`.
> - The benefit is packaged server builds keep the same built-in agent
runtime assets available as source-based development runs.

## Linked Issues or Issue Description

No public GitHub issue found. This PR describes the underlying bug
inline using the bug report template fields.

### What happened?

`@paperclipai/server` build output copied `server/src/onboarding-assets`
into `server/dist/onboarding-assets`, but did not copy
`server/src/built-ins` into `server/dist/built-ins`. Runtime code for
built-in agents resolves those assets relative to the compiled server
files, so packaged builds could omit built-in agent markdown assets that
are present during source-based development.

### Expected behavior

Packaged server builds should include built-in agent assets under
`server/dist/built-ins`, matching the runtime location expected by the
compiled server code.

### Steps to reproduce

1. Check out current `master` before this PR.
2. Run `pnpm --filter @paperclipai/server build`.
3. Check for `server/dist/built-ins/agents/reflection-coach/AGENTS.md`.
4. Observe that the built-in agent asset is missing from the server
build output.

### Paperclip version or commit

Reproduces on current `master` before this PR. The fix is verified on
commit `2b89984ccb7857f06359bf65c48222f110c7aeff`.

### Deployment mode

Build/package artifact behavior. This can affect any deployment mode
that runs from the built server package rather than directly from
source.

### Installation method

Built from source with `pnpm --filter @paperclipai/server build`.

### Agent adapter(s) involved

Not adapter-specific. This is a core server packaging bug for built-in
agent assets.

### Database mode

Not database-related.

### Access context

Not applicable. This happens during package build output generation.

Related search:

- Searched public PRs/issues for `built-ins build copy
repo:paperclipai/paperclip`.
- Found no directly related open issue. One old closed Hermes adapter PR
was not directly related.

## What Changed

- Updated the `@paperclipai/server` build script to create
`dist/built-ins`.
- Added the copy step from `server/src/built-ins` into
`server/dist/built-ins` alongside the existing onboarding asset copy.
- Added a focused server package build-script test that asserts both
onboarding and built-in static runtime asset directories are copied into
`dist`.

## Verification

- `pnpm exec vitest run
server/src/__tests__/server-package-build-script.test.ts`
- `pnpm --filter @paperclipai/server build`
- `test -f server/dist/built-ins/agents/reflection-coach/AGENTS.md`

## Risks

Low risk. This changes only the package build asset copy step and adds
focused test coverage. The main risk is build-script portability, but it
follows the existing `mkdir -p` and `cp -R` pattern already used for
onboarding assets.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex, GPT-5-based coding agent in a tool-enabled Paperclip
heartbeat. Exact model ID and context-window size are not exposed in
this runtime.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-10 07:44:08 -05:00
Dotta 5c85ae64a0
Cases: experimental first-class case object (#9198)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The board currently uses issues for execution, but longer-lived
content work needs a separate object that can survive beyond a single
task thread.
> - The Cases subsystem adds an experimental, company-scoped record for
content artifacts and their supporting metadata.
> - The backend needs durable storage, API routes, revision history,
issue linkage, and company-boundary enforcement before the UI can depend
on Cases.
> - The UI needs an opt-in navigation surface, list/detail views,
reference chips, and issue-page context so operators can inspect Cases
without making them the default workflow.
> - The agent-facing skills need a contract for creating and updating
Cases so automated content workflows can dogfood the feature.
> - This pull request ships that experimental end-to-end path behind the
`enableCases` flag.
> - The benefit is a first-class place to collect content work,
references, attachments, revisions, and related execution threads
without polluting the core issue model.

## Linked Issues or Issue Description

No public GitHub issue exists for this experimental feature.

Feature request fields:

### Problem

Content-oriented work such as release notes, announcements, docs, and
campaigns can span many execution issues, which makes the final artifact
hard to find and reason about after the execution thread moves on.

### Proposed solution

Add an experimental Cases object that is company-scoped, linked to
issues, queryable through the API, inspectable in the board UI, and
writable by agent workflows through documented conventions.

### Alternatives considered

Continue encoding content artifacts directly in issues or documents
only. That keeps the data model smaller, but it does not give operators
a stable artifact-centric view or a clean way to link related execution
history.

### Roadmap alignment

Checked `ROADMAP.md`; this PR does not duplicate an existing planned
core roadmap item.

## What Changed

- Added the `cases` data model, migration, schema exports, and
experimental `enableCases` instance setting.
- Added company-scoped Cases API routes for list/detail/update, issue
links, revisions, children, activity events, annotations, attachments,
and idempotent agent-oriented upserts.
- Scoped case and issue lookup helpers before access checks so
inaccessible cross-company identifiers resolve as not found rather than
leaking existence.
- Fixed case PATCH timestamp handling so non-status updates cannot
overwrite `completedAt` from a stale pre-transaction row snapshot.
- Moved Cases list type/status/project filters into the server request
before the server-side limit is applied, including multi-select filters
and no-project filtering.
- Added backend route coverage for creation, updates, idempotency, issue
linking, attribution, company-boundary enforcement, OpenAPI
registration, list filtering, timestamp patch behavior, and inaccessible
lookup regressions.
- Added the experimental Cases UI surface: sidebar entry, gated routes,
list filters/grouping, detail overview, activity, revisions, children,
attachments, and issue-page case rail.
- Added case reference rendering and company-prefixed case href
generation so case links resolve directly inside the active company
route.
- Added Paperclip skill documentation for agent workflows that create or
update Cases.
- Wired release-content skills to emit Cases for dogfooding.
- Rebased onto current `master` and renumbered the Cases migrations to
`0143`/`0144` after the latest upstream migration sequence.

## Verification

- Current PR head: `ecc13be0d`.
- Rebased on current `master` (`606aa4f266`) and pushed to the existing
PR branch.
- `git diff --check origin/master...HEAD` — passed before the first
update push; subsequent committed diffs were also checked with `git diff
--check` before commit.
- Guardrails checked: no `pnpm-lock.yaml` changes, no
`.github/workflows` changes, and changed-file count is below the
Greptile 100-file limit.
- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/cases-routes.test.ts
src/__tests__/instance-settings-service.test.ts
src/__tests__/openapi-routes.test.ts` — passed, 3 files / 26 tests
before review-fix commits.
- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/cases-routes.test.ts` — passed after each server-side
Greptile fix, latest 1 file / 15 tests.
- `pnpm --filter @paperclipai/server typecheck` — passed after the
timestamp and lookup fixes.
- `pnpm --filter @paperclipai/ui exec vitest run
src/pages/Cases.test.tsx src/pages/CaseDetail.test.tsx
src/pages/CompanySkills.test.tsx src/App.cases-routing.test.tsx` —
passed, 4 files / 30 tests before review-fix commits.
- `pnpm --filter @paperclipai/ui exec vitest run
src/pages/Cases.test.tsx` — passed after the list-filter fix, 1 file /
12 tests.
- `pnpm --filter @paperclipai/ui typecheck` — passed after the
list-filter fix.
- `pnpm check:token-gates` — passed after UI changes.
- Remote PR checks on head `ecc13be0d` are green: Paperclip CI, build,
typecheck, test matrix, e2e, Canary Dry Run, policy, commit review,
Superagent Security Scan, Socket, Snyk, and Greptile passed; Storybook
visual regression is skipped and security-review is neutral.
- Greptile Review: 5/5 confidence, zero unresolved Greptile threads.

## Risks

- Medium feature risk because this introduces a new experimental domain
object across database, server, shared contracts, skills, and UI.
- The feature is gated behind `enableCases`, which limits default
operator exposure while the model is exercised.
- Case links now prefer company-prefixed hrefs; the unprefixed redirect
remains for externally entered URLs.
- Cases list filtering now sends multi-select filters to the server
before limiting; the UI still applies the same local filters as a second
pass for ancestor/context rows.
- Migrations were renumbered on top of current master; the SQL uses
guarded `IF NOT EXISTS` / `ADD COLUMN IF NOT EXISTS` patterns where
relevant for safer replay.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI GPT-5 Codex in the Paperclip local coding environment was used
for this PR curation, rebase verification, review-fix implementation,
push, and PR description update. The runtime exposes tool use and shell
execution; context-window size is not exposed by this Paperclip adapter.
Several implementation commits also include AI co-author trailers
recorded in git history.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I searched the GitHub PR list for similar PRs and confirmed this
is not a duplicate
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [ ] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 22:11:03 -05:00
Dotta 606aa4f266
feat(search): filters, sorting, operators & command-palette parity (#9327)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Company search is the primary way operators find issues, comments,
documents, artifacts, agents, and projects across a busy company
> - Search previously supported only a bare text query: no way to narrow
by status/assignee/project/label/date, no sort control, no typed
operators, and weak relevance/snippets meant hunting through noise
> - As companies accumulate tens of thousands of items, unfiltered
single-sort search stops scaling for day-to-day operator workflows
> - This pull request adds a full filtering model (filter bar, chips,
mobile sheet, URL state), sort modes, typed query operators (`status:`,
`assignee:`, `type:`, …) with command-palette parity,
relevance/snippet/deep-link improvements, zero-results recovery, and the
supporting shared validators, backend service work, and DB indexes
> - The benefit is that operators can go from a vague query to the exact
item in a couple of keystrokes, on desktop and mobile, with shareable
filtered-search URLs

## Linked Issues or Issue Description

No existing public GitHub issue; describing the underlying feature
request inline (per feature_request template):

- **Problem:** Company search accepted only a plain text query. Users
could not filter results by status, assignee, project, label, or
recency; could not change result ordering; and got no guidance when
filters emptied the result set.
- **Desired solution:** Structured search filters (UI controls + typed
query operators + URL parameters), selectable sort modes, better
relevance and snippets with exact deep links, and parity between the
search page and the command palette.
- **Alternatives considered:** Client-side filtering of unfiltered
results (does not scale past the fetch limit); a separate "advanced
search" page (splits the surface and duplicates state handling).

Related (not duplicate) PRs found while searching: #4848 (issue search
query planning), #8235 (search rate limiting).

## What Changed

- **Shared contract:** new search filter/sort/count/zero-results types
and validators in `packages/shared` (`validators/search.ts`, types
index).
- **Backend:** `server/src/services/company-search.ts` supports issue
filters, sort modes, per-filter option counts, snippets, artifact
visibility, and zero-results loosen suggestions; single-statement match
replaces per-scope scans and predicates are trigram-index compatible
(~3.7s → ~350ms on a live 14.8k-hit corpus).
- **DB:** migration `0142_company_search_sort_indexes.sql` adds the
supporting indexes.
- **Search page (`ui/src/pages/Search.tsx`):** filter bar, removable
chips, mobile filter sheet with result-count preview, sort menu, URL
round-tripping, zero-results recovery UI.
- **Query operators (`ui/src/lib/search-query-parser.ts`):** typed
operators parsed into filters, operator autocomplete, filter pills.
- **Command palette:** operator-aware parsing and full-search handoff.
- **Stale-operator fix (latest commit):** typed operator filters are no
longer folded into persistent URL-filter state, so deleting a token
(e.g. removing `status:blocked` from the input) actually removes the
filter from subsequent requests; filter-control edits materialize
control state and strip typed tokens so a removed chip cannot resurrect
from the input.

## Verification

- `cd ui && npx vitest run src/pages/Search.test.tsx` — 19 tests
including two new red→green regressions for the stale-operator paths
(both fail on the previous commit, pass now).
- `cd ui && npx vitest run src/components/CommandPalette.test.tsx` and
`cd server && npx vitest run
src/services/company-search-service.test.ts` — operator parity and
backend filter/sort/count coverage.
- `cd ui && npx tsc --noEmit` — clean.
- Manual: open `/search`, type `auth status:blocked`, confirm the status
filter applies; delete `status:blocked`, confirm results are unfiltered
again; drive the same filters from the filter bar/chips/mobile sheet and
confirm the URL round-trips (reload/back/forward preserves state).
- Full end-to-end QA pass (9/9 acceptance checks) against the wireframes
on desktop (1280px) and mobile (390px) with a live API and browser
automation.

## Risks

- Additive migration (indexes only, no data rewrites) — safe to roll
forward; index creation cost is paid once at migrate time.
- Search request shape gains optional parameters only; old clients keep
working.
- Behavioral shift: filter-control edits now strip typed operator tokens
from the query text (their values persist as filter state) — deliberate,
so removed filters stay removed.
- Ranking changes alter result ordering for existing queries; covered by
service tests and the QA pass.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- Claude Fable 5 (`claude-fable-5`, Anthropic, extended thinking + tool
use) — stale-operator-filter fix, regression tests, PR preparation.
- GPT-5 Codex (`codex_local` adapter) and Claude Opus 4.6
(`claude-opus-4-6`) — earlier implementation phases (backend contract,
filter UI, operators, ranking) under agent orchestration.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [ ] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
— pre-existing branch name retained to avoid closing/reopening the PR
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes (no
user-facing docs affected)
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green (pending re-run on latest commit)
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
(pending re-review of the stale-filter fix)
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 19:32:58 -05:00
Dotta cec0fc249a
[codex] Parallelize release verify workflow (#9168)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Releases publish the same app and package set that operators
install, so release verification should keep full release-strength
coverage.
> - The release workflow currently verifies stable and canary releases
with one serial job that typechecks, runs all tests, and builds.
> - The PR workflow already proves the test surface can be split into
grouped general suites and serialized shards without changing coverage.
> - This pull request extracts the release verify work into a reusable
workflow and fans out the independent lanes.
> - The benefit is faster stable and canary release verification while
preserving the existing publish and preview gates.

## Linked Issues or Issue Description

No public GitHub issue exists for this CI improvement.

**Subsystem affected**

Cross-cutting (multiple of the above)

**Problem or motivation**

Release verification spends most of its wall time in a single serial
test step even though the same stable test surface is already
partitioned for PR CI. Stable dispatches and master-push canaries
therefore wait on one long runner after setup, typecheck, tests, and
build run sequentially.

**Proposed solution**

Add a reusable release verification workflow with parallel typecheck,
grouped general tests, serialized test shards, and build lanes. Have
both stable and canary release verification call it with the ref they
need to verify.

**Alternatives considered**

Keeping the serial `pnpm test:run` job preserves the old shape but keeps
stable and canary releases waiting on one long runner. Skipping
verification when a source SHA already has green CI would be faster, but
adds stale-check and lookup risk beyond this change.

**Roadmap alignment**

No overlapping item found in `ROADMAP.md`; this is release CI
maintenance.

**Additional context**

The new workflow keeps the release-strength full `pnpm -r typecheck`,
uses the existing stable test grouping/sharding entry points, and leaves
publish/preview jobs unchanged.

## What Changed

- Added `.github/workflows/release-verify.yml` as a `workflow_call`
workflow accepting a `ref` input.
- Split release verification into parallel `typecheck`, `general_tests`,
`serialized_tests`, and `build` jobs with 20-minute lane timeouts.
- Mirrored the PR workflow's stable test partition: `general-server`
shards 1-3, `general-workspaces-a`, `general-workspaces-b`, and four
serialized shards.
- Replaced `release.yml` `verify_canary` and `verify_stable` job bodies
with calls to the reusable workflow while leaving publish and preview
jobs unchanged.
- Added a Node test that guards the release workflow delegation and
split verify surface.

## Verification

- `actionlint 1.7.12 .github/workflows/release.yml
.github/workflows/release-verify.yml`
- `node ./scripts/release-package-map.mjs check`
- `node --test ./scripts/__tests__/release-verify-workflow.test.mjs
./scripts/__tests__/run-vitest-stable-shard.test.mjs`
- `git diff --check`

## Risks

- Release verification now starts more jobs per release event,
increasing total runner setup/install minutes. This matches the existing
PR CI tradeoff and should reduce release wall time substantially.
- The called workflow checks out the requested ref shallowly. That is
intentional for verify lanes; publish and preview jobs still retain
their existing full-history checkouts.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex, GPT-5-class coding agent in local tool-use mode with shell
execution, repository editing, GitHub connector access, and medium
reasoning.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-09 19:28:00 -05:00
Dotta f3ca4d24bc
fix: repair dirty/foreign-branch execution worktrees (#9297)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Execution workspaces are the bridge between Paperclip's control
plane and a local agent's checked-out repository state.
> - When a workspace is restored after a failed or interrupted run, the
recorded branch can disagree with the branch currently checked out on
disk.
> - A clean branch mismatch can be reconciled safely, but a dirty
mismatch needs a lossless path that does not discard uncommitted agent
work.
> - This pull request adds a quarantine-and-restore path that saves
dirty work to a rescue branch, restores the recorded branch, and exposes
the repair from the board UI and run page.
> - The benefit is that operators can recover wedged execution
workspaces without losing work or moving another live branch
unexpectedly.

## Linked Issues or Issue Description

No public GitHub issue exists for this workspace-recovery failure, so
this PR includes the bug report inline.

**What happened**

A git worktree-backed execution workspace could become wedged when
Paperclip expected one branch but found a different checked-out branch
with dirty tracked or untracked files. The existing safe repair path
refused the restore, leaving the source task blocked with no lossless
one-click recovery path.

**Expected behavior**

Paperclip should preserve dirty work before restoring the recorded
workspace branch. If another live workspace claims the checked-out
branch, or an attached runtime service is active, the repair should
refuse with clear operator-facing evidence instead of risking work loss
or file contention.

**Steps to reproduce**

Create a git worktree execution workspace whose persisted branch name
differs from the checked-out branch, add dirty tracked or untracked
files in that worktree, then trigger workspace validation or use the
branch reconcile endpoint. Before this change, the dirty mismatch
remained blocked because Paperclip had no quarantine restore mode.

**Paperclip version or commit**

Observed on the pre-fix workspace-recovery implementation. Verified on
this PR head after rebasing onto current `master`.

**Deployment mode**

Local trusted development/worktree deployments using git worktree
execution workspaces and optional workspace runtime services.

## What Changed

- Added dirty-worktree quarantine repair that creates a rescue branch,
commits dirty tracked and untracked files there, restores the recorded
branch, writes audit comments/activity, and preserves the live foreign
branch ref.
- Added `quarantine_restore` branch reconcile API support,
recovery-action resolution, source-task wake behavior, execution-review
preservation, claimant refusal, runtime-service refusal, and coverage
for the non-transactional git ordering.
- Added board UI controls for the repair action in the recovery card
plus a compact failed-run workspace recovery surface that uses the same
reconcile handlers.
- Hardened Greptile follow-up cases by best-effort restoring the
recorded branch after a mid-sequence rescue commit failure and by
refusing quarantine restore while attached runtime services are active.

## Verification

- `pnpm exec vitest run
server/src/__tests__/execution-workspaces-service.test.ts -t
"quarantine_restore"`
- `pnpm exec vitest run server/src/__tests__/workspace-runtime.test.ts
-t "workspace dirty quarantine branch repair"`
- `pnpm exec vitest run
server/src/__tests__/heartbeat-workspace-finalize-branch.test.ts -t
"repairs clean unrecorded branch drift|adopts unrecorded forward branch
drift"`
- `pnpm exec vitest run
server/src/__tests__/workspace-runtime-routes-authz.test.ts`
- `pnpm --filter @paperclipai/server typecheck`
- Earlier PR verification covered the route, service, heartbeat, UI
component, and run-page recovery surfaces; Cutter posted public preview
screenshots for the repair popover and run-page panel at
https://github.com/paperclipai/paperclip/pull/9297#issuecomment-4926934211.
- GitHub PR checks are green on
`dcac76b05f4cf6e1ee16544c2831d83c7857e475`.
- Greptile is 5/5 with zero annotations and no unresolved review threads
on `dcac76b05f4cf6e1ee16544c2831d83c7857e475`.

## Risks

- Moderate risk because the change intentionally runs git commands
against local worktrees; the implementation refuses dirty repair when
another claimant or active runtime service is detected and records
rescue refs for auditability.
- Compatibility / release-note callout for self-hosted operators:
existing instances that left `enableWorkspaceBranchReconcileForward`
unset now get automatic forward branch reconciliation during heartbeat
workspace recovery. Operators who want the previous advisory-only
behavior can set `experimental.enableWorkspaceBranchReconcileForward` to
`false`; dirty quarantine repair can likewise be disabled with
`experimental.enableWorkspaceDirtyQuarantineRepair: false`.
- If the git rescue succeeds but a later database write fails, the
worktree may already be restored while the recovery action remains open;
this ordering is documented in code because git side effects cannot
participate in the database transaction.
- UI risk is limited to the workspace recovery surfaces and covered by
component tests plus the existing Cutter visual preview.

## Model Used

OpenAI Codex coding agent based on GPT-5, with repository tool use,
shell execution, and local test execution. Earlier preserved commits on
this branch also show Claude Code / Claude Opus 4.8 assistance in their
commit metadata.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] Branch naming exception documented: this PR preserves the existing
worktree branch requested for publication while keeping the PR title and
body public-facing
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 18:19:49 -05:00
Dotta 4d898aa7af
feat(prompt): one-time execution-workspace branch guard in wake prompt (PAP-13326) (#9319)
## Summary

When a task runs in a branch-pinned execution workspace, agents
sometimes switch or rename the workspace branch, which breaks the
worktree contract. This adds a short, one-time prompt hint telling the
agent to stay on the pinned branch.

- **heartbeat.ts**: after the execution workspace is resolved, attach
`executionWorkspace: { branchName }` to the wake payload (only when a
branch pin exists — agent-home runs without a branch are untouched).
- **server-utils.ts (adapter-utils)**: normalize the new payload field
and render one bullet in `renderPaperclipWakePrompt`:
> `- execution workspace branch: you are running in an execution
workspace on branch \`<name>\`. Do not switch, rename, or re-point this
branch; keep all commits on it.`
- The hint renders **only on non-resumed sessions** — resume-delta
prompts skip it, so it appears the first time an issue's session starts,
not on every turn, and it never pollutes the issue thread. One renderer
change covers every adapter (claude, codex, cursor, gemini, grok,
opencode, pi, hermes, acpx engine) with zero per-adapter edits.

## Tests

- `server-utils.test.ts`: branch guard renders on first prompt, absent
on resumed-session prompts, absent when no branch is pinned; payload
round-trips through `stringifyPaperclipWakePayload`.
- `heartbeat-workspace-branch-containment.test.ts`: the finalize-path
adapter mock now asserts the wake payload the adapter receives carries
the branch pin matching `context.paperclipWorkspace.branchName`
(end-to-end heartbeat wiring, embedded postgres). All 6 pass.
- Full `server-utils` (56) and acpx-engine execute (34) suites green;
adapter-utils typechecks clean; no new server tsc errors.

PAP-13326

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-09 17:53:00 -05:00
Dotta 176645187c
Fix request storm polling and issue-list coalescing (#9190)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The board UI keeps issue, agent, activity, and run state fresh
through polling across several pages and sidebar surfaces
> - When multiple components or browser tabs poll the same company data
at the same time, the API can receive bursts of duplicate issue-list
requests
> - Those duplicate requests increase database and server load without
returning meaningfully different data
> - This pull request adds server-side compression/coalescing plus
client-side visibility-aware and cross-tab shared polling
> - The benefit is lower request volume during normal board usage while
preserving fresh UI data for active users

## Linked Issues or Issue Description

No exact public GitHub issue was found for this request.

Problem:
- The board can issue redundant polling requests for the same issue-list
data from multiple UI surfaces and tabs.
- In busy operator sessions, those bursts can trigger request-storm
behavior and unnecessary issue-list load.
- Expected behavior is to reuse identical in-flight work server-side and
reduce hidden-tab or duplicate-tab polling client-side while preserving
normal refresh behavior.

Related public context found during duplicate search:
- #8206 covers a different board UI 404-storm scope.
- #5165 covers separate issue-list behavior around page-size truncation.

## What Changed

- Added API compression middleware foundation and a company/created-at
index for heartbeat run access.
- Added server-side issue-list request storm detection and identical
in-flight request coalescing.
- Added UI fetch metadata, visibility-aware polling, and request
deduplication for issue/activity/client calls.
- Added cross-tab shared polling primitives and wired them into the
sidebar, inbox, dashboard, issue, project, routine, and agent surfaces.
- Resolved the latest `master` migration collision by keeping upstream
`0140_built_in_managed_resources.sql` and renumbering this branch's
heartbeat-run index migration to
`0141_heartbeat_runs_company_created_at_index.sql`; the SQL uses `CREATE
INDEX IF NOT EXISTS` for idempotency.
- Stabilized server heartbeat cleanup tests exposed by the PR check
matrix.
- Fixed the Greptile compression follow-up by weakening strong ETags on
encoded JSON responses and bypassing compression for streamed/download
responses.

## Verification

- `pnpm exec vitest run ui/src/components/IssuesList.test.tsx
ui/src/pages/Inbox.test.tsx` — passed after resolving the latest
`master` conflict in `IssuesList.tsx` and updating the 200-result cap
expectations.
- `pnpm check:token-gates` — passed after the UI conflict resolution.
- `jq -e '.entries | length as $n | (map(.idx) | unique | length == $n)
and (map(.tag) | unique | length == $n)'
packages/db/src/migrations/meta/_journal.json` — passed after
renumbering the migration to `0141`.
- `pnpm exec vitest run server/src/__tests__/api-compression.test.ts` -
passed after the compression follow-up.
- `pnpm exec vitest run
server/src/__tests__/issue-list-assignee-filter-routes.test.ts` - passed
after the compression follow-up.
- `pnpm --filter @paperclipai/server typecheck` - passed after the
compression follow-up.
- Greptile Review for head `8dbddac41ec273fda404100b4981ddb912fad57b` -
passed after the latest conflict/migration fix; all Greptile review
threads are resolved.
- `pnpm exec vitest run server/src/__tests__/api-compression.test.ts
server/src/__tests__/issue-list-assignee-filter-routes.test.ts
ui/src/api/client.test.ts ui/src/api/issues.test.ts
ui/src/lib/polling.test.ts ui/src/lib/cross-tab-poll.test.ts
ui/src/pages/Inbox.test.tsx ui/src/components/SidebarProjects.test.tsx
ui/src/components/SidebarAccountMenu.test.tsx
ui/src/lib/issueDetailCache.test.ts` — passed.
- `pnpm exec vitest run ui/src/api/client.test.ts` — passed.
- `pnpm exec vitest run ui/src/pages/Inbox.test.tsx
ui/src/components/SidebarProjects.test.tsx
ui/src/components/SidebarAccountMenu.test.tsx
ui/src/lib/issueDetailCache.test.ts` — passed.
- `pnpm exec vitest run
server/src/__tests__/heartbeat-worktree-suppression.test.ts` — passed.
- `pnpm exec vitest run
server/src/__tests__/low-trust-red-team-routes.test.ts` — passed.
- `pnpm exec vitest run
server/src/__tests__/heartbeat-workspace-finalize-branch.test.ts` —
passed.
- `pnpm --filter @paperclipai/ui typecheck` — passed.
- `pnpm --filter @paperclipai/server typecheck` — passed.
- GitHub PR checks for head `8dbddac41ec273fda404100b4981ddb912fad57b`:
all GitHub Actions/status checks passed; Greptile, Superagent, Socket,
Snyk, build, typecheck/release registry, general tests, serialized
server suites, e2e, canary dry run, policy, and commitperclip review are
green; Storybook visual regression and security-review were
skipped/neutral by policy.
- Confirmed this branch does not include `pnpm-lock.yaml` or
`.github/workflows` changes.

## Risks

- Medium risk: issue-list coalescing changes request timing and cache
semantics for a hot API path.
- Medium risk: cross-tab polling uses browser coordination primitives,
so older or unusual browser environments need fallback behavior to stay
correct.
- Low migration risk: the new index migration is ordered after current
`master` and uses `CREATE INDEX IF NOT EXISTS`.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex coding agent, GPT-5-based model, tool-enabled with
shell/git execution. Exact hosted deployment identifier and
context-window size were not surfaced in the agent runtime.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-09 17:38:34 -05:00
Nicky Leach 4856558fd9
Fix skills routes to skip user secret resolution
Skip user_secret_ref bindings when resolving adapter config for agent skill listing and sync paths, while keeping normal runtime resolution strict. Add route and service regression tests for required user-secret refs in adapter config.
2026-07-09 15:09:58 -07:00
Dotta 8b6a06ee25
[codex] Add built-in agents and Reflection Coach bundle (#9206)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Operators need first-party agent capabilities for repeatable company
work, not just manually created one-off agents.
> - Built-in agents need to behave like normal company-scoped agents
while preserving approval gates, permissions, budgets, and audit trails.
> - Reflection and coaching work also needs bundled instructions, skill
content, and a routine so the feature can be installed and reset
predictably.
> - The API, database, UI, portability, and tests all need to agree on
the built-in lifecycle from not provisioned through setup, approval,
ready, paused, and reset.
> - This pull request adds built-in agent provisioning and the
Reflection Coach bundle end-to-end.
> - The benefit is a safer first-party path for Paperclip-managed agents
without bypassing the same governance model used for operator-created
agents.

## Linked Issues or Issue Description

No public GitHub issue was found for this exact built-in agent and
Reflection Coach bundle work.

Problem/motivation:
- Paperclip did not have a first-party built-in agent lifecycle for
product-owned agents.
- Bundled agent resources such as default instructions, skills, and
routines needed managed ownership and reset semantics.
- Approval-gated companies needed built-in setup to preserve requested
adapter, budget, manager, and permission state through board approval.
- The board UI needed clear built-in badges, setup affordances,
readiness state, and bundle status without exposing secrets.

Proposed solution:
- Add a company-scoped built-in agent registry,
provisioning/reset/reconcile/status APIs, and Reflection Coach bundled
resources.
- Track bundled managed resources in the database with idempotent
migration behavior.
- Reuse existing agent approval, authorization, budget, and activity-log
paths instead of creating a bypass.
- Add UI setup, badges, gates, bundle panels, and route coverage for
built-in agents.

Duplicate search:
- Searched GitHub PRs for `built-in agents Reflection Coach
repo:paperclipai/paperclip`; only this PR was returned.
- Searched GitHub issues for the same query; no public issues were
returned.

## What Changed

- Added built-in agent definitions, lifecycle state derivation,
provisioning, reset, reconcile, status, and routine-control routes.
- Added the `built_in_managed_resources` migration and schema exports
for bundled instructions, skill, and routine ownership.
- Added the Reflection Coach built-in bundle with default instructions,
skill catalog content, routine template, default permissions, and
managed-resource drift handling.
- Added approval-aware provisioning behavior that preserves requested
adapter config, budgets, manager assignment, and built-in permissions
through hire approval.
- Added authorization and mutation gates for built-in agent and skill
changes, including consented Reflection Coach change paths.
- Added UI surfaces for built-in agent setup, roster/detail badges,
readiness gates, bundle status, routine controls, and route filtering.
- Added company import/export and validator coverage for built-in
managed resources and low-trust/red-team presets.
- Addressed Greptile follow-ups for pending approval reconciliation,
consent-gate error propagation, config-read authorization fallback,
approval-path manager preservation, and non-model adapter provisioning.

## Verification

Local verification:
- `git diff --check public/master..HEAD` passed.
- `pnpm check:token-gates` passed with all gates clean.
- `pnpm exec vitest run
ui/src/components/ConfigureBuiltInAgentModal.test.tsx` passed: 1 file, 4
tests.
- `pnpm exec vitest run ui/src/components/EntityRow.test.tsx
ui/src/pages/Agents.test.tsx ui/src/components/BuiltInAgentGate.test.tsx
ui/src/components/ConfigureBuiltInAgentModal.test.tsx
ui/src/components/BuiltInBundlePanel.test.tsx
ui/src/pages/InstanceExperimentalSettings.test.tsx
ui/src/pages/Routines.test.tsx` passed: 7 files, 64 tests.
- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/built-in-agents.test.ts
src/__tests__/authorization-service.test.ts
src/__tests__/company-skills-routes.test.ts` passed: 3 files, 91 tests.
- `pnpm --filter @paperclipai/db check:migrations` passed.
- `pnpm -r typecheck` passed after the rebase; `pnpm --filter ui
typecheck` passed after the final UI review fix.

Remote verification on latest head
`1c61f693a4ec881d739022b0e75a8ca8bf8c2cd8`:
- Merge state: `CLEAN`.
- Greptile: `5/5`, zero unresolved Greptile threads.
- PR check rollup: all checks successful, neutral, or skipped as
expected.
- Passing gates include Build, Typecheck + Release Registry, all server
shards, all workspace shards, all serialized server suites, e2e, Canary
Dry Run, policy, review, verify, Socket, Superagent, and Snyk.

## Risks

- This adds a new managed-resource table and migration; the migration
uses idempotent create/add/index guards and passed migration safety
checks.
- Built-in agent provisioning touches approval and authorization paths;
tests cover pending approval preservation, stale retry rejection,
consent gates, and config-read fallback behavior.
- Reflection Coach creates managed instructions, skill, and routine
resources; drift/reset behavior is covered by service tests and redacted
API responses.
- Non-model adapter setup now provisions a `needs_setup` built-in row
before command/endpoint fields are complete; this matches the server
lifecycle and is covered by the setup modal regression test.

## Model Used

OpenAI Codex coding agent based on GPT-5. Exact hosted model ID,
context-window size, and reasoning-mode labels are not exposed in this
runtime; tool use, shell execution, GitHub CLI/API access, and local
code editing were enabled.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-09 16:29:30 -05:00
Dotta b13eb5b2b5
Skill Studio: three-pane skill IDE with sandboxed test runs (#9241)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Skills Manager gives operators a reusable skill layer, but
iteration still required manual edits, ad hoc prompts, and indirect run
inspection.
> - Skill authors need a focused workflow for editing skill files,
saving representative test inputs, and running those inputs through an
agent without exposing harness tasks as normal company work.
> - The backend therefore needs durable test inputs, reusable run
templates, hidden harness issues, scoped run execution, retention
metadata, and read-containment rules around hidden work.
> - The frontend needs a three-pane Studio that keeps skill files, saved
inputs/templates, and run output/history visible together while
preserving the existing design system and token rules.
> - This pull request ships that Skill Studio surface end to end:
database migrations, shared contracts, server APIs/services, hidden
harness execution behavior, UI routes/components, and focused tests.
> - The benefit is faster and safer skill iteration, with inspectable
outputs and fewer ways for internal harness work to leak into normal
task lists, costs, or adjacent read APIs.

## Linked Issues or Issue Description

No public GitHub issue exists for this feature. Feature request summary:

- Problem: Skill authors need to edit and test company skills in one
place instead of switching between the skill detail page, task creation,
run output, and manual prompt history.
- Proposed solution: Add a Skill Studio workbench with saved inputs,
reusable templates, hidden sandboxed test runs, live run status, output
inspection, run history, rerun/delete controls, and frontmatter-aware
editing.
- Expected users: Paperclip operators and agent-company maintainers who
create, fork, import, and tune skills.
- Related public PRs: Supersedes #9205, which was replaced so the public
PR branch name follows contributor policy.
- Duplicate search: searched public GitHub issues and PRs for "Skill
Studio"; no other active public issue or PR directly covers this
feature.

## What Changed

- Added database migrations for Skill Studio test inputs, test runs,
test run retention, and reusable run templates.
- Added shared Skill Studio types, validators, route helpers,
frontmatter utilities, and status handling.
- Added server services and routes for saved inputs, test runs,
templates, reruns, terminal-run deletion, hidden harness issue
execution, and run-detail hydration.
- Strengthened hidden-issue read containment across issue-adjacent
routes and cost rollups used by skill test harness work.
- Added the Skill Studio UI with skill file editing, frontmatter
editing, saved inputs, templates, run creation/cancel/rerun/delete
flows, output rendering, history, route support, and responsive pane
behavior.
- Added focused backend, shared, and UI tests for the new APIs, routing
logic, editor/run behavior, hidden-issue containment, and migration
safety.
- Rebased onto current `master`, removed the generated lockfile diff
from the PR, and verified no workflow files are changed.

## Verification

- [x] `pnpm --filter @paperclipai/db check:migrations`
- [x] `pnpm check:token-gates`
- [x] `pnpm exec vitest run
server/src/__tests__/company-skills-service.test.ts
server/src/__tests__/company-skills-routes.test.ts
server/src/__tests__/company-skill-test-runs-service.test.ts
ui/src/lib/skill-studio.test.ts ui/src/pages/SkillStudio.test.tsx` — 5
files, 132 tests passed
- [x] Greptile review on the latest PR head
- [x] GitHub PR checks on the latest PR head

## Risks

- Medium risk because this is a broad feature touching database schema,
server orchestration, issue visibility, and a large UI surface.
- Hidden harness issue containment is security-sensitive; this PR
includes regression coverage for adjacent read paths and cost rollups.
- The new migrations are additive and use idempotent guards where
applicable, but deployed databases that previously tested draft
migration numbers should still be checked carefully.
- The UI depends on a new resizable panels package in `ui/package.json`;
the lockfile is intentionally left to repository automation.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex, GPT-5 coding agent with shell, git, and GitHub CLI tool
use. Earlier feature commits include assistance from other Paperclip
coding agents; this PR preparation, rebase, cleanup commit, and PR body
were completed by OpenAI Codex in a Paperclip worktree.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 13:08:56 -05:00
Dotta 1c75a46c10
feat(ui): add waiting-on-live-work blocked notice (#9298)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Operators rely on the issue detail thread to understand whether a
task is blocked, live, or waiting on another task.
> - A blocked issue can have a healthy blocker chain where downstream
work is actively running and the parent will resume automatically.
> - Showing that case with the same amber blocked notice as a stalled or
attention-needed blocker makes the state look more severe than it is.
> - The UI already receives blocker-attention state, blocker summaries,
and company live-run ids, so this can be clarified without a new API
shape.
> - This pull request adds a blue "Waiting on live work" notice for
covered blocker chains while preserving the existing amber notice for
the other blocked states.
> - The benefit is that operators can distinguish healthy queued work
from blocked work that needs intervention.

## Linked Issues or Issue Description

Refs #3820
Refs #8271
Related PR: #3877
Supersedes #9295

## What Changed

- Added a blue `IssueBlockedNotice` variant when
`blockerAttention.state` is `covered` and the blocker chain has live
work.
- Rendered blocker-chain progress as done, running, and queued steps,
including a "Now running" row for live terminal blockers.
- Preserved the existing amber blocked notice for stalled,
attention-needed, ordinary blocked, and successful-run handoff states.
- Plumbed the existing `liveIssueIds`, `blockedBy`, and
`blockerAttention` data from issue detail into the chat-thread blocked
notice.
- Added regression coverage around the covered live-work state, the
no-confirmed-live fallback, numeric step ordering, and amber fallback
states.
- Hardened a low-trust server route test cleanup helper so CI deletes
heartbeat run events before deleting heartbeat runs.

## Verification

- `pnpm check:token-gates`
- `pnpm --filter @paperclipai/ui typecheck`
- `pnpm exec vitest run ui/src/components/IssueBlockedNotice.test.tsx`
- GitHub PR workflow is green on head
`52ab6d9076ce233c183bf7133fa666e8597b6765`.
- Greptile check is green on head
`52ab6d9076ce233c183bf7133fa666e8597b6765` with zero unresolved review
threads.

## Risks

Low runtime risk: the product change is frontend-only and uses data
already returned to the issue detail page. The main risk is visual
regression in the blocked notice; the change keeps non-covered states on
the existing amber path and adds focused regression coverage. The
server-side change is test-only cleanup for an existing CI shard
failure.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex using GPT-5, tool-use enabled in a repository workspace.
The runtime did not expose a more specific model build id or
context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-09 10:59:18 -05:00
Dotta 7cf0d3ebb0
Require health readiness for Paperclip dev services (#9269)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents often run against managed workspace runtime services,
including reusable Paperclip dev servers
> - A running process and an open root URL are not enough to prove the
Paperclip API is actually ready
> - If the API health endpoint is still failing, agents can reuse a
service that looks alive but cannot safely serve the board or API
clients
> - This pull request makes Paperclip dev runtime readiness probe the
resolved `/api/health` endpoint
> - The benefit is that runtime service reuse waits for the same health
signal operators and agents depend on

## Linked Issues or Issue Description

No matching public GitHub issue was found. Public duplicate search found
no open PR for "workspace runtime health readiness".

Bug report:

### What happened?

A managed Paperclip dev runtime service could satisfy HTTP readiness at
the exposed base URL even when the Paperclip health endpoint was
returning an unhealthy status.

### Expected behavior

Paperclip dev runtime services should not be considered ready until
their health endpoint succeeds.

### Steps to reproduce

1. Start a workspace runtime service named `paperclip-dev` whose base
URL responds successfully.
2. Make that same service return HTTP 503 from `/api/health`.
3. Ask Paperclip to ensure the runtime service for a run.
4. Observe that the service can be reused even though the API health
endpoint is not ready.

### Paperclip version or commit

Current `origin/master` before this PR.

### Deployment mode

Local workspace runtime service management.

## What Changed

- Resolve Paperclip dev runtime readiness checks to the service health
URL before polling.
- Surface readiness errors with the actual health URL that failed.
- Add a regression test that fails when `/api/health` returns HTTP 503
even if the service process is running.

## Verification

- `pnpm exec vitest run server/src/__tests__/workspace-runtime.test.ts`
— 81 tests passed.
- `git diff --check origin/master...HEAD` — passed.

## Risks

- Low to medium risk. This tightens readiness for Paperclip dev runtime
services, so a service that previously looked ready while unhealthy will
now fail fast instead of being reused.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex coding agent based on GPT-5, tool-enabled shell workflow.
Exact hosted model variant and context window were not exposed by the
runtime.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-09 08:25:59 -05:00
Nicky Leach 719da5f9b5
Harden environment deletion and expose delete blast radius (#9250)
## Thinking Path

> - Paperclip manages AI agents that each have an associated execution
environment (local, Kubernetes, etc.)
> - Instance administrators can create and delete environments;
currently the DELETE endpoint has no protection against deleting managed
or in-use environments
> - Deleting the managed local environment or the instance-default
environment would break all agents using those environments with no path
to recovery
> - The endpoint also suffered a TOCTOU race: a check-then-delete
pattern allowed the managed-local or default guard to pass if the
environment's role changed between the read and the delete
> - This pull request adds a blast-radius read endpoint so admins can
preview impact, hard-blocks the dangerous deletes atomically, cleans up
all dependent references after a valid delete, and fixes a concurrent
creation race in ensureLocalEnvironment

## Linked Issues or Issue Description

Fixes #9251

## What Changed

- **New endpoint** `GET /api/environments/:id/delete-blast-radius`
(instance-admin gated): returns reference counts (agent defaults,
workspace selections, issue selections, project selections, secret
bindings, active leases, active setup sessions) and blocking reasons —
no config, env-var values, or secret data returned.
- **Atomic delete guard** `environmentService.removeIfDeletable(id)`:
performs the DELETE with an inline `WHERE driver != 'local' AND NOT
EXISTS (instanceSettings where defaultEnvironmentId = id)` predicate,
eliminating the TOCTOU race between the app-level check and the DB
write.
- **Route hardening**: `DELETE /environments/:id` now calls
`getDeleteBlastRadius` first (app-level check + logging), then calls
`removeIfDeletable` (atomic guard). If the atomic guard returns null the
route fetches a fresh blast-radius snapshot and rejects with a 409
Conflict carrying `deleteBlockedReasons`.
- **Reference cleanup on valid delete**: after a successful delete, the
route clears environment selections on all company execution workspaces,
issues, and projects; syncs env-var secret bindings to `{}` (removing
bindings for the deleted environment); syncs config secret refs to `[]`
for the environment target; and removes the SSH private-key secret if
one was stored.
- **Race fix in `ensureLocalEnvironment`**: the insert-or-nothing path
now catches a `environments_name_idx` unique-constraint violation and
falls through to the existing SELECT, treating the name conflict as
idempotent.
- **Shared types**: `EnvironmentDeleteBlastRadius` and
`EnvironmentDeleteBlockedReason` exported from `@paperclipai/shared`.
- **OpenAPI**: registers the new blast-radius endpoint; updates the
delete-environment response schema to document 403/404/409.
- **Tests**: 56 existing environment-route and service tests continue to
pass; new service-level regression tests assert the atomic guard rejects
`local`-driver environments and instance-default environments and
succeeds for deletable ones.

## Verification

```
corepack pnpm exec vitest run \
  server/src/__tests__/environment-routes.test.ts \
  server/src/__tests__/environment-service.test.ts
# 56 tests, all passing
corepack pnpm --filter @paperclipai/shared typecheck
node scripts/ensure-plugin-build-deps.mjs
cd server && ../node_modules/.bin/tsc --noEmit
```

## Risks

- **Blast-radius endpoint auth**: guarded by
`assertCanAccessInstanceEnvironments`, the same gate as the existing
environment-list and delete routes. Non-admin callers receive 401/403
before any data is returned.
- **Atomic guard may reject a delete that the app-level check passed**:
this is intentional — it means the environment became protected between
the read and the write. The caller receives a fresh blast-radius
snapshot explaining why.
- **Secret cleanup ordering**: cleanup runs after the atomic DELETE
succeeds, in parallel across companies. If cleanup partially fails the
environment row is already gone; partial-cleanup state is recoverable by
re-running the sync operations. Risk: low — these are idempotent
upsert/sync operations.
- **ensureLocalEnvironment race fix**: swapping a unique-constraint
error for an idempotent SELECT adds one extra query on the conflict
path. This path is rare (only fires during concurrent boot) and is
significantly safer than the previous behavior.
- **No migration**: all changes are application-level; no schema changes
required.

## Model Used

- Provider: Anthropic
- Model: claude-sonnet-4-6 (Claude Sonnet 4.6)
- Context window: 200k tokens
- Mode: agentic tool use via Paperclip agent system (Claude Code)

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `fix/...`) and contains
no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Priya Raman <priya.raman@paperclip.ing>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Harold Kim <harold.kim@paperclip.ing>
2026-07-08 22:04:22 -07:00
Devin Foley eedc7ddef2
Make ACP the default engine for local adapters (#9238)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Adapter packages are the bridge between the control plane and local
agent harnesses such as Claude Code, Codex, and Gemini CLI.
> - ACP support was concentrated in a separate `acpx_local` adapter,
which made ACP feel like a separate agent choice instead of an execution
capability of the harness adapters.
> - Claude, Codex, and Gemini now have ACP-capable harnesses, so the
native adapter should own ACP selection, fallback, config, transcript
parsing, and environment diagnostics.
> - The standalone ACPX adapter still needs a compatibility path for
existing rows, but it should not be offered as an active adapter for new
agents.
> - This pull request moves the shared ACP runtime into
`@paperclipai/acpx-engine`, wires Claude/Codex/Gemini local adapters to
prefer ACP when prerequisites are available, and retires `acpx_local` to
a tombstone.
> - The benefit is one adapter per harness, richer ACP transcripts by
default where possible, and a migration path for existing Claude/Codex
ACPX agents.

## Linked Issues or Issue Description

Closes #5932 — the broken default `acpx_local` Claude path is replaced
by native `claude_local` ACP support, existing Claude/Codex ACPX rows
migrate to native adapters, and new agents no longer choose the
standalone ACPX adapter.

Refs #4893 — original merged ACPX local adapter runtime that this PR
replaces with native per-harness ACP engines.
Refs #6590 — prior ACPX-Claude seamlessness work folded into the new
native Claude ACP path.
Refs #197 — related open generic ACP/Kiro adapter work; this PR does not
close it because Kiro/custom generic ACP remains a separate adapter
decision.
Refs #7018 — related Kimi-specific `acpx_local` shell failure; this PR
retires the built-in standalone adapter but does not add a native Kimi
adapter.
Refs #8864 — related ACPX prompt/API guidance PR; this PR moves runtime
guidance into the shared/native ACP engine path instead of the old
standalone adapter.
Refs #8881 — related `acpx_local` POSIX shell failure from the old
`acpx` pin; this PR updates ACP dependencies but does not claim
custom/OMP ACP support as a first-class native adapter.
Refs #8964 — related open `acpx_local` stderr cleanup PR; this PR makes
the old runtime path obsolete for new agents but keeps it as a
non-closing reference.

Problem description:

- The standalone `acpx_local` adapter duplicates Claude/Codex agent
choices that already have first-class local adapters.
- ACP should be an execution engine capability of each harness adapter
when the underlying harness supports ACP.
- Existing `acpx_local` agents should either migrate to native harness
adapters or fail with an explicit retirement message instead of silently
falling back to the process adapter.

## What Changed

- Added `@paperclipai/acpx-engine` as the shared ACP execution,
session-codec, CLI formatter, and UI parser package.
- Wired `claude_local`, `codex_local`, and `gemini_local` to auto-select
ACP by default when prerequisites pass, with `engine=cli` opt-out and
`engine=acp` strict mode.
- Added ACP config schema/UI fields, environment checks, session-codec
preservation, transcript parsing, and adapter capability metadata for
the native adapters.
- Retired `acpx_local` to a server tombstone, removed its
UI/package/runtime image surface, and added a migration for existing
Claude/Codex ACPX agents.
- Updated package manifests, lockfile, release tooling, docs, Kubernetes
sandbox defaults, and tests.

## Verification

- `corepack pnpm --filter @paperclipai/acpx-engine typecheck`
- `corepack pnpm --filter @paperclipai/adapter-claude-local typecheck`
- `corepack pnpm --filter @paperclipai/adapter-codex-local typecheck`
- `corepack pnpm --filter @paperclipai/adapter-gemini-local typecheck`
- `corepack pnpm --filter @paperclipai/acpx-engine exec vitest run`
- `corepack pnpm --filter @paperclipai/adapter-claude-local exec vitest
run src/server/acp.test.ts src/server/execute.acp-fallback.test.ts
src/ui/build-config.test.ts`
- `corepack pnpm --filter @paperclipai/adapter-codex-local exec vitest
run src/server/acp.test.ts src/ui/build-config.test.ts`
- `corepack pnpm --filter @paperclipai/adapter-gemini-local exec vitest
run src/server/acp.test.ts src/ui/build-config.test.ts
src/ui/parse-stdout.test.ts`
- `corepack pnpm --filter @paperclipai/plugin-sdk ensure-build-deps &&
corepack pnpm --filter @paperclipai/server exec tsc --noEmit`
- `corepack pnpm --filter @paperclipai/server exec vitest run
src/__tests__/adapter-routes.test.ts
src/__tests__/adapter-session-codecs.test.ts
src/__tests__/adapter-models.test.ts`
- `corepack pnpm --filter @paperclipai/ui typecheck`
- `corepack pnpm --filter @paperclipai/ui exec vitest run
src/adapters/metadata.test.ts
src/adapters/adapter-display-registry.test.ts
src/components/AgentConfigForm.test.ts
src/components/AgentConfigForm.render.test.tsx
src/components/transcript/RunTranscriptView.test.tsx`
- `node --test scripts/bootstrap-npm-package.test.mjs
scripts/release-package-map.test.mjs
scripts/verify-release-registry-state.test.mjs`

Note: the server typecheck script calls `pnpm` internally; this dev
shell exposes pnpm through Corepack only, so I ran the two script steps
manually with `corepack pnpm`.

## Risks

- Migration changes existing `acpx_local` Claude/Codex agents to native
adapter types and clears old ACPX task sessions/runtime state.
- Custom ACP commands remain on the retired tombstone and will need a
separate future adapter/plugin path.
- ACP auto-selection depends on local Node and ACP server command
prerequisites; remote and unsupported environments fall back to CLI
unless `engine=acp` is explicit.
- `@paperclipai/acpx-engine` is a new public package and needs npm
trusted-publishing bootstrap before release automation can publish it.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI GPT-5 via Codex coding agent. Exact hosted model build and
context-window size are not exposed in this runtime. Tool use included
shell execution, repository editing, GitHub CLI operations, and local
test/typecheck execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-08 19:05:03 -07:00
Dotta 4a7a732476
feat(skills): add company skill fork prechecks (#9235)
Adds company skill fork precheck metadata, fork result/reassignment contracts, selected-agent reassignment during fork creation, and targeted server/shared test coverage.
2026-07-08 14:22:39 -05:00
Dotta f616b6746c
fix(server): clean heartbeat run scratch directories (#9234)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-07-08 13:38:36 -05:00
Nicky Leach 38cca22b09
fix(server): avoid accepted-plan workspace branch freeze before child realization (#9233)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents tackle complex tasks via *plan* flows: a planner decomposes
work into child issues, which are accepted by the board and then
executed
> - When a plan is accepted, `createChild` in `issues.ts` inserts child
issues pre-bound to the parent's already-realized execution workspace —
carrying over its concrete branch ref
> - If the repository's base ref advances between plan acceptance and a
child's first heartbeat, the child inherits a stale branch that no
longer matches the current base
> - At first heartbeat the workspace validator detects the mismatch and
freezes the child ("branch freeze"), blocking it from starting any work
> - The real fix is to strip the concrete workspace binding when
creating accepted-plan children: they should receive only the unresolved
*intent* (mode, baseRef, branchTemplate) and realize a fresh workspace
from the current base on their own first heartbeat
> - This PR implements that strip, adds a regression test that proves a
post-base-advance child realizes cleanly, and also fixes
`parseIssueExecutionWorkspaceSettings` so `environmentId` is not
silently dropped on update round-trips (a latent bug that was masking
the original fix)

## Linked Issues or Issue Description

No public GitHub issue exists for this bug. Bug description follows the
bug-report template:

**What happened:** Accepted-plan decomposition pre-binds child issues to
the parent's realized execution workspace branch (`executionWorkspaceId`
+ `executionWorkspaceBranch`). When `origin/master` advances between
plan acceptance and the child's first heartbeat, the workspace branch
interlock fires and the child is permanently frozen before it can start.

**Expected behavior:** Accepted-plan children should receive only
unresolved workspace intent (mode, git strategy fields) and realize a
fresh isolated worktree from the current base on first heartbeat. A
base-ref advance between acceptance and first-run should be transparent.

**Steps to reproduce:**
1. Accept a plan that decomposes into one or more child issues
(isolated_workspace + git_worktree mode).
2. Allow `origin/master` to advance (new merge).
3. Observe the first child heartbeat: workspace validation fails with a
branch-freeze error.

**Paperclip version:** current `master` (pre-fix).

**Deployment mode:** any (affects all modes that use isolated workspace
+ git worktree strategy).

Supersedes #9227 (earlier attempt, now closed — the fix was incomplete
because `environmentId` was silently dropped during
`parseIssueExecutionWorkspaceSettings` update round-trips, causing the
child workspace to lose its environment binding; this PR includes that
fix).

## What Changed

- **`server/src/issues.ts` — `createChild` / accepted-plan decomposition
path:** strip resolved workspace fields (`executionWorkspaceId`,
concrete branch) when creating accepted-plan children; preserve only
unresolved intent fields (`mode`, `baseRef`, `branchTemplate`,
`environmentId`, runtime/provisioning settings).
- **`server/src/execution-workspace-policy.ts` —
`parseIssueExecutionWorkspaceSettings`:** preserve `environmentId`
through update round-trips (was silently dropped, causing environment to
detach on any workspace settings update).
-
**`server/src/__tests__/heartbeat-accepted-plan-workspace-refresh.test.ts`:**
new regression test — accepted-plan child created after `origin/master`
moves realizes a fresh isolated worktree from the moved base and passes
workspace execution.
- **`server/src/__tests__/issues-service.test.ts`:** extended
workspace-linkage and `createChild` tests covering the accepted-plan
strip and the unchanged direct-child path.

## Verification

```sh
pnpm exec vitest run server/src/__tests__/heartbeat-accepted-plan-workspace-refresh.test.ts
pnpm exec vitest run server/src/__tests__/issues-service.test.ts -t "workspace linkage|accepted plan decomposition|createChild applies"
pnpm --filter @paperclipai/server typecheck
```

All three pass on this branch.

## Risks

**Low.** The change is scoped to the accepted-plan `createChild` code
path. The direct child / follow-up issue creation path (normal non-plan
decomposition) is unchanged and covered by existing tests. The
`parseIssueExecutionWorkspaceSettings` fix is additive — it now
preserves a field that was previously silently dropped, so no consumer
loses data.

## Model Used

Claude Sonnet 4.6 (`claude-sonnet-4-6`), Anthropic, 200K context window,
extended tool use + code generation.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above (supersedes #9227)
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-08 11:07:36 -07:00
Nicky Leach 88bf71b84e
Reject projectless isolated git worktree tasks (#9231)
## Thinking Path

> - Paperclip is an open-source platform for orchestrating AI agents;
agents run inside execution workspaces that range from a shared
container to full git worktrees cloned from a project repository.
> - Isolated git-worktree workspaces require a project to determine
which repository to clone — without a project the worktree base path
cannot be computed.
> - A task pinned to `isolated_workspace` + `git_worktree` with no
project was previously accepted at creation time but failed late at
dispatch with the opaque `workspace_validation_failed` /
`git_worktree_base_agent_home` error — only after the heartbeat
attempted to provision the workspace.
> - Fail-closed validation should happen in two places: (1) explicit
create/update pins that contradict the requirement are rejected at the
HTTP layer with a structured 422; (2) rows that reach the heartbeat
dispatcher with this invalid combination (e.g. through inheritance or a
retroactively-removed project) are blocked before any heartbeat run or
adapter spawn.
> - This PR adds the shared detection policy, the create/update guard in
the issues service, and the heartbeat pre-dispatch guard, together with
focused unit tests for all three layers.
> - The benefit is deterministic early failure with a clear remediation
message instead of a late, cryptic runtime error.

## Linked Issues or Issue Description

No upstream public GitHub issue — describing the problem inline
(bug-report format).

**What happened?**
Creating an issue with `executionWorkspaceSettings: { mode:
"isolated_workspace", type: "git_worktree" }` and no `projectId` was
accepted without error. The issue then became blocked at dispatch time
with the opaque message `git_worktree_base_agent_home` /
`workspace_validation_failed` — surfaced only after the heartbeat
attempted to provision the workspace.

**Expected behavior**
The platform should reject the invalid combination at create/update time
with a structured 422 that includes a clear remediation message, before
any heartbeat resource is consumed.

**Steps to reproduce**
1. Call `POST /api/issues` (or `PATCH /api/issues/:id`) with
`executionWorkspaceSettings: { mode: "isolated_workspace", type:
"git_worktree" }` and omit `projectId` (or set it to `null`).
2. Observe: request succeeds (200/201).
3. Assign the issue to an agent and watch it enter `blocked` with a
cryptic `workspace_validation_failed` error at dispatch.

**Related prior fix** — Refs #4844 (`fix(validator): reject static cwd
combined with git_worktree strategy`) — same validation area, different
dimension (static cwd vs. missing project).

**Paperclip version / commit**
Latest `master` (pre-this-PR).

**Deployment mode**
Standard (app-global server).

## What Changed

- **`execution-workspace-policy.ts`** — new shared
`detectWorkspaceWorktreeRequiresProject` function returning a stable
`workspace_worktree_requires_project` policy violation when an isolated
git-worktree task has no project, project workspace, or reusable
execution workspace; exports canonical remediation text used by both the
HTTP guard and the heartbeat guard.
- **`issues.ts`** — create and update paths check the new policy before
persisting; explicit pins to `isolated_workspace` / `operator_branch` +
`git_worktree` with no project are rejected with a 422 including the
policy code and remediation text.
- **`heartbeat.ts`** — pre-dispatch preflight checks the same policy for
rows that reach the heartbeat with the invalid combination (e.g. through
inheritance); such rows are marked `blocked` with a skipped wakeup
request, durable issue comment, and activity log before any heartbeat
run or adapter spawn.
- **`execution-workspace-policy.test.ts`** — focused policy-layer unit
tests for detection logic and remediation text.
- **`issues-service.test.ts`** — create/update 422 guard tests for the
new policy.
- **`heartbeat-workspace-branch-containment.test.ts`** — pre-dispatch
blocking test for inherited/ambiguous invalid rows; also fixes a cleanup
race in the existing test suite.

## Verification

```sh
pnpm exec vitest run \
  server/src/__tests__/execution-workspace-policy.test.ts \
  server/src/__tests__/issues-service.test.ts \
  server/src/__tests__/heartbeat-workspace-branch-containment.test.ts

pnpm --filter @paperclipai/server typecheck

# Targeted regression
pnpm exec vitest run \
  server/src/__tests__/heartbeat-workspace-branch-containment.test.ts \
  -t "blocks projectless isolated git-worktree issues before dispatch"
```

All three test files and typecheck passed locally before this PR was
opened.

## Risks

**Low risk.** The policy detection function is pure with no side
effects. The create/update guard only triggers on explicit
`isolated_workspace` or `operator_branch` + `git_worktree` pins combined
with a missing project — it does not fire on inherited settings (handled
by the heartbeat preflight), so there is no false-positive rejection
risk for valid tasks. The heartbeat guard fires before any resource is
provisioned; the only behavioral change for already-invalid rows is that
they receive a clear `blocked` status and durable comment instead of a
late cryptic error.

## Model Used

Claude Sonnet 4.6 (`claude-sonnet-4-6`), 200k context window, tool use
enabled (agentic coding). Used to implement all server-side changes and
tests in this PR.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-08 10:31:37 -07:00
Nicky Leach 11177c2665
Fix resolved blocker wake reconciliation (#9229)
## Thinking Path

> - Paperclip is an open source platform for managing AI agent companies
— agents pick up issues, do work, and release checkouts in a heartbeat
loop
> - Issue dependency resolution is handled by `issue_blockers_resolved`
wakes: when a blocking issue reaches `done`, dependent blocked issues
should be woken so they can resume
> - The workspace-finalize path maintained its own special-case loop to
retry missed dependency wakes at run completion, duplicating logic that
already exists in the shared level-triggered reconciliation backstop
> - Additionally, the resolved-blocker reconciliation sweep was gated
behind the broader liveness auto-recovery escalation setting — so
instances that disabled auto-escalation creation also lost the baseline
reconciliation sweep
> - This PR routes the workspace-finalize retry through the shared
backstop and decouples the reconciliation sweep from the escalation
creation gate
> - The benefit is simpler code (one authoritative path instead of two),
and correct behaviour on instances where escalation creation is disabled

## Linked Issues or Issue Description

No existing GitHub issue. Describing inline:

**Bug (blocker wake reconciliation):** `issue_blockers_resolved` wakes
can be missed when:

1. A `workspace_finalize` heartbeat retries dependency resolution using
its own inline loop instead of the shared level-triggered backstop,
making them diverge over time.
2. The `blockedByIssueIds` dependency is set (or the issue is moved to
`blocked`) *after* the blocker already reached `done` — the PATCH-time
wake fires on a non-blocked issue and the dependency reconciliation
never catches up.
3. An assignee briefly becomes `null` between the blocker reaching
`done` and the reconciliation sweep running — the sweep skips the issue
and never retries.

Related PRs:
- Refs #8009 — adds dedup for `issue_blockers_resolved` re-fires
(complementary; prevents over-firing; this PR ensures under-firing is
caught)
- Refs #6522 — `auto-unblock dependents with no assignee` (related
no-assignee edge case)

## What Changed

- **`server/src/services/heartbeat.ts`** — remove the inline
dependency-wake retry loop from the `workspace_finalize` path; delegate
to the shared `reconcileResolvedDependencyWakeups` helper instead
- **`server/src/services/recovery/service.ts`** — split the
resolved-blocker wake reconciliation sweep out from under the
`liveness_escalation_auto_recovery` feature flag; the sweep runs
unconditionally while escalation *creation* remains behind the flag
- **`server/src/__tests__/issue-dependency-wakeups-routes.test.ts`** —
regression: `blockedBy` set after blocker already done still triggers a
reconciliation wake
- **`server/src/__tests__/heartbeat-issue-liveness-escalation.test.ts`**
— regression: assignee-null churn before reconciliation; stale skipped
dependency wakes do not suppress a fresh reconciliation wake

## Verification

```
pnpm exec vitest run \
  server/src/__tests__/issue-dependency-wakeups-routes.test.ts \
  server/src/__tests__/heartbeat-issue-liveness-escalation.test.ts
```

23 tests, all passing locally. `pnpm --filter @paperclipai/server
typecheck` clean.

## Risks

Low risk. Bounded blast radius:
- The reconciliation sweep only considers non-hidden `blocked` issues
with an agent assignee
- Uses keyset pagination with an existing 500-candidate cap
- Reuses dependency readiness/finalize gating logic unchanged
- Skips issues with existing active/queued runs and pending interactions
- Deduplicates against live/completed `issue_blockers_resolved` wakes
(skipped/cancelled wakes intentionally do not suppress a fresh
reconciliation)
- Observability: healed reconciliations emit
`issue.blockers_resolved_wake_emitted` activity and log the healed issue
ids and source

## Model Used

Claude Sonnet 4.6 (`claude-sonnet-4-6`) with tool use and extended
context. Paperclip AI agent runtime.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-08 09:32:12 -07:00
Dotta 562567fcd6
[codex] Improve work timeline activity story (#9222)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The work timeline helps operators understand when agent and user
activity actually happened across a project.
> - The timeline view needs clearer interaction context so activity is
easier to inspect and reason about.
> - The existing story coverage did not fully exercise the denser
activity states needed to review this UI safely.
> - This pull request expands the work timeline data shape, service
behavior, UI rendering, tests, and Storybook story so the activity
timeline is easier to verify.
> - The benefit is a more inspectable timeline for project activity,
backed by targeted server and UI coverage.

## Linked Issues or Issue Description

No public GitHub issue found, so this PR describes the feature inline
following the feature request template.

**Subsystem affected**

Cross-cutting: `server/`, `packages/shared`, and `ui/`.

**Problem or motivation**

Project operators need a clearer timeline view that shows when work
activity happened, how much agent time is represented inside the
selected window, and enough realistic activity states for safe visual
review. Sparse mock data and unbounded summary calculations make it
harder to trust the timeline when inspecting historical or capped
windows.

**Proposed solution**

Enrich the work timeline activity data returned by the service, render
clearer top-level timeline summary stats, clamp duration calculations to
the returned window, prorate token totals for partially visible spans,
and add Storybook/test coverage with realistic timeline activity data.

**Alternatives considered**

Keeping the existing sparse timeline story was considered, but it would
leave dense activity layouts and selected-window summary behavior
under-reviewed. Counting full span usage for partially visible spans was
also considered, but it makes historical windows report activity outside
the displayed range.

**Roadmap alignment**

Searched `ROADMAP.md` for timeline/activity references and found no
conflicting planned core work.

**Additional context**

This PR does not include migrations and does not commit generated design
screenshots or images.

## What Changed

- Extended shared work timeline activity types and server timeline
service behavior.
- Updated the timeline page and work timeline chart for richer activity
rendering.
- Clamped timeline runtime summary calculations to the returned window
and prorated summary token usage for clipped spans.
- Added and updated targeted server/UI tests for timeline activity
behavior.
- Added Storybook timeline mock coverage and Storybook preview setup
needed by the story.

## Verification

- `git rebase origin/master` completed cleanly after fetching
`paperclipai/paperclip:master`.
- `git diff --check origin/master...HEAD`
- `pnpm exec vitest run
server/src/__tests__/work-timeline-service.test.ts
ui/src/components/timeline/WorkTimelineChart.test.tsx
ui/src/pages/Timeline.test.tsx` — latest run: 3 files passed, 28 tests
passed.
- Greptile review completed at 5/5 with no unresolved Greptile threads
after fixes.
- GitHub checks completed green on the latest head SHA; Storybook visual
regression was skipped by the workflow.
- `pnpm check:token-gates` currently fails locally on existing
`origin/master` violations in `ui/src/components/ActivityCharts.tsx` and
`ui/src/components/IssueRecoveryActionCard.tsx`; this PR does not modify
those files.

## Risks

Low to moderate risk. The change affects the work timeline service
response shape and timeline UI rendering, so regressions would likely
show up as missing/incorrect timeline activity display. Targeted service
and UI tests cover the changed behavior. No migrations are included.

## Model Used

OpenAI Codex running GPT-5 as a tool-enabled coding agent with local
shell and GitHub CLI access. Exact runtime model ID/context-window size
was not exposed by the environment.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-08 08:59:24 -05:00
Dotta 5d0de3499d
[codex] Fix collapsed starred project indentation (#9215)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The board sidebar is a high-frequency navigation surface for
companies, projects, and work queues.
> - Starred projects render as child rows under Projects in the expanded
sidebar.
> - The collapsed rail should align every nav icon in the same rail
column.
> - The starred-project child indent was still applied in the collapsed
rail, which pushed the project glyph out of alignment.
> - This pull request keeps the expanded hierarchy indent while removing
it only for the collapsed rail.
> - The benefit is a cleaner collapsed sidebar without changing expanded
sidebar hierarchy.

## Linked Issues or Issue Description

No public GitHub issue exists.

## What happened?

In the collapsed sidebar rail, starred project rows kept the expanded
child indentation. That pushed the project glyph out of alignment with
the rest of the collapsed sidebar icons.

## Expected behavior

Collapsed starred project icons should align with the other sidebar rail
icons while the expanded sidebar should keep the child-row indentation
under Projects.

## Steps to reproduce

1. Open Paperclip with at least one starred project.
2. Collapse the sidebar into rail mode.
3. Compare the starred project glyph position with the other collapsed
sidebar glyphs.

## Paperclip version or commit

Reproduced on the PR base before this branch; fixed on commit
e57d14343d with CI cleanup on commit
12aafe8959.

## Deployment mode

Local dev (`pnpm dev`).

## What Changed

- Applies the starred-project left padding only when the sidebar is not
in rail mode.
- Adds a regression test covering expanded and collapsed starred-project
rendering.
- Makes the heartbeat worktree suppression test cleanup tolerate late
heartbeat run events before deleting heartbeat runs.

## Verification

- Passed: `pnpm exec vitest run
ui/src/components/SidebarStarredProjects.test.tsx`
- Passed: `pnpm exec vitest run
server/src/__tests__/heartbeat-worktree-suppression.test.ts`
- Passed: PR #9215 latest-head GitHub checks on commit
`12aafe8959351826038baf0c1e401fb44913c67c`
- Passed: Greptile 5/5 with no inline comments or unresolved review
threads on commit `12aafe8959351826038baf0c1e401fb44913c67c`
- Known existing baseline failure: `pnpm check:token-gates` reports
violations in `ui/src/components/ActivityCharts.tsx` and
`ui/src/components/IssueRecoveryActionCard.tsx`, which this PR does not
touch.

## Risks

Low risk. The UI change adjusts one conditional class on starred project
links and preserves the expanded sidebar layout. The server test change
is cleanup-only and does not alter production behavior.

## Model Used

OpenAI GPT-5 Codex coding agent with local command execution and
repository editing tools.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-08 07:19:40 -05:00
Dotta 555391fed7
fix: run restart recovery, workspace self-heal, quota-aware retries, failed-run metrics (#9183)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents run in heartbeat runs orchestrated by the server; run
lifecycle, retry scheduling, and the dashboard's run-activity metrics
are the subsystems involved
> - A spike in "failed" tasks traced to three causes: server restarts
killing in-flight runs and mislabeling them as failures, deterministic
workspace-validation loops when a worktree's branch diverged, and
provider quota/usage-limit errors being classified as generic transient
failures (putting agents into error state and polluting metrics)
> - Killed-then-recovered runs and quota waits are not product failures,
so both the runtime behavior and the reporting needed to distinguish
them
> - This pull request drains runs gracefully on shutdown with idempotent
restart retries, self-heals workspace branch mismatches, adds a
quota-aware failure class with reset-time retry, separates recovered
restart kills from true failures on the dashboard, and documents restart
hygiene for operators
> - The benefit is fewer spurious failures, automatic recovery instead
of manual repair, and dashboard metrics that reflect real failure rates

## Linked Issues or Issue Description

No public GitHub issue exists; describing the bug inline per the
bug-report template:

**What happened?**

In-flight heartbeat runs are marked `failed` when the server restarts,
even though a retry later succeeds. Worktrees whose checked-out branch
diverges from the issue branch fail workspace validation on every
subsequent run with no recovery path. Provider quota/usage-limit
responses are treated as generic transient upstream errors, putting
agents into an error state and retrying before the quota window resets.
The dashboard counts all of these as true failures, inflating failure
metrics.

**Expected behavior**

Graceful shutdown should interrupt (not fail) running runs and chain
exactly one recovery retry. Workspace validation should repair
recoverable branch mismatches automatically. Quota errors should get
their own error class with the retry scheduled at the provider reset
time and the agent left idle. The dashboard should report recovered
restart kills separately from true failures.

**Steps to reproduce**

1. Start a heartbeat run, then restart the server (SIGTERM) while it is
in flight — the run lands as `failed` with a process-loss error code
even when its retry succeeds
2. Check out an issue whose worktree branch has diverged (e.g. after a
force-moved branch) — every subsequent run fails
`workspace_validation_failed` deterministically
3. Drive an agent into a provider usage-limit window — the run fails as
a generic transient upstream error and the agent enters an error state
instead of idling until the reset time

**Paperclip version or commit**

master (base c07e650cd)

**Deployment mode**

Self-hosted dev plane (Linux, node server + embedded Postgres)

## What Changed

- Graceful shutdown (SIGTERM hook) now marks in-flight runs
`interrupted` instead of `failed` and enqueues an idempotent
process-loss retry (pre-insert existence check on `retryOfRunId`
prevents duplicates; bursts chain exactly one retry per interrupted run)
- Run-liveness classification routes `interrupted` to `needs_followup`
rather than `failed`
- Workspace validation self-heals branch mismatch / missing-branch
states instead of failing deterministically on every run
- New `provider_quota` error class: session/usage-limit responses
schedule the retry at the provider reset time and leave the agent idle
(not errored); fixes a case where a quota-terminated run with subtype
`success` was misclassified as failed; HTTP 529 remains transient
- Dashboard run-activity query separates recovered restart kills from
true failures via a recursive CTE over `retry_of_run_id` (ancestors of a
succeeded retry count as recovered), adds a per-day failed-by-error-code
breakdown, and binds the window start as a timestamptz string
- Activity charts UI: amber "Recovered" segment with legend and per-day
error-code tooltip; success-rate chart counts recovered runs as
successes
- New ops runbook: `docs/deploy/dev-plane-restart-hygiene.md`

## Verification

- Greptile follow-up fixes on `992705edd`: `pnpm exec vitest run
server/src/__tests__/server-startup-feedback-export.test.ts
server/src/__tests__/heartbeat-workspace-branch-containment.test.ts
server/src/__tests__/heartbeat-workspace-session.test.ts
server/src/__tests__/heartbeat-process-recovery.test.ts
server/src/__tests__/heartbeat-workspace-finalize-branch.test.ts` (209
tests); `pnpm --filter @paperclipai/server typecheck`; `git diff
--check`
- Post-rebase CI fixes: `pnpm exec vitest run
server/src/__tests__/heartbeat-retry-scheduling.test.ts`; `pnpm exec
vitest run server/src/__tests__/heartbeat-retry-scheduling.test.ts
server/src/__tests__/workspace-runtime.test.ts
server/src/__tests__/heartbeat-workspace-branch-containment.test.ts
server/src/__tests__/heartbeat-workspace-finalize-branch.test.ts
server/src/__tests__/heartbeat-workspace-session.test.ts` (227 tests);
`pnpm --filter @paperclipai/server typecheck`
- `npm test` server suites covering the changes:
`heartbeat-process-recovery`, `heartbeat-stop-metadata`,
`heartbeat-retry-scheduling` (95 tests), quota parse +
execute/retry-scheduling suites (100 tests), workspace self-heal suites
(200 tests), dashboard run-activity tests (3 tests) — all green,
typecheck exit 0
- Dashboard CTE cross-checked against a real development database: two
restart-burst days moved from 17 to 8 and 19 to 6 true failures once
recovered kills were separated, matching manual retry-chain inspection
- Screenshot verification of the real ActivityCharts component
(recovered segment + tooltip) during QA

## Risks

- Behavioral shift: runs killed by a restart no longer surface as
`failed`; anyone consuming raw run statuses will see `interrupted` (new
status value) — dashboards/queries in this repo were updated accordingly
- Retry chaining on repeated restarts is bounded (one chained retry per
interruption) but a pathological restart loop still delays work rather
than failing it; the runbook covers operator hygiene for that case
- Dashboard query adds a recursive CTE; cost is bounded by the
day-window row count and was verified against production-sized data
- No schema migrations; low migration risk

## Model Used

- Claude (Anthropic) — claude-fable-5 via Claude Code / Paperclip agent
harness, extended thinking with tool use; implementation commits also
produced with Codex CLI (GPT-5 class) agents under the same harness

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [ ] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-07 20:30:09 -05:00
tmartin2113 3b16ac3804
fix(server): use run.id for activity_log in heartbeat invoke/resume (#3424)
## Summary

- The heartbeat invoke and resume endpoints log activity with
`actor.runId` (the caller's auto-generated run ID from JWT), which
hasn't been registered in `heartbeat_runs` yet
- This causes a FK constraint violation: `activity_log.run_id →
heartbeat_runs.id`
- Fix: use `run.id` (the newly created heartbeat_run) instead, which is
guaranteed to exist in the table

## Test plan

- [ ] Trigger a heartbeat invoke via the API — verify no FK constraint
error in logs
- [ ] Trigger a heartbeat resume — verify activity_log row is created
successfully
- [ ] Verify existing activity_log queries still return correct results

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 18:48:08 -05:00
Dotta 83f5f59842
[codex] Hide goals sidebar link behind experiment (#9189)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The board sidebar is the primary navigation surface for operators
scanning companies, projects, tasks, agents, and related control-plane
tools.
> - Goals still has a route and product surface, but keeping the
top-level sidebar link always visible makes it part of the default
navigation whether or not that surface is ready for every operator.
> - Instance experimental settings already provide a controlled place to
expose optional UI surfaces while they are being evaluated.
> - This pull request adds a dedicated experimental setting for
restoring the Goals sidebar link.
> - The benefit is a quieter default sidebar with an explicit escape
hatch for operators who still need the Goals entry point.

## Linked Issues or Issue Description

No public GitHub issue exists for this internal task, so the feature
request is described inline.

**Subsystem affected**
Cross-cutting: `ui/`, `server/`, and `packages/shared`.

**Problem or motivation**
The Goals route remains available, but the top-level Goals sidebar entry
makes that surface part of the default operator navigation. While the
goals surface is still being evaluated, operators need a quieter default
sidebar without losing an escape hatch for teams that still rely on the
link.

**Proposed solution**
Add a boolean instance experimental setting, `enableGoalsSidebarLink`,
default it to `false`, and render the Goals sidebar link only when the
setting is enabled. Expose the toggle in Instance Experimental Settings
so operators can restore the link without changing routes or rebuilding
the app.

**Alternatives considered**
- Remove the Goals route entirely: rejected because this task only asks
to hide the sidebar entry point and preserve access for teams evaluating
goals.
- Keep the sidebar link always visible: rejected because it does not
provide the requested quieter default navigation.
- Hard-code a local UI flag: rejected because instance experimental
settings already provide the expected operator-controlled pattern.

**Roadmap alignment**
Checked `ROADMAP.md`; no overlapping goals/sidebar/experimental roadmap
entry was found.

**Additional context**
The `/goals` route is preserved. This PR only gates the sidebar
navigation item.

## What Changed

- Added `enableGoalsSidebarLink` to the shared instance experimental
settings type and validator, defaulting to `false`.
- Normalized the new setting in the server instance settings service.
- Hid the Goals sidebar nav item unless the new setting is enabled.
- Added a Goals Sidebar Link toggle to the Instance Experimental
Settings page.
- Updated shared, server, sidebar, and settings page tests for the new
setting.

## Verification

- `pnpm exec vitest run packages/shared/src/validators/instance.test.ts
server/src/__tests__/instance-settings-service.test.ts
server/src/__tests__/instance-settings-routes.test.ts
ui/src/components/Sidebar.test.tsx
ui/src/pages/InstanceExperimentalSettings.test.tsx`
- `git diff --check origin/master...HEAD`
- `git merge-tree --write-tree HEAD origin/master`
- Searched for duplicate/related PRs by title and
`enableGoalsSidebarLink`; none found.
- Checked `ROADMAP.md` for overlapping goals/sidebar/experimental
entries; none found.

## Risks

Low risk. The main behavior shift is that operators who depended on the
sidebar Goals link need to enable the new experimental toggle. The
`/goals` route itself is not removed.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex, GPT-5-based Paperclip CodexCoder session with repository
tool access and command execution. Exact API model identifier and
context window were not exposed by the Paperclip harness.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-07-07 16:48:33 -05:00
Nicky Leach bb87047fe6
Add auto-forward execution workspace branch reconciliation (#9172)
## Thinking Path

> - Paperclip manages execution workspaces for AI agent runs, each
associated with a git branch so the agent always works in a known code
state.
> - Workspace runtime reconciles an agent's checkout branch against the
workspace's recorded branch when a heartbeat resumes; without
forward-ancestry detection, any divergence fails closed and blocks the
run.
> - When the workspace branch has moved forward (e.g. after a feature
merge), the recorded branch is an ancestor of the current HEAD — a safe,
forward-only case that the previous implementation refused even though
it carries no safety risk.
> - The gap means legitimate forward-advancing deployments require
manual operator intervention to unblock agents every time, creating
operational friction and interrupting automated workflows.
> - This pull request adds a flag-gated reconcile-forward path that
detects when the current branch is a strict forward descendant of the
workspace branch and auto-reconciles, while preserving fail-closed
behavior for all non-forward or flag-off cases.
> - It also threads the active execution workspace id through restore
and finalize call sites so the reconcile verdict can be persisted
durably across heartbeats.
> - The benefit is that agents resume automatically from
forward-advancing workspace branches without operator intervention,
while adversarial and backward branch changes continue to fail closed.

## Linked Issues or Issue Description

This PR adds an auto-forward reconcile path for execution workspace
branch tracking. When a workspace's recorded branch is a strict ancestor
of the current HEAD (a forward-only advancement), the runtime now
auto-reconciles rather than hard-blocking. The feature is gated behind
an explicit runtime flag, defaults to off, and falls back to fail-closed
behavior for all non-forward or flag-off cases.

The prior implementation treated all branch divergences identically: any
mismatch between the recorded workspace branch and the current HEAD
failed closed. This prevented agents from resuming after routine forward
deployments (e.g. after a feature branch merges into the workspace
branch), requiring manual operator action to unblock every affected run.

## What Changed

- Added `reconcileForward` flag-gated path in workspace runtime
reconciliation logic that allows auto-reconciliation when the workspace
branch is a strict ancestor of the current HEAD.
- Threaded active execution workspace id through `restore` and
`finalize` call sites so reconcile verdicts are persisted durably.
- Added `plainLanguageReason` and `ancestryVerdict` evidence fields to
the reconciliation result structure for operator visibility.
- Stabilized a branch containment test that exposed a late run-linked
activity FK cleanup race during the focused Vitest rerun.
- All new paths remain fail-closed when the flag is off or when the
branch relationship is not strictly forward.

## Verification

```bash
pnpm --filter @paperclipai/shared typecheck
pnpm --filter @paperclipai/server typecheck
pnpm exec vitest run \
  server/src/__tests__/workspace-runtime.test.ts \
  server/src/__tests__/heartbeat-workspace-branch-containment.test.ts \
  server/src/__tests__/execution-workspaces-service.test.ts
git diff --check origin/master..HEAD
```

All 3 test files / 98 tests pass. Typecheck passes for both shared and
server packages.

> **Note:** This is a stacked PR on top of PR #9170 (Add execution
workspace branch reconciliation route). The diff shown targets that
branch; the combined change builds on the reconciliation route
infrastructure it provides.

## Risks

- **Flag-off default:** The reconcile-forward path is off by default. No
behavior change for existing workspaces unless the flag is explicitly
enabled by an operator.
- **Ancestry check correctness:** The forward-only guard uses git
ancestry verification; a branch that is not a strict ancestor of HEAD
remains fail-closed. Adversarial or concurrent branch resets are not
auto-reconciled.
- **FK cleanup race (stabilized):** A late run-linked activity FK
cleanup race in the containment test was exposed during the Vitest
rerun. The stabilization commit addresses the non-deterministic ordering
without changing production behavior.
- **Stacking dependency:** This PR must not be merged before PR #9170
merges, as it is built on top of the reconciliation route
infrastructure.

## Model Used

- Provider: Anthropic
- Model: Claude Sonnet 4.6 (`claude-sonnet-4-6`)
- Context: 200k token context window
- Mode: Agentic tool use with code execution and git operations

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-07 14:12:17 -07:00
Nicky Leach f17202b571
Add execution workspace branch reconciliation route (#9170)
## Thinking Path

> - Paperclip is an open-source app that lets teams run AI agents for
work tasks; each agent session uses an execution workspace — a git
checkout — to track the agent's active code state.
> - Every execution workspace has an expected target branch
(`PAPERCLIP_WORKSPACE_BRANCH`). The workspace git HEAD should always
point to that branch so agents commit in the right place.
> - When workspace git HEAD diverges from the expected branch — for
example after a harness branch-name fix or an accidental `checkout -b`
during a CI-retrigger — the discrepancy must be corrected before agents
can continue safely.
> - Operators (board users) need a controlled, audited path to reconcile
a workspace's live branch back to the expected target, with an override
escape-hatch for cases where the normal forward path is blocked.
> - This pull request adds a board-only `POST
/api/execution-workspaces/:id/reconcile-branch` service operation and
route that validates safety preconditions, resolves matching
recovery-action fingerprints, posts source-issue audit comments, and
records the reconciliation outcome.
> - The benefit is that operators can correct branch divergence through
the API with a full audit trail, instead of via raw database edits.

## Linked Issues or Issue Description

No public GitHub issue exists for this change. Context below follows the
feature-request template format.

**Subsystem affected**

server/ — REST API & orchestration services; packages/shared — request
validation.

**Problem or motivation**

Execution workspaces have an expected branch record that must match the
checked-out worktree branch. When the live git branch and stored branch
record drift apart, operators currently lack a first-class, audited API
to reconcile the record. The fallback is manual database repair or
workspace replacement, both of which are risky and hard to audit.

**Proposed solution**

Add a board-only execution workspace branch reconciliation operation.
`forward` mode re-inspects the server-side git state and only updates
the branch record when the stored branch is an ancestor of the
checked-out branch. `override` mode is a break-glass path that requires
board access and an operator reason. Both modes require a clean, idle
workspace, write audit details, post a source-issue audit comment, and
resolve the matching workspace-validation recovery action.

**Alternatives considered**

Manual database edit (no durable audit trail and easy to mistype),
recreating the workspace (heavier operational disruption), or trusting
client-supplied ancestry evidence (unsafe because the server must verify
the git state itself).

**Roadmap alignment**

This is incremental hardening for execution-workspace recovery and
operator controls. It does not duplicate a public roadmap item.

**Additional context**

The endpoint is intended for operator recovery, not normal agent control
flow, so the generated OpenAPI metadata and runtime route both classify
it as board-only.
## What Changed

- Added `reconcileExecutionWorkspaceBranchSchema` discriminated-union
validator (`forward` with optional reason, `override` requiring a
non-empty reason string) to
`packages/shared/src/validators/execution-workspace.ts`
- Exported `ReconcileExecutionWorkspaceBranch` type and the new schema
from the shared package index
- Added board-only reconcile-branch service operation in the execution
workspaces service: safety checks, recovery-action fingerprint
resolution, source-issue audit comment, and outcome recording
- Added clean-worktree and stopped-runtime-service preconditions before
branch-record mutation.
- Marked the reconcile route as board-only in OpenAPI generated auth
metadata.
- Added `POST /api/execution-workspaces/:id/reconcile-branch` route
wired to the new service operation with board-permission gate
- Extended `execution-workspaces-routes.test.ts` and
`execution-workspaces-service.test.ts` to cover: safety-check rejection,
override-reason validation, audit-comment posting, and recovery-action
fingerprint resolution (2 files / 19 tests)

## Verification

```sh
pnpm --filter @paperclipai/shared typecheck
pnpm --filter @paperclipai/server typecheck
pnpm exec vitest run server/src/__tests__/execution-workspaces-routes.test.ts server/src/__tests__/execution-workspaces-service.test.ts
pnpm exec vitest run server/src/__tests__/execution-workspaces-service.test.ts server/src/__tests__/openapi-routes.test.ts
```

## Risks

- **Board-only gate:** the operation is gated behind the board
permission; no agent can trigger it without operator authorization.
- **Override requires reason:** the `override` mode requires a non-empty
reason string so every bypass is audited.
- **Idempotent recovery-action resolution:** re-running with the same
fingerprint is safe; duplicate resolution is a no-op.
- **No execution-state mutation:** the route records a reconciliation
intent and updates the branch record; it does not restart the workspace
or modify running agent state.
- Overall risk: **low**.

## Model Used

- Provider: Anthropic
- Model ID: `claude-sonnet-4-6` (Claude Sonnet 4.6)
- Context window: 200 K tokens
- Capabilities: tool use, code execution, multi-turn context

Follow-up safety commit:
- Provider: OpenAI
- Model ID: `codex` / GPT-5 with tool use and code execution

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` /
`Closes: #` / `Refs: #` OR (b) described the issue in-PR following the
relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change
(`feat/execution-workspace-branch-reconciliation-route`) and contains no
internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-07 13:41:23 -07:00
dependabot[bot] bdd3aa2110
build(deps): bump sharp from 0.35.2 to 0.35.3 (#9061)
Bumps [sharp](https://github.com/lovell/sharp) from 0.35.2 to 0.35.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/lovell/sharp/releases">sharp's
releases</a>.</em></p>
<blockquote>
<h2>v0.35.3</h2>
<ul>
<li>
<p>Tighten verification of <code>text</code> dimensions, TIFF tile
dimensions and <code>extend</code> values.</p>
</li>
<li>
<p>Improve code bundler support by resolving path to libvips binary.</p>
</li>
<li>
<p>Increase default concurrency when use of
<code>MALLOC_ARENA_MAX</code> is detected.</p>
</li>
<li>
<p>Emit warning about binaries provided by Electron for use on
Linux.</p>
</li>
<li>
<p>Add <code>hasAlpha</code> property to output <code>info</code>.
<a
href="https://redirect.github.com/lovell/sharp/issues/4500">#4500</a></p>
</li>
<li>
<p>TypeScript: Return more precise
<code>Buffer&lt;ArrayBuffer&gt;</code> from <code>toBuffer</code>.
<a href="https://redirect.github.com/lovell/sharp/pull/4520">#4520</a>
<a href="https://github.com/Andarist"><code>@​Andarist</code></a></p>
</li>
<li>
<p>Bound <code>clahe</code> width and height to avoid signed overflow.
<a href="https://redirect.github.com/lovell/sharp/pull/4551">#4551</a>
<a
href="https://github.com/metsw24-max"><code>@​metsw24-max</code></a></p>
</li>
<li>
<p>Bound <code>trim</code> margin to avoid signed overflow.
<a href="https://redirect.github.com/lovell/sharp/pull/4552">#4552</a>
<a
href="https://github.com/metsw24-max"><code>@​metsw24-max</code></a></p>
</li>
<li>
<p>Reject infinite values when validating numbers.
<a href="https://redirect.github.com/lovell/sharp/pull/4553">#4553</a>
<a
href="https://github.com/metsw24-max"><code>@​metsw24-max</code></a></p>
</li>
<li>
<p>Bound extract region to libvips coordinate limit.
<a href="https://redirect.github.com/lovell/sharp/pull/4555">#4555</a>
<a
href="https://github.com/metsw24-max"><code>@​metsw24-max</code></a></p>
</li>
<li>
<p>Verify background colour values are numbers.
<a href="https://redirect.github.com/lovell/sharp/pull/4556">#4556</a>
<a
href="https://github.com/metsw24-max"><code>@​metsw24-max</code></a></p>
</li>
<li>
<p>Bound create and raw input dimensions to coordinate limit.
<a href="https://redirect.github.com/lovell/sharp/pull/4558">#4558</a>
<a
href="https://github.com/metsw24-max"><code>@​metsw24-max</code></a></p>
</li>
<li>
<p>Tighten recomb and affine matrix verification.
<a href="https://redirect.github.com/lovell/sharp/pull/4560">#4560</a>
<a
href="https://github.com/chatman-media"><code>@​chatman-media</code></a></p>
</li>
<li>
<p>Verify cache memory limit to avoid overflow.
<a href="https://redirect.github.com/lovell/sharp/pull/4561">#4561</a>
<a
href="https://github.com/metsw24-max"><code>@​metsw24-max</code></a></p>
</li>
</ul>
<h2>v0.35.3-rc.2</h2>
<ul>
<li>Tighten verification of <code>text</code> dimensions, TIFF tile
dimensions and <code>extend</code> values.</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="1018449164"><code>1018449</code></a>
Release v0.35.3</li>
<li><a
href="ba303a799d"><code>ba303a7</code></a>
Prerelease v0.35.3-rc.2</li>
<li><a
href="4f94fc5162"><code>4f94fc5</code></a>
Upgrade to sharp-libvips v1.3.2</li>
<li><a
href="c5e7a3ff20"><code>c5e7a3f</code></a>
Bump devDeps, fix Deno/Windows smoke tests</li>
<li><a
href="9a8d002688"><code>9a8d002</code></a>
Docs: Add changelog entry and note about transferable <a
href="https://redirect.github.com/lovell/sharp/issues/4520">#4520</a></li>
<li><a
href="8694db0bac"><code>8694db0</code></a>
TypeScript: Return more precise <code>Buffer\&lt;ArrayBuffer&gt;</code>
from <code>toBuffer</code> (<a
href="https://redirect.github.com/lovell/sharp/issues/4520">#4520</a>)</li>
<li><a
href="e000d0b5e1"><code>e000d0b</code></a>
Prerelease v0.35.3-rc.1</li>
<li><a
href="9554ca9553"><code>9554ca9</code></a>
Prerelease v0.35.3-rc.0</li>
<li><a
href="6a29fd55db"><code>6a29fd5</code></a>
Emit warning about native binaries on Linux Electron</li>
<li><a
href="540d2eada4"><code>540d2ea</code></a>
Increase default concurrency when use of MALLOC_ARENA_MAX detected</li>
<li>Additional commits viewable in <a
href="https://github.com/lovell/sharp/compare/v0.35.2...v0.35.3">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-07 13:03:30 -07:00
dependabot[bot] 077ba611fa
build(deps-dev): bump @types/multer from 2.1.0 to 2.2.0 (#9065)
Bumps
[@types/multer](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/multer)
from 2.1.0 to 2.2.0.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/multer">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@types/multer&package-manager=npm_and_yarn&previous-version=2.1.0&new-version=2.2.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-07 10:03:47 -07:00
Dotta 390627b46e
[codex] Suppress worktree heartbeat scheduling (#9163)
Suppress heartbeat scheduling in worktree and restore runtimes while keeping routine ticks and setup cleanup active.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-07-07 09:27:46 -05:00
Dotta 57a7da81ee
[codex] Isolate run JWTs by control-plane instance (#9162)
Bind local agent run JWT signing and validation to the issuing Paperclip instance while preserving rollout compatibility for legacy tokens.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-07-07 09:27:19 -05:00
Dotta 09f503f216
[codex] Surface AWS secret provider create errors (#9161)
Preserve sanitized AWS Secrets Manager create errors and make rollback/cleanup failures explicit.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-07-07 09:26:41 -05:00
Dotta 88ce6d3575
Speed up issue detail payloads (#9125)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Operators spend a lot of time in issue detail pages and agent
activity views while supervising work
> - Those views were receiving large embedded project, workspace,
runtime-service, and heartbeat context payloads
> - Large payloads make issue comments and page loads slower, especially
on active issues with workspaces and runtime metadata
> - This pull request trims the issue detail and activity ledger
response shapes to the fields those views need
> - The benefit is faster issue detail loading without changing the
underlying project, workspace, or run persistence model

## Linked Issues or Issue Description

No public GitHub issue was found for this exact problem, so this PR
describes the bug inline using the bug report template fields.

### Pre-submission checklist

- [x] I have searched existing open and closed issues and this is not a
duplicate.
- [x] I am on the latest released version of Paperclip (or can reproduce
on `master`).
- [x] I have confirmed the error originates in Paperclip itself — not in
my agent adapter, API provider, or local configuration.

### What happened?

Issue detail and related activity responses could include bulky embedded
metadata such as project environment values, workspace metadata, stopped
runtime services, and heartbeat context snapshots. On active issues with
workspaces and long activity history, that makes issue comments and page
loads slower than needed.

### Expected behavior

Issue detail endpoints should return bounded, UI-oriented embeds that
avoid shipping large or sensitive internal blobs when the full object
graph is not needed.

### Steps to reproduce

1. Create or open an issue with a project workspace and execution
workspace.
2. Ensure the workspace has runtime services and heartbeat runs with
context snapshots.
3. Inspect `GET /api/issues/:id` and the issue activity ledger payloads.
4. Observe that the response includes large embedded
project/workspace/runtime/run fields unrelated to rendering the issue
detail page.

### Paperclip version or commit

Reproduced against current `master` lineage before this change.

### Deployment mode

Local dev / server API behavior.

### Installation method

Built from source (`pnpm dev` / `pnpm build`).

### Agent adapter(s) involved

Not adapter-specific (core API payload shape).

### Database mode

Not database-related; no migration.

### Access context

Board and agent-facing issue detail consumers can both benefit from
smaller payloads.

### Node.js version

Not version-specific.

### Operating system

Not OS-specific.

### Relevant logs or output

Not applicable.

### Relevant config (if applicable)

Not applicable.

### Additional context

Related search:
- Searched public GitHub issues for `currentExecutionWorkspace metadata
runtimeServices issue detail`; no matching issue found.
- Searched public GitHub PRs for `compact currentExecutionWorkspace
metadata runtimeServices`; no matching PR found.

### Privacy checklist

- [x] I have reviewed all pasted output for PII (usernames, file paths,
API keys, tokens, company names) and redacted where necessary.

## What Changed

- Added compact response shaping for issue detail project, project
workspace, execution workspace, and runtime-service embeds.
- Dropped large project `env`, workspace `metadata` / embedded runtime
service lists, execution workspace `metadata`, and non-active runtime
services from `GET /api/issues/:id` responses.
- Removed heartbeat `contextSnapshot` from the activity ledger query
result.
- Added focused route and activity-service tests covering the compact
response shape.

## Verification

- `pnpm exec vitest run
server/src/__tests__/issues-goal-context-routes.test.ts
server/src/__tests__/activity-service.test.ts --no-file-parallelism
--maxWorkers=1`
- `pnpm --filter @paperclipai/server typecheck`
- `git diff --check public/master..HEAD`
- Confirmed the branch is based on current
`paperclipai/paperclip:master` and contains no `pnpm-lock.yaml` or
`.github/workflows` changes.

## Risks

Low to medium risk. The persisted data model is unchanged, but consumers
relying on the full embedded project/workspace/runtime metadata from
`GET /api/issues/:id` will now need to fetch the dedicated resource
endpoint instead of depending on the issue detail payload.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI GPT-5 Codex coding agent with repository file access, shell
command execution, GitHub connector usage, and local test execution.
Context window and exact hosted model variant are not exposed in this
runtime.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-07-07 06:28:54 -05:00
Dotta 19454ce385
Deduplicate open watchdog review wakes (#9148)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Watchdogs keep issue execution moving by waking agents or creating
recovery paths when work stalls.
> - Open review states should generate useful follow-up, not repeated
duplicate wake requests for the same unresolved review condition.
> - Duplicate wakes create noise and can make the control plane look
busier without increasing progress.
> - This pull request deduplicates open watchdog review wake scheduling
and covers the behavior with scheduler tests.
> - The benefit is cleaner review wake behavior and fewer redundant
agent runs.

## Linked Issues or Issue Description

No public GitHub issue exists. Inline bug report:

**Pre-submission checklist**

- [x] I have searched existing open and closed issues and this is not a
duplicate.
- [x] I am on the latest released version of Paperclip (or can reproduce
on `master`).
- [x] I have confirmed the error originates in Paperclip itself — not in
my agent adapter, API provider, or local configuration.

**What happened?**

Watchdog scheduling could enqueue duplicate open review wake requests
while the same unresolved review condition was already pending.

**Expected behavior**

A watchdog should avoid scheduling redundant review wakes for the same
unresolved condition while preserving legitimate wake paths.

**Steps to reproduce**

1. Create an issue state that requires an open watchdog review wake.
2. Run the watchdog scheduler once and observe a wake request.
3. Run the scheduler again before resolving the original review
condition.
4. Observe whether a duplicate wake is created.

**Paperclip version or commit**

`master` at the PR base.

**Deployment mode**

Local dev (`pnpm dev`) and server deployments running watchdog
scheduling.

**Installation method**

Built from source (`pnpm dev` / `pnpm build`).

**Agent adapter(s) involved**

- [x] Not adapter-specific (core bug)

**Database mode**

Not database-related beyond scheduler persistence.

**Access context**

Agent wake scheduling and board-visible review state.

**Relevant logs or output**

Covered by the added scheduler regression test.

**Relevant config (if applicable)**

Not applicable.

**Additional context**

This suppresses duplicate wake scheduling only while the open review
state is still unresolved.

**Privacy checklist**

- [x] I have reviewed all pasted output for PII (usernames, file paths,
API keys, tokens, company names) and redacted where necessary.

## What Changed

- Added deduplication logic for open watchdog review wake scheduling.
- Added scheduler regression coverage for duplicate open review wake
suppression.

## Verification

- `/srv/paperclip/home/paperclipai/paperclip/node_modules/.bin/vitest
run server/src/__tests__/task-watchdogs-scheduler.test.ts`

## Risks

Low-to-medium risk. The change intentionally suppresses duplicate wake
scheduling, so reviewers should confirm no legitimate repeated wake path
depends on creating multiple open requests for the same unresolved
review state.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex, GPT-5.5 coding agent with repository tool use and local
shell execution. Context window was not surfaced by the runtime.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-07 05:54:23 -05:00
Dotta be821a4f7e
Fix DB backup health alerts (#9147)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Operators depend on `/api/health` and OpenAPI status surfaces to
know whether the local control plane is healthy.
> - Database backups are a safety-critical background process, but
backup failures were not represented in health responses.
> - That gap means an instance can look healthy while backup state is
stale, failing, or unavailable.
> - This pull request adds backup-health evaluation and exposes it
through the health route, server startup wiring, and OpenAPI contract.
> - The benefit is earlier operator visibility when automatic backups
stop protecting instance data.

## Linked Issues or Issue Description

No public GitHub issue exists. Inline bug report:

**Pre-submission checklist**

- [x] I have searched existing open and closed issues and this is not a
duplicate.
- [x] I am on the latest released version of Paperclip (or can reproduce
on `master`).
- [x] I have confirmed the error originates in Paperclip itself — not in
my agent adapter, API provider, or local configuration.

**What happened?**

Automatic database backup health was not included in the app health
response, so backup failures or stale backups could be missed while
`/api/health` still looked otherwise usable.

**Expected behavior**

The health endpoint should include backup-health details that let
operators identify disabled, stale, failing, or healthy backup states.

**Steps to reproduce**

1. Configure a Paperclip instance with automatic database backups.
2. Force backup status into a stale or failing state.
3. Call `/api/health` and inspect whether backup state is represented.

**Paperclip version or commit**

`master` at the PR base.

**Deployment mode**

Local dev (`pnpm dev`) and self-hosted server deployments.

**Installation method**

Built from source (`pnpm dev` / `pnpm build`).

**Agent adapter(s) involved**

- [x] Not adapter-specific (core bug)

**Database mode**

Embedded development Postgres and external Postgres backup paths.

**Access context**

Board/operator health checks.

**Relevant logs or output**

Covered by the added `server/src/__tests__/health.test.ts` cases.

**Relevant config (if applicable)**

Not applicable.

**Additional context**

This surfaces backup status only; it does not change backup execution
scheduling.

**Privacy checklist**

- [x] I have reviewed all pasted output for PII (usernames, file paths,
API keys, tokens, company names) and redacted where necessary.

## What Changed

- Added a database backup health service that classifies backup recency,
status, and failure conditions.
- Wired backup health into app/server startup and the health route
response.
- Documented the backup-health behavior in development docs and OpenAPI
output.
- Added focused health route tests for healthy, stale, disabled, and
failing backup states.

## Verification

- `/srv/paperclip/home/paperclipai/paperclip/node_modules/.bin/vitest
run server/src/__tests__/health.test.ts`

## Risks

Low-to-medium risk. This changes health response content and may affect
external health consumers that parse fields strictly. It should not
alter backup execution itself.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex, GPT-5.5 coding agent with repository tool use and local
shell execution. Context window was not surfaced by the runtime.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-07 05:54:20 -05:00
Nicky Leach 9d5b0e3c57
Add read-only issue subtree diagnostics endpoint (#9135)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The issue/task orchestration subsystem tracks parent–child and
blocker–dependent relationships, forming a directed acyclic (in
intention) subtree below each root issue
> - Agents and operators have no lightweight way to inspect the
dependency and wake state across an entire issue subtree — they must
walk the tree issue-by-issue, making multiple round-trips with full
object fetches
> - A bounded, read-only subtree diagnostic endpoint lets callers
understand the health of an entire work tree (which nodes are blocked,
which are cycling, which have pending wakes) from a single authenticated
request
> - This pull request adds `GET /api/issues/:id/diagnostics/subtree`, a
depth/node/per-node capped traversal that reuses the blocker and wake
projection helpers from the companion blocker and wake diagnostics
endpoints (see Refs #9114, #9133)
> - The benefit is that platform operators, monitoring, and coaching
tooling can surface \"why is this subtree stalled?\" across all nodes
without database access or unbounded graph walks, using only data the
caller already has read permission for

## Linked Issues or Issue Description

Refs #9114 (companion blocker diagnostics endpoint — blocker projection
helpers reused here)
Refs #9133 (companion wake diagnostics endpoint — wake projection
helpers reused here)

## What Changed

- **New route** `GET /api/issues/:id/diagnostics/subtree` in
`server/src/routes/issues.ts`: returns a bounded subtree traversal
rooted at `:id`, with depth/node/per-node caps and explicit truncation
flags
- **Cycle-safe traversal**: visited-node set prevents infinite loops on
any accidental cycle in the ancestry graph
- **Per-node authorization**: each subtree node is individually filtered
through `assertIssueReadAllowed`; unauthorized nodes are omitted from
the response and do not influence aggregate counts
- **Blocker and wake reuse**: per-node blocker rows and wake events are
projected through the same helpers as #9114 and #9133 — raw wake
payloads, raw errors, activity details, and trigger detail fields are
stripped
- **Low-trust filtering**: the `mention-scoped` low-trust path redacts
node/blocker identifiers for unauthorized actors, consistent with #9133
- **Truncation reporting**: response includes `depthTruncated`,
`nodeTruncated`, and per-node `blockersTruncated`/`wakesTruncated` flags
when caps are hit
- **Shared types** in `@paperclipai/shared`:
`IssueSubtreeDiagnosticsResponse` and supporting node/blocker/wake types
exported from the shared package
- **OpenAPI tag registration** for the new route
- **API reference docs** in
`skills/paperclip/references/api-reference.md`
- **Test coverage**
(`server/src/__tests__/issue-subtree-diagnostics-routes.test.ts`,
embedded Postgres): happy path, quiet singleton (no children/blockers),
node cap truncation, mention-scoped low-trust filtering, cross-company
denial

## Verification

```bash
# Subtree diagnostics tests only
pnpm exec vitest run server/src/__tests__/issue-subtree-diagnostics-routes.test.ts

# Full diagnostics suite (blocker + wake + subtree)
pnpm exec vitest run server/src/__tests__/issue-blocker-diagnostics-routes.test.ts server/src/__tests__/issue-wake-diagnostics-routes.test.ts server/src/__tests__/issue-subtree-diagnostics-routes.test.ts

# Type-check shared and server packages
pnpm --filter @paperclipai/shared typecheck
pnpm --filter @paperclipai/server typecheck

# Whitespace / diff check
git diff --check
```

All commands passed locally (5 subtree tests, 17 total across the three
diagnostics test files).

## Risks

- **No schema or migration changes** — read-only projection over
existing relations; no DDL risk
- **Bounded traversal** — depth, node count, and per-node blocker/wake
caps prevent unbounded graph walks; truncation is reported explicitly in
the response
- **Auth boundary** — root issue read is company-scoped and checked
before the subtree is built; each subtree node is individually
authorized; cross-company access is denied at `assertCompanyAccess`
- **No raw payloads** — raw wake payload, raw error, activity details,
and trigger detail fields are stripped from all nodes, consistent with
the companion endpoints
- Low overall risk; the endpoint is additive and read-only

## Model Used

- **Provider:** Anthropic
- **Model:** Claude Sonnet 4.6 (`claude-sonnet-4-6`)
- **Tool use:** yes (file reads, edits, bash execution, Paperclip API
calls)
- **Reasoning mode:** standard (no extended thinking)

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-06 22:39:34 -07:00
Nicky Leach 47aef634e5
Add branch incoherence containment (#9131)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents run inside git worktrees; the heartbeat system establishes a
workspace branch and tracks it through checkout, realization, restore,
and finalization
> - When the live git branch diverges from the recorded workspace branch
mid-change (branch incoherence), the heartbeat must fail closed with
`workspace_validation_failed` and block the source issue with a recovery
action
> - There were no embedded-Postgres tests covering this fail-closed
behavior across the three interlock call sites: fresh git-worktree
realization, persisted workspace restore, and heartbeat finalization
> - This PR adds a single test file covering all three call sites with
an embedded-Postgres heartbeat test harness and asserts the exact
fail-closed outcome and evidence fields
> - The benefit is confidence that branch-incoherence containment is
correct and regressions in the interlock chain are caught before they
silently corrupt workspace state

## Linked Issues or Issue Description

Refs: #6425 (related: enforce issue branch matches workspace on
wake/checkout)

No pre-existing public GitHub issue for this specific reproduction test
gap. The underlying problem:

**Bug / gap:** The heartbeat's branch-incoherence containment was
untested by any embedded-Postgres integration test. All three call sites
— fresh git-worktree realization, persisted workspace restore, and
finalization — could regress without detection. The fail-closed path
(`workspace_validation_failed` + source-issue block + deduped recovery
action) and the evidence fields surfaced to operators were unverified.

## What Changed

- Added
`server/src/__tests__/heartbeat-workspace-branch-containment.test.ts`
with embedded-Postgres integration tests covering:
- **Fresh git-worktree realization** — heartbeat detects branch
divergence at workspace setup and fails closed
- **Persisted workspace restore** — re-entering a previously-established
workspace with a diverged branch fails closed instead of being silently
coerced into a generic reuse-failure path
- **Heartbeat finalization** — any late-stage branch incoherence
detected at finalization fails closed
- Asserts fail-closed behavior in all three cases: run status =
`workspace_validation_failed`, source issue status = `blocked`, exactly
one deduped workspace-validation recovery action on the blocked issue,
sibling issues on same/other workspaces retain their status
- Asserts evidence completeness: `expectedBranch`, `liveBranch`,
`expectedHead`, `liveHead`, `cleanliness`, `ancestryVerdict`,
`plainLanguageReason`, and `recoveryGuidance` fields are present and
correct on the run
- Ensures release/promotion errors after setup failures are logged (not
silently swallowed), making cleanup failures observable

## Verification

```bash
pnpm exec vitest run server/src/__tests__/heartbeat-workspace-branch-containment.test.ts
pnpm --filter @paperclipai/server typecheck
```

All 3 tests pass, typecheck clean.

## Risks

Low. Test-only change — no production code paths are modified. The tests
use an embedded-Postgres harness and do not touch any shared or live
database.

## Model Used

Claude Sonnet 4.6 (`claude-sonnet-4-6`) via Claude Code — tool use mode,
standard context window.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-06 22:02:52 -07:00
Nicky Leach 31a0080e61
Fix wake diagnostics low-trust identifier redaction (#9133)
## Thinking Path

> - Paperclip is the open-source app people use to manage AI agents for
work
> - The task/issue lifecycle subsystem tracks when agents wake up, are
suppressed, or are deferred, recording each wake request in
`agent_wakeup_requests` and each defer/suppression event in
`activity_log`
> - When an agent appears stuck or doesn't resume after a dependency
resolves, there is currently no read-only API surface to inspect its
wake history — operators must query the database directly
> - Making wake history queryable via a first-class endpoint lets
operators, support, and monitoring tools diagnose "why didn't this agent
wake up?" without database access
> - This pull request adds `GET /api/issues/:id/diagnostics/wakes`,
returning a bounded 14-day/50-row projection of wake requests and
defer/suppression activity events, with a deterministic `diagnosis`
field and a `likelyReason` inference — including a Case-B inference ("no
wake enqueued because a visible blocker is not done") that reuses the
blocker readiness data from the companion blocker diagnostics endpoint
(see Refs #9114)
> - The benefit is that platform operators can answer "why is this agent
not waking up?" from a safe, read-only HTTP endpoint rather than needing
direct database access, and CI/monitoring can assert expected wake
behavior

## Linked Issues or Issue Description

Refs #9114 (companion blocker diagnostics endpoint, already merged —
this PR extends the same diagnostic surface to wake/activity history)

## What Changed

- **New route** `GET /api/issues/:id/diagnostics/wakes` in
`server/src/routes/issues.ts`: returns a bounded (14-day window, 50-row
cap) projection of `agent_wakeup_requests` rows and wake-relevant
`activity_log` rows (defer/suppression events)
- **Sanitized projection**: raw `payload`, `details`, `error`, and
`triggerDetail` fields are stripped; unknown free-form `source`,
`reason`, and `status` values are projected to `"other"` to prevent
schema bleed
- **Deterministic `diagnosis` and `likelyReason` fields**: includes
Case-B inference ("no wake enqueued — visible blocker not done") that
calls the existing blocker-readiness helper from Slice 1 (#9114) so the
wake surface can explain missing wakes caused by outstanding blockers
- **Auth**: `assertCompanyAccess` + `assertIssueReadAllowed`;
cross-company requests are denied; Case-B blocker inference filters by
caller trust level so hidden (low-trust) blockers are mentioned but not
identified
- **Types in `@paperclipai/shared`**: `IssueWakeDiagnosticsResponse`,
`WakeEvent`, `ActivityEvent` exported from the shared package
- **OpenAPI tag registration** for the new route
- **Skill reference docs** in
`skills/paperclip/references/api-reference.md` documenting the endpoint
contract
- **Test coverage**
(`server/src/__tests__/issue-wake-diagnostics-routes.test.ts`, embedded
Postgres): happy path, empty/null diagnosis, Case-B inference, low-trust
hidden blocker, cross-company denial, raw blob minimization, cap
behaviour, combined blocker+wake test run

## Verification

```bash
# Wake diagnostics tests only
pnpm exec vitest run server/src/__tests__/issue-wake-diagnostics-routes.test.ts

# Wake + blocker diagnostics together (integration)
pnpm exec vitest run server/src/__tests__/issue-blocker-diagnostics-routes.test.ts server/src/__tests__/issue-wake-diagnostics-routes.test.ts

# Type-check shared and server packages
pnpm --filter @paperclipai/shared typecheck
pnpm --filter @paperclipai/server typecheck

# Whitespace / diff check
git diff --check
```

All commands passed locally.

## Risks

- **No schema or migration changes** — this is a read-only projection
over existing tables; no DDL risk.
- **Bounded queries** — 14-day window + 50-row cap limit per call; no
unbounded scans.
- **Auth boundary** — cross-company access is denied at
`assertCompanyAccess`; Case-B inference uses the same per-node trust
filtering as the blocker endpoint so low-trust blockers are acknowledged
but not identified.
- Low overall risk; the endpoint is additive and read-only.

## Model Used

- **Provider:** Anthropic
- **Model:** Claude Sonnet 4.6 (`claude-sonnet-4-6`)
- **Tool use:** yes (file reads, edits, bash execution, Paperclip API
calls)
- **Reasoning mode:** standard (no extended thinking)

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-07 04:45:23 +00:00
Nicky Leach 295294d7ce
Add read-only issue blocker diagnostics endpoint (#9114)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents block each other with `blockedByIssueIds` relationships to
express dependencies
> - Users and tooling have no lightweight way to inspect *why* an issue
is blocked or whether its blockers are themselves ready to resolve
> - A read-only diagnostic endpoint over the existing blocker graph lets
callers understand dependency chains without requiring a full issue-tree
traversal
> - This pull request adds `GET /api/issues/:id/diagnostics/blockers` —
a bounded, read-only projection over each blocker's readiness state
> - The benefit is that callers can surface blocking-chain diagnosis
(e.g. "waiting on N blockers, M of which are themselves blocked") from a
single authenticated request, using only data they already have read
permission for

## Linked Issues or Issue Description

No public GitHub issue exists for this change. Feature description:

**Subsystem affected:** `server/` — REST API & orchestration services;
`packages/shared` — types, constants, validators, API paths

**Problem or motivation**

There is no API endpoint to inspect *why* an issue is blocked or to get
a per-blocker readiness summary. Clients must walk the issue graph
manually or fetch full issue objects, which requires multiple
round-trips and is expensive.

**Proposed solution**

A single `GET /api/issues/:id/diagnostics/blockers` endpoint returns a
bounded projection: root issue summary, an ordered blocker list with
per-blocker `readiness` state, and a top-level `diagnosis` field
summarizing overall blocking status. Authorization mediation omits
blockers the caller cannot read, so `diagnosis` only reflects visible
data.

**Alternatives considered**

A general graph-walk query (too broad/expensive for a targeted
diagnostic call); enriching the existing `GET /api/issues/:id` response
(too coupled to the main response shape and adds weight for callers that
do not need blocker detail).

**Roadmap alignment**

Read-only observability surface over existing data; no database schema
changes. This aligns with tooling that helps users understand dependency
state without mutating anything.

## What Changed

- Added `GET /api/issues/:id/diagnostics/blockers` route to the server
- Returns per-blocker `readiness` state and a top-level `diagnosis`
field summarizing overall blocking status
- Enforces `issue:read` authorization per-blocker: unauthorized blockers
are omitted and do not influence `diagnosis` or `readiness` values
- Added shared TypeScript response types in `@paperclipai/shared`
- Added route-level tests using embedded Postgres
- Added API documentation in the `paperclip` skill

## Verification

```sh
./node_modules/.bin/vitest run server/src/__tests__/issue-blocker-diagnostics-routes.test.ts
pnpm --filter @paperclipai/shared typecheck
pnpm --filter @paperclipai/server typecheck
```

All three commands pass locally.

## Risks

- Read-only endpoint over existing relations — no writes, no schema or
migration changes — low risk
- Authorization mediation intentionally omits unauthorized blockers from
both the list and from `diagnosis`/`readiness`; callers with partial
access will see a narrower picture than the full blocker graph

## Model Used

- Provider: Anthropic
- Model: Claude Sonnet 4.6 (`claude-sonnet-4-6`)
- Context window: 200k tokens
- Mode: Tool use, code generation, extended reasoning

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` /
`Closes: #` / `Refs: #` OR (b) described the issue in-PR following the
relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-06 20:42:40 -07:00
Nicky Leach a371ceec60
Fail projectless git-worktree workspaces during heartbeat setup (#9118)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agent work can run in shared, isolated, or operator-branch execution
workspaces
> - Isolated/operator git-worktree modes require a real git checkout as
their base
> - A projectless issue can otherwise resolve to the agent fallback
workspace directory
> - That fallback is not a valid project checkout for git worktree setup
> - This pull request adds a setup-time guard before workspace
realization starts
> - The benefit is that misconfigured work fails with a typed
remediation instead of raw git errors or accidental execution from the
agent home directory

## Linked Issues or Issue Description

No public GitHub issue was found for this specific failure mode. Inline
description follows the bug report template:

**What happened?**
When a Paperclip issue has no associated project (`projectId: null`) and
is configured for `isolated_workspace` or operator-branch execution with
`strategy: git_worktree`, the heartbeat setup silently fell back to the
`agent_home` directory as the base workspace. Because `agent_home` is
not a git repository checkout, the subsequent git worktree operations
either failed with raw git errors or — in the degraded path — ran in the
wrong directory entirely.

**Expected behavior**
A projectless issue requesting `git_worktree` execution should fail
immediately at setup with a typed `workspace_validation_failed` result
and a human-readable remediation message explaining that a project
workspace or a reusable execution workspace with a valid git base is
required.

**Steps to reproduce**
1. Create a Paperclip issue with `projectId: null` (no project
attached).
2. Assign it to an agent configured for `isolated_workspace` execution
with `strategy: git_worktree`.
3. Trigger a heartbeat run.
4. Observe: the heartbeat resolves the base workspace to `agent_home`
and either emits raw git errors during worktree setup or silently
executes from an incorrect directory.

**Paperclip version or commit**
`5cdf5103c` (current `master` HEAD at time of fix)

**Deployment mode**
Local dev (`pnpm dev`) / built from source — reproduces in any mode
because the fallback is in core workspace resolution logic.

**Agent adapter(s) involved**
Not adapter-specific (core bug — affects all adapters that issue
heartbeats for projectless tasks)

**Database mode**
Not database-related

**Access context**
Agent (bearer API key via `agent_api_keys`)

## What Changed

- Added a heartbeat setup guard that validates isolated/operator
`git_worktree` base workspaces before realization.
- The guard fails projectless `agent_home` fallback cases with a typed
`workspace_validation_failed` result and remediation text.
- The guard also fails non-git project base directories before raw git
worktree operations run.
- Added regression coverage for projectless isolated mode,
operator-branch mode, non-git bases, valid git bases, and
shared-workspace no-op behavior.

## Verification

- `pnpm exec vitest run
server/src/__tests__/heartbeat-workspace-session.test.ts`
- `pnpm exec vitest run server/src/__tests__/workspace-runtime.test.ts`
- `pnpm --filter @paperclipai/server typecheck`
- `pnpm -r typecheck`
- `pnpm test:run`
- `pnpm build`

## Risks

- Low risk. The new guard only applies to issue-backed isolated/operator
execution modes using `git_worktree`; shared workspaces and
non-git-worktree strategies are left unchanged.
- The intentional behavior shift is that invalid git-worktree bases now
fail earlier with a structured remediation instead of reaching
lower-level git setup.

## Model Used

- OpenAI GPT-5 Codex, coding-agent tool-use mode with local command
execution; context window size not exposed by this runtime.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-06 16:48:05 -07:00
Nicky Leach 5163208c3c
Add workspace branch ancestry diagnostics (#9117)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents run in git worktrees tied to a workspace branch; when the
actual branch diverges from the expected one (e.g. a parent feature
branch was renamed), Paperclip currently has no structured field to
report *why* the branch is incoherent or whether it can be
auto-reconciled
> - The workspace-incoherence fingerprint already captures SHA
mismatches, but there is no evidence field distinguishing "actual branch
is a descendant of expected" (safe to fast-forward) from "branches have
diverged" (needs human review) or "SHAs are unavailable" (unknown)
> - Operators and future recovery flows need a typed verdict to make
decisions without re-running git commands themselves
> - This pull request adds `ancestryVerdict` and `plainLanguageReason`
evidence fields computed via `git merge-base --is-ancestor`, and
scaffolds the off-by-default `enableWorkspaceBranchReconcileForward`
instance setting with no runtime behavior yet
> - The benefit is that future recovery logic can branch on a typed
verdict rather than parsing prose, while the fingerprint v1 payload
stays stable

## Linked Issues or Issue Description

No public GitHub issue pre-exists for this diagnostic addition.

**Problem or motivation**

When Paperclip detects that an agent's actual workspace branch differs
from the recorded expected branch, the current fingerprint carries only
raw SHAs. There is no typed field indicating whether the actual branch
is a descendant of the expected one (safe reconcile path) vs. a true
divergence (requires human intervention) vs. an indeterminate state
(missing SHAs or git errors). Downstream recovery logic cannot branch
safely without re-running git.

**Proposed solution**

Add `ancestryVerdict` and `plainLanguageReason` to the workspace
incoherence evidence type; compute via `git merge-base --is-ancestor`;
scaffold a feature-flag for future forward-reconcile behavior
(`enableWorkspaceBranchReconcileForward`, off by default, not yet read
by any runtime path).

**Alternatives considered**

Encoding the verdict in the existing fingerprint string was rejected
because the fingerprint is a stable identity hash, not a mutable
evidence bag. Changing it would break monitors keyed on the string.

**Roadmap alignment**

Supports future workspace auto-reconcile work; ROADMAP.md has no
conflicting entry for this diagnostic layer.

## What Changed

- `packages/shared/src/types/heartbeat.ts` adds `ancestryVerdict` and
`plainLanguageReason` fields to `WorkspaceIncoherenceEvidence`
- `packages/shared/src/types/instance.ts` adds
`enableWorkspaceBranchReconcileForward` boolean (off by default)
- `packages/shared/src/validators/instance.ts` exports the new flag from
the settings validator
- `server/src/services/workspace-runtime.ts` computes `ancestryVerdict`
via `git merge-base --is-ancestor`; falls back to `unknown` on missing
SHAs or command errors; excludes verdict fields from fingerprint v1
computation
- `server/src/services/instance-settings.ts` wires the new setting
through to the settings service
- Tests updated in `workspace-runtime.test.ts`,
`instance-settings-service.test.ts`, `instance-settings-routes.test.ts`,
and `instance.test.ts` (104 tests total)

## Verification

```bash
pnpm exec vitest run \
  server/src/__tests__/workspace-runtime.test.ts \
  server/src/__tests__/instance-settings-service.test.ts \
  server/src/__tests__/instance-settings-routes.test.ts \
  packages/shared/src/validators/instance.test.ts
# 104 tests pass

pnpm --filter @paperclipai/shared typecheck
pnpm --filter @paperclipai/server typecheck
# both exit 0
```

Manual: trigger a workspace incoherence event and confirm the evidence
object carries `ancestryVerdict` and `plainLanguageReason`; confirm the
fingerprint string stays `workspace_incoherence:v1:sha256:...`.

## Risks

**Low risk.** Purely additive. Fingerprint v1 payload is unchanged. The
new flag has no runtime effect in this PR. `git merge-base
--is-ancestor` exits non-zero for both "not an ancestor" and "command
error"; both are handled and collapsed to typed values with a prose
reason.

## Model Used

Provider: Anthropic, model: Claude Sonnet 4.6 (`claude-sonnet-4-6`),
200k context, tool use enabled.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-06 16:29:01 -07:00
Dotta ef617bee5c
[codex] Enforce backend execution release gates (#9089)
## Thinking Path

> - Paperclip is the open source control plane people use to manage AI
agents for work.
> - Backend execution safety is part of the control plane contract:
agents must stop at budget hard limits, stale execution paths must not
create duplicate live work, and checkout ownership must remain
authoritative.
> - The recovery branch bundled these release-gate checks with broader
unrelated work.
> - Reviewers need a narrow PR that isolates only the backend safety
behavior and regression coverage.
> - This pull request keeps budget incident creation idempotent so
repeated evaluation does not duplicate release-gate telemetry or
approvals.
> - It also adds focused coverage for idle timer skips, stale queued-run
behavior, and live checkout conflict preservation.
> - The benefit is a smaller, reviewable release-gate slice for budget
hard stops, stale execution recovery, and ownership-safe issue mutation.

## Linked Issues or Issue Description

Refs #8866

This PR extracts a focused backend safety slice from the closed broad
recovery PR. The underlying problem is that release-gate behavior needs
direct regression coverage before review: budget hard stops should not
duplicate incidents/logging on repeated evaluation, timer wakes should
respect the no-actionable-work skip policy, stale queued runs should
remain invalidated, and active checkout ownership must survive
conflicting checkout attempts without side effects.

## What Changed

- Made budget incident creation report whether an incident was newly
created, so soft/hard threshold activity logs are emitted once per
incident window.
- Added embedded Postgres budget release-gate tests covering soft
incident idempotency, hard-stop pause/cancel behavior, budget override
resume behavior, and telemetry redaction.
- Added heartbeat coverage for skipping generic timer wakes when the
agent opts into `skipTimerWhenNoActionableWork`, while preserving
legacy/proactive timer behavior.
- Added stale execution lock route coverage proving a conflicting
checkout returns `409` without overwriting live checkout or execution
ownership and without writing checkout activity.

## Verification

- `./node_modules/.bin/vitest run
server/src/__tests__/budgets-service.test.ts
server/src/__tests__/heartbeat-process-recovery.test.ts
server/src/__tests__/heartbeat-stale-queue-invalidation.test.ts
server/src/__tests__/issue-stale-execution-lock-routes.test.ts
--no-file-parallelism --maxWorkers=1`
- First run: 3 files passed, 98 tests passed;
`issue-stale-execution-lock-routes.test.ts` failed during import because
the isolated worktree initially lacked dev dependency links for
`supertest`.
- `CI=true NODE_ENV=development pnpm install --frozen-lockfile
--ignore-scripts`
- Recreated worktree dev dependency links; emitted unrelated plugin SDK
bin warnings because plugin SDK dist files were not built under
`--ignore-scripts`.
- `./node_modules/.bin/vitest run
server/src/__tests__/issue-stale-execution-lock-routes.test.ts
--no-file-parallelism --maxWorkers=1`
  - Passed: 1 file, 7 tests.
- `git diff --check`
  - Passed.

## Risks

Low to medium risk. The production code change is intentionally small
and only suppresses duplicate threshold activity logging for
already-open budget incidents, but it affects budget release-gate
observability. The new tests use embedded Postgres and should catch
regressions in budget hard stops, timer wake gating, stale queue
invalidation, and checkout conflict preservation.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex, GPT-5 coding agent, tool-use enabled.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-06 16:33:36 -05:00
Dotta dfc256a543
[codex] Add heartbeat policy eval coverage (#9087)
## Thinking Path

> - Paperclip is the open source control plane people use to manage AI
agents for work.
> - The relevant subsystem is the agent heartbeat policy surface: the
Paperclip skill, default onboarding AGENTS.md, new-agent runtime
defaults, and promptfoo eval coverage for agent behavior.
> - A broad recovery PR collected several unrelated local-mainline
changes, which made review too large and mixed policy/eval updates with
server execution and UI work.
> - This PR extracts only the heartbeat policy and prompt-eval slice so
reviewers can assess the behavior contract independently.
> - The eval additions cover scoped wake handling, idle no-op behavior,
dependency-blocked comment triage, final disposition, budget hard stops,
and Phase 5 memory/control-surface policy expectations.
> - The benefit is a narrower review surface plus deterministic
follow-up guidance for server/shared tests that should back these
prompt-level checks.

## Linked Issues or Issue Description

Refs #8866

No public issue was filed for this split. This is a focused extraction
from the closed broad recovery PR so heartbeat policy and eval coverage
can be reviewed separately from execution behavior, work-product feature
work, plugin hardening, pipeline health, and unrelated UI polish.

## What Changed

- Added promptfoo release-gate cases for scoped wake payload handling,
idle exits, dependency-blocked comment triage, final disposition, and
budget hard-stop behavior.
- Added Phase 5 memory/control-surface prompt eval cases for provider
binding precedence, provenance/audit fields, hook cost/trust handling,
and auditable board command surfaces.
- Documented how these prompt evals map to deterministic server/shared
follow-up coverage.
- Updated agent policy guidance so operator-facing engineering outputs
such as PRs, branches, commits, previews, and runtime services get
matching work products.
- Defaulted new agent runtime config to skip timer heartbeats when there
is no actionable work, with focused test coverage.

## Verification

- `cd evals/promptfoo && npx promptfoo@latest validate -c
promptfooconfig.yaml` passes.
- `/srv/paperclip/home/paperclipai/paperclip/node_modules/.bin/vitest
run ui/src/lib/new-agent-runtime-config.test.ts` passes in an isolated
worktree after `pnpm install --ignore-scripts --frozen-lockfile` created
workspace links.
- A live promptfoo eval was not run because `OPENROUTER_API_KEY`,
`OPENAI_API_KEY`, and `ANTHROPIC_API_KEY` were unset in the workspace.

## Risks

Low-to-medium risk. The runtime default reduces timer-driven empty
heartbeats for newly created agents, so the main behavioral risk is
missing an edge case where timer wakes were expected despite no
actionable work. The promptfoo additions are deterministic assertion
coverage and documentation-only until a live eval is run with provider
credentials.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI GPT-5-based Codex coding agent in the Paperclip local Codex
adapter environment; exact hosted model ID and context window were not
exposed to the agent runtime. Tool use included shell, git, promptfoo
validation, Vitest, and the GitHub connector/CLI.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-06 16:31:14 -05:00
Dotta 903886bc79
[codex] Add starred resource sidebar controls (#9085)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The board UI is the main daily navigation surface for agents,
projects, and their related resources.
> - Operators need a lightweight way to keep frequently used agents and
projects close without changing company-wide ordering or ownership.
> - Resource memberships already model per-user relationships to
projects and agents, so they are the right place to store user-specific
starred state.
> - This pull request extends that membership contract with a starred
timestamp and exposes star controls in list/detail views.
> - The sidebar then uses those starred memberships to show compact,
user-specific shortcuts.
> - The benefit is faster navigation without introducing a separate
favorites system or leaking preferences across users.

## Linked Issues or Issue Description

No public GitHub issue exists.

Feature request:

## Problem or motivation

Users cannot pin frequently used agents or projects into the main
sidebar. Returning to important resources requires scanning full
project/agent lists or navigating through detail pages, which adds
friction to repeated daily workflows.

## Proposed solution

Store a per-user `starred_at` timestamp on agent and project
memberships, expose API actions to set or clear that state, add star
toggle controls to list/detail pages, and render starred projects and
agents as compact sidebar shortcuts.

## Alternatives considered

A separate favorites table would work, but it would duplicate membership
scoping and require another resource relationship model. Keeping starred
state on memberships preserves existing company/user boundaries and
avoids a second source of truth.

## Roadmap alignment

Checked `ROADMAP.md`; no overlapping planned core work for starred
resource/sidebar navigation was found.

## Additional context

The affected subsystems are `packages/db`, `packages/shared`, `server/`,
and `ui/`. The migration is idempotent with `IF NOT EXISTS` guards so
environments that saw an earlier local migration name can still apply
the final ordered migration safely.

## What Changed

- Added idempotent migration `0133_resource_membership_stars` for
`starred_at` columns and lookup indexes on agent/project memberships.
- Extended shared resource membership types and validators with starred
metadata and actions.
- Updated server resource membership services/routes to read and mutate
starred resource state.
- Added reusable star toggle UI and resource membership hook support for
starred state.
- Added starred projects and agents sidebar rendering, plus star
controls on list and detail pages.
- Added focused shared, server, and UI coverage for starred membership
behavior and sidebar rendering.

## Verification

- Rebased and force-with-lease pushed current PR head
`a086fc965391c9e50a51b5b83b5b44a797b2a6f4` onto current
`paperclipai/paperclip:master`; `gh pr view` reports `MERGEABLE` with no
merge conflicts. GitHub checks are green for this fresh head.
- `pnpm exec vitest run packages/shared/src/resource-memberships.test.ts
server/src/__tests__/resource-memberships-routes.test.ts
server/src/__tests__/workspace-runtime.test.ts
ui/src/components/Sidebar.test.tsx
ui/src/components/SidebarAgents.test.tsx
ui/src/components/SidebarStarredProjects.test.tsx
ui/src/components/StarToggle.test.tsx
ui/src/pages/InstanceExperimentalSettings.test.tsx` passed after the
rebase: 8 files, 143 tests.
- Greptile re-review is 5/5; the remaining screenshot thread was
resolved as non-blocking because this task explicitly requested no
screenshots/images in the PR.
- `pnpm exec vitest run
ui/src/components/SidebarStarredProjects.test.tsx` passed after the
mobile pending-spinner fix.
- `pnpm exec vitest run packages/shared/src/resource-memberships.test.ts
server/src/__tests__/resource-memberships-routes.test.ts
ui/src/components/Sidebar.test.tsx
ui/src/components/SidebarAgents.test.tsx
ui/src/components/SidebarStarredProjects.test.tsx
ui/src/components/StarToggle.test.tsx
ui/src/pages/InstanceExperimentalSettings.test.tsx` passed: 7 files, 68
tests.
- `pnpm --filter @paperclipai/db typecheck && pnpm --filter
@paperclipai/shared typecheck && pnpm --filter @paperclipai/server
typecheck && pnpm --filter @paperclipai/ui typecheck` passed
db/shared/server, then failed in pre-existing UI code outside this PR:
`src/pages/CompanyEnvironments.tsx` missing `@xterm/*` type declarations
and `previous` possibly null.
- Checked that the PR diff does not include `pnpm-lock.yaml` or
`.github/workflows` changes.
- Checked `ROADMAP.md` and found no overlapping planned core work for
starred resource/sidebar navigation.
- Searched existing GitHub PRs for duplicate starred-resource/sidebar
work and found none.

## Risks

- Migration touches membership tables. The SQL uses `IF NOT EXISTS` for
columns and indexes so environments that saw an earlier local migration
name can still apply this safely.
- Sidebar ordering and visibility changes could affect users who rely on
the previous flat sidebar layout.
- Starred state is per-user membership metadata; code paths must
continue preserving company/user scoping around memberships.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI GPT-5 Codex, tool-enabled coding agent with shell/GitHub access.
Context window not disclosed by the runtime.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-06 14:09:11 -05:00
Nicky Leach 8516700217
fix(server): report source-install version from git metadata (#9103)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The server reports its own version through `server/src/version.ts`,
which is read by the `/health` endpoint and the telemetry client
> - When running from a cloned source tree, `server/package.json` is
frozen at the last published release version (e.g. `0.3.1`), so the
reported `serverVersion` never reflects how far the local checkout has
drifted from that release
> - Operators and support staff cannot tell from telemetry or health
output whether they are running a tagged release or a development build
with local commits on top
> - A `git describe --tags --match v* --long --dirty` call at startup
gives the exact nearest tag, number of commits since it, the current
SHA, and whether the tree is dirty — all the information needed to
compute a semantically meaningful version
> - This pull request replaces the static `pkg.version` export with a
`resolveServerVersion()` call that parses `git describe` output into
`YYYY.MDD.P+N.git.<sha>` (drift), `YYYY.MDD.P` (clean on-tag), or
appends `.dirty` for a modified tree, with a non-throwing fallback to
`package.json` when git is unavailable
> - The benefit is that from-source installs now report a version string
that lets operators and support quickly identify their exact checkout
state without running additional git commands

## Linked Issues or Issue Description

No pre-existing public issue. Inline description:

**What happened?**

When Paperclip is installed from source (git clone + pnpm), `GET
/health` and the telemetry envelope report the version frozen at the
last published `package.json` value (e.g. `0.3.1`) regardless of how
many commits ahead of that tag the local checkout is.

**Expected behavior**

The reported version should reflect the actual local state — nearest
release tag, number of commits since that tag, abbreviated commit SHA,
and a dirty marker when the working tree has uncommitted changes.

**Steps to reproduce**

Clone the repo, run `pnpm install && pnpm --filter @paperclipai/server
start`, then call `GET /health` or inspect telemetry envelopes. The
`serverVersion` field shows the `package.json` version even when the
checkout is dozens of commits ahead of that tag.

**Paperclip version or commit**

Affects all source-tree installs where `package.json` has not been
updated to match the current HEAD.

**Deployment mode**

Source install (git clone).

## What Changed

- `server/src/version.ts`: extracted `resolveServerVersion()` (replaces
the module-level `const serverVersion`) and `parseGitDescribeVersion()`
(exported for unit testing); the default implementation shells out to
`git describe --tags --match v* --long --dirty` with a 1 500 ms timeout;
falls back to `pkg.version ?? "0.0.0"` without throwing when git is
unavailable or the output cannot be parsed; replaced `logger` import
with a `console.debug`-based default to avoid pulling pino transport
side effects into a zero-dependency utility module
- `server/src/__tests__/version.test.ts`: 7-test unit suite covering
drift, clean on-tag collapse, dirty on-tag edge case, unparseable
fallback, `resolveServerVersion` happy path, and git-unavailable
fallback — all exercised via injected stubs without spawning a real git
process

## Verification

```sh
# Unit tests (7 tests)
pnpm exec vitest run server/src/__tests__/version.test.ts

# Type check
pnpm --filter @paperclipai/server typecheck

# Health and telemetry regression
pnpm exec vitest run server/src/__tests__/health.test.ts server/src/__tests__/telemetry-client-flush.test.ts

# Runtime smoke (from-source checkout)
# git describe --tags --match 'v*' --long  =>  v2026.626.0-58-g518fc71ce
# server startup => serverVersion = 2026.626.0+59.git.3367571cc
```

All commands passed at the committed HEAD.

## Risks

Low. The change is additive and self-contained to
`server/src/version.ts`:

- `git describe` is called once at module load with a 1 500 ms timeout;
failure (non-git environment, git not on PATH, timeout) is silently
caught and falls back to `pkg.version`, preserving existing behavior for
published-package installs
- No API surface, database schema, or migration is touched
- The telemetry envelope already carried `serverVersion`; only the value
changes for source-tree installs

## Model Used

Claude Sonnet 4.6 (`claude-sonnet-4-6`) with tool use and code
execution. Context window: 200 k tokens.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [ ] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-06 09:15:44 -07:00
Nicky Leach 8a058f9d79
fix: deduplicate adapter-agnostic config keys (#9058)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - When you swap an agent's adapter (e.g. from one LLM provider to
another), the server merges the incoming PATCH body with stored config —
keys listed in \`ADAPTER_AGNOSTIC_KEYS\` are preserved regardless of
which adapter is active
> - That constant was defined independently in two places:
\`server/src/agents.ts\` (used by the adapter-swap route) and
\`ui/src/lib/agent-config-patch.ts\` (used by the UI patch builder)
> - PR #8975 fixed the bug where \`paperclipSkillSync.desiredSkills\`
was dropped on adapter swap by adding it to the server-side constant,
but the UI-side copy was not updated in the same PR — creating ongoing
drift risk
> - This pull request hoists \`ADAPTER_AGNOSTIC_KEYS\` into
\`packages/shared\` so both consumers import the same constant
> - The benefit is a single source of truth: any future key addition is
made in one place and both the server route and the UI patch builder
pick it up automatically, with a drift guard to catch any accidental
re-duplication

## Linked Issues or Issue Description

Refs #8975 — follow-up deduplication: #8975 fixed the runtime bug but
left the constant duplicated across server and UI. This PR closes that
gap.

## What Changed

- Added \`ADAPTER_AGNOSTIC_KEYS\` constant and \`AdapterAgnosticKey\`
type to \`packages/shared/src/adapter-agnostic-keys.ts\`
- Updated \`server/src/agents.ts\` to import the shared constant,
removing the local copy
- Updated \`ui/src/lib/agent-config-patch.ts\` to import the shared
constant, removing the local copy
- Added \`packages/shared/src/adapter-agnostic-keys.test.ts\`: drift
guard asserting the expected key set and both consumer import sites

## Verification

\`\`\`bash
pnpm exec vitest run packages/shared/src/adapter-agnostic-keys.test.ts
ui/src/lib/agent-config-patch.test.ts
server/src/__tests__/agent-instructions-routes.test.ts
pnpm --filter @paperclipai/shared typecheck
pnpm --filter @paperclipai/server typecheck
pnpm --filter @paperclipai/ui typecheck
\`\`\`

All 15 tests pass across the three files; all three packages typecheck
clean.

## Risks

Low risk — behavior-preserving refactor. The key set is unchanged; only
the import source changes. The drift guard will fail loudly if someone
accidentally re-introduces a local copy or modifies one without updating
the other.

> For core feature work, check [\`ROADMAP.md\`](ROADMAP.md) first and
discuss it in \`#dev\` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See \`CONTRIBUTING.md\`.

## Model Used

- Provider: Anthropic
- Model: Claude Sonnet 4.6 (\`claude-sonnet-4-6\`)
- Context: standard context window, tool use enabled
- Reasoning: standard mode (no extended thinking)

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with \`Fixes: #\` /
\`Closes #\` / \`Refs #\` OR (b) described the issue in-PR following the
relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub \`#NNN\` /
\`github.com/paperclipai/paperclip\` URLs)
- [ ] My branch name describes the change (e.g. \`docs/...\`,
\`fix/...\`) and contains no internal Paperclip ticket id or
instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-05 21:47:38 -07:00
Dotta ad961227f5
feat(secrets): add user-specific runtime secrets (#8825)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent runs often need provider credentials, API tokens, and other
environment-bound secrets.
> - Company-level secrets work for shared credentials, but they do not
model values that should differ by human operator.
> - Without a user-scoped model, a run can dispatch without knowing
whether the responsible human has supplied the needed value.
> - Paperclip also needs run attribution to make those user-scoped
runtime checks deterministic and auditable.
> - This pull request adds user-specific secret definitions, per-user
values, environment bindings, responsible-user attribution, and runtime
resolution gates.
> - The benefit is that teams can define the secret once, let each user
provide their own value, and block runs before dispatch when required
user secrets or active definitions are unavailable.

## Linked Issues or Issue Description

Refs #224
Refs #6057

This PR implements user-specific secret support as a core
secret-management capability rather than a one-off adapter setting. It
is related to existing public work on company secrets UI and runtime
secret refs, but is distinct because the value is owned by the
responsible user and resolved at run dispatch time.

Related PR search before opening found existing secrets work such as
#1550, #8256, #8614, #8634, and #8647; none of those add the full
user-secret definition/value/runtime gate covered here.

## What Changed

- Added user-secret definitions and per-user "My secrets" values,
keeping stored values out of access metadata.
- Added `user_secret_ref` environment bindings and UI affordances to
pick them alongside existing secret refs.
- Added responsible-user runtime resolution so user-secret refs resolve
against the human responsible for the run.
- Added pre-dispatch missing-secret gates so runs fail before adapter
dispatch when required user values are absent or definitions are
inactive.
- Added low-trust allowlist hardening for user-secret runtime access.
- Added issue, routine, run, and agent API key responsible-user
attribution and fail-closed dispatch behavior when attribution cannot be
resolved.
- Added denial-copy mapping so responsible-user authorization failures
surface as actionable run outcomes instead of opaque setup failures.
- Added OpenAPI documentation for the user-secret routes.
- Rebases cleanly on current `master`; migrations were renumbered
incrementally as `0128_user_specific_secrets`,
`0129_agent_api_key_responsible_user`, and
`0130_run_responsible_user_invariant` after upstream `0126`/`0127`
migrations.
- Removed previously committed local design screenshots so the PR
contains code/docs/tests only.

## Verification

- PASS: PR head `2527febd106bcf3ca264ca0da7fca491084192d6` is based on
`paperclipai/paperclip:master`.
- PASS: `git diff --check`
- PASS: `git diff --name-only public/master...HEAD | rg
'^(pnpm-lock\\.yaml|\\.github/workflows/|screenshots/)' || true`
produced no files.
- PASS: migration journal audit confirmed unique indexes through `130`
with tail entries `0126_issue_comment_derived_attribution`,
`0127_environment_custom_images_instance_scoped`,
`0128_user_specific_secrets`, `0129_agent_api_key_responsible_user`, and
`0130_run_responsible_user_invariant`.
- PASS: `pnpm --filter @paperclipai/ui typecheck`
- PASS: `pnpm --filter @paperclipai/server typecheck`
- PASS: `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/heartbeat-responsible-user-invariant.test.ts`
- PASS: `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/heartbeat-active-run-output-watchdog.test.ts
src/__tests__/heartbeat-stale-queue-invalidation.test.ts
src/__tests__/heartbeat-workspace-finalize-branch.test.ts
src/__tests__/issue-monitor-scheduler.test.ts`
- PASS: `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/heartbeat-comment-wake-batching.test.ts
src/__tests__/heartbeat-retry-scheduling.test.ts
src/__tests__/heartbeat-accepted-plan-workspace-refresh.test.ts
src/__tests__/heartbeat-plugin-environment.test.ts`
- PASS: `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/low-trust-red-team-routes.test.ts`
- PASS: `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/secrets-service.test.ts` (55 tests)
- PASS: `pnpm vitest run server/src/__tests__/secrets-routes.test.ts
server/src/__tests__/secrets-service.test.ts` (89 tests after final
Greptile cleanup fixes)
- PASS: `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/heartbeat-issue-liveness-escalation.test.ts` (17 tests
after the final rebase CI fix)
- PASS: focused server Vitest batches covering heartbeat recovery,
project env, plugin env, routines, low-trust, pipelines, monitors,
watchdog, and stale queue paths.
- PASS: GitHub checks are green on
`2527febd106bcf3ca264ca0da7fca491084192d6`, including Typecheck +
Release Registry, Build, General tests, serialized server suites, e2e,
Canary Dry Run, verify, security checks, and Greptile Review.
- PASS: Greptile Review completed successfully on
`2527febd106bcf3ca264ca0da7fca491084192d6` with Confidence Score 5/5,
and GraphQL review-thread audit returned zero unresolved non-outdated
threads.

## Risks

- Runtime behavior now depends on a run having a correct responsible
user; missing or incorrect responsibility assignment can block runs
before adapter dispatch.
- `user_secret_ref` bindings intentionally expose metadata without
values, but UI/API callers may need to handle the new binding kind
explicitly.
- External secret providers and IAM policies are not automatically
provisioned by this PR; operators still need to configure provider-side
access for non-local vaults.
- The PR is broad across db/shared/server/UI/runtime paths, so release
validation should include both API and UI secret workflows before merge.
- The migration renumbering is intentionally incremental after upstream
migrations; the branch migrations use guarded
column/table/index/constraint creation so users who tested the older
draft numbering should not hit duplicate DDL for the existing objects.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex, GPT-5-based coding agent (`gpt-5`), Codex local adapter
with shell/tool use and code execution. Context window and internal
reasoning mode are not exposed by the runtime.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 05:58:20 -05:00