from @unified-product-graph/sdk
The high-level programmatic client for reading and writing .upg product knowledge graphs. Constructs over a single file, namespaces node and edge operations under .nodes / .edges, and persists to disk after each successful mutation.
new UPGClient(options: UPGClientOptions)
Builds a client bound to one .upg file. The file is not read until the first operation runs (lazy by default).
import { UPGClient } from '@unified-product-graph/sdk'
const upg = new UPGClient({ file: './product.upg' })The constructor does not create the file. If ./product.upgdoesn’t exist, the first read or write throws ENOENT. Scaffold one first with npx @unified-product-graph/cli init ./product.upg --title “My Product”. (A single-call UPGClient.init() factory is planned.)
load(): Promise<void>
Explicitly reads and parses the file. Called automatically by every operation if the client hasn’t loaded yet. Call it directly only if you want to surface ENOENT or parse errors at startup.
flush(): Promise<void>
Persists pending in-memory state to disk. Every mutation flushes automatically, so this is rarely needed.
close(): Promise<void>
Flushes and releases the file handle. Call before your process exits if you’ve done long-lived work.
create(args: CreateNodeArgs): Promise<{ node, edge? }>Creates a typed node. If parent_id is provided, an auto-parent edge is created and returned alongside the node.
const { node } = await upg.nodes.create({
type: 'feature',
title: 'Dark mode',
})
console.log(node.id) // 'n_Kg19aubWwbwm7V5t'Return shape note: create() returns { node, edge? }, not the node directly. Destructure.
list(options?: NodeListOptions): Promise<{ nodes, total }>Lists nodes. Optional filters: type, parent_id, status, tags.
const { nodes, total } = await upg.nodes.list({ type: 'feature' })
console.log(total, nodes.length)Return shape note: list() returns { nodes, total }, not a bare array. Use result.nodes for the array, result.total for the unfiltered count.
get(id: string): Promise<UPGBaseNode | undefined>
Returns the node or undefined. Does not throw on missing.
update(id: string, patch: Partial<UPGBaseNode>): Promise<UPGBaseNode>
Shallow-merges patch into the existing node and persists.
delete(id: string): Promise<void>
Removes the node. Edges with this node as source or target are removed as well to keep the graph well-formed.
connect(sourceId: string, targetId: string, opts?: Partial<CreateEdgeArgs>): Promise<UPGEdge>
Creates an edge between two existing nodes. If opts.typeisn’t provided, the canonical edge type is inferred from the source and target entity types via the catalog.
const edge = await upg.edges.connect(persona.id, job.id)
// type inferred → 'persona_pursues_job'list(options?: EdgeListOptions): Promise<UPGEdge[]>
Lists edges, filterable by source, target, or type. Returns an array directly (unlike nodes.list).
delete(id: string): Promise<void>
Removes a single edge.
health(): Promise<HealthResult>
Computes a structural health score (0–10) plus a digest of node + edge counts. Useful as a CI gate to keep a long-running graph from rotting.
const { score, digest } = await upg.health()
// → { score: 8, digest: { nodes: 42, edges: 73, ... } }search(query: string, options?: SearchOptions): Promise<SearchResult[]>
Fuzzy title + description match across all nodes. Cheap.
verify(): Promise<ValidationReport>
Runs the schema validator and the anti-pattern catalogue. Use before persisting any batch write from an adapter or migration.
diff(ref: string): Promise<never>
Not yet implemented. Currently throws. Planned alongside the broader ergonomics work.
interface UPGClientOptions {
file: string // path to .upg
lazy?: boolean // defer load() until first op (default true)
}
interface NodeListOptions {
type?: string
parent_id?: string
status?: string
tags?: string[]
}
interface EdgeListOptions {
source?: string
target?: string
type?: string
}
interface HealthResult {
score: number // 0–10
digest: Record<string, number>
}
interface SearchOptions {
limit?: number // default 10
}UnknownEntityTypeErrorThrown by nodes.create when type is not in the canonical catalog. Includes the offending type name and a list of close matches.
ENOENT (raw)Thrown by the first read or write if the underlying file doesn’t exist. Scaffold with the CLI (see Constructor note above). A friendlier wrapper is planned.
The SDK re-exports the lower-level helpers from @unified-product-graph/corefor advanced consumers: adapter authors, validator builders, anyone writing tooling that doesn’t need a live client instance.
Browse them under the Core primitives section of the sidebar: catalog, shapes, registry, grammar, properties, presentation, intelligence, playbooks, approaches, regions.