mirror of
https://github.com/awizemann/scarf.git
synced 2026-05-10 10:36:35 +00:00
docs: refresh for Scarf v2.5.1 — profiles, density, keychain sync, pill, remote project add, release gate
+24
-1
@@ -27,6 +27,29 @@ Streams tokens, thoughts, and tool calls live via the [ACP subprocess](ACP-Subpr
|
|||||||
|
|
||||||
**Voice mode controls:** PTT (push-to-talk), TTS playback, STT transcription preferences live in **Settings → Voice**. The chat toolbar exposes the basic toggles.
|
**Voice mode controls:** PTT (push-to-talk), TTS playback, STT transcription preferences live in **Settings → Voice**. The chat toolbar exposes the basic toggles.
|
||||||
|
|
||||||
|
## Chat density preferences _(v2.5.1+, Mac)_
|
||||||
|
|
||||||
|
**Settings → Display → Chat density** has three Scarf-local controls that change how the chat is rendered. They're independent of the Hermes config flags one section below (`Show Reasoning`, `Show Cost`, `Compact`) — those gate what Hermes EMITS, these gate how Scarf RENDERS what was emitted.
|
||||||
|
|
||||||
|
- **Tool calls** — `Full card` (today's expandable card per call), `Compact chip` (one-line tappable chip per call — kind icon + function name + status dot — opening the right-pane inspector with the same details), `Hidden` (per-call rows skipped; the always-visible group summary pill stays and becomes tappable so the inspector is still one click away).
|
||||||
|
- **Reasoning** — `Disclosure box` (today's yellow box), `Inline (italic)` (italic faded caption text inline above the reply with a small brain prefix — same data, far less vertical space), `Hidden` (reasoning text not rendered; per-message token count stays visible in the bubble's metadata footer).
|
||||||
|
- **Chat font size** — 85% to 130% slider (5% step) applied at the chat root via `.environment(\.dynamicTypeSize, ...)` so the message list, input bar, session info bar, and inspector pane scale together.
|
||||||
|
|
||||||
|
Defaults match today's UI exactly so existing users see no change until they opt in. Per-turn stopwatch, per-message tokens, finish reason, and timestamp stay in the bubble metadata footer in every density mode; SessionInfoBar's input/output/reasoning tokens, USD cost, model, project, and git branch are unaffected. See issues [#47](https://github.com/awizemann/scarf/issues/47) and [#48](https://github.com/awizemann/scarf/issues/48) for the original asks and the full preservation audit.
|
||||||
|
|
||||||
|
## Streaming performance _(v2.5.1)_
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
## 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:
|
||||||
|
|
||||||
|
- `.scrollDismissesKeyboard(.interactively)` on the message list — drag the messages downward to collapse the keyboard with the gesture.
|
||||||
|
- A `keyboard.chevron.compact.down` button in the keyboard accessory toolbar above the system keyboard.
|
||||||
|
|
||||||
|
Either dismisses the keyboard, the system tab bar reappears, and the user can switch tabs again. Issue [#51](https://github.com/awizemann/scarf/issues/51).
|
||||||
|
|
||||||
## Terminal mode
|
## Terminal mode
|
||||||
|
|
||||||
The full `hermes chat` CLI rendered in an embedded SwiftTerm terminal:
|
The full `hermes chat` CLI rendered in an embedded SwiftTerm terminal:
|
||||||
@@ -66,4 +89,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-25 — Scarf v2.5.0 (3-pane Mac redesign + v0.11 chat parity + project-scoped slash commands)_
|
_Last updated: 2026-04-27 — Scarf v2.5.1 (chat density preferences + streaming O(n)-per-token fix + iOS keyboard dismissal)_
|
||||||
|
|||||||
+4
-3
@@ -24,7 +24,8 @@ Canonical layout of `~/.hermes/`. Scarf reads these paths through [`HermesPathSe
|
|||||||
| `~/.hermes/skills/` | Installed skills (with v0.11 SKILL.md frontmatter) | read + write (install/update/uninstall) |
|
| `~/.hermes/skills/` | Installed skills (with v0.11 SKILL.md frontmatter) | read + write (install/update/uninstall) |
|
||||||
| `~/.hermes/plugins/` | Installed plugins (cloned from Git URLs) | read + write |
|
| `~/.hermes/plugins/` | Installed plugins (cloned from Git URLs) | read + write |
|
||||||
| `~/.hermes/personalities/` | Personalities + their `SOUL.md` | read + write |
|
| `~/.hermes/personalities/` | Personalities + their `SOUL.md` | read + write |
|
||||||
| `~/.hermes/profiles/` | Isolated Hermes instances | read + write |
|
| `~/.hermes/profiles/<name>/` | Isolated Hermes instances (Hermes v0.11+) — each profile carries its own `state.db`, `sessions/`, `config.yaml`, `.env`, `memories/`, `cron/`, etc. | read + write |
|
||||||
|
| `~/.hermes/active_profile` | Single-line text file holding the active profile name (or absent / empty for default). _v2.5.1+:_ Scarf reads this via [`HermesProfileResolver`](Core-Services) and routes every derived path under it, so `hermes profile use coder` followed by a Scarf relaunch correctly reads the new profile's data. | read-only |
|
||||||
| `~/.hermes/mcp-tokens/*.json` | Per-server MCP OAuth tokens | read (detect) + delete (clear) |
|
| `~/.hermes/mcp-tokens/*.json` | Per-server MCP OAuth tokens | read (detect) + delete (clear) |
|
||||||
|
|
||||||
## Scarf-owned paths under `~/.hermes/scarf/`
|
## Scarf-owned paths under `~/.hermes/scarf/`
|
||||||
@@ -64,7 +65,7 @@ ScarfGo can't write to `~/Library/Caches/scarf/...` — it lives in its own iOS
|
|||||||
| SQLite snapshots | iOS Caches dir → `<sandbox>/Library/Caches/scarf/snapshots/<server-id>/state.db` |
|
| SQLite snapshots | iOS Caches dir → `<sandbox>/Library/Caches/scarf/snapshots/<server-id>/state.db` |
|
||||||
| Skill snapshots ("What's New" pill) | `UserDefaults` (the iOS sandbox doesn't have a clean Application Support equivalent for tiny per-server JSON) |
|
| Skill snapshots ("What's New" pill) | `UserDefaults` (the iOS sandbox doesn't have a clean Application Support equivalent for tiny per-server JSON) |
|
||||||
| Server registry (multi-server) | `UserDefaults` key `com.scarf.ios.servers.v2` (auto-migrated from legacy `ScarfGo.servers.v1`) |
|
| Server registry (multi-server) | `UserDefaults` key `com.scarf.ios.servers.v2` (auto-migrated from legacy `ScarfGo.servers.v1`) |
|
||||||
| SSH private keys | iOS Keychain — service `com.scarf.ssh-key`, account `server-key:<UUID>`, accessibility `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly`. Never iCloud-synced. |
|
| SSH private keys | iOS Keychain — service `com.scarf.ssh-key`, account `server-key:<UUID>`. Default accessibility `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly` + `kSecAttrSynchronizable=false` (device-local). _v2.5.1+:_ opt-in System → Security toggle flips writes to `kSecAttrAccessibleAfterFirstUnlock` + `kSecAttrSynchronizable=true` so the key syncs to iCloud Keychain across the user's signed-in Apple devices. Off by default. |
|
||||||
| Template config secrets | iOS Keychain — service `com.scarf.template.<slug>`, account `<fieldKey>:<project-path-hash>` |
|
| Template config secrets | iOS Keychain — service `com.scarf.template.<slug>`, account `<fieldKey>:<project-path-hash>` |
|
||||||
|
|
||||||
## Log line format
|
## Log line format
|
||||||
@@ -72,4 +73,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-25 — Scarf v2.5.0 (Scarf-owned paths section, slash-commands/template lock-files, iOS sandbox + Keychain layout)_
|
_Last updated: 2026-04-27 — Scarf v2.5.1 (active_profile awareness via HermesProfileResolver; iOS Keychain optional iCloud sync)_
|
||||||
|
|||||||
@@ -37,9 +37,11 @@ Scarf reads Hermes's SQLite database directly and parses CLI output from `hermes
|
|||||||
|
|
||||||
## v0.11 CLIs not yet adopted
|
## v0.11 CLIs not yet adopted
|
||||||
|
|
||||||
Hermes v0.11 added a handful of new top-level CLIs Scarf doesn't yet drive directly: `hermes plugins`, `hermes profile`, `hermes webhook`, `hermes insights`, `hermes logs`, `hermes dashboard`, `hermes completion`. Scarf still reads the underlying files (`~/.hermes/plugins/`, `~/.hermes/profiles/`, etc.) directly today, which keeps working. Switching to the canonical CLIs is forward-compatible work for v2.6+.
|
Hermes v0.11 added a handful of new top-level CLIs Scarf doesn't yet drive directly: `hermes plugins`, `hermes webhook`, `hermes insights`, `hermes logs`, `hermes dashboard`, `hermes completion`. Scarf still reads the underlying files (`~/.hermes/plugins/`, `~/.hermes/webhooks/`, etc.) directly today, which keeps working. Switching to the canonical CLIs is forward-compatible work for v2.6+.
|
||||||
|
|
||||||
`hermes memory reset` is the one v0.11 CLI v2.5 *does* drive — surfaced as the **Reset memory…** toolbar action on Memory views (Mac + iOS) with a destructive-confirmation dialog.
|
**`hermes memory reset`** is surfaced as the **Reset memory…** toolbar action on Memory views (Mac + iOS) with a destructive-confirmation dialog.
|
||||||
|
|
||||||
|
**`hermes profile`** is half-adopted as of v2.5.1. Scarf doesn't yet drive `hermes profile create / use / delete` from in-app UI (still file-based, still local for now), BUT Scarf v2.5.1+ **respects the active profile** by reading `~/.hermes/active_profile` at path-resolution time via [`HermesProfileResolver`](Core-Services). So `hermes profile use coder` on the host followed by a Scarf relaunch correctly reads `~/.hermes/profiles/coder/state.db`, `config.yaml`, sessions, memory, cron, etc. See [Projects & Profiles](Projects-and-Profiles) for the full profile model. In-app profile switching (writing `active_profile` from a UI control) is a separate v2.6+ feature — handling running ACP processes through a profile switch is more involved than just flipping a file.
|
||||||
|
|
||||||
## What breaks across major Hermes versions
|
## What breaks across major Hermes versions
|
||||||
|
|
||||||
@@ -61,4 +63,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).
|
- The relevant log snippet from `~/.hermes/logs/errors.log` (filter sensitive content first).
|
||||||
|
|
||||||
---
|
---
|
||||||
_Last updated: 2026-04-25 — Scarf v2.5.0 + Hermes v0.11.0_
|
_Last updated: 2026-04-27 — Scarf v2.5.1 + Hermes v0.11.0 (active_profile awareness)_
|
||||||
|
|||||||
+12
-4
@@ -30,16 +30,24 @@ The full schema is documented in [`scarf/docs/DASHBOARD_SCHEMA.md`](https://gith
|
|||||||
|
|
||||||
## Profiles
|
## Profiles
|
||||||
|
|
||||||
A profile is an isolated Hermes installation — separate config, sessions, memory, skills, the lot. Useful for keeping work / personal context separate, or for testing a config change without disturbing your main instance.
|
A profile is an isolated Hermes installation — separate config, sessions, memory, skills, the lot. Useful for keeping work / personal context separate, or for testing a config change without disturbing your main instance. Hermes ships profiles as of **v0.11.0**.
|
||||||
|
|
||||||
|
**How profile storage actually works** _(v0.11+, as Scarf reads it in v2.5.1+):_
|
||||||
|
|
||||||
|
- The "default" profile is `~/.hermes/` itself — backward compatible, zero migration.
|
||||||
|
- Named profiles live under `~/.hermes/profiles/<name>/`, each a fully independent `HERMES_HOME`. Each profile carries its own `state.db`, `sessions/`, `config.yaml`, `.env`, `memories/`, `cron/`, `skills/`, `gateway_state.json`, etc.
|
||||||
|
- The active profile is recorded in `~/.hermes/active_profile` — a single-line text file containing the profile name, or absent / empty when default is active. `hermes profile use <name>` writes that file; the Hermes CLI then sets `HERMES_HOME` accordingly per invocation.
|
||||||
|
- **Scarf v2.5.1+ reads `active_profile`** via [`HermesProfileResolver`](Core-Services) and routes every derived path through it — `state.db`, `sessions/`, `config.yaml`, `memories/`, `cron/jobs.json`, `auth.json`, plugins, gateway state, logs, all of it. So switching profiles on the host with `hermes profile use coder` and relaunching Scarf correctly reads the new profile's data. The chat session info bar surfaces a small profile chip when not on default so you can tell at a glance which profile Scarf is reading from.
|
||||||
|
- Pre-2.5.1 Scarf hardcoded `~/.hermes` and ignored `active_profile`, which silently read the wrong DB after a profile switch (issue [#50](https://github.com/awizemann/scarf/issues/50)). If you're on 2.5.0 or older, upgrade.
|
||||||
|
|
||||||
**Operations** (all wrap `hermes profile ...` via `context.runHermes`):
|
**Operations** (all wrap `hermes profile ...` via `context.runHermes`):
|
||||||
|
|
||||||
- **Switch** — make a profile active. Scarf shows a "restart Scarf to fully apply" reminder because the active profile path is read at launch.
|
- **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.
|
||||||
- **Import** — unzip into a new profile slot.
|
- **Import** — unzip into a new profile slot.
|
||||||
|
|
||||||
Profiles live under `~/.hermes/profiles/`. The currently active profile is whatever Hermes points its `~/.hermes/` symlink (or equivalent) at — Scarf reflects that.
|
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.
|
||||||
|
|
||||||
## Related pages
|
## Related pages
|
||||||
|
|
||||||
@@ -50,4 +58,4 @@ Profiles live under `~/.hermes/profiles/`. The currently active profile is whate
|
|||||||
- [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-25 — Scarf v2.5.0 (per-project Sessions / Site / Slash Commands tabs + AGENTS.md context handoff)_
|
_Last updated: 2026-04-27 — Scarf v2.5.1 (Hermes v0.11 profile awareness via HermesProfileResolver + active_profile chip in chat info bar)_
|
||||||
|
|||||||
+3
-1
@@ -13,6 +13,8 @@ Mac releases are produced by a single local script: [`scripts/release.sh`](https
|
|||||||
|
|
||||||
A full release bumps the version, archives Universal (arm64 + x86_64) + ARM64-only variants, signs with Developer ID, notarizes via `xcrun notarytool`, staples, EdDSA-signs the appcast entry with Sparkle's key, pushes the appcast to `gh-pages`, and creates a GitHub release with both zips attached.
|
A full release bumps the version, archives Universal (arm64 + x86_64) + ARM64-only variants, signs with Developer ID, notarizes via `xcrun notarytool`, staples, EdDSA-signs the appcast entry with Sparkle's key, pushes the appcast to `gh-pages`, and creates a GitHub release with both zips attached.
|
||||||
|
|
||||||
|
**Post-package verification gate** _(v2.5.1+)._ After every variant's final `ditto`, the script extracts the packaged zip into a temp dir and runs `codesign --verify --strict --deep --verbose=4` + `spctl --assess --type execute --verbose` on the extracted bundle. Either failure aborts the release. This catches any regression in the shipped artifact (stapler edge cases, post-staple modifications, framework-seal drift) before users see "Scarf.app is damaged" reports — issue [#49](https://github.com/awizemann/scarf/issues/49).
|
||||||
|
|
||||||
A draft release stops after the GitHub release is uploaded, so the current version stays "latest" until explicitly promoted.
|
A draft release stops after the GitHub release is uploaded, so the current version stays "latest" until explicitly promoted.
|
||||||
|
|
||||||
## Release notes
|
## Release notes
|
||||||
@@ -58,4 +60,4 @@ ScarfGo ships through:
|
|||||||
The iOS `MARKETING_VERSION` should match the Mac `MARKETING_VERSION` for the same release; the iOS `CURRENT_PROJECT_VERSION` (build number) increments independently per Apple's monotonic-build-number rule. There's no automation for iOS bumping yet — manual edit in the Xcode target before archiving.
|
The iOS `MARKETING_VERSION` should match the Mac `MARKETING_VERSION` for the same release; the iOS `CURRENT_PROJECT_VERSION` (build number) increments independently per Apple's monotonic-build-number rule. There's no automation for iOS bumping yet — manual edit in the Xcode target before archiving.
|
||||||
|
|
||||||
---
|
---
|
||||||
_Last updated: 2026-04-25 — Scarf v2.5.0 (added iOS release flow + cross-link to TestFlight + App Store metadata files)_
|
_Last updated: 2026-04-27 — Scarf v2.5.1 (post-package verification gate)_
|
||||||
|
|||||||
+7
-6
@@ -15,7 +15,7 @@ ScarfGo never asks for your account password. It also never holds an Apple-side
|
|||||||
|
|
||||||
1. Server details (hostname, user, port, optional nickname)
|
1. Server details (hostname, user, port, optional nickname)
|
||||||
2. Choose: generate a new SSH key, or import one you already have
|
2. Choose: generate a new SSH key, or import one you already have
|
||||||
3. Generate (or paste) the keypair — the private half lives in the iOS Keychain, never iCloud-synced
|
3. Generate (or paste) the keypair — the private half lives in the iOS Keychain (device-local by default; opt-in iCloud Keychain sync from System → Security as of v2.5.1)
|
||||||
4. Show the public key — copy and paste it into `~/.ssh/authorized_keys` on the host
|
4. Show the public key — copy and paste it into `~/.ssh/authorized_keys` on the host
|
||||||
5. Test connection — ScarfGo SSHes in, looks for the `hermes` binary, saves on success
|
5. Test connection — ScarfGo SSHes in, looks for the `hermes` binary, saves on success
|
||||||
|
|
||||||
@@ -50,9 +50,10 @@ Either way, the private half is stored in the iOS Keychain with these attributes
|
|||||||
|
|
||||||
- **Service:** `com.scarf.ssh-key`
|
- **Service:** `com.scarf.ssh-key`
|
||||||
- **Account:** `server-key:<UUID>` (one entry per configured server)
|
- **Account:** `server-key:<UUID>` (one entry per configured server)
|
||||||
- **Accessibility:** `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly`
|
- **Accessibility (default):** `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly` + `kSecAttrSynchronizable=false`. Key unreachable while the device is locked, doesn't leave the device, survives passcode changes. Pre-v2.5.1 this was the only mode.
|
||||||
|
- **Accessibility (opt-in, v2.5.1+):** `kSecAttrAccessibleAfterFirstUnlock` + `kSecAttrSynchronizable=true`. Toggle from System → Security → "Sync SSH key with iCloud Keychain". The Keychain entry now syncs across signed-in Apple devices, end-to-end encrypted by iCloud Keychain (with Advanced Data Protection enabled, the encryption keys never leave your devices). Adding a second device no longer requires generating a fresh key — install ScarfGo, sign in to the same Apple ID with iCloud Keychain enabled, the same key shows up.
|
||||||
|
|
||||||
That last attribute means the key is unreachable while the device is locked, doesn't sync to iCloud (so adding the same key to a second device requires re-onboarding), and survives device passcode changes. If you ever delete the app, iOS purges the Keychain group along with it.
|
If you ever delete the app, iOS purges its Keychain group; for synced items, iCloud Keychain mirrors the deletion across devices.
|
||||||
|
|
||||||
### 4. Show the public key — paste into authorized_keys
|
### 4. Show the public key — paste into authorized_keys
|
||||||
|
|
||||||
@@ -140,10 +141,10 @@ Cancelling Face ID or the device passcode prompt no longer drops you back into o
|
|||||||
|
|
||||||
## Privacy and key handling — quick recap
|
## Privacy and key handling — quick recap
|
||||||
|
|
||||||
- **No iCloud sync.** Keys are explicitly marked `ThisDeviceOnly` and excluded from iCloud Keychain.
|
- **iCloud sync is opt-in (v2.5.1+).** Default is device-local — keys are marked `ThisDeviceOnly` and excluded from iCloud Keychain unless you enable the System → Security toggle. With it on, the key syncs end-to-end encrypted via iCloud Keychain (Advanced Data Protection makes the encryption keys client-side only).
|
||||||
- **No cloud accounts.** Scarf has no developer-controlled server. Your iPhone connects directly to your Hermes host over SSH.
|
- **No cloud accounts.** Scarf has no developer-controlled server. Your iPhone connects directly to your Hermes host over SSH.
|
||||||
- **No analytics.** ScarfGo doesn't transmit any data to any third party.
|
- **No analytics.** ScarfGo doesn't transmit any data to any third party.
|
||||||
- **One key per device.** Adding a second iPhone means a second `authorized_keys` line. Same convention you'd follow for a new Mac.
|
- **One key per device — unless you opt into sync.** Default behavior: adding a second device means a second `authorized_keys` line. With iCloud Keychain sync enabled, the same key appears on every signed-in Apple device with iCloud Keychain on, so a single `authorized_keys` line covers all of them.
|
||||||
|
|
||||||
Full policy: [Privacy Policy](Privacy-Policy).
|
Full policy: [Privacy Policy](Privacy-Policy).
|
||||||
|
|
||||||
@@ -156,4 +157,4 @@ Full policy: [Privacy Policy](Privacy-Policy).
|
|||||||
- [Support](Support) — bug reports, feature requests, security disclosures.
|
- [Support](Support) — bug reports, feature requests, security disclosures.
|
||||||
|
|
||||||
---
|
---
|
||||||
_Last updated: 2026-04-25 — Scarf v2.5.0 (audit pass: corrected PATH-prefix candidate count + `~/.hermes/bin` claim)_
|
_Last updated: 2026-04-27 — Scarf v2.5.1 (opt-in iCloud Keychain sync for SSH keys)_
|
||||||
|
|||||||
+2
-2
@@ -26,7 +26,7 @@ ScarfGo is in **public TestFlight**. Apple-provided test environment, free to jo
|
|||||||
|
|
||||||
Onboarding details:
|
Onboarding details:
|
||||||
|
|
||||||
- ScarfGo generates a fresh Ed25519 keypair on first run. The private half lives in the iOS Keychain (`kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly` — never iCloud-synced).
|
- ScarfGo generates a fresh Ed25519 keypair on first run. The private half lives in the iOS Keychain. **Default:** device-local (`kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly`, not iCloud-synced). **v2.5.1+:** an opt-in toggle in System tab → Security flips it to sync via iCloud Keychain (`kSecAttrAccessibleAfterFirstUnlock` + `kSecAttrSynchronizable=true`) so iPhone + iPad + Mac see the same key without onboarding each device. End-to-end encrypted by iCloud Keychain; with Advanced Data Protection enabled, the encryption keys never leave your devices.
|
||||||
- The public-key snippet is shown for you to copy and append to `~/.ssh/authorized_keys` on your Hermes host. Plain `ssh-copy-id` doesn't work from iPhone, so the manual paste is the safest path.
|
- The public-key snippet is shown for you to copy and append to `~/.ssh/authorized_keys` on your Hermes host. Plain `ssh-copy-id` doesn't work from iPhone, so the manual paste is the safest path.
|
||||||
- A one-tap "Test connection" verifies SSH + the `hermes` binary's path before saving.
|
- A one-tap "Test connection" verifies SSH + the `hermes` binary's path before saving.
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ See [Platform Differences](Platform-Differences) for a full Mac-vs-iOS feature m
|
|||||||
A: No. Hermes is a Python agent that needs Python plus a model provider's CLI plus a writable filesystem. iOS doesn't make any of that practical. ScarfGo is a thin client.
|
A: No. Hermes is a Python agent that needs Python plus a model provider's CLI plus a writable filesystem. iOS doesn't make any of that practical. ScarfGo is a thin client.
|
||||||
|
|
||||||
**Q: Will my SSH key sync to my other devices?**
|
**Q: Will my SSH key sync to my other devices?**
|
||||||
A: No. The Keychain entry is `ThisDeviceOnly` — explicitly excluded from iCloud Keychain sync. Adding a second device means a second key + a second `authorized_keys` line.
|
A: Optional as of v2.5.1. Default is **off** — the Keychain entry is `ThisDeviceOnly` and adding a second device means a second key + a second `authorized_keys` line. Toggle **System → Security → Sync SSH key with iCloud Keychain** to flip the entry to a synced item. iCloud Keychain encrypts the bundle end-to-end; with Advanced Data Protection on, the keys are encrypted client-side with material that never leaves your devices. Off is still the right choice if you want a hard guarantee that the key is bound to one device — issue [#52](https://github.com/awizemann/scarf/issues/52).
|
||||||
|
|
||||||
**Q: Can I use ScarfGo with a Hermes host that's not on my LAN?**
|
**Q: Can I use ScarfGo with a Hermes host that's not on my LAN?**
|
||||||
A: Yes — anywhere reachable over SSH. Tailscale, port forwarding, a VPS, anything. The Hermes host doesn't know it's being driven by an iPhone vs a Mac.
|
A: Yes — anywhere reachable over SSH. Tailscale, port forwarding, a VPS, anything. The Hermes host doesn't know it's being driven by an iPhone vs a Mac.
|
||||||
|
|||||||
+18
-2
@@ -39,7 +39,23 @@ The remote host must have:
|
|||||||
|
|
||||||
If the connection pill is green but the Dashboard shows "Stopped", "unknown", or empty values, the SSH user can't read the Hermes state files.
|
If the connection pill is green but the Dashboard shows "Stopped", "unknown", or empty values, the SSH user can't read the Hermes state files.
|
||||||
|
|
||||||
**Manage Servers → 🩺 Run Diagnostics** (or click the yellow "Can't read Hermes state" pill in the toolbar) 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.
|
**The pill itself diagnoses common cases inline** _(v2.5.1+)._ Clicking the yellow "Can't read Hermes state" pill opens a popover with:
|
||||||
|
|
||||||
|
- The specific reason (`config.yaml is missing`, `permission denied on config.yaml`, `~/.hermes` doesn't exist, `Hermes profile <name> is active`, etc.)
|
||||||
|
- An actionable hint paragraph (`run hermes setup on the remote`, `chmod a+r ~/.hermes/config.yaml`, etc.)
|
||||||
|
- A Run Diagnostics button (opens the heavy 14-check sheet) and a Retry button
|
||||||
|
|
||||||
|
For the "profile is active" case the popover includes a copy-paste `hermes profile use default` command. See [Projects & Profiles](Projects-and-Profiles) for the full Hermes v0.11 profile model.
|
||||||
|
|
||||||
|
**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.
|
||||||
|
|
||||||
|
**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).
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
A full SFTP-backed remote directory picker is on the roadmap (issue [#54](https://github.com/awizemann/scarf/issues/54)). Until then, type the absolute remote path (or paste from a remote shell), Verify, then Add.
|
||||||
|
|
||||||
## Switching the active window
|
## Switching the active window
|
||||||
|
|
||||||
@@ -56,4 +72,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-25 — Scarf v2.5.0 (added ScarfGo cross-references)_
|
_Last updated: 2026-04-27 — Scarf v2.5.1 (granular degraded-pill popover + unified pill/diagnostics transport + context-aware Add Project)_
|
||||||
|
|||||||
Reference in New Issue
Block a user