Documentation
¶
Overview ¶
Package design implements Pando's Design Studio: HTML/CSS/JS design artifacts that agents build, render, inspect and iterate on.
An artifact is a directory in the user's working tree (designer/<slug>/ by default) holding an entry document, its assets and a portable pando-design.json manifest. Agents mutate those files with the regular write/edit tools, so permissions, diffs and agent-vcs keep working unchanged.
History is not a copy-per-version store: each accepted iteration takes a directory-scoped snapshot (internal/snapshot), so checking out an old version can never revert work outside the artifact directory. SQLite holds only the metadata needed to list and navigate artifacts.
Index ¶
- Constants
- Variables
- func BlendScore(audited, written float64) float64
- func BundledTemplateContent(name string) (string, bool)
- func CloseDefaultProvider()
- func ClosePreviewServer()
- func ContrastRatio(foreground, background RGB) float64
- func CountsBySeverity(issues []Issue) map[string]int
- func CraftReference(name string) (string, bool)
- func CraftReferenceNames() []string
- func EnsurePreviewServer() (*preview.Server, error)
- func Events() *pubsub.Broker[Event]
- func ExampleSystem(name string) (string, bool)
- func ExampleSystemNames() []string
- func ExampleSystemTitle(name string) string
- func InstallBundle(name, targetDir string, force bool) ([]string, error)
- func MirrorPath(name string) string
- func NewArtifactID() string
- func NewCritiqueID() string
- func NormalizePolicy(policy string) string
- func ParseSelectionURI(uri string) (string, bool)
- func PreviewOptions(baseURL func() string, access func() error) preview.Options
- func PreviewServer() *preview.Server
- func PromptConstraints() string
- func RuleCodes(issues []Issue) []string
- func Scaffold(name, title string) (map[string]string, error)
- func SelectionURI(nodeID string) string
- func SetDefaultProvider(p *Provider)
- func SetPreviewServer(s *preview.Server)
- func Slugify(title string) string
- func SortedTokenGroups(tokens map[string]map[string]string) []string
- func SortedTokenNames(values map[string]string) []string
- func ValidKind(k Kind) bool
- func WriteManifest(absDir string, m Manifest) error
- type ApplyResult
- type Artifact
- type AuditInput
- type AuditResult
- type BrowserAutoOpener
- type BrowserOptions
- type ConsoleEntry
- type CreateParams
- type Critique
- type CritiqueOptions
- type CritiqueReport
- type CritiqueSettings
- type DeckSpec
- type DesignSystem
- type ErrAmbiguousRef
- type Event
- type ExportOptions
- type ExportResult
- type ExtractOptions
- type ExtractResult
- type ExtractSource
- type GateDecision
- type ImageDiff
- type InspectOptions
- type InspectResult
- type Issue
- type Kind
- type Layout
- type Manifest
- type NetworkFailure
- type Node
- type NodeFacts
- type PatchChange
- type PatchFilePlan
- type PatchOp
- type PatchPlan
- type Presentation
- type PreviewSpec
- type PrintOptions
- type Provider
- type RGB
- type Rect
- type RenderOptions
- type RenderResult
- type Renderer
- func (r *Renderer) Available() bool
- func (r *Renderer) Close()
- func (r *Renderer) EntryURL(a Artifact) (string, error)
- func (r *Renderer) PrintPDF(ctx context.Context, a Artifact, opts PrintOptions) ([]byte, error)
- func (r *Renderer) Rasterize(ctx context.Context, html string, width, height int, wait time.Duration) ([]byte, error)
- func (r *Renderer) Render(ctx context.Context, a Artifact, opts RenderOptions) (RenderResult, error)
- func (r *Renderer) Screenshot(ctx context.Context, a Artifact, opts ScreenshotOptions) ([]byte, error)
- func (r *Renderer) SlideBreaks(ctx context.Context, a Artifact, opts RenderOptions) ([]SlideBreak, error)
- type ScreenshotOptions
- type Service
- func (s *Service) AbsDir(a Artifact) (string, error)
- func (s *Service) ApplyPatchPlan(ctx context.Context, plan *PatchPlan, summary string, commit bool) (int, error)
- func (s *Service) ApplySystem(ctx context.Context, artifactID string) (ApplyResult, error)
- func (s *Service) Checkout(ctx context.Context, artifactID string, number int) error
- func (s *Service) CommitVersion(ctx context.Context, artifactID, summary string) (Version, error)
- func (s *Service) ContractPath() string
- func (s *Service) Create(ctx context.Context, p CreateParams) (Artifact, error)
- func (s *Service) Critique(ctx context.Context, artifactID string, opts CritiqueOptions) (CritiqueReport, error)
- func (s *Service) CritiqueSettingsFor(skillID string) CritiqueSettings
- func (s *Service) Delete(ctx context.Context, artifactID string) error
- func (s *Service) Diff(ctx context.Context, artifactID string, from, to int) ([]snapshot.DiffEntry, error)
- func (s *Service) Export(ctx context.Context, artifactID string, opts ExportOptions) (ExportResult, error)
- func (s *Service) ExtractSystem(ctx context.Context, opts ExtractOptions) (ExtractResult, error)
- func (s *Service) Get(ctx context.Context, id string) (Artifact, error)
- func (s *Service) Inspect(ctx context.Context, artifactID string, version int, opts InspectOptions) (InspectResult, error)
- func (s *Service) LatestCritique(ctx context.Context, artifactID string, version int) (Critique, error)
- func (s *Service) Layout() Layout
- func (s *Service) List(ctx context.Context, sessionOnly bool) ([]Artifact, error)
- func (s *Service) LiveURL(ctx context.Context, artifactID string, slide int) (Presentation, error)
- func (s *Service) LoadSystem() (DesignSystem, bool, error)
- func (s *Service) MirrorSystem(ctx context.Context, ds DesignSystem, source ExtractSource, target string) (string, error)
- func (s *Service) Node(ctx context.Context, artifactID string, version int, nodeID string) (Node, error)
- func (s *Service) Patch(ctx context.Context, artifactID string, ops []PatchOp, summary string, ...) (*PatchPlan, int, error)
- func (s *Service) PreparePatch(ctx context.Context, artifactID string, ops []PatchOp) (*PatchPlan, error)
- func (s *Service) Presentation(ctx context.Context, artifactID string, slide int, nodeID string) (Presentation, error)
- func (s *Service) PublishPreview(ctx context.Context, artifactID string) (preview.Grant, error)
- func (s *Service) Render(ctx context.Context, artifactID string, opts RenderOptions) (RenderResult, error)
- func (s *Service) Renderer() *Renderer
- func (s *Service) Resolve(ctx context.Context, ref string) (Artifact, error)
- func (s *Service) SaveSystem(ds DesignSystem) (string, string, error)
- func (s *Service) SetSystemTokens(name string, updates map[string]map[string]string) (DesignSystem, error)
- func (s *Service) Store() *Store
- func (s *Service) SystemRelPath(file string) string
- func (s *Service) Versions(ctx context.Context, artifactID string) ([]Version, error)
- func (s *Service) WithMirror(m SystemMirror) *Service
- func (s *Service) WithRenderer(r *Renderer) *Service
- func (s *Service) WriteWorkspaceFile(rel string, data []byte) (string, error)
- type SlideBreak
- type Snapshotter
- type Store
- func (s *Store) AddCritique(ctx context.Context, c Critique) (Critique, error)
- func (s *Store) AddVersion(ctx context.Context, v Version) error
- func (s *Store) CreateArtifact(ctx context.Context, a Artifact) (Artifact, error)
- func (s *Store) DeleteArtifact(ctx context.Context, id string) error
- func (s *Store) GetArtifact(ctx context.Context, id string) (Artifact, error)
- func (s *Store) GetArtifactByDir(ctx context.Context, dir string) (Artifact, error)
- func (s *Store) GetNode(ctx context.Context, artifactID string, version int, nodeID string) (Node, error)
- func (s *Store) GetVersion(ctx context.Context, artifactID string, number int) (Version, error)
- func (s *Store) LatestCritique(ctx context.Context, artifactID string, version int) (Critique, error)
- func (s *Store) ListArtifacts(ctx context.Context, sessionID string) ([]Artifact, error)
- func (s *Store) ListNodes(ctx context.Context, artifactID string, version, slide int) ([]Node, error)
- func (s *Store) ListVersions(ctx context.Context, artifactID string) ([]Version, error)
- func (s *Store) ReplaceNodes(ctx context.Context, artifactID string, version int, nodes []Node) error
- func (s *Store) SetCurrentVersion(ctx context.Context, artifactID string, number int) error
- func (s *Store) UpdateArtifact(ctx context.Context, a Artifact) error
- type SystemFinding
- type SystemMirror
- type Template
- type TemplateSource
- type Version
- type Viewport
Constants ¶
const ( RuleImageAlt = "a11y.image-alt" RuleControlName = "a11y.control-name" RuleHeadingOrder = "a11y.heading-order" RuleMissingH1 = "a11y.missing-h1" RuleContrast = "a11y.contrast" RuleTapTarget = "a11y.tap-target" RuleDocumentTitle = "a11y.document-title" RuleConsoleError = "runtime.console-error" RuleNetworkFailure = "runtime.network-failure" RuleHorizontalOverflow = "layout.horizontal-overflow" RuleEmptyDocument = "layout.empty-document" RuleDeckNoSlides = "deck.no-slides" RuleDeckPageBreak = "deck.page-break" RuleSystemUnlinked = "system.unlinked" RuleSystemHardcoded = "system.hardcoded" )
Audit rule codes. They are stable identifiers: an issue travels to the UI, to the agent and into the critique history, and all three need to be able to group and suppress findings by something other than their prose.
const ( // PolicyNone scores and reports but never blocks. It is for artifacts // where the brief is exploratory and an iteration budget is waste. PolicyNone = "none" // PolicyStandard gates on the score alone. PolicyStandard = "standard" // PolicyStrict also refuses to pass while any error-level finding remains, // and holds the score to a higher bar. PolicyStrict = "strict" )
Critique policies. A policy decides how hard the gate is, not what the audit looks for: every rule runs under every policy, so the issue list a user reads is the same one either way.
const ( // EventCreated fires once, when an artifact directory is materialised. EventCreated = "design.created" // EventVersion fires when an iteration is committed, which is what a // version timeline and a thumbnail strip listen for. EventVersion = "design.version" // EventRender fires after a successful render, carrying the fresh node // count so an open preview knows to reload. EventRender = "design.render" // EventCritique fires when a critic pass scores a version (P8). EventCritique = "design.critique" )
Event kinds published by the design subsystem. They are the names the SSE stream carries, so surfaces can switch on them directly.
const ( ExportHTML = "html" ExportPNG = "png" ExportPDF = "pdf" )
Export formats supported in v1. Anything richer (Figma, video, sprite sheets) is deliberately out of scope.
const ( SeverityInfo = "info" SeverityWarning = "warning" SeverityError = "error" SeverityBlocking = "blocking" )
Issue severities produced by the critic and the accessibility pass.
const ( OpSetText = "set_text" // replace the element's children with escaped text OpSetHTML = "set_html" // replace the element's children with raw markup OpSetAttr = "set_attr" // add or update one attribute OpRemoveAttr = "remove_attr" // drop one attribute OpSetStyle = "set_style" // merge declarations into the inline style attribute OpAddClass = "add_class" // append a class if missing OpRemoveClass = "remove_class" // drop a class if present OpInsertHTML = "insert_html" // insert markup relative to the element OpReplaceHTML = "replace_outer" // replace the whole element OpRemove = "remove" // delete the whole element )
Patch operations. Each one targets a single element resolved by selector (or, through the node index, by the data-pando-id a render stamped on it).
const ( PositionBefore = "before" PositionAfter = "after" PositionPrepend = "prepend" PositionAppend = "append" )
Insert positions accepted by OpInsertHTML.
const ( // SystemTokensFile is the token source of truth. SystemTokensFile = "tokens.json" // SystemStylesheet is generated from the tokens. SystemStylesheet = "system.css" )
The shared design system lives in designer/_system/ and is a plain pair of files: tokens.json (the source of truth, committed and diffable) and the system.css it generates. Artifacts opt in by linking system.css, so a token change is a one-file edit that every artifact picks up on its next render.
const DefaultSlideSelector = "[data-slide], .slide, section.slide"
DefaultSlideSelector matches the slide containers a deck is expected to use.
const ManifestName = "pando-design.json"
ManifestName is the portable per-artifact manifest, committed with the files.
const (
// SystemContractFile is the prose half of the design system.
SystemContractFile = "DESIGN.md"
)
The design system is a contract, not a prompt. tokens.json is the machine half — the values the stylesheet and the constraint block are generated from. DESIGN.md is the human half: the rules a reviewer reads and the designer is held to. Both are committed, and the generated part of DESIGN.md is fenced by markers so regenerating it never destroys what a person wrote around it.
Variables ¶
var DefaultStyleProps = []string{
"display", "position", "color", "background-color",
"font-family", "font-size", "font-weight", "line-height",
"margin", "padding", "border-radius", "text-align",
}
DefaultStyleProps is the computed-style subset carried in the node index. It is deliberately short: the index is fed to a model, so every extra property costs tokens on every node.
var DefaultViewport = Viewport{W: 1440, H: 900}
DefaultViewport is the render size used when a manifest does not set one.
var ErrBundleInstalled = errors.New("design: template already installed")
ErrBundleInstalled reports that a skill of that name is already present.
var ErrNoBrowser = fmt.Errorf("design: no browser available")
ErrNoBrowser is returned when no Chromium-family browser can be resolved. Callers degrade gracefully: the live preview is the user's own browser, so a missing Chromium only costs screenshots, inspection, export and rasterizing.
var ErrNoIndex = errors.New("design: no structure index")
ErrNoIndex reports that an artifact exists but carries no structure index for the requested version, which only a render can produce.
var ErrNoProvider = errors.New("design: the design subsystem is not available in this process")
ErrNoProvider is returned by the tools when the design subsystem was never wired, which happens in stripped-down entry points that run without a database.
var ErrNotFound = errors.New("design: not found")
ErrNotFound is returned when an artifact, version or node does not exist.
var ErrSchemaOutdated = errors.New("design: database schema is outdated; the design tables are missing; restart Pando so pending migrations run")
ErrSchemaOutdated reports a database created before the design migrations ran.
Functions ¶
func BlendScore ¶
BlendScore combines the deterministic audit score with the critic's own. The deterministic pass cannot see whether a layout reads well and the critic cannot count contrast failures reliably, so neither is allowed to be the whole verdict. A critic that offers no score leaves the audit score standing.
func BundledTemplateContent ¶
BundledTemplateContent returns the raw SKILL.md of a bundled template, which is what the installer writes and what the gallery shows as "read the skill".
func CloseDefaultProvider ¶
func CloseDefaultProvider()
CloseDefaultProvider shuts the shared browser down at application exit.
func ClosePreviewServer ¶
func ClosePreviewServer()
ClosePreviewServer stops and forgets the process-wide preview server.
func ContrastRatio ¶
ContrastRatio returns the WCAG contrast ratio between a foreground and the surface behind it. A translucent foreground is composited over the background first: that is what the eye sees, and what the browser paints.
func CountsBySeverity ¶
CountsBySeverity summarises an issue list for a header line.
func CraftReference ¶
CraftReference returns one craft reference by name ("typography").
func CraftReferenceNames ¶
func CraftReferenceNames() []string
CraftReferenceNames lists the bundled craft references.
func EnsurePreviewServer ¶
EnsurePreviewServer returns the installed preview server, starting a loopback one if there is none. Surfaces that need a URL call it; nothing starts a listener merely because the design package was imported.
func Events ¶
Events returns the process-wide design event broker. It is created on first use so a process that never designs anything never allocates it.
func ExampleSystem ¶
ExampleSystem returns the prose of a bundled style guide.
func ExampleSystemNames ¶
func ExampleSystemNames() []string
ExampleSystemNames lists the bundled style guides, sorted for a stable listing in every surface that offers them.
func ExampleSystemTitle ¶
ExampleSystemTitle returns the first heading of a bundled guide, which is what a picker should show next to its name.
func InstallBundle ¶
InstallBundle writes a bundled template into a skills root as {targetDir}/{name}/SKILL.md plus the craft references it declares. It returns the paths written. Installing is what makes the bundle visible to the agent's skill loader; the gallery works without it.
It refuses to overwrite an existing skill unless force is set: the installed copy is the user's to edit, and silently replacing their edits with ours is the one thing an install must never do.
func MirrorPath ¶
MirrorPath is where a design system is mirrored in the knowledge base.
func NormalizePolicy ¶
NormalizePolicy maps a written policy onto a known one, returning "" for anything unrecognised so the caller can keep its own default rather than silently running a policy nobody asked for.
func ParseSelectionURI ¶
ParseSelectionURI extracts the node id from a selection reference.
func PreviewOptions ¶
PreviewOptions builds the options every preview server in this process shares. baseURL and access may be nil for the loopback fallback, which serves its own origin and is unreachable from the network by construction.
func PreviewServer ¶
PreviewServer returns the installed preview server, or nil.
func PromptConstraints ¶
func PromptConstraints() string
PromptConstraints returns the constraint block for the current project, or an empty string when the project has not committed a system. That still matters: a default system nobody chose is not a constraint worth stating.
func RuleCodes ¶
RuleCodes lists the rules that fired, worst-severity first, for a compact one-line summary.
func Scaffold ¶
Scaffold returns the seed files of a bundled template with the artifact title substituted, keyed by their path inside the artifact directory. A template with no scaffold returns an empty map and the caller falls back to the placeholder entry, which is still renderable.
func SelectionURI ¶
SelectionURI formats the selection protocol every surface speaks.
func SetDefaultProvider ¶
func SetDefaultProvider(p *Provider)
SetDefaultProvider installs the process-wide provider.
func SetPreviewServer ¶
SetPreviewServer installs the process-wide preview server. The API server calls it with an instance mounted on its own listener, so previews live on the Pando origin and inherit its bind address and its authentication.
func Slugify ¶
Slugify reduces a free-form title to a lowercase, hyphen-separated, filesystem-safe name. It never returns a path separator, a leading dot or a reserved name.
func SortedTokenGroups ¶
SortedTokenGroups and SortedTokenNames are the exported forms of the ordering every surface needs: a token table shown in a different order each time is unreadable, and the sort belongs here rather than in each renderer.
func SortedTokenNames ¶
SortedTokenNames returns the token names of a group in stable order.
func WriteManifest ¶
WriteManifest writes pando-design.json into an artifact directory. The file is committed with the artifact, so it is formatted for humans to read.
Types ¶
type ApplyResult ¶
type ApplyResult struct {
ArtifactID string `json:"artifact_id"`
System string `json:"system"`
// Stylesheet is the artifact-relative href of the linked stylesheet.
Stylesheet string `json:"stylesheet"`
// Linked is true when this call added the link, false when it was already
// there.
Linked bool `json:"linked"`
// Entry is the artifact-relative entry document.
Entry string `json:"entry"`
// Findings are hardcoded values a token already covers.
Findings []SystemFinding `json:"findings,omitempty"`
// Scanned counts the files audited.
Scanned int `json:"scanned"`
// Truncated is true when the finding list was cut short.
Truncated bool `json:"truncated,omitempty"`
}
ApplyResult reports what applying the system did and what it found.
type Artifact ¶
type Artifact struct {
ID string `json:"id"` // dsg_<hex>
SessionID string `json:"session_id,omitempty"`
ProjectID string `json:"project_id,omitempty"`
Title string `json:"title"`
Slug string `json:"slug"`
Dir string `json:"dir"` // project-relative, slash-separated
Kind Kind `json:"kind"`
SkillID string `json:"skill_id,omitempty"`
DesignSystemID string `json:"design_system_id,omitempty"`
CurrentVersion int `json:"current_version"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Artifact is the metadata record of a design artifact. The files themselves live in Dir, relative to the project working directory.
type AuditInput ¶
type AuditInput struct {
// Rendered reports that the browser half of the pass actually happened.
// Every accessibility, runtime, layout and deck rule reads a render, so
// with no render they must not run at all: firing "the document has no
// title" because nobody loaded the document is a finding about the audit,
// not about the artifact.
Rendered bool
Kind Kind
Viewport Viewport
Title string
Slides int
Width float64
Nodes []Node
Facts []NodeFacts
Console []ConsoleEntry
Failures []NetworkFailure
// Breaks is the per-slide print behaviour, filled only when the caller
// rendered under print emulation. Empty means the deck print rule is not
// evaluated at all, rather than evaluated and passed.
Breaks []SlideBreak
// SystemLinked reports whether the entry document links the design system
// stylesheet, and SystemFindings are the hardcoded values the P6 audit
// found. RequiresSystem turns the unlinked finding on: an artifact built
// from a template that declares no design system is not in breach.
SystemLinked bool
RequiresSystem bool
SystemFindings []SystemFinding
}
AuditInput is everything the deterministic quality pass reads. It is a plain struct rather than a service call so the rules can be tested against a hand-built render — no browser, no database, no project on disk.
type AuditResult ¶
type AuditResult struct {
Score float64 `json:"score"`
Summary string `json:"summary"`
Issues []Issue `json:"issues"`
// Counts is how many times each rule fired, including the occurrences that
// were folded away by maxIssuesPerRule.
Counts map[string]int `json:"counts,omitempty"`
}
AuditResult is one deterministic quality pass.
func Audit ¶
func Audit(in AuditInput) AuditResult
Audit runs every deterministic rule over one render and scores the result. It never calls a model: this is the evidence a critic pass argues from, and evidence that changes between two identical runs is not evidence.
type BrowserAutoOpener ¶
type BrowserAutoOpener struct {
// contains filtered or unexported fields
}
BrowserAutoOpener deduplicates best-effort browser launches for design artifacts so one artifact opens at most once automatically per process or session surface.
func NewBrowserAutoOpener ¶
func NewBrowserAutoOpener() *BrowserAutoOpener
func (*BrowserAutoOpener) Open ¶
func (o *BrowserAutoOpener) Open(artifactID, url string) error
type BrowserOptions ¶
type BrowserOptions struct {
// Type is a browser type understood by internal/browser ("chrome",
// "chromium", "msedge", "brave", "lightpanda", …). Empty means auto-detect.
Type string
// Executable overrides the resolved browser binary.
Executable string
// Headless runs the browser without a window. Default: true.
Headless bool
// IdleTimeout closes the browser after this long without a render.
// Zero means the session stays open until Close.
IdleTimeout time.Duration
}
BrowserOptions configures how the design renderer launches a browser.
func BrowserOptionsFromConfig ¶
func BrowserOptionsFromConfig() BrowserOptions
BrowserOptionsFromConfig reads the browser settings the browser_* tools already use, so Pando drives one browser configuration, not two.
type ConsoleEntry ¶
ConsoleEntry is a JavaScript console message captured during a render.
type CreateParams ¶
type CreateParams struct {
Title string
Kind Kind
Slug string
SkillID string
DesignSystem string
ProjectID string
// Files seeds the artifact directory: project-relative-to-the-artifact
// paths mapped to their content. A scaffold normally provides at least the
// entry document; when it is empty a minimal placeholder entry is written
// so the artifact is renderable from version 1.
Files map[string]string
// Entry overrides the manifest entry document (default "index.html").
Entry string
}
CreateParams describes a new artifact. Only Title is mandatory.
type Critique ¶
type Critique struct {
ID string `json:"id"`
ArtifactID string `json:"artifact_id"`
Version int `json:"version"`
Score float64 `json:"score"` // 0-10
Summary string `json:"summary,omitempty"`
Issues []Issue `json:"issues"`
CreatedAt time.Time `json:"created_at"`
}
Critique is one critic pass over a version.
type CritiqueOptions ¶
type CritiqueOptions struct {
// Version critiques a specific version; 0 means the current one. Only the
// current version can be re-rendered, so an older version is audited from
// what was stored for it.
Version int
// Render overrides the render the audit runs on.
Render RenderOptions
// SkipRender audits without a browser: the design-system checks still run,
// the accessibility, runtime and layout rules cannot.
SkipRender bool
// Round is the 1-based iteration number. Zero means "use the version
// number", which is what an ordinary designer/critic loop wants: one
// committed version per round.
Round int
// Policy overrides the resolved critique policy for this pass.
Policy string
// Score, Summary and Issues carry a critic's own judgement. They are
// optional: a pass with none of them recorded is a purely deterministic
// audit, which is exactly what a CI check wants.
Score float64
Summary string
Issues []Issue
// Record stores the critique against the version. Pass false for a dry
// look that leaves no history behind.
Record bool
}
CritiqueOptions drives one critic pass. The zero value is a valid deterministic pass over the current version.
type CritiqueReport ¶
type CritiqueReport struct {
Artifact Artifact `json:"artifact"`
Version int `json:"version"`
Rendered bool `json:"rendered"`
Audit AuditResult `json:"audit"`
Critique Critique `json:"critique"`
Decision GateDecision `json:"decision"`
Settings CritiqueSettings `json:"settings"`
// Recorded is true when the critique was written to the history.
Recorded bool `json:"recorded"`
// RenderError explains why the render half of the audit is missing, when
// it is. A pass that silently drops two thirds of its rules would report a
// high score for a page nobody looked at.
RenderError string `json:"render_error,omitempty"`
}
CritiqueReport is one complete critic pass: the evidence, the stored critique, and the decision the gate reached from them.
type CritiqueSettings ¶
type CritiqueSettings struct {
Enabled bool `json:"enabled"`
MaxRounds int `json:"max_rounds"`
Threshold float64 `json:"threshold"`
Policy string `json:"policy"`
}
CritiqueSettings bounds one designer/critic loop.
func DefaultCritiqueSettings ¶
func DefaultCritiqueSettings() CritiqueSettings
DefaultCritiqueSettings reads the configured bounds, falling back to the package defaults when configuration has not been loaded — the CLI and the tests both reach the gate without a config in some paths, and a gate that panics there is worse than one that uses its defaults.
func (CritiqueSettings) Gate ¶
func (s CritiqueSettings) Gate(c Critique, round int) GateDecision
Gate decides whether the loop stops after this critique. round is 1-based: the critique of the first version is round 1.
func (CritiqueSettings) WithPolicy ¶
func (s CritiqueSettings) WithPolicy(policy string) CritiqueSettings
WithPolicy applies a per-skill override (od.critique.policy). An unknown or empty policy leaves the settings untouched: a template is allowed to say nothing about critique.
type DeckSpec ¶
type DeckSpec struct {
Slides int `json:"slides,omitempty"`
}
DeckSpec carries deck-only metadata. Slides is informational: the renderer re-counts slides on every render, since the files are edited by hand.
type DesignSystem ¶
type DesignSystem struct {
Name string `json:"name"`
// Tokens maps a group ("color", "space", "font", ...) to its named values.
// Custom properties are emitted as --<group>-<name>.
Tokens map[string]map[string]string `json:"tokens"`
// Fonts lists stylesheet URLs to import ahead of the custom properties.
Fonts []string `json:"fonts,omitempty"`
}
DesignSystem is the token set shared by the artifacts of a project.
func DefaultDesignSystem ¶
func DefaultDesignSystem() DesignSystem
DefaultDesignSystem is the starting point written by design_system init: a neutral, accessible base rather than an opinionated theme.
func LoadSystemAt ¶
func LoadSystemAt(layout Layout) (DesignSystem, bool, error)
LoadSystemAt reads a design system from a layout without a Service, which is what the prompt builder needs: it runs before any session exists.
func (DesignSystem) CSS ¶
func (ds DesignSystem) CSS() string
CSS renders the tokens as custom properties. Groups and names are sorted so that the generated stylesheet is byte-stable across runs and produces a clean diff when a single token changes.
func (DesignSystem) ConstraintBlock ¶
func (ds DesignSystem) ConstraintBlock(stylesheetPath, contractPath string) string
ConstraintBlock renders the system as the hard constraint injected into the designer's prompt. It is deliberately short: it is paid for on every request where design is enabled, so it carries the values and the rule, and leaves the reasoning to DESIGN.md, which the agent can read when it needs to.
func (DesignSystem) Contract ¶
func (ds DesignSystem) Contract() string
Contract renders a complete DESIGN.md for a system that has none yet. The prose is a starting point on purpose: the rules that matter to a project are the ones its designers write down, and an empty file invites nobody to write them.
func (DesignSystem) TokenSection ¶
func (ds DesignSystem) TokenSection() string
TokenSection renders the generated, fenced half of DESIGN.md.
type ErrAmbiguousRef ¶
ErrAmbiguousRef is returned when a human-typed reference matches more than one artifact. It carries the candidates so a surface can show them.
func (*ErrAmbiguousRef) Error ¶
func (e *ErrAmbiguousRef) Error() string
type Event ¶
type Event struct {
Kind string `json:"kind"`
ArtifactID string `json:"artifact_id"`
SessionID string `json:"session_id,omitempty"`
Title string `json:"title,omitempty"`
Slug string `json:"slug,omitempty"`
ArtifactKind Kind `json:"artifact_kind,omitempty"`
Version int `json:"version,omitempty"`
Summary string `json:"summary,omitempty"`
// URL is the preview address when one could be minted, empty otherwise.
URL string `json:"url,omitempty"`
// Nodes is the size of the index a render produced.
Nodes int `json:"nodes,omitempty"`
// Slides is the deck slide count.
Slides int `json:"slides,omitempty"`
// Score is the critic score, for EventCritique.
Score float64 `json:"score,omitempty"`
At time.Time `json:"at"`
}
Event is one design lifecycle notification. It is deliberately flat and small: it travels over SSE to every connected surface, and a surface that wants more calls the REST API for it.
type ExportOptions ¶
type ExportOptions struct {
// Format is html, png or pdf.
Format string
// Dest is the output file, absolute or relative to the working directory.
// Empty writes next to the artifact under exports/.
Dest string
// Slide exports a single deck slide (PNG only); -1 for the whole document.
Slide int
// FullPage captures beyond the viewport for PNG exports.
FullPage bool
// Viewport overrides the manifest viewport.
Viewport Viewport
// Landscape applies to PDF exports without their own @page size.
Landscape bool
}
ExportOptions configures one export.
type ExportResult ¶
type ExportResult struct {
Format string `json:"format"`
Path string `json:"path"`
Bytes int `json:"bytes"`
Note string `json:"note,omitempty"`
}
ExportResult reports where an export landed.
type ExtractOptions ¶
type ExtractOptions struct {
// Source selects the extractor. Empty defaults to SourceCode.
Source ExtractSource
// Target is a directory (code), a URL, an image path or a markdown path.
// Empty means the project root for code, and is an error otherwise.
Target string
// Name overrides the name given to the extracted system.
Name string
// MaxFiles bounds a code scan. Zero uses defaultExtractMaxFiles.
MaxFiles int
}
ExtractOptions configures one extraction.
type ExtractResult ¶
type ExtractResult struct {
System DesignSystem `json:"system"`
Source ExtractSource `json:"source"`
Target string `json:"target"`
Scanned []string `json:"scanned,omitempty"`
Notes []string `json:"notes,omitempty"`
}
ExtractResult is an extracted system plus an account of how it was obtained, so a caller can show what was looked at before committing anything to disk.
type ExtractSource ¶
type ExtractSource string
ExtractSource names where a design system is read from.
const ( // SourceCode scans stylesheets and component files in a directory. SourceCode ExtractSource = "code" // SourceURL renders a page and reads its computed styles. SourceURL ExtractSource = "url" // SourceImage quantises a bitmap into a palette. SourceImage ExtractSource = "image" // SourceText reads a written style guide, including the bundled examples. SourceText ExtractSource = "text" )
type GateDecision ¶
type GateDecision struct {
// Pass is true when this version meets the bar.
Pass bool `json:"pass"`
// Iterate is true when the loop should produce another version. It is not
// simply !Pass: a run that has spent its rounds stops without passing.
Iterate bool `json:"iterate"`
// Reason is one sentence for a human and for the agent transcript.
Reason string `json:"reason"`
Round int `json:"round"`
MaxRounds int `json:"max_rounds"`
Score float64 `json:"score"`
Threshold float64 `json:"threshold"`
Policy string `json:"policy"`
// Blocking counts the error- and blocking-severity findings that remain,
// which is what a strict policy refuses to pass with.
Blocking int `json:"blocking"`
}
GateDecision is the answer to the only question the loop asks: iterate again, or stop. It carries the numbers behind the answer so a surface can show why without recomputing them.
type ImageDiff ¶
type ImageDiff struct {
Width int `json:"width"`
Height int `json:"height"`
// Changed is how many pixels differ by more than the tolerance, and Total
// how many were compared.
Changed int `json:"changed"`
Total int `json:"total"`
// Fraction is Changed/Total, which is the number a regression check reads.
Fraction float64 `json:"fraction"`
// MaxDelta is the largest single-channel difference seen, so a caller can
// tell "everything moved a shade" from "one region changed completely".
MaxDelta int `json:"max_delta"`
// SizeMismatch reports that the two images do not even have the same
// dimensions, which is a regression on its own and makes Fraction 1.
SizeMismatch bool `json:"size_mismatch"`
}
ImageDiff is the result of comparing two renders of the same artifact.
func ComparePNG ¶
ComparePNG measures how much two PNG renders differ. tolerance is the per-channel difference below which two pixels count as the same; pass 0 for the default.
This is a perceptual-diff floor, not a perceptual model: it answers "did this render change" for a regression check, which is the question the fixture suite asks.
type InspectOptions ¶
type InspectOptions struct {
// NodeID restricts the result to one node and its descendants.
NodeID string
// Selector matches nodes whose selector or role contains this string.
Selector string
// Text matches nodes whose text contains this string (case-insensitive).
Text string
// Slide restricts the result to one deck slide; -1 for every slide.
Slide int
// Depth limits how far below the root nodes the result descends.
// Zero means unlimited.
Depth int
// Offset and Limit page the result.
Offset int
Limit int
// IncludeStyles carries the computed-style subset. Off by default: styles
// are the largest part of a node and are rarely needed for every node.
IncludeStyles bool
// StyleProps narrows which style properties survive when IncludeStyles is
// set. Empty keeps all indexed properties.
StyleProps []string
// MaxTextLen truncates node text. Zero keeps the indexed text.
MaxTextLen int
}
InspectOptions narrows and pages the structure index.
type InspectResult ¶
type InspectResult struct {
ArtifactID string `json:"artifact_id"`
Version int `json:"version"`
// Total is how many nodes matched before paging.
Total int `json:"total"`
Offset int `json:"offset"`
Limit int `json:"limit"`
Nodes []Node `json:"nodes"`
// NextOffset is the offset of the next page, or -1 when this is the last.
NextOffset int `json:"next_offset"`
}
InspectResult is one page of the structure index.
func Inspect ¶
func Inspect(nodes []Node, opts InspectOptions) InspectResult
Inspect filters, trims and pages a node index. It works on any node slice, so the same code serves a fresh render and the stored index of an old version.
func (InspectResult) Text ¶
func (r InspectResult) Text() string
Text renders an inspect page as compact lines for a tool result. One node per line keeps it readable for a model without spending a JSON envelope per node.
type Issue ¶
type Issue struct {
// Code is the stable rule identifier for a finding the deterministic audit
// produced ("a11y.contrast"), empty for a finding a critic wrote in prose.
// It is what lets a UI group findings and a caller suppress a rule without
// matching on its message.
Code string `json:"code,omitempty"`
Severity string `json:"severity"`
NodeID string `json:"node_id,omitempty"`
Slide int `json:"slide,omitempty"`
Message string `json:"message"`
Fix string `json:"fix,omitempty"`
}
Issue is a single actionable finding against a version. NodeID (and Slide for decks) let the UI turn an issue into a selection.
func MergeIssues ¶
MergeIssues folds a critic's own findings into the deterministic ones, dropping a critic finding that only restates a rule already fired on the same node. The audit is the evidence; the critic adds judgement, not an echo.
type Kind ¶
type Kind string
Kind enumerates the artifact kinds supported in v1. Further kinds (mobile, document, dashboard, diagram) are deliberately deferred.
type Layout ¶
type Layout struct {
// WorkingDir is the absolute project root.
WorkingDir string
// OutputDir is the project-relative root holding artifacts ("designer").
OutputDir string
// SystemDir is the design-system directory inside OutputDir ("_system").
SystemDir string
}
Layout resolves artifact directories inside a project. Every path handed to the rest of the package goes through it, so nothing can address a directory outside the configured output root.
func (Layout) AbsDir ¶
AbsDir returns the absolute directory for a project-relative artifact dir, rejecting anything that escapes the output root.
func (Layout) AvailableSlug ¶
AvailableSlug turns title into a directory-safe slug and appends a numeric suffix until it names a directory that does not exist yet.
func (Layout) EnsureRoot ¶
EnsureRoot creates the output root if it does not exist yet.
func (Layout) SystemPath ¶
SystemPath returns the absolute path of the design-system directory.
type Manifest ¶
type Manifest struct {
ID string `json:"id"`
Kind Kind `json:"kind"`
Title string `json:"title,omitempty"`
Version int `json:"version"`
Entry string `json:"entry"`
DesignSystem string `json:"designSystem,omitempty"`
Skill string `json:"skill,omitempty"`
Preview PreviewSpec `json:"preview"`
Deck *DeckSpec `json:"deck,omitempty"`
}
Manifest is pando-design.json: the portable, committable description of an artifact. It is the source of truth when the SQLite metadata is missing (a fresh clone, another machine), so a design directory alone is enough to re-adopt the artifact.
func NewManifest ¶
NewManifest builds a manifest with the defaults for a kind.
func ReadManifest ¶
ReadManifest loads pando-design.json from an artifact directory.
type NetworkFailure ¶
type NetworkFailure struct {
URL string `json:"url"`
Status int `json:"status,omitempty"`
Error string `json:"error,omitempty"`
}
NetworkFailure is a request that failed or answered with an error status while rendering. Broken assets are a design defect, so they are reported to the agent with the render result instead of being swallowed.
type Node ¶
type Node struct {
ArtifactID string `json:"artifact_id"`
Version int `json:"version"`
NodeID string `json:"node_id"`
ParentID string `json:"parent_id,omitempty"`
Selector string `json:"selector,omitempty"`
Role string `json:"role,omitempty"`
Text string `json:"text,omitempty"`
Slide int `json:"slide,omitempty"` // deck only
Box Rect `json:"box"`
Styles map[string]string `json:"styles,omitempty"`
}
Node is one entry of the structure index the inspector builds after a render. NodeID is the stable data-pando-id attribute injected at render time and is what a UI selection resolves to (design://<node_id>).
type NodeFacts ¶
type NodeFacts struct {
NodeID string `json:"node_id"`
Tag string `json:"tag"`
// Name is an approximation of the accessible name: enough to tell a named
// control from an unnamed one.
Name string `json:"name"`
// AltPresent distinguishes an image with alt="" — decorative on purpose —
// from one that simply has no alt attribute at all.
AltPresent bool `json:"alt_present"`
HeadingLevel int `json:"heading_level"`
Interactive bool `json:"interactive"`
AriaHidden bool `json:"aria_hidden"`
HasText bool `json:"has_text"`
Color string `json:"color"`
Background string `json:"background"`
FontSize float64 `json:"font_size"`
FontWeight int `json:"font_weight"`
// Slide and Box are copied from the matching node so a rule can report a
// finding without a second lookup.
Slide int `json:"slide"`
Box Rect `json:"box"`
}
NodeFacts is what the audit needs to know about one rendered element beyond what the node index stores.
type PatchChange ¶
type PatchChange struct {
Op string `json:"op"`
Selector string `json:"selector"`
Matches int `json:"matches"`
Detail string `json:"detail,omitempty"`
}
PatchChange reports what one operation did, for the tool response and the permission prompt.
func ApplyPatch ¶
func ApplyPatch(src []byte, ops []PatchOp) ([]byte, []PatchChange, error)
ApplyPatch applies ops to the HTML source and returns the new bytes together with a description of every change. The source is spliced, never reserialised: bytes outside the targeted ranges are preserved exactly.
type PatchFilePlan ¶
type PatchFilePlan struct {
// RelPath is relative to the artifact directory; Path is absolute.
RelPath string `json:"rel_path"`
Path string `json:"-"`
Old string `json:"-"`
New string `json:"-"`
Changes []PatchChange `json:"changes"`
}
PatchFilePlan is the pending rewrite of one artifact file.
type PatchOp ¶
type PatchOp struct {
NodeID string `json:"node_id,omitempty"`
Selector string `json:"selector,omitempty"`
File string `json:"file,omitempty"`
Op string `json:"op"`
Attr string `json:"attr,omitempty"`
Value string `json:"value,omitempty"`
Style map[string]string `json:"style,omitempty"`
Class string `json:"class,omitempty"`
HTML string `json:"html,omitempty"`
Position string `json:"position,omitempty"`
// All allows an operation to apply to every match instead of failing when a
// selector is ambiguous.
All bool `json:"all,omitempty"`
}
PatchOp is one edit request. Exactly one of NodeID or Selector must be set; File defaults to the artifact's entry document.
type PatchPlan ¶
type PatchPlan struct {
Artifact Artifact `json:"artifact"`
Files []PatchFilePlan `json:"files"`
}
PatchPlan is the resolved, not-yet-written result of a design_patch call. It exists so the tool layer can show a real diff in the permission prompt before anything touches the user's working tree.
type Presentation ¶
type Presentation struct {
ArtifactID string `json:"artifact_id"`
Title string `json:"title"`
Kind Kind `json:"kind"`
Version int `json:"version"`
// Dir and Entry are project-relative.
Dir string `json:"dir"`
Entry string `json:"entry"`
// URL is the address to open. It is a served preview URL whenever a preview
// server is running in this process, and a file:// address otherwise, so a
// surface never has to ask which mode it is in.
URL string `json:"url"`
// FileURL is always the file:// address of the entry document. Exports and
// "reveal in file manager" want the file, not the server.
FileURL string `json:"file_url"`
// BridgeURL is the preview URL with the selection bridge enabled. Only the
// Pando UI loads it: it is what makes click-to-select work in the iframe.
// Empty when no preview server is running.
BridgeURL string `json:"bridge_url,omitempty"`
// Slides is the deck slide count, zero for other kinds.
Slides int `json:"slides,omitempty"`
// Slide is the slide to open at, zero when unset.
Slide int `json:"slide,omitempty"`
// Selection is the design://<node_id> reference of the focused element.
Selection string `json:"selection,omitempty"`
}
Presentation is what a surface needs to show an artifact to the user: where to open it, which slide, and which element is selected.
URL is a file:// address until the preview server exists; every surface reads it from here, so pointing them all at the served preview later is a change in one place.
func ResolveCreatedArtifactPresentation ¶
func ResolveCreatedArtifactPresentation(ctx context.Context, artifactID string) (Presentation, error)
ResolveCreatedArtifactPresentation resolves the URL a newly created artifact should be opened with. It upgrades a file:// presentation to a served preview when this process can start a preview server.
type PreviewSpec ¶
type PreviewSpec struct {
Viewport Viewport `json:"viewport"`
}
PreviewSpec holds render defaults carried with the artifact.
type PrintOptions ¶
type PrintOptions struct {
RenderOptions
// Landscape prints in landscape orientation.
Landscape bool
// PaperWidth and PaperHeight are in inches; zero uses the page's own CSS
// size, which is what makes one-slide-per-page decks work.
PaperWidth float64
PaperHeight float64
// NoBackground omits background graphics. They print by default: a design
// without its backgrounds is not the design.
NoBackground bool
}
PrintOptions configures PDF export.
type Provider ¶
type Provider struct {
// contains filtered or unexported fields
}
Provider owns the process-wide pieces of the Design Studio — the database handle, the snapshot service and the single headless browser — and hands out cheap per-session Service values.
The renderer is shared on purpose: starting a browser costs far more than a tool call should, and every design surface (tools, HTTP preview, CLI) renders through the same one.
func DefaultProvider ¶
func DefaultProvider() *Provider
DefaultProvider returns the process-wide provider, or nil when the design subsystem was never wired.
func NewProvider ¶
NewProvider builds a provider over an open database. The snapshot service is created here because artifact versions are directory-scoped snapshots.
func NewProviderWith ¶
func NewProviderWith(db *sql.DB, snaps Snapshotter) *Provider
NewProviderWith builds a provider over an explicit snapshotter, which is what tests use.
func (*Provider) Service ¶
Service returns a design service bound to a session. The returned value is cheap: it shares the store, the snapshotter and the renderer.
func (*Provider) SetMirror ¶
func (p *Provider) SetMirror(m SystemMirror)
SetMirror attaches the knowledge-base mirror handed to every service the provider creates. Wired at start-up when the knowledge base is available.
type RGB ¶
RGB is an 8-bit colour with an alpha channel, as a CSS colour value carries.
func ParseCSSColor ¶
ParseCSSColor reads the colour notations a computed style actually produces — rgb(), rgba(), and the hex forms an inline style may still carry. It returns false for anything else (named colours, colour functions), because a rule that guesses at a colour reports contrast failures that are not real.
type Rect ¶
type Rect struct {
X float64 `json:"x"`
Y float64 `json:"y"`
W float64 `json:"w"`
H float64 `json:"h"`
}
Rect is a layout box in CSS pixels, as reported by the renderer.
type RenderOptions ¶
type RenderOptions struct {
// URL overrides the document to load. Empty renders the artifact's entry
// document from disk (file://); the preview server takes over in P3.
URL string
// Viewport overrides the artifact manifest viewport.
Viewport Viewport
// Wait is an extra settle delay after the load event, for pages that build
// themselves in script.
Wait time.Duration
// MaxNodes and MaxDepth bound the structure index.
MaxNodes int
MaxDepth int
// StyleProps overrides the computed-style subset.
StyleProps []string
// SlideSelector overrides the deck slide selector.
SlideSelector string
// PrintMedia renders under print emulation instead of screen.
PrintMedia bool
}
RenderOptions configures one render.
type RenderResult ¶
type RenderResult struct {
URL string `json:"url"`
Title string `json:"title"`
Viewport Viewport `json:"viewport"`
Slides int `json:"slides"`
Nodes []Node `json:"nodes"`
Truncated bool `json:"truncated,omitempty"`
Console []ConsoleEntry `json:"console,omitempty"`
Failures []NetworkFailure `json:"failures,omitempty"`
Height float64 `json:"height"`
// Width is the document scroll width, which is how a horizontal overflow
// is detected: a page wider than its own viewport.
Width float64 `json:"width,omitempty"`
// Facts carries the per-node accessibility and typography detail the
// quality audit runs on. It is never persisted and never travels to a
// model as part of the structure index: it exists for the lifetime of one
// render, so the index itself stays as small as the inspector needs.
Facts []NodeFacts `json:"-"`
}
RenderResult is what one render reports back to the agent.
type Renderer ¶
type Renderer struct {
// contains filtered or unexported fields
}
Renderer drives a headless browser over design artifacts: render + index, screenshots, PDF printing and canvas rasterization.
func NewRenderer ¶
func NewRenderer(layout Layout, opts BrowserOptions) *Renderer
NewRenderer builds a renderer. The browser is started lazily on first use, so constructing one is free on machines with no Chromium.
func (*Renderer) Available ¶
Available reports whether a usable browser can be resolved, without starting one. Callers use it to degrade instead of failing a whole design flow.
func (*Renderer) PrintPDF ¶
PrintPDF renders the artifact under print emulation and prints it to PDF. Deck exports rely on the artifact's own @page rules, so preferCSSPageSize is always on.
func (*Renderer) Rasterize ¶
func (r *Renderer) Rasterize(ctx context.Context, html string, width, height int, wait time.Duration) ([]byte, error)
Rasterize renders an HTML document that draws into a canvas (or any markup) and captures the result as a PNG. This is Pando's image-generation path: the browser is the renderer, so no image-model provider is involved.
func (*Renderer) Render ¶
func (r *Renderer) Render(ctx context.Context, a Artifact, opts RenderOptions) (RenderResult, error)
Render loads an artifact, stamps data-pando-id on its elements and returns the structure index together with whatever the page logged or failed to load.
func (*Renderer) Screenshot ¶
func (r *Renderer) Screenshot(ctx context.Context, a Artifact, opts ScreenshotOptions) ([]byte, error)
Screenshot renders the artifact and captures a PNG.
func (*Renderer) SlideBreaks ¶
func (r *Renderer) SlideBreaks(ctx context.Context, a Artifact, opts RenderOptions) ([]SlideBreak, error)
SlideBreaks reports how each slide behaves under print emulation. A deck whose slides do not break after each other will not export one slide per page.
type ScreenshotOptions ¶
type ScreenshotOptions struct {
RenderOptions
// Selector captures a single element instead of the page.
Selector string
// Slide captures one deck slide; -1 for the whole document.
Slide int
// FullPage captures beyond the viewport.
FullPage bool
// Quality is the PNG/JPEG quality passed to the browser (0 keeps the
// browser default).
Quality int
}
ScreenshotOptions selects what a screenshot captures.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service is the artifact and version API the design tools, the HTTP surface and the CLI all share.
func NewService ¶
func NewService(store *Store, snaps Snapshotter, layout Layout, sessionID string) *Service
NewService builds a design service. sessionID is recorded on artifacts and on the snapshots they take; it may be empty for CLI use.
func NewServiceFromConfig ¶
func NewServiceFromConfig(db *sql.DB, snaps Snapshotter, sessionID string) *Service
NewServiceFromConfig builds a design service from the loaded configuration, which is how the tools, the HTTP surface and the CLI all obtain one.
func ServiceFor ¶
ServiceFor returns a session-bound service from the default provider.
func (*Service) ApplyPatchPlan ¶
func (s *Service) ApplyPatchPlan(ctx context.Context, plan *PatchPlan, summary string, commit bool) (int, error)
ApplyPatchPlan writes a prepared plan to disk. When commit is true a new version (a directory-scoped snapshot) is recorded and its number returned; otherwise the returned version is 0 and the change stays uncommitted, exactly like an ordinary edit of the files.
func (*Service) ApplySystem ¶
ApplySystem links the design-system stylesheet into an artifact's entry document and audits the artifact for values a token already covers.
func (*Service) Checkout ¶
Checkout restores the artifact directory to a previous version. The revert is scoped to that directory, so unrelated files are never touched, and the current state is snapshotted first by RevertScoped.
func (*Service) CommitVersion ¶
CommitVersion snapshots the artifact directory and records it as the next version. The manifest is rewritten so a checkout of the directory alone still reports the right version number.
func (*Service) ContractPath ¶
ContractPath returns the absolute path of DESIGN.md.
func (*Service) Create ¶
Create materialises a new artifact: directory, seed files, manifest, metadata row and version 1 (a scoped snapshot of the fresh directory).
func (*Service) Critique ¶
func (s *Service) Critique(ctx context.Context, artifactID string, opts CritiqueOptions) (CritiqueReport, error)
Critique runs a quality pass over an artifact: render it, run every deterministic rule, fold in whatever judgement the caller brings, score it, store it and decide whether the loop should go round again.
func (*Service) CritiqueSettingsFor ¶
func (s *Service) CritiqueSettingsFor(skillID string) CritiqueSettings
CritiqueSettingsFor resolves the bounds for one artifact: the configured defaults, overridden by the skill's own od.critique.policy when the artifact was built from a template that declares one.
func (*Service) Delete ¶
Delete drops the metadata of an artifact. The files stay on disk: they belong to the user's repository, and removing them is an explicit, separate act.
func (*Service) Diff ¶
func (s *Service) Diff(ctx context.Context, artifactID string, from, to int) ([]snapshot.DiffEntry, error)
Diff compares two versions of an artifact.
func (*Service) Export ¶
func (s *Service) Export(ctx context.Context, artifactID string, opts ExportOptions) (ExportResult, error)
Export writes the artifact out in one of the supported formats. HTML exports are self-contained single files: local stylesheets, scripts and images are inlined so the result can be mailed or committed on its own.
func (*Service) ExtractSystem ¶
func (s *Service) ExtractSystem(ctx context.Context, opts ExtractOptions) (ExtractResult, error)
ExtractSystem runs the extractor named by opts and returns the resulting system without writing anything. Persisting is a separate, explicit step.
func (*Service) Inspect ¶
func (s *Service) Inspect(ctx context.Context, artifactID string, version int, opts InspectOptions) (InspectResult, error)
Inspect returns a filtered, paged view of a version's stored index. Pass version 0 for the artifact's current version.
func (*Service) LatestCritique ¶
func (s *Service) LatestCritique(ctx context.Context, artifactID string, version int) (Critique, error)
LatestCritique returns the most recent pass over a version, or ErrNotFound when the version has never been critiqued. Pass version 0 for the current version.
func (*Service) List ¶
List returns artifacts newest first. Pass sessionOnly to restrict the result to the current session.
func (*Service) LiveURL ¶
LiveURL resolves how to show an artifact, starting a loopback preview server first when this process has none.
It is the call every "open it" path goes through — the CLI, the TUI `o` key, the ACP resource link and the design_present tool — so that they all agree on when a listener is allowed to come into existence: on an explicit request to show something, never as a side effect of rendering or listing.
A preview server that cannot start is not fatal: the returned Presentation still carries the file:// address, which is enough for a local browser.
func (*Service) LoadSystem ¶
func (s *Service) LoadSystem() (DesignSystem, bool, error)
LoadSystem reads the design system, returning the default when none exists yet so callers never have to special-case a fresh project.
func (*Service) MirrorSystem ¶
func (s *Service) MirrorSystem(ctx context.Context, ds DesignSystem, source ExtractSource, target string) (string, error)
MirrorSystem writes the design system to the knowledge base. It returns the document path so a caller can report where it went, and an empty path when no mirror is wired.
func (*Service) Node ¶
func (s *Service) Node(ctx context.Context, artifactID string, version int, nodeID string) (Node, error)
Node resolves one indexed node, which is what a design://<node_id> selection from the UI turns into. Pass version 0 for the current version.
func (*Service) Patch ¶
func (s *Service) Patch(ctx context.Context, artifactID string, ops []PatchOp, summary string, commit bool) (*PatchPlan, int, error)
Patch is the one-shot convenience path used by the CLI and tests: prepare, write, optionally commit. The tool layer uses PreparePatch/ApplyPatchPlan so it can gate the write on a permission prompt showing the diff.
func (*Service) PreparePatch ¶
func (s *Service) PreparePatch(ctx context.Context, artifactID string, ops []PatchOp) (*PatchPlan, error)
PreparePatch resolves patch operations against the artifact's source files and returns the rewritten content without writing anything.
Operations addressed by node_id are resolved through the node index of the artifact's current version, which is what turns a UI selection (design://<node_id>) into a source edit.
func (*Service) Presentation ¶
func (s *Service) Presentation(ctx context.Context, artifactID string, slide int, nodeID string) (Presentation, error)
Presentation resolves how an artifact should be shown. A node id is validated against the current index so a surface never receives a selection it cannot resolve.
func (*Service) PublishPreview ¶
PublishPreview registers an artifact with the preview server and returns the grant. It is idempotent: re-publishing an artifact keeps its token, so a preview already open in a browser survives every iteration.
func (*Service) Render ¶
func (s *Service) Render(ctx context.Context, artifactID string, opts RenderOptions) (RenderResult, error)
Render renders an artifact and stores the resulting structure index against its current version, so a later Inspect (or a UI selection) resolves without re-rendering.
func (*Service) Resolve ¶
Resolve turns a human-typed reference into an artifact. It accepts, in order of precedence, an exact id, an exact slug, an id prefix, and finally a case-insensitive substring of the slug or title. An empty reference selects the most recently updated artifact, which is what "the one I am working on" means at a prompt.
Precedence is ordered rather than scored on purpose: an exact id must never lose to a substring match on some other artifact's title.
func (*Service) SaveSystem ¶
func (s *Service) SaveSystem(ds DesignSystem) (string, string, error)
SaveSystem writes tokens.json, regenerates system.css and refreshes the generated section of DESIGN.md, returning the token and stylesheet paths.
func (*Service) SetSystemTokens ¶
func (s *Service) SetSystemTokens(name string, updates map[string]map[string]string) (DesignSystem, error)
SetSystemTokens merges updates into the design system and persists it. A token whose value is empty is removed, which is how a group is pruned.
func (*Service) Store ¶
Store exposes the metadata store for the node index and critiques, which the renderer and the critic loop own.
func (*Service) SystemRelPath ¶
SystemRelPath returns the project-relative path of a design-system file, for linking it from an artifact.
func (*Service) Versions ¶
Versions returns the full history of an artifact, each entry carrying its last critique when there is one.
func (*Service) WithMirror ¶
func (s *Service) WithMirror(m SystemMirror) *Service
WithMirror attaches the knowledge-base mirror used by the design system. It is optional: every surface works without one, they just do not publish what they extract.
func (*Service) WithRenderer ¶
WithRenderer attaches a renderer to the service. It is optional: everything that does not need a browser (create, versions, checkout, diff) works without one, so a machine with no Chromium keeps a usable Design Studio.
func (*Service) WriteWorkspaceFile ¶
WriteWorkspaceFile writes generated bytes to a working-directory-relative path, refusing to escape the project. It backs image generation, whose output belongs next to the artifact that uses it rather than in a cache.
type SlideBreak ¶
type SlideBreak struct {
Index int `json:"index"`
BreakAfter string `json:"break_after"`
Height float64 `json:"height"`
}
SlideBreak reports how one slide behaves under print emulation.
type Snapshotter ¶
type Snapshotter interface {
CreateScoped(ctx context.Context, sessionID, description, rootDir string) (snapshot.Snapshot, error)
RevertScoped(ctx context.Context, snapshotID string) error
Compare(ctx context.Context, snapshotID1, snapshotID2 string) ([]snapshot.DiffEntry, error)
}
Snapshotter is the slice of the snapshot service the design package needs. Only the scoped operations are used: an artifact's history must never be able to restore or delete a file outside its own directory.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store persists design metadata. The artifact files and their history live on disk (working tree + scoped snapshots); this only holds what is needed to list, resolve and navigate them.
func (*Store) AddCritique ¶
AddCritique records a critic pass over a version.
func (*Store) AddVersion ¶
AddVersion records an iteration and makes it the artifact's current version.
func (*Store) CreateArtifact ¶
CreateArtifact inserts a new artifact row.
func (*Store) DeleteArtifact ¶
DeleteArtifact removes an artifact and, by cascade, its versions, nodes and critiques. The files on disk are never touched: they belong to the user.
func (*Store) GetArtifact ¶
GetArtifact returns one artifact by id.
func (*Store) GetArtifactByDir ¶
GetArtifactByDir returns the artifact stored at a project-relative directory.
func (*Store) GetNode ¶
func (s *Store) GetNode(ctx context.Context, artifactID string, version int, nodeID string) (Node, error)
GetNode resolves a single node of a version, which is what a design://<id> selection turns into.
func (*Store) GetVersion ¶
GetVersion returns one version of an artifact.
func (*Store) LatestCritique ¶
func (s *Store) LatestCritique(ctx context.Context, artifactID string, version int) (Critique, error)
LatestCritique returns the most recent critic pass over a version, or ErrNotFound when the version has never been critiqued.
func (*Store) ListArtifacts ¶
ListArtifacts returns artifacts newest first. An empty sessionID lists all of them: artifacts outlive the session that created them.
func (*Store) ListNodes ¶
func (s *Store) ListNodes(ctx context.Context, artifactID string, version, slide int) ([]Node, error)
ListNodes returns the structure index of one version. A slide >= 0 narrows the result to that slide; pass -1 for every node.
func (*Store) ListVersions ¶
ListVersions returns every version of an artifact, oldest first.
func (*Store) ReplaceNodes ¶
func (s *Store) ReplaceNodes(ctx context.Context, artifactID string, version int, nodes []Node) error
ReplaceNodes swaps the whole structure index of one artifact version. The index is a render product, so it is rebuilt wholesale rather than merged.
func (*Store) SetCurrentVersion ¶
SetCurrentVersion points the artifact at an existing version, as a checkout does. It does not create history.
type SystemFinding ¶
type SystemFinding struct {
// File is the artifact-relative file the value was found in.
File string `json:"file"`
// Line is the 1-indexed line.
Line int `json:"line"`
// Property is the CSS property, when the value came from a declaration.
Property string `json:"property,omitempty"`
// Value is the literal as written.
Value string `json:"value"`
// Token is the custom property that should replace it.
Token string `json:"token"`
}
SystemFinding is one hardcoded value that a token already covers.
type SystemMirror ¶
type SystemMirror interface {
AddDocument(ctx context.Context, filePath, content string, metadata map[string]interface{}) error
}
SystemMirror is the slice of the knowledge base the design system needs. It is an interface so internal/design does not depend on the RAG stack, which carries an embedding provider and a database of its own.
type Template ¶
type Template struct {
Name string `json:"name"`
Description string `json:"description"`
Category string `json:"category"`
Scenario string `json:"scenario"`
ExamplePrompt string `json:"example_prompt,omitempty"`
Mode string `json:"mode,omitempty"`
Kind Kind `json:"kind,omitempty"`
Preview string `json:"preview,omitempty"`
Viewport Viewport `json:"viewport,omitempty"`
// RequiresSystem is od.design_system.requires: the template expects a
// committed design system and will otherwise produce a look nobody chose.
RequiresSystem bool `json:"requires_system"`
Craft []string `json:"craft,omitempty"`
CritiquePolicy string `json:"critique_policy,omitempty"`
// Startable reports whether an artifact can be created from this entry. A
// craft reference or a workflow bundle is real, useful, and not startable.
Startable bool `json:"startable"`
// Source is where the entry came from; Installed reports whether it is
// present in a skills root, which is what makes it visible to the agent.
Source TemplateSource `json:"source"`
Installed bool `json:"installed"`
// SourcePath is set for installed entries so a user can find the file.
SourcePath string `json:"source_path,omitempty"`
}
Template is one gallery entry: a design skill described by its `od:` block. Third-party bundles reach the gallery through the same struct — Pando speaks the format, it does not ship anyone else's content.
func BundledTemplate ¶
BundledTemplate returns one Pando-authored bundle by name.
func BundledTemplates ¶
BundledTemplates returns the Pando-authored bundles, sorted by name.
func Gallery ¶
Gallery merges the bundled templates with the design bundles already present in the skill discovery roots. An installed bundle of the same name wins: the user's copy is the one the agent actually reads, so listing ours would show a description that is not in force.
func TemplateFromSkill ¶
TemplateFromSkill converts a discovered skill into a gallery entry. It reports false for a skill with no `od:` block: an ordinary Claude Code skill is not a design template and must not appear as one. Callers pass the fields rather than the skill itself because the design package must not depend on the skills subsystem, which depends on the tool layer, which depends on this package.
type TemplateSource ¶
type TemplateSource string
TemplateSource says where a gallery entry came from.
const ( // SourceBundled is a Pando-authored bundle embedded in the binary. SourceBundled TemplateSource = "bundled" // SourceInstalled is a bundle found in one of the skill discovery roots. SourceInstalled TemplateSource = "installed" )
type Version ¶
type Version struct {
ArtifactID string `json:"artifact_id"`
Number int `json:"number"`
SnapshotID string `json:"snapshot_id"`
Summary string `json:"summary"`
Critique *Critique `json:"critique,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
Version is one accepted iteration of an artifact, backed by a scoped snapshot of its directory.
Source Files
¶
- apply.go
- audit.go
- browser.go
- browser_open.go
- contract.go
- critique.go
- events.go
- examples.go
- export.go
- extract.go
- htmldoc.go
- imagediff.go
- inspect.go
- layout.go
- manifest.go
- mirror.go
- model.go
- patch.go
- present.go
- preview_link.go
- provider.go
- render_script.go
- renderer.go
- scaffold.go
- selector.go
- service.go
- service_critique.go
- service_patch.go
- service_render.go
- store.go
- surface.go
- system.go
- templates.go
- tokens.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package preview serves design artifacts over HTTP so every surface — the WebUI iframe, a system browser opened from the TUI, a Zed resource link — looks at the same running document instead of a file:// copy.
|
Package preview serves design artifacts over HTTP so every surface — the WebUI iframe, a system browser opened from the TUI, a Zed resource link — looks at the same running document instead of a file:// copy. |