feat: Plannr Platform — Planner, Ideation, Forge, Mull, Cultivate, Portfolio-Core, Tend#4
Open
feat: Plannr Platform — Planner, Ideation, Forge, Mull, Cultivate, Portfolio-Core, Tend#4
Conversation
- Update issue link from jahala/plannr to AgentWorkforce/planner - Replace local paths with GitHub URLs in feature docs Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update issue link from jahala/plannr to AgentWorkforce/planner - Replace local paths with GitHub URLs in feature docs Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
a9c0329 to
9df3096
Compare
jahala
added a commit
that referenced
this pull request
Jan 31, 2026
Implement ui-editor-multiscope and ui-plan-create-import features
- Database is automatically seeded with "Planner v1" initiative on first startup - Contains 69 plans from docs/flow (the plans used to build Planner itself) - Migration script updated to use default org for API compatibility - README updated to document auto-seeding behavior Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add three view modes for /plans: table, sectioned (collapsible scopes), and cards - Display plan context/description in card view - Move status badge from card header to footer (right-aligned) - Add context field to PlanSummary type and API response - Create SectionedPlanTable with collapsible scope sections (Linear-style) - Create PlanTable for simple table view - Add new components: AgentActivityDot, ProgressBar, QuestionsBadge - Set pipeline page default to board (kanban) view - Swap pipeline toggle order: board first, then sequence - Remove dead code: PlansViewModeToggle.tsx, ScopeGroup.tsx - Add TableIcon for sectioned view toggle Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Switch from queryMessages to getInbox with channel filter, add chronological sorting so messages appear oldest-first in chat. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add pendingJoinsRef to track in-flight joins before server confirms. Reset channel state on disconnect since server forgets membership. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change PlannerLead agentId from 'planner-core' to 'planner-lead'.
The relay connection name ('planner-core') is transport, the agent
identity ('planner-lead') is for UI display and question matching.
- Add explicit agent identity to system prompt
- Update agents endpoint to include registry agents connected through planner-core
- Exclude planner-core itself from agent list (it's just the connection)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Refactor to use fixed positioning with spacers, matching the left sidebar pattern. Prevents layout shift and z-index issues. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix overflow handling in Layout and ChannelPage - Adjust heights for consistency (ChannelHeader h-12) - Style Select component to match design system - Reduce dependency curve offsets to stay in bounds - Remove redundant back link from PlanBreadcrumb - Remove extra padding/borders from decision components Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Route /plans/:planId/decisions to PlanEditorPage instead of separate DecisionLogPage. Add tab switching, decision filtering, and detail sheet within the unified plan view. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add InitiativeSelect dropdown to filter plans by initiative alongside status filter. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace modal-based AI chat with channel-based messaging sidebar. These components are superseded by MessagingSidebar and relay channels. Removed: - ChatPanel.tsx - modal chat panel - ChatMessage.tsx - individual message component - AIConnectionBadge.tsx - connection status indicator - useAIChat.ts - chat state management hook Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Broadcast answered questions to plan channels for agent visibility.
When a question is answered, the Q&A pair is sent to #plan-{id} so
other agents can see human decisions without re-asking.
- QAMessageCard: Display component for Q&A messages in channel
- qa-message.ts: Type definitions for QA message payloads
- questions handler: Broadcast Q&A on answer submission
- Added tests for QA message rendering and API
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enable users to send direct messages to specific agents from the messaging sidebar. Includes agent selector dropdown and DM channel management. Features: - useDmChannel hook for DM channel state management - ChannelHeader with agent selector for initiating DMs - ChannelList with DM channel display - UserIcon component for user avatars - Backend DM channel creation and routing - Comprehensive test coverage for DM flows Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add MessagingSidebar to the main Layout component with persistent collapsed state. Update channel APIs and hooks for global availability. Changes: - Layout.tsx: Add MessagingSidebar with localStorage persistence - API client: Add DM channel creation endpoint - channels handler: Enhanced channel listing and DM support - useActiveChannels/useChannels: Support DM channel filtering - MessageStream: QA message type handling - PlannerLead: Updated message handling Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Improve consistency between idle, hover, and edit states for inline editable fields. Fix layout shift when entering edit mode. Changes: - EditableText: Consistent hover outline, cyan bottom border in edit - EditableTextarea: Add display:block to fix 6.5px height shift caused by inline-block baseline alignment. Use cyan tint background and bottom border only. Auto-resize to content height. - StepEditor: Updated for new editable styling - PlanEditorPage: Use EditableTextarea for title field, remove old chat panel references Styling: - Idle: No visible border, natural text - Hover: 1px dashed cyan outline, cursor-text - Edit: 10% cyan tint background, 2px solid cyan bottom border Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document schema-related features for the flow system including specifications, API endpoints, DB migrations, MCP tools, and UI. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use consistent 8-character prefix for plan channel IDs everywhere.
The channel format is `#plan-{planId.slice(0,8)}`, not full UUID.
Fixed:
- questions.ts: Use getPlanChannelId() for QA broadcast
- mcp/tools: Use getPlanChannelId() for agent channel join
- client.ts: Use 8-char prefix for agent pre-join
- Updated test to expect correct channel format
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Plan channel ID format:
- Changed getPlanChannelId() to return #plan-{full-uuid}
- Updated all code to use getPlanChannelId() instead of manual construction
- Display truncation now happens in UI layer, not channel IDs
- Updated documentation in .claude/rules/agent-relay.md
Test seeding fix:
- Added skipSeed option to SqliteStorage constructor
- Tests now use { skipSeed: true } to prevent seed data interference
- Fixes test failures caused by seed data being present
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Updates tests to match current component implementations: - App.test.tsx: Add RelayProvider/useRelay mocks, ResizeObserver mock, MessagingSidebar mock, fix brand text assertion - plans.test.ts: Update listPlans calls to use object params format - Pipeline tests (BoardColumn, BoardView, SequenceView, WaveColumn): Fix CSS class selectors to match flex-1 min-w-0 layout pattern - PlansToolbar.test.tsx: Use exact string matches for view mode toggles to avoid regex ambiguity, fix Radix ToggleGroup role="radio" - InitiativesListPage.test.tsx: Fix ToggleGroup role from button to radio, update aria-labels, use invalidateInitiatives for refresh assertion - InitiativeDetailPage.test.tsx: Fix empty state text to match component - PlanEditorPage.test.tsx: Fix workflow status assertions, check published and ready-for-orchestrator text separately - IconPicker.test.tsx: Fix grid to flex-wrap class selector - Various tests: Add proper mocks for hooks and context providers All 692 tests now passing across 37 test files. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Complete feature planning for the ideation module:
Domain & Architecture:
- Freeform understanding schema: Record<string, Record<string, unknown>>
- Intelligence lives in agent prompts, not Zod schemas
- Three-tier model: Understanding → Context → Specification (all freeform)
Interviewer Agent (ideation-lead):
- Lazy specialist spawning (on-demand, not all 5 at start)
- Pure facilitated conversation (never reveals specialists to user)
- spawn_specialist tool for on-demand specialist creation
Dynamic Specialists (ideation-specialists):
- Prompt templates as suggestions, not requirements
- Freeform observations with no schema validation
- ActiveSpecialist type: { name, agent_id, spawned_at, role_hint? }
Storage & API:
- active_specialists JSONB column for lazy spawning tracking
- updateUnderstanding with freeform specialist observations
- Session stays active after sending to planner
UI (specialists-panel):
- Dynamic specialist cards (not fixed 5)
- Icon mapping based on role_hint or name matching
- Confidence extraction from freeform observations
Includes:
- 12 ideation feature files with implementation plans
- 80 tasks exported to docs/tasks-temp.md
- Initial packages/ideation structure with storage layer
- Related schema-* and UI feature files
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- types.ts: SessionStatus (active/abandoned), TranscriptRole (user/assistant) - understanding.ts: Freeform Understanding schema Record<string, Record<string, unknown>> Part of ideation-package epic - implements dom001 and dom002. https://claude.ai/code/session_01DYeuwomvGfp1VXSiTqrqWb
Domain model tasks #83-#91 complete: - types.ts: SessionStatus (active/abandoned), TranscriptRole (user/assistant) - understanding.ts: Freeform Record<string, Record<string, unknown>> - transcript.ts: TranscriptMessage (user+assistant only) - planner-send.ts: PlannerSend with payload and result - active-specialist.ts: ActiveSpecialist for lazy spawning - session.ts: Full Session entity - confidence.ts: Aggregate confidence computation - index.ts: Export all types Key decisions: - No Nugget entity (understanding is live state) - No fixed specialist roles (dynamic spawning) - Sessions stay active after sending to planner https://claude.ai/code/session_01DYeuwomvGfp1VXSiTqrqWb
Storage tasks #96-#105 complete: - interface.ts: Simplified interface (no Nugget operations) - sqlite.ts: Full implementation with JSON functions for efficient updates - appendTranscript: uses json_insert for efficient array append - updateUnderstanding: uses json_set for per-specialist updates - appendPlannerSend: captures full payload snapshot - sqlite.test.ts: 16 passing tests covering all operations https://claude.ai/code/session_01DYeuwomvGfp1VXSiTqrqWb
API tasks #110-#119 complete: - schemas.ts: Request/response validation schemas - events.ts: Event emitter for SSE pub/sub - handlers.ts: All endpoint handlers - routes.ts: Express router setup - api.test.ts: 18 passing API tests Endpoints: - POST /sessions - create session - GET /sessions - list sessions (with status/initiative filter) - GET /sessions/:id - get session - POST /sessions/:id/abandon - abandon session - POST /sessions/:id/messages - add transcript message - PUT /sessions/:id/understanding - update specialist observations - POST /sessions/:id/send-to-planner - send to planner (mock) - GET /sessions/:id/confidence - get aggregate confidence - GET /sessions/:id/events - SSE subscription https://claude.ai/code/session_01DYeuwomvGfp1VXSiTqrqWb
Implements the Interviewer service - the lead agent for ideation sessions. Features: - Interviewer config with channel routing and LLM settings - System prompt as Brainstorming Facilitator (invisible specialists) - Anthropic tools for session management and specialist spawning - Tool executor with mock mode for testing without API key - Conversation history per channel for LLM context - Specialist input queue for weaving insights into conversation - Full service with message handling and response generation - 46 tests covering config, prompt, tools, history, queue, service https://claude.ai/code/session_01DYeuwomvGfp1VXSiTqrqWb
…ltivateConfig, CultivateOutcome, and Recommendation Zod schemas
…awEvent, NormalizedEvent, ExtractionResult)
…down into graceful shutdown handler - Move cultivate.shutdown() before HTTP server close to allow in-flight requests to complete - Add error handling with logging that doesn't block other service shutdowns - Shutdown is called on both SIGTERM and SIGINT signals
…hConfig, SourcePreset, FilterRule, and IngestionJob schemas
…erences for cultivate dependency - Reorder root tsconfig references: move cultivate before server for proper build ordering - Add references to server/tsconfig.json for composite project dependencies (cultivate, planner, ideation, forge-core, mull) - Update cultivate/tsconfig.json to extend tsconfig.node.json for composite build support This ensures cultivate is built before server in the monorepo, and TypeScript can properly resolve the @plannr/cultivate import in the server package. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…hecks to dev.sh and document CULTIVATE_REDIS_URL
…primitive types - all schemas correct (SignalStatus, GreenhouseMode, ClusterTrend, AdapterType, AuthorType, AuthType, FilterRuleType, IngestionJobStatus, SourceHealth, ScoringFactors with 8 fields 0-1)
…e, and Cluster types - Added StepProvenanceSchema for pipeline stage tracking - Added SignalSchema with all required fields and optional cluster_id, url, linked_plan_id - Added GreenhouseSchema with GreenhouseMode enum validation - Added ClusterSchema with ClusterTrend enum validation All schemas follow Zod validation patterns and include TypeScript type inference.
Consolidates all forge agent work done after auckland's .git was accidentally reinitialized by a rogue haiku agent (session 62bc8c85). Original standalone commits: 669e603..eb8a778 (90 commits) Includes: cultivate filter rules, dedup, clustering, scoring, source presets, forge-ui 404 fixes, dev.sh reliability fixes.
- New scoring package: factors, weights, score computation with tests - Add createCluster() for cluster lifecycle management - Add ML model-loader for embedding model initialization - Evolve SourcePreset with InputField schema for adapter configuration - Fix extract.ts import path Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Persist execution_policy in runs table (schema, converter, CRUD) - Add execution_policy override to CreateRunRequest API schema - Auto-detect master runs (all tasks have sub_plan_id) and relax parallelism constraints since master tasks don't edit files - Add RunService.updateParallelism() for post-load config changes - Lower default max_concurrent_tasks from 5 to 3 - Add domain type tests and task-queue tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The SDK spawn() signature is spawn(options, timeoutMs?). Passing timeoutMs inside the options object was silently ignored. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ma already implemented with all required fields
… (reddit, hackernews, twitter, RSS, web)
… (support tickets, surveys, interviews) Create three factory functions for highest-authority source presets: - createSupportTicketPreset() - poll_api, authority 0.85 - createSurveyPreset() - structured_pull, authority 0.90 - createInterviewPreset() - push, authority 0.95 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…luster isolation invariant Add storage-level constraints and query filters to ensure clusters never span Greenhouses: **Database Schema Changes:** - Added FOREIGN KEY constraint on clusters.greenhouse_id → greenhouses.id with CASCADE delete - Added UNIQUE(greenhouse_id, label) composite constraint to prevent duplicate cluster labels - greenhouse_id remains NOT NULL to guarantee every cluster belongs to a greenhouse **Storage Layer Enhancements:** - Added getClusterByIdAndGreenhouse(id, greenhouse_id) method for greenhouse-safe cluster access - Marked getClusterById() as @deprecated; consumers should use the new method - Both methods properly filter by greenhouse_id in WHERE clauses **Application Layer Validation:** - Updated assignCluster() with multi-layer Greenhouse isolation validation: 1. Validate cluster exists in greenhouse-filtered list (listClustersByGreenhouse) 2. Double-check by fetching cluster via getClusterByIdAndGreenhouse() 3. Assert greenhouse_id matches expected value (defensive programming) - Errors propagate as SignalProcessingError for proper BullMQ handling **Tests:** - Added comprehensive isolation.test.ts verifying: - Storage-level NOT NULL and FOREIGN KEY constraints - UNIQUE(greenhouse_id, label) constraint prevents duplicate labels - Query-level isolation in listClustersByGreenhouse and getClusterByLabel - Greenhouse isolation invariant: cluster_id never spans Greenhouses - CASCADE delete removes all clusters when greenhouse is deleted Acceptance Criteria Met: ✓ Database constraint preventing cluster_id reuse across Greenhouses (PRIMARY KEY + UNIQUE) ✓ greenhouse_id NOT NULL foreign key in clusters table ✓ All cluster queries include greenhouse_id in WHERE clauses ✓ Assertions in assignCluster() validate Greenhouse matching ✓ Multi-layer validation prevents isolation violations Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…) for new clusters - Fixed tsconfig.node.json required by package tsconfig references - Fixed create.test.ts to properly initialize SqliteCultivateStorage with path string instead of Database instance - All 5 tests for createCluster() now passing - Verified createCluster accepts greenhouseId, name, summary, initialSignalId - Returns new cluster with generated ID, greenhouse association, signal_count=1, and timestamps Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
WorktreeManager.remove() was blindly running destructive git worktree operations on any path passed to it. When a run used the project directory as its workspace (instead of a forge-created worktree), cleanup destroyed the parent repo's worktree metadata and deleted files. Three layers of defense added: 1. WorktreeManager.remove() refuses paths without forge-run-/forge-build- 2. Orchestrator.cleanupWorktree() refuses non-forge paths 3. Orchestrator.mergeWorktreeCommits() skips non-forge paths Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite README to reflect current project state — Tend as primary UI, domain descriptions with actual detail, Cultivate marked WIP, standalone UIs marked legacy. Remove ideation-ui (port 3002) from dev.sh since Tend replaces it. Add runtime data patterns to .gitignore and untrack .mull/realtime/ JSON files and FORGE_INVESTIGATION.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ified) Full cultivate package implementation across 4 dependency layers: - Layer 1: domain types, errors, dedup, extractor, presets, jobs infra - Layer 2: storage, filter rules, auth/encryption, scorer, clusterer, adapters, SSE, startup - Layer 3: pipeline orchestration, tuner client, recommender, decay/trends, ML classifier - Layer 4: REST API (12 endpoints), server mount, service plugin 311 tests passing across 27 test files. Flow audit complete on all 22 features. Two features remain partial: presets (missing Tier 2/5), jobs (poll-sources/ingest-document stubs). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… point) Remove duplicate `conflict` function in @plannr/errors that caused SyntaxError at runtime. Point tuner package.json main to src/index.ts since dist was never built and server runs via tsx. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements cross-domain portfolio intelligence: - New @plannr/portfolio-core package with suggestion engine, health calculator, and scoring system across planner/cultivate/forge domains - 6 REST endpoints: suggestions, overview, health, decisions - Planner domain extended with source tracking, project listing, and initiative queries - Tend dashboard restructured with PortfolioSummary, SuggestionCard, InitiativeTree - Fixed O(N²) query pattern in suggestion engine (pre-fetch + index strategy) - Fixed useInitiatives hook (wrong API path and response parsing) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…hestration Add agent model selection endpoint, session presence tracking, and improved orchestration hooks with specialist agent support. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend: GitService with porcelain v2 status parsing, numstat line stats, commit file listing, mutex-guarded CLI execution, and TTL caching. API endpoints: GET /git/status, /git/log, /git/commits/:hash/files. Frontend: Context-adaptive right panel that shows plan tree when a plan exists, changeset tree otherwise. Changeset tree displays uncommitted changes grouped by package scope (top, scrollable) and recent commits pinned to bottom (independent scroll). Files show status icons using semantic theme tokens and bracketed line stats [+N | -N]. Commits expand inline to show changed files. Polls every 5s with visibility gating; commit log auto-refreshes when file count drops. Components: TreePanel, ChangesetTree, ChangeGroup, CommitSection, CommitNode, FileNode, TreeNodeLayout, TreeModeSwitch, ChangeDetailSheet. Hooks: useWorkingChanges, useCommitLog. Refactored StepNode to share TreeNodeLayout skeleton. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add materialized source_session_id column to plans table, enabling efficient querying of all plans originating from a given ideation session. Migration backfills from json_extract(source_json, '$.session_id'). - Add source_session_id to schema, domain, storage, API filter - Support GET /api/plans?source_session_id=xxx - Rewrite seed data with realistic session-based hierarchy (3 initiatives, 7 plans) - Dynamic updatePlan with priority/value_score support Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enable one session to produce multiple independent plans via new_plan flag on sendToPlanner. Enhance graduate_blocks with target_plan_id to add steps to specific existing plans. AI Interviewer now receives linked plan summaries via read_session and consults user before graduating blocks. - Add new_plan: boolean to SendToPlannerRequestSchema - sendToPlanner: new_plan=true creates independent plan, default versions most recent - graduate_blocks: target_plan_id for explicit plan targeting, defaults to most recent send - read_session: returns linked_plans array with goal/status from planner API - Interviewer prompt: Plan Awareness section with graduation guidelines Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace project-centric navigation with session-first architecture. Sessions are the primary entity; plans materialize from conversation. No mode switching, no phase branching — single layout always. - Add SessionProvider context (fetches session + plans via source_session_id) - Add SessionWorkspace page at /s/:id with SSE for real-time updates - Dashboard: fetch sessions from ideation API, show in initiative tree - InitiativeTree: sessions grouped by initiative, plans nested under sessions - NewConversationModal: simplified from 3-step to single POST - ProjectPage: thin redirect to /s/:sessionId for backward compat Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Complete agentic planning and execution platform with seven backend domains and a unified frontend:
/s/:idrouting, initiative tree, portfolio dashboardInfrastructure
Also includes
Test plan
npm installsucceedsnpm testpasses across all packages./scripts/dev.sh startbrings up backend + UIs/s/:idworkspace🤖 Generated with Claude Code