Skip to content

feat(ide): promote OpenCode to first-class IDE integration#1321

Open
Lokesh7025 wants to merge 15 commits into
mainfrom
feature/opencode-integration
Open

feat(ide): promote OpenCode to first-class IDE integration#1321
Lokesh7025 wants to merge 15 commits into
mainfrom
feature/opencode-integration

Conversation

@Lokesh7025
Copy link
Copy Markdown
Contributor

@Lokesh7025 Lokesh7025 commented Jun 1, 2026

Fixes

  • Resolves the OpenCode integration gap, previously listed as "Functional" tier with no telemetry, now upgraded to first-class with full session parsing.

Approach

OpenCode does not write JSONL session files like Claude Code. Instead it stores messages in a SQLite DB accessible via its SDK. The approach:

  1. Plugin-based telemetry A TypeScript plugin (`.opencode/plugins/observal-plugin.ts`) subscribes to OpenCode's `session.idle` event via the catch-all `event:` handler pattern.
  2. SDK-driven message retrieval On each idle event, the plugin uses the OpenCode SDK `client.session.messages()` to fetch the full conversation.
  3. Format conversion Messages are converted to Claude-Code-compatible JSONL format (handling OpenCode's `{created: epoch_ms}` timestamp objects).
  4. Standard ingest Data is POSTed to `/api/v1/ingest/session` with `ide: "opencode"`, reusing the existing Claude Code classifier since the wire format is compatible.

Files changed:

  • `observal_cli/ide_specs/opencode_hooks_spec.py` (new) Hook spec + plugin source
  • `observal-server/services/session_parsers/opencode.py` (new) Server-side parser
  • `observal_cli/ide/opencode.py` , Full CLI adapter (scanning MCPs, skills, agents, hooks)
  • `observal_cli/ide_registry.py` + `observal-server/schemas/ide_registry.py` Added `skills` feature, `opencode` session parser, updated event map
  • `observal-server/services/ide/opencode.py` , Full config generation with skills
  • `observal-server/services/ide/helpers.py` , Proper telemetry plugin source
  • `observal-server/services/session_ingest.py` , Registered OpenCode extractors
  • `observal-server/services/session_parsers/init.py` + `ingest_classify.py` Registered parser/classifier

How Has This Been Tested?

  • Unit tests: All 109 existing tests pass (constants sync, IDE adapters, CLI commands)
  • Lint: `ruff check` + `ruff format` clean
  • End-to-end locally: Full Docker stack with enterprise license:
    1. `observal pull test --ide opencode` — plugin installed at `.opencode/plugins/`
    2. Launched OpenCode, sent messages using the pulled agent
    3. Plugin captured session data and pushed to server (verified via debug logging)
    4. Data persisted in ClickHouse and visible in the sessions API/frontend

Learning

  • OpenCode plugins use a catch-all `event: async ({ event }) => {}` handler pattern, NOT individual named event handlers like `"session.idle": async () => {}`
  • OpenCode timestamps are objects (`{created: epoch_ms}`), not ISO strings needed explicit conversion
  • The OpenCode SDK `client` object is injected into the plugin context and provides full access to session/message data

Checklist

  • You have a descriptive commit message with a short title (first line, max 50 chars).
  • You have commented your code, particularly in hard-to-understand areas
  • You have performed a self-review of your own code
  • UI changes: include screenshots of all affected screens N/A (no UI changes)"

Screenshots

opencode opencode2

- Add full CLI adapter with scanning for MCPs, skills, agents, hooks
- Add hook spec with TypeScript plugin for session telemetry
- Plugin subscribes to session.idle events, fetches messages via
  OpenCode SDK, converts to Claude-Code-compatible JSONL, and pushes
  to the Observal ingest endpoint
- Register 'opencode' session parser, classifier, timestamp extractor,
  usage extractor, and UUID extractor on the server side
- Add 'skills' to OpenCode's feature set in IDE registry
- Update server adapter to generate skills and proper plugin source
- Handle OpenCode's timestamp format ({created: epoch_ms} objects)

Tested end-to-end: agent pull -> plugin install -> session capture ->
ClickHouse persistence -> frontend visibility.
@github-actions github-actions Bot added cli CLI changes server Pull request touches server code labels Jun 1, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 1, 2026

⚠️ Deprecation Warning: The deny-licenses option is deprecated for possible removal in the next major release. For more information, see issue 997.

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

- Feature matrix now includes 'skills'
- Env vars key renamed to 'environment' (OpenCode config format)
- Plugin uses execFileSync not execSync
- Compatibility warnings test reflects skills support
@github-actions github-actions Bot added the tests Pull request adds or modifies tests label Jun 1, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 1, 2026

Skip built-in agents (build, plan, general, explore, scout, etc.)
and only push telemetry for user-pulled Observal agents. Matches
behavior of Claude Code (agent-setting detection) and Kiro
(per-agent hook commands with OBSERVAL_AGENT_NAME).
- _build_mcp_configs now handles 'mcp' key returned by generate_config
  for OpenCode (previously MCPs were silently dropped)
- config_generator uses 'environment' (not 'env') for OpenCode entries
- opencode.py adapter normalizes any remaining 'env' → 'environment'
- opencode.py passes skill_configs through as-is for CLI-side install
  (was pre-rendering via _generate_skill_file causing 'no content' error)
- Custom hook components generate per-event plugin files in
  .opencode/plugins/hook-<name>.ts (command and http handler types)
- .opencode/hooks/ added to HOOK_SCRIPTS_DIR for script-based hooks
- Update test to expect 'environment' key in MCP config
When pulling an agent with a sandbox component, the generated
opencode.json uses bare 'python3' for the observal-sandbox MCP.
OpenCode resolves this from its own subprocess PATH which may not
include the observal_cli venv, causing a 30s timeout.

Rewrite ['python3', '-m', 'observal_cli.*'] command arrays to use
sys.executable so the correct interpreter is always used regardless
of the environment OpenCode is launched from.
@Lokesh7025 Lokesh7025 force-pushed the feature/opencode-integration branch from f1e3ce1 to 8b5adcf Compare June 1, 2026 12:40
- Replace curl subprocess with Node.js http/https modules for Windows compat
- Fix command injection in hook plugins (use shell:true with constant arg)
- Fix JSONC comment stripping to handle inline comments
- Add message.updated event handling and conditional final flag
- Cap sessionState Map to prevent memory leaks in long-lived processes
- Remove duplicate plugin source from CLI (delegate to server)
- Validate URLs in HTTP hook plugin generation
- Fix detect_hooks to not rely on Path.cwd()
- Fix frontmatter parsing to only match top-level keys
- Restore test coverage for session.created and message.updated
- Bump HOOKS_SPEC_VERSION to 2
@Lokesh7025 Lokesh7025 force-pushed the feature/opencode-integration branch from 8b5adcf to f35821a Compare June 1, 2026 12:44
Copy link
Copy Markdown
Contributor

@Haz3-jolt Haz3-jolt left a comment

Choose a reason for hiding this comment

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

Please add to supported IDEs in README.md And add screenshots of it in Observal.

Lokesh7025 and others added 9 commits June 2, 2026 06:42
Multi-worker uvicorn takes longer to stabilize on startup due to
the Redis pubsub subscriber retrying connections. The 15s start_period
caused the container to be marked unhealthy before the app fully
stabilized, failing CI deploys.
…gured

The /status endpoint was showing 'AWS access key not configured' even
when insights.api_key was set. Now it reads the API key first and only
checks AWS credentials for Bedrock models when no direct key exists.
…r Analytics tab

StatusBadge no longer shows indicator dots for approved and pending
statuses. Dots remain for active/running states where animation is
meaningful.

The Analytics tab on the agent detail page was a hardcoded empty state
with no real data fetching. Removed it entirely since traces are
accessible from the admin dashboard and stats are in the sidebar.
The insights endpoints (session-count, generate, list-reports,
get-report, export-html, status) now accept any authenticated user
with owner or edit permission on the agent, not just admins.

Frontend changes:
- Add Insights tab to agent detail page (visible to owners/co-authors)
- Shows session count, generate button, and report list
- Move report detail route from admin-only to authenticated user level
- Remove dots from approved/pending status badges (prior commit)
Insights are now accessed per-agent via the Insights tab on the agent
detail page. Admins still see the tab on every agent since they have
owner-level permission.

Removed:
- Sidebar nav entry for /insights
- Admin insights index route and page
- Retention banner link to /insights (replaced with inline text)
- Back button in report detail now uses browser history
Signed-off-by: Hari Srinivasan <harisrini21@gmail.com>
@github-actions github-actions Bot added the web Pull request touches web frontend code label Jun 2, 2026
@Lokesh7025
Copy link
Copy Markdown
Contributor Author

@Haz3-jolt Screenshots added, and README.md changes done, merge after a final review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli CLI changes server Pull request touches server code tests Pull request adds or modifies tests web Pull request touches web frontend code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants