Preferences
Per-agent and per-user preference storage for scoped configuration that customizes agent behavior without affecting the global system
This interface is experimental — no production implementation exists yet. The API surface may change.
Overview
The Preferences interface provides kernel-level storage for per-agent and per-user configuration that customizes agent behavior without affecting the global system. Unlike system-wide settings, preferences are scoped — each entry belongs to an agent, user, or system scope — and resolved in cascade order: agent overrides user, user overrides system. Familiar provider analogs include VS Code Settings, Claude Code Scoped Config, and GitHub User Preferences.
Scope Resolution
When an agent requests a preference value, the kernel checks scopes from most specific to least specific. The first match wins.
TypeScript API
import type {
Preferences,
PreferenceEntry,
PreferenceScope,
PreferencesContext,
PreferencesActions,
} from 'osprotocol/system/preferences'PreferenceScope
The three available scopes for a preference entry.
type PreferenceScope = 'agent' | 'user' | 'system'PreferenceEntry
A single preference value with its scope and optional metadata.
interface PreferenceEntry<T = unknown> {
key: string
value: T
scope: PreferenceScope
metadata?: Record<string, unknown>
}PreferencesContext
Read-only access for the context phase of the agent loop.
interface PreferencesContext {
get<T = unknown>(key: string, scope: PreferenceScope): Promise<PreferenceEntry<T> | null>
list(scope: PreferenceScope): Promise<PreferenceEntry[]>
}PreferencesActions
Write operations for the actions phase of the agent loop.
interface PreferencesActions {
set<T = unknown>(key: string, value: T, scope: PreferenceScope): Promise<PreferenceEntry<T>>
remove(key: string, scope: PreferenceScope): Promise<boolean>
}Preferences
Full preferences management interface combining context and actions.
interface Preferences {
get<T = unknown>(key: string, scope: PreferenceScope): Promise<PreferenceEntry<T> | null>
set<T = unknown>(key: string, value: T, scope: PreferenceScope): Promise<PreferenceEntry<T>>
remove(key: string, scope: PreferenceScope): Promise<boolean>
list(scope: PreferenceScope): Promise<PreferenceEntry[]>
}Usage Examples
Read an agent-scoped preference
Agent-scoped preferences take priority over user or system values with the same key.
const entry = await preferences.get<string>('output.format', 'agent')
if (entry) {
console.log(entry.key) // 'output.format'
console.log(entry.value) // 'json'
console.log(entry.scope) // 'agent'
}Set a user-scoped preference
User-scoped preferences apply across agents that have not overridden the key at the agent scope.
await preferences.set('output.format', 'markdown', 'user')Implement the cascade manually
When you need to resolve a value across all scopes in priority order:
async function resolve<T>(
preferences: Preferences,
key: string,
): Promise<T | null> {
const scopes: PreferenceScope[] = ['agent', 'user', 'system']
for (const scope of scopes) {
const entry = await preferences.get<T>(key, scope)
if (entry !== null) return entry.value
}
return null
}
const format = await resolve<string>(preferences, 'output.format')Integration
- Settings: System-wide configuration that acts as the baseline before preference scopes are applied
- Environment: Platform-level variables for credentials and deployment targets; preferences handle behavioral customization above that layer
- Registry: Agent registration metadata may include default preference values that seed the agent scope at registration time