Skip to content

Latest commit

 

History

History
179 lines (139 loc) · 12.4 KB

File metadata and controls

179 lines (139 loc) · 12.4 KB

Architecture

All src/ paths below are relative to packages/plugin/ — the published npm package.

Pattern Overview

Overall: Use a plugin-driven orchestration pattern centered on @opencode-ai/plugin entrypoints in src/index.ts.

Key Characteristics:

  • Route all OpenCode integration through thin adapters in src/plugin/ and keep feature logic in src/hooks/, src/features/, and src/tools/.
  • Use SQLite-backed durable state from src/features/magic-context/storage*.ts for tags, pending ops, compartments, memories, dreamer queue state, and per-session cache-stability watermarks (cleared_reasoning_through_tag, stripped_placeholder_ids).
  • Use hidden subagents from src/agents/*.ts plus prompt builders in src/features/magic-context/dreamer/task-prompts.ts, src/features/magic-context/sidekick/agent.ts, and src/hooks/magic-context/compartment-prompt.ts.
  • Replay all persistent message mutations (reasoning clearing, placeholder stripping) on every transform pass — including defer passes — so stripped state survives OpenCode's message rebuilds without re-triggering a cache bust.

Layers

Plugin bootstrap:

  • Purpose: Register the plugin, load config, wire agents, hooks, commands, and tools.
  • Location: src/index.ts
  • Contains: Plugin factory, config mutation, hidden agent registration.
  • Depends on: src/config/index.ts, src/plugin/, src/features/builtin-commands/commands.ts, src/shared/model-requirements.ts.
  • Used by: Bun build output at dist/index.js and OpenCode plugin loading.

Plugin adapters:

  • Purpose: Keep OpenCode-facing handlers small and delegate real work.
  • Location: src/plugin/event.ts, src/plugin/messages-transform.ts, src/plugin/tool-registry.ts, src/plugin/hooks/create-session-hooks.ts
  • Contains: Hook wrappers, tool registration, per-session hook construction.
  • Depends on: src/hooks/magic-context/, src/tools/, src/features/magic-context/.
  • Used by: src/index.ts.

Magic-context runtime:

  • Purpose: Execute message transforms, lifecycle hooks, nudging, compaction reactions, command handling, and historian coordination.
  • Location: src/hooks/magic-context/
  • Contains: Transform pipeline, postprocess phase, event handlers, command handlers, prompt hashing, compartment runners.
  • Depends on: src/features/magic-context/, src/shared/, src/agents/magic-context-prompt.ts.
  • Used by: src/plugin/hooks/create-session-hooks.ts and src/plugin/event.ts.

Core feature services:

  • Purpose: Encapsulate reusable stateful services behind pure or narrow APIs.
  • Location: src/features/magic-context/
  • Contains: Storage access, scheduler, tagger, compaction handler, memory system, dreamer queue/runner/scheduler, sidekick support.
  • Depends on: src/shared/ and Bun SQLite.
  • Used by: src/hooks/magic-context/, src/plugin/tool-registry.ts, and src/index.ts.

Tool surface:

  • Purpose: Expose agent tools with validated schemas and storage-backed execution.
  • Location: src/tools/ctx-reduce/tools.ts, src/tools/ctx-expand/tools.ts, src/tools/ctx-note/tools.ts, src/tools/ctx-memory/tools.ts
  • Contains: Tool definitions, argument schemas, action gating, user-facing result formatting.
  • Depends on: src/features/magic-context/ and src/hooks/magic-context/read-session-chunk.ts.
  • Used by: src/plugin/tool-registry.ts.

Configuration and shared utilities:

  • Purpose: Centralize config parsing, defaults, path resolution, logging, and SDK normalization.
  • Location: src/config/ and src/shared/
  • Contains: Zod schemas, config merging, data-path helpers, logger, JSONC parsing, model helpers.
  • Depends on: Node built-ins and Zod.
  • Used by: All other layers.

CLI:

  • Purpose: Provide a standalone interactive setup wizard runnable via bunx or npx outside of OpenCode.
  • Location: src/cli/
  • Contains: Setup orchestration (src/cli/setup.ts), config-path detection (src/cli/config-paths.ts), OpenCode integration helpers (src/cli/opencode-helpers.ts), prompt wrappers (src/cli/prompts.ts).
  • Depends on: @clack/prompts, Node built-ins; no dependency on plugin runtime layers.
  • Used by: dist/cli.js built separately as a Node ESM target.

Data Flow

Plugin startup:

  1. Load and merge config from src/config/index.ts — prefer project-root magic-context.jsonc, then .opencode/magic-context.*, then user config.
  2. Build session hooks in src/plugin/hooks/create-session-hooks.ts — create the tagger, scheduler, and compaction handler.
  3. Register tools in src/plugin/tool-registry.ts — open the SQLite database, initialize embeddings, and expose ctx_reduce, ctx_expand, ctx_note, and conditional ctx_memory.
  4. Register OpenCode entrypoints in src/index.ts — bind message transforms, event hooks, command hooks, and hidden agents.

Session transform pipeline:

  1. Enter createMagicContextHook() in src/hooks/magic-context/hook.ts — open persistent storage, set up in-memory maps, and create the transform.
  2. Run the transform from src/hooks/magic-context/transform.ts — tag messages, load session state, prepare compartment injection, and schedule deferred work. On every pass (including defer), replay persisted reasoning clearing using replayClearedReasoning() and replayStrippedInlineThinking() from src/hooks/magic-context/strip-content.ts to maintain stripped state when OpenCode rebuilds messages from its own DB.
  3. Run postprocessing in src/hooks/magic-context/transform-postprocess-phase.ts — apply pending ops, heuristic cleanup, reasoning cleanup, stale reduce-call cleanup, compartment rendering, and nudge placement. Stripped placeholder message IDs are read from stripped_placeholder_ids in session_meta (via src/features/magic-context/storage-meta-persisted.ts) and replayed on every pass; the persisted set is updated when new empty shells are detected on cache-busting passes only.
  4. Persist session state through storage helpers exported by src/features/magic-context/storage.ts.

System prompt stability:

  • Freeze the Today's date: line in the system prompt on defer passes using a per-session stickyDateBySession map in src/hooks/magic-context/system-prompt-hash.ts. Update the sticky date only on cache-busting passes. This prevents a midnight date flip from causing a spurious cache rebuild.
  • Track the reasoning-clearing watermark (cleared_reasoning_through_tag column in session_meta) as a persisted integer so clearing survives across OpenCode message rebuilds.

Note nudge trigger gating:

  • The todowrite note-nudge fires in src/hooks/magic-context/hook-handlers.ts only when ALL todo items have a terminal status (completed or cancelled). Intermediate todowrite calls during active work do not trigger the nudge.

Memory and search flow:

  1. Create, update, merge, archive, list, or search memories through src/tools/ctx-memory/tools.ts.
  2. Store canonical records in src/features/magic-context/memory/storage-memory.ts and sync full-text search through the FTS triggers created in src/features/magic-context/storage-db.ts.
  3. Generate and store embeddings through src/features/magic-context/memory/embedding.ts and src/features/magic-context/memory/storage-memory-embeddings.ts.
  4. Inject cached project memories into <session-history> through src/hooks/magic-context/inject-compartments.ts.

Dreamer flow:

  1. Detect eligible projects during message.updated handling in src/hooks/magic-context/hook.ts.
  2. Enqueue projects on a schedule through src/features/magic-context/dreamer/scheduler.ts and src/features/magic-context/dreamer/queue.ts.
  3. Serialize dream runs with the lease in src/features/magic-context/dreamer/lease.ts.
  4. Spawn one child session per task from src/features/magic-context/dreamer/runner.ts using prompts from src/features/magic-context/dreamer/task-prompts.ts.

Command augmentation flow:

  1. Register /ctx-status, /ctx-flush, /ctx-recomp, /ctx-aug, and /ctx-dream in src/features/builtin-commands/commands.ts.
  2. Intercept command execution in src/hooks/magic-context/command-handler.ts.
  3. Run sidekick augmentation from src/features/magic-context/sidekick/agent.ts or queue dream work through src/features/magic-context/dreamer/runner.ts.
  4. Send ignored notifications or real user prompts through src/hooks/magic-context/send-session-notification.ts.

Key Abstractions

Magic Context hook:

  • Purpose: Own the runtime state for one plugin instance.
  • Location: src/hooks/magic-context/hook.ts, src/hooks/magic-context/index.ts
  • Pattern: Composition root that returns OpenCode hook handlers.

Tool registry:

  • Purpose: Gate tool availability by config and persistent-storage readiness.
  • Location: src/plugin/tool-registry.ts
  • Pattern: Registry builder with conditional feature exposure.

Memory store:

  • Purpose: Keep project-scoped durable knowledge searchable and mergeable.
  • Location: src/features/magic-context/memory/storage-memory.ts, src/features/magic-context/memory/storage-memory-fts.ts, src/features/magic-context/memory/storage-memory-embeddings.ts
  • Pattern: SQLite repository plus FTS and embedding side tables.

Dream queue and lease:

  • Purpose: Run at most one dream worker at a time and survive restarts.
  • Location: src/features/magic-context/dreamer/queue.ts, src/features/magic-context/dreamer/lease.ts, src/features/magic-context/dreamer/storage-dream-state.ts
  • Pattern: SQLite-backed queue plus cooperative lease lock.

Agent prompt pack:

  • Purpose: Keep hidden-agent identities and prompt text isolated from runtime wiring.
  • Location: src/agents/dreamer.ts, src/agents/historian.ts, src/agents/sidekick.ts, src/agents/magic-context-prompt.ts
  • Pattern: Constants plus prompt builders.

Content stripping and replay:

  • Purpose: Strip reasoning, inline thinking, placeholder shells, and structural noise from messages, and replay those operations on every transform pass to maintain stable message content across OpenCode's message rebuilds.
  • Location: src/hooks/magic-context/strip-content.ts
  • Pattern: Stateless strip functions paired with persisted watermarks (cleared_reasoning_through_tag, stripped_placeholder_ids) read from session_meta via src/features/magic-context/storage-meta-persisted.ts.

Persisted session meta:

  • Purpose: Store per-session scalars and JSON blobs that must survive across transform passes and OpenCode restarts.
  • Location: src/features/magic-context/storage-meta-shared.ts, src/features/magic-context/storage-meta-persisted.ts, src/features/magic-context/storage-meta-session.ts
  • Pattern: session_meta SQLite table with ensureColumn() migrations; typed row interfaces with runtime guards.

Entry Points

CLI entry:

  • Location: src/cli/index.ts
  • Triggers: Executed as the opencode-magic-context bin target via bunx or npx.
  • Responsibilities: Dispatch the setup wizard sub-command; print usage on unknown commands.

Plugin entry:

  • Location: src/index.ts
  • Triggers: OpenCode loads the package entry declared in package.json.
  • Responsibilities: Load config, disable the plugin when OpenCode auto-compaction is active, register hidden agents, hooks, commands, and tools.

Message transform entry:

  • Location: src/plugin/messages-transform.ts
  • Triggers: experimental.chat.messages.transform
  • Responsibilities: Delegate the mutable message pipeline to the magic-context hook.

Event entry:

  • Location: src/plugin/event.ts
  • Triggers: OpenCode session and message lifecycle events.
  • Responsibilities: Forward lifecycle events to the runtime event handler.

Tool entry:

  • Location: src/plugin/tool-registry.ts
  • Triggers: Plugin initialization.
  • Responsibilities: Open storage, normalize arg schemas, and expose the supported tool set.

Error Handling

Strategy: Fail closed when persistent storage is unavailable in src/plugin/tool-registry.ts and src/hooks/magic-context/hook.ts; fail open inside per-turn handlers by logging and skipping unsafe mutations; stop OpenCode command fallthrough with sentinel errors from src/hooks/magic-context/command-handler.ts.

Cross-Cutting Concerns

Logging: Use buffered file logging from src/shared/logger.ts and write to the temp-file path returned by getLogFilePath().

Caching: Use deferred reductions, cached memory-block injection, per-session TTL tracking, and anchored nudge placement from src/hooks/magic-context/.

Storage: Use the SQLite database created by src/features/magic-context/storage-db.ts under the OpenCode data directory resolved by src/shared/data-path.ts.