Rough

Reference

Feature SDK changelog

What changed in @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 SpriteBuild export must handle the new CANCELED status. Build records also include cancelRequestedAt: 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 call await 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 to document.body.

Breaking changes

The recommended migration is shown below. In summary:

  • All stateful functions and components now take a client. Pass client and surface to getRoughFeatures(), 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() and modal.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, projectId and person fails with RoughReplicacheIdentityConflictError. 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 by defineRoughSurface(). Rename toolList to tools when updating your surface definitions.
  • registerSurfaceEntry has 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

Unsupported release

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

Unsupported release

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.
  • getRoughFeatures is a live subscription rather than a one-shot fetch. In 0.1.0 the callback fired once and only fired again when something called triggerRefresh. 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.js grows 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.

  • Sprite and SpriteBuild reference 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, .status or .prompt off a getRoughFeatures result must be reworked, and SpriteBuild no 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, SurfaceId and PersonId are now string & { __brand: … } rather than string, on RoughFeature's featureId and buildId, RoughCreateModal's and SpriteBuildMenu's surfaceId, SpriteFrame's spriteBuildId, and registerSurfaceEntry's surfaceId.

    Reading is unaffected, because a branded string is still assignable to string. Passing one in is not: an ID you hold as a plain string, 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 getRoughFeatures into 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.0Closest 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-brand is the saturated brand colour

    Watch --rough-accent in 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-primary now controls primary actions. --rough-background and --rough-border also kept their names with new values. The expanded set adds variables for radius and success states.

Removed

  • onpublish is gone from RoughCreateModal, RoughEditButton and RoughEditModal. Because getRoughFeatures is 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 the getRoughFeatures callback. Note that the prop was optional, so depending on your setup this may fail quietly rather than at compile time.
  • triggerRefresh is gone from the SurfaceEntry passed to registerSurfaceEntry. 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-dark class 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

Unsupported release

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-provided fetchUserToken callback and an optional API base URL.
  • Typed surface definitions. defineSurface() describes where features can appear and the Query, Mutation and Subscription tools they can call.
  • Published feature rendering and discovery. Apps can use RoughSurface or <rough-surface> to render features and getRoughFeatures() 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.