The embedded-Postgres support probe returned a promise that was never
awaited, so `supported` was always falsy and all 4 gate tests skipped.
QA (PAP-13227) validated this fix; committing it so the suite stays live.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Add suggest/change permission keys for agent and skill configuration, route protected mutations through authorization.decide, repair default root and reflection-coach grants, and carry agent permission grants through company portability.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Normalize built-in routine defaults through the same projection used by persisted routine status checks so pristine bundles do not report operator_modified after a clean reconcile. Add regression coverage for the status read path after Reflection Coach materialization.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Phase 1 of PAP-13031: markdown-backed shipped defaults for the built-in
Reflection Coach — agent AGENTS.md, paused-by-default recent-agent-reflection
routine template, and the bundled reflection-coach operations skill. Grounded
in the live coach but cleaned up: adds the interaction-gated apply model
(displayed diff + accepted interaction + separate follow-up run) now that the
built-in ships with skill/instruction update permissions.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
## 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>
## 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>
## 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>
## 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>
## 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>
Adds company skill fork precheck metadata, fork result/reassignment contracts, selected-agent reassignment during fork creation, and targeted server/shared test coverage.
## 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>
## 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>
## 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>
## 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>