Skip to content

Commit 00c498f

Browse files
phodalcodex
andcommitted
feat(artifacts): publish provider sdk
Move the host-neutral Artifact wire model and external Provider contract into @qoder-ai/harness/artifacts, then let Studio accept explicitly injected, fingerprint-bound Providers. Keep React, HTTP, activation, CSP, and iframe ownership in Studio, and make numeric compile budgets bounded host policy without expanding package imports. The accepted spec is docs/specs/2026-08-22-artifact-provider-sdk-and-structurizr.md. Validation includes the serial npm run check gate, package dry-runs, and the cross-repository Structurizr catalog/snapshot/resource/viewer smoke. Co-authored-by: Codex (GPT 5.6 Sol) <codex@openai.com>
1 parent 1e6ad4a commit 00c498f

22 files changed

Lines changed: 1220 additions & 712 deletions

docs/adrs/studio-artifact-runtime-and-providers.md

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- [Render SVG and Mermaid artifacts through the React preview runtime](../specs/2026-08-22-studio-react-document-artifacts.md)
1616
- [Keep Walnut bootstrap receipts portable across platforms](../specs/2026-08-21-walnut-cross-platform-paths.md)
1717
- [Implement external Artifact providers in Harness Studio](../specs/2026-08-22-studio-external-artifact-provider-runtime.md)
18+
- [Extract the Artifact provider SDK and prove it with Structurizr](../specs/2026-08-22-artifact-provider-sdk-and-structurizr.md)
1819

1920
## Context
2021

@@ -175,12 +176,16 @@ type ArtifactSurfaceBinding =
175176
| { kind: "unavailable"; reason: string };
176177
```
177178

178-
All TypeScript shapes in this ADR are conceptual ownership contracts until a
179-
dated implementation spec freezes their internal names and validators; they are
180-
not a new public package API. The current V2 catalog may continue to project
181-
them through `backing`, `build`, and `renderer`. A later wire-format revision is
182-
justified only when a client needs information that cannot be represented
183-
safely and additively.
179+
The host-neutral descriptor, snapshot, source-entry, adapter, surface, and
180+
external Provider shapes are a public package API under
181+
`@qoder-ai/harness/artifacts`. Studio keeps compatibility re-exports while the
182+
core subpath is their sole source owner. React views, catalog discovery and
183+
classification, HTTP routes, activation storage, provider selection, compile
184+
execution, CSP, and iframe hosting stay in `@qoder-ai/harness-studio`; they are
185+
not SDK abstractions. The current V2 catalog continues to project the public
186+
contract through `backing`, `build`, and `renderer`. A later wire-format
187+
revision is justified only when a client needs information that cannot be
188+
represented safely and additively.
184189

185190
The V2 compatibility projection is explicit:
186191

@@ -253,6 +258,13 @@ executes the selected contribution and enforces project, dependency, time, and
253258
output bounds. Adding an SVG-like virtual document edits the build-runtime
254259
composition, not the compiler implementation.
255260

261+
Numeric compile limits are Studio host policy. An embedder may lower them or
262+
raise them within Studio-owned hard ceilings; the effective policy participates
263+
in cache and build identity. Package permissions are not a numeric limit and
264+
remain owned by the selected trusted build-runtime contribution. A Provider
265+
that needs repository libraries performs a declared adapter transform instead
266+
of granting artifact-authored source arbitrary workspace imports.
267+
256268
Build and snapshot identities include the source revision, adapter or build
257269
runtime id and version, schema version, and any external provider fingerprint
258270
that can affect output. Cache hits therefore cannot cross a meaningful runtime
@@ -550,24 +562,26 @@ must show that compare or replay is unavailable.
550562

551563
### Keep ownership narrow and discoverable
552564

553-
Current source ownership remains:
565+
Current source ownership is:
554566

555567
| Concern | Owner |
556568
| --- | --- |
557-
| Browser-safe catalog, descriptor, snapshot, and build protocols | `packages/harness-studio/src/artifact-model.ts` |
569+
| Host-neutral descriptor, snapshot, source-entry, adapter, surface, and Provider contracts | `packages/harness/src/artifacts/`, published as `@qoder-ai/harness/artifacts` |
570+
| Browser-safe compatibility re-export | `packages/harness-studio/src/artifact-model.ts` |
558571
| Directory discovery, classification, revision hashing, and catalog projection | `packages/harness-studio/src/server/artifact-catalog.ts` |
559-
| Adapter/build/plugin contracts and ordered server selection | `packages/harness-studio/src/server/artifact-adapter-contract.ts` and `artifact-plugin-registry.ts` |
572+
| Ordered server selection, receipt verification, activation, and embedded Provider injection | `packages/harness-studio/src/server/artifact-plugin-registry.ts`, `artifact-provider-discovery.ts`, and `artifact-provider-activation.ts` |
560573
| Format parsing and semantic projection | Format-owned adapter modules such as `pptx-artifact-adapter.ts` and `markdown-artifact-adapter.ts` |
561574
| Studio compile/build lifecycle | `artifact-build-runtimes.ts` and `artifact-compile-runtime.ts` |
562575
| Browser renderer composition | `packages/harness-studio/src/app/ArtifactView.tsx` |
563576
| Opaque-origin Studio preview lifecycle | `packages/harness-studio/src/app/ArtifactPreviewHost.tsx` |
564577
| External acquisition and verification | Provider-owned server modules, currently `packages/harness-studio/src/server/artifact-viewers.ts`, `qoder-canvas-viewer-bridge.ts`, and `walnut-bootstrap.ts` |
565578

566-
The first external-provider implementation spec will choose the exact module
567-
split. It must move vendor translation and execution behind a provider-owned
568-
boundary rather than creating a global service locator. Core catalog, common
569-
server routes, and browser mounting must not gain another vendor branch when a
570-
provider is added.
579+
External-provider implementations keep vendor translation and execution behind
580+
a provider-owned boundary rather than creating a global service locator. An
581+
embedding application supplies installed Providers explicitly to server
582+
startup; activation still binds one contribution, fingerprint, lane, matcher,
583+
adapter profile, and surface profile. Core catalog, common server routes, and
584+
browser mounting do not gain another vendor branch when a provider is added.
571585

572586
After that migration, `artifact-plugin-registry.ts` is the server composition
573587
root: a `createArtifactPluginRegistry({ builtIns, externalProviders })`-shaped
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Artifact provider SDK and Structurizr integration
2+
3+
## Traceability
4+
5+
- Spec ID: artifact-provider-sdk-and-structurizr
6+
- Status: Accepted
7+
8+
## Intent
9+
10+
Expose the host-neutral Artifact descriptor, snapshot, and external Provider
11+
contracts from `@qoder-ai/harness` so a repository can implement one Provider
12+
without importing Studio server internals. Keep Studio responsible for catalog
13+
HTTP routes, activation, provider selection, sandbox policy, and React UI. Prove
14+
the boundary with a local Structurizr DSL Provider before publishing the SDK and
15+
Studio packages.
16+
17+
## Acceptance Scenarios
18+
19+
- AC-1: `@qoder-ai/harness/artifacts` exports the Artifact wire model, source
20+
entry, adapter/runtime bindings, Provider contract, and an inference helper;
21+
the subpath imports no React or Studio server module.
22+
- AC-2: Harness Studio consumes the shared contract without changing its V2
23+
catalog/snapshot wire format and accepts explicitly injected Providers through
24+
`HarnessStudioServerOptions`; fingerprint-bound activation remains required.
25+
- AC-3: Studio's numeric source-file, source-byte, output-byte, and timeout
26+
budgets are an explicit host policy with bounded overrides. Effective limits
27+
participate in build/cache identity. Package imports remain restricted to the
28+
selected trusted build runtime.
29+
- AC-4: Structurizr4js provides an experimental-local `.dsl` contribution using
30+
the published SDK shape, runs parsing/layout in a bounded child process, and
31+
renders the generated SVG through Studio's common opaque-origin hosted
32+
surface. A cross-repository test exercises catalog, snapshot, resource, and
33+
viewer routes.
34+
- AC-5: focused tests, package dry-runs, the serial Better Harness checks, and
35+
Structurizr provider tests pass before publication. Publication uses the
36+
repository's GitHub Actions workflow; registry reads and a clean-consumer
37+
install verify the released versions separately from local tests.
38+
39+
## Non-goals
40+
41+
- Moving `ArtifactView`, React renderers, HTTP routing, iframe policy, or
42+
activation storage into `@qoder-ai/harness`.
43+
- Allowing artifact-authored code to import arbitrary workspace or npm packages.
44+
- Claiming the first Structurizr Provider is reviewed, remotely sandboxed, or a
45+
general provider marketplace/discovery mechanism.
46+
- Publishing the Structurizr Provider package in this change.
47+
48+
## Plan and Tasks
49+
50+
1. Move the host-neutral contracts to a public `artifacts` subpath and keep
51+
Studio compatibility re-exports while internal imports migrate.
52+
2. Add explicit embedded-provider injection, provider receipt/fingerprint
53+
validation, public activation helpers, and configurable bounded compile
54+
limits to Studio.
55+
3. Add the Structurizr Provider package, child driver, hosted SVG surface, and
56+
focused tests in structurizr4js.
57+
4. Run focused and package checks in both repositories, then run Better Harness
58+
generated/Harness/UI/Studio checks serially.
59+
5. Perform Review Readiness Check, commit exact paths, push, dispatch releases,
60+
and verify npm plus a clean consumer.
61+
62+
## Test and Review Evidence
63+
64+
- AC-1/AC-2: Harness and Studio TypeScript builds plus Artifact provider,
65+
activation, registry, catalog, and server focused Vitest files.
66+
- AC-3: compile-runtime tests cover custom accepted limits, hard-ceiling
67+
rejection, and cache/build identity separation.
68+
- AC-4: Structurizr Provider tests cover valid DSL, invalid DSL, exact revision
69+
envelope/resource identity, hosted document safety, and real Studio routes.
70+
- AC-5: `npm pack --dry-run --json` for both packages, serial workspace checks,
71+
GitHub Actions run URLs, `npm view`, and an isolated install/import receipt.
72+
- Risk: provider code is trusted local code. The initial contribution therefore
73+
stays `experimental-local`, uses `trusted-local-process`, and never weakens the
74+
opaque-origin surface or artifact-authored package allowlist.

package-lock.json

Lines changed: 29 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/harness-studio/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,38 @@ only by Run. Other providers, including versioned document or presentation
7171
systems, can inject the same server adapter interface without adopting the
7272
catalog's storage format.
7373

74+
An embedding application can install an Artifact Provider implemented against
75+
`@qoder-ai/harness/artifacts`, activate one exact fingerprint-bound
76+
contribution, and inject it explicitly:
77+
78+
```ts
79+
import {
80+
activateArtifactContribution,
81+
startHarnessStudioServer,
82+
} from "@qoder-ai/harness-studio";
83+
84+
await activateArtifactContribution(
85+
provider,
86+
"my-format",
87+
"external-fallback",
88+
{ extensions: ["my-format"] },
89+
{ root: stateRoot },
90+
);
91+
92+
await startHarnessStudioServer({
93+
appDir,
94+
artifactDirectory,
95+
artifactProviderStateRoot: stateRoot,
96+
artifactProviders: [provider],
97+
artifactCompileLimits: { maxSourceFiles: 128 },
98+
});
99+
```
100+
101+
Numeric compile limits may be adjusted only within Studio's hard ceilings and
102+
are part of build/cache identity. They do not expand the package allowlist.
103+
Injected Provider receipts are fingerprint-checked, and an inactive or changed
104+
fingerprint never enters selection.
105+
74106
## Architecture
75107

76108
```text

packages/harness-studio/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"dependencies": {
4242
"@phosphor-icons/react": "^2.1.10",
4343
"@pierre/diffs": "^1.3.5",
44-
"@qoder-ai/harness": "0.1.0",
44+
"@qoder-ai/harness": "0.2.0",
4545
"@qoder-ai/harness-ui": "0.1.0",
4646
"@shikijs/core": "^4.4.3",
4747
"@shikijs/engine-javascript": "^4.4.3",

0 commit comments

Comments
 (0)