Skip to content

fix(opencode): initialize plugin hooks correctly#21

Merged
oritwoen merged 4 commits into
mainfrom
fix/opencode-observations-persistence
Mar 12, 2026
Merged

fix(opencode): initialize plugin hooks correctly#21
oritwoen merged 4 commits into
mainfrom
fix/opencode-observations-persistence

Conversation

@oritwoen
Copy link
Copy Markdown
Owner

Pull request

What

OpenCode was receiving the plugin factory as default export instead of a plugin instance, so hooks were never registered and observations were not persisted; this switches the wrapper default to createObsxaPlugin(), aligns wrapper typings, and adds an obsxa tool hook with updated tests so both automatic hook ingestion and explicit observation writes work in real sessions.

Closes

Closes #20

@oritwoen oritwoen added this to the v0.0.4 milestone Mar 12, 2026
@oritwoen oritwoen self-assigned this Mar 12, 2026
@oritwoen oritwoen added the bug Something isn't working label Mar 12, 2026
@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Fix plugin initialization and add obsxa tool hook
🐞 Bug fix ✨ Enhancement

Grey Divider

Walkthroughs

Description
• Export instantiated plugin instance instead of factory function
• Add comprehensive obsxa tool hook for observation management
• Update agent instruction to reference obsxa tool explicitly
• Fix wrapper typings to properly reflect plugin instance export
Diagram
flowchart LR
  A["Plugin Factory"] -->|"instantiate"| B["Plugin Instance"]
  B -->|"register hooks"| C["system.transform Hook"]
  B -->|"register hooks"| D["obsxa Tool Hook"]
  D -->|"supports"| E["add/get/list/search/stats"]
  C -->|"injects"| F["Agent Instructions"]
Loading

Grey Divider

File Changes

1. opencode/index.mjs 🐞 Bug fix +6/-2

Export instantiated plugin instance as default

• Changed default export from factory function to instantiated plugin
• Import createObsxaPlugin and call it to create plugin instance
• Export both named export and instantiated default

opencode/index.mjs


2. opencode/index.d.mts 🐞 Bug fix +4/-1

Align type definitions with plugin instance export

• Updated type definitions to match runtime behavior
• Export instantiated plugin type as default instead of factory
• Declare default as ReturnType<typeof createObsxaPlugin>

opencode/index.d.mts


3. src/opencode.ts ✨ Enhancement +122/-1

Implement obsxa tool hook with observation operations

• Add createObsxaTool() function implementing full observation CRUD operations
• Support operations: add, get, list, search, stats with proper schema validation
• Update agent instruction to reference "obsxa tool" with operation parameter
• Integrate obsxa tool into plugin hooks during initialization

src/opencode.ts


View more (1)
4. test/opencode.test.ts 🧪 Tests +4/-4

Update tests for obsxa tool naming

• Update test assertions to check for "obsxa tool" instead of "observation tool"
• Maintain existing test coverage for agent instruction injection
• Verify tool availability in system transform hook tests

test/opencode.test.ts


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Mar 12, 2026

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (1) 📎 Requirement gaps (0)

Grey Divider


Action required

1. createObsxaPlugin missing import type📘 Rule violation ✓ Correctness
Description
In opencode/index.d.mts, createObsxaPlugin is only referenced in a type position but is imported
as a value import. This violates the requirement to use import type for type-only imports and can
cause incorrect module/type semantics.
Code

opencode/index.d.mts[R1-4]

+import { createObsxaPlugin } from "obsxa/opencode";
+export { createObsxaPlugin };
+declare const _default: ReturnType<typeof createObsxaPlugin>;
+export default _default;
Evidence
The rule requires type-only identifiers to be imported with import type. The diff shows
createObsxaPlugin imported normally while only used inside ReturnType (a type-only context).

Rule 82475: Use explicit, extension-aware import paths and import type for type-only imports
opencode/index.d.mts[1-4]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`opencode/index.d.mts` imports `createObsxaPlugin` as a value import even though it is only used in a type position (`ReturnType&amp;amp;lt;typeof createObsxaPlugin&amp;amp;gt;`). The compliance rule requires `import type` for type-only imports.
## Issue Context
This is an ESM declaration file (`.d.mts`); `createObsxaPlugin` is not used at runtime in this file, only for typing the default export.
## Fix Focus Areas
- opencode/index.d.mts[1-4]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Instruction references missing tool🐞 Bug ✓ Correctness
Description
experimental.chat.system.transform always injects AGENT_INSTRUCTION telling the agent to use the
"obsxa" tool, but createObsxaTool can return undefined and then Hooks.tool is not registered. This
leads to sessions where the prompt instructs calling a tool that does not exist, causing tool-call
failures.
Code

src/opencode.ts[R180-295]

const AGENT_INSTRUCTION =
-  "When you notice patterns, anomalies, correlations, or interesting measurements during your work, record them using the observation tool for future reference. Types: pattern, anomaly, measurement, correlation, artifact.";
+  "When you notice patterns, anomalies, correlations, or interesting measurements during your work, record them using the obsxa tool (operation=add) for future reference. Types: pattern, anomaly, measurement, correlation, artifact.";
+
+async function createObsxaTool(
+  obsxa: ObsxaInstance,
+  defaultProjectId: string,
+): Promise<Record<string, unknown> | undefined> {
+  try {
+    const pluginToolModule = await import("@opencode-ai/plugin/tool");
+    const pluginTool = pluginToolModule.tool;
+    const schema = pluginTool.schema;
+
+    return pluginTool({
+      description:
+        "Manage obsxa observations: add/get/list/search/stats. Defaults to current OpenCode project when projectId is omitted.",
+      args: {
+        operation: schema.enum(["add", "get", "list", "search", "stats"]),
+        projectId: schema.string().optional(),
+        id: schema.number().optional(),
+        title: schema.string().optional(),
+        description: schema.string().optional(),
+        type: schema
+          .enum(["pattern", "anomaly", "measurement", "correlation", "artifact"])
+          .optional(),
+        source: schema.string().optional(),
+        sourceType: schema
+          .enum(["experiment", "manual", "scan", "computation", "external"])
+          .optional(),
+        confidence: schema.number().min(0).max(100).optional(),
+        query: schema.string().optional(),
+        status: schema.enum(["active", "promoted", "dismissed", "archived"]).optional(),
+        limit: schema.number().optional(),
+      },
+      async execute(args) {
+        const operation = String(args.operation ?? "");
+        const projectId =
+          typeof args.projectId === "string" && args.projectId.length > 0
+            ? args.projectId
+            : defaultProjectId;
+
+        let result: unknown;
+        switch (operation) {
+          case "add": {
+            const title = typeof args.title === "string" ? args.title : "";
+            const source = typeof args.source === "string" ? args.source : "opencode";
+            if (!title) throw new Error("obsxa tool: 'title' is required for add");
+            result = await obsxa.observation.add({
+              projectId,
+              title,
+              description: typeof args.description === "string" ? args.description : undefined,
+              type:
+                typeof args.type === "string"
+                  ? (args.type as
+                      | "pattern"
+                      | "anomaly"
+                      | "measurement"
+                      | "correlation"
+                      | "artifact")
+                  : undefined,
+              source,
+              sourceType:
+                typeof args.sourceType === "string"
+                  ? (args.sourceType as
+                      | "experiment"
+                      | "manual"
+                      | "scan"
+                      | "computation"
+                      | "external")
+                  : undefined,
+              confidence: typeof args.confidence === "number" ? args.confidence : undefined,
+            });
+            break;
+          }
+          case "get": {
+            if (typeof args.id !== "number")
+              throw new Error("obsxa tool: 'id' is required for get");
+            result = await obsxa.observation.get(args.id);
+            break;
+          }
+          case "list": {
+            result = await obsxa.observation.list(projectId, {
+              status:
+                typeof args.status === "string"
+                  ? (args.status as "active" | "promoted" | "dismissed" | "archived")
+                  : undefined,
+            });
+            break;
+          }
+          case "search": {
+            if (typeof args.query !== "string" || args.query.length === 0) {
+              throw new Error("obsxa tool: 'query' is required for search");
+            }
+            result = await obsxa.search.search(
+              args.query,
+              projectId,
+              typeof args.limit === "number" ? args.limit : undefined,
+            );
+            break;
+          }
+          case "stats": {
+            result = await obsxa.analysis.stats(projectId);
+            break;
+          }
+          default:
+            throw new Error(
+              "obsxa tool: unsupported operation; expected one of add/get/list/search/stats",
+            );
+        }
+
+        return JSON.stringify(result, null, 2);
+      },
+    });
+  } catch (error) {
+    logHookError("tool.init", error);
+    return undefined;
+  }
Evidence
The prompt instruction was changed to explicitly name the obsxa tool, but tool registration is
conditional and can be skipped when the dynamic import fails; the system hook still injects the
instruction unconditionally, creating a deterministic mismatch.

src/opencode.ts[180-296]
src/opencode.ts[417-427]
src/opencode.ts[663-673]
package.json[71-86]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The plugin always injects a system instruction telling the agent to use the `obsxa` tool, but tool registration is conditional and can fail (notably because `@opencode-ai/plugin` is an optional peer dependency). This creates sessions where the agent is instructed to call a tool that doesn’t exist.
## Issue Context
`createObsxaTool()` catches dynamic import errors and returns `undefined`, and the hooks return `tool: undefined` in that case. The system prompt injection does not check whether the tool was registered.
## Fix Focus Areas
- src/opencode.ts[180-296]
- src/opencode.ts[417-427]
- src/opencode.ts[663-673]
## Suggested approach
- Keep two instruction variants:
- If `obsxaTool` exists: mention `obsxa` tool.
- Else: revert to generic wording (or omit tool instruction).
- Alternatively, if running under OpenCode requires the tool, throw on tool init failure so the plugin doesn’t run in a partially-enabled state.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Obsxa tool self-observed 🐞 Bug ✓ Correctness
Description
The new "obsxa" tool is not in SKIP_TOOLS, so tool.execute.after will persist an additional
"measurement" observation for every obsxa tool call. This inflates/pollutes stored observations with
meta-records about observation management actions.
Code

src/opencode.ts[R420-427]

+      const obsxaTool = await createObsxaTool(obsxa, projectId);
    return {
+        tool: obsxaTool
+          ? {
+              obsxa: obsxaTool,
+            }
+          : undefined,
Evidence
This PR registers a new tool named "obsxa". The plugin already persists tool calls for all tools not
in SKIP_TOOLS, and the skip list does not include "obsxa", so obsxa tool calls will be recorded as
observations as well.

src/opencode.ts[417-427]
src/opencode.ts[116-126]
src/opencode.ts[518-559]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Using the new `obsxa` tool will be recorded by the generic `tool.execute.after` persistence hook, creating extra measurement observations about the obsxa tool’s own operations.
## Issue Context
The plugin persists all non-skipped tool calls as observations. With the new `obsxa` tool now registered, it will also be persisted unless explicitly skipped.
## Fix Focus Areas
- src/opencode.ts[116-126]
- src/opencode.ts[417-427]
- src/opencode.ts[518-559]
## Suggested approach
- Add `&amp;amp;quot;obsxa&amp;amp;quot;` to `SKIP_TOOLS`, or
- Special-case in `tool.execute.after`:
- `if (toolInput.tool === &amp;amp;quot;obsxa&amp;amp;quot;) return;`
- If you still want analytics, consider recording obsxa tool calls with a different collector and filtering them out from prompt injection/search context.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

4. Default export API changed 🐞 Bug ⛯ Reliability
Description
obsxa-opencode now default-exports a plugin instance (createObsxaPlugin()) instead of the
createObsxaPlugin factory. Code that previously imported the default export and called it as a
factory to pass options will now fail because the default export expects PluginInput.
Code

opencode/index.mjs[R1-6]

+import { createObsxaPlugin } from "obsxa/opencode";
+
+const plugin = createObsxaPlugin();
+
+export { createObsxaPlugin };
+export default plugin;
Evidence
The wrapper’s runtime default export is now the return value of createObsxaPlugin(), and the type
declaration matches that; this is a breaking shape change from “factory function” to “plugin
function”.

opencode/index.mjs[1-6]
opencode/index.d.mts[1-4]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The wrapper package’s default export changed from exporting the factory to exporting an already-created plugin. Any code that treated the default export as a factory (calling it with options) will now misbehave.
## Issue Context
This may be intended for OpenCode compatibility, but it is still an API-shape breaking change for the wrapper package.
## Fix Focus Areas
- opencode/index.mjs[1-6]
- opencode/index.d.mts[1-4]
## Suggested approach
- If you must keep OpenCode behavior, consider one of:
- Add a named export like `plugin` and keep `default` as factory (only if OpenCode can be configured to use named export), OR
- Export a default function that can act as a plugin when called with PluginInput, but also exposes a named factory export (and clearly document it), OR
- Treat as breaking change and bump the wrapper package major version / add migration notes.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9b99113b-cff7-4df7-9d55-0d7327353b55

📥 Commits

Reviewing files that changed from the base of the PR and between 2e275a5 and 1d81034.

📒 Files selected for processing (3)
  • opencode/index.d.mts
  • src/opencode.ts
  • test/opencode.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/opencode.test.ts
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: cubic · AI code reviewer
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,mjs}

📄 CodeRabbit inference engine (AGENTS.md)

Use ESM-only TypeScript with "type": "module" in package.json; do not introduce CommonJS

Files:

  • src/opencode.ts
**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.ts: Keep imports explicit and extension-aware using ./file.ts style; use import type for type-only imports
Never use as any, @ts-ignore, or @ts-expect-error

Files:

  • src/opencode.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: oritwoen
Repo: oritwoen/obsxa PR: 9
File: package.json:58-58
Timestamp: 2026-03-11T19:03:02.039Z
Learning: In `package.json` of `oritwoen/obsxa`, `opencode-ai/plugin` is intentionally pinned to `"latest"` in devDependencies to track plugin API movement. Do not flag this as a non-reproducible build issue.
📚 Learning: 2026-03-12T11:16:05.994Z
Learnt from: CR
Repo: oritwoen/obsxa PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-12T11:16:05.994Z
Learning: Applies to **/*.ts : Keep imports explicit and extension-aware using `./file.ts` style; use `import type` for type-only imports

Applied to files:

  • opencode/index.d.mts
📚 Learning: 2026-03-11T19:03:02.039Z
Learnt from: oritwoen
Repo: oritwoen/obsxa PR: 9
File: package.json:58-58
Timestamp: 2026-03-11T19:03:02.039Z
Learning: In `package.json` of `oritwoen/obsxa`, `opencode-ai/plugin` is intentionally pinned to `"latest"` in devDependencies to track plugin API movement. Do not flag this as a non-reproducible build issue.

Applied to files:

  • opencode/index.d.mts
🧬 Code graph analysis (1)
src/opencode.ts (1)
src/index.ts (1)
  • ObsxaInstance (193-202)
🔇 Additional comments (8)
src/opencode.ts (7)

12-12: LGTM on toolLoader option

Good addition for testability - allows injecting a mock tool loader in tests without hitting the real @opencode-ai/plugin/tool module.


181-186: Clean instruction separation

Tool vs fallback instructions are clearly differentiated. The fallback gracefully degrades when the tool module can't be loaded.


258-263: Good project isolation check

Line 262 correctly filters by projectId to prevent observations from other projects being accessed. Prevents information leakage between projects.


426-433: LGTM on conditional tool exposure

Tool is only exposed when successfully created. When createObsxaTool returns undefined (module load failed), the tool property is undefined instead of an empty object - clean behavior.


676-678: LGTM on tool-aware instruction injection

Correctly selects the appropriate instruction based on whether the tool was successfully initialized.


703-703: Code structure is correct as-is

Source exports the factory, wrapper instantiates it and re-exports the instance as default. No changes needed.


193-195: No issue here. The @opencode-ai/plugin/tool module exports tool with a .schema property as its documented contract, so lines 194-195 are safe. The code correctly assumes this shape.

			> Likely an incorrect or invalid review comment.
opencode/index.d.mts (1)

1-3: Types correctly reflect instantiated plugin

The declaration types the default as ReturnType<typeof createObsxaPlugin> which is Plugin (not the factory function type). This matches the PR objective - consumers importing the default get a ready-to-use plugin function, while the named export gives access to the factory for custom options.


📝 Walkthrough

Walkthrough

Default export for the OpenCode wrapper now exports an instantiated plugin (createObsxaPlugin()) instead of the factory; a dynamic obsxa tool integration and loader option were added, and tests updated to reflect the new "" token and tool usage.

Changes

Cohort / File(s) Summary
Opencode bundle exports
opencode/index.mjs, opencode/index.d.mts
Change default export from the factory to an instantiated plugin (createObsxaPlugin() -> plugin). Keep createObsxaPlugin as a named export; switch from re-export to local import + named export.
Obsxa tool integration
src/opencode.ts
Add toolLoader?: () => Promise<...> option, introduce createObsxaTool() producing a tool with operations (add/get/list/search/stats), wire tool into plugin (expose tool.obsxa), and use tool-aware system transform / instructions. Add input validation, execute routing, and error handling.
Tests and helpers
test/opencode.test.ts
Add getObsxaTool helper and ObsxaTool type; update tests to assert presence/absence of the obsxa tool, use <obsxa-instruction> token, and add scenarios for cross-project observation fetches.

Sequence Diagram(s)

sequenceDiagram
    participant Host as OpenCode Host
    participant Wrapper as opencode/index (default export)
    participant Plugin as Obsxa Plugin (createObsxaPlugin())
    participant ToolPkg as `@opencode-ai/plugin/tool` (loaded via toolLoader)
    participant ObsxaAPI as Obsxa backend/API

    Host->>Wrapper: import default (plugin instance)
    Host->>Plugin: call plugin(input) -> receives hooks
    Plugin->>ToolPkg: toolLoader?() (async) / createObsxaTool()
    ToolPkg-->>Plugin: tool config { obsxa: { schema, execute } }
    Host->>Plugin: chat.message / system.transform triggers
    Plugin->>ToolPkg: tool.execute({ operation, params })
    ToolPkg->>ObsxaAPI: call API (add/get/list/search/stats)
    ObsxaAPI-->>ToolPkg: results (JSON)
    ToolPkg-->>Plugin: execute returns JSON string
    Plugin->>Host: hooks persist observations / return enriched context
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

⚙️ A factory sat in a box, silent and neat,
We called it once, now hooks finally meet.
Tools load on demand, obsxa speaks back,
Observations land, no longer do they lack.
Small change, big unstick — tests give a clap.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title directly describes the fix: initializing plugin hooks correctly, which is the core issue addressed in this PR.
Description check ✅ Passed Description covers the core problem and solution with linked issue, though minimal detail on implementation approach.
Linked Issues check ✅ Passed Code changes directly address #20: default export now instantiates the plugin, wrapper typings align, obsxa tool hook added, tests updated for hook ingestion and persistence.
Out of Scope Changes check ✅ Passed All changes directly support fixing hooks initialization: TypeScript declarations, module exports, tool integration, and tests—nothing extraneous.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/opencode-observations-persistence
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/opencode-observations-persistence
📝 Coding Plan for PR comments
  • Generate coding plan

Comment @coderabbitai help to get the list of available commands and usage tips.

@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented Mar 12, 2026

Sequence Diagram

This PR fixes the wrapper default export to return an instantiated plugin so OpenCode registers hooks correctly at startup. It also adds an obsxa tool hook, enabling both normal hook-driven ingestion and explicit tool based observation writes to persist in real sessions.

sequenceDiagram
    participant OpenCode
    participant Wrapper
    participant ObsxaPlugin
    participant Agent
    participant ObsxaStore

    OpenCode->>Wrapper: Load default plugin export
    Wrapper-->>OpenCode: Return instantiated plugin
    OpenCode->>ObsxaPlugin: Initialize plugin for session
    ObsxaPlugin-->>OpenCode: Register hooks and obsxa tool
    Agent->>OpenCode: Send message or obsxa add request
    OpenCode->>ObsxaPlugin: Trigger hook or tool execution
    ObsxaPlugin->>ObsxaStore: Write observation
    ObsxaStore-->>ObsxaPlugin: Observation persisted
Loading

Generated by CodeAnt AI

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 4 files

Comment thread opencode/index.d.mts Outdated
Comment thread src/opencode.ts Outdated
Comment thread src/opencode.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2e275a5246

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/opencode.ts Outdated
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="opencode/index.d.mts">

<violation number="1" location="opencode/index.d.mts:1">
P1: The declaration file imports `createObsxaPlugin` from `../src/opencode.ts`, but that path is not shipped by the wrapper package, so TypeScript consumers cannot resolve this module’s types.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread opencode/index.d.mts
@oritwoen oritwoen merged commit 53efa05 into main Mar 12, 2026
4 checks passed
@oritwoen oritwoen deleted the fix/opencode-observations-persistence branch March 12, 2026 15:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenCode wrapper exports factory, hooks never run

1 participant