@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.
- package/DEVELOPMENT.md +14 -13
- package/README.md +37 -43
- package/dist/assets/.agents/aidlc/docker/Dockerfile.claude +7 -0
- package/dist/assets/.agents/aidlc/docker/Dockerfile.codex +9 -0
- package/dist/assets/.agents/aidlc/docker/Dockerfile.opencode +8 -0
- package/dist/assets/.agents/aidlc/orchestrator.md +2 -2
- package/dist/assets/.agents/aidlc/phase-clarify.md +1 -1
- package/dist/assets/.agents/aidlc/phase-plan.md +2 -2
- package/dist/assets/.agents/aidlc/schemas/config.schema.json +2 -1
- package/dist/assets/.agents/aidlc/schemas/state.schema.json +2 -0
- package/dist/assets/.agents/aidlc/scripts/lib/assignment-store.mjs +94 -48
- package/dist/assets/.agents/aidlc/scripts/lib/context-runtime.mjs +5 -4
- package/dist/assets/.agents/aidlc/scripts/lib/loop-authority.mjs +261 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-commit-message.mjs +45 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-daemon.mjs +206 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-drivers.mjs +100 -14
- package/dist/assets/.agents/aidlc/scripts/lib/loop-env.mjs +279 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet-cli.mjs +105 -32
- package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet-remote.mjs +17 -1
- package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet-supervisor.mjs +24 -7
- package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet.mjs +42 -16
- package/dist/assets/.agents/aidlc/scripts/lib/loop-git.mjs +20 -6
- package/dist/assets/.agents/aidlc/scripts/lib/loop-holder.mjs +376 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-intake.mjs +33 -7
- package/dist/assets/.agents/aidlc/scripts/lib/loop-lease.mjs +67 -61
- package/dist/assets/.agents/aidlc/scripts/lib/loop-leases.mjs +268 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-local-workers.mjs +116 -28
- package/dist/assets/.agents/aidlc/scripts/lib/loop-runtime.mjs +114 -12
- package/dist/assets/.agents/aidlc/scripts/lib/loop-stream.mjs +117 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-supervisor-local.mjs +16 -56
- package/dist/assets/.agents/aidlc/scripts/lib/loop-supervisor-run-local.mjs +149 -6
- package/dist/assets/.agents/aidlc/scripts/lib/loop-supervisor.mjs +9 -1
- package/dist/assets/.agents/aidlc/scripts/lib/loop-worker-docker.mjs +44 -6
- package/dist/assets/.agents/aidlc/scripts/lib/loop-worker-image.mjs +64 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-worker-log.mjs +158 -0
- package/dist/assets/.agents/aidlc/scripts/lib/repo-head.mjs +22 -0
- package/dist/assets/.agents/aidlc/scripts/lib/store.mjs +68 -2
- package/dist/assets/.agents/aidlc/scripts/lib/task-runtime-migrate.mjs +75 -0
- package/dist/assets/.agents/aidlc/scripts/lib/task-runtime.mjs +97 -0
- package/dist/assets/.agents/aidlc/scripts/loop-entry.mjs +168 -73
- package/dist/assets/.agents/aidlc/scripts/loop-gate.mjs +19 -7
- package/dist/assets/.agents/aidlc/scripts/loop.cmd +101 -0
- package/dist/assets/.agents/aidlc/scripts/loop.mjs +2 -1
- package/dist/assets/.agents/aidlc/scripts/loop.sh +71 -0
- package/dist/assets/.agents/aidlc/scripts/remote-state.mjs +10 -4
- package/dist/assets/.agents/aidlc/scripts/state.mjs +16 -8
- package/dist/assets/.agents/aidlc/templates/design.md +9 -0
- package/dist/assets/.agents/aidlc/templates/intent.md +4 -0
- package/dist/assets/.agents/aidlc/templates/workplan.md +1 -1
- package/dist/assets/.agents/skills/aidlc-plan/SKILL.md +1 -1
- package/dist/assets/ui/bulma.min.css +3 -0
- package/dist/assets/ui/changes.js +83 -0
- package/dist/assets/ui/common.js +664 -0
- package/dist/assets/ui/dashboard.css +636 -0
- package/dist/assets/ui/dashboard.js +77 -0
- package/dist/assets/ui/detail.js +159 -0
- package/dist/assets/ui/live-log.js +332 -0
- package/dist/services/aidlc-coordination/Dockerfile +11 -3
- package/dist/services/aidlc-coordination/compose.yaml +12 -0
- package/dist/services/aidlc-coordination/package-lock.json +3 -1
- package/dist/services/aidlc-coordination/package.json +9 -4
- package/dist/services/aidlc-coordination/src/lifecycle-core.mjs +68 -2
- package/dist/services/aidlc-coordination/src/repository.mjs +66 -0
- package/dist/services/aidlc-coordination/src/server.mjs +9 -3
- package/dist/services/aidlc-coordination/test/fleet.test.mjs +21 -0
- package/dist/services/aidlc-coordination/test/server-health-auth.test.mjs +67 -0
- package/dist/src/adapters.d.ts +0 -3
- package/dist/src/adapters.js +3 -5
- package/dist/src/cli/argv.d.ts +12 -0
- package/dist/src/cli/argv.js +68 -0
- package/dist/src/cli/commands.d.ts +8 -0
- package/dist/src/cli/commands.js +159 -0
- package/dist/src/cli/loop-launcher.d.ts +47 -0
- package/dist/src/cli/loop-launcher.js +322 -0
- package/dist/src/cli/options.d.ts +25 -0
- package/dist/src/cli/options.js +32 -0
- package/dist/src/cli/prompt.d.ts +9 -0
- package/dist/src/cli/prompt.js +66 -0
- package/dist/src/cli.js +28 -191
- package/dist/src/gate.js +3 -2
- package/dist/src/installer.d.ts +14 -7
- package/dist/src/installer.js +42 -143
- package/dist/src/legacy.js +1 -0
- package/dist/src/managed-content.d.ts +7 -0
- package/dist/src/managed-content.js +15 -4
- package/dist/src/managed-planning.d.ts +65 -0
- package/dist/src/managed-planning.js +219 -0
- package/dist/src/mcp-setup.js +3 -1
- package/dist/src/model/config-contracts.d.ts +65 -0
- package/dist/src/model/config-contracts.js +1 -0
- package/dist/src/model/install-contracts.d.ts +29 -0
- package/dist/src/model/install-contracts.js +1 -0
- package/dist/src/model/lifecycle-enums.d.ts +13 -0
- package/dist/src/model/lifecycle-enums.js +1 -0
- package/dist/src/model/loop.d.ts +20 -0
- package/dist/src/model/loop.js +1 -0
- package/dist/src/model/manifest.d.ts +16 -0
- package/dist/src/model/manifest.js +1 -0
- package/dist/src/model/records.d.ts +142 -0
- package/dist/src/model/records.js +1 -0
- package/dist/src/model.d.ts +11 -264
- package/dist/src/model.js +1 -1
- package/dist/src/profiles.d.ts +2 -0
- package/dist/src/profiles.js +53 -9
- package/dist/src/state/archive-record.d.ts +9 -0
- package/dist/src/state/archive-record.js +26 -0
- package/dist/src/state/commands.d.ts +18 -0
- package/dist/src/state/commands.js +27 -0
- package/dist/src/state/domain.d.ts +9 -0
- package/dist/src/state/domain.js +9 -0
- package/dist/src/state/guards.d.ts +7 -0
- package/dist/src/state/guards.js +17 -0
- package/dist/src/state/io.d.ts +10 -0
- package/dist/src/state/io.js +35 -0
- package/dist/src/state/items.d.ts +3 -4
- package/dist/src/state/items.js +58 -57
- package/dist/src/state/lessons.js +14 -7
- package/dist/src/state/lifecycle.js +2 -2
- package/dist/src/state/lock.js +7 -6
- package/dist/src/state/memory.js +24 -12
- package/dist/src/state/{archive.js → migrate.js} +7 -7
- package/dist/src/state/partition.d.ts +15 -0
- package/dist/src/state/partition.js +90 -0
- package/dist/src/state/paths.d.ts +11 -0
- package/dist/src/state/paths.js +12 -0
- package/dist/src/state/render.js +9 -6
- package/dist/src/state/store.js +9 -15
- package/dist/src/state/transitions.js +9 -7
- package/dist/src/state/validate.js +55 -7
- package/dist/src/state.d.ts +16 -11
- package/dist/src/state.js +16 -11
- package/dist/src/task-ui.d.ts +33 -0
- package/dist/src/task-ui.js +33 -0
- package/dist/src/ui/assets.d.ts +14 -0
- package/dist/src/ui/assets.js +45 -0
- package/dist/src/ui/changes.d.ts +83 -0
- package/dist/src/ui/changes.js +498 -0
- package/dist/src/ui/containers.d.ts +71 -0
- package/dist/src/ui/containers.js +214 -0
- package/dist/src/ui/daemon.d.ts +75 -0
- package/dist/src/ui/daemon.js +232 -0
- package/dist/src/ui/data.d.ts +42 -0
- package/dist/src/ui/data.js +89 -0
- package/dist/src/ui/docs.d.ts +13 -0
- package/dist/src/ui/docs.js +39 -0
- package/dist/src/ui/files.d.ts +3 -0
- package/dist/src/ui/files.js +20 -0
- package/dist/src/ui/http.d.ts +14 -0
- package/dist/src/ui/http.js +80 -0
- package/dist/src/ui/live.d.ts +5 -0
- package/dist/src/ui/live.js +43 -0
- package/dist/src/ui/markdown.d.ts +2 -0
- package/dist/src/ui/markdown.js +127 -0
- package/dist/src/ui/options.d.ts +48 -0
- package/dist/src/ui/options.js +81 -0
- package/dist/src/ui/security.d.ts +34 -0
- package/dist/src/ui/security.js +38 -0
- package/dist/src/ui/server.d.ts +39 -0
- package/dist/src/ui/server.js +347 -0
- package/dist/src/ui/sse.d.ts +14 -0
- package/dist/src/ui/sse.js +281 -0
- package/dist/src/ui/views/board.d.ts +7 -0
- package/dist/src/ui/views/board.js +131 -0
- package/dist/src/ui/views/changes.d.ts +19 -0
- package/dist/src/ui/views/changes.js +154 -0
- package/dist/src/ui/views/components.d.ts +56 -0
- package/dist/src/ui/views/components.js +113 -0
- package/dist/src/ui/views/docs.d.ts +15 -0
- package/dist/src/ui/views/docs.js +64 -0
- package/dist/src/ui/views/layout.d.ts +44 -0
- package/dist/src/ui/views/layout.js +233 -0
- package/dist/src/ui/views/task.d.ts +25 -0
- package/dist/src/ui/views/task.js +320 -0
- package/dist/src/upgrade-board.js +10 -10
- package/dist/src/upgrade.d.ts +0 -1
- package/dist/src/upgrade.js +24 -85
- package/dist/src/workflow.d.ts +4 -0
- package/dist/src/workflow.js +36 -4
- package/docs/README.md +41 -22
- package/docs/architecture.md +101 -37
- package/docs/command-reference.md +289 -52
- package/docs/configuration.md +70 -30
- package/docs/coordination-service.md +91 -30
- package/docs/design-decisions.md +87 -0
- package/docs/development.md +124 -49
- package/docs/loop-local-run.md +228 -0
- package/docs/loop-runbook.md +214 -0
- package/docs/operating-workflow.md +55 -42
- package/docs/testing-and-release.md +72 -49
- package/docs/troubleshooting.md +221 -0
- package/package.json +4 -1
- package/dist/src/ledger.d.ts +0 -22
- package/dist/src/ledger.js +0 -119
- package/dist/src/state/shared.d.ts +0 -29
- package/dist/src/state/shared.js +0 -71
- package/dist/src/tracker.d.ts +0 -36
- package/dist/src/tracker.js +0 -44
- /package/dist/src/state/{archive.d.ts → migrate.d.ts} +0 -0
package/docs/configuration.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Configuration
|
|
2
2
|
|
|
3
|
-
Each installed project owns
|
|
3
|
+
Each installed project owns `.agents/config.json`: topology profiles, specification roots, verification commands, local rules, and the optional `mcp` and `loop.*` settings. CLI flags and environment variables: [Command reference](./command-reference.md); loop setup: [Loop setup runbook](./loop-runbook.md).
|
|
4
4
|
|
|
5
5
|
## Minimal configuration
|
|
6
6
|
|
|
@@ -20,32 +20,26 @@ Each installed project owns its workflow configuration at `.agents/config.json`.
|
|
|
20
20
|
}
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
Commands are
|
|
23
|
+
- Commands are executable and argument arrays, never shell strings.
|
|
24
|
+
- G0, G1, and G2 always require explicit human approval; configuration cannot auto-pass a gate.
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
## Optional `$schema` key
|
|
27
|
+
|
|
28
|
+
- `init` writes a top-level `$schema` of `./aidlc/schemas/config.schema.json` (installed under `.agents/aidlc/schemas/`); existing installs can add it by hand.
|
|
29
|
+
- Editors use it for autocompletion and validation; it has no runtime effect.
|
|
30
|
+
- Must be a string of at most 512 characters; the relative path keeps validation offline.
|
|
26
31
|
|
|
27
32
|
## Configuration layers
|
|
28
33
|
|
|
29
|
-
|
|
34
|
+
Later applicable layers take precedence:
|
|
30
35
|
|
|
31
36
|
```text
|
|
32
37
|
kernel → built-in topology → local profile parents/child → project config/rules → approved task decisions
|
|
33
38
|
```
|
|
34
39
|
|
|
35
|
-
Built-in topology profiles
|
|
36
|
-
|
|
37
|
-
- `
|
|
38
|
-
- `topology/single`
|
|
39
|
-
- `topology/workspace`
|
|
40
|
-
- `topology/git-submodules`
|
|
41
|
-
|
|
42
|
-
Arrays are stable-deduplicated. Command keys are last-wins, so a project can replace a profile command intentionally. Validate the resolved profile chain with:
|
|
43
|
-
|
|
44
|
-
```sh
|
|
45
|
-
npx --package @felixdotgo/aidlc-kit@0.1.1 aidlc-kit profile validate .
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
This command uses the npm package at version `0.1.1`. To run from a source checkout instead, see the [development guide](./development.md).
|
|
40
|
+
- Built-in topology profiles: `topology/generic`, `topology/single`, `topology/workspace`, `topology/git-submodules`.
|
|
41
|
+
- Arrays are stable-deduplicated; command keys are last-wins, so a project can replace a profile command.
|
|
42
|
+
- Validate the resolved chain with `npx --package @felixdotgo/aidlc-kit@0.3.0 aidlc-kit profile validate .` (source checkout: [development guide](./development.md)).
|
|
49
43
|
|
|
50
44
|
## Rules, project data, and managed assets
|
|
51
45
|
|
|
@@ -55,40 +49,86 @@ This command uses the npm package at version `0.1.1`. To run from a source check
|
|
|
55
49
|
| `.agents/data/` | Project owned | Lifecycle state, task artifacts, indexes, memory, and evidence. |
|
|
56
50
|
| `.agents/project/` | Project owned | Profiles, rules, and project-specific evaluation material. |
|
|
57
51
|
|
|
58
|
-
Keep business/domain rules in `.agents/project/rules/`.
|
|
52
|
+
Keep business/domain rules in `.agents/project/rules/`. Never edit managed kernel files; a later install or upgrade may report conflicts for modified managed content.
|
|
59
53
|
|
|
60
54
|
## Agent permissions
|
|
61
55
|
|
|
62
|
-
|
|
56
|
+
Each adapter grants only what the lifecycle needs; general commands stay unapproved.
|
|
63
57
|
|
|
64
|
-
|
|
58
|
+
| Adapter | Installed files | What is allowed | Notes |
|
|
59
|
+
| --- | --- | --- | --- |
|
|
60
|
+
| Codex | A managed block in `AGENTS.md`, `.codex/config.toml` (`approval_policy = "on-request"`, `sandbox_mode = "workspace-write"`), and `.codex/rules/aidlc.rules` | The execpolicy allowlists only the seven lifecycle entry points under `node .agents/aidlc/scripts/` (`state`, `task-next`, `context`, `gate-check`, `gate-view`, `render`, `assignment`). | Loaded only after the user trusts the project; network access stays disabled unless the project enables it. |
|
|
61
|
+
| Claude Code | A managed block in `CLAUDE.md`, `.claude/settings.local.json`, and phase skills | Only `node .agents/aidlc/scripts/*`. | Other Bash commands stay unapproved. |
|
|
62
|
+
| OpenCode | An owner-scoped managed block in `AGENTS.md` only | Nothing: no OpenCode configuration, MCP, or permission file is written. | Reads `.opencode/` only to detect the adapter; OpenCode settings are never overridden. |
|
|
65
63
|
|
|
66
|
-
|
|
64
|
+
- Codex allowlist rule: run each lifecycle command as its own exec invocation. Commands joined with `&`, `&&`, `;`, or `|` create shell segments that a single prefix rule does not cover.
|
|
65
|
+
- Codex and OpenCode blocks are independently owned and merge in the same `AGENTS.md` when both are installed.
|
|
66
|
+
- `init --force --yes` is only for an intentional initial install that replaces an unmanaged conflicting file, never an upgrade ([Command reference](./command-reference.md#init)).
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
## Context and risk
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
- `context.maxChars` bounds a phase packet. The runtime preserves lifecycle instructions, approved decisions, and mandatory invariants, and fails clearly rather than silently truncating them.
|
|
71
|
+
- Set `risk.default` deliberately: planning, migrations, cross-service contracts, and security-sensitive changes deserve a stronger reviewer or an explicit human decision even at `normal`.
|
|
71
72
|
|
|
72
73
|
## Optional AI-DLC Coordination
|
|
73
74
|
|
|
74
|
-
`mcp` is absent (or `{ "enabled": false }`) by default.
|
|
75
|
+
`mcp` is absent (or `{ "enabled": false }`) by default. Enabled, it requires an HTTP(S) `endpoint` and non-empty `workspace`, and may name a token environment variable, a polling interval from 1,000 to 3,600,000 ms, and the enabled Jira/Trello/GitHub Issues preflight providers. Experimental ([Status and stability](./loop-runbook.md#status-and-stability)); contract in [AI-DLC Coordination service](./coordination-service.md).
|
|
75
76
|
|
|
76
77
|
## Optional loop configuration
|
|
77
78
|
|
|
78
79
|
> [!WARNING]
|
|
79
|
-
>
|
|
80
|
+
> Experimental, pre-1.0. See [Status and stability](./loop-runbook.md#status-and-stability).
|
|
80
81
|
|
|
81
|
-
`loop
|
|
82
|
+
The `loop` object selects the loop mode, agents, and limits, set through `init`, the human-run upgrade preview, or a deliberate edit. It installs and starts nothing, authorizes no upgrade, grants no gate approval, and holds no provider credentials.
|
|
82
83
|
|
|
83
84
|
```json
|
|
84
85
|
{
|
|
85
86
|
"loop": {
|
|
86
87
|
"mode": "local",
|
|
87
|
-
"agents": { "lead": "codex", "workers": { "worker-a": "codex", "worker-b": "opencode" } }
|
|
88
|
+
"agents": { "lead": "codex", "workers": { "worker-a": "codex", "worker-b": "opencode" } },
|
|
89
|
+
"pollMs": 5000,
|
|
90
|
+
"limits": { "maxTurns": 12, "turnTimeoutMs": 600000, "maxStallTurns": 2 }
|
|
88
91
|
}
|
|
89
92
|
}
|
|
90
93
|
```
|
|
91
94
|
|
|
92
|
-
|
|
95
|
+
### Mode and agents
|
|
96
|
+
|
|
97
|
+
- `loop.mode` is `off`, `local`, or `fleet`; an absent `loop` means `off`. Selecting a mode starts nothing: run `./.agents/aidlc/scripts/loop.sh up` (or `aidlc-kit loop start`).
|
|
98
|
+
- Both enabled modes run one lock-enforced multi-task daemon per project. It polls its authority — canonical local state, or the coordination service in `fleet` mode — and auto-picks every actionable **loop-owned** task without prompting for a requirement.
|
|
99
|
+
- A task is loop-owned when created through loop intake (dashboard **New task**, `aidlc-kit loop intake`, `loop-entry.mjs intake`) or, locally, when it has a loop run record; fleet ownership is `.agents/data/tasks/<id>/runtime/intake.json` with `authority: "fleet"`. Interactive-lead tasks are never picked up.
|
|
100
|
+
- `loop.agents` maps one lead and named workers to `codex`, `claude`, or `opencode`, independently of `mcp.providers`.
|
|
101
|
+
|
|
102
|
+
### Polling and limits
|
|
103
|
+
|
|
104
|
+
| Field | Range | Default | Meaning |
|
|
105
|
+
| --- | --- | --- | --- |
|
|
106
|
+
| `loop.pollMs` | integer `1000`–`300000` | `5000` | Daemon poll interval. |
|
|
107
|
+
| `loop.limits.maxTurns` | `1`–`1000` | `12` | Turn budget of **one supervised lead run**; a resumed run starts a fresh budget. |
|
|
108
|
+
| `loop.limits.turnTimeoutMs` | `1`–`3600000` | `600000` | Caps a single agent turn. |
|
|
109
|
+
| `loop.limits.maxStallTurns` | `1`–`20` | `2` | Pauses after that many consecutive turns without observable progress. |
|
|
110
|
+
|
|
111
|
+
In `fleet` mode these become `AIDLC_FLEET_MAX_TURNS`, `AIDLC_FLEET_TURN_TIMEOUT_MS`, `AIDLC_FLEET_MAX_STALL_TURNS`, and `AIDLC_FLEET_POLL_MS`; an exported value overrides the config.
|
|
112
|
+
|
|
113
|
+
### Worker image
|
|
114
|
+
|
|
115
|
+
`loop.workerImage` maps a provider to a worker Docker image tag (for example `{ "opencode": "aidlc-worker-opencode:local" }`), recorded by `aidlc-kit loop worker-image`. Local dispatch and fleet workers fall back to `aidlc-worker-<provider>:local`, auto-built from the packaged Dockerfile when missing; `AIDLC_WORKER_DOCKER_IMAGE` overrides it.
|
|
116
|
+
|
|
117
|
+
### Provider credentials and OpenCode
|
|
118
|
+
|
|
119
|
+
Provider credentials go in the git-ignored `.agents/loop.env` (or the shell), never in this file; env-file and auto-detection rules are in [Command reference](./command-reference.md#loop).
|
|
120
|
+
|
|
121
|
+
- Any `opencode` provider needs `AIDLC_OPENCODE_MODEL` as `provider/model[#variant]` (for example `opencode-go/gpt-6-luna`) in `.agents/loop.env`, the shell, or `"model"` in `opencode.json` (detected locally). Without a valid value the provider turn fails closed and `loop start`/`loop up` stop before the daemon starts.
|
|
122
|
+
- **Isolated lead.** Rejects OpenCode with `OpenCode workers require file-based credentials and are not available in isolated containers yet`; no host fallback.
|
|
123
|
+
- **Docker workers.** Local worker batches and fleet worker containers accept OpenCode, authenticating from the key matching the model prefix (`openai/` → `OPENAI_API_KEY`, `anthropic/` → `ANTHROPIC_API_KEY`, otherwise `OPENCODE_API_KEY`) and redirecting OpenCode's XDG data/config roots into the worker's ephemeral HOME.
|
|
124
|
+
|
|
125
|
+
### Parallel work partition
|
|
126
|
+
|
|
127
|
+
With `loop.mode` `local` or `fleet`, the Approve plan gate check requires owned paths on every open build item (`PARTITION_SCOPE`) and no overlapping paths between items that can run concurrently (`PARTITION_OVERLAP`). With the loop `off` both are warnings and the gate passes; see [Troubleshooting](./troubleshooting.md#parallel-work-partition-partition_overlap--partition_scope).
|
|
128
|
+
|
|
129
|
+
## Related
|
|
93
130
|
|
|
94
|
-
|
|
131
|
+
- [Loop setup runbook](./loop-runbook.md) — loop setup.
|
|
132
|
+
- [Command reference](./command-reference.md#loop) — loop actions and environment.
|
|
133
|
+
- [AI-DLC Coordination service](./coordination-service.md) — fleet operations.
|
|
134
|
+
- [Operating the workflow](./operating-workflow.md) — lifecycle and gates.
|
|
@@ -1,52 +1,72 @@
|
|
|
1
1
|
# AI-DLC Coordination service
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
> The coordination service (and the end-to-end loop that builds on it) is **experimental and unfinished**: it contains known bugs and rough edges. The package is pre-1.0 (`0.x`), so setup flags, `mcp.*`/`loop.*` configuration, endpoints, environment variables, and storage behaviour can change incompatibly in any release before `1.0.0`. Do not treat it as a stable dependency yet.
|
|
3
|
+
The optional, Docker-deployable authority for a workflow workspace: remote canonical state for a team, or the fleet loop across machines ([runbook](./loop-runbook.md#fleet-multi-machine)). Disabled by default: without an enabled `mcp` block, installed lifecycle scripts stay local and make no network calls.
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
> [!WARNING]
|
|
6
|
+
> Experimental, pre-1.0. See [Status and stability](./loop-runbook.md#status-and-stability).
|
|
7
7
|
|
|
8
8
|
## Safe setup
|
|
9
9
|
|
|
10
|
-
Preview
|
|
10
|
+
Preview first; outside an interactive terminal, provide all four selection flags:
|
|
11
11
|
|
|
12
12
|
```sh
|
|
13
|
-
npx --package @felixdotgo/aidlc-kit@0.
|
|
13
|
+
npx --package @felixdotgo/aidlc-kit@0.3.0 aidlc-kit mcp setup . --dry-run \
|
|
14
14
|
--deployment docker --storage sqlite --bind localhost --workspace engineering
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Remove `--dry-run` and confirm to create `.agents/aidlc-coordination/` and update `.agents/config.json`. Setup does not start Docker. Copy `.env.example` to a secret-managed `.env`, review it, then start explicitly:
|
|
17
|
+
Remove `--dry-run` and confirm to create `.agents/aidlc-coordination/` and update `.agents/config.json`. Setup does not start Docker. Copy `.env.example` to a secret-managed `.env`, review it, then start:
|
|
20
18
|
|
|
21
19
|
```sh
|
|
22
20
|
docker compose --env-file .agents/aidlc-coordination/.env -f .agents/aidlc-coordination/compose.yaml up -d
|
|
23
21
|
```
|
|
24
22
|
|
|
25
|
-
|
|
23
|
+
- SQLite only on the local Docker volume; PostgreSQL for multiple hosts.
|
|
24
|
+
- A network bind requires `MCP_STATE_AUTH_TOKEN` and TLS/reverse-proxy termination. Never commit `.env` or provider credentials.
|
|
25
|
+
- Source checkout: [development guide](./development.md).
|
|
26
26
|
|
|
27
27
|
## State and synchronization contract
|
|
28
28
|
|
|
29
|
-
When enabled, the remote workspace is canonical. Import/export is an explicit recovery or migration action; there is no background dual-write or local fallback during an outage.
|
|
29
|
+
- When enabled, the remote workspace is canonical. Import/export is an explicit recovery or migration action; there is no background dual-write or local fallback during an outage.
|
|
30
|
+
- Clients pull a revision or poll `state_events_since`; there are no realtime subscriptions or push notifications.
|
|
30
31
|
|
|
31
32
|
## Multi-machine loop deployment
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
Storage backends, with no implicit fallback or migration between them (never switch an existing authority automatically):
|
|
35
|
+
|
|
36
|
+
- **SQLite**: one service on one host, database on a local volume (`MCP_STATE_DATABASE=sqlite`, the default, plus `MCP_STATE_SQLITE_PATH`). Availability and write concurrency are limited to that host.
|
|
37
|
+
- **PostgreSQL**: multiple hosts or service instances.
|
|
34
38
|
|
|
35
|
-
Fleet mode is separate
|
|
39
|
+
Fleet mode is a separate compose profile. The source checkout keeps the template in `services/aidlc-coordination/`; human-run `mcp setup` copies it to `.agents/aidlc-coordination/`. Copy `.env.fleet.example` to a private `.env`, set the database and three distinct credential classes (`MCP_FLEET_LEAD_TOKEN`, `MCP_FLEET_REVIEWER_TOKEN`, and the worker-ID-to-token JSON map `MCP_FLEET_WORKER_TOKENS`), then start:
|
|
36
40
|
|
|
37
41
|
```sh
|
|
38
42
|
docker compose --env-file .env --profile fleet -f services/aidlc-coordination/compose.yaml up -d fleet-coordination
|
|
43
|
+
# installed project: -f .agents/aidlc-coordination/compose.yaml
|
|
39
44
|
```
|
|
40
45
|
|
|
41
|
-
|
|
46
|
+
- Default binding `127.0.0.1:8788`; for workers on other machines, expose `POST /mcp` through a TLS reverse proxy and set the binding deliberately.
|
|
47
|
+
- Requires the chosen database backend and a shared Git remote. Each worker gets an isolated worktree, a scoped branch, and its own credential.
|
|
48
|
+
- A process supervisor must restart the supervisor, lead, and workers; after restart they reacquire fenced leases and reconcile reported or uncertain Git results before retrying.
|
|
49
|
+
|
|
50
|
+
**Vocabulary.** Three kinds of fenced ownership, each with its own epoch counter:
|
|
51
|
+
|
|
52
|
+
- **supervisor lease** (`supervisor_*`): one `loop start` supervising a task;
|
|
53
|
+
- **lead lease** (`run_claim`): the lead epoch every lifecycle mutation must present;
|
|
54
|
+
- **job claims** (`job_*`): a worker's ownership of one item, with a job epoch.
|
|
55
|
+
|
|
56
|
+
`aidlc-kit loop leases` shows the supervisor epoch only when it differs from the lead epoch. A `FleetConflict` (for example `stale or expired lead claim`) is reported as `Fleet conflict: <explanation>. Inspect: node .agents/aidlc/scripts/loop-entry.mjs leases (<original message>)`. Local leases: [Troubleshooting](./troubleshooting.md#loop-leases-locks-and-claims).
|
|
57
|
+
|
|
58
|
+
**Roles.**
|
|
42
59
|
|
|
43
|
-
|
|
60
|
+
- Lead credential: advances lifecycle state only while holding the current task epoch.
|
|
61
|
+
- Worker credentials: claim, checkpoint, and report assigned jobs; never mutate lifecycle state or approve gates.
|
|
62
|
+
- Reviewer credential: reads pending gate snapshots and records a later explicit human approval against the snapshot and current revision.
|
|
63
|
+
- When the database, Git remote, or reviewer is unavailable, the run waits or fails closed; never a local fallback.
|
|
44
64
|
|
|
45
|
-
The
|
|
65
|
+
The remote lifecycle client needs `AIDLC_FLEET_URL` (full HTTPS `/mcp` URL), `AIDLC_FLEET_WORKSPACE`, and `AIDLC_FLEET_PROJECT_ROOT` (absolute); lead mutations also `AIDLC_FLEET_TOKEN` and the current `AIDLC_FLEET_LEAD_EPOCH` from its claim.
|
|
46
66
|
|
|
47
|
-
|
|
67
|
+
### Create tasks and a feature manifest
|
|
48
68
|
|
|
49
|
-
Create
|
|
69
|
+
Create task records before the manifest: claim a lead epoch, export it, create the task with the feature ID, release; repeat per task; then create and link the manifest:
|
|
50
70
|
|
|
51
71
|
```sh
|
|
52
72
|
node .agents/aidlc/scripts/remote-state.mjs run claim checkout-api
|
|
@@ -59,40 +79,81 @@ node .agents/aidlc/scripts/remote-state.mjs feature link checkout checkout-integ
|
|
|
59
79
|
node .agents/aidlc/scripts/remote-state.mjs feature ready checkout
|
|
60
80
|
```
|
|
61
81
|
|
|
62
|
-
|
|
82
|
+
Every manifest member must have a canonical task record with the matching feature ID; a partially created task stays fail-closed until the manifest is complete. The lead epoch is task-specific; refresh it after release or expiry.
|
|
63
83
|
|
|
64
|
-
|
|
84
|
+
### Approve gates as the reviewer
|
|
85
|
+
|
|
86
|
+
In a connected reviewer conversation with `AIDLC_FLEET_REVIEWER_TOKEN`, inspect the pending packet; only after the human approves it, run:
|
|
65
87
|
|
|
66
88
|
```sh
|
|
67
89
|
node .agents/aidlc/scripts/remote-state.mjs gate inbox
|
|
68
90
|
node .agents/aidlc/scripts/remote-state.mjs gate approve <task-id> --snapshot <snapshot-id> --source "<explicit user approval>"
|
|
69
91
|
```
|
|
70
92
|
|
|
71
|
-
|
|
93
|
+
- `gate approve` checks the snapshot is still current and uses the reviewer-only operation; at G2 it also verifies the snapshot's integration commit matches the live remote branch (protect that branch against writes outside the lead).
|
|
94
|
+
- `--source` is the review message as provenance; the token authenticates the client, and the operator is responsible for using the user's actual reply.
|
|
95
|
+
|
|
96
|
+
### Run the fleet processes
|
|
72
97
|
|
|
73
|
-
Run the packaged fleet process on
|
|
98
|
+
Run the packaged fleet process on the lead and each worker machine under a process supervisor, same `AIDLC_FLEET_URL` and workspace, own role token each. Environment variables: runbook [lead](./loop-runbook.md#step-2--set-lead-machine-environment) and [worker](./loop-runbook.md#step-4--run-a-worker-on-each-worker-machine) tables; `AIDLC_FLEET_AGENT` selects the lead provider for the direct runner (default `codex`; `aidlc-kit loop` sets it from `loop.agents.lead`) and is the per-worker fallback; `AIDLC_FLEET_WORKER_PROVIDERS` overrides it per worker. `job_schedule` accepts `codex`, `claude`, or `opencode`; worker containers run all three, only the isolated lead container does not support OpenCode ([credentials](./configuration.md#provider-credentials-and-opencode)). The worker image is resolved to its immutable `sha256:` id before any job runs.
|
|
74
99
|
|
|
75
100
|
```sh
|
|
76
101
|
node dist/services/aidlc-coordination/src/fleet-run.mjs feature <feature-id>
|
|
77
102
|
node dist/services/aidlc-coordination/src/fleet-run.mjs worker
|
|
103
|
+
# installed project: node .agents/aidlc-coordination/src/fleet-run.mjs …
|
|
78
104
|
```
|
|
79
105
|
|
|
80
|
-
`coordinator <task-id>` runs one task
|
|
106
|
+
- `coordinator <task-id>` runs one task; `--once` runs a bounded polling pass.
|
|
107
|
+
- Defaults: four worker jobs per feature, five-minute leases with one-minute heartbeat, 12 turns per phase or assignment, 10 minutes per turn, two consecutive stalls. Override: `AIDLC_FLEET_MAX_WORKERS`, `AIDLC_FLEET_LEASE_MS`, `AIDLC_FLEET_HEARTBEAT_MS`, `AIDLC_FLEET_MAX_TURNS`, `AIDLC_FLEET_TURN_TIMEOUT_MS`, `AIDLC_FLEET_MAX_STALL_TURNS`.
|
|
108
|
+
- Feature mode dispatches dependency-ready tasks in order from one integration checkout; independent items of the active task can run on several machines.
|
|
109
|
+
- The coordinator never dispatches two items whose owned paths overlap by path segment (`src` overlaps `src/a.ts`, not `srcx`); the later item waits. With `MCP_FLEET_ENABLED=1` the service also refuses to approve the Approve plan gate for such overlaps or unscoped open items (`PARTITION_OVERLAP`, `PARTITION_SCOPE`).
|
|
110
|
+
- After a lost worker report the lead checks remote Git state and stops for reconciliation if ambiguous. `AIDLC_FLEET_CODE_ONLY_RETRY=1` permits an automatic retry only after the prior turn's timeout window elapsed and Git confirms no branch was published.
|
|
111
|
+
- The coordinator and feature commands return at a human gate (feature mode dispatches no further tasks); restart after the reviewer acts.
|
|
112
|
+
- Command events and failure diagnostics report status and exit code, never command text or output. Worker progress observes file content changes as well as paths.
|
|
81
113
|
|
|
82
|
-
|
|
114
|
+
### Unattended operation with the loop daemon
|
|
115
|
+
|
|
116
|
+
`aidlc-kit loop start --mode fleet` on the lead machine replaces a hand-run supervisor: it runs each fleet loop-owned task until its next gate, releases the supervisor lease, and re-claims after reviewer approval. It takes `loop.limits` and `loop.pollMs` as defaults for the `AIDLC_FLEET_*` limits and never passes `AIDLC_FLEET_REVIEWER_TOKEN` to a lead or worker process. Steps: [loop runbook](./loop-runbook.md#fleet-multi-machine). On the lead machine the task's event history, run record, and intake files live under `.agents/data/tasks/<task-id>/runtime/` exactly as in local mode; worker machines write only `runtime/workers/` there. Claims are service-side, so no `assignments.json` exists in fleet mode.
|
|
83
117
|
|
|
84
118
|
## Shared coordination board
|
|
85
119
|
|
|
86
|
-
|
|
120
|
+
A small workspace-scoped Kanban board, separate from lifecycle state. Board tasks may link to an AI-DLC task ID or artifact, but board writes, comments, and claims cannot mutate lifecycle state, approve a gate, or rewrite project files.
|
|
121
|
+
|
|
122
|
+
- Bounded MCP tools: `board_get`, `board_apply`, `task_thread_get`, `task_comment_add`, `task_claim`, `coordination_events_since`.
|
|
123
|
+
- Status `backlog`, `ready`, `in_progress`, `blocked`, `done`, or `cancelled`, plus priority, labels, assignees, and renewable one-minute-to-one-hour claims.
|
|
124
|
+
- Mutations require an expected board revision, idempotency key, actor ID, and role; a conflicting live claim is rejected.
|
|
125
|
+
- Threads: short append-only comments with author type, optional mentions, and `question`, `status`, `handoff`, or `decision` intent; never credentials, hidden reasoning, chat, or gate approvals.
|
|
126
|
+
- Clients poll compact cursor events, coalesce them, and read details only for assignment, mention, watched-task, explicit-user, or claim-expiry activity, always after a fresh revision check.
|
|
127
|
+
|
|
128
|
+
### `state_apply` contract
|
|
129
|
+
|
|
130
|
+
- Every write needs an `expectedRevision`, an `idempotencyKey`, and an absolute `clientProjectRoot`. The root only formats portable `nextActions` (absolute script paths, explicit `--root`); it grants no filesystem access or authority.
|
|
131
|
+
- A stale revision returns the current projection for pull/rebase; a retry with the same idempotency key returns the original committed result.
|
|
132
|
+
- Responses include `nextActions` for touched tasks, so remote callers follow the same item loop and stop classifications as the local CLI.
|
|
133
|
+
- SQLite uses an immediate transaction and busy timeout; PostgreSQL locks the workspace row in a transaction.
|
|
134
|
+
|
|
135
|
+
Lifecycle invariants are checked across the whole before/after snapshot, not only touched task IDs:
|
|
136
|
+
|
|
137
|
+
- Evidence is append-only: the prior evidence array must remain an exact structural prefix (field-wise; key order is free, record order is not).
|
|
138
|
+
- A validated `blocked_on_user` wait cannot be deleted; while a task waits, every non-evidence field (items, decisions, artifacts, …) is frozen.
|
|
139
|
+
- Leaving a wait requires, in the same mutation, one of: a passing approval for that exact gate; gate-bound cancellation evidence with a non-empty source; or a sourced closure/handoff record (`closed`/`superseded` with closure metadata, `paused` with handoff metadata). One compatibility recovery mirrors the local CLI: an invalid wait at the gateless wrap phase may return to `active` with no appended evidence; it is not a human approval.
|
|
140
|
+
- A snapshot that requests or holds `blocked_on_user` while shared predicates still require planning, items, verification, review, or an unexhausted repair bound is rejected.
|
|
141
|
+
- The `legacyG2Wait` repair-bound exemption marker is migration-owned: stamped only when upgrading a stored pre-v4 row; client mutations creating or changing it are rejected.
|
|
87
142
|
|
|
88
|
-
|
|
143
|
+
In default shared-token mode these guards keep history tamper-evident but do not authenticate approvals: `source` is client-supplied provenance. Fleet mode binds lead, worker, and reviewer credentials to server-side roles; only a reviewer credential can call the atomic gate approval tool. The service cannot inspect client artifacts: the lead runs local artifact checks before publishing a review snapshot; the service enforces structural gate readiness and snapshot revision at approval.
|
|
89
144
|
|
|
90
|
-
|
|
145
|
+
`work_item_request` is only a credential-free preflight for Jira, Trello, or GitHub Issues: it reports the required environment variable names and never returns a reusable token, Authorization header, or token-bearing URL. External updates are opt-in, outside the lifecycle transaction.
|
|
91
146
|
|
|
92
|
-
|
|
147
|
+
## Service health, logging, and image
|
|
93
148
|
|
|
94
|
-
|
|
149
|
+
- `GET /healthz`: unauthenticated, static `200 {"ok":true}`, reads no state, version, or workspace data; registered before the auth middleware; used by the container `HEALTHCHECK` and compose healthchecks.
|
|
150
|
+
- Each request logs one JSON line to stderr: `{"ts":...,"method":...,"path":...,"status":...,"principal":...,"ms":...}` (`principal` omitted when absent). Never headers, bodies, or tokens.
|
|
151
|
+
- McpServer version: the `version` field of the `package.json` next to the service root (`new URL("../package.json", import.meta.url)`), fallback `"0.0.0-dev"` (source checkouts); the bundled image gets it by build-time injection.
|
|
152
|
+
- Image: two stages, both `node:24-bookworm-slim` (matching `better-sqlite3` ABI), non-root `node` user, `HEALTHCHECK` against `/healthz`; the compose `aidlc-coordination` and `fleet-coordination` services define matching healthchecks.
|
|
95
153
|
|
|
96
|
-
|
|
154
|
+
## Related
|
|
97
155
|
|
|
98
|
-
|
|
156
|
+
- [Loop setup runbook](./loop-runbook.md#fleet-multi-machine) — step-by-step fleet loop setup.
|
|
157
|
+
- [Configuration](./configuration.md) — the `mcp` and `loop` config blocks.
|
|
158
|
+
- [Command reference](./command-reference.md) — `mcp setup`, `loop`, and environment variables.
|
|
159
|
+
- [Troubleshooting](./troubleshooting.md#loop-leases-locks-and-claims) — leases, claims, and fleet conflicts.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Design decisions (ADR-lite)
|
|
2
|
+
|
|
3
|
+
Numbered decisions that constrain future changes across modules or releases (runtime boundaries, state formats, safety policies). Local implementation choices belong in code comments or the originating task.
|
|
4
|
+
|
|
5
|
+
## D1. Dual lifecycle cores with conformance instead of codegen
|
|
6
|
+
|
|
7
|
+
- **Context:** Installed projects need dependency-free lifecycle scripts; the package CLI is TypeScript.
|
|
8
|
+
- **Decision:** Two cores: `src/state.ts` (TypeScript) and `assets/aidlc/scripts/lib/store.mjs` (dependency-free ESM), plus a committed byte-identical copy in `services/aidlc-coordination/src/lifecycle-core.mjs`.
|
|
9
|
+
- **Consequences:** Parity is checked by `lifecycle-core-conformance` (byte identity + property/fuzz), not generated; a core change requires `npm run sync-core` and those tests.
|
|
10
|
+
|
|
11
|
+
## D2. Single JSON state with file lock and archive catalog
|
|
12
|
+
|
|
13
|
+
- **Context:** Local-first; no registry or database in consumer projects.
|
|
14
|
+
- **Decision:** One JSON file (`.agents/data/state/aidlc-state.json`) serialized by a file lock (`.aidlc-state.lock` + guard); terminal records archived under `.agents/data/state/backups/`, digest-verified.
|
|
15
|
+
- **Consequences:** Simple backup, restore, and git diffing; contention is bounded by the 5s/30s lock defaults; unsuited to high-concurrency multi-writer workloads.
|
|
16
|
+
|
|
17
|
+
## D3. Append-only evidence with append-order boundaries
|
|
18
|
+
|
|
19
|
+
- **Context:** Verification and review outcomes must stay auditable and never be rewritten.
|
|
20
|
+
- **Decision:** Evidence is append-only; current-build boundaries follow append order, not wall-clock timestamps.
|
|
21
|
+
- **Consequences:** Re-running a check appends; "latest" means latest appended. Tampering requires rewriting the whole state file, detectable via lock and digest checks.
|
|
22
|
+
|
|
23
|
+
## D4. Human-only upgrades
|
|
24
|
+
|
|
25
|
+
- **Context:** Upgrades touch managed assets and state; automated upgrades risk data loss.
|
|
26
|
+
- **Decision:** `upgrade` rejects `--yes`/`--force`, requires an interactive TTY, and asks the human to type the target version; no background checks or postinstall.
|
|
27
|
+
- **Consequences:** Upgrades are auditable and intentional; CI cannot auto-upgrade; rollback uses the upgrade journal.
|
|
28
|
+
|
|
29
|
+
## D5. Local-first / no-registry policy
|
|
30
|
+
|
|
31
|
+
- **Context:** Consumer projects must work offline; status/doctor must not phone home.
|
|
32
|
+
- **Decision:** `remoteUpdates: false` by default; status and doctor never consult a registry; fleet is opt-in and separately deployed.
|
|
33
|
+
- **Consequences:** No surprise network calls; version drift is detected locally; fleet authority is explicit via `AIDLC_FLEET_URL`.
|
|
34
|
+
|
|
35
|
+
## D6. Compact code style in the installed kernel
|
|
36
|
+
|
|
37
|
+
- **Context:** Installed scripts must fit the 16,000-character phase-packet budget.
|
|
38
|
+
- **Decision:** The installed kernel uses compact style; package and service code do not.
|
|
39
|
+
- **Consequences:** Two style regimes; never "pretty-print" installed scripts in ways that bloat packets; mandatory sections are never truncated.
|
|
40
|
+
|
|
41
|
+
## D7. Machine-enforced repair bounds
|
|
42
|
+
|
|
43
|
+
- **Context:** Repair loops need a hard stop.
|
|
44
|
+
- **Decision:** Three failed verify records per affected area, or two failed review records, in the current build flip `nextAction` to `blocked` and add a `REPAIR_BOUND` error to the Review implementation gate check.
|
|
45
|
+
- **Consequences:** No self-approval past the bound; a durable handoff is required. Legacy G2 waits migrated by schema v4 are exempt once.
|
|
46
|
+
|
|
47
|
+
## D8. Assignment records are operational metadata
|
|
48
|
+
|
|
49
|
+
- **Context:** Worker assignment state must not become a second lifecycle authority.
|
|
50
|
+
- **Decision:** Assignment records (`.agents/data/tasks/<id>/runtime/assignments.json`) are operational metadata; canonical task state is the authority.
|
|
51
|
+
- **Consequences:** Assignment corruption or loss does not invalidate the task; `assignment.mjs reconcile` is required before dispatch.
|
|
52
|
+
|
|
53
|
+
## D9. Configured commands as executable + args arrays
|
|
54
|
+
|
|
55
|
+
- **Context:** Shell strings are unsafe and non-portable.
|
|
56
|
+
- **Decision:** Project-configured commands are stored and executed as executable + args arrays; shell strings are rejected.
|
|
57
|
+
- **Consequences:** No shell injection; explicit invocation; predictable cross-platform behaviour.
|
|
58
|
+
|
|
59
|
+
## D10. Task language `vi` / `en`
|
|
60
|
+
|
|
61
|
+
- **Context:** Artifacts and prompts need a declared language; broader i18n is not justified yet.
|
|
62
|
+
- **Decision:** Task language is `vi` or `en`; further extensibility is deferred.
|
|
63
|
+
- **Consequences:** New languages need a schema and conformance change; existing tasks keep their declared language.
|
|
64
|
+
|
|
65
|
+
## D11. Optional `$schema` reference in generated config
|
|
66
|
+
|
|
67
|
+
- **Context:** Offline-first tooling needs schema validation without network.
|
|
68
|
+
- **Decision:** Generated config may include an optional relative `$schema` reference to the local schema.
|
|
69
|
+
- **Consequences:** Editors validate offline; a missing reference degrades gracefully.
|
|
70
|
+
|
|
71
|
+
## D12. Timing-safe comparison for all coordination auth
|
|
72
|
+
|
|
73
|
+
- **Context:** Non-fleet coordination endpoints must not leak tokens via timing.
|
|
74
|
+
- **Decision:** Non-fleet coordination auth uses the same timing-safe comparison as the fleet path.
|
|
75
|
+
- **Consequences:** One auth implementation; no fast-path bypass; consistent with the service's credential model.
|
|
76
|
+
|
|
77
|
+
## How to add a decision
|
|
78
|
+
|
|
79
|
+
1. Record it in canonical state via `decision set`, tracked with its task.
|
|
80
|
+
2. Cite the source (file, PR, or task id) and present it at Approve plan (G1).
|
|
81
|
+
3. Append a numbered Context / Decision / Consequences entry here; link from [Architecture](./architecture.md) when it changes a boundary.
|
|
82
|
+
|
|
83
|
+
## Related
|
|
84
|
+
|
|
85
|
+
- [Architecture](./architecture.md)
|
|
86
|
+
- [Development guide](./development.md)
|
|
87
|
+
- [Testing and release](./testing-and-release.md)
|