Skip to content

feat: project sessions and notes#244

Merged
matt2e merged 33 commits intomainfrom
project-ai
Feb 25, 2026
Merged

feat: project sessions and notes#244
matt2e merged 33 commits intomainfrom
project-ai

Conversation

@matt2e
Copy link
Contributor

@matt2e matt2e commented Feb 24, 2026

  • Adds project-level sessions: a project prompt input starts an agent session scoped to the whole project, backed by an embedded MCP server that exposes two tools to the agent:
    • start_repo_session — starts a subagent session in a specific repo (waits for completion, returns output + note)
    • add_project_repo — adds a new repo to the project, sets up the worktree, and runs prerun actions before returning
  • Adds project notes (always produced by project sessions); displayed under the project prompt with the same timeline UX as branch notes
  • Shows a dismissible info banner on branch cards when a repo is added via add_project_repo, explaining why it was added
  • Moves worktree setup and prerun-action execution to the backend (branches.rs); emits project-setup-progress events so the frontend refreshes without driving setup itself
  • Fixes a ref-update race when setting up worktrees: replaces the broad git fetch origin in ensure_local_clone with a targeted fetch_for_worktree that only fetches the refs needed, and tolerates git CAS race errors (incorrect old value provided)
  • Injects the MCP server into the ACP session via NewSessionRequest so it works with any ACP-compatible agent (Claude Code, Goose, etc.)
  • Cancellation propagates: cancelling a project session cancels any in-flight child repo sessions

matt2e and others added 30 commits February 24, 2026 15:21
- Add ProjectNote model with project-scoped notes for cross-cutting context
- Add project_notes table to SQLite schema with cascade delete
- Add reason column to project_repos for tracking why repos are attached
- Add start_project_session command for project-level sessions
- Add create_project_note, list_project_notes, delete_project_note commands
- Build project session context with repo listing, existing notes, and
  chronological branch timeline summaries grouped by repository
- Inject project notes into branch-level timeline context
- Add project note extraction to session_runner post-completion hooks
- Add ProjectNote and ProjectSessionResponse types to frontend
- Add project session UI with prompt input, notes display, and deletion
- Bump schema version (wipe-and-recreate on mismatch)
… section

- Remove createNote parameter from startProjectSession, always pass true
  so every project session generates a note
- Remove session running state from prompt input — the textarea is always
  available, allowing multiple concurrent project sessions
- Track active sessions in a Set<string> instead of a single ID
- Reload notes immediately after starting a session so the stub appears
  as a 'Generating note…' card with a spinner in the notes section
- Support multiple concurrent generating notes via filter instead of find
- Remove unused Loader2 import, .running CSS state, and spin animation
… add_project_repo tools

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
These files were written locally but never committed before the rebase
moved the directory from staged/ to apps/mark/, leaving the pub mod
declarations in lib.rs dangling.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix project sessions appearing completed immediately by saving the
  initial note stub with empty title/content (matching branch note
  behavior) so the generating state is correctly detected
- MCP add_project_repo now blocks until worktree is set up, detect_actions
  has run, and all prerun setup actions have completed
- Emit project-repo-added Tauri event from MCP handler so ProjectHome
  reactively reloads when a repo is added via MCP without manual refresh
- Remove debug log statements from project_mcp.rs, session_commands.rs,
  session_runner.rs, ProjectSection.svelte, and acp-client/driver.rs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- start_repo_session: add `return_info` param so parent session can
  specify what the child should return; child prompt is suffixed with
  the instruction; last assistant message is returned as `output` in
  the result JSON
- add_project_repo: emit `project-repo-added` Tauri event at each
  stage (repo created, worktree ready, prerun actions done) so the UI
  updates progressively without requiring a manual reload

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ards

When a project session adds a repo via MCP with a reason, save it to the
DB and display it as the first item in the branch card timeline — styled
with an info (blue) color theme and an Info icon. Hovering reveals an X
button on the right to dismiss it, which clears the reason from the DB.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Before creating the repo, run the monorepo check. If the score is >= 20
and no subpath was provided, return an error telling the agent it must
re-call the tool with a subpath pointing to the specific service or
package root (e.g. "packages/api"). Also expose `subpath` as an explicit
MCP parameter so agents can supply it directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…+subpath

Add subpath parameter to StartRepoSessionParams and update the repo lookup
to match on both github_repo and subpath exactly, so multiple copies of the
same repo with different subpaths are disambiguated correctly. Calls now fail
immediately with a clear error listing available repo+subpath combos if no
match is found. Also sets the working directory to include the subpath.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…d unread tracking

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the implicit return-only behaviour with an explicit
`expected_outcome` field (`return_output_only`, `note_in_repo`,
`commit`). When `note_in_repo` or `commit` is requested the agent
receives the same action-prefix prompt used by branch sessions, a Note
or Commit stub is created in the DB (linked via session_id so the
branch card timeline picks it up automatically), and commit sessions
capture the pre-HEAD SHA so the post-completion hook can resolve the
new SHA. Expand the log line to include all params including the full
instructions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…h cards live

When start_repo_session creates a note/commit artifact, it now emits a
session-status-changed event with status "running" and branch_id,
project_id, session_type fields. BranchCard listens for running events
matching its branch and calls loadTimeline() immediately, so the pending
stub appears without a reload. App.svelte registers the session in
sessionRegistry and projectStateStore so the project spinner activates
and cleanup on completion works correctly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
start_repo_session now builds the same <branch-history> and project
information context that user-triggered branch sessions receive.
Looks up the worktree path for local branches (falling back to the
clone path) and calls the now pub(crate) build_branch_context /
build_remote_branch_context helpers from session_commands. The prompt
structure matches build_full_prompt: <action> block with action
instructions + project info, <branch-history> block, then user
instructions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the blanket `git fetch origin` in `ensure_local_clone` with a
new `fetch_for_worktree` helper that fetches only `base_branch` and
`branch_name`. The full fetch updated every remote-tracking ref via
compare-and-swap, which caused spurious "incorrect old value provided"
failures (and a needless HTTPS retry) when another worktree or process
had already updated some refs in the shared clone.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tart_repo_session call

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
base_branch is stored in the DB with an "origin/" prefix but git fetch
expects the bare ref name. Without stripping, fetch ran:
  git fetch origin origin/main
which failed with "couldn't find remote ref origin/main".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…o on completion

- Clarify note_in_repo and commit expected_outcome descriptions with usage guidance
- Explain that existing notes are accessible by name in the instructions field
- Add guidance on reason field for add_project_repo (describe repo, not todos)
- Return created note info in the same format as session-start notes when a note_in_repo session completes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ponse

The note is now returned separately in the `note` field, so the raw
agent output no longer needs to include the content after the `---`
separator.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…essions

Ensures project sessions always have a real working directory by creating
the project-scoped worktree root (~/.staged/workspaces/local/projects/<id>/)
at project creation time, and falling back to it instead of /tmp when the
project has no repos attached yet.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…f-race errors

fetch_for_worktree already fetches the base branch with SSH→HTTPS fallback
before create_worktree_at_path is called, so the second best-effort fetch
inside create_worktree_at_path was redundant and could cause duplicate
ref-update races.

Also swallow "incorrect old value provided" errors in fetch_for_worktree:
this is a CAS race where a concurrent fetch already updated the tracking ref,
leaving it at least as up-to-date as needed, so the error is non-fatal.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- project_mcp: add CancellationToken to ProjectToolsHandler and use
  tokio::select! in start_repo_session polling loop so the parent
  session's cancellation stops the loop immediately
- ProjectSection: fix 'failed' -> 'error' status string in
  session-status-changed listener to match what the backend emits
- project_mcp: create Note stub with empty title so post-completion
  hook can find and populate it via get_empty_note_by_session
- project_mcp: use serde_json::to_string for error messages in
  add_project_repo JSON responses to prevent injection from OS/git output
- git/github: restore unconditional HTTPS retry in fetch_for_worktree
  on any fetch failure (except ref-race), removing is_fetch_auth_failure
  and matching the original ensure_local_clone behaviour from main

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tting helper

- Require a recorded worktree for local branches in start_repo_session, returning
  an error instead of silently falling back to the clone directory
- Extract format_note_for_context into a shared helper used by both
  note_timeline_entries and the MCP poll loop
- Thread is_remote through ProjectToolsHandler and start_project_mcp_server,
  derived from workspace_name presence in session_runner
- Replace manual JSON string formatting with serde_json::json! in project_mcp

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously Ok(None) fell through to Ok(_) => continue, causing an
infinite spin if the session row was deleted mid-run.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…dded setup

- Cancel the child repo session via registry.cancel() when the parent
  project session's cancel_token fires, preventing orphaned agent sessions
- Guard startInitialBranchSetup in the project-repo-added listener with a
  Set of already-submitted branch IDs, making it idempotent across the
  three rapid-fire emissions from add_project_repo

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
matt2e and others added 3 commits February 25, 2026 12:36
Backend now owns all worktree setup and prerun actions for every repo-add
path (UI-triggered add_project_repo, create_project, and MCP). Frontend
only reacts to project-setup-progress events to refresh display state,
removing the need for frontend-driven setup orchestration.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Project sessions always produce notes, but were registered with type
'other' which maps to label 'task' via sessionTypeLabel. This caused
the project list and sidebar to show 'making a task' during project
sessions. Change to 'note' so the subtitle shows 'making a note',
matching the behavior of normal note sessions.
- Log warning instead of silently swallowing spawn_blocking panics in
  start_repo_session context build
- Move setup_worktree_sync and run_prerun_actions_for_branch from
  project_mcp.rs to branches.rs where they logically belong
- Use temp-file references for project notes in branch/project context,
  matching branch note behaviour; fall back to inline on write error
- Fix stale CLAUDE_MCP_CONFIG mention in SessionConfig::mcp_project_id
  doc comment
- Extract ReasonBanner shared component to remove duplication between
  BranchCard and RemoteBranchCard
- Require exact org/repo slug match in start_repo_session; remove the
  ends_with suffix fallback that could silently match the wrong repo

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@matt2e matt2e marked this pull request as ready for review February 25, 2026 02:26
@matt2e matt2e changed the title feat: project sessions, notes, and per-repo branch timelines feat: project sessions, notes Feb 25, 2026
@matt2e matt2e changed the title feat: project sessions, notes feat: project sessions and notes Feb 25, 2026
@matt2e matt2e merged commit 231e0f6 into main Feb 25, 2026
5 checks passed
@matt2e matt2e deleted the project-ai branch February 25, 2026 02:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant