Repository navigation
sdk: who made each step: Author, act, and the host's author map - #474
Merged
Merged
Conversation
The first half of plans/SHARED_HISTORY_PLAN.md's step 2 (as amended in fizzyedit/plans#21): who made each step of a document's history, kept by the host on the channel owners already report through (Host.recordStep, fizzy#456). - sdk.Author: the person, an agent, a tape, or nobody known; identity is kind, plugin and session. - Host.act / endAct / acted / actAgain / author: who is acting. Innermost wins; an outermost act starts a run; work put off acts again as its stored author and run. - Host.setInputAuthor: the frame's input author, for the app to set where input is consumed. - Host.recordStep keeps who made every step not the person's, per document, by step id, and the document's top; the recorder still hears a step only while recording. Working alone, nothing is kept. Host.stepAuthor, topStep, mayMerge; forgetDocumentAuthors when a document closes. - Step.top: the entry on top after a step, so Undo can name whose step it takes back. The fingerprint moves. Nothing calls act yet, and owners report steps only while recording until the plan's step 3, so nothing changes for a person yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator
Author
|
Gates on this head (macOS): |
foxnne
marked this pull request as ready for review
October 16, 2026 21:48
2 of 6 tasks
foxnne
added a commit
that referenced
this pull request
Oct 16, 2026
#474 landed squashed; this branch carried its original commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
foxnne
added a commit
that referenced
this pull request
Oct 16, 2026
Stacked on #474 (the SDK half); review that first. Part of fizzyedit/plans#14: `plans/SHARED_HISTORY_PLAN.md`, step 2, as amended in fizzyedit/plans#21. ## What changes The app now says who is acting, using #474's `Host.act` and `setInputAuthor`. - **The frame's input author.** - `Editor.tick` sets it where input is consumed: around the active document's tick, native menu actions, the layout's draw and floats, then around plugin keybinds, the keymap, overlays and the palette. - It clears it around plugins' `endFrame`. Plugins' `beginFrame` and event delivery run with none, as the plan says: they act for themselves, or are nobody's. - The author is the person's, or a tape's while one drives (`Demo.author`). The demo player and the live driver stop for a real press or key before the frame's input is consumed, so a frame a person takes over is theirs. - **Tapes act.** A tape's command ops run inside `act` as the tape (`Demo`'s stage `command`), and a live tape's as whoever it plays for. A demo's author is its title; a live tape played by nobody in particular is "a tape". - **`automation.Api.playAs(bytes, author)`** (service version 6): a live tape played for an author. An agent's pointer tape (`fizzy_act`) is then the agent's. Plain `play` leaves the tape its own author. The service tells the app through a new `OnAuthor` hook, beside its `Other`. - **Bubbles name agents.** An edit made while an agent acts shows as "Claude · Draw". The person's own edits stay plain, as the plan has it, and so does a demo narrating itself. The plan says "others", but prefixing every bubble of a playing demo with its title cluttered the demo; that's a judgement call for review. - **The integration check.** The whole-editor test asserts the tour adds no unattributed step. Owners report every step only from the plan's step 3, so today it guards the steps reported while recording. ## SDK impact - [ ] None - [x] Core-only or additive: reaches plugins at the next SDK release. The automation service is versioned on its own (`service_version` 5 → 6), so a plugin built for version 5 gets null from `getServiceTyped` on this host and degrades. The agent plugin is the one consumer: it moves to `playAs` with its repin. - [ ] Fingerprint moved - [ ] SDK release ## Verified - [x] macOS: - **Unit test:** an agent-acting edit's activity title is "Claude · Draw", the person's "Draw". - **Gates:** `zig build`, `zig build test`, `check-fmt`. `test-integration`, `check-web` and `test-sdk-version` results are in a comment below once they finish. - [ ] Not tried by hand: a demo's edits attributed while it plays, and an agent's pointer tape through `playAs`. The agent plugin calls `playAs` after the SDK release; that PR will show it end to end. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 17, 2026
Merged
foxnne
added a commit
that referenced
this pull request
Oct 17, 2026
…g joins (#479) Part of fizzyedit/plans#14: `plans/SHARED_HISTORY_PLAN.md`, step 3 (text's half; pixi's follows in its repo). ## What changes - **Text reports every step** through `Host.recordStep`, not only while recording. The host keeps who made each one (#474); working alone, it keeps nothing. Encoding a step's `effect` still happens only while the document is recorded, so a document nobody records costs one call per step. - **Each step carries `top`:** the last applied entry after it (`History.lastApplied`), for added, joined, undone and redone alike. The host knows the top step and its author without asking for the line, which Undo's "Undo Claude's …" label (step 5) needs. - **One hand's typing never joins another's run.** `History.end` takes `may_join`. The editor's edit hook fills it from `Host.mayMerge` on the step on top. When that step is someone else's, VSCode's grouping rule doesn't get to fold the new keystroke into it: an agent typing doesn't extend the person's step, nor the person an agent's. - **Typing calls `documentEdited`,** as its doc comment always said it did. A person's typing runs no command, so it still raises no activity bubble. ## SDK impact - [x] None. Text is built in, and #474's API is used as is. ## Verified - [x] macOS: - **New unit test:** an edit with `may_join = false` starts a step of its own where VSCode's rule would have joined it. The existing history tests pass `true` and behave as before. - **`zig build test`:** 573/574 (1 skipped). `check-tests-reached` passes. - **`test-integration`:** 53/53 steps, 556/556 tests. The whole-editor test's check from #475, that the tour adds no unattributed step, now covers real steps: the tour's typing and commands are each attributed to the tape. Two warnings print, and both are on unmodified `main` too (a demo replay mismatch and a float position). - `check-fmt`, `check-web`, `test-sdk-version`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
foxnne
added a commit
that referenced
this pull request
Oct 17, 2026
## What changes `sdk_version` goes from 0.2.28 to 0.2.29. Merging this tags `sdk-v0.2.29` and publishes its tarball. **Why now:** authors (#474, #475) need a release before plugins can use them: - the agent acts as its connection around each command, and plays its pointer tapes with `playAs`; - chat acts around its writes; - pixi's calls that wait out the person's stroke keep their author (`plans/SHARED_HISTORY_PLAN.md` step 2's plugin PRs). ## SDK impact - [ ] None - [ ] Core-only or additive: reaches plugins at the next SDK release - [ ] Fingerprint moved: recorded in `sdk/src/version.zig`, `sdk_version` untouched, PR labelled `sdk` - [x] SDK release: bumps `sdk_version`, lists the `sdk` PRs since the last `sdk-v*` tag **`sdk` PRs since `sdk-v0.2.28`:** - **#474:** who made each step. - `sdk.Author`; `Host.act` / `endAct` / `acted` / `actAgain` / `author` / `setInputAuthor`. - The host keeps a per-document author map filled in `recordStep`. - `stepAuthor`, `topStep`, `mayMerge`, `forgetDocumentAuthors`, and `Step.top`. - The fingerprint moved. Everything is additive (a defaulted field, new functions). **Reaching plugins, no fingerprint move:** - **#475:** the automation service's `playAs(bytes, author)` (`service_version` 5 → 6). Activity titles name an acting agent ("Claude · Draw"). - **#468:** `core`: `MenuRowOptions.anchor`, a stable name for a menu row's button. ## Verified - [x] macOS: - On this head, `zig build test-sdk-version` passes, and `scripts/pack-sdk.sh` packs `fizzy-sdk-v0.2.29.tar.gz`. - fizzyedit/pixi, fizzyedit/agent and fizzyedit/atlas `main` build against this `sdk/` (`--fork`) with no changes. - [ ] Windows: - [ ] Linux: CI. - [ ] Web: ## Follow-ups - The repin automation opens `sdk: repin to fizzy SDK 0.2.29` PRs in the store plugins whose fingerprint moved. - The agent has no repin automation: its repin is a hand-made PR, carrying the agent's `act` around `agentCall` and `playAs` for its pointer tapes. - Chat's repin carries its `act` around ACP writes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
foxnne
added a commit
that referenced
this pull request
Oct 17, 2026
Part of fizzyedit/plans#14 — `plans/SHARED_HISTORY_PLAN.md` step 5a, as amended for `plans/CONTROL_SERVER_PLAN.md` (fizzyedit/plans#24). ## What changes `fizzy.undo` and `fizzy.redo` take two optional arguments: - **`path`**: the open document to undo, which need not be the active one. It goes through the owner's `historyLine` and `historyGoTo` (text and pixi both have them), so nothing is focused and the document in front is untouched. An owner with no line undoes only the active document, as before. - **`expect`**: the step id the caller means, the last change for undo or the next one for redo. When another step is there instead, the call refuses and names it: *"step 41 is not the one to undo: that is step 43, Draw, by the person. The document changed since; fix it forward."* So a caller never takes back a step made since it looked. Its answer is `.{ .step, .title, .by }`, where `by` is whose the step was: "the person", or an author's label (`Host.stepAuthor`, #474). Keys, menus and the palette run Undo exactly as before (`run`, with its transport and key repeat). Only a call with arguments takes the new path. This is the refusal the shared-history plan wanted from the agent plugin (fizzyedit/agent#21's `undoesAnother`). As a command, it holds for any caller, and over the control server it becomes a 409 from `POST /commands/fizzy.undo` with no agent code. **One trade-off.** `fizzy.undo`/`redo` are now enabled while any document is open, as text's by-path commands are, because a call may name a document other than the active one. The command palette therefore shows Undo enabled when the active document has nothing to undo; running it then does nothing. The menus still grey it by the active document (`menu_model.canUndo`). An enabled check that sees the call's target is the control plan's open question ("Commands that take a document"), so it isn't decided here. ## SDK impact - [x] None. A doc comment on `Plugin.historyGoTo` notes that `fizzy.undo` reaches it; the fingerprint does not move (`test-sdk-version` passes). ## Verified - Integration (`headless: the whole editor comes up…`), on the open text documents: an author acting as "Claude" writes into `notes.txt` by path while `main.zig` is in front. - A stale `expect` is refused, naming Claude, and changes nothing. - The right `expect` undoes it, answering `.by = "Claude"`, and `main.zig` stays in front, untouched. - Redo and undo again by the same id work. - Gates on macOS: `check-fmt`, `zig build test` (573/574, 1 skipped), `zig build test-integration` (53/53 steps), `check-web`, `test-sdk-version`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
foxnne
added a commit
to fizzyedit/chat
that referenced
this pull request
Oct 18, 2026
A file the agent writes into an open document (`fs/write_text_file`, through `text.write`) is now recorded as that chat's agent's step (`sdk.Author`, fizzyedit/fizzy#474/#475), labelled with the name the agent gave in `initialize` (`agentInfo`), rather than as the person's. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of fizzyedit/plans#14:
plans/SHARED_HISTORY_PLAN.md, step 2, as amended in fizzyedit/plans#21. This is the SDK half; the app half (the frame's input author, tapes acting, activity bubbles naming others, the integration check) follows as a PR stacked on this one.What changes
The host learns who made each step of a document's history. It keeps this on the channel owners already report steps through (
Host.recordStep, #456), not a second one.sdk.Author: the person, an agent, a tape, or nobody known (unattributed, a missed site). Identity is kind, plugin and session; the label ("Claude", "the tour") is display only.act(author)andendAct(outer): the innermost act wins. An outermostactstarts a run (one agent call, one tape op).acted()andactAgain(stored): work put off (pixi's call that waits out the person's stroke) runs as the author and run it was asked in.author(): the innermost act, else the frame's input author (setInputAuthor, for the app to set where input is consumed), elseunattributed.recordStep:unattributed_steps, which the app's tests will assert stays 0);stepAuthor,topStepandmayMerge(whether the acting author may fold an edit into a step; it keeps an agent's keystrokes from joining the person's run of typing).forgetDocumentAuthorsruns when a document closes, besidereleaseDocumentClaims.Step.top: the entry on top after the step, so Undo can name whose step it takes back. An owner that leaves it 0 still gets a sensible top afteraddedandjoined.docs/PLUGINS.md:recording;actaround commands run on someone's behalf,actAgainfor deferred work,mayMergefor runs.Nothing calls
actyet. Owners report steps only while recording until the plan's step 3. So nothing a person sees changes in this PR.SDK impact
sdk/src/version.zig(0x78f2a3cc371828ef),sdk_versionuntouched, PR labelledsdksdk_version, lists thesdkPRs since the lastsdk-v*tagFor plugin authors: additive.
Stephas a new defaulted fieldtop, and the host has new functions. Nothing existing changes shape.After the release that carries this:
agentCallacts as its connection;acted()and run inactAgain.Verified
sdk/src/Host.zigandsdk/src/Author.zig:actAgain;mayMergeboth ways;zig build test: 568/569 passed (1 skipped).check-tests-reachedpasses.zig build,test-sdk-version,check-webandtest-integration. Results are in the comment below once they finish.sdk/.check-web.🤖 Generated with Claude Code