Dashboard › opencode › Distillation
299da91c-c494-4750-8a90-10805ff3a07c["lore_tm_v1_9QtYXN2kqR66uzk7lXptBt2OnADkHgNtPzl9mqDQNks","lore_tm_v1_sVlAFBukM5NPcIdCT7RJy0YtnZG-41i83nUHKAd49UQ","lore_tm_v1_bR5wndEv8SVE5nqgO279CxKSVVLwxV2E3jOnjbjzDWY","lore_tm_v1_44QInvzgFXCwBkSRKvBmr0Nya7VB1mvcOSwlUuiBsvk","lore_tm_v1_8WqnUCKP2XjG8HAypHMq8urpyr-j52Mc9a4ZUWA2EDg"]
TransformCallback<Editor>, MakeEditor<State, Editor>, Effect-based Registration.dispose, scoped Transform<Editor>, Reload, Transformable<Editor>, and Failure { state: string; cause: unknown }.CurrentGroup = Context.Reference<RegistrationGroup | undefined>("@opencode/State/CurrentGroup", ...); group(report) provides a group containing failed, a Set<GroupedRegistration>, and report(failure, refresh).disable(group, failure) is idempotent after group.failed; on first failure it synchronously marks the group failed, removes every grouped registration, deduplicates their notify Effects in a Set, and calls group.report(failure, Effect.forEach(notifications, ..., { discard: true })).CurrentBatch = Context.Reference<Batch | undefined>("@opencode/State/CurrentBatch", ...), where Batch contains active, shutdown, and a notification Set; batch(effect) calls run(effect, false), while shutdown(effect) calls run(effect, true).run(effect, shutdown) is wrapped in Effect.uninterruptibleMask; an active non-shutdown nested batch runs directly via restore(effect), otherwise it captures the effect exit, deactivates the batch, executes collected notifications with Effect.exit, combines exits through Exit.asVoidAll([exit, ...notifications]), and returns the original exit.reconcile(root, fork, work) awaits fork(work()); it suppresses an interrupt-only failure when root.state._tag === "Closed", but otherwise yields the fiber exit. inherit captures CurrentBatch and returns a function that provides it to another Effect.State.create(options) maintains state, a Set of transforms, dirty, closed, and monotonically increasing version; invalidate() sets dirty = true and increments version.State.create().get() returns the existing value when closed or clean; otherwise it repeatedly creates next = options.initial(), wraps it with options.editor(next), and runs transforms in insertion order. A grouped transform exception calls disable(group, { state: options.name ?? "anonymous", cause }); a version change during rebuilding restarts from a fresh candidate, while ungrouped failures propagate.notify Effect per State so a batch Set holds it at most once. notify exits when closed, calls get(), invokes optional options.notify(value), and is traced with Effect.withSpan("State.notify").changed is uninterruptible around invalidation and batch handling: it returns if closed; in a shutdown batch it sets closed = true; in an ordinary active batch it adds stable notify; outside a batch it runs restore(notify).State.transform is traced as "State.transform" and annotates the span with state = options.name ?? "anonymous". It returns a no-op disposal if the current group already failed; otherwise it registers the transform, links it to the group, installs scoped finalization, calls changed, and returns an idempotent uninterruptible dispose that removes the exact transform and calls changed only when removal succeeded. reload delegates to changed.defaultID = ID.make("build"); agent state is State.create<Data, Editor> named "agent" with agents: new Map(), editor operations list, get, default, update, and remove, and notification bus.publish(Agent.Event.Updated, {}).pipe(Effect.asVoid).Info.default(id) and receive four additional allowed external_directory permissions: path.join(global.data, "shell", "*", "*"), path.join(global.data, "tool-output", "*"), path.join(global.tmp, "*"), and path.join(global.config, "*"); every update restores current.id = id.mode === "subagent" or hidden === true. Default selection order is: 1. configured default, 2. agent ID "build", 3. first selectable agent in map iteration order. select() falls back to { id: defaultID, info: undefined }; list() puts the selected default first and removes its duplicate from the remainder.makeLocationNode({ service: Service, layer, deps: [Bus.node, Global.node] }); its interface exposes Effect methods get, resolve, select, and list plus State.Transformable<Editor>.@opencode/schema/agent defines branded Agent.ID and Agent.Name, annotated Agent.Color, and Agent.Info fields: id, name, optional model, request, optional system, optional description, mode in "subagent" | "primary" | "all", hidden, optional color, optional positive-integer steps, and permissions.Agent.Info.default(id) sets name = Name.make(id), empty request settings/headers/body, mode: "primary", hidden: false, and permissions in this exact order: 1. allow * on *; 2. ask external_directory on *; 3. ask read on *.env; 4. ask read on *.env.*; 5. allow read on *.env.example.Updated with { type: "agent.updated", schema: {} }; Event exposes Updated and Definitions: inventory(Updated)."opencode.config.agent". Its legacy source patterns are "{agent,agents}/**/*.md" with primary: false and "{mode,modes}/*.md" with primary: true; synchronized source directories are "agent", "agents", "mode", and "modes".discover; unreadable, empty, or undecodable files are omitted. load() flattens documents from all config.entries(), while reload replaces loaded.documents and then calls ctx.agent.reload().PubSub.sliding<void>(1) and one shared trigger feed. It eagerly subscribes separate scoped fibers to relevant config.changes() and "config.updated" events, subscribes before the initial scan to avoid races, then serially reloads through Stream.debounce("100 millis").isAgentSource(entries, file) accepts any event at or below <root>/{agent,agents,mode,modes} using FSUtil.contains; it intentionally performs no file-suffix check because directory-level rename events may not contain per-file paths."default_agent" via editor.default(Agent.ID.make(configuredDefault)), and appends global permissions to every existing agent. It then processes configured agents: disabled removes the agent; otherwise it updates model (id, providerID, optional variant), request headers/body, system, description, mode, hidden, color, steps, and expanded per-agent permissions.expandPermissions expands home references only for path-resolving actions "external_directory", "read", and "edit"; shell/bash resources remain unchanged because safe $HOME expansion would require shell-aware parsing.expandHome(resource, home) maps exact "~" or "$HOME" to home; handles "~/", "$HOME/", and "$HOME\\"; selects path.posix or path.win32 based on whether home is POSIX-absolute; and leaves all other resources unchanged.discover scans both legacy patterns with { cwd: directory, absolute: true, dot: true, symlink: true }, sorts each result, records { directory, filepath, primary }, flattens all results, and falls back to [] on failure.decode parses markdown, derives nested agent names by making the path relative, normalizing \ to /, stripping the leading agent|agents|mode|modes directory and .md, and trimming the markdown body. Unknown frontmatter keys trigger legacy decoding through ConfigAgentV1.Info followed by ConfigMigrateV1.migrateAgent; modern decoding uses ConfigAgent.Info with the body as system.agents: { [name]: ... }; files from mode/modes force mode: "primary". The final result is new Document({ type: "document", path: AbsolutePath.make(file.filepath), info }).429114122aa1170fd171aa3f0a2bb97e5a6bd6aa, packages/opencode/src/index.ts contains agent definitions "lore-distill" near line 351, "lore-curator" near line 356, and "lore-query-expand" near line 361.SessionRequestKind = "primary" | "compaction" | "title" | "generate". SessionModelRequest, SessionHttpRequest, and SessionHttpResponse all carry sessionID, agent, model, and kind; model requests additionally expose mutable optional baseURL and headers, HTTP requests expose mutable request, and HTTP responses retain the request plus mutable response.SessionPrompt contains sessionID, messageID, mutable deep prompt, optional metadata, and delivery. SessionContext contains sessionID, agent, model, mutable system, messages, and tools, mutable deep generation overrides, and mutable providerOptions.{ retry: false } | { retry: true; delay: number }; SessionRetry carries sessionID, agent, model, error, attempt, and mutable decision.SessionHooks defines prompt, context, "model.request", "http.request", "http.response", and retry. SessionDomain selects create, get, switchAgent, switchModel, prompt, generate, command, synthetic, interrupt, rename, move, wait, and context from SessionApi, plus hook: ModelHooks<SessionHooks>.Context includes app, location, options, and domains agent, aisdk, catalog, command, event, integration, mcp, generate, permission, plugin, reference, rpc, session, shell, skill, storage, tool, vcs, websearch, and worktree; experimental.terminal exposes only persistent-PTY read, and plugin exposes only list.() => Promise<void> | void; Plugin requires id: string and setup(context) returning cleanup or void, either synchronously or by Promise. define(plugin) returns the plugin unchanged.