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:
- operating_rhythms — recurring cadence and calendar structure
- recurring_decisions — decisions made on a regular schedule
- dependencies — people, systems, and inputs the work relies on
- institutional_knowledge — tribal knowledge and hard-won context
- 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
- func EntryEntityID(org, platform, entryID string) string
- func IsValidLayer(name string) bool
- func LayerEntityID(org, platform, userID, layer string) string
- func LayerTriples(ref ProfileRef, layer string, checkpointSummary string, entries []Entry, ...) []message.Triple
- func Layers() []string
- func ProfileEntityID(org, platform, userID string) string
- type EmptyProfileReader
- type Entry
- type GraphProfileReader
- type LayerApproved
- type ProfileContext
- func (p *ProfileContext) HasOperatingModel() bool
- func (p *ProfileContext) MarshalJSON() ([]byte, error)
- func (p *ProfileContext) Schema() message.Type
- func (p *ProfileContext) SystemPromptPreamble() string
- func (p *ProfileContext) UnmarshalJSON(data []byte) error
- func (p *ProfileContext) Validate() error
- type ProfileContextSlice
- type ProfileReader
- type ProfileRef
- type ProfileResult
Constants ¶
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.
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.
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.
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.
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.
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.
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 ¶
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 ¶
IsValidLayer reports whether name is one of the five canonical layer names.
func LayerEntityID ¶
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 ¶
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 ¶
ResolvedSourceConfidence returns SourceConfidence or the default ConfidenceConfirmed when empty.
func (*Entry) ResolvedStatus ¶
ResolvedStatus returns Status or the default StatusActive when empty.
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 ¶
ProfileResult holds the output of a ProfileReader query.