[codex] add comprehensive UI Storybook coverage (#4132)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies.
> - The board UI is the main operator surface, so its component and
workflow coverage needs to stay reviewable as the product grows.
> - This branch adds Storybook as a dedicated UI reference surface for
core Paperclip screens and interaction patterns.
> - That work spans Storybook infrastructure, app-level provider wiring,
and a large fixture set that can render real control-plane states
without a live backend.
> - The branch also expands coverage across agents, budgets, issues,
chat, dialogs, navigation, projects, and data visualization so future UI
changes have a concrete visual baseline.
> - This pull request packages that Storybook work on top of the latest
`master`, excludes the lockfile from the final diff per repo policy, and
fixes one fixture contract drift caught during verification.
> - The benefit is a single reviewable PR that adds broad UI
documentation and regression-surfacing coverage without losing the
existing branch work.
## What Changed
- Added Storybook 10 wiring for the UI package, including root scripts,
UI package scripts, Storybook config, preview wrappers, Tailwind
entrypoints, and setup docs.
- Added a large fixture-backed data source for Storybook so complex
board states can render without a live server.
- Added story suites covering foundations, status language,
control-plane surfaces, overview, UX labs, agent management, budget and
finance, forms and editors, issue management, navigation and layout,
chat and comments, data visualization, dialogs and modals, and
projects/goals/workspaces.
- Adjusted several UI components for Storybook parity so dialogs, menus,
keyboard shortcuts, budget markers, markdown editing, and related
surfaces render correctly in isolation.
- Rebasing work for PR assembly: replayed the branch onto current
`master`, removed `pnpm-lock.yaml` from the final PR diff, and aligned
the dashboard fixture with the current `DashboardSummary.runActivity`
API contract.
## Verification
- `pnpm --filter @paperclipai/ui typecheck`
- `pnpm --filter @paperclipai/ui build-storybook`
- Manual diff audit after rebase: verified the PR no longer includes
`pnpm-lock.yaml` and now cleanly targets current `master`.
- Before/after UI note: before this branch there was no dedicated
Storybook surface for these Paperclip views; after this branch the local
Storybook build includes the new overview and domain story suites in
`ui/storybook-static`.
## Risks
- Large static fixture files can drift from shared types as dashboard
and UI contracts evolve; this PR already needed one fixture correction
for `runActivity`.
- Storybook bundle output includes some large chunks, so future growth
may need chunking work if build performance becomes an issue.
- Several component tweaks were made for isolated rendering parity, so
reviewers should spot-check key board surfaces against the live app
behavior.
## Model Used
- OpenAI Codex, GPT-5-based coding agent in the Paperclip harness; exact
serving model ID is not exposed in-runtime to the agent.
- Tool-assisted workflow with terminal execution, git operations, local
typecheck/build verification, and GitHub CLI PR creation.
- Context window/reasoning mode not surfaced by the 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 run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 12:13:23 -05:00
import { useMemo , useState , type ReactNode } from "react" ;
import type { Meta , StoryObj } from "@storybook/react-vite" ;
import type { Agent , CompanySecret , EnvBinding , Project , RoutineVariable } from "@paperclipai/shared" ;
import { Code2 , FileText , ListPlus , RotateCcw , Table2 } from "lucide-react" ;
import { EnvVarEditor } from "@/components/EnvVarEditor" ;
import { ExecutionParticipantPicker } from "@/components/ExecutionParticipantPicker" ;
[codex] Polish issue composer and long document display (#4420)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Issue comments and documents are the main working surface where
operators and agents collaborate
> - File drops, markdown editing, and long issue descriptions need to
feel predictable because they sit directly in the task execution loop
> - The composer had edge cases around drag targets, attachment
feedback, image drops, and long markdown content crowding the page
> - This pull request polishes the issue composer, hardens markdown
editor regressions, and adds a fold curtain for long issue
descriptions/documents
> - The benefit is a calmer issue detail surface that handles uploads
and long work products without hiding state or breaking layout
## What Changed
- Scoped issue-composer drag/drop behavior so the composer owns file
drops without turning the whole thread into a competing drop target.
- Added clearer attachment upload feedback for non-image files and
image-drop stability coverage.
- Hardened markdown editor and markdown body handling around HTML-like
tag regressions.
- Added `FoldCurtain` and wired it into issue descriptions and issue
documents so long markdown previews can expand/collapse.
- Added Storybook coverage for the fold curtain state.
## Verification
- `pnpm exec vitest run ui/src/components/IssueChatThread.test.tsx
ui/src/components/MarkdownEditor.test.tsx
ui/src/components/MarkdownBody.test.tsx --config ui/vitest.config.ts`
passed: 3 files, 75 tests.
- `git diff --check public-gh/master..pap-2228-editor-composer-polish --
. ':(exclude)ui/storybook-static'` passed.
- Confirmed this PR does not include `pnpm-lock.yaml`.
## Risks
- Low-to-medium risk: this changes user-facing composer/drop behavior
and long markdown display.
- The fold curtain uses DOM measurement and `ResizeObserver`; reviewers
should check browser behavior for very long descriptions and documents.
- No database migrations.
> 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, Paperclip
API, and GitHub CLI tool use in the local Paperclip workspace.
## 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 run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
Note: screenshots were not newly captured during branch splitting; the
UI states are covered by component tests and a Storybook story.
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-24 14:12:41 -05:00
import { FoldCurtain } from "@/components/FoldCurtain" ;
[codex] add comprehensive UI Storybook coverage (#4132)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies.
> - The board UI is the main operator surface, so its component and
workflow coverage needs to stay reviewable as the product grows.
> - This branch adds Storybook as a dedicated UI reference surface for
core Paperclip screens and interaction patterns.
> - That work spans Storybook infrastructure, app-level provider wiring,
and a large fixture set that can render real control-plane states
without a live backend.
> - The branch also expands coverage across agents, budgets, issues,
chat, dialogs, navigation, projects, and data visualization so future UI
changes have a concrete visual baseline.
> - This pull request packages that Storybook work on top of the latest
`master`, excludes the lockfile from the final diff per repo policy, and
fixes one fixture contract drift caught during verification.
> - The benefit is a single reviewable PR that adds broad UI
documentation and regression-surfacing coverage without losing the
existing branch work.
## What Changed
- Added Storybook 10 wiring for the UI package, including root scripts,
UI package scripts, Storybook config, preview wrappers, Tailwind
entrypoints, and setup docs.
- Added a large fixture-backed data source for Storybook so complex
board states can render without a live server.
- Added story suites covering foundations, status language,
control-plane surfaces, overview, UX labs, agent management, budget and
finance, forms and editors, issue management, navigation and layout,
chat and comments, data visualization, dialogs and modals, and
projects/goals/workspaces.
- Adjusted several UI components for Storybook parity so dialogs, menus,
keyboard shortcuts, budget markers, markdown editing, and related
surfaces render correctly in isolation.
- Rebasing work for PR assembly: replayed the branch onto current
`master`, removed `pnpm-lock.yaml` from the final PR diff, and aligned
the dashboard fixture with the current `DashboardSummary.runActivity`
API contract.
## Verification
- `pnpm --filter @paperclipai/ui typecheck`
- `pnpm --filter @paperclipai/ui build-storybook`
- Manual diff audit after rebase: verified the PR no longer includes
`pnpm-lock.yaml` and now cleanly targets current `master`.
- Before/after UI note: before this branch there was no dedicated
Storybook surface for these Paperclip views; after this branch the local
Storybook build includes the new overview and domain story suites in
`ui/storybook-static`.
## Risks
- Large static fixture files can drift from shared types as dashboard
and UI contracts evolve; this PR already needed one fixture correction
for `runActivity`.
- Storybook bundle output includes some large chunks, so future growth
may need chunking work if build performance becomes an issue.
- Several component tweaks were made for isolated rendering parity, so
reviewers should spot-check key board surfaces against the live app
behavior.
## Model Used
- OpenAI Codex, GPT-5-based coding agent in the Paperclip harness; exact
serving model ID is not exposed in-runtime to the agent.
- Tool-assisted workflow with terminal execution, git operations, local
typecheck/build verification, and GitHub CLI PR creation.
- Context window/reasoning mode not surfaced by the 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 run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 12:13:23 -05:00
import { InlineEditor } from "@/components/InlineEditor" ;
import { InlineEntitySelector , type InlineEntityOption } from "@/components/InlineEntitySelector" ;
import { JsonSchemaForm , type JsonSchemaNode , getDefaultValues } from "@/components/JsonSchemaForm" ;
import { MarkdownBody } from "@/components/MarkdownBody" ;
import { MarkdownEditor , type MentionOption } from "@/components/MarkdownEditor" ;
import { ReportsToPicker } from "@/components/ReportsToPicker" ;
import {
RoutineRunVariablesDialog ,
type RoutineRunDialogSubmitData ,
} from "@/components/RoutineRunVariablesDialog" ;
import { RoutineVariablesEditor , RoutineVariablesHint } from "@/components/RoutineVariablesEditor" ;
import { ScheduleEditor , describeSchedule } from "@/components/ScheduleEditor" ;
import { Badge } from "@/components/ui/badge" ;
import { Button } from "@/components/ui/button" ;
import { buildExecutionPolicy } from "@/lib/issue-execution-policy" ;
import { createIssue , storybookAgents } from "../fixtures/paperclipData" ;
function Section ( {
eyebrow ,
title ,
description ,
children ,
} : {
eyebrow : string ;
title : string ;
description? : string ;
children : ReactNode ;
} ) {
return (
< section className = "paperclip-story__frame overflow-hidden" >
< div className = "border-b border-border px-5 py-4" >
< div className = "paperclip-story__label" > { eyebrow } < / div >
< div className = "mt-1 flex flex-wrap items-end justify-between gap-3" >
< div >
< h2 className = "text-xl font-semibold" > { title } < / h2 >
{ description ? (
< p className = "mt-2 max-w-3xl text-sm leading-6 text-muted-foreground" > { description } < / p >
) : null }
< / div >
< / div >
< / div >
< div className = "p-5" > { children } < / div >
< / section >
) ;
}
function StatePanel ( {
label ,
detail ,
children ,
disabled = false ,
} : {
label : string ;
detail? : string ;
children : ReactNode ;
disabled? : boolean ;
} ) {
return (
< div className = "min-w-0 rounded-lg border border-border bg-background/70 p-4" >
< div className = "mb-3 flex min-h-6 flex-wrap items-start justify-between gap-2" >
< div >
< div className = "text-sm font-medium" > { label } < / div >
{ detail ? < div className = "mt-1 text-xs leading-5 text-muted-foreground" > { detail } < / div > : null }
< / div >
{ disabled ? < Badge variant = "outline" > disabled < / Badge > : null }
< / div >
< div className = { disabled ? "pointer-events-none opacity-55" : undefined } > { children } < / div >
< / div >
) ;
}
function StoryShell ( { children } : { children : ReactNode } ) {
return (
< div className = "paperclip-story" >
< main className = "paperclip-story__inner space-y-6" > { children } < / main >
< / div >
) ;
}
const reviewMarkdown = ` # Release review
Ship criteria for the board UI refresh :
- [ x ] Preserve company - scoped routes
- [ x ] Keep comments and task updates auditable
- [ ] Attach screenshots after QA
[codex] Split PR #4692 UI/QoL updates (#4701)
## Thinking Path
> - Paperclip orchestrates AI agents through a company-scoped control
plane.
> - The affected surface is the board UI for issue threads, issue lists,
routines, dialogs, navigation, and issue review indicators.
> - Closed PR #4692 bundled backend, schema, docs, workflow, and UI/QoL
work into one oversized change set.
> - Greptile could not keep reviewing that broad PR because it exceeded
the 100-file review limit and mixed unrelated concerns.
> - This pull request extracts the UI/QoL slice into a fresh branch
under the review limit while leaving workflow and lockfile churn out.
> - The benefit is a focused review path for the board UI performance
and workflow improvements without reopening the oversized PR.
## What Changed
- Added long issue-thread virtualization, scroll-container binding,
anchor preservation, latest-comment jump targeting, and related
regression/perf fixtures.
- Improved issue list scalability with scroll-based loading, server
offset parameters, and pagination-focused UI tests.
- Reduced new issue dialog typing churn and split dialog action
subscriptions so broad layout/nav surfaces avoid unnecessary renders.
- Added routine variables help and routine description mention options
for users, agents, and projects.
- Added productivity review badge/link UI and fixed the badge to use
Paperclip's company-prefixed router link.
- Kept the split PR below Greptile's review limit and excluded
`.github/workflows/pr.yml` and `pnpm-lock.yaml`.
## Verification
- `pnpm install --no-frozen-lockfile` in the clean worktree to install
`@tanstack/react-virtual` locally without committing lockfile churn.
- `pnpm --filter @paperclipai/ui exec vitest run --config
vitest.config.ts src/components/IssueChatThread.test.tsx
src/components/IssuesList.test.tsx
src/components/NewIssueDialog.test.tsx src/pages/Routines.test.tsx
src/pages/Issues.test.tsx` passed: 5 files, 83 tests.
- `pnpm --filter @paperclipai/ui typecheck` passed.
- `git diff --check origin/master..HEAD` passed.
- Split-scope checks: 53 changed files; no `.github/workflows/pr.yml`;
no `pnpm-lock.yaml`.
- Screenshots were not captured in this heartbeat; the changes are
primarily virtualization, routing, pagination, and editor behavior
covered by focused regression tests.
## Risks
- Moderate UI risk because issue-thread virtualization changes scroll
behavior on long conversations; regression tests cover anchor jumps,
latest-comment targeting, row metadata, and short-thread fallback.
- Moderate integration risk because the issue-list offset parameter and
productivity review field depend on matching API behavior.
- Dependency risk: the UI package adds `@tanstack/react-virtual` while
repository policy keeps `pnpm-lock.yaml` out of PRs, so CI must resolve
dependency changes through the repo's normal lockfile policy.
> 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 local repository and
GitHub workflow. Exact runtime context window was not exposed by the
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 run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-28 17:18:58 -05:00
Tooling : lean on [ /react-perf-optimizer](skill:/ / skill - react - perf ? s = react - perf - optimizer ) and [ /vercel-react-best-practices](skill:/ / skill - vercel - react ? s = vercel - react - best - practices ) so we don 't regress render performance on the page it' s open to . Inline skill chips like [ /release-changelog](skill:/ / skill - release ? s = release - changelog ) must sit on the surrounding text line , not hang below it .
[codex] add comprehensive UI Storybook coverage (#4132)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies.
> - The board UI is the main operator surface, so its component and
workflow coverage needs to stay reviewable as the product grows.
> - This branch adds Storybook as a dedicated UI reference surface for
core Paperclip screens and interaction patterns.
> - That work spans Storybook infrastructure, app-level provider wiring,
and a large fixture set that can render real control-plane states
without a live backend.
> - The branch also expands coverage across agents, budgets, issues,
chat, dialogs, navigation, projects, and data visualization so future UI
changes have a concrete visual baseline.
> - This pull request packages that Storybook work on top of the latest
`master`, excludes the lockfile from the final diff per repo policy, and
fixes one fixture contract drift caught during verification.
> - The benefit is a single reviewable PR that adds broad UI
documentation and regression-surfacing coverage without losing the
existing branch work.
## What Changed
- Added Storybook 10 wiring for the UI package, including root scripts,
UI package scripts, Storybook config, preview wrappers, Tailwind
entrypoints, and setup docs.
- Added a large fixture-backed data source for Storybook so complex
board states can render without a live server.
- Added story suites covering foundations, status language,
control-plane surfaces, overview, UX labs, agent management, budget and
finance, forms and editors, issue management, navigation and layout,
chat and comments, data visualization, dialogs and modals, and
projects/goals/workspaces.
- Adjusted several UI components for Storybook parity so dialogs, menus,
keyboard shortcuts, budget markers, markdown editing, and related
surfaces render correctly in isolation.
- Rebasing work for PR assembly: replayed the branch onto current
`master`, removed `pnpm-lock.yaml` from the final PR diff, and aligned
the dashboard fixture with the current `DashboardSummary.runActivity`
API contract.
## Verification
- `pnpm --filter @paperclipai/ui typecheck`
- `pnpm --filter @paperclipai/ui build-storybook`
- Manual diff audit after rebase: verified the PR no longer includes
`pnpm-lock.yaml` and now cleanly targets current `master`.
- Before/after UI note: before this branch there was no dedicated
Storybook surface for these Paperclip views; after this branch the local
Storybook build includes the new overview and domain story suites in
`ui/storybook-static`.
## Risks
- Large static fixture files can drift from shared types as dashboard
and UI contracts evolve; this PR already needed one fixture correction
for `runActivity`.
- Storybook bundle output includes some large chunks, so future growth
may need chunking work if build performance becomes an issue.
- Several component tweaks were made for isolated rendering parity, so
reviewers should spot-check key board surfaces against the live app
behavior.
## Model Used
- OpenAI Codex, GPT-5-based coding agent in the Paperclip harness; exact
serving model ID is not exposed in-runtime to the agent.
- Tool-assisted workflow with terminal execution, git operations, local
typecheck/build verification, and GitHub CLI PR creation.
- Context window/reasoning mode not surfaced by the 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 run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 12:13:23 -05:00
| Surface | Owner | State |
| -- - | -- - | -- - |
| Issues | CodexCoder | In progress |
| Approvals | CTO | Ready |
\ ` \` \` ts
const shouldRun = issue . status === "in_progress" && issue . companyId === company . id ;
\ ` \` \`
See [ the implementation notes ] ( https : //github.com/paperclipai/paperclip).`;
const editorMentions : MentionOption [ ] = [
{ id : "agent-codex" , name : "CodexCoder" , kind : "agent" , agentId : "agent-codex" , agentIcon : "code" } ,
{ id : "agent-qa" , name : "QAChecker" , kind : "agent" , agentId : "agent-qa" , agentIcon : "shield" } ,
{ id : "project-board-ui" , name : "Board UI" , kind : "project" , projectId : "project-board-ui" , projectColor : "#0f766e" } ,
{ id : "user-board" , name : "Board Operator" , kind : "user" , userId : "user-board" } ,
] ;
const adapterSchema : JsonSchemaNode = {
type : "object" ,
required : [ "adapterName" , "apiKey" , "concurrency" ] ,
properties : {
adapterName : {
type : "string" ,
title : "Adapter name" ,
description : "Human-readable name shown in the adapter manager." ,
minLength : 3 ,
default : "Codex local" ,
} ,
mode : {
type : "string" ,
title : "Run mode" ,
enum : [ "review" , "implementation" , "maintenance" ] ,
default : "implementation" ,
} ,
apiKey : {
type : "string" ,
title : "API key" ,
format : "secret-ref" ,
description : "Stored with the active Paperclip secret provider." ,
} ,
concurrency : {
type : "integer" ,
title : "Max concurrent runs" ,
minimum : 1 ,
maximum : 6 ,
default : 2 ,
} ,
dryRun : {
type : "boolean" ,
title : "Dry run first" ,
description : "Require a preview run before mutating company data." ,
default : true ,
} ,
notes : {
type : "string" ,
title : "Operator notes" ,
format : "textarea" ,
maxLength : 500 ,
description : "Shown to the agent before checkout." ,
} ,
allowedCommands : {
type : "array" ,
title : "Allowed commands" ,
description : "Commands this adapter can run without extra approval." ,
items : { type : "string" , default : "pnpm test" } ,
minItems : 1 ,
} ,
advanced : {
type : "object" ,
title : "Advanced guardrails" ,
properties : {
timeoutSeconds : { type : "integer" , title : "Timeout seconds" , minimum : 60 , default : 900 } ,
requireApproval : { type : "boolean" , title : "Require board approval" , default : false } ,
} ,
} ,
} ,
} ;
const validAdapterValues = {
. . . getDefaultValues ( adapterSchema ) ,
adapterName : "Codex local" ,
mode : "implementation" ,
apiKey : "secret:openai-api-key" ,
concurrency : 2 ,
dryRun : true ,
notes : "Use the project worktree and post a concise task update before handoff." ,
allowedCommands : [ "pnpm --filter @paperclipai/ui typecheck" , "pnpm build-storybook" ] ,
advanced : { timeoutSeconds : 900 , requireApproval : false } ,
} ;
const invalidAdapterValues = {
. . . validAdapterValues ,
adapterName : "AI" ,
apiKey : "" ,
concurrency : 9 ,
} ;
const adapterErrors = {
"/adapterName" : "Must be at least 3 characters" ,
"/apiKey" : "This field is required" ,
"/concurrency" : "Must be at most 6" ,
} ;
const storybookSecrets : CompanySecret [ ] = [
Add secrets provider vaults and remote import (#5429)
## Thinking Path
> - Paperclip orchestrates AI-agent companies and needs secrets handling
to work across local development, hosted operators, and governed agent
execution.
> - The affected subsystem is the company-scoped secrets control plane:
database schema, server services/routes, CLI workflows, and the Secrets
settings UI.
> - The gap was that secrets were local-only and operators could not
manage provider vaults or import existing remote references without
exposing plaintext.
> - This branch adds provider vault configuration plus an AWS Secrets
Manager remote-import path while preserving company boundaries, binding
context, and audit trails.
> - I kept the PR to a single branch PR, removed unrelated
lockfile/package drift, rebased the full branch onto the current
`public-gh/master`, and addressed fresh Greptile findings.
> - The benefit is a reviewable implementation of provider-backed
secrets with focused tests covering provider selection, import
conflicts, deleted secret reuse, rotation guards, and AWS signing
behavior.
## What Changed
- Added provider vault support for company secrets, including provider
config storage, default vault handling, health checks, binding usage,
access events, and remote import preview/commit.
- Added an AWS Secrets Manager provider using SigV4 request signing,
bounded request timeouts, namespace guardrails, cached runtime
credential resolution, and external-reference linking without plaintext
reads.
- Added Secrets UI surfaces for vault management and remote import, plus
CLI/API documentation for setup and operations.
- Stabilized routine webhook secret binding paths and SSH
environment-driver fixture bindings discovered during verification.
- Addressed Greptile and CI findings: no lockfile/package drift,
monotonic migration metadata, disabled-vault default races, soft-deleted
secret hiding/recreate behavior, remove behavior with disabled vaults,
soft-deleted external-reference re-import, non-active rotation guards,
managed-secret soft deletion through PATCH, and per-call AWS SDK
credential client churn.
- Rebased this branch onto `public-gh/master` at `0e1a5828` and
force-pushed with lease to keep this as the single PR for the branch.
## Verification
- `git fetch public-gh master`
- `git rebase public-gh/master`
- `git diff --name-only public-gh/master...HEAD | grep
'^pnpm-lock\.yaml$' || true` confirmed `pnpm-lock.yaml` is not in the PR
diff.
- Confirmed migration ordering: master ends at `0081_optimal_dormammu`;
this PR adds `0082_dry_vision` and
`0083_company_secret_provider_configs`.
- Inspected migrations for repeat safety: new tables/indexes use `IF NOT
EXISTS`; foreign keys are guarded by `DO $$ ... IF NOT EXISTS`; column
additions use `ADD COLUMN IF NOT EXISTS`.
- `pnpm -r typecheck` passed before the Greptile follow-up commits.
- `pnpm test:run` ran the full stable Vitest path before the Greptile
follow-up commits; it completed with 3 timing-related failures under
parallel load: `codex-local-execute.test.ts`,
`cursor-local-execute.test.ts`, and `environment-service.test.ts`.
- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/codex-local-execute.test.ts
src/__tests__/cursor-local-execute.test.ts
src/__tests__/environment-service.test.ts` passed on targeted rerun
(`24/24`).
- `pnpm build` passed before the Greptile follow-up commits. Vite
reported existing chunk-size/dynamic-import warnings.
- After Greptile follow-up commits: `pnpm --filter @paperclipai/server
exec vitest run src/__tests__/secrets-service.test.ts` passed (`26/26`).
- After Greptile follow-up commits: `pnpm --filter @paperclipai/server
exec vitest run src/__tests__/aws-secrets-manager-provider.test.ts
src/__tests__/secrets-service.test.ts` passed (`39/39`).
- After Greptile follow-up commits: `pnpm --filter @paperclipai/server
typecheck` passed.
- Captured Storybook screenshots from `ui/storybook-static` for visual
review.
- Latest PR checks on `5ca3a5cf`: `policy`, serialized server suites
1/4-4/4, `Canary Dry Run`, `e2e`, `security/snyk`, and `Greptile Review`
pass; aggregate `verify` is still registering the completed child
checks.
- Greptile review loop continued through the latest requested pass; all
Greptile review threads are resolved and the latest `Greptile Review`
check on `5ca3a5cf` passed with 0 comments added.
## Screenshots
Before: the provider-vault and remote-import surfaces did not exist on
`master`; these are after-state screenshots from the Storybook fixtures.



## Risks
- Migration risk: this adds new secret provider tables and extends
existing secret rows. The migrations were checked for monotonic ordering
and idempotent guards, but reviewers should still inspect upgrade
behavior carefully.
- Provider risk: AWS support uses direct SigV4 requests. Automated tests
cover signing, request timeouts, vault-config selection, namespace
guardrails, pending-version archival, sanitized provider errors, and
service-level cleanup paths. A real-vault AWS smoke test remains
deployment validation for an operator with AWS credentials rather than
an unverified merge blocker in this local branch.
- UI risk: the Secrets page and import dialog are large new surfaces;
screenshots are included above for reviewer inspection.
- Verification risk: the full local stable test command hit
parallel-load timing failures, although the exact failed files passed
when rerun directly.
- Operational risk: remote import intentionally avoids plaintext reads;
operators must understand that imported external references resolve at
runtime and may fail if AWS permissions change.
> 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 local shell/tool use in the
Paperclip worktree. Exact context-window size was 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
- [ ] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] 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-05-09 18:22:17 -05:00
{
id : "secret-openai" ,
companyId : "company-storybook" ,
key : "openai-api-key" ,
name : "OPENAI_API_KEY" ,
provider : "local_encrypted" ,
status : "active" ,
managedMode : "paperclip_managed" ,
externalRef : null ,
providerConfigId : null ,
providerMetadata : null ,
latestVersion : 3 ,
description : null ,
lastResolvedAt : new Date ( "2026-04-20T09:00:00.000Z" ) ,
lastRotatedAt : new Date ( "2026-04-18T10:00:00.000Z" ) ,
deletedAt : null ,
createdByAgentId : null ,
[codex] add comprehensive UI Storybook coverage (#4132)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies.
> - The board UI is the main operator surface, so its component and
workflow coverage needs to stay reviewable as the product grows.
> - This branch adds Storybook as a dedicated UI reference surface for
core Paperclip screens and interaction patterns.
> - That work spans Storybook infrastructure, app-level provider wiring,
and a large fixture set that can render real control-plane states
without a live backend.
> - The branch also expands coverage across agents, budgets, issues,
chat, dialogs, navigation, projects, and data visualization so future UI
changes have a concrete visual baseline.
> - This pull request packages that Storybook work on top of the latest
`master`, excludes the lockfile from the final diff per repo policy, and
fixes one fixture contract drift caught during verification.
> - The benefit is a single reviewable PR that adds broad UI
documentation and regression-surfacing coverage without losing the
existing branch work.
## What Changed
- Added Storybook 10 wiring for the UI package, including root scripts,
UI package scripts, Storybook config, preview wrappers, Tailwind
entrypoints, and setup docs.
- Added a large fixture-backed data source for Storybook so complex
board states can render without a live server.
- Added story suites covering foundations, status language,
control-plane surfaces, overview, UX labs, agent management, budget and
finance, forms and editors, issue management, navigation and layout,
chat and comments, data visualization, dialogs and modals, and
projects/goals/workspaces.
- Adjusted several UI components for Storybook parity so dialogs, menus,
keyboard shortcuts, budget markers, markdown editing, and related
surfaces render correctly in isolation.
- Rebasing work for PR assembly: replayed the branch onto current
`master`, removed `pnpm-lock.yaml` from the final PR diff, and aligned
the dashboard fixture with the current `DashboardSummary.runActivity`
API contract.
## Verification
- `pnpm --filter @paperclipai/ui typecheck`
- `pnpm --filter @paperclipai/ui build-storybook`
- Manual diff audit after rebase: verified the PR no longer includes
`pnpm-lock.yaml` and now cleanly targets current `master`.
- Before/after UI note: before this branch there was no dedicated
Storybook surface for these Paperclip views; after this branch the local
Storybook build includes the new overview and domain story suites in
`ui/storybook-static`.
## Risks
- Large static fixture files can drift from shared types as dashboard
and UI contracts evolve; this PR already needed one fixture correction
for `runActivity`.
- Storybook bundle output includes some large chunks, so future growth
may need chunking work if build performance becomes an issue.
- Several component tweaks were made for isolated rendering parity, so
reviewers should spot-check key board surfaces against the live app
behavior.
## Model Used
- OpenAI Codex, GPT-5-based coding agent in the Paperclip harness; exact
serving model ID is not exposed in-runtime to the agent.
- Tool-assisted workflow with terminal execution, git operations, local
typecheck/build verification, and GitHub CLI PR creation.
- Context window/reasoning mode not surfaced by the 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 run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 12:13:23 -05:00
createdByUserId : "user-board" ,
createdAt : new Date ( "2026-04-18T10:00:00.000Z" ) ,
updatedAt : new Date ( "2026-04-20T10:00:00.000Z" ) ,
} ,
Add secrets provider vaults and remote import (#5429)
## Thinking Path
> - Paperclip orchestrates AI-agent companies and needs secrets handling
to work across local development, hosted operators, and governed agent
execution.
> - The affected subsystem is the company-scoped secrets control plane:
database schema, server services/routes, CLI workflows, and the Secrets
settings UI.
> - The gap was that secrets were local-only and operators could not
manage provider vaults or import existing remote references without
exposing plaintext.
> - This branch adds provider vault configuration plus an AWS Secrets
Manager remote-import path while preserving company boundaries, binding
context, and audit trails.
> - I kept the PR to a single branch PR, removed unrelated
lockfile/package drift, rebased the full branch onto the current
`public-gh/master`, and addressed fresh Greptile findings.
> - The benefit is a reviewable implementation of provider-backed
secrets with focused tests covering provider selection, import
conflicts, deleted secret reuse, rotation guards, and AWS signing
behavior.
## What Changed
- Added provider vault support for company secrets, including provider
config storage, default vault handling, health checks, binding usage,
access events, and remote import preview/commit.
- Added an AWS Secrets Manager provider using SigV4 request signing,
bounded request timeouts, namespace guardrails, cached runtime
credential resolution, and external-reference linking without plaintext
reads.
- Added Secrets UI surfaces for vault management and remote import, plus
CLI/API documentation for setup and operations.
- Stabilized routine webhook secret binding paths and SSH
environment-driver fixture bindings discovered during verification.
- Addressed Greptile and CI findings: no lockfile/package drift,
monotonic migration metadata, disabled-vault default races, soft-deleted
secret hiding/recreate behavior, remove behavior with disabled vaults,
soft-deleted external-reference re-import, non-active rotation guards,
managed-secret soft deletion through PATCH, and per-call AWS SDK
credential client churn.
- Rebased this branch onto `public-gh/master` at `0e1a5828` and
force-pushed with lease to keep this as the single PR for the branch.
## Verification
- `git fetch public-gh master`
- `git rebase public-gh/master`
- `git diff --name-only public-gh/master...HEAD | grep
'^pnpm-lock\.yaml$' || true` confirmed `pnpm-lock.yaml` is not in the PR
diff.
- Confirmed migration ordering: master ends at `0081_optimal_dormammu`;
this PR adds `0082_dry_vision` and
`0083_company_secret_provider_configs`.
- Inspected migrations for repeat safety: new tables/indexes use `IF NOT
EXISTS`; foreign keys are guarded by `DO $$ ... IF NOT EXISTS`; column
additions use `ADD COLUMN IF NOT EXISTS`.
- `pnpm -r typecheck` passed before the Greptile follow-up commits.
- `pnpm test:run` ran the full stable Vitest path before the Greptile
follow-up commits; it completed with 3 timing-related failures under
parallel load: `codex-local-execute.test.ts`,
`cursor-local-execute.test.ts`, and `environment-service.test.ts`.
- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/codex-local-execute.test.ts
src/__tests__/cursor-local-execute.test.ts
src/__tests__/environment-service.test.ts` passed on targeted rerun
(`24/24`).
- `pnpm build` passed before the Greptile follow-up commits. Vite
reported existing chunk-size/dynamic-import warnings.
- After Greptile follow-up commits: `pnpm --filter @paperclipai/server
exec vitest run src/__tests__/secrets-service.test.ts` passed (`26/26`).
- After Greptile follow-up commits: `pnpm --filter @paperclipai/server
exec vitest run src/__tests__/aws-secrets-manager-provider.test.ts
src/__tests__/secrets-service.test.ts` passed (`39/39`).
- After Greptile follow-up commits: `pnpm --filter @paperclipai/server
typecheck` passed.
- Captured Storybook screenshots from `ui/storybook-static` for visual
review.
- Latest PR checks on `5ca3a5cf`: `policy`, serialized server suites
1/4-4/4, `Canary Dry Run`, `e2e`, `security/snyk`, and `Greptile Review`
pass; aggregate `verify` is still registering the completed child
checks.
- Greptile review loop continued through the latest requested pass; all
Greptile review threads are resolved and the latest `Greptile Review`
check on `5ca3a5cf` passed with 0 comments added.
## Screenshots
Before: the provider-vault and remote-import surfaces did not exist on
`master`; these are after-state screenshots from the Storybook fixtures.



## Risks
- Migration risk: this adds new secret provider tables and extends
existing secret rows. The migrations were checked for monotonic ordering
and idempotent guards, but reviewers should still inspect upgrade
behavior carefully.
- Provider risk: AWS support uses direct SigV4 requests. Automated tests
cover signing, request timeouts, vault-config selection, namespace
guardrails, pending-version archival, sanitized provider errors, and
service-level cleanup paths. A real-vault AWS smoke test remains
deployment validation for an operator with AWS credentials rather than
an unverified merge blocker in this local branch.
- UI risk: the Secrets page and import dialog are large new surfaces;
screenshots are included above for reviewer inspection.
- Verification risk: the full local stable test command hit
parallel-load timing failures, although the exact failed files passed
when rerun directly.
- Operational risk: remote import intentionally avoids plaintext reads;
operators must understand that imported external references resolve at
runtime and may fail if AWS permissions change.
> 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 local shell/tool use in the
Paperclip worktree. Exact context-window size was 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
- [ ] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] 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-05-09 18:22:17 -05:00
{
id : "secret-github" ,
companyId : "company-storybook" ,
key : "github-token" ,
name : "GITHUB_TOKEN" ,
provider : "local_encrypted" ,
status : "active" ,
managedMode : "paperclip_managed" ,
externalRef : null ,
providerConfigId : null ,
providerMetadata : null ,
latestVersion : 1 ,
description : null ,
lastResolvedAt : null ,
lastRotatedAt : new Date ( "2026-04-19T10:00:00.000Z" ) ,
deletedAt : null ,
createdByAgentId : null ,
[codex] add comprehensive UI Storybook coverage (#4132)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies.
> - The board UI is the main operator surface, so its component and
workflow coverage needs to stay reviewable as the product grows.
> - This branch adds Storybook as a dedicated UI reference surface for
core Paperclip screens and interaction patterns.
> - That work spans Storybook infrastructure, app-level provider wiring,
and a large fixture set that can render real control-plane states
without a live backend.
> - The branch also expands coverage across agents, budgets, issues,
chat, dialogs, navigation, projects, and data visualization so future UI
changes have a concrete visual baseline.
> - This pull request packages that Storybook work on top of the latest
`master`, excludes the lockfile from the final diff per repo policy, and
fixes one fixture contract drift caught during verification.
> - The benefit is a single reviewable PR that adds broad UI
documentation and regression-surfacing coverage without losing the
existing branch work.
## What Changed
- Added Storybook 10 wiring for the UI package, including root scripts,
UI package scripts, Storybook config, preview wrappers, Tailwind
entrypoints, and setup docs.
- Added a large fixture-backed data source for Storybook so complex
board states can render without a live server.
- Added story suites covering foundations, status language,
control-plane surfaces, overview, UX labs, agent management, budget and
finance, forms and editors, issue management, navigation and layout,
chat and comments, data visualization, dialogs and modals, and
projects/goals/workspaces.
- Adjusted several UI components for Storybook parity so dialogs, menus,
keyboard shortcuts, budget markers, markdown editing, and related
surfaces render correctly in isolation.
- Rebasing work for PR assembly: replayed the branch onto current
`master`, removed `pnpm-lock.yaml` from the final PR diff, and aligned
the dashboard fixture with the current `DashboardSummary.runActivity`
API contract.
## Verification
- `pnpm --filter @paperclipai/ui typecheck`
- `pnpm --filter @paperclipai/ui build-storybook`
- Manual diff audit after rebase: verified the PR no longer includes
`pnpm-lock.yaml` and now cleanly targets current `master`.
- Before/after UI note: before this branch there was no dedicated
Storybook surface for these Paperclip views; after this branch the local
Storybook build includes the new overview and domain story suites in
`ui/storybook-static`.
## Risks
- Large static fixture files can drift from shared types as dashboard
and UI contracts evolve; this PR already needed one fixture correction
for `runActivity`.
- Storybook bundle output includes some large chunks, so future growth
may need chunking work if build performance becomes an issue.
- Several component tweaks were made for isolated rendering parity, so
reviewers should spot-check key board surfaces against the live app
behavior.
## Model Used
- OpenAI Codex, GPT-5-based coding agent in the Paperclip harness; exact
serving model ID is not exposed in-runtime to the agent.
- Tool-assisted workflow with terminal execution, git operations, local
typecheck/build verification, and GitHub CLI PR creation.
- Context window/reasoning mode not surfaced by the 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 run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 12:13:23 -05:00
createdByUserId : "user-board" ,
createdAt : new Date ( "2026-04-19T10:00:00.000Z" ) ,
updatedAt : new Date ( "2026-04-19T10:00:00.000Z" ) ,
} ,
] ;
const filledEnv : Record < string , EnvBinding > = {
NODE_ENV : { type : "plain" , value : "development" } ,
OPENAI_API_KEY : { type : "secret_ref" , secretId : "secret-openai" , version : "latest" } ,
} ;
const routineVariables : RoutineVariable [ ] = [
{
name : "repo" ,
label : "Repository" ,
type : "text" ,
defaultValue : "paperclipai/paperclip" ,
required : true ,
options : [ ] ,
} ,
{
name : "priority" ,
label : "Priority" ,
type : "select" ,
defaultValue : "medium" ,
required : true ,
options : [ "low" , "medium" , "high" ] ,
} ,
{
name : "include_browser" ,
label : "Include browser QA" ,
type : "boolean" ,
defaultValue : true ,
required : false ,
options : [ ] ,
} ,
{
name : "notes" ,
label : "Run notes" ,
type : "textarea" ,
defaultValue : "Capture any visible layout regressions." ,
required : false ,
options : [ ] ,
} ,
] ;
const storybookProject : Project = {
id : "project-board-ui" ,
companyId : "company-storybook" ,
urlKey : "board-ui" ,
goalId : "goal-company" ,
goalIds : [ "goal-company" ] ,
goals : [ { id : "goal-company" , title : "We're building Paperclip" } ] ,
name : "Board UI" ,
description : "Control-plane interface, Storybook review surfaces, and operator workflows." ,
status : "in_progress" ,
leadAgentId : "agent-codex" ,
targetDate : null ,
color : "#0f766e" ,
env : null ,
pauseReason : null ,
pausedAt : null ,
executionWorkspacePolicy : null ,
codebase : {
workspaceId : "workspace-board-ui" ,
repoUrl : "https://github.com/paperclipai/paperclip" ,
repoRef : "master" ,
defaultRef : "master" ,
repoName : "paperclip" ,
localFolder : "/Users/dotta/paperclip" ,
managedFolder : "paperclip" ,
effectiveLocalFolder : "/Users/dotta/paperclip" ,
origin : "local_folder" ,
} ,
workspaces : [ ] ,
primaryWorkspace : null ,
archivedAt : null ,
createdAt : new Date ( "2026-04-01T10:00:00.000Z" ) ,
updatedAt : new Date ( "2026-04-20T10:00:00.000Z" ) ,
} ;
const entityOptions : InlineEntityOption [ ] = [
{ id : "issue-1672" , label : "Storybook forms and editors" , searchText : "PAP-1672 ui story coverage" } ,
{ id : "project-board-ui" , label : "Board UI" , searchText : "project frontend Storybook" } ,
{ id : "agent-codex" , label : "CodexCoder" , searchText : "engineer implementation" } ,
] ;
function MarkdownEditorGallery() {
const [ emptyMarkdown , setEmptyMarkdown ] = useState ( "" ) ;
const [ filledMarkdown , setFilledMarkdown ] = useState ( reviewMarkdown ) ;
const [ actionMarkdown , setActionMarkdown ] = useState ( "Draft an update for @CodexCoder and /check-pr." ) ;
return (
< Section
eyebrow = "MarkdownEditor"
title = "Composer states with content, read-only mode, and action buttons"
description = "The editor is controlled in all examples so reviewers can type, trigger mentions, and see command insertion behavior."
>
< div className = "grid gap-4 lg:grid-cols-2" >
< StatePanel label = "Empty" detail = "Placeholder, border, and mention-ready empty state." >
< MarkdownEditor
value = { emptyMarkdown }
onChange = { setEmptyMarkdown }
placeholder = "Write a task update..."
mentions = { editorMentions }
/ >
< / StatePanel >
< StatePanel label = "Filled" detail = "Long-form markdown with a table and fenced code block." >
< MarkdownEditor value = { filledMarkdown } onChange = { setFilledMarkdown } mentions = { editorMentions } / >
< / StatePanel >
< StatePanel label = "Read-only" detail = "Uses the editor rendering path without accepting edits." disabled >
< MarkdownEditor value = { reviewMarkdown } onChange = { ( ) = > undefined } readOnly mentions = { editorMentions } / >
< / StatePanel >
< StatePanel label = "Toolbar actions" detail = "External controls exercise insertion actions around the editor." >
< div className = "mb-3 flex flex-wrap gap-2" >
< Button size = "sm" variant = "outline" onClick = { ( ) = > setActionMarkdown ( ( value ) = > ` ${ value } \ n \ n## Next action \ n ` ) } >
< FileText className = "mr-2 h-4 w-4" / >
Heading
< / Button >
< Button size = "sm" variant = "outline" onClick = { ( ) = > setActionMarkdown ( ( value ) = > ` ${ value } \ n \ n- Verify typecheck \ n- Build Storybook \ n ` ) } >
< ListPlus className = "mr-2 h-4 w-4" / >
List
< / Button >
< Button size = "sm" variant = "outline" onClick = { ( ) = > setActionMarkdown ( ( value ) = > ` ${ value } \ n \ n| Field | State | \ n| --- | --- | \ n| Forms | Ready | \ n ` ) } >
< Table2 className = "mr-2 h-4 w-4" / >
Table
< / Button >
< Button size = "sm" variant = "outline" onClick = { ( ) = > setActionMarkdown ( ( value ) = > ` ${ value } \ n \ n \` \` \` sh \ npnpm build-storybook \ n \` \` \` \ n ` ) } >
< Code2 className = "mr-2 h-4 w-4" / >
Code
< / Button >
< Button size = "sm" variant = "ghost" onClick = { ( ) = > setActionMarkdown ( "Draft an update for @CodexCoder and /check-pr." ) } >
< RotateCcw className = "mr-2 h-4 w-4" / >
Reset
< / Button >
< / div >
< MarkdownEditor value = { actionMarkdown } onChange = { setActionMarkdown } mentions = { editorMentions } / >
< / StatePanel >
< / div >
< / Section >
) ;
}
function MarkdownBodyGallery() {
return (
< Section
eyebrow = "MarkdownBody"
title = "Rendered markdown for task documents and comments"
description = "GFM coverage includes headings, task lists, links, tables, and code blocks in the app's prose wrapper."
>
< div className = "grid gap-4 lg:grid-cols-[minmax(0,1fr)_320px]" >
< StatePanel label = "Filled markdown" detail = "Mixed document syntax with code and table overflow handling." >
< MarkdownBody linkIssueReferences = { false } > { reviewMarkdown } < / MarkdownBody >
< / StatePanel >
< div className = "space-y-4" >
< StatePanel label = "Empty" >
< MarkdownBody > { "" } < / MarkdownBody >
< p className = "text-sm text-muted-foreground" > No markdown body content . < / p >
< / StatePanel >
< StatePanel label = "Disabled container" disabled >
< MarkdownBody linkIssueReferences = { false } > A read - only preview can be dimmed by the parent surface . < / MarkdownBody >
< / StatePanel >
< / div >
< / div >
< / Section >
) ;
}
function JsonSchemaFormGallery() {
const [ filledValues , setFilledValues ] = useState < Record < string , unknown > > ( validAdapterValues ) ;
const [ errorValues , setErrorValues ] = useState < Record < string , unknown > > ( invalidAdapterValues ) ;
return (
< Section
eyebrow = "JsonSchemaForm"
title = "Generated adapter configuration forms"
description = "The schema exercises strings, enums, secrets, numbers, booleans, arrays, objects, validation errors, and disabled controls."
>
< div className = "grid gap-4 xl:grid-cols-2" >
< StatePanel label = "Filled" >
< JsonSchemaForm schema = { adapterSchema } values = { filledValues } onChange = { setFilledValues } / >
< / StatePanel >
< StatePanel label = "Validation errors" >
< JsonSchemaForm schema = { adapterSchema } values = { errorValues } onChange = { setErrorValues } errors = { adapterErrors } / >
< / StatePanel >
< StatePanel label = "Empty schema" >
< JsonSchemaForm schema = { { type : "object" , properties : { } } } values = { { } } onChange = { ( ) = > undefined } / >
< / StatePanel >
< StatePanel label = "Disabled" disabled >
< JsonSchemaForm schema = { adapterSchema } values = { filledValues } onChange = { ( ) = > undefined } disabled / >
< / StatePanel >
< / div >
< / Section >
) ;
}
function InlineEditorGallery() {
const [ title , setTitle ] = useState ( "Storybook: Forms & Editors stories" ) ;
const [ description , setDescription ] = useState (
"Create fixture-backed editor stories for the board UI, then verify Storybook builds." ,
) ;
const [ emptyTitle , setEmptyTitle ] = useState ( "" ) ;
return (
< Section eyebrow = "InlineEditor" title = "Inline title and description editing" >
< div className = "grid gap-4 lg:grid-cols-3" >
< StatePanel label = "Title editing" detail = "Click the title to edit and press Enter to save." >
< InlineEditor value = { title } onSave = { setTitle } as = "h2" className = "text-2xl font-semibold" / >
< / StatePanel >
< StatePanel label = "Description editing" detail = "Multiline markdown editor with autosave affordance." >
< InlineEditor value = { description } onSave = { setDescription } as = "p" multiline nullable / >
< / StatePanel >
< StatePanel label = "Empty nullable title" detail = "Placeholder state for optional inline fields." >
< InlineEditor value = { emptyTitle } onSave = { setEmptyTitle } as = "h2" nullable placeholder = "Untitled issue" / >
< / StatePanel >
< / div >
< / Section >
) ;
}
function EnvVarEditorGallery() {
const [ emptyEnv , setEmptyEnv ] = useState < Record < string , EnvBinding > > ( { } ) ;
const [ env , setEnv ] = useState < Record < string , EnvBinding > > ( filledEnv ) ;
const createSecret = async ( name : string ) : Promise < CompanySecret > = > ( {
. . . storybookSecrets [ 0 ] ! ,
id : ` secret- ${ name . toLowerCase ( ) } ` ,
name ,
latestVersion : 1 ,
} ) ;
return (
< Section eyebrow = "EnvVarEditor" title = "Runtime environment bindings" >
< div className = "grid gap-4 lg:grid-cols-3" >
< StatePanel label = "Empty add row" detail = "Trailing blank row is the add state." >
< EnvVarEditor value = { emptyEnv } secrets = { storybookSecrets } onCreateSecret = { createSecret } onChange = { ( next ) = > setEmptyEnv ( next ? ? { } ) } / >
< / StatePanel >
< StatePanel label = "Plain and secret values" detail = "Filled rows show edit, seal, secret select, and remove controls." >
< EnvVarEditor value = { env } secrets = { storybookSecrets } onCreateSecret = { createSecret } onChange = { ( next ) = > setEnv ( next ? ? { } ) } / >
< / StatePanel >
< StatePanel label = "Disabled shell" disabled >
< EnvVarEditor value = { filledEnv } secrets = { storybookSecrets } onCreateSecret = { createSecret } onChange = { ( ) = > undefined } / >
< / StatePanel >
< / div >
< / Section >
) ;
}
function ScheduleEditorGallery() {
const [ emptyCron , setEmptyCron ] = useState ( "" ) ;
const [ weeklyCron , setWeeklyCron ] = useState ( "30 9 * * 1" ) ;
const [ customCron , setCustomCron ] = useState ( "15 16 1 * *" ) ;
return (
< Section eyebrow = "ScheduleEditor" title = "Cron picker with human-readable previews" >
< div className = "grid gap-4 lg:grid-cols-3" >
< StatePanel label = "Empty default" detail = { describeSchedule ( emptyCron ) } >
< ScheduleEditor value = { emptyCron } onChange = { setEmptyCron } / >
< / StatePanel >
< StatePanel label = "Weekly filled" detail = { describeSchedule ( weeklyCron ) } >
< ScheduleEditor value = { weeklyCron } onChange = { setWeeklyCron } / >
< / StatePanel >
< StatePanel label = "Custom disabled preview" detail = { describeSchedule ( customCron ) } disabled >
< ScheduleEditor value = { customCron } onChange = { setCustomCron } / >
< / StatePanel >
< / div >
< / Section >
) ;
}
function RoutineVariablesGallery() {
const [ variables , setVariables ] = useState < RoutineVariable [ ] > ( routineVariables ) ;
return (
< Section
eyebrow = "RoutineVariablesEditor"
title = "Detected runtime variable definitions"
description = "Variable rows are synced from title and instructions placeholders, then configured with types, defaults, required flags, and select options."
>
< div className = "grid gap-4 lg:grid-cols-[minmax(0,1fr)_320px]" >
< StatePanel label = "Detected variables" >
< RoutineVariablesEditor
title = "Review {{repo}} at {{priority}} priority"
description = "Include browser QA: {{include_browser}}\n\nOperator notes: {{notes}}"
value = { variables }
onChange = { setVariables }
/ >
< / StatePanel >
< div className = "space-y-4" >
< StatePanel label = "Empty hint" >
< RoutineVariablesHint / >
< / StatePanel >
< StatePanel label = "Disabled shell" disabled >
< RoutineVariablesEditor
title = "Review {{repo}}"
description = "Use {{priority}} priority"
value = { variables . slice ( 0 , 2 ) }
onChange = { ( ) = > undefined }
/ >
< / StatePanel >
< / div >
< / div >
< / Section >
) ;
}
function PickerGallery() {
const [ issue , setIssue ] = useState ( ( ) = >
createIssue ( {
executionPolicy : buildExecutionPolicy ( {
reviewerValues : [ "agent:agent-qa" ] ,
approverValues : [ "user:user-board" ] ,
} ) ,
} ) ,
) ;
const [ manager , setManager ] = useState < string | null > ( "agent-cto" ) ;
const [ selectorValue , setSelectorValue ] = useState ( "project-board-ui" ) ;
const agentsWithTerminated : Agent [ ] = useMemo (
( ) = > [
. . . storybookAgents ,
{
. . . storybookAgents [ 1 ] ! ,
id : "agent-legacy" ,
name : "LegacyReviewer" ,
status : "terminated" ,
reportsTo : null ,
} ,
] ,
[ ] ,
) ;
return (
< Section
eyebrow = "Pickers"
title = "Execution participants, reporting hierarchy, and inline entity selection"
description = "Closed trigger states stay compact, while the dropdowns are interactive for search and selection review."
>
< div className = "grid gap-4 xl:grid-cols-3" >
< StatePanel label = "ExecutionParticipantPicker" detail = "Review and approval participants share the same policy object." >
< div className = "flex flex-wrap gap-3" >
< ExecutionParticipantPicker
issue = { issue }
stageType = "review"
agents = { storybookAgents }
currentUserId = "user-board"
onUpdate = { ( patch ) = > setIssue ( ( current ) = > ( { . . . current , . . . patch } ) ) }
/ >
< ExecutionParticipantPicker
issue = { issue }
stageType = "approval"
agents = { storybookAgents }
currentUserId = "user-board"
onUpdate = { ( patch ) = > setIssue ( ( current ) = > ( { . . . current , . . . patch } ) ) }
/ >
< / div >
< / StatePanel >
< StatePanel label = "ReportsToPicker" detail = "Selected manager, CEO disabled state, and filtered hierarchy choices." >
< div className = "flex flex-wrap gap-3" >
< ReportsToPicker agents = { agentsWithTerminated } value = { manager } onChange = { setManager } excludeAgentIds = { [ "agent-codex" ] } / >
< ReportsToPicker agents = { agentsWithTerminated } value = { null } onChange = { ( ) = > undefined } disabled / >
< / div >
< / StatePanel >
< StatePanel label = "InlineEntitySelector" detail = "Search/select dropdown for issue, project, and agent entities." >
< div className = "flex flex-wrap gap-3" >
< InlineEntitySelector
value = { selectorValue }
options = { entityOptions }
recentOptionIds = { [ "issue-1672" ] }
placeholder = "Entity"
noneLabel = "No entity"
searchPlaceholder = "Search entities..."
emptyMessage = "No matching entity."
onChange = { setSelectorValue }
/ >
< div className = "pointer-events-none opacity-55" >
< InlineEntitySelector
value = ""
options = { entityOptions }
placeholder = "Entity"
noneLabel = "No entity"
searchPlaceholder = "Search entities..."
emptyMessage = "No matching entity."
onChange = { ( ) = > undefined }
/ >
< / div >
< / div >
< / StatePanel >
< / div >
< / Section >
) ;
}
function FormsEditorsShowcase() {
return (
< StoryShell >
< section className = "paperclip-story__frame p-6" >
< div className = "flex flex-wrap items-start justify-between gap-5" >
< div >
< div className = "paperclip-story__label" > Forms and editors < / div >
< h1 className = "mt-2 text-3xl font-semibold tracking-tight" > Paperclip form controls under realistic state < / h1 >
< p className = "mt-3 max-w-3xl text-sm leading-6 text-muted-foreground" >
Dense control - plane forms need to hold empty , filled , validation , and disabled states without losing scan
speed . These fixtures keep the components reviewable outside production routes .
< / p >
< / div >
< div className = "flex flex-wrap gap-2" >
< Badge variant = "outline" > empty < / Badge >
< Badge variant = "outline" > filled < / Badge >
< Badge variant = "outline" > validation < / Badge >
< Badge variant = "outline" > disabled < / Badge >
< / div >
< / div >
< / section >
< MarkdownEditorGallery / >
< MarkdownBodyGallery / >
< JsonSchemaFormGallery / >
< InlineEditorGallery / >
< EnvVarEditorGallery / >
< ScheduleEditorGallery / >
< RoutineVariablesGallery / >
< PickerGallery / >
< / StoryShell >
) ;
}
function RoutineRunDialogStory() {
const [ open , setOpen ] = useState ( true ) ;
const [ submitted , setSubmitted ] = useState < RoutineRunDialogSubmitData | null > ( null ) ;
return (
< StoryShell >
< Section
eyebrow = "RoutineRunVariablesDialog"
title = "Manual routine run configuration"
description = "The dialog collects runtime variables, the target assignee, and optional project context before creating the run issue."
>
< div className = "flex flex-wrap items-center gap-3" >
< Button onClick = { ( ) = > setOpen ( true ) } > Open run dialog < / Button >
{ submitted ? (
< pre className = "max-w-full overflow-x-auto rounded-md border border-border bg-muted/40 px-3 py-2 text-xs" >
{ JSON . stringify ( submitted , null , 2 ) }
< / pre >
) : (
< span className = "text-sm text-muted-foreground" > Submit the dialog to inspect the payload . < / span >
) }
< / div >
< / Section >
< RoutineRunVariablesDialog
open = { open }
onOpenChange = { setOpen }
companyId = "company-storybook"
routineName = "Weekly release review"
projects = { [ storybookProject ] }
agents = { storybookAgents }
defaultProjectId = "project-board-ui"
defaultAssigneeAgentId = "agent-codex"
variables = { routineVariables }
isPending = { false }
onSubmit = { ( data ) = > {
setSubmitted ( { . . . data } ) ;
setOpen ( false ) ;
} }
/ >
< / StoryShell >
) ;
}
const meta = {
title : "Components/Forms & Editors" ,
parameters : {
docs : {
description : {
component :
"Fixture-backed stories for Paperclip form controls, markdown editors, inline editors, schedule controls, runtime-variable dialogs, and selection pickers." ,
} ,
} ,
} ,
} satisfies Meta ;
export default meta ;
type Story = StoryObj < typeof meta > ;
export const AllFormsAndEditors : Story = {
name : "All Forms And Editors" ,
render : ( ) = > < FormsEditorsShowcase / > ,
} ;
export const RoutineRunVariablesDialogOpen : Story = {
name : "Routine Run Variables Dialog" ,
render : ( ) = > < RoutineRunDialogStory / > ,
} ;
[codex] Polish issue composer and long document display (#4420)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Issue comments and documents are the main working surface where
operators and agents collaborate
> - File drops, markdown editing, and long issue descriptions need to
feel predictable because they sit directly in the task execution loop
> - The composer had edge cases around drag targets, attachment
feedback, image drops, and long markdown content crowding the page
> - This pull request polishes the issue composer, hardens markdown
editor regressions, and adds a fold curtain for long issue
descriptions/documents
> - The benefit is a calmer issue detail surface that handles uploads
and long work products without hiding state or breaking layout
## What Changed
- Scoped issue-composer drag/drop behavior so the composer owns file
drops without turning the whole thread into a competing drop target.
- Added clearer attachment upload feedback for non-image files and
image-drop stability coverage.
- Hardened markdown editor and markdown body handling around HTML-like
tag regressions.
- Added `FoldCurtain` and wired it into issue descriptions and issue
documents so long markdown previews can expand/collapse.
- Added Storybook coverage for the fold curtain state.
## Verification
- `pnpm exec vitest run ui/src/components/IssueChatThread.test.tsx
ui/src/components/MarkdownEditor.test.tsx
ui/src/components/MarkdownBody.test.tsx --config ui/vitest.config.ts`
passed: 3 files, 75 tests.
- `git diff --check public-gh/master..pap-2228-editor-composer-polish --
. ':(exclude)ui/storybook-static'` passed.
- Confirmed this PR does not include `pnpm-lock.yaml`.
## Risks
- Low-to-medium risk: this changes user-facing composer/drop behavior
and long markdown display.
- The fold curtain uses DOM measurement and `ResizeObserver`; reviewers
should check browser behavior for very long descriptions and documents.
- No database migrations.
> 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, Paperclip
API, and GitHub CLI tool use in the local Paperclip workspace.
## 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 run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
Note: screenshots were not newly captured during branch splitting; the
UI states are covered by component tests and a Storybook story.
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-24 14:12:41 -05:00
const foldCurtainLongMarkdown = [
"# paperclip-bench" ,
"" ,
"Ship criteria for the benchmark harness — these notes are intentionally lengthy so the fold-curtain clips them." ,
"" ,
"## Overview" ,
"" ,
"We need a benchmark that compares agent performance across task types and model backends. This includes:" ,
"" ,
"- a **runner** that executes tasks in isolated workspaces" ,
"- a **scorer** that grades outputs against ground truth" ,
"- a **dashboard** that trends metrics over time" ,
"" ,
"## Task format" ,
"" ,
"Each task is a directory containing a `task.md`, an optional `setup.sh`, and an `expected/` fixture. The runner mounts the task, executes the agent, and diffs the resulting workspace against `expected/`." ,
"" ,
"```ts" ,
"type TaskResult = {" ,
" taskId: string;" ,
" agent: string;" ,
" exitCode: number;" ,
" scoreBreakdown: Record<string, number>;" ,
"};" ,
"```" ,
"" ,
"## Metrics" ,
"" ,
"| Metric | Description |" ,
"| --- | --- |" ,
"| Pass@1 | First-try correctness |" ,
"| Tokens | Cost per task |" ,
"| Wall time | End-to-end minutes |" ,
"" ,
"## Next steps" ,
"" ,
"1. Land the runner with support for 3 task types." ,
"2. Backfill 50 tasks from open-source benchmarks." ,
"3. Wire the scorer to GitHub Actions." ,
"4. Publish baseline numbers on the main branch." ,
"" ,
"All of this is described in more detail in the design doc linked from the home page." ,
] . join ( "\n" ) ;
const foldCurtainShortMarkdown = "This description is short. No curtain should appear." ;
function FoldCurtainStory() {
return (
< StoryShell >
< Section
eyebrow = "Presentation"
title = "FoldCurtain"
description = "Long content collapses to a preview with a bottom fade and a Show more button. Short content renders untouched."
>
< div className = "space-y-6" >
< StatePanel
label = "Long description (collapsed)"
detail = "Default state on every fresh page load. Natural height far exceeds the collapsed height, so the curtain activates."
>
< FoldCurtain >
< MarkdownBody className = "text-[15px] leading-7" > { foldCurtainLongMarkdown } < / MarkdownBody >
< / FoldCurtain >
< / StatePanel >
< StatePanel
label = "Short description (no curtain)"
detail = "Content below the activation threshold renders with no curtain and no button."
>
< FoldCurtain >
< MarkdownBody className = "text-[15px] leading-7" > { foldCurtainShortMarkdown } < / MarkdownBody >
< / FoldCurtain >
< / StatePanel >
< / div >
< / Section >
< / StoryShell >
) ;
}
export const FoldCurtainShowcase : Story = {
name : "Fold Curtain" ,
render : ( ) = > < FoldCurtainStory / > ,
} ;