Skip to content
This repository was archived by the owner on Mar 29, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b46e02d
chore(repo): bootstrap tooling, ci, and packaging
rbright Feb 19, 2026
6ca2671
feat(asr): implement local-first cli runtime and asr pipeline
rbright Feb 19, 2026
133297a
test(asr): add broad unit and integration coverage
rbright Feb 19, 2026
636489b
docs(readme): add progressive-disclosure docs set
rbright Feb 19, 2026
d030b2e
docs(config): document configurable paste shortcut
rbright Feb 19, 2026
0a0fcdb
test(ipc): stabilize read-response failure coverage
rbright Feb 19, 2026
25d4f15
fix(config): report vocabset start line on parse errors
rbright Feb 19, 2026
2f0bd1d
fix(ipc): keep probe failures distinct from running state
rbright Feb 19, 2026
eb6b585
fix(pipeline): always signal send-loop completion
rbright Feb 19, 2026
bf9540d
test(doctor): normalize riva endpoint fixture format
rbright Feb 19, 2026
523989e
docs(verification): tighten manual checklist wording
rbright Feb 19, 2026
fe5fb6d
build(codegen): use local protoc plugins for buf generate
rbright Feb 19, 2026
0cdc48d
feat(indicator): support desktop notification backend
rbright Feb 19, 2026
7d4cd9b
build(indicator): add busctl runtime dependency
rbright Feb 19, 2026
53e9468
docs(indicator): document desktop backend and placement
rbright Feb 19, 2026
c767b61
fix(config): initialize vocab map during parse
rbright Feb 19, 2026
75797b4
chore(tooling): modularize just recipes and docs
rbright Feb 19, 2026
b11ae08
docs(apps): add package and function-level code comments
rbright Feb 19, 2026
2c62d95
docs(apps): inline package docs into primary files
rbright Feb 19, 2026
d97878f
refactor(riva): split stream helpers from client lifecycle
rbright Feb 19, 2026
c32739b
docs(architecture): add FSM-derived state diagram
rbright Feb 19, 2026
4949ca7
feat(config): prefer JSONC config with legacy fallback
rbright Feb 19, 2026
c248564
fix(pipeline): harden stop paths for capture and transcriber reuse
rbright Feb 19, 2026
206face
fix(riva): bound stream startup and cancel stalled init
rbright Feb 19, 2026
6d8880f
fix(pipeline): avoid startup deadlock on stream init failure
rbright Feb 19, 2026
0640ec2
chore(nix): use hostPlatform system for module package wiring
rbright Feb 19, 2026
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
19 changes: 19 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true

[*.go]
indent_style = tab
indent_size = 4

[Makefile]
indent_style = tab

[*.md]
trim_trailing_whitespace = false
47 changes: 47 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: CI

on:
push:
branches:
- main
pull_request:

concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install Nix
uses: cachix/install-nix-action@v27
with:
extra_nix_config: |
experimental-features = nix-command flakes

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go.work

- name: Install just
uses: taiki-e/install-action@just

- name: Nix lint
run: just lint-nix

- name: Pre-commit hooks
run: just precommit-run

- name: Guardrails
run: just ci-check

- name: Nix build package
run: nix build 'path:.#sotto'

- name: Nix run --help smoke
run: nix run 'path:.#sotto' -- --help
37 changes: 37 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Release

on:
push:
tags:
- "v*"

permissions:
contents: write

jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install Nix
uses: cachix/install-nix-action@v27
with:
extra_nix_config: |
experimental-features = nix-command flakes

- name: Build
run: nix build 'path:.#sotto'

- name: Package binary
run: |
mkdir -p dist
cp result/bin/sotto dist/sotto
chmod +x dist/sotto

- name: Create release
uses: softprops/action-gh-release@v2
with:
files: dist/sotto
generate_release_notes: true
27 changes: 27 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Build artifacts
/bin/
/dist/
/result
/result-*
/apps/sotto/sotto
/apps/sotto/vendor/

# Go
**/*.test
**/*.out
coverage.out

# Editor/system
.DS_Store
.direnv/
.env
.env.*

# Runtime artifacts
*.log
*.sock

# Local planning/session notes
.pi/
PLAN.md
SESSION.md
26 changes: 26 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
run:
timeout: 5m
tests: true

linters:
disable-all: true
enable:
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- typecheck
- unused
- revive
- misspell

linters-settings:
revive:
rules:
- name: package-comments
disabled: true

issues:
max-issues-per-linter: 0
max-same-issues: 0
57 changes: 57 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
exclude: ^apps/sotto/(vendor/|proto/third_party/)
stages: [pre-commit]
- id: end-of-file-fixer
exclude: ^apps/sotto/(vendor/|proto/third_party/)
stages: [pre-commit]
- id: check-added-large-files
exclude: ^apps/sotto/(vendor/|proto/third_party/)
stages: [pre-commit]
- id: check-merge-conflict
stages: [pre-commit]

- repo: local
hooks:
- id: go-fmt-check
name: go fmt check
entry: just fmt-check
language: system
pass_filenames: false
always_run: true
stages: [pre-commit]

- id: lint-nix
name: nix lint
entry: just lint-nix
language: system
pass_filenames: false
always_run: true
stages: [pre-push]

- id: ci-check
name: ci-check
entry: just ci-check
language: system
pass_filenames: false
always_run: true
stages: [pre-push]

- id: nix-build-check
name: nix build package
entry: just nix-build-check
language: system
pass_filenames: false
always_run: true
stages: [pre-push]

- id: nix-run-help-check
name: nix run --help smoke
entry: just nix-run-help-check
language: system
pass_filenames: false
always_run: true
stages: [pre-push]
129 changes: 129 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# sotto Agent Guide

## Scope

These rules apply to the entire `sotto/` repository.

## Mission

Ship a production-grade, local-first ASR CLI with:

- a single Go binary
- no background daemon
- strong crash/cleanup guarantees
- clear modular boundaries for safe refactoring
- reproducible packaging and CI

## First 60 Seconds (Progressive Disclosure)

1. Read this file fully.
2. Read `README.md` for user-facing behavior.
3. Read `PLAN.md` (current milestones/checklist) and `SESSION.md` (what actually ran).
4. Run `just --list` to see current task entrypoints.
5. Open only the component(s) you are changing (map below).

---

## Project Map (What to read by task)

| Area | Primary paths | Notes |
| --- | --- | --- |
| CLI contract + dispatch | `apps/sotto/internal/cli/`, `apps/sotto/internal/app/` | Commands, flags, top-level flow |
| Session state machine | `apps/sotto/internal/session/`, `apps/sotto/internal/fsm/`, `apps/sotto/internal/ipc/` | Toggle/stop/cancel semantics, single-instance behavior |
| Audio capture + device selection | `apps/sotto/internal/audio/` | PipeWire/Pulse capture, device fallback/mute handling |
| Riva streaming ASR | `apps/sotto/internal/riva/`, `apps/sotto/internal/pipeline/` | gRPC stream config, segment assembly inputs |
| Transcript assembly | `apps/sotto/internal/transcript/` | Whitespace normalization + trailing-space behavior |
| Output dispatch | `apps/sotto/internal/output/`, `apps/sotto/internal/hypr/` | Clipboard + paste behavior |
| Indicator + cues | `apps/sotto/internal/indicator/` | Visual notify + audio cue lifecycle |
| Config grammar/defaults | `apps/sotto/internal/config/` | Any new key must update parser/defaults/tests/docs |
| Packaging + tooling | `justfile`, `flake.nix`, `.github/workflows/` | CI/tooling changes |
| Protobuf contracts | `apps/sotto/proto/third_party/`, `proto/gen/go/` | Run codegen when proto inputs change |

---

## Engineering Workflow Rules

1. Read target files before editing.
2. Keep changes aligned to `PLAN.md` milestones; avoid drive-by refactors.
3. Keep `PLAN.md` checkboxes accurate (only mark executed + verified work).
4. Log key decisions/trade-offs/blockers/commands in `SESSION.md`.
5. Prefer additive changes with regression tests.
6. Never claim runtime integrations (Riva, PipeWire, Hyprland) were verified unless actually exercised.

### Design principles (repo-wide)

- Prefer boring, explicit code over clever code.
- Fail fast at boundaries (config parse, startup checks, I/O preconditions).
- Keep business/state logic separate from transport/I/O adapters.
- Use guard clauses to reduce nesting.
- Keep files top-down readable (public entrypoints first, private helpers below).

### Dependency + architecture rules

- Prefer manual constructor-based dependency injection.
- Keep package responsibilities narrow; avoid utility dumping grounds.
- Do not couple domain/state transitions directly to shell command details.

---

## Go Conventions

- Use table-driven tests for branch-heavy logic.
- Prefer `errors.Is` / wrapped errors with context.
- Keep I/O timeouts explicit.
- Use `testing` + `testify` (`require`/`assert`) for expressive assertions when useful.
- Add focused regression tests for bug fixes whenever feasible.

### Testing boundaries (repo policy)

- Prefer real interfaces/adapters and real resources (temp files, unix sockets, `httptest`, PATH fixtures).
- Do **not** introduce mocking frameworks or expectation-driven mock suites.
- Riva runtime/model inference remains a local-manual smoke concern (non-CI); use lightweight protocol/contract tests in CI.

### File size / readability guardrails

- Handwritten files should target `<= 250` LOC where practical.
- Files above `~350` LOC require extraction-plan notes in `PLAN.md` before refactor work.
- Exclude generated code from these thresholds: `apps/sotto/vendor/**`, `apps/sotto/proto/gen/**`.

---

## Config Change Contract (Mandatory)

When adding or changing a config key, update all of:

1. `apps/sotto/internal/config/types.go`
2. `apps/sotto/internal/config/defaults.go`
3. `apps/sotto/internal/config/parser.go`
4. validation if required (`validate.go`)
5. parser/validation tests
6. `README.md` config example + notes
7. any deployed default config in consuming repos (when in scope)

---

## Required Local Checks Before Hand-off

Run and report status for:

1. `just ci-check`
2. `nix build 'path:.#sotto'`

If any check is skipped, state exactly what was skipped, why, and the exact command to run.

### Pre-commit Hooks (`prek`)

- Install hooks: `just precommit-install`
- Run lightweight pre-commit hooks: `just precommit-run`
- Run heavier pre-push hooks: `just prepush-run`

Use hooks to catch formatting/lint drift early and run full guardrails before pushing.

---

## Safety

- Never store secrets in repo files.
- Assume `NGC_API_KEY` and other credentials are external env/secrets only.
- Avoid destructive shell operations unless explicitly requested.
- Do not edit files outside `sotto/` unless explicitly requested.
Loading
Loading