Channel CONTEXT.md: agent generation + inject into task prompts (local & cloud)#2627
Channel CONTEXT.md: agent generation + inject into task prompts (local & cloud)#2627raquelmsmith wants to merge 4 commits into
Conversation
Adds a one-shot background agent to the per-channel CONTEXT.md empty state. The agent explores a selected local repo (read-only) plus PostHog data via the PostHog MCP for things related to the folder name, then publishes CONTEXT.md itself through the MCP (desktop-file-system-instructions-partial-update). - New ContextGenService (host-router), mirroring CanvasGenService: real repoPath, denies file-write/shell/network tools, keeps MCP enabled, streams prose + tool activity. Bound as a singleton with a BindingMap entry. - Core schemas + identifier + service interface; one-line tRPC router registered in both host-router and apps/code aggregators. - UI: folder picker (existing registered repos), context-gen store + stream subscription, GeneratingPanel reusing MarkdownRenderer, done -> refetch + render. v1 is local-repo only; cloud/GitHub-sandbox mode is a follow-up. Generated-By: PostHog Code Task-Id: 8b4fb28f-6761-49c4-9b2f-dc62f2305ca2
When a task is created from a channel, that channel's CONTEXT.md is appended to the agent's initial prompt as optional background — framed as reference material, not instructions, so the agent can use it as a starting point without being limited to it. Threads an optional channelContext string from WebsiteNewTask (fetched via useFolderInstructions) through TaskInput -> useTaskCreation -> prepareTaskInput -> TaskCreationInput, and appends it as a labeled <channel_context> block to the initial prompt in TaskCreationSaga. Empty/missing instructions inject nothing. Generated-By: PostHog Code Task-Id: 8b4fb28f-6761-49c4-9b2f-dc62f2305ca2
Three related changes to how a channel's CONTEXT.md flows through tasks: - New-task input: when a channel has a CONTEXT.md, show a dismissable "Using: #channel CONTEXT.md" chip; dismissing drops it from the prompt. - Conversation: the injected <channel_context> block renders as a clickable "#channel CONTEXT.md" tag instead of inline text; clicking opens the exact snapshot that was sent as a real file tab in the split (not a fetched/live copy), via a new "context" panel tab type. - Generation: replace the bespoke streaming generator with a normal task in the channel's repo that publishes CONTEXT.md via the PostHog MCP. The view tracks that task — a centered "Generating" state with a View task button while its session runs, and a re-generate path if it stops before producing a file. Removes ContextGenService, its router/schemas/store/subscriptions, and the CONTEXT_GEN_SERVICE DI wiring. Generated-By: PostHog Code Task-Id: 8b4fb28f-6761-49c4-9b2f-dc62f2305ca2
…n tracking
- Channel-context injection now reaches cloud tasks: split buildChannelContextText
out of buildChannelContextBlock and fold it into the cloud task's
pendingUserMessage (local still appends a block to initialPrompt). The shared
conversation tag parser renders both identically; task titles stay clean.
- CONTEXT.md generation works for cloud: the generate picker has a Local/Cloud
toggle reusing FolderPicker / GitHubRepoPicker + useUserRepositoryIntegration;
useGenerateContext builds a local or cloud TaskCreationInput. The "generating"
status is now environment-aware (cloud uses cloudStatus/latest_run.status,
local uses the live session).
- Generation tracking moved off fragile local electronStorage to a server-side,
project-shared association keyed on the folder (works before any instructions
exist): new api-client get/setDesktopFolderGenerationTask + useFolderGenerationTask
hook. Deleted contextGenTaskStore.
Requires a PostHog cloud backend change (separate repo) to add the
GET/PUT .../desktop_file_system/{id}/context_generation/ endpoints; until then the
client no-ops gracefully (generation runs and the file renders on publish, only
the shared in-progress indicator is dormant).
Generated-By: PostHog Code
Task-Id: 8b4fb28f-6761-49c4-9b2f-dc62f2305ca2
|
React Doctor could not complete this scan.
Reviewed by React Doctor for commit |
Prompt To Fix All With AIFix the following 2 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 2
packages/core/src/editor/prompt-builder.test.ts:7-11
The null/empty cases for both `buildChannelContextText` and `buildChannelContextBlock` are tested with multiple assertions inside a single `it` block. The team rule is to always prefer parameterised tests (`it.each`), which would also give a clear label per failing input if one regresses.
```suggestion
describe("buildChannelContextText", () => {
it.each([
[undefined],
[" \n "],
] as const)("returns null for empty or whitespace content (%s)", (input) => {
expect(buildChannelContextText(input)).toBeNull();
});
```
### Issue 2 of 2
packages/core/src/editor/prompt-builder.test.ts:29-35
Same pattern — four inputs collapsed into one `it` block. Each would be a separate row in an `it.each` table, making it immediately obvious which specific input fails.
```suggestion
describe("buildChannelContextBlock", () => {
it.each([
[undefined],
[null],
[""],
[" \n "],
] as const)("returns null for empty or whitespace content (%s)", (input) => {
expect(buildChannelContextBlock(input)).toBeNull();
});
```
Reviews (1): Last reviewed commit: "feat(canvas): cloud support for channel ..." | Re-trigger Greptile |
| describe("buildChannelContextText", () => { | ||
| it("returns null for empty or whitespace content", () => { | ||
| expect(buildChannelContextText(undefined)).toBeNull(); | ||
| expect(buildChannelContextText(" \n ")).toBeNull(); | ||
| }); |
There was a problem hiding this comment.
The null/empty cases for both
buildChannelContextText and buildChannelContextBlock are tested with multiple assertions inside a single it block. The team rule is to always prefer parameterised tests (it.each), which would also give a clear label per failing input if one regresses.
| describe("buildChannelContextText", () => { | |
| it("returns null for empty or whitespace content", () => { | |
| expect(buildChannelContextText(undefined)).toBeNull(); | |
| expect(buildChannelContextText(" \n ")).toBeNull(); | |
| }); | |
| describe("buildChannelContextText", () => { | |
| it.each([ | |
| [undefined], | |
| [" \n "], | |
| ] as const)("returns null for empty or whitespace content (%s)", (input) => { | |
| expect(buildChannelContextText(input)).toBeNull(); | |
| }); |
Context Used: Do not attempt to comment on incorrect alphabetica... (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/core/src/editor/prompt-builder.test.ts
Line: 7-11
Comment:
The null/empty cases for both `buildChannelContextText` and `buildChannelContextBlock` are tested with multiple assertions inside a single `it` block. The team rule is to always prefer parameterised tests (`it.each`), which would also give a clear label per failing input if one regresses.
```suggestion
describe("buildChannelContextText", () => {
it.each([
[undefined],
[" \n "],
] as const)("returns null for empty or whitespace content (%s)", (input) => {
expect(buildChannelContextText(input)).toBeNull();
});
```
**Context Used:** Do not attempt to comment on incorrect alphabetica... ([source](https://app.greptile.com/review/custom-context?memory=instruction-0))
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| describe("buildChannelContextBlock", () => { | ||
| it("returns null for empty or whitespace content", () => { | ||
| expect(buildChannelContextBlock(undefined)).toBeNull(); | ||
| expect(buildChannelContextBlock(null)).toBeNull(); | ||
| expect(buildChannelContextBlock("")).toBeNull(); | ||
| expect(buildChannelContextBlock(" \n ")).toBeNull(); | ||
| }); |
There was a problem hiding this comment.
Same pattern — four inputs collapsed into one
it block. Each would be a separate row in an it.each table, making it immediately obvious which specific input fails.
| describe("buildChannelContextBlock", () => { | |
| it("returns null for empty or whitespace content", () => { | |
| expect(buildChannelContextBlock(undefined)).toBeNull(); | |
| expect(buildChannelContextBlock(null)).toBeNull(); | |
| expect(buildChannelContextBlock("")).toBeNull(); | |
| expect(buildChannelContextBlock(" \n ")).toBeNull(); | |
| }); | |
| describe("buildChannelContextBlock", () => { | |
| it.each([ | |
| [undefined], | |
| [null], | |
| [""], | |
| [" \n "], | |
| ] as const)("returns null for empty or whitespace content (%s)", (input) => { | |
| expect(buildChannelContextBlock(input)).toBeNull(); | |
| }); |
Context Used: Do not attempt to comment on incorrect alphabetica... (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/core/src/editor/prompt-builder.test.ts
Line: 29-35
Comment:
Same pattern — four inputs collapsed into one `it` block. Each would be a separate row in an `it.each` table, making it immediately obvious which specific input fails.
```suggestion
describe("buildChannelContextBlock", () => {
it.each([
[undefined],
[null],
[""],
[" \n "],
] as const)("returns null for empty or whitespace content (%s)", (input) => {
expect(buildChannelContextBlock(input)).toBeNull();
});
```
**Context Used:** Do not attempt to comment on incorrect alphabetica... ([source](https://app.greptile.com/review/custom-context?memory=instruction-0))
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
What
Builds out the per-channel
CONTEXT.md(folder instructions) feature across three areas, for both local and cloud runs:1. Generate CONTEXT.md with an agent
FolderPicker/GitHubRepoPicker+useUserRepositoryIntegration).desktop-file-system-instructions-partial-update).cloudStatus/latest_run.status, local live session).2. Channel CONTEXT.md injected into task prompts
Using: #channel CONTEXT.mdchip (dismiss drops it from the prompt).3. Conversation rendering
<channel_context>block renders as a clickable#channel CONTEXT.mdtag instead of inline text; clicking opens the exact snapshot that was sent as a real file tab in the split (a newcontextpanel-tab type), not a live re-fetch.Shared, server-side generation tracking
electronStorage. New api-clientget/setDesktopFolderGenerationTask+useFolderGenerationTaskhook.The shared generation indicator depends on new endpoints that must be added in the PostHog cloud repo:
plus auto-clear of the association when a new folder-instructions version is published.
Until that lands, the client no-ops gracefully: generation still runs and the file still renders on publish — only the project-shared in-progress indicator is dormant. (Everything else in this PR works without backend changes.)
Testing
pnpm typecheck(22/22),pnpm lint,node scripts/check-host-boundaries.mjs— all green.prompt-builder.test.ts(channel-context block/text),channelContext.test.ts(conversation tag parser).Created with PostHog Code