@openengio/cli 0.0.0-stage → 0.23.3
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.
- package/LICENSE +202 -0
- package/README.md +326 -2
- package/THIRD-PARTY-NOTICES.md +235 -0
- package/bin/public/openeng.js +10528 -0
- package/package.json +21 -4
- package/skill/build-ui/SKILL.md +132 -0
- package/skill/conventions/SKILL.md +197 -0
- package/skill/demo/SKILL.md +112 -0
- package/skill/new-use-case/SKILL.md +132 -0
- package/skill/openeng/SKILL.md +238 -0
- package/skill/playbooks/engineering-requirements.md +121 -0
- package/skill/playbooks/product-lifecycle.md +115 -0
- package/skill/playbooks/project-management.md +100 -0
package/package.json
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openengio/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.23.3",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=22"
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"openeng": "bin/public/openeng.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin/public/",
|
|
14
|
+
"skill/",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE",
|
|
17
|
+
"THIRD-PARTY-NOTICES.md"
|
|
18
|
+
],
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public",
|
|
21
|
+
"registry": "https://registry.npmjs.org/"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-ui
|
|
3
|
+
description: Use when a person wants an object type's drawer (its object view) or its page (its App view) laid out, with the platform's own view components.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Build an object view or an App view
|
|
7
|
+
|
|
8
|
+
A type carries up to two views in `presentationBindings.views`: an **object view**, which lays out the drawer of
|
|
9
|
+
one object, and an **App view**, which lays out the type's page. Both are display only: they show data and take
|
|
10
|
+
page controls, and they never act. A view is built only from the platform's view catalogue. Read the catalogue
|
|
11
|
+
reference before step 3: the platform's agent loads it as the skill `author-views`, generated from the
|
|
12
|
+
catalogue the platform validates against. The CLI does not yet ship that generated reference. With `openeng`,
|
|
13
|
+
use this guide's examples and `openeng help types draft revise` for the wire shape, then validate the change
|
|
14
|
+
set; the host decides which components, props, bounds and bindings your version admits.
|
|
15
|
+
|
|
16
|
+
Work through the steps in order, and stop where a step says so.
|
|
17
|
+
|
|
18
|
+
## 1. Know what the view must answer
|
|
19
|
+
|
|
20
|
+
Ask the person what someone opening this drawer or this page needs to see or find, in their words: "which
|
|
21
|
+
requirements are still in review", "what is this part's target and its tolerance". Three to five questions.
|
|
22
|
+
|
|
23
|
+
Stop: the person agrees the questions.
|
|
24
|
+
|
|
25
|
+
## 2. Read the type
|
|
26
|
+
|
|
27
|
+
Read the type's whole document: its properties and their kinds, its required keys, its enumerations, and its
|
|
28
|
+
current views. A view names properties by key, and only properties the type defines. A derived value reads only
|
|
29
|
+
the type's number and boolean properties.
|
|
30
|
+
|
|
31
|
+
## 3. Choose the components
|
|
32
|
+
|
|
33
|
+
For each question, choose the components that answer it. Use the reference for what each takes.
|
|
34
|
+
|
|
35
|
+
| the view must | object view | App view |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| show this object's fields | `PropertyList`, `PropertyField`, `Value` | |
|
|
38
|
+
| show a number with its unit, or two side by side | `MetricCard`, `Stat` | `MetricCard` (count), `Stat` |
|
|
39
|
+
| show a state as a coloured label | `Badge` with `tones` | `Badge` |
|
|
40
|
+
| list this object's links | `ConnectionList` | |
|
|
41
|
+
| list the type's objects | | `Query` with `Table` and `Column`, or `List`, or `ObjectTable`, `ObjectList` |
|
|
42
|
+
| let the reader filter | `Search`, `Select`, `Toggle` | `Search`, `Select`, `Toggle` |
|
|
43
|
+
| group or hide detail | `Section`, `Tabs` and `TabPanel`, `Disclosure`, `Card`, `Grid`, `Stack` | the same |
|
|
44
|
+
| link to an object | `Link` | `Link` |
|
|
45
|
+
|
|
46
|
+
The root is `ObjectBody` for an object view and `AppBody` for an App view, and appears nowhere else.
|
|
47
|
+
|
|
48
|
+
## 4. Bind the data
|
|
49
|
+
|
|
50
|
+
- A page control's `value` binds two-way to page state: `{"$bindState": "/page/<name>"}`.
|
|
51
|
+
- A `Query` names the type that owns the view, its `fields`, a `limit`, and filters whose value is a literal or
|
|
52
|
+
`{"$state": "/page/<name>"}`; a text filter searches named properties.
|
|
53
|
+
- A `Table`, `Stat` or `List` names the `Query` element by its id in its `query` prop. Beneath a `Table` or a
|
|
54
|
+
`List`, a child reads the current row with `{"$item": "properties/<key>"}`, where the key is among the Query's
|
|
55
|
+
`fields`, or `{"$item": "objectId"}` for a `Link`.
|
|
56
|
+
- A `List` also carries `repeat: {"statePath": "/queries/<queryId>/items", "key": "objectId"}`.
|
|
57
|
+
|
|
58
|
+
## 5. Write, validate and show
|
|
59
|
+
|
|
60
|
+
Write the whole document, save it as part of the type's next version, and validate. Then show the person the
|
|
61
|
+
layout as an indented outline of element types and labels, and, where the platform's change-set preview is
|
|
62
|
+
offered, ask them to look at it there.
|
|
63
|
+
|
|
64
|
+
- [ ] Every property key the view names is one the type defines.
|
|
65
|
+
- [ ] Every `$item` key is among its Query's `fields`.
|
|
66
|
+
- [ ] No prop carries scope or styling (see "How this differs from json-render").
|
|
67
|
+
|
|
68
|
+
Stop: the person agrees the layout before the change set is accepted.
|
|
69
|
+
|
|
70
|
+
## How this differs from json-render
|
|
71
|
+
|
|
72
|
+
The platform renders views with json-render, and the public json-render skills (`json-render-core`,
|
|
73
|
+
`json-render-react` on skills.sh) teach features this catalogue refuses. If you know json-render, these are the
|
|
74
|
+
differences:
|
|
75
|
+
|
|
76
|
+
| json-render teaches | here | why |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| props naming a project, ref, organisation, namespace, object, type version, URL or path | refused, always | a view never chooses its own scope: the host derives the page's project and ref from its address, so a view cannot read or link outside it |
|
|
79
|
+
| `className`, `style`, `html`, `color` | refused, always | a visual choice is a design-token name, such as a Badge's `tone`, so every view keeps the platform's look and carries no raw HTML |
|
|
80
|
+
| defining your own catalog and components | not possible | a view is display data, not a capability: the web renders only the catalogue's components |
|
|
81
|
+
| fetching data from json-render | not possible | data enters only through a `Query` element, which the host scopes |
|
|
82
|
+
| `on` and actions | admits two checked actions | unchecked built-in state actions stay refused |
|
|
83
|
+
| `$computed` | refused | a closed list of registered functions, such as the signed-in person, is planned, not built |
|
|
84
|
+
| `$cond` / `$then` / `$else`, `visible`, `$template`, `$format` and other directives, `slots`, `$bindItem`, `watch` | refused | no reason is recorded yet; they are under review, and some may be admitted |
|
|
85
|
+
|
|
86
|
+
Use `$state`, `$bindState`, `$item` and `$index` where the reference marks a prop bindable. When this skill is
|
|
87
|
+
wired in, this table is printed from the catalogue's own list of refusals and their reasons.
|
|
88
|
+
|
|
89
|
+
## Examples
|
|
90
|
+
|
|
91
|
+
Both validate against the current catalogue for a `requirement` type with `identifier`, `title`, `statement`,
|
|
92
|
+
`status`, `priority`, `category`, `targetValue`, `tolerance` and `unit`.
|
|
93
|
+
|
|
94
|
+
An App view, the requirements page: a search box and a status filter over a table.
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{ "root": "body", "elements": {
|
|
98
|
+
"body": { "type": "AppBody", "props": {}, "children": ["controls", "requirements", "table"] },
|
|
99
|
+
"controls": { "type": "Stack", "props": { "direction": "row", "gap": "medium" }, "children": ["search", "status"] },
|
|
100
|
+
"search": { "type": "Search", "props": { "label": "Search", "value": { "$bindState": "/page/term" } }, "children": [] },
|
|
101
|
+
"status": { "type": "Select", "props": { "label": "Status", "value": { "$bindState": "/page/status" }, "property": "status" }, "children": [] },
|
|
102
|
+
"requirements": { "type": "Query", "props": { "typeKey": "requirement", "limit": 100,
|
|
103
|
+
"fields": ["identifier", "title", "status", "priority"],
|
|
104
|
+
"filters": [{ "kind": "text", "term": { "$state": "/page/term" }, "properties": ["identifier", "title", "statement"] }],
|
|
105
|
+
"sort": { "kind": "property", "property": "identifier", "direction": "asc" } }, "children": [] },
|
|
106
|
+
"table": { "type": "Table", "props": { "query": "requirements" }, "children": ["colId", "colTitle", "colStatus"] },
|
|
107
|
+
"colId": { "type": "Column", "props": { "header": "ID" }, "children": ["idValue"] },
|
|
108
|
+
"idValue": { "type": "Value", "props": { "value": { "$item": "properties/identifier" } }, "children": [] },
|
|
109
|
+
"colTitle": { "type": "Column", "props": { "header": "Requirement" }, "children": ["titleLink"] },
|
|
110
|
+
"titleLink": { "type": "Link", "props": { "object": { "$item": "objectId" }, "label": { "$item": "properties/title" } }, "children": [] },
|
|
111
|
+
"colStatus": { "type": "Column", "props": { "header": "Status" }, "children": ["statusBadge"] },
|
|
112
|
+
"statusBadge": { "type": "Badge", "props": { "label": { "$item": "properties/status" },
|
|
113
|
+
"tones": { "draft": "neutral", "in-review": "info", "approved": "success", "rejected": "danger" } }, "children": [] }
|
|
114
|
+
} }
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
An object view, the requirement's drawer: the statement first, the acceptance values in a tab.
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
{ "root": "body", "elements": {
|
|
121
|
+
"body": { "type": "ObjectBody", "props": {}, "children": ["header", "tabs", "links"] },
|
|
122
|
+
"header": { "type": "Stack", "props": { "direction": "row", "gap": "small" }, "children": ["status", "priority"] },
|
|
123
|
+
"status": { "type": "PropertyField", "props": { "field": "status" }, "children": [] },
|
|
124
|
+
"priority": { "type": "PropertyField", "props": { "field": "priority" }, "children": [] },
|
|
125
|
+
"tabs": { "type": "Tabs", "props": {}, "children": ["about", "acceptance"] },
|
|
126
|
+
"about": { "type": "TabPanel", "props": { "label": "Requirement" }, "children": ["fields"] },
|
|
127
|
+
"fields": { "type": "PropertyList", "props": { "fields": ["identifier", "title", "statement", "category"] }, "children": [] },
|
|
128
|
+
"acceptance": { "type": "TabPanel", "props": { "label": "Acceptance" }, "children": ["target"] },
|
|
129
|
+
"target": { "type": "PropertyList", "props": { "fields": ["targetValue", "tolerance", "unit"] }, "children": [] },
|
|
130
|
+
"links": { "type": "ConnectionList", "props": {}, "children": [] }
|
|
131
|
+
} }
|
|
132
|
+
```
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: conventions
|
|
3
|
+
description: Read before designing platform types, to understand field meanings, edge direction, trees, views and version constraints.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Conventions of the type language
|
|
7
|
+
|
|
8
|
+
This file explains what the fields of a type mean, how the platform draws them, and what can never
|
|
9
|
+
change after a type is published. Field names, kinds and allowed values are in `openeng help`. Read this
|
|
10
|
+
file before you design a type. Each section ends with what to check.
|
|
11
|
+
|
|
12
|
+
## 1. Things and links
|
|
13
|
+
|
|
14
|
+
- An **object type** is a kind of thing the team names, tracks and links: a system, a requirement, a
|
|
15
|
+
part. Do not make a type for a document that lists those things, such as a "system requirements
|
|
16
|
+
specification" whose text holds the requirements: each requirement would then be a paragraph that
|
|
17
|
+
nothing can link, count, verify or give a status. Make `requirement` a type, and show the document as
|
|
18
|
+
a view over the requirement objects. Put state such as status in an enumerated property.
|
|
19
|
+
- An **edge type** is one kind of relationship between two object types. Every relationship is an edge;
|
|
20
|
+
a property never holds another object's identifier, because nothing checks, follows, protects or
|
|
21
|
+
counts an identifier in a property.
|
|
22
|
+
- **One edge type per meaning.** Each edge has a label for each end, so one edge reads both ways.
|
|
23
|
+
- **Reuse before you create.** Extend an existing type with an optional property in a new version
|
|
24
|
+
rather than make a near-copy under a new name.
|
|
25
|
+
|
|
26
|
+
## 2. The fields of an edge type
|
|
27
|
+
|
|
28
|
+
| field | means |
|
|
29
|
+
|---|---|
|
|
30
|
+
| `sourceObjectType`, `targetObjectType` | exactly one object type at each end. To link a third type, add another edge type. |
|
|
31
|
+
| `kind` | `structural`: the object's one home. An object has at most one structural parent, and both ends are in one project. `traceability`: every other link, including links across projects. |
|
|
32
|
+
| `sourceLabel`, `targetLabel` | how the edge reads from each end, as a sentence from that side: "verified by" from the source, "verifies" from the target. |
|
|
33
|
+
| `parentEnd` | the end that is the parent in a tree: `source`, `target`, or `null` when the edge never shapes a tree. A structural edge must have one; the write is refused otherwise, and validate does not catch it. A traceability edge may have one, which lets an object sit under several parents. |
|
|
34
|
+
| `subjectEnd` | no effect today. Set it to `"source"`. |
|
|
35
|
+
| `readRule`, `writeRule` | `both-endpoints` unless the person accepts that a reader of one end learns the far end's identity and project (`either-endpoint`). The write rule is `both-endpoints`. |
|
|
36
|
+
|
|
37
|
+
Check: every structural edge has a `parentEnd`; every label reads as a sentence from its own end.
|
|
38
|
+
|
|
39
|
+
## 3. Direction
|
|
40
|
+
|
|
41
|
+
The graph view draws an edge's source before its target: with the default left-to-right layout, the source
|
|
42
|
+
is on the left. Which end is the source is therefore a choice about how the model reads. Two conventions
|
|
43
|
+
are in use, and both are sound:
|
|
44
|
+
|
|
45
|
+
- **Flow of work.** The source is the upstream end: the thing that comes first in the work. A
|
|
46
|
+
requirement is the source of its verification (`verified-by`: requirement to verification), a
|
|
47
|
+
verification the source of its result, a risk the source of the requirement that mitigates it. The
|
|
48
|
+
graph view reads left to right as the work proceeds, and a change to an object concerns everything to its
|
|
49
|
+
right. Jama Connect uses this direction ("upstream" and "downstream", with suspect links flowing
|
|
50
|
+
downstream).
|
|
51
|
+
- **Points at what is proved.** The arrow points at the thing that is satisfied or verified: a
|
|
52
|
+
verification is the source and the requirement the target (`verifies`: verification to requirement).
|
|
53
|
+
SysML's «satisfy» and «verify» relationships read this way, so a model meant to meet SysML tools reads
|
|
54
|
+
naturally in it.
|
|
55
|
+
|
|
56
|
+
Choose one convention for the whole model with the person, say which in the object types'
|
|
57
|
+
descriptions, and make every edge follow it. A model that mixes them reads backwards in places, and
|
|
58
|
+
because an edge's direction can never change once published (section 7), a mistake costs a new edge type
|
|
59
|
+
and a reconnection of every edge.
|
|
60
|
+
|
|
61
|
+
`parentEnd` is independent of direction. In "flow of work" a decomposition `derives` (parent requirement
|
|
62
|
+
to child requirement) has its parent at the source; in "points at what is proved" a `derives` drawn from
|
|
63
|
+
child to parent has its parent at the target. Both give the same tree.
|
|
64
|
+
|
|
65
|
+
Check: the model's convention is written down, and every edge follows it.
|
|
66
|
+
|
|
67
|
+
## 4. Trees
|
|
68
|
+
|
|
69
|
+
- An object type lists the edge types it hangs from, in rank order, in
|
|
70
|
+
`structureDeclaration.relationships`. For each object the first rank that offers it a parent wins, so
|
|
71
|
+
a requirement with `["has-requirement", "derives"]` hangs under its system in the default tree, not
|
|
72
|
+
under its parent requirement.
|
|
73
|
+
- Climbing up uses each type's own list: a requirement hangs under its system by the requirement's list,
|
|
74
|
+
and the system under its parent system by the system's list.
|
|
75
|
+
- An object under several parents through a traceability edge with a parent end appears once under each.
|
|
76
|
+
Each placement is an occurrence.
|
|
77
|
+
- "View" names two different things. A **named view** in `structureDeclaration.views` is a tree; an object
|
|
78
|
+
view or an App view in `presentationBindings.views` is a layout of the drawer or the page (section 5 and the
|
|
79
|
+
`build-ui` skill).
|
|
80
|
+
- A **named view** (`structureDeclaration.views`, each `{ key, label, steps }`) is a saved tree: one or
|
|
81
|
+
two edge steps. A two-step view passes through an intermediate object, which is left out of the tree
|
|
82
|
+
and may lend properties to the row (`decoration`); a part under its assembly through a BOM line, with
|
|
83
|
+
the line's quantity on the row.
|
|
84
|
+
- **Declaring any named view replaces the web's relationship picker with a picker of those views alone.**
|
|
85
|
+
When you add a view, declare the tree people use most as a view too, first, because the first view is
|
|
86
|
+
the default.
|
|
87
|
+
|
|
88
|
+
Check: each type's default tree is the one the person expects; a type with views has its main tree as
|
|
89
|
+
the first view.
|
|
90
|
+
|
|
91
|
+
## 5. The rail and the page
|
|
92
|
+
|
|
93
|
+
- The organisation holds one list of rail groups, in the order the rail draws them; it is sent whole
|
|
94
|
+
with the revise (`--rail-groups`, `railGroups`). A type places itself with
|
|
95
|
+
`presentationBindings.rail: { group, order }`; the group must be one of the list. A type with no
|
|
96
|
+
`rail` is listed under "More types": leave it off for a type that is the detail of another, not a
|
|
97
|
+
destination.
|
|
98
|
+
- `presentationBindings.title` names the property that titles the object in tables, trees and the graph view.
|
|
99
|
+
`presentationBindings.typeIcon` is a Material Symbols glyph name.
|
|
100
|
+
- An **object view** (`presentationBindings.views.object`, root `ObjectBody`) lays out the object's
|
|
101
|
+
drawer; an **App view** (`.app`, root `AppBody`) lays out the type's page. Only components the view
|
|
102
|
+
catalogue admits may appear, each with the props it takes.
|
|
103
|
+
|
|
104
|
+
## 6. Versions
|
|
105
|
+
|
|
106
|
+
- A new type key starts at version 1. A changed type is sent at its published version plus one;
|
|
107
|
+
`openeng types export` writes every type at that next version, ready to send.
|
|
108
|
+
- A change set holds only the types you change. A type sent unchanged publishes an identical new
|
|
109
|
+
version.
|
|
110
|
+
- Objects take their type's current version for presentation; an update moves an object to it.
|
|
111
|
+
|
|
112
|
+
## 7. What never changes
|
|
113
|
+
|
|
114
|
+
| once published | why |
|
|
115
|
+
|---|---|
|
|
116
|
+
| a type's key | versions are append-only |
|
|
117
|
+
| an edge's kind, endpoints, parent end, subject end, labels, read and write rules | existing edges were checked against them, and the read rule is written into every edge row and enforced below the API |
|
|
118
|
+
| a property, a required key, an enumeration member | a later version may only widen: add an optional property, add an enumeration member, raise a bound |
|
|
119
|
+
|
|
120
|
+
So keep required keys few, choose enumeration members the team will keep, and decide each edge with
|
|
121
|
+
care.
|
|
122
|
+
|
|
123
|
+
Three words are refused anywhere a key or an enumeration member may appear, from the first version on:
|
|
124
|
+
`__proto__`, `constructor` and `prototype` (rule `prototype-key`). Use another word, such as `prototyping`
|
|
125
|
+
for a lifecycle state. A wrong edge is replaced by a new edge type key and a reconnection, on a branch.
|
|
126
|
+
|
|
127
|
+
## 8. Writing data
|
|
128
|
+
|
|
129
|
+
- Data is written on a branch, submitted as a proposal, and merged. A merge names the branch and the
|
|
130
|
+
hash the reviewer reviewed (the proposal's `reviewedHash`), and lands on the project's trunk.
|
|
131
|
+
- An update is a compare-and-set per property: `{"<property>": {"from": {"value": <what it holds now>}, "to":
|
|
132
|
+
{"value": <the new value>}}}`; `{"absent": true}` stands for no value on either side. A `from` that no
|
|
133
|
+
longer matches is refused, so read the object first.
|
|
134
|
+
|
|
135
|
+
## 9. Examples
|
|
136
|
+
|
|
137
|
+
A minimal object type and a structural edge, every key at version 1:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"system": {
|
|
142
|
+
"typeCategory": "object", "typeKey": "system", "version": 1, "displayName": "System",
|
|
143
|
+
"description": "A system, subsystem or component; systems nest to form the product breakdown.",
|
|
144
|
+
"schemaLanguageVersion": "1",
|
|
145
|
+
"propertyDefinitions": { "identifier": { "kind": "string" }, "name": { "kind": "string" } },
|
|
146
|
+
"requiredPropertyKeys": ["identifier", "name"],
|
|
147
|
+
"presentationBindings": { "title": "name", "typeIcon": "account_tree", "rail": { "group": "Engineering", "order": 10 } },
|
|
148
|
+
"structureDeclaration": { "relationships": ["contains"] }
|
|
149
|
+
},
|
|
150
|
+
"contains": {
|
|
151
|
+
"typeCategory": "edge", "typeKey": "contains", "version": 1, "displayName": "Contains",
|
|
152
|
+
"sourceObjectType": "system", "targetObjectType": "system",
|
|
153
|
+
"kind": "structural", "subjectEnd": "source", "parentEnd": "source",
|
|
154
|
+
"sourceLabel": "contains", "targetLabel": "part of",
|
|
155
|
+
"schemaLanguageVersion": "1", "propertyDefinitions": {}, "requiredPropertyKeys": [],
|
|
156
|
+
"readRule": "both-endpoints", "writeRule": "both-endpoints"
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Send it with `--rail-groups '["Engineering"]'` when the organisation has no such group, or drop the
|
|
162
|
+
`rail` entry.
|
|
163
|
+
|
|
164
|
+
Two trees for one type, the main one first:
|
|
165
|
+
|
|
166
|
+
```json
|
|
167
|
+
"structureDeclaration": {
|
|
168
|
+
"relationships": ["has-requirement", "derives"],
|
|
169
|
+
"views": [
|
|
170
|
+
{ "key": "by-system", "label": "By system", "steps": ["has-requirement"] },
|
|
171
|
+
{ "key": "decomposition", "label": "Decomposition", "steps": ["derives"] }
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
An object view with a derived value, and an App view:
|
|
177
|
+
|
|
178
|
+
```json
|
|
179
|
+
"views": {
|
|
180
|
+
"object": { "root": "body", "elements": {
|
|
181
|
+
"body": { "type": "ObjectBody", "props": { "derived": [{ "id": "lowerBound", "label": "Lower bound", "result": "number",
|
|
182
|
+
"reads": ["targetValue", "tolerance"],
|
|
183
|
+
"expression": { "op": "-", "left": { "op": "property", "key": "targetValue" }, "right": { "op": "property", "key": "tolerance" } } }] },
|
|
184
|
+
"children": ["fields", "target", "links"] },
|
|
185
|
+
"fields": { "type": "PropertyList", "props": { "fields": ["identifier", "title", "statement", "status"] }, "children": [] },
|
|
186
|
+
"target": { "type": "MetricCard", "props": { "label": "Target", "values": [
|
|
187
|
+
{ "source": "property", "field": "targetValue" }, { "source": "derived", "id": "lowerBound" }] }, "children": [] },
|
|
188
|
+
"links": { "type": "ConnectionList", "props": {}, "children": [] } } },
|
|
189
|
+
"app": { "root": "body", "elements": {
|
|
190
|
+
"body": { "type": "AppBody", "props": {}, "children": ["count", "table"] },
|
|
191
|
+
"count": { "type": "ObjectCount", "props": { "label": "Requirements" }, "children": [] },
|
|
192
|
+
"table": { "type": "ObjectTable", "props": { "fields": ["identifier", "title", "status"] }, "children": [] } } }
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
These examples come from a requirements model;
|
|
197
|
+
`openeng skill playbook engineering-requirements` gives the whole model.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: demo
|
|
3
|
+
description: Use when a person new to OpenEngineering wants a hands-on tour, or has just signed in and has no task of their own yet. Builds a small example with them on a familiar workflow (requirements, product lifecycle, project tracking) or their own, optionally connects Onshape or a small local OAuth app, alternating your configuration with links and actions they take in the app.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Give a person a tour of OpenEngineering
|
|
7
|
+
|
|
8
|
+
The aim is one outcome the person cares about, experienced in the app with their own hands. Covering
|
|
9
|
+
features is not the aim: a tour is done when they have seen that outcome and know how to carry on.
|
|
10
|
+
Ask at most two questions at a time. Do not turn routine commands into permission questions.
|
|
11
|
+
|
|
12
|
+
## 1. Offer the tour once
|
|
13
|
+
|
|
14
|
+
After sign-in, when the person has no task of their own, offer once: "I can set up a small example
|
|
15
|
+
around your work, then we can explore it together in the app." They may accept, decline, or go to
|
|
16
|
+
their own task. An accepted tour covers work inside a demo organisation. It does not cover inviting
|
|
17
|
+
anyone, connecting an external account (Onshape), registering an app, or touching an existing
|
|
18
|
+
organisation's data: ask before each of those.
|
|
19
|
+
|
|
20
|
+
## 2. Learn what matters to them
|
|
21
|
+
|
|
22
|
+
Ask about their work first: "What do you design or manage, and where does the work get hard today?"
|
|
23
|
+
|
|
24
|
+
Then anchor the tour on a workflow they will recognise, and offer two or three that fit what they said,
|
|
25
|
+
each with one line on why:
|
|
26
|
+
- a requirements platform in the style of Jama or DOORS: requirements, their decomposition, and the
|
|
27
|
+
verification that proves them (`openeng skill playbook engineering-requirements`);
|
|
28
|
+
- a product lifecycle platform in the style of Arena or Windchill: parts, revisions, the bill of
|
|
29
|
+
materials, and changes that are requested, approved and released (`openeng skill playbook
|
|
30
|
+
product-lifecycle`);
|
|
31
|
+
- a project and work tracker (`openeng skill playbook project-management`).
|
|
32
|
+
|
|
33
|
+
Say plainly that they can go smaller, or ask for something entirely their own, and follow that when
|
|
34
|
+
they do. Then refine the chosen one in their terms: who is involved, what starts the work, what they
|
|
35
|
+
need to see, and what a good result looks like. Use their names for things inside the familiar shape.
|
|
36
|
+
If they would rather look around a fuller example before building their own, build a slightly larger
|
|
37
|
+
one from the chosen playbook first, and say which data is invented.
|
|
38
|
+
|
|
39
|
+
## 3. Agree a small story
|
|
40
|
+
|
|
41
|
+
Propose a short flow with a visible result, for example: "We make the controller and its thermal
|
|
42
|
+
requirement, record a failed test, then propose a fix on a branch for review." Keep it to two or three
|
|
43
|
+
types, a handful of objects, one relationship that shows structure, and one change that shows a
|
|
44
|
+
branch and a review. Create a new organisation for the tour (`openeng org create`) unless they ask to
|
|
45
|
+
use an existing one. Say which data is invented.
|
|
46
|
+
|
|
47
|
+
Design the types with `openeng skill new-use-case`, and keep its stop points. Read `openeng skill
|
|
48
|
+
conventions` before you choose relationships: structure (one parent) is not navigation (declared
|
|
49
|
+
relationships), and the difference shows in their tree.
|
|
50
|
+
|
|
51
|
+
## 4. Build in small steps, each with something to see
|
|
52
|
+
|
|
53
|
+
For each step:
|
|
54
|
+
1. Say in their words what you will do next and why.
|
|
55
|
+
2. Make the smallest useful change with `openeng`. Use one atomic batch for related writes.
|
|
56
|
+
3. Read the result back in the organisation, project and ref you meant. Validate before you publish.
|
|
57
|
+
Keep apart: accepted, validated, published, and seen rendered in the app.
|
|
58
|
+
4. Give a link from `openeng link` at once. Say what they should see there, and any limit of that page.
|
|
59
|
+
5. Invite one action that matters: edit a value, comment, subscribe, compare a branch with main, or
|
|
60
|
+
accept a proposal if their role allows it. Say what to do and what you will check afterwards.
|
|
61
|
+
6. Check the result with a read, not with their click. Then use their reaction to choose the next step.
|
|
62
|
+
|
|
63
|
+
Leave a state on screen until they have had a chance to see it. If they say a step is dull or already
|
|
64
|
+
clear, move on.
|
|
65
|
+
|
|
66
|
+
## 5. Make it usable in the app
|
|
67
|
+
|
|
68
|
+
Choose readable names and a distinct icon per type from the supported set. Build object views and
|
|
69
|
+
apps with `openeng skill build-ui` and the component catalogue it names; do not guess components or
|
|
70
|
+
bindings. A view is worth building when it serves the story; most tours need none.
|
|
71
|
+
|
|
72
|
+
## 6. Connect their tools, when it serves the story
|
|
73
|
+
|
|
74
|
+
Two extensions show that the platform is open. Offer each one when it fits; ask before starting either.
|
|
75
|
+
|
|
76
|
+
**Onshape, if they use it.** Ask whether they have an Onshape account and which document, team or
|
|
77
|
+
company they would like to mirror. Create a connector with `openeng connector create`. The person enters
|
|
78
|
+
their Onshape key pair themselves at the prompt of `openeng connector set-credential`: never ask for a key
|
|
79
|
+
in the conversation, never accept one pasted there, and never type one. Agree the import scope before
|
|
80
|
+
`openeng connector run`, then read `openeng connector runs` and show what arrived. Mirrored objects are owned by
|
|
81
|
+
the connector and are not edited here; trace them into the story with links. If a run imports nothing,
|
|
82
|
+
say what was looked for and ask them to check the scope.
|
|
83
|
+
|
|
84
|
+
**A small app of their own, using OAuth.** Offer to build a tiny local web app that signs in to
|
|
85
|
+
OpenEngineering and reads their data, for example a dashboard of failed tests. Register it as a public
|
|
86
|
+
client of their organisation with `openeng admin-sdk registerClient` (read `openeng help admin-sdk
|
|
87
|
+
registerClient` first), using a `http://127.0.0.1:<port>/callback` redirect. The app uses the
|
|
88
|
+
authorization-code flow with PKCE against the issuer the help names, so the person signs in and
|
|
89
|
+
consents on OpenEngineering's own page; the app never sees their password. Keep it read-only unless
|
|
90
|
+
they ask for more, run it on their machine, and give them the local link. Read the platform's published
|
|
91
|
+
client contract before you write the app; do not guess the request shape.
|
|
92
|
+
|
|
93
|
+
## 7. When something goes wrong
|
|
94
|
+
|
|
95
|
+
Read the refusal and fix the input. When the help does not say enough, make a minimal example, record
|
|
96
|
+
the exact command and answer, and ask the person; do not guess in a loop. When an outcome is unknown,
|
|
97
|
+
read the state before you write again. Never claim to have contacted the OpenEngineering team.
|
|
98
|
+
|
|
99
|
+
## 8. End on the outcome
|
|
100
|
+
|
|
101
|
+
Recap what they saw, with the links to come back to, and one or two next steps for their own work. Say
|
|
102
|
+
what remains in the demo organisation: types, objects, branches, proposals and drafts, and any
|
|
103
|
+
connector or registered client, which they can revoke (`openeng connector revoke`). Agree before
|
|
104
|
+
deleting anything. Do not imply that a short tour proves every feature or permission.
|
|
105
|
+
|
|
106
|
+
## Dogfood mode (only when the person asks for feedback capture)
|
|
107
|
+
|
|
108
|
+
The OpenEngineering team uses this mode to test the product. Record each friction as it happens, with
|
|
109
|
+
the command, the answer and your confidence, classed as: your own omission, a help gap, an observed
|
|
110
|
+
defect, a user-reported issue, a feature request, or an open question. Merge later corrections into
|
|
111
|
+
earlier entries. At the end, hand over one file: the findings grouped, with evidence, a proposed
|
|
112
|
+
priority and the open questions, kept apart from the recap. Never send feedback anywhere yourself.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: new-use-case
|
|
3
|
+
description: Use when a person wants types for a use case their organisation's catalogue does not yet model, from the platform's own agent or from your own agent using `openeng`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Design the types for a new use case
|
|
7
|
+
|
|
8
|
+
Work through the steps in order. Do not skip a stop point: at each one, show the person what you
|
|
9
|
+
have and wait for their agreement. Ask at most three questions at a time, each with lettered options
|
|
10
|
+
and your recommendation. Draft nothing in a change set before step 7. Read `openeng skill conventions` before
|
|
11
|
+
step 3; it holds the rules every step below relies on.
|
|
12
|
+
|
|
13
|
+
## The tools, by step
|
|
14
|
+
|
|
15
|
+
| step | in the platform's agent | with `openeng` |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| read the catalogue | `read_catalogue` | `openeng types list --project <id>`; `openeng types export --project <id>` for every type's whole document |
|
|
18
|
+
| read one type | `describe_type` | the type's key in `openeng types export --project <id>` |
|
|
19
|
+
| read the change set | `read_change_set` | `openeng types draft current`; `openeng types draft show --change-set <id> --project <id>` |
|
|
20
|
+
| read sample objects | `sample_objects` | `openeng objects-sdk queryObjects` |
|
|
21
|
+
| open a change set | `open_change_set` | `openeng types draft open` |
|
|
22
|
+
| save the changed types | `revise_change_set` | `openeng types draft revise --change-set <id> --revision <token> --from <file> [--rail-groups <json>]` |
|
|
23
|
+
| validate | `validate_change_set` | `openeng types draft validate --change-set <id> --revision <token>` (exit 4 with violations) |
|
|
24
|
+
| try a sample against a draft type | `try_instance` | none yet; validate, and after acceptance write one object on a throwaway branch |
|
|
25
|
+
| publish | never: the person publishes | `openeng types draft accept` only after the person says so, for that change set |
|
|
26
|
+
| search the web | `web_search`, `web_fetch` | your own tools, under the same rule: never put anything read from the platform into a query or an address |
|
|
27
|
+
|
|
28
|
+
## 1. Understand the use case
|
|
29
|
+
|
|
30
|
+
Ask what the team does, who uses the model, and which questions it must answer. Write the questions
|
|
31
|
+
down in the team's own words, for example "which requirements have no verification".
|
|
32
|
+
|
|
33
|
+
- [ ] The use case in one or two sentences.
|
|
34
|
+
- [ ] Three to seven questions the model must answer.
|
|
35
|
+
|
|
36
|
+
Stop: the person agrees the use case and the questions.
|
|
37
|
+
|
|
38
|
+
## 1b. Orient in the existing catalogue
|
|
39
|
+
|
|
40
|
+
Read the whole published catalogue and every type that might touch the use case. Other use cases built
|
|
41
|
+
it, and this one should join it. An organisation with no published types starts from the examples in
|
|
42
|
+
`openeng skill conventions`; there is nothing to export.
|
|
43
|
+
|
|
44
|
+
- [ ] Each concept mapped to an existing type, a close type, or nothing yet.
|
|
45
|
+
- [ ] For each close type: reuse with an extension (an optional property in a new version), or a new
|
|
46
|
+
type, with the cost of each and a recommendation.
|
|
47
|
+
- [ ] The existing types the new ones must connect to, and by which edge.
|
|
48
|
+
- [ ] The catalogue's naming, icons and rail groups, to follow.
|
|
49
|
+
|
|
50
|
+
Stop: show the person the map, and agree what is reused, what is extended and what is new.
|
|
51
|
+
|
|
52
|
+
## 2. Survey the domain
|
|
53
|
+
|
|
54
|
+
Read the domain playbook with `openeng skill playbook <name>`, when there is one.
|
|
55
|
+
`openeng help skill` lists the available playbooks. Then check it against the
|
|
56
|
+
established tools and standards the team names, and where sources disagree, say what each choice
|
|
57
|
+
costs.
|
|
58
|
+
|
|
59
|
+
- [ ] The concepts most sources share.
|
|
60
|
+
- [ ] Where sources disagree, and the cost of each choice.
|
|
61
|
+
- [ ] Any standard the team follows, by name.
|
|
62
|
+
|
|
63
|
+
Stop: a summary of no more than ten lines, and ask what the team does differently.
|
|
64
|
+
|
|
65
|
+
## 3. Propose the core
|
|
66
|
+
|
|
67
|
+
Propose five to ten object types and the edges between them. Say what one object of each type is, in
|
|
68
|
+
one sentence, and what fact each edge records. Reuse and extend what step 1b agreed. Where the shape is
|
|
69
|
+
a real choice, offer one or two alternatives with their cost, and recommend one.
|
|
70
|
+
|
|
71
|
+
- [ ] Each type is a kind of thing, not a document or a state.
|
|
72
|
+
- [ ] Each relationship is an edge; no property holds another object's identifier.
|
|
73
|
+
- [ ] One edge type per meaning.
|
|
74
|
+
- [ ] No new type is a near-copy of an existing one.
|
|
75
|
+
- [ ] Every question from step 1 is answered by following edges and reading properties.
|
|
76
|
+
|
|
77
|
+
Stop: the person chooses the core.
|
|
78
|
+
|
|
79
|
+
## 4. Decide the edges and the trees
|
|
80
|
+
|
|
81
|
+
For each edge type, decide what `openeng skill conventions` lists: kind, source and target, which end is upstream,
|
|
82
|
+
labels for both ends, the parent end, and the read rule. Then decide each object type's ranked
|
|
83
|
+
relationships and any named views.
|
|
84
|
+
|
|
85
|
+
- [ ] One direction convention for the whole model, chosen with the person and written in the types'
|
|
86
|
+
descriptions: "flow of work" or "points at what is proved" (`openeng skill conventions`, section 3). Every
|
|
87
|
+
edge follows it; a model never mixes the two.
|
|
88
|
+
- [ ] Every structural edge has a parent end.
|
|
89
|
+
- [ ] If a type declares any named view, the tree the person uses most is declared as a view too, and
|
|
90
|
+
first, because declaring views replaces the relationship picker.
|
|
91
|
+
|
|
92
|
+
Stop: show the person the tree each type will produce and the direction it gives the graph view, drawn as text.
|
|
93
|
+
|
|
94
|
+
## 5. Decide properties, titles, icons and the rail
|
|
95
|
+
|
|
96
|
+
- [ ] Scalars rather than arrays.
|
|
97
|
+
- [ ] Few required keys: a later version cannot add one.
|
|
98
|
+
- [ ] State as an enumeration whose members the team will keep: a member cannot be removed.
|
|
99
|
+
- [ ] `presentationBindings.title`, a required string property that names the object.
|
|
100
|
+
- [ ] `presentationBindings.typeIcon`, a Material Symbols glyph name.
|
|
101
|
+
- [ ] The rail: the organisation's groups, and each type's group and order; or no rail entry for a type
|
|
102
|
+
that is the detail of another, not a destination.
|
|
103
|
+
|
|
104
|
+
Stop: the person agrees the properties and the rail.
|
|
105
|
+
|
|
106
|
+
## 6. Decide views, if any
|
|
107
|
+
|
|
108
|
+
An object view shapes the object's drawer; an App view shapes the type's page. Propose one only when the
|
|
109
|
+
default layout does not answer step 1's questions. Use only the components the view catalogue admits.
|
|
110
|
+
|
|
111
|
+
- [ ] For each view: its kind, its root component, and the properties and derived values it shows.
|
|
112
|
+
|
|
113
|
+
## 7. Draft small and validate
|
|
114
|
+
|
|
115
|
+
Propose a plan for the change set. Once it is approved, open the change set and save the core: the
|
|
116
|
+
object types and the edge types between them, nothing more. Then validate until it answers no
|
|
117
|
+
violations. Where the tool exists, try one realistic sample of each type, and one that lacks a required
|
|
118
|
+
key.
|
|
119
|
+
|
|
120
|
+
## 8. Iterate
|
|
121
|
+
|
|
122
|
+
Add the rest in small saves, validating after each. Each save holds the whole set of changed types.
|
|
123
|
+
When a save is refused as stale, read the change set again and build on it.
|
|
124
|
+
|
|
125
|
+
Stop: walk the person through the draft, type by type, and take their changes.
|
|
126
|
+
|
|
127
|
+
## 9. Hand over
|
|
128
|
+
|
|
129
|
+
Tell the person, in a few lines: the types and edges drafted, the tree and the direction each produces,
|
|
130
|
+
the rail, any choice you made that they did not ask for, and what a later version can and cannot
|
|
131
|
+
change. Show the change set's diff. The person publishes; with `openeng`, accept only on their word naming
|
|
132
|
+
this change set.
|