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
78 changes: 78 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Release

# Publish to PyPI via trusted publishing (OIDC — no stored token) when a
# version tag is pushed. The publish job is additionally gated behind the
# `pypi` GitHub environment, and PyPI's trusted-publisher config pins
# repo + this workflow filename + that environment, so no other workflow
# (or fork) can mint a publishable token.
on:
push:
tags: ["v*"]

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- name: Guard — tag must match pyproject version
run: |
TAG="${GITHUB_REF_NAME#v}"
VERSION=$(python3 -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
if [ "$TAG" != "$VERSION" ]; then
echo "Tag v$TAG does not match pyproject version $VERSION" >&2
exit 1
fi

# Same baseline system dep as ci.yml — the release gate re-runs the
# suite so an artifact is never published from an untested tree.
- name: Install system deps (PortAudio for pyaudio)
run: sudo apt-get update && sudo apt-get install -y portaudio19-dev

- name: Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.12"

- name: Sync dependencies
run: uv sync --dev

- name: Tests
run: uv run pytest -q

- name: Build sdist + wheel
run: uv build

- name: Guard — no direct-URL dependencies in wheel metadata
run: |
if unzip -p dist/*.whl '*/METADATA' | grep -E '^Requires-Dist:.*@ (git\+|https?://)'; then
echo "Direct-URL dependency in metadata — PyPI will reject this" >&2
exit 1
fi

- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
if-no-files-found: error

publish:
needs: build
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/onoats
permissions:
# OIDC token for PyPI trusted publishing — granted ONLY to this job.
id-token: write
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
11 changes: 11 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,17 @@ surfaces** that must agree — `pyproject.toml`, the `uv.lock` onoats entry
tag time by `scripts/release_check.sh vX.Y.Z <commit>` (run before pushing
any release tag).

Releasing to PyPI (v1.1.0+): pushing a `v*` tag triggers
`.github/workflows/release.yml` — full suite + two guards (tag must equal
the pyproject version; wheel metadata must carry no direct-URL deps), then
publish via PyPI **trusted publishing** (OIDC, no stored token) gated behind
the GitHub `pypi` environment. One-time prerequisites: a PyPI trusted
publisher (project `onoats`, repo `vr000m/onoats-bot`, workflow
`release.yml`, environment `pypi`) and the GitHub `pypi` environment itself.
PyPI rejects direct-URL `Requires-Dist` entries — dependencies must come
from PyPI (this is why `pipecat-local-stt-server` is a `>=0.1.2,<0.2`
registry dep, not a git pin).

## Supervisor ↔ capturer lifecycle (`cli._run_socket_supervisor`)

- The **supervisor owns the capturer process.** It mints a private `0700` socket
Expand Down
16 changes: 15 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,23 @@ no backdated tags exist). PR numbers `#1`–`#7` refer to this repository;
older history predates the extraction and is cited by merge-commit SHA.
Annotated tags exist from `v0.9.0` forward.

## [Unreleased]
## [1.1.0] - 2026-06-12

First PyPI release (`pip install onoats` / `uv tool install onoats`).

### Changed
- `pipecat-local-stt-server` is now consumed from PyPI (`>=0.1.2,<0.2`)
instead of a git-URL pin — `0.1.2` is the release of the exact commit
previously pinned (`5062b98` == tag `v0.1.2`). This removes the
direct-reference metadata PyPI rejects, unblocking publication. Packaging
metadata (readme, authors, URLs, classifiers) added for the PyPI page.

### Added
- Tag-triggered PyPI publish via GitHub Actions trusted publishing
(`.github/workflows/release.yml`): pushing a `v*` tag runs the full suite
plus two guards (tag == pyproject version; no direct-URL deps in wheel
metadata), then publishes via OIDC behind the `pypi` GitHub environment —
no stored token.
- `[stt] language` in `config.toml`: the STT decode language is now a
first-class config key (env `STT_LANGUAGE` > legacy alias `STT_WS_LANGUAGE`
> `[stt].language` > `en`),
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,15 @@ the **terminal app**, not to onoats — see
# Linux: PortAudio dev headers are needed to build pyaudio
# sudo apt-get install -y portaudio19-dev # (macOS Homebrew ships them)

# From PyPI (v1.1.0+) — no clone needed:
uv tool install onoats # baseline (PortAudio + Deepgram/TCP STT)
# uv tool install 'onoats[macos]' # Apple Silicon: adds Whisper-MLX + Kokoro

# Or from a checkout (development):
git clone https://github.com/vr000m/onoats-bot.git
cd onoats-bot
uv tool install --editable . # baseline (PortAudio + Deepgram/TCP STT)
# uv tool install --editable '.[macos]' # Apple Silicon: adds Whisper-MLX + Kokoro
uv tool install --editable . # baseline
# uv tool install --editable '.[macos]' # Apple Silicon extras

onoats init # guided setup → config.toml + 0600 secrets.env
onoats bot # dual-input recorder (mic + system loopback)
Expand Down
6 changes: 4 additions & 2 deletions docs/blackhole-fallback.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ a PortAudio input device:

This is the default `portaudio` audio source. There is deliberately **no make
target** for it — this path must not require the native toolchain (`make`,
`swiftc`, `codesign`). The whole install, after cloning the repo, is:
`swiftc`, `codesign`). The whole install is:

```bash
uv tool install --editable . # the CLI ('.[macos]' on Apple Silicon adds Whisper-MLX)
uv tool install onoats # from PyPI (v1.1.0+; 'onoats[macos]' on Apple
# Silicon adds Whisper-MLX). From a checkout:
# uv tool install --editable .
onoats init # guided setup → config.toml + 0600 secrets.env
```

Expand Down
4 changes: 2 additions & 2 deletions native/onoats-menubar/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<string>1.1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<string>2</string>
<key>LSMinimumSystemVersion</key>
<string>14.4</string>
<key>LSUIElement</key>
Expand Down
27 changes: 21 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,38 @@ build-backend = "hatchling.build"

[project]
name = "onoats"
version = "1.0.0"
version = "1.1.0"
description = "Standalone onoats voice recorder (extracted from koda)."
readme = "README.md"
license = "BSD-2-Clause"
authors = [{ name = "Varun Singh" }]
# >=3.12: the pinned pipecat-local-stt-server requires Python >=3.12.
requires-python = ">=3.12"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"Intended Audience :: End Users/Desktop",
"Operating System :: MacOS",
"Operating System :: POSIX",
"Programming Language :: Python :: 3.12",
"Topic :: Multimedia :: Sound/Audio :: Capture/Recording",
]
dependencies = [
"pipecat-ai[deepgram,google,local,runner,silero,soundfile,webrtc,whisper]>=1.0.0,<2.0.0",
"pipecat-local-stt-server @ git+https://github.com/vr000m/pipecat-local-stt-server.git@5062b984b164baec1e2396cf412888b2b64f2fa1",
# 0.1.2 is the PyPI release of the exact commit previously pinned by git
# URL (5062b98 == tag v0.1.2). <0.2 until the 0.2/0.3 wire protocol is
# smoke-tested live against the recorder.
"pipecat-local-stt-server>=0.1.2,<0.2",
"websockets>=13.0",
"python-dotenv>=1.2.1",
"loguru>=0.7.0",
]

[project.urls]
Homepage = "https://github.com/vr000m/onoats-bot"
Changelog = "https://github.com/vr000m/onoats-bot/blob/main/CHANGELOG.md"
Issues = "https://github.com/vr000m/onoats-bot/issues"

[project.optional-dependencies]
# macOS-only acceleration. Apple Silicon Whisper (mlx-whisper) + Kokoro TTS.
# Install with `uv tool install 'onoats[macos]'`. NOT in the baseline — the
Expand All @@ -38,10 +57,6 @@ macos = [
[project.scripts]
onoats = "onoats.cli:main"

[tool.hatch.metadata]
# Allow the git+https direct reference for pipecat-local-stt-server.
allow-direct-references = true

[tool.hatch.build.targets.wheel]
packages = ["src/onoats"]

Expand Down
10 changes: 7 additions & 3 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.