Skip to content

Writing phase 6: README, uninstall, agent docs and prompt, cask zap - #1872

Merged
r3dbars merged 9 commits into
claude/writing-phase-4from
claude/writing-phase-6
Sep 28, 2026
Merged

r3dbars merged 9 commits into
claude/writing-phase-4from
claude/writing-phase-6

Conversation

@r3dbars

@r3dbars r3dbars commented Sep 25, 2026

Copy link
Copy Markdown
Owner

Phase 6 docs and release polish from docs/writing-plan.md, stacked on #1871. This is the last PR in the Writing stack: #1866 → #1868 → #1869 → #1870 → #1871 → this.

What's in it

  • README: a "Helps you write" section (autocomplete plus saving what you wrote), the model disk and memory needs, a privacy line (writing stays on your Mac; only anonymous suggestion counts leave, under the usage-stats switch), and a new Uninstall section, including removing the keyboard.
  • AgentConnectionGuide: the file-fallback prompt lists the writing folder in all four places, and the Agent settings page shows a Writing folder row.
  • docs/agent-connect.md: covers list_writing/read_writing and kind: "writing" on search_context/recent_context.
  • MCP tool descriptions: "what the user wrote", not "typed".
  • Homebrew cask zap: also removes ~/Library/Input Methods/Transcripted Keyboard.app and Writing's two preference domains.
  • Provenance: the llama-server source is recorded as llama.cpp 2115b73 (AppleClang 21, arm64, static), with a reproducible-build recipe in the ledger's follow-ups.

Verification (local, full stack): build, deep signing, fast tests, Swift Testing, swift test, MCP tests, E2E smoke, source pins, parity. Results are in the PR comments once the final gate finishes.

Still to do before release (Justin):

  1. Test it by hand: try the tab on a signed build.
  2. Release decisions: the version bump, appcast, and cask SHA through the normal release flow.
  3. Tilde's README note: it goes up when Writing ships (draft in the plan).

🤖 Generated with Claude Code

r3dbars and others added 4 commits September 25, 2026 16:53
- AgentConnectionGuide: list <capture-library>/writing/ next to meetings
  and dictations in the starter prompt, Codex setup prompt, copied folder
  paths, and Codex inbox AGENTS.md; search "meetings, dictations, and
  writing together". Uses the pure FileManager.writingDirectory(in:) so
  building a prompt never creates the folder. Tests updated.
- README: a Writing bullet, the writing/ folder, model disk and memory
  needs, a Privacy line for suggestion counts, and a new Uninstall section
  that removes the keyboard.
- agent-connect.md: list_writing/read_writing, kind "writing" on
  search_context/recent_context, the writing fallback folder and
  TRANSCRIPTED_WRITING_DIR.
- Ledger: drop the AgentConnectionGuide follow-up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	docs/writing-port-ledger.md
- The Homebrew cask's zap removes the Transcripted keyboard and Writing's
  two preference domains.
- MCP tool descriptions say what the user wrote, not typed.
- The Agent settings page lists the Writing folder next to Meetings and
  Dictation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@r3dbars
r3dbars marked this pull request as ready for review September 25, 2026 22:17
@r3dbars

r3dbars commented Sep 25, 2026

Copy link
Copy Markdown
Owner Author

Final local gate on the complete stack (this branch):

  • Build and signing: build.sh passes; the app is Developer ID signed (team XG6WL66WUQ), and codesign --verify --deep --strict passes on the app and the keyboard.
  • Tests: run-tests.sh all pass; 782 Writing tests (Swift Testing); swift test 588 XCTest; MCP 211 (isolated home).
  • Other checks: run-e2e-smoke.sh, source pins and parity pass. linux-checks.sh passes apart from the two VM self-tests.

A signed test build is at ~/Transcripted-Writing-Test/ on Justin's Mac, with a HOW-TO-TEST.md.

🤖 Generated with Claude Code

r3dbars and others added 3 commits September 25, 2026 17:29
A from-source build of llama.cpp 2115b73 with Command Line Tools 26.6
reproduces the pinned unsigned code hash 3f6895ab… exactly (twice, fresh
clones). docs/llama-server-provenance.md records the recipe, what it
depends on (toolchain, GGML_NATIVE=OFF, prefix map, the web UI snapshot)
and why build-deps should keep pinning Tilde's binary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pp support

TranscriptedStoragePathsTests used to snapshot the manifest at
transcriptedMCPDirectoriesManifestURL and write it back afterwards. Under
run-tests.sh that URL is the throwaway TRANSCRIPTED_CONTAINER_DIR, but the
test itself never checked that, so run anywhere else it would rewrite
~/Library/Application Support/Transcripted/mcp-directories.json. Drop the
rewrite-restore. Fail closed unless the manifest URL resolves under the test
container, read the parity suite's manifest from that checked URL, and end
with a guard that the real manifest's mtime and size didn't change.

The home recent-captures benchmark had no container override at all: its
loader and its cleanup both go through transcriptedCaptureLibraryDir, which
rewrote the real manifest (to the benchmark process's own default library,
not the user's), and the loader filled the real Home metadata cache. Point
TRANSCRIPTED_CONTAINER_DIR at the run's scratch folder before any storage is
touched, and refuse to run if the override doesn't take.

No production change: the writer already takes manifestURL, and the
container root is already overridable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@r3dbars

r3dbars commented Sep 25, 2026

Copy link
Copy Markdown
Owner Author

Two more commits on this PR:

  • llama-server provenance, verified. An exact from-source rebuild of llama.cpp 2115b73 matches the pinned code hash. See docs/llama-server-provenance.md.
  • Test isolation fix, which predates Writing. Tests/Benchmarks/HomeRecentCaptureBenchmark.swift had no container override: it rewrote the real mcp-directories.json and wrote rows into the real Home meeting cache. It now runs inside its scratch container and refuses to run otherwise. TranscriptedStoragePathsTests now checks that the manifest path is inside its temp container, and that the real manifest's mtime and size are unchanged. run-tests.sh 19240/19240.

🤖 Generated with Claude Code

@r3dbars
r3dbars merged commit e7407ad into claude/writing-phase-4 Sep 28, 2026
8 checks passed
@r3dbars
r3dbars deleted the claude/writing-phase-6 branch September 28, 2026 01:50
r3dbars added a commit that referenced this pull request Sep 28, 2026
…1871)

* Writing phase 4 (P4-B): add the Writing tab to the sidebar and Go menu

Writing sits after Dictations on ⌘4; Speakers moves to ⌘5 and Agent to ⌘6.
The row shows a quiet "New" badge, styled like the footer's update badge,
until WritingSidebarNewBadge.dismissedDefaultsKey is set. The shell routes
.writing to a placeholder WritingSettingsPage that the page work replaces.

Updates the exhaustive switches (refresh policy, discovery area, Go menu,
focus order), the pinned tests, UISmoke, and the UI CLAUDE docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Writing phase 4 (P4-B): stop promising Transcripted never needs Screen Recording

Meetings still only need System Audio Recording. Full Screen Recording is
now only for Writing's autocomplete, if you turn it on, so the migration
guide no longer tells everyone to turn the broader permission off.
Screen Recording stays out of TranscriptedPermissionKind; Writing owns it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Writing phase 5 (P5): count-only usage telemetry under the analytics toggle

writing_daily_counts reports the previous whole local day once, from the
text-free outcome ledger summary: suggestions shown and accepted, a words
bucket on the word_count_bucket boundaries, and the setup enums. The day is
claimed in the Writing app suite before the ledger is read, so launch and a
quick wake can't double-send, and idle days send nothing. It runs from the
controller's launch and wake hooks. writing_setup_completed gets its emitter
for the Writing tab to call later.

Both events are registered in the psv taxonomy and the privacy doc. Fast tests
cover the day boundary (including DST), no re-emit, zero-day skips, exact keys,
enums, and the sanitizer round trip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Writing: daily counts report the real Save my writing and app scope settings

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Writing phase 4 (P4-A): run Writing from its setup state

Writing now starts at launch once the Writing tab's setup is done and
Save my writing or Autocomplete is on (the WritingDebugEnabled default
still starts it for development). The tab can start it right after
"Turn on writing" and stop it when both features go off; a later start
builds a fresh runtime. After the quit nothing starts again.

Autocomplete alone runs the model, the llama-server helper and Screen
Memory: with only Save my writing on, nothing downloads and nothing on
screen is read, and turning Autocomplete off stops the download and the
helper. The controller also gains what the tab needs: pause and resume
(which pause saving too), a keyboard turn-on that selects the input
source every time it's asked, the Screen Recording settings link, and
a sizes-only storage reading.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Writing phase 4 (P4-A): runtime status text says autocomplete, not Tilde

The held-back, menu-detail, engine and history status lines the Writing
tab can show still named Tilde and its "Screen Access". They now say
autocomplete, Transcripted and Screen Recording. The tests that pin the
strings follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Writing phase 4 (P4-A): the Writing tab

The approved design, built in SwiftUI: two intro pages (the second with
a looping autocomplete demo that holds still under Reduce Motion), the
three setup steps, and the everyday view with today's saved writing,
the autocomplete numbers and a settings section (the two features,
personalized suggestions, the model switch, a storage meter and Delete
all writing with a confirm).

"Turn on writing" saves the choices, turns on and selects the keyboard,
starts Writing (which starts the model download), then asks for Screen
Recording last. That ask, and the tab's later one, waits while a
meeting or dictation records, since macOS may ask Transcripted to quit
and reopen after the grant. It also records writing_setup_completed and
clears the sidebar's New badge.

The copy lives in WritingSetupPresentation and the demo in
WritingDemoScript, both Foundation-only. The shell only routes: it hands
the page the controller and the recording check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Writing phase 4 (P4-A): fast tests and automation pins for the Writing tab

Fast tests pin the approved copy word for word, which step 3 rows show,
the keyboard badge, validation, the everyday summary and status lines,
the app-chip order, the demo script, the day-file reader, when Writing
runs, and the storage meter. The helpers join APP_SOURCES.
UIAutomationSurfaceContractTests pins the tab's automation identifiers,
its routing, and the rule that Screen Recording is never asked for while
anything records.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Writing phase 4 (P4-A): idle while hidden; retry the keyboard select once

The Settings window stays alive when closed, so the Writing tab's
refresh timers and the intro demo now idle unless its window is on
screen. "Turn on writing" gives Text Input Sources a second to list a
just-registered keyboard before falling back to Keyboard settings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Writing docs: record llama-server provenance (llama.cpp 2115b73)

llama-server --version on the pinned helper reports version 0.2.0-dev
(build 1, commit 2115b73), AppleClang 21 for Darwin arm64. The ledger
follow-up now carries a reproducible build recipe to confirm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Writing phase 4: show save failures in the tab; ledger and docs catch up

- The everyday view says "Writing couldn't be saved to this folder" while
  Save my writing is on and the day-file recorder has a write failure.
- Ledger rows for the replaced Tilde settings, setup and stats views point
  at their Writing tab files; Sources/UI/Settings/CLAUDE.md no longer calls
  the page a placeholder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Writing phase 4: review fixes

- Intro gets a quiet "Not now" that leaves Writing off and clears the
  sidebar's New badge (plan: the badge stays until setup finishes or the
  intro is dismissed).
- App activation refreshes keyboard state only while the Writing page is on
  screen; refreshKeyboard validates code signatures on the main thread.
- writing_setup_completed fires on the first setup only, not on Edit setup.
- Pause also stops Screen Memory, so a paused Writing reads nothing.
- The Screen Recording hold line says "Finish recording and transcribing
  first", matching the hold condition (queued transcription counts).
- Entry rows and the collapse control get accessibility actions; the page
  transition respects Reduce Motion.
- The plan's everyday view documents pause and Not now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Writing: fold tiny scraps into the next entry

An entry under 3 words (a quick "sounds good") no longer ends at a
segment break when the same app's next segment starts within a minute.
It folds into that entry, each segment on its own line. App switches,
2 minutes idle, and deletions still split as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Writing phase 4 (P4-K): honest keyboard enable and guided keyboard step

macOS 26 returns noErr from TISEnableInputSource and leaves the keyboard
off, so the enable now re-reads the source and returns .needsUserToAdd,
and WritingController logs what actually happened.

A new WritingKeyboardSetupState (selected, enabledNotSelected,
needsUserToAdd, needsRelogin) drives setup step 3 and the everyday
"Keyboard off" row with plain steps and an Open Keyboard Settings button.
needsRelogin comes from a persisted marker: the login session (boot time
plus audit session ID) the app first copied the keyboard in.

The tab re-checks on activation and on the Input Sources notifications,
only while it's on screen, and selects the keyboard once the moment it
becomes enabled. Only the button opens System Settings; Turn on writing
no longer waits on or opens anything for the keyboard.

Tests: fast-test copy per state; Swift Testing resolution, enable and
auto-select tests with a fake Input Sources provider. Plan doc updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* MCP: rebuild the index in place and never lower its version

Every agent runs its own MCP server on one index. After an update (or with
two Transcripted builds side by side) an old server still has it open when a
new one trips the schema gate. Deleting the file under that connection left
the old server failing every query with "disk I/O error" until restarted,
and the old server then stamped its lower version back, so the next new
server rebuilt again. Now the gate drops the tables in one transaction, and
opening only ever raises user_version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Writing phase 6: README, uninstall, agent docs and prompt, cask zap (#1872)

* Writing phase 6 (P6-D): user docs and agent prompt for Writing

- AgentConnectionGuide: list <capture-library>/writing/ next to meetings
  and dictations in the starter prompt, Codex setup prompt, copied folder
  paths, and Codex inbox AGENTS.md; search "meetings, dictations, and
  writing together". Uses the pure FileManager.writingDirectory(in:) so
  building a prompt never creates the folder. Tests updated.
- README: a Writing bullet, the writing/ folder, model disk and memory
  needs, a Privacy line for suggestion counts, and a new Uninstall section
  that removes the keyboard.
- agent-connect.md: list_writing/read_writing, kind "writing" on
  search_context/recent_context, the writing fallback folder and
  TRANSCRIPTED_WRITING_DIR.
- Ledger: drop the AgentConnectionGuide follow-up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Writing phase 6: cask zap, "wrote" wording, Agent page writing folder

- The Homebrew cask's zap removes the Transcripted keyboard and Writing's
  two preference domains.
- MCP tool descriptions say what the user wrote, not typed.
- The Agent settings page lists the Writing folder next to Meetings and
  Dictation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Writing docs: llama-server provenance verified by an exact rebuild

A from-source build of llama.cpp 2115b73 with Command Line Tools 26.6
reproduces the pinned unsigned code hash 3f6895ab… exactly (twice, fresh
clones). docs/llama-server-provenance.md records the recipe, what it
depends on (toolchain, GGML_NATIVE=OFF, prefix map, the web UI snapshot)
and why build-deps should keep pinning Tilde's binary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Writing phase 6 (P6-H): keep manifest-writing tests out of the real app support

TranscriptedStoragePathsTests used to snapshot the manifest at
transcriptedMCPDirectoriesManifestURL and write it back afterwards. Under
run-tests.sh that URL is the throwaway TRANSCRIPTED_CONTAINER_DIR, but the
test itself never checked that, so run anywhere else it would rewrite
~/Library/Application Support/Transcripted/mcp-directories.json. Drop the
rewrite-restore. Fail closed unless the manifest URL resolves under the test
container, read the parity suite's manifest from that checked URL, and end
with a guard that the real manifest's mtime and size didn't change.

The home recent-captures benchmark had no container override at all: its
loader and its cleanup both go through transcriptedCaptureLibraryDir, which
rewrote the real manifest (to the benchmark process's own default library,
not the user's), and the loader filled the real Home metadata cache. Point
TRANSCRIPTED_CONTAINER_DIR at the run's scratch folder before any storage is
touched, and refuse to run if the override doesn't take.

No production change: the writer already takes manifestURL, and the
container root is already overridable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: r3dbars <r3dbars@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: r3dbars <r3dbars@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant