Dashboard › opencode › Distillation
7d91b0f1-3398-491f-8c0a-e791efda2926["lore_tm_v1_gtD3R7IG96MjMGss8gdjLowGsJeUAypRTuySXsao5mA","lore_tm_v1_pi-sveKdmHXarfyPS1dmhzAnMgyKBdVAeHmaLEy8C_s","lore_tm_v1_esOtO0eWjXtjHcWOyh6O7AqW29rtL239R6qd3FdgX2o","lore_tm_v1_QwM5Yu2lEJjICzqd8uu4QCX415kfc4QqFGS-xEz8Z6Q","lore_tm_v1_qk5JQ8P1cydzLLWY9-X_3C60f9yJ_KUAwwQTztHNZOs","lore_tm_v1_Uc_O51CzsFpW2CRjT4U2zz4fcvuonl5QGjJDe2z8Vo4"]
Date: September 9, 2026
/home/byk/Code/opencode-v2-pilot/packages/core/src/plugin/: warming.ts, vcs/hg.ts, vcs/git.ts, variant.ts, update.ts, supervisor.ts, source-directory.ts, skill.ts, service.ts, sdk.ts, provider.ts, promise.ts, plan.ts, optimize.ts, module.ts, models-dev.ts, mcp-codemode-exclusion.ts, internal.ts, instance.ts, host.ts, hooks.ts, command.ts, and agent.ts./home/byk/Code/opencode-v2-pilot/packages/core/src/plugin/websearch/: tavily.ts, parallel.ts, mcp.ts, index.ts, firecrawl.ts, and exa.ts./home/byk/Code/opencode-v2-pilot/packages/core/src/plugin/provider/: cohere.ts, cloudflare-workers-ai.ts, cloudflare-ai-gateway.ts, cerebras.ts, azure.ts, anthropic.ts, amazon-bedrock.ts, alibaba.ts, gateway.ts, factory.ts, dynamic.ts, digitalocean.ts, configured.ts, google-vertex.ts, gitlab.ts, github-copilot.ts, llmgateway.ts, kilo.ts, lmstudio.ts, mistral.ts, zenmux.ts, perplexity.ts, openrouter.ts, opencode.ts, xai.ts, openai.ts, vllm.ts, openai-compatible.ts, vercel.ts, ollama.ts, venice.ts, nvidia.ts, modal.ts, sap-ai-core.ts, sdk-factory.ts, and snowflake-cortex.ts./home/byk/Code/opencode-v2-pilot/packages/core/src/config/plugin/: worktree.ts, websearch.ts, tool-output.ts, source.ts, snapshot.ts, skill.ts, skill-file.ts, shell.ts, reference.ts, provider.ts, policy.ts, mcp.ts, location-watcher.ts, instruction.ts, image.ts, formatter.ts, entry-observer.ts, compaction.ts, command.ts, and agent.ts./home/byk/Code/opencode-v2-pilot/packages/core/src/config/discovery.ts defines config names ["opencode.json", "opencode.jsonc"], supports optional global?: AbsolutePath, resolves global roots from global.config, ~/.claude, and ~/.agents, honors options?.global !== false, resolves parents so missing children respect symlinked global roots, and prevents global sources from re-entering through the project walk.define from @opencode/plugin/effect/plugin, including worktree.ts, websearch.ts, tool-output.ts, snapshot.ts, skill.ts, shell.ts, reference.ts, formatter.ts, compaction.ts, command.ts, location-watcher.ts, agent.ts, image.ts, mcp.ts, policy.ts, provider.ts, and instruction.ts; entry-observer.ts instead imports type EventDomain from @opencode/plugin/effect/event./home/byk/Code/opencode-v2-pilot/packages/core/src/config/plugin/source.ts imports ConfigPlugin from @opencode/schema/config/plugin, Host from @opencode/plugin/host, and PluginSourceDirectory from ../../plugin/source-directory.js; it supports configured local plugins outside config roots, avoids duplicate watching of {plugin,plugins} directories, logs configured-watch failures, warns when a configured plugin path is not a directory, and checks package.json under either the target directory or the target file’s parent./home/byk/Code/opencode-v2-pilot/packages/core/src/config/normalize.ts:185-190 decodes legacy input.plugin entries with ConfigPluginV1.Spec, converts tuple entries to { package: plugin[0], options: plugin[1] }, decodes native input.plugins entries with ConfigPlugin.Plugin, and combines both into encoded.plugins = [...legacyPlugins, ...nativePlugins]./home/byk/Code/opencode-v2-pilot/packages/core/src/config/plugin/instruction.ts does nothing when both project and global discovery scopes are absent; resolves global AGENTS.md; excludes the global file from ancestor-walk results when global discovery is disabled; isolates global and project source effects; and combines both file arrays when available./home/byk/Code/opencode-v2-pilot/packages/core/src/config/plugin/policy.ts documents that user-global policy takes priority over repository-authored policy; /home/byk/Code/opencode-v2-pilot/packages/core/src/config/plugin/mcp.ts documents that global timeout defaults merge in config order and each server may override them./home/byk/Code/opencode-lore/packages/opencode/package.json defines @loreai/opencode version 0.40.0, ESM package type, license FSL-1.1-Apache-2.0, description “Three-tier memory architecture for OpenCode — distillation, not summarization,” raw TypeScript entry/export ./src/index.ts, typecheck script tsc --noEmit, and build script echo '@loreai/opencode ships raw TS — no build step needed'.@loreai/opencode declares peer dependency @opencode-ai/plugin: >=1.1.0; dependencies @loreai/core: workspace:* and @loreai/gateway: workspace:*; dev dependencies @opencode-ai/plugin: ^1.1.39, @opencode-ai/sdk: ^1.1.39, and @types/bun: ^1.2.0; published files are src/, README.md, and LICENSE; repository is git+https://github.com/BYK/loreai.git under packages/opencode; npm access is public; author is BYK.>= 22.5, TypeScript with pnpm workspaces, and SQLite in WAL mode with FTS5 full-text search; the database is stored at ~/.local/share/lore/lore.db.packages/core/test/setup.ts and must never use the production database.quality/REVIEW.md; review practices include regression-test discipline, adversarial-order state setup, fan-out registry coverage, recurring bug-class batteries, and the two-reviewer rule.CHANGELOG.md must never be manually bumped or edited because Craft handles both automatically.gh workflow run release.yml -f version=auto for conventional-commit-derived semver or gh workflow run release.yml -f version=0.23.0 for an explicit version. The workflow order is: 1. run scripts/bump-version.sh across all package.json files, 2. generate changelog from conventional commits, 3. create and push release/X.Y.Z, 4. run CI to test and build npm tarballs, standalone binaries, and delta patches, 5. have Craft open a publish issue whose accepted label triggers publishing, 6. publish npm packages through OIDC trusted publishing and create a GitHub Release with binaries and patches. .craft.yml targets 4 npm workspaces, the legacy opencode-lore alias, and GitHub Release artifacts.packages/core/src/temporal.ts, where store() converts parts to text and stores temporal_messages with FTS5, distilled=0/1, and chunk separator \x1f; Tier 2 packages/core/src/distillation.ts, where run() executes resetOrphans() → undistilled retrieval → detectSegments() with time-gap/token splitting and a 16K-token maximum → distillSegment(), and metaDistill() runs when generation-0 count exceeds 20; Tier 3 packages/core/src/gradient.ts, where transform() applies Layer 0 full passthrough, Layer 1 distilled prefix plus compressed raw content, Layer 2 aggressive tool-output stripping, and Layer 3 emergency compression, with caps calibrated from actual API token counts and model pricing.packages/core/src/ltm.ts have categories decision, pattern, preference, architecture, and gotcha; fields are id as UUIDv7, project_id, category, title, content limited to 1200 characters, confidence from 0.0 to 1.0, and cross_project. Creation paths are: 1. LLM curator in packages/core/src/curator.ts, 2. regex-based non-LLM extraction in packages/core/src/pattern-extract.ts, 3. .lore.md import in packages/core/src/agents-file.ts, 4. consolidate() when entry count exceeds maxEntries of 25./home/byk/Code/opencode-lore/packages/opencode/src/index.ts imports only types Hooks, Plugin, and PluginInput from @opencode-ai/plugin; imports log, getGitRemote, discoverWorkspaceRoot, and installFetchInterceptor from @loreai/core; and keeps applyLoreProviderConfig, gatewayAccessHeadersForRemote, probeGateway, shouldForwardUpstreamExtraHeader, and surfaceGatewayUnavailable in ./internal.applyLoreProviderConfig returned undefined, which was pushed into the host hooks array and later crashed dispatch with undefined is not an object (evaluating 'A.event'). Fix: helpers live in packages/opencode/src/internal.ts, while packages/opencode/src/index.ts exports only LorePlugin and the same-reference default. This is guarded by the “plugin entry module export shape” test in test/index.test.ts.packages/opencode/src/index.ts uses KNOWN_GATEWAY_PORTS = [3207, 5673] and resolves in this order: 1. LORE_REMOTE_URL, 2. LORE_GATEWAY_URL, 3. a dynamically imported readPortFile() result from @loreai/gateway, 4. known defaults 3207 and 5673. Unreachable remote or explicit URLs fall through to local discovery.startInProcess() dynamically imports startGateway from @loreai/gateway, calls startGateway({ quiet: true, local: true }), returns http://127.0.0.1:${handle.port}, logs reuse when handle.owned is false, stores the underlying failure in lastGatewayStartError, and returns null on failure. The gateway’s fallback chain is 3207 → 5673 → random.packages/opencode/src/index.ts uses processInitDone, processLoreActive, processLoreBase, and memoized loreInitPromise so concurrent LorePlugin calls do not race during gateway probe/start.projectState, a Map<string, { projectPath: string; gitRemote: string; lastSeenAt: number }> keyed by ctx.project.id; currentProject is only a fallback for requests bypassing chat.headers. Stale project entries are reaped after SESSION_STATE_TTL_MS = 24 * 60 * 60 * 1000 (24 hours); comments estimate each entry at approximately 200 bytes and 100 projects at 20 KB.thisProjectPath = discoverWorkspaceRoot(ctx.worktree || ctx.directory), reuses a cached git remote only when the project’s cached path matches, otherwise calls getGitRemote(thisProjectPath) ?? "", updates projectState, reaps stale entries, and updates currentProject = { path: thisProjectPath, gitRemote: thisGitRemote }.sessionParent, a Map<string, { parentID: string | null; lastSeenAt: number }> with the same 24-hour TTL. resolveParentSession() queries client.session.get({ path: { id: sessionID } }), caches successful results including null, and deliberately does not cache failures so transient errors can be retried rather than permanently misclassifying a real sub-agent.parentID; when non-null, chat.headers emits x-parent-session-id so the gateway recognizes the session as a sub-agent and sizes LTM injection accordingly, matching Claude Code’s native Task-sub-agent signal documented under issue #1300.isInertTestEnv() makes the plugin inert when NODE_ENV === "test" or any process.argv entry contains .test., unless LORE_OPENCODE_FORCE_ACTIVE === "1". Active wiring tests retain NODE_ENV=test and use LORE_GATEWAY_URL with a controlled in-process gateway; this mirrors LORE_PI_FORCE_ACTIVE.log.silenceStderr() suppresses every terminal byte to protect the full-screen TUI while preserving file and Sentry logging. It is skipped in inert test mode. Lore can also be disabled with LORE_DISABLED=1 or LORE_DISABLED=true.Lore failed to start — memory features are unavailable. with the actual lastGatewayStartError. Errors matching not found|not exported|cannot find module are identified as possible stale builds and recommend pnpm --filter @loreai/gateway run bundle or run build for a development checkout; otherwise it advises ensuring @loreai/gateway is installed.config hook sets cfg.compaction = { auto: false, prune: false }, because the gateway handles compaction, and registers 3 hidden workers: lore-distill with description Lore memory distillation worker, lore-curator with description Lore knowledge curator worker, and lore-query-expand with description Lore query expansion worker. Each uses mode: "subagent" and hidden: true; subagent mode is required because OpenCode otherwise defaults to mode: "all" and exposes them in primary Tab and @-mention/skill pickers.chat.headers hook emits x-lore-session-id from input.sessionID, x-lore-agent from input.agent, x-parent-session-id when a parent exists, x-lore-project, paired x-lore-git-remote, and runtime provider ID as x-lore-provider.vllm, ollama, and llamacpp, the plugin maps provider IDs to environment keys using LORE_UPSTREAM_${providerID.toUpperCase().replace(/-/g, "_")} and emits the value as x-lore-upstream-url only if that header is not already present.LORE_UPSTREAM_EXTRA_HEADERS is parsed line-by-line on \r?\n, with each non-empty line split at its first colon. Allowed literal headers are added to the request, while gateway-managed credentials and routing headers are filtered by shouldForwardUpstreamExtraHeader().shouldForwardUpstreamExtraHeader() rejects all names beginning with x-lore-, plus case-insensitive x-api-key, x-goog-api-key, and authorization; provider and Lore credentials are applied by the gateway rather than this plugin hop.gatewayAccessHeadersForRemote() adds { [GATEWAY_AUTH_HEADER]: LORE_GATEWAY_AUTH_TOKEN } only when the normalized selected gatewayBase exactly matches normalized LORE_REMOTE_URL; local gateways do not receive this access token.applyLoreProviderConfig() deep-merges every object-valued cfg.provider.<id> so custom headers, model overrides, and other user options survive while options.baseURL becomes ${gatewayBase}/v1. For openai and openai-codex, it also forces headerTimeout: false; if openai is absent, it creates openai: { options: { baseURL: baseUrl, headerTimeout: false } }.packages/opencode/src/internal.ts: OpenCode can derive Anthropic’s base URL from OPENAI_BASE_URL while stripping /v1, producing http://host/messages; the Lore gateway routes /v1/messages, and the fetch interceptor skips 127.0.0.1 to avoid loops, so the bare path returns 404. OpenCode’s resolveSDK() always passes options.baseURL, preventing @ai-sdk’s loadOptionalSetting() from consulting environment variables, while many providers have no baseURL environment variable at all. Chosen universal fix: iterate through cfg.provider and pin each provider’s options.baseURL.headerTimeout: false overrides OpenCode’s Codex 10-second header deadline because Lore may need longer while preparing context; the gateway owns the foreground request deadline.probeGateway(baseURL, timeoutMs = 1500) requests ${baseURL}/health with an AbortController; loopback URLs use Node http/https directly and accept status 200–299, while non-loopback URLs use fetch(...).ok. Invalid URLs, timeout, and request errors return false, and the timer is always cleared.localhost, localhost., ::1, and IPv4 addresses matching ^127(?:\.\d{1,3}){3}$, after stripping IPv6 brackets and lowercasing the hostname.surfaceGatewayUnavailable() logs to file/Sentry and invokes client?.tui?.showToast({ body: { title: "Lore", message, variant: "error" } }). It is fire-and-forget, guards optional .catch, swallows promise rejection, and catches synchronous throws so missing/headless TUIs or older servers without /tui/show-toast cannot crash a degraded session.getHeaders() includes remote access headers and only emits x-lore-git-remote alongside the exact currentProject.path with which that remote was resolved. Startup logs include active: ${projectPath}, routing through ${gatewayBase}, and dashboard: ${gatewayBase}/ui, all through log, never raw stderr.