Files
PaperClipAI/ui
93d26eb84e feat(ui): link routine-created tasks back to their source routine (#16471)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Routines create tasks on a schedule. Each task records its source in
`originKind = "routine_execution"` and `originId = <routine id>`.
> - The issue Properties card shows Relationships such as Parent. It
does not show the routine that created the task.
> - An operator who reads a routine-created task cannot go to the
routine from the task. They must find the routine by hand.
> - This pull request adds a "Routine" row under Relationships, below
Parent. The row links to the source routine.
> - The benefit is a direct path from a routine-created task to the
routine that made it.

## Linked Issues or Issue Description

Refs #9727. That PR adds a general provenance model and an "Origin"
chip. It also links routine executions to the routine. It is much larger
(DB migration, server, plugin SDK). It has merge conflicts and no
updates since August. This PR is a small UI-only change with no schema
or API change. If #9727 merges later, the two rows can be merged into
one.

**Is your feature request related to a problem?**
A task that a routine creates has no visible link back to that routine
in the Properties card.

**Describe the solution you'd like**
Show a "Routine" row under Relationships for routine-created tasks. The
row shows the routine title and links to `/routines/:id`.

**Describe alternatives you've considered**
A generic "Origin" row for all origin kinds (the #9727 approach). That
needs new server data for most kinds. A routine link needs only data
that the issue already has.

## What Changed

- Add `ui/src/components/issue-properties/routine-origin-row.tsx`
(`RoutineOriginRow`). It reads the routine with the same
`queryKeys.routines.detail` query as the routine page, so the cache is
shared.
- Show the row in `IssueProperties.tsx` after Parent, only when
`originKind === "routine_execution"` and `originId` is set (+5 lines).
The new component is in its own file because `IssueProperties.tsx`
already has more than 3,000 lines.
- States:
- Routine found: an outline chip with the repeat icon and the routine
title. The chip links to the routine page.
- Routine still loading, routine deleted (404), or any other lookup
error: no row. The card never shows an empty Routine field.
  - Task not created by a routine: no row. No routine request is sent.
- Add 4 tests in `IssueProperties.test.tsx`: routine found, routine
loading, routine deleted, and task not created by a routine.

## Verification

- `pnpm --filter @paperclipai/ui exec vitest run
src/components/IssueProperties.test.tsx`: 94/94 pass.
- `vitest run src/pages/IssueDetail.test.tsx
src/components/TaskSidePanel.test.tsx` (other surfaces that render the
panel): 195/195 pass.
- `node scripts/check-token-gates.mjs`: all gates clean.
- `tsc --noEmit` in `ui`: no errors in the changed files. Other errors
came from workspace packages that were not built locally
(`@paperclipai/plugin-sdk/ui`, generated storybook catalog JSON). This
change does not touch them.
- Manual check: open a task that a routine created. Find the "Routine"
row under Parent. Click it. The routine page opens.
- Not run locally: full `pnpm -r typecheck`, `pnpm test:run`, `pnpm
build`, and a browser check. CI runs these.

## Risks

- Low risk. The change is UI-only and additive. It has no schema, API,
or contract change.
- Each routine-created task view sends one extra `GET /routines/:id`
request. The routine page uses the same cache key, so the response is
often cached already.
- The row appears only after the routine request finishes. On a cold
cache, it shows up a moment after the rest of the card.
- If the routine is deleted or the user cannot read it, the task shows
no Routine row. The task still records `originKind`/`originId`.

> 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

- Anthropic Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with
tool use (shell, file edit, test execution). Standard context window.

## Checklist

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

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

---------

Co-authored-by: Devin Foley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:20:58 -07:00
..

@paperclipai/ui

Published static assets for the Paperclip board UI.

What gets published

The npm package contains the production build under dist/. It does not ship the UI source tree or workspace-only dependencies.

Storybook

Storybook config, stories, and fixtures live under ui/storybook/.

pnpm --filter @paperclipai/ui storybook
pnpm --filter @paperclipai/ui build-storybook

Typical use

Install the package, then serve or copy the built files from node_modules/@paperclipai/ui/dist.

Editor dependency identity

Keep the root and workspace overrides for @codemirror/state, @codemirror/view, and @lezer/common aligned. CodeMirror requires shared extension identity, while Lezer parsers and syntax highlighters require shared NodeProp IDs. Multiple Lezer copies can crash code-block highlighting with tags is not iterable. src/lib/codemirror-single-instance.test.ts checks the installed dependency graph and highlights sample code through the editor's real language dependencies. GitHub Actions owns regeneration of pnpm-lock.yaml.