feat: align studio surfaces and add signals workspace#414
Conversation
…igrate _audit.py - Add EventType class to message_schema.py with 7 new constants (4 lifecycle + 3 tool) and 7 documented existing-type aliases (job_start, insight, etc.) - Create agent_events.py with make_lifecycle_event() and make_tool_call_event() helpers - Migrate _audit.py: replace raw 'error'/'tool_result' strings with EventType constants
- types.ts: 7 exported types mirroring Python EventType vocabulary (AgentStatus, AgentLifecycleEvent, ToolCallEvent, AgentEventEnvelopeRaw, ActivityFeedItem, AgentStatusEntry, ToolCallEntry) - parsers.ts: 3 parser functions (parseActivityItem, parseAgentStatus, parseToolCall) with human summary derivation - store.ts: useAgentEventStore with feed cap at 200, tool timeline cap at 100, per-agent status map - parsers.test.ts: 15 vitest tests covering all parser behavior cases - store.test.ts: 12 vitest tests covering store actions, caps, and status tracking
- Add 08-01-SUMMARY.md for EventType constants and helpers plan - STATE.md: advance position, add 3 decisions, update progress to 93% - ROADMAP.md: mark phase 08 plan 1/2 in-progress - REQUIREMENTS.md: mark EVNT-01, EVNT-02, EVNT-03 complete Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- useAgentEvents.ts: SSE consumer hook connecting to /api/events/stream with 3s reconnect - ActivityFeed.tsx: scrolling event list with color-coded agent/type badges using Radix ScrollArea - AgentStatusPanel.tsx: per-agent status badge grid with idle/working/completed/errored icons (lucide-react) - ToolCallTimeline.tsx: tool call rows showing name, duration, args (collapsed), result summary, error badge - agent-events/page.tsx: test harness page mounting all three components with SSE hook at root - Next.js build: zero type errors or server component violations
- 08-02-SUMMARY.md: documents types/parsers/store/hook/components delivery - STATE.md: advance to plan 2 complete, add Phase 08 P02 decisions - ROADMAP.md: mark both 08-01 and 08-02 plans complete
…store file tracking - Add FileChangeStatus and FileTouchedEntry types to types.ts - Add parseFileTouched() to parsers.ts (handles file_change and write_file tool_result) - Extend useAgentEventStore with filesTouched (dedup+20-run eviction), selectedRunId, selectedFile - 12 new TDD tests (6 parser + 6 store), all 39 tests pass
…hook to parseFileTouched - Add FILE_CHANGE = "file_change" constant to EventType class in message_schema.py - Add test_file_change_event_type() test (8 total, all pass) - Import parseFileTouched in useAgentEvents.ts and dispatch to addFileTouched in for-await loop - Add addFileTouched to useEffect dependency array
- SUMMARY.md: FileTouchedEntry types, parseFileTouched parser, store file tracking - STATE.md: advanced progress, recorded metrics and decisions - ROADMAP.md: phase 09 updated to 1/2 plans complete - REQUIREMENTS.md: DASH-01, FILE-01, FILE-02 marked complete
…atusPanel compact prop - Add optional compact prop to AgentStatusPanel: hides heading/connection indicator, uses grid-cols-1, truncates name to 12 chars - Create TasksPanel with compact AgentStatusPanel + run selector derived from feed - Create FileListPanel with created/modified file icons and run-id filtering - Create InlineDiffPanel wrapping DiffViewer in read-only mode with back navigation
…debar nav link - Create /agent-dashboard page with three-panel layout using SplitPanels (storageKey=agent-dashboard) - Mount useAgentEvents() once at page root for SSE connection - Compose TasksPanel (rail), ActivityFeed (list), FileListPanel (detail) - Add Agent Dashboard nav entry in Sidebar with Monitor icon after DeepCode Studio
- SUMMARY.md: IDE-style three-panel /agent-dashboard with SplitPanels, TasksPanel, FileListPanel, InlineDiffPanel - STATE.md: advance to phase 9/plan 2, record decisions and session - ROADMAP.md: update phase 9 plan progress (2/2 plans complete)
…mary - Updated 09-02-SUMMARY.md: all 3 tasks complete (checkpoint APPROVED) - STATE.md: updated progress, recorded session completion - ROADMAP.md: phase 9 marked Complete (2/2 plans) - Requirements DASH-01, DASH-04, FILE-01, FILE-02 noted complete Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…low stub, and emit helper - Add four codex delegation constant tests to test_agent_events_vocab.py - Create test_codex_overflow.py for _should_overflow_to_codex env var logic - Create test_agent_board_codex_events.py for _emit_codex_event helper
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedToo many files! This PR contains 188 files, which is 38 over the limit of 150. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (188)
You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Tip Flake8 can be used to improve the quality of Python code reviews.Flake8 is a Python linter that wraps PyFlakes, pycodestyle and Ned Batchelder's McCabe script. To configure Flake8, add a '.flake8' or 'setup.cfg' file to your project root. See Flake8 Documentation for more details. |
There was a problem hiding this comment.
Pull request overview
This PR continues the Studio/Dashboard alignment by introducing a Studio Skills surface (discovery + install/update flows), expanding agent event vocabulary (including Codex delegation events), and enriching backend provenance/allowlisting behavior to support the updated UX.
Changes:
- Add Studio skills registry/catalog plumbing + a new FastAPI surface for listing, installing, updating, and fetching skill details.
- Extend agent event vocabulary/helpers and emit Codex delegation lifecycle events; add an env-var-based Codex overflow flag.
- Improve saved-paper payloads with provenance/workflow summary and adjust runbook directory allowlist defaults/mutation behavior.
Reviewed changes
Copilot reviewed 71 out of 189 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_studio_skill_registry.py | Adds unit coverage for skill discovery and ecosystem merging. |
| tests/unit/test_studio_skill_catalog.py | Adds unit coverage for installing/updating/listing installed skill repos (git-backed). |
| tests/unit/test_studio_chat_path_validation.py | Adds tests for model-id mapping and Studio CWD allowlist behavior. |
| tests/unit/test_runbook_project_dir_prepare_route.py | Extends runbook route tests for HOME/Documents defaults and mutation error messaging. |
| tests/unit/test_research_feedback_state.py | Extends feedback tests for provenance/judge summary and adjusts saved-paper shape expectations. |
| tests/unit/test_codex_overflow.py | Adds unit tests for Codex overflow env-var flag parsing. |
| tests/unit/test_api_security_middleware.py | Adds unit test for “full_access” mode flags. |
| tests/unit/test_agent_events_vocab.py | Adds TDD tests for EventType constants + Codex delegation event types. |
| tests/unit/test_agent_board_route.py | Adds tests for creating Studio ad-hoc tasks and latest-session “found=false” payload. |
| tests/unit/test_agent_board_codex_events.py | Adds TDD tests for Codex delegation event emission helper. |
| src/paperbot/repro/orchestrator.py | Implements _should_overflow_to_codex() env-var flag parsing. |
| src/paperbot/mcp/tools/_audit.py | Migrates tool audit event types to EventType constants. |
| src/paperbot/infrastructure/stores/research_store.py | Adds provenance normalization/labels and enriches saved-paper payloads. |
| src/paperbot/application/services/studio_skill_registry.py | Introduces skill discovery/manifest parsing + summary/merge logic. |
| src/paperbot/application/collaboration/message_schema.py | Adds EventType string constants (lifecycle/tool/file/Codex + existing types). |
| src/paperbot/application/collaboration/agent_events.py | Adds helper constructors for lifecycle and tool-call event envelopes. |
| src/paperbot/api/routes/studio_skills.py | Adds Studio Skills API routes for catalog/install/update/detail. |
| src/paperbot/api/routes/runbook.py | Adds HOME/Documents default prefix, refactors normalization, and adds mutation-root checks. |
| src/paperbot/api/routes/harvest.py | Adds metadata to save requests and routes “save” feedback via add_paper_feedback. |
| src/paperbot/api/routes/agent_board.py | Adds Codex event emission helpers, latest-session “found” payload, and Studio task creation endpoint. |
| src/paperbot/api/routes/init.py | Exposes studio_skills router. |
| src/paperbot/api/middleware/auth.py | Adds localhost:3010 to allowed origins. |
| src/paperbot/api/main.py | Registers Studio Skills router. |
| .planning/phases/11-dag-visualization/11-VALIDATION.md | Adds Phase 11 validation strategy doc. |
| .planning/phases/11-dag-visualization/11-01-SUMMARY.md | Adds Phase 11 plan summary doc. |
| .planning/phases/10-agent-board-codex-bridge/10-VALIDATION.md | Adds Phase 10 validation strategy doc. |
| .planning/phases/10-agent-board-codex-bridge/10-03-SUMMARY.md | Adds Phase 10 plan summary doc (Plan 03). |
| .planning/phases/10-agent-board-codex-bridge/10-03-PLAN.md | Adds Phase 10 execution plan doc (Plan 03). |
| .planning/phases/10-agent-board-codex-bridge/10-02-SUMMARY.md | Adds Phase 10 plan summary doc (Plan 02). |
| .planning/phases/10-agent-board-codex-bridge/10-01-SUMMARY.md | Adds Phase 10 plan summary doc (Plan 01). |
| .planning/phases/10-agent-board-codex-bridge/10-01-PLAN.md | Adds Phase 10 execution plan doc (Plan 01). |
| .planning/phases/09-three-panel-dashboard/09-VERIFICATION.md | Adds verification report doc for Phase 09. |
| .planning/phases/09-three-panel-dashboard/09-VALIDATION.md | Adds Phase 09 validation strategy doc. |
| .planning/phases/09-three-panel-dashboard/09-02-SUMMARY.md | Adds Phase 09 plan summary doc (Plan 02). |
| .planning/phases/09-three-panel-dashboard/09-01-SUMMARY.md | Adds Phase 09 plan summary doc (Plan 01). |
| .planning/phases/08-agent-event-vocabulary/08-VERIFICATION.md | Adds verification report doc for Phase 08. |
| .planning/phases/08-agent-event-vocabulary/08-VALIDATION.md | Adds Phase 08 validation strategy doc. |
| .planning/phases/08-agent-event-vocabulary/08-02-SUMMARY.md | Adds Phase 08 plan summary doc (Plan 02). |
| .planning/phases/08-agent-event-vocabulary/08-01-SUMMARY.md | Adds Phase 08 plan summary doc (Plan 01). |
| .planning/phases/08-agent-event-vocabulary/08-01-PLAN.md | Adds Phase 08 execution plan doc (Plan 01). |
| .planning/codebase/TESTING.md | Adds codebase testing patterns doc. |
| .planning/codebase/STACK.md | Adds stack inventory doc. |
| .planning/codebase/INTEGRATIONS.md | Adds integrations inventory doc. |
| .planning/codebase/CONVENTIONS.md | Adds conventions doc. |
| .planning/codebase/ARCHITECTURE.md | Adds architecture doc. |
| .planning/STATE.md | Updates project state (milestone focus + progress). |
| .planning/REQUIREMENTS.md | Updates requirements statuses and adds v1.2 requirements. |
| .planning/PROJECT.md | Updates project framing toward agent-agnostic dashboard + v1.2 milestone. |
| .claude/agents/codex-worker.md | Adds Claude Code sub-agent definition for Codex delegation (JSON-only output contract). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| await _emit_codex_event( | ||
| "codex_dispatched", | ||
| task, | ||
| session, | ||
| {"assignee": task.assignee}, | ||
| ) |
| class CreateTaskRequest(BaseModel): | ||
| title: str | ||
| description: str | ||
| workspace_dir: Optional[str] = None | ||
| assignee: Literal["codex", "opencode"] = "codex" | ||
| tags: List[str] = Field(default_factory=list) |
| try: | ||
| roots.append(Path.home().resolve()) | ||
| except Exception: |
| def _git(cwd: Path, *args: str) -> str: | ||
| result = subprocess.run( | ||
| ["git", *args], | ||
| cwd=str(cwd), | ||
| capture_output=True, | ||
| text=True, | ||
| check=True, | ||
| ) |
| import types | ||
| from typing import Any, List, Optional |
| import paperbot.api.routes.agent_board as ab_mod | ||
|
|
||
| def _fake_container_instance(): | ||
| return fake_container |
| Checks the PAPERBOT_CODEX_OVERFLOW_THRESHOLD environment variable: | ||
| - Unset or empty -> False | ||
| - "1", "true", "yes", "on" (case-insensitive) -> True | ||
| - Any other value -> False |
| - Any other value -> False | ||
|
|
||
| Wraps in try/except so any unexpected error returns False safely. | ||
| """ | ||
| try: | ||
| value = os.getenv("PAPERBOT_CODEX_OVERFLOW_THRESHOLD", "").strip() | ||
| if not value: | ||
| return False | ||
| return value.lower() in {"1", "true", "yes", "on"} |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly advances the PaperBot project's strategic direction by refining the Studio user experience and laying foundational architectural groundwork for a more versatile agent interaction model. It focuses on consolidating existing features, introducing new dedicated workspaces, and updating core planning documents to reflect a shift towards an agent-agnostic dashboard capable of visualizing and controlling various code agents. The changes aim to enhance usability, provide clearer insights into agent activities, and prepare the platform for future multi-agent capabilities. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a significant set of features and refactorings, primarily focused on creating a "signals" workspace and aligning various UI surfaces. Key changes include adding a codex-worker agent, extensive updates to project planning documents, and a major refactoring of the studio chat functionality to support more complex interactions and telemetry. New services for managing "studio skills" have been added, and paper provenance tracking has been enriched.
My review focuses on a few key areas. I've identified a critical performance issue in the new studio_skills API where blocking I/O calls are made from async routes, which could stall the server under load. I've also suggested a refactoring in the research_store to improve the maintainability of the new provenance logic. Overall, the changes are extensive and well-tested, but the blocking I/O issue should be addressed before merging.
| async def studio_skill_install(request: InstallStudioSkillRepoRequest): | ||
| try: | ||
| return install_studio_skill_repo(request.repo_url, repo_ref=request.repo_ref) | ||
| except StudioSkillCatalogError as exc: | ||
| raise HTTPException(status_code=400, detail=str(exc)) from exc | ||
|
|
||
|
|
||
| @router.post("/studio/skills/repos/{repo_slug}/update") | ||
| async def studio_skill_repo_update(repo_slug: str, request: UpdateStudioSkillRepoRequest): | ||
| try: | ||
| return update_studio_skill_repo(repo_slug, repo_ref=request.repo_ref) | ||
| except StudioSkillCatalogError as exc: | ||
| raise HTTPException(status_code=400, detail=str(exc)) from exc |
There was a problem hiding this comment.
The install_studio_skill_repo and update_studio_skill_repo functions are synchronous but perform blocking I/O operations (git commands via subprocess.run). Calling them directly from async FastAPI routes will block the event loop, impacting server performance and responsiveness.
To fix this, the service functions in studio_skill_catalog.py should be converted to async functions, and their blocking _run_git calls should be wrapped with await asyncio.to_thread(). Consequently, you should await the calls here.
| async def studio_skill_install(request: InstallStudioSkillRepoRequest): | |
| try: | |
| return install_studio_skill_repo(request.repo_url, repo_ref=request.repo_ref) | |
| except StudioSkillCatalogError as exc: | |
| raise HTTPException(status_code=400, detail=str(exc)) from exc | |
| @router.post("/studio/skills/repos/{repo_slug}/update") | |
| async def studio_skill_repo_update(repo_slug: str, request: UpdateStudioSkillRepoRequest): | |
| try: | |
| return update_studio_skill_repo(repo_slug, repo_ref=request.repo_ref) | |
| except StudioSkillCatalogError as exc: | |
| raise HTTPException(status_code=400, detail=str(exc)) from exc | |
| @router.post("/studio/skills/install") | |
| async def studio_skill_install(request: InstallStudioSkillRepoRequest): | |
| try: | |
| return await install_studio_skill_repo(request.repo_url, repo_ref=request.repo_ref) | |
| except StudioSkillCatalogError as exc: | |
| raise HTTPException(status_code=400, detail=str(exc)) from exc | |
| @router.post("/studio/skills/repos/{repo_slug}/update") | |
| async def studio_skill_repo_update(repo_slug: str, request: UpdateStudioSkillRepoRequest): | |
| try: | |
| return await update_studio_skill_repo(repo_slug, repo_ref=request.repo_ref) | |
| except StudioSkillCatalogError as exc: | |
| raise HTTPException(status_code=400, detail=str(exc)) from exc |
| primary = _normalize_saved_paper_provenance(metadata.get("import_source")) | ||
| if not primary: | ||
| if metadata.get("context_run_id") is not None or metadata.get("context_rank") is not None: | ||
| primary = "research_context" | ||
| else: | ||
| retrieval_sources = metadata.get("retrieval_sources") | ||
| if isinstance(retrieval_sources, list) and any( | ||
| str(source).strip() for source in retrieval_sources | ||
| ): | ||
| primary = "research_search" | ||
| else: | ||
| anchor_mode = _normalize_saved_paper_provenance(metadata.get("anchor_mode")) | ||
| if anchor_mode in {"personalized", "global"}: | ||
| primary = f"{anchor_mode}_routing" | ||
| else: | ||
| primary = "manual_save" |
There was a problem hiding this comment.
This nested if/else block for determining the primary provenance is becoming complex and hard to follow. As more provenance sources are added, this logic will become even more difficult to maintain.
Consider refactoring this into a more declarative pattern, such as a list of check functions. This would improve readability and make it easier to add or reorder provenance checks in the future.
For example:
def _get_primary_provenance(metadata: dict) -> str:
provenance_checks = [
lambda m: _normalize_saved_paper_provenance(m.get("import_source")),
lambda m: "research_context" if m.get("context_run_id") is not None or m.get("context_rank") is not None else None,
lambda m: "research_search" if isinstance(m.get("retrieval_sources"), list) and any(str(s).strip() for s in m["retrieval_sources"]) else None,
# ... and so on
]
for check in provenance_checks:
if result := check(metadata):
return result
return "manual_save"
# In _build_saved_paper_provenance:
primary = _get_primary_provenance(metadata)There was a problem hiding this comment.
Pull request overview
This PR expands the Studio/agent-dashboard backend capabilities by adding skill catalog endpoints and Codex delegation observability, while tightening/adjusting workspace allowlisting and enriching saved-paper provenance metadata.
Changes:
- Add Studio skills discovery/installation/update API surface and supporting skill registry/service logic.
- Introduce Codex delegation event vocab + emission helpers, plus overflow flag plumbing and new agent-board endpoints/behaviors.
- Enrich research “saved papers” response with provenance/workflow data and adjust runbook allowlist defaults/mutation rules.
Reviewed changes
Copilot reviewed 70 out of 189 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_studio_skill_catalog.py | Adds unit coverage for installing/updating Studio skill repos via local git. |
| tests/unit/test_studio_chat_path_validation.py | Adds tests for model-id mapping and Studio CWD allowlist behavior. |
| tests/unit/test_runbook_project_dir_prepare_route.py | Adds tests for HOME/Documents default allowlist and allowlist mutation rules. |
| tests/unit/test_research_feedback_state.py | Updates saved-papers assertions and adds provenance/workflow summary coverage. |
| tests/unit/test_codex_overflow.py | Adds tests defining _should_overflow_to_codex env-var behavior. |
| tests/unit/test_api_security_middleware.py | Extends tests for full-access code-mode flags. |
| tests/unit/test_agent_events_vocab.py | Adds EventType coverage including Codex delegation constants. |
| tests/unit/test_agent_board_route.py | Extends agent-board route tests for ad-hoc tasks and latest-session semantics. |
| tests/unit/test_agent_board_codex_events.py | Adds tests defining _emit_codex_event behavior. |
| src/paperbot/repro/orchestrator.py | Adds _should_overflow_to_codex env-var based routing stub. |
| src/paperbot/mcp/tools/_audit.py | Switches tool-call audit event types to EventType constants. |
| src/paperbot/infrastructure/stores/research_store.py | Adds saved-paper provenance labeling and track/workflow summary enrichment. |
| src/paperbot/application/services/studio_skill_registry.py | Implements skill discovery + manifest/frontmatter parsing and normalization. |
| src/paperbot/application/collaboration/message_schema.py | Introduces EventType constants including Codex delegation types. |
| src/paperbot/application/collaboration/agent_events.py | Adds helpers to create lifecycle/tool-call event envelopes. |
| src/paperbot/api/routes/studio_skills.py | Adds Studio Skills API routes for catalog/install/update/detail. |
| src/paperbot/api/routes/runbook.py | Adjusts allowlist defaults; refactors path normalization; adds mutation roots. |
| src/paperbot/api/routes/harvest.py | Extends save-paper request with metadata; routes to add_paper_feedback. |
| src/paperbot/api/routes/agent_board.py | Adds Codex delegation event emission helper + task creation + latest-session response change. |
| src/paperbot/api/routes/init.py | Exposes studio_skills routes module. |
| src/paperbot/api/middleware/auth.py | Extends localhost CORS allowlist to include port 3010. |
| src/paperbot/api/main.py | Registers Studio Skills router. |
| .planning/phases/11-dag-visualization/11-VALIDATION.md | Adds Phase 11 validation strategy doc. |
| .planning/phases/11-dag-visualization/11-01-SUMMARY.md | Adds Phase 11 Plan 01 summary. |
| .planning/phases/10-agent-board-codex-bridge/10-VALIDATION.md | Adds Phase 10 validation strategy doc. |
| .planning/phases/10-agent-board-codex-bridge/10-03-SUMMARY.md | Adds Phase 10 Plan 03 summary. |
| .planning/phases/10-agent-board-codex-bridge/10-03-PLAN.md | Adds Phase 10 Plan 03 execution plan. |
| .planning/phases/10-agent-board-codex-bridge/10-02-SUMMARY.md | Adds Phase 10 Plan 02 summary. |
| .planning/phases/10-agent-board-codex-bridge/10-01-SUMMARY.md | Adds Phase 10 Plan 01 summary. |
| .planning/phases/10-agent-board-codex-bridge/10-01-PLAN.md | Adds Phase 10 Plan 01 execution plan. |
| .planning/phases/09-three-panel-dashboard/09-VERIFICATION.md | Adds Phase 09 verification report. |
| .planning/phases/09-three-panel-dashboard/09-VALIDATION.md | Adds Phase 09 validation strategy doc. |
| .planning/phases/09-three-panel-dashboard/09-02-SUMMARY.md | Adds Phase 09 Plan 02 summary. |
| .planning/phases/09-three-panel-dashboard/09-01-SUMMARY.md | Adds Phase 09 Plan 01 summary. |
| .planning/phases/08-agent-event-vocabulary/08-VERIFICATION.md | Adds Phase 08 verification report. |
| .planning/phases/08-agent-event-vocabulary/08-VALIDATION.md | Adds Phase 08 validation strategy doc. |
| .planning/phases/08-agent-event-vocabulary/08-02-SUMMARY.md | Adds Phase 08 Plan 02 summary. |
| .planning/phases/08-agent-event-vocabulary/08-01-SUMMARY.md | Adds Phase 08 Plan 01 summary. |
| .planning/phases/08-agent-event-vocabulary/08-01-PLAN.md | Adds Phase 08 Plan 01 execution plan. |
| .planning/codebase/TESTING.md | Adds documentation of repo testing patterns/conventions. |
| .planning/codebase/STACK.md | Adds documentation of repo technology stack. |
| .planning/codebase/INTEGRATIONS.md | Adds documentation of external integrations. |
| .planning/codebase/CONVENTIONS.md | Adds documentation of coding conventions. |
| .planning/codebase/ARCHITECTURE.md | Adds documentation of system architecture. |
| .planning/STATE.md | Updates project state/milestone metadata. |
| .planning/REQUIREMENTS.md | Updates requirements state and expands v1.2 requirements. |
| .planning/PROJECT.md | Updates project description/milestones to agent-agnostic dashboard direction. |
| .claude/agents/codex-worker.md | Adds Codex worker sub-agent definition and strict JSON output contract. |
Comments suppressed due to low confidence (1)
src/paperbot/api/routes/agent_board.py:496
- This endpoint changes behavior from raising a 404 to returning HTTP 200 with a sentinel payload (
found: False). That’s an API-breaking change for any clients relying on status code semantics for control-flow. If you need the softer contract, consider preserving the previous 404 behavior by default and gating the 200/empty response behind an explicit query param (or a separate endpoint), or document/version the change clearly.
async def get_latest_session(paper_id: Optional[str] = None):
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
src/paperbot/api/routes/runbook.py
Outdated
| def _normalize_path_input(raw_path: str, field_name: str) -> Path: | ||
| raw = raw_path.strip() | ||
| if not raw: | ||
| raise HTTPException(status_code=400, detail=f"{field_name} cannot be empty") |
src/paperbot/api/routes/runbook.py
Outdated
| if not os.path.isabs(normalized): | ||
| normalized = str((Path.cwd() / normalized).resolve(strict=False)) | ||
| normalized_real = os.path.realpath(normalized) | ||
| return Path(os.path.realpath(normalized)).resolve(strict=False) |
| try: | ||
| roots.append(Path.home().resolve()) | ||
| except Exception: |
| task.updated_at = datetime.utcnow().isoformat() | ||
| await _emit_codex_event( | ||
| "codex_dispatched", | ||
| task, | ||
| session, | ||
| {"assignee": task.assignee}, | ||
| ) |
| return { | ||
| "found": False, | ||
| "session_id": None, | ||
| "paper_id": paper_id, | ||
| "context_pack_id": None, | ||
| "workspace_dir": None, | ||
| "user_id": None, | ||
| "sandbox_id": None, | ||
| "sandbox_executor": None, | ||
| "paper_slug_name": None, | ||
| "tasks": [], | ||
| "status": "idle", | ||
| "checkpoint": "", | ||
| "updated_at": None, | ||
| "control_state": None, | ||
| "session": None, | ||
| } |
| rows.append( | ||
| { | ||
| "paper": self._paper_to_dict(paper), | ||
| "track_id": ( | ||
| min(saved_track_membership.get(pid, set())) | ||
| if saved_track_membership.get(pid) | ||
| else None | ||
| ), |
| def _should_overflow_to_codex() -> bool: | ||
| """Return True if the Paper2Code CODING stage should overflow to Codex. | ||
|
|
||
| Checks the PAPERBOT_CODEX_OVERFLOW_THRESHOLD environment variable: | ||
| - Unset or empty -> False | ||
| - "1", "true", "yes", "on" (case-insensitive) -> True | ||
| - Any other value -> False | ||
|
|
||
| Wraps in try/except so any unexpected error returns False safely. | ||
| """ |
| def _git(cwd: Path, *args: str) -> str: | ||
| result = subprocess.run( | ||
| ["git", *args], | ||
| cwd=str(cwd), | ||
| capture_output=True, | ||
| text=True, | ||
| check=True, | ||
| ) |
| import types | ||
| from typing import Any, List, Optional | ||
| from unittest.mock import MagicMock |
Vercel Preview
|
|
There was a problem hiding this comment.
Pull request overview
This PR expands the Studio/Agent Board backend surface area by adding Codex delegation event vocabulary + emission hooks, a Studio skills catalog API, and richer saved-paper provenance data, alongside substantial planning/validation documentation updates.
Changes:
- Add Codex delegation EventType constants + event helpers/emission points (agent-board + MCP audit typing).
- Introduce Studio skills discovery/registry + REST endpoints and tests for skill repo install/update.
- Enrich saved-papers responses with provenance/workflow labels and track summary; broaden runbook allowed directory defaults and mutation policy.
Reviewed changes
Copilot reviewed 69 out of 189 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_studio_skill_catalog.py | Adds unit tests covering install/list/update/detail of Studio skill repos. |
| tests/unit/test_studio_chat_path_validation.py | Extends tests for model-id mapping and studio_cwd allowlist behaviors. |
| tests/unit/test_runbook_project_dir_prepare_route.py | Adds tests for home/Documents default acceptance and allowlist mutation rules. |
| tests/unit/test_research_feedback_state.py | Updates feedback tests for new saved-paper payload shape + adds provenance/judge summary coverage. |
| tests/unit/test_codex_overflow.py | Adds unit tests for _should_overflow_to_codex env-var behavior. |
| tests/unit/test_api_security_middleware.py | Adds test coverage for “full_access” code mode flags. |
| tests/unit/test_agent_events_vocab.py | Defines TDD contract for EventType constants and event helper APIs (incl. Codex types). |
| tests/unit/test_agent_board_route.py | Expands Agent Board tests for task creation and “latest session” empty payload behavior. |
| tests/unit/test_agent_board_codex_events.py | Adds async tests for _emit_codex_event behavior and payload merging. |
| src/paperbot/repro/orchestrator.py | Adds _should_overflow_to_codex env-var gate helper. |
| src/paperbot/mcp/tools/_audit.py | Migrates tool audit type strings to EventType constants. |
| src/paperbot/infrastructure/stores/research_store.py | Adds provenance labeling + track name lookup to saved-paper listing. |
| src/paperbot/application/services/studio_skill_registry.py | Implements skill discovery/parsing from multiple ecosystems and manifests. |
| src/paperbot/application/collaboration/message_schema.py | Introduces EventType constants (incl. file + codex delegation types). |
| src/paperbot/application/collaboration/agent_events.py | Adds helper builders for lifecycle and tool-call envelopes. |
| src/paperbot/api/routes/studio_skills.py | Adds Studio skills catalog/install/update/detail API routes. |
| src/paperbot/api/routes/runbook.py | Expands allowed prefixes to include home/Documents; adds allowlist-mutation root checks. |
| src/paperbot/api/routes/harvest.py | Extends save request with metadata and records save feedback via add_paper_feedback. |
| src/paperbot/api/routes/agent_board.py | Adds codex event emission helper + task creation endpoint + latest-session payload tweak. |
| src/paperbot/api/routes/init.py | Exposes new studio_skills router module. |
| src/paperbot/api/middleware/auth.py | Adds localhost:3010 to allowed origins. |
| src/paperbot/api/main.py | Registers Studio skills router in FastAPI app. |
| .planning/phases/11-dag-visualization/11-VALIDATION.md | Adds Phase 11 validation strategy doc. |
| .planning/phases/11-dag-visualization/11-01-SUMMARY.md | Adds Phase 11 plan summary doc. |
| .planning/phases/10-agent-board-codex-bridge/10-VALIDATION.md | Adds Phase 10 validation strategy doc. |
| .planning/phases/10-agent-board-codex-bridge/10-03-SUMMARY.md | Adds Phase 10-03 execution summary doc. |
| .planning/phases/10-agent-board-codex-bridge/10-03-PLAN.md | Adds Phase 10-03 execution plan doc. |
| .planning/phases/10-agent-board-codex-bridge/10-02-SUMMARY.md | Adds Phase 10-02 execution summary doc. |
| .planning/phases/10-agent-board-codex-bridge/10-01-SUMMARY.md | Adds Phase 10-01 execution summary doc. |
| .planning/phases/10-agent-board-codex-bridge/10-01-PLAN.md | Adds Phase 10-01 execution plan doc. |
| .planning/phases/09-three-panel-dashboard/09-VERIFICATION.md | Adds Phase 09 verification report doc. |
| .planning/phases/09-three-panel-dashboard/09-VALIDATION.md | Adds Phase 09 validation strategy doc. |
| .planning/phases/09-three-panel-dashboard/09-02-SUMMARY.md | Adds Phase 09-02 summary doc. |
| .planning/phases/09-three-panel-dashboard/09-01-SUMMARY.md | Adds Phase 09-01 summary doc. |
| .planning/phases/08-agent-event-vocabulary/08-VERIFICATION.md | Adds Phase 08 verification report doc. |
| .planning/phases/08-agent-event-vocabulary/08-VALIDATION.md | Adds Phase 08 validation strategy doc. |
| .planning/phases/08-agent-event-vocabulary/08-02-SUMMARY.md | Adds Phase 08-02 summary doc. |
| .planning/phases/08-agent-event-vocabulary/08-01-SUMMARY.md | Adds Phase 08-01 summary doc. |
| .planning/phases/08-agent-event-vocabulary/08-01-PLAN.md | Adds Phase 08-01 execution plan doc. |
| .planning/codebase/TESTING.md | Adds repository testing conventions reference. |
| .planning/codebase/STACK.md | Adds technology stack reference. |
| .planning/codebase/INTEGRATIONS.md | Adds integrations inventory reference. |
| .planning/codebase/CONVENTIONS.md | Adds coding conventions reference. |
| .planning/codebase/ARCHITECTURE.md | Adds high-level architecture reference. |
| .planning/STATE.md | Updates program state/milestones and recent decision log. |
| .planning/REQUIREMENTS.md | Updates v1.1 requirement status and adds v1.2 requirements mapping. |
| .planning/PROJECT.md | Updates project framing to agent-agnostic dashboard direction. |
| .claude/agents/codex-worker.md | Adds Claude Code sub-agent definition for Codex delegation workflow. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| await _emit_codex_event( | ||
| "codex_dispatched", | ||
| task, | ||
| session, | ||
| {"assignee": task.assignee}, | ||
| ) |
| async def create_task(session_id: str, request: CreateTaskRequest): | ||
| """Create an ad-hoc task in an existing session for Studio-triggered delegation.""" | ||
| session = _load_session(session_id) | ||
| if not session: | ||
| raise HTTPException(status_code=404, detail="Session not found") | ||
|
|
||
| title = request.title.strip() | ||
| description = request.description.strip() | ||
| if not title: | ||
| raise HTTPException(status_code=400, detail="title is required") | ||
| if not description: | ||
| raise HTTPException(status_code=400, detail="description is required") | ||
| if request.assignee != "codex": | ||
| raise HTTPException( | ||
| status_code=400, | ||
| detail="Only Codex delegation is wired right now; OpenCode runtime is not available yet.", | ||
| ) | ||
|
|
||
| if request.workspace_dir and request.workspace_dir.strip(): | ||
| session.workspace_dir = str(_sanitize_workspace_dir(request.workspace_dir)) | ||
|
|
||
| tags = [tag.strip() for tag in request.tags if isinstance(tag, str) and tag.strip()] | ||
| if "studio" not in tags: | ||
| tags.append("studio") | ||
| if "ad_hoc" not in tags: | ||
| tags.append("ad_hoc") | ||
|
|
||
| task = AgentTask( | ||
| id=f"task-{uuid.uuid4().hex[:12]}", | ||
| title=title, | ||
| description=description, | ||
| status="planning", | ||
| assignee="claude", | ||
| progress=0, | ||
| tags=tags, | ||
| paper_id=session.paper_id or None, | ||
| ) |
| return Path(__file__).resolve().parents[4] | ||
|
|
||
|
|
| fake_container = MagicMock() | ||
| fake_container.event_log = fake_log | ||
|
|
||
| # Patch Container inside agent_board module | ||
| import paperbot.api.routes.agent_board as ab_mod | ||
|
|
||
| def _fake_container_instance(): | ||
| return fake_container | ||
|
|
| Checks the PAPERBOT_CODEX_OVERFLOW_THRESHOLD environment variable: | ||
| - Unset or empty -> False | ||
| - "1", "true", "yes", "on" (case-insensitive) -> True | ||
| - Any other value -> False | ||
|
|
||
| Wraps in try/except so any unexpected error returns False safely. | ||
| """ | ||
| try: | ||
| value = os.getenv("PAPERBOT_CODEX_OVERFLOW_THRESHOLD", "").strip() |
| @router.get("/studio/skills") | ||
| async def studio_skills_catalog(): | ||
| return list_studio_skill_catalog() | ||
|
|
||
|
|
||
| _SKILL_CATALOG_BAD_REQUEST_RESPONSE = { | ||
| 400: {"description": "Invalid skill catalog request or repository metadata."} | ||
| } | ||
|
|
||
|
|
||
| @router.post("/studio/skills/install", responses=_SKILL_CATALOG_BAD_REQUEST_RESPONSE) | ||
| async def studio_skill_install(request: InstallStudioSkillRepoRequest): | ||
| try: | ||
| return install_studio_skill_repo(request.repo_url, repo_ref=request.repo_ref) | ||
| except StudioSkillCatalogError as exc: | ||
| raise HTTPException(status_code=400, detail=str(exc)) from exc | ||
|
|
||
|
|
||
| @router.post( | ||
| "/studio/skills/repos/{repo_slug}/update", | ||
| responses=_SKILL_CATALOG_BAD_REQUEST_RESPONSE, | ||
| ) | ||
| async def studio_skill_repo_update(repo_slug: str, request: UpdateStudioSkillRepoRequest): | ||
| try: | ||
| return update_studio_skill_repo(repo_slug, repo_ref=request.repo_ref) | ||
| except StudioSkillCatalogError as exc: | ||
| raise HTTPException(status_code=400, detail=str(exc)) from exc | ||
|
|
||
|
|
||
| @router.get("/studio/skills/{skill_key}") | ||
| async def studio_skill_detail(skill_key: str): | ||
| try: | ||
| detail = get_studio_skill_detail(skill_key) | ||
| except StudioSkillCatalogError as exc: | ||
| raise HTTPException(status_code=404, detail=str(exc)) from exc | ||
| return detail.to_payload() |
| """ | ||
| normalized_real = _normalize_path_input(raw_path, field_name) | ||
| return _resolve_real_path_within_prefixes( | ||
| normalized_real, | ||
| _allowed_workdir_prefixes(), |
| track_names = [ | ||
| track_name_by_id[track_ref] | ||
| for track_ref in sorted(saved_track_membership.get(pid, set())) | ||
| if track_name_by_id.get(track_ref) | ||
| ] | ||
| rows.append( | ||
| { | ||
| "paper": self._paper_to_dict(paper), | ||
| "track_id": ( | ||
| min(saved_track_membership.get(pid, set())) | ||
| if saved_track_membership.get(pid) | ||
| else None | ||
| ), |
| app.include_router(model_endpoints.router, prefix="/api", tags=["Model Endpoints"]) | ||
| app.include_router(embedding_settings.router, prefix="/api", tags=["Embedding Settings"]) | ||
| app.include_router(studio_chat.router, prefix="/api", tags=["Studio Chat"]) | ||
| app.include_router(studio_skills.router, prefix="/api", tags=["Studio Skills"]) |



Summary
Validation
cd web && npm run build/dashboard,/settings?tab=daily-brief, and/signalsNotes