diff --git a/Architecture-Overview.md b/Architecture-Overview.md index 757a5db..127268d 100644 --- a/Architecture-Overview.md +++ b/Architecture-Overview.md @@ -5,16 +5,29 @@ Scarf is a SwiftUI app organized around **MVVM-F** (Model-View-ViewModel-Feature ## Layering at a glance ``` -Features/ SwiftUI views + @Observable ViewModels (one per capability) -Navigation/ AppCoordinator (single source of truth for navigation state) -Core/Services/ Shared services injected via .environment() -Core/Models/ Plain Codable structs -Core/Transport/ Local + SSH transport behind one protocol -Core/Persistence/ Server registry (Codable plist) -Core/Utilities/ Markdown rendering, shared helpers +Mac target (scarf): + scarf/Features/ SwiftUI views + @Observable ViewModels (one per capability) + scarf/Navigation/ AppCoordinator (single source of truth for nav state) + scarf/Core/Services/ Mac-only services (SwiftTerm bridge, Sparkle wrapper) + scarf/Core/Persistence/ Server registry (Codable plist) + +iOS target (scarf mobile): + Scarf iOS/App/ ScarfGoTabRoot, ScarfGoCoordinator, theme glue + Scarf iOS/Onboarding/ SSH key generation, paste-public-key, connection test + Scarf iOS// Dashboard, Chat, Projects, Skills, Memory, Cron, Settings, Servers, Notifications + +Shared (Packages/): + ScarfCore Models, services, view-models, transport protocol, ACP + client, parsers, security helpers — consumed by both + targets via local SPM package. + ScarfIOS Citadel-backed SSH transport, KeychainSSHKeyStore, the + iOS-specific bits that can't compile on macOS. + ScarfDesign Rust palette, ScarfFont scale, ScarfSpace/Radius/Shadow + tokens, reusable components (PageHeader, Card, Badge, + TextField, four button styles). Linked into both targets. ``` -See [Core Services](Core-Services), [Data Model](Data-Model), [Transport Layer](Transport-Layer), and [Sidebar & Navigation](Sidebar-and-Navigation) for the detail per layer. +See [Core Services](Core-Services), [Data Model](Data-Model), [Transport Layer](Transport-Layer), [ScarfCore Package](ScarfCore-Package), [Design System](Design-System), and [Sidebar & Navigation](Sidebar-and-Navigation) for the detail per layer. ## Key invariants @@ -30,16 +43,18 @@ A single `@Observable AppCoordinator` holds `selectedSection: SidebarSection`, ` The sidebar groups capabilities into four sections: **Monitor**, **Interact**, **Configure**, **Manage**. See [Sidebar & Navigation](Sidebar-and-Navigation) for the full section list. -## Multi-server: one window per server +## Multi-server: one window per server (Mac) / one tab root per server (iOS) -Scarf 2.0 is multi-window. Each window binds to exactly one **`ServerContext`** — either the local `~/.hermes/` (synthesized automatically) or a remote SSH host. Windows are independent; opening a second window for a different server gives you side-by-side state. +Scarf 2.0 is multi-window on Mac. Each window binds to exactly one **`ServerContext`** — either the local `~/.hermes/` (synthesized automatically) or a remote SSH host. Windows are independent; opening a second window for a different server gives you side-by-side state. -Server state lives in the `ServerRegistry` (`Core/Persistence/`), which serializes to `~/Library/Preferences/com.scarf.app`. A window's `ServerContext` is built once and provides the unified API services use: +ScarfGo (iOS) uses the same `ServerContext` abstraction but with a single-window TabView. Switching servers from the Servers list rebuilds the `ScarfGoTabRoot` against the new context — same effect as opening a different window on Mac. + +Server state lives in the `ServerRegistry` (Mac: Codable plist in `~/Library/Preferences/com.scarf.app`; iOS: `UserDefaults` under `com.scarf.ios.servers.v2` + per-server SSH keys in the iOS Keychain). A window's `ServerContext` is built once and provides the unified API services use: - `context.readText(path)` / `writeText(path, body)` — file I/O via the active transport. - `context.runHermes(args…)` — invokes `hermes` locally or `ssh host -- hermes` remotely. -- `context.openInLocalEditor(path)` — pulls remote files local first, then opens. -- `context.transport` — `LocalTransport` or `SSHTransport`, both implementing `ServerTransport`. +- `context.openInLocalEditor(path)` — pulls remote files local first, then opens (Mac only). +- `context.transport` — `LocalTransport` (Mac local), `SSHTransport` (Mac remote, OpenSSH-driven), or `CitadelServerTransport` (iOS, pure-Swift Citadel). All three implement `ServerTransport`. Services receive a `ServerContext`, never raw `FileManager`, `Process`, or `NSWorkspace.open` for Hermes paths. See [Transport Layer](Transport-Layer) for the protocol details. @@ -56,4 +71,4 @@ The Rich Chat surface speaks the Hermes Agent Client Protocol (ACP) — a JSON-R `UpdaterService` is a thin wrapper around Sparkle. The appcast lives at `https://awizemann.github.io/scarf/appcast.xml` (gh-pages branch); each entry is EdDSA-signed by the release script. See [Release Process](Release-Process). --- -_Last updated: 2026-04-20 — Scarf v2.0.1_ +_Last updated: 2026-04-25 — Scarf v2.5.0 (ScarfCore + ScarfIOS + ScarfDesign extraction)_ diff --git a/Chat.md b/Chat.md index 21cd4d4..7b7e59a 100644 --- a/Chat.md +++ b/Chat.md @@ -8,13 +8,16 @@ Streams tokens, thoughts, and tool calls live via the [ACP subprocess](ACP-Subpr **What it renders:** -- iMessage-style bubbles, user vs. assistant. +- Rust-tinted bubbles in the v2.5 design (UnevenRoundedRectangle for the user; bordered card with a sparkles gradient avatar for the assistant). User text in `ScarfColor.onAccent`; assistant in `ScarfColor.foregroundPrimary` over `ScarfColor.backgroundSecondary`. - Markdown content (links, lists, code blocks, tables). -- **Reasoning / thinking** chunks in a collapsible block above the answer. -- **Tool calls** as inline cards with the function name, argument summary, and (when complete) the result. -- **Permission requests** as modal sheets — Hermes asks before executing risky tools; you choose Allow / Deny. +- **Reasoning / thinking** chunks in a warning-tinted disclosure block ("REASONING" uppercase label) above the answer. +- **Tool calls** as inline cards with kind-tinted borders + uppercase tracked labels (READ / EDIT / EXECUTE / FETCH / BROWSER) using `ScarfColor.success` / `info` / `warning` / `Tool.web` / `Tool.search`. Expanded JSON in a bordered `backgroundSecondary` panel. +- **Permission requests** as modal sheets — Hermes asks before executing risky tools; you choose Allow / Deny. **Numbered keyboard shortcuts** _(v2.5+)_: 1–9 bind to the option buttons on Mac (visible "1. " / "2. " prefixes); approve / deny without reaching for the mouse. iOS shows the same numbered hints as a hierarchy cue without the keyboard binding. +- **Per-turn stopwatch** _(v2.5+)_ — wall-clock duration of each completed assistant turn renders as a compact pill (`4.2s` / `1m 12s`) on the bubble's metadata footer (Mac) or below the bubble (iOS). Resumed sessions loaded from `state.db` show no pill — timing is captured live only. +- **Git branch chip** _(v2.5+)_ — chat header shows the project's current git branch as a tinted chip alongside the project name (e.g. `📂 myproject · main`). One SSH `git rev-parse --abbrev-ref HEAD` per session start; nil-out gracefully on non-git dirs / missing git / SSH errors. Backed by [`GitBranchService`](Core-Services). - **`/compress`** — when Hermes advertises the command via `availableCommands`, a one-click focus sheet appears in the toolbar. -- **Slash-command menu** _(new in 2.1)_ — type `/` and a floating menu appears above the input with every command Hermes has advertised via ACP's `available_commands_update` plus any user-defined `quick_commands:` from `~/.hermes/config.yaml`. ↑/↓ to navigate, Tab or Enter to complete, Esc to dismiss. Commands with argument hints (e.g. `/compress `) insert a trailing space so you can start typing the argument immediately. +- **`/steer `** _(v2.5+)_ — non-interruptive mid-run guidance. Surfaces in the slash menu as a special command; sending it doesn't flip the "Agent working…" indicator (the agent's still on its current turn) and shows a transient toast above the composer: "Guidance queued — applies after the next tool call." +- **Slash-command menu** — type `/` and a floating menu appears above the input with every command Hermes has advertised via ACP's `available_commands_update`, any user-defined `quick_commands:` from `~/.hermes/config.yaml`, and any **project-scoped slash commands** _(v2.5+)_ from `/.scarf/slash-commands/`. See [Slash Commands](Slash-Commands). ↑/↓ to navigate, Tab or Enter to complete, Esc to dismiss. Commands with argument hints (e.g. `/compress `) insert a trailing space so you can start typing the argument immediately. **Session lifecycle:** @@ -36,9 +39,19 @@ The full `hermes chat` CLI rendered in an embedded SwiftTerm terminal: The Stop button sends `session/cancel` over the JSON-RPC channel. The model stops generating; any in-flight tool call completes. You can immediately send another prompt without restarting the session. +## Mac 3-pane chat (v2.5) + +The Mac chat surface re-laid out as a three-pane composition: + +- **Left pane** — sessions sidebar (search + project filter + the 50 most recent sessions). Right-click any row for Rename / Delete (when Hermes advertises those CLIs). +- **Middle pane** — transcript (the bubbles, reasoning, tool cards described above) + composer. +- **Right pane** — live inspector. Surfaces git branch, project chip, model + reasoning effort, total tokens / API calls / tool calls, and the current MCP server status. + +iPhone keeps a single-column transcript — three panes don't translate to phone-width screens. iPad inherits the Mac layout via SwiftUI's adaptive sizing but hasn't been polished yet (deferred per [Platform Differences](Platform-Differences)). + ## Multi-server chat -Each window is bound to one server, so chat in window A talks to local Hermes while window B talks to a remote one. Sessions don't cross windows — they live on the server they were created on. +Each Mac window is bound to one server, so chat in window A talks to local Hermes while window B talks to a remote one. ScarfGo uses a single-window TabView; switching servers from the Servers list rebuilds the tab root against the new context. Sessions don't cross windows / contexts — they live on the server they were created on. ## Troubleshooting @@ -53,4 +66,4 @@ Each window is bound to one server, so chat in window A talks to local Hermes wh - [Settings — Voice tab](Gateway-Cron-Health-Logs) for TTS/STT configuration (Settings is documented there). --- -_Last updated: 2026-04-21 — Scarf v2.1.0_ +_Last updated: 2026-04-25 — Scarf v2.5.0 (3-pane Mac redesign + v0.11 chat parity + project-scoped slash commands)_ diff --git a/Core-Services.md b/Core-Services.md index 6c19087..5ed0cea 100644 --- a/Core-Services.md +++ b/Core-Services.md @@ -1,6 +1,8 @@ # Core Services -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. +The services in this layer are the data-and-side-effects bridge between Hermes and the SwiftUI features. Each takes a `ServerContext` (local, SSH, or Citadel) so the same service code works against a local install, a Mac SSH remote, or an iOS Citadel-driven remote. + +In v2.5 most service code moved out of the Mac target into the shared **ScarfCore** SwiftPM package at [`scarf/Packages/ScarfCore/`](https://github.com/awizemann/scarf/tree/main/scarf/Packages/ScarfCore), so iOS reuses it byte-for-byte. A handful of Mac-only services (Sparkle wrapper, SwiftTerm bridge) stay in `scarf/scarf/Core/Services/`. | Service | Isolation | Lines | Purpose | |---|---|---|---| @@ -16,6 +18,29 @@ The 11 services under [`scarf/scarf/scarf/Core/Services/`](https://github.com/aw | [`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. | +## v2.5 additions (in ScarfCore — shared across Mac + iOS) + +| Service | Isolation | Purpose | +|---|---|---| +| `SessionAttributionService` | `Sendable struct` | Owns `~/.hermes/scarf/session_project_map.json`. Records which Hermes session belongs to which project so both clients render project badges and the per-project Sessions tab. Read on every Dashboard refresh; write when project-scoped chat starts a new session. | +| `ProjectAgentContextService` | `Sendable struct` | Idempotently maintains the `` block in `/AGENTS.md`. Surfaces project name, dashboard path, configuration field names (never values — Keychain refs only), and registered cron jobs. Bounded so template-author content outside the markers is preserved across refreshes. | +| `CronScheduleFormatter` | `Sendable enum` | Pure-Swift cron-string → English translation. Recognizes the common shapes (`*/N * * * *`, `0 H * * *`, `0 H * * 1-5`, `@hourly` / `@daily` / `@weekly` / `@monthly`); falls back to the raw expression for anything custom. Used by Mac Cron Manager + iOS Cron list. | +| `GitBranchService` | `Sendable struct` | Single SSH `git rev-parse --abbrev-ref HEAD` per session start; surfaces the project's current branch as a chip in the chat header. Nil-out gracefully on non-git dirs / missing git / SSH errors. | +| `SkillSnapshotService` | `Sendable struct` | Per-server snapshot of `[skillId: signature]` (file count + sorted file names). When the snapshot changes between visits, the Skills tab shows a "What's New" pill. Persisted to `~/Library/Application Support/com.scarf/skill-snapshots/.json` (Mac) / `UserDefaults` (iOS). | +| `SkillPrereqService` | `Sendable struct` | Probes for a host-side binary via the transport (`which `); surfaces a yellow banner on a skill detail when a prerequisite is missing. Currently feeds the `design-md` skill's `npx` check; pluggable for future prereq surfaces. | +| `ProjectSlashCommandService` | `Sendable struct` | Reads / writes `/.scarf/slash-commands/.md` files with YAML frontmatter; expands `{{argument}}` and `{{argument \| default: "..."}}` substitutions; renders `` markers in expanded prompts so the agent can recognize them in transcripts. Used by Mac authoring tab + iOS read-only browser. See [Slash Commands](Slash-Commands). | +| `SpotifyAuthFlow` | `@Observable @MainActor` | Drives the Spotify OAuth handshake on Mac (5-state machine: starting → waiting → verifying → success / failure). Mirrors the v2.3 `NousAuthFlow` pattern. iOS surfaces a documentation row instead — phone OAuth flows are their own UX problem. | + +## v2.5 additions (iOS-only — in ScarfIOS) + +| Service | Purpose | +|---|---| +| `KeychainSSHKeyStore` | Per-server Ed25519 keypair persistence in the iOS Keychain (`com.scarf.ssh-key` service, `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly`). v2 multi-server format: account `"server-key:"`. Auto-migrates v1 (`"primary"` account) on first `listAll`. Wipe via single `SecItemDelete`. | +| `CitadelSSHService` | Pure-Swift Ed25519 keypair generation + connection probes via Citadel. Used by Onboarding's "Generate Key" + "Test Connection" steps. | +| `CitadelServerTransport` | Citadel-backed implementation of `ServerTransport` — drives `executeCommandStream` for resilient stdout capture (preserves output on non-zero exit) and prepends `PATH=$HOME/.local/bin:/opt/homebrew/bin:/usr/local/bin:$PATH` so non-interactive sessions resolve `hermes` and its sub-tools without sourcing user shell rc files. | + +See [ScarfCore Package](ScarfCore-Package) for the package architecture and how to add a new shared service. + ## Patterns shared across the layer - **`ServerContext` parameterizes all I/O.** Services receive the context at init; routing local vs. SSH happens through `context.transport`. See [Transport Layer](Transport-Layer). @@ -31,4 +56,4 @@ The 11 services under [`scarf/scarf/scarf/Core/Services/`](https://github.com/aw 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-24 — Scarf v2.3.0_ +_Last updated: 2026-04-25 — Scarf v2.5.0 (ScarfCore extraction + 9 new services)_ diff --git a/Design-System.md b/Design-System.md new file mode 100644 index 0000000..9880c2b --- /dev/null +++ b/Design-System.md @@ -0,0 +1,148 @@ +# Design System (ScarfDesign) + +Scarf and ScarfGo share a single typed design-token bundle: the **ScarfDesign** Swift Package at [`scarf/Packages/ScarfDesign/`](https://github.com/awizemann/scarf/tree/main/scarf/Packages/ScarfDesign). Both targets `import ScarfDesign` and consume the same `ScarfColor` / `ScarfFont` / `ScarfSpace` / `ScarfRadius` / `ScarfShadow` tokens plus a small set of reusable SwiftUI components. + +If you're building a new view or polishing an existing one, reach for these tokens first. Hardcoded colors, fonts, paddings, and corner radii are a code smell — convert them. + +## Where the tokens live + +``` +scarf/Packages/ScarfDesign/ + Sources/ScarfDesign/ + ScarfBrand.xcassets/ # color set: brand rust, grayscale, semantic, tool kinds + ScarfTheme.swift # ScarfColor accessors + environment keys + ScarfTypography.swift # ScarfFont scale + .scarfStyle modifier + ScarfComponents.swift # PageHeader, Card, Badge, TextField, button styles + ScarfChatView.swift # 3-pane chat reference (Mac) + ScarfPreview.swift # preview canvas helpers +``` + +The `ScarfBrand.xcassets` color set ships in the package; both targets resolve `Color("AccentColor", bundle: .module)` to the rust accent automatically. No per-target asset duplication. + +## Color tokens + +| Token | Use | +|---|---| +| `ScarfColor.accent` | Primary brand rust. Buttons, focused states, chat user-bubble fill. | +| `ScarfColor.accentTint` | Translucent accent for chip backgrounds + selection rows. | +| `ScarfColor.onAccent` | Foreground on rust fills (high-contrast). | +| `ScarfColor.foregroundPrimary` | Default body text. | +| `ScarfColor.foregroundMuted` | Secondary text — captions, list-row subtitles. | +| `ScarfColor.foregroundFaint` | Tertiary text — metadata, "12 / 100 chars" hints. | +| `ScarfColor.backgroundPrimary` | Window/page background. | +| `ScarfColor.backgroundSecondary` | Card / list-row background. Elevated one step. | +| `ScarfColor.backgroundTertiary` | Sub-elevation for inset / inner panels. | +| `ScarfColor.border` | Default 1px stroke for cards + inputs. | +| `ScarfColor.borderStrong` | Pronounced stroke for divider rules between sections. | +| `ScarfColor.success` | Green — success badges, "Saved" pill. | +| `ScarfColor.danger` | Red — destructive button accent, error banners. | +| `ScarfColor.warning` | Amber — non-fatal banner, "missing dependency" hint. | +| `ScarfColor.info` | Cool blue — informational chips. | +| `ScarfColor.Tool.bash` | Tool-call card kind tints — `bash`. | +| `ScarfColor.Tool.edit` | `edit` (file changes). | +| `ScarfColor.Tool.search` | `search` / `grep`. | +| `ScarfColor.Tool.web` | `fetch` / browser. | +| `ScarfColor.Tool.think` | reasoning / thinking. | + +All colors resolve from `ScarfBrand.xcassets`, so they adapt light/dark automatically. Don't ship terminal or syntax-highlight palettes through ScarfColor — those are content semantics, keep them inline. + +## Typography (ScarfFont) + +Eleven preset styles, all fixed-size on Mac: + +```swift +.scarfStyle(.title1) // 32pt semibold +.scarfStyle(.title2) // 24pt semibold +.scarfStyle(.title3) // 20pt semibold +.scarfStyle(.headline) // 17pt semibold +.scarfStyle(.body) // 15pt regular +.scarfStyle(.callout) // 14pt regular +.scarfStyle(.footnote) // 13pt regular +.scarfStyle(.caption) // 12pt regular +.scarfStyle(.captionUppercase) // 11pt semibold tracked, uppercase +.scarfStyle(.codeInline) // 13pt monospaced +.scarfStyle(.codeBlock) // 13pt monospaced, room for tabs +``` + +**Mac:** adopt `ScarfFont` everywhere. The Mac doesn't have system-wide text scaling, so fixed sizes are correct. + +### iOS Dynamic Type policy + +iOS users can scale text via Settings → Accessibility → Display & Text Size. ScarfFont uses fixed point sizes; adopting it blanket on iOS would regress accessibility on `.accessibility2` (much larger) or `.xSmall` (smaller) users. + +iOS-specific rule: + +- **Use `ScarfFont` only for**: status badges, chip labels, intentional-display elements (e.g. onboarding step titles, header chrome that's meant to be a fixed visual size). +- **Keep `.font(.headline)` / `.body` / `.caption` semantic tokens for**: list-row primary + secondary text, body copy, error messages, chat content — anything the user reads. + +Decision tree per text element: *"is this read for content?"* → semantic token. *"Is this chrome / a label / a badge?"* → ScarfFont. + +The iOS app already clamps Dynamic Type at the scene root (`ScarfIOSApp.swift`: `.dynamicTypeSize(.xSmall ... .accessibility2)`) so the maximum scale factor stays sane — keep that in place. + +### iOS page chrome + +Don't retrofit `ScarfPageHeader` over iOS tab roots. iOS uses `.navigationTitle(...)` + `.navigationBarTitleDisplayMode(.large)` as its native page-header pattern; stacking ScarfPageHeader on top creates double titles. Use ScarfPageHeader only on iOS sub-views without a native large-title bar (rare). + +iOS button styling: only swap `.borderedProminent` → `ScarfPrimaryButton`. **Leave `.bordered` native** — it's the iOS convention and inherits rust through `AccentColor.colorset` automatically. Same for `.plain` (used as compact tap targets in lists). + +## Spacing, radius, shadow + +```swift +ScarfSpace.s1 = 4 // tight (chip padding) +ScarfSpace.s2 = 8 // small (intra-row gap) +ScarfSpace.s3 = 12 // medium (form fields) +ScarfSpace.s4 = 16 // page padding +ScarfSpace.s5 = 20 +ScarfSpace.s6 = 24 // section break +ScarfSpace.s7 = 32 +ScarfSpace.s8 = 40 +ScarfSpace.s9 = 56 +ScarfSpace.s10 = 80 + +ScarfRadius.sm = 4 +ScarfRadius.md = 6 +ScarfRadius.lg = 8 // default for cards, inputs +ScarfRadius.xl = 12 +ScarfRadius.xxl = 14 +ScarfRadius.pill = 999 +``` + +Hardcoded `.padding(12)` or `cornerRadius: 8` is a code smell — convert. Same for `.scarfShadow(.sm/.md/.lg/.xl)` instead of bespoke `Shadow(...)`. + +## Components + +Apply with `.buttonStyle(...)` for buttons; the rest are SwiftUI views you compose directly. + +| Component | Purpose | +|---|---| +| `ScarfPageHeader("Title", subtitle: "...") { trailing }` | Mac-style page header with title + subtitle + trailing-edge actions slot. | +| `ScarfCard { ... }` | Bordered, elevated container with `backgroundSecondary` fill + border + radius + shadow baked in. | +| `ScarfBadge("text", kind: .success)` | Pill chip with semantic kind (`.success/.danger/.warning/.info/.neutral`). | +| `ScarfTextField` | Themed text field — bordered, rounded, accent on focus. | +| `ScarfSectionHeader("Section")` | Uppercase tracked label used inside cards / lists. | +| `ScarfDivider` | 1px border-colored hairline. | +| `.buttonStyle(ScarfPrimaryButton())` | Rust filled button. | +| `.buttonStyle(ScarfSecondaryButton())` | Bordered button — neutral surface. | +| `.buttonStyle(ScarfGhostButton())` | Text-only button, no chrome. Use for Cancel / dismiss. | +| `.buttonStyle(ScarfDestructiveButton())` | Red filled button. Confirmation actions only. | + +## Reference: design folder + +Full screen mockups live at [`design/static-site/ui-kit/*.jsx`](https://github.com/awizemann/scarf/tree/main/design/static-site/ui-kit). Open `design/static-site/index.html` in a browser to walk through every screen at fidelity. + +The `ScarfChatView.ChatRootView` reference component in the package is a 3-pane chat redesign target — usable for previews but not yet swapped into the live chat (the existing `RichChatView` machinery still owns the real ACP pipeline). + +## Common mistakes to avoid + +- **Don't introduce purple/violet tones.** v2.5 shifted away; rust is the brand color now. +- **Don't use yellow for success.** `#F0AD4E` is `.warning`. `.success` is green. +- **Don't bypass the type scale** with `.font(.system(size: 13.5))`. Pick the closest preset. +- **Don't ship terminal / syntax-highlight palettes through ScarfColor.** Content semantics — keep them inline in the renderer. +- **Don't double-up page headers on iOS** (large nav title + ScarfPageHeader → looks broken). + +## Adding a new component + +If you're tempted to add a ninth button style or a new section-header variant: see if an existing component plus a token modifier covers it. New components belong in `ScarfComponents.swift`, must accept `ScarfColor` / `ScarfSpace` / `ScarfRadius` parameters (no hardcoded values), and need a corresponding entry in this page. + +--- +_Last updated: 2026-04-25 — Scarf v2.5.0 (initial publication)_ diff --git a/Hermes-Version-Compatibility.md b/Hermes-Version-Compatibility.md index 7f8082a..ec8e92c 100644 --- a/Hermes-Version-Compatibility.md +++ b/Hermes-Version-Compatibility.md @@ -31,6 +31,16 @@ Scarf reads Hermes's SQLite database directly and parses CLI output from `hermes **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. +**iOS exec channel — non-interactive PATH (v2.5+).** `CitadelServerTransport` runs commands over Citadel's raw exec channel which doesn't source the user's shell rc files, so non-interactive sessions land with a stripped PATH (typically `/usr/bin:/bin`). pipx installs `hermes` at `~/.local/bin/hermes`, and many sub-tools (git, curl, python) live in homebrew prefixes that the remote sshd would otherwise add via login-shell init. Mac's OpenSSH sshd handles this transparently; Citadel does not. v2.5 inline-prepends `PATH="$HOME/.local/bin:/opt/homebrew/bin:/usr/local/bin:$PATH"` on every iOS-routed `runProcess` so bare `hermes` resolves AND any subprocess it spawns can still find its tools. If you install `hermes` at an unusual path on a remote host (custom virtualenv, system-managed install dir), set the **Hermes binary hint** field when adding the server to point at the absolute path. + +**iOS exec output capture (v2.5+).** Citadel's `executeCommand` API throws `CommandFailed` on any non-zero exit and *discards* the captured stdout buffer in the throw path. `hermes skills browse` happens to print its full table and *then* exit non-zero on some hosts — pre-2.5 iOS got nothing while Mac (Foundation `Process`) got the full table with `exitCode=1`. v2.5 drives `executeCommandStream` directly, drains stdout + stderr regardless of outcome, and recovers the exit code from the `CommandFailed` catch — feature parity with Mac for any Hermes command that emits useful output before exiting non-zero. + +## 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 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. + ## What breaks across major Hermes versions If Hermes ships a major release that changes: diff --git a/Home.md b/Home.md index 281094f..b4082fe 100644 --- a/Home.md +++ b/Home.md @@ -2,22 +2,26 @@ 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 + Mac Sessions parity. Bump this line after `scripts/release.sh` completes the v2.5 publish in Phase G. -**Latest mobile:** ScarfGo public TestFlight — see [ScarfGo](ScarfGo) for the invite link. +**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. +**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. -**Available in:** English, Simplified Chinese (zh-Hans), German (de), French (fr), Spanish (es), Japanese (ja), Brazilian Portuguese (pt-BR). See [Localization](Localization). +**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._ ## Quick links - [Installation](Installation) — download, first launch, system requirements (Mac) - **[ScarfGo](ScarfGo)** — the iPhone companion (public TestFlight from v2.5) +- **[ScarfGo Onboarding](ScarfGo-Onboarding)** — SSH keys, paste-public-key, connection test - [Platform Differences](Platform-Differences) — Mac vs iOS feature matrix - [First Run](First-Run) — what Scarf expects in `~/.hermes/` - [Project Templates](Project-Templates) — `.scarftemplate` bundles, install / export / author -- [Architecture Overview](Architecture-Overview) — MVVM-F, services, transport +- **[Slash Commands](Slash-Commands)** — author project-scoped slash commands (v2.5+) +- **[Design System](Design-System)** — ScarfColor / ScarfFont / components reference +- [Architecture Overview](Architecture-Overview) — MVVM-F, services, transport, ScarfCore - [Servers & Remote](Servers-and-Remote) — adding remote Hermes hosts over SSH - [Localization](Localization) — supported languages + how to contribute a new one - [Release Notes Index](Release-Notes-Index) — every version's notes +- [Privacy Policy](Privacy-Policy) · [Support](Support) — what data the apps access; how to get help - [Wiki Maintenance](Wiki-Maintenance) — how this wiki is edited and kept in sync ## What Scarf does @@ -36,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. --- -_Last updated: 2026-04-25 — Scarf v2.5.0 queued + ScarfGo public TestFlight_ +_Last updated: 2026-04-25 — Scarf v2.5.0 + ScarfGo public TestFlight_ diff --git a/Memory-and-Skills.md b/Memory-and-Skills.md index 18089a3..99c415e 100644 --- a/Memory-and-Skills.md +++ b/Memory-and-Skills.md @@ -11,12 +11,13 @@ Live editor for Hermes's two memory files: **What you get:** -- Side-by-side edit + render with markdown preview. +- Side-by-side edit + render with markdown preview (Mac); single-pane editor with a "Saved" pill that survives keyboard dismissal + a Revert button (iOS). - **Live refresh** — when Hermes (or you) updates the file from outside, the view reloads via `HermesFileWatcher`. - **Profile awareness** — if you have multiple Hermes profiles, the picker switches between their memory files. - **External provider awareness** — when `memory_provider` in `config.yaml` is set to a service like Honcho or Supermemory, the view tells you so and links to the provider's docs. +- **Reset memory** _(v2.5+)_ — toolbar button on Mac + iOS Memory views that runs `hermes memory reset --yes` and refreshes the on-screen content. Destructive-confirmation dialog before the call lands. Surfaces stderr in an alert on failure. -Edits are written through `ServerContext.writeText` — local: atomic temp + swap; remote: scp + remote `mv`. See [Transport Layer](Transport-Layer). +Edits are written through `ServerContext.writeText` — local: atomic temp + swap; remote (Mac): `scp` + remote `mv`; remote (iOS): SFTP write via Citadel. See [Transport Layer](Transport-Layer). ## Skills @@ -27,6 +28,13 @@ Browse and manage Hermes skills: Operations are wrappers around the `hermes skills` CLI invoked via `context.runHermes(...)`, so they work identically against local and remote servers. +### v2.5 additions + +- **SKILL.md frontmatter chips.** Hermes v0.11 SKILL.md files carry richer YAML frontmatter (`allowed_tools`, `related_skills`, `dependencies`). Scarf parses it on both platforms and renders chip rows in the skill detail view. Old skills without these fields stay nil and the rows hide themselves. +- **"What's New" pill.** Per-server snapshot of `[skillId: signature]` (file count + sorted file names). When the snapshot changes between visits, both Skills views render a tinted pill at the top: "2 new, 4 updated since you last looked." Tap **Mark as seen** to update the snapshot. First-time loads silently prime so users don't see "everything is new!" noise on a fresh install. Backed by [`SkillSnapshotService`](Core-Services). +- **`design-md` skill prereq banner.** The `design-md` skill needs `npx` (Node.js 18+) on the host. New `SkillPrereqService.probe(binary:)` runs `which npx` over the transport when you open the skill detail; on miss, both Mac and iOS render a yellow banner with a per-OS install hint. +- **Spotify OAuth sheet.** The `spotify` skill needs OAuth via `hermes auth spotify`. Mac ships a dedicated Sign-in sheet (mirroring the v2.3 Nous Portal pattern): runs the subprocess, regex-detects the `accounts.spotify.com/authorize?...` URL, auto-opens it in your browser, polls `~/.hermes/auth.json` after subprocess exit to confirm the token landed. Five-state machine (starting → waiting → verifying → success / failure) with retry. iOS surfaces a documentation row noting OAuth needs to happen from Mac or a shell — phone OAuth flows are their own UX problem. + ## Related pages - [Hermes Paths](Hermes-Paths) for the underlying file layout. @@ -34,4 +42,4 @@ Operations are wrappers around the `hermes skills` CLI invoked via `context.runH - [Settings — Memory tab](Gateway-Cron-Health-Logs) for `memory_enabled`, `memory_char_limit`, `memory_provider`. --- -_Last updated: 2026-04-20 — Scarf v2.0.1_ +_Last updated: 2026-04-25 — Scarf v2.5.0 (memory reset, frontmatter chips, "What's New" pill, design-md/spotify prereqs)_ diff --git a/Platform-Differences.md b/Platform-Differences.md index 7614799..7b531b7 100644 --- a/Platform-Differences.md +++ b/Platform-Differences.md @@ -18,6 +18,8 @@ Both clients talk to the same Hermes host with the same paths and the same data. | **Skills tree** | Yes | Yes (read-only) | iOS won't grow a skill editor — too cramped. | | **Settings (read)** | Yes (full YAML) | Yes (full YAML) | — | | **Settings (write)** | Yes (full YAML editor) | **No** | iOS deferred. The plan was a curated `hermes config set ` shell-out for 7 keys; that landed in the codebase but isn't surfaced in v1 because changing settings remotely without local validation is too easy to break. Mac stays the canonical editor. | +| **Slash commands — author** _(v2.5)_ | Yes (per-project tab + live preview) | **No** | Multi-line markdown editing on a phone keyboard is its own UX problem; iOS gets a read-only browser instead. | +| **Slash commands — invoke / browse** _(v2.5)_ | Yes (slash menu) | Yes (read-only browser sheet) | — | | **Templates — install** | Yes | No | Templates are a content-creation surface; iOS won't get a UI for it in v1. Use Mac. | | **Templates — uninstall** | Yes | No | Same. | | **Templates — author / export** | Yes | No | Same. | diff --git a/Privacy-Policy.md b/Privacy-Policy.md new file mode 100644 index 0000000..b9c6a53 --- /dev/null +++ b/Privacy-Policy.md @@ -0,0 +1,91 @@ +# Privacy Policy + +> **Canonical version:** [awizemann.github.io/scarf/privacy/](https://awizemann.github.io/scarf/privacy/) +> +> This wiki page mirrors the canonical policy at [`scarf/docs/PRIVACY_POLICY.md`](https://github.com/awizemann/scarf/blob/main/scarf/docs/PRIVACY_POLICY.md). The repo file is the source of truth; the wiki copy is updated alongside major releases. + +_Last updated: 2026-04-25._ + +## Plain summary + +Scarf and ScarfGo are companion clients for the open-source [Hermes AI agent](https://github.com/awizemann/hermes-agent). Both apps connect from your device to a Hermes host you (or your team) operate. **Neither app collects, transmits, or stores your data on any server controlled by the developer.** All data the apps work with stays on your device or on Hermes hosts you configured yourself. + +## Apps covered + +- **Scarf** — macOS desktop client. Distributed via direct download (Sparkle) and built-in auto-update. +- **ScarfGo** — iOS companion. Distributed via TestFlight (and, in future, the App Store). + +## What data the apps access + +### On your device + +- **SSH credentials.** ScarfGo generates and stores an SSH private key in the iOS Keychain (`kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly`, never iCloud-synced). Used solely to authenticate with Hermes hosts you configure. Scarf reads SSH keys from `~/.ssh/` like any other SSH client. +- **Server configuration.** Host, user, port, nickname, and an optional remote `~/.hermes` path. Stored in `UserDefaults` (ScarfGo) or the standard app container (Scarf). Never transmitted off-device except as the destination address of your own SSH connections. +- **Hermes state cache.** When you tap a session or open the Dashboard, the app downloads a snapshot of `~/.hermes/state.db` from your Hermes host over SFTP and reads it locally. Cached on-device temporarily for performance; cleared when the app is force-quit or the OS reclaims storage. +- **Project registry + session attribution sidecar.** Scarf and ScarfGo read (and write, when you opt in) two JSON sidecar files on the Hermes host: `~/.hermes/scarf/projects.json` and `~/.hermes/scarf/session_project_map.json`. These describe the projects you've registered and which Hermes sessions belong to which project. Owned by you on your Hermes host. + +### On Hermes hosts you configure + +Same as the [Hermes agent privacy policy](https://hermes-agent.nousresearch.com/) (or whoever operates your Hermes deployment). The apps do not introduce any new server-side data collection. + +## What data the apps DO NOT collect + +- **No analytics.** No event tracking, no crash analytics, no performance metrics sent to any third party. Crash logs stay on-device unless you choose to share them with Apple via the standard iOS / macOS reporting flows. +- **No telemetry.** No "improve our product" beacons, no version-pinging, no install counters. +- **No ads or ad identifiers.** The `IDFA` / `IDFV` are not read or transmitted. +- **No cloud accounts.** There's no "Sign in with Scarf" — the apps only know about Hermes hosts you give them SSH access to. +- **No iCloud Keychain sync.** SSH keys are explicitly marked `ThisDeviceOnly` so they don't propagate. + +## Network connections the apps make + +- **SSH connections** to Hermes hosts you configured (port 22 by default; user-configurable). All Hermes data flows over these. +- **HTTPS to GitHub** for Sparkle's update check (Scarf only) and to fetch the public template catalog (`https://awizemann.github.io/scarf/templates/`). No personally identifying headers; cacheable. +- **HTTPS to models.dev** when Hermes refreshes its model catalog cache. Initiated by Hermes, not the apps directly. + +That's the complete list. The apps make no other network requests. + +## Push notifications + +ScarfGo includes a push-notification skeleton for future use — pending permissions on a remote agent run. **The Push Notifications capability is disabled in shipping builds** (gated by an internal `apnsEnabled = false` flag) until Apple Developer Program enrollment + a Hermes-side push sender land. No device tokens are registered with Apple's APNs servers in current builds. + +When push lands, only the device token will be transmitted, and only to the Hermes host you authorize (so it can address pushes back to your phone). Apple's APNs infrastructure will route the actual push payload, but the developer never sees it. + +## TestFlight beta program + +If you join the ScarfGo beta via TestFlight, Apple shares anonymized crash reports + the email you used to redeem the invite with the developer. Apple's standard [TestFlight terms](https://www.apple.com/legal/internet-services/itunes/testflight/) apply to that data — out of scope for this policy. + +## Security + +- iOS Keychain storage uses `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly` so credentials are unreachable while the device is locked and never synced to iCloud. +- SSH connections use the same protocol stack as `ssh(1)` — strict host-key verification on first connect, key-based auth (no passwords are sent over the wire), and Citadel's pure-Swift implementation on iOS. +- The macOS app is sandboxed where possible and notarized via Apple's standard Developer ID flow. + +## Children's privacy + +Neither app is directed at children under 13 and we do not knowingly collect any data from them. + +## Your rights + +Because we don't collect any data on developer-controlled servers, there is nothing for you to opt out of, request deletion of, or export. To remove all app-stored data from your device: + +- **ScarfGo**: delete the app. iOS purges the Keychain group + app container. +- **Scarf**: delete the app and the `~/Library/Containers/com.scarf` directory (the app is sandboxed; this is the only on-disk data). + +Your Hermes host's data (`~/.hermes/`) stays untouched — that's yours to manage. + +## Contact + +Questions, concerns, or notice of a security issue: [alan@wizemann.com](mailto:alan@wizemann.com). + +## Changes + +Material changes to this policy will be announced on the [Scarf wiki](https://github.com/awizemann/scarf/wiki) and recorded here with a new "Last updated" date. Beta testers will see a TestFlight build note when policy changes affect data handling. + +## Related pages + +- [Support](Support) — bug reports, feature requests, security disclosures. +- [ScarfGo Onboarding](ScarfGo-Onboarding) — how SSH keys are generated and stored. +- [Architecture Overview](Architecture-Overview) — what the apps actually do at a technical level. + +--- +_Last updated: 2026-04-25 — Scarf v2.5.0 (wiki mirror — canonical at [awizemann.github.io/scarf/privacy](https://awizemann.github.io/scarf/privacy/))_ diff --git a/Project-Templates.md b/Project-Templates.md index 538bed4..0bda0d1 100644 --- a/Project-Templates.md +++ b/Project-Templates.md @@ -132,6 +132,8 @@ And optionally: ├── skills/ │ └── / │ └── SKILL.md +├── slash-commands/ # NEW in schemaVersion 3 (v2.5) +│ └── .md # one Markdown file per project-scoped slash command ├── cron/ │ └── jobs.json # array of cron job definitions └── memory/ @@ -142,7 +144,7 @@ And optionally: ```json { - "schemaVersion": 2, + "schemaVersion": 3, "id": "yourname/your-template", "name": "Your Template", "version": "1.0.0", @@ -155,6 +157,7 @@ And optionally: "agentsMd": true, "instructions": ["CLAUDE.md"], "skills": ["example-skill"], + "slashCommands": ["audit-prs", "summarize-week"], "cron": 1, "memory": true, "config": 2 @@ -173,7 +176,13 @@ And optionally: } ``` -The `contents` block is a *claim* — the installer verifies every claim against the actual zip entries before anything touches disk. A bundle that ships 2 cron jobs while claiming `"cron": 1` is refused at load time. +The `contents` block is a *claim* — the installer verifies every claim against the actual zip entries before anything touches disk. A bundle that ships 2 cron jobs while claiming `"cron": 1` is refused at load time. Same applies to `slashCommands` — every name must have a matching `slash-commands/.md` file at the bundle root. + +### `slashCommands` (v2.5+, schemaVersion 3) + +Templates can ship project-scoped slash commands by listing each name in `contents.slashCommands` and including a matching `slash-commands/.md` file at the bundle root. The installer copies them to `/.scarf/slash-commands/` and tracks them in the lock file. **User-authored slash commands in the same directory survive uninstall** — only the template-shipped ones are removed. + +`schemaVersion` bumps to **3** only when a bundle ships slash commands. v1 and v2 bundles continue to install identically (the installer accepts schemaVersion 1, 2, and 3). See [Slash Commands](Slash-Commands) for the file format and substitution rules. ### `AGENTS.md` contract @@ -276,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. --- -_Last updated: 2026-04-23 — Scarf v2.2.0_ +_Last updated: 2026-04-25 — Scarf v2.5.0 (schemaVersion 3 — slash commands)_ diff --git a/ScarfCore-Package.md b/ScarfCore-Package.md new file mode 100644 index 0000000..2080bbe --- /dev/null +++ b/ScarfCore-Package.md @@ -0,0 +1,97 @@ +# ScarfCore Package + +`ScarfCore` is the local SwiftPM package at [`scarf/Packages/ScarfCore/`](https://github.com/awizemann/scarf/tree/main/scarf/Packages/ScarfCore) that holds every piece of code shared between the Mac (`scarf`) and iOS (`scarf mobile`) targets — models, services, view-models, the transport protocol, the ACP client, parsers, and security helpers. v2.5 extracted it from the Mac target so iOS could reuse it byte-for-byte instead of duplicating logic. + +If you're touching a service, model, or parser that needs to work on both platforms, that's ScarfCore's job. If you're touching something that only compiles on one platform (Sparkle, SwiftTerm, Citadel, KeychainSSHKeyStore), it lives in the per-platform target instead. + +## Package layout + +``` +Packages/ + ScarfCore/ # platform-agnostic core, no UI + Sources/ScarfCore/ + ACP/ # ACP wire types + ProcessACPChannel + SSHExecACPChannel + Models/ # HermesSession, HermesMessage, HermesConfig, ProjectEntry, etc. + Parsing/ # CronScheduleFormatter, HermesSkillsHubParser + Persistence/ # Codable structs for JSON sidecars + Security/ # OnboardingViewModel, IOSServerConfig, OnboardingState + Services/ # HermesDataService, ProjectDashboardService, SkillsScanner, … + ServerContext/ # ServerContext + ServerTransport protocol + factory + Transport/ # LocalTransport (Mac), SSHTransport (Mac remote) + ViewModels/ # IOSDashboardViewModel, IOSCronViewModel, SkillsViewModel, … + Tests/ScarfCoreTests/ # 163 tests across 12 suites — runs on Linux CI + + ScarfIOS/ # iOS-only glue + Sources/ScarfIOS/ + CitadelServerTransport.swift # ServerTransport via Citadel SSH (replaces system ssh) + KeychainSSHKeyStore.swift # iOS Keychain-backed Ed25519 key persistence + CitadelSSHService.swift # Pure-Swift keypair gen + connection probes + + ScarfDesign/ # rust palette, ScarfFont, ScarfSpace, ScarfRadius, components + Sources/ScarfDesign/ # See: Design System +``` + +Both `scarf` (Mac target) and `scarf mobile` (iOS target) declare local SPM dependencies on the three packages via `XCLocalSwiftPackageReference` entries in `project.pbxproj`. No registry, no fetch step — they live next to the app code in the repo. + +## What lives where + +### ScarfCore (both platforms) + +**Models** — plain `Codable` `Sendable` structs. `HermesSession`, `HermesMessage`, `HermesSkill`, `HermesConfig`, `HermesProject`, `ProjectEntry`, `ProjectDashboard`, `IOSServerConfig`, `ServerID`, etc. No reference types. + +**Services** — actor-isolated or `Sendable struct` services that read/write Hermes state through a transport. See [Core Services](Core-Services) for the catalog. + +**ViewModels** — `@Observable @MainActor` classes that drive feature UI. Mac and iOS both consume `IOSDashboardViewModel`, `IOSCronViewModel`, `SkillsViewModel`, `IOSSettingsViewModel`, `RichChatViewModel`, etc. (The `IOS` prefix is historical — the view-models are platform-agnostic now; renaming them is a v2.6 cleanup item.) + +**Transport** — `ServerTransport` protocol declaring the I/O surface every backend implements. `LocalTransport` (local file ops + `Process` exec) and `SSHTransport` (system `ssh` via OpenSSH) live here because they don't pull in iOS-specific dependencies. `CitadelServerTransport` lives in `ScarfIOS` because Citadel is iOS-only. + +**ACP** — `ACPChannel` protocol + `ACPRequest`/`ACPResponse`/`ACPNotification` types + `ProcessACPChannel` (Mac-spawned subprocess) + `SSHExecACPChannel` (iOS SSH-tunneled JSON-RPC). Both channels surface the same async event stream. + +**Parsing** — `HermesSkillsHubParser` (Rich-table parser for `hermes skills browse`/`search` output), `CronScheduleFormatter` (cron string → English). + +**Security / Onboarding** — `OnboardingViewModel` (state machine for the iOS onboarding flow), `OnboardingState` enum, `IOSServerConfig` (host/user/port/binaryHint shape). + +### ScarfIOS (iOS only) + +iOS-specific glue that can't compile on macOS: + +- `CitadelServerTransport` — `ServerTransport` implementation via [Citadel](https://github.com/orlandos-nl/Citadel) 0.12.x. Pure-Swift SSH; no `ssh` subprocess dependency. Drives `executeCommandStream` directly so stdout survives non-zero exits, prepends `PATH=$HOME/.local/bin:/opt/homebrew/bin:/usr/local/bin:$PATH` so non-interactive sessions resolve `hermes`. +- `KeychainSSHKeyStore` — Ed25519 keypair persistence in the iOS Keychain. Service `com.scarf.ssh-key`, account `server-key:`, accessibility `ThisDeviceOnly`. Wraps `SecItemCopyMatching` / `SecItemAdd` / `SecItemDelete` behind a typed API. +- `CitadelSSHService` — pure-Swift keypair generation + connection probes for the onboarding flow. + +### ScarfDesign (both platforms) + +Tokens + components. See **[Design System](Design-System)**. + +## Why `KeychainSSHKeyStore` isn't in ScarfCore + +`Security.framework` is available on both Mac and iOS but the **Keychain item attributes that make sense** differ between platforms. Mac uses `kSecClassGenericPassword` with file-protection levels; iOS uses `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly` to opt out of iCloud Keychain sync (which doesn't exist on Mac in the same form). Trying to share one type across both led to a parameter explosion. + +Mac doesn't need an in-app SSH key store because it uses the system `~/.ssh/` directory and ssh-agent. iOS does need one because there's no system SSH agent. The asymmetry is the reason the type lives in `ScarfIOS` and not `ScarfCore`. + +## Adding a new shared service + +1. Decide the service is platform-agnostic (no `AppKit` / `UIKit` / `WatchKit` imports, no `Process()` / `NSWorkspace`, no Citadel-specific types). If any of those creep in, the service belongs in the platform target instead. +2. Add a Swift file under `Packages/ScarfCore/Sources/ScarfCore/Services/`. +3. Take a `ServerContext` in `init`, decide isolation (`actor` for stateful, `Sendable struct` for stateless), expose async public methods, route I/O through `context.transport`. +4. Add a corresponding row to [Core Services](Core-Services) so the wiki catalog stays current. +5. Write a `Tests/ScarfCoreTests/Tests.swift` suite. Tests run on Linux CI, so no Foundation-mac-only APIs. + +The current breakdown: 30+ services, 12 test suites, 163 tests, three consecutive green runs as of v2.5.0. + +## Why we extracted in v2.5 + +Pre-v2.5, services lived in `scarf/scarf/Core/Services/` and the iOS target either duplicated them or imported them via a brittle `target` membership trick. The duplication path drifted (project context block subtly differed between platforms); the trick path didn't survive Swift 6 strict concurrency. Pulling everything into a proper SPM package solved both: one source of truth, one set of tests, both targets `import ScarfCore`. + +The split between ScarfCore (platform-agnostic) and ScarfIOS (iOS glue) keeps the package builds clean — ScarfCore compiles on Linux without dragging Citadel into the dependency tree. + +## Related pages + +- [Architecture Overview](Architecture-Overview) — high-level layering. +- [Core Services](Core-Services) — service catalog. +- [Transport Layer](Transport-Layer) — `ServerTransport` protocol details. +- [Design System](Design-System) — ScarfDesign package reference. +- [Adding a Service](Adding-a-Service) — full recipe for new shared services. + +--- +_Last updated: 2026-04-25 — Scarf v2.5.0 (initial publication)_ diff --git a/ScarfGo-Onboarding.md b/ScarfGo-Onboarding.md new file mode 100644 index 0000000..f65b21e --- /dev/null +++ b/ScarfGo-Onboarding.md @@ -0,0 +1,159 @@ +# ScarfGo Onboarding & SSH Keys + +ScarfGo connects to a Hermes server you operate over SSH. There's no Scarf-controlled cloud account — your iPhone holds an SSH key, your Hermes host trusts that key, and that's the entire trust relationship. This page walks through the onboarding flow step by step and explains what to do if the connection test fails. + +## What you'll need + +- An iPhone running iOS 18 or later. +- A Hermes-running host you can reach over SSH from your phone's network. Mac, a Linux box at home, a Tailscale node, a cloud VM — anything that `ssh user@host` works against from a regular machine. +- The host running Hermes v0.10.0 or later (v0.11.0 recommended for full v2.5 feature parity — see [Hermes Version Compatibility](Hermes-Version-Compatibility)). +- A way to paste a single line of text into a file on that host. Usually `ssh user@host` from another machine and editing `~/.ssh/authorized_keys`. If you're already running [Scarf](Home) on Mac, you have this. + +ScarfGo never asks for your account password. It also never holds an Apple-side cloud token — there's no "sign in with Scarf" anywhere. + +## The flow at a glance + +1. Server details (hostname, user, port, optional nickname) +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 +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 + +The whole thing takes about a minute once you have shell access to the host. + +## Step-by-step + +### 1. Server details + +Tap **Add Server**. Fill in: + +- **Host** — IP or DNS of the Hermes host. `192.168.1.50`, `myhost.local`, `tailscale-name.tailnet-xyz.ts.net`, anything `ssh` would accept. +- **User** — the SSH user. Often the same login you `ssh user@host` with from your terminal. +- **Port** — defaults to 22. Override if your host uses a non-standard SSH port. +- **Nickname (optional)** — display name in ScarfGo. Defaults to `user@host`. +- **Hermes binary hint (optional)** — leave empty unless you know `hermes` is at an unusual path. ScarfGo prepends `~/.local/bin`, `/opt/homebrew/bin`, and `/usr/local/bin` to PATH automatically — those four cover ~95% of pipx + Homebrew installs. + +Tap **Next**. + +### 2. Choose: generate or import + +- **Generate a new key** — recommended for most users. ScarfGo creates a fresh Ed25519 keypair on-device. This is the right choice unless you have a specific reason to reuse an existing key. +- **Import existing key** — paste a private + public key pair. Only useful if you already have an Ed25519 key you want to reuse (e.g. for ssh-agent compat). Note that iOS won't let you reuse `id_ed25519` from your Mac — it has to be specifically allowed on the Hermes host's `authorized_keys`. + +### 3. Generate (or paste) the keypair + +If generating: ScarfGo runs `CitadelSSHService.generateEd25519Key()` (pure-Swift, no `ssh-keygen`). About a second. + +If importing: paste the private-key PEM in the top box and the matching public-key line in the bottom box. ScarfGo validates the pair before accepting. + +Either way, the private half is stored in the iOS Keychain with these attributes: + +- **Service:** `com.scarf.ssh-key` +- **Account:** `server-key:` (one entry per configured server) +- **Accessibility:** `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly` + +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. + +### 4. Show the public key — paste into authorized_keys + +ScarfGo displays the public-key line in a monospaced selectable box, with a Copy button. + +Tap **Copy public key**. Now go to your Hermes host (in another shell) and append it: + +```bash +cat >> ~/.ssh/authorized_keys <<'EOF' +ssh-ed25519 AAAAC3...the-line-ScarfGo-showed-you... scarf-ios- +EOF +chmod 600 ~/.ssh/authorized_keys +chmod 700 ~/.ssh +``` + +This is its own line per device — the convention any second SSH client uses. Mac's Scarf keeps using your existing ssh-agent / `~/.ssh/config` and is unaffected. + +If `~/.ssh` doesn't exist yet on the host, create it: `mkdir -p ~/.ssh && chmod 700 ~/.ssh` first. + +Back in ScarfGo, tap **I've added this key**. + +### 5. Test connection + +ScarfGo opens an SSH session, runs a single probe (`echo $HOME && which hermes`), and if both succeed, saves the server. Expect a 2–4 second wait. + +If the probe succeeds you land on the Dashboard tab. **Done.** + +If it fails, see [Troubleshooting](#troubleshooting) below. + +## Multiple servers + +Same flow per server. The Servers list (under the **System** tab) shows every configured host with a connection-status pill. Tap any row to switch contexts; long-press for **Forget this server**, which deletes the Keychain key + UserDefaults entry for that one server (other servers are untouched). + +Each server holds its own keypair — there's no "primary key" anymore as of v2.5. (v1 builds had a `"primary"` Keychain account; v2 multi-server format auto-migrates the moment you `listAll`.) + +## Troubleshooting + +### "command not found" or "hermes: not found" + +Citadel's raw exec channel doesn't source the user's shell rc files (`.bashrc`, `.zshrc`, `.profile`). Non-interactive SSH sessions on most Linux distros land with `PATH=/usr/bin:/bin`. pipx installs `hermes` at `~/.local/bin/hermes` and Homebrew at `/opt/homebrew/bin` — neither of which are on the bare PATH. + +**v2.5 inline-prepends** `PATH="$HOME/.local/bin:/opt/homebrew/bin:/usr/local/bin:$PATH"` on every `runProcess` call, so the four common install locations resolve automatically. If you still see "command not found": + +1. SSH to the host yourself and run `which hermes`. Note the absolute path. +2. In ScarfGo: **Servers → tap the server → Edit → Hermes binary hint** → paste the absolute path (e.g. `/opt/scarf-tools/bin/hermes`). +3. Re-test the connection. + +The `~/.hermes/bin/hermes` location is also auto-probed (some self-install layouts put it there), so set the hint only if your install is somewhere none of the four candidates cover. + +### "Connection refused" / "Connection timed out" + +Network can't reach the host. Check: + +- Same Wi-Fi as the host? Verify with another tool (Files app, browsing a web service on the host). +- Tailscale / VPN? Make sure it's connected on the phone. +- Firewall on the host? `sudo ufw status` on Linux; **System Settings → Network → Firewall** on macOS. +- Custom SSH port? Confirm in ScarfGo's server-edit screen. + +If `ssh user@host` from another device on the same network also fails, fix that first — ScarfGo can't connect to a host you can't ssh to. + +### "Authentication failed" / "Permission denied (publickey)" + +The public key you copied into `authorized_keys` doesn't match what ScarfGo is offering. Common causes: + +- **You pasted the wrong line.** Tap **Show public key** again in ScarfGo and re-copy. Compare line-for-line against what's in `~/.ssh/authorized_keys`. +- **`authorized_keys` permissions are wrong.** Run `chmod 600 ~/.ssh/authorized_keys && chmod 700 ~/.ssh` on the host. SSH refuses to read `authorized_keys` if it's group-writable. +- **You appended after a line without a trailing newline.** `cat >>` should add the newline; if you used a text editor and saved without a final newline, the new line gets glued to the old one. Fix with `echo "" >> ~/.ssh/authorized_keys` then re-paste. +- **The host's `sshd` config disabled key auth.** Run `sshd -T 2>/dev/null | grep pubkeyauth` — should be `yes`. + +### "Host key verification failed" + +ScarfGo strict-checks SSH host keys. If the host's key changed (new install, MITM unlikely but possible), use **Servers → Forget this server** and re-onboard — Citadel will accept the new host key on first connect. + +### Onboarding succeeds but Dashboard shows zero sessions + +ScarfGo downloads a snapshot of `~/.hermes/state.db` over SFTP. If your Hermes install hasn't yet written the DB (no sessions ever started), the snapshot is empty. Start a session via the Mac app or `hermes chat` first, then pull-to-refresh the Dashboard. + +### "Memory says 'Save failed' silently" + +Pull-to-refresh — usually a transient SFTP hiccup. If it persists, check the SSH user has write permission on `~/.hermes/memories/`. + +### Biometric / passcode prompt loops + +Cancelling Face ID or the device passcode prompt no longer drops you back into onboarding (v2.5 fix). If it happens, the app surfaces a banner on the server list with a Dismiss button — re-tap the server to retry the unlock. + +## Privacy and key handling — quick recap + +- **No iCloud sync.** Keys are explicitly marked `ThisDeviceOnly` and excluded from iCloud Keychain. +- **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. +- **One key per device.** Adding a second iPhone means a second `authorized_keys` line. Same convention you'd follow for a new Mac. + +Full policy: [Privacy Policy](Privacy-Policy). + +## Related pages + +- [ScarfGo](ScarfGo) — feature tour, FAQs, limitations. +- [Platform Differences](Platform-Differences) — Mac vs iOS feature matrix. +- [Hermes Version Compatibility](Hermes-Version-Compatibility) — what's required on the host. +- [Servers & Remote](Servers-and-Remote) — Mac equivalent for adding remote Hermes hosts. +- [Support](Support) — bug reports, feature requests, security disclosures. + +--- +_Last updated: 2026-04-25 — Scarf v2.5.0_ diff --git a/ScarfGo.md b/ScarfGo.md index 8d19fa2..ffaf1fc 100644 --- a/ScarfGo.md +++ b/ScarfGo.md @@ -20,9 +20,9 @@ ScarfGo is a fully native iOS app — not a web view, not a remote desktop. It s ScarfGo is in **public TestFlight**. Apple-provided test environment, free to join, no payment, no Apple ID needed for beta installs. 1. **Get the TestFlight app** — install from the App Store if you don't have it. -2. **Open the public TestFlight invite link** — _link will appear here once Apple's Beta Review approves the first build. Bookmark this page._ +2. **Open the public TestFlight invite link** — ****. The link is live now but only accepts new beta testers once Apple's Beta Review approves the first build. If you hit a "this beta isn't accepting any new testers" splash, bookmark this page and try again in 24–48h — that's the Beta Review queue, not a permanent state. 3. **Tap "Accept" and "Install"** — TestFlight installs ScarfGo alongside your other apps. -4. **Open ScarfGo** — onboarding walks you through host details, generates a new SSH keypair, and gives you the public-key snippet to paste into your Hermes host's `~/.ssh/authorized_keys`. +4. **Open ScarfGo** — onboarding walks you through host details, generates a new SSH keypair, and gives you the public-key snippet to paste into your Hermes host's `~/.ssh/authorized_keys`. Step-by-step walkthrough: [ScarfGo Onboarding](ScarfGo-Onboarding). Onboarding details: @@ -42,6 +42,7 @@ Onboarding details: | **Cron** | List view of `~/.hermes/cron/jobs.json` with **human-readable schedules** ("Every 6 hours", "Weekdays at 09:00") and a relative next-run ("in 4 hours"). Read-only in v1 — editing comes later. | | **Skills** | Browse the skills tree from `~/.hermes/skills/`. Read-only. | | **Settings** | Read-only view of `config.yaml`. An in-app editor is planned but not in v1 — see [Platform Differences](Platform-Differences). | +| **Slash commands** _(v2.5)_ | Read-only browser of project-scoped slash commands shipped via `/.scarf/slash-commands/`. Tap a row to see the expanded prompt with a sample-argument field. Authoring is Mac-only in v1. See [Slash Commands](Slash-Commands). | ## Project-scoped chat diff --git a/Sidebar-and-Navigation.md b/Sidebar-and-Navigation.md index aa20bee..8dc90fc 100644 --- a/Sidebar-and-Navigation.md +++ b/Sidebar-and-Navigation.md @@ -84,5 +84,11 @@ There is no search bar, no collapsible-section state to persist — every sectio Each window is bound to one `ServerContext` and one `AppCoordinator`. The window menu (and `⌘1…⌘9` keyboard shortcuts) opens additional windows for other servers — see [Keyboard Shortcuts](Keyboard-Shortcuts). Closing a window destroys its coordinator; reopening reads the section back from defaults. +## ScarfGo (iOS) navigation + +ScarfGo uses a different model — a 5-tab `TabView` rather than a sidebar. The tabs (Dashboard | Projects | Chat | Skills | System) are wrapped in their own `NavigationStack`s so push navigation (Cron editor, Memory detail, Project detail, Settings) stays scoped to the tab. Cross-tab signalling (Dashboard row → Chat tab resume, Project Detail → in-project chat handoff, notification deep-link → Chat) flows through `ScarfGoCoordinator`. `.tabViewStyle(.sidebarAdaptable)` automatically switches to a sidebar layout on iPad / Mac Catalyst — no separate code path. + +The Mac sidebar's "System" / advanced sections collapse into the iOS **System** tab (server identity, Memory link, Cron link, Settings link, Disconnect / Forget). See [Platform Differences](Platform-Differences) for the full Mac↔iOS feature matrix. + --- -_Last updated: 2026-04-20 — Scarf v2.0.1_ +_Last updated: 2026-04-25 — Scarf v2.5.0 (ScarfGo 5-tab nav added)_ diff --git a/Slash-Commands.md b/Slash-Commands.md new file mode 100644 index 0000000..4434f96 --- /dev/null +++ b/Slash-Commands.md @@ -0,0 +1,123 @@ +# Slash Commands (project-scoped) + +A project can ship its own slash commands — reusable prompt templates as Markdown files at `/.scarf/slash-commands/.md` with YAML frontmatter. Invoke as `/ [args]` from chat; Scarf substitutes `{{argument}}` placeholders in the body and sends the expanded prompt to Hermes. The agent never sees the slash itself, just the rendered prompt with a `` marker so it can recognize the command in transcripts. + +Project-scoped slash commands are a Scarf primitive — Hermes has no project-scoped slash command concept of its own. Scarf intercepts the chat menu client-side, expands the prompt, and forwards. Works uniformly on Mac + iOS, local + remote SSH, against any Hermes version. + +## File format + +```markdown +--- +name: audit-prs +description: Summarize open pull requests on the active branch +argumentHint: "" +model: claude-sonnet-4.5 +tags: [git, summary] +--- + +You are auditing open pull requests for **{{argument | default: "the current repo"}}**. + +For each PR: +1. Title + author + age +2. One-line summary of the diff +3. Status (mergeable, conflicts, draft, blocked on review) + +Output as a Markdown table sorted by age (oldest first). +``` + +Front matter fields: + +| Key | Required | Type | Purpose | +|---|---|---|---| +| `name` | yes | string | The slash. Lowercase, dashes-allowed, no spaces. Must match the filename minus `.md`. | +| `description` | yes | string | Single-line summary for the slash menu. | +| `argumentHint` | no | string | Display hint shown in the slash menu after the name (e.g. ``). | +| `model` | no | string | Override the active model just for this command's expansion. Use the same provider/model identifier the model picker uses. | +| `tags` | no | string[] | Free-form tags for grouping in the slash menu. | + +Body is plain Markdown. Two substitution patterns: + +- `{{argument}}` — replaced with whatever the user typed after `/`. If they typed nothing, the placeholder stays literal. +- `{{argument | default: "fallback"}}` — replaced with the user's input, OR the fallback when input is empty. + +Multi-argument support is **not** in v2.5 — `argument` is a single string. Future-versioned slash commands may add `{{arg1}}` / `{{arg2}}`; current bundles ignore unknown placeholders. + +## Authoring (Mac) + +Mac per-project view gains a **Slash Commands** tab alongside Dashboard / Site / Sessions. List, add, edit, duplicate, delete commands. The editor includes a live preview pane that shows the expanded prompt with a sample-argument field so authors see exactly what Hermes will receive. + +Workflow: + +1. **Projects sidebar → pick a project → Slash Commands tab.** +2. **+ New** → fill in name, description, optional argumentHint and model, then write the body. +3. **Sample argument** field — type a value to preview the expansion. +4. **Save** writes the file to `/.scarf/slash-commands/.md`. + +Files are plain Markdown, so you can also author them outside Scarf — any editor works. Scarf watches the directory and refreshes the menu live. + +## Invoking (Mac + iOS) + +In any chat scoped to that project, type `/`. The slash menu shows: + +- **Hermes-advertised commands** (`/compress`, `/clear`, etc.) at the top. +- **User `quick_commands:` from `~/.hermes/config.yaml`** in the middle. +- **Project-scoped slash commands** at the bottom under a "**Project commands**" subheading. + +Pick one with ↑/↓ + Enter or Tab. Commands with `argumentHint` insert a trailing space so you can start typing the argument immediately. Hit Enter again to send. Scarf expands the body, prepends the `` marker, and sends the result to Hermes. + +iOS shows the same menu but as a sheet that slides up from the composer (touch targets too small for a popover). Same picking model: tap a row, fill in the argument field at the bottom, send. + +## ScarfGo (iOS) — read-only browser + +iOS ships in v2.5 as **read-only**. The chat-context bar grows a ` slash` chip when the project has slash commands; tap to browse them in a sheet. Multi-line markdown editing is a phone keyboard's nightmare, so v2.5 keeps Mac as the canonical editor; iOS catches up in v2.6+. + +## AGENTS.md block extension + +The Scarf-managed project context block written to `/AGENTS.md` (between `` and `:end -->`) lists every available slash command so the agent can answer *"what slash commands does this project have?"* and recognise the `` marker prepended to expanded prompts. + +The block is regenerated before each project-scoped session start, so adding a new command is reflected on the next chat without a separate refresh step. + +## Packaging via `.scarftemplate` (schemaVersion 3) + +Templates ship slash commands by: + +1. Including `slash-commands/.md` files at the bundle root. +2. Listing each name in `manifest.contents.slashCommands`. +3. Bumping `schemaVersion` to 3. + +Example manifest: + +```json +{ + "schemaVersion": 3, + "id": "yourname/your-template", + "name": "Your Template", + "version": "1.2.0", + "contents": { + "dashboard": true, + "agentsMd": true, + "slashCommands": ["audit-prs", "summarize-week"] + } +} +``` + +The installer copies the files to the project's `.scarf/slash-commands/` directory and tracks them in the lock file. **User-authored slash commands in the same directory survive uninstall** — only the template-shipped ones are removed. + +The catalog validator (`tools/build-catalog.py`) enforces the same schema as the Swift verifier — invalid bundles fail PR CI before they hit the catalog. v1 and v2 templates remain byte-compatible; only bundles that ship slash commands need to bump to schemaVersion 3. + +See [Project Templates](Project-Templates) for the full bundle format. + +## Why a Scarf primitive (not a Hermes one) + +Hermes already has a slash-command surface — `quick_commands:` in `~/.hermes/config.yaml`, plus whatever slashes the agent advertises via ACP's `available_commands_update`. Both are global to the host. Project-scoped commands need to live with the project, travel with it via templates, and not pollute the global namespace when many projects share a host. + +Implementing them at the client makes the slash a pure UI concern: Hermes never knows the slash existed, just receives a normal prompt with a marker comment. The marker survives transcript export, AGENTS.md introspection, and resume — so the agent has audit context for what the user invoked even though the dispatch is client-side. + +## Related pages + +- [Project Templates](Project-Templates) — schemaVersion 3 packaging details. +- [Chat](Chat) — slash menu UX in context. +- [ScarfGo](ScarfGo) — iOS read-only browser. + +--- +_Last updated: 2026-04-25 — Scarf v2.5.0 (initial publication)_ diff --git a/Support.md b/Support.md new file mode 100644 index 0000000..67aec48 --- /dev/null +++ b/Support.md @@ -0,0 +1,86 @@ +# Support + +How to get help with Scarf (macOS) or ScarfGo (iOS), report a bug, request a feature, or disclose a security issue. This page is the **Support URL** Apple's App Store reviewer follows — it's intentionally simple and link-heavy so anyone landing here from the App Store finds what they need without scrolling. + +## I'm having trouble using the app + +Start with the troubleshooting docs — most issues match a known cause. + +| Symptom | Page to check | +|---|---| +| ScarfGo can't connect to my Hermes host | [ScarfGo Onboarding](ScarfGo-Onboarding) → Troubleshooting | +| Mac Scarf can't reach a remote server | [Servers & Remote](Servers-and-Remote) | +| Chat hangs or shows "Spinning forever" | [Chat](Chat) → Troubleshooting + [Slow Chat Startup](Troubleshooting-Slow-Chat-Startup) | +| Skills hub Browse is empty | [Hermes Version Compatibility](Hermes-Version-Compatibility) — usually a v2.5+ Citadel exec channel issue, fixed in 2.5 | +| TestFlight says "this beta isn't accepting any new testers" | Apple's Beta Review queue is processing the latest build. See [ScarfGo](ScarfGo) — bookmark the page and try again in 24–48h. | +| Hermes "command not found" over iOS SSH | [ScarfGo Onboarding](ScarfGo-Onboarding) — set the **Hermes binary hint** in the server-edit screen | + +## Bug reports + +GitHub Issues is the canonical bug tracker: + +**[github.com/awizemann/scarf/issues](https://github.com/awizemann/scarf/issues)** + +Tag your issue with the right component so it gets routed: + +- `component: scarf` — Mac app bugs. +- `component: scarfgo` — iOS app bugs. +- `component: scarfcore` — shared package bugs (services, models, transport). +- `component: design-system` — ScarfDesign tokens / components. +- `component: templates` — `.scarftemplate` install / uninstall / catalog issues. +- `component: docs` — wiki / README / release-notes corrections. + +Include in every report: + +- Scarf version: **Settings → General → About** (Mac) / **System tab → Server section** (iOS). +- Hermes version: `hermes --version` on the host. +- macOS / iOS version. +- Steps to reproduce. +- Relevant log snippet from `~/.hermes/logs/errors.log` (filter sensitive content first). + +## Feature requests + +Same place, different tag: + +- `feature: scarf` / `feature: scarfgo` / etc. + +Include the use case ("I want to do X because Y") and ⭐ the issue if you'd use the proposed feature — star count is a real input to prioritization. + +## TestFlight feedback (ScarfGo only) + +Open ScarfGo → take a screenshot → use the **Send Beta Feedback** button TestFlight overlays on your screenshot. The screenshot + your text go straight to the developer along with device + iOS version metadata. This is the right channel for TestFlight build issues (crashes, layout glitches on a specific device, missing strings). + +For non-TestFlight-build issues (architectural feature requests, Mac↔iOS parity gaps), GitHub Issues is still the right place. + +## Security issues + +**Do not** open public GitHub issues for security disclosures. Instead: + +- Email **[alan@wizemann.com](mailto:alan@wizemann.com)** with `[security]` in the subject line. +- Or use GitHub's private security advisories: . + +I'll acknowledge within 48 hours and coordinate disclosure timing. Standard 90-day disclosure window applies for non-critical issues; immediate coordination for anything affecting credential storage or remote-code-execution surfaces. + +## Privacy + +See **[Privacy Policy](Privacy-Policy)** for what data the apps access and what they do not collect. Short version: nothing leaves your device or your Hermes host except over SSH connections you authorize. No analytics, no telemetry, no developer-controlled cloud. + +## License + +Both Scarf and ScarfGo are MIT-licensed. Source: . + +## Direct contact + +Email: **[alan@wizemann.com](mailto:alan@wizemann.com)** + +Email is for security disclosures, press / partnership inquiries, and "I tried GitHub Issues and the issue was closed but I think you missed something" situations. For everything else, the Issues tracker has more eyes on it and a better chance of someone else hitting the same problem and helping. + +## Related pages + +- [ScarfGo](ScarfGo) — feature tour, FAQs. +- [ScarfGo Onboarding](ScarfGo-Onboarding) — SSH key setup walkthrough. +- [Servers & Remote](Servers-and-Remote) — Mac remote-server setup. +- [Privacy Policy](Privacy-Policy) — data handling. + +--- +_Last updated: 2026-04-25 — Scarf v2.5.0 (initial publication)_ diff --git a/_Sidebar.md b/_Sidebar.md index 23c5886..b8b32ca 100644 --- a/_Sidebar.md +++ b/_Sidebar.md @@ -6,12 +6,14 @@ **ScarfGo (iOS)** - [ScarfGo](ScarfGo) +- [ScarfGo Onboarding](ScarfGo-Onboarding) - [Platform Differences](Platform-Differences) **User Guide** - [Dashboard](Dashboard) - [Insights & Activity](Insights-and-Activity) - [Chat](Chat) +- [Slash Commands](Slash-Commands) - [Memory & Skills](Memory-and-Skills) - [Projects & Profiles](Projects-and-Profiles) - [Project Templates](Project-Templates) @@ -23,8 +25,10 @@ **Architecture** - [Overview](Architecture-Overview) - [Core Services](Core-Services) +- [Design System](Design-System) - [Data Model](Data-Model) - [Transport Layer](Transport-Layer) +- [ScarfCore Package](ScarfCore-Package) - [Sidebar & Navigation](Sidebar-and-Navigation) - [ACP Subprocess](ACP-Subprocess) @@ -51,3 +55,7 @@ **Release History** - [Release Notes Index](Release-Notes-Index) - [Roadmap](Roadmap) + +**Legal & Support** +- [Privacy Policy](Privacy-Policy) +- [Support](Support)