@openship/protocol 0.0.3 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,11 +6,31 @@
6
6
  "openship": "1.0",
7
7
  "capability": "sources",
8
8
  "digest": "sha256:1d322539e651a3c2d7c51eb8b33160627395b9601bff909e599771b806d9e565",
9
- "project": { "name": "Example", "description": "An example OpenShip project." },
10
- "totals": { "files": 2, "bytes": 53 },
9
+ "project": {
10
+ "name": "Example",
11
+ "description": "An example OpenShip project."
12
+ },
13
+ "totals": {
14
+ "files": 2,
15
+ "bytes": 53
16
+ },
11
17
  "files": [
12
- { "path": "app/page.js", "size": 34, "sha256": "6ce070542590adb63fd9621ff65be91446f8bd9b65465cda5e4ec43e5d86dc5e", "encoding": "utf-8", "mediaType": "text/plain; charset=utf-8", "type": "file" },
13
- { "path": "package.json", "size": 19, "sha256": "9579cf52285b23b618b615d704b19d04ff591ae513f6ae34ef37e2b9a067cb12", "encoding": "utf-8", "mediaType": "application/json; charset=utf-8", "type": "file" }
18
+ {
19
+ "path": "app/page.js",
20
+ "size": 34,
21
+ "sha256": "6ce070542590adb63fd9621ff65be91446f8bd9b65465cda5e4ec43e5d86dc5e",
22
+ "encoding": "utf-8",
23
+ "mediaType": "text/plain; charset=utf-8",
24
+ "type": "file"
25
+ },
26
+ {
27
+ "path": "package.json",
28
+ "size": 19,
29
+ "sha256": "9579cf52285b23b618b615d704b19d04ff591ae513f6ae34ef37e2b9a067cb12",
30
+ "encoding": "utf-8",
31
+ "mediaType": "application/json; charset=utf-8",
32
+ "type": "file"
33
+ }
14
34
  ]
15
35
  },
16
36
  "bundle": {
@@ -18,38 +38,133 @@
18
38
  "capability": "sources",
19
39
  "digest": "sha256:1d322539e651a3c2d7c51eb8b33160627395b9601bff909e599771b806d9e565",
20
40
  "files": {
21
- "app/page.js": { "encoding": "utf-8", "content": "export default function Page() {}\n" },
22
- "package.json": { "encoding": "utf-8", "content": "{\"name\":\"example\"}\n" }
41
+ "app/page.js": {
42
+ "encoding": "utf-8",
43
+ "content": "export default function Page() {}\n"
44
+ },
45
+ "package.json": {
46
+ "encoding": "utf-8",
47
+ "content": "{\"name\":\"example\"}\n"
48
+ }
23
49
  }
24
50
  }
25
51
  },
26
52
  "system": {
27
53
  "id": "example-system",
28
54
  "name": "Example system",
29
- "rootNodeId": "s.root",
30
- "nodes": [
31
- { "id": "s.root", "kind": "Root", "name": "Example", "metadata": { "ownership": "first_party" } },
32
- { "id": "h.runtime", "kind": "Host", "name": "Application runtime", "parentId": "s.root", "metadata": { "ownership": "first_party" } },
33
- { "id": "p.web", "kind": "Process", "name": "Web process", "parentId": "h.runtime", "sourceSelectors": ["app/**"], "metadata": { "ownership": "first_party" } },
34
- { "id": "l.config", "kind": "Library", "name": "Project configuration", "sourceSelectors": ["package.json"], "metadata": { "ownership": "third_party" } }
35
- ],
36
- "edges": [
37
- { "id": "e.web.config", "type": "Dependency", "fromNodeId": "p.web", "toNodeId": "l.config" }
38
- ],
39
55
  "context": {
40
- "concerns": ["Interfaces", "Implementation"],
56
+ "concerns": [
57
+ "Interfaces",
58
+ "Implementation"
59
+ ],
41
60
  "documents": [
42
- { "kind": "Document", "hash": "sha256:77760f8cb9fdaaadd3c22612d97fba630f78730c8d750c6cce02754b689b11da", "title": "API contract", "language": "en", "text": "The API returns JSON." },
43
- { "kind": "Skill", "hash": "sha256:bae5f866c2994c1cec740965e45935920376a2df1fb933e798c3e2c3b8c0e391", "title": "Node implementation", "language": "en", "text": "Use Node.js." },
44
- { "kind": "Prompt", "hash": "sha256:416a3efe045d89a00fa0cca4516b8bdd442a8f65a42e35a5c102067f3ecb429d", "title": "System prompt", "language": "en", "text": "Keep changes minimal." }
61
+ {
62
+ "kind": "Document",
63
+ "hash": "sha256:77760f8cb9fdaaadd3c22612d97fba630f78730c8d750c6cce02754b689b11da",
64
+ "title": "API contract",
65
+ "language": "en",
66
+ "text": "The API returns JSON."
67
+ },
68
+ {
69
+ "kind": "Skill",
70
+ "hash": "sha256:bae5f866c2994c1cec740965e45935920376a2df1fb933e798c3e2c3b8c0e391",
71
+ "title": "Node implementation",
72
+ "language": "en",
73
+ "text": "Use Node.js."
74
+ },
75
+ {
76
+ "kind": "Prompt",
77
+ "hash": "sha256:416a3efe045d89a00fa0cca4516b8bdd442a8f65a42e35a5c102067f3ecb429d",
78
+ "title": "System prompt",
79
+ "language": "en",
80
+ "text": "Keep changes minimal."
81
+ }
45
82
  ],
46
83
  "matrix": [
47
- { "nodeId": "p.web", "concern": "Interfaces", "documentRefs": ["sha256:77760f8cb9fdaaadd3c22612d97fba630f78730c8d750c6cce02754b689b11da"], "skillRefs": [] }
84
+ {
85
+ "nodeId": "p.web",
86
+ "concern": "Interfaces",
87
+ "documentRefs": [
88
+ "sha256:77760f8cb9fdaaadd3c22612d97fba630f78730c8d750c6cce02754b689b11da"
89
+ ],
90
+ "skillRefs": []
91
+ }
92
+ ],
93
+ "systemPromptRefs": [
94
+ "sha256:416a3efe045d89a00fa0cca4516b8bdd442a8f65a42e35a5c102067f3ecb429d"
48
95
  ],
49
- "systemPromptRefs": ["sha256:416a3efe045d89a00fa0cca4516b8bdd442a8f65a42e35a5c102067f3ecb429d"],
50
96
  "artifacts": [
51
- { "id": "a.web.code", "nodeId": "p.web", "concern": "Implementation", "type": "Code", "sourcePaths": ["app/page.js"] }
97
+ {
98
+ "id": "a.web.code",
99
+ "nodeId": "p.web",
100
+ "concern": "Implementation",
101
+ "type": "Code",
102
+ "sourcePaths": [
103
+ "app/page.js"
104
+ ]
105
+ }
52
106
  ]
53
- }
54
- }
107
+ },
108
+ "layers": [
109
+ {
110
+ "rootNodeId": "s.root",
111
+ "nodes": [
112
+ {
113
+ "id": "s.root",
114
+ "kind": "Root",
115
+ "name": "Example",
116
+ "metadata": {
117
+ "ownership": "first_party"
118
+ }
119
+ },
120
+ {
121
+ "id": "h.runtime",
122
+ "kind": "Host",
123
+ "name": "Application runtime",
124
+ "parentId": "s.root",
125
+ "metadata": {
126
+ "ownership": "first_party"
127
+ }
128
+ },
129
+ {
130
+ "id": "p.web",
131
+ "kind": "Process",
132
+ "name": "Web process",
133
+ "parentId": "h.runtime",
134
+ "sourceSelectors": [
135
+ "app/**"
136
+ ],
137
+ "metadata": {
138
+ "ownership": "first_party"
139
+ }
140
+ },
141
+ {
142
+ "id": "l.config",
143
+ "kind": "Library",
144
+ "name": "Project configuration",
145
+ "sourceSelectors": [
146
+ "package.json"
147
+ ],
148
+ "metadata": {
149
+ "ownership": "third_party"
150
+ },
151
+ "parentId": "s.root"
152
+ }
153
+ ],
154
+ "edges": [
155
+ {
156
+ "id": "e.web.config",
157
+ "type": "Dependency",
158
+ "fromNodeId": "p.web",
159
+ "toNodeId": "l.config"
160
+ }
161
+ ],
162
+ "id": "technical",
163
+ "name": "Technical",
164
+ "role": "technical"
165
+ }
166
+ ],
167
+ "refinements": []
168
+ },
169
+ "systemsVersion": "2.0"
55
170
  }
@@ -1,98 +1,118 @@
1
- # OpenShip Systems v1
1
+ # OpenShip Systems 2.0
2
2
 
3
- OpenShip Systems is the advanced OpenShip capability. It publishes one self-contained JSON document containing a complete Sources snapshot, a typed architecture graph, and optional context for humans and agents.
3
+ Systems publishes one JSON document containing a complete Sources snapshot, ordered design layers, explicit implementation mappings, optional instance descriptions, and shared context. Systems 2.0 replaces the previous single-graph format; legacy Systems documents are unsupported. Sources and Changes remain OpenShip 1.0.
4
4
 
5
- Systems is JSON-only in v1. Legacy directory or YAML bundles are not canonical OpenShip Systems representations.
6
-
7
- ## Top-level document
5
+ ## Envelope and system
8
6
 
9
7
  ```json
10
8
  {
11
9
  "openship": "1.0",
12
10
  "capability": "systems",
13
- "source": {
14
- "manifest": { "openship": "1.0", "capability": "sources", "digest": "sha256:..." },
15
- "bundle": { "openship": "1.0", "capability": "sources", "digest": "sha256:...", "files": {} }
16
- },
11
+ "systemsVersion": "2.0",
12
+ "source": { "manifest": {}, "bundle": {} },
17
13
  "system": {
18
- "id": "example-system",
19
- "name": "Example system",
20
- "rootNodeId": "s.root",
21
- "nodes": [],
22
- "edges": []
14
+ "id": "example",
15
+ "name": "Example",
16
+ "layers": [],
17
+ "refinements": [],
18
+ "instances": []
23
19
  }
24
20
  }
25
21
  ```
26
22
 
27
- `source.manifest` and `source.bundle` MUST form a valid, complete Sources snapshot. External URLs or omitted contents are not self-contained and are non-conformant.
23
+ This illustrates the envelope only: `source.manifest` and `source.bundle` MUST be valid, complete Sources, and `layers` MUST contain at least one layer. See [the complete layered example](examples/valid/systems-layered.json) and [the schema](schemas/systems.schema.json).
28
24
 
29
- See [schemas/systems.schema.json](schemas/systems.schema.json).
25
+ The old `system.nodes`, `system.edges`, and `system.rootNodeId` members are forbidden. Metadata and unrecognized extension members MUST be preserved. Self-containment covers the design and source bytes; external secret and runtime-state references need not resolve within the document. Consumers MUST NOT interpret validation as proof of deployment or runtime health.
30
26
 
31
- ## Nodes and containment
27
+ ## Ordered design layers
32
28
 
33
- Node kinds are closed in v1:
29
+ Each layer has `id`, `name`, `role`, `rootNodeId`, `nodes`, and `edges`. Array order runs from abstract to concrete. Layer IDs MUST be unique. Roles are `logical`, `technical`, `provider`, or `custom`; roles MAY repeat and standard roles MAY be omitted.
34
30
 
35
- | Kind | Meaning |
31
+ | Recommended role | Decisions represented |
36
32
  |---|---|
37
- | `Root` | The logical boundary of the described system. |
38
- | `Host` | An execution environment or external platform. |
39
- | `Container` | A grouped runtime unit hosted by a Host. |
40
- | `Process` | A running service or executable component. |
41
- | `Library` | A reusable code dependency outside runtime containment. |
33
+ | logical | Responsibilities, contracts, logical entities and invariants, required initial data. |
34
+ | technical | Frameworks, runtimes, database engines, schemas, migrations and seed scripts. |
35
+ | provider | Hosting providers, intended regions, resources and deployment settings. |
36
+
37
+ Any positive number of layers is supported. Each is an explicit graph, not a generated projection or an inherited configuration overlay. Alternative branches are not defined in this version.
42
38
 
43
- Canonical node shape:
39
+ ## Nodes, containment and sources
40
+
41
+ Node kinds are `Root`, `Block`, `Store`, `Host`, `Container`, `Process`, and `Library`. Block describes a capability; Store describes persistent data. The other kinds describe a system boundary, execution environment, grouped runtime, executable component, and reusable dependency respectively.
44
42
 
45
43
  ```json
46
44
  {
47
- "id": "p.api",
48
- "kind": "Process",
49
- "name": "API",
50
- "parentId": "h.runtime",
51
- "sourceSelectors": ["apps/api/**", "packages/contracts/index.ts"],
52
- "metadata": { "runtime": "node", "ownership": "first_party" }
45
+ "id": "technical.database",
46
+ "kind": "Store",
47
+ "name": "PostgreSQL database",
48
+ "parentId": "technical.root",
49
+ "metadata": { "ownership": "first_party" },
50
+ "sourceSelectors": ["db/**"],
51
+ "configuration": [
52
+ { "name": "engine", "description": "Database engine", "required": true, "value": "PostgreSQL" }
53
+ ]
53
54
  }
54
55
  ```
55
56
 
56
- Rules:
57
+ - Node IDs MUST be globally unique across all layers. IDs match `^[A-Za-z0-9._:-]+$`.
58
+ - Each layer MUST have exactly one parentless Root identified by its `rootNodeId`. Every other node, including Library, MUST have a parent in the same layer. Containment MUST be acyclic; no kind-specific parent restrictions apply.
59
+ - Every node MUST declare `metadata.ownership`: `first_party` means publisher-controlled implementation or operation; `third_party` means external control.
60
+ - Optional source selectors select an exact Manifest path or a directory ending in `/**`. No other wildcards are supported. Every selector MUST match at least one Manifest path. Sharing selected paths is allowed.
61
+
62
+ ## Connections and refinements
57
63
 
58
- - Every node has `metadata.ownership`, whose value is `first_party` or `third_party`.
59
- - `first_party` means the system publisher owns or controls the component's implementation or operation. `third_party` means an external provider owns or controls it.
60
- - Exactly one node has kind `Root`; its ID equals `rootNodeId` and it has no parent.
61
- - Every Host has the Root as parent.
62
- - Every Container has a Host parent.
63
- - Every Process has a Host or Container parent.
64
- - Library has no parent. Process and Library cannot contain children.
65
- - IDs are unique and match `^[A-Za-z0-9._:-]+$`.
66
- - The containment graph is acyclic.
67
- - Metadata is open-ended beyond the required, typed `ownership` member. Boundary, ID prefixes, host naming, and other metadata are not required by v1.
64
+ Layer-local edges have `id`, `type`, `fromNodeId`, `toNodeId`, and optional metadata. IDs MUST be unique within their layer. Endpoints MUST be non-root nodes in that layer. Types are Runtime (cycles allowed), Dataflow (acyclic), and Dependency (acyclic). Endpoint kinds do not constrain the connection type.
68
65
 
69
- ### Source selectors
66
+ Refinements have `id`, `fromNodeId`, and `toNodeId`. IDs MUST be unique within `system.refinements`. The source MUST belong to a later layer than the target. Thus the concrete source implements the more abstract target. Many-to-many mappings, skipped layers, and root mappings are allowed. Refinements neither imply containment nor copy configuration, documents, or runtime edges.
70
67
 
71
- `sourceSelectors` is optional. An exact path selects itself. A selector ending in `/**` selects that directory and descendants. No other wildcard syntax is defined.
68
+ ## Domains (optional)
69
+
70
+ `system.domains` MAY declare an ordered list of domains. A domain groups blocks independently of layers, containment, and refinement. Each requires a unique `id`, a nonempty `name`, and `nodeIds`; an optional nonempty `description` explains its scope. Domain IDs use the standard ID grammar. Member IDs MUST be unique within the domain and MUST reference existing nodes anywhere in the system.
71
+
72
+ ```json
73
+ "domains": [
74
+ { "id": "web", "name": "Web app", "nodeIds": ["logical.web", "technical.web"] },
75
+ { "id": "state", "name": "State", "nodeIds": ["technical.web", "technical.database"] }
76
+ ]
77
+ ```
72
78
 
73
- Every selector MUST match at least one Manifest path. Multiple nodes MAY select the same path and some source paths MAY remain unassigned.
79
+ A node MAY belong to zero, one, or multiple domains. Empty domains and an empty domain list are valid. Membership is explicit and is not inherited through parents or refinements. Omitting domains preserves the existing Systems behavior.
74
80
 
75
- ## Edges
81
+ Viewers SHOULD select all domains initially. When filtering, a node matches if it has no domain or belongs to any selected domain. Keep the layer root and ancestors needed to render matching nodes as structural boundaries; this does not make other children visible. Hide connections whose endpoints do not match. Domain filters are presentation controls, not access controls. Keep domain selections across layer changes.
76
82
 
77
- Edge types are closed in v1:
83
+ Domains are an additive capability in package 0.1.1. The envelope remains `openship: "1.0"` and `systemsVersion: "2.0"`.
78
84
 
79
- | Type | Source | Target | Cycle rule |
80
- |---|---|---|---|
81
- | `Runtime` | Process | Process or Container | Cycles allowed. |
82
- | `Dataflow` | Process | Process or Container | Projected graph must be acyclic. |
83
- | `Dependency` | Process | Library | Graph must be acyclic. |
85
+ ## Configuration
86
+
87
+ Nodes and instance bindings MAY contain a `configuration` array. Each entry requires a unique `name`, a nonempty `description`, and a boolean `required` flag. Optional `value` contains JSON data; its absence means unresolved, whereas an explicit null is a supplied value.
88
+
89
+ A sensitive entry uses `sensitive: true` and MUST NOT contain a literal value. An optional `secretRef` is `{ "nodeId": "provider.app", "key": "DATABASE_URL" }`; its node MUST exist and scopes the external key to a component. Any entry with `secretRef` MUST NOT also contain `value`. A secret reference is descriptive: validation does not resolve it or require the external key to exist. Producers MUST classify credentials as sensitive and MUST NOT publish credential values elsewhere in metadata or context.
90
+
91
+ ## Instances and database state
92
+
93
+ Instances are separate from design layers. Each has a unique `id`, `name`, `environment`, `layerId`, and `bindings` array. Multiple instances MAY bind the same layer. Each binding refers to a distinct non-root node in that layer and MAY include `resourceId`, configuration, and database `state`. Missing resource IDs are unresolved.
84
94
 
85
95
  ```json
86
96
  {
87
- "id": "e.api.database",
88
- "type": "Runtime",
89
- "fromNodeId": "p.api",
90
- "toNodeId": "p.database",
91
- "metadata": { "protocol": "pgwire", "layer7": "postgresql-sql" }
97
+ "id": "production",
98
+ "name": "Production target",
99
+ "environment": "production",
100
+ "layerId": "provider",
101
+ "bindings": [{
102
+ "nodeId": "provider.database",
103
+ "configuration": [{
104
+ "name": "DATABASE_URL", "description": "Database connection", "required": true,
105
+ "sensitive": true, "secretRef": { "nodeId": "provider.database", "key": "DATABASE_URL" }
106
+ }]
107
+ }]
92
108
  }
93
109
  ```
94
110
 
95
- Root and Host cannot be edge endpoints under these rules. A Container target represents an opaque routing boundary.
111
+ Instance values are explicit observations or supplied descriptions, never implicit overrides of intended design values. Consumers SHOULD display them separately.
112
+
113
+ Only Store bindings may include state. State MAY contain `appliedMigration` and a `snapshot` object with required `ref` and RFC3339 `capturedAt`, and optional `sha256:...` digest. Omitted state means not supplied, not an empty database. References are opaque identifiers; consumers MUST NOT automatically fetch or restore them.
114
+
115
+ Logical entities and invariants belong in shared Data Model documents assigned to Store nodes. Technical schema, migration and seed files use source selectors or Code artifacts. Actual database records are not required. A snapshot reference does not establish that a deployment currently contains that state.
96
116
 
97
117
  ## Optional context
98
118
 
@@ -139,11 +159,11 @@ kind + "\n" + title + "\n" + language + "\n" + text
139
159
 
140
160
  Matrix assignments connect a node, a declared concern, and one or more `Document` or `Skill` hashes. References MUST resolve to documents of the corresponding kind.
141
161
 
142
- Prompts are not ordinary matrix references. `systemPromptRefs` belongs to context, references only `Prompt` documents, and applies only to the Root.
162
+ Prompts are not ordinary matrix references. `systemPromptRefs` belongs to context, references only `Prompt` documents, and applies to the overall system.
143
163
 
144
164
  ### Artifacts
145
165
 
146
- Artifact types are `Summary`, `Docs`, and `Code`. Each belongs to one node and one declared concern.
166
+ Artifact types are `Summary`, `Docs`, and `Code`. Each belongs to one globally identified node and one declared concern.
147
167
 
148
168
  - Summary and Docs carry UTF-8 `text` and optional language.
149
169
  - Code carries `sourcePaths` that resolve to Manifest files.
@@ -153,13 +173,11 @@ Artifact IDs are unique within the system.
153
173
 
154
174
  ## Validation order
155
175
 
156
- A consumer SHOULD validate in this order:
157
-
158
- 1. Top-level schema and embedded Sources.
159
- 2. Node IDs, root, containment, and parent kinds.
160
- 3. Edge endpoints and cycle rules.
161
- 4. Source selectors.
162
- 5. Concern declarations and document hashes.
163
- 6. Matrix, prompt, artifact, and supersession references.
176
+ 1. Envelope, Systems version, and embedded Sources integrity.
177
+ 2. Layer IDs, global node IDs, roots, containment, configuration and source selectors.
178
+ 3. Layer-local edges and cycle checks.
179
+ 4. Domain declarations and member references; refinement endpoints and order.
180
+ 5. Instance membership, bindings, configuration, state and secret scopes.
181
+ 6. Shared document hashes, concerns, matrix/artifact references, prompts and supersession chains.
164
182
 
165
- Unknown metadata keys MUST be preserved. Unknown node, edge, document, or artifact kinds are invalid in v1.
183
+ Unknown node, edge, document, artifact or layer-role values are invalid. Use the `custom` role for additional refinement levels.
@@ -7,7 +7,7 @@ OpenShip is a public interface between a running project and the people or agent
7
7
 
8
8
  1. **Sources** publishes an integrity-checked source snapshot.
9
9
  2. **Changes** accepts a patch against a Sources digest and produces an isolated candidate origin.
10
- 3. **Systems** publishes a self-contained JSON description of source, architecture, infrastructure, and optional agent context.
10
+ 3. **Systems** publishes a self-contained JSON description of source, ordered design layers, instance bindings, and optional agent context. Systems uses the additional `systemsVersion: "2.0"` discriminator.
11
11
 
12
12
  Sources is the foundation. Changes depends on Sources. Systems embeds a complete Sources snapshot but does not require Changes.
13
13