Changelog

26.1.0 Welcome Page, Notifications Overhaul, and a New Release Cadence

Two headline features in this release: a real Welcome page when you sign in, and a rewritten watcher × notification system with a preferences UI. We also flipped the release-tag scheme to a calendar-year format — this is the first release on the new pattern, so the version jumped from 1.16.0 to 26.x. New features A…

Read more

Two headline features in this release: a real Welcome page when you sign in, and a rewritten watcher × notification system with a preferences UI. We also flipped the release-tag scheme to a calendar-year format — this is the first release on the new pattern, so the version jumped from 1.16.0 to 26.x.

New features

A welcome page that actually welcomes you

The placeholder at /[tenant]/ is replaced with a launchpad: my active work, goals and projects you own, what you’re watching, and active cycles. Each section renders through the familiar RecordRow / GoalRow / ProjectRow components the list pages use.

The active-cycles section offers a unique list view of all active cycles relevant to the user. Previously the quickest way to an active cycle was through the cycle planner, this eliminates that navigation requirement.

Notifications, rewritten

Watchers existed before this release, but only for goals and projects, and the fan-out was a bit ad-hoc. This release replaces the whole pipeline.

Watchers now cover every entity. Records and ideas are watchable too, with a WatchButton exposed on detail pages, the actions tray, and the properties pane. Auto-watch fires on create, on assignment, and on check-in across all four entity types — the same opt-in pattern goals and projects had, now consistent everywhere.

Mention × watcher dedup. If you’re @-mentioned in a comment and you watch the entity, you used to get two notifications for one event. A new partial unique index on notification_source_event_id collapses those into one row, race-safe under concurrent fan-out (with a separate metric on the rare collision so it stays visible).

IDEA_PROMOTED fans out to watchers. Previously this event only notified the original submitter; now anyone watching the idea gets told when it becomes a record, project, or goal.

Every emit goes through one helper. A single emit() function is the only path from the resolvers to the notification consumer. This feature is more internal facing, allowing the team better insights and debugging for event processing.

Notification preferences at /profile

The flip side of opt-in watchers is opt-out preferences. The new /profile page exposes a channel × type grid: in-app and email columns, one row per notification type. A master mute toggles the whole grid; mandatory rows (security events, billing) are starred and require at least one channel.

DPA acceptance at workspace creation

Every new workspace now requires explicit acceptance of the Data Processing Addendum at sign-up, with the accepted version, timestamp, and accepting user captured on the tenant row. The acceptance event appears as a TENANT/dpa_accepted entry in Settings → Activity alongside the workspace’s creation event.

This backs the public commitment we made when we launched trust.sagapm.io and sagapm.io/dpa — every new tenant is now provably bound to a specific DPA version at sign-up.

Improvements

Form primitives standardized on bits-ui

The radio group picks up a small UX upgrade in the process: the original markup had no card-level selected state, so the only signal was the radio dot itself. Selected radio cards now highlight the border and add a faint primary tint, which is much clearer in the Jira import wizard’s structure and subtask pickers.

Fixes

  • Relate picker dropped display-ID hits. Typing id-52 into the relate picker on an entity detail page returned 0 results, even when the target existed and the backend matched it. The picker now matches the command palette’s behavior; the two surfaces share one search contract again.
  • Improved description readability. Read-only entity descriptions were rendering adjacent paragraphs 4px apart — a bit too tight, resulting in multi-paragraph descriptions reading as a wall of text. Paragraph margins bumped from 0.25rem to 0.75em, with first/last-child resets so single-paragraph descriptions stay flush with their container and look unchanged.

A new release cadence

Up to v0.9.1 we shipped on a rolling nightly-to-prod cadence — every commit on main rolled to production automatically, with version bumps done by hand. Our release and documentation process is maturning so no-more nightly main branch deploys, instead a more controlled and deliberate release process.

1.16.0 Tag Management, Cycle Reliability, and a Steadier App

This release focuses on refinements and bug fixes with one headline feature: Improved Tag Management. New features Improved tag management Settings → Tags is now a full management surface rather than a flat list. Tags are split into two sections — Key/Value Pairs (collapsible groups; auto-collapsed once a key has 3+…

Read more

This release focuses on refinements and bug fixes with one headline feature: Improved Tag Management.

New features

Improved tag management

Settings → Tags is now a full management surface rather than a flat list. Tags are split into two sections — Key/Value Pairs (collapsible groups; auto-collapsed once a key has 3+ values) and Single Keys — and each tag shows a usage count so you can tell what’s actually load-bearing.

Two new admin/owner-only operations cover the common cleanup needs: rename a key (e.g. area:domain:) propagates to every entity carrying that key in one transaction, and delete a key removes the whole family. Per-key advisory locks serialize concurrent renames; collisions and a 50,000-row safety threshold are surfaced explicitly rather than running quietly to completion.

The native browser color picker is gone too. A curated 36-swatch palette (12 hues × 3 tints) replaces it, and tag chips now render as a colored dot + neutral chip + foreground text — so labels stay readable regardless of the swatch. The fix resolves a saga-pm report that “Add tags” text was hard to read on every theme.

Cycles stop hiding records

Two cycle-planning gaps are closed in this release.

Backlog promotion at cycle start. When you start a cycle, any records you’d assigned to it that were still BACKLOG now auto-promote to TODO in the same transaction. Previously, BACKLOG-in-cycle was counted in the swimlane header but invisible on the board (which only renders TODO / IN_PROGRESS / IN_REVIEW / DONE). Bringing a record into a cycle is a clear intent — it should reach a status the board can show.

Full state on the cycle planner. The cycle column on the planner inherited the backlog’s status filter, so DONE records assigned to active cycles silently disappeared from the planner view. The cycle column now sources directly from the cycle’s records — including DONE — so you see the full state of the work you committed to.

Lookahead on manual create. When you manually create a cycle, the configured lookahead (default 3) now spawns the future PLANNED cycles automatically. Previously this only fired on cycle complete or cancel, leaving manually-bootstrapped workspaces stuck with a single cycle visible.

Faster jumping in the command palette

The palette has long supported direct lookup like RC-42 to jump to a record. Two upgrades:

  • Short-prefix listing. Typing just gl-, pj-, rc-, id-, or ml- (with the dash, no digits) now lists up to 50 of the most-recent entities of that type, ordered by display ID descending — useful for “the goal I just made” workflows.
  • OS-aware shortcut hint. The hotkey label shows ⌘K on Apple OSes and Ctrl+K on Windows/Linux. The handler always accepted both; this fixes a display gap.

Improvements

Detail-page layout

The properties sidebar widens from 320px to 384px so longer team names, owners, and check-in metadata fit without truncation, and the attachments grid moves from 2 columns to 3 in the non-compact view. The biggest change: the Related entity-link field moves out of the cramped properties sidebar into its own section directly below, mirroring the Similar Entities panel. Hover-reveal delete and an always-visible + picker replace the old inline UI. Project Owners are now editable from the project sheet too, matching the long-standing Goal Owners affordance.

Gantt timeline polish

The project timeline picks up a stack of alignment fixes:

  • Month-aligned primary gridlines; week ticks suppressed at year/quarter/month zooms.
  • Year zoom narrowed from 18 to 12 months so a calendar year fits the visible window.
  • Today badge nudged inside the visible header so it doesn’t clip on the top edge.
  • Project titles now render alongside the PJ-# chip inside the bar at non-year zooms.

Plus a new month-header detail: months that start a quarter (Jan, Apr, Jul, Oct) prepend a bold Q1· / Q2· / Q3· / Q4· label, so quarter boundaries read at a glance without a second header tier.

Stable attachment URLs

Attachment.url previously returned a 5-minute presigned S3 URL. When users copy-pasted images between descriptions, the URL got persisted into stored content and started 403’ing minutes later. The resolver now returns a stable tenant-scoped proxy URL that signs a fresh presigned URL on each request and 302-redirects to S3, so byte transfer still goes browser ↔ S3 directly.

The editor also sanitizes HTML clipboard payloads on paste: pre-cutover content with presigned URLs is rewritten silently, and <img> tags pointing at another workspace are stripped with a clear toast — a small defense against accidental cross-workspace leaks.

Record team picker

The record properties panel was missing the Team picker entirely, meaning records couldn’t be moved onto restricted teams from the UI. The picker is now wired up everywhere goals and projects had it, with the same restricted-team and limited-team visibility hints. Private-team isolation now applies to records as well as goals and projects.

The new-idea dialog (and any other modal with long content) now scrolls inside a 90vh cap, so the save and cancel buttons stay reachable regardless of description length. Previously, pasting a long brief into a new idea could push the action buttons off-screen.

Admin trial controls

Admins can now see and adjust the trial length on demo tenants from the admin portal — both during creation (default 14 days, customizable) and afterward via a “set remaining days” control on the tenant detail page. The path also closes a bug where admin-created demo tenants shipped with no trial_ends_at set, suppressing the in-app trial banner.

Fixes

  • API token scopes. 33 GraphQL mutations were unclassified and silently fell through to the settings scope, blocking write-scoped API tokens from making basic entity edits like createRelationship and submitFeedback. Every mutation is now classified, and a schema-walking lint test prevents the regression class entirely going forward. Heads-up: 12 billing and workspace-creation mutations move to cookie-only as the correct security posture — API tokens with settings scope can no longer trigger them.
  • Sidebar team selector is no longer hidden when a workspace has only one team — the “All Teams” entry-point is back.
  • Inspire form attachments now render in-line within the embedded editor, completing the 1.15.0 idea-promotion polish.
  • HotKey help popover guard the hotkey help popover is keyed to ’?’ which was guarded against in inputs and text areas, but got missed for the TipTap editor. This resulted in the “helpful” popover obscuring the screen everytime anyone tried to type a ’?’ into a description or comment.

1.15.0 Idea promotion: Content Carryover & Multi-Target Inspirations

Following on from the Inspirations rework in 1.13.0, this release fills out the rest of the idea-promotion workflow. Inspiring an idea now seeds the new or existing entity (Goal, Project, or Record) with the idea's description and attachments. New features Content and attachments carry over When you inspire one or…

Read more

Following on from the Inspirations rework in 1.13.0, this release fills out the rest of the idea-promotion workflow. Inspiring an idea now seeds the new or existing entity (Goal, Project, or Record) with the idea’s description and attachments.

New features

Content and attachments carry over

When you inspire one or more ideas into a new or existing Goal, Project, or Record, each idea appends its description and attachments to the tail of the target’s description. For new entities, the appended details appear below the template, so the team’s preferred formatting is maintained.

Inspire form linking ideas ID-2 and ID-5 to GL-3, with "Append idea content" toggled on so the goal&#x27;s description merges in each idea&#x27;s body and attachment

Behind the scenes, attachment storage is now reference-counted, so the same file can live on multiple entities without duplication, and a daily background sweep cleans up anything that’s truly orphaned.

One idea, many destinations

An idea no longer has to pick a single home. The same idea can now inspire a goal and a record, or two different projects, or any other combination — useful when one piece of input genuinely belongs in multiple places.

Inspirations show up on the target, too

Goal, Project, and Record detail pages now have an Inspirations section listing the ideas that, well, inspired them. Until now this link was only visible from the idea side; making it bidirectional means you can choose to not include the content from ideas directly in the description of the new entity while maintaining a single click to the full details of the original inspiration should you want to reference it.

Improvements

Permission-aware inspire picker

The inspiration form now hides goals, projects, and records you don’t have permission to edit, so you can’t pick a target only to be rejected on submit. Server-side authorization remains the source of truth — the picker filter is purely a UX improvement on top of it.

Fixes

  • Attachments such as images now correctly appear in-line within the idea inspiration form.

1.14.0 Jira Import (beta)

You can now easily migrate Jira Cloud projects into Saga PM. Connect your Atlassian workspace, pick a project, walk through a short mapping wizard, and watch the import populate goals, projects, records, comments, and attachments live. If anything looks off, you can cancel mid-run or fully roll back the import in one…

Read more

You can now easily migrate Jira Cloud projects into Saga PM. Connect your Atlassian workspace, pick a project, walk through a short mapping wizard, and watch the import populate goals, projects, records, comments, and attachments live. If anything looks off, you can cancel mid-run or fully roll back the import in one click.

Jira import is shipping as Beta while we iterate on edge cases with early users. The core path has been validated, but if you encounter quirks, please submit feedback; we’d love to hear about them.

New features

Jira integration setup screen with the OAuth credentials form open

Connect your Atlassian workspace

Open Settings → Integrations → Jira and follow the OAuth flow. Saga PM acts as a per-tenant Atlassian app: each workspace registers its own OAuth 2.0 (3LO) app in the Atlassian Developer Console, pastes the client ID and secret, and connects. From there you’ll see every Jira site your account can reach, with a quick Refresh affordance if you’ve added new sites since.

We never store your Atlassian password — Saga PM only holds an encrypted refresh token, scoped to read access on Jira work and users.

A wizard to demystify the mapping process

Saga PM has similarities to Jira, but some core differences in entity hierarchy, labels, and fields require decisions on how to map your data to Saga PMs conventions. Saga PM breaks this mapping process down into a few different concrete steps.

  1. Project & Date window — pick the Jira project and the date range to import.
  2. Structure — choose how initiatives & epics from Jira map to goals, projects, and milestones in Saga PM.
  3. Teams — map Jira spaces to Saga PM teams.
  4. Issue types — decide how Jira work types map to Saga PM record types.
  5. Subtasks — choose between flattening the hierarchy but preserving the relationship or documenting sub-tasks in the record description.
  6. Attachments — opt in or out, with a per-attachment size cap.
  7. Advanced options — (coming soon) more fine-grained control over more nuanced mappings and options.
  8. Review — preview the import before starting to ensure everything looks correct.

Every step is reversible and the entire import can be cancelled or rolled back at any time.

Live progress, cancel, and rollback

Once an import is running you’ll see entity counts updating in real time — fetch, transform, persist, and attachment phases each report progress as they go. If you spot a problem, Cancel stops the run cleanly; if it’s already finished and you don’t like the result, Rollback removes everything the import created and leaves your workspace exactly as it was before.

Attachments come along for the ride

Opt in to attachment import and Saga PM will stream files directly from Jira into the workspace’s storage, preserving the original uploader and timestamp. Files larger than your configured size cap are skipped with a clear note in the import summary, so you can decide whether to bring them over manually.

A provenance trail on every imported entity

Every imported goal, project, and record links back to its Jira source — the originating issue key, a clickable link to the Jira issue, and a short comment explaining when it was imported and by whom. If you ever need to trace a Saga PM record back to its Jira origin, it’s one click away.

What’s next

Beta means we’re actively iterating. Coming up:

  • Custom field mapping — bring your Jira custom fields onto Saga PM fields directly
  • Data export - export data to CSV, JSON, or XML

If you try the import and hit something rough, the in-app feedback widget routes straight to the team — please send notes.

1.13.0 Entity relationships, richer activity feed, and Inspirations

You can now connect work across the hierarchy with explicit relationships — call out what blocks what, mark duplicates, and group items that simply belong together. The activity feed has been rebuilt on a new event foundation that surfaces a much wider set of changes, and the "Linked Entities" section on Ideas has…

Read more

You can now connect work across the hierarchy with explicit relationships — call out what blocks what, mark duplicates, and group items that simply belong together. The activity feed has been rebuilt on a new event foundation that surfaces a much wider set of changes, and the “Linked Entities” section on Ideas has been renamed (and refactored) to Inspirations.

New features

Same-level relationships between entities

Goals, projects, milestones, records, and ideas can now reference each other through three relationship types:

  • Blocks / Blocked by — asymmetric. Use it when one item can’t move forward until another lands.
  • Duplicates / Duplicated by — asymmetric. Use it when one item supersedes another.
  • Relates to — symmetric. Use it for loose, “see also” connections.

Relationships live in a new Related block in the entity properties sidebar. Click the picker to search for a peer of any supported type — the popover scopes to the relationship type you chose so you can’t accidentally point a “blocks” at something that doesn’t make sense.

When you mark something as blocked, the blocked entity’s owners and assignees get a notification. The activity feed shows the relationship from both sides — “marked this as blocks X” on one entity, “marked X as is blocked by this” on the other — so context isn’t lost no matter which side you’re looking at.

Inspirations on Ideas

The section formerly known as Linked Entities on Idea detail pages is now Inspirations. Beyond the rename, the underlying link model was rebuilt so an inspiration can point at a Goal, a Project, or a Record directly — no more flat denormalized references — which makes the link richer and easier to follow.

Improvements

Activity feed: more event types, more detail

The activity feed has moved off the original four-action event log onto a new foundation that can capture a much wider set of events. Today that means relationship changes show up inline with the rest of an entity’s history; in upcoming releases the same pipeline will surface integration imports (Jira and friends) and automation actions, all rendered through a consistent UI.

The renderer is registry-based, so new event kinds will appear in the feed as soon as they’re emitted — no migration required on existing entities.

1.12.0 Goals & projects list polish — owners, icons, and faster charts

This release wraps up a round of UX polish across the goals and projects surfaces. The changes are incremental but meaningfully improve scannability — you can now tell at a glance who owns a goal and what kind of project you're looking at without opening the detail page. Improvements Owner avatars and type icons in…

Read more

This release wraps up a round of UX polish across the goals and projects surfaces. The changes are incremental but meaningfully improve scannability — you can now tell at a glance who owns a goal and what kind of project you’re looking at without opening the detail page.

Improvements

Owner avatars and type icons in lists

Goals and project list rows now display the owner’s avatar and a small icon indicating the item type (goal, key result, project). Both are inline in the row, so dense lists stay compact while adding enough signal to navigate without reading every title.

Goals list showing owner avatars and type icons inline

Smoother chart tooltips

The charting library (layerchart) was pinned to 2.0.0-next.53 and migrated to its new tooltip API. Hover states on cycle progress and goal rollup charts are now noticeably crisper — tooltips appear with less jitter and don’t clip at panel edges.

Fixes

  • Resolved an issue where the vertical lines on the project Gantt chart seamed to appear in the wrong place. This was due to an issue where the label was positioned on the first day of the month and the line was the first Monday of the month.

1.11.0 Invite emails, in-app feedback, and support channels

Two things that make Saga PM easier to adopt as a team: invites now arrive in email rather than requiring a link share, and there's a direct feedback channel from inside the app. We also shipped a round of auth hardening and tenant polish under the hood. New features Team invite emails When you invite a teammate from…

Read more

Two things that make Saga PM easier to adopt as a team: invites now arrive in email rather than requiring a link share, and there’s a direct feedback channel from inside the app. We also shipped a round of auth hardening and tenant polish under the hood.

New features

Team invite emails

When you invite a teammate from the Members settings, they now receive an email with a direct accept link. No more copy-pasting invite URLs. Emails are delivered via Postmark with a clean transactional template that matches the Saga PM brand.

In-app feedback and support

A feedback button in the app shell opens a panel where you can send a message directly to the team. For urgent issues you can also reach us via the support channel linked in the panel. We read everything.

Improvements

Auth hardening

Several hardening fixes landed across the authentication flow: stricter session validation, improved OIDC error messages, and better handling of expired sessions that redirect cleanly to login instead of showing a blank screen.

Tenant polish

Tenant provisioning is faster and more resilient. A handful of edge cases around schema initialization were fixed, and the admin console shows clearer status during setup.

Fixes

  • Password recovery flow now works end-to-end in production (Postmark integration was missing from the worker config — now set)
  • Fixed a race condition in tenant middleware that could 500 on the first request after a cold start

1.10.0 Billing and seat management

The billing and seat management milestone is complete. Workspace admins have a self-service billing console, and seat limits are now enforced — the app won't let you exceed the seats you've paid for. New features Self-service billing console A new Billing section in the admin console connects to Stripe. From there you…

Read more

The billing and seat management milestone is complete. Workspace admins have a self-service billing console, and seat limits are now enforced — the app won’t let you exceed the seats you’ve paid for.

New features

Self-service billing console

A new Billing section in the admin console connects to Stripe. From there you can:

  • View your current plan and seat count
  • Add or remove seats
  • Update your payment method
  • Download past invoices

Billing is handled by Stripe; Saga PM stores only the Stripe customer ID and subscription ID — no raw card data.

Seat enforcement

When your workspace reaches its seat limit, new members can’t join until a seat is freed or you add more. Existing members are never locked out mid-session — enforcement applies at the invite and login stages. Admins see a clear indicator in the Members page when seats are nearly full.

Public API tokens

Workspace admins can generate long-lived API tokens for programmatic access. Tokens are scoped to the workspace, authenticate via Authorization: Bearer, and appear in the audit log. Useful for CI integrations and custom dashboards.