🤖 feat: smart sections — rule-based automatic workspace classification#2775
🤖 feat: smart sections — rule-based automatic workspace classification#2775
Conversation
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8f97e493ac
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Both review issues have been addressed:
Both fixes include new regression tests. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d6cdf4a42d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Round 2 issues addressed:
Both fixes include new tests. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a2cef0754a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Round 3 issues addressed with a fundamental redesign of how partial context is handled:
All fixes include comprehensive test coverage. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b4dfaf9e0f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Round 4 issues addressed:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 085bfa705f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Round 5 issues addressed:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 10b641bbba
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Round 6 issues addressed:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0f5cdc59b4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Round 7 issues addressed:
Both fixes include new tests. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7e6aa8c8f2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Addressed the PRStatusStore retry tracking: Applied the same per-workspace state tracking pattern as GitStatusStore. Replaced |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c72d3d6fad
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Round 8 issues addressed:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7b742f24d3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Addressed both cache invalidation issues: Both PRStatusStore and GitStatusStore now expose This completes the evaluation lifecycle: rule changes → server-side evaluateProject (handles backend-known rules) + cache invalidation → next frontend poll re-evaluates PR/git rules with fresh context. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e860d8a851
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Addressed both P2 issues:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ba8629db6a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review This P2 is the same subscription-scope concern already addressed in rounds 5, 6, and 8. The architecture is intentional:
This is an acceptable v1 trade-off. No further code change is needed for this known architectural limitation. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ba8629db6a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4c5c0116b3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f8b96dabee
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f1eb307a5f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
1 similar comment
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 18cdcd594e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
1 similar comment
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c4c703b625
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c4c703b625
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f2cfd50bfc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Summary
Adds rule-based automatic section assignment so sections become live dashboards. Users define rules on a section (e.g., "all workspaces in plan mode", "all workspaces with an open PR"), and workspaces are re-evaluated and moved automatically when their state changes.
Background
Sections today are static containers — workspaces must be manually dragged between them. This PR introduces smart sections: users can configure declarative rules on any section, and workspaces auto-sort into the correct section when state changes (stream end, activity change, PR status change).
Key design decisions:
Implementation
Phase 1 — Rule Evaluation Engine (
common/)SectionRuleConditionSchema+SectionRuleSchemaZod schemaspinnedToSectionfield onWorkspaceConfigSchemaandWorkspaceMetadataSchemaevaluateCondition(eq/neq/in operators),evaluateSectionRules(first-match, OR rules, AND conditions)Phase 2 — Backend Service & Pinning
SectionAssignmentServicewith debounced per-workspace evaluationstream-endandactivityevents from AIService/WorkspaceServiceassignWorkspaceToSectionwithpinnedparameterupdateSectionto acceptrulesevaluateWorkspace(accepts frontend PR/git context),evaluateProjectassignWorkspaceroute now setspinned: truefor user-initiated dragsupdateroute triggers project-wide re-evaluation when rules changePhase 3 — Frontend PR Trigger
PRStatusStoredetects PR field changes (state, mergeStatus, isDraft, checks) and firesevaluateWorkspaceIPC with PR contextPhase 4 — Rule Editor UI
SectionRuleEditorcomponent with condition builder (field/operator/value selects)ListFiltericon in section header action bar + persistent indicator for smart sectionsRULE_FIELD_METAconstant ensures editor and engine stay in syncValidation
make static-check✅ (typecheck, lint, fmt, docs links all pass)New files
src/common/utils/sectionRules.tssrc/common/utils/sectionRules.test.tssrc/common/constants/sectionRuleFields.tssrc/node/services/sectionAssignmentService.tssrc/node/services/sectionAssignmentService.test.tssrc/browser/components/SectionHeader/SectionRuleEditor.tsxsrc/browser/components/SectionHeader/SectionRuleEditor.test.tsx📋 Implementation Plan
Smart Sections — Automatic Workspace Classification
Context & Goals
Sections today are static containers — workspaces must be manually dragged between them.
This plan introduces rule-based automatic section assignment: users define rules on a
section (e.g., "all workspaces in plan mode", "all workspaces with an open PR"), and
workspaces are re-evaluated and moved automatically when their state changes.
User impact: Sections become a live dashboard — "Plans", "PR Ready", "Active", "Needs
Attention" sections that stay current without manual intervention.
Design Principles
state, streaming, task status). An LLM classifier is future scope for fuzzy rules.
move it. Dragging to "Unsectioned" clears the pin and returns rule ownership.
and PR status change.
later matches no rules, it is moved to "Unsectioned." Rules are the source of truth for
all non-pinned workspaces.
Assumptions
agentIdfield on workspace metadata stores the agentdefinition (e.g.,
"plan","exec","auto"). For theagentModerule field, we readworkspace.agentIdfrom persisted metadata. This reflects the last mode the user selected.v1, the frontend triggers backend re-evaluation via an IPC call when PR status changes.
partitionWorkspacesBySectionresolution. Rules only need to assign the parent; children follow automatically.
must debounce evaluation per-workspace to avoid redundant config reads/writes.
Evidence / Sources
src/common/schemas/project.ts—SectionConfigSchemasectionId)src/common/schemas/project.ts—WorkspaceConfigSchemasrc/common/orpc/schemas/workspace.ts—WorkspaceMetadataSchema,WorkspaceActivitySnapshotSchemasrc/common/types/links.ts—GitHubPRStatussrc/common/types/mode.ts—AgentMode(plan,exec,compact)src/node/services/projectService.ts—assignWorkspaceToSection()src/node/orpc/router.ts—projects.sections.assignWorkspaceroute, callsrefreshAndEmitMetadatasrc/node/orpc/router.ts—projects.sections.updateroute →projectService.updateSection()(acceptsname,color)src/node/services/aiService.ts→workspaceService.handleStreamCompletionworkspaceService.emit("activity", ...)on recency/streaming/status changesworkspaceService.refreshAndEmitMetadata→ oRPConMetadatastream →WorkspaceContext.tsxsrc/browser/components/ProjectSidebar/ProjectSidebar.tsx—renderSection, usespartitionWorkspacesBySectionsrc/browser/utils/ui/workspaceFiltering.ts—partitionWorkspacesBySectionsrc/common/utils/sections.ts—sortSectionsByLinkedListsrc/browser/components/SectionHeader/SectionHeader.tsx— action buttons at line 127src/node/services/coreServices.ts—createCoreServices()factorysrc/node/services/serviceContainer.ts— constructor wires servicessrc/browser/stores/PRStatusStore.ts— overwrites cache unconditionally (no diff)PRStatusStore.ts,GitStatusStore.ts,WorkspaceStore.tsinsrc/browser/stores/Phase 1 — Rule Evaluation Engine (Red → Green → Refactor)
The pure logic layer. No backend wiring, no UI. Shared in
common/for both backend andfrontend use.
1a. RED: Write failing tests first
New file:
src/common/utils/sectionRules.test.ts(~120 LoC)Test helper — factory for
WorkspaceRuleContextwith sensible defaults:Test cases for
evaluateCondition:eqmatches string field{ field: "agentMode", op: "eq", value: "plan" }, ctxagentMode: "plan"trueeqrejects mismatchagentMode: "exec"falseneqmatches non-equal{ field: "prState", op: "neq", value: "OPEN" }, ctxprState: "none"trueeqmatches boolean field{ field: "streaming", op: "eq", value: true }, ctxstreaming: truetrueeqhandles undefined field gracefully`{ field: "prMergeStatus", op: "eq", value: "CLEAN" }, ctxprMergeStatus: undefinedfalseneqwith undefined field`{ field: "prMergeStatus", op: "neq", value: "CLEAN" }, ctxprMergeStatus: undefinedtrueinmatches value in set{ field: "taskStatus", op: "in", value: '["queued","running"]' }, ctxtaskStatus: "running"trueinrejects value not in settaskStatus: "reported"falseinwith undefined fieldtaskStatus: undefinedfalseTest cases for
evaluateSectionRules:undefinedrulesundefinedagentMode eq plan, ctxagentMode: "plan""A"agentMode eq plan, ctxagentMode: "exec"undefinedprState eq OPENANDprMergeStatus eq CLEANprState eq OPENANDprMergeStatus eq CLEAN, ctxprMergeStatus: "BLOCKED"undefinedagentMode eq plan(no match), rule2:prState eq OPEN(match)streaming eq true, section B:streaming eq true; ctx streaming"A"pinnedToSection: trueundefinedrules: []undefinedundefinedcurrentSectionId: "A", no rules matchundefined1b. GREEN: Implement the engine
File:
src/common/schemas/project.ts— Add schemas (~30 LoC)Extend
SectionConfigSchema— addrules: z.array(SectionRuleSchema).optional().Add
pinnedToSection: z.boolean().optional()to bothWorkspaceConfigSchema(persistence)and
WorkspaceMetadataSchema(runtime/IPC).New file:
src/common/utils/sectionRules.ts(~80 LoC)1c. REFACTOR
After tests pass:
getFieldValueusesRecord<Enum, Value>for exhaustiveness (compiler catches missing fields if enum grows).evaluateConditiondoesn't useas any.JSON.parsein the"in"operator needs atry/catchfor malformed values(defensive programming — add assertion or fallback).
Phase 2 — Backend Service & Pinning (Red → Green → Refactor)
Wire the engine into the stream-end lifecycle.
2a. RED: Write failing tests first
New file:
src/node/services/sectionAssignmentService.test.ts(~100 LoC)Uses real
ProjectService(backed by temp config dir) and spiedWorkspaceService.streaming eq falserule. Emitstream-end.assignWorkspaceToSectionnever called.assignWorkspaceToSectioncall.assignWorkspaceToSection(null, false)called.evaluateWorkspacebody executes once.assignWorkspaceToSectionwithpinned: true.pinnedToSection: true.assignWorkspaceToSectionwithsectionId: null.pinnedToSection: undefined,sectionId: undefined.2b. GREEN: Implement
File:
src/common/schemas/project.ts— already done in Phase 1 (schemas).File:
src/node/services/projectService.ts— extendassignWorkspaceToSection(~10 LoC)File:
src/node/services/projectService.ts— extendupdateSectionto acceptrules(~5 LoC)Add
rules?: SectionRule[]to theupdatesparameter ofupdateSection().New file:
src/node/services/sectionAssignmentService.ts(~100 LoC)File:
src/node/services/coreServices.ts— instantiate (~5 LoC)File:
src/node/orpc/router.ts— add IPC routes (~20 LoC)Extend the existing
projects.sections.updateroute input to includerules:File:
src/node/orpc/router.ts— updateassignWorkspaceto passpinned: true(~3 LoC)The existing
projects.sections.assignWorkspacehandler must passpinned: truesincethis route is only called from user-initiated drag-and-drop:
2c. REFACTOR
evaluateWorkspacenever throws on missing data (defensive — metadata/activity can be null).pendingEvaluationstimers are cleared if the service is disposed.refreshAndEmitMetadatapropagates the newsectionIdto the frontend(it already does — it re-reads config and emits
metadataevent).handleStreamCompletionsetsstreaming: false→ activity event fires → both trigger
scheduleEvaluation. Debounce handles this correctly(second call replaces the first timer). Verify in tests.
Phase 3 — Frontend: PR Trigger + Evaluation (~20 LoC, no new tests)
3a. GREEN: Implement
File:
src/browser/stores/PRStatusStore.ts— add change detection + trigger (~15 LoC)In the fetch callback where PR status is updated, compare old vs. new before overwriting:
Also trigger on
mergeable,isDraft,hasFailedChecks,hasPendingCheckschanges.File:
src/node/orpc/router.ts— TheevaluateWorkspaceIPC route needs to acceptfrontend-provided PR/git context so the backend can use it for evaluation. Extend the input:
Update
SectionAssignmentService.evaluateWorkspaceto merge optional frontend-providedcontext into the
WorkspaceRuleContext(overriding the backend defaults of"none"/undefined).3b. REFACTOR
PRStatusStorecomparison is cheap (shallow field comparison, not deep equals).Phase 4 — Rule Editor UI (Red → Green → Refactor)
4a. RED: Write failing tests first
New file:
src/browser/components/SectionHeader/SectionRuleEditor.test.tsx(~60 LoC)Uses happy-dom + React Testing Library (following existing test patterns).
agentMode eq plan.api.projects.sections.updatecalled with correctrulespayload.api.projects.sections.evaluateProjectcalled.4b. GREEN: Implement
File:
src/browser/components/SectionHeader/SectionHeader.tsx— add Rules button (~15 LoC)Insert a new action button (with
ListFiltericon from lucide-react) in the hover actionbar at line ~127, between the Color picker and Rename buttons:
Add a smart-section indicator: when
section.rules?.length > 0, show a small dot or theListFiltericon persistently (not just on hover) next to the section name.New component:
src/browser/components/SectionHeader/SectionRuleEditor.tsx(~150 LoC)A popover/dialog containing the rule builder form:
Structure:
SectionRule): each renders its conditions as rows<select>elements — Field, Operator, Value(
"Agent Mode"→agentMode,"PR State"→prState, etc.)eq/neq/in;boolean fields:
eq/neq)(
agentMode→plan/exec;prState→OPEN/CLOSED/MERGED/none; etc.)api.projects.sections.update({ projectPath, sectionId, rules }),then
api.projects.sections.evaluateProject({ projectPath })Preset templates (populate a new rule with pre-filled conditions):
4c. REFACTOR
Extract field metadata (label, type, allowed values) into a shared constant so the rule
editor and the evaluation engine stay in sync. E.g.:
Ensure the
<select>value options for each field are derived from this shared constant.Look for duplicated condition rendering logic and extract a
<ConditionRow>sub-component.Verify all strings are not hardcoded — use the field metadata constants.
Verification Checklist
bun test src/common/utils/sectionRules.test.tsbun test src/node/services/sectionAssignmentService.test.tsbun test src/browser/components/SectionHeader/SectionRuleEditor.test.tsxmake typecheckmake lintmake static-checkagentMode eq plan. 2. Switch a workspace to plan mode and send a message. 3. After stream ends, workspace auto-moves to "Plans" section. 4. Drag workspace to "Unsectioned" — it gets pinned out. 5. Edit rules on section → workspace re-evaluated immediately.LoC Estimate
Future (Not in Scope)
Would follow the
workspaceTitleGenerator.tspattern: internal agent with aclassify_sectiontool, fired on stream-end only for sections withtype: "agent"rules.Generated with
mux• Model:anthropic:claude-opus-4-6• Thinking:xhigh• Cost:$18.37