Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes
6 changes: 3 additions & 3 deletions Docs/Memory/Conversation-LongTerm-Memory-Design.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,6 @@ Tiered cleanup defaults:
- Validated/confirmed and pattern aggregates: 365 days

## Feature Flags
- `KEYSCRIBE_FEATURE_CONVERSATION_LONG_TERM_MEMORY`
- `KEYSCRIBE_FEATURE_CONVERSATION_AUTO_PROMOTION`
- `KEYSCRIBE_FEATURE_STRICT_PROJECT_ISOLATION`
- `OPENASSIST_FEATURE_CONVERSATION_LONG_TERM_MEMORY`
- `OPENASSIST_FEATURE_CONVERSATION_AUTO_PROMOTION`
- `OPENASSIST_FEATURE_STRICT_PROJECT_ISOLATION`
16 changes: 8 additions & 8 deletions Docs/User-Guide.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# KeyScribe User Guide
# Open Assist User Guide

This guide is for end users who want to install KeyScribe, configure it quickly, and use its core features with confidence.
This guide is for end users who want to install Open Assist, configure it quickly, and use its core features with confidence.

## 1. What KeyScribe Does
## 1. What Open Assist Does

KeyScribe is a macOS menu-bar dictation app. You press a shortcut, speak, and text is inserted into your active app.
Open Assist is a macOS menu-bar dictation app. You press a shortcut, speak, and text is inserted into your active app.

Core capabilities:

Expand All @@ -24,9 +24,9 @@ Core capabilities:
## 3. Install and Launch

1. Download the latest release from GitHub Releases.
2. Open `KeyScribe.app`.
2. Open `Open Assist.app`.
3. Approve requested permissions when prompted.
4. You should now see the KeyScribe icon in the macOS menu bar.
4. You should now see the Open Assist icon in the macOS menu bar.

## 4. First-Run Setup Checklist

Expand Down Expand Up @@ -97,7 +97,7 @@ Provider options include:

## 8. AI Studio and Local AI Setup

Open **Settings → AI & Models → Open AI Studio**.
Open **Settings → AI & Models → AI Studio**.

For local AI with no API key:

Expand Down Expand Up @@ -160,7 +160,7 @@ If update checks fail, confirm the appcast feed is published and reachable by th

## 11. Privacy and Local Data

KeyScribe is local-first:
Open Assist is local-first:

- No account required
- No telemetry by default
Expand Down
File renamed without changes
14 changes: 7 additions & 7 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,36 @@
import PackageDescription

let package = Package(
name: "KeyScribe",
name: "OpenAssist",
platforms: [
.macOS("13.3")
],
products: [
.executable(name: "KeyScribe", targets: ["KeyScribe"])
.executable(name: "OpenAssist", targets: ["OpenAssist"])
],
dependencies: [
.package(url: "https://github.com/sparkle-project/Sparkle", from: "2.6.0"),
.package(url: "https://github.com/gonzalezreal/swift-markdown-ui", from: "2.4.1")
],
targets: [
.executableTarget(
name: "KeyScribe",
name: "OpenAssist",
dependencies: [
"whisper",
.product(name: "Sparkle", package: "Sparkle"),
.product(name: "MarkdownUI", package: "swift-markdown-ui")
],
path: "Sources/KeyScribe",
path: "Sources/OpenAssist",
resources: [.process("../../Resources")]
),
.binaryTarget(
name: "whisper",
path: "Vendor/Whisper/whisper.xcframework"
),
.testTarget(
name: "KeyScribeTests",
dependencies: ["KeyScribe"],
path: "Tests/KeyScribeTests"
name: "OpenAssistTests",
dependencies: ["OpenAssist"],
path: "Tests/OpenAssistTests"
)
]
)
58 changes: 29 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
<p align="center">
<img src="Assets/AppLogo.png" alt="KeyScribe" width="120" />
<img src="Assets/AppLogo.png" alt="Open Assist" width="120" />
</p>

<h1 align="center">KeyScribe</h1>
<h1 align="center">Open Assist</h1>

<p align="center">
A macOS menu-bar dictation app that inserts text into your current app.<br/>
Local-first speech, optional AI help, and simple setup.
</p>

<p align="center">
<a href="https://github.com/manikv12/KeyScribe/releases"><img alt="Download" src="https://img.shields.io/github/v/release/manikv12/KeyScribe?label=Download&color=0f172a&style=flat-square" /></a>
<a href="https://github.com/manikv12/OpenAssist/releases"><img alt="Download" src="https://img.shields.io/github/v/release/manikv12/OpenAssist?label=Download&color=0f172a&style=flat-square" /></a>
<img alt="macOS" src="https://img.shields.io/badge/macOS-13.3%2B-blue?style=flat-square" />
<img alt="Swift" src="https://img.shields.io/badge/Swift-5.9-orange?style=flat-square" />
<img alt="License" src="https://img.shields.io/github/license/manikv12/KeyScribe?style=flat-square" />
<img alt="License" src="https://img.shields.io/github/license/manikv12/OpenAssist?style=flat-square" />
</p>

---

## What KeyScribe Is
## What Open Assist Is

KeyScribe is a menu-bar app for macOS.
Open Assist is a menu-bar app for macOS.

You press a shortcut, speak, and KeyScribe inserts the text into the app you are using right now. It is built for fast dictation, low friction, and local-first use.
You press a shortcut, speak, and Open Assist inserts the text into the app you are using right now. It is built for fast dictation, low friction, and local-first use.

Important behavior today:

Expand Down Expand Up @@ -79,7 +79,7 @@ Important behavior today:
- Pinned or automatic rewrite context selection in AI Studio
- Cross-IDE conversation sharing for matching coding contexts
- Context mappings and conversation inspection are available in AI Studio
- External memory indexing exists, but it is still behind the `KEYSCRIBE_FEATURE_AI_MEMORY=1` feature flag
- External memory indexing exists, but it is still behind the `OPENASSIST_FEATURE_AI_MEMORY=1` feature flag

### Quality-of-Life Features

Expand All @@ -97,8 +97,8 @@ Important behavior today:
- Settings, transcript history, and learned corrections stay on your Mac
- API keys and OAuth sessions are stored in macOS Keychain
- If you choose cloud transcription or cloud rewrite providers, your audio/text is sent to that provider
- Clipboard copying is off by default, so KeyScribe tries to avoid leaving dictation in clipboard history
- Local crash logs stay on disk in `~/Library/Logs/KeyScribe/`
- Clipboard copying is off by default, so Open Assist tries to avoid leaving dictation in clipboard history
- Local crash logs stay on disk in `~/Library/Logs/OpenAssist/`

---

Expand Down Expand Up @@ -133,8 +133,8 @@ All shortcuts can be changed in Settings.

## Quick Start

1. Download the latest release from [GitHub Releases](https://github.com/manikv12/KeyScribe/releases).
2. Open `KeyScribe.app`.
1. Download the latest release from [GitHub Releases](https://github.com/manikv12/OpenAssist/releases).
2. Open `Open Assist.app`.
3. Grant **Accessibility** and **Microphone** access when prompted.
4. If you use **Apple Speech**, also grant **Speech Recognition**.
5. Open **Settings** from the menu bar.
Expand Down Expand Up @@ -168,13 +168,13 @@ For a step-by-step walkthrough, see the [User Guide](Docs/User-Guide.md).

This creates:

- `dist/KeyScribe.app`
- `dist/Open Assist.app`

What `build.sh` does today:

- Downloads `Vendor/Whisper/whisper.xcframework` automatically if it is missing
- Runs `swift build -c release`
- Bundles the app into `dist/KeyScribe.app`
- Bundles the app into `dist/Open Assist.app`
- Uses ad-hoc signing by default unless `DEVELOPER_ID` is set

### Useful build options
Expand All @@ -184,8 +184,8 @@ What `build.sh` does today:
./build.sh --make-dmg
```

- `--install` copies the app to `/Applications/KeyScribe.app`
- `--make-dmg` also creates `dist/KeyScribe.dmg`
- `--install` copies the app to `/Applications/Open Assist.app`
- `--make-dmg` also creates `dist/Open Assist.dmg`
- `--install` also resets Accessibility permission, so you will need to grant it again after install

### Signed / distribution builds
Expand All @@ -202,7 +202,7 @@ There is also a project-specific helper:
./build-local.sh --make-dmg
```

`Scripts/notarize.sh` notarizes `dist/KeyScribe.dmg` and expects these environment variables:
`Scripts/notarize.sh` notarizes `dist/Open Assist.dmg` and expects these environment variables:

- `APPLE_ID`
- `APPLE_TEAM_ID`
Expand Down Expand Up @@ -230,40 +230,40 @@ Run insertion reliability checks directly with:
Scripts/run-insertion-reliability.sh --regression
```

The repo also contains `XCTest` coverage for some conversation and settings behavior in `Tests/KeyScribeTests/`.
The repo also contains `XCTest` coverage for some conversation and settings behavior in `Tests/OpenAssistTests/`.

---

## Diagnostics

If insertion is not behaving the way you expect, you can enable insertion diagnostics:

- Turn it on in app settings, or set `KEYSCRIBE_INSERTION_DIAGNOSTICS=1`
- Default log path: `/tmp/keyscribe-insertion-diagnostics.log`
- You can override the log path with `KEYSCRIBE_INSERTION_DIAGNOSTICS_PATH`
- Turn it on in app settings, or set `OPENASSIST_INSERTION_DIAGNOSTICS=1`
- Default log path: `/tmp/openassist-insertion-diagnostics.log`
- You can override the log path with `OPENASSIST_INSERTION_DIAGNOSTICS_PATH`

Crash logs, when present, are stored locally at `~/Library/Logs/KeyScribe/crash.log`.
Crash logs, when present, are stored locally at `~/Library/Logs/OpenAssist/crash.log`.

---

## Repo Layout

```text
Sources/KeyScribe/ App code
Sources/OpenAssist/ App code
Resources/ Info.plist, icons, entitlements
Scripts/ Build, test, release, and utility scripts
Tests/KeyScribeTests/ XCTest coverage
Tests/OpenAssistTests/ XCTest coverage
Docs/ User-facing docs
Wiki/ Extra product notes
Vendor/Whisper/ Bundled whisper.cpp XCFramework
```

Main app areas:

- `Sources/KeyScribe/App.swift` wires the app lifecycle, menu bar, settings, and windows.
- `Sources/KeyScribe/Services/` contains transcription, insertion, AI, memory, and settings logic.
- `Sources/KeyScribe/Views/` contains SwiftUI screens such as the status popover and AI Studio.
- `Sources/KeyScribe/Support/` contains feature flags, permissions, and window helpers.
- `Sources/OpenAssist/App.swift` wires the app lifecycle, menu bar, settings, and windows.
- `Sources/OpenAssist/Services/` contains transcription, insertion, AI, memory, and settings logic.
- `Sources/OpenAssist/Views/` contains SwiftUI screens such as the status popover and AI Studio.
- `Sources/OpenAssist/Support/` contains feature flags, permissions, and window helpers.

---

Expand All @@ -280,5 +280,5 @@ Main app areas:

- The app currently supports three speech paths: Apple Speech, local `whisper.cpp`, and cloud providers.
- AI Studio is already integrated and is the main place for rewrite provider setup and local AI setup.
- The advanced external memory-indexing workflow is present in the codebase, but it is still gated behind `KEYSCRIBE_FEATURE_AI_MEMORY=1`.
- The advanced external memory-indexing workflow is present in the codebase, but it is still gated behind `OPENASSIST_FEATURE_AI_MEMORY=1`.
- The old README said the default build created both `.app` and `.dmg`; today, the default build creates the `.app`, and DMG creation is opt-in with `--make-dmg`.
12 changes: 6 additions & 6 deletions Resources/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>com.keyscribe.KeyScribe</string>
<string>com.manikvashith.OpenAssist</string>
<key>CFBundleName</key>
<string>KeyScribe</string>
<string>Open Assist</string>
<key>CFBundleExecutable</key>
<string>KeyScribe</string>
<string>OpenAssist</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>LSUIElement</key>
<true />
<key>NSMicrophoneUsageDescription</key>
<string>KeyScribe needs microphone access to transcribe your voice.</string>
<string>Open Assist needs microphone access to transcribe your voice.</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>KeyScribe uses speech recognition so you can transcribe while holding the shortcut.</string>
<string>Open Assist uses speech recognition so you can transcribe while holding the shortcut.</string>
<key>LSMinimumSystemVersion</key>
<string>13.3</string>
<key>CFBundleIconFile</key>
Expand All @@ -27,7 +27,7 @@
<key>CFBundleVersion</key>
<string>73</string>
<key>SUFeedURL</key>
<string>https://manikv12.github.io/KeyScribe/appcast.xml</string>
<string>https://manikv12.github.io/OpenAssist/appcast.xml</string>
<key>SUEnableAutomaticChecks</key>
<true />
<key>SUPublicEDKey</key>
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions Scripts/CoreLogicSmokeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,9 @@ struct CoreLogicSmokeTests {
}

private static func testTextCleanupPipeline() {
let lightInput = " hello world!! this is is keyscribe "
let lightInput = " hello world!! this is is openassist "
let lightOutput = TextCleanup.process(lightInput, mode: .light)
check(lightOutput == "Hello world! This is keyscribe", "Light cleanup pipeline normalization failed")
check(lightOutput == "Hello world! This is openassist", "Light cleanup pipeline normalization failed")

let aggressiveInput = "i m here\n\n\n\nand dont panic??"
let aggressiveOutput = TextCleanup.process(aggressiveInput, mode: .aggressive)
Expand Down
4 changes: 2 additions & 2 deletions Scripts/GenerateIcon.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import AppKit

// MARK: - Load the transparent logo PNG

let logoImagePath = FileManager.default.currentDirectoryPath + "/KeyScribe.png"
let logoImagePath = FileManager.default.currentDirectoryPath + "/Assets/AppLogo.png"

func loadLogoPNG() -> NSImage? {
guard let img = NSImage(contentsOfFile: logoImagePath) else {
Expand Down Expand Up @@ -130,7 +130,7 @@ func savePNG(_ image: NSImage, to path: String) {
@MainActor
func main() {
let projectDir = FileManager.default.currentDirectoryPath
let iconsetDir = "/tmp/KeyScribeIcon.iconset"
let iconsetDir = "/tmp/OpenAssistIcon.iconset"
let resourcesDir = projectDir + "/Resources"

guard let rawLogo = loadLogoPNG() else {
Expand Down
2 changes: 1 addition & 1 deletion Scripts/InsertionReliabilityRunner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ struct InsertionReliabilityRunner {
--expect-result <empty|pasted|copied-only|not-inserted>

Example:
/tmp/keyscribe-insertion-reliability \
/tmp/openassist-insertion-reliability \
--text hello --copy true --direct false --typing false --special false \
--expect-path special-paste-clipboard --expect-result copied-only
""")
Expand Down
4 changes: 2 additions & 2 deletions Scripts/MemoryIndexingSmokeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -425,14 +425,14 @@ struct MemoryIndexingSmokeTests {
sandboxRoot
.appendingPathComponent("Library", isDirectory: true)
.appendingPathComponent("Application Support", isDirectory: true)
.appendingPathComponent("KeyScribe", isDirectory: true)
.appendingPathComponent("OpenAssist", isDirectory: true)
.appendingPathComponent("Memory", isDirectory: true)
.appendingPathComponent(fileName)
}

private static func makeSandbox() throws -> URL {
let root = FileManager.default.temporaryDirectory
.appendingPathComponent("keyscribe-memory-smoke-\(UUID().uuidString)", isDirectory: true)
.appendingPathComponent("openassist-memory-smoke-\(UUID().uuidString)", isDirectory: true)
try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true)

try write(
Expand Down
2 changes: 1 addition & 1 deletion Scripts/PromptRewriteSmokeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ struct PromptRewriteSmokeTests {
private static func testStrictProjectIsolation() async {
do {
let sandboxRoot = FileManager.default.temporaryDirectory
.appendingPathComponent("keyscribe-retrieval-scope-\(UUID().uuidString)", isDirectory: true)
.appendingPathComponent("openassist-retrieval-scope-\(UUID().uuidString)", isDirectory: true)
try FileManager.default.createDirectory(at: sandboxRoot, withIntermediateDirectories: true)
defer { try? FileManager.default.removeItem(at: sandboxRoot) }

Expand Down
6 changes: 3 additions & 3 deletions Scripts/RecognitionTuningSmokeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ struct RecognitionTuningSmokeTests {
let parsed = RecognitionTuning.parseCustomPhrases("alpha, beta\n gamma\n\n,delta")
check(parsed == ["alpha", "beta", "gamma", "delta"], "Phrase parsing failed")

let better = RecognitionTuning.chooseBetterTranscript(primary: "hello", fallback: "hello world from keyscribe")
check(better == "hello world from keyscribe", "Best transcript selection failed")
let better = RecognitionTuning.chooseBetterTranscript(primary: "hello", fallback: "hello world from openassist")
check(better == "hello world from openassist", "Best transcript selection failed")

let hints = RecognitionTuning.contextualHints(defaults: ["KeyScribe", "dictation", "macOS"], custom: ["dictation", "custom"], limit: 4)
let hints = RecognitionTuning.contextualHints(defaults: ["OpenAssist", "dictation", "macOS"], custom: ["dictation", "custom"], limit: 4)
check(hints.count <= 4, "Hints limit failed")
check(Set(hints).contains("custom"), "Hints custom merge failed")

Expand Down
Loading