mirror of
https://github.com/awizemann/scarf.git
synced 2026-05-08 02:14:37 +00:00
docs(v2.3): Tool Gateway — Nous Portal sign-in + Hermes v0.10.0 bump
+7
-4
@@ -1,16 +1,18 @@
|
||||
# Core Services
|
||||
|
||||
The 9 services under [`scarf/scarf/scarf/Core/Services/`](https://github.com/awizemann/scarf/tree/main/scarf/scarf/Core/Services) are the data-and-side-effects layer between Hermes and the SwiftUI features. Each takes a `ServerContext` (local or SSH) so the same service code works against a local install or a remote one.
|
||||
The 11 services under [`scarf/scarf/scarf/Core/Services/`](https://github.com/awizemann/scarf/tree/main/scarf/scarf/Core/Services) are the data-and-side-effects layer between Hermes and the SwiftUI features. Each takes a `ServerContext` (local or SSH) so the same service code works against a local install or a remote one.
|
||||
|
||||
| Service | Isolation | Lines | Purpose |
|
||||
|---|---|---|---|
|
||||
| [`ACPClient`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/ACPClient.swift) | `actor` | ~605 | Spawns `hermes acp` subprocess; JSON-RPC over stdio; async event stream for chat. |
|
||||
| [`HermesDataService`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/HermesDataService.swift) | `actor` | ~658 | Read-only SQLite queries against `state.db`; pulls atomic snapshots for remote; dedupes concurrent snapshot calls via a nested `SnapshotCoordinator` actor. |
|
||||
| [`HermesEnvService`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/HermesEnvService.swift) | `Sendable struct` | ~217 | Non-destructive `~/.hermes/.env` I/O — preserves comments and blanks; `unset` comments out instead of deleting. |
|
||||
| [`HermesFileService`](https://github.com/awizemann/scarf/blob/main/scarf/scarf/Core/Services/HermesFileService.swift) | `Sendable struct` | ~600 | Parses `config.yaml` into typed nested structs; 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. |
|
||||
| [`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` | ~210 | Reads `~/.hermes/models_dev_cache.json` (~1500 models across ~110 providers); helpers for cost and 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. |
|
||||
| [`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. |
|
||||
| [`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. |
|
||||
|
||||
@@ -22,10 +24,11 @@ The 9 services under [`scarf/scarf/scarf/Core/Services/`](https://github.com/awi
|
||||
- **Schema tolerance.** `HermesDataService` checks for v0.7+ columns (`reasoning_tokens`, `actual_cost_usd`, `cost_status`, `billing_provider`) and degrades gracefully on older databases.
|
||||
- **Snapshot dedup.** `SnapshotCoordinator` (nested in `HermesDataService`) ensures concurrent callers from Dashboard + Sessions + Activity await the same in-flight `sqlite3 .backup` rather than each spawning a fresh one.
|
||||
- **Error hints over raw stderr.** `ACPClient` keeps a 50-line stderr ring buffer and pattern-matches into `ACPErrorHint` for user-friendly messages (missing `ANTHROPIC_API_KEY`, binary not on `PATH`, rate-limited).
|
||||
- **Subprocess parsers are pure and testable.** `NousAuthFlow.parseDeviceCode` and `parseSubscriptionRequired` are `nonisolated static` functions over `String` → regex capture, so tests feed fixture stdout buffers without standing up a live subprocess. Same shape `OAuthFlowController.extractAuthURL` already uses for PKCE.
|
||||
|
||||
## Adding a service
|
||||
|
||||
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-20 — Scarf v2.0.1_
|
||||
_Last updated: 2026-04-24 — Scarf v2.3.0_
|
||||
|
||||
@@ -4,7 +4,7 @@ Scarf reads Hermes's SQLite database directly and parses CLI output from `hermes
|
||||
|
||||
## Currently targeted
|
||||
|
||||
**Scarf 2.0.x targets Hermes v0.10.0** for the ACP `session/fork` / `session/list` / `session/resume` capabilities used by remote chat. The `CLAUDE.md` in the repo declares this as `Targets Hermes v0.9.0 (v2026.4.13)` for the broader feature set; v0.10.0 is the recommended minimum to get every chat capability working.
|
||||
**Scarf 2.3.x targets Hermes v0.10.0 (v2026.4.16)**, bumped from Scarf 2.2's v0.9.0 target. v0.10.0 is the recommended minimum to get every feature working — the **Tool Gateway** surface (Nous Portal in the model picker, subscription detection, per-task Nous routing, in-app sign-in, Credential Pools auth-type gating) is sourced from the `HERMES_OVERLAYS` table in `hermes-agent/hermes_cli/providers.py`, which is only populated in v0.10.0+. On earlier Hermes releases, Scarf 2.3 still runs — you just won't see Nous Portal in the picker and the Tool Gateway Health card won't have subscription data to show. ACP `session/fork` / `session/list` / `session/resume` used by remote chat also need v0.10.0.
|
||||
|
||||
## Verified versions
|
||||
|
||||
@@ -14,7 +14,7 @@ Scarf reads Hermes's SQLite database directly and parses CLI output from `hermes
|
||||
| v0.7.0 | 2026-04-03 | Verified |
|
||||
| v0.8.0 | 2026-04-08 | Verified |
|
||||
| v0.9.0 | 2026-04-13 | Verified |
|
||||
| v0.10.0 | 2026-04-18 | Verified (recommended for full 2.0 feature support) |
|
||||
| v0.10.0 | 2026-04-16 | **Verified — current target (Tool Gateway requires this)** |
|
||||
|
||||
## How compatibility is maintained
|
||||
|
||||
@@ -26,6 +26,10 @@ Scarf reads Hermes's SQLite database directly and parses CLI output from `hermes
|
||||
|
||||
**CLI output parsing.** Where Scarf parses `hermes` CLI output (Health, Tools, Pairing), the parsers tolerate field reordering and unknown lines.
|
||||
|
||||
**HERMES_OVERLAYS mirror.** [`ModelCatalogService.overlayOnlyProviders`](Core-Services) mirrors the 6 overlay-only entries from `hermes-agent/hermes_cli/providers.py` (Nous Portal, OpenAI Codex, Qwen OAuth, Google Gemini CLI, GitHub Copilot ACP, Arcee). When Hermes adds a new overlay-only provider, Scarf needs a release to surface it in the picker — but existing overlays silently pick up base-URL and auth-type refinements without a Scarf release, because only the identity is mirrored, not the full overlay struct.
|
||||
|
||||
**Device-code OAuth flow (v0.10.0+).** Nous Portal sign-in goes through `hermes auth add nous --no-browser` as a subprocess (see [`NousAuthFlow`](Core-Services)). Scarf regex-extracts the device-code block from stdout and auto-opens the verification URL via `NSWorkspace`. On success, it re-reads `~/.hermes/auth.json` to confirm `providers.nous.access_token` landed. Any change to Hermes's `To continue: / 1. Open: / 2. If prompted, enter code:` output shape would break the parser — low-risk because it's been stable across v0.9 and v0.10, but worth a smoke test on future Hermes releases.
|
||||
|
||||
## What breaks across major Hermes versions
|
||||
|
||||
If Hermes ships a major release that changes:
|
||||
@@ -46,4 +50,4 @@ If a new Hermes release breaks something in Scarf, please file an issue includin
|
||||
- The relevant log snippet from `~/.hermes/logs/errors.log` (filter sensitive content first).
|
||||
|
||||
---
|
||||
_Last updated: 2026-04-20 — Scarf v2.0.1_
|
||||
_Last updated: 2026-04-24 — Scarf v2.3.0_
|
||||
|
||||
+3
-3
@@ -2,8 +2,8 @@
|
||||
|
||||
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.2.1](https://github.com/awizemann/scarf/releases/tag/v2.2.1)
|
||||
**Targets Hermes:** v0.9.0 (v2026.4.13)
|
||||
**Latest release:** [v2.2.1](https://github.com/awizemann/scarf/releases/tag/v2.2.1) (v2.3.0 queued — bump this line after `scripts/release.sh` completes)
|
||||
**Targets Hermes:** v0.10.0 (v2026.4.16) — Tool Gateway features require this
|
||||
**Available in:** English, Simplified Chinese (zh-Hans), German (de), French (fr), Spanish (es), Japanese (ja), Brazilian Portuguese (pt-BR). See [Localization](Localization).
|
||||
|
||||
## Quick links
|
||||
@@ -33,4 +33,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.
|
||||
|
||||
---
|
||||
_Last updated: 2026-04-23 — Scarf v2.2.1_
|
||||
_Last updated: 2026-04-24 — Scarf v2.3.0 queued_
|
||||
|
||||
Reference in New Issue
Block a user