@felixdotgo/aidlc-kit 0.0.1 → 0.1.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 +1 -1
- package/README.md +5 -4
- package/dist/assets/.agents/aidlc/conventions.md +8 -8
- package/dist/assets/.agents/aidlc/orchestrator.md +15 -10
- package/dist/assets/.agents/aidlc/phase-build.md +7 -7
- package/dist/assets/.agents/aidlc/phase-clarify.md +3 -3
- package/dist/assets/.agents/aidlc/phase-plan.md +6 -6
- package/dist/assets/.agents/aidlc/phase-wrap.md +1 -1
- package/dist/assets/.agents/aidlc/scripts/assignment.mjs +36 -0
- package/dist/assets/.agents/aidlc/scripts/context.mjs +2 -0
- package/dist/assets/.agents/aidlc/scripts/gate-check.mjs +2 -0
- package/dist/assets/.agents/aidlc/scripts/gate-view.mjs +2 -0
- package/dist/assets/.agents/aidlc/scripts/lib/assignment-store.mjs +181 -0
- package/dist/assets/.agents/aidlc/scripts/lib/authority.mjs +3 -0
- package/dist/assets/.agents/aidlc/scripts/lib/context-runtime.mjs +8 -1
- package/dist/assets/.agents/aidlc/scripts/lib/feature-store.mjs +70 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-drivers.mjs +215 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet-cli.mjs +183 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet-remote.mjs +100 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet-supervisor.mjs +58 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-fleet.mjs +314 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-git.mjs +279 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-intake.mjs +51 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-lead-artifacts.mjs +63 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-lead-broker.mjs +53 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-lead-local-broker.mjs +44 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-lead-sandbox.mjs +88 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-lease.mjs +89 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-local-gate-receipt.mjs +32 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-local-workers.mjs +161 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-planner.mjs +13 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-runtime.mjs +254 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-supervisor-local.mjs +131 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-supervisor-run-local.mjs +55 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-supervisor.mjs +101 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-worker-docker.mjs +32 -0
- package/dist/assets/.agents/aidlc/scripts/lib/loop-worker-snapshot.mjs +65 -0
- package/dist/assets/.agents/aidlc/scripts/lib/remote-state-client.mjs +112 -0
- package/dist/assets/.agents/aidlc/scripts/lib/store.mjs +39 -4
- package/dist/assets/.agents/aidlc/scripts/loop-entry.mjs +90 -0
- package/dist/assets/.agents/aidlc/scripts/loop-gate.mjs +58 -0
- package/dist/assets/.agents/aidlc/scripts/loop.mjs +36 -0
- package/dist/assets/.agents/aidlc/scripts/remote-state.mjs +309 -0
- package/dist/assets/.agents/aidlc/scripts/render.mjs +2 -0
- package/dist/assets/.agents/aidlc/scripts/state.mjs +67 -11
- package/dist/assets/.agents/aidlc/scripts/task-next.mjs +2 -0
- package/dist/assets/.agents/aidlc/templates/model-contract.md +3 -3
- package/dist/assets/.agents/aidlc/templates/workplan.md +2 -2
- package/dist/assets/.agents/skills/aidlc-build/SKILL.md +2 -2
- package/dist/assets/.agents/skills/aidlc-clarify/SKILL.md +2 -2
- package/dist/assets/.agents/skills/aidlc-plan/SKILL.md +2 -2
- package/dist/assets/.agents/skills/aidlc-wrap/SKILL.md +1 -1
- package/dist/services/aidlc-coordination/.env.fleet.example +11 -0
- package/dist/services/aidlc-coordination/compose.yaml +23 -2
- package/dist/services/aidlc-coordination/package-lock.json +1 -0
- package/dist/services/aidlc-coordination/package.json +2 -1
- package/dist/services/aidlc-coordination/src/coordination.mjs +1 -1
- package/dist/services/aidlc-coordination/src/fleet-client.mjs +36 -0
- package/dist/services/aidlc-coordination/src/fleet-run.mjs +18 -0
- package/dist/services/aidlc-coordination/src/fleet.mjs +233 -0
- package/dist/services/aidlc-coordination/src/git-gateway.mjs +50 -0
- package/dist/services/aidlc-coordination/src/lifecycle-core.mjs +39 -4
- package/dist/services/aidlc-coordination/src/repository.mjs +167 -4
- package/dist/services/aidlc-coordination/src/server.mjs +53 -9
- package/dist/services/aidlc-coordination/test/fleet.test.mjs +351 -0
- package/dist/services/aidlc-coordination/test/git-gateway.test.mjs +75 -0
- package/dist/services/aidlc-coordination/test/supervisor-fencing.test.mjs +59 -0
- package/dist/src/adapters.js +25 -5
- package/dist/src/cli.js +66 -6
- package/dist/src/gate.js +3 -3
- package/dist/src/installer.d.ts +5 -1
- package/dist/src/installer.js +114 -30
- package/dist/src/managed-content.js +1 -1
- package/dist/src/model.d.ts +15 -0
- package/dist/src/model.js +1 -1
- package/dist/src/profiles.d.ts +3 -1
- package/dist/src/profiles.js +26 -3
- package/dist/src/state.d.ts +7 -0
- package/dist/src/state.js +54 -3
- package/dist/src/upgrade.d.ts +2 -2
- package/dist/src/upgrade.js +39 -4
- package/dist/src/workflow.d.ts +1 -0
- package/dist/src/workflow.js +2 -1
- package/docs/README.md +2 -2
- package/docs/architecture.md +6 -1
- package/docs/command-reference.md +63 -5
- package/docs/configuration.md +20 -1
- package/docs/coordination-service.md +54 -1
- package/docs/development.md +1 -1
- package/docs/operating-workflow.md +50 -14
- package/docs/testing-and-release.md +47 -4
- package/package.json +2 -2
package/dist/src/upgrade.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, renameSync, rmdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
import { findAdapterForUpgrade, resolvedAdaptersForUpgrade } from "./adapters.js";
|
|
4
|
-
import { managedContentHash, readManifest } from "./installer.js";
|
|
4
|
+
import { installedHashFor, managedContentHash, planLoopSelection, readManifest } from "./installer.js";
|
|
5
5
|
import { legacyV021AdapterContents, legacyV021Hashes } from "./legacy.js";
|
|
6
6
|
import { planProjectLayoutMigration } from "./project-migration.js";
|
|
7
7
|
import { mergeManagedBlock } from "./managed-content.js";
|
|
@@ -113,7 +113,7 @@ const planManaged = (root, spec, installedHash, legacy) => {
|
|
|
113
113
|
return { ...spec, content: next, action: "conflict", reason: "managed prompt block was modified" };
|
|
114
114
|
return { ...spec, content: next, action: "conflict", reason: legacy ? "legacy core differs from known baseline" : "managed file differs from installed hash" };
|
|
115
115
|
};
|
|
116
|
-
export const planUpgrade = (root) => {
|
|
116
|
+
export const planUpgrade = (root, loop) => {
|
|
117
117
|
const project = resolve(root);
|
|
118
118
|
const installed = readManifest(project);
|
|
119
119
|
const legacy = !installed && legacyManifest(project);
|
|
@@ -124,9 +124,43 @@ export const planUpgrade = (root) => {
|
|
|
124
124
|
const selected = requested.filter((id) => findAdapterForUpgrade(id));
|
|
125
125
|
const agentFiles = selected.flatMap((id) => findAdapterForUpgrade(id)?.files() ?? []).map((file) => ({ ...file, ownershipClass: "managed" }));
|
|
126
126
|
const managed = [...coreWorkflowFiles(), ...agentFiles];
|
|
127
|
-
const plan =
|
|
127
|
+
const plan = [];
|
|
128
|
+
const mergedBlocks = new Map();
|
|
129
|
+
for (const spec of managed) {
|
|
130
|
+
if (spec.strategy !== "managed-block") {
|
|
131
|
+
plan.push(planManaged(project, spec, installedHashFor(installed?.files, spec), legacy));
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
const previous = mergedBlocks.get(spec.path);
|
|
135
|
+
if (!previous) {
|
|
136
|
+
const write = planManaged(project, spec, installedHashFor(installed?.files, spec), legacy);
|
|
137
|
+
plan.push(write);
|
|
138
|
+
mergedBlocks.set(spec.path, write);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (!["create", "update", "skip"].includes(previous.action))
|
|
142
|
+
continue;
|
|
143
|
+
const target = safePath(project, spec.path);
|
|
144
|
+
const current = existsSync(target) ? readFileSync(target, "utf8") : "";
|
|
145
|
+
// Every owner block is checked before merging so a user edit to a later
|
|
146
|
+
// adapter's block is reported instead of being silently overwritten.
|
|
147
|
+
const installedBlockHash = installedHashFor(installed?.files, spec);
|
|
148
|
+
const currentBlockHash = managedContentHash(spec, current);
|
|
149
|
+
if (installedBlockHash !== undefined && currentBlockHash !== undefined && installedBlockHash !== currentBlockHash) {
|
|
150
|
+
previous.action = "conflict";
|
|
151
|
+
previous.reason = "managed prompt block was modified";
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
previous.content = mergeManagedBlock(spec, previous.content);
|
|
155
|
+
previous.action = existsSync(target) ? (previous.content === current ? "skip" : "update") : "create";
|
|
156
|
+
previous.reason = "managed prompt block";
|
|
157
|
+
}
|
|
128
158
|
if (installed) {
|
|
129
|
-
for (const [
|
|
159
|
+
for (const [key, item] of Object.entries(installed.files)) {
|
|
160
|
+
const path = key.includes("#") ? key.slice(0, key.lastIndexOf("#")) : key;
|
|
161
|
+
// Shared prompt blocks are upgraded through the merged plan above; never delete their whole path here.
|
|
162
|
+
if (item.strategy === "managed-block")
|
|
163
|
+
continue;
|
|
130
164
|
if (managed.some((spec) => spec.path === path))
|
|
131
165
|
continue;
|
|
132
166
|
const target = safePath(project, path);
|
|
@@ -194,6 +228,7 @@ export const planUpgrade = (root) => {
|
|
|
194
228
|
}
|
|
195
229
|
const manifest = manifestSpec(managed, selected);
|
|
196
230
|
plan.push({ ...manifest, action: "update", reason: legacy ? "migrate manifest to schema v2" : "update manifest inventory" });
|
|
231
|
+
planLoopSelection(plan, loop);
|
|
197
232
|
return plan;
|
|
198
233
|
};
|
|
199
234
|
export const applyUpgrade = (root, plan) => {
|
package/dist/src/workflow.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { AgentId, FileSpec, WorkflowManifest } from "./model.js";
|
|
|
2
2
|
export declare const contentHash: (content: string | Uint8Array) => string;
|
|
3
3
|
export declare const coreWorkflowFiles: () => FileSpec[];
|
|
4
4
|
export declare const initialProjectFiles: () => FileSpec[];
|
|
5
|
+
export declare const manifestKey: (spec: Pick<FileSpec, "path" | "owner" | "strategy">) => string;
|
|
5
6
|
export declare const manifestFor: (files: FileSpec[], adapters: AgentId[]) => WorkflowManifest;
|
|
6
7
|
export declare const manifestSpec: (files: FileSpec[], adapters: AgentId[]) => FileSpec;
|
|
7
8
|
export declare const packageVersion: () => string;
|
package/dist/src/workflow.js
CHANGED
|
@@ -23,6 +23,7 @@ export const initialProjectFiles = () => [
|
|
|
23
23
|
{ path: ".agents/data/lessons/index.json", owner: "aidlc-state", ownershipClass: "state", content: `${JSON.stringify(createLessonIndex([], lessonStateDigest(emptyState())), null, 2)}\n` },
|
|
24
24
|
{ path: ".agents/data/memory/agentic-memory.json", owner: "aidlc-memory", ownershipClass: "project", content: `${JSON.stringify(emptyMemoryRegistry(), null, 2)}\n` }
|
|
25
25
|
];
|
|
26
|
+
export const manifestKey = (spec) => spec.strategy === "managed-block" ? `${spec.path}#${spec.owner}` : spec.path;
|
|
26
27
|
export const manifestFor = (files, adapters) => ({
|
|
27
28
|
schemaVersion: 2,
|
|
28
29
|
packageVersion: packageJson.version,
|
|
@@ -31,7 +32,7 @@ export const manifestFor = (files, adapters) => ({
|
|
|
31
32
|
remoteUpdates: false,
|
|
32
33
|
managedBy: "aidlc-workflow",
|
|
33
34
|
adapters,
|
|
34
|
-
files: Object.fromEntries(files.filter((file) => file.ownershipClass === "managed" || !file.ownershipClass).map((file) => [file
|
|
35
|
+
files: Object.fromEntries(files.filter((file) => file.ownershipClass === "managed" || !file.ownershipClass).map((file) => [manifestKey(file), {
|
|
35
36
|
hash: contentHash(file.strategy === "managed-block" ? file.content.trimEnd() : file.content),
|
|
36
37
|
owner: file.owner,
|
|
37
38
|
strategy: file.strategy ?? "replace"
|
package/docs/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Use this page to choose the guide that matches your role and next task.
|
|
|
6
6
|
|
|
7
7
|
1. Start with the repository [README](../README.md) to install the workflow.
|
|
8
8
|
2. Read [Operating the workflow](./operating-workflow.md) before asking an agent to change a project.
|
|
9
|
-
3. Use [Configuration](./configuration.md) to configure project rules, profiles, and Codex
|
|
9
|
+
3. Use [Configuration](./configuration.md) to configure project rules, profiles, and Codex, Claude Code, and OpenCode permissions.
|
|
10
10
|
4. Keep [Command reference](./command-reference.md) nearby for safe CLI usage.
|
|
11
11
|
5. Read [AI-DLC Coordination service](./coordination-service.md) before enabling remote canonical state.
|
|
12
12
|
|
|
@@ -21,7 +21,7 @@ Use this page to choose the guide that matches your role and next task.
|
|
|
21
21
|
| Page | Audience | Purpose |
|
|
22
22
|
| --- | --- | --- |
|
|
23
23
|
| [Operating the workflow](./operating-workflow.md) | Operators | Lifecycle, task state, human gates, and blocked work. |
|
|
24
|
-
| [Configuration](./configuration.md) | Operators and maintainers | Project configuration, profile precedence, rules, and Codex
|
|
24
|
+
| [Configuration](./configuration.md) | Operators and maintainers | Project configuration, profile precedence, rules, and Codex, Claude Code, and OpenCode permissions. |
|
|
25
25
|
| [Command reference](./command-reference.md) | Operators | Package CLI commands, flags, previews, and safety limits. |
|
|
26
26
|
| [Development](./development.md) | Contributors | Dependencies, source layout, local commands, and implementation rules. |
|
|
27
27
|
| [Testing and release](./testing-and-release.md) | Maintainers | Test strategy, evaluator, package smoke test, and release checks. |
|
package/docs/architecture.md
CHANGED
|
@@ -47,6 +47,8 @@ The installed kernel consists of contracts, templates, schemas, profiles, and de
|
|
|
47
47
|
|
|
48
48
|
The state machine enforces the lifecycle; gates require explicit human approval; evidence is append-only. Installed scripts remain usable without an `aidlc-workflow` executable or a duplicate board file.
|
|
49
49
|
|
|
50
|
+
The interactive loop runs inside the current Codex, Claude Code, or OpenCode conversation. Native workers use local assignment records under `.agents/data/loop/`; those records hold claims and checkpoints while `.agents/data/state/` remains lifecycle authority. The optional headless fleet runner uses the coordination service's PostgreSQL state, fenced lead and worker claims, and Git commit handoff. Its assignment records are operational metadata; task phase, evidence, and gates stay in the canonical lifecycle state. All hosts derive dispatch from task `nextAction` and dependency-ready work.
|
|
51
|
+
|
|
50
52
|
Installed entry points share a strict dependency-free argv parser. Parsing and command-shape validation precede root discovery, lock acquisition, and state reads. Explicit roots are validated project directories; implicit roots use nearest-ancestor `.agents/aidlc/` discovery and never fall back to writing beneath an arbitrary working directory.
|
|
51
53
|
|
|
52
54
|
## Trust and safety boundaries
|
|
@@ -54,7 +56,7 @@ Installed entry points share a strict dependency-free argv parser. Parsing and c
|
|
|
54
56
|
- Workflow assets are local package assets. The manifest records `remoteUpdates: false`; status and doctor do not consult a registry.
|
|
55
57
|
- Install/upgrade plans are conflict-first, path-contained, and reject unsafe symlink traversal.
|
|
56
58
|
- Human-only upgrade is an intentional boundary: interactive confirmation is required and agents must not run or discover upgrades.
|
|
57
|
-
-
|
|
59
|
+
- Codex, Claude Code, and OpenCode adapters are installed. Codex uses trusted project-scoped `.codex/config.toml` and `.codex/rules/aidlc.rules`; Claude Code scopes lifecycle-script permission through its local settings and phase skills. OpenCode gets an owner-scoped `AGENTS.md` block only, and `.opencode/` is read solely for detection, so no OpenCode configuration, MCP, or permission file is overridden.
|
|
58
60
|
- Project commands are configured as executable-and-argument arrays rather than opaque shell strings.
|
|
59
61
|
- Canonical state, terminal records, and rendered workplans reject symlink traversal and use same-directory atomic replacement. Lock acquisition is guard-serialized, while release verifies the owner token directly so a contended guard cannot strand the owner's main lock.
|
|
60
62
|
- The compact master catalog remains archive authority. Recovery can replace only a valid, unreferenced terminal orphan tied by `id` and `createdAt` to the still-active catalog task; referenced, malformed, and identity-conflicting records fail closed.
|
|
@@ -70,3 +72,6 @@ Installed entry points share a strict dependency-free argv parser. Parsing and c
|
|
|
70
72
|
| A public command | CLI parsing, README/setup guidance, command reference, and package tests. |
|
|
71
73
|
|
|
72
74
|
Use this guide with [Development](./development.md) and [Testing and release](./testing-and-release.md) before changing a cross-cutting boundary.
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
The optional end-to-end loop coordinator is implemented for both authorities. Local mode runs a foreground supervisor over the canonical local state: Docker-isolated workers, a read-only lead sandbox whose structured proposals are applied by a host broker, and gate approval only through the trusted host terminal. Fleet mode runs the same loop against a coordination service: the service owns supervisor leases, gate checkpoints, and reviewer approval, workers execute in Docker with their own credentials, and Git integration is fenced per backend (SQLite on one host with a local volume, or PostgreSQL across hosts). Selecting a mode configures the loop; only an explicit `loop start` runs it. Host-executed lead turns accept Codex, Claude Code, or OpenCode; container-isolated lead turns and worker containers accept Codex and Claude Code only and reject OpenCode with an explicit diagnostic because its credentials are file-based. See [Coordination service](./coordination-service.md) for deployment and recovery constraints.
|
|
@@ -5,11 +5,13 @@ All package commands operate on local files. The examples run version `0.0.1` th
|
|
|
5
5
|
## `init`
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
|
-
npx --package @felixdotgo/aidlc-kit@0.0.1 aidlc-workflow init [path] [--agent <name[,name]> | --all] [--yes] [--dry-run] [--force]
|
|
8
|
+
npx --package @felixdotgo/aidlc-kit@0.0.1 aidlc-workflow init [path] [--agent <name[,name]> | --all] [--loop-mode off|local|fleet] [--loop-lead codex|claude|opencode] [--loop-workers <id=provider,...>] [--yes] [--dry-run] [--force]
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
Plans the installation, prints a preview, and then writes the workflow only after confirmation (or `--yes`). `--dry-run` prints the same plan without writing. If exactly one installed agent is detected, it can be selected automatically. In an interactive terminal, choose multiple agents with the checkbox prompt: use arrow keys to move, Space to toggle, A to toggle all, and Enter to confirm. For scripts and non-interactive terminals, use `--agent <name[,name]>` or `--all`.
|
|
12
12
|
|
|
13
|
+
In interactive setup, choose a loop mode and, when enabled, the lead and worker providers. For non-interactive setup, omit loop options to keep the default off, or specify `--loop-mode local|fleet` together with `--loop-lead` and `--loop-workers` (for example, `--loop-workers a=codex,b=opencode`). The preview includes the project config change. These settings only configure the loop; run `aidlc-workflow loop start` to actually start it.
|
|
14
|
+
|
|
13
15
|
`--force` is for an intentional initial replacement of an unmanaged conflicting file. It is not an upgrade mechanism. If the project already has another workflow package version, use the human-run upgrade flow instead.
|
|
14
16
|
|
|
15
17
|
## `status`
|
|
@@ -55,13 +57,29 @@ Previews the optional AI-DLC Coordination service configuration, then writes onl
|
|
|
55
57
|
## `upgrade`
|
|
56
58
|
|
|
57
59
|
```sh
|
|
58
|
-
npx --package @felixdotgo/aidlc-kit@0.0.1 aidlc-workflow upgrade [path] [--dry-run]
|
|
60
|
+
npx --package @felixdotgo/aidlc-kit@0.0.1 aidlc-workflow upgrade [path] [--loop-mode off|local|fleet] [--loop-lead codex|claude|opencode] [--loop-workers <id=provider,...>] [--dry-run]
|
|
59
61
|
```
|
|
60
62
|
|
|
61
63
|
Upgrade is deliberately human-only. The command rejects `--yes` and `--force`; applying it requires an interactive terminal and an exact typed confirmation of the package version. Interactive confirmations use the same styled terminal prompt as `init`. Agents must not run, preview, detect, or suggest package upgrades on their own.
|
|
62
64
|
|
|
65
|
+
An omitted loop selection preserves the existing config; an explicit selection appears in the preview and is included in the upgrade backup and rollback. Enabling a mode requires a lead and worker mapping.
|
|
66
|
+
|
|
63
67
|
The upgrade plan handles supported legacy `.aidlc/` project data transactionally: identical paths are deduplicated, differing content or unsafe entries stop the plan, and an audit backup supports rollback. Review the preview before an authorised human applies it.
|
|
64
68
|
|
|
69
|
+
## `loop`
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
npx --package @felixdotgo/aidlc-kit@0.0.1 aidlc-workflow loop start|status|resume [options]
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Options: `--task-id <id>` (optional for `start`, which derives one; required for `status`/`resume`), `--root <path>`, and `--mode local|fleet` (defaults to the configured `loop.mode`). `start` reads the requirement from an interactive prompt or stdin — the requirement is never passed as an argument. The command fails closed when the requested mode does not match the configured authority, when another task is actionable, or when a resume record is missing.
|
|
76
|
+
|
|
77
|
+
`status` prints the canonical task, its derived next action, and — in fleet mode — the durable gate checkpoint. `start` and `resume` run the supervisor in the foreground until the next gate, a pause, a blocked state, or completion; the emitted events include each gate view and the waiting state.
|
|
78
|
+
|
|
79
|
+
Local mode requires the Docker worker image configuration described in [Testing and release](./testing-and-release.md) plus the provider credential environment; approval happens through the trusted host terminal command `node .agents/aidlc/scripts/loop-gate.mjs <task-id>`, which refuses piped input.
|
|
80
|
+
|
|
81
|
+
Fleet mode requires the running coordination service (`AIDLC_FLEET_URL`, `AIDLC_FLEET_WORKSPACE`, lead `AIDLC_FLEET_TOKEN`, `AIDLC_FLEET_INTEGRATION_BRANCH`, and optionally `AIDLC_FLEET_GIT_REMOTE`); worker IDs must match the configured `loop.agents.workers`, and `AIDLC_FLEET_WORKER_PROVIDERS` may map each worker to `codex`, `claude`, or `opencode`. The facade preflights the service and the integration branch and fails closed with a diagnosis instead of falling back to local. Fleet worker containers reject `opencode` with the container diagnostic above; assignment validation accepts it so that blocker surfaces when the job executes rather than being reported as an invalid provider. Fleet workers run separately through the fleet runner (`worker --once`) on each worker machine with `AIDLC_WORKER_DOCKER_IMAGE` and their own worker credential; a reviewer approves gates through the reviewer credential as documented in [Coordination service](./coordination-service.md).
|
|
82
|
+
|
|
65
83
|
## Installed lifecycle scripts
|
|
66
84
|
|
|
67
85
|
After `init`, task lifecycle commands live in the target project, not in the package CLI:
|
|
@@ -71,10 +89,50 @@ node .agents/aidlc/scripts/state.mjs task list --limit 20
|
|
|
71
89
|
node .agents/aidlc/scripts/state.mjs task find --query "<words>" --include-archive
|
|
72
90
|
node .agents/aidlc/scripts/state.mjs task show <task-id>
|
|
73
91
|
node .agents/aidlc/scripts/state.mjs task next <task-id>
|
|
92
|
+
node .agents/aidlc/scripts/state.mjs task ready <task-id>
|
|
93
|
+
node .agents/aidlc/scripts/state.mjs feature create <feature-id> --branch <integration-branch>
|
|
94
|
+
node .agents/aidlc/scripts/state.mjs feature link <feature-id> <task-id> [--depends-on <task-id,...>]
|
|
95
|
+
node .agents/aidlc/scripts/state.mjs feature ready <feature-id>
|
|
74
96
|
node .agents/aidlc/scripts/task-next.mjs <task-id> --require-stop
|
|
75
97
|
node .agents/aidlc/scripts/gate-view.mjs <task-id>
|
|
76
98
|
```
|
|
77
99
|
|
|
100
|
+
The normal interactive loop runs in the current Codex, Claude Code, or OpenCode conversation, using native agents and the installed lifecycle commands. The optional `loop.mjs` command is for unattended CLI execution:
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
node .agents/aidlc/scripts/loop.mjs run <task-id> --agent codex|claude|opencode [--max-turns N] [--turn-timeout-ms N] [--max-stall-turns N] [--root PATH]
|
|
104
|
+
node .agents/aidlc/scripts/loop.mjs resume <task-id> [--max-turns N] [--turn-timeout-ms N] [--max-stall-turns N] [--root PATH]
|
|
105
|
+
node .agents/aidlc/scripts/loop.mjs status <task-id> [--root PATH]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`--agent opencode` requires `AIDLC_OPENCODE_MODEL` in `provider/model[#variant]` form; the turn fails closed without it. Docker-isolated lead turns, local Docker worker batches, and fleet worker containers reject OpenCode with `OpenCode workers require file-based credentials and are not available in isolated containers yet` and do not fall back to the host. Use `loop.mjs run --agent opencode` for host-executed lead turns, or use Codex or Claude Code where container isolation is required.
|
|
109
|
+
|
|
110
|
+
The defaults are 12 turns and 10 minutes per turn; two completed turns without observable progress stop the run. Each run records its provider, and `resume` rejects a different agent. The runner never grants human approval. An interactive client can resume by reading `task next` and reconciling local assignment metadata; fleet execution uses fenced service leases and the remote canonical state.
|
|
111
|
+
|
|
112
|
+
If context preparation fails before an agent turn starts, the loop pauses with a reason; fix the context problem and use `resume`. An interrupted running turn with no captured session ID still requires inspection of canonical state before recovery.
|
|
113
|
+
|
|
114
|
+
The fleet runner drives the supervised multi-worker flow against a coordination service. From the service deployment (a source checkout or the installed `.agents/aidlc-coordination/`), with the lead credential plus `AIDLC_FLEET_WORKER_IDS`, `AIDLC_FLEET_INTEGRATION_BRANCH`, and `AIDLC_FLEET_PROJECT_ROOT` set:
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
node .agents/aidlc-coordination/src/fleet-run.mjs supervisor <task-id>
|
|
118
|
+
node .agents/aidlc-coordination/src/fleet-run.mjs coordinator <task-id> --once
|
|
119
|
+
node .agents/aidlc-coordination/src/fleet-run.mjs worker --once
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`supervisor` claims the task's supervisor lease, runs fenced lead turns through the coordinator, publishes each gate snapshot with its checkpoint in one service transaction, waits for the reviewer approval, and resumes automatically; it returns at a pause, blocked state, or completion, and never approves a gate. `coordinator --once` runs a single unattended pass without the supervisor lease. `worker --once` claims one ready assignment on a worker machine; it requires `AIDLC_WORKER_DOCKER_IMAGE` and that machine's worker credential and fails closed without them. `aidlc-workflow loop start --mode fleet` wraps the same supervisor with requirement intake and preflight.
|
|
123
|
+
|
|
124
|
+
Fleet mode uses `remote-state.mjs` instead of local `state.mjs`. Set `AIDLC_FLEET_URL`, `AIDLC_FLEET_WORKSPACE`, and `AIDLC_FLEET_PROJECT_ROOT`; lead mutations additionally require `AIDLC_FLEET_TOKEN` and the current `AIDLC_FLEET_LEAD_EPOCH`. Claim an epoch before creating or changing a task:
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
node .agents/aidlc/scripts/remote-state.mjs run claim <task-id>
|
|
128
|
+
node .agents/aidlc/scripts/remote-state.mjs task next <task-id>
|
|
129
|
+
node .agents/aidlc/scripts/remote-state.mjs phase context <task-id>
|
|
130
|
+
node .agents/aidlc/scripts/remote-state.mjs run release <task-id> --epoch <epoch>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The same client supports task items, evidence, decisions, status, audited transitions, wrap lessons, and feature manifests through revision-checked remote mutations. It cannot approve gates with a lead token. A connected reviewer uses `gate inbox` and, only after an explicit later user reply, `gate approve <task-id> --snapshot <id> --source <reply>` with `AIDLC_FLEET_REVIEWER_TOKEN`. See [Coordination service](./coordination-service.md#multi-machine-loop-deployment) for bootstrap, fleet processes, and credentials.
|
|
134
|
+
When `AIDLC_FLEET_URL` is set, local lifecycle, context, gate, assignment, and standalone loop commands reject use so an unattended lead cannot accidentally mutate a second local authority. Unset it only when deliberately returning to a local run.
|
|
135
|
+
|
|
78
136
|
Installed lifecycle options may appear before or after positionals and accept both `--name value` and `--name=value`. Unknown, duplicate, command-irrelevant, missing-value, and surplus positional arguments are rejected before state I/O. Boolean options such as `--all`, `--include-archive`, and `--require-stop` do not accept values. When a literal value begins with `--`, use the equals form so it is not confused with a missing value.
|
|
79
137
|
|
|
80
138
|
An explicit `--root <path>` wins and must identify a directory containing `.agents/`. Without `--root`, the runtime walks upward from the current working directory and selects the nearest ancestor containing `.agents/aidlc/`. If no installed-workflow marker exists, the command fails without creating local state. Manual calls from a nested directory need an absolute or upward-relative script path so Node can locate the entry point. Runtime-generated actions always include both an absolute script path and an absolute `--root`, so they remain executable from any working directory.
|
|
@@ -83,7 +141,7 @@ Every `state.mjs` and `task-next.mjs` command prints one JSON envelope: `{ok: tr
|
|
|
83
141
|
|
|
84
142
|
`task-next.mjs --require-stop` prints the current action plus a machine-readable `continuation` object in the stdout envelope — `{required, code, taskId, classification}` and, when work remains, `command`, `reason`, `itemId`, and `remainingItems` — and exits `2` when the classification is `run_phase`. The first stderr line is `CONTINUATION_REQUIRED: {json}` carrying the same task id, command, and reason (followed by an explicit "expected pause, not a failure" note); it is a local guard against a premature final response, and the caller must execute `continuation.command` instead of replying. It exits normally (`continuation.code = STOP_ALLOWED`) for a valid human gate, durable blocker, terminal outcome, or completion. The guard is detection at the package boundary: it cannot technically intercept a message a model host has already emitted, so hosts recover by running `task next <task-id>` in the next turn and executing its command. `task status ... --status blocked_on_user` fails instead of persisting when the current gate is not ready, and `gate-view.mjs` only renders tasks already in that validated status.
|
|
85
143
|
|
|
86
|
-
Human approval is a dedicated atomic operation:
|
|
144
|
+
Human approval is a dedicated atomic operation. The displayed review steps map to stable `--gate` values: **Confirm requirements** → `G0_confirm`, **Approve plan** → `G1_review`, **Review implementation** → `G2_codereview`. Display labels are always English; task prose may follow the task language:
|
|
87
145
|
|
|
88
146
|
```sh
|
|
89
147
|
node .agents/aidlc/scripts/state.mjs gate approve <task-id> --gate <gate> --source "<explicit approval>"
|
|
@@ -91,13 +149,13 @@ node .agents/aidlc/scripts/state.mjs gate approve <task-id> --gate <gate> --sour
|
|
|
91
149
|
|
|
92
150
|
`--source` is audit provenance, not authentication or proof of consent. The host agent must invoke this command only in a later user turn that explicitly approves the gate currently presented.
|
|
93
151
|
|
|
94
|
-
`evidence add` accepts `spec`, `test`, `lint`, `review`, and `diagnostic`; it rejects `approval`. An evidence `--area` must belong to the task's affected areas, and multi-area test or lint evidence must name its area. `task status` accepts `active`, `blocked_on_user`, and `paused` (`done` is not a status command; finish with `task transition --to done` or `task archive`), and rejects `blocked_on_user` at wrap, which has no human gate. Every route out of a validated `blocked_on_user` wait, including `paused`, requires audited `--reason` and `--source` metadata and appends diagnostic evidence; entering `paused` from `active` requires the same audited `--mode audited --reason --source` triple and appends a `Paused while active` diagnostic, while resuming `paused → active` needs no audit metadata. Repair bounds are machine-enforced: the third failed verify record per area, or the second failed review record, in the current build flips `nextAction` to `blocked` and adds a `REPAIR_BOUND` error to the
|
|
152
|
+
`evidence add` accepts `spec`, `test`, `lint`, `review`, and `diagnostic`; it rejects `approval`. An evidence `--area` must belong to the task's affected areas, and multi-area test or lint evidence must name its area. `task status` accepts `active`, `blocked_on_user`, and `paused` (`done` is not a status command; finish with `task transition --to done` or `task archive`), and rejects `blocked_on_user` at wrap, which has no human gate. Every route out of a validated `blocked_on_user` wait, including `paused`, requires audited `--reason` and `--source` metadata and appends diagnostic evidence; entering `paused` from `active` requires the same audited `--mode audited --reason --source` triple and appends a `Paused while active` diagnostic, while resuming `paused → active` needs no audit metadata. Repair bounds are machine-enforced: the third failed verify record per area, or the second failed review record, in the current build flips `nextAction` to `blocked` and adds a `REPAIR_BOUND` error to the Review implementation gate check. Normal phase advancement uses `gate approve`, and wrap completion uses `task transition --to done` or `task archive <task-id> --reason "<reason>" --source "<source>"`, which applies the same transition checks and appends an `Archive to done` diagnostic. The low-level transition escape hatch is intentionally noisy, records diagnostic evidence, still applies all transition checks, and requires audit metadata:
|
|
95
153
|
|
|
96
154
|
```sh
|
|
97
155
|
node .agents/aidlc/scripts/state.mjs task transition <task-id> --to <phase> --mode audited --reason "<reason>" --source "<source>"
|
|
98
156
|
```
|
|
99
157
|
|
|
100
|
-
Self-transitions are rejected, and `task create` rejects an id that collides case-insensitively with an existing task or archive record. `task create` also fails while
|
|
158
|
+
Self-transitions are rejected, and `task create` rejects an id that collides case-insensitively with an existing task or archive record. `task create` also fails while another unrelated task is actionable; its `--switch-from <ids>` acknowledgement still requires explicit user direction. `--feature <feature-id>` permits sibling tasks in an existing feature without abandoning them. `feature link` checks membership and task dependencies; `task item ... --depends-on <item-id,...> --owns <path,...>` adds item edges and an optional Git path scope. Fleet dispatch requires a nonempty path scope. Missing and cyclic dependencies fail, and an item or feature task cannot finish before its prerequisites. After reopening the Approve plan step, all non-deferred execution items return to `todo`; prior Review implementation, verification, and review evidence cannot satisfy the new build boundary, and repair-bound counters reset with it.
|
|
101
159
|
|
|
102
160
|
State writes and generated workplans use symlink-checked atomic replacement. State-lock release is owner-token checked and never removes a replacement owner's lock. If a process stops after writing a terminal archive record but before committing the catalog, a retry replaces that orphan only when the persisted catalog still contains the same active task identity and does not reference an archive record; malformed, referenced, or identity-conflicting records fail closed.
|
|
103
161
|
|
package/docs/configuration.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Configuration
|
|
2
2
|
|
|
3
|
-
Each installed project owns its workflow configuration at `.agents/config.json`. It selects topology profiles, specification roots, safe verification commands, and local rules without changing the package-managed kernel. The package supports
|
|
3
|
+
Each installed project owns its workflow configuration at `.agents/config.json`. It selects topology profiles, specification roots, safe verification commands, and local rules without changing the package-managed kernel. The package supports Codex, Claude Code, and OpenCode.
|
|
4
4
|
|
|
5
5
|
## Minimal configuration
|
|
6
6
|
|
|
@@ -61,6 +61,8 @@ Keep business/domain rules in `.agents/project/rules/`. Do not edit managed kern
|
|
|
61
61
|
|
|
62
62
|
The Codex adapter installs `.codex/config.toml` with `approval_policy = "on-request"` and `sandbox_mode = "workspace-write"`, plus `.codex/rules/aidlc.rules`. The execpolicy allowlists only the six lifecycle entry points under `node .agents/aidlc/scripts/`, allowing AI-DLC state transitions without granting general command approval. Each allowed lifecycle command must be run as its own exec invocation: joining commands with `&`, `&&`, `;`, or `|` creates shell command segments that are not covered by a single prefix rule. Codex loads this project config only after the user trusts the project; network access stays disabled unless the project separately enables it. Claude Code installs `.claude/settings.local.json` and phase skills that allow only `node .agents/aidlc/scripts/*`, so lifecycle state updates do not require repeated confirmation while general Bash commands remain unapproved.
|
|
63
63
|
|
|
64
|
+
The OpenCode adapter installs only an owner-scoped managed block in `AGENTS.md` and reads `.opencode/` solely to detect the adapter. It writes no OpenCode configuration, MCP, or permission file, so user and project OpenCode settings are not overridden. Codex and OpenCode blocks are independently owned and merge in the same `AGENTS.md` when both adapters are installed.
|
|
65
|
+
|
|
64
66
|
## Context and risk
|
|
65
67
|
|
|
66
68
|
`context.maxChars` bounds a phase packet. The runtime preserves lifecycle instructions, approved decisions, and mandatory invariants; it fails clearly rather than silently truncating required contract content.
|
|
@@ -70,3 +72,20 @@ Set the default risk level deliberately. Planning, migrations, cross-service con
|
|
|
70
72
|
## Optional AI-DLC Coordination
|
|
71
73
|
|
|
72
74
|
`mcp` is absent (or `{ "enabled": false }`) by default. An enabled configuration requires an HTTP(S) `endpoint` and non-empty `workspace`; it may also name a token environment variable, polling interval from 1,000 to 3,600,000 ms, and the enabled Jira/Trello/GitHub Issues preflight providers. See [AI-DLC Coordination service](./coordination-service.md) for the remote-authority and deployment contract.
|
|
75
|
+
|
|
76
|
+
## Optional loop configuration
|
|
77
|
+
|
|
78
|
+
`loop.mode` can be `off`, `local`, or `fleet`; an absent `loop` field means `off`. The optional `loop.agents` maps one lead and named workers to `codex`, `claude`, or `opencode`, independently of `mcp.providers`:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"loop": {
|
|
83
|
+
"mode": "local",
|
|
84
|
+
"agents": { "lead": "codex", "workers": { "worker-a": "codex", "worker-b": "opencode" } }
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
When any selected provider is `opencode`, set `AIDLC_OPENCODE_MODEL` to a `provider/model[#variant]` value such as `opencode-go/gpt-6-luna`. The provider turn fails closed without a valid value. Docker-isolated lead turns, local Docker worker batches, and fleet worker containers reject OpenCode with `OpenCode workers require file-based credentials and are not available in isolated containers yet`; they do not fall back to the host.
|
|
90
|
+
|
|
91
|
+
Configure this field through the init or human-run upgrade preview, or edit the project-owned config deliberately. Provider credentials do not belong in this object. The configuration is an opt-in selection; it does not install or start a service, authorize an upgrade, or grant gate approval. Selecting a mode alone does not start the loop — run `aidlc-workflow loop start` explicitly. Existing fleet operations and storage requirements are documented in [Coordination service](./coordination-service.md).
|
|
@@ -25,6 +25,59 @@ Use SQLite only on the local Docker volume. Use PostgreSQL for multiple hosts. A
|
|
|
25
25
|
|
|
26
26
|
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. Clients pull a revision or poll `state_events_since`; the service provides neither realtime subscriptions nor push notifications.
|
|
27
27
|
|
|
28
|
+
## Multi-machine loop deployment
|
|
29
|
+
|
|
30
|
+
The fleet service supports both approved storage backends: SQLite through one coordination service on one host with the database on a local volume (set `MCP_STATE_DATABASE=sqlite`, the default, and `MCP_STATE_SQLITE_PATH`), and PostgreSQL for deployments spanning multiple hosts or service instances. Each deployment keeps its chosen backend; there is no implicit fallback or migration between them. SQLite limits availability and write concurrency to that single host. Do not switch an existing authority automatically; follow the supported deployment below.
|
|
31
|
+
|
|
32
|
+
Fleet mode is separate from the default local service profile. The source checkout keeps its deployment template in `services/aidlc-coordination/`; human-run `mcp setup` copies it into the target project's `.agents/aidlc-coordination/`. Copy that directory's `.env.fleet.example` to a private `.env`, set the database choice 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 the fleet profile. From a source checkout:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
docker compose --env-file .env --profile fleet -f services/aidlc-coordination/compose.yaml up -d fleet-coordination
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
For an installed project, use `-f .agents/aidlc-coordination/compose.yaml` instead.
|
|
39
|
+
|
|
40
|
+
The default host binding is `127.0.0.1:8788`. For workers on other machines, expose `POST /mcp` through a TLS reverse proxy and set the binding deliberately. Fleet mode requires the chosen database backend and a shared Git remote. Give each worker an isolated worktree, a scoped branch, and its own worker credential. 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.
|
|
41
|
+
|
|
42
|
+
The lead credential can advance lifecycle state only while holding the current task epoch. Worker credentials can claim, checkpoint, and report assigned jobs but cannot mutate lifecycle state or approve gates. The reviewer credential can read pending gate snapshots and record a later explicit human approval against the snapshot and current revision. When the database, Git remote, or reviewer is unavailable, the run waits or fails closed; it does not fall back to local state.
|
|
43
|
+
|
|
44
|
+
The installed remote lifecycle client needs `AIDLC_FLEET_URL` (the full HTTPS `/mcp` URL), `AIDLC_FLEET_WORKSPACE`, and `AIDLC_FLEET_PROJECT_ROOT` (absolute). Lead mutations also need `AIDLC_FLEET_TOKEN` and the current `AIDLC_FLEET_LEAD_EPOCH` from its claim.
|
|
45
|
+
|
|
46
|
+
Create the task records before the remote feature manifest. For each task, claim a lead epoch, export the returned `epoch`, then create it with the feature ID; repeat for sibling tasks. Once both records exist, create and link the manifest:
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
node .agents/aidlc/scripts/remote-state.mjs run claim checkout-api
|
|
50
|
+
export AIDLC_FLEET_LEAD_EPOCH=<returned-epoch>
|
|
51
|
+
node .agents/aidlc/scripts/remote-state.mjs task create checkout-api --title "Checkout API" --feature checkout
|
|
52
|
+
node .agents/aidlc/scripts/remote-state.mjs run release checkout-api --epoch <returned-epoch>
|
|
53
|
+
# Repeat claim/create/release for checkout-ui and checkout-integration.
|
|
54
|
+
node .agents/aidlc/scripts/remote-state.mjs feature create checkout --branch feature/checkout --tasks checkout-api,checkout-ui,checkout-integration
|
|
55
|
+
node .agents/aidlc/scripts/remote-state.mjs feature link checkout checkout-integration --depends-on checkout-api,checkout-ui
|
|
56
|
+
node .agents/aidlc/scripts/remote-state.mjs feature ready checkout
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The service checks that every manifest member has a canonical task record with the matching feature ID. A partially created task stays fail-closed until the manifest is completed. The lead epoch is task-specific and must be refreshed after release or expiry.
|
|
60
|
+
|
|
61
|
+
In a connected reviewer conversation, configure `AIDLC_FLEET_REVIEWER_TOKEN`, inspect the pending packet, and only after the human replies approving that packet run:
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
node .agents/aidlc/scripts/remote-state.mjs gate inbox
|
|
65
|
+
node .agents/aidlc/scripts/remote-state.mjs gate approve <task-id> --snapshot <snapshot-id> --source "<explicit user approval>"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The second command checks that the snapshot remains current and uses the reviewer-only service operation. At G2 it also verifies that the snapshot's integration commit still matches the live remote branch. Protect the integration branch against writes outside the lead so it cannot change between verification and approval. The review message is the source provenance; the token authenticates the reviewer client, while the client operator remains responsible for using the user's actual later reply.
|
|
69
|
+
|
|
70
|
+
Run the packaged fleet process on a lead machine and worker machines under a process supervisor. Point every process to the same `AIDLC_FLEET_URL` and workspace, but give each its own role token. On the lead, set `AIDLC_FLEET_WORKER_IDS` (comma-separated), `AIDLC_FLEET_INTEGRATION_BRANCH`, and optionally `AIDLC_FLEET_AGENT` (`codex`, `claude`, or `opencode`); `AIDLC_FLEET_WORKER_PROVIDERS` can override the provider per worker. The `job_schedule` tool accepts the same three agent values, but worker containers reject `opencode` with `OpenCode workers require file-based credentials and are not available in isolated containers yet`. The explicit blocker is reported when the job executes; there is no silent host fallback. On each worker, set its matching `AIDLC_FLEET_WORKER_ID` and `AIDLC_FLEET_WORKTREES_ROOT`:
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
node dist/services/aidlc-coordination/src/fleet-run.mjs feature <feature-id>
|
|
74
|
+
node dist/services/aidlc-coordination/src/fleet-run.mjs worker
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`coordinator <task-id>` runs one task. `--once` processes a bounded polling pass for supervision or diagnostics. Defaults are four worker jobs per feature, five-minute leases with one-minute heartbeat, 12 turns per phase or assignment, 10 minutes per turn, and two consecutive stalls. Set `AIDLC_FLEET_MAX_WORKERS`, `AIDLC_FLEET_LEASE_MS`, `AIDLC_FLEET_HEARTBEAT_MS`, `AIDLC_FLEET_MAX_TURNS`, `AIDLC_FLEET_TURN_TIMEOUT_MS`, and `AIDLC_FLEET_MAX_STALL_TURNS` to change them. Feature mode dispatches dependency-ready tasks in order from one integration checkout; independent items within the active task can use several machines concurrently. After a lost worker report, the lead checks remote Git state and stops for reconciliation if the outcome is ambiguous. Set `AIDLC_FLEET_CODE_ONLY_RETRY=1` to permit an automatic retry only after the prior turn's timeout window has elapsed and Git confirms that no branch was published.
|
|
78
|
+
|
|
79
|
+
The coordinator and feature commands return when a task reaches a human gate; feature mode stops before dispatching further tasks. After the reviewer acts, restart the command to continue. Command events and command-failure diagnostics report status and exit code without the command text or its output. Worker progress observes changes to file content as well as paths.
|
|
80
|
+
|
|
28
81
|
## Shared coordination board
|
|
29
82
|
|
|
30
83
|
The opt-in service also provides a small workspace-scoped Kanban board that is 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.
|
|
@@ -37,6 +90,6 @@ Every `state_apply` write needs an `expectedRevision`, an `idempotencyKey`, and
|
|
|
37
90
|
|
|
38
91
|
The service checks lifecycle invariants across the whole before/after snapshot, not only touched task IDs. Existing evidence is append-only: the prior evidence array must remain an exact structural prefix (compared field-wise, so re-serialization key order does not matter, while record order still does). A validated `blocked_on_user` wait cannot be deleted, and while a task waits its readiness-bearing state (items, decisions, artifacts, and every other non-evidence field) is frozen; only evidence may be appended. Leaving a wait requires, in the same mutation, one of: a passing approval for that exact gate, gate-bound cancellation diagnostic evidence with a non-empty source, or a sourced closure/handoff record (`closed`/`superseded` with closure metadata, or `paused` with handoff metadata). The 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. A snapshot that requests or holds `blocked_on_user` while shared lifecycle predicates still require planning, items, verification, review, or an unexhausted repair bound is rejected. The `legacyG2Wait` repair-bound exemption marker is migration-owned: the service stamps it only when upgrading a stored pre-v4 row, and rejects any client mutation that creates or changes it. SQLite uses an immediate transaction and busy timeout; PostgreSQL locks the workspace row in a transaction.
|
|
39
92
|
|
|
40
|
-
|
|
93
|
+
In default shared-token mode, these guards keep remote history tamper-evident but do not authenticate approvals: `source` remains provenance supplied by a client. Fleet mode binds separate lead, worker, and reviewer credentials to server-side roles, and only a reviewer credential can call the atomic gate approval tool. The service cannot inspect client project artifacts, so the lead must run local artifact checks before publishing a review snapshot; the service enforces structural gate readiness and snapshot revision at approval.
|
|
41
94
|
|
|
42
95
|
`work_item_request` is intentionally 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 remain opt-in and must be made outside the lifecycle transaction.
|
package/docs/development.md
CHANGED
|
@@ -13,7 +13,7 @@ This guide is for contributors to `@felixdotgo/aidlc-kit`. It covers local setup
|
|
|
13
13
|
npm install
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
Codex
|
|
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.
|
|
17
17
|
|
|
18
18
|
## Repository layout
|
|
19
19
|
|
|
@@ -5,18 +5,35 @@
|
|
|
5
5
|
## Lifecycle at a glance
|
|
6
6
|
|
|
7
7
|
```text
|
|
8
|
-
request → clarify →
|
|
8
|
+
request → clarify → Confirm requirements → plan → Approve plan → build and verify → Review implementation → wrap → done
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
| Stage | Result | Human action |
|
|
12
12
|
| --- | --- | --- |
|
|
13
|
-
| Clarify | Intent, scope, assumptions, and open questions |
|
|
14
|
-
| Plan | Design, decisions, work items, and verification plan | Resolve decisions and approve
|
|
15
|
-
| Build | Approved change, verification, and adversarial review | Review the completed change at
|
|
16
|
-
| Wrap | Delivery notes, lessons, and residual risk | Runs only after
|
|
13
|
+
| Clarify | Intent, scope, assumptions, and open questions | Confirm the requirements. |
|
|
14
|
+
| Plan | Design, decisions, work items, and verification plan | Resolve decisions and approve the plan. |
|
|
15
|
+
| Build | Approved change, verification, and adversarial review | Review the completed change at Review implementation. |
|
|
16
|
+
| Wrap | Delivery notes, lessons, and residual risk | Runs only after Review implementation approval. |
|
|
17
17
|
|
|
18
18
|
An agent continues after each non-terminal transition and after every item or evidence mutation. Completing one work item is a progress update, not a turn boundary: the agent consumes the returned `nextAction` and continues through the remaining items, verification, and review. It stops only for a gate that is ready for human action, a durable blocker, a terminal non-success outcome, or successful completion.
|
|
19
19
|
|
|
20
|
+
In ordinary use, ask Codex, Claude Code, or OpenCode to work on the feature in the same conversation. The client remains the lead, starts native agents for independent items, and presents each review gate in that conversation. After a restart, open the project and ask the client to resume the task ID. It rereads `task next`, inspects assignment records and worktree results, and continues only dependency-ready work. A human approval is still a later reply to the gate shown in that conversation.
|
|
21
|
+
|
|
22
|
+
For example, a feature with API, UI, and integration tasks can be recorded as a feature graph:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
node .agents/aidlc/scripts/state.mjs feature create checkout --branch feature/checkout
|
|
26
|
+
node .agents/aidlc/scripts/state.mjs feature link checkout checkout-api
|
|
27
|
+
node .agents/aidlc/scripts/state.mjs feature link checkout checkout-ui
|
|
28
|
+
node .agents/aidlc/scripts/state.mjs feature link checkout checkout-integration --depends-on checkout-api,checkout-ui
|
|
29
|
+
node .agents/aidlc/scripts/state.mjs feature ready checkout
|
|
30
|
+
node .agents/aidlc/scripts/state.mjs task ready checkout-api
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The task IDs must already exist before `feature link`. To create a new sibling in an existing feature, use `task create <id> --title <title> --feature checkout` and optionally `--depends-on <task-id,...>`. Each task still goes through its own G0/G1/G2. Build items can declare `--depends-on <item-id,...>` through `task item`; `task ready` reports which items can be dispatched. Dependencies that are missing, cyclic, or incomplete at completion are rejected.
|
|
34
|
+
|
|
35
|
+
For unattended work on multiple machines, deploy the optional coordination service with PostgreSQL, distinct lead/worker/reviewer credentials, a shared Git remote, and supervised coordinator/worker processes. The remote workspace is the sole canonical authority for that run. A worker claims a bounded assignment, commits and pushes within its owned paths, and reports its commit. The lead verifies and integrates it before marking the item done. Restarted processes reread canonical state and fenced leases; uncertain results are checked before retry. At G0/G1/G2 the coordinator publishes a review snapshot and waits for a reviewer in a connected client. It cannot grant its own approval.
|
|
36
|
+
|
|
20
37
|
## Parallel workstreams
|
|
21
38
|
|
|
22
39
|
At any phase, the lead agent may use the orchestration contract to delegate independent, bounded workstreams when the host has spare worker capacity. The lead keeps one slot, assigns explicit ownership and completion criteria, and integrates returned work before relying on it. It remains the only writer for task state, evidence, review artifacts, and gates. In build, a batch may contain only items with non-overlapping file/area ownership; shared surfaces, integration, task-wide verification, and adversarial review remain lead-owned. Parallel work never changes the approval or lifecycle requirements described below.
|
|
@@ -29,11 +46,11 @@ After installation, make a normal change request to the selected coding agent. F
|
|
|
29
46
|
Add rate limiting to the login endpoint using the AI-DLC workflow.
|
|
30
47
|
```
|
|
31
48
|
|
|
32
|
-
The adapter creates a task, writes an intent brief, and presents
|
|
49
|
+
The adapter creates a task, writes an intent brief, and presents Confirm requirements. Do not treat a partial implementation as approved work before Approve plan, and do not treat a passing test as approval at Review implementation.
|
|
33
50
|
|
|
34
51
|
## State and review artifacts
|
|
35
52
|
|
|
36
|
-
Each installed project owns its data under `.agents/data/`. Package-managed workflow instructions live under `.agents/aidlc/`; project configuration, local rules, and evidence are project-owned. The package supports Codex
|
|
53
|
+
Each installed project owns its data under `.agents/data/`. Package-managed workflow instructions live under `.agents/aidlc/`; project configuration, local rules, and evidence are project-owned. The package supports Codex, Claude Code, and OpenCode. Do not hand-edit lifecycle state: use the installed scripts instead.
|
|
37
54
|
|
|
38
55
|
```sh
|
|
39
56
|
node .agents/aidlc/scripts/state.mjs task list --limit 20
|
|
@@ -43,13 +60,23 @@ node .agents/aidlc/scripts/state.mjs task next <task-id>
|
|
|
43
60
|
node .agents/aidlc/scripts/gate-view.mjs <task-id>
|
|
44
61
|
```
|
|
45
62
|
|
|
46
|
-
`task next` is the authoritative instruction for what happens next. `gate-view` renders the review packet consistently for
|
|
63
|
+
`task next` is the authoritative instruction for what happens next. `gate-view` renders the review packet consistently for Confirm requirements, Approve plan, and Review implementation.
|
|
47
64
|
|
|
48
65
|
Lifecycle options support both `--name value` and `--name=value` in any order. Invalid options and command shapes fail before lock or state access. From a project subdirectory, an omitted `--root` selects the nearest ancestor containing `.agents/aidlc/`; outside an installed project the command fails without creating `.agents`. Use explicit `--root` to select a different installed project.
|
|
49
66
|
|
|
50
|
-
Every `state.mjs` and `task-next.mjs` command returns one JSON envelope `{ok, result, nextAction?}`. Rendering, gate-check, and context commands may produce Markdown or plain text. All failures use one-line `{ok: false, error}` records on stderr with typed exit codes (`1` expected, `2` continuation guard, `3` crash). During build, the action identifies the next `in_progress` or `todo` item; after all items are terminal it still returns `run_phase` until verification, adversarial review, and
|
|
67
|
+
Every `state.mjs` and `task-next.mjs` command returns one JSON envelope `{ok, result, nextAction?}`. Rendering, gate-check, and context commands may produce Markdown or plain text. All failures use one-line `{ok: false, error}` records on stderr with typed exit codes (`1` expected, `2` continuation guard, `3` crash). During build, the action identifies the next `in_progress` or `todo` item; after all items are terminal it still returns `run_phase` until verification, adversarial review, and Review implementation preparation finish. Before any final response, the agent runs `task-next.mjs <task-id> --require-stop` and parses its machine-readable `continuation` object; exit code `2` (`continuation.code = CONTINUATION_REQUIRED`) means it must execute `continuation.command` instead of replying. This guard is detection, not hard prevention: no package-owned hook can intercept a message the model host has already emitted, so the residual risk is a premature final response that the host must recover from by running `task next <task-id>` in its very next turn and executing the returned command — never by re-approving a gate. Creating a new task while another is actionable is likewise fail-closed at the local CLI: `task create` rejects it until the agent passes the returned `--switch-from` acknowledgement with explicit user direction, which stamps a resume-marker diagnostic on the acknowledged task instead of mutating it. The optional AI-DLC Coordination service does not enforce this switch guard; remote `upsertTask`/`replaceState` can still add tasks alongside actionable work, so MCP-backed hosts rely on the adapter protocol for switch discipline.
|
|
68
|
+
|
|
69
|
+
## Review steps and approvals
|
|
51
70
|
|
|
52
|
-
|
|
71
|
+
Review-step names are English in every task. Internal IDs remain unchanged for commands and structured state:
|
|
72
|
+
|
|
73
|
+
| Review step | Internal gate ID |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| Confirm requirements | `G0_confirm` |
|
|
76
|
+
| Approve plan | `G1_review` |
|
|
77
|
+
| Review implementation | `G2_codereview` |
|
|
78
|
+
|
|
79
|
+
Display text such as JSON `title` and `action` uses these names; integrations should identify gates by `gate`, not by display text.
|
|
53
80
|
|
|
54
81
|
Approval is an explicit human action. When the agent receives an approval, it records the approval and advances the lifecycle atomically:
|
|
55
82
|
|
|
@@ -57,17 +84,17 @@ Approval is an explicit human action. When the agent receives an approval, it re
|
|
|
57
84
|
node .agents/aidlc/scripts/state.mjs gate approve <task-id> --gate <gate-name> --source "<explicit approval>"
|
|
58
85
|
```
|
|
59
86
|
|
|
60
|
-
Do not invent approvals or approve unresolved design decisions. Approval evidence can be created only by `gate approve`; generic evidence recording cannot manufacture it. A passing
|
|
87
|
+
Do not invent approvals or approve unresolved design decisions. Approval evidence can be created only by `gate approve`; generic evidence recording cannot manufacture it. A passing approval at Approve plan starts a build boundary. Verification, adversarial review, and approval at Review implementation used to enter wrap must all belong to the current boundary.
|
|
61
88
|
|
|
62
89
|
`--source` records provenance; it is not authentication or proof of consent. The local CLI enforces lifecycle structure, while the host agent must call `gate approve` only in a later user turn that explicitly assents to the gate currently shown.
|
|
63
90
|
|
|
64
|
-
A reopened plan invalidates
|
|
91
|
+
A reopened plan invalidates prior approvals at Approve plan and Review implementation, resets every non-deferred build item to `todo`, and requires current-build verification and review. Evidence is append-only, so the runtime identifies the current boundary by evidence order instead of trusting timestamps. For each affected area, at least one `test` or `lint` result is required and the latest result of every verification kind present must pass; one kind cannot hide a failure in the other.
|
|
65
92
|
|
|
66
93
|
Terminal archiving commits the immutable record before the compact catalog. A retry may recover the narrow interrupted-write window only when the catalog still proves the same task is active and the unreferenced record has the same stable identity. Other archive conflicts require investigation rather than overwrite. Rendered workplans are derived views and are replaced atomically under the same state lock when rendered by the standalone command.
|
|
67
94
|
|
|
68
95
|
## Blocked work and successors
|
|
69
96
|
|
|
70
|
-
`blocked_on_user` means a valid human gate is ready; wrap has no human gate and rejects it. The status command validates gate prerequisites before persisting it, and `gate-view` refuses to present an active or unready task. Ordinary exits from a validated human-gate wait require audited reason and source metadata plus diagnostic evidence; sourced closure and handoff records provide the corresponding terminal trail. The two compatibility paths are migration-stamped legacy
|
|
97
|
+
`blocked_on_user` means a valid human gate is ready; wrap has no human gate and rejects it. The status command validates gate prerequisites before persisting it, and `gate-view` refuses to present an active or unready task. Ordinary exits from a validated human-gate wait require audited reason and source metadata plus diagnostic evidence; sourced closure and handoff records provide the corresponding terminal trail. The two compatibility paths are migration-stamped legacy Review implementation waits and recovery of an invalid `wrap`/`none` wait; neither is a human approval. The `legacyG2Wait` marker is written only by state-schema migration (`state.mjs state migrate` or a human-run installer upgrade), only exempts a still-ready pre-existing wait from the repair bound, and is cleared by every route out of the wait. Repair bounds are machine-enforced: three failed verify records per area or two failed review records in the current build flip `nextAction` to `blocked` and close Review implementation with `REPAIR_BOUND` until a durable handoff is recorded. It does not mean a failed change is waiting for a rubber stamp. When verification or review cannot pass, the workflow records a durable handoff and offers structured options.
|
|
71
98
|
|
|
72
99
|
```sh
|
|
73
100
|
node .agents/aidlc/scripts/state.mjs task handoff <task-id> --kind <kind> --reason "<reason>" --source "<evidence>"
|
|
@@ -75,7 +102,7 @@ node .agents/aidlc/scripts/state.mjs task reopen <task-id> --to plan --reason "<
|
|
|
75
102
|
node .agents/aidlc/scripts/state.mjs task close <task-id> --reason "<reason>" --source "<explicit request>"
|
|
76
103
|
```
|
|
77
104
|
|
|
78
|
-
If work continues in a fresh task, create that task at
|
|
105
|
+
If work continues in a fresh task, create that task at Confirm requirements and link it as a successor. `closed` and `superseded` are terminal non-success outcomes; they do not transfer approvals or imply a completed delivery.
|
|
79
106
|
|
|
80
107
|
## Operational rules
|
|
81
108
|
|
|
@@ -85,3 +112,12 @@ If work continues in a fresh task, create that task at G0 and link it as a succe
|
|
|
85
112
|
- Put project-specific behaviour in project configuration or local rules, not in the package-managed workflow kernel.
|
|
86
113
|
|
|
87
114
|
See [Configuration](./configuration.md) for project customisation and [Command reference](./command-reference.md) for package commands.
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
## Optional end-to-end loop
|
|
118
|
+
|
|
119
|
+
When the project enables `loop.mode`, `aidlc-workflow loop start` accepts a requirement once (interactive prompt or stdin), creates exactly one task under the configured authority, and runs the loop to the first gate or to completion. `loop status` reports the canonical task and gate checkpoint; `loop resume` continues after an interruption. The intake is idempotent: re-running `start` with the same task ID and requirement reuses the existing task, and it refuses to create a second task while another one is actionable.
|
|
120
|
+
|
|
121
|
+
The loop never approves a gate itself. At each gate it publishes the review packet and waits; in local mode approval happens only through the trusted host terminal command, and in fleet mode only through the reviewer credential against the published snapshot and revision. After a real approval the running supervisor re-reads the canonical state and checkpoint, re-acquires its fenced lease, and resumes automatically. If the supervisor is not running at approval time, restart it and it reconciles from the checkpoint; a consumed, stale, or mismatched checkpoint stops for manual reconciliation instead of guessing. Restarting never resumes a paused or handed-off task, an outdated snapshot, or an uncertain Git result — those require the documented recovery actions.
|
|
122
|
+
|
|
123
|
+
The supervisor runs in the foreground or under a process supervisor you choose; there is no background daemon. Workers execute in Docker with their own scoped credentials and never inherit host access. Host-executed lead turns support `codex`, `claude`, or `opencode`; container-isolated lead turns, local Docker worker batches, and fleet worker containers reject `opencode` because it requires file-based credentials, returning `OpenCode workers require file-based credentials and are not available in isolated containers yet` instead of falling back to the host. When the loop uses `opencode`, set `AIDLC_OPENCODE_MODEL` to a `provider/model[#variant]` value. See [Command reference](./command-reference.md) for the loop commands and environment, and [Coordination service](./coordination-service.md) for fleet deployment, backends, and recovery.
|