@yannelli/paseo-linear-plugin 1.0.1 → 1.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/OVERVIEW.md +32 -2
  2. package/README.md +134 -8
  3. package/client/access.tsx +67 -0
  4. package/client/browser.tsx +12 -9
  5. package/client/compat.ts +23 -5
  6. package/client/connect.tsx +3 -2
  7. package/client/launch-assignments.tsx +182 -0
  8. package/client/launch-choices.ts +21 -6
  9. package/client/launch-guidance.tsx +103 -0
  10. package/client/launch-plan.ts +114 -17
  11. package/client/launch.tsx +55 -9
  12. package/client/live-agents.tsx +446 -0
  13. package/client/live-feed.tsx +151 -0
  14. package/client/live-header.tsx +310 -0
  15. package/client/live-issues.tsx +345 -0
  16. package/client/live-map.tsx +351 -0
  17. package/client/live-panel.tsx +392 -0
  18. package/client/live-timeline.ts +379 -0
  19. package/client/pill.tsx +394 -0
  20. package/client/plugin-icon.tsx +75 -0
  21. package/client/project-init.tsx +192 -0
  22. package/client/project-knowledge.tsx +87 -0
  23. package/client/settings-access.tsx +56 -0
  24. package/client/settings-agents.tsx +113 -0
  25. package/client/settings-fields.tsx +11 -3
  26. package/client/settings-icon.tsx +277 -0
  27. package/client/settings-live.tsx +128 -0
  28. package/client/settings-overrides.tsx +148 -0
  29. package/client/settings-projects.tsx +26 -4
  30. package/client/settings-prompts.tsx +3 -3
  31. package/client/timeline-card.tsx +2 -1
  32. package/client/tool-buttons.tsx +68 -0
  33. package/client/ui.tsx +16 -7
  34. package/client/web.ts +81 -0
  35. package/index.client.tsx +160 -51
  36. package/index.server.ts +32 -5
  37. package/package.json +1 -1
  38. package/server/agent-hooks.ts +37 -0
  39. package/server/agent-runs.ts +312 -0
  40. package/server/agent-tools.ts +276 -0
  41. package/server/handlers.ts +12 -1
  42. package/server/init.ts +89 -0
  43. package/server/inspect.ts +392 -0
  44. package/server/knowledge.ts +157 -0
  45. package/server/live.ts +371 -0
  46. package/server/mcp-http.ts +156 -0
  47. package/server/stores.ts +126 -0
  48. package/server/subagent-logs.ts +146 -0
  49. package/server/sync.ts +133 -0
  50. package/shared/activity.ts +268 -0
  51. package/shared/agent-hooks.ts +68 -0
  52. package/shared/agent-tools.ts +157 -0
  53. package/shared/custom-icon.ts +188 -0
  54. package/shared/knowledge.ts +255 -0
  55. package/shared/live.ts +248 -0
  56. package/shared/map-model.ts +240 -0
  57. package/shared/project-setup.ts +56 -0
  58. package/shared/prompts.ts +109 -2
  59. package/shared/settings.ts +145 -3
  60. package/shared/shell-activity.ts +309 -0
  61. package/shared/shell-lexer.ts +180 -0
  62. package/shared/subagents.ts +106 -0
  63. package/shared/todo-sync.ts +158 -0
package/OVERVIEW.md CHANGED
@@ -23,7 +23,37 @@ To use a different Linear key for one Paseo project, add it under **Project keys
23
23
 
24
24
  Select **Start agent** or **Start review** on an issue. The setup page shows the prompt and the composer controls for the prompt template, model, thinking level, and mode. The model picker lists providers first, and its search covers all models. Choose the project and where the agent runs: a new worktree, a pull request checkout, the issue branch, an existing agent workspace, or the current workspace or project folder. You can include comments in the prompt. For Implement, you can also move the issue to In Progress and assign it to you.
25
25
 
26
- The prompt follows the template until you edit it. **Reset prompt** restores it. Edit the templates in **Prompts**, and add project instructions in **Projects**.
26
+ **Agent guidance** switches add instructions to the prompt: keep Linear updated, have subagents state their issue key, and hand off work to Paseo agents. Each project keeps its choices. With the first and last switches, the agent gets the plugin's Linear tools. It edits the issue description, checks off task list items, and starts one Paseo agent for each sub-issue. It posts no comments. For Claude agents, the switches also add hooks that give subagents the issue keys. In **Sub-issue agents**, choose an agent, model, and thinking level for a sub-issue. The agent you start hands that sub-issue to it. The prompt follows the template until you edit it. **Reset prompt** restores it. Edit the templates in **Prompts**, and add project instructions in **Projects**.
27
+
28
+ ## Agent settings
29
+
30
+ In **Settings → Plugins → Linear → Agents**, turn the plugin's Linear tools on or off, allow or block description edits, show or hide sub-issue agents, and limit how many agents one launch runs at the same time. In **Projects**, a project can have its own values for these settings, the agent defaults, and todo sync.
31
+
32
+ ## Linear Live
33
+
34
+ Open **Linear Live** from the Linear pill in an agent's composer. It shows the issue's sub-issues with their statuses and the agent's todos, a map of the files the agent reads and edits, the agents it starts, and its latest commands. It works with Claude, Codex, and other providers. The map comes from paths in the ticket text, or, if you choose it in **Settings → Plugins → Linear → Live**, from an explore agent that reads the repository before the agent starts. The implement agent waits for the map. The explore agent uses provider usage. Buttons on the map reload it, build it again with the explore agent, or clear it. Agents in worktrees of the same project show on the map. Explore and setup agents are told to only read. The plugin starts Claude in Always Ask and answers the permission requests these agents raise: it allows reads and search commands in the project folder and denies the rest. Codex has no read-only mode, so it runs in its default mode, and the plugin answers only the requests Codex raises.
35
+
36
+ On agents not started from an issue, the Linear pill searches Linear and sends an issue to the agent.
37
+
38
+ ## Plugin icon
39
+
40
+ In **Settings → Plugins → Linear → Icon**, choose an SVG file or paste SVG markup. Composer pills, the Linear sidebar row, the timeline card, and the Linear screens use it. Panel tabs, the new tab menu, and Command Center take built-in icons only, so pick one of those for them. Keep the original colors, or paint the icon with the theme color, the theme accent, Linear indigo, or a custom color. **Solid** fills outline shapes. The plugin refuses SVGs with scripts, event handlers, or links to other files. The iOS and Android apps show the built-in icon in the chosen color.
41
+
42
+ ## Update Linear from todos
43
+
44
+ Turn on **Update Linear from agent todos** in the Live settings. After each turn, a todo that starts with a sub-issue key, such as `ENG-124: add the queue`, moves that sub-issue to In Progress, and then to Done when all its todos are done. The parent moves to In Review when every sub-issue is done, never to Done. Statuses only move forward.
45
+
46
+ ## Project knowledge
47
+
48
+ The daemon keeps a map of each project's files without an agent: its folders, services, packages, languages, commands, and guide files. Explore and setup agents start from it. Ticket-text maps use it to match short paths to real files and to put a named service on the map. When an agent works off the map, Linear Live shows the service or folder it is in. See it, or inspect again, under **Project knowledge** in **Projects**.
49
+
50
+ ## Set up project prompts
51
+
52
+ In **Projects**, select **Start** under **Set up with an agent**. An agent reads the repository's guidelines, scripts, and CI files and proposes project instructions, steps, and prompt additions. You accept each change before it is saved. **Open agent** shows the agent while it works, and the lines it writes about the project and its areas go into the project knowledge.
53
+
54
+ ## Choose projects
55
+
56
+ In **Projects**, **Use Linear in** turns Linear on or off for all projects, and each project has its own switch. In a project where Linear is off, its panels show that Linear is off, its agents get no Linear pill, and the agent setup page does not offer it. Todo sync and the explore agent skip it.
27
57
 
28
58
  ## Attach an issue
29
59
 
@@ -31,4 +61,4 @@ Choose **Attach Linear issue** in the composer attachment menu. The agent gets t
31
61
 
32
62
  ## Data and permissions
33
63
 
34
- Only the daemon sends requests to `https://api.linear.app/graphql`. The daemon never sends a key back to the app. Paseo sends the prompt, with the issue snapshot, to the agent provider. The daemon keeps recent Linear responses in memory for up to 24 hours, and the list shows them with **Showing saved results. Updating…** while it gets new data.
64
+ Only the daemon sends requests to `https://api.linear.app/graphql`. The daemon never sends a key back to the app. Paseo sends the prompt, with the issue snapshot, to the agent provider. Explore and setup agents read project files and send them to your agent provider. The daemon saves explore maps, project knowledge, and agents that wait for a map, beside the key file, and Linear Live lists and reads files only inside the agent's folder. For Claude agents, the daemon also reads the subagent transcripts Claude saves for the session, to show what each subagent does. With agent guidance on, it writes Claude Code hooks with the issue keys and titles beside the key file, and it serves the Linear tools on 127.0.0.1 with a token for each agent. Each token reaches only its issue and that issue's sub-issues. With todo sync on, the daemon changes issue statuses in Linear. The daemon keeps recent Linear responses in memory for up to 24 hours, and the list shows them with **Showing saved results. Updating…** while it gets new data.
package/README.md CHANGED
@@ -13,6 +13,13 @@ A Paseo plugin for Linear. It adds a Linear screen and a workspace panel where y
13
13
  - Use a different Linear key for a Paseo project.
14
14
  - See saved results at once while the plugin gets new data from Linear.
15
15
  - Attach a Linear issue to a message in the composer.
16
+ - Follow an agent in **Linear Live**: sub-issues, todos, and a map of the files it reads and edits.
17
+ - Open the issue from a **Linear** pill in each agent's composer, or send an issue to any agent.
18
+ - Choose an agent, model, and thinking level for each sub-issue. The agent you start hands those sub-issues to them.
19
+ - Let agent todos move sub-issues to In Progress and Done. This is off until you turn it on.
20
+ - Turn the plugin's Linear tools for agents on or off, and set agent defaults for all projects or for one project.
21
+ - Let an agent read a project's guidelines and propose its instructions and steps.
22
+ - Turn Linear on or off for all projects, or project by project.
16
23
 
17
24
  ![Linear screen with an issue list grouped by status on the left and issue ENG-123 open on the right](docs/images/browse.png)
18
25
 
@@ -115,21 +122,124 @@ Select **Start agent** or **Start review** in the issue view. The agent setup pa
115
122
 
116
123
  The worktree and checkout options show only for a Git project. When agents run in worktrees (the default), a review uses the pull request, then the implementation workspace, then the issue branch.
117
124
  5. Set the options: **Include comments in the prompt**, **Move the issue to In Progress**, and **Assign the issue to me**. The last two show only for Implement, and only when they would change the issue.
118
- 6. Select **Start agent** or **Start review**.
125
+ 6. Set the **Agent guidance** switches. Each one adds instructions to the prompt. The project keeps your choices for its next launch.
126
+ - **Keep Linear updated:** the agent edits the issue description as it works. It checks off each task list item it finishes and updates the plan when it changes. It posts no comments. Todos start with their issue key, so todo sync can move each sub-issue.
127
+ - **Subagents state their issue key:** each subagent's description and prompt start with the key of the issue it works on. The subagent states the key again when its work moves to another issue.
128
+ - **Hand off work to Paseo agents:** the agent starts one Paseo agent for each sub-issue instead of its built-in subagents. Each one runs in the same workspace on the same provider and model, with thinking that fits its task, and checks off its own items. Linear Live shows their work.
129
+
130
+ **Keep Linear updated**, **Hand off work to Paseo agents**, and sub-issue agents give the agent the plugin's `linear` MCP server. It has four tools: `read_issue` and `edit_issue` for the issue and its sub-issues, and `start_agent` and `wait_agent` for agents on the sub-issues. Agents that `start_agent` starts get only `read_issue` and `edit_issue`. Paseo allows these tools without a permission prompt. When the Linear tools are off for the project, **Hand off work to Paseo agents** is off, and **Keep Linear updated** only asks for issue keys in todos. See [Agent settings](#agent-settings).
131
+
132
+ For Claude agents, these switches also add Claude Code hooks. With **Subagents state their issue key** on, each subagent gets the issue keys when it starts. With any switch on, the agent gets the issue again after Claude compacts the conversation. The hooks only print that text.
133
+ 7. For Implement on an issue with sub-issues, choose agents in **Sub-issue agents**. Select the chip next to a sub-issue to choose the agent and model, then the thinking chip to change the thinking level. Select **×** to remove the agent. The prompt lists the sub-issues with an agent, and the agent you start hands each of them off with `start_agent`, which runs it on the chosen agent. The chosen thinking level wins over the one the agent asks for. An agent of the same provider runs in the mode of the agent you start. It does the other sub-issues itself, or hands them off when **Hand off work to Paseo agents** is on.
134
+ 8. Select **Start agent** or **Start review**.
119
135
 
120
136
  The plugin starts the agent and then updates Linear. If the Linear update fails, the agent keeps running and a message shows the error. The agent's timeline gets a card that links to the issue. The issue view lists the agents started from it under **Agents on this issue**.
121
137
 
122
- Set the default model, where agents run, the default options, and the Implement and Review templates in **Settings → Plugins → Linear → Prompts**. In **Projects**, add instructions and steps for a project, or append to or replace a template for that project.
138
+ Set the default model, where agents run, the default options, and the Implement and Review templates in **Settings → Plugins → Linear → Prompts**. In **Projects**, add instructions and steps for a project, append to or replace a template for that project, or give the project its own defaults.
139
+
140
+ ### Agent settings
141
+
142
+ **Settings → Plugins → Linear → Agents** applies to all projects:
143
+
144
+ - **Give agents the Linear tools:** agents started from an issue get the `linear` MCP server when an option needs it. When you turn it off, no new agent gets the server, and agents that have it get no tools from it. They get a message that the tools are off.
145
+ - **Let agents edit issue descriptions:** the `edit_issue` tool. When it is off, agents can only read the issue and its sub-issues.
146
+ - **Choose agents for sub-issues:** shows **Sub-issue agents** on the agent setup page. Turn it off to hide the section.
147
+ - **Agents at the same time:** how many agents one launch can run at the same time with `start_agent`. When the limit is reached, `start_agent` refuses until one of them finishes. The prompt gives the limit.
148
+
149
+ The daemon reads these settings for each tool call, so a change applies to agents that already run.
150
+
151
+ In **Projects**, the **Agent defaults for this project** and **Linear tools and sync for this project** sections give a project its own values: the model, where agents run, the three launch options, todo sync, and the four settings above. Each one starts at **Same as all projects**, which shows the current value for all projects. The agent setup page uses the values of the project you choose.
123
152
 
124
153
  ### Attach an issue to a message
125
154
 
126
155
  In the composer, open the attachment menu and choose **Attach Linear issue**. Type an identifier such as `ENG-123`, or words from a title. An empty search lists the 20 most recently updated issues. The agent gets the issue text with your message. The plugin takes this snapshot when you select the issue.
127
156
 
157
+ ### Turn Linear on or off per project
158
+
159
+ In **Settings → Plugins → Linear → Projects**, **Use Linear in** has an **All projects** switch and one switch per Paseo project. A project switch wins over **All projects**. A project without its own switch follows **All projects**. Save to apply.
160
+
161
+ In a project where Linear is off:
162
+
163
+ - The workspace **Linear** panel and **Linear Live** show that Linear is off.
164
+ - Agents get no Linear pill.
165
+ - The agent setup page does not offer the project.
166
+ - Todo sync and the explore agent skip the project's agents.
167
+
168
+ The **Linear** screen in the sidebar is not tied to a project, so it stays available. To turn off the whole plugin, use **Settings → Plugins**.
169
+
170
+ ### Linear Live
171
+
172
+ Linear Live is an agent panel. Open it from the Linear pill, or with **Linear: Open Linear Live** in the command center while an agent is open. It works for agents started from an issue, with Claude, Codex, and other providers.
173
+
174
+ - **Sub-issues:** each sub-issue shows its Linear status and the agent's todo progress. The todos of the current sub-issue show under it. Select a sub-issue to show only its files on the map. Hide the issues column with the button on the **Issue** card to give the map the full width. The column becomes a strip with the status of each issue. Select an issue there to show only its files.
175
+ - **Map:** files are grouped by folder. The map marks the files the agent read, edited, or created, and the file it is on now. Files the agent touched but the map did not predict have a dashed border. A folder the agent listed or searched gets a solid border, and its header shows how many of its files the agent touched. The header also names the service, package, or main folder the folder is in, from the [project knowledge](#project-knowledge). When the agent touches files the map did not predict, the line under the map tells where they are, such as `Off the map: billing-api · service (2), docs (1)`, and the **Now** line in the header shows **Off the map** with the place of the current file. Reads through the shell count too: `cat`, `sed -n`, `head`, `grep`, `rg`, `ls`, `find`, `git show`, and redirects to files.
176
+ - **Agents:** the agents that work under this agent. Paseo agents that this agent started show their status, their files, and their own markers on the map when they work in the same folder or in a worktree of the same project. Select one to open it. Subagents that run inside the provider, such as Claude's Agent tool, show their type, description, and status. For Claude, the daemon reads each subagent's transcript, also for subagents that run in the background, so a subagent shows what it does now and adds its files to the map. Other providers do not send subagent file reads, so the map shows only the files named in the subagent's prompt.
177
+ - **Activity:** the latest reads, edits, searches, and commands, with line counts and exit codes.
178
+
179
+ The map comes from one of two sources. Choose it in **Settings → Plugins → Linear → Live**:
180
+
181
+ - **Ticket text** (the default) finds file and folder paths in the issue title, description, and sub-issue titles. It costs nothing, but it finds only paths the issue names. Linear sends sub-issue titles but not their descriptions. With project knowledge, a short path such as `queries.ts` becomes the one project file that ends with it, and a service or package that the text names, such as `billing-api` or "the billing service", puts its folder on the map. A plain folder counts only when the text calls it a folder, such as "the docs folder".
182
+ - **Explore agent** maps the files first when you start an implement agent. It starts from the project map in the project knowledge, reads the repository, and lists the files for each sub-issue. The implement agent starts when the map is ready, or with the ticket-text map if exploring fails. A saved map is used again, so each issue is explored once. The plugin archives the explore agent when it finishes. Choose its model and effort in the Live settings. A faster, cheaper model, such as Haiku, is usually enough. It lists up to 150 files.
183
+
184
+ The buttons on the map card control the saved map. **Read the files again** reloads the map and the folder lists. **Build** or **Rebuild the map with the explore agent** starts an explore run now and replaces the saved map when it finishes. **Clear the saved map** deletes it, so the map uses the ticket text until the next explore run. You cannot clear a map while an explore run makes it.
185
+
186
+ The daemon starts the waiting agent, so you can close the app while the map is made. If the plugin reloads or the daemon restarts during the run, the plugin finishes it when the explore agent's turn ends. A waiting agent that has not started after one hour is dropped.
187
+
188
+ Explore and setup agents are told to only read. The plugin starts them in a mode that asks before tool use when the provider has one: **Always Ask** for Claude, never a bypass mode. When such an agent asks for permission, the plugin answers. It allows file reads inside the project folder and these commands: `ls`, `find`, `rg`, `grep`, `cat`, `head`, `tail`, `wc`, `git ls-files`, and `git grep`. It denies other commands, edits, web requests, redirection, and paths outside the folder. The plugin sees only the requests the provider raises: Claude runs some read commands without asking, and Codex has no read-only mode, so it runs in its default mode and its own sandbox decides what needs a request.
189
+
190
+ For implement agents on an issue with sub-issues, the prompt asks the agent to start each todo with its sub-issue key, such as `ENG-124: add the queue`. That is how todos map to sub-issues.
191
+
192
+ ### Linear pill
193
+
194
+ Each agent's composer has a **Linear** pill. On an agent started from an issue, the pill shows the issue key. It opens the issue status, each sub-issue with its todo progress, and buttons for Linear Live, the issue, and **Sync now**. On other agents, the pill searches Linear and sends the issue text to the agent as a message.
195
+
196
+ ### Plugin icon
197
+
198
+ In **Settings → Plugins → Linear → Icon**, choose an SVG file or paste SVG markup. Composer pills, the Linear sidebar row on Paseo 0.11 and newer, the issue card in the timeline, and the Linear screens then use it. The plugin accepts SVG only. It refuses scripts, event handlers, HTML content, entities, and links to other files or bitmap images. The SVG needs a viewBox, or a width and height in pixels.
199
+
200
+ - **Color:** **Original colors** keeps the SVG as drawn, and `currentColor` takes the color Paseo gives the icon. **Theme color**, **Theme accent**, **Linear indigo**, and **Custom color** paint the whole icon one color and keep its transparency. These choices also apply to the built-in icon.
201
+ - **Solid:** fills shapes that only have an outline, with their stroke color, so a line icon shows as a solid shape.
202
+ - **Built-in icon:** Paseo draws panel tabs, the new tab menu, and Command Center with built-in Lucide icons only, so your SVG cannot show there. Pick the built-in icon for those places, such as Rocket or Target. Without an SVG, every place uses it. Tabs that are open change when you reload Paseo or open them again. The web app keeps the choice on the device, so the tabs get it as Paseo starts.
203
+
204
+ The preview shows each change before you save. The iOS and Android apps cannot draw SVG images from plugins, so they show the built-in icon in the chosen color.
205
+
206
+ ### Update Linear from agent todos
207
+
208
+ Turn on **Update Linear from agent todos** in the Live settings. After each turn of an implement agent, the daemon reads the agent's todos:
209
+
210
+ - A sub-issue with a todo in progress or done moves to the team's first started status, such as In Progress.
211
+ - A sub-issue whose todos are all done moves to the team's first completed status, such as Done.
212
+ - The parent moves to In Progress when work starts. When every sub-issue is done, it moves to a started status whose name has "review", such as In Review. It never moves to Done by itself.
213
+ - Statuses only move forward. Canceled issues and issues outside the parent and its sub-issues never change.
214
+
215
+ The daemon reads the issue from Linear before each sync, so a status you changed by hand counts. **Sync now** in the pill runs the same check at once.
216
+
217
+ ### Project knowledge
218
+
219
+ The daemon keeps a map of each project's files, so explore and setup agents, ticket-text maps, and Linear Live know the project before an agent reads it. No agent runs for it, and it costs no provider usage. The daemon makes it the first time a project needs it: when you open the project in **Settings → Plugins → Linear → Projects**, open Linear Live for one of its agents, or start an explore or setup run. It makes it again when it is 6 hours old, and **Inspect again** under **Project knowledge** makes it at once.
220
+
221
+ - **Files:** the files git tracks or would track, without ignored files. Outside a git repository, the daemon walks the folder and skips folders such as `node_modules`, `dist`, and `.git`. It keeps up to 20,000 paths, the shallow ones first.
222
+ - **Areas:** services, packages, and main folders. A folder with a manifest such as `package.json`, `go.mod`, `Cargo.toml`, `pyproject.toml`, or a `.csproj` file is a package, named by the manifest. A folder with a `Dockerfile`, `Procfile`, `fly.toml`, or a similar file, a folder that a compose file builds, and a package under a folder such as `apps/` or `services/` is a service. Each top folder is an area too, and so is each subfolder of a top folder that holds 40% or more of the files. Folder names give a role, such as backend, frontend, tests, or docs. Manifests in fixture, example, and template folders do not count.
223
+ - **Languages, commands, and guides:** file counts by language, the root package scripts and Makefile targets, and files that guide agents, such as `AGENTS.md`, `CLAUDE.md`, the README, CONTRIBUTING, and CI workflows.
224
+ - **Summaries:** the setup agent adds one line about the project and one line about each area. They stay when the daemon makes the map again.
225
+
226
+ The **Project knowledge** section in the Projects settings shows what the daemon found.
227
+
228
+ ### Set up project prompts with an agent
229
+
230
+ In **Settings → Plugins → Linear → Projects**, select **Start** under **Set up with an agent**. The daemon makes the project knowledge again first, and the agent starts from that project map. While it runs, **Open agent** opens the setup agent so you can watch it. The agent reads the project's AGENTS.md, CLAUDE.md, CONTRIBUTING, README, scripts, and CI files. It then proposes project instructions, steps, and text to add to the Implement and Review prompts. Each change shows the current and proposed text. Turn off the ones you do not want, select **Use accepted changes**, and then save. Nothing changes until you save. The agent also describes the project and each area, and the daemon saves those lines to the project knowledge at once.
231
+
128
232
  ## Data and permissions
129
233
 
130
234
  - **Your key stays on the daemon host.** When you save a key, the app sends it to the daemon once. The daemon never sends a key back to the app. The app gets only the last four characters, to show which key is in use. Only the daemon sends requests to `https://api.linear.app/graphql`.
131
235
  - **Data sent to Linear:** queries for issues, teams, users, and comments, and the changes you make. When you start an agent with the options on, the plugin moves the issue to In Progress and assigns it to you.
132
236
  - **Data sent to the agent provider:** the prompt. It holds the template text and an issue snapshot: identifier, title, URL, team, status, priority, assignee, project, labels, parent, description, sub-issues, and links. It holds comments only when **Include comments in the prompt** is on. It also holds the project instructions and steps from the Projects settings. An attached issue sends the identifier, title, URL, status, priority, assignee, project, labels, and description.
237
+ - **Linear Live and setup agents:** the explore agent gets the issue snapshot without comments, and both agents read files in the project. Your agent provider gets what they read. The map of an explore run is saved in `live-maps.json` beside the key file, for up to 200 issues. An agent that waits for a map is saved in `pending-launches.json` there until it starts. Linear Live lists files only in the folders it shows, inside the agent's own folder. It does not follow links that lead outside that folder. For a Claude agent with subagents, the daemon reads the tool calls in the subagent transcripts that Claude saves for that session. It sends the app only the tool names, file paths, and commands, never file text.
238
+ - **Project knowledge:** the daemon lists the files of a Paseo project with `git ls-files`, or by walking the folder, and reads small manifest files (up to 256 KB) inside the project folder. It does not follow links that lead outside the folder. It saves file paths, manifest names, script names, and summaries in `knowledge/` beside the key file, one file per project. The app gets the areas, counts, commands, and guides, never the file list. Explore and setup prompts hold the project map: folder names with file counts, areas, commands, and guide file names. Your agent provider gets that text.
239
+ - **Linear tools for agents:** the daemon runs the `linear` MCP server on `127.0.0.1` only, and only after an agent gets it. When the tools are off for a project, its agents get no tools. Each agent gets its own random token, and its tools reach only its issue and that issue's sub-issues. Edits use the Linear key of the project that loaded the issue. Requests from a web page are refused. `agent-tools.json` beside the key file keeps the port and a hash of each token, so agents keep their tools after a restart. The token itself is in the agent's Paseo config.
240
+ - **Claude hooks:** when an **Agent guidance** switch is on for a Claude agent, the daemon writes a Claude Code plugin to `claude-hooks/` beside the key file, one folder for each issue and set of hooks. It holds the issue key and title and the sub-issue keys and titles. The agent starts with `--plugin-dir` set to that folder. The hooks print that text and run no other command. The daemon does not write hooks on Windows hosts.
241
+ - **Todo sync:** when it is on for the agent's project, the daemon changes issue statuses in Linear with the key of the project that loaded the issue.
242
+ - **Plugin icon:** the SVG is saved in the plugin settings on the daemon host. The app draws it as an image, which does not run scripts or load other files. The web app keeps the name of the built-in icon in its local storage.
133
243
  - **Cached results:** the daemon keeps up to 300 recent Linear responses in memory for up to 24 hours. It groups them by a hash of the key, so two keys never share results. The app shows saved results at once with **Showing saved results. Updating…** while it gets new data. An edit clears the cached lists and issues for that key. Saving or removing a key clears the whole cache. The cache is not written to disk, and a daemon restart clears it.
134
244
 
135
245
  Linear errors, such as a rejected key or a rate limit, show in the panel or as a message.
@@ -138,30 +248,46 @@ Linear errors, such as a rejected key or a rate limit, show in the panel or as a
138
248
 
139
249
  | File | Runtime | Role |
140
250
  | --- | --- | --- |
141
- | `index.client.tsx` | App | Registers the Linear screen, the workspace panel, the Account, Prompts, and Projects settings, the command center items, the `/linear` command, the timeline card, and the composer attachment |
142
- | `index.server.ts` | Daemon | Registers the settings and the RPC handlers |
251
+ | `index.client.tsx` | App | Registers the Linear screen, the workspace panel, the Linear Live panel, the Account, Prompts, Agents, Live, Icon, and Projects settings, the command center items, the `/linear` command, the timeline card, the composer attachment, and the Linear pill |
252
+ | `index.server.ts` | Daemon | Registers the settings, the RPC handlers, and the todo sync hook |
143
253
  | `client/browser.tsx` | App | Screen and panel: picks the key, then shows the list, the issue, or the agent setup page |
144
254
  | `client/issue-list.tsx`, `client/issue-row.tsx`, `client/issue-tree.ts` | App | Search, filters, sort, rows, status groups, and sub-issue nesting |
145
255
  | `client/issue-detail.tsx`, `client/issue-sections.tsx`, `client/breadcrumbs.tsx` | App | Issue view: properties, breadcrumbs, sub-issues, links, agents, and comments |
146
256
  | `client/issue-description.tsx`, `client/autosave.ts` | App | Description editor, task list checkboxes, and debounced saves |
147
257
  | `client/markdown.tsx` | App | Renders Markdown |
148
- | `client/launch.tsx`, `client/launch-fields.tsx`, `client/launch-choices.ts`, `client/launch-plan.ts`, `client/agent-options.ts` | App | Agent setup page, Run in options, and agent start |
258
+ | `client/launch.tsx`, `client/launch-fields.tsx`, `client/launch-guidance.tsx`, `client/launch-assignments.tsx`, `client/launch-choices.ts`, `client/launch-plan.ts`, `client/agent-options.ts` | App | Agent setup page, Run in options, agent guidance, sub-issue agents, and agent start |
149
259
  | `client/model-browser.tsx`, `client/provider-icon.tsx` | App | Model picker and provider icons |
260
+ | `client/plugin-icon.tsx`, `client/settings-icon.tsx`, `shared/custom-icon.ts` | App, Both | The plugin icon, its settings screen, and the SVG checks, colors, and fill |
150
261
  | `client/create-issue.tsx`, `client/pickers.tsx` | App | New issue form and option pickers |
151
- | `client/connect.tsx`, `client/settings-*.tsx` | App | Key form and settings screens |
262
+ | `client/connect.tsx`, `client/settings-*.tsx` | App | Key form and settings screens, with the Agents screen and the project's own values in `settings-agents.tsx` and `settings-overrides.tsx` |
152
263
  | `client/queries.ts`, `client/store.ts`, `client/key-scope.tsx` | App | Data hooks with saved results, browser state, and the key in use |
153
264
  | `client/compat.ts` | App | Registers the screen on Paseo 0.10 and on later releases |
154
265
  | `client/timeline-card.tsx`, `client/ui.tsx`, `client/glyphs.tsx` | App | Timeline card, shared controls, and icons |
266
+ | `client/live-panel.tsx`, `client/live-header.tsx`, `client/live-issues.tsx`, `client/live-feed.tsx`, `client/live-timeline.ts` | App | Linear Live panel, header, sub-issues, activity, and the agent timeline feed |
267
+ | `client/live-map.tsx`, `client/live-agents.tsx` | App | File map and the agents list |
268
+ | `client/tool-buttons.tsx`, `client/web.ts` | App | Icon buttons for the map, and the file picker and local storage on the web |
269
+ | `client/pill.tsx` | App | Linear pill in each agent's composer |
270
+ | `client/project-init.tsx`, `client/project-knowledge.tsx` | App | Project setup proposal and the Project knowledge section in the Projects settings |
155
271
  | `shared/linear.ts` | Both | RPC contracts and issue schemas |
156
272
  | `shared/issues.ts` | Both | The `issues.search` RPC and the composer attachment source |
157
- | `shared/settings.ts` | Both | Settings schema: templates, agent defaults, and project settings |
273
+ | `shared/settings.ts` | Both | Settings schema: templates, agent defaults, Linear tools, and project settings with their own values |
158
274
  | `shared/prompts.ts` | Both | Default templates and the issue snapshot |
159
275
  | `shared/markdown.ts` | Both | Markdown parser and task list toggle |
276
+ | `shared/live.ts`, `shared/activity.ts`, `shared/subagents.ts` | Both | Linear Live contracts, the ticket text map, timeline activity, and subagent runs |
277
+ | `shared/shell-lexer.ts`, `shared/shell-activity.ts` | Both | Shell command parsing for reads, edits, and searches |
278
+ | `shared/map-model.ts` | Both | Map folders and tiles |
279
+ | `shared/agent-hooks.ts`, `server/agent-hooks.ts` | Both, Daemon | Claude Code hooks for agent guidance, and the plugin folder the daemon writes |
280
+ | `shared/agent-tools.ts`, `server/agent-tools.ts`, `server/mcp-http.ts` | Both, Daemon | The `linear` MCP server: its tools, tokens, and HTTP transport |
281
+ | `shared/todo-sync.ts`, `shared/project-setup.ts` | Both | Todo keys, status moves, and setup proposals |
282
+ | `shared/knowledge.ts` | Both | Project knowledge contracts, areas and their labels, the project map for prompts, and ticket path matching |
160
283
  | `server/handlers.ts` | Daemon | RPC handlers, key lookup, and cache use |
161
284
  | `server/credentials.ts` | Daemon | Key file and key order |
162
285
  | `server/cache.ts` | Daemon | Response cache in memory |
163
286
  | `server/graphql.ts`, `server/queries.ts` | Daemon | Linear GraphQL client, queries, and changes |
164
287
  | `server/linear.ts` | Daemon | Search and snapshot text for the composer attachment |
288
+ | `server/live.ts`, `server/subagent-logs.ts`, `server/agent-runs.ts` | Daemon | File listing, subagent transcripts, explore runs, and the saved maps |
289
+ | `server/sync.ts`, `server/init.ts` | Daemon | Todo sync after each turn, and project setup runs |
290
+ | `server/inspect.ts`, `server/knowledge.ts` | Daemon | Project inspection without an agent, and the saved project knowledge |
165
291
 
166
292
  The client bundle holds no credentials and makes no calls to Linear.
167
293
 
@@ -177,7 +303,7 @@ npm run check
177
303
  paseo plugin add "$PWD"
178
304
  ```
179
305
 
180
- After you edit the source, run `paseo plugin reload paseo-linear-plugin`. `npm run check` runs the typecheck and the tests. The tests cover the Linear client, the key file, the cache, the handlers, sub-issue nesting, the Markdown parser and task list toggle, the description autosave, the agent options, and the release scripts. They use a local GraphQL server and do not call Linear.
306
+ After you edit the source, run `paseo plugin reload paseo-linear-plugin`. `npm run check` runs the typecheck and the tests. The tests cover the Linear client, the key file, the cache, the handlers, sub-issue nesting, the Markdown parser and task list toggle, the description autosave, the agent options, the prompt guidance and its hooks, the MCP server and its tools with their settings, sub-issue agents, the project's own settings, the SVG icon checks and colors, and the release scripts. They use a local GraphQL server and do not call Linear.
181
307
 
182
308
  ## Graphics
183
309
 
@@ -0,0 +1,67 @@
1
+ import { type PluginAgentPanelProps, useSettings, useWorkspace } from "@getpaseo/plugin/client";
2
+ import { type ComponentType, type ReactNode, useEffect } from "react";
3
+ import { linearSettings, type ProjectAccess, projectEnabled } from "../shared/settings";
4
+ import { PluginIcon } from "./plugin-icon";
5
+ import { EmptyState, type Theme } from "./ui";
6
+
7
+ // Composer pills live outside React, so components that read settings share the project
8
+ // switches here, and the pill code listens for changes.
9
+ let current: ProjectAccess | null = null;
10
+ const listeners = new Set<(access: ProjectAccess) => void>();
11
+
12
+ export function publishAccess(access: ProjectAccess): void {
13
+ if (current && JSON.stringify(current) === JSON.stringify(access)) return;
14
+ current = access;
15
+ for (const listener of listeners) listener(access);
16
+ }
17
+
18
+ export function currentAccess(): ProjectAccess | null {
19
+ return current;
20
+ }
21
+
22
+ export function onAccessChange(listener: (access: ProjectAccess) => void): () => void {
23
+ listeners.add(listener);
24
+ return () => listeners.delete(listener);
25
+ }
26
+
27
+ /** Null while settings load or when the project is unknown, so callers can wait. */
28
+ export function useProjectEnabled(projectId: string | null | undefined): boolean | null {
29
+ const settings = useSettings(linearSettings);
30
+ const access = settings.status === "ready" ? settings.values.access : null;
31
+ useEffect(() => {
32
+ if (access) publishAccess(access);
33
+ }, [access]);
34
+ if (!access || projectId === undefined) return null;
35
+ return projectEnabled(access, projectId);
36
+ }
37
+
38
+ export function ProjectGate(props: {
39
+ theme: Theme;
40
+ projectId: string | null | undefined;
41
+ children: ReactNode;
42
+ }) {
43
+ const enabled = useProjectEnabled(props.projectId);
44
+ if (enabled !== false) return <>{props.children}</>;
45
+ return (
46
+ <EmptyState
47
+ theme={props.theme}
48
+ icon={PluginIcon}
49
+ title="Linear is off for this project"
50
+ detail="Turn it on in Linear settings, under Projects."
51
+ />
52
+ );
53
+ }
54
+
55
+ const selectProjectId = (workspace: { projectId: string }) => workspace.projectId;
56
+
57
+ /** Wraps an agent panel so it shows the off state in projects where Linear is off. */
58
+ export function gateAgentPanel(Panel: ComponentType<PluginAgentPanelProps>) {
59
+ return function GatedAgentPanel(props: PluginAgentPanelProps) {
60
+ const projectId = useWorkspace(props.workspaceId, selectProjectId);
61
+ return (
62
+ <ProjectGate theme={props.theme} projectId={projectId}>
63
+ <Panel {...props} />
64
+ </ProjectGate>
65
+ );
66
+ };
67
+ }
@@ -11,6 +11,7 @@ import { ConnectCard } from "./connect";
11
11
  import { CreateIssueModal } from "./create-issue";
12
12
  import { IssueDetailView } from "./issue-detail";
13
13
  import { IssueList } from "./issue-list";
14
+ import { ProjectGate } from "./access";
14
15
  import { effectiveKeyScope, KeyScopeProvider } from "./key-scope";
15
16
  import { LaunchPage, type LaunchTarget } from "./launch";
16
17
  import { useAuthStatus, useCatalog, useProjects } from "./queries";
@@ -262,14 +263,16 @@ export function LinearPanel({ theme, layout, navigation, workspaceId }: PluginWo
262
263
  if (teamId) update({ teamId, assignee: "anyone" });
263
264
  }, [settings, projectId, update]);
264
265
  return (
265
- <IssueBrowser
266
- theme={theme}
267
- compact={layout.compact}
268
- navigation={navigation}
269
- scope={scope}
270
- target={target}
271
- keyProjectId={projectId ?? null}
272
- canSwitchKey={false}
273
- />
266
+ <ProjectGate theme={theme} projectId={projectId}>
267
+ <IssueBrowser
268
+ theme={theme}
269
+ compact={layout.compact}
270
+ navigation={navigation}
271
+ scope={scope}
272
+ target={target}
273
+ keyProjectId={projectId ?? null}
274
+ canSwitchKey={false}
275
+ />
276
+ </ProjectGate>
274
277
  );
275
278
  }
package/client/compat.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { PluginClientContext, PluginSurfaceProps } from "@getpaseo/plugin/client";
2
2
  import * as hostUi from "@getpaseo/plugin/client/ui";
3
- import { type ComponentType, createElement } from "react";
3
+ import { type ComponentType, createContext, createElement, useContext } from "react";
4
4
 
5
5
  // Paseo 0.11 replaced surfaces with screens and sidebar header items. 0.10 only has
6
6
  // addSurface/addSidebarItem; later releases drop those aliases. Detect once, register once.
@@ -13,6 +13,7 @@ interface ScreenRef {
13
13
  interface SidebarItemProps {
14
14
  currentScreen: ScreenRef | null;
15
15
  openScreen(input: ScreenRef): void;
16
+ theme?: PluginSurfaceProps["theme"];
16
17
  }
17
18
 
18
19
  interface ScreenClient {
@@ -33,8 +34,13 @@ interface SurfaceClient {
33
34
  addSidebarItem(input: { id: string; title: string; icon: string; surface: string }): Cleanup;
34
35
  }
35
36
 
37
+ interface RowIconProps {
38
+ size: number;
39
+ color: string;
40
+ }
41
+
36
42
  type SidebarRowComponent = ComponentType<{
37
- icon?: string;
43
+ icon?: string | ComponentType<RowIconProps>;
38
44
  label?: string;
39
45
  active?: boolean;
40
46
  onPress(): void;
@@ -48,9 +54,14 @@ export interface ScreenRegistration {
48
54
  id: string;
49
55
  title: string;
50
56
  icon: string;
57
+ /** Drawn in the sidebar row where the host accepts icon components; else `icon`. */
58
+ RowIcon?: ComponentType<RowIconProps & { theme: PluginSurfaceProps["theme"] | null }>;
51
59
  Component: ComponentType<PluginSurfaceProps>;
52
60
  }
53
61
 
62
+ // The row draws its icon with a size and a color only, so the item passes its theme down.
63
+ const RowTheme = createContext<PluginSurfaceProps["theme"] | null>(null);
64
+
54
65
  export function registerScreen(client: PluginClientContext, screen: ScreenRegistration): Cleanup {
55
66
  const SidebarRow = (hostUi as Record<string, unknown>).SidebarRow as
56
67
  | SidebarRowComponent
@@ -61,12 +72,19 @@ export function registerScreen(client: PluginClientContext, screen: ScreenRegist
61
72
  title: screen.title,
62
73
  Component: screen.Component,
63
74
  });
64
- function SidebarItem({ currentScreen, openScreen }: SidebarItemProps) {
65
- return createElement(SidebarRow as SidebarRowComponent, {
66
- icon: screen.icon,
75
+ const { RowIcon } = screen;
76
+ const ThemedIcon = RowIcon
77
+ ? function ThemedIcon(props: RowIconProps) {
78
+ return createElement(RowIcon, { ...props, theme: useContext(RowTheme) });
79
+ }
80
+ : null;
81
+ function SidebarItem({ currentScreen, openScreen, theme }: SidebarItemProps) {
82
+ const row = createElement(SidebarRow as SidebarRowComponent, {
83
+ icon: ThemedIcon ?? screen.icon,
67
84
  active: currentScreen?.screenId === screen.id,
68
85
  onPress: () => openScreen({ screenId: screen.id }),
69
86
  });
87
+ return createElement(RowTheme.Provider, { value: theme ?? null }, row);
70
88
  }
71
89
  const removeItem = client.addSidebarHeaderItem({
72
90
  id: screen.id,
@@ -1,10 +1,11 @@
1
1
  import { useRpc } from "@getpaseo/plugin/client";
2
- import { Icon, TextInput, useToast } from "@getpaseo/plugin/client/react-native";
2
+ import { TextInput, useToast } from "@getpaseo/plugin/client/react-native";
3
3
  import { ExternalLink } from "@getpaseo/plugin/client/ui";
4
4
  import { useMutation, useQueryClient } from "@tanstack/react-query";
5
5
  import { useCallback, useMemo, useState } from "react";
6
6
  import { Text, View } from "react-native";
7
7
  import { authSaveRpc } from "../shared/linear";
8
+ import { PluginIcon } from "./plugin-icon";
8
9
  import { Button, errorMessage, type Theme } from "./ui";
9
10
 
10
11
  export const LINEAR_KEY_SETTINGS_URL = "https://linear.app/settings/account/security";
@@ -121,7 +122,7 @@ export function ConnectCard({ theme, compact }: { theme: Theme; compact: boolean
121
122
  <View style={styles.root}>
122
123
  <View style={styles.card}>
123
124
  <View style={styles.header}>
124
- <Icon name="SquareKanban" size={22} color={colors.foreground} />
125
+ <PluginIcon size={22} color={colors.foreground} theme={theme} />
125
126
  <Text style={styles.title}>Connect Linear</Text>
126
127
  </View>
127
128
  <Text style={styles.body}>