feat: carry item origin, share form, and recipe in the HolaHub ShareDraft - #444
Merged
Merged
Conversation
…raft The draft is the only channel from a real run to a post, so anything the post wants to claim has to travel on it. - ShareDraftItem gains a required origin: "derived" is what was detected from what the sharer actually invoked and is not theirs to remove; "attached" is a recommendation they can drop. Also adds the integration type, which the catalog already has. - ShareDraft gains form (which share mode produced it — the tie-breaker for which is the hero when a draft carries both a transcript and media) and recipe (the prompt + model that made the Output, for Reproduce). - Attribution items resolved from an output's module_id are marked derived, since that is exactly a detection. Drops the "Everything here is user-editable in the composer" note, which had been contradicting the "auto-attributed" one directly above it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The draft could already carry a form and a recipe; nothing filled them, so the web side was still inferring the shape from which fields happened to be set. - ShareableOutput keeps input_id, and resolveRecipePrompt walks it back to the user turn that produced the artifact, falling back to the conversation's opening ask. Quoted-skill command lines are stripped: the skills travel as items, so leaving the raw /skill lines in would seed a prompt that only runs for someone who already has them. - An outputs share now sends form "output" plus that prompt as its recipe; a conversation share sends form "conversation". The sharer already made this choice in the mode switch — it just wasn't travelling. recipe.model stays empty for now. It is the session model that Reproduce hands to chat.start, and capturing a structured id (rather than the display string the pane renders) is its own change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`model` is what Reproduce seeds a new session with; `outputModel` is what actually generated the artifact and exists to be shown to the reader. A share can have both — an image made by a skill inside a chat session — so one field always dropped one of them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jotyy
force-pushed
the
feat/holahub-share-draft-provenance
branch
from
July 28, 2026 05:58
5587174 to
e7cfaf1
Compare
Attribution was one line of guesswork: every share credited the apps behind its outputs and nothing else, so the skills someone picked out of the composer — the thing they most obviously "made it with" — never travelled at all. - gatherQuotedToolItems reads the skills and integrations quoted in the turns being shared. A quoted skill is a detection, so it ships as derived and the composer will not let the author drop it. An integration is a prerequisite rather than an actor, so it rides along as a recommendation. - Detection is scoped to what actually travels: the turns kept in a conversation share, and for an outputs share the turns that produced the picked artifacts. Dropping a turn drops its credit, which is the point — you cannot keep the artifact and lose the tool. - The Recipe now carries the resolvable model id rather than the display label, which was never something Reproduce could select again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reproduce promises "make your own equivalent", and the model is half of what made the original — but chat.start had no way to say which one, so a shared Output always reproduced on whatever the viewer happened to have selected. ChatStartInput gains `model`, carried to ChatPane through the same request-atom route the composer prefill already uses and applied through the same path as the composer's own picker. A model this install does not have is ignored rather than raised: the viewer still gets the session, the tools, and the prompt, and only loses the exact match — blocking the hand-off over it would be worse. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reproduce promises "one like this", and until now the viewer never saw "this" — only a prompt describing it. ChatStartInput gains `attachments`, base64 over the same IPC bridge a ShareDraft's images already use, decoded into the ordinary pending-attachment path. Going through that path rather than a bespoke one is the point: the composer's own image-support check applies, and removing the reference is just removing an attachment — which is what makes it optional without any extra affordance. A malformed attachment is dropped rather than raised. Losing the reference is a smaller failure than losing the hand-off it was riding along with. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A reader of a generated sample should be able to see what made it, and the runtime already stamps that on the output — `model` on a written report, `model_id` on a generated image. The share just never read it, so every desktop post arrived with an empty outputModel while growth-pipeline posts had one. Display-only, and deliberately separate from the session model: this is what produced the artifact, not something Reproduce can open a conversation on. Empty when the producing tool records no model. Image outputs are the case worth watching — image_generate returns model_id to its caller, and whether that reaches the output record is a runtime question this change does not answer; it reads the convention and starts working the moment the stamp is there. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Falling back silently let someone believe they had reproduced something on the model it was made with. The hand-off still proceeds — tools, prompt, session — but now it names the model the original used and says the default is standing in. Co-Authored-By: Claude Opus 5 (1M context) <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.
The ShareDraft is the only channel from a real desktop run to a HolaHub post, so anything a post wants to claim has to travel on it. This is the holaOS half of the post provenance contract; the backend and web halves land separately.
What changes
ShareDraftItemgains a requiredorigin.derivedis what was detected from what the sharer actually invoked — it renders in the post's "Made with" row and is not theirs to remove, only to demote.attachedis a plain recommendation they can drop. Also adds theintegrationtype, which the catalog already has but the draft could not express.ShareDraftgainsform— which share mode produced it. It settles exactly one question: which is the hero when a draft carries both a transcript and media. It is not a post taxonomy; absent means "not a desktop share".ShareDraftgainsrecipe({ prompt, model }) — what Reproduce seeds into a new session.module_idare markedderived, since that is exactly a detection.Also drops the
"Everything here is user-editable in the composer"note onShareDraft, which had been contradicting the"auto-attributed"note directly above it — that contradiction is what this contract resolves.Notes
Types and capture only. Nothing renders the two zones yet, and richer detection (session
skillIds→ skill,tool_callevents) is a follow-up — this PR just stops the draft from throwing away what it already knows.@holaboss/app-hostand the desktop typecheck clean on this branch.🤖 Generated with Claude Code