Augments (data that survives re-syncs)
Synced provider data and your own judgments have different lifecycles. A re-sync must be free to overwrite provider data wholesale — names, statuses, dates, custom fields, and prioritization derived from provider custom fields via fieldmap — so the store always mirrors the source. But locally-authored prioritization and planning data must not be lost when that happens.
The augment package and item_augments table solve this: augments are
stored separately from synced items, keyed by the source system's stable
reference — e.g. an Aha reference number like MYPROJ-123 — and the sync
engine never touches them. Reads overlay augments onto items, with augment
values winning.
| Layer | Written by | On re-sync |
|---|---|---|
items table |
omniroadmap sync (provider data + fieldmap) |
Overwritten |
item_augments table |
You (augment set, store.SetItemAugment) |
Untouched |
What an augment holds
| Field | Meaning |
|---|---|
moscow |
must_have | should_have | could_have | wont_have |
kano |
must-be | performance | attractive | indifferent | reverse | questionable |
rice |
RICE components (reach, impact, confidence, effort, score). Set components override same-name synced/fieldmap components; unset ones shine through |
okr_refs |
Links to OKR documents/objectives (e.g. prism-roadmap objective IDs) |
notes |
Free text |
metadata |
Anything else; surfaces on the item's Metadata prefixed augment. |
CLI
# Set fields (merges with any existing augment for that ref):
omniroadmap augment set --provider aha-studio --ref MYPROJ-123 \
--moscow must_have --kano performance --effort 2 \
--okr OKR-2026-Q3-01 --notes "exec ask"
# Inspect the augment layer alone:
omniroadmap augment get --provider aha-studio --ref MYPROJ-123
omniroadmap augment list
# Read the merged item (synced data + augment overlay):
omniroadmap item get MYPROJ-123
# Clear one field / remove the whole augment:
omniroadmap augment set --provider aha-studio --ref MYPROJ-123 --moscow ""
omniroadmap augment rm --provider aha-studio --ref MYPROJ-123
augment set and augment rm each finish with a Dolt commit, so the
augment history is versioned alongside sync history (dolt log).
Library
import (
"github.com/grokify/omniroadmap/augment"
"github.com/grokify/omniroadmap/store"
)
s, _ := store.New(store.DefaultDSN())
// Write local judgments:
err := s.SetItemAugment(ctx, augment.ItemAugment{
Provider: "aha-studio",
SourceRef: "MYPROJ-123",
MoSCoW: "must_have",
Kano: "performance",
})
// Reads overlay augments by default:
item, err := s.GetItem(ctx, "aha-studio", "MYPROJ-123")
// Raw synced data, no overlay:
items, err := s.ListItems(ctx, store.ItemFilter{
Provider: "aha-studio",
WithoutAugments: true,
})
augment.Apply(items, augs) is also usable standalone against items from
any source (a live provider, an export pipeline) — matching is by
(Provider, SourceRef) with a fallback to SourceID for providers
without human-facing refs (e.g. ProductBoard UUIDs).
Precedence
For any one field on a read item:
- Augment value, when set — hand-authored wins.
- Fieldmap-derived value stored at sync time (from provider custom fields).
- Unset.
RICE merges per component: an augment that sets only effort overrides
effort while fieldmap-derived reach shines through.
Fields with no canonical Item slot
okr_refs, notes, and metadata have no first-class field on the
canonical Item; after Apply they surface in Item.Metadata under
augment.okr_refs, augment.notes, and augment.<key>.
Note: prism-roadmap export currently carries
MoSCoW and RICE into rmi.RoadmapItem; Kano has no RMI field yet and
stays on the canonical Item.