@felixdotgo/aidlc-kit 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/DEVELOPMENT.md +14 -13
  2. package/README.md +37 -43
  3. package/dist/assets/.agents/aidlc/docker/Dockerfile.claude +7 -0
  4. package/dist/assets/.agents/aidlc/docker/Dockerfile.codex +9 -0
  5. package/dist/assets/.agents/aidlc/docker/Dockerfile.opencode +8 -0
  6. package/dist/assets/.agents/aidlc/orchestrator.md +2 -2
  7. package/dist/assets/.agents/aidlc/phase-clarify.md +1 -1
  8. package/dist/assets/.agents/aidlc/phase-plan.md +2 -2
  9. package/dist/assets/.agents/aidlc/schemas/config.schema.json +2 -1
  10. package/dist/assets/.agents/aidlc/schemas/state.schema.json +2 -0
  11. package/dist/assets/.agents/aidlc/scripts/lib/assignment-store.mjs +94 -48
  12. package/dist/assets/.agents/aidlc/scripts/lib/context-runtime.mjs +5 -4
  13. package/dist/assets/.agents/aidlc/scripts/lib/loop-authority.mjs +261 -0
  14. package/dist/assets/.agents/aidlc/scripts/lib/loop-commit-message.mjs +45 -0
  15. package/dist/assets/.agents/aidlc/scripts/lib/loop-daemon.mjs +206 -0
  16. package/dist/assets/.agents/aidlc/scripts/lib/loop-drivers.mjs +100 -14
  17. package/dist/assets/.agents/aidlc/scripts/lib/loop-env.mjs +279 -0
  18. package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet-cli.mjs +105 -32
  19. package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet-remote.mjs +17 -1
  20. package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet-supervisor.mjs +24 -7
  21. package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet.mjs +42 -16
  22. package/dist/assets/.agents/aidlc/scripts/lib/loop-git.mjs +20 -6
  23. package/dist/assets/.agents/aidlc/scripts/lib/loop-holder.mjs +376 -0
  24. package/dist/assets/.agents/aidlc/scripts/lib/loop-intake.mjs +33 -7
  25. package/dist/assets/.agents/aidlc/scripts/lib/loop-lease.mjs +67 -61
  26. package/dist/assets/.agents/aidlc/scripts/lib/loop-leases.mjs +268 -0
  27. package/dist/assets/.agents/aidlc/scripts/lib/loop-local-workers.mjs +116 -28
  28. package/dist/assets/.agents/aidlc/scripts/lib/loop-runtime.mjs +114 -12
  29. package/dist/assets/.agents/aidlc/scripts/lib/loop-stream.mjs +117 -0
  30. package/dist/assets/.agents/aidlc/scripts/lib/loop-supervisor-local.mjs +16 -56
  31. package/dist/assets/.agents/aidlc/scripts/lib/loop-supervisor-run-local.mjs +149 -6
  32. package/dist/assets/.agents/aidlc/scripts/lib/loop-supervisor.mjs +9 -1
  33. package/dist/assets/.agents/aidlc/scripts/lib/loop-worker-docker.mjs +44 -6
  34. package/dist/assets/.agents/aidlc/scripts/lib/loop-worker-image.mjs +64 -0
  35. package/dist/assets/.agents/aidlc/scripts/lib/loop-worker-log.mjs +158 -0
  36. package/dist/assets/.agents/aidlc/scripts/lib/repo-head.mjs +22 -0
  37. package/dist/assets/.agents/aidlc/scripts/lib/store.mjs +68 -2
  38. package/dist/assets/.agents/aidlc/scripts/lib/task-runtime-migrate.mjs +75 -0
  39. package/dist/assets/.agents/aidlc/scripts/lib/task-runtime.mjs +97 -0
  40. package/dist/assets/.agents/aidlc/scripts/loop-entry.mjs +168 -73
  41. package/dist/assets/.agents/aidlc/scripts/loop-gate.mjs +19 -7
  42. package/dist/assets/.agents/aidlc/scripts/loop.cmd +101 -0
  43. package/dist/assets/.agents/aidlc/scripts/loop.mjs +2 -1
  44. package/dist/assets/.agents/aidlc/scripts/loop.sh +71 -0
  45. package/dist/assets/.agents/aidlc/scripts/remote-state.mjs +10 -4
  46. package/dist/assets/.agents/aidlc/scripts/state.mjs +16 -8
  47. package/dist/assets/.agents/aidlc/templates/design.md +9 -0
  48. package/dist/assets/.agents/aidlc/templates/intent.md +4 -0
  49. package/dist/assets/.agents/aidlc/templates/workplan.md +1 -1
  50. package/dist/assets/.agents/skills/aidlc-plan/SKILL.md +1 -1
  51. package/dist/assets/ui/bulma.min.css +3 -0
  52. package/dist/assets/ui/changes.js +83 -0
  53. package/dist/assets/ui/common.js +664 -0
  54. package/dist/assets/ui/dashboard.css +636 -0
  55. package/dist/assets/ui/dashboard.js +77 -0
  56. package/dist/assets/ui/detail.js +159 -0
  57. package/dist/assets/ui/live-log.js +332 -0
  58. package/dist/services/aidlc-coordination/Dockerfile +11 -3
  59. package/dist/services/aidlc-coordination/compose.yaml +12 -0
  60. package/dist/services/aidlc-coordination/package-lock.json +3 -1
  61. package/dist/services/aidlc-coordination/package.json +9 -4
  62. package/dist/services/aidlc-coordination/src/lifecycle-core.mjs +68 -2
  63. package/dist/services/aidlc-coordination/src/repository.mjs +66 -0
  64. package/dist/services/aidlc-coordination/src/server.mjs +9 -3
  65. package/dist/services/aidlc-coordination/test/fleet.test.mjs +21 -0
  66. package/dist/services/aidlc-coordination/test/server-health-auth.test.mjs +67 -0
  67. package/dist/src/adapters.d.ts +0 -3
  68. package/dist/src/adapters.js +3 -5
  69. package/dist/src/cli/argv.d.ts +12 -0
  70. package/dist/src/cli/argv.js +68 -0
  71. package/dist/src/cli/commands.d.ts +8 -0
  72. package/dist/src/cli/commands.js +159 -0
  73. package/dist/src/cli/loop-launcher.d.ts +47 -0
  74. package/dist/src/cli/loop-launcher.js +322 -0
  75. package/dist/src/cli/options.d.ts +25 -0
  76. package/dist/src/cli/options.js +32 -0
  77. package/dist/src/cli/prompt.d.ts +9 -0
  78. package/dist/src/cli/prompt.js +66 -0
  79. package/dist/src/cli.js +28 -191
  80. package/dist/src/gate.js +3 -2
  81. package/dist/src/installer.d.ts +14 -7
  82. package/dist/src/installer.js +42 -143
  83. package/dist/src/legacy.js +1 -0
  84. package/dist/src/managed-content.d.ts +7 -0
  85. package/dist/src/managed-content.js +15 -4
  86. package/dist/src/managed-planning.d.ts +65 -0
  87. package/dist/src/managed-planning.js +219 -0
  88. package/dist/src/mcp-setup.js +3 -1
  89. package/dist/src/model/config-contracts.d.ts +65 -0
  90. package/dist/src/model/config-contracts.js +1 -0
  91. package/dist/src/model/install-contracts.d.ts +29 -0
  92. package/dist/src/model/install-contracts.js +1 -0
  93. package/dist/src/model/lifecycle-enums.d.ts +13 -0
  94. package/dist/src/model/lifecycle-enums.js +1 -0
  95. package/dist/src/model/loop.d.ts +20 -0
  96. package/dist/src/model/loop.js +1 -0
  97. package/dist/src/model/manifest.d.ts +16 -0
  98. package/dist/src/model/manifest.js +1 -0
  99. package/dist/src/model/records.d.ts +142 -0
  100. package/dist/src/model/records.js +1 -0
  101. package/dist/src/model.d.ts +11 -264
  102. package/dist/src/model.js +1 -1
  103. package/dist/src/profiles.d.ts +2 -0
  104. package/dist/src/profiles.js +53 -9
  105. package/dist/src/state/archive-record.d.ts +9 -0
  106. package/dist/src/state/archive-record.js +26 -0
  107. package/dist/src/state/commands.d.ts +18 -0
  108. package/dist/src/state/commands.js +27 -0
  109. package/dist/src/state/domain.d.ts +9 -0
  110. package/dist/src/state/domain.js +9 -0
  111. package/dist/src/state/guards.d.ts +7 -0
  112. package/dist/src/state/guards.js +17 -0
  113. package/dist/src/state/io.d.ts +10 -0
  114. package/dist/src/state/io.js +35 -0
  115. package/dist/src/state/items.d.ts +3 -4
  116. package/dist/src/state/items.js +58 -57
  117. package/dist/src/state/lessons.js +14 -7
  118. package/dist/src/state/lifecycle.js +2 -2
  119. package/dist/src/state/lock.js +7 -6
  120. package/dist/src/state/memory.js +24 -12
  121. package/dist/src/state/{archive.js → migrate.js} +7 -7
  122. package/dist/src/state/partition.d.ts +15 -0
  123. package/dist/src/state/partition.js +90 -0
  124. package/dist/src/state/paths.d.ts +11 -0
  125. package/dist/src/state/paths.js +12 -0
  126. package/dist/src/state/render.js +9 -6
  127. package/dist/src/state/store.js +9 -15
  128. package/dist/src/state/transitions.js +9 -7
  129. package/dist/src/state/validate.js +55 -7
  130. package/dist/src/state.d.ts +16 -11
  131. package/dist/src/state.js +16 -11
  132. package/dist/src/task-ui.d.ts +33 -0
  133. package/dist/src/task-ui.js +33 -0
  134. package/dist/src/ui/assets.d.ts +14 -0
  135. package/dist/src/ui/assets.js +45 -0
  136. package/dist/src/ui/changes.d.ts +83 -0
  137. package/dist/src/ui/changes.js +498 -0
  138. package/dist/src/ui/containers.d.ts +71 -0
  139. package/dist/src/ui/containers.js +214 -0
  140. package/dist/src/ui/daemon.d.ts +75 -0
  141. package/dist/src/ui/daemon.js +232 -0
  142. package/dist/src/ui/data.d.ts +42 -0
  143. package/dist/src/ui/data.js +89 -0
  144. package/dist/src/ui/docs.d.ts +13 -0
  145. package/dist/src/ui/docs.js +39 -0
  146. package/dist/src/ui/files.d.ts +3 -0
  147. package/dist/src/ui/files.js +20 -0
  148. package/dist/src/ui/http.d.ts +14 -0
  149. package/dist/src/ui/http.js +80 -0
  150. package/dist/src/ui/live.d.ts +5 -0
  151. package/dist/src/ui/live.js +43 -0
  152. package/dist/src/ui/markdown.d.ts +2 -0
  153. package/dist/src/ui/markdown.js +127 -0
  154. package/dist/src/ui/options.d.ts +48 -0
  155. package/dist/src/ui/options.js +81 -0
  156. package/dist/src/ui/security.d.ts +34 -0
  157. package/dist/src/ui/security.js +38 -0
  158. package/dist/src/ui/server.d.ts +39 -0
  159. package/dist/src/ui/server.js +347 -0
  160. package/dist/src/ui/sse.d.ts +14 -0
  161. package/dist/src/ui/sse.js +281 -0
  162. package/dist/src/ui/views/board.d.ts +7 -0
  163. package/dist/src/ui/views/board.js +131 -0
  164. package/dist/src/ui/views/changes.d.ts +19 -0
  165. package/dist/src/ui/views/changes.js +154 -0
  166. package/dist/src/ui/views/components.d.ts +56 -0
  167. package/dist/src/ui/views/components.js +113 -0
  168. package/dist/src/ui/views/docs.d.ts +15 -0
  169. package/dist/src/ui/views/docs.js +64 -0
  170. package/dist/src/ui/views/layout.d.ts +44 -0
  171. package/dist/src/ui/views/layout.js +233 -0
  172. package/dist/src/ui/views/task.d.ts +25 -0
  173. package/dist/src/ui/views/task.js +320 -0
  174. package/dist/src/upgrade-board.js +10 -10
  175. package/dist/src/upgrade.d.ts +0 -1
  176. package/dist/src/upgrade.js +24 -85
  177. package/dist/src/workflow.d.ts +4 -0
  178. package/dist/src/workflow.js +36 -4
  179. package/docs/README.md +41 -22
  180. package/docs/architecture.md +101 -37
  181. package/docs/command-reference.md +289 -52
  182. package/docs/configuration.md +70 -30
  183. package/docs/coordination-service.md +91 -30
  184. package/docs/design-decisions.md +87 -0
  185. package/docs/development.md +124 -49
  186. package/docs/loop-local-run.md +228 -0
  187. package/docs/loop-runbook.md +214 -0
  188. package/docs/operating-workflow.md +55 -42
  189. package/docs/testing-and-release.md +72 -49
  190. package/docs/troubleshooting.md +221 -0
  191. package/package.json +4 -1
  192. package/dist/src/ledger.d.ts +0 -22
  193. package/dist/src/ledger.js +0 -119
  194. package/dist/src/state/shared.d.ts +0 -29
  195. package/dist/src/state/shared.js +0 -71
  196. package/dist/src/tracker.d.ts +0 -36
  197. package/dist/src/tracker.js +0 -44
  198. /package/dist/src/state/{archive.d.ts → migrate.d.ts} +0 -0
@@ -1,26 +1,32 @@
1
1
  # Development guide
2
2
 
3
- This guide is for contributors to `@felixdotgo/aidlc-kit`. It covers local setup, source ownership, and the rules that keep the package runtime and installed workflow behaviour aligned.
3
+ Local setup, dogfooding, source ownership, and the rules that keep package runtime and installed workflow aligned. To use the workflow in your own project, start at the [documentation index](./README.md).
4
4
 
5
5
  ## Requirements and dependencies
6
6
 
7
- - Node.js 20.17 or newer is required by the package runtime.
8
- - npm installs the repository development dependencies.
9
- - `@inquirer/prompts` is the runtime dependency for interactive CLI prompts; installed lifecycle scripts remain dependency-free.
10
- - Development uses TypeScript and `@types/node` as declared in `package.json`.
7
+ - Node.js 20.17 or newer; npm installs the dev dependencies (TypeScript, `@types/node`).
8
+ - `@inquirer/prompts` is the only runtime dependency; installed lifecycle scripts are dependency-free.
9
+ - Codex, Claude Code, or OpenCode: only for real evaluator drivers; OpenCode also needs `AIDLC_OPENCODE_MODEL` (`provider/model[#variant]`).
11
10
 
12
11
  ```sh
13
12
  npm install
14
13
  ```
15
14
 
16
- Codex, Claude Code, or OpenCode are optional for manually exercising real evaluator drivers. Ordinary build, lint, and unit-test work does not need external model credentials. OpenCode driver runs also need `AIDLC_OPENCODE_MODEL` set to a `provider/model[#variant]` value.
15
+ ## Platform support
16
+
17
+ | Platform | Status | Notes |
18
+ | --- | --- | --- |
19
+ | Linux | Supported | Full CI coverage; Docker worker isolation available. |
20
+ | macOS | Supported | Full test coverage; POSIX shell recipes apply. |
21
+ | Windows | Best-effort | Use WSL or Git Bash for shell recipes. win32 separators handled in `src/state/guards.ts`, `src/profiles.ts`, installed `lib/store.mjs` and `context-runtime.mjs`; state lock liveness via `process.kill(pid, 0)`. Not in CI. |
22
+ | Loop / fleet | Linux only | Needs Docker and a POSIX shell; `loop-local-workers.mjs` rejects other hosts. E2e tests need `AIDLC_TEST_WORKER_IMAGE` and `AIDLC_WORKER_DOCKER_IMAGE`. |
17
23
 
18
24
  ## Repository layout
19
25
 
20
26
  ```text
21
27
  assets/aidlc/ Source workflow contracts, schemas, and installed scripts
22
28
  skills/ Source thin phase adapters
23
- src/ TypeScript package CLI, installer, lifecycle, profiles, and migrations
29
+ src/ Package CLI (src/cli/), installer, shared planning core, lifecycle domain (src/model/, src/state/), profiles, migrations
24
30
  dev/evaluator/ Development-only evaluator harness and runners
25
31
  scripts/build-assets.mjs Bundles workflow assets for package distribution
26
32
  test/unit/ Unit and installed-runtime parity tests
@@ -28,25 +34,22 @@ docs/ User, operator, and contributor documentation
28
34
  dist/ Generated TypeScript and bundled assets; do not hand-edit
29
35
  ```
30
36
 
31
- The asset build copies `assets/aidlc/` and `skills/` into `dist/assets/.agents/`. At install time, the package writes the workflow to a consumer project's `.agents/aidlc/` and `.agents/skills/` locations. Always state which of these three layouts—source, bundle, or installed project—you mean in code or documentation.
37
+ Three layouts: source (`assets/aidlc/`, `skills/`), bundle (`dist/assets/.agents/`), installed (consumer `.agents/aidlc/` and `.agents/skills/`). Say which you mean.
32
38
 
33
39
  ## Local commands
34
40
 
35
41
  | Command | Purpose |
36
42
  | --- | --- |
37
- | `npm run build` | Rebuild bundled workflow assets and compile TypeScript into `dist/`. |
43
+ | `npm run build` | Bundle workflow assets and compile TypeScript into `dist/`. |
44
+ | `npm run sync-core` | Copy `assets/aidlc/scripts/lib/store.mjs` to `services/aidlc-coordination/src/lifecycle-core.mjs` byte-identically. |
38
45
  | `npm run lint` | Type-check without emitting files. |
39
- | `npm test` | Build, then run every compiled unit test with Node's test runner. |
40
- | `node --test dist/test/unit/<file>.test.js` | Run a focused compiled test after building. |
41
- | `npm run release:check` | Run the repository release-evidence policy check. |
42
-
43
- Run the narrowest relevant test while iterating, then run `npm test` and `npm run lint` before handing off a non-trivial change. See [Testing and release](./testing-and-release.md) for the package smoke test and evaluator.
46
+ | `npm test` | Build, then run all compiled unit tests (Node test runner). |
47
+ | `node --test dist/test/unit/<file>.test.js` | Run one compiled test after building. |
48
+ | `npm run release:check` | Release-evidence policy check. |
44
49
 
45
50
  ## Local build and registry-free installation
46
51
 
47
- Use this fast smoke test to install workflow assets from the current checkout into a disposable consumer project. It invokes the freshly compiled CLI directly, so the consumer installation does not use `npm install`, `npx`, a published package, or an npm registry. Repository bootstrap and build still use npm and the dependencies already installed in this checkout.
48
-
49
- Run the following POSIX shell commands from the repository root:
52
+ Install the checkout's assets into a disposable consumer project via the compiled CLI (no `npm install`, `npx`, or registry). From the repository root:
50
53
 
51
54
  ```sh
52
55
  AIDLC_REPO="$(pwd)"
@@ -62,59 +65,131 @@ node "$AIDLC_LOCAL_PROJECT/.agents/aidlc/scripts/state.mjs" task list --root "$A
62
65
  printf 'Local test project: %s\n' "$AIDLC_LOCAL_PROJECT"
63
66
  ```
64
67
 
65
- The dry run previews the managed writes before `--yes` applies them. `status` describes the installed version and adapters, `doctor --strict` is the integrity check, and the final command confirms that the copied dependency-free lifecycle runtime can read its canonical state without the package CLI.
68
+ - Use a new empty directory each time (reuse across versions triggers the human-only upgrade protection); remove it manually. On Windows, create it in PowerShell and pass the absolute path.
69
+ - Do not target a real project unless its managed files and state are intentional test targets.
70
+ - This checks the compiled checkout only, not the published allowlist, bin metadata, or tarball exclusions; run the [package smoke test](./testing-and-release.md#package-smoke-test) before release.
71
+
72
+ ## Run `npx` from a local package archive
73
+
74
+ ```sh
75
+ npm pack
76
+ npx --package felixdotgo-aidlc-kit-0.3.0.tgz -- aidlc-kit init .
77
+ ```
66
78
 
67
- Always use a new empty directory and inspect the printed path before removing it manually. Do not point this recipe at a real project unless its managed files and workflow state are intentional test targets. Reusing a fixture across package versions triggers the human-only upgrade protection by design. On Windows, use WSL or Git Bash for the snippet, or create a temporary directory in PowerShell and pass its absolute path to the same Node commands.
79
+ Run from the archive's directory; pass a disposable project instead of `.` to avoid writing into the current directory.
68
80
 
69
- This direct-`dist` smoke verifies the compiled checkout, but it does not verify the published file allowlist, package bin metadata, or tarball exclusions. Before release, also run the separate [package smoke test](./testing-and-release.md#package-smoke-test), which packs and extracts a local tarball without installing or fetching the package from a registry.
81
+ ## Dogfooding this repository
70
82
 
71
- ## Run `npx` from a local package archive
83
+ `.agents/` is gitignored; each contributor installs the repository's own workflow from the checkout.
72
84
 
73
- To test the package before release, create its `.tgz` archive and run the local archive with `npx`:
85
+ ### Install the workflow from source
74
86
 
75
87
  ```sh
76
- npm pack
77
- npx --package felixdotgo-aidlc-kit-0.1.1.tgz -- aidlc-kit init .
88
+ npm install
89
+ npm run build
90
+ node dist/src/cli.js init . --agent <codex|claude|opencode> --loop-mode off --yes
78
91
  ```
79
92
 
80
- `npx` runs the archive without publishing it. Run the command from the directory containing the archive. Use a disposable project instead of `.` if you do not want the command to write workflow files into the current directory.
93
+ Edit `.agents/config.json` as below (`commands` as executable-and-argument arrays; your adapter id → `"scripted"` in `agentState`), then `node dist/src/cli.js profile validate .`.
94
+
95
+ ```json
96
+ {
97
+ "commands": {
98
+ "build": { "command": "npm", "args": ["run", "build"] },
99
+ "test": { "command": "npm", "args": ["test"] },
100
+ "lint": { "command": "npm", "args": ["run", "lint"] }
101
+ },
102
+ "agentState": { "opencode": "scripted" }
103
+ }
104
+ ```
81
105
 
82
- ## Ownership boundaries
106
+ ### Check for drift and re-sync
83
107
 
84
- The package has three ownership layers:
108
+ After changing `assets/aidlc/`, check for a stale install (any output means stale; symptom: `loop: Isolated local worker dispatcher is not integrated; loop execution is unavailable`):
85
109
 
86
- 1. Package-managed kernel assets installed under `.agents/aidlc/`.
87
- 2. Project-owned configuration, profiles, rules, and evaluation material under `.agents/project/`.
88
- 3. Project-owned task state and derived data under `.agents/data/`.
110
+ ```sh
111
+ diff -rq assets/aidlc/scripts .agents/aidlc/scripts
112
+ ```
89
113
 
90
- Do not introduce a second lifecycle board or hand-edit canonical state. The installed lifecycle scripts are dependency-free so consumer projects do not need this package to operate after installation.
114
+ Re-sync is a human-only upgrade (TTY required); stop the loop daemon first (`node dist/src/cli.js loop down --root .` or `loop stop`), then re-run `diff -rq`:
91
115
 
92
- ## Mirrored runtime behaviour
116
+ ```sh
117
+ npm run build
118
+ node dist/src/cli.js upgrade . --dry-run # preview the plan
119
+ node dist/src/cli.js upgrade . # type the package version when prompted
120
+ ```
121
+
122
+ ### Run the loop from a source checkout
123
+
124
+ > [!WARNING]
125
+ > Experimental, pre-1.0. See [Status and stability](./loop-runbook.md#status-and-stability).
126
+
127
+ In place of `npx --package @felixdotgo/aidlc-kit@<version> aidlc-kit …`, run the compiled CLI after `npm run build`:
93
128
 
94
- The TypeScript implementation powers the package CLI. Installed projects use a dependency-free mirror under `assets/aidlc/scripts/`. Changes to shared lifecycle, state, gate, profile, or context behaviour must preserve parity between these paths and add coverage for both package and installed-runtime execution.
129
+ | Task | Command |
130
+ | --- | --- |
131
+ | Start the daemon and dashboard | `node dist/src/cli.js loop up --root .` |
132
+ | Check daemon and task status | `node dist/src/cli.js loop status --root . [--task-id <task-id>]` |
133
+ | Serve only the dashboard | `node dist/src/cli.js ui .` |
134
+
135
+ See [Local loop walkthrough](./loop-local-run.md) and [Command reference](./command-reference.md#loop).
95
136
 
96
- Likewise, a public configuration or schema change must update its validator, JSON schema, installed assets, package inventory, documentation, and tests together.
137
+ ## Ownership boundaries
138
+
139
+ - `.agents/aidlc/`: package-managed kernel assets.
140
+ - `.agents/project/`: project-owned config, profiles, rules, and evaluation material.
141
+ - `.agents/data/`: project-owned task state and derived data; never add a second lifecycle board or hand-edit it.
142
+
143
+ ## Mirrored runtime behaviour
144
+
145
+ - TypeScript powers the package CLI; installed projects use the dependency-free mirror in `assets/aidlc/scripts/`. Lifecycle, state, gate, profile, or context changes keep parity and add coverage for both.
146
+ - A public configuration or schema change updates validator, JSON schema, installed assets, package inventory, docs, and tests together.
147
+ - Dual-core sync rule: after editing `assets/aidlc/scripts/lib/store.mjs`, run `npm run sync-core` so `services/aidlc-coordination/src/lifecycle-core.mjs` stays byte-identical.
97
148
 
98
149
  ## Code style and conventions
99
150
 
100
- Adopted as the project baseline (approved decision `D1-convention-standard` on task `refactor-source-readability`):
151
+ Baseline (decision `D1-convention-standard`, task `refactor-source-readability`):
101
152
 
102
- - **Strict TypeScript, no new dependencies for tooling.** Keep `strict` mode; enforce via `npm run lint` (`tsc --noEmit`). No ESLint/Prettier for now.
103
- - **File size targets.** Aim for ≤250 lines per source file and ≤60 lines per function; split by domain responsibility when exceeded.
104
- - **Module boundaries.** One responsibility per module; a facade module may re-export a public API for compatibility (for example `src/state.ts`).
105
- - **Naming.** Descriptive camelCase for functions/variables, `PascalCase` for types/interfaces, `SCREAMING_SNAKE_CASE` for true constants; file names match their primary export.
106
- - **Error handling.** Fail with typed, one-line errors; never swallow exceptions silently; validate inputs before I/O.
107
- - **Dependencies.** Pass dependencies (fetch, clock, environment) explicitly as parameters; avoid module-level mutable state.
108
- - **Public API.** Document exported symbols with JSDoc when the contract is non-obvious.
109
- - **Behavior preservation.** Refactors must not change CLI output, state schema, file layout, or installed assets; run parity tests.
110
- - **Verification.** Run the narrowest relevant test while iterating; `npm test` + `npm run lint` before handing off.
153
+ - **Strict TypeScript.** Keep `strict`; enforce via `npm run lint` (`tsc --noEmit`). No ESLint/Prettier or other tooling deps.
154
+ - **Size.** ≤250 lines per file, ≤60 per function; split by responsibility.
155
+ - **Modules.** One responsibility each; a facade may re-export a public API (e.g. `src/state.ts`).
156
+ - **Naming.** camelCase functions/variables, `PascalCase` types, `SCREAMING_SNAKE_CASE` constants; file name matches primary export.
157
+ - **Errors.** Typed one-line errors; never swallow; validate inputs before I/O.
158
+ - **Dependencies.** Pass fetch, clock, environment explicitly; no module-level mutable state.
159
+ - **Public API.** JSDoc exported symbols with non-obvious contracts.
160
+ - **Behavior preservation.** Refactors never change CLI output, state schema, file layout, or installed assets; run parity tests.
161
+ - **Verification.** Narrowest test while iterating; `npm test` + `npm run lint` before handoff.
111
162
 
112
163
  ## Safe implementation rules
113
164
 
114
- - Resolve all project-relative paths through the shared path helpers; reject traversal and symlink escape.
115
- - Keep installation, migration, and upgrade plans deterministic and conflict-first.
165
+ - Resolve project-relative paths through the shared path helpers; reject traversal and symlink escape.
166
+ - Keep install, migration, and upgrade plans deterministic and conflict-first.
116
167
  - Preserve project-owned configuration and state when changing managed assets.
117
- - Do not add remote profile discovery, runtime asset downloads, executable plugin hooks, registry checks, or shell-string command execution.
118
- - Treat human-gated lifecycle transitions as atomic, auditable state operations.
168
+ - Never add remote profile discovery, runtime asset downloads, executable plugin hooks, registry checks, or shell-string execution.
169
+ - Human-gated lifecycle transitions are atomic, auditable state operations.
170
+ - Read [Architecture](./architecture.md) before changing a module boundary, migration, installed script, or bundle layout.
171
+
172
+ ## Contributing to prompt assets
173
+
174
+ Prompt assets are the contracts under `assets/aidlc/` (`orchestrator.md`, `phase-*.md`) that `context.mjs` turns into phase packets.
175
+
176
+ - Keep them compact: default packet budget is 16,000 characters (`config.context.maxChars`); optional rules and diagnostics drop first.
177
+ - Never truncated (generation fails instead): next-action contract, phase contract, approved decisions, safety/spec anchors, task state, latest applicable evidence.
178
+ - Heading invariants enforced by `gate-check.mjs`:
179
+ - Intent (`G0_confirm`): `## 📋 Problem`, `## 🗺️ Affected areas`, `## 💭 Assumptions`, `## ❓ Open questions`, `## 🎯 Scope`.
180
+ - Design (`G1_review`): `## 🧩 Solution per affected area`, `## 📌 Spec traceability`, `## 🔗 Cross-service contracts`, `## ⚠️ Risks / edge cases`.
181
+ - After changing contracts, run `npm run release:check` (`--adapters opencode`) and the evaluator suite; update docs and tests in the same change. Rationale: [Design decisions](./design-decisions.md) D6.
182
+
183
+ ## Documentation conventions
184
+
185
+ Follow [Adding or changing a page](./README.md#adding-or-changing-a-page). In addition:
186
+
187
+ - A public contract change (command, config field, schema, installed asset) updates its guide and the asserting test in the same change.
188
+ - Never duplicate canonical agent instructions from `assets/aidlc/`; link to the installed asset.
189
+
190
+ ## Related
119
191
 
120
- Read [Architecture](./architecture.md) before changing a module boundary, migration, installed script, or bundle layout.
192
+ - [Testing and release](./testing-and-release.md)
193
+ - [Architecture](./architecture.md)
194
+ - [Design decisions](./design-decisions.md)
195
+ - [Configuration](./configuration.md)
@@ -0,0 +1,228 @@
1
+ # Local loop walkthrough
2
+
3
+ Day-to-day operation of the loop in `local` mode on one machine: start the daemon, add tasks, watch, answer gates, resume. To enable the loop first, follow the [Loop setup runbook](./loop-runbook.md#local-mode).
4
+
5
+ > [!WARNING]
6
+ > Experimental, pre-1.0. See [Status and stability](./loop-runbook.md#status-and-stability).
7
+
8
+ Commands use the published package (`npx --package @felixdotgo/aidlc-kit@0.3.0 aidlc-kit …`) or the installed launcher `./.agents/aidlc/scripts/loop.sh`; both drive the installed `loop-entry.mjs`. Source checkout: [Dogfooding this repository](./development.md#dogfooding-this-repository).
9
+
10
+ ## How the loop works
11
+
12
+ - The **lead** runs `clarify` (gate `G0_confirm`), `plan` (`G1_review`), and `wrap` on the host, no Docker; **workers** run only `build` items (`G2_codereview`), isolated in Docker. Gates: [Operating the workflow](./operating-workflow.md).
13
+ - Each iteration reads `state.mjs task next`, runs one agent turn on the returned `nextAction`, re-reads canonical state, and updates the checkpoint/fingerprint.
14
+ - The loop **stops at every gate** and **never self-approves**; only a human on the trusted terminal or the signed-in dashboard approves.
15
+ - It also stops after the per-run `maxTurns` budget (a resumed run gets a fresh one), after `maxStallTurns` unchanged turns, or at `blocked`/`terminal`/`complete` (`loop.limits`: [Configuration](./configuration.md#optional-loop-configuration)).
16
+ - Config alone runs nothing; only `loop start` or `loop.sh up` runs the loop.
17
+
18
+ ## Prerequisites
19
+
20
+ - Linux host with Docker (`docker info` must pass for the build phase) and a POSIX shell; Node.js ≥ 20.17.
21
+ - Lead provider CLI (`opencode`, `codex`, or `claude`) on the host `PATH`, matching `loop.agents.lead`.
22
+ - If any provider is `opencode`: `AIDLC_OPENCODE_MODEL` naming a model listed by `opencode models`.
23
+ - Worker credentials per provider/model: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, or `OPENCODE_API_KEY`. The worker image is built automatically ([Worker Docker image](#worker-docker-image)).
24
+
25
+ ## Set the environment
26
+
27
+ Put loop variables in `.agents/loop.env` (installed as a commented template, git-ignored through `.agents/.gitignore`) or `export` them in the shell that starts the daemon; exported values win. `loop start`, `loop up`, and a dashboard-started daemon load the file.
28
+
29
+ ```sh
30
+ # .agents/loop.env
31
+ # Required for opencode unless "model" is set in opencode.json; use a model from `opencode models`:
32
+ AIDLC_OPENCODE_MODEL=<provider/model>
33
+ # Worker key for the build phase; read from ~/.local/share/opencode/auth.json when unset:
34
+ # OPENCODE_API_KEY=...
35
+ ```
36
+
37
+ ```sh
38
+ ./.agents/aidlc/scripts/loop.sh check # what the daemon will see; secrets are never printed
39
+ ```
40
+
41
+ `AIDLC_LOOP_EVENT_LOG` is set to `.agents/data/loop/ui-events.jsonl` automatically. All variables: [runbook](./loop-runbook.md#step-2--fill-in-agentsloopenv); lookup order: [Command reference](./command-reference.md#loop).
42
+
43
+ > [!IMPORTANT]
44
+ > A running daemon keeps the environment it started with. After editing `.agents/loop.env`, run `loop.sh down`, then `loop.sh up`; `loop up` warns when the file changed after the daemon started.
45
+
46
+ ## Start the daemon and add tasks
47
+
48
+ ```sh
49
+ ./.agents/aidlc/scripts/loop.sh up # --open launches the browser; --no-ui starts only the daemon
50
+ ./.agents/aidlc/scripts/loop.sh status # daemon, dashboard, environment
51
+ ./.agents/aidlc/scripts/loop.sh logs # follow the daemon log
52
+ ./.agents/aidlc/scripts/loop.sh down # stop both; --now cancels the running turn
53
+ ```
54
+
55
+ `Ctrl-C` in the `up` terminal closes only the dashboard. Windows: `.agents\aidlc\scripts\loop.cmd`, same commands.
56
+
57
+ Underneath, `loop start` runs the persistent daemon in the foreground and reads no requirement; one per project (a second fails with `Loop daemon already running (pid N)`):
58
+
59
+ ```sh
60
+ npx --package @felixdotgo/aidlc-kit@0.3.0 aidlc-kit loop start
61
+ ```
62
+
63
+ - The daemon runs only **loop-owned** tasks: created through loop intake (`.agents/data/tasks/<id>/runtime/intake.json`) or holding a loop run record (`runtime/run.json`). An interactively created task (`state.mjs task create`) is never picked up, so the daemon cannot race an interactive lead.
64
+ - It runs one bounded run per actionable task in turn and keeps polling after a gate or completion.
65
+
66
+ Add a loop-owned task:
67
+
68
+ - **Dashboard → New task** creates the task and starts the daemon if none is running.
69
+ - **Terminal intake** reads the requirement from stdin (never an argument), at most 8192 bytes; id and title derive from the first line (`--task-id`/`--title` override).
70
+
71
+ ```sh
72
+ echo "Add PDF report export" | npx --package @felixdotgo/aidlc-kit@0.3.0 aidlc-kit loop intake
73
+ echo "Add PDF report export" | node .agents/aidlc/scripts/loop-entry.mjs intake "" . # installed entry point
74
+ ```
75
+
76
+ - Intake refuses (creates nothing) while an **interactive** task is actionable; finish or pause it first.
77
+
78
+ Stopping (`Ctrl-C` or `SIGTERM`) is staged: first signal stops after the current turn, second cancels the in-flight agent turn, third exits immediately.
79
+
80
+ - A stopped run is recorded as `stopped` (the task is **not** paused) and resumes on the next `loop start`. A terminal `Ctrl-C` also reaches the agent child, so the turn usually ends on the first press; still `stopped`, not a transport failure.
81
+ - `aidlc-kit loop start` stays in the foreground for the whole shutdown (forwards `SIGTERM`, lets the terminal deliver `Ctrl-C`), so later presses reach the daemon.
82
+
83
+ ## Watch status
84
+
85
+ ```sh
86
+ npx --package @felixdotgo/aidlc-kit@0.3.0 aidlc-kit loop status --task-id <task-id>
87
+ ```
88
+
89
+ Prints `authority`, `record` (the loop run record), and `nextAction` (`classification`: `run_phase`, `await_user`, `blocked`, `complete`, …).
90
+
91
+ ## Approve a gate or send feedback
92
+
93
+ Answer a gate on the trusted host terminal or the signed-in dashboard, never from the lead or a worker, never with piped input:
94
+
95
+ ```sh
96
+ node .agents/aidlc/scripts/loop-gate.mjs <task-id>
97
+ # type: approve -> approves this exact review and advances the phase
98
+ # type: <any other text> -> feedback: the task stays at this gate
99
+ ```
100
+
101
+ - Prints the exact review (task, phase, gate, artifact digests, and at `G2_codereview` the integration commit), then prompts `Type approve to approve this exact review, or type feedback to send guidance back to the loop:`.
102
+ - **`approve`** is the only answer that moves the task forward; if the review changes while you type, it fails closed.
103
+ - **Any other text is feedback**: recorded as evidence `Cancelled gate wait at <gate>: <feedback>`; the task returns to `active` at the same gate, and the next lead turn revises the review and re-presents the **same** gate.
104
+ - The dashboard detail page offers the same actions, **Send feedback (stay at gate)** and **✓ Approve** ([dashboard](#use-the-web-dashboard)).
105
+
106
+ ## Resume after a gate or a pause
107
+
108
+ There is **no `loop resume`** in either mode; the daemon auto-resumes every task whose `nextAction` is `run_phase` (*actionable*).
109
+
110
+ - **After approving a gate**: nothing; the next poll runs the next lead turn.
111
+ - **After a pause** (agent transport failure, per-run turn limit): the task is `paused` (`nextAction` `blocked`) and skipped. Fix the cause, then press **resume** on the dashboard or run the command below; the next poll (default about 5 s) picks it up.
112
+
113
+ ```sh
114
+ node .agents/aidlc/scripts/state.mjs task status <task-id> --status active # or: loop-entry.mjs resume-task <task-id> .
115
+ ```
116
+
117
+ - `aidlc-kit loop resume` and `loop-entry.mjs resume` fail closed with `loop resume is removed; the daemon auto-resumes actionable tasks — run 'loop start', and re-activate a paused task from the dashboard (resume) or with the task status command`.
118
+
119
+ ## Follow the streaming log
120
+
121
+ Progress goes to **stderr** (stdout stays the final JSON):
122
+
123
+ ```
124
+ ━━ turn 1 · phase clarify · agent opencode ━━
125
+ › tool: grep
126
+ › tool: read
127
+ › command completed (exit 0)
128
+ <stream text from the lead>
129
+ ━━ turn done ━━
130
+ ```
131
+
132
+ A clarify or plan turn can take minutes without output. At a gate the daemon prints the **gate view** and moves on. Every event carries its `taskId`:
133
+
134
+ | Event | Meaning |
135
+ | --- | --- |
136
+ | `turn_start` / `turn_end` | Turn boundary, with phase and agent. |
137
+ | `agent_text` | Lead text, capped at 4096 characters per chunk. |
138
+ | `agent_tool` | Tool in use (`grep`, `read`, `glob`, `shell`, …). |
139
+ | `lifecycle_command` | Shell result and exit code. |
140
+ | `gate` | Gate view. |
141
+ | `daemon_start`, `daemon_poll`, `daemon_turn`, `loop_stopped` | Daemon lifecycle. |
142
+ | `daemon_poll_error` | The task list could not be read; the daemon keeps polling. |
143
+ | `daemon_turn_error` | A task run threw (or ended `blocked`/`reconcile`); retried with exponential backoff (poll interval doubled per failure, capped at 10 minutes). |
144
+ | `build_deferred` | A ready build item held for a later batch. `reason`: overlaps another item, busy path held by an active assignment, unresolved assignment, or `capacity` (one item per configured worker per batch). |
145
+
146
+ ## Use the web dashboard
147
+
148
+ ```sh
149
+ npx --package @felixdotgo/aidlc-kit@0.3.0 aidlc-kit ui . # loop.sh up starts the same dashboard
150
+ ```
151
+
152
+ Branded **Loop**, binds `127.0.0.1:4173` by default and prints `Open: http://127.0.0.1:4173` (or pass `--open`).
153
+
154
+ **Access**
155
+
156
+ - There is no login or session token: the dashboard is for a trusted local machine or internal network. Mutating actions (new task, resume, gate feedback, gate approve) work right away from the page.
157
+ - Another origin, a foreign `Host` header, or a request that does not look like the dashboard's own `fetch` gets `403` ([Dashboard access](./command-reference.md#dashboard-access)). Binding to a non-loopback address prints a warning that the dashboard has no authentication.
158
+
159
+ **Header and updates**
160
+
161
+ - Header: authority (`authority · local`), daemon state, and a bell listing tasks needing review. The daemon pill turns amber (**daemon · N errors**) while a turn or poll keeps failing; hover for messages.
162
+ - Pages poll about every 1.5 s and patch only what changed. An unreachable server shows a **reconnecting…** pill and polling backs off.
163
+ - A new gate updates the bell, the tab title (`(2) Loop`), and a **Review needed** toast; with **Settings → notifications** on, a browser notification too (permission is asked only then).
164
+ - Light/dark follows the system unless pinned in **Settings**. Shortcuts: <kbd>N</kbd> new task, <kbd>/</kbd> search, <kbd>Esc</kbd> close.
165
+
166
+ **Where things live**
167
+
168
+ | Where | What |
169
+ | --- | --- |
170
+ | Header bell | Tasks waiting at a gate (5 newest; **Load more**). A `blocked_on_user` card shows **review**, which opens the detail page. |
171
+ | Card | Title only (id on hover and in search). Click opens the side panel and adds `?task=<task-id>` to the URL (or the full page, per **Settings**); ctrl/cmd/middle-click opens the full page in a new tab, shift-click in this tab. |
172
+ | Side panel | Stepper (clarify → plan → build → wrap → done), artifacts, last 20 important log lines, a copy button for the id, **Open full page ↗**; at a gate, **Open review →**. |
173
+ | Detail page `/tasks/<task-id>` | The only place with gate approval and feedback; containers, full live log — the one place to follow everything a task does. |
174
+ | Settings (header ⚙) | Browser-only preferences: theme, live-update interval or pause, browser notifications for reviews, live log defaults, diff wrap / ignore whitespace, container log tail size, card click target. **Reset to defaults** restores them. |
175
+ | Containers (detail page) | Every worker container the loop ran for the task (local or fleet; same layout), newest first: worker, item, turn, `running` / `exited <code>` / `signal`, start time and duration, host when recorded elsewhere. **Log** opens the raw output of that assignment (all turns, stdout and stderr unredacted) with **Follow** while it runs; the tail size comes from Settings. `docker · unavailable` means the state comes from the index only. |
176
+ | Review panel (while `blocked_on_user`) | **Feedback** textarea + **Send feedback (stay at gate)**; **Approve** note + **✓ Approve** (popup; only **Confirm approve** sends). |
177
+ | Approve semantics | The note is audit provenance, never feedback. A moved gate is refused with `409`. After feedback a **feedback pending** pill shows until approval; failing structural checks replace the gate view. |
178
+ | New task (side panel) | Markdown editor. **Create task** runs loop intake and starts the daemon if none runs (stderr → `.agents/data/loop/daemon.log`); a toast shows the id or the intake error. |
179
+ | Search and filters | Browser-only; never call the API. The **done** column shows 8 recent tasks; **Show N more** expands it. |
180
+ | resume | On `paused` tasks; sets them back to `active`. |
181
+ | Live log (detail page) | Lines `time · actor · what happened`, grouped by turn. **Important** (default) hides bookkeeping, **All** shows everything, **Raw JSON** shows the events. |
182
+ | Changes `/tasks/<id>/changes` | Files and diff per work item from the commits workers recorded; otherwise the task range from the task's `baseCommit` to its `finalCommit` (or `HEAD` plus the working tree while open) — so a task driven from the terminal, or a finished task whose worker worktrees are gone, still shows its changes; last resort, the uncommitted working tree. **Wrap lines** and **Ignore whitespace** toggles. |
183
+
184
+ Live log files: the log replays the last 200 events of `.agents/data/tasks/<task-id>/runtime/events.jsonl` (1 MiB, one `.1` generation; a file an older version left in `.agents/data/loop/events/` is read until `loop migrate-data` moves it), then follows live; older tasks fall back to the global `.agents/data/loop/ui-events.jsonl` (rotated to `.jsonl.1` at 5 MB), written only when `AIDLC_LOOP_EVENT_LOG` points at it. Container output is separate: `.agents/data/tasks/<task-id>/runtime/workers/<assignment>.log` (5 MiB, one `.log.1` generation) next to `index.json`, never committed. **Docs** in the header opens these guides.
185
+
186
+ ## Worker Docker image
187
+
188
+ The build phase runs workers in Docker containers whose image contains the provider CLI (`opencode`, `codex`, or `claude`):
189
+
190
+ - Dockerfiles ship with the package (`assets/aidlc/docker/Dockerfile.<provider>`); the supervisor **auto-builds** a missing image before preflight and records the name in `.agents/config.json` (`loop.workerImage`), so `AIDLC_WORKER_DOCKER_IMAGE` is not needed.
191
+ - Build ahead of time (default provider `opencode`; default tag `aidlc-worker-<provider>:local`):
192
+
193
+ ```sh
194
+ npx @felixdotgo/aidlc-kit loop worker-image --provider opencode # or codex | claude
195
+ ```
196
+
197
+ - Images named `aidlc-worker-*-test:local` contain only a fake CLI for tests. The real image is `node:24-bookworm-slim` (Debian/glibc, because `opencode` is a dynamically linked ELF) with the CLI from `npm install -g`.
198
+ - Each worker container is started with labels `aidlc.task`, `aidlc.item`, `aidlc.worker`, and `aidlc.assignment` (`docker ps --filter label=aidlc.task=<task-id>` lists a task's workers), and its stdout/stderr are teed unredacted into the task's `runtime/workers/` log while the live log keeps only summaries.
199
+ - The container runs non-root and `--read-only`, so the CLI must be on the system `PATH` (npm global → `/usr/local/bin`). `opencode` uses `@opencode/cli` (OpenCode 2), **not** `opencode-ai` (OpenCode 1).
200
+ - Worker credentials come from the environment, per model: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, or `OPENCODE_API_KEY`. Preflight runs `docker run … --entrypoint <cli> --version`; a missing or invalid binary fails before any worker starts.
201
+
202
+ ## Quick lead-only run
203
+
204
+ A single lead with no Docker or workers, using the installed loop runner directly:
205
+
206
+ ```sh
207
+ export AIDLC_OPENCODE_MODEL=<provider/model>
208
+
209
+ node .agents/aidlc/scripts/loop.mjs run <task-id> --agent opencode --max-turns 12 --root .
210
+ node .agents/aidlc/scripts/loop.mjs status <task-id> --root .
211
+ node .agents/aidlc/scripts/loop.mjs resume <task-id> --root .
212
+ ```
213
+
214
+ The JSON output reports `status` (`gate`, `paused`, `blocked`, or `complete`) with `stopReason` and `nextAction`.
215
+
216
+ ## Troubleshooting
217
+
218
+ - [Loop stops, pauses, or never starts](./troubleshooting.md#loop-stops-pauses-or-never-starts)
219
+ - [Dashboard live log or actions do nothing](./troubleshooting.md#dashboard-live-log-or-actions-do-nothing)
220
+ - [Loop leases, locks and claims](./troubleshooting.md#loop-leases-locks-and-claims) — "already running", unapprovable gate, stuck claims
221
+ - [Build items deferred](./troubleshooting.md#build-items-deferred-or-build-dispatch-failure-unresolved-assignment) — `build_deferred`, `build dispatch failure`
222
+
223
+ ## Related
224
+
225
+ - [Loop setup runbook](./loop-runbook.md) — enabling and configuring the loop.
226
+ - [Configuration](./configuration.md#optional-loop-configuration) — `loop.*` fields.
227
+ - [Command reference](./command-reference.md#loop) — all loop flags and environment variables.
228
+ - [AI-DLC Coordination service](./coordination-service.md) — fleet (multi-machine) deployment.