Skip to content

Spike: Decide on approach for language service #209

Closed

Description

@lornakelly

Description

Editor decided (#208): Monaco.

Evaluate and decide how we deliver schema-driven autocomplete/IntelliSense: reuse an existing library/language server vs build our own. The chosen service must be a standalone, host-agnostic engine as it will be reused beyond milestone 1 (VsCode, IntelliJ etc).

Comment on this ticket with findings and review with team

Motivation

Authoring assistance is crucial to support the two ADR use cases:

  1. Make editor approachable for the newcomer
  2. Faster for authoring and debugging for the fixer

Proposed Implementation

No response

Definition of Done

  • Implementation: Fully implemented according to the Serverless Workflow spec.
  • Unit Tests: Comprehensive unit tests are included and passing.
  • Integration Tests: Verified within the monorepo and target environments (Web/VS Code).
  • Documentation: Updated README.md, ADRs, or official docs.
  • Performance: No significant regression in editor responsiveness.
  • Accessibility: UI changes comply with accessibility standards.

Activity

  1. changed the title [-]Spike: Language service[/-] [+]Spike: Decide on approach for language service[/+] on Jun 30, 2026
  2. fantonangeli commented on Aug 7, 2026

    @fantonangeli
    Member

    @lornakelly @ricardozanini @handreyrc @JBBianchi @cdavernas
    Below are my proposals open for voting or suggestion:

    OWS Language Service Architecture Spike

    Requirements

    • @openworkflowspec/language-service editor-agnostic, and have no Monaco or React dependencies.
    • Support JSON and YAML completion, diagnostics, augmentations, and OWS-specific semantics.
    • Support incomplete YAML documents and cursor-position edge cases.
    • The Text Editor must be embeddable as a Web Component.
    • Worker creation must be configurable, allowing the host application to provide a worker URL.
    • Multiple Text Editor instances should be able to reuse a shared worker.
    • Validate the integration in a host application consuming the Web Component.
    • Check direct and transitive dependency licenses.
    • Keep the architecture open to a possible VS Code extension.

    Notes: The VS Code extension is not part of this spike. It is shown only to explain that the architecture remains open to a future LSP client.


    🚀 Option 1 — Volar

    https://github.com/volarjs/volar.js

    @openworkflowspec/text-editor
    ├─ monaco-editor
    ├─ @volar/monaco
    └─ @openworkflowspec/language-service
    
    
    @openworkflowspec/language-service
    └─ src/
       ├─ core/ (must not import any @volar/*)
       │  ├─ OWS semantics
       │  ├─ completions
       │  ├─ diagnostics
       │  └─ SDK integration
       │     └─ workflowSchema / semantic validation
       │
       └─ volar/
          ├─ @volar/language-service
          ├─ volar-service-json
          │  └─ vscode-json-languageservice
          └─ volar-service-yaml
             └─ yaml-language-server
                └─ yaml
    
    
    @openworkflowspec/language-server
    ├─ @volar/language-server
    └─ @openworkflowspec/language-service
    
    
    @openworkflowspec/vscode-extension (to be determined)
    └─ @openworkflowspec/language-server
    

    Pros

    • Reuses the Monaco integration provided by @volar/monaco.
    • Reuses JSON and YAML services built on established upstream language-service engines.
    • Avoids maintaining most Monaco provider registration, worker communication, document synchronisation, and LSP-to-Monaco conversion code.
    • Keeps OWS-specific completion, validation, hover, and reference logic isolated.
    • Generic YAML parsing, ranges, and cursor-position handling are delegated to volar-service-yaml and yaml-language-server.
    • Used by the Vue language tools.

    Cons

    • Adds an abstraction layer and additional framework dependencies.
    • The Volar starter repository is useful as a reference, but a bit outdated.

    Project vitality

    As of August 2026:

    • The Volar repository is active.
    • Approximately 1.3k GitHub stars.
    • Current core npm packages: 2.4.28 January 2026.
    • @volar/language-service has 67 dependants packages.

    Main licenses

    @volar/language-service       MIT
    @volar/monaco                 MIT
    @volar/language-server        MIT
    volar-service-json            MIT
    volar-service-yaml            MIT
    vscode-json-languageservice   MIT
    yaml-language-server          MIT
    yaml                          ISC
    monaco-editor                 MIT
    

    These licenses are compatible with an Apache license and are marked as category-A:
    https://www.apache.org/legal/resolved.html#category-a


    🎉 Option 2 — Custom

    @openworkflowspec/text-editor
    ├─ monaco-editor
    ├─ OWS Monaco providers
    ├─ Worker lifecycle and RPC
    └─ @openworkflowspec/language-service
    
    
    @openworkflowspec/language-service
    ├─ OWS-specific language semantics
    ├─ vscode-json-languageservice
    └─ yaml-language-server
       └─ yaml
    
    
    @openworkflowspec/language-server
    ├─ OWS LSP adapter
    └─ @openworkflowspec/language-service
    
    
    @openworkflowspec/vscode-extension (to be determined)
    └─ @openworkflowspec/language-server
    

    Benefits

    • Full control over public APIs and lifecycle.
    • Can expose only the features required by OWS.
    • Easier to customize specifically for the OWS use case.

    Drawbacks

    OWS would need to implement and maintain the logic.

    OWS would also own the integration logic and test coverage for incomplete YAML and cursor-position edge cases.

    Main licenses

    vscode-json-languageservice   MIT
    yaml-language-server          MIT
    yaml                          ISC
    monaco-editor                 MIT
    

    These licenses are compatible with an Apache license and are marked as category-A:
    https://www.apache.org/legal/resolved.html#category-a


    (excluded) Option 3 — monaco-languageclient

    monaco-languageclient was also considered. It is a good fit when Monaco needs to communicate with a standalone LSP server, but our browser Text Editor can consume the language service directly.

    Volar provides the Monaco integration directly while still allowing the same language capabilities to be exposed through @volar/language-server if a VS Code extension is added in the future.


    Configurable Worker Creation

    The Text Editor must not assume where the worker asset is hosted.

    new Worker(hostWorkerUrl, {
      type: "module",
    });

    It must also allow the host application to provide its own worker factory or URL:

    createLanguageWorker: () =>
      new Worker(hostWorkerUrl, { type: "module" });

    This allows a host application to:

    • package the worker as a separate asset;
    • serve it from a host-specific path;
    • embed the Text Editor in a Web Component;
    • share one worker instance across multiple editors.

    Recommendation

    🚀 Use Volar.

    Both options ultimately reuse vscode-json-languageservice and yaml-language-server.

    Volar already provides reusable infrastructure around Monaco, workers, language-service composition, and a future LSP server. This lets OWS focus on Open Workflow Spec semantics..

    Vote

    • React with 🚀 for the Volar-based architecture.
    • React with 🎉 for the custom architecture.
  3. ricardozanini commented on Aug 7, 2026

    @ricardozanini
    Contributor

    +1 to reuse Volar capabilities. I see little reason to maintain our own libraries if we can rely on an established framework.

  4. kumaradityaraj commented on Aug 10, 2026

    @kumaradityaraj
    Contributor

    I’d recommend Volar, as it minimizes custom integration and maintenance while keeping the architecture editor-agnostic.

  5. handreyrc commented on Aug 10, 2026

    @handreyrc
    Contributor

    +1 to use volar. I would avoid rebuilding features already available in libs we can use.

  6. JBBianchi commented on Aug 17, 2026

    @JBBianchi
    Collaborator

    Thanks for putting this together.

    I'm leaning 🚀 Volar, but I think there are a few things worth validating before closing the spike.

    The two options overlap quite a bit: both ultimately use vscode-json-languageservice and yaml-language-server. The main difference is really whether we use Volar for the composition/Monaco/worker integration, or own that layer ourselves.

    Because of that, I'd try to keep the OWS-specific language logic independent from Volar. Ideally the semantics package shouldn't import @volar/* at all, and Volar would just be an adapter around it. That keeps the decision reasonably reversible if maintenance or integration becomes an issue later.

    I also think some of the OWS-specific validation belongs in the SDK rather than the editor. Things like unresolved functions, authentication references or retry policies shouldn't be implemented twice. A useful contract could be for the SDK to return diagnostics with JSON pointers, and for the language service to resolve those pointers to YAML/JSON ranges. However, we'd probably still need some editor-side handling for incomplete documents that can't be deserialized by the SDK yet, so it would be worth exploring where that boundary sits.

    One thing that might be interesting to explore on the editor side is reference-aware completion and navigation. Completion could suggest functions already defined in the workflow, and eventually go-to-definition could jump to their declaration. It seems like a natural extension of the same document index we'd need for unresolved-reference diagnostics, and could be particularly useful for authoring.

    The main thing I'd personally like to see validated early is browser packaging. I've hit this before with monaco-yaml in a Blazor application: many Monaco integrations assume the consuming application has a JS bundler capable of dealing with workers and import.meta.url, and I ended up maintaining a prebuilt version for that reason.

    Since the editor is meant to be an embeddable Web Component, I wonder if it would be worth making the browser distribution itself part of the spike, so that a consumer doesn't need to introduce Vite or Webpack just to embed the editor:

    • a prebuilt ESM entry point and worker asset;
    • no consumer-side bundling required for the basic case;
    • worker URL configurable by the host;
    • a plain HTML + <script type="module"> smoke test, and possibly a Blazor one, since that's a host that consumes JavaScript without necessarily having its own JS build pipeline.

    Related to that, @volar/monaco appears to rely on Monaco's MonacoEnvironment.getWorker / createWebWorker model rather than exposing the worker factory shown in the proposal. That may be perfectly fine, but it would be good to confirm early how that fits with the Web Component requirements and multiple editor instances.

    For the spike itself, it might also be useful to exercise one small end-to-end OWS-specific scenario rather than only generic schema completion. An unresolved reference could be enough to validate the path from document parsing, to OWS semantics, to a diagnostic at the correct range. If completion or navigation falls naturally out of that work, even better.

    I'd also document why monaco-languageclient isn't being considered. It's an obvious alternative for "one LSP server everywhere", but the current ecosystem around it appears to bring more of the VS Code compatibility layer than we probably need for an embeddable component.

    So I'm leaning 🚀 for Volar, mostly because it gives us the integration layer without changing the underlying engines. I'd just try to keep the OWS semantics independent from it, and use the spike to validate the incomplete-document and browser/worker packaging assumptions early.

  7. fantonangeli commented on Aug 24, 2026

    @fantonangeli
    Member

    @JBBianchi thanks a lot you for your input.
    cc @ricardozanini @lornakelly
    I updated my spike investigation with the following updates:

    • Option 1 — Volar: updated hierarchy
    • (excluded) Option 3 — monaco-languageclient: added this section

    Regarding a POC creation:
    I agree this should be validated, but I would do it using the actual package structure below rather than creating a temporary parallel POC.

    examples/vanilla-web-component
    └─ @openworkflowspec/text-editor (loaded as Web Component)
       ├─ monaco-editor
       ├─ @volar/monaco
       └─ @openworkflowspec/language-service
          └─ @openworkflowspec/sdk
    

    Once #332 provides the text-editor foundation, #331 can validate the full Monaco + Volar + Language Service + Worker integration, including the Web Component integration.

  8. lornakelly commented on Aug 25, 2026

    @lornakelly
    CollaboratorAuthor

    Thanks Fabrizio and agree on validate as part of 331.

    Thanks for you inputs JB as well

  9. fantonangeli commented on Aug 28, 2026

    @fantonangeli
    Member

    @lornakelly @handreyrc @JBBianchi @ricardozanini

    High-level architecture spike integration

    At a higher level, the editor architecture would look like this:

    host-webapp
    └─ @openworkflowspec/dual-editor
       ├─ @openworkflowspec/text-editor
       │  └─ @openworkflowspec/language-service
       └─ @openworkflowspec/diagram-editor
    
    
    @openworkflowspec/vscode-extension
    ├─ @openworkflowspec/language-server
    │  └─ @openworkflowspec/language-service
    └─ @openworkflowspec/diagram-editor
    

    The host-webapp is a placeholder for the application that embeds and orchestrates the dual-editor. The dual-editor composes the Text Editor and Diagram Editor, while the Language Service remains owned by the Text Editor path. The future VS Code extension would reuse the same Language Service through the Language Server.

    The Text Editor owns the Language Service worker integration. Host applications may configure the worker URL/factory through the dual-editor, which forwards the configuration to the Text Editor.

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

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions