archik 0.2.1 → 0.4.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.
@@ -20,16 +20,71 @@ can talk about the system without re-explaining it every time.
20
20
  1. **Before** answering structural questions — *"what does X do?",
21
21
  "what depends on Y?", "where does data flow when …?"* — read
22
22
  `architecture.archik.yaml`. Don't guess from filenames or memory.
23
- 2. **When** work introduces, removes, or rewires components, propose
24
- an update to the YAML alongside the implementation. The user owns
25
- the file — suggest, don't silently apply.
26
- 3. **After** every edit to the YAML, run `archik validate`. Fix any
23
+ 2. **When** work introduces, removes, or rewires components, write
24
+ the proposed end-state to `architecture.archik.suggested.yaml`
25
+ (same schema, plus a `metadata.suggestion` block — see "Suggesting
26
+ changes" below). Don't edit `architecture.archik.yaml` directly;
27
+ the user reviews and accepts in the canvas or via
28
+ `archik suggest accept`.
29
+ 3. **After** every edit to a YAML, run `archik validate`. Fix any
27
30
  reported errors before declaring the change done.
28
31
 
29
32
  The sections below are the detailed reference behind these three
30
33
  rules — *when* to consult, *when* to propose, schema, taxonomy,
31
34
  relationship vocabulary, and CLI.
32
35
 
36
+ ## Suggesting changes (the sidecar workflow)
37
+
38
+ The `archik.yaml` is the user's source of truth. You don't get to
39
+ mutate it directly. Instead, write your proposed end-state to a
40
+ sidecar file:
41
+
42
+ ```
43
+ architecture.archik.yaml ← truth — user owns it
44
+ architecture.archik.suggested.yaml ← your draft proposal
45
+ ```
46
+
47
+ The sidecar is a complete, valid Archik document — same schema as the
48
+ main file, plus a `metadata.suggestion` block that marks it as a
49
+ proposal:
50
+
51
+ ```yaml
52
+ version: "1.0"
53
+ name: My Architecture
54
+ metadata:
55
+ suggestion:
56
+ from: architecture.archik.yaml
57
+ at: 2026-04-26T17:00:00Z
58
+ note: add Stripe payment flow # optional one-liner
59
+ nodes:
60
+ # ... entire proposed end-state, not just the delta
61
+ edges:
62
+ # ...
63
+ ```
64
+
65
+ Once you've written the sidecar:
66
+
67
+ * The canvas shows a **📝 Suggestion pending** banner with `Review`,
68
+ `Accept`, `Reject` buttons. Review opens a colour-coded SVG diff in
69
+ a new tab; Accept renames the sidecar over the main file; Reject
70
+ deletes the sidecar.
71
+ * From the terminal: `archik suggest show | accept | reject`.
72
+
73
+ If the user has no canvas open and asks "apply it", run
74
+ `archik suggest accept` for them (only after they've explicitly
75
+ asked).
76
+
77
+ **Key rules:**
78
+
79
+ * Write the *full proposed document*, not a patch. The diff is
80
+ computed by archik between the main file and the sidecar.
81
+ * Run `archik validate architecture.archik.suggested.yaml` after
82
+ writing. The schema enforces cross-references (no dangling edges,
83
+ no parent cycles, no duplicate ids); silent failures are not OK.
84
+ * If a suggestion sidecar already exists, treat it as your previous
85
+ proposal — extend or replace it. Don't write a new sidecar with a
86
+ different name.
87
+
33
88
  ## When to consult the YAML
34
89
 
35
90
  Read it **before answering** any of these:
@@ -69,17 +124,30 @@ The YAML tracks **shape**, not implementation detail.
69
124
 
70
125
  ## Hard rules for editing
71
126
 
127
+ The schema enforces these — `archik validate` will reject the file
128
+ if you break any of them, so don't bother trying.
129
+
72
130
  - **Never put coordinates** (`x`, `y`, `width`, `height`, `viewport`) in
73
131
  the YAML. Layout is computed by ELK on every render. The schema
74
132
  rejects unknown keys at root, node, edge, and metadata levels.
75
133
  - **Every id matches** `^[a-z][a-z0-9-]*$` — lowercase, starts with a
76
134
  letter, hyphens allowed.
77
- - **Edges reference existing nodes**. If `from` or `to` doesn't match a
78
- node id, the document fails to load.
79
- - **`parentId` references existing nodes** (typically `module` or
80
- `custom` containers).
135
+ - **Node ids and edge ids are unique** within their respective lists.
136
+ Duplicates fail validation.
137
+ - **Edges reference existing nodes**. If `from` or `to` doesn't match
138
+ a node id, the document fails to load.
139
+ - **No self-loop edges** — `from === to` isn't meaningful for an
140
+ architecture diagram and the schema rejects it.
141
+ - **`parentId` references an existing node** (any kind — typically a
142
+ `module` or `custom` container, but any node-with-children renders
143
+ as a container).
144
+ - **No `parentId` cycles** — a → b → a, or a node with itself as parent.
145
+ - **Any node with children is rendered as a container** regardless of
146
+ kind. So you can have a `frontend` "Web App" containing `module`
147
+ sub-areas, or a `service` containing `adapter` children — the icon
148
+ and KIND tag in the header still reflect the node's own kind.
81
149
  - **Don't rename a node id**. Remove the old node and re-add it with
82
- the new id, then fix every edge that referenced it.
150
+ the new id, then fix every edge / parentId that referenced it.
83
151
  - **Don't change `version`** — it's `"1.0"`.
84
152
 
85
153
  ## Schema (top-level)
@@ -163,8 +231,27 @@ Picking the right kind:
163
231
  - A logical grouping container (component, module) → `module`
164
232
  - Anything that doesn't fit and you want a custom shape → `custom`
165
233
 
166
- `module` and `custom` render as containers when they have children — set
167
- `parentId` on the children to nest them inside.
234
+ **Distinct visual shapes** (not just an icon — the *outline* differs):
235
+
236
+ | Kind | Shape |
237
+ | ---- | ----- |
238
+ | `database` | classic UML cylinder |
239
+ | `cloud` | cumulus cloud silhouette |
240
+ | `queue` | rounded capsule (pill) |
241
+ | `external` | dashed-border card |
242
+ | `module` / `custom` (with children) | container panel with header + tinted body |
243
+
244
+ Every other kind renders as the standard rounded card — the kind icon
245
+ in the header and the KIND label do the visual lifting. Don't expect
246
+ each kind to have its own outline; the icon + KIND tag is the
247
+ identity.
248
+
249
+ **Containers**: any node with children (declared via other nodes'
250
+ `parentId`) renders as a container, regardless of kind. So
251
+ `frontend` "Web App" can contain `module` sub-areas, a `service`
252
+ can contain hexagonal `port`/`adapter` children, etc. The kind of
253
+ the container itself controls the icon + accent colour shown in the
254
+ header bar.
168
255
 
169
256
  ## Edge fields
170
257
 
@@ -179,29 +266,56 @@ Picking the right kind:
179
266
  color: "#f97316" # optional, any CSS color (hex / named / var())
180
267
  ```
181
268
 
182
- ## Relationships (12 total)
183
-
184
- | Category | Relationship | Visual |
185
- | -------------- | ------------ | ------ |
186
- | Sync calls | `http_call`, `invokes`, `routes_to` | dotted, animated |
187
- | Data access | `reads`, `writes` | dotted, animated |
188
- | Messaging | `publishes`, `subscribes`, `streams_to` | dotted, animated |
189
- | Architectural | `implements`, `depends_on`, `has_a`, `uses` | static + muted |
269
+ ## Relationships (17 total)
270
+
271
+ | Category | Relationship | Visual signature |
272
+ | -------------- | ------------ | ---------------- |
273
+ | Sync wire | `http_call` | dotted, animated, filled-triangle arrow |
274
+ | | `grpc` | thicker dashed, animated, **double-tick chevron** arrow |
275
+ | | `invokes` | dotted, animated, filled-triangle arrow |
276
+ | | `routes_to` | solid, no animation |
277
+ | Bidirectional | `websocket` | dashed, **fast** animation, **arrows on both ends** |
278
+ | Async callback | `webhook` | long-dash dashed, animated, hollow-triangle arrow |
279
+ | Data access | `reads` | dotted, animated, hollow-triangle arrow |
280
+ | | `writes` | thicker dotted, animated, filled-triangle arrow |
281
+ | Messaging | `publishes` | dotted, animated, **circle** arrow head |
282
+ | | `subscribes` | dotted, animated, filled-triangle arrow |
283
+ | | `streams_to` | long-dash, **fast** animation, filled-triangle |
284
+ | UML structural | `implements` | dashed, **hollow-triangle** at the interface end (UML realisation) |
285
+ | | `extends` | solid, **hollow-triangle** at parent end (UML inheritance) |
286
+ | | `composes` | solid, **filled-diamond at the owner (source) end** (UML composition) |
287
+ | Loose deps | `depends_on` | dashed, hollow-triangle arrow |
288
+ | | `has_a` | solid, filled-triangle (informal composition) |
289
+ | | `uses` | short-dash, hollow-triangle (lightest dependency) |
190
290
 
191
291
  Picking the right relationship:
192
292
 
193
- - Service-to-service HTTP / RPC call → `http_call`
194
- - Calling a function or agent → `invokes`
195
- - Gateway routing requests → `routes_to`
293
+ **Wire-protocol calls** (something is going over the network *now*):
294
+ - Generic HTTP / REST call → `http_call`
295
+ - Typed RPC (protobuf, Connect, Twirp) → `grpc`
296
+ - Function / agent / lambda invocation → `invokes`
297
+ - Gateway / ingress routing → `routes_to`
298
+ - Long-lived bidirectional connection (chat, live trading, collab) → `websocket`
299
+ - Async callback the *other party* pushes to *us* (Stripe webhook, GitHub event) → `webhook`
300
+
301
+ **Data access**:
196
302
  - DB read query → `reads`
197
303
  - DB write / mutation → `writes`
304
+
305
+ **Messaging**:
198
306
  - Emitting an event / message → `publishes`
199
307
  - Consuming an event / message → `subscribes`
200
- - Continuous stream of records → `streams_to`
201
- - Adapter implements an interface → `implements`
202
- - A depends on B at the package / build level → `depends_on`
203
- - Composition / ownership ("has a") → `has_a`
204
- - Lighter-weight dependency → `uses`
308
+ - Continuous stream of records (Kafka, Kinesis, log shipping) → `streams_to`
309
+
310
+ **UML class-diagram structural** (drawn in the same style as a UML class diagram, so the visual matches what an engineer expects on a board):
311
+ - Adapter realises an abstract interface → `implements`
312
+ - Subclass / subtype inherits → `extends`
313
+ - Whole owns the part's lifecycle (component composition) → `composes`
314
+
315
+ **Looser architectural** (not UML-strict — for "X depends on Y" without claiming a specific relationship):
316
+ - Package / build-level dependency → `depends_on`
317
+ - Informal "has a" without lifecycle ownership → `has_a`
318
+ - Lightest weight: "X uses Y somewhere" → `uses`
205
319
 
206
320
  ## Common editing patterns
207
321
 
@@ -285,6 +399,67 @@ edges:
285
399
  relationship: implements
286
400
  ```
287
401
 
402
+ **Modelling a real-time chat with WebSocket + a Stripe webhook**:
403
+
404
+ ```yaml
405
+ nodes:
406
+ - id: web
407
+ kind: frontend
408
+ name: Web App
409
+ - id: api
410
+ kind: service
411
+ name: Chat API
412
+ - id: stripe
413
+ kind: external
414
+ name: Stripe
415
+ edges:
416
+ - id: web-api-ws
417
+ from: web
418
+ to: api
419
+ relationship: websocket # bidirectional, fast animation
420
+ label: messages
421
+ - id: stripe-api-webhook
422
+ from: stripe
423
+ to: api
424
+ relationship: webhook # async callback
425
+ label: payment.succeeded
426
+ ```
427
+
428
+ **gRPC between two Go services + UML class hierarchy**:
429
+
430
+ ```yaml
431
+ nodes:
432
+ - id: orders
433
+ kind: service
434
+ name: Orders
435
+ - id: payments
436
+ kind: service
437
+ name: Payments
438
+ - id: order
439
+ kind: interface
440
+ name: Order
441
+ - id: subscription-order
442
+ kind: interface
443
+ name: SubscriptionOrder
444
+ - id: cart
445
+ kind: custom
446
+ name: Cart
447
+ edges:
448
+ - id: orders-payments-grpc
449
+ from: orders
450
+ to: payments
451
+ relationship: grpc # double-tick chevron
452
+ label: ChargeRequest
453
+ - id: subscription-extends-order
454
+ from: subscription-order
455
+ to: order
456
+ relationship: extends # UML hollow triangle
457
+ - id: cart-composes-order
458
+ from: cart
459
+ to: order
460
+ relationship: composes # UML filled diamond at Cart
461
+ ```
462
+
288
463
  ## CLI
289
464
 
290
465
  These commands are available globally if archik was installed via
@@ -296,6 +471,11 @@ archik validate # schema check (run after every edit)
296
471
  archik validate path/to/file.yaml
297
472
  archik render --out diagram.svg # headless layout → SVG
298
473
  archik render --theme light --out diagram-light.svg
474
+ archik diff a.yaml b.yaml # text + colour-coded SVG diff
475
+ archik diff a.yaml b.yaml --out diff.svg
476
+ archik suggest show # summary of pending sidecar (default)
477
+ archik suggest accept # apply the sidecar over the main file
478
+ archik suggest reject # discard the sidecar
299
479
  archik watch # re-render SVG on save
300
480
  archik check # drift: nodes vs source dirs
301
481
  archik dev # open the live editor in the browser (foreground)