Skip to content

feat: live raid vars reload + MCP resource (closes #27)#70

Merged
8bitAlex merged 3 commits into
mainfrom
feat/issue-27-live-vars-watcher
May 10, 2026
Merged

feat: live raid vars reload + MCP resource (closes #27)#70
8bitAlex merged 3 commits into
mainfrom
feat/issue-27-live-vars-watcher

Conversation

@8bitAlex
Copy link
Copy Markdown
Owner

Summary

Resolves #27Add watcher on variables that executes updates live.

  • raid context serve now watches ~/.raid/vars (via fsnotify on the parent dir, debounced 50ms to coalesce atomic-rename bursts) and reloads the in-memory workspace whenever the file changes. Reload runs ForceLoad under the cross-process mutation lock so it serializes cleanly with concurrent raid_install / raid_env_switch / raid_run_task mutations.
  • New MCP resource raid://workspace/vars (JSON) exposes the persisted variables — Set-task values plus the auto-derived RAID_REPO_* keys — alongside the existing profile, env, repos, commands, recent set. The handler returns {} rather than null for the empty case so clients don't need to special-case it.
  • Workspace snapshot gains a Vars field; GetWorkspaceContext populates it via a defensive copy under raidVarsMu.RLock() so callers cannot mutate the live map.
  • Version bumped 0.8.1-beta → 0.9.0-beta. fsnotify promoted from indirect to direct in go.mod.

Why

raidVars was loaded once at process start. The MCP server is long-running, so when another raid process (or a hand edit) wrote to ~/.raid/vars, the server kept serving stale state and AI agents saw lies. Variables also weren't exposed as a resource at all — issue #27 was driven by both gaps.

Test plan

  • go test ./... — all packages green.
  • Coverage: lib 93.5%, cmd/context 91.4%, raid 90.0% (project ≥90% gate maintained).
  • New tests cover snapshot copy semantics, nil-onChange guard, watcher factory error, fire-on-change, debounce coalescing, context-cancel teardown, parent-dir creation, the new MCP handler, and the raid.WatchRaidVars re-export.
  • go build succeeds; raid --version reports 0.9.0-beta.
  • cd site && npm run build — no broken links.
  • Manual end-to-end: start raid context serve, write to ~/.raid/vars from another shell, confirm raid://workspace/vars reflects the change in <100ms.

Out of scope

  • MCP push notifications / subscriptions to connected clients on change. The server is registered with WithResourceCapabilities(false, false); subscription support is a separate, larger change.
  • Watching profile.raid.yml or per-repo raid.yaml for live reload. Same mechanism would compose, but Add watcher on variables that executes updates live #27 is scoped to vars.

🤖 Generated with Claude Code

Watch ~/.raid/vars for the lifetime of `raid context serve` and refresh
the in-memory map (via ForceLoad under the cross-process mutation lock)
whenever it changes on disk, so MCP clients see fresh state when other
raid processes mutate vars instead of values cached at server start.

Adds `raid://workspace/vars` as a JSON MCP resource alongside the
existing profile/env/repos/commands/recent set, and exposes vars on the
shared Workspace snapshot.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 10, 2026 17:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds live reloading of persisted Raid variables for long-running raid context serve sessions and exposes those variables as a first-class MCP resource, keeping the MCP workspace view consistent with concurrent CLI invocations and manual edits.

Changes:

  • Add lib.WatchRaidVars (and raid.WatchRaidVars re-export) to fsnotify-watch ~/.raid/vars with debounce, and trigger workspace reloads under the cross-process mutation lock in raid context serve.
  • Extend the workspace snapshot with Vars and add MCP resource raid://workspace/vars that returns an object (never null) even when empty.
  • Bump version to 0.9.0-beta, promote fsnotify to a direct dependency, and add unit tests covering watcher behavior + snapshot copy semantics.

Reviewed changes

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

Show a summary per file
File Description
src/resources/app.properties Bumps application version to 0.9.0-beta.
src/raid/raid.go Re-exports WatchRaidVars from internal/lib at the public API layer.
src/raid/raid_test.go Adds coverage ensuring the public raid.WatchRaidVars rejects nil callbacks.
src/internal/lib/lib.go Implements vars snapshot copying and the fsnotify-based vars watcher with debouncing.
src/internal/lib/vars_watch_test.go Adds tests for watcher behavior (debounce/coalesce/cancel/error paths) and snapshot semantics.
src/internal/lib/context.go Adds Workspace.Vars and includes a defensive copy in GetWorkspaceContext.
src/internal/lib/context_test.go Tests that vars are included and are copy-safe / omitted when empty.
src/cmd/context/serve.go Starts vars watcher for MCP server and adds raid://workspace/vars resource handler.
src/cmd/context/serve_test.go Adds tests for vars resource shape and watcher-start wiring.
site/docs/whats-new.mdx Documents upcoming 0.9.0 features related to live vars + MCP resource.
site/docs/usage/context.mdx Updates MCP resource list to include raid://workspace/vars and describes live reload behavior.
llms.txt Updates high-level project index to mention context serve + live vars resource.
go.mod Promotes fsnotify (and flock) to direct dependencies.
go.sum Updates sums consistent with dependency graph changes.

Comment thread src/cmd/context/serve.go Outdated
Comment on lines +130 to +132
_ = raid.WithMutationLock(func() error {
return raid.ForceLoad()
})
Comment thread src/internal/lib/lib.go Outdated
Comment on lines +175 to +181
var timer *time.Timer
for {
select {
case <-ctx.Done():
if timer != nil {
timer.Stop()
}
8bitAlex and others added 2 commits May 10, 2026 10:57
Copilot review feedback on #70:

- startVarsWatcher now logs ForceLoad failures to stderr instead of
  swallowing them, so a recurring reload failure (bad profile after an
  external edit, transient IO) is visible rather than silently leaving
  the MCP server with a stale snapshot.
- runVarsWatcher switches from time.AfterFunc to a timer.C channel
  consumed inside the same select that watches ctx.Done. This makes
  onChange run from the watcher goroutine — gated by the same lifecycle
  signal — instead of a separate timer goroutine that could fire after
  ctx was already cancelled. A belt-and-braces ctx.Err() check before
  the reload covers the same-tick race where both channels become
  ready simultaneously.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@8bitAlex 8bitAlex enabled auto-merge (squash) May 10, 2026 17:59
@codecov
Copy link
Copy Markdown

codecov Bot commented May 10, 2026

Codecov Report

❌ Patch coverage is 67.70833% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.72%. Comparing base (fd1bb7f) to head (2b8c2a2).

Files with missing lines Patch % Lines
src/internal/lib/lib.go 64.61% 15 Missing and 8 partials ⚠️
src/cmd/context/serve.go 71.42% 6 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #70      +/-   ##
==========================================
- Coverage   91.56%   90.72%   -0.84%     
==========================================
  Files          33       33              
  Lines        2678     2772      +94     
==========================================
+ Hits         2452     2515      +63     
- Misses        147      168      +21     
- Partials       79       89      +10     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@8bitAlex 8bitAlex merged commit 26f3e51 into main May 10, 2026
11 of 13 checks passed
@8bitAlex 8bitAlex deleted the feat/issue-27-live-vars-watcher branch May 10, 2026 18:00
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.

Add watcher on variables that executes updates live

2 participants