Skip to content

feat(mcp): support project reassignment in mem_update - #679

Open
Faturrachman-dev wants to merge 1 commit into
Gentleman-Programming:mainfrom
Faturrachman-dev:feat/mem-update-project-reassign
Open

feat(mcp): support project reassignment in mem_update#679
Faturrachman-dev wants to merge 1 commit into
Gentleman-Programming:mainfrom
Faturrachman-dev:feat/mem-update-project-reassign

Conversation

@Faturrachman-dev

@Faturrachman-dev Faturrachman-dev commented Jul 28, 2026

Copy link
Copy Markdown

Problem

mem_update exposes title, content, type, scope, and topic_key, but not project. So an observation saved under the wrong project can never be moved through the public API — the only recourse is raw SQL against engram.db or a full export → edit → reimport round-trip. There's no per-observation reassignment anywhere (CLI, MCP, or HTTP); projects/migrate and consolidate operate at whole-project granularity.

This is easy to hit in practice: when the working directory resolves to a fallback/default project, a batch of observations lands in the wrong bucket and there's no supported way to reclassify them individually.

Fix

The backend already supports this — the missing piece was only the MCP surface:

  • store.UpdateObservationParams already has a Project *string field.
  • store.UpdateObservation already writes it (via NormalizeProject).
  • handleUpdate's "nothing to update" guard already references update.Project.

Only the tool schema and the argument parse were absent. This PR:

  1. Adds mcp.WithString("project", ...) to the mem_update tool definition.
  2. Reads it in handleUpdate into update.Project.
  3. Adds TestUpdateObservationReassignsProject covering reassign + persisted re-read.

Test

go test ./internal/store/ -run TestUpdateObservationReassignsProject
ok  github.com/Gentleman-Programming/engram/internal/store

+46 lines, no behavior change to existing fields.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added support for reassigning an observation to a different project when updating it.
    • The updated project assignment is saved and reflected when the observation is viewed again.

mem_update accepted title/content/type/scope/topic_key but not project, so
an observation saved under the wrong project could never be moved — the only
recourse was raw SQL or an export/edit/reimport round-trip.

The store layer already supported this: UpdateObservationParams has a Project
field, UpdateObservation writes it (with NormalizeProject), and handleUpdate's
guard already referenced update.Project. Only the tool schema and the argument
parse were missing. This wires both and adds a store-level test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 28, 2026 16:58
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The mem_update MCP tool now accepts an optional project value, passes it into observation updates, and includes a test confirming the reassigned project persists after re-fetching.

Changes

Observation project reassignment

Layer / File(s) Summary
Project reassignment persistence
internal/store/store_test.go
Adds coverage for changing an observation’s project, checking the returned value, and verifying persistence through GetObservation.
MCP update project input
internal/mcp/mcp.go
Adds the optional project tool parameter and assigns it to the update request in handleUpdate.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested labels: type:feature

Suggested reviewers: copilot, gentleman-programming, alan-thegentleman

Sequence Diagram(s)

sequenceDiagram
  participant MCPClient
  participant handleUpdate
  participant UpdateObservation
  MCPClient->>handleUpdate: mem_update with project
  handleUpdate->>UpdateObservation: update.Project
  UpdateObservation-->>handleUpdate: updated observation
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: enabling project reassignment in mem_update.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/store/store_test.go`:
- Around line 8834-8872: Extend TestUpdateObservationReassignsProject to cover
UpdateObservation error handling for an invalid or missing observation ID, plus
deterministic assertions for empty project input and the intended project-name
normalization behavior before merge. Keep the existing successful reassignment
and persistence checks, and use the store’s established error and normalization
expectations rather than inventing new behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 588bb4d5-e193-4d21-b742-99c292312a69

📥 Commits

Reviewing files that changed from the base of the PR and between 763a6ba and 18dd410.

📒 Files selected for processing (2)
  • internal/mcp/mcp.go
  • internal/store/store_test.go

Comment on lines +8834 to +8872
func TestUpdateObservationReassignsProject(t *testing.T) {
s := newTestStore(t)

if err := s.CreateSession("s1", "alpha", "/tmp/alpha"); err != nil {
t.Fatalf("create session: %v", err)
}

id, err := s.AddObservation(AddObservationParams{
SessionID: "s1",
Type: "config",
Title: "movable",
Content: "belongs elsewhere",
Project: "alpha",
Scope: "project",
})
if err != nil {
t.Fatalf("add observation: %v", err)
}

newProject := "beta"
updated, err := s.UpdateObservation(id, UpdateObservationParams{
Project: &newProject,
})
if err != nil {
t.Fatalf("update observation: %v", err)
}
if derefString(updated.Project) != "beta" {
t.Fatalf("project reassignment did not apply; got project=%q, want %q", derefString(updated.Project), "beta")
}

// Confirm it persisted on re-read.
got, err := s.GetObservation(id)
if err != nil {
t.Fatalf("get observation: %v", err)
}
if derefString(got.Project) != "beta" {
t.Fatalf("reassignment not persisted; got project=%q, want %q", derefString(got.Project), "beta")
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Extend coverage beyond the happy path.

This test verifies successful reassignment and persistence, but omits UpdateObservation error paths and project-input edge cases. Add deterministic assertions for an invalid/missing observation ID and the intended empty/normalization behavior before merge.

As per path instructions, **/*_test.go must verify happy path, error paths, and edge cases, and behavior changes without tests should be blocked.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/store/store_test.go` around lines 8834 - 8872, Extend
TestUpdateObservationReassignsProject to cover UpdateObservation error handling
for an invalid or missing observation ID, plus deterministic assertions for
empty project input and the intended project-name normalization behavior before
merge. Keep the existing successful reassignment and persistence checks, and use
the store’s established error and normalization expectations rather than
inventing new behavior.

Source: Path instructions

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the MCP mem_update tool so callers can reassign an existing observation to a different project, matching capabilities already present in the store layer. It also adds a store-level test to confirm project reassignment persists.

Changes:

  • Add a project string parameter to the MCP mem_update tool schema.
  • Parse the project argument in handleUpdate and forward it via store.UpdateObservationParams.
  • Add TestUpdateObservationReassignsProject to validate reassignment and persistence on re-read.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
internal/mcp/mcp.go Exposes and parses project in mem_update so MCP callers can reassign an observation’s project.
internal/store/store_test.go Adds a regression test ensuring UpdateObservation can change (and persist) an observation’s project.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/mcp/mcp.go
Comment on lines +1416 to +1418
if v, ok := req.GetArguments()["project"].(string); ok {
update.Project = &v
}
Comment on lines +8853 to +8856
newProject := "beta"
updated, err := s.UpdateObservation(id, UpdateObservationParams{
Project: &newProject,
})
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.

2 participants