@alisio/plugin-swarm 0.0.0-stage → 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.
Files changed (266) hide show
  1. package/.agents/agents/swarm-architect.md +20 -0
  2. package/.agents/agents/swarm-cleaner.md +20 -0
  3. package/.agents/agents/swarm-coder.md +20 -0
  4. package/.agents/agents/swarm-hardener.md +20 -0
  5. package/.agents/agents/swarm-lieutenant.md +20 -0
  6. package/.agents/agents/swarm-qa.md +20 -0
  7. package/.agents/agents/swarm-refactorer.md +20 -0
  8. package/.agents/agents/swarm-specifier.md +20 -0
  9. package/.agents/skills/swarm-architecture-rules/SKILL.md +43 -0
  10. package/.agents/skills/swarm-clarification/SKILL.md +42 -0
  11. package/.agents/skills/swarm-cleaner-metrics/SKILL.md +44 -0
  12. package/.agents/skills/swarm-engineering-constitution/SKILL.md +44 -0
  13. package/.agents/skills/swarm-gherkin-spec/SKILL.md +43 -0
  14. package/.agents/skills/swarm-handoff-protocol/SKILL.md +45 -0
  15. package/.agents/skills/swarm-lieutenant/SKILL.md +41 -0
  16. package/.agents/skills/swarm-mutation-hardening/SKILL.md +43 -0
  17. package/.agents/skills/swarm-qa-acceptance/SKILL.md +42 -0
  18. package/.agents/skills/swarm-tdd-slice/SKILL.md +44 -0
  19. package/.agents/skills/swarm-toolchain-profile/SKILL.md +41 -0
  20. package/LICENSE +21 -0
  21. package/README.es.md +337 -0
  22. package/README.md +322 -2
  23. package/assets/approval-flow.svg +1 -0
  24. package/assets/architecture.svg +1 -0
  25. package/assets/audit-states.svg +1 -0
  26. package/assets/dashboard.css +964 -0
  27. package/assets/dashboard.html +123 -0
  28. package/assets/dashboard.js +965 -0
  29. package/assets/dashboard.svg +1 -0
  30. package/assets/handoff-sequence.svg +1 -0
  31. package/assets/pack-pipelines.svg +1 -0
  32. package/assets/packs/four-pack/pack.json +18 -0
  33. package/assets/packs/six-pack/pack.json +22 -0
  34. package/assets/packs/two-pack/pack.json +14 -0
  35. package/assets/screenshots/dashboard-board-dark.png +0 -0
  36. package/assets/screenshots/dashboard-board-light.png +0 -0
  37. package/assets/screenshots/dashboard-documents-diff.png +0 -0
  38. package/assets/screenshots/dashboard-empty-state.png +0 -0
  39. package/assets/screenshots/dashboard-phone.png +0 -0
  40. package/assets/screenshots/dashboard-reject-dialog.png +0 -0
  41. package/assets/screenshots/dashboard-transcript-tail.png +0 -0
  42. package/assets/screenshots/dashboard-work-queue.png +0 -0
  43. package/assets/task-states.svg +1 -0
  44. package/assets/toolchains/node-ts.json +61 -0
  45. package/cover.svg +46 -0
  46. package/dist/adapters/child-session-runner.d.ts +36 -0
  47. package/dist/adapters/child-session-runner.d.ts.map +1 -0
  48. package/dist/adapters/child-session-runner.js +156 -0
  49. package/dist/adapters/child-session-runner.js.map +1 -0
  50. package/dist/adapters/fs-board-store.d.ts +11 -0
  51. package/dist/adapters/fs-board-store.d.ts.map +1 -0
  52. package/dist/adapters/fs-board-store.js +27 -0
  53. package/dist/adapters/fs-board-store.js.map +1 -0
  54. package/dist/adapters/fs-handoff-store.d.ts +36 -0
  55. package/dist/adapters/fs-handoff-store.d.ts.map +1 -0
  56. package/dist/adapters/fs-handoff-store.js +254 -0
  57. package/dist/adapters/fs-handoff-store.js.map +1 -0
  58. package/dist/adapters/fs-task-state-store.d.ts +16 -0
  59. package/dist/adapters/fs-task-state-store.d.ts.map +1 -0
  60. package/dist/adapters/fs-task-state-store.js +66 -0
  61. package/dist/adapters/fs-task-state-store.js.map +1 -0
  62. package/dist/adapters/git-worktree.d.ts +31 -0
  63. package/dist/adapters/git-worktree.d.ts.map +1 -0
  64. package/dist/adapters/git-worktree.js +209 -0
  65. package/dist/adapters/git-worktree.js.map +1 -0
  66. package/dist/adapters/process-exec.d.ts +36 -0
  67. package/dist/adapters/process-exec.d.ts.map +1 -0
  68. package/dist/adapters/process-exec.js +138 -0
  69. package/dist/adapters/process-exec.js.map +1 -0
  70. package/dist/adapters/process-gate-runner.d.ts +39 -0
  71. package/dist/adapters/process-gate-runner.d.ts.map +1 -0
  72. package/dist/adapters/process-gate-runner.js +242 -0
  73. package/dist/adapters/process-gate-runner.js.map +1 -0
  74. package/dist/adapters/unavailable-runner.d.ts +4 -0
  75. package/dist/adapters/unavailable-runner.d.ts.map +1 -0
  76. package/dist/adapters/unavailable-runner.js +12 -0
  77. package/dist/adapters/unavailable-runner.js.map +1 -0
  78. package/dist/app/audit.d.ts +23 -0
  79. package/dist/app/audit.d.ts.map +1 -0
  80. package/dist/app/audit.js +9 -0
  81. package/dist/app/audit.js.map +1 -0
  82. package/dist/app/budget.d.ts +29 -0
  83. package/dist/app/budget.d.ts.map +1 -0
  84. package/dist/app/budget.js +78 -0
  85. package/dist/app/budget.js.map +1 -0
  86. package/dist/app/chat-store.d.ts +18 -0
  87. package/dist/app/chat-store.d.ts.map +1 -0
  88. package/dist/app/chat-store.js +48 -0
  89. package/dist/app/chat-store.js.map +1 -0
  90. package/dist/app/documents.d.ts +33 -0
  91. package/dist/app/documents.d.ts.map +1 -0
  92. package/dist/app/documents.js +63 -0
  93. package/dist/app/documents.js.map +1 -0
  94. package/dist/app/forge.d.ts +106 -0
  95. package/dist/app/forge.d.ts.map +1 -0
  96. package/dist/app/forge.js +420 -0
  97. package/dist/app/forge.js.map +1 -0
  98. package/dist/app/operator.d.ts +46 -0
  99. package/dist/app/operator.d.ts.map +1 -0
  100. package/dist/app/operator.js +168 -0
  101. package/dist/app/operator.js.map +1 -0
  102. package/dist/app/pidfile.d.ts +18 -0
  103. package/dist/app/pidfile.d.ts.map +1 -0
  104. package/dist/app/pidfile.js +56 -0
  105. package/dist/app/pidfile.js.map +1 -0
  106. package/dist/app/project.d.ts +93 -0
  107. package/dist/app/project.d.ts.map +1 -0
  108. package/dist/app/project.js +291 -0
  109. package/dist/app/project.js.map +1 -0
  110. package/dist/app/prompts.d.ts +48 -0
  111. package/dist/app/prompts.d.ts.map +1 -0
  112. package/dist/app/prompts.js +88 -0
  113. package/dist/app/prompts.js.map +1 -0
  114. package/dist/app/pump.d.ts +144 -0
  115. package/dist/app/pump.d.ts.map +1 -0
  116. package/dist/app/pump.js +707 -0
  117. package/dist/app/pump.js.map +1 -0
  118. package/dist/app/services.d.ts +112 -0
  119. package/dist/app/services.d.ts.map +1 -0
  120. package/dist/app/services.js +323 -0
  121. package/dist/app/services.js.map +1 -0
  122. package/dist/app/state.d.ts +70 -0
  123. package/dist/app/state.d.ts.map +1 -0
  124. package/dist/app/state.js +96 -0
  125. package/dist/app/state.js.map +1 -0
  126. package/dist/args.d.ts +10 -0
  127. package/dist/args.d.ts.map +1 -0
  128. package/dist/args.js +33 -0
  129. package/dist/args.js.map +1 -0
  130. package/dist/coordinator.d.ts +80 -0
  131. package/dist/coordinator.d.ts.map +1 -0
  132. package/dist/coordinator.js +481 -0
  133. package/dist/coordinator.js.map +1 -0
  134. package/dist/dashboard/api.d.ts +28 -0
  135. package/dist/dashboard/api.d.ts.map +1 -0
  136. package/dist/dashboard/api.js +178 -0
  137. package/dist/dashboard/api.js.map +1 -0
  138. package/dist/dashboard/auth.d.ts +13 -0
  139. package/dist/dashboard/auth.d.ts.map +1 -0
  140. package/dist/dashboard/auth.js +36 -0
  141. package/dist/dashboard/auth.js.map +1 -0
  142. package/dist/dashboard/open.d.ts +7 -0
  143. package/dist/dashboard/open.d.ts.map +1 -0
  144. package/dist/dashboard/open.js +17 -0
  145. package/dist/dashboard/open.js.map +1 -0
  146. package/dist/dashboard/server.d.ts +28 -0
  147. package/dist/dashboard/server.d.ts.map +1 -0
  148. package/dist/dashboard/server.js +176 -0
  149. package/dist/dashboard/server.js.map +1 -0
  150. package/dist/doctor.d.ts +28 -0
  151. package/dist/doctor.d.ts.map +1 -0
  152. package/dist/doctor.js +108 -0
  153. package/dist/doctor.js.map +1 -0
  154. package/dist/domain/attention.d.ts +20 -0
  155. package/dist/domain/attention.d.ts.map +1 -0
  156. package/dist/domain/attention.js +41 -0
  157. package/dist/domain/attention.js.map +1 -0
  158. package/dist/domain/envelope.d.ts +37 -0
  159. package/dist/domain/envelope.d.ts.map +1 -0
  160. package/dist/domain/envelope.js +106 -0
  161. package/dist/domain/envelope.js.map +1 -0
  162. package/dist/domain/handoff.d.ts +57 -0
  163. package/dist/domain/handoff.d.ts.map +1 -0
  164. package/dist/domain/handoff.js +191 -0
  165. package/dist/domain/handoff.js.map +1 -0
  166. package/dist/domain/identifiers.d.ts +18 -0
  167. package/dist/domain/identifiers.d.ts.map +1 -0
  168. package/dist/domain/identifiers.js +70 -0
  169. package/dist/domain/identifiers.js.map +1 -0
  170. package/dist/domain/pack.d.ts +45 -0
  171. package/dist/domain/pack.d.ts.map +1 -0
  172. package/dist/domain/pack.js +207 -0
  173. package/dist/domain/pack.js.map +1 -0
  174. package/dist/domain/pipeline.d.ts +33 -0
  175. package/dist/domain/pipeline.d.ts.map +1 -0
  176. package/dist/domain/pipeline.js +50 -0
  177. package/dist/domain/pipeline.js.map +1 -0
  178. package/dist/domain/task.d.ts +26 -0
  179. package/dist/domain/task.d.ts.map +1 -0
  180. package/dist/domain/task.js +154 -0
  181. package/dist/domain/task.js.map +1 -0
  182. package/dist/domain/taskstate.d.ts +37 -0
  183. package/dist/domain/taskstate.d.ts.map +1 -0
  184. package/dist/domain/taskstate.js +98 -0
  185. package/dist/domain/taskstate.js.map +1 -0
  186. package/dist/gates/dry.d.ts +14 -0
  187. package/dist/gates/dry.d.ts.map +1 -0
  188. package/dist/gates/dry.js +71 -0
  189. package/dist/gates/dry.js.map +1 -0
  190. package/dist/gates/parsers.d.ts +34 -0
  191. package/dist/gates/parsers.d.ts.map +1 -0
  192. package/dist/gates/parsers.js +120 -0
  193. package/dist/gates/parsers.js.map +1 -0
  194. package/dist/index.d.ts +45 -0
  195. package/dist/index.d.ts.map +1 -0
  196. package/dist/index.js +207 -0
  197. package/dist/index.js.map +1 -0
  198. package/dist/options.d.ts +13 -0
  199. package/dist/options.d.ts.map +1 -0
  200. package/dist/options.js +27 -0
  201. package/dist/options.js.map +1 -0
  202. package/dist/panel.d.ts +5 -0
  203. package/dist/panel.d.ts.map +1 -0
  204. package/dist/panel.js +52 -0
  205. package/dist/panel.js.map +1 -0
  206. package/dist/ports/agent-runner.d.ts +51 -0
  207. package/dist/ports/agent-runner.d.ts.map +1 -0
  208. package/dist/ports/agent-runner.js +2 -0
  209. package/dist/ports/agent-runner.js.map +1 -0
  210. package/dist/ports/board-store.d.ts +7 -0
  211. package/dist/ports/board-store.d.ts.map +1 -0
  212. package/dist/ports/board-store.js +2 -0
  213. package/dist/ports/board-store.js.map +1 -0
  214. package/dist/ports/clock.d.ts +5 -0
  215. package/dist/ports/clock.d.ts.map +1 -0
  216. package/dist/ports/clock.js +2 -0
  217. package/dist/ports/clock.js.map +1 -0
  218. package/dist/ports/gate-runner.d.ts +34 -0
  219. package/dist/ports/gate-runner.d.ts.map +1 -0
  220. package/dist/ports/gate-runner.js +2 -0
  221. package/dist/ports/gate-runner.js.map +1 -0
  222. package/dist/ports/handoff-store.d.ts +39 -0
  223. package/dist/ports/handoff-store.d.ts.map +1 -0
  224. package/dist/ports/handoff-store.js +2 -0
  225. package/dist/ports/handoff-store.js.map +1 -0
  226. package/dist/ports/isolation.d.ts +43 -0
  227. package/dist/ports/isolation.d.ts.map +1 -0
  228. package/dist/ports/isolation.js +2 -0
  229. package/dist/ports/isolation.js.map +1 -0
  230. package/dist/ports/notifier.d.ts +28 -0
  231. package/dist/ports/notifier.d.ts.map +1 -0
  232. package/dist/ports/notifier.js +2 -0
  233. package/dist/ports/notifier.js.map +1 -0
  234. package/dist/ports/task-state-store.d.ts +10 -0
  235. package/dist/ports/task-state-store.d.ts.map +1 -0
  236. package/dist/ports/task-state-store.js +2 -0
  237. package/dist/ports/task-state-store.js.map +1 -0
  238. package/dist/refs.d.ts +10 -0
  239. package/dist/refs.d.ts.map +1 -0
  240. package/dist/refs.js +19 -0
  241. package/dist/refs.js.map +1 -0
  242. package/dist/resources.d.ts +55 -0
  243. package/dist/resources.d.ts.map +1 -0
  244. package/dist/resources.js +255 -0
  245. package/dist/resources.js.map +1 -0
  246. package/dist/status.d.ts +18 -0
  247. package/dist/status.d.ts.map +1 -0
  248. package/dist/status.js +60 -0
  249. package/dist/status.js.map +1 -0
  250. package/dist/storage.d.ts +18 -0
  251. package/dist/storage.d.ts.map +1 -0
  252. package/dist/storage.js +79 -0
  253. package/dist/storage.js.map +1 -0
  254. package/dist/toolchains/profile.d.ts +21 -0
  255. package/dist/toolchains/profile.d.ts.map +1 -0
  256. package/dist/toolchains/profile.js +60 -0
  257. package/dist/toolchains/profile.js.map +1 -0
  258. package/dist/toolchains/thresholds.d.ts +29 -0
  259. package/dist/toolchains/thresholds.d.ts.map +1 -0
  260. package/dist/toolchains/thresholds.js +45 -0
  261. package/dist/toolchains/thresholds.js.map +1 -0
  262. package/dist/version.d.ts +2 -0
  263. package/dist/version.d.ts.map +1 -0
  264. package/dist/version.js +3 -0
  265. package/dist/version.js.map +1 -0
  266. package/package.json +51 -3
package/README.md CHANGED
@@ -1,3 +1,323 @@
1
- # Temporary Holding Version
1
+ # @alisio/plugin-swarm
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ ![Swarm](./cover.svg)
4
+
5
+ > Español: [README.es.md](./README.es.md). The two READMEs must be updated together.
6
+
7
+ Swarm for Alisio runs a pipeline of specialised agents. Each agent works in its own git worktree and
8
+ passes committed work to the next one through durable handoff files. Deterministic code owns routing,
9
+ state and quality gates; agents only return strict JSON envelopes that the code validates.
10
+
11
+ > **Status: pre-release.** Everything below is implemented and tested with scripted fakes, including
12
+ > the local dashboard. The Alisio child-session runner, background execution and the dashboard have
13
+ > not been exercised against a live Alisio host yet; see "Running it for real".
14
+
15
+ ## Architecture
16
+
17
+ ![Swarm architecture: front ends call one services layer over ports and adapters](./assets/architecture.svg)
18
+
19
+ Commands, tools, the dashboard and the TUI panel are thin front ends over one services layer, which
20
+ drives pure domain code through ports (agent runner, isolation, stores, gate runner).
21
+
22
+ ## Requirements
23
+
24
+ - Node.js 22.16 or newer and `@alisio/sdk` 0.3 to 0.6.
25
+ - `git` 2.28 or newer on `PATH`. Run `/swarm:doctor` to check.
26
+ - No credentials and no network access, except when you clone a GitHub repository.
27
+
28
+ ## Install
29
+
30
+ ```sh
31
+ alisio install npm:@alisio/plugin-swarm
32
+ ```
33
+
34
+ ## Quickstart
35
+
36
+ ```text
37
+ /swarm:init
38
+ /swarm:doctor
39
+ /swarm:pack list
40
+ /swarm:project new demo --pack two-pack -- A small todo application
41
+ /swarm:task demo new -- Add a form to create todos
42
+ /swarm:status
43
+ /swarm:dashboard
44
+ ```
45
+
46
+ ## Commands
47
+
48
+ | Command | Purpose |
49
+ | --- | --- |
50
+ | `/swarm:init` | Create the forge under `.alisio/swarm` in the workspace. |
51
+ | `/swarm:doctor` | Check Node.js, git, the toolchain commands and the workspace. |
52
+ | `/swarm:pack list` / `show <name>` | List shipped and workspace packs, or show one. |
53
+ | `/swarm:project new <name> [--pack <p>] [--github <owner/repo>] -- <mission>` | Create and open a project. |
54
+ | `/swarm:project open <name>` / `close <name>` / `list` | Open, close or list projects. Closing never touches project files. |
55
+ | `/swarm:task <project> new [name] -- <text>` | Create a task card and queue it for the first role. |
56
+ | `/swarm:task <project> retry <name>` / `delete <name>` / `accept <name>` | Retry a stuck task, archive and remove it, or accept its work as it is. |
57
+ | `/swarm:status [project]` | Show lanes, tasks and items that need your attention. |
58
+ | `/swarm:approve <project>/<task>` | Approve the handoff held at the approval gate. Disabled while document comments exist. |
59
+ | `/swarm:reject <project>/<task> retry\|delete\|accept [-- comments]` | Retry (rejected commit kept under `refs/swarm/rejected/<task>`, base restored, role re-run with your findings), delete, or accept unchanged. |
60
+ | `/swarm:comment <project>/<task> <document> -- <text>` / `<project>/<task> clear` | Comment on a document of a task waiting for approval, or clear the comments. |
61
+ | `/swarm:answer <project>/<task> -- <text>` | Answer a clarification question from a role. |
62
+ | `/swarm:chat [project] -- <message>` | Talk to the read-only Lieutenant of a project. |
63
+ | `/swarm:stop <project>` | Cancel the project's agents and halt its pump; the project stays open. |
64
+ | `/swarm:run <project> [--seconds <1-3600>]` | Run the pump in the foreground until the project is idle (see "Running it for real"). |
65
+ | `/swarm:budget` / `budget raise <tokens>` | Show the swarm token budget or raise the cap. |
66
+ | `/swarm:dashboard [project\|project/task]` | Start the local follow-up dashboard and print its link (see "Dashboard"). |
67
+ | `/swarm:teardown --confirm TEARDOWN` | Cancel every agent and stop every project. Project files stay. |
68
+
69
+ A reference is `<project>/<task>` or the id of an item under needs your attention
70
+ (`approval:<project>:<task>`). In an interactive session, `approve`, `reject` and `teardown` ask with
71
+ `ui.askQuestions` when an argument is missing; headless, the command forms above are the contract.
72
+
73
+ The tools `swarm_status`, `swarm_task_new`, `swarm_gate_run` and `swarm_doctor` expose the same
74
+ services to agents. `swarm_gate_run` runs one named quality gate for a role and returns its report.
75
+
76
+ ## Agents
77
+
78
+ Every agent is named with the `swarm-` prefix (`swarm-specifier`, `swarm-coder`, `swarm-cleaner`,
79
+ `swarm-refactorer`, `swarm-architect`, `swarm-hardener`, `swarm-qa`, `swarm-lieutenant`) so the host
80
+ agent catalog never collides with another plugin that ships a `specifier` or `coder`. Pack role ids stay
81
+ short (`coder`, `qa`); one map in the plugin turns a role id into its agent name. Each agent file
82
+ declares its tools, turn limit, timeout and output budget; children can never call `task`, `delegate`,
83
+ `subagent` or `sessions_create`, and read-only roles run with `readOnly: true`.
84
+
85
+ ## Packs
86
+
87
+ A pack is data: the ordered roles, which role works on the main checkout, the approval gate, quality
88
+ gates and thresholds. Packs ship with the plugin and can also live in `.alisio/swarm/packs/<name>.json`
89
+ in the workspace; a workspace pack shadows a shipped pack with the same name.
90
+
91
+ ![The two-pack, four-pack and six-pack pipelines](./assets/pack-pipelines.svg)
92
+
93
+ The shipped pipelines, in order; the approval gate sits after the specifier in four-pack and six-pack.
94
+
95
+ | Pack | Pipeline |
96
+ | --- | --- |
97
+ | `two-pack` | coder, cleaner |
98
+ | `four-pack` | specifier, coder, refactorer, architect (approval after the specifier) |
99
+ | `six-pack` | specifier, coder, cleaner, architect, hardener, qa (approval after the specifier) |
100
+
101
+ The last role's handoff is broadcast merge-only to every other role and moves the card to Done.
102
+ Default thresholds (coverage 80 percent, complexity 6, CRAP 8, mutation 80 percent) are pack data and
103
+ can be changed per pack. The CRAP formula is the published `CC^2 * (1 - coverage)^3 + CC`.
104
+
105
+ ## How it works
106
+
107
+ - **Worktrees.** The master role works on the project's main checkout. Every other role gets a
108
+ worktree on the branch `swarm/<project>/<role>`. A `commit-msg` hook appends `By <role>.`.
109
+ - **Handoffs.** Work travels as a ten-character commit id inside a header-plus-body file under
110
+ `<project>/.alisio/swarm/handoffs/<role>/`. Files are the source of truth: after a crash the pump
111
+ replays the outbox and the board is rebuilt from them.
112
+ - **Merges.** The coordinator merges the sender's commit into the receiver's worktree before the
113
+ receiver runs. Conflicts are handed to the receiving role as part of its task.
114
+ - **Audit handshake.** The first handoff envelope is parked, the same session is asked to re-verify,
115
+ and an unchanged second envelope releases it.
116
+ - **Strict envelopes.** Invalid output (including output cut short by the turn limit) is rejected,
117
+ never repaired, and retried at most once before the card becomes blocked and appears under needs
118
+ your attention.
119
+ - **Approval gate.** In packs with `approval.after`, the handoff of that role is held until you
120
+ approve it. Reject offers retry, delete or accept unchanged.
121
+ - **Clarifications.** A role can ask one question; the card shows `clarifying` and the question is
122
+ persisted, so it survives a restart. Your answer resumes the same session (or a fresh one with the
123
+ question repeated after a restart).
124
+ - **Holds survive restarts.** Clarifications, agent-reported blocks, gate failures, approvals and
125
+ their comments are persisted. A runtime failure (for example output rejected twice) is retried
126
+ after a restart instead.
127
+
128
+ ## Handoffs, audits and task states
129
+
130
+ ![One handoff from the sender's envelope to the receiver's merge](./assets/handoff-sequence.svg)
131
+
132
+ A handoff is parked, audited with a second envelope, gated by code, then delivered and merged.
133
+
134
+ ![Task card statuses and their transitions](./assets/task-states.svg)
135
+
136
+ A card is `queued`, `working`, `merging`, `waiting_approval`, `clarifying`, `blocked`, `rejected` or `done`.
137
+
138
+ ![The two-pass audit handshake](./assets/audit-states.svg)
139
+
140
+ The audit releases a handoff only when the second envelope names the same commit and the gates pass.
141
+
142
+ ![The approval gate and the clarification flow](./assets/approval-flow.svg)
143
+
144
+ Approval is blocked while document comments exist; reject offers retry, delete or accept unchanged.
145
+
146
+ ## Quality gates
147
+
148
+ After the audit is unchanged, the coordinator runs the role's gates from the pack (`gates` block)
149
+ with the `node-ts` toolchain profile. A failing gate returns its report to the same role, which fixes
150
+ it and goes through the audit again. After `limits.maxBounces` (default 2) failures the task is
151
+ blocked and you decide: retry (fresh allowance), accept as it is, or delete.
152
+
153
+ | Gate | What it checks |
154
+ | --- | --- |
155
+ | `tests-green` | The profile's `test` command exits 0. |
156
+ | `test-first` | A test file is part of the role's diff since its base commit. |
157
+ | `coverage` | Overall line coverage from the coverage summary meets `thresholds.coverage`. |
158
+ | `crap` | For changed functions, complexity and CRAP (`CC^2 * (1 - coverage)^3 + CC`, using the file's coverage) stay under `thresholds.complexity` and `thresholds.crap`. |
159
+ | `dry` | No block of 6 identical significant lines duplicated against a changed file. |
160
+ | `mutation` | Differential: Stryker runs on the changed source files only and the score meets `thresholds.mutation`. |
161
+ | `acceptance` | The profile's `acceptance` command (falling back to `test`) exits 0. |
162
+ | `structure` | Skipped with a stated reason: there is no deterministic structure checker yet. |
163
+
164
+ Thresholds come from the pack, never from constants. Gate processes run from argument arrays with a
165
+ timeout, an output cap and a scrubbed environment. A gate that cannot run at all (missing tool,
166
+ unparseable report) does not bounce the role: it blocks the task with the reason.
167
+
168
+ QA rejection: when the last role reports `blocked`, its findings go back to the coder by default (or
169
+ to the role named by `rejectTo` on that role, or by a `route: <role>` line in the findings), bounded
170
+ by `maxBounces`. A pack may declare `parallel` stages (adjacent roles that are not the master or the
171
+ last role): they run concurrently and the next role receives all their commits, merged in pack
172
+ order, once every role of the stage has handed off.
173
+
174
+ ## Toolchain configuration
175
+
176
+ v1 ships one toolchain profile, `node-ts` (`assets/toolchains/node-ts.json`). It declares argument
177
+ arrays and output parsers, never shell strings. Your project must provide:
178
+
179
+ | Gate input | Command run | Needs |
180
+ | --- | --- | --- |
181
+ | tests | `npm test --silent` | a `test` script |
182
+ | coverage | `npx vitest run --coverage --coverage.reporter=json-summary` | Vitest with a coverage provider |
183
+ | complexity (CRAP) | `npx eslint --format json --rule complexity ...` | ESLint |
184
+ | mutation | `npx stryker run --incremental` | Stryker with the JSON reporter |
185
+ | acceptance | `npm run --if-present test:acceptance --silent` | optional script; falls back to `test` |
186
+
187
+ `/swarm:doctor` reports which commands are missing. Thresholds and limits (`coverage`, `complexity`,
188
+ `crap`, `mutation`, `maxBounces`, `maxAuditRounds`) are pack data. Other toolchains (go, java, python,
189
+ clojure) are not shipped in v1.
190
+
191
+ ## Token budget
192
+
193
+ `options.tokenBudget` is a soft cap on total tokens across the swarm. When it is reached the pumps
194
+ stop starting new runs (runs in flight finish) and a decision appears under needs your attention. Raise
195
+ the cap with `/swarm:budget raise <tokens>`. Idle roles never run: there are no eager agents.
196
+
197
+ ## Running it for real
198
+
199
+ Child sessions are created lazily from the session that last issued a `/swarm` command, with the
200
+ role's worktree as the workspace, and are cancelled on close, stop, teardown and dispose. The pump
201
+ runs in the background of the host process. Whether a promise that outlives its command keeps running,
202
+ how the host schedules concurrent child runs, and how headless `permission: ask` behaves are not
203
+ verified against a live host yet. If the background pump stalls, `/swarm:run <project>` drives it in
204
+ the foreground for up to an hour; a one-second safety tick restarts stalled work when the process is
205
+ alive. A pidfile under `.alisio/swarm` flags a previous process that died without cleaning up.
206
+
207
+ ## Options
208
+
209
+ Set them under `pluginOverrides.swarm.options` in the Alisio configuration:
210
+
211
+ | Option | Default | Meaning |
212
+ | --- | --- | --- |
213
+ | `maxConcurrent` | `3` | Roles running at the same time (1 to 8). |
214
+ | `roles.<role>.model` | session model | Model for one role. |
215
+ | `tokenBudget` | none | Soft cap on total tokens (at least 1000). |
216
+
217
+ ## Dashboard
218
+
219
+ The dashboard is a **follow-up view** of the swarm running in your workspace. Work is started and
220
+ managed from the Alisio chat with `/swarm:*` commands; the page only offers what the chat does
221
+ poorly: watching many roles at once, reading evidence, and making review decisions next to it.
222
+ Every role, the Lieutenant included, runs as an Alisio child session.
223
+
224
+ `/swarm:dashboard [project | project/task]` starts a local web page on `127.0.0.1` (ephemeral port),
225
+ prints its link and tries to open your browser; the optional argument deep-links to a project or card
226
+ (`#project/task`). When nothing is running the page tells you to start from the chat
227
+ (`/swarm:project new`, `/swarm:task <project> new`).
228
+
229
+ The board with the Attention strip, in the light theme. One Approval, one Clarification and one
230
+ failed gate wait for you; the `shuffle` card is highlighted while it merges.
231
+
232
+ ![Swarm dashboard in the light theme: a top bar, an Attention strip with Approval, Clarification and Gate failed items, and a board with one band per project](./assets/screenshots/dashboard-board-light.png)
233
+
234
+ The same view in the dark theme, which follows the system setting unless you override it.
235
+
236
+ ![Swarm dashboard in the dark theme with the same board, Attention strip, Work Queue and Activity log](./assets/screenshots/dashboard-board-dark.png)
237
+
238
+ The Work Queue lists every role with a live, idle or none marker (a text label as well as a colour),
239
+ an activity meter and its Alisio session id; the Activity log records handoffs, merges, gates and
240
+ bounces.
241
+
242
+ ![Work Queue with live, idle and none roles, plus the Activity log](./assets/screenshots/dashboard-work-queue.png)
243
+
244
+ Select a role to read the tail of its Alisio session: the recent prompts and replies.
245
+
246
+ ![Transcript tail dialog for the coder role showing a prompt and a reply](./assets/screenshots/dashboard-transcript-tail.png)
247
+
248
+ Documents shows the files held for approval, a side-by-side diff from the role base to the held
249
+ commit, and your comments. Approve stays disabled while comments exist.
250
+
251
+ ![Documents dialog with a task file, one comment and a side-by-side diff](./assets/screenshots/dashboard-documents-diff.png)
252
+
253
+ Reject lets you retry with your comments, delete the task or accept the work unchanged.
254
+
255
+ ![Reject dialog with the retry, delete and accept options and a comment typed in](./assets/screenshots/dashboard-reject-dialog.png)
256
+
257
+ When nothing is running, the page tells you to start from the Alisio chat.
258
+
259
+ ![Empty dashboard telling the user to start a project from the Alisio chat with /swarm:project new](./assets/screenshots/dashboard-empty-state.png)
260
+
261
+ It also works at phone width.
262
+
263
+ ![Dashboard at phone width with the Attention items stacked above the board](./assets/screenshots/dashboard-phone.png)
264
+
265
+ All screenshots use synthetic demo data served by `demo/dashboard-demo.mjs`.
266
+
267
+ | Part | What it shows or does |
268
+ | --- | --- |
269
+ | Top bar | Live chip, a "needs your decision" count (also in the tab title and favicon badge), token budget, pause refresh, theme and chime. |
270
+ | Filters | Project, role and status; pause refresh while you read a long diff or transcript. |
271
+ | Attention strip | Approval, Clarification, Blocked and Gate failed items with Documents, Approve, Reject, Answer, Retry and Delete, plus a button that copies the equivalent chat command. |
272
+ | Board | One band per running project, one column per pack role plus DONE; cards show audit count, a status snippet, a merging highlight and a copy-command button. |
273
+ | Work Queue | Task, role, age, a live/idle/none marker with a text label, a 0 to 6 activity meter, the Alisio session id with a copy button, and the recent prompts and replies of a role. |
274
+ | Activity | Recent handoffs, merges, gate results, bounces and approval waits. |
275
+ | Documents | Task files, a side-by-side or unified diff from the role base to the held commit, and per-document comments (Approve stays disabled while comments exist). |
276
+
277
+ It follows the system light or dark setting (with an explicit override), uses design tokens aligned
278
+ with the Alisio web app, works at phone width and never relies on colour alone. The only changes it
279
+ can make are the gate decisions above, and they call the same services as the commands. It cannot
280
+ create, open, close or tear down projects or tasks, and has no chat: that is an owner decision, so
281
+ the page never duplicates a command.
282
+
283
+ ![Dashboard layout and API](./assets/dashboard.svg)
284
+
285
+ The page polls `/api/state` every two seconds. Without a host that can show it, the same data is
286
+ available as `/swarm:status` (tables and a mermaid pipeline), a `ui.panel` tree (projects, roles,
287
+ tasks) and the read-only `swarm-board` data view; each is registered only when the host offers it.
288
+ To inspect the UI without a host, from a repository checkout build the package and run `node demo/dashboard-demo.mjs`: it serves
289
+ the page with synthetic data.
290
+
291
+ ## Security
292
+
293
+ Git and gate commands run with argument arrays and a scrubbed environment, never through a shell.
294
+ Identifiers and paths are validated, project paths cannot escape their root through symlinks, and
295
+ persisted files are written atomically with private permissions and a schema version.
296
+
297
+ The dashboard binds to loopback only. Every request needs a random 256-bit token (a cookie for
298
+ reading, a header for changes), a loopback `Host` and, when present, a local `Origin`; there is no
299
+ CORS, the content security policy is `default-src 'self'`, bodies are capped at 256 KiB, every
300
+ identifier is validated and all agent and task text is rendered as text. The link printed by the
301
+ command carries the token: do not share it. Documents are read from the git object store, so no path
302
+ can leave the repository. The plugin never pushes or opens pull requests.
303
+
304
+ ## Limits
305
+
306
+ - Not verified against a live host: background pump execution, concurrent child runs, headless
307
+ `permission: ask`, and a child workspace that is a worktree (see "Running it for real").
308
+ - The SDK has no transcript API: the role activity shown in the dashboard is what the plugin recorded
309
+ (bounded prompts and replies), not the host transcript.
310
+ - Child agents cannot call plugin tools; they answer with JSON envelopes only.
311
+ - v1 ships the `node-ts` toolchain only; the `structure` gate is skipped with a stated reason.
312
+ - No tmux or external CLI agents; no pushes or pull requests; Windows is not a target beyond not crashing.
313
+ - Thresholds are our defaults, not SwarmForge's, which publishes none.
314
+
315
+ ## Attribution
316
+
317
+ Inspired by SwarmForge by Robert C. Martin (`unclebob/swarm-forge`). This is a clean-room
318
+ implementation of the ideas; no upstream text or code is copied, and the upstream licence has not
319
+ been confirmed.
320
+
321
+ ## License
322
+
323
+ MIT
@@ -0,0 +1 @@
1
+ <svg id="my-svg" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="flowchart" style="max-width: 1067.4px; background-color: #ffffff;" viewBox="-24 -24 1067.3984 1078" role="graphics-document document" aria-roledescription="flowchart-v2"><rect x="-24" y="-24" width="1067.3984" height="1078" fill="#ffffff"/><style>#my-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#my-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#my-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#my-svg .error-icon{fill:#552222;}#my-svg .error-text{fill:#552222;stroke:#552222;}#my-svg .edge-thickness-normal{stroke-width:1px;}#my-svg .edge-thickness-thick{stroke-width:3.5px;}#my-svg .edge-pattern-solid{stroke-dasharray:0;}#my-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#my-svg .edge-pattern-dashed{stroke-dasharray:3;}#my-svg .edge-pattern-dotted{stroke-dasharray:2;}#my-svg .marker{fill:#333333;stroke:#333333;}#my-svg .marker.cross{stroke:#333333;}#my-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#my-svg p{margin:0;}#my-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#my-svg .cluster-label text{fill:#333;}#my-svg .cluster-label span{color:#333;}#my-svg .cluster-label span p{background-color:transparent;}#my-svg .label text,#my-svg span{fill:#333;color:#333;}#my-svg .node rect,#my-svg .node circle,#my-svg .node ellipse,#my-svg .node polygon,#my-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#my-svg .rough-node .label text,#my-svg .node .label text,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-anchor:middle;}#my-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#my-svg .rough-node .label,#my-svg .node .label,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-align:center;}#my-svg .node.clickable{cursor:pointer;}#my-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#my-svg .arrowheadPath{fill:#333333;}#my-svg .edgePaths .path{stroke:#333333;stroke-width:1px;}#my-svg .flowchart-link{stroke:#333333;fill:none;}#my-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#my-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#my-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#my-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#my-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#my-svg .cluster text{fill:#333;}#my-svg .cluster span{color:#333;}#my-svg .node .collapsed-indicator{fill:#aaaa33;stroke:none;opacity:0.6;}#my-svg .node .collapsed-separator{stroke:#aaaa33;stroke-width:0.75px;}#my-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#my-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#my-svg rect.text{fill:none;stroke-width:0;}#my-svg .icon-shape,#my-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#my-svg .icon-shape p,#my-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#my-svg .icon-shape .label rect,#my-svg .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#my-svg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#my-svg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#my-svg .node .neo-node{stroke:#9370DB;}#my-svg [data-look="neo"].node rect,#my-svg [data-look="neo"].cluster rect,#my-svg [data-look="neo"].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#my-svg [data-look="neo"].swimlane.cluster rect{filter:none;}#my-svg [data-look="neo"].node path{stroke:#9370DB;stroke-width:1px;}#my-svg [data-look="neo"].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#my-svg [data-look="neo"].node .neo-line path{stroke:#9370DB;filter:none;}#my-svg [data-look="neo"].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#my-svg [data-look="neo"].node circle .state-start{fill:#000000;}#my-svg [data-look="neo"].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#my-svg [data-look="neo"].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#my-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="my-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointEnd-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="11.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="10.5" markerHeight="14" orient="auto"><path d="M 0 0 L 11.5 7 L 0 14 z" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointStart-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="1" refY="7" markerUnits="userSpaceOnUse" markerWidth="11.5" markerHeight="14" orient="auto"><polygon points="0,7 11.5,14 11.5,0" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleEnd-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refY="5" refX="12.25" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleStart-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-2" refY="5" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossEnd-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="17.7" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5;"/></marker><marker id="my-svg_flowchart-v2-crossStart-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="-3.5" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5; stroke-dasharray: 1, 0;"/></marker><g class="root"><g class="clusters"/><g class="edgePaths"><path d="M447.5,86L447.5,90.167C447.5,94.333,447.5,102.667,447.5,110.333C447.5,118,447.5,125,447.5,128.5L447.5,132" id="my-svg-L_H_P_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_H_P_0" data-points="W3sieCI6NDQ3LjUsInkiOjg2fSx7IngiOjQ0Ny41LCJ5IjoxMTF9LHsieCI6NDQ3LjUsInkiOjEzNn1d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M447.5,214L447.5,218.167C447.5,222.333,447.5,230.667,447.5,238.333C447.5,246,447.5,253,447.5,256.5L447.5,260" id="my-svg-L_P_A_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_P_A_0" data-points="W3sieCI6NDQ3LjUsInkiOjIxNH0seyJ4Ijo0NDcuNSwieSI6MjM5fSx7IngiOjQ0Ny41LCJ5IjoyNjR9XQ==" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M357.5,327.563L333.417,334.136C309.333,340.709,261.167,353.854,237.083,363.927C213,374,213,381,213,384.5L213,388" id="my-svg-L_A_D_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_A_D_0" data-points="W3sieCI6MzU3LjUsInkiOjMyNy41NjI4OTk3ODY3ODA0fSx7IngiOjIxMywieSI6MzY3fSx7IngiOjIxMywieSI6MzkyfV0=" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M213,494L213,498.167C213,502.333,213,510.667,213,518.333C213,526,213,533,213,536.5L213,540" id="my-svg-L_D_C_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_D_C_0" data-points="W3sieCI6MjEzLCJ5Ijo0OTR9LHsieCI6MjEzLCJ5Ijo1MTl9LHsieCI6MjEzLCJ5Ijo1NDR9XQ==" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M167.641,696.641L156.035,710.368C144.428,724.094,121.214,751.547,109.607,770.774C98,790,98,801,98,806.5L98,812" id="my-svg-L_C_X_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_C_X_0" data-points="W3sieCI6MTY3LjY0MTQzNDI2Mjk0ODIsInkiOjY5Ni42NDE0MzQyNjI5NDgyfSx7IngiOjk4LCJ5Ijo3Nzl9LHsieCI6OTgsInkiOjgxNn1d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M258.359,696.641L269.965,710.368C281.572,724.094,304.786,751.547,316.393,772.774C328,794,328,809,328,816.5L328,824" id="my-svg-L_C_Ok_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_C_Ok_0" data-points="W3sieCI6MjU4LjM1ODU2NTczNzA1MTgsInkiOjY5Ni42NDE0MzQyNjI5NDgyfSx7IngiOjMyOCwieSI6Nzc5fSx7IngiOjMyOCwieSI6ODI4fV0=" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M328,882L328,888.167C328,894.333,328,906.667,328,916.333C328,926,328,933,328,936.5L328,940" id="my-svg-L_Ok_Rel_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Ok_Rel_0" data-points="W3sieCI6MzI4LCJ5Ijo4ODJ9LHsieCI6MzI4LCJ5Ijo5MTl9LHsieCI6MzI4LCJ5Ijo5NDR9XQ==" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M537.5,327.895L561.061,334.413C584.622,340.93,631.745,353.965,655.306,367.983C678.867,382,678.867,397,678.867,404.5L678.867,412" id="my-svg-L_A_Rej_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_A_Rej_0" data-points="W3sieCI6NTM3LjUsInkiOjMyNy44OTU0OTIxNDkyNDg3fSx7IngiOjY3OC44NjcxODc1LCJ5IjozNjd9LHsieCI6Njc4Ljg2NzE4NzUsInkiOjQxNn1d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M598.27,470L573.891,478.167C549.513,486.333,500.757,502.667,476.378,518.333C452,534,452,549,452,556.5L452,564" id="my-svg-L_Rej_R1_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Rej_R1_0" data-points="W3sieCI6NTk4LjI2OTYzNDA0NjA1MjYsInkiOjQ3MH0seyJ4Ijo0NTIsInkiOjUxOX0seyJ4Ijo0NTIsInkiOjU2OH1d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M679.98,470L680.317,478.167C680.653,486.333,681.327,502.667,681.663,524.333C682,546,682,573,682,586.5L682,600" id="my-svg-L_Rej_R2_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Rej_R2_0" data-points="W3sieCI6Njc5Ljk4MDE2MDM2MTg0MjEsInkiOjQ3MH0seyJ4Ijo2ODIsInkiOjUxOX0seyJ4Ijo2ODIsInkiOjYwNH1d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M761.691,470L786.742,478.167C811.794,486.333,861.897,502.667,886.948,522.333C912,542,912,565,912,576.5L912,588" id="my-svg-L_Rej_R3_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Rej_R3_0" data-points="W3sieCI6NzYxLjY5MDY4NjY3NzYzMTYsInkiOjQ3MH0seyJ4Ijo5MTIsInkiOjUxOX0seyJ4Ijo5MTIsInkiOjU5Mn1d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M915.133,86L915.133,90.167C915.133,94.333,915.133,102.667,915.133,110.333C915.133,118,915.133,125,915.133,128.5L915.133,132" id="my-svg-L_Q_QA_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Q_QA_0" data-points="W3sieCI6OTE1LjEzMjgxMjUsInkiOjg2fSx7IngiOjkxNS4xMzI4MTI1LCJ5IjoxMTF9LHsieCI6OTE1LjEzMjgxMjUsInkiOjEzNn1d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M915.133,214L915.133,218.167C915.133,222.333,915.133,230.667,915.133,238.333C915.133,246,915.133,253,915.133,256.5L915.133,260" id="my-svg-L_QA_Ans_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_QA_Ans_0" data-points="W3sieCI6OTE1LjEzMjgxMjUsInkiOjIxNH0seyJ4Ijo5MTUuMTMyODEyNSwieSI6MjM5fSx7IngiOjkxNS4xMzI4MTI1LCJ5IjoyNjR9XQ==" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M915.133,342L915.133,346.167C915.133,350.333,915.133,358.667,915.133,368.333C915.133,378,915.133,389,915.133,394.5L915.133,400" id="my-svg-L_Ans_Res_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Ans_Res_0" data-points="W3sieCI6OTE1LjEzMjgxMjUsInkiOjM0Mn0seyJ4Ijo5MTUuMTMyODEyNSwieSI6MzY3fSx7IngiOjkxNS4xMzI4MTI1LCJ5Ijo0MDR9XQ==" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/></g><g class="edgeLabels"><g class="edgeLabel"><g class="label" data-id="L_H_P_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_P_A_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_A_D_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_D_C_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(98, 779)"><g class="label" data-id="L_C_X_0" transform="translate(-12.453125, -12)"><foreignObject width="24.90625" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>yes</p></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(328, 779)"><g class="label" data-id="L_C_Ok_0" transform="translate(-8.8984375, -12)"><foreignObject width="17.796875" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>no</p></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_Ok_Rel_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_A_Rej_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_Rej_R1_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_Rej_R2_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_Rej_R3_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_Q_QA_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_QA_Ans_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_Ans_Res_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node default" id="my-svg-flowchart-H-0" data-look="classic" transform="translate(447.5, 47)"><rect class="basic label-container" style="" x="-90" y="-39" width="180" height="78"/><g class="label" style="" transform="translate(-60, -24)"><rect/><foreignObject width="120" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Gate role hands off</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-P-1" data-look="classic" transform="translate(447.5, 175)"><rect class="basic label-container" style="" x="-93.609375" y="-39" width="187.21875" height="78"/><g class="label" style="" transform="translate(-63.609375, -24)"><rect/><foreignObject width="127.21875" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Handoff held in pending_approval</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-A-3" data-look="classic" transform="translate(447.5, 303)"><rect class="basic label-container" style="" x="-90" y="-39" width="180" height="78"/><g class="label" style="" transform="translate(-60, -24)"><rect/><foreignObject width="120" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Attention: Approval</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-D-5" data-look="classic" transform="translate(213, 443)"><rect class="basic label-container" style="" x="-90" y="-51" width="180" height="102"/><g class="label" style="" transform="translate(-60, -36)"><rect/><foreignObject width="120" height="72"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Documents view: files, diff, comments</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-C-7" data-look="classic" transform="translate(213, 643)"><polygon points="99,0 198,-99 99,-198 0,-99" class="label-container" transform="translate(-98.5, 99)"/><g class="label" style="" transform="translate(-60, -24)"><rect/><foreignObject width="120" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Comments exist?</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-X-9" data-look="classic" transform="translate(98, 855)"><rect class="basic label-container" style="" x="-90" y="-39" width="180" height="78"/><g class="label" style="" transform="translate(-60, -24)"><rect/><foreignObject width="120" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Approve disabled</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-Ok-11" data-look="classic" transform="translate(328, 855)"><rect class="basic label-container" style="" x="-90" y="-27" width="180" height="54"/><g class="label" style="" transform="translate(-60, -12)"><rect/><foreignObject width="120" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: nowrap; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Approve</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-Rel-13" data-look="classic" transform="translate(328, 983)"><rect class="basic label-container" style="" x="-90" y="-39" width="180" height="78"/><g class="label" style="" transform="translate(-60, -24)"><rect/><foreignObject width="120" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Release to the next role</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-Rej-15" data-look="classic" transform="translate(678.8671875, 443)"><rect class="basic label-container" style="" x="-90" y="-27" width="180" height="54"/><g class="label" style="" transform="translate(-60, -12)"><rect/><foreignObject width="120" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: nowrap; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Reject</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-R1-17" data-look="classic" transform="translate(452, 643)"><rect class="basic label-container" style="" x="-90" y="-75" width="180" height="150"/><g class="label" style="" transform="translate(-60, -60)"><rect/><foreignObject width="120" height="120"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Retry: keep rejected commit,<br />restore base, re-run with comments</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-R2-19" data-look="classic" transform="translate(682, 643)"><rect class="basic label-container" style="" x="-90" y="-39" width="180" height="78"/><g class="label" style="" transform="translate(-60, -24)"><rect/><foreignObject width="120" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Delete: archive and remove</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-R3-21" data-look="classic" transform="translate(912, 643)"><rect class="basic label-container" style="" x="-90" y="-51" width="180" height="102"/><g class="label" style="" transform="translate(-60, -36)"><rect/><foreignObject width="120" height="72"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Accept unchanged: release</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-Q-22" data-look="classic" transform="translate(915.1328125, 47)"><rect class="basic label-container" style="" x="-96.265625" y="-39" width="192.53125" height="78"/><g class="label" style="" transform="translate(-66.265625, -24)"><rect/><foreignObject width="132.53125" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Role returns needs_clarification</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-QA-23" data-look="classic" transform="translate(915.1328125, 175)"><rect class="basic label-container" style="" x="-90" y="-39" width="180" height="78"/><g class="label" style="" transform="translate(-60, -24)"><rect/><foreignObject width="120" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Attention: Clarification</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-Ans-25" data-look="classic" transform="translate(915.1328125, 303)"><rect class="basic label-container" style="" x="-90" y="-39" width="180" height="78"/><g class="label" style="" transform="translate(-60, -24)"><rect/><foreignObject width="120" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Operator answers</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-Res-27" data-look="classic" transform="translate(915.1328125, 443)"><rect class="basic label-container" style="" x="-90" y="-39" width="180" height="78"/><g class="label" style="" transform="translate(-60, -24)"><rect/><foreignObject width="120" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Same session resumes</p></span></div></foreignObject></g></g></g></g></g><defs><filter id="my-svg-drop-shadow" height="130%" width="130%"><feDropShadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"/></filter></defs><defs><filter id="my-svg-drop-shadow-small" height="150%" width="150%"><feDropShadow dx="2" dy="2" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"/></filter></defs></svg>
@@ -0,0 +1 @@
1
+ <svg id="my-svg" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="flowchart" style="max-width: 1569px; background-color: #ffffff;" viewBox="-24 -24 1569 900" role="graphics-document document" aria-roledescription="flowchart-v2"><rect x="-24" y="-24" width="1569" height="900" fill="#ffffff"/><style>#my-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#my-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#my-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#my-svg .error-icon{fill:#552222;}#my-svg .error-text{fill:#552222;stroke:#552222;}#my-svg .edge-thickness-normal{stroke-width:1px;}#my-svg .edge-thickness-thick{stroke-width:3.5px;}#my-svg .edge-pattern-solid{stroke-dasharray:0;}#my-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#my-svg .edge-pattern-dashed{stroke-dasharray:3;}#my-svg .edge-pattern-dotted{stroke-dasharray:2;}#my-svg .marker{fill:#333333;stroke:#333333;}#my-svg .marker.cross{stroke:#333333;}#my-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#my-svg p{margin:0;}#my-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#my-svg .cluster-label text{fill:#333;}#my-svg .cluster-label span{color:#333;}#my-svg .cluster-label span p{background-color:transparent;}#my-svg .label text,#my-svg span{fill:#333;color:#333;}#my-svg .node rect,#my-svg .node circle,#my-svg .node ellipse,#my-svg .node polygon,#my-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#my-svg .rough-node .label text,#my-svg .node .label text,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-anchor:middle;}#my-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#my-svg .rough-node .label,#my-svg .node .label,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-align:center;}#my-svg .node.clickable{cursor:pointer;}#my-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#my-svg .arrowheadPath{fill:#333333;}#my-svg .edgePaths .path{stroke:#333333;stroke-width:1px;}#my-svg .flowchart-link{stroke:#333333;fill:none;}#my-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#my-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#my-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#my-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#my-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#my-svg .cluster text{fill:#333;}#my-svg .cluster span{color:#333;}#my-svg .node .collapsed-indicator{fill:#aaaa33;stroke:none;opacity:0.6;}#my-svg .node .collapsed-separator{stroke:#aaaa33;stroke-width:0.75px;}#my-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#my-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#my-svg rect.text{fill:none;stroke-width:0;}#my-svg .icon-shape,#my-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#my-svg .icon-shape p,#my-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#my-svg .icon-shape .label rect,#my-svg .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#my-svg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#my-svg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#my-svg .node .neo-node{stroke:#9370DB;}#my-svg [data-look="neo"].node rect,#my-svg [data-look="neo"].cluster rect,#my-svg [data-look="neo"].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#my-svg [data-look="neo"].swimlane.cluster rect{filter:none;}#my-svg [data-look="neo"].node path{stroke:#9370DB;stroke-width:1px;}#my-svg [data-look="neo"].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#my-svg [data-look="neo"].node .neo-line path{stroke:#9370DB;filter:none;}#my-svg [data-look="neo"].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#my-svg [data-look="neo"].node circle .state-start{fill:#000000;}#my-svg [data-look="neo"].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#my-svg [data-look="neo"].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#my-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="my-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointEnd-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="11.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="10.5" markerHeight="14" orient="auto"><path d="M 0 0 L 11.5 7 L 0 14 z" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointStart-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="1" refY="7" markerUnits="userSpaceOnUse" markerWidth="11.5" markerHeight="14" orient="auto"><polygon points="0,7 11.5,14 11.5,0" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleEnd-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refY="5" refX="12.25" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleStart-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-2" refY="5" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossEnd-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="17.7" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5;"/></marker><marker id="my-svg_flowchart-v2-crossStart-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="-3.5" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5; stroke-dasharray: 1, 0;"/></marker><g class="root"><g class="clusters"><g class="cluster" id="my-svg-Adapters" data-look="classic"><rect style="" x="1283" y="8" width="230" height="520"/><g class="cluster-label" transform="translate(1365.9765625, 8)"><foreignObject width="64.046875" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5;"><span class="nodeLabel"><p>Adapters</p></span></div></foreignObject></g></g><g class="cluster" id="my-svg-Ports" data-look="classic"><rect style="" x="1003" y="20" width="230" height="496"/><g class="cluster-label" transform="translate(1099.328125, 20)"><foreignObject width="37.34375" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5;"><span class="nodeLabel"><p>Ports</p></span></div></foreignObject></g></g><g class="cluster" id="my-svg-Core" data-look="classic"><rect style="" x="518" y="536" width="715" height="224"/><g class="cluster-label" transform="translate(728.8984375, 536)"><foreignObject width="293.203125" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5;"><span class="nodeLabel"><p>Application and domain (pure TypeScript)</p></span></div></foreignObject></g></g><g class="cluster" id="my-svg-Front" data-look="classic"><rect style="" x="8" y="336" width="230" height="508"/><g class="cluster-label" transform="translate(26.078125, 336)"><foreignObject width="193.84375" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5;"><span class="nodeLabel"><p>Front ends (same services)</p></span></div></foreignObject></g></g></g><g class="edgePaths"><path d="M213,410L217.167,410C221.333,410,229.667,410,238,410C246.333,410,254.667,410,270.48,430.255C286.294,450.511,309.587,491.022,321.234,511.277L332.881,531.532" id="my-svg-L_Cmd_Services_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Cmd_Services_0" data-points="W3sieCI6MjEzLCJ5Ijo0MTB9LHsieCI6MjM4LCJ5Ijo0MTB9LHsieCI6MjYzLCJ5Ijo0MTB9LHsieCI6MzM0Ljg3NSwieSI6NTM1fV0=" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M213,526L217.167,526C221.333,526,229.667,526,238,526C246.333,526,254.667,526,262.462,528.65C270.257,531.301,277.513,536.601,281.142,539.251L284.77,541.902" id="my-svg-L_Tools_Services_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Tools_Services_0" data-points="W3sieCI6MjEzLCJ5Ijo1MjZ9LHsieCI6MjM4LCJ5Ijo1MjZ9LHsieCI6MjYzLCJ5Ijo1MjZ9LHsieCI6Mjg4LCJ5Ijo1NDQuMjYwODY5NTY1MjE3NH1d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M213,642L217.167,642C221.333,642,229.667,642,238,642C246.333,642,254.667,642,262.358,641.019C270.049,640.039,277.098,638.077,280.622,637.096L284.146,636.116" id="my-svg-L_Dash_Services_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Dash_Services_0" data-points="W3sieCI6MjEzLCJ5Ijo2NDJ9LHsieCI6MjM4LCJ5Ijo2NDJ9LHsieCI6MjYzLCJ5Ijo2NDJ9LHsieCI6Mjg4LCJ5Ijo2MzUuMDQzNDc4MjYwODY5Nn1d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M213,770L217.167,770C221.333,770,229.667,770,238,770C246.333,770,254.667,770,268.627,756.375C282.586,742.749,302.173,715.499,311.966,701.873L321.759,688.248" id="my-svg-L_Panel_Services_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Panel_Services_0" data-points="W3sieCI6MjEzLCJ5Ijo3NzB9LHsieCI6MjM4LCJ5Ijo3NzB9LHsieCI6MjYzLCJ5Ijo3NzB9LHsieCI6MzI0LjA5Mzc1LCJ5Ijo2ODV9XQ==" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M468,610L472.167,610C476.333,610,484.667,610,493,610C501.333,610,509.667,610,517.333,610C525,610,532,610,535.5,610L539,610" id="my-svg-L_Services_Forge_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Services_Forge_0" data-points="W3sieCI6NDY4LCJ5Ijo2MTB9LHsieCI6NDkzLCJ5Ijo2MTB9LHsieCI6NTE4LCJ5Ijo2MTB9LHsieCI6NTQzLCJ5Ijo2MTB9XQ==" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M723,610L727.167,610C731.333,610,739.667,610,747.333,610C755,610,762,610,765.5,610L769,610" id="my-svg-L_Forge_Pump_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Forge_Pump_0" data-points="W3sieCI6NzIzLCJ5Ijo2MTB9LHsieCI6NzQ4LCJ5Ijo2MTB9LHsieCI6NzczLCJ5Ijo2MTB9XQ==" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M953,641.304L957.167,642.754C961.333,644.203,969.667,647.101,978,648.551C986.333,650,994.667,650,1002.333,650C1010,650,1017,650,1020.5,650L1024,650" id="my-svg-L_Pump_Domain_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Pump_Domain_0" data-points="W3sieCI6OTUzLCJ5Ijo2NDEuMzA0MzQ3ODI2MDg3fSx7IngiOjk3OCwieSI6NjUwfSx7IngiOjEwMDMsInkiOjY1MH0seyJ4IjoxMDI4LCJ5Ijo2NTB9XQ==" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M953,573.217L957.167,571.514C961.333,569.812,969.667,566.406,978,564.703C986.333,563,994.667,563,1016.769,487.982C1038.872,412.963,1074.743,262.927,1092.679,187.909L1110.615,112.89" id="my-svg-L_Pump_PRun_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Pump_PRun_0" data-points="W3sieCI6OTUzLCJ5Ijo1NzMuMjE3MzkxMzA0MzQ3OX0seyJ4Ijo5NzgsInkiOjU2M30seyJ4IjoxMDAzLCJ5Ijo1NjN9LHsieCI6MTExMS41NDQ2OTg1NDQ2OTg2LCJ5IjoxMDl9XQ==" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M1208,82L1212.167,82C1216.333,82,1224.667,82,1233,82C1241.333,82,1249.667,82,1258,82C1266.333,82,1274.667,82,1282.333,82C1290,82,1297,82,1300.5,82L1304,82" id="my-svg-L_PRun_ARun_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_PRun_ARun_0" data-points="W3sieCI6MTIwOCwieSI6ODJ9LHsieCI6MTIzMywieSI6ODJ9LHsieCI6MTI1OCwieSI6ODJ9LHsieCI6MTI4MywieSI6ODJ9LHsieCI6MTMwOCwieSI6ODJ9XQ==" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M953,588.87L957.167,587.891C961.333,586.913,969.667,584.957,978,583.978C986.333,583,994.667,583,1016.465,523.972C1038.263,464.944,1073.527,346.888,1091.159,287.861L1108.79,228.833" id="my-svg-L_Pump_PIso_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Pump_PIso_0" data-points="W3sieCI6OTUzLCJ5Ijo1ODguODY5NTY1MjE3MzkxM30seyJ4Ijo5NzgsInkiOjU4M30seyJ4IjoxMDAzLCJ5Ijo1ODN9LHsieCI6MTEwOS45MzUwNjQ5MzUwNjUsInkiOjIyNX1d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M1208,198L1212.167,198C1216.333,198,1224.667,198,1233,198C1241.333,198,1249.667,198,1258,198C1266.333,198,1274.667,198,1282.333,198C1290,198,1297,198,1300.5,198L1304,198" id="my-svg-L_PIso_AGit_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_PIso_AGit_0" data-points="W3sieCI6MTIwOCwieSI6MTk4fSx7IngiOjEyMzMsInkiOjE5OH0seyJ4IjoxMjU4LCJ5IjoxOTh9LHsieCI6MTI4MywieSI6MTk4fSx7IngiOjEzMDgsInkiOjE5OH1d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M953,610L957.167,610C961.333,610,969.667,610,978,610C986.333,610,994.667,610,1014.308,571.785C1033.949,533.569,1064.898,457.138,1080.373,418.923L1095.847,380.708" id="my-svg-L_Pump_PStore_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Pump_PStore_0" data-points="W3sieCI6OTUzLCJ5Ijo2MTB9LHsieCI6OTc4LCJ5Ijo2MTB9LHsieCI6MTAwMywieSI6NjEwfSx7IngiOjEwOTcuMzQ4NTkxNTQ5Mjk1OSwieSI6Mzc3fV0=" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M1208,326L1212.167,326C1216.333,326,1224.667,326,1233,326C1241.333,326,1249.667,326,1258,326C1266.333,326,1274.667,326,1282.333,326C1290,326,1297,326,1300.5,326L1304,326" id="my-svg-L_PStore_AFs_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_PStore_AFs_0" data-points="W3sieCI6MTIwOCwieSI6MzI2fSx7IngiOjEyMzMsInkiOjMyNn0seyJ4IjoxMjU4LCJ5IjozMjZ9LHsieCI6MTI4MywieSI6MzI2fSx7IngiOjEzMDgsInkiOjMyNn1d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M953,625.652L957.167,626.377C961.333,627.101,969.667,628.551,978,629.275C986.333,630,994.667,630,1014.695,605.725C1034.723,581.45,1066.447,532.899,1082.308,508.624L1098.17,484.349" id="my-svg-L_Pump_PGate_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Pump_PGate_0" data-points="W3sieCI6OTUzLCJ5Ijo2MjUuNjUyMTczOTEzMDQzNX0seyJ4Ijo5NzgsInkiOjYzMH0seyJ4IjoxMDAzLCJ5Ijo2MzB9LHsieCI6MTEwMC4zNTc5NTQ1NDU0NTQ1LCJ5Ijo0ODF9XQ==" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M1208,454L1212.167,454C1216.333,454,1224.667,454,1233,454C1241.333,454,1249.667,454,1258,454C1266.333,454,1274.667,454,1282.333,454C1290,454,1297,454,1300.5,454L1304,454" id="my-svg-L_PGate_AProc_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_PGate_AProc_0" data-points="W3sieCI6MTIwOCwieSI6NDU0fSx7IngiOjEyMzMsInkiOjQ1NH0seyJ4IjoxMjU4LCJ5Ijo0NTR9LHsieCI6MTI4MywieSI6NDU0fSx7IngiOjEzMDgsInkiOjQ1NH1d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/></g><g class="edgeLabels"><g class="edgeLabel"><g class="label" data-id="L_Cmd_Services_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_Tools_Services_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_Dash_Services_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_Panel_Services_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_Services_Forge_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_Forge_Pump_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_Pump_Domain_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_Pump_PRun_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_PRun_ARun_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_Pump_PIso_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_PIso_AGit_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_Pump_PStore_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_PStore_AFs_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_Pump_PGate_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="L_PGate_AProc_0" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node default" id="my-svg-flowchart-Cmd-0" data-look="classic" transform="translate(123, 410)"><rect class="basic label-container" style="" x="-90" y="-39" width="180" height="78"/><g class="label" style="" transform="translate(-60, -24)"><rect/><foreignObject width="120" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>/swarm:* commands</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-Tools-1" data-look="classic" transform="translate(123, 526)"><rect class="basic label-container" style="" x="-90" y="-27" width="180" height="54"/><g class="label" style="" transform="translate(-60, -12)"><rect/><foreignObject width="120" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: nowrap; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>swarm_* tools</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-Dash-2" data-look="classic" transform="translate(123, 642)"><rect class="basic label-container" style="" x="-90" y="-39" width="180" height="78"/><g class="label" style="" transform="translate(-60, -24)"><rect/><foreignObject width="120" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Dashboard (HTTP + UI)</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-Panel-3" data-look="classic" transform="translate(123, 770)"><rect class="basic label-container" style="" x="-90" y="-39" width="180" height="78"/><g class="label" style="" transform="translate(-60, -24)"><rect/><foreignObject width="120" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>ui.panel and views</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-Services-4" data-look="classic" transform="translate(378, 610)"><rect class="basic label-container" style="" x="-90" y="-75" width="180" height="150"/><g class="label" style="" transform="translate(-60, -60)"><rect/><foreignObject width="120" height="120"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>SwarmServices<br />one implementation of every decision</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-Forge-5" data-look="classic" transform="translate(633, 610)"><rect class="basic label-container" style="" x="-90" y="-39" width="180" height="78"/><g class="label" style="" transform="translate(-60, -24)"><rect/><foreignObject width="120" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Forge and ProjectRuntime</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-Pump-6" data-look="classic" transform="translate(863, 610)"><rect class="basic label-container" style="" x="-90" y="-39" width="180" height="78"/><g class="label" style="" transform="translate(-60, -24)"><rect/><foreignObject width="120" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Pump, audit, gates, approval</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-Domain-7" data-look="classic" transform="translate(1118, 650)"><rect class="basic label-container" style="" x="-90" y="-75" width="180" height="150"/><g class="label" style="" transform="translate(-60, -60)"><rect/><foreignObject width="120" height="120"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Packs, envelopes, pipeline,<br />task state, attention</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-PRun-8" data-look="classic" transform="translate(1118, 82)"><rect class="basic label-container" style="" x="-90" y="-27" width="180" height="54"/><g class="label" style="" transform="translate(-60, -12)"><rect/><foreignObject width="120" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: nowrap; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>AgentRunner</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-PIso-9" data-look="classic" transform="translate(1118, 198)"><rect class="basic label-container" style="" x="-90" y="-27" width="180" height="54"/><g class="label" style="" transform="translate(-60, -12)"><rect/><foreignObject width="120" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: nowrap; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Isolation</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-PStore-10" data-look="classic" transform="translate(1118, 326)"><rect class="basic label-container" style="" x="-90" y="-51" width="180" height="102"/><g class="label" style="" transform="translate(-60, -36)"><rect/><foreignObject width="120" height="72"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>HandoffStore, BoardStore,<br />TaskStateStore</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-PGate-11" data-look="classic" transform="translate(1118, 454)"><rect class="basic label-container" style="" x="-90" y="-27" width="180" height="54"/><g class="label" style="" transform="translate(-60, -12)"><rect/><foreignObject width="120" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: nowrap; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>GateRunner</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-ARun-12" data-look="classic" transform="translate(1398, 82)"><rect class="basic label-container" style="" x="-90" y="-39" width="180" height="78"/><g class="label" style="" transform="translate(-60, -24)"><rect/><foreignObject width="120" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Alisio child sessions</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-AGit-13" data-look="classic" transform="translate(1398, 198)"><rect class="basic label-container" style="" x="-90" y="-27" width="180" height="54"/><g class="label" style="" transform="translate(-60, -12)"><rect/><foreignObject width="120" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: nowrap; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>git worktrees</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-AFs-14" data-look="classic" transform="translate(1398, 326)"><rect class="basic label-container" style="" x="-90" y="-39" width="180" height="78"/><g class="label" style="" transform="translate(-60, -24)"><rect/><foreignObject width="120" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Atomic JSON files</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-AProc-15" data-look="classic" transform="translate(1398, 454)"><rect class="basic label-container" style="" x="-90" y="-39" width="180" height="78"/><g class="label" style="" transform="translate(-60, -24)"><rect/><foreignObject width="120" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table; white-space: break-spaces; line-height: 1.5; max-width: 120px; text-align: center; width: 120px;"><span class="nodeLabel"><p>Process gates (node-ts)</p></span></div></foreignObject></g></g></g></g></g><defs><filter id="my-svg-drop-shadow" height="130%" width="130%"><feDropShadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"/></filter></defs><defs><filter id="my-svg-drop-shadow-small" height="150%" width="150%"><feDropShadow dx="2" dy="2" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"/></filter></defs></svg>