Skip to content

Settings schema unification and file watching#209

Merged
rgbkrk merged 6 commits intomainfrom
rgbkrk/porto-v4
Feb 23, 2026
Merged

Settings schema unification and file watching#209
rgbkrk merged 6 commits intomainfrom
rgbkrk/porto-v4

Conversation

@rgbkrk
Copy link
Member

@rgbkrk rgbkrk commented Feb 22, 2026

Summary

  • Unified AppSettings to serialize in the same nested format as SyncedSettings, fixing a schema mismatch where the daemon and notebook wrote different JSON formats to the same file
  • Added JSON Schema support via schemars crate for machine-readable settings documentation
  • Implemented file watching for settings.json via notify crate with automatic change propagation to all connected notebook windows
  • Added cargo xtask install-daemon for convenient daemon upgrades during development
  • Improved get_synced_settings fallback to use local settings file when daemon is unavailable (issue Unified settings read path: frontend should read settings.json when daemon is unavailable #188)

Verification

To test the file watching workflow:

  1. Edit ~/Library/Application Support/runt-notebook/settings.json manually while the daemon is running
  2. Check that changes appear in all open notebook windows within 500ms
  3. Verify backward compatibility by starting with an old flat-format settings.json
  4. Test cargo xtask install-daemon to verify daemon reinstallation and version detection

Closes #190

PR submitted by @rgbkrk's agent, Quill

rgbkrk and others added 2 commits February 22, 2026 13:40
Three changes:

1. **Schema unification**: AppSettings now serializes to the same nested
   JSON format as SyncedSettings ({ uv: { default_packages: [...] } }).
   Both the daemon and notebook write the same schema to settings.json.
   Backward-compat: load_settings() migrates old flat keys on read.

2. **File watching**: The daemon watches settings.json using the notify
   crate with a 500ms debouncer. External edits (manual or CLI) are
   detected, applied to the Automerge doc, and broadcast to all connected
   windows. Self-writes are automatically skipped via field comparison.

3. **JSON Schema**: Added schemars with #[derive(JsonSchema)] on all
   settings types (SyncedSettings, AppSettings, UvDefaults, CondaDefaults,
   Runtime, PythonEnvType).

Also fixes #188: get_synced_settings now falls back to settings.json
when the daemon is unavailable instead of returning an error.

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
Implements an explicit dev command to rebuild and install the daemon
into the running launchd/systemd service. This solves the friction of
testing daemon changes locally without manually stopping/replacing/restarting.

The command:
1. Builds runtimed in release mode
2. Stops the running service (gracefully)
3. Copies the new binary over the installed one
4. Restarts the service
5. Verifies the version from daemon.json

Also updates contributing/runtimed.md with the new command in the quick
reference and development workflow documentation.

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
s.conda.default_packages = packages;
settings::save_settings(&s).map_err(|e| e.to_string())
}
// Theme has no local fallback in settings.json (handled by localStorage)
Copy link
Member Author

Choose a reason for hiding this comment

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

Actually theme should have a local fallback in settings.json. We can do local storage first but there is a theme key.

settings
}

/// Extract packages from an old flat key (comma-separated string or array).
Copy link
Member Author

Choose a reason for hiding this comment

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

Considering we haven't released this yet with the flat key, it's going to be ok to rip this out before mondays pre release.

}
}
}

Copy link
Member Author

Choose a reason for hiding this comment

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

The only funny thing I've noticed is that if I change the file in zed then it also reformats the file. Then the daemon gets the update and writes the file with the new setting back but formatted in its own json way. Just to cause less churn I feel like we should adopt json formatting here.

Separately I think we should use the json with comments format so we can leave comments in the document for the user.

}
}
}

Copy link
Member Author

Choose a reason for hiding this comment

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

The only funny thing I've noticed is that if I change the file in zed then it also reformats the file. Then the daemon gets the update and writes the file with the new setting back but formatted in its own json way. Just to cause less churn I feel like we should adopt json formatting here.

Separately I think we should use the json with comments format so we can leave comments in the document for the user.

rgbkrk and others added 4 commits February 22, 2026 16:07
Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
- Remove backward-compat flat key migration code from settings.rs and
  settings_doc.rs since the flat format was never shipped publicly
- Stop writing JSON mirror in the file watcher handler to avoid
  reformatting the user's settings.json with serde's formatting
- Remove backward compatibility docs section from settings.md
- Remove related tests for flat format handling

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
Both save_json_mirror and save_settings now emit a trailing newline to
match standard editor formatting, reducing churn when the user edits
settings.json in their editor. The watch handler now writes the JSON
mirror back (matching the sync server behavior).

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
serde_json expands arrays to one element per line, while editors like
Zed keep short arrays inline. Writing the mirror back would reformat
the user's file every time they save it. The user's file already has
the correct values so only the Automerge binary needs persisting.

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
@rgbkrk rgbkrk merged commit a432f3f into main Feb 23, 2026
5 checks passed
@rgbkrk rgbkrk deleted the rgbkrk/porto-v4 branch February 23, 2026 01:12
rgbkrk added a commit that referenced this pull request Mar 11, 2026
build-dependencies.md:
- Remove stale PR #209 reference
- Fix Python wheel description (pyo3, not bin bindings)
- Add notebook-doc to both dependency graphs
- Fix sidecar→runt-cli edge (doesn't exist)
- Add runt-workspace and kernel deps to crate graph

development.md:
- Fix AGENTS.md → CLAUDE.md reference
- Add explicit env var instructions for agents in raw terminals
- Add 'Before You Commit' section with formatting requirements
- Add 'Zed Editor Integration' section documenting .zed/tasks.json

README.md:
- Add notebook-doc to project structure tree
- Add Contributing section with links to key guides
rgbkrk added a commit that referenced this pull request Mar 11, 2026
build-dependencies.md:
- Remove stale PR #209 reference
- Fix Python wheel description (pyo3, not bin bindings)
- Add notebook-doc to both dependency graphs
- Fix sidecar→runt-cli edge (doesn't exist)
- Add runt-workspace and kernel deps to crate graph

development.md:
- Fix AGENTS.md → CLAUDE.md reference
- Add explicit env var instructions for agents in raw terminals
- Add 'Before You Commit' section with formatting requirements
- Add 'Zed Editor Integration' section documenting .zed/tasks.json

README.md:
- Add notebook-doc to project structure tree
- Add Contributing section with links to key guides
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.

Watch settings.json for external changes and propagate via Automerge

1 participant