duaer-spec 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.
Files changed (75) hide show
  1. package/.cursor/rules/agents-workflow.mdc +50 -0
  2. package/.cursor/rules/ai-ui-copy.mdc +12 -0
  3. package/.cursor/rules/duaer-spec.mdc +33 -0
  4. package/.cursor/skills/duaer-analyze/SKILL.md +259 -0
  5. package/.cursor/skills/duaer-checklist/SKILL.md +383 -0
  6. package/.cursor/skills/duaer-clarify/SKILL.md +291 -0
  7. package/.cursor/skills/duaer-constitution/SKILL.md +177 -0
  8. package/.cursor/skills/duaer-converge/SKILL.md +277 -0
  9. package/.cursor/skills/duaer-git-commit/SKILL.md +68 -0
  10. package/.cursor/skills/duaer-git-feature/SKILL.md +94 -0
  11. package/.cursor/skills/duaer-git-initialize/SKILL.md +54 -0
  12. package/.cursor/skills/duaer-git-remote/SKILL.md +50 -0
  13. package/.cursor/skills/duaer-git-validate/SKILL.md +54 -0
  14. package/.cursor/skills/duaer-implement/SKILL.md +226 -0
  15. package/.cursor/skills/duaer-plan/SKILL.md +166 -0
  16. package/.cursor/skills/duaer-specify/SKILL.md +345 -0
  17. package/.cursor/skills/duaer-tasks/SKILL.md +214 -0
  18. package/.cursor/skills/duaer-taskstoissues/SKILL.md +109 -0
  19. package/.duaer/extensions/.registry +23 -0
  20. package/.duaer/extensions/git/README.md +119 -0
  21. package/.duaer/extensions/git/commands/duaer.git.commit.md +63 -0
  22. package/.duaer/extensions/git/commands/duaer.git.feature.md +82 -0
  23. package/.duaer/extensions/git/commands/duaer.git.initialize.md +49 -0
  24. package/.duaer/extensions/git/commands/duaer.git.remote.md +45 -0
  25. package/.duaer/extensions/git/commands/duaer.git.validate.md +49 -0
  26. package/.duaer/extensions/git/config-template.yml +79 -0
  27. package/.duaer/extensions/git/extension.yml +142 -0
  28. package/.duaer/extensions/git/git-config.yml +79 -0
  29. package/.duaer/extensions/git/scripts/bash/auto-commit.sh +211 -0
  30. package/.duaer/extensions/git/scripts/bash/create-new-feature-branch.sh +626 -0
  31. package/.duaer/extensions/git/scripts/bash/git-common.sh +56 -0
  32. package/.duaer/extensions/git/scripts/bash/initialize-repo.sh +54 -0
  33. package/.duaer/extensions/git/scripts/powershell/auto-commit.ps1 +230 -0
  34. package/.duaer/extensions/git/scripts/powershell/create-new-feature-branch.ps1 +592 -0
  35. package/.duaer/extensions/git/scripts/powershell/git-common.ps1 +52 -0
  36. package/.duaer/extensions/git/scripts/powershell/initialize-repo.ps1 +69 -0
  37. package/.duaer/extensions/git/scripts/python/auto_commit.py +195 -0
  38. package/.duaer/extensions/git/scripts/python/create_new_feature_branch.py +634 -0
  39. package/.duaer/extensions/git/scripts/python/git_common.py +81 -0
  40. package/.duaer/extensions/git/scripts/python/initialize_repo.py +89 -0
  41. package/.duaer/extensions.yml +167 -0
  42. package/.duaer/init-options.json +9 -0
  43. package/.duaer/integration.json +15 -0
  44. package/.duaer/integrations/cursor-agent.manifest.json +17 -0
  45. package/.duaer/integrations/duaer.manifest.json +19 -0
  46. package/.duaer/memory/.constitution-template.json +4 -0
  47. package/.duaer/memory/constitution.md +37 -0
  48. package/.duaer/memory/project-context.md +24 -0
  49. package/.duaer/memory/testing.md +14 -0
  50. package/.duaer/scripts/bash/check-prerequisites.sh +243 -0
  51. package/.duaer/scripts/bash/common.sh +926 -0
  52. package/.duaer/scripts/bash/create-new-feature.sh +407 -0
  53. package/.duaer/scripts/bash/resolve-template.sh +57 -0
  54. package/.duaer/scripts/bash/setup-plan.sh +85 -0
  55. package/.duaer/scripts/bash/setup-tasks.sh +94 -0
  56. package/.duaer/templates/checklist-template.md +45 -0
  57. package/.duaer/templates/constitution-template.md +50 -0
  58. package/.duaer/templates/plan-template.md +113 -0
  59. package/.duaer/templates/spec-template.md +131 -0
  60. package/.duaer/templates/tasks-template.md +252 -0
  61. package/.duaer/workflows/duaer/workflow.yml +78 -0
  62. package/.duaer/workflows/workflow-registry.json +13 -0
  63. package/ADOPT.md +75 -0
  64. package/AGENTS.md +290 -0
  65. package/CHANGELOG.md +28 -0
  66. package/DUADER.md +57 -0
  67. package/LICENSE +21 -0
  68. package/README.md +74 -0
  69. package/bin/duaer.mjs +298 -0
  70. package/docs/agent/README.md +12 -0
  71. package/docs/agent/change-checklist.md +130 -0
  72. package/docs/agent/e2e-test-plan.md +33 -0
  73. package/docs/agent/workflow.md +127 -0
  74. package/docs/baseline.md +10 -0
  75. package/package.json +49 -0
package/bin/duaer.mjs ADDED
@@ -0,0 +1,298 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * duaer — CLI for the duaer-spec methodology
4
+ *
5
+ * duaer init [dir] [--all|--method|--ops] [--force] [--branch <name>]
6
+ * duaer check [dir]
7
+ * duaer version
8
+ * duaer help
9
+ */
10
+
11
+ import {
12
+ cpSync,
13
+ existsSync,
14
+ mkdirSync,
15
+ readFileSync,
16
+ readdirSync,
17
+ statSync,
18
+ writeFileSync,
19
+ } from 'node:fs'
20
+ import { dirname, join, resolve } from 'node:path'
21
+ import { fileURLToPath } from 'node:url'
22
+
23
+ const __dirname = dirname(fileURLToPath(import.meta.url))
24
+ const PKG_ROOT = resolve(__dirname, '..')
25
+ const PKG = JSON.parse(readFileSync(join(PKG_ROOT, 'package.json'), 'utf8'))
26
+
27
+ const USAGE = `duaer — Duaer methodology installer (duaer-spec ${PKG.version})
28
+
29
+ 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
34
+
35
+ 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)
39
+ --force Overwrite existing managed files
40
+ --branch <n> Integration branch for baseline note (default: main)
41
+ --here Same as dir=.
42
+
43
+ Examples:
44
+ npx github:fujiezee/duaer-spec duaer init --here
45
+ node bin/duaer.mjs init ../my-app --all
46
+ duaer check .
47
+ `
48
+
49
+ function parseArgs(argv) {
50
+ const args = argv.slice(2)
51
+ const out = {
52
+ cmd: args[0] || 'help',
53
+ dir: '.',
54
+ mode: 'all',
55
+ force: false,
56
+ branch: 'main',
57
+ }
58
+ const rest = args.slice(1)
59
+ for (let i = 0; i < rest.length; i++) {
60
+ const a = rest[i]
61
+ if (a === '--all') out.mode = 'all'
62
+ else if (a === '--method') out.mode = 'method'
63
+ else if (a === '--ops') out.mode = 'ops'
64
+ else if (a === '--force') out.force = true
65
+ else if (a === '--here') out.dir = '.'
66
+ else if (a === '--branch') {
67
+ out.branch = rest[++i]
68
+ if (!out.branch) throw new Error('--branch requires a value')
69
+ } else if (a.startsWith('-')) {
70
+ throw new Error(`Unknown flag: ${a}`)
71
+ } else {
72
+ out.dir = a
73
+ }
74
+ }
75
+ return out
76
+ }
77
+
78
+ function ensureDir(p) {
79
+ mkdirSync(p, { recursive: true })
80
+ }
81
+
82
+ function copyPath(from, to, { force }) {
83
+ if (!existsSync(from)) {
84
+ throw new Error(`Package missing required path: ${from}`)
85
+ }
86
+ if (existsSync(to) && !force) {
87
+ const st = statSync(to)
88
+ if (st.isDirectory()) {
89
+ // merge: copy children carefully
90
+ for (const name of readdirSync(from)) {
91
+ copyPath(join(from, name), join(to, name), { force })
92
+ }
93
+ return { skipped: false, merged: true }
94
+ }
95
+ console.log(`skip (exists): ${to} (use --force to overwrite)`)
96
+ return { skipped: true }
97
+ }
98
+ ensureDir(dirname(to))
99
+ cpSync(from, to, { recursive: true, force: true })
100
+ return { skipped: false }
101
+ }
102
+
103
+ function writeIfNeeded(path, content, { force }) {
104
+ if (existsSync(path) && !force) {
105
+ console.log(`skip (exists): ${path} (use --force to overwrite)`)
106
+ return
107
+ }
108
+ ensureDir(dirname(path))
109
+ writeFileSync(path, content, 'utf8')
110
+ console.log(`wrote ${path}`)
111
+ }
112
+
113
+ function installMethod(target, opts) {
114
+ console.log('Installing Duaer method…')
115
+ copyPath(join(PKG_ROOT, '.duaer'), join(target, '.duaer'), opts)
116
+ console.log(' .duaer/')
117
+
118
+ ensureDir(join(target, '.cursor', 'skills'))
119
+ const skillsRoot = join(PKG_ROOT, '.cursor', 'skills')
120
+ for (const name of readdirSync(skillsRoot)) {
121
+ if (!name.startsWith('duaer-')) continue
122
+ copyPath(join(skillsRoot, name), join(target, '.cursor', 'skills', name), opts)
123
+ }
124
+ console.log(' .cursor/skills/duaer-*')
125
+
126
+ ensureDir(join(target, '.cursor', 'rules'))
127
+ copyPath(
128
+ join(PKG_ROOT, '.cursor', 'rules', 'duaer-spec.mdc'),
129
+ join(target, '.cursor', 'rules', 'duaer-spec.mdc'),
130
+ opts,
131
+ )
132
+ console.log(' .cursor/rules/duaer-spec.mdc')
133
+
134
+ copyPath(join(PKG_ROOT, 'DUADER.md'), join(target, 'DUADER.md'), opts)
135
+ console.log(' DUADER.md')
136
+ }
137
+
138
+ function installOps(target, opts) {
139
+ console.log('Installing agent ops…')
140
+ copyPath(join(PKG_ROOT, 'AGENTS.md'), join(target, 'AGENTS.md'), opts)
141
+ console.log(' AGENTS.md')
142
+
143
+ ensureDir(join(target, '.cursor', 'rules'))
144
+ for (const name of ['agents-workflow.mdc', 'ai-ui-copy.mdc']) {
145
+ copyPath(
146
+ join(PKG_ROOT, '.cursor', 'rules', name),
147
+ join(target, '.cursor', 'rules', name),
148
+ opts,
149
+ )
150
+ }
151
+ console.log(' .cursor/rules/agents-workflow.mdc, ai-ui-copy.mdc')
152
+
153
+ ensureDir(join(target, 'docs', 'agent'))
154
+ for (const name of ['workflow.md', 'change-checklist.md', 'e2e-test-plan.md', 'README.md']) {
155
+ copyPath(
156
+ join(PKG_ROOT, 'docs', 'agent', name),
157
+ join(target, 'docs', 'agent', name),
158
+ opts,
159
+ )
160
+ }
161
+ console.log(' docs/agent/')
162
+
163
+ const baselineSrc = join(PKG_ROOT, 'docs', 'baseline.md')
164
+ const baselineDst = join(target, 'docs', 'baseline.md')
165
+ if (!existsSync(baselineDst) || opts.force) {
166
+ let text = readFileSync(baselineSrc, 'utf8')
167
+ text = text.replace(
168
+ /\*\*duaer-spec itself:\*\*[^\n]*/,
169
+ `**This project:** integration branch \`${opts.branch}\`; replace frozen decisions below.`,
170
+ )
171
+ if (!text.includes('Integration branch')) {
172
+ text += `\n\n## Integration branch\n\n\`${opts.branch}\`\n`
173
+ } else {
174
+ text = text.replace(/Integration branch[^\n]*/i, `Integration branch: \`${opts.branch}\``)
175
+ }
176
+ writeIfNeeded(baselineDst, text, opts)
177
+ } else {
178
+ console.log(`skip (exists): ${baselineDst}`)
179
+ }
180
+ }
181
+
182
+ function writeInitMarker(target, opts) {
183
+ const marker = join(target, '.duaer', 'duaer-init.json')
184
+ ensureDir(dirname(marker))
185
+ const payload = {
186
+ version: PKG.version,
187
+ installedAt: new Date().toISOString(),
188
+ mode: opts.mode,
189
+ branch: opts.branch,
190
+ source: 'duaer-spec',
191
+ }
192
+ writeFileSync(marker, JSON.stringify(payload, null, 2) + '\n')
193
+ console.log(' .duaer/duaer-init.json')
194
+ }
195
+
196
+ function cmdInit(opts) {
197
+ const target = resolve(opts.dir)
198
+ if (!existsSync(target)) {
199
+ ensureDir(target)
200
+ }
201
+ if (!statSync(target).isDirectory()) {
202
+ throw new Error(`Not a directory: ${target}`)
203
+ }
204
+
205
+ console.log(`Target: ${target}`)
206
+ console.log(`Mode: ${opts.mode}`)
207
+ console.log(`Branch: ${opts.branch}`)
208
+ console.log('')
209
+
210
+ if (opts.mode === 'all' || opts.mode === 'method') {
211
+ installMethod(target, opts)
212
+ }
213
+ if (opts.mode === 'all' || opts.mode === 'ops') {
214
+ installOps(target, opts)
215
+ }
216
+ if (opts.mode === 'all' || opts.mode === 'method') {
217
+ writeInitMarker(target, opts)
218
+ }
219
+
220
+ console.log(`
221
+ Done.
222
+
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
228
+
229
+ See DUADER.md and AGENTS.md in the target project.
230
+ `)
231
+ }
232
+
233
+ function cmdCheck(dir) {
234
+ const target = resolve(dir)
235
+ const checks = [
236
+ ['.duaer/memory/constitution.md', 'method'],
237
+ ['DUADER.md', 'method'],
238
+ ['.cursor/rules/duaer-spec.mdc', 'method'],
239
+ ['.cursor/skills/duaer-specify/SKILL.md', 'method'],
240
+ ['AGENTS.md', 'ops'],
241
+ ['.cursor/rules/agents-workflow.mdc', 'ops'],
242
+ ['docs/agent/workflow.md', 'ops'],
243
+ ]
244
+ let missing = 0
245
+ console.log(`Checking ${target}\n`)
246
+ for (const [rel, kind] of checks) {
247
+ const ok = existsSync(join(target, rel))
248
+ console.log(`${ok ? 'ok ' : 'MISS'} [${kind}] ${rel}`)
249
+ if (!ok) missing++
250
+ }
251
+ if (missing) {
252
+ console.log(`\n${missing} missing — run: duaer init ${dir} --all`)
253
+ process.exitCode = 1
254
+ } else {
255
+ console.log('\nInstall looks complete.')
256
+ }
257
+ }
258
+
259
+ function main() {
260
+ let opts
261
+ try {
262
+ opts = parseArgs(process.argv)
263
+ } catch (e) {
264
+ console.error(e.message)
265
+ console.error(USAGE)
266
+ process.exit(1)
267
+ }
268
+
269
+ try {
270
+ switch (opts.cmd) {
271
+ case 'init':
272
+ cmdInit(opts)
273
+ break
274
+ case 'check':
275
+ cmdCheck(opts.dir)
276
+ break
277
+ case 'version':
278
+ case '--version':
279
+ case '-v':
280
+ console.log(PKG.version)
281
+ break
282
+ case 'help':
283
+ case '--help':
284
+ case '-h':
285
+ console.log(USAGE)
286
+ break
287
+ default:
288
+ console.error(`Unknown command: ${opts.cmd}\n`)
289
+ console.log(USAGE)
290
+ process.exit(1)
291
+ }
292
+ } catch (e) {
293
+ console.error(e.message || e)
294
+ process.exit(1)
295
+ }
296
+ }
297
+
298
+ main()
@@ -0,0 +1,12 @@
1
+ # Agent workflow (duaer-spec)
2
+
3
+ Authoritative docs for *how* agents operate. Wins over Duaer and `examples/`
4
+ when they conflict.
5
+
6
+ | Doc | Description |
7
+ |---|---|
8
+ | [workflow.md](workflow.md) | Rules R1–R6, development loop, spec guidance |
9
+ | [change-checklist.md](change-checklist.md) | Finish checklist |
10
+ | [e2e-test-plan.md](e2e-test-plan.md) | E2E scenario catalog template |
11
+
12
+ Root contract: [`AGENTS.md`](../../AGENTS.md). Adoption: [`ADOPT.md`](../../ADOPT.md).
@@ -0,0 +1,130 @@
1
+ # Change Checklist
2
+
3
+ > Practical finish checklist for **duaer-spec** agent ops.
4
+ > Cross-references: [workflow](workflow.md) · [e2e-test-plan](e2e-test-plan.md) · [ADR index](../adr/README.md) · [AGENTS.md](../../AGENTS.md)
5
+
6
+ ---
7
+
8
+ ## 0. GitHub Issue Intake
9
+
10
+ When the prompt includes a GitHub issue URL or unambiguous issue number for
11
+ this repository:
12
+
13
+ - [ ] Issue title, body, labels, comments, and state were fetched.
14
+ - [ ] The reported problem was independently verified.
15
+ - [ ] Implementation started only after the problem was confirmed to exist.
16
+ - [ ] If the problem does not exist: verification comment; close when clear,
17
+ or leave open when inconclusive.
18
+ - [ ] After a confirmed fix was merged: resolution comment and close.
19
+ - [ ] Comment uses the issue's language.
20
+ - [ ] No unrelated issue was touched; push was not inferred from the link.
21
+
22
+ See [R5](workflow.md#r5--verify-linked-github-issues-before-work-then-reply-and-close).
23
+
24
+ ---
25
+
26
+ ## 0.1 GitHub Pull Request Intake
27
+
28
+ When the prompt includes a GitHub pull request URL or unambiguous PR number:
29
+
30
+ - [ ] PR metadata, files, commits, checks, draft state, and linked issues were
31
+ fetched.
32
+ - [ ] The **principle** was judged independently.
33
+ - [ ] Completeness gaps were not treated as merge blockers.
34
+ - [ ] If sound: merged first, preserving commits; follow-up only after `main`.
35
+ - [ ] If unsound or harmful: not merged; evidence commented; not reimplemented.
36
+ - [ ] Draft not merged unless the user explicitly asked.
37
+ - [ ] Comment uses the PR's language; no force-push of the contributor branch.
38
+
39
+ See [R6](workflow.md#r6--merge-a-linked-pull-request-whose-principle-is-sound-then-follow-up).
40
+
41
+ ---
42
+
43
+ ## 1. Request Start
44
+
45
+ - [ ] Existing uncommitted work is identified and preserved.
46
+ - [ ] `origin/main` fetched; local `main` fast-forwarded when clean.
47
+ - [ ] Dedicated `<type>/<short-description>` branch and worktree created from
48
+ that commit.
49
+ - [ ] Shared toolchains/caches reused where safe; mutable state stays local.
50
+ - [ ] Current branch is not `main` before implementation begins.
51
+
52
+ ---
53
+
54
+ ## 2. Impact Analysis
55
+
56
+ - [ ] What behavior changes?
57
+ - [ ] Which specs / Duaer features are affected? (list paths)
58
+ - [ ] Architectural boundary? (contracts, storage, security, public API)
59
+ - [ ] User-visible or protocol-visible?
60
+ - [ ] Smallest targeted validation set (or none, with reason)?
61
+
62
+ See [spec update guidance](workflow.md#3-spec-update-guidance).
63
+
64
+ ---
65
+
66
+ ## 3. Spec Sync
67
+
68
+ - [ ] Every affected spec is updated.
69
+ - [ ] Architectural boundary change → ADR under `docs/adr/`.
70
+ - [ ] Cross-references still correct (no stale links).
71
+
72
+ ---
73
+
74
+ ## 4. E2E / Test Docs
75
+
76
+ - [ ] User/protocol-visible change → scenario added or updated in the project's
77
+ E2E catalog ([template](e2e-test-plan.md)).
78
+ - [ ] Unit/integration tests updated when risk requires them.
79
+ - [ ] Targeted local checks passed, or assessed unnecessary.
80
+ - [ ] E2E suites run only if the user explicitly requested them (except fork
81
+ landing rules in `AGENTS.md`).
82
+
83
+ ---
84
+
85
+ ## 5. Git Commit
86
+
87
+ - [ ] One logical unit (or split into focused commits).
88
+ - [ ] No secrets, tokens, or local data.
89
+ - [ ] No build artifacts or dependency trees in the diff.
90
+ - [ ] Message: `type(scope): description` (English, imperative).
91
+ - [ ] `git diff --stat` reviewed — nothing unexpected.
92
+
93
+ ---
94
+
95
+ ## 6. Merge / PR
96
+
97
+ - [ ] Branch refreshed against latest `main`.
98
+ - [ ] Merged into local `main` (and/or remote PR/MR when required).
99
+ - [ ] Only this request's logical changes included.
100
+ - [ ] Push performed only if the user explicitly asked for this request.
101
+
102
+ ---
103
+
104
+ ## 6.1 Merge Cleanup
105
+
106
+ - [ ] Expected commits present in `main`.
107
+ - [ ] Request worktree clean.
108
+ - [ ] `git worktree remove <path>` succeeded without forcing.
109
+ - [ ] `git branch -d <branch>` succeeded (no `-D` on unmerged).
110
+ - [ ] `git worktree prune`; no stale entry for this request.
111
+ - [ ] No other agent's worktree or branch was removed.
112
+
113
+ ---
114
+
115
+ ## 7. Definition of Done
116
+
117
+ | # | Gate | Source |
118
+ |---|---|---|
119
+ | 1 | Branch + worktree from up-to-date `main` | [R4](workflow.md#r4--request-branch--worktree--merge-gate) |
120
+ | 2 | Change implements the planned work | [Development loop](workflow.md#2-development-loop) |
121
+ | 3 | Impacted specs updated | [R1](workflow.md#r1--spec-first--spec-sync) |
122
+ | 4 | E2E docs updated or confirmed unnecessary | [R3](workflow.md#r3--e2e-coverage-doc) |
123
+ | 5 | Targeted validation done or waived with reason | Development loop |
124
+ | 6 | Conventional commits | [R2](workflow.md#r2--commit-per-change) |
125
+ | 7 | No secrets or local data | [§4](workflow.md#4-what-never-to-commit) |
126
+ | 8 | Merged into `main`; worktree and branch removed | [R4](workflow.md#r4--request-branch--worktree--merge-gate) · [§6.1](#61-merge-cleanup) |
127
+ | 9 | Linked issue: verified, commented, closed when conclusive | [R5](workflow.md#r5--verify-linked-github-issues-before-work-then-reply-and-close) |
128
+ | 10 | Linked PR: principle reviewed; merged when sound; follow-up after | [R6](workflow.md#r6--merge-a-linked-pull-request-whose-principle-is-sound-then-follow-up) |
129
+
130
+ If any gate fails, the change is **not Done**.
@@ -0,0 +1,33 @@
1
+ # E2E test plan (template)
2
+
3
+ Each adopting project should maintain its own E2E scenario catalog. This file is
4
+ a **template** for that catalog — not a product suite.
5
+
6
+ When a change is user-visible or protocol-visible, add or update a scenario
7
+ before or alongside the change (see [R3](workflow.md#r3--e2e-coverage-doc)).
8
+
9
+ ## Scenario template
10
+
11
+ ```text
12
+ ID: E2E-NNN
13
+ Title: Short name
14
+ Preconditions:
15
+ Steps:
16
+ Expected:
17
+ Specs: Links to specs / Duaer feature dirs
18
+ Status: planned | automated | manual
19
+ ```
20
+
21
+ ## Catalog
22
+
23
+ | ID | Title | Status |
24
+ |---|---|---|
25
+ | — | *(replace with project scenarios)* | — |
26
+
27
+ ## Traceability
28
+
29
+ Keep this matrix current when scenarios or specs change.
30
+
31
+ | Scenario | Spec / feature | Notes |
32
+ |---|---|---|
33
+ | — | — | — |
@@ -0,0 +1,127 @@
1
+ # AI-Assisted Development Workflow
2
+
3
+ > Scope: **duaer-spec** agent ops (adoptable by other repositories)
4
+ > Status: Accepted
5
+ > Precedence: this document and root `AGENTS.md` win over Duaer / examples
6
+ > Cross-references: [baseline](../baseline.md) · [e2e-test-plan](e2e-test-plan.md) · [change-checklist](change-checklist.md) · [ADR index](../adr/README.md) · [ADOPT](../../ADOPT.md)
7
+
8
+ ---
9
+
10
+ ## 1. Core Immutable Rules
11
+
12
+ R1–R4 restate the numbered Immutable Rules in `AGENTS.md` (R4 covers merge-back
13
+ and worktree clean-up). R5 and R6 restate GitHub issue and pull request
14
+ handling. They cannot be relaxed without explicit human override.
15
+
16
+ ### R1 — Spec-first / Spec-sync
17
+
18
+ > **No behavior change without updating the corresponding spec.**
19
+
20
+ - Every change that alters observable behavior must update the relevant
21
+ specification (project `docs/spec/`, Duaer feature specs, or
22
+ `docs/agent/` when changing duaer-spec itself).
23
+ - Architectural boundary changes also require an ADR under `docs/adr/`.
24
+ - Pure refactors that preserve behavior and contracts do not require spec
25
+ updates, but must still be committed (R2).
26
+
27
+ ### R2 — Commit-per-change
28
+
29
+ > **Every completed logical change must be git committed.**
30
+
31
+ - One logical unit per commit. No large uncommitted piles at session end.
32
+ - Incomplete work: commit as `WIP:` draft or roll it back.
33
+
34
+ ### R3 — E2E coverage doc
35
+
36
+ > **User-visible or protocol-visible changes must update E2E scenario docs.**
37
+
38
+ - Document scenarios in the project's E2E catalog (see
39
+ [e2e-test-plan](e2e-test-plan.md)).
40
+ - Internal-only changes (logging format, private renames) do not require it.
41
+
42
+ ### R4 — Request branch + worktree + merge gate
43
+
44
+ > **Every new request starts from `main` in a dedicated worktree on a dedicated
45
+ > branch and finishes only after it is merged into `main`.**
46
+
47
+ - Before editing: preserve existing uncommitted work; fetch and fast-forward
48
+ local `main` when clean; create a new request branch and worktree from that
49
+ commit. Never stash or overwrite another agent's work merely to start.
50
+ - Name branches `<type>/<short-description>` (for example `feat/adopt-docs`).
51
+ - Do not implement in the primary checkout or reuse another request's worktree.
52
+ - Reuse shared toolchains and caches where safe; keep mutable or
53
+ concurrency-sensitive state worktree-local and ignored.
54
+ - After validation: merge into local `main` (or via PR/MR when required), then
55
+ remove the request worktree and delete the merged branch immediately.
56
+ - Push only when the user explicitly requests remote publishing for this
57
+ request.
58
+
59
+ Adopting projects may replace `main` with another integration branch; document
60
+ it in the project baseline. **duaer-spec itself uses `main`.** Example overlays
61
+ under `examples/` do not change this repo's default.
62
+
63
+ ### R5 — Verify linked GitHub issues before work, then reply and close
64
+
65
+ > **A linked GitHub issue is not a task until the reported problem is shown to
66
+ > exist. After a conclusive outcome, reply and close.**
67
+
68
+ Applies when the prompt includes a GitHub issue URL or unambiguous issue number
69
+ for this repository. Comment in the issue's language. An issue link does not
70
+ authorize push.
71
+
72
+ ### R6 — Merge a linked pull request whose principle is sound, then follow up
73
+
74
+ > **Judge principle first. Merge that PR when sound; completeness is follow-up.**
75
+
76
+ Do not silently reimplement. Do not force-push the contributor branch. Draft
77
+ PRs stay unmerged unless the user explicitly asks. A PR link does not authorize
78
+ unrelated pushes.
79
+
80
+ ---
81
+
82
+ ## 2. Development Loop
83
+
84
+ 1. **Intake** — If an issue or PR is linked, complete R5 / R6 first.
85
+ 2. **Isolate** — Update `main`, create branch + worktree (R4).
86
+ 3. **Orient** — Read baseline, relevant specs, and Duaer memory when present.
87
+ 4. **Specify (when using Duaer)** — Feature / hotfix specs before coding.
88
+ 5. **Implement** — Smallest coherent change; update specs alongside (R1).
89
+ 6. **Verify** — Targeted checks; E2E runs only if the user asks (except fork
90
+ landing rules in `AGENTS.md`).
91
+ 7. **Commit** — One logical change per commit (R2).
92
+ 8. **Merge & clean** — Refresh against `main`, merge, remove worktree (R4 / R5).
93
+ 9. **Report** — Use the Final Report section in `AGENTS.md`.
94
+
95
+ ---
96
+
97
+ ## 3. Spec Update Guidance
98
+
99
+ | Change type | Spec sync | ADR |
100
+ |---|---|---|
101
+ | User-visible or protocol-visible behavior | Required | If architecture / contracts / security boundaries change |
102
+ | Internal refactor, same behavior | Not required | No |
103
+ | New public interface or data ownership | Required | Required |
104
+ | Docs-only / standards-only in this repo | Update `docs/` / `AGENTS.md` as needed | If a frozen decision changes |
105
+
106
+ Prefer Duaer feature directories for product feature work. Prefer `docs/agent/`
107
+ when changing duaer-spec's own agent-ops contract.
108
+
109
+ ---
110
+
111
+ ## 4. What Never to Commit
112
+
113
+ - Secrets, tokens, credentials, private keys
114
+ - Local databases, caches, build artifacts, `node_modules/`
115
+ - Machine-specific paths or environment files with secrets
116
+ - Unrelated changes from another request or agent
117
+
118
+ ---
119
+
120
+ ## 5. Duaer Relationship
121
+
122
+ - **Agent ops** (`AGENTS.md`, this file): isolation, commits, Issue/PR, merge.
123
+ - **Duaer** (repo root `.duaer/`, `DUADER.md`): what to build — specify →
124
+ plan → tasks → implement → converge.
125
+
126
+ When they conflict, **agent ops win**. Install and conventions:
127
+ [DUADER.md](../../DUADER.md) · [ADOPT.md](../../ADOPT.md).
@@ -0,0 +1,10 @@
1
+ # Baseline (project-specific)
2
+
3
+ Frozen decisions for the adopting project: language, stack, architecture
4
+ boundaries, and integration-branch override (if not `main`).
5
+
6
+ **duaer-spec itself:** English docs and commits; integration branch `main`;
7
+ no application runtime.
8
+
9
+ When you copy agent ops into another repository, replace this file with that
10
+ product's baseline (or point agents at the project's existing baseline path).
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "duaer-spec",
3
+ "version": "0.1.0",
4
+ "description": "Duaer Spec-Driven Development methodology + agent ops for AI coding agents",
5
+ "type": "module",
6
+ "bin": {
7
+ "duaer": "bin/duaer.mjs",
8
+ "duaer-spec": "bin/duaer.mjs"
9
+ },
10
+ "files": [
11
+ "bin",
12
+ ".duaer",
13
+ ".cursor",
14
+ "AGENTS.md",
15
+ "DUADER.md",
16
+ "ADOPT.md",
17
+ "CHANGELOG.md",
18
+ "docs/agent",
19
+ "docs/baseline.md",
20
+ "LICENSE",
21
+ "README.md"
22
+ ],
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "engines": {
27
+ "node": ">=18"
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/fujiezee/duaer-spec.git"
32
+ },
33
+ "bugs": {
34
+ "url": "https://github.com/fujiezee/duaer-spec/issues"
35
+ },
36
+ "homepage": "https://github.com/fujiezee/duaer-spec#readme",
37
+ "keywords": [
38
+ "duaer",
39
+ "spec-driven",
40
+ "agents",
41
+ "cursor",
42
+ "ai-engineering",
43
+ "methodology"
44
+ ],
45
+ "license": "MIT",
46
+ "scripts": {
47
+ "duaer": "node ./bin/duaer.mjs"
48
+ }
49
+ }