Standalone Swift package for hosting the local SpeakSwiftly runtime behind an app-friendly HTTP API, an optional MCP surface, and a small embedded Apple-platform API.
- Overview
- Quick Start
- Usage
- Embedding
- Configuration
- Codex Plugin
- Development
- Repo Structure
- Release Notes
- License
This project is actively available and stable enough to try.
SpeakSwiftlyServer is the standalone Swift Package Manager home for the local SpeakSwiftly server layer. It ships one reusable library target for embedding and one executable target, SpeakSwiftlyServerTool, for running the shared localhost service, LaunchAgent maintenance commands, and health checks.
The package exposes three user-facing surfaces:
- a localhost HTTP API for app and operator control
- an optional MCP surface for tool, resource, and prompt access
- a small embedded Apple-platform API centered on the public
EmbeddedServerobservable model
The goal is to give macOS and near-future Apple-platform apps one small, typed local speech-service layer without adding a second runtime stack or forcing every consumer to rebuild the same transport and lifecycle glue around SpeakSwiftly.
Build the package with Xcode's selected Swift toolchain:
xcrun swift buildRun the shared server executable locally:
xcrun swift run SpeakSwiftlyServerToolCheck the current operator surface:
xcrun swift run SpeakSwiftlyServerTool help
xcrun swift run SpeakSwiftlyServerTool healthcheck --base-url http://127.0.0.1:7338For contributor setup, validation, release workflow, and live end-to-end coverage, use CONTRIBUTING.md.
Run the server directly in the foreground:
xcrun swift run SpeakSwiftlyServerTool serveInstall or refresh the per-user LaunchAgent with a config file:
This command expects the staged tool artifact to already exist at .release-artifacts/current/SpeakSwiftlyServerTool. On a clean checkout, build and stage the release artifact first, or pass --tool-executable-path /absolute/path/to/SpeakSwiftlyServerTool explicitly.
xcrun swift run SpeakSwiftlyServerTool launch-agent install \
--config-file ./server.yamlPromote the current checkout into the live LaunchAgent-backed service:
xcrun swift run SpeakSwiftlyServerTool launch-agent promote-live \
--config-file ./server.yamlInspect or remove the installed LaunchAgent:
xcrun swift run SpeakSwiftlyServerTool launch-agent status
xcrun swift run SpeakSwiftlyServerTool launch-agent uninstallThe package uses distinct default localhost ports by entrypoint:
- direct executable startup defaults to
127.0.0.1:7338 - LaunchAgent installs default to
127.0.0.1:7337 - embedded app-owned sessions default to
127.0.0.1:7339
The full transport contract lives in API.md.
The supported public embedding surface is EmbeddedServer, defined in Sources/SpeakSwiftlyServer/Host/ServerState.swift. App code owns that one observable object directly, calls liftoff(), binds UI to its observable properties, and uses the same object for runtime controls, playback controls, voice-profile actions, and direct live speech submission through queueLiveSpeech(...).
import SpeakSwiftlyServer
import SwiftUI
@main
struct ExampleApp: App {
@State private var server = EmbeddedServer(
options: .init(
port: 7811,
runtimeProfileRootURL: FileManager.default
.urls(for: .applicationSupportDirectory, in: .userDomainMask)
.first?
.appendingPathComponent("ExampleApp/SpeakSwiftlyRuntime", isDirectory: true)
)
)
var body: some Scene {
WindowGroup {
ContentView(server: server)
.task {
try? await server.liftoff()
}
}
}
}If you do not pass EmbeddedServer.Options(port:), the embedded host defaults to 127.0.0.1:7339. If you pass EmbeddedServer.Options(runtimeProfileRootURL:), the server treats that as its profile-store root and bridges it at startup into the broader persistence root expected by the current pinned SpeakSwiftly runtime, while keeping the server's own runtime-configuration snapshot aligned with the same on-disk state.
The shared server supports these environment variables:
APP_CONFIG_FILEAPP_NAMEAPP_ENVIRONMENTAPP_DEFAULT_VOICE_PROFILE_NAMEAPP_HOSTAPP_PORTAPP_SSE_HEARTBEAT_SECONDSAPP_COMPLETED_JOB_TTL_SECONDSAPP_COMPLETED_JOB_MAX_COUNTAPP_JOB_PRUNE_INTERVAL_SECONDSAPP_HTTP_ENABLEDAPP_HTTP_HOSTAPP_HTTP_PORTAPP_HTTP_SSE_HEARTBEAT_SECONDSAPP_MCP_ENABLEDAPP_MCP_PATHAPP_MCP_SERVER_NAMEAPP_MCP_TITLESPEAKSWIFTLY_PROFILE_ROOT
If APP_CONFIG_FILE points at a YAML file, the server loads it through swift-configuration, with environment variables taking precedence over YAML and YAML taking precedence over built-in defaults.
app:
name: speak-swiftly-server
environment: development
host: 127.0.0.1
port: 7338
sseHeartbeatSeconds: 10
completedJobTTLSeconds: 900
completedJobMaxCount: 200
jobPruneIntervalSeconds: 60
http:
enabled: true
host: 127.0.0.1
port: 7338
sseHeartbeatSeconds: 10
mcp:
enabled: false
path: /mcp
serverName: speak-swiftly-mcp
title: Speak SwiftlyThe app-managed install layout is centered on one per-user location under ~/Library/Application Support/SpeakSwiftlyServer, with logs in ~/Library/Logs/SpeakSwiftlyServer. The package exposes that layout directly through AppManagedInstallLayout.swift.
This repository is also packaged as a repo-local Codex plugin through .codex-plugin/plugin.json. The plugin points at the checked-in .mcp.json connection for the local speak_swiftly MCP server and the tracked skills bundle that teaches Codex how to use the surface intentionally.
The first plugin pass ships focused skills for:
- broad MCP orientation
- LaunchAgent setup and maintenance
- runtime, playback, and queue control
- voice workflows
- text-profile workflows
The contributor and maintainer workflow lives in CONTRIBUTING.md.
Use that guide for:
- local setup and runtime expectations
- validation commands
- live end-to-end coverage
- pull request and release workflow
- monorepo and submodule handoff rules
The short version is:
- use
xcrun swift testfor the normal package-development loop - use
sh scripts/repo-maintenance/validate-all.shfor the full maintainer and CI gate - use
scripts/repo-maintenance/release-prepare.shonly for branch-side PR prep - use
scripts/repo-maintenance/release-publish.shas the single publish-time artifact and tag path
.
├── Sources/
│ ├── SpeakSwiftlyServer/
│ └── SpeakSwiftlyServerTool/
├── Tests/
├── docs/
├── API.md
├── CONTRIBUTING.md
├── Package.swift
└── README.md
Sources/SpeakSwiftlyServer/contains the reusable library target.Sources/SpeakSwiftlyServerTool/contains the unified executable wrapper.Tests/contains unit, integration, and a small opt-in live E2E smoke suite.docs/contains maintainer-facing supporting documentation.
Tagged release notes live in GitHub Releases and the repo keeps matching historical release notes and release checklists under docs/releases. Investigations and incident writeups live under docs/investigations.
See LICENSE.