Imported from r3dbars/transcripted (
AGENTS.md). Install upstream withnpx skills add r3dbars/transcripted. Copyright stays with the author.
Transcripted Agent Guide
Current repo truth
mainis the current Transcripted product, derived from the earlier Draft codebase.- The current app on
mainsupports dictation and meetings. - Meeting capture includes local mic + system audio, imported-audio transcription, optional local-speaker review, and agent-readable Markdown output.
- The older draft / ghostwriting flow is not active on
main. Sources/TranscriptedCore/is an in-repo library consumed throughSources/Meeting/. Keep it as a library boundary.Sources/Speech/owns the app-owned local STT path. Meetings reuse that path throughSources/Meeting/MeetingSTTAdapter.swift.Sources/Reliability/owns wake / sleep recovery for hotkeys and active capture flows.build.shbuilds the app target. The rootPackage.swiftexists forTranscriptedCorepackage tests and smoke coverage, not as the main app build.
Product capability contract
Simplification work must preserve the current product surface unless the owner explicitly approves a capability change. In particular, keep:
- automatic meeting detection and its record / dismiss / remind flow
- the Speakers directory and speaker review, rename, merge, and delete tools
- per-app dictation Auto Enter
- manual model-cache inspection and cleanup controls
- the status item's right-click quick menu
- retained meeting-audio playback; transcript rows stay static and do not highlight or follow the playhead
These surfaces may share less code underneath, but do not delete, hide, or make them harder to reach as part of an architecture or visual cleanup.
Response voice
- Write like a real person texting a friend, not like a presentation.
- Keep things simple, direct, and useful.
- Use short, punchy sentences most of the time.
- Vary the rhythm. Short punch. Then a little more detail when it helps.
- Use casual connectors when they fit: "so", "anyway", "plus", "also".
- Be honest when something is weird, unclear, or unknown.
- Use light natural hesitation sparingly: "I think maybe", "probably", "not sure but".
- Avoid marketing speak, corporate buzzwords, stiff transitions, and obvious AI phrases like "dive into", "delve into", or "let's explore".
- Avoid piling on adjectives.
- Keep capitalization normal.
- Be relaxed, but still clear. Real, not sloppy.
Read this first
AGENT_START.mdfor the short agent entrypointREADME.mdAGENTS.mddocs/repo-layout.mddocs/agent-onboarding.mdCLAUDE.mdSources/CLAUDE.md- the nearest local
CLAUDE.mdfor the area you are changing Sources/Accessibility/CLAUDE.mdwhen touching focused-editor AX metadata, overlay placement, or paste-back contextSources/Dictation/CLAUDE.mdwhen touching dictation persistenceSources/Meeting/CLAUDE.mdwhen touching meeting capture or meeting UISources/TranscriptedCore/CLAUDE.mdwhen touching the shared librarySources/Speech/CLAUDE.mdwhen touching dictation STT, audio recovery, or device handlingSources/Support/CLAUDE.mdwhen touching shared preferences, permissions, paths, or Claude Desktop install flowSources/UI/CLAUDE.mdwhen touching overlay, menubar, onboarding, settings, or agent-connect UISources/Capture/CLAUDE.mdwhen touching hotkeys or physical dictation trigger routingTests/README.mddocs/storage-paths.mdSources/Reliability/CLAUDE.mdwhen touching wake / sleep recovery or hotkey recoverySources/Observability/CLAUDE.mdwhen touching crash reporting, event forwarding, anonymous analytics, or app updatesdocs/release-packaging.mdwhen touching packaging, signing, notarization, or user-facing releasesdocs/sparkle-updates.mdwhen touching app updates or cutting a release users should receive in-appTools/*/CLAUDE.mdwhen touching standalone CLI, MCP, or QA tools
Use docs/repo-layout.md as the canonical directory map and doc hierarchy.
Use .agents/test-matrix.yml as the quick path-to-verification map, with this
file taking precedence when there is any conflict.
Coordinator closeout
When a worker lane reports back to the Transcripted coordinator, use this exact one-line shape and keep it short:
COORD_DONE: GREEN/BRIEF/RED | PR URL if any | changes made | GitHub cleanup recommendations | decisions needed | tests/checks run | lanes used: Codex=...; Claude=...; Local=...; Windows=... | smallest next action
For review, merge-room, and worker-thread prompts, include the Maestro lane contract. Codex is the final reviewer / merger. Claude is for risky reasoning. Mac local models and the Windows worker are cheap first-pass lanes for summaries, clustering, log triage, and draft work. If a lane is skipped, say why in the closeout.
For non-Codex lanes, use ~/.codex/bin/maestro-delegate whenever possible, for
example maestro-delegate local --label pr-dedupe -- "...",
maestro-delegate windows --label review -- "...", or
maestro-delegate claude --label risk-review -- "...". A lane only counts as
used if the closeout includes a real MAESTRO_PROOF path, output path, or pasted
command output.
Use docs/agent-closeout.md for the status meanings and GitHub cleanup
boundaries.
Build and test
bash build-deps.sh
bash build.sh --no-open
bash run-tests.sh
bash run-integration-smoke.sh
swift test
Rules. Use .agents/test-matrix.yml for the full path-to-verification map;
these are the common minimums:
- After changing Swift source, run
bash build.sh --no-openandbash run-tests.sh. - If you touch
Sources/Meeting/orSources/TranscriptedCore/, also runbash build-deps.sh --forceandbash run-integration-smoke.sh. - If you touch
Package.swift,Sources/TranscriptedCore/, or the public core seam, also runbash build-deps.sh --force,bash run-integration-smoke.sh, andswift test. build.shmust not compileSources/TranscriptedCore/directly into the app target.
PR QA levels:
- Tiny docs-only: run
scripts/dev/agent-preflight.shand the mapped docs gate. Do not require full release QA for spelling, comments, or internal docs that do not change release truth. - Meaningful code: run
codex-reviewagainst the real PR base, then run the union of.agents/test-matrix.ymlchecks for the changed paths. - Broad, risky, or release-impacting: run
codex-review, the mapped checks, andbash scripts/ops/transcripted-qa-bench.sh --mode full.
Treat release notes, appcast/update docs, Homebrew cask docs, QA-gate docs, and public download/release-truth docs as release-impacting even when the diff is Markdown-only.
codex-review means: an independent model review of the full PR diff against
the real base branch — e.g. codex review from the OpenAI Codex CLI, or an
equivalent independent agent reviewer. Record the verdict (and any findings you
rejected, with reasons) in the PR description. It is not defined as a repo
script; any tool that reviews the true diff qualifies.
Before opening a repair branch
When a PR goes dirty (conflicting) the reflex is to spin up a fresh
repair-pr-NNNN branch. Do not. First confirm the change did not ALREADY merge
under a different PR number — this has burned multiple threads that each
re-opened a repair branch for a fix that was already on main.
Required step before opening any repair/redo/reland branch:
python3 scripts/dev/check-superseded.py --pr <dirty-pr-number>
# or, once you are on the repair branch:
python3 scripts/dev/check-superseded.py --branch "$(git branch --show-current)"
- Exit
3withSTOP: #NNNN already merged thismeans the scope is already onmain. Close the dirty PR as superseded and do the work only if something is genuinely still missing. Do not open the repair branch. - Exit
0(no merged PR already covers ...) means the change is novel. Proceed.
scripts/dev/agent-preflight.sh also prints this reminder automatically when it
detects a repair-shaped branch name.
Releases, Sparkle, and Homebrew
When the task is a user-facing release, package handoff, or update-path change, agents must treat Sparkle as part of the release contract, not as optional follow-up work.
Rules:
- Read
docs/release-packaging.mdanddocs/sparkle-updates.mdbefore changing release flow. - For builds intended for other machines, use
build-beta.sh, notbuild.sh. - A release is not complete just because a DMG exists. For in-app updates to work, the release flow must also:
- publish the signed archive where users can fetch it
- update
docs/appcast.xml - push the updated appcast to the branch that backs the live feed
- If the release should also be installable or upgradeable through Homebrew, the release flow must also:
- run
bash scripts/release/update-cask.sh <version>after the GitHub release is published - commit the updated
Casks/transcripted.rb - push that cask update so
brew installandbrew upgradesee the new version
- run
- If Sparkle metadata was not updated, say explicitly that existing installs will not discover the new release in-app yet.
- If the Homebrew cask was not updated, say explicitly that
brew install/brew upgradewill still point at the older release. - If the release artifact URL, appcast URL, public key, Sparkle tooling, or Homebrew install path changes, update the docs in the same change.
- Keep
Info.plistSparkle settings aligned with the actual release feed:SUFeedURLSUPublicEDKey- any automatic-check / automatic-download flags
- Preferred release verification for release-path changes:
bash build-deps.sh --forcewhen dependency tooling changesbash build.sh --no-openbash run-tests.shSKIP_NOTARIZATION=1 bash build-beta.sh '' <user-name>for packaging smoke, or the full notarized path when cutting a real release
Observability, Sentry, and Analytics
Treat Sentry and PostHog as explicitly bounded integrations, not generic log sinks.
Rules:
- Read
Sources/Observability/CLAUDE.mdbefore changing crash reporting, event forwarding, anonymous analytics, file logging, or update plumbing. - Runtime Sentry config lives in
Info.plistunder:TranscriptedSentryDSNTranscriptedSentryEnvironmentTranscriptedSentryReleasePrefix- optional:
TranscriptedSentryAppHangTrackingEnabled
- Local overrides for testing can come from process environment:
SENTRY_DSNSENTRY_ENVIRONMENTSENTRY_RELEASESENTRY_DISTSENTRY_ENABLE_APP_HANG_TRACKING
- Runtime PostHog config lives in
Info.plistunder:TranscriptedPostHogAPIKeyTranscriptedPostHogHost
- Local overrides for analytics testing can come from process environment:
POSTHOG_API_KEYPOSTHOG_HOST
- The user-facing crash reporting and anonymous analytics preferences are stored by
CrashReportingPreferencesandAnalyticsPreferences. Both default to enabled until the user changes them in Settings or onboarding. EventReporterdoes not forward every.errorevent to Sentry. Off-device forwarding is gated by the explicit allowlist inSources/Observability/SentryEventPolicy.swift.- PostHog events and properties are gated by
Sources/Observability/AnalyticsEventPolicy.swift. - Keep off-device payloads privacy-safe. Do not send raw transcript text, audio references, meeting titles, speaker names, emails, tokens, or absolute file paths. If payload shape changes, update the relevant sanitizer and tests in the same change:
Sources/Observability/SentryPayloadSanitizer.swiftSources/Observability/AnalyticsPayloadSanitizer.swift
- Test and smoke runs should keep local production logs clean with
TRANSCRIPTED_DISABLE_FILE_LOGGER=1when invoking binaries directly. - Preserve the user verification path when touching the integrations:
- Settings should still expose the crash-reporting toggle
- Settings should still expose the anonymous analytics toggle
- About should still expose the
Send diagnosticsaction when Sentry is configured (the oldSend Test Sentry Eventsettings row was removed by owner decision in the 2026-08 settings simplification)
- Preferred verification for observability-related changes:
bash build.sh --no-openbash run-tests.sh- confirm Sentry, analytics, and observability preference tests still pass through
run-tests.sh
Testing gotchas
run-tests.shis a customswiftcrunner, not XCTest.- Root fast tests are discovered by convention:
Tests/FooTests.swiftmust expose exactly one top-leveltestFoo()entry function. Tests/TranscriptedCoreTests/is a separate Swift Package target, run viaswift testrather thanrun-tests.sh.
Storage
Current app builds on main default to Transcripted-named Application Support paths:
- app support root:
~/Library/Application Support/Transcripted/ - capture library:
~/Library/Application Support/Transcripted/captures/ - meetings:
~/Library/Application Support/Transcripted/captures/meetings/ - dictations:
~/Library/Application Support/Transcripted/captures/dictations/
The user can relocate the capture library in Settings via
transcriptSaveLocation. App-owned state, cache, logs, and temp files stay
under ~/Library/Application Support/Transcripted/.
Historic Draft paths still exist for migration and standalone-tool fallback.
See docs/storage-paths.md for the canonical storage map, including legacy fallbacks and TranscriptedCore standalone defaults.
Default orchestration: ultracode + workflows
For substantive work — research, audits, multi-file or cross-cutting changes, design, and reviews — default to authoring and running a Workflow that fans out parallel agents and adversarially verifies findings, rather than working solo. Reserve solo execution for trivial mechanical edits and conversational replies. Spawned worker threads inherit this default: a thread doing real work should itself orchestrate with a workflow wherever breadth or independent verification helps. Token cost is not the constraint here — correctness and coverage are. This is "ultracode" as the standing default for this repo.