deepmodel-dmx 0.3.2__tar.gz → 0.3.4__tar.gz
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.
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/CHANGELOG.md +19 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/PKG-INFO +107 -4
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/README.md +106 -3
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/pyproject.toml +1 -1
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/loop_tools.py +135 -2
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/loops/release.yaml +0 -1
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/utility/dmx-update-memory.md +24 -1
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/workflow/1-triage/dmx-create-ticket.md +34 -12
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/workflow/5-ship/dmx-close-ticket.md +6 -2
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/workflow/6-release/dmx-draft-release-note.md +32 -1
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/validators/check_pr_ready.py +35 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/validators/check_spec_complete.py +1 -1
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/tests/test_loop_integration.py +6 -8
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/tests/test_loop_tools.py +208 -1
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/tests/test_validators.py +70 -1
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/uv.lock +1 -1
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/.editorconfig +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/.github/dependabot.yml +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/.github/workflows/publish.yml +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/.github/workflows/test.yml +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/.gitignore +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/.pre-commit-config.yaml +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/CLA.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/CONTRIBUTING.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/LICENSE +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/SECURITY.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/__init__.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/_workflow_version.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/catalog.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/cli.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/exceptions.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/http_auth.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/ide/__init__.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/ide/detect.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/ide/emitters.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/loop_memory.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/loop_schema.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/loop_state.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/loops/__init__.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/loops/dev.yaml +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/loops/plan.yaml +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/loops/spec.yaml +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/loops/validate.yaml +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/repeat_until.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/rules/system-prompt.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/server.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/loop/dmx-loop-continue.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/loop/dmx-run-loop.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/specialist/dmx-docs.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/specialist/dmx-review.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/specialist/dmx-secure.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/specialist/dmx-test.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/utility/dmx-commit.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/utility/dmx-create-branch.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/utility/dmx-draft-pr-description.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/utility/dmx-status.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/utility/dmx-sync-branch.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/workflow/0-init/dmx-init.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/workflow/1-triage/dmx-derive-ticket.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/workflow/1-triage/dmx-hotfix.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/workflow/2-plan/dmx-plan.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/workflow/3-build/dmx-implement-next-phase.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/workflow/3-build/dmx-implement-next-task.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/workflow/4-validate/dmx-validate.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/workflow/5-ship/dmx-create-pr.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/workflow/6-release/dmx-create-release.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/workflow/6-release/dmx-release-merge.md +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/tools.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/validator_runner.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/validators/__init__.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/validators/check_plan_complete.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/validators/run_tests.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/validators/spec_adherence.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/workspace.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/tests/__init__.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/tests/__snapshots__/test_ide.ambr +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/tests/conftest.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/tests/test_catalog.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/tests/test_cli.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/tests/test_ide.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/tests/test_loop_memory.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/tests/test_loop_schema.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/tests/test_loop_state.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/tests/test_repeat_until.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/tests/test_server.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/tests/test_tools.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/tests/test_validator_runner.py +0 -0
- {deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/tests/test_workspace.py +0 -0
|
@@ -7,6 +7,25 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [Unreleased]
|
|
11
|
+
|
|
12
|
+
## [0.3.4] — 2026-09-08
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Loop run state (`.dmx/jobs/{job_id}/*.json`) and the session-note breadcrumb `_finish_loop` writes to `activeContext.md` are now committed once a loop run genuinely finishes (not `paused`/`iterating`), instead of being left as an uncommitted, local-only change — matching the README's documented "committed with the PR" contract for `jobs/`. This mattered most for the bundled `release` loop, which has no `on_complete` chain target: nothing downstream ran to commit its final state, and `close-ticket` explicitly makes no `.dmx/` changes before force-deleting the branch, so the loop's own "complete" outcome was silently and permanently lost every time. Silent no-op outside a git repo or when there's nothing to commit; if a commit is attempted but fails (e.g. rejected by a pre-commit hook), the loop's own response now surfaces a warning instead of only logging it server-side, and every git call is timeout-bounded so a hung `git commit` (e.g. waiting on a GPG passphrase) can't hang the whole MCP tool call. (GH-23)
|
|
17
|
+
- `close-ticket` no longer transitions the ticket to Done/Complete (or adds the "PR merged" comment) unless Step 4 actually found a merged PR for the branch — previously the transition step ran unconditionally, so running `/dmx/close-ticket` while a PR was still open could mark the ticket Done before the code had actually merged. Also hardened the transition itself to treat an already-terminal ticket/issue as a no-op success rather than an error (idempotent for `github-issues`' auto-close-via-`Closes #N`, and for Jira setups where a GitHub↔Jira integration already auto-transitioned the ticket). (GH-21)
|
|
18
|
+
- `draft-release-note` now commits and pushes `.dmx/releases/{version}.md` after writing it, instead of leaving it as an uncommitted local file. `release-merge` opens its PR straight from `{branch_base}`'s pushed state, so the release notes file was previously silently absent from that PR's diff whenever it hadn't been committed by hand first. Re-running it against unchanged content (nothing new merged) is a no-op rather than failing on "nothing to commit". (GH-22)
|
|
19
|
+
- Starting the `spec` loop, or running `/dmx/create-ticket` manually, on a repository with zero commits now surfaces a clear, actionable error instead of a confusing one. Previously, `current_branch()` (which shells out to `git rev-parse --abbrev-ref HEAD`) silently returned `None` on a freshly `git init`'d repo's unborn `HEAD`, causing the `spec` loop's branch guard to fail with a generic "could not determine the current git branch" message — even though the branch name itself was perfectly resolvable. `_branch_guard_error` now distinguishes this specific case and tells the user to commit and push before retrying. `dmx-create-ticket.md` gained the same check as its new Step 2, so manual/foreground usage fails fast before creating a ticket or attempting to branch, rather than failing later when GitHub's `create_branch` API rejects branching from a ref-less remote. (GH-19)
|
|
20
|
+
|
|
21
|
+
## [0.3.3] — 2026-09-02
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- The bundled `release` loop no longer runs `update-memory` after `create-pr` has already opened the PR — `create-pr` already performs its own memory-bank sync and commit (Steps 4-5), so chaining `update-memory` immediately after left its edits (further inbox promotions, `activeContext.md` rewrites) as dangling uncommitted changes never included in the PR, and silently discarded later by `close-ticket`'s branch deletion. `release.yaml` now runs `create-pr` only.
|
|
26
|
+
- `update-memory` now commits its own changes at the end of its instructions, so it can never leave dangling uncommitted `.dmx/` state regardless of when or how it's invoked in the future.
|
|
27
|
+
- `check_pr_ready`'s `memory_updated` check now fails if `.dmx/` has any uncommitted changes (staged or not), instead of only checking the latest commit or the mere existence of `activeContext.md` — a loop-config ordering mistake now surfaces loudly instead of silently passing. (GH-15)
|
|
28
|
+
|
|
10
29
|
## [0.3.2] — 2026-08-31
|
|
11
30
|
|
|
12
31
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: deepmodel-dmx
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: AI SDLC MCP server — skills and rules for any AI IDE.
|
|
5
5
|
License: AGPL-3.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -90,7 +90,7 @@ Bundled loops for the SDLC pipeline:
|
|
|
90
90
|
| `plan` | plan | `dev` |
|
|
91
91
|
| `dev` | implement-next-phase, commit | `validate` |
|
|
92
92
|
| `validate` | validate | `release` |
|
|
93
|
-
| `release` | create-pr
|
|
93
|
+
| `release` | create-pr | — |
|
|
94
94
|
|
|
95
95
|
Each loop config defines a goal state, optional `repeat_until` condition, validators, human gate policy, and `on_complete` chaining. Run state is written to `.dmx/jobs/{job_id}/{loop_name}-{task_id}.json` — there's no separate active-run pointer; the active run is derived by scanning a job's state files for the one non-terminal (`pending`/`running`/`paused`/`iterating`) entry, keyed off the current branch/ticket. This keeps loop state isolated per branch: pausing work on one branch and running a loop on another can't corrupt or lose either one's state.
|
|
96
96
|
|
|
@@ -121,12 +121,111 @@ Loop-level memory hooks: before the first skill runs, the runtime surfaces `acti
|
|
|
121
121
|
}
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
-
Add to your IDE config ([Claude Code, Copilot, Antigravity ↓](#step-1--add-the-mcp-server)).
|
|
124
|
+
Add to your IDE config ([Claude Code, Copilot, Antigravity ↓](#step-1--add-the-mcp-server)). Then follow [Your first project](#your-first-project) to initialize and run the full loop on a new repo.
|
|
125
|
+
|
|
126
|
+
## Your first project
|
|
127
|
+
|
|
128
|
+
A brand-new repo, from `/dmx/init` through the first merged PR. You review at every gate; `/dmx/loop-continue` is how you move forward.
|
|
129
|
+
|
|
130
|
+
### Before you start
|
|
131
|
+
|
|
132
|
+
- A GitHub repo cloned locally with an `origin` remote. The spec loop creates the feature branch on GitHub from `origin/{branch_base}` (usually `main` or `master`), even if you track work in Jira or use no ticketing system.
|
|
133
|
+
- The dmx MCP server added to your IDE ([install guide](#step-1--add-the-mcp-server)).
|
|
134
|
+
- The GitHub MCP server (`user-github`) authenticated. `/dmx/init` probes it before writing any files.
|
|
135
|
+
- The Atlassian MCP server only if you will choose Jira at init.
|
|
136
|
+
|
|
137
|
+
### 1. Initialize
|
|
138
|
+
|
|
139
|
+
On the integration branch (`main` or `master`):
|
|
125
140
|
|
|
126
141
|
```
|
|
127
|
-
/dmx/
|
|
142
|
+
/dmx/init
|
|
128
143
|
```
|
|
129
144
|
|
|
145
|
+
Choose a workflow — **sdlc** (this walkthrough) or **freestyle** (no process enforced) — and a ticketing system: `none`, `github-issues`, or `jira`. Re-run `/dmx/init` at any time to switch workflow or ticketing; existing memory bank files with content are left intact.
|
|
146
|
+
|
|
147
|
+
Init writes `.dmx/config.md` and the memory bank (`projectbrief.md`, `productContext.md`, `systemPatterns.md`, `techContext.md`, `activeContext.md`). Open a **new chat** so the IDE rules take effect.
|
|
148
|
+
|
|
149
|
+
If you already have a `docs/` folder, init reads it when populating the memory bank. Writing the requirement first is slightly better; either order works.
|
|
150
|
+
|
|
151
|
+
### 2. Write the product requirement
|
|
152
|
+
|
|
153
|
+
Create `docs/requirements.md` at the repo root and put the product or feature description there. You can paste the requirement into chat later instead, but a file is easier to review and reuse.
|
|
154
|
+
|
|
155
|
+
`docs/requirements.md` is a convention, not a dmx artifact. The spec loop uses whatever you point it at.
|
|
156
|
+
|
|
157
|
+
### 3. Commit and push
|
|
158
|
+
|
|
159
|
+
The spec loop must start from the configured integration branch, and it creates the remote feature branch from whatever is already on origin. Commit `.dmx/`, `docs/`, and any files init wrote, then push:
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
git add .
|
|
163
|
+
git commit -m "chore: initialize dmx and capture product requirements"
|
|
164
|
+
git push -u origin HEAD
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Stay on `main` or `master`.
|
|
168
|
+
|
|
169
|
+
### 4. Start the spec loop
|
|
170
|
+
|
|
171
|
+
In the same message as the command, point at the requirement file or paste it:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
/dmx/run-loop spec
|
|
175
|
+
|
|
176
|
+
See docs/requirements.md
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
This creates a GitHub issue or Jira ticket (if you configured one), cuts a feature branch from `origin/{branch_base}`, checks it out, and writes `.dmx/spec.md`. Then it pauses.
|
|
180
|
+
|
|
181
|
+
### 5. Answer the spec
|
|
182
|
+
|
|
183
|
+
Open `.dmx/spec.md`. Fill in Technical Approach if it is incomplete, and answer every question. Empty answers or placeholders (`TBD`, `TODO`) fail the spec validator.
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
/dmx/loop-continue
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
On success the runtime auto-chains to the `plan` loop.
|
|
190
|
+
|
|
191
|
+
### 6. Review the plan
|
|
192
|
+
|
|
193
|
+
`plan` writes `.dmx/tasks.md` with phases and tasks, then pauses. Edit freely — this is the implementation contract.
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
/dmx/loop-continue
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
That starts the `dev` loop.
|
|
200
|
+
|
|
201
|
+
### 7. Build phase by phase
|
|
202
|
+
|
|
203
|
+
Each `dev` cycle:
|
|
204
|
+
|
|
205
|
+
1. Implements the next unchecked phase in `tasks.md`, then pauses.
|
|
206
|
+
2. Review the diff.
|
|
207
|
+
3. `/dmx/loop-continue` runs **commit only**. It does not push.
|
|
208
|
+
4. Review the commit.
|
|
209
|
+
5. `/dmx/loop-continue` again — validators run, then either the next phase starts or the loop chains to `validate`.
|
|
210
|
+
|
|
211
|
+
Repeat until every phase is checked off.
|
|
212
|
+
|
|
213
|
+
### 8. Validate and open the PR
|
|
214
|
+
|
|
215
|
+
After the last phase, `validate` runs the quality gate and pauses. Review the report, then `/dmx/loop-continue`. On success the `release` loop runs `create-pr`: it pushes the feature branch and opens the pull request.
|
|
216
|
+
|
|
217
|
+
### 9. Merge and close
|
|
218
|
+
|
|
219
|
+
Review the PR and merge it. Then:
|
|
220
|
+
|
|
221
|
+
```
|
|
222
|
+
/dmx/close-ticket
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
That closes the ticket, comments the PR link, and deletes the feature branch locally and on origin. `/dmx/loop-continue` after merge is not a close path — the release loop ends when the PR exists.
|
|
226
|
+
|
|
227
|
+
You can run the same steps by hand (`/dmx/create-ticket`, `/dmx/plan`, `/dmx/implement-next-phase`, …) instead of loops. See the skill catalog below.
|
|
228
|
+
|
|
130
229
|
## Learn more
|
|
131
230
|
|
|
132
231
|
- [When Is a Loop Ready to Run Without You?](https://himakara.hashnode.dev/when-is-a-loop-ready-to-run-without-you) — the thinking behind dmx
|
|
@@ -208,6 +307,10 @@ Safe to re-run. Updates config without overwriting memory bank files that alread
|
|
|
208
307
|
|
|
209
308
|
### Step 3 — Start your first ticket
|
|
210
309
|
|
|
310
|
+
On a new repo, follow [Your first project](#your-first-project) (`/dmx/run-loop spec` through `/dmx/close-ticket`).
|
|
311
|
+
|
|
312
|
+
To start a ticket by hand instead:
|
|
313
|
+
|
|
211
314
|
```
|
|
212
315
|
/dmx/create-ticket
|
|
213
316
|
```
|
|
@@ -55,7 +55,7 @@ Bundled loops for the SDLC pipeline:
|
|
|
55
55
|
| `plan` | plan | `dev` |
|
|
56
56
|
| `dev` | implement-next-phase, commit | `validate` |
|
|
57
57
|
| `validate` | validate | `release` |
|
|
58
|
-
| `release` | create-pr
|
|
58
|
+
| `release` | create-pr | — |
|
|
59
59
|
|
|
60
60
|
Each loop config defines a goal state, optional `repeat_until` condition, validators, human gate policy, and `on_complete` chaining. Run state is written to `.dmx/jobs/{job_id}/{loop_name}-{task_id}.json` — there's no separate active-run pointer; the active run is derived by scanning a job's state files for the one non-terminal (`pending`/`running`/`paused`/`iterating`) entry, keyed off the current branch/ticket. This keeps loop state isolated per branch: pausing work on one branch and running a loop on another can't corrupt or lose either one's state.
|
|
61
61
|
|
|
@@ -86,12 +86,111 @@ Loop-level memory hooks: before the first skill runs, the runtime surfaces `acti
|
|
|
86
86
|
}
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
Add to your IDE config ([Claude Code, Copilot, Antigravity ↓](#step-1--add-the-mcp-server)).
|
|
89
|
+
Add to your IDE config ([Claude Code, Copilot, Antigravity ↓](#step-1--add-the-mcp-server)). Then follow [Your first project](#your-first-project) to initialize and run the full loop on a new repo.
|
|
90
|
+
|
|
91
|
+
## Your first project
|
|
92
|
+
|
|
93
|
+
A brand-new repo, from `/dmx/init` through the first merged PR. You review at every gate; `/dmx/loop-continue` is how you move forward.
|
|
94
|
+
|
|
95
|
+
### Before you start
|
|
96
|
+
|
|
97
|
+
- A GitHub repo cloned locally with an `origin` remote. The spec loop creates the feature branch on GitHub from `origin/{branch_base}` (usually `main` or `master`), even if you track work in Jira or use no ticketing system.
|
|
98
|
+
- The dmx MCP server added to your IDE ([install guide](#step-1--add-the-mcp-server)).
|
|
99
|
+
- The GitHub MCP server (`user-github`) authenticated. `/dmx/init` probes it before writing any files.
|
|
100
|
+
- The Atlassian MCP server only if you will choose Jira at init.
|
|
101
|
+
|
|
102
|
+
### 1. Initialize
|
|
103
|
+
|
|
104
|
+
On the integration branch (`main` or `master`):
|
|
90
105
|
|
|
91
106
|
```
|
|
92
|
-
/dmx/
|
|
107
|
+
/dmx/init
|
|
93
108
|
```
|
|
94
109
|
|
|
110
|
+
Choose a workflow — **sdlc** (this walkthrough) or **freestyle** (no process enforced) — and a ticketing system: `none`, `github-issues`, or `jira`. Re-run `/dmx/init` at any time to switch workflow or ticketing; existing memory bank files with content are left intact.
|
|
111
|
+
|
|
112
|
+
Init writes `.dmx/config.md` and the memory bank (`projectbrief.md`, `productContext.md`, `systemPatterns.md`, `techContext.md`, `activeContext.md`). Open a **new chat** so the IDE rules take effect.
|
|
113
|
+
|
|
114
|
+
If you already have a `docs/` folder, init reads it when populating the memory bank. Writing the requirement first is slightly better; either order works.
|
|
115
|
+
|
|
116
|
+
### 2. Write the product requirement
|
|
117
|
+
|
|
118
|
+
Create `docs/requirements.md` at the repo root and put the product or feature description there. You can paste the requirement into chat later instead, but a file is easier to review and reuse.
|
|
119
|
+
|
|
120
|
+
`docs/requirements.md` is a convention, not a dmx artifact. The spec loop uses whatever you point it at.
|
|
121
|
+
|
|
122
|
+
### 3. Commit and push
|
|
123
|
+
|
|
124
|
+
The spec loop must start from the configured integration branch, and it creates the remote feature branch from whatever is already on origin. Commit `.dmx/`, `docs/`, and any files init wrote, then push:
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
git add .
|
|
128
|
+
git commit -m "chore: initialize dmx and capture product requirements"
|
|
129
|
+
git push -u origin HEAD
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Stay on `main` or `master`.
|
|
133
|
+
|
|
134
|
+
### 4. Start the spec loop
|
|
135
|
+
|
|
136
|
+
In the same message as the command, point at the requirement file or paste it:
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
/dmx/run-loop spec
|
|
140
|
+
|
|
141
|
+
See docs/requirements.md
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
This creates a GitHub issue or Jira ticket (if you configured one), cuts a feature branch from `origin/{branch_base}`, checks it out, and writes `.dmx/spec.md`. Then it pauses.
|
|
145
|
+
|
|
146
|
+
### 5. Answer the spec
|
|
147
|
+
|
|
148
|
+
Open `.dmx/spec.md`. Fill in Technical Approach if it is incomplete, and answer every question. Empty answers or placeholders (`TBD`, `TODO`) fail the spec validator.
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
/dmx/loop-continue
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
On success the runtime auto-chains to the `plan` loop.
|
|
155
|
+
|
|
156
|
+
### 6. Review the plan
|
|
157
|
+
|
|
158
|
+
`plan` writes `.dmx/tasks.md` with phases and tasks, then pauses. Edit freely — this is the implementation contract.
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
/dmx/loop-continue
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
That starts the `dev` loop.
|
|
165
|
+
|
|
166
|
+
### 7. Build phase by phase
|
|
167
|
+
|
|
168
|
+
Each `dev` cycle:
|
|
169
|
+
|
|
170
|
+
1. Implements the next unchecked phase in `tasks.md`, then pauses.
|
|
171
|
+
2. Review the diff.
|
|
172
|
+
3. `/dmx/loop-continue` runs **commit only**. It does not push.
|
|
173
|
+
4. Review the commit.
|
|
174
|
+
5. `/dmx/loop-continue` again — validators run, then either the next phase starts or the loop chains to `validate`.
|
|
175
|
+
|
|
176
|
+
Repeat until every phase is checked off.
|
|
177
|
+
|
|
178
|
+
### 8. Validate and open the PR
|
|
179
|
+
|
|
180
|
+
After the last phase, `validate` runs the quality gate and pauses. Review the report, then `/dmx/loop-continue`. On success the `release` loop runs `create-pr`: it pushes the feature branch and opens the pull request.
|
|
181
|
+
|
|
182
|
+
### 9. Merge and close
|
|
183
|
+
|
|
184
|
+
Review the PR and merge it. Then:
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
/dmx/close-ticket
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
That closes the ticket, comments the PR link, and deletes the feature branch locally and on origin. `/dmx/loop-continue` after merge is not a close path — the release loop ends when the PR exists.
|
|
191
|
+
|
|
192
|
+
You can run the same steps by hand (`/dmx/create-ticket`, `/dmx/plan`, `/dmx/implement-next-phase`, …) instead of loops. See the skill catalog below.
|
|
193
|
+
|
|
95
194
|
## Learn more
|
|
96
195
|
|
|
97
196
|
- [When Is a Loop Ready to Run Without You?](https://himakara.hashnode.dev/when-is-a-loop-ready-to-run-without-you) — the thinking behind dmx
|
|
@@ -173,6 +272,10 @@ Safe to re-run. Updates config without overwriting memory bank files that alread
|
|
|
173
272
|
|
|
174
273
|
### Step 3 — Start your first ticket
|
|
175
274
|
|
|
275
|
+
On a new repo, follow [Your first project](#your-first-project) (`/dmx/run-loop spec` through `/dmx/close-ticket`).
|
|
276
|
+
|
|
277
|
+
To start a ticket by hand instead:
|
|
278
|
+
|
|
176
279
|
```
|
|
177
280
|
/dmx/create-ticket
|
|
178
281
|
```
|
|
@@ -40,6 +40,7 @@ from __future__ import annotations
|
|
|
40
40
|
import importlib.resources as pkg
|
|
41
41
|
import logging
|
|
42
42
|
import re
|
|
43
|
+
import subprocess
|
|
43
44
|
from pathlib import Path
|
|
44
45
|
|
|
45
46
|
from fastmcp import (
|
|
@@ -150,6 +151,41 @@ def _read_branch_base(workspace_root: Path) -> str | None:
|
|
|
150
151
|
return value if value and value != "{REQUIRED}" else None
|
|
151
152
|
|
|
152
153
|
|
|
154
|
+
def _repo_has_no_commits(root: Path) -> bool:
|
|
155
|
+
"""True if *root* is a git repo with an unborn HEAD (zero commits).
|
|
156
|
+
|
|
157
|
+
``git rev-parse --abbrev-ref HEAD`` — what :func:`current_branch` uses —
|
|
158
|
+
fails on a freshly ``git init``'d repo before its first commit, even
|
|
159
|
+
though the branch name (e.g. ``main``/``master``) is perfectly
|
|
160
|
+
resolvable via ``git symbolic-ref``. This distinguishes that specific,
|
|
161
|
+
fixable case (make a commit) from other reasons ``current_branch``
|
|
162
|
+
might return ``None`` (not a git repo at all, detached HEAD, etc.),
|
|
163
|
+
which don't have an actionable one-line fix.
|
|
164
|
+
"""
|
|
165
|
+
try:
|
|
166
|
+
result = subprocess.run(
|
|
167
|
+
["git", "rev-parse", "--is-inside-work-tree"],
|
|
168
|
+
capture_output=True,
|
|
169
|
+
text=True,
|
|
170
|
+
cwd=root,
|
|
171
|
+
)
|
|
172
|
+
except Exception: # noqa: BLE001
|
|
173
|
+
return False
|
|
174
|
+
if result.returncode != 0 or result.stdout.strip() != "true":
|
|
175
|
+
return False # not a git repo at all — a different problem
|
|
176
|
+
|
|
177
|
+
try:
|
|
178
|
+
verify = subprocess.run(
|
|
179
|
+
["git", "rev-parse", "--verify", "--quiet", "HEAD"],
|
|
180
|
+
capture_output=True,
|
|
181
|
+
text=True,
|
|
182
|
+
cwd=root,
|
|
183
|
+
)
|
|
184
|
+
except Exception: # noqa: BLE001
|
|
185
|
+
return False
|
|
186
|
+
return verify.returncode != 0
|
|
187
|
+
|
|
188
|
+
|
|
153
189
|
def _branch_guard_error(root: Path, config: LoopConfig) -> str | None:
|
|
154
190
|
"""Return an error message if *config* declares ``require_branch`` and
|
|
155
191
|
the current branch doesn't satisfy it, else None."""
|
|
@@ -166,6 +202,13 @@ def _branch_guard_error(root: Path, config: LoopConfig) -> str | None:
|
|
|
166
202
|
|
|
167
203
|
branch = current_branch(root)
|
|
168
204
|
if branch is None:
|
|
205
|
+
if _repo_has_no_commits(root):
|
|
206
|
+
return (
|
|
207
|
+
f"Cannot start the `{config.name}` loop: this repository has no commits yet. "
|
|
208
|
+
f"`{config.name}` creates a new branch from `{branch_base}` on GitHub, which "
|
|
209
|
+
"requires at least one commit to exist first. Commit something (e.g. the "
|
|
210
|
+
"`.dmx/` files `/dmx/init` just wrote) and push to origin, then try again."
|
|
211
|
+
)
|
|
169
212
|
return (
|
|
170
213
|
f"Cannot start the `{config.name}` loop: could not determine the current git "
|
|
171
214
|
f"branch. Make sure you're in a git repository checked out to `{branch_base}`."
|
|
@@ -451,6 +494,79 @@ def _start_loop(root: Path, name: str, description: str | None = None) -> str:
|
|
|
451
494
|
# ---------------------------------------------------------------------------
|
|
452
495
|
|
|
453
496
|
|
|
497
|
+
_COMMIT_DMX_STATE_TIMEOUT_SECONDS = 15
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
def _commit_dmx_state(root: Path, message: str) -> str | None:
|
|
501
|
+
"""Best-effort commit of any uncommitted ``.dmx/`` changes.
|
|
502
|
+
|
|
503
|
+
Called once a loop run has genuinely finished (a terminal outcome —
|
|
504
|
+
not ``paused``/``iterating``, which will write state again on the next
|
|
505
|
+
call) so its final state — the job's state JSON and the session-note
|
|
506
|
+
breadcrumb ``_finish_loop`` just wrote to ``activeContext.md`` — isn't
|
|
507
|
+
left as an uncommitted, local-only change. This matters most for a
|
|
508
|
+
loop with no ``on_complete`` chain target (e.g. the bundled ``release``
|
|
509
|
+
loop): nothing downstream runs to commit on its behalf, and
|
|
510
|
+
``close-ticket`` explicitly makes no ``.dmx/`` changes before
|
|
511
|
+
force-deleting the branch, so an uncommitted final state here would be
|
|
512
|
+
silently and permanently lost — see GH-23.
|
|
513
|
+
|
|
514
|
+
Silently does nothing if *root* isn't a git repo or there's nothing to
|
|
515
|
+
commit — this is a best-effort durability improvement (matching the
|
|
516
|
+
README's "committed with the PR" claim for ``.dmx/jobs/``), not
|
|
517
|
+
something that should ever break a loop response.
|
|
518
|
+
|
|
519
|
+
Every subprocess call is timeout-bounded so a hung ``git`` invocation
|
|
520
|
+
(e.g. a pre-commit hook prompting for input, or GPG signing waiting on
|
|
521
|
+
a passphrase) can't hang the whole MCP tool call indefinitely.
|
|
522
|
+
|
|
523
|
+
Returns:
|
|
524
|
+
``None`` if there was nothing to commit or the commit succeeded.
|
|
525
|
+
A short, user-facing warning string if a commit was *attempted*
|
|
526
|
+
but failed (e.g. a pre-commit hook rejected it) — silently
|
|
527
|
+
swallowing that would defeat the entire point of this call, so
|
|
528
|
+
callers should surface it in the loop's response rather than only
|
|
529
|
+
logging it server-side.
|
|
530
|
+
"""
|
|
531
|
+
try:
|
|
532
|
+
status = subprocess.run(
|
|
533
|
+
["git", "status", "--short", "--", ".dmx/"],
|
|
534
|
+
capture_output=True,
|
|
535
|
+
text=True,
|
|
536
|
+
cwd=root,
|
|
537
|
+
timeout=_COMMIT_DMX_STATE_TIMEOUT_SECONDS,
|
|
538
|
+
)
|
|
539
|
+
except Exception: # noqa: BLE001
|
|
540
|
+
return None
|
|
541
|
+
if status.returncode != 0 or not status.stdout.strip():
|
|
542
|
+
return None # not a git repo, or nothing under .dmx/ to commit
|
|
543
|
+
|
|
544
|
+
try:
|
|
545
|
+
subprocess.run(
|
|
546
|
+
["git", "add", ".dmx/"],
|
|
547
|
+
capture_output=True,
|
|
548
|
+
text=True,
|
|
549
|
+
cwd=root,
|
|
550
|
+
check=True,
|
|
551
|
+
timeout=_COMMIT_DMX_STATE_TIMEOUT_SECONDS,
|
|
552
|
+
)
|
|
553
|
+
subprocess.run(
|
|
554
|
+
["git", "commit", "-m", message],
|
|
555
|
+
capture_output=True,
|
|
556
|
+
text=True,
|
|
557
|
+
cwd=root,
|
|
558
|
+
check=True,
|
|
559
|
+
timeout=_COMMIT_DMX_STATE_TIMEOUT_SECONDS,
|
|
560
|
+
)
|
|
561
|
+
except Exception as exc: # noqa: BLE001
|
|
562
|
+
logger.warning("could not auto-commit .dmx/ state (%s): %s", message, exc)
|
|
563
|
+
return (
|
|
564
|
+
"⚠️ Could not auto-commit the loop's final `.dmx/` state (see server logs for "
|
|
565
|
+
"details) — run `git status .dmx/` and commit manually if needed."
|
|
566
|
+
)
|
|
567
|
+
return None
|
|
568
|
+
|
|
569
|
+
|
|
454
570
|
def _finish_loop(
|
|
455
571
|
root: Path,
|
|
456
572
|
job_id: str,
|
|
@@ -571,25 +687,42 @@ def _finish_loop(
|
|
|
571
687
|
f"{loop_name} loop completed (outcome: {outcome}) — chaining to "
|
|
572
688
|
f"{next_loop} was configured but blocked: {chain_guard_error}",
|
|
573
689
|
)
|
|
574
|
-
|
|
690
|
+
commit_warning = _commit_dmx_state(
|
|
691
|
+
root, f"chore: sync loop state for {loop_name} (job {job_id})"
|
|
692
|
+
)
|
|
693
|
+
message = (
|
|
575
694
|
f"{_complete_message(loop_name, job_id, outcome)}\n\n"
|
|
576
695
|
f"Configured to chain to **{next_loop}**, but it couldn't start: "
|
|
577
696
|
f"{chain_guard_error}"
|
|
578
697
|
)
|
|
698
|
+
if commit_warning:
|
|
699
|
+
message += f"\n\n{commit_warning}"
|
|
700
|
+
return message
|
|
579
701
|
|
|
580
702
|
append_session_note(
|
|
581
703
|
root,
|
|
582
704
|
f"{loop_name} loop completed (outcome: {outcome}) — "
|
|
583
705
|
f"chained to {next_loop} (job `{job_id}`).",
|
|
584
706
|
)
|
|
707
|
+
commit_warning = _commit_dmx_state(
|
|
708
|
+
root, f"chore: sync loop state for {loop_name} (job {job_id})"
|
|
709
|
+
)
|
|
585
710
|
chain_header = (
|
|
586
711
|
f"**{loop_name} loop — complete** (outcome: `{outcome}`)\n\n"
|
|
587
712
|
f"Chaining automatically to **{next_loop}** loop.\n\n"
|
|
588
713
|
)
|
|
714
|
+
if commit_warning:
|
|
715
|
+
chain_header += f"{commit_warning}\n\n"
|
|
589
716
|
return chain_header + _start_loop(root, next_loop)
|
|
590
717
|
|
|
591
718
|
append_session_note(root, f"{loop_name} loop completed (outcome: {outcome}) (job `{job_id}`).")
|
|
592
|
-
|
|
719
|
+
commit_warning = _commit_dmx_state(
|
|
720
|
+
root, f"chore: sync loop state for {loop_name} (job {job_id})"
|
|
721
|
+
)
|
|
722
|
+
message = _complete_message(loop_name, job_id, outcome)
|
|
723
|
+
if commit_warning:
|
|
724
|
+
message += f"\n\n{commit_warning}"
|
|
725
|
+
return message
|
|
593
726
|
|
|
594
727
|
|
|
595
728
|
# ---------------------------------------------------------------------------
|
|
@@ -85,7 +85,27 @@ After promoting inbox items, rewrite `activeContext.md` to the learning-inbox st
|
|
|
85
85
|
|
|
86
86
|
Do not add an `## Active Ticket` section. Branch identity lives in `spec.md`, not here.
|
|
87
87
|
|
|
88
|
-
## Step 6 —
|
|
88
|
+
## Step 6 — Commit memory changes
|
|
89
|
+
|
|
90
|
+
Run:
|
|
91
|
+
```
|
|
92
|
+
git status --short .dmx/
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
If any files under `.dmx/` were modified in Steps 4–5:
|
|
96
|
+
```
|
|
97
|
+
git add .dmx/
|
|
98
|
+
git commit -m "chore: sync memory bank"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
If nothing changed, continue without committing.
|
|
102
|
+
|
|
103
|
+
This skill must never leave uncommitted `.dmx/` changes in the working tree —
|
|
104
|
+
regardless of when or how it's invoked (standalone, chained after another
|
|
105
|
+
skill, or as part of a loop), it is responsible for committing its own edits.
|
|
106
|
+
Do not skip this step even if you expect the caller to commit afterward.
|
|
107
|
+
|
|
108
|
+
## Step 7 — Return the result
|
|
89
109
|
|
|
90
110
|
Output:
|
|
91
111
|
```
|
|
@@ -101,6 +121,8 @@ activeContext inbox:
|
|
|
101
121
|
Promoted: {N} items
|
|
102
122
|
Remaining: {M} items
|
|
103
123
|
|
|
124
|
+
{if committed in Step 6} Committed: chore: sync memory bank
|
|
125
|
+
|
|
104
126
|
Next:
|
|
105
127
|
- Run /dmx/create-ticket to start the next piece of work.
|
|
106
128
|
- Run /dmx/derive-ticket if you have uncommitted changes to formalise.
|
|
@@ -112,3 +134,4 @@ Next:
|
|
|
112
134
|
- Never store ticket-specific implementation details (function names, line numbers, single-branch decisions) in core files. Those belong in `spec.md` or `tasks.md`.
|
|
113
135
|
- If `tasks.md` shows unchecked tasks remaining, note in output: "Note: tasks.md has unchecked tasks — memory updated with progress so far, not a completed state."
|
|
114
136
|
- After Step 5, `activeContext.md` must not contain an `## Active Ticket` section.
|
|
137
|
+
- Never leave `.dmx/` changes uncommitted — Step 6 is mandatory whenever files were modified.
|
{deepmodel_dmx-0.3.2 → deepmodel_dmx-0.3.4}/src/dmx/skills/workflow/1-triage/dmx-create-ticket.md
RENAMED
|
@@ -28,7 +28,29 @@ The project configuration is injected into your context as a rule. Extract:
|
|
|
28
28
|
|
|
29
29
|
If configuration is not available in context, fall back to reading `.dmx/config.md`. If neither is found, stop: "Project configuration not found. Run /dmx/init to set up this project."
|
|
30
30
|
|
|
31
|
-
## Step 2 —
|
|
31
|
+
## Step 2 — Verify the repo has at least one commit
|
|
32
|
+
|
|
33
|
+
Run:
|
|
34
|
+
```
|
|
35
|
+
git rev-parse --verify --quiet HEAD
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
If this fails (non-zero exit, no output — an unborn `HEAD`, meaning zero commits exist yet), stop before creating anything:
|
|
39
|
+
```
|
|
40
|
+
This repository has no commits yet. Creating a ticket branches from `{config.branch_base}`
|
|
41
|
+
on GitHub, which requires at least one commit to exist first.
|
|
42
|
+
|
|
43
|
+
Commit something first, e.g. the files /dmx/init just wrote:
|
|
44
|
+
git add .
|
|
45
|
+
git commit -m "chore: initialize project"
|
|
46
|
+
git push -u origin HEAD
|
|
47
|
+
|
|
48
|
+
Then run /dmx/create-ticket again.
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Do not proceed to Step 3 in this case, even if `{{task}}` was provided.
|
|
52
|
+
|
|
53
|
+
## Step 3 — Read project context
|
|
32
54
|
|
|
33
55
|
Read the following memory bank files:
|
|
34
56
|
- `.dmx/projectbrief.md` — project goals and scope
|
|
@@ -39,7 +61,7 @@ If `.dmx/` does not exist, stop: "Memory bank not found. Run /dmx/init to set up
|
|
|
39
61
|
|
|
40
62
|
Store this context. It will inform the ticket content, technical approach, and spec questions.
|
|
41
63
|
|
|
42
|
-
## Step
|
|
64
|
+
## Step 4 — Infer type
|
|
43
65
|
|
|
44
66
|
If `{{type}}` was provided, use it. Accepted values: `feature`, `bug`, `chore`.
|
|
45
67
|
|
|
@@ -53,9 +75,9 @@ Store as `branch_type` (`feature` | `bug` | `chore`).
|
|
|
53
75
|
For Jira `issueTypeName` mapping: `feature` → `Story`, `bug` → `Bug`, `chore` → `Task`.
|
|
54
76
|
For GitHub Issues label: use `branch_type` as-is.
|
|
55
77
|
|
|
56
|
-
## Step
|
|
78
|
+
## Step 5 — Draft ticket content
|
|
57
79
|
|
|
58
|
-
Using `{{task}}` and the project context from Step
|
|
80
|
+
Using `{{task}}` and the project context from Step 3, generate a `summary` and `description`.
|
|
59
81
|
|
|
60
82
|
### Summary
|
|
61
83
|
Single sentence, max 80 characters, imperative present tense, capital first letter, no trailing period. Specific enough that scope is clear without reading the description.
|
|
@@ -86,7 +108,7 @@ Examples:
|
|
|
86
108
|
|
|
87
109
|
Rules: write for the implementer. For bugs, lead with observed vs expected behaviour. Acceptance criteria must be independently verifiable.
|
|
88
110
|
|
|
89
|
-
## Step
|
|
111
|
+
## Step 6 — Create the ticket
|
|
90
112
|
|
|
91
113
|
**If `ticketing` is `jira`:**
|
|
92
114
|
|
|
@@ -96,7 +118,7 @@ Call `createJiraIssue` on `user-atlassian`:
|
|
|
96
118
|
```
|
|
97
119
|
cloudId: {config.cloud_id}
|
|
98
120
|
projectKey: {config.project_key}
|
|
99
|
-
issueTypeName: {Jira type from Step
|
|
121
|
+
issueTypeName: {Jira type from Step 4}
|
|
100
122
|
summary: {summary}
|
|
101
123
|
description: {description}
|
|
102
124
|
assignee_account_id: {account_id}
|
|
@@ -129,7 +151,7 @@ Store `ticket_url` = `{html_url}`.
|
|
|
129
151
|
|
|
130
152
|
No ticket is created. `ticket_ref` = `none`. `ticket_url` = none.
|
|
131
153
|
|
|
132
|
-
## Step
|
|
154
|
+
## Step 7 — Construct the branch name
|
|
133
155
|
|
|
134
156
|
Slugify the summary:
|
|
135
157
|
- Lowercase, hyphens for spaces, remove special characters, collapse consecutive hyphens, truncate to 60 chars
|
|
@@ -140,7 +162,7 @@ Slugify the summary:
|
|
|
140
162
|
| `github-issues` | `{branch_type}-gh-{number}-{slug}` | `feature-gh-123-add-rate-limiting` |
|
|
141
163
|
| `none` | `{branch_type}-{slug}` | `feature-add-rate-limiting` |
|
|
142
164
|
|
|
143
|
-
## Step
|
|
165
|
+
## Step 8 — Create the remote branch and check out locally
|
|
144
166
|
|
|
145
167
|
Call `create_branch` on `user-github`:
|
|
146
168
|
```
|
|
@@ -158,7 +180,7 @@ git fetch origin
|
|
|
158
180
|
git checkout {branch_name}
|
|
159
181
|
```
|
|
160
182
|
|
|
161
|
-
## Step
|
|
183
|
+
## Step 9 — Scaffold spec.md
|
|
162
184
|
|
|
163
185
|
Write `.dmx/spec.md`:
|
|
164
186
|
|
|
@@ -179,7 +201,7 @@ ticketing: {ticketing}
|
|
|
179
201
|
---
|
|
180
202
|
|
|
181
203
|
## Context
|
|
182
|
-
{From ticket description Step
|
|
204
|
+
{From ticket description Step 5 — why this work is needed in this project}
|
|
183
205
|
|
|
184
206
|
## Scope
|
|
185
207
|
{Bullet list of what is included. Use project patterns to name specific layers, services, or files.}
|
|
@@ -221,7 +243,7 @@ ticketing: {ticketing}
|
|
|
221
243
|
|
|
222
244
|
When `ticketing` is `none`, omit `ticket` from frontmatter.
|
|
223
245
|
|
|
224
|
-
## Step
|
|
246
|
+
## Step 10 — Transition to In Progress
|
|
225
247
|
|
|
226
248
|
**If `ticketing` is `jira`:**
|
|
227
249
|
Call `getTransitionsForJiraIssue` on `user-atlassian`. Find `In Progress`. Call `transitionJiraIssue`.
|
|
@@ -237,7 +259,7 @@ labels: ["in-progress"]
|
|
|
237
259
|
|
|
238
260
|
**If `ticketing` is `none`:** Skip.
|
|
239
261
|
|
|
240
|
-
## Step
|
|
262
|
+
## Step 11 — Return the result
|
|
241
263
|
|
|
242
264
|
```
|
|
243
265
|
{if ticketing ≠ none} Ticket: {ticket_ref} — {summary}
|