operatingmodel

package
v1.0.0-beta.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 22, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package operatingmodel defines the data model and payload types for a user's work operating model: the rhythms, decisions, dependencies, institutional knowledge, and friction that describe how a user works.

The operating model is populated by the /onboard dispatch command through a five-layer elicitation interview and consumed by the agentic loop as injected system-prompt context (via teams-memory's hydrator).

Layers

The interview captures five ordered layers:

  1. operating_rhythms — recurring cadence and calendar structure
  2. recurring_decisions — decisions made on a regular schedule
  3. dependencies — people, systems, and inputs the work relies on
  4. institutional_knowledge — tribal knowledge and hard-won context
  5. friction — where the work gets stuck today

Entity model

Operating-model facts land in the knowledge graph as predicate-per-field triples under a user-profile subtree:

{org}.{platform}.user.teams.profile.{userID}                   — profile root
{org}.{platform}.user.teams.om-layer.{userID}-{layer}          — per layer
{org}.{platform}.user.teams.om-entry.{entryID}                 — per entry

Predicates use the om.* namespace (om.entry.title, om.layer.checkpoint_summary, user.operating_model.version, etc.) so operating-model facts can be queried cleanly without blurring into other teams-memory categories such as lessons-learned.

Message types

Two payload types are registered with the global component.PayloadRegistry in init():

  • operating_model.layer_approved.v1 — emitted when a layer checkpoint is approved by the user; consumed by teams-memory to write triples.
  • operating_model.profile_context.v1 — published by the teams-memory hydrator on loop-starting events and consumed by teams-loop to inject a "How this user works" section into the system prompt.

Index

Constants

View Source
const (
	// Domain is the payload registry domain for all operating-model messages.
	Domain = "operating_model"

	// SchemaVersion is the current schema version for operating-model payloads.
	SchemaVersion = "v1"
)

Domain and version constants for the operating-model message namespace.

View Source
const (
	// CategoryLayerApproved is the payload category for an approved-layer checkpoint.
	CategoryLayerApproved = "layer_approved"

	// CategoryProfileContext is the payload category for assembled profile context
	// injected into the agentic loop's system prompt.
	CategoryProfileContext = "profile_context"
)

Category constants for operating-model message types.

View Source
const (
	// LayerOperatingRhythms captures recurring cadence and calendar structure.
	LayerOperatingRhythms = "operating_rhythms"

	// LayerRecurringDecisions captures decisions made on a regular schedule.
	LayerRecurringDecisions = "recurring_decisions"

	// LayerDependencies captures people, systems, and inputs the work relies on.
	LayerDependencies = "dependencies"

	// LayerInstitutionalKnowledge captures tribal knowledge and hard-won context.
	LayerInstitutionalKnowledge = "institutional_knowledge"

	// LayerFriction captures where the work gets stuck today.
	LayerFriction = "friction"
)

Layer names, in interview order.

View Source
const (
	// ConfidenceConfirmed marks an entry the user explicitly approved.
	ConfidenceConfirmed = "confirmed"

	// ConfidenceSynthesized marks an entry inferred from other entries or
	// from a contradiction pass.
	ConfidenceSynthesized = "synthesized"
)

Source-confidence values for operating-model entries.

View Source
const (
	// StatusActive marks a currently-true entry.
	StatusActive = "active"

	// StatusUnresolved marks an entry flagged for follow-up.
	StatusUnresolved = "unresolved"

	// StatusSuperseded marks an entry replaced by a later profile version.
	StatusSuperseded = "superseded"
)

Entry-status values.

View Source
const (
	// Profile-level predicates
	PredicateProfileVersion     = "user.operating_model.version"
	PredicateProfileLastUpdated = "user.operating_model.last_updated"
	PredicateProfileHasLayer    = "user.operating_model.has_layer"

	// Layer-level predicates
	PredicateLayerName              = "om.layer.name"
	PredicateLayerCheckpointSummary = "om.layer.checkpoint_summary"
	PredicateLayerVersion           = "om.layer.version"
	PredicateLayerHasEntry          = "om.layer.has_entry"

	// Entry-level predicates
	PredicateEntryTitle            = "om.entry.title"
	PredicateEntrySummary          = "om.entry.summary"
	PredicateEntryCadence          = "om.entry.cadence"
	PredicateEntryTrigger          = "om.entry.trigger"
	PredicateEntryInputs           = "om.entry.inputs"
	PredicateEntryStakeholders     = "om.entry.stakeholders"
	PredicateEntryConstraints      = "om.entry.constraints"
	PredicateEntrySourceConfidence = "om.entry.source_confidence"
	PredicateEntryStatus           = "om.entry.status"
)

Predicate constants for operating-model triples. All predicates live under the om.* or user.operating_model.* namespace so they can be queried cleanly without conflicting with other teams-memory categories.

View Source
const TripleSource = "operating_model"

TripleSource identifies operating-model triples in the Source field. This matches the convention from semstreams' agentic graph_writer where the source names the producing component.

Variables

This section is empty.

Functions

func EntryEntityID

func EntryEntityID(org, platform, entryID string) string

EntryEntityID constructs the 6-part entity ID for an operating-model entry. Format: {org}.{platform}.user.teams.om-entry.{entryID}

Panics if any input part is empty or contains a dot.

func IsValidLayer

func IsValidLayer(name string) bool

IsValidLayer reports whether name is one of the five canonical layer names.

func LayerEntityID

func LayerEntityID(org, platform, userID, layer string) string

LayerEntityID constructs the 6-part entity ID for a per-user layer checkpoint. Format: {org}.{platform}.user.teams.om-layer.{userID}-{layer}

The instance part ({userID}-{layer}) is treated as opaque — callers should not attempt to reverse-parse it. Both userIDs and layer names may contain hyphens and underscores, so the boundary is not unambiguously recoverable from the string alone. Use LayerEntityID whenever a layer identifier is needed, not manual string concatenation.

Panics if any input part is empty, contains a dot, or if layer is not one of the canonical layer names.

func LayerTriples

func LayerTriples(
	ref ProfileRef,
	layer string,
	checkpointSummary string,
	entries []Entry,
	now time.Time,
) []message.Triple

LayerTriples returns the triples that describe an approved layer checkpoint and all of its entries, plus the profile-root links that connect the layer into the user's profile.

The caller is responsible for deduplicating profile-root links across multiple layer writes (e.g. by using an "upsert" graph operation). entries is treated as approved content; each entry's Validate() should have passed before this call.

now is captured in each triple's Timestamp field so all triples from a single approval share the same time.

func Layers

func Layers() []string

Layers returns the canonical interview order. The returned slice is a copy so callers can safely mutate it without affecting package state.

func ProfileEntityID

func ProfileEntityID(org, platform, userID string) string

ProfileEntityID constructs the 6-part entity ID for a user's operating-model profile root. Format: {org}.{platform}.user.teams.profile.{userID}

Panics if any input part is empty or contains a dot; callers are responsible for supplying well-formed identifiers.

Types

type EmptyProfileReader

type EmptyProfileReader struct{}

EmptyProfileReader always reports no profile. Used as the default when a real graph client is not wired.

func (EmptyProfileReader) ReadOperatingModel

func (EmptyProfileReader) ReadOperatingModel(_ context.Context, _, _, _ string) (*ProfileResult, error)

ReadOperatingModel implements ProfileReader. No I/O — always returns nil.

type Entry

type Entry struct {
	// EntryID is the stable identifier for this entry. Callers should supply a
	// UUID or other dot-free string. Used as the instance part of the entity ID.
	EntryID string `json:"entry_id"`

	// Title is a short human-readable label for the entry.
	Title string `json:"title"`

	// Summary is a one-or-two-sentence description.
	Summary string `json:"summary"`

	// Cadence is an optional cadence string (e.g., "weekly", "daily", "quarterly").
	Cadence string `json:"cadence,omitempty"`

	// Trigger is an optional trigger description (e.g., "Monday 9am").
	Trigger string `json:"trigger,omitempty"`

	// Inputs lists the inputs this entry depends on.
	Inputs []string `json:"inputs,omitempty"`

	// Stakeholders lists the people or systems involved.
	Stakeholders []string `json:"stakeholders,omitempty"`

	// Constraints lists the constraints that apply.
	Constraints []string `json:"constraints,omitempty"`

	// SourceConfidence is ConfidenceConfirmed or ConfidenceSynthesized.
	// Defaults to ConfidenceConfirmed if empty.
	SourceConfidence string `json:"source_confidence,omitempty"`

	// Status is StatusActive, StatusUnresolved, or StatusSuperseded.
	// Defaults to StatusActive if empty.
	Status string `json:"status,omitempty"`
}

Entry is a single structured fact captured during a layer of the operating-model interview. Fields match OB1's schema.sql one-for-one so operating-model exports, if ever added, are a templated graph query rather than a schema migration.

func (*Entry) ResolvedSourceConfidence

func (e *Entry) ResolvedSourceConfidence() string

ResolvedSourceConfidence returns SourceConfidence or the default ConfidenceConfirmed when empty.

func (*Entry) ResolvedStatus

func (e *Entry) ResolvedStatus() string

ResolvedStatus returns Status or the default StatusActive when empty.

func (*Entry) Validate

func (e *Entry) Validate() error

Validate checks that required fields are present and enum fields hold canonical values. Required fields: EntryID, Title, Summary.

type GraphProfileReader

type GraphProfileReader struct {
	// contains filtered or unexported fields
}

GraphProfileReader implements ProfileReader by querying the ENTITY_STATES KV bucket for operating-model entities. It reconstructs []Entry from predicate-per-field triples stored by the graph-ingest component.

All KV operations go through semstreams' natsclient.KVStore wrapper.

func NewGraphProfileReader

func NewGraphProfileReader(ctx context.Context, nc *natsclient.Client, bucketName string, logger *slog.Logger) (*GraphProfileReader, error)

NewGraphProfileReader creates a reader backed by the named KV bucket. The caller passes the natsclient.Client and bucket name; the reader opens the bucket and wraps it in a KVStore. Returns an error if the bucket doesn't exist or isn't reachable.

func (*GraphProfileReader) ReadOperatingModel

func (r *GraphProfileReader) ReadOperatingModel(ctx context.Context, org, platform, userID string) (*ProfileResult, error)

ReadOperatingModel implements ProfileReader. It fetches the user's profile entity for the version number, then scans for all om-entry.* entities and reconstructs typed Entry objects from their triples.

type LayerApproved

type LayerApproved struct {
	// UserID is the profile owner. Used as the instance part of profile and
	// layer entity IDs.
	UserID string `json:"user_id"`

	// LoopID is the agentic loop that produced the approval. Used by
	// teams-memory to correlate the graph mutation with its originating loop.
	LoopID string `json:"loop_id"`

	// Layer is one of the five canonical layer names.
	Layer string `json:"layer"`

	// ProfileVersion is the profile version this layer belongs to (starts at 1).
	// Monotonically increments when the user re-runs the full interview.
	ProfileVersion int `json:"profile_version"`

	// CheckpointSummary is the user-approved natural-language summary of the layer.
	CheckpointSummary string `json:"checkpoint_summary"`

	// Entries is the structured list of facts captured during this layer.
	Entries []Entry `json:"entries"`

	// ApprovedAt is the timestamp of user approval. Populated by the publisher.
	ApprovedAt time.Time `json:"approved_at"`
}

LayerApproved is the payload emitted by the /onboard command handler when a user approves a layer checkpoint. It carries everything teams-memory needs to write the approved layer and its entries into the graph.

Message type: operating_model.layer_approved.v1.

func (*LayerApproved) MarshalJSON

func (p *LayerApproved) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler using the Alias pattern to avoid recursion via the Payload interface.

func (*LayerApproved) Schema

func (p *LayerApproved) Schema() message.Type

Schema implements message.Payload. Schema returns static constants so it remains callable on a zero-value receiver; the payload registry invokes Schema() on a freshly constructed payload during init-time validation.

func (*LayerApproved) Triples

func (p *LayerApproved) Triples(org, platform string) []message.Triple

Triples converts an approved layer into a slice of graph triples ready for publication on graph.mutation.{loopID}. Callers must call Validate() first; this method assumes all fields are present and valid, including ApprovedAt.

func (*LayerApproved) UnmarshalJSON

func (p *LayerApproved) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler using the Alias pattern to avoid recursion via the Payload interface.

func (*LayerApproved) Validate

func (p *LayerApproved) Validate() error

Validate implements message.Payload.

type ProfileContext

type ProfileContext struct {
	// UserID is the profile owner.
	UserID string `json:"user_id"`

	// LoopID is the loop this context is being delivered to.
	LoopID string `json:"loop_id"`

	// ProfileVersion is the version of the operating-model profile the
	// OperatingModel slice was assembled from. Zero if no profile exists yet.
	ProfileVersion int `json:"profile_version"`

	// OperatingModel is the operating-model slice of the context. Populated
	// from the user's profile triples in the graph. Empty if the user has
	// not completed an onboarding interview yet.
	OperatingModel ProfileContextSlice `json:"operating_model"`

	// LessonsLearned is the lessons-learned slice. Reserved — not populated
	// in v1. Future hydrator passes will fill this from
	// compaction-extracted triples.
	LessonsLearned ProfileContextSlice `json:"lessons_learned"`

	// TokenBudget is the total token budget applied when assembling this
	// payload. The sum of OperatingModel.TokenCount and LessonsLearned.TokenCount
	// should not exceed it.
	TokenBudget int `json:"token_budget"`

	// AssembledAt is the timestamp of assembly.
	AssembledAt time.Time `json:"assembled_at"`
}

ProfileContext is the assembled context payload teams-memory publishes on loop-starting events. The teams-loop hydrator consumes it and prepends a "How this user works" section to the system prompt.

The payload shape reserves fields for multiple memory categories. v1 only populates OperatingModel; future PRs will fill LessonsLearned.

Message type: operating_model.profile_context.v1.

func (*ProfileContext) HasOperatingModel

func (p *ProfileContext) HasOperatingModel() bool

HasOperatingModel reports whether the operating-model slice carries any rendered content — a quick check for consumers deciding whether to inject.

func (*ProfileContext) MarshalJSON

func (p *ProfileContext) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler using the Alias pattern to avoid recursion via the Payload interface.

func (*ProfileContext) Schema

func (p *ProfileContext) Schema() message.Type

Schema implements message.Payload. Schema returns static constants so it remains callable on a zero-value receiver; the payload registry invokes Schema() on a freshly constructed payload during init-time validation.

func (*ProfileContext) SystemPromptPreamble

func (p *ProfileContext) SystemPromptPreamble() string

SystemPromptPreamble renders the payload into the final string the teams-loop hydrator prepends to the system prompt. Returns "" when there is nothing to inject. Slice content is trimmed of surrounding whitespace and terminated with exactly one newline to keep the rendered prompt stable regardless of producer formatting.

func (*ProfileContext) UnmarshalJSON

func (p *ProfileContext) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler using the Alias pattern to avoid recursion via the Payload interface.

func (*ProfileContext) Validate

func (p *ProfileContext) Validate() error

Validate implements message.Payload.

type ProfileContextSlice

type ProfileContextSlice struct {
	// Content is the rendered natural-language text for this slice, ready to
	// prepend to the system prompt.
	Content string `json:"content"`

	// TokenCount is the estimated token count for Content.
	TokenCount int `json:"token_count"`

	// EntryCount is the number of distinct entries condensed into Content.
	// Informational; useful for telemetry and UI displays.
	EntryCount int `json:"entry_count"`
}

ProfileContextSlice is a single category of injected context.

type ProfileReader

type ProfileReader interface {
	ReadOperatingModel(ctx context.Context, org, platform, userID string) (*ProfileResult, error)
}

ProfileReader reads a user's current operating-model profile from the knowledge graph.

A nil *ProfileResult with a nil error signals "no profile yet" — the assembler produces an empty operating-model slice and downstream consumers skip injection.

type ProfileRef

type ProfileRef struct {
	// Org is the organization part of the entity ID.
	Org string
	// Platform is the platform part of the entity ID.
	Platform string
	// UserID is the instance part for the profile entity.
	UserID string
	// Version is the current operating-model profile version (starts at 1).
	Version int
}

ProfileRef identifies a user's operating-model profile in the 6-part entity-ID namespace. It is the minimum information needed to emit triples.

type ProfileResult

type ProfileResult struct {
	Entries []Entry
	Version int
}

ProfileResult holds the output of a ProfileReader query.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL