mirror of
https://github.com/awizemann/scarf.git
synced 2026-05-10 10:36:35 +00:00
docs: refresh for Scarf v2.5.2 — chat resilience, model preflight, Nous catalog, remote-aware admin sheets
+19
-1
@@ -51,6 +51,24 @@ Defaults match today's UI exactly so existing users see no change until they opt
|
|||||||
|
|
||||||
Pre-2.5.1 long chats progressively bogged down because every streamed ACP token rebuilt the full message-group array AND every `MessageGroupView` / `RichMessageBubble` re-evaluated its body. v2.5.1 caps per-chunk work at O(1) for settled groups via `Equatable` + `.equatable()` short-circuits, plus a trailing-group patch helper that replaces the per-chunk full rebuild. ScarfGo's chat (different rendering path — `LazyVStack` directly over `controller.vm.messages`) gained an iOS-equivalent `MessageBubble: Equatable`. Issue [#46](https://github.com/awizemann/scarf/issues/46).
|
Pre-2.5.1 long chats progressively bogged down because every streamed ACP token rebuilt the full message-group array AND every `MessageGroupView` / `RichMessageBubble` re-evaluated its body. v2.5.1 caps per-chunk work at O(1) for settled groups via `Equatable` + `.equatable()` short-circuits, plus a trailing-group patch helper that replaces the per-chunk full rebuild. ScarfGo's chat (different rendering path — `LazyVStack` directly over `controller.vm.messages`) gained an iOS-equivalent `MessageBubble: Equatable`. Issue [#46](https://github.com/awizemann/scarf/issues/46).
|
||||||
|
|
||||||
|
## Chat-start model preflight _(v2.5.2+, Mac)_
|
||||||
|
|
||||||
|
When chat-start hits a server whose `config.yaml` has no `model.default` / `model.provider`, the upstream provider returns an opaque `Model parameter is required` 400 only **after** the user types a prompt and hits send. New `ModelPreflight` (in ScarfCore) catches the missing keys before any ACP work; `ChatView` presents the existing `ModelPickerSheet` via a thin `ChatModelPreflightSheet` wrapper so the picker / validation / Nous-catalog branch stay single-sourced. `ChatViewModel` writes the selection via `hermes config set` and replays the original `startACPSession` arguments — the chat the user originally opened lands without re-clicking the project row. Note: `HermesConfig.empty` and the YAML parser's missing-key fallback both use the literal string `"unknown"`, so the check treats `""` and `"unknown"` as equivalent.
|
||||||
|
|
||||||
|
## ScarfGo chat resilience _(v2.5.2+, iOS)_
|
||||||
|
|
||||||
|
ScarfGo now survives phone-sleep, network handoffs, and SSH socket drops without losing the agent's work. Hermes already persists messages to `state.db` in real-time; iOS just had no resync path pre-2.5.2.
|
||||||
|
|
||||||
|
- **5-attempt exponential reconnect** (1 → 2 → 4 → 8 → 16s) via `session/resume` with `session/load` fallback. On success, `reconcileWithDB` merges any messages the agent emitted while disconnected, and a *"Resynced N new messages"* toast surfaces above the composer.
|
||||||
|
- **`NetworkReachabilityService`** (NWPathMonitor singleton) suspends reconnect attempts while offline; kicks a fresh cycle on link-up. Two banner states render slim ScarfDesign-tinted strips above the message list — `.reconnecting` (yellow) and `.offline` (grey) — so the user always knows what the chat is doing.
|
||||||
|
- **Scene-phase aware** — returning the app to foreground triggers a channel-health check; if dead, reconnect starts immediately rather than waiting for the next interaction.
|
||||||
|
- **Draft persistence** per (server, session) survives force-quit; UserDefaults-backed with a 7-day janitor at app launch.
|
||||||
|
- **Cached-snapshot fallback** at the transport layer (`ServerTransport.cachedSnapshotPath`) — `HermesDataService` falls back to the prior snapshot when a fresh pull fails, so Dashboard / Sessions / Activity stay readable while disconnected. `isUsingStaleSnapshot` + `lastSnapshotMtime` surface to views as *"Last updated X ago."*
|
||||||
|
|
||||||
|
## Bounded message-history paging _(v2.5.2+)_
|
||||||
|
|
||||||
|
`HermesDataService.fetchMessages(sessionId:limit:before:)` paginates by id desc with centralized `HistoryPageSize` constants. `RichChatViewModel.loadEarlier()` walks back through long sessions via `oldestLoadedMessageID` + `hasMoreHistory`. Pre-fix the message fetch was unbounded — sessions with thousands of messages were doing a full-history load on every reconnect.
|
||||||
|
|
||||||
## iOS keyboard dismissal _(v2.5.1+)_
|
## iOS keyboard dismissal _(v2.5.1+)_
|
||||||
|
|
||||||
Pre-fix the chat composer's `TextField` had no keyboard dismissal at all — the keyboard would rise and stick, hiding the system tab bar (which iOS auto-hides while a keyboard is up) and trapping users in the Chat tab. v2.5.1 adds two redundant dismissal paths:
|
Pre-fix the chat composer's `TextField` had no keyboard dismissal at all — the keyboard would rise and stick, hiding the system tab bar (which iOS auto-hides while a keyboard is up) and trapping users in the Chat tab. v2.5.1 adds two redundant dismissal paths:
|
||||||
@@ -99,4 +117,4 @@ Each Mac window is bound to one server, so chat in window A talks to local Herme
|
|||||||
- [Settings — Voice tab](Gateway-Cron-Health-Logs) for TTS/STT configuration (Settings is documented there).
|
- [Settings — Voice tab](Gateway-Cron-Health-Logs) for TTS/STT configuration (Settings is documented there).
|
||||||
|
|
||||||
---
|
---
|
||||||
_Last updated: 2026-04-27 — Scarf v2.5.1 (chat density preferences + streaming O(n)-per-token fix + iOS keyboard dismissal)_
|
_Last updated: 2026-04-29 — Scarf v2.5.2 (chat-start model preflight + ScarfGo resilience + cached-snapshot fallback + bounded history paging)_
|
||||||
|
|||||||
+18
-2
@@ -12,12 +12,28 @@ In v2.5 most service code moved out of the Mac target into the shared **ScarfCor
|
|||||||
| [`HermesFileService`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/HermesFileService.swift) | `Sendable struct` | ~620 | Parses `config.yaml` into typed nested structs (now including `platform_toolsets`); resolves `hermes` binary; enriches `$PATH` for spawned tools (brew/nvm/asdf). |
|
| [`HermesFileService`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/HermesFileService.swift) | `Sendable struct` | ~620 | Parses `config.yaml` into typed nested structs (now including `platform_toolsets`); resolves `hermes` binary; enriches `$PATH` for spawned tools (brew/nvm/asdf). |
|
||||||
| [`HermesFileWatcher`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/HermesFileWatcher.swift) | `@Observable` | ~122 | Local: FSEvents via `DispatchSourceFileSystemObject`. Remote: mtime polling over the SSH ControlMaster. Updates `lastChangeDate`; views observe and refresh. |
|
| [`HermesFileWatcher`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/HermesFileWatcher.swift) | `@Observable` | ~122 | Local: FSEvents via `DispatchSourceFileSystemObject`. Remote: mtime polling over the SSH ControlMaster. Updates `lastChangeDate`; views observe and refresh. |
|
||||||
| [`HermesLogService`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/HermesLogService.swift) | `actor` | ~173 | Tails `agent.log` / `errors.log` / `gateway.log`. Local: `FileHandle`. Remote: `ssh host tail -F` with partial-line buffering. |
|
| [`HermesLogService`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/HermesLogService.swift) | `actor` | ~173 | Tails `agent.log` / `errors.log` / `gateway.log`. Local: `FileHandle`. Remote: `ssh host tail -F` with partial-line buffering. |
|
||||||
| [`ModelCatalogService`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/ModelCatalogService.swift) | `Sendable struct` | ~290 | Reads `~/.hermes/models_dev_cache.json` (~1500 models across ~110 providers) **and merges `HERMES_OVERLAYS`** — 6 provider entries (Nous Portal, OpenAI Codex, Qwen OAuth, Google Gemini CLI, GitHub Copilot ACP, Arcee) Hermes exposes via `hermes model` that aren't in the models.dev mirror. Helpers for cost + context-window display. |
|
| [`ModelCatalogService`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/ModelCatalogService.swift) | `Sendable struct` | ~290 | Reads `~/.hermes/models_dev_cache.json` (~1500 models across ~110 providers) **and merges `HERMES_OVERLAYS`** — 6 provider entries (Nous Portal, OpenAI Codex, Qwen OAuth, Google Gemini CLI, GitHub Copilot ACP, Arcee) Hermes exposes via `hermes model` that aren't in the models.dev mirror. Helpers for cost + context-window display. _v2.5.2:_ `loadProvidersAsync()` and `loadModelsAsync(for:)` wrappers route the multi-MB JSON read off the MainActor — issue [#59](https://github.com/awizemann/scarf/issues/59). |
|
||||||
| [`NousSubscriptionService`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/NousSubscriptionService.swift) | `Sendable struct` | ~85 | Read-only parser for `~/.hermes/auth.json` → `providers.nous`. Returns `NousSubscriptionState { present, providerIsNous, subscribed }`. Tool Gateway features gate on this. Hermes owns the write path (`hermes auth add nous`). |
|
| [`NousSubscriptionService`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/NousSubscriptionService.swift) | `Sendable struct` | ~85 | Read-only parser for `~/.hermes/auth.json` → `providers.nous`. Returns `NousSubscriptionState { present, providerIsNous, subscribed }`. Tool Gateway features gate on this. Hermes owns the write path (`hermes auth add nous`). |
|
||||||
| [`NousAuthFlow`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/NousAuthFlow.swift) | `@Observable @MainActor` | ~200 | Drives the Nous Portal device-code sign-in. Spawns `hermes auth add nous --no-browser` with `PYTHONUNBUFFERED=1` (Python block-buffers without it, stalling the flow). Regex-extracts `verification_uri_complete` + `user_code` from stdout, auto-opens the browser via `NSWorkspace`, confirms success by re-reading `auth.json`, detects the `subscription_required` failure and extracts the billing URL. Parsers are `nonisolated static` for easy testing. |
|
| [`NousAuthFlow`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/NousAuthFlow.swift) | `@Observable @MainActor` | ~200 | Drives the Nous Portal device-code sign-in. Spawns `hermes auth add nous --no-browser` with `PYTHONUNBUFFERED=1` (Python block-buffers without it, stalling the flow). Regex-extracts `verification_uri_complete` + `user_code` from stdout, auto-opens the browser via `NSWorkspace`, confirms success by re-reading `auth.json`, detects the `subscription_required` failure and extracts the billing URL. Parsers are `nonisolated static` for easy testing. |
|
||||||
| [`ProjectDashboardService`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/ProjectDashboardService.swift) | `Sendable struct` | ~71 | Loads/saves the project registry and per-project `.scarf/dashboard.json`. |
|
| [`ProjectDashboardService`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/ProjectDashboardService.swift) | `Sendable struct` | ~71 | Loads/saves the project registry and per-project `.scarf/dashboard.json`. |
|
||||||
| [`UpdaterService`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/UpdaterService.swift) | `@MainActor @Observable` | ~41 | Thin Sparkle wrapper exposing the auto-check toggle, last-check date, and a "check now" trigger. |
|
| [`UpdaterService`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/UpdaterService.swift) | `@MainActor @Observable` | ~41 | Thin Sparkle wrapper exposing the auto-check toggle, last-check date, and a "check now" trigger. |
|
||||||
|
|
||||||
|
## v2.5.2 additions (in ScarfCore)
|
||||||
|
|
||||||
|
| Service | Isolation | Purpose |
|
||||||
|
|---|---|---|
|
||||||
|
| `ModelPreflight` | `Sendable enum` | Pre-flight check used before opening an ACP session. Hermes resolves model+provider from `config.yaml` at session boot; on a fresh install that file is missing or has the YAML parser's `"unknown"` fallback for those keys, and the chat fails with an opaque "Model parameter is required" 400 from the upstream provider only after the user has typed a prompt. Catches the missing config here so `ChatView` can surface a real "pick a model" sheet before any ACP work starts. Treats `""` and `"unknown"` as equivalent. |
|
||||||
|
| `NousModelCatalogService` | `Sendable struct` | Fetches `GET /v1/models` from `inference-api.nousresearch.com` using the bearer token in `auth.json`. Cached at `~/.hermes/scarf/nous_models_cache.json` with a 24h TTL; survives offline runs so the picker still has something to render. Used by `ModelPickerSheet`'s nous-overlay detail view to switch from a free-form TextField to a real model list (with a "Custom…" escape hatch for IDs not yet in the API response). |
|
||||||
|
| `ProjectHermesShadowDetector` | `Sendable struct` | Probes each registered project at chat-start for project-local Hermes config (`.hermes/` dir or `hermes.yaml` file) that would shadow the server-level config. Surfaces a banner explaining the shadow when found — a quiet failure mode pre-fix where users didn't realize Hermes prefers project-local config. |
|
||||||
|
| `HermesFileService.runHermesWithStdin` | `Sendable` (extension) | Runs a `hermes` subcommand with bytes piped via stdin. Used by the new remote profile import flow to pass the zip contents through SSH stdin rather than landing them on the remote disk first. |
|
||||||
|
| `ServerTransport.cachedSnapshotPath` | protocol additive | Implementations expose the path of the most recent successful `state.db` snapshot. `HermesDataService.refresh(forceFresh:)` falls back to the cache when a fresh pull fails, so Dashboard / Sessions / Activity stay readable while the SSH connection is down. `isUsingStaleSnapshot` + `lastSnapshotMtime` surface to the UI. |
|
||||||
|
|
||||||
|
## v2.5.2 additions (iOS-only — in ScarfIOS)
|
||||||
|
|
||||||
|
| Service | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `NetworkReachabilityService` | `NWPathMonitor` singleton. ScarfGo's reconnect loop suspends attempts while offline and kicks a fresh cycle on link-up. Two new banner states above the message list — `.reconnecting` and `.offline` — render slim ScarfDesign-tinted strips so the user always knows what the chat is doing. |
|
||||||
|
|
||||||
## v2.5.1 additions (in ScarfCore)
|
## v2.5.1 additions (in ScarfCore)
|
||||||
|
|
||||||
| Service | Isolation | Purpose |
|
| Service | Isolation | Purpose |
|
||||||
@@ -75,4 +91,4 @@ See [ScarfCore Package](ScarfCore-Package) for the package architecture and how
|
|||||||
See [Adding a Service](Adding-a-Service) for the recipe. Short version: take `ServerContext` in `init`, decide isolation (`actor` for stateful, `struct` for stateless), expose async public methods, route I/O through `context.transport`.
|
See [Adding a Service](Adding-a-Service) for the recipe. Short version: take `ServerContext` in `init`, decide isolation (`actor` for stateful, `struct` for stateless), expose async public methods, route I/O through `context.transport`.
|
||||||
|
|
||||||
---
|
---
|
||||||
_Last updated: 2026-04-27 — Scarf v2.5.1 (HermesProfileResolver + SSHScriptRunner; iCloud Keychain sync option on KeychainSSHKeyStore)_
|
_Last updated: 2026-04-29 — Scarf v2.5.2 (ModelPreflight + NousModelCatalogService + ProjectHermesShadowDetector + NetworkReachabilityService; ModelCatalogService async wrappers; ServerTransport.cachedSnapshotPath)_
|
||||||
|
|||||||
+2
-1
@@ -41,6 +41,7 @@ These are written by Scarf, never by Hermes. Both clients (Mac + iOS) read and w
|
|||||||
| `<project>/.scarf/manifest.json` | Cached `template.json` for templates with a config schema | Drives the post-install Configuration sheet. |
|
| `<project>/.scarf/manifest.json` | Cached `template.json` for templates with a config schema | Drives the post-install Configuration sheet. |
|
||||||
| `<project>/.scarf/config.json` | Non-secret configuration values | Secrets are `keychain://...` URIs; resolved at use time. |
|
| `<project>/.scarf/config.json` | Non-secret configuration values | Secrets are `keychain://...` URIs; resolved at use time. |
|
||||||
| `<project>/.scarf/slash-commands/<name>.md` _(v2.5+)_ | Project-scoped slash commands | See [Slash Commands](Slash-Commands). |
|
| `<project>/.scarf/slash-commands/<name>.md` _(v2.5+)_ | Project-scoped slash commands | See [Slash Commands](Slash-Commands). |
|
||||||
|
| `~/.hermes/scarf/nous_models_cache.json` _(v2.5.2+)_ | Cached Nous Portal model list (24h TTL) | Populated by `NousModelCatalogService` from `GET /v1/models`. Survives offline so the picker still has a model list to render. |
|
||||||
| `<project>/AGENTS.md` (between `<!-- scarf-project:begin -->` markers) | Auto-managed project context block | Idempotent, secret-safe. See [Projects & Profiles](Projects-and-Profiles). |
|
| `<project>/AGENTS.md` (between `<!-- scarf-project:begin -->` markers) | Auto-managed project context block | Idempotent, secret-safe. See [Projects & Profiles](Projects-and-Profiles). |
|
||||||
|
|
||||||
## ACP
|
## ACP
|
||||||
@@ -73,4 +74,4 @@ ScarfGo can't write to `~/Library/Caches/scarf/...` — it lives in its own iOS
|
|||||||
Hermes log lines may carry an optional `[session_id]` tag between the level and the logger name. `HermesLogService.parseLine` treats the session tag as an optional capture group, so older untagged lines still parse correctly.
|
Hermes log lines may carry an optional `[session_id]` tag between the level and the logger name. `HermesLogService.parseLine` treats the session tag as an optional capture group, so older untagged lines still parse correctly.
|
||||||
|
|
||||||
---
|
---
|
||||||
_Last updated: 2026-04-27 — Scarf v2.5.1 (active_profile awareness via HermesProfileResolver; iOS Keychain optional iCloud sync)_
|
_Last updated: 2026-04-29 — Scarf v2.5.2 (Nous live catalog cache path)_
|
||||||
|
|||||||
+2
-2
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
A native macOS companion app for the [Hermes AI agent](https://github.com/hermes-ai/hermes-agent). Full visibility into what Hermes is doing, when, and what it creates — across one local install or many remote ones.
|
A native macOS companion app for the [Hermes AI agent](https://github.com/hermes-ai/hermes-agent). Full visibility into what Hermes is doing, when, and what it creates — across one local install or many remote ones.
|
||||||
|
|
||||||
**Latest release:** [v2.5.0](https://github.com/awizemann/scarf/releases/tag/v2.5.0) — ScarfGo iOS companion + ScarfDesign overhaul + Hermes v0.11 chat parity. Patched in [v2.5.1](https://github.com/awizemann/scarf/releases/tag/v2.5.1) (Mac chat performance, Hermes v0.11 profile awareness, iOS keyboard dismissal, opt-in iCloud Keychain sync, chat density preferences — see [release notes](https://github.com/awizemann/scarf/blob/main/releases/v2.5.1/RELEASE_NOTES.md)).
|
**Latest release:** [v2.5.0](https://github.com/awizemann/scarf/releases/tag/v2.5.0) — ScarfGo iOS companion + ScarfDesign overhaul + Hermes v0.11 chat parity. Patched in [v2.5.1](https://github.com/awizemann/scarf/releases/tag/v2.5.1) (Mac chat performance, Hermes v0.11 profile awareness, iOS keyboard dismissal, opt-in iCloud Keychain sync, chat density preferences) and [v2.5.2](https://github.com/awizemann/scarf/releases/tag/v2.5.2) (iOS chat resilience + reconnect, cached snapshot fallback, history paging, chat-start model preflight, Nous Portal live catalog, remote-aware admin sheets — see [release notes](https://github.com/awizemann/scarf/blob/main/releases/v2.5.2/RELEASE_NOTES.md)).
|
||||||
**Latest mobile:** [Join the public TestFlight](https://testflight.apple.com/join/qCrRpcTz). The link is live now but only accepts new beta testers once Apple's Beta Review approves the first build — see [ScarfGo](ScarfGo) for the full feature tour.
|
**Latest mobile:** [Join the public TestFlight](https://testflight.apple.com/join/qCrRpcTz). The link is live now but only accepts new beta testers once Apple's Beta Review approves the first build — see [ScarfGo](ScarfGo) for the full feature tour.
|
||||||
**Targets Hermes:** v0.11.0 (v2026.4.23) — `/steer`, new state.db columns, design-md/spotify skills, SKILL.md frontmatter chips. v0.10.0 still works for everything that didn't change.
|
**Targets Hermes:** v0.11.0 (v2026.4.23) — `/steer`, new state.db columns, design-md/spotify skills, SKILL.md frontmatter chips. v0.10.0 still works for everything that didn't change.
|
||||||
**Available in:** English, Simplified Chinese (zh-Hans), German (de), French (fr), Spanish (es), Japanese (ja), Brazilian Portuguese (pt-BR). See [Localization](Localization). _ScarfGo is English-only in v1._
|
**Available in:** English, Simplified Chinese (zh-Hans), German (de), French (fr), Spanish (es), Japanese (ja), Brazilian Portuguese (pt-BR). See [Localization](Localization). _ScarfGo is English-only in v1._
|
||||||
@@ -40,4 +40,4 @@ Scarf 2.0 is a multi-window app — one window per Hermes server, local or remot
|
|||||||
Open-source (MIT), 160+ stars, actively maintained. See [Roadmap](Roadmap) for what's coming.
|
Open-source (MIT), 160+ stars, actively maintained. See [Roadmap](Roadmap) for what's coming.
|
||||||
|
|
||||||
---
|
---
|
||||||
_Last updated: 2026-04-27 — Scarf v2.5.1 patch (Mac + iOS bugfixes + chat density + iCloud Keychain sync)_
|
_Last updated: 2026-04-29 — Scarf v2.5.2 patch (iOS chat resilience + remote-aware admin sheets + Nous live catalog)_
|
||||||
|
|||||||
+2
-2
@@ -26,7 +26,7 @@ Three entry points, all under **Projects → Templates** in the project sidebar'
|
|||||||
|
|
||||||
Every install goes through a preview sheet that lists:
|
Every install goes through a preview sheet that lists:
|
||||||
|
|
||||||
- The exact project directory to be created (you pick the parent folder).
|
- The exact project directory to be created (you pick the parent folder). _v2.5.2+:_ on remote server contexts the parent-directory step uses a path-input + Verify sheet (mirroring the Add Project pattern from #54) — the installer writes the project files to the remote host via SFTP rather than to the Mac filesystem.
|
||||||
- Every file inside the project.
|
- Every file inside the project.
|
||||||
- Every skill to be namespaced under `~/.hermes/skills/templates/<slug>/`.
|
- Every skill to be namespaced under `~/.hermes/skills/templates/<slug>/`.
|
||||||
- Every cron job to be registered, always paused on install — you enable each one manually from the Cron sidebar when ready.
|
- Every cron job to be registered, always paused on install — you enable each one manually from the Cron sidebar when ready.
|
||||||
@@ -285,4 +285,4 @@ Use `{{PROJECT_DIR}}` in the cron prompt. Hermes doesn't set a CWD for cron runs
|
|||||||
- [Release Notes Index](Release-Notes-Index) — v2.2.0 for the full launch notes.
|
- [Release Notes Index](Release-Notes-Index) — v2.2.0 for the full launch notes.
|
||||||
|
|
||||||
---
|
---
|
||||||
_Last updated: 2026-04-25 — Scarf v2.5.0 (schemaVersion 3 — slash commands)_
|
_Last updated: 2026-04-29 — Scarf v2.5.2 (remote-aware parent-directory pick on remote server contexts)_
|
||||||
|
|||||||
+3
-3
@@ -44,8 +44,8 @@ A profile is an isolated Hermes installation — separate config, sessions, memo
|
|||||||
|
|
||||||
- **Switch** — make a profile active. Scarf shows a "restart Scarf to fully apply" reminder; the resolver re-reads `active_profile` on launch and on each `HermesPathSet` construction (5s cache).
|
- **Switch** — make a profile active. Scarf shows a "restart Scarf to fully apply" reminder; the resolver re-reads `active_profile` on launch and on each `HermesPathSet` construction (5s cache).
|
||||||
- **Create / rename / delete** — straightforward.
|
- **Create / rename / delete** — straightforward.
|
||||||
- **Export** — zips the profile directory; useful for backup or moving to a new machine.
|
- **Export** — zips the profile directory; useful for backup or moving to a new machine. _v2.5.2+:_ on remote contexts a path-input + Verify sheet captures the destination zip path on the SSH host (mirrors the Add Project sheet's pattern from #54).
|
||||||
- **Import** — unzip into a new profile slot.
|
- **Import** — unzip into a new profile slot. _v2.5.2+:_ on remote contexts a path-input + Verify sheet captures the source zip path on the SSH host. Local context still uses `NSOpenPanel`. Drives `hermes profile import <zip>` over SSH; bytes are piped via `HermesFileService.runHermesWithStdin` (rather than landing on the remote disk first) when invoked from the local-file-on-Mac flow.
|
||||||
|
|
||||||
Remote SSH contexts don't yet auto-resolve `active_profile` — `HermesPathSet.defaultRemoteHome` stays at the configured remote home. If you're using profiles on a remote, set the **Hermes data directory** field in Manage Servers to point at `~/.hermes/profiles/<name>` for that server context. Issue [#53](https://github.com/awizemann/scarf/issues/53)'s degraded-pill diagnostics will tell you when this is the cause of an empty dashboard.
|
Remote SSH contexts don't yet auto-resolve `active_profile` — `HermesPathSet.defaultRemoteHome` stays at the configured remote home. If you're using profiles on a remote, set the **Hermes data directory** field in Manage Servers to point at `~/.hermes/profiles/<name>` for that server context. Issue [#53](https://github.com/awizemann/scarf/issues/53)'s degraded-pill diagnostics will tell you when this is the cause of an empty dashboard.
|
||||||
|
|
||||||
@@ -58,4 +58,4 @@ Remote SSH contexts don't yet auto-resolve `active_profile` — `HermesPathSet.d
|
|||||||
- [Settings](Gateway-Cron-Health-Logs) — exposes "Backup & Restore" buttons (`hermes backup` / `hermes import`) at the profile level.
|
- [Settings](Gateway-Cron-Health-Logs) — exposes "Backup & Restore" buttons (`hermes backup` / `hermes import`) at the profile level.
|
||||||
|
|
||||||
---
|
---
|
||||||
_Last updated: 2026-04-27 — Scarf v2.5.1 (Hermes v0.11 profile awareness via HermesProfileResolver + active_profile chip in chat info bar)_
|
_Last updated: 2026-04-29 — Scarf v2.5.2 (remote-aware profile import/export sheets)_
|
||||||
|
|||||||
+4
-1
@@ -4,6 +4,7 @@ Every Scarf release in chronological order. The notes themselves live in `releas
|
|||||||
|
|
||||||
| Version | Date | GitHub release | Notes file |
|
| Version | Date | GitHub release | Notes file |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
|
| **v2.5.2** | 2026-04-29 | [v2.5.2](https://github.com/awizemann/scarf/releases/tag/v2.5.2) | [`releases/v2.5.2/RELEASE_NOTES.md`](https://github.com/awizemann/scarf/blob/main/releases/v2.5.2/RELEASE_NOTES.md) |
|
||||||
| **v2.5.1** | 2026-04-27 | [v2.5.1](https://github.com/awizemann/scarf/releases/tag/v2.5.1) | [`releases/v2.5.1/RELEASE_NOTES.md`](https://github.com/awizemann/scarf/blob/main/releases/v2.5.1/RELEASE_NOTES.md) |
|
| **v2.5.1** | 2026-04-27 | [v2.5.1](https://github.com/awizemann/scarf/releases/tag/v2.5.1) | [`releases/v2.5.1/RELEASE_NOTES.md`](https://github.com/awizemann/scarf/blob/main/releases/v2.5.1/RELEASE_NOTES.md) |
|
||||||
| **v2.5.0** | 2026-04-25 | [v2.5.0](https://github.com/awizemann/scarf/releases/tag/v2.5.0) | [`releases/v2.5.0/RELEASE_NOTES.md`](https://github.com/awizemann/scarf/blob/main/releases/v2.5.0/RELEASE_NOTES.md) |
|
| **v2.5.0** | 2026-04-25 | [v2.5.0](https://github.com/awizemann/scarf/releases/tag/v2.5.0) | [`releases/v2.5.0/RELEASE_NOTES.md`](https://github.com/awizemann/scarf/blob/main/releases/v2.5.0/RELEASE_NOTES.md) |
|
||||||
| **v2.3.0** | 2026-04-24 | [v2.3.0](https://github.com/awizemann/scarf/releases/tag/v2.3.0) | [`releases/v2.3.0/RELEASE_NOTES.md`](https://github.com/awizemann/scarf/blob/main/releases/v2.3.0/RELEASE_NOTES.md) |
|
| **v2.3.0** | 2026-04-24 | [v2.3.0](https://github.com/awizemann/scarf/releases/tag/v2.3.0) | [`releases/v2.3.0/RELEASE_NOTES.md`](https://github.com/awizemann/scarf/blob/main/releases/v2.3.0/RELEASE_NOTES.md) |
|
||||||
@@ -20,6 +21,8 @@ Every Scarf release in chronological order. The notes themselves live in `releas
|
|||||||
|
|
||||||
## Highlights by major
|
## Highlights by major
|
||||||
|
|
||||||
|
**2.5.2** — Patch release with one substantial new feature (**iOS chat resilience**) plus a stack of fixes. ScarfGo gains 5-attempt exponential reconnect via `session/resume`/`session/load`, a `NetworkReachabilityService` that suspends reconnect attempts while offline, scene-phase aware reconnect on foreground, and per-session draft persistence — phone-sleep, network handoffs, and SSH socket drops no longer cost the agent's work. Cross-platform cached-snapshot fallback (`ServerTransport.cachedSnapshotPath`) lets Dashboard / Sessions / Activity stay readable while the connection is down. Bounded message-history paging via `HermesDataService.fetchMessages(limit:before:)` + `loadEarlier()` replaces the prior unbounded fetch — long sessions stay smooth. Mac fixes: Settings → Model and Credential Pools no longer freeze for 1–2 minutes on remote contexts ([#59](https://github.com/awizemann/scarf/issues/59)) — `loadProvidersAsync()` / `loadModelsAsync(for:)` dispatch off MainActor. Diagnostics tri-state — missing `config.yaml` is informational on a fresh Hermes v0.11 install (Hermes lazy-creates it), reads "12/12 passing (2 optional skipped)" instead of "12/14". Credential Pools surfaces OAuth-authed providers (Nous, Spotify, Copilot, Qwen, Gemini) in a parallel section. New `ProjectHermesShadowDetector` warns when a project-local `.hermes/` shadows the server-level config. iOS fixes: [#56](https://github.com/awizemann/scarf/issues/56) Citadel snapshot path now uses `executeCommandStream` + Citadel-friendly `PATH=` prefix so missing-sqlite3 errors surface meaningfully; [#57](https://github.com/awizemann/scarf/issues/57) keyboard-dismiss chevron moved to the leading edge so it doesn't stack over the send button. New: chat-start model preflight (`ChatModelPreflightSheet`) catches missing model/provider before the ACP session opens; Nous Portal live model catalog (`NousModelCatalogService`); remote-aware admin sheets for profile import/export, backup restore, and template install destination — all mirroring the Add Project pattern from #54.
|
||||||
|
|
||||||
**2.5.1** — Patch release bundling every reported issue against 2.5.0 plus TestFlight-driven iOS fixes. Mac chat O(n)-per-token rendering bog-down on long sessions ([#46](https://github.com/awizemann/scarf/issues/46)) — settled bubbles now short-circuit body re-eval via `Equatable`, trailing-group patch helper replaces full `buildMessageGroups()` per chunk. Hermes v0.11 profile awareness ([#50](https://github.com/awizemann/scarf/issues/50)) — new `HermesProfileResolver` reads `~/.hermes/active_profile`, every derived path follows automatically, SessionInfoBar gains a profile chip. Granular reasons + actionable hint popover on the "Connected — can't read Hermes state" pill ([#53](https://github.com/awizemann/scarf/issues/53)). Pill probe and Run Diagnostics no longer disagree ([#44](https://github.com/awizemann/scarf/issues/44)) — both now go through a shared `SSHScriptRunner` that bypasses `runProcess`'s argument quoting. New chat density preferences in Settings → Display ([#47](https://github.com/awizemann/scarf/issues/47) + [#48](https://github.com/awizemann/scarf/issues/48)) — Tool calls Full / Compact / Hidden, Reasoning Disclosure / Inline / Hidden, chat font size 85–130%. iOS keyboard now dismissable via swipe + accessory toolbar ([#51](https://github.com/awizemann/scarf/issues/51)); first-run Cancel button hidden when there's nothing to cancel back to ([#55](https://github.com/awizemann/scarf/issues/55)); opt-in iCloud Keychain sync for SSH keys ([#52](https://github.com/awizemann/scarf/issues/52)) — pair iPhone + iPad without onboarding twice. Add Project on remote contexts now hides the local Browse button and shows a Verify-against-remote affordance ([#54](https://github.com/awizemann/scarf/issues/54)). Release pipeline gains a post-package codesign / spctl gate ([#49](https://github.com/awizemann/scarf/issues/49)). No data migrations.
|
**2.5.1** — Patch release bundling every reported issue against 2.5.0 plus TestFlight-driven iOS fixes. Mac chat O(n)-per-token rendering bog-down on long sessions ([#46](https://github.com/awizemann/scarf/issues/46)) — settled bubbles now short-circuit body re-eval via `Equatable`, trailing-group patch helper replaces full `buildMessageGroups()` per chunk. Hermes v0.11 profile awareness ([#50](https://github.com/awizemann/scarf/issues/50)) — new `HermesProfileResolver` reads `~/.hermes/active_profile`, every derived path follows automatically, SessionInfoBar gains a profile chip. Granular reasons + actionable hint popover on the "Connected — can't read Hermes state" pill ([#53](https://github.com/awizemann/scarf/issues/53)). Pill probe and Run Diagnostics no longer disagree ([#44](https://github.com/awizemann/scarf/issues/44)) — both now go through a shared `SSHScriptRunner` that bypasses `runProcess`'s argument quoting. New chat density preferences in Settings → Display ([#47](https://github.com/awizemann/scarf/issues/47) + [#48](https://github.com/awizemann/scarf/issues/48)) — Tool calls Full / Compact / Hidden, Reasoning Disclosure / Inline / Hidden, chat font size 85–130%. iOS keyboard now dismissable via swipe + accessory toolbar ([#51](https://github.com/awizemann/scarf/issues/51)); first-run Cancel button hidden when there's nothing to cancel back to ([#55](https://github.com/awizemann/scarf/issues/55)); opt-in iCloud Keychain sync for SSH keys ([#52](https://github.com/awizemann/scarf/issues/52)) — pair iPhone + iPad without onboarding twice. Add Project on remote contexts now hides the local Browse button and shows a Verify-against-remote affordance ([#54](https://github.com/awizemann/scarf/issues/54)). Release pipeline gains a post-package codesign / spctl gate ([#49](https://github.com/awizemann/scarf/issues/49)). No data migrations.
|
||||||
|
|
||||||
**2.5** — **[ScarfGo](ScarfGo) iOS companion** ships in public TestFlight + full **Hermes v2026.4.23 (v0.11.0)** support: `/steer` non-interruptive guidance, per-turn stopwatch, numbered approval shortcuts, git branch chip in chat header, `messages.reasoning_content` + `sessions.api_call_count` columns surfaced. **Portable project-scoped slash commands** — author at `<project>/.scarf/slash-commands/<name>.md` and ship via `.scarftemplate` (schemaVersion 3); Mac authoring tab + iOS read-only browser. New skills: in-app **Spotify OAuth sheet** + **design-md npx prereq check**. SKILL.md frontmatter chips (`allowed_tools`, `related_skills`, `dependencies`). "What's New" pill on the Skills tab tracks per-server skill deltas. Mac global Sessions gets project filter + badges (parity with ScarfGo). Cross-platform `CronScheduleFormatter`, `GitBranchService`, `SkillSnapshotService`, `SkillPrereqService`, `ProjectSlashCommandService`, `SpotifyAuthFlow` consolidate into ScarfCore. See [Platform Differences](Platform-Differences) for the Mac↔iOS feature matrix.
|
**2.5** — **[ScarfGo](ScarfGo) iOS companion** ships in public TestFlight + full **Hermes v2026.4.23 (v0.11.0)** support: `/steer` non-interruptive guidance, per-turn stopwatch, numbered approval shortcuts, git branch chip in chat header, `messages.reasoning_content` + `sessions.api_call_count` columns surfaced. **Portable project-scoped slash commands** — author at `<project>/.scarf/slash-commands/<name>.md` and ship via `.scarftemplate` (schemaVersion 3); Mac authoring tab + iOS read-only browser. New skills: in-app **Spotify OAuth sheet** + **design-md npx prereq check**. SKILL.md frontmatter chips (`allowed_tools`, `related_skills`, `dependencies`). "What's New" pill on the Skills tab tracks per-server skill deltas. Mac global Sessions gets project filter + badges (parity with ScarfGo). Cross-platform `CronScheduleFormatter`, `GitBranchService`, `SkillSnapshotService`, `SkillPrereqService`, `ProjectSlashCommandService`, `SpotifyAuthFlow` consolidate into ScarfCore. See [Platform Differences](Platform-Differences) for the Mac↔iOS feature matrix.
|
||||||
@@ -47,4 +50,4 @@ When `scripts/release.sh <version>` completes a full (non-draft) release, this p
|
|||||||
This is one of the [wiki update triggers](Wiki-Maintenance) that future Claude Code sessions will follow automatically.
|
This is one of the [wiki update triggers](Wiki-Maintenance) that future Claude Code sessions will follow automatically.
|
||||||
|
|
||||||
---
|
---
|
||||||
_Last updated: 2026-04-27 — Scarf v2.5.1 patch (Mac + iOS bugfixes + chat density + iCloud Keychain sync)_
|
_Last updated: 2026-04-29 — Scarf v2.5.2 patch (iOS chat resilience + remote-aware admin sheets + Nous live catalog)_
|
||||||
|
|||||||
+1
-1
@@ -116,4 +116,4 @@ A: [ScarfGo Roadmap](ScarfGo-Roadmap) tracks shipped milestones (M6 / M7 / M8 /
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
_Last updated: 2026-04-25 — v2.5 public TestFlight (corrected Settings — Quick Edits ship in v1)._
|
_Last updated: 2026-04-29 — Scarf v2.5.2 (Auto-reconnect + Draft persistence + Load earlier messages rows added to features matrix)._
|
||||||
|
|||||||
+7
-1
@@ -63,8 +63,14 @@ The Mac Dashboard surfaces a yellow banner ("Project-local Hermes home shadowing
|
|||||||
|
|
||||||
**Manage Servers → 🩺 Run Diagnostics** runs **fourteen** checks in one SSH session: connectivity, `sqlite3` presence, read access to `config.yaml` and `state.db`, the effective non-login `$PATH`, etc. Each failure explains itself with a remediation hint. **Copy Full Report** dumps the whole output for bug reports.
|
**Manage Servers → 🩺 Run Diagnostics** runs **fourteen** checks in one SSH session: connectivity, `sqlite3` presence, read access to `config.yaml` and `state.db`, the effective non-login `$PATH`, etc. Each failure explains itself with a remediation hint. **Copy Full Report** dumps the whole output for bug reports.
|
||||||
|
|
||||||
|
**Tri-state probes (v2.5.2+).** Hermes v0.11+ doesn't materialize `config.yaml` until the user changes a setting from defaults — so the diagnostics view was reporting *"12/14 passing"* on healthy fresh installs and confusing users into thinking something was wrong. Probes now distinguish `.pass` / `.fail` / `.skipped`; a missing `config.yaml` emits `SKIP` (Hermes lazy-creates it; only "exists but unreadable" still fails). The summary reads *"12/12 passing (2 optional skipped)"* and the probe titles say *"config.yaml readable (optional)"* so the file's optional nature is obvious at a glance. The pill's tier-2 probe checks `state.db` instead of `config.yaml` for the same reason.
|
||||||
|
|
||||||
**Pill probe and diagnostics now use the same plumbing** _(v2.5.1+)._ Both go through the shared [`SSHScriptRunner`](Core-Services) (raw `/usr/bin/ssh ... -- /bin/sh -s`, script piped via stdin) instead of the prior split where the pill went through `runProcess`'s argument quoting and the diagnostics view used a local workaround. They no longer disagree about what the remote sees — issue [#44](https://github.com/awizemann/scarf/issues/44).
|
**Pill probe and diagnostics now use the same plumbing** _(v2.5.1+)._ Both go through the shared [`SSHScriptRunner`](Core-Services) (raw `/usr/bin/ssh ... -- /bin/sh -s`, script piped via stdin) instead of the prior split where the pill went through `runProcess`'s argument quoting and the diagnostics view used a local workaround. They no longer disagree about what the remote sees — issue [#44](https://github.com/awizemann/scarf/issues/44).
|
||||||
|
|
||||||
|
## Project-shadowed Hermes detection _(v2.5.2+)_
|
||||||
|
|
||||||
|
A new `ProjectHermesShadowDetector` in ScarfCore probes each registered project at chat-start for project-local Hermes config (`.hermes/` dir or `hermes.yaml` file) that would shadow the server-level config. When found, the chat surfaces a banner explaining the shadow — a quiet failure mode pre-fix where users didn't realize Hermes prefers project-local config and were debugging server-level changes that weren't actually being used.
|
||||||
|
|
||||||
## Adding a project on a remote server _(v2.5.1+)_
|
## Adding a project on a remote server _(v2.5.1+)_
|
||||||
|
|
||||||
The Add Project sheet is now context-aware. On a local server it works as before — click **Browse...** to pick a directory with `NSOpenPanel`. On a remote server the Browse button is hidden (a Mac-local Finder dialog can't see the remote filesystem) and replaced with a **Verify** button that runs `transport.stat(path)` over SSH and renders a green ✓ if the path exists and is a directory, or a yellow ⚠ if it's missing / a file / unreadable. Edit the path field and the verification resets to idle so you don't see a stale ✓ for a path you've since changed.
|
The Add Project sheet is now context-aware. On a local server it works as before — click **Browse...** to pick a directory with `NSOpenPanel`. On a remote server the Browse button is hidden (a Mac-local Finder dialog can't see the remote filesystem) and replaced with a **Verify** button that runs `transport.stat(path)` over SSH and renders a green ✓ if the path exists and is a directory, or a yellow ⚠ if it's missing / a file / unreadable. Edit the path field and the verification resets to idle so you don't see a stale ✓ for a path you've since changed.
|
||||||
@@ -86,4 +92,4 @@ See [Keyboard Shortcuts](Keyboard-Shortcuts).
|
|||||||
- [Hermes Paths](Hermes-Paths) for what each remote file is.
|
- [Hermes Paths](Hermes-Paths) for what each remote file is.
|
||||||
|
|
||||||
---
|
---
|
||||||
_Last updated: 2026-04-27 — Scarf v2.5.1 (granular degraded-pill popover + unified pill/diagnostics transport + context-aware Add Project)_
|
_Last updated: 2026-04-29 — Scarf v2.5.2 (tri-state diagnostics + project-shadowed Hermes detection)_
|
||||||
|
|||||||
+1
-1
@@ -160,4 +160,4 @@ Citadel's `SSHClient.connect(...)` handshake costs ~500ms on a warm network. Sca
|
|||||||
See [ScarfGo Onboarding](ScarfGo-Onboarding) for user-side setup and [ScarfCore Package](ScarfCore-Package) for why `KeychainSSHKeyStore` lives in `ScarfIOS` and not `ScarfCore`.
|
See [ScarfGo Onboarding](ScarfGo-Onboarding) for user-side setup and [ScarfCore Package](ScarfCore-Package) for why `KeychainSSHKeyStore` lives in `ScarfIOS` and not `ScarfCore`.
|
||||||
|
|
||||||
---
|
---
|
||||||
_Last updated: 2026-04-25 — Scarf v2.5.0 (ScarfCore path refresh + CitadelServerTransport section)_
|
_Last updated: 2026-04-29 — Scarf v2.5.2 (snapshot fallback via `cachedSnapshotPath`)_
|
||||||
|
|||||||
Reference in New Issue
Block a user