duaer-spec 0.1.0 → 0.2.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.
@@ -5,14 +5,15 @@ alwaysApply: true
5
5
 
6
6
  # Duaer required (NON-NEGOTIABLE)
7
7
 
8
- See repo `DUADER.md` and `.duaer/memory/constitution.md`.
8
+ Treat agents as digital employees: assign a Brief (Spec) before code; accept
9
+ only via converge. See `DUADER.md` and `.duaer/memory/constitution.md`.
9
10
 
10
11
  If this rule conflicts with root `AGENTS.md` / `docs/agent/` (worktrees, commits,
11
12
  Issue/PR), **AGENTS.md wins**.
12
13
 
13
14
  ## When Duaer is mandatory
14
15
 
15
- Always write/update a feature spec before coding for:
16
+ Always write/update a feature spec (Brief) before coding for:
16
17
 
17
18
  - New features / user-visible behavior
18
19
  - Architecture or contract changes
@@ -31,3 +32,4 @@ Forbidden: jump from chat to code with no `spec.md` / feature directory under `.
31
32
  - Implement only from `tasks.md` when it exists
32
33
  - Update `.duaer/memory/project-context.md` when architecture changes
33
34
  - Run the verification named in the feature docs before merge
35
+ - Before merge: `duaer check . --gate` (Spec present, no open tasks, `delivery.json` accepted)
@@ -71,10 +71,17 @@ of remaining work as a new, traceable task** at the bottom of `tasks.md` so that
71
71
  This is **not** a diff tool and does **not** track changes. It assesses the present state
72
72
  of the code relative to the feature's artifacts — no git, no branch comparison, no history.
73
73
 
74
+ **Delivery stamp:** Always update `FEATURE_DIR/delivery.json` after assessment (see Step 7).
75
+ That file is what `duaer check --gate` reads for machine-checkable acceptance.
76
+
74
77
  ## Operating Constraints
75
78
 
76
- **APPEND-ONLY, NEVER REWRITE**: The command's **only** write is appending a new
77
- `## Phase N: Convergence` section to `tasks.md`. It MUST NOT:
79
+ **APPEND-ONLY FOR TASKS, STAMP FOR DELIVERY**: The command's writes are limited to:
80
+
81
+ 1. appending a new `## Phase N: Convergence` section to `tasks.md` when findings exist;
82
+ 2. writing / overwriting `FEATURE_DIR/delivery.json` (the machine-readable accept stamp).
83
+
84
+ It MUST NOT:
78
85
 
79
86
  - modify `spec.md` or `plan.md` in any way;
80
87
  - rewrite, renumber, reorder, or delete any existing task (including tasks from a prior
@@ -83,7 +90,8 @@ of the code relative to the feature's artifacts — no git, no branch comparison
83
90
  job of `/duaer-implement`.
84
91
 
85
92
  When the codebase already satisfies everything, the command MUST leave `tasks.md`
86
- **byte-for-byte unchanged** (no empty Convergence header) and report a clean result.
93
+ **byte-for-byte unchanged** (no empty Convergence header) and still write
94
+ `delivery.json` with `status: "accepted"`.
87
95
 
88
96
  **Constitution Authority**: The project constitution (`.duaer/memory/constitution.md`) is
89
97
  **non-negotiable**. Code that violates a MUST principle is the highest-severity finding and
@@ -221,20 +229,51 @@ Append to the **end** of `tasks.md`, per the append contract:
221
229
  `CRITICAL`.
222
230
  4. Never reuse or renumber existing IDs. If a prior Convergence phase exists, add a new,
223
231
  separately-numbered one below it — do not touch the old one.
232
+ 5. **Write / overwrite** `FEATURE_DIR/delivery.json`:
233
+
234
+ ```json
235
+ {
236
+ "schemaVersion": 1,
237
+ "status": "open",
238
+ "outcome": "tasks_appended",
239
+ "checkedAt": "<ISO-8601 UTC>",
240
+ "openTasks": <count of - [ ] in tasks.md after append>,
241
+ "findings": <number of findings appended>,
242
+ "source": "duaer-converge"
243
+ }
244
+ ```
224
245
 
225
246
  **If there are no actionable findings** (`converged` outcome):
226
247
 
227
248
  - Do **not** modify `tasks.md` at all — no empty phase header.
249
+ - **Write / overwrite** `FEATURE_DIR/delivery.json` with:
250
+
251
+ ```json
252
+ {
253
+ "schemaVersion": 1,
254
+ "status": "accepted",
255
+ "outcome": "converged",
256
+ "checkedAt": "<ISO-8601 UTC>",
257
+ "openTasks": 0,
258
+ "findings": 0,
259
+ "source": "duaer-converge"
260
+ }
261
+ ```
262
+
263
+ Set `openTasks` to the count of unchecked `- [ ]` lines currently in `tasks.md`
264
+ (must be `0` for `status: "accepted"`; if any remain, treat as `tasks_appended`
265
+ path instead — do not stamp accepted).
228
266
  - Report: **"✅ Converged — the implementation satisfies the spec, plan, and tasks."**
229
267
  - Include the summary counts of what was checked.
230
-
268
+ - Tell the user they can run `duaer check . --gate` to verify the machine gate.
231
269
  ### 8. Provide Next Actions (Handoff)
232
270
 
233
271
  - On `tasks_appended`: state how many tasks were appended under which phase, and recommend
234
272
  running `/duaer-implement` to complete them; note that a follow-up converge
235
- run will find fewer or no remaining items.
236
- - On `converged`: recommend proceeding to review / opening a PR. No further implement pass
237
- is needed for this feature's specified scope.
273
+ run will find fewer or no remaining items. Remind: `delivery.json` is `open` —
274
+ `duaer check --gate` will fail until accepted.
275
+ - On `converged`: recommend `duaer check . --gate`, then review / opening a PR. No further
276
+ implement pass is needed for this feature's specified scope.
238
277
 
239
278
  ### 9. Check for extension hooks
240
279
 
@@ -35,3 +35,8 @@ Do not expand scope without updating the spec and tasks.
35
35
 
36
36
  Mark tasks complete only when the stated verification (tests, manual checks,
37
37
  or converge) has been performed or explicitly waived in the feature docs.
38
+
39
+ Before merge, run `duaer check . --gate`. It fails on missing Spec, open
40
+ `- [ ]` tasks, or `delivery.json` that is not `status: "accepted"`. Converge
41
+ assessment is still agent-assisted; the gate makes the **handoff state**
42
+ machine-checkable.
package/ADOPT.md CHANGED
@@ -1,22 +1,21 @@
1
1
  # Adopt duaer-spec
2
2
 
3
- Install the **Duaer** methodology and agent-ops contract into another
4
- repository.
3
+ Onboard a **digital employee** into another repository: install the Duaer
4
+ delivery OS (method) and the agent-ops contract (how they are allowed to work).
5
5
 
6
6
  ## Recommended: CLI
7
7
 
8
8
  From the target project (Node 18+):
9
9
 
10
10
  ```bash
11
- # GitHub pin
12
- npx github:fujiezee/duaer-spec@v0.1.0 duaer init --here
13
-
14
- # npm (after publish)
15
11
  npx duaer-spec init --here
16
12
 
17
- # method only / ops only / other integration branch
18
- npx github:fujiezee/duaer-spec@v0.1.0 duaer init --here --method
19
- npx github:fujiezee/duaer-spec@v0.1.0 duaer init --here --ops --branch develop
13
+ # Pin a release
14
+ npx github:fujiezee/duaer-spec@v0.2.0 duaer init --here
15
+
16
+ # Lite (method only) / ops only / other integration branch
17
+ npx duaer-spec init --here --method
18
+ npx duaer-spec init --here --ops --branch develop
20
19
  ```
21
20
 
22
21
  From a clone of this repo:
@@ -30,9 +29,12 @@ node bin/duaer.mjs check /path/to/project
30
29
 
31
30
  Then:
32
31
 
33
- 1. Edit `.duaer/memory/constitution.md` and `project-context.md` for the product
34
- 2. Confirm `docs/baseline.md` (integration branch)
35
- 3. Use `/duaer-specify` → `/duaer-plan` → `/duaer-tasks` → `/duaer-implement` → `/duaer-converge`
32
+ 1. **Orient** — edit `.duaer/memory/constitution.md` and `project-context.md`
33
+ 2. **Confirm workplace** — `docs/baseline.md` (integration branch)
34
+ 3. **Assign → work → accept → gate** — `/duaer-specify` → `/duaer-plan` → `/duaer-tasks` → `/duaer-implement` → `/duaer-converge` → `duaer check . --gate`
35
+
36
+ A job without Spec is not assigned. Open tasks or a non-`accepted` `delivery.json`
37
+ is not accepted. `duaer check --gate` is the machine merge check.
36
38
 
37
39
  ## Manual copy (optional)
38
40
 
@@ -59,7 +61,7 @@ cp DUADER.md /path/to/project/
59
61
 
60
62
  ## Precedence
61
63
 
62
- 1. `AGENTS.md` / agent-ops — how agents operate
64
+ 1. `AGENTS.md` / agent-ops — how employees operate
63
65
  2. `DUADER.md` / `.duaer/` — what to build
64
66
  3. Product overlays (do not copy `examples/` blindly)
65
67
 
package/AGENTS.md CHANGED
@@ -3,8 +3,10 @@
3
3
  Mandatory rules for AI coding agents working in **duaer-spec**, and for any
4
4
  repository that adopts this file as its agent-ops contract.
5
5
 
6
- This file is authoritative for *how* agents operate. If Duaer (`.duaer/`,
7
- `DUADER.md`), `examples/`, or other overlays conflict with this file,
6
+ Treat agents as **digital employees**: this file is the workplace policy for
7
+ *how* they may operate (isolation, commits, Issue/PR gates). Duaer
8
+ ([`DUADER.md`](DUADER.md)) is how jobs are briefed and accepted. If Duaer
9
+ (`.duaer/`), `examples/`, or other overlays conflict with this file,
8
10
  **follow this file**.
9
11
 
10
12
  See also: [workflow](docs/agent/workflow.md) · [change checklist](docs/agent/change-checklist.md) · [ADOPT](ADOPT.md)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.0 — 2026-09-15
4
+
5
+ ### Controllable delivery (machine gate)
6
+
7
+ - `/duaer-converge` writes `.duaer/specs/<feature>/delivery.json`
8
+ (`accepted` | `open`)
9
+ - `duaer check` reports workplace **and** delivery status
10
+ - `duaer check --gate` fails on missing Spec, open tasks, or non-accepted stamp
11
+ - Constitution, DUADER, README, ADOPT, and merge checklist require the gate
12
+ - Honest scope: gate checks **handoff state**; Spec↔code judgment remains
13
+ agent-assisted
14
+
15
+ ### E2E
16
+
17
+ - E2E-003 / E2E-004 / E2E-005 for delivery report and gate
18
+
19
+ ## 0.1.1 — 2026-09-15
20
+
21
+ ### Docs / product identity
22
+
23
+ - Position Duaer as a **delivery OS for AI digital employees**: hire → assign
24
+ (Spec) → work → accept (converge)
25
+ - README, ADOPT, DUADER, AGENTS intro, and CLI `init` / `check` / help copy
26
+ use that language
27
+ - E2E catalog: E2E-001 (init next steps), E2E-002 (README positioning)
28
+
3
29
  ## 0.1.0 — 2026-09-15
4
30
 
5
31
  First public methodology release.
package/DUADER.md CHANGED
@@ -1,7 +1,10 @@
1
1
  # Duaer methodology
2
2
 
3
- **duaer-spec** owns this method. Artifacts live under `.duaer/`; Cursor skills
4
- are `duaer-*` at `.cursor/skills/`.
3
+ **duaer-spec** owns this method. Treat AI coding agents as **digital employees**:
4
+ you assign a Brief (Spec), they follow a fixed work order, and delivery only
5
+ counts after **converge** accepts the result against that Brief.
6
+
7
+ Artifacts live under `.duaer/`; Cursor skills are `duaer-*` at `.cursor/skills/`.
5
8
 
6
9
  **Precedence:** root [`AGENTS.md`](AGENTS.md) / [`docs/agent/`](docs/agent/) win
7
10
  over anything here for isolation, commits, and Issue/PR gates.
@@ -18,24 +21,25 @@ over anything here for isolation, commits, and Issue/PR gates.
18
21
  **Full (recommended):**
19
22
 
20
23
  1. `/duaer-constitution` — only when principles change
21
- 2. `/duaer-specify` — what / why / acceptance (not stack trivia)
24
+ 2. `/duaer-specify` — **Assign**: what / why / acceptance (not stack trivia)
22
25
  3. `/duaer-clarify` — optional
23
26
  4. `/duaer-plan` — technical plan aligned with project-context
24
27
  5. `/duaer-checklist` — optional quality checklist
25
28
  6. `/duaer-tasks` — checkbox task breakdown
26
29
  7. `/duaer-analyze` — optional consistency check
27
30
  8. `/duaer-implement` — implement tasks only
28
- 9. `/duaer-converge` — compare result to spec; append remaining tasks if gaps
31
+ 9. `/duaer-converge` — **Accept**: compare result to Spec; write `delivery.json`; append remaining tasks if gaps
32
+ 10. `duaer check . --gate` — **Gate**: fail merge if Spec missing, tasks open, or stamp not accepted
29
33
 
30
- **Small feature:** specify → plan → tasks → implement → converge
34
+ **Small feature:** specify → plan → tasks → implement → converge → `check --gate`
31
35
 
32
- **Hotfix:** specify (mark hotfix) → tasks → implement → converge
33
- Never skip specify or converge.
36
+ **Hotfix:** specify (mark hotfix) → tasks → implement → converge → `check --gate`
37
+ Never skip specify (assign), converge (accept), or the gate.
34
38
 
35
39
  ## Install
36
40
 
37
41
  ```bash
38
- npx github:fujiezee/duaer-spec duaer init --here
42
+ npx duaer-spec init --here
39
43
  ```
40
44
 
41
45
  Or see [`ADOPT.md`](ADOPT.md). No third-party Spec CLI is required — `duaer`
@@ -45,10 +49,11 @@ installs this repository's method files into the target project.
45
49
 
46
50
  ```text
47
51
  .duaer/specs/<nnn-slug>/
48
- spec.md
49
- plan.md # after /duaer-plan
50
- tasks.md # after /duaer-tasks
51
- # research / contracts as needed
52
+ spec.md # Brief
53
+ plan.md # after /duaer-plan
54
+ tasks.md # after /duaer-tasks
55
+ delivery.json # after /duaer-converge (accepted | open)
56
+ … # research / contracts as needed
52
57
  ```
53
58
 
54
59
  ## Related
package/README.md CHANGED
@@ -1,44 +1,70 @@
1
1
  # duaer-spec
2
2
 
3
- **Duaer** is a Spec-Driven Development methodology for AI coding agents
4
- (Cursor first), plus enforceable **agent ops** for isolation, commits, and
5
- Issue/PR gates.
3
+ **Duaer** is a delivery operating system for AI coding agents treated as
4
+ **digital employees**.
6
5
 
7
- Not a wrapper around another toolkit. The method, directories, skills, and rules
8
- in this repository **are** duaer-spec.
6
+ Agents write the code. Duaer makes the **handoff controllable**: every job has a
7
+ Brief (Spec), follows a fixed work order, and only counts as done when the
8
+ **delivery gate** passes — not after a lucky chat.
9
9
 
10
- ## Install into a project
10
+ Cursor is the labor. Duaer is hire → assign → accept.
11
11
 
12
- ```bash
13
- # GitHub (available now)
14
- npx github:fujiezee/duaer-spec@v0.1.0 duaer init --here
12
+ ## Install (onboard the employee)
15
13
 
16
- # npm (after the package is published)
14
+ ```bash
17
15
  npx duaer-spec init --here
16
+ # or pin: npx github:fujiezee/duaer-spec@v0.2.0 duaer init --here
18
17
  ```
19
18
 
20
19
  ```bash
21
- # method only / ops only / other integration branch
22
- npx github:fujiezee/duaer-spec duaer init --here --method
23
- npx github:fujiezee/duaer-spec duaer init --here --ops --branch develop
20
+ # Lite: method only (personal / small changes)
21
+ npx duaer-spec init --here --method
22
+
23
+ # Full ops on another integration branch
24
+ npx duaer-spec init --here --ops --branch develop
24
25
  ```
25
26
 
26
- Verify: `npx github:fujiezee/duaer-spec duaer check .`
27
+ Verify: `npx duaer-spec check .`
28
+ Merge gate: `npx duaer-spec check . --gate`
27
29
  Details: [`ADOPT.md`](ADOPT.md)
28
30
 
31
+ ## How you run them
32
+
33
+ | Step | Meaning | Command |
34
+ |---|---|---|
35
+ | **Hire** | Install SOP + gates into the repo | `duaer init` |
36
+ | **Assign** | Write the Brief (what / why / acceptance) | `/duaer-specify` |
37
+ | **Work** | Plan, break down, implement | `/duaer-plan` → `/duaer-tasks` → `/duaer-implement` |
38
+ | **Accept** | Converge stamps `delivery.json`; gaps stay open | `/duaer-converge` |
39
+ | **Gate** | Machine check before merge | `duaer check . --gate` |
40
+
41
+ Never skip **Assign** or **Accept**. Hotfix may shorten the middle; Spec,
42
+ converge, and the gate stay.
43
+
44
+ ### What the gate actually enforces
45
+
46
+ `duaer check --gate` fails when any feature under `.duaer/specs/` has:
47
+
48
+ - missing `spec.md`
49
+ - open `- [ ]` tasks in `tasks.md`
50
+ - missing `delivery.json`, or `status` other than `accepted`
51
+
52
+ Converge judgment is still agent-assisted. The gate makes **handoff state**
53
+ checkable (and CI-friendly), not a substitute for tests.
54
+
29
55
  ## Two layers
30
56
 
31
57
  | Layer | Role | Where |
32
58
  |---|---|---|
33
- | **Agent ops** | How agents operate | [`AGENTS.md`](AGENTS.md), [`docs/agent/`](docs/agent/) |
59
+ | **Agent ops** | How the employee is allowed to operate | [`AGENTS.md`](AGENTS.md), [`docs/agent/`](docs/agent/) |
34
60
  | **Duaer method** | What to build (Spec → Plan → Tasks → Implement → Converge) | [`DUADER.md`](DUADER.md), [`.duaer/`](.duaer/), [`.cursor/skills/`](.cursor/skills/) |
35
61
 
36
- When they conflict, **agent ops win**.
62
+ When they conflict, **agent ops win** — process beats improvisation.
37
63
 
38
64
  ## Default loop
39
65
 
40
66
  ```text
41
- constitution → specify → plan → tasks → implement → converge
67
+ constitution → specify → plan → tasks → implement → converge → check --gate
42
68
  ```
43
69
 
44
70
  Small change: `specify → plan → tasks → implement → converge`
@@ -52,14 +78,16 @@ Slash skills: `/duaer-specify`, `/duaer-plan`, `/duaer-tasks`, `/duaer-implement
52
78
  ```text
53
79
  bin/duaer.mjs CLI (duaer init | check | version)
54
80
  package.json npm package metadata
55
- AGENTS.md Agent-ops contract
56
- DUADER.md Methodology conventions
57
- ADOPT.md Install guide
81
+ AGENTS.md Agent-ops contract (how employees operate)
82
+ DUADER.md Methodology conventions (how work is briefed)
83
+ ADOPT.md Onboarding guide
58
84
  .duaer/ Memory, templates, workflows, scripts
85
+ .duaer/specs/<feature>/ Brief + tasks + delivery.json stamp
59
86
  .cursor/rules/ Agent-ops + Duaer rules
60
87
  .cursor/skills/ duaer-* skills
61
88
  docs/agent/ Workflow detail + checklists
62
89
  docs/maintaining.md How maintainers evolve the method
90
+ docs/npm-trusted-publishing.md npm Trusted Publishing (OIDC) setup
63
91
  examples/ Optional product overlays (not defaults)
64
92
  ```
65
93
 
package/bin/duaer.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * duaer — CLI for the duaer-spec methodology
3
+ * duaer — CLI for the duaer-spec delivery OS (digital employees)
4
4
  *
5
5
  * duaer init [dir] [--all|--method|--ops] [--force] [--branch <name>]
6
- * duaer check [dir]
6
+ * duaer check [dir] [--workplace|--delivery|--gate]
7
7
  * duaer version
8
8
  * duaer help
9
9
  */
@@ -24,26 +24,35 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
24
24
  const PKG_ROOT = resolve(__dirname, '..')
25
25
  const PKG = JSON.parse(readFileSync(join(PKG_ROOT, 'package.json'), 'utf8'))
26
26
 
27
- const USAGE = `duaer — Duaer methodology installer (duaer-spec ${PKG.version})
27
+ const USAGE = `duaer — Delivery OS for AI digital employees (duaer-spec ${PKG.version})
28
+
29
+ Hire agents into a repo, assign Briefs (Specs), accept only when the gate passes.
28
30
 
29
31
  Usage:
30
- duaer init [dir] [options] Install Duaer into a project
31
- duaer check [dir] Verify install shape
32
- duaer version Print version
33
- duaer help Show this help
32
+ duaer init [dir] [options] Hire / onboard into a project
33
+ duaer check [dir] [options] Workplace + delivery status
34
+ duaer version Print version
35
+ duaer help Show this help
34
36
 
35
37
  Init options:
36
- --all Agent ops + method (default)
37
- --method Method only (.duaer, skills, DUADER.md, duaer-spec rule)
38
- --ops Agent ops only (AGENTS.md, docs/agent, ops rules)
38
+ --all Full hire: agent ops + method (default)
39
+ --method Lite: method only (.duaer, skills, DUADER.md, duaer-spec rule)
40
+ --ops Ops only (AGENTS.md, docs/agent, ops rules)
39
41
  --force Overwrite existing managed files
40
42
  --branch <n> Integration branch for baseline note (default: main)
41
43
  --here Same as dir=.
42
44
 
45
+ Check options:
46
+ --workplace Only verify install files
47
+ --delivery Only report feature Brief / open tasks / delivery.json
48
+ --gate Fail unless every feature is accepted (merge gate)
49
+ (default) Workplace + delivery report; exit 1 on workplace miss
50
+ or delivery blockers (missing Spec / open tasks / open stamp)
51
+
43
52
  Examples:
44
- npx github:fujiezee/duaer-spec duaer init --here
45
- node bin/duaer.mjs init ../my-app --all
53
+ npx duaer-spec init --here
46
54
  duaer check .
55
+ duaer check . --gate
47
56
  `
48
57
 
49
58
  function parseArgs(argv) {
@@ -54,6 +63,9 @@ function parseArgs(argv) {
54
63
  mode: 'all',
55
64
  force: false,
56
65
  branch: 'main',
66
+ workplace: false,
67
+ delivery: false,
68
+ gate: false,
57
69
  }
58
70
  const rest = args.slice(1)
59
71
  for (let i = 0; i < rest.length; i++) {
@@ -63,6 +75,9 @@ function parseArgs(argv) {
63
75
  else if (a === '--ops') out.mode = 'ops'
64
76
  else if (a === '--force') out.force = true
65
77
  else if (a === '--here') out.dir = '.'
78
+ else if (a === '--workplace') out.workplace = true
79
+ else if (a === '--delivery') out.delivery = true
80
+ else if (a === '--gate') out.gate = true
66
81
  else if (a === '--branch') {
67
82
  out.branch = rest[++i]
68
83
  if (!out.branch) throw new Error('--branch requires a value')
@@ -86,7 +101,6 @@ function copyPath(from, to, { force }) {
86
101
  if (existsSync(to) && !force) {
87
102
  const st = statSync(to)
88
103
  if (st.isDirectory()) {
89
- // merge: copy children carefully
90
104
  for (const name of readdirSync(from)) {
91
105
  copyPath(join(from, name), join(to, name), { force })
92
106
  }
@@ -218,20 +232,101 @@ function cmdInit(opts) {
218
232
  }
219
233
 
220
234
  console.log(`
221
- Done.
235
+ Hired.
222
236
 
223
- Next:
224
- 1. Edit .duaer/memory/constitution.md and project-context.md for this product
225
- 2. Confirm docs/baseline.md (integration branch: ${opts.branch})
226
- 3. In Cursor, use /duaer-specify /duaer-plan /duaer-tasks → /duaer-implement → /duaer-converge
227
- 4. Agent ops: AGENTS.md wins over DUADER.md when they conflict
237
+ Next (digital employee loop):
238
+ 1. Orient — edit .duaer/memory/constitution.md and project-context.md
239
+ 2. Workplace — confirm docs/baseline.md (integration branch: ${opts.branch})
240
+ 3. Assign — /duaer-specify (Brief: what / why / acceptance)
241
+ 4. Work — /duaer-plan /duaer-tasks /duaer-implement
242
+ 5. Accept — /duaer-converge (writes delivery.json; gaps stay open)
243
+ 6. Gate — duaer check . --gate before merge
244
+ 7. Policy — AGENTS.md wins over DUADER.md when they conflict
228
245
 
246
+ No Spec = not assigned. Open tasks or open delivery.json = not accepted.
229
247
  See DUADER.md and AGENTS.md in the target project.
230
248
  `)
231
249
  }
232
250
 
233
- function cmdCheck(dir) {
234
- const target = resolve(dir)
251
+ function countOpenTasks(tasksPath) {
252
+ if (!existsSync(tasksPath)) return null
253
+ const text = readFileSync(tasksPath, 'utf8')
254
+ const open = (text.match(/^\s*-\s*\[\s\]/gm) || []).length
255
+ const done = (text.match(/^\s*-\s*\[x\]/gim) || []).length
256
+ return { open, done }
257
+ }
258
+
259
+ function readDelivery(path) {
260
+ if (!existsSync(path)) return null
261
+ try {
262
+ return JSON.parse(readFileSync(path, 'utf8'))
263
+ } catch {
264
+ return { status: 'invalid', error: 'unreadable delivery.json' }
265
+ }
266
+ }
267
+
268
+ function listFeatures(target) {
269
+ const root = join(target, '.duaer', 'specs')
270
+ if (!existsSync(root)) return []
271
+ return readdirSync(root)
272
+ .filter((name) => {
273
+ try {
274
+ return statSync(join(root, name)).isDirectory()
275
+ } catch {
276
+ return false
277
+ }
278
+ })
279
+ .sort()
280
+ .map((name) => {
281
+ const dir = join(root, name)
282
+ const specPath = join(dir, 'spec.md')
283
+ const tasksPath = join(dir, 'tasks.md')
284
+ const deliveryPath = join(dir, 'delivery.json')
285
+ const tasks = countOpenTasks(tasksPath)
286
+ const delivery = readDelivery(deliveryPath)
287
+ const hasSpec = existsSync(specPath)
288
+ const stamp = delivery?.status || 'none'
289
+ let verdict = 'accepted'
290
+ const blockers = []
291
+
292
+ if (!hasSpec) {
293
+ verdict = 'blocked'
294
+ blockers.push('missing spec.md')
295
+ }
296
+ if (tasks && tasks.open > 0) {
297
+ verdict = 'blocked'
298
+ blockers.push(`${tasks.open} open task(s)`)
299
+ }
300
+ if (stamp === 'open' || stamp === 'invalid') {
301
+ verdict = 'blocked'
302
+ blockers.push(`delivery.json status=${stamp}`)
303
+ }
304
+ if (hasSpec && tasks && tasks.open === 0 && (stamp === 'none' || !delivery)) {
305
+ // Brief exists and tasks clear, but never stamped by converge
306
+ verdict = 'unaccepted'
307
+ blockers.push('no delivery.json (run /duaer-converge)')
308
+ }
309
+ if (hasSpec && !tasks && (stamp === 'none' || !delivery)) {
310
+ verdict = 'unaccepted'
311
+ blockers.push('no tasks.md / no delivery.json')
312
+ }
313
+ if (stamp === 'accepted' && tasks && tasks.open === 0 && hasSpec) {
314
+ verdict = 'accepted'
315
+ blockers.length = 0
316
+ }
317
+
318
+ return {
319
+ name,
320
+ hasSpec,
321
+ tasks,
322
+ stamp,
323
+ verdict,
324
+ blockers,
325
+ }
326
+ })
327
+ }
328
+
329
+ function checkWorkplace(target) {
235
330
  const checks = [
236
331
  ['.duaer/memory/constitution.md', 'method'],
237
332
  ['DUADER.md', 'method'],
@@ -242,17 +337,95 @@ function cmdCheck(dir) {
242
337
  ['docs/agent/workflow.md', 'ops'],
243
338
  ]
244
339
  let missing = 0
245
- console.log(`Checking ${target}\n`)
340
+ console.log('## Workplace\n')
246
341
  for (const [rel, kind] of checks) {
247
342
  const ok = existsSync(join(target, rel))
248
343
  console.log(`${ok ? 'ok ' : 'MISS'} [${kind}] ${rel}`)
249
344
  if (!ok) missing++
250
345
  }
251
- if (missing) {
252
- console.log(`\n${missing} missing — run: duaer init ${dir} --all`)
253
- process.exitCode = 1
346
+ return missing
347
+ }
348
+
349
+ function checkDelivery(target, { gate }) {
350
+ const features = listFeatures(target)
351
+ console.log('\n## Delivery\n')
352
+ if (features.length === 0) {
353
+ console.log('ok no features under .duaer/specs/ (nothing to accept)')
354
+ return { blocked: 0, unaccepted: 0, features: 0 }
355
+ }
356
+
357
+ let blocked = 0
358
+ let unaccepted = 0
359
+ for (const f of features) {
360
+ const taskInfo = f.tasks
361
+ ? `tasks open=${f.tasks.open} done=${f.tasks.done}`
362
+ : 'no tasks.md'
363
+ const line = `${f.verdict.padEnd(10)} ${f.name} spec=${f.hasSpec ? 'yes' : 'NO'} stamp=${f.stamp} ${taskInfo}`
364
+ console.log(line)
365
+ if (f.blockers.length) {
366
+ for (const b of f.blockers) console.log(` · ${b}`)
367
+ }
368
+ if (f.verdict === 'blocked') blocked++
369
+ if (f.verdict === 'unaccepted') unaccepted++
370
+ }
371
+
372
+ if (gate) {
373
+ console.log('\nGate mode: every feature must be accepted.')
374
+ }
375
+ return { blocked, unaccepted, features: features.length }
376
+ }
377
+
378
+ function cmdCheck(opts) {
379
+ const target = resolve(opts.dir)
380
+ // Default: workplace + delivery. --gate alone is delivery-only (merge gate).
381
+ const runWorkplace = opts.workplace || (!opts.delivery && !opts.gate)
382
+ const runDelivery = opts.delivery || opts.gate || !opts.workplace
383
+
384
+ console.log(`Checking ${target}${opts.gate ? ' (gate)' : ''}\n`)
385
+
386
+ let workplaceMissing = 0
387
+ if (runWorkplace) {
388
+ workplaceMissing = checkWorkplace(target)
389
+ }
390
+
391
+ let delivery = { blocked: 0, unaccepted: 0, features: 0 }
392
+ if (runDelivery) {
393
+ delivery = checkDelivery(target, { gate: opts.gate })
394
+ }
395
+
396
+ let fail = false
397
+ if (workplaceMissing) {
398
+ console.log(`\n${workplaceMissing} workplace file(s) missing — run: duaer init ${opts.dir} --all`)
399
+ fail = true
400
+ }
401
+
402
+ if (runDelivery) {
403
+ if (delivery.blocked) {
404
+ console.log(`\n${delivery.blocked} feature(s) blocked — close open tasks / fix Spec / re-run converge`)
405
+ fail = true
406
+ }
407
+ if (opts.gate && delivery.unaccepted) {
408
+ console.log(
409
+ `\n${delivery.unaccepted} feature(s) not accepted — run /duaer-converge until delivery.json status=accepted`,
410
+ )
411
+ fail = true
412
+ } else if (!opts.gate && delivery.unaccepted) {
413
+ console.log(
414
+ `\n${delivery.unaccepted} feature(s) not yet accepted (warning). Use --gate to fail the merge check.`,
415
+ )
416
+ }
417
+ }
418
+
419
+ if (!fail) {
420
+ if (opts.gate) {
421
+ console.log('\nGate passed — deliverable.')
422
+ } else if (runWorkplace && !workplaceMissing) {
423
+ console.log('\nWorkplace ready. Use --gate before merge when features exist.')
424
+ } else {
425
+ console.log('\nDelivery report done.')
426
+ }
254
427
  } else {
255
- console.log('\nInstall looks complete.')
428
+ process.exitCode = 1
256
429
  }
257
430
  }
258
431
 
@@ -272,7 +445,7 @@ function main() {
272
445
  cmdInit(opts)
273
446
  break
274
447
  case 'check':
275
- cmdCheck(opts.dir)
448
+ cmdCheck(opts)
276
449
  break
277
450
  case 'version':
278
451
  case '--version':
@@ -1,7 +1,7 @@
1
1
  # Agent workflow (duaer-spec)
2
2
 
3
- Authoritative docs for *how* agents operate. Wins over Duaer and `examples/`
4
- when they conflict.
3
+ Authoritative docs for *how* digital employees operate (workplace policy).
4
+ Wins over Duaer and `examples/` when they conflict.
5
5
 
6
6
  | Doc | Description |
7
7
  |---|---|
@@ -94,6 +94,7 @@ See [spec update guidance](workflow.md#3-spec-update-guidance).
94
94
 
95
95
  ## 6. Merge / PR
96
96
 
97
+ - [ ] `duaer check . --gate` passed (or no `.duaer/specs/` features yet).
97
98
  - [ ] Branch refreshed against latest `main`.
98
99
  - [ ] Merged into local `main` (and/or remote PR/MR when required).
99
100
  - [ ] Only this request's logical changes included.
@@ -121,6 +122,7 @@ See [spec update guidance](workflow.md#3-spec-update-guidance).
121
122
  | 3 | Impacted specs updated | [R1](workflow.md#r1--spec-first--spec-sync) |
122
123
  | 4 | E2E docs updated or confirmed unnecessary | [R3](workflow.md#r3--e2e-coverage-doc) |
123
124
  | 5 | Targeted validation done or waived with reason | Development loop |
125
+ | 5a | `duaer check . --gate` when features exist | Delivery OS gate |
124
126
  | 6 | Conventional commits | [R2](workflow.md#r2--commit-per-change) |
125
127
  | 7 | No secrets or local data | [§4](workflow.md#4-what-never-to-commit) |
126
128
  | 8 | Merged into `main`; worktree and branch removed | [R4](workflow.md#r4--request-branch--worktree--merge-gate) · [§6.1](#61-merge-cleanup) |
@@ -20,9 +20,16 @@ Status: planned | automated | manual
20
20
 
21
21
  ## Catalog
22
22
 
23
+ This repository’s own product surface (CLI + docs). Adopters replace or extend
24
+ the table for their app.
25
+
23
26
  | ID | Title | Status |
24
27
  |---|---|---|
25
- | | *(replace with project scenarios)* | |
28
+ | E2E-001 | After `duaer init`, CLI prints hire → assign → accept next steps | manual |
29
+ | E2E-002 | README positions Duaer as delivery OS for digital employees | manual |
30
+ | E2E-003 | `duaer check --delivery` reports open tasks as blocked | manual |
31
+ | E2E-004 | `duaer check --gate` fails without `delivery.json` accepted | manual |
32
+ | E2E-005 | After converge stamps `accepted`, `--gate` passes | manual |
26
33
 
27
34
  ## Traceability
28
35
 
@@ -30,4 +37,8 @@ Keep this matrix current when scenarios or specs change.
30
37
 
31
38
  | Scenario | Spec / feature | Notes |
32
39
  |---|---|---|
33
- | | | |
40
+ | E2E-001 | `bin/duaer.mjs` init banner | Controllable-delivery onboarding |
41
+ | E2E-002 | `README.md` / `ADOPT.md` | Product identity |
42
+ | E2E-003 | `bin/duaer.mjs` delivery check | Open `- [ ]` tasks |
43
+ | E2E-004 | `bin/duaer.mjs` `--gate` | Merge gate |
44
+ | E2E-005 | `/duaer-converge` → `delivery.json` | Accept stamp |
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "duaer-spec",
3
- "version": "0.1.0",
4
- "description": "Duaer Spec-Driven Development methodology + agent ops for AI coding agents",
3
+ "version": "0.2.0",
4
+ "description": "Delivery OS for AI digital employees: Spec briefs, agent ops, check --gate handoffs",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "duaer": "bin/duaer.mjs",
@@ -36,11 +36,13 @@
36
36
  "homepage": "https://github.com/fujiezee/duaer-spec#readme",
37
37
  "keywords": [
38
38
  "duaer",
39
+ "digital-employee",
40
+ "delivery-os",
39
41
  "spec-driven",
40
42
  "agents",
41
43
  "cursor",
42
44
  "ai-engineering",
43
- "methodology"
45
+ "controllable-delivery"
44
46
  ],
45
47
  "license": "MIT",
46
48
  "scripts": {