Reference
Feature SDK changelog
@roughapp/feature, why it matters, and what to do
when upgrading.The SDK is pre-1.0, so minor releases can contain breaking changes.
v0.4.1
Documentation-only release. The README now has expanded setup, security, lifecycle, theming and API guidance, and the changelog includes the release notes that were missing from 0.4.0. There are no runtime, type or API changes.
v0.4.0
The Feature Builder is now conversational: Rough can clarify what to build, inspect the tools available on the surface and start a build when it has enough context. The recommended client and surface APIs are unchanged, so host apps do not need an integration migration.
Added
- Feature Builder chat. Conversations are saved per feature and remain available when the builder is reopened. Follow-up messages can refine the feature before Rough starts another build.
- Markdown responses. Assistant messages render headings, lists, links, tables, blockquotes and code blocks.
- Build cancellation. Pending and in-progress builds have a Stop control. Canceled builds remain in the conversation and build log with the time they ran before stopping.
Changed
- Build and publish updates reach open clients sooner. The SDK uses an authenticated WebSocket when available, so updates no longer wait for the five-second polling interval. Polling remains available as a fallback.
- Abandoned create flows no longer leave empty features behind. Rough creates the feature only after the user sends the first message.
- Advanced consumers of the incidental
SpriteBuildexport must handle the newCANCELEDstatus. Build records also includecancelRequestedAt: number | null; update exhaustive status switches and test fixtures accordingly.
v0.3.0
This release has breaking API changes. Rough now uses an explicit client for each project instead of global initialization. Apps can safely show features from multiple Rough projects at the same time, and each client has a clear, awaitable lifecycle.
Added
createRoughClient({ projectId, baseUrl?, fetchUserToken })creates and starts a client for one project. Keep the client for as long as your app needs that project, then callawait client.destroy().whenRoughClientReady({ client })lets you wait for startup or handle a startup error.openRoughCreate({ target })lets you attach the create modal inside the element that scopes your Rough theme. It defaults todocument.body.
Breaking changes
The recommended migration is shown below. In summary:
- All stateful functions and components now take a client. Pass
clientandsurfacetogetRoughFeatures(),openRoughCreate(),<rough-surface>,<rough-feature>,<rough-edit-button>and the modal elements. - Cleanup methods are asynchronous and safe to call more than once. Await
client.destroy(),subscription.unsubscribe()andmodal.close()when you need to know that cleanup has finished. - Create one client and share it for each signed-in person and project. A second client for the same
baseUrl,projectIdand person fails withRoughReplicacheIdentityConflictError. Clients for different projects or different signed-in people can run together. openRoughCreate()no longer requires a mounted Rough component. You can open it directly with a client and surface.
Removed
initRough()has been removed. There is no default or global client.defineSurface()has been replaced bydefineRoughSurface(). RenametoolListtotoolswhen updating your surface definitions.registerSurfaceEntryhas been removed. You no longer need to register a surface before using it.
Migration
// Before
initRough({ projectId, fetchUserToken })
const surface = defineSurface({ key, name, description, toolList })
const unsubscribe = getRoughFeatures(surface, onFeatures)
openRoughCreate(surface, { projectId })
// After
const client = createRoughClient({ projectId, fetchUserToken })
const surface = defineRoughSurface({ key, name, description, tools })
const subscription = getRoughFeatures({ client, surface, onFeatures })
const modal = await openRoughCreate({ client, surface })
await modal.close()
await subscription.unsubscribe()
await client.destroy()v0.2.1
The published package now includes this changelog, so release and migration notes are available alongside the installed SDK. There are no runtime, type or API changes.
v0.2.0
Upgrade from 0.1.0 as soon as you can. Version 0.1.0 relies on retired service endpoints and can no longer list, create, build or publish features. Version 0.2.0 uses the supported synchronization service.
Upgrading needs no configuration change. initRough takes
the same projectId, fetchUserToken and
optional baseUrl, and no export was added or removed.
Consumers of the exported data types or theme variables need the
migrations below.
Changed
- Feature data now stays synchronized while the SDK is mounted. Published features and build changes can appear without another host action. Unlike 0.1.0's one-off requests, 0.2.0 keeps a sync loop open and polls every five seconds, which may affect network monitoring or request allowlists.
getRoughFeaturesis a live subscription rather than a one-shot fetch. In 0.1.0 the callback fired once and only fired again when something calledtriggerRefresh. It now re-fires on every relevant change that syncs in, so a feature published in another tab or by another user appears without the host doing anything.- The JavaScript bundle is larger because it now includes continuous sync.
index.jsgrows from 105 kB to 320 kB raw (27 kB to 77 kB gzipped). The stylesheet grows from 324 B to 5.2 kB with the expanded theme token set.
Breaking changes
Hosts using exported data types or custom theme variables need the migrations below.
SpriteandSpriteBuildreference related records by ID instead of nesting them.// 0.1.0 type Sprite = { id: string name: string ownedByPersonId: string publishedSpriteBuild: SpriteBuild | null // full nested record } type SpriteBuild = { createdByPerson: { id: string; name: string } // ... } // 0.2.0 type Sprite = { id: SpriteId name: string ownedByPersonId: PersonId publishedSpriteBuildId: SpriteBuildId | null // ID only } type SpriteBuild = { createdByPersonId: PersonId // ... }Anything reading
sprite.publishedSpriteBuild.artifactUrl,.statusor.promptoff agetRoughFeaturesresult must be reworked, andSpriteBuildno longer carries the build author's display name. There is no replacement for that name in the public API.- ID fields are branded string types.
SpriteId,SpriteBuildId,SurfaceIdandPersonIdare nowstring & { __brand: … }rather thanstring, onRoughFeature'sfeatureIdandbuildId,RoughCreateModal's andSpriteBuildMenu'ssurfaceId,SpriteFrame'sspriteBuildId, andregisterSurfaceEntry'ssurfaceId.Reading is unaffected, because a branded string is still assignable to
string. Passing one in is not: an ID you hold as a plainstring, from your own database or a URL parameter, is rejected. The brand types are not themselves exported, so reach them through the types that are:type SpriteId = Sprite['id'] type SpriteBuildId = NonNullable<Sprite['publishedSpriteBuildId']> type SurfaceId = RoughCreateModalElement['surfaceId']IDs that flow straight out of
getRoughFeaturesinto a component still typecheck with no cast. - The stylesheet ships an expanded set of semantic design tokens. Hosts that theme Rough through CSS custom properties need to remap
these eight removed variables to their nearest replacement:
Removed in 0.2.0 Closest 0.2.0 token --rough-text--rough-foreground--rough-text-secondary--rough-muted-foreground--rough-surface--rough-card--rough-surface-border--rough-border--rough-background-muted--rough-muted--rough-danger--rough-destructive--rough-shadow--rough-shadow-xs,-md,-lg--rough-accent-secondaryNo equivalent; --rough-brandis the saturated brand colourWatch
--rough-accentin particular. The name survived but now controls a subtle hover background rather than the primary action colour. A host that set it to a brand colour to tint buttons will find it tinting hover states instead.--rough-primarynow controls primary actions.--rough-backgroundand--rough-borderalso kept their names with new values. The expanded set adds variables for radius and success states.
Removed
onpublishis gone fromRoughCreateModal,RoughEditButtonandRoughEditModal. BecausegetRoughFeaturesis now a live subscription, a publish already reaches the host through that callback, which is what the prop existed to signal. Move any publish handling into thegetRoughFeaturescallback. Note that the prop was optional, so depending on your setup this may fail quietly rather than at compile time.triggerRefreshis gone from theSurfaceEntrypassed toregisterSurfaceEntry. It was the manual refresh hook for the old fetch-once model and has nothing to do now. Delete it from the object you pass in; leaving it there is an excess property and will be rejected.
Added
- A light and dark mode toggle in the Feature Builder. The stylesheet
now carries a
.rough-darkclass holding the dark values for every token. - The Feature Builder's build log now reports token usage and estimated cost per agent step, formatted in cents below one dollar.
v0.1.0
Initial public release of the Rough Feature SDK. This version is no longer supported because the service endpoints it uses have been retired; upgrade to a current release before integrating it.
Added
- An embeddable browser SDK for Rough Features. The npm package ships compiled ESM, TypeScript declarations, Web Components and a separate stylesheet for apps using a modern bundler.
- Project and user authentication.
initRough()configures a project with a host-providedfetchUserTokencallback and an optional API base URL. - Typed surface definitions.
defineSurface()describes where features can appear and theQuery,MutationandSubscriptiontools they can call. - Published feature rendering and discovery. Apps can
use
RoughSurfaceor<rough-surface>to render features andgetRoughFeatures()to receive the published feature list for a surface. - Embedded feature creation and editing.
openRoughCreate()opens the Feature Builder, where users can create, build and publish a feature without leaving the host product.