@openship/protocol 0.0.3 → 0.1.0

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,101 @@
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
+ ## Configuration
72
69
 
73
- Every selector MUST match at least one Manifest path. Multiple nodes MAY select the same path and some source paths MAY remain unassigned.
70
+ 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.
74
71
 
75
- ## Edges
72
+ 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.
76
73
 
77
- Edge types are closed in v1:
74
+ ## Instances and database state
78
75
 
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. |
76
+ 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
77
 
85
78
  ```json
86
79
  {
87
- "id": "e.api.database",
88
- "type": "Runtime",
89
- "fromNodeId": "p.api",
90
- "toNodeId": "p.database",
91
- "metadata": { "protocol": "pgwire", "layer7": "postgresql-sql" }
80
+ "id": "production",
81
+ "name": "Production target",
82
+ "environment": "production",
83
+ "layerId": "provider",
84
+ "bindings": [{
85
+ "nodeId": "provider.database",
86
+ "configuration": [{
87
+ "name": "DATABASE_URL", "description": "Database connection", "required": true,
88
+ "sensitive": true, "secretRef": { "nodeId": "provider.database", "key": "DATABASE_URL" }
89
+ }]
90
+ }]
92
91
  }
93
92
  ```
94
93
 
95
- Root and Host cannot be edge endpoints under these rules. A Container target represents an opaque routing boundary.
94
+ Instance values are explicit observations or supplied descriptions, never implicit overrides of intended design values. Consumers SHOULD display them separately.
95
+
96
+ 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.
97
+
98
+ 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
99
 
97
100
  ## Optional context
98
101
 
@@ -139,11 +142,11 @@ kind + "\n" + title + "\n" + language + "\n" + text
139
142
 
140
143
  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
144
 
142
- Prompts are not ordinary matrix references. `systemPromptRefs` belongs to context, references only `Prompt` documents, and applies only to the Root.
145
+ Prompts are not ordinary matrix references. `systemPromptRefs` belongs to context, references only `Prompt` documents, and applies to the overall system.
143
146
 
144
147
  ### Artifacts
145
148
 
146
- Artifact types are `Summary`, `Docs`, and `Code`. Each belongs to one node and one declared concern.
149
+ Artifact types are `Summary`, `Docs`, and `Code`. Each belongs to one globally identified node and one declared concern.
147
150
 
148
151
  - Summary and Docs carry UTF-8 `text` and optional language.
149
152
  - Code carries `sourcePaths` that resolve to Manifest files.
@@ -153,13 +156,11 @@ Artifact IDs are unique within the system.
153
156
 
154
157
  ## Validation order
155
158
 
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.
159
+ 1. Envelope, Systems version, and embedded Sources integrity.
160
+ 2. Layer IDs, global node IDs, roots, containment, configuration and source selectors.
161
+ 3. Layer-local edges and cycle checks.
162
+ 4. Refinement endpoints and order.
163
+ 5. Instance membership, bindings, configuration, state and secret scopes.
164
+ 6. Shared document hashes, concerns, matrix/artifact references, prompts and supersession chains.
164
165
 
165
- Unknown metadata keys MUST be preserved. Unknown node, edge, document, or artifact kinds are invalid in v1.
166
+ 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