JSON Configuration Rules for DMtools Jobs
CRITICAL: Understanding the “name” Field
The "name" field in DMtools job configuration is NOT a user-defined name or description.
"name" = Java Job Class Name (Technical Identifier)
What is the “name” field?
The "name" field is a technical identifier that tells DMtools which Java class to instantiate. It must exactly match the compiled Java class name in the DMtools codebase.
// DMtools code (JobRunner.java):
if (jobName.equals("TestCasesGenerator")) {
return new TestCasesGenerator(); // Java class instantiation
}
What the “name” field is NOT:
- NOT a display name or title
- NOT a description of what the job does
- NOT something you can customize
- NOT user-defined or configurable
Analogy:
"name": "TestCasesGenerator" ≈ import com.github.istin.dmtools.qa.TestCasesGenerator;
Just like you cannot change import statements in code, you cannot change the "name" field in configuration.
Example of Correct vs Incorrect:
// ✅ CORRECT - Uses exact Java class name
{
"name": "TestCasesGenerator",
"params": { ... }
}
// ❌ WRONG - Custom name will cause error
{
"name": "My Custom Test Generator",
"params": { ... }
}
// Error: Unknown job: My Custom Test Generator
Critical Rules
1. Job Name Field is Immutable
The "name" field in JSON configuration MUST exactly match the Java Job class name. This is not a user-configurable parameter.
WRONG - Never do this:
{
"name": "My Custom Test Generator",
"params": { ... }
}
CORRECT - Use exact Java class name:
{
"name": "TestCasesGenerator",
"params": { ... }
}
Valid Job Names
Accepted job name | Purpose |
|---|---|
TestCasesGenerator | Generate test cases from stories |
Teammate | AI teammate for ticket analysis |
Expert | Domain expert Q&A |
CodeGenerator | Deprecated compatibility shim. Accepted for one release, logs a warning, and performs no generation. |
UnitTestsGenerator | Generate unit tests |
DocumentationGenerator | Generate documentation |
DiagramsCreator | Create Mermaid diagrams |
SolutionArchitectureCreator | Create architecture docs |
InstructionsGenerator | Generate implementation instructions |
RequirementsCollector | Collect requirements |
UserStoryGenerator | Generate user stories |
JSRunner | Run JavaScript agents |
ReportGenerator / ReportGeneratorJob | Generate configurable analytics reports |
ReportVisualizer / ReportVisualizerJob | Render report JSON as HTML |
KBProcessingJob / KBProcessing | Process knowledge-base content |
Important: Run dmtools --list-jobs to see the CLI-facing class names. Report and KB configs also accept the alternate names shown above.
Configuration Structure
Basic Structure
{
"name": "JobName",
"params": {
// Job-specific parameters
}
}
Required Fields
- name (string, required) - Supported job identifier (usually the Java Job class name)
- params (object, required) - Job parameters
Common Parameters
All jobs that extend TrackerParams support these common parameters:
{
"name": "JobName",
"params": {
"inputJql": "project = PROJ AND type = Story",
"initiator": "user@company.com",
"targetProject": "PROJ",
"outputType": "comment",
"fieldName": "Custom Field",
"operationType": "Append",
"preJSAction": "agents/js/preprocess.js",
"postJSAction": "agents/js/postprocess.js",
"attachResponseAsFile": false,
"ticketContextDepth": 1,
"chunkProcessingTimeoutInMinutes": 60,
"issueIgnorePrefixes": "PSR,RFC,CVE",
"issueAllowedPrefixes": "PROJ,TEAM,PLATFORM",
"envVariables": {
"JIRA_ISSUE_IGNORE_PREFIXES": "PSR,RFC,CVE",
"JIRA_ISSUE_ALLOWED_PREFIXES": "PROJ,TEAM,PLATFORM"
}
}
}
issueIgnorePrefixes— comma-separated list of Jira issue key prefixes to exclude when parsing ticket references (e.g.PSR-18,RFC-6749). Empty by default.issueAllowedPrefixes— comma-separated list of allowed Jira issue key prefixes; when set, only keys matching these prefixes are kept. Empty by default.envVariables— per-job environment variable overrides. Job-levelissueIgnorePrefixes/issueAllowedPrefixestake precedence over env variables with the same name.
When neither list is configured, parsing behavior remains unchanged (full backward compatibility).
Configuration Validation
How DMtools Resolves Job Name
// JobRunner.java
public static Job<?, ?> createJobInstance(String jobName) {
// jobName must EXACTLY match Job class name
if (jobName.equals("TestCasesGenerator")) {
return new TestCasesGenerator();
} else if (jobName.equals("Teammate")) {
return new Teammate();
}
// ...
}
If the name doesn’t match exactly, you’ll get:
Error: Unknown job: My Custom Test Generator
Case Sensitivity
Job names are case-sensitive:
-
TestCasesGenerator- Correct -
testcasesgenerator- Wrong -
test-cases-generator- Wrong -
TestCasesGeneratorJob- Wrong
Best Practices
1. Use Real Configuration Examples
Always reference actual configuration files from the agents/ directory:
# Copy existing configuration
cp agents/xray_test_cases_generator.json agents/my_test_generator.json
# Edit only the params, never change "name"
2. Configuration Inheritance
Jobs inherit parameters from parent classes:
TestCasesGeneratorParams
extends Params
extends TrackerParams
This means TestCasesGenerator supports:
- All TestCasesGeneratorParams fields
- All Params fields (isCodeAsSource, confluencePages, etc.)
- All TrackerParams fields (inputJql, outputType, etc.)
3. Validate Configuration
# Test configuration before committing
dmtools run agents/my_config.json
4. Use JSON Schema Validation (Optional)
For IDE support, you can reference JSON schemas:
{
"$schema": "path/to/job-schema.json",
"name": "TestCasesGenerator",
"params": {
// IDE will provide autocomplete
}
}
Common Mistakes
Mistake 1: Changing Job Name
{
"name": "MyTestGenerator", // WRONG - not a valid Job class
"params": { ... }
}
Mistake 2: Missing Required Parameters
{
"name": "TestCasesGenerator",
"params": {
// Missing inputJql - required by TrackerParams
}
}
Mistake 3: Incorrect Parameter Names
{
"name": "TestCasesGenerator",
"params": {
"jqlQuery": "...", // WRONG - should be "inputJql"
}
}
Mistake 4: Wrong Parameter Type
{
"name": "TestCasesGenerator",
"params": {
"isFindRelated": "true" // WRONG - should be boolean, not string
}
}
Debugging Configuration Issues
Check Job Name
# List all available jobs
dmtools --list-jobs
# Verify exact spelling
dmtools --list-jobs | grep TestCases
Validate JSON Syntax
# Use jq to validate JSON
cat agents/my_config.json | jq .
# Check for syntax errors
dmtools run agents/my_config.json --validate
Enable Debug Logging
# Run with debug output
dmtools --debug run agents/my_config.json
Real Configuration Examples
TestCasesGenerator (from agents/xray_test_cases_generator.json)
{
"name": "TestCasesGenerator",
"params": {
"inputJql": "key in (TP-1309)",
"testCasesPriorities": "Highest, High, Medium, Lowest, Low",
"outputType": "creation",
"existingTestCasesJql": "project = TP and issueType in ('Test', 'Precondition')",
"testCasesCustomFields": ["xrayTestSteps", "xrayPreconditions"],
"isFindRelated": true,
"isConvertToJiraMarkdown": false,
"testCaseIssueType": "Test",
"preprocessJSAction": "agents/js/preprocessXrayTestCases.js"
}
}
Teammate (from agents/story_description.json)
{
"name": "Teammate",
"params": {
"agentParams": {
"aiRole": "Experienced Business Analyst",
"instructions": [
"https://yourcompany.atlassian.net/wiki/spaces/YOUR_SPACE/pages/PAGE_ID/Template+Story",
"./agents/instructions/common/response_output.md"
],
"formattingRules": "https://yourcompany.atlassian.net/wiki/spaces/YOUR_SPACE/pages/PAGE_ID/Template+Jira+Markdown"
},
"outputType": "field",
"fieldName": "Description",
"operationType": "Replace",
"inputJql": "key = DMC-532",
"preJSAction": "agents/js/checkWipLabel.js",
"postJSAction": "agents/js/assignForReview.js"
}
}
Summary
- DO: Use exact Job class names for
"name"field - DO: Reference real configuration files from
agents/directory - DO: Validate JSON syntax before running
- DO: Test configuration with
dmtools run - DON’T: Change or customize the
"name"field - DON’T: Invent parameter names - use documented ones
- DON’T: Mix string and boolean types
Remember: The "name" field is a technical identifier used by DMtools to instantiate the correct Job class. It is not a display name or description.
Config inheritance via parent
Any job config (Teammate, TestCasesGenerator, or any other) can inherit from a base config file by adding a "parent" block at the root level.
Shape
{
"name": "Teammate",
"parent": {
"path": "agents/base-teammate.json",
"override": ["params.agentParams"],
"merge": ["params.agentParams.instructions"]
},
"params": {
"inputJql": "key = SPECIFIC-123",
"agentParams": {
"aiRole": "QA Engineer",
"instructions": ["Also check performance"]
}
}
}
| Field | Type | Description |
|---|---|---|
path | string | Path to the parent config file. Resolved relative to the directory of the current file. |
override | string[] | Dot-notation paths whose values should completely replace the parent (no recursive merge). |
merge | string[] | Dot-notation paths that are arrays: parent items are prepended before child items. |
Resolution order (lowest → highest priority)
| Step | What happens |
|---|---|
| 1 | Parent config is loaded (recursively — parent can itself have a parent) |
| 2 | Child’s own fields are deep-merged on top (child scalars & arrays win by default) |
| 3 | override paths: child value replaces merged value at that path (no deep-merge at that node) |
| 4 | merge paths: merged array = parent items + child items |
| 5 | parent block is stripped from the final config before the job runs |
Default deep-merge behaviour
Without override or merge, the standard deep-merge applies:
- Scalars (strings, numbers, booleans): child value wins
- Objects: merged recursively (child wins for conflicting keys, parent keys not in child are kept)
- Arrays: child array completely replaces parent array
When to use override
Use override when a parent has a nested object that you want to completely replace, not extend field-by-field.
// parent has: "agentParams": {"aiRole": "Engineer", "knownInfo": "base knowledge"}
// child has: "agentParams": {"aiRole": "QA"}
// without override → deep-merge keeps "knownInfo" from parent
// with override:["params.agentParams"] → parent's "knownInfo" is gone, child wins entirely
When to use merge
Use merge for array fields where you want to extend the parent list rather than replace it.
// parent instructions: ["be thorough", "check security"]
// child instructions: ["also check performance"]
// with merge:["params.agentParams.instructions"] →
// result: ["be thorough", "check security", "also check performance"]
Example: Shared base + specialised child agents
agents/base-reviewer.json:
{
"name": "Teammate",
"params": {
"outputType": "comment",
"ticketContextDepth": 2,
"agentParams": {
"aiRole": "Senior Software Engineer",
"instructions": [
"Review for bugs",
"Check security implications",
"Verify code style"
]
}
}
}
agents/qa-reviewer.json (inherits base, adds QA focus):
{
"name": "Teammate",
"parent": {
"path": "base-reviewer.json",
"merge": ["params.agentParams.instructions"]
},
"params": {
"inputJql": "project = QA AND type = Story",
"agentParams": {
"aiRole": "QA Lead",
"instructions": [
"Write acceptance criteria",
"Identify edge cases"
]
}
}
}
Result after resolution:
{
"name": "Teammate",
"params": {
"inputJql": "project = QA AND type = Story",
"outputType": "comment",
"ticketContextDepth": 2,
"agentParams": {
"aiRole": "QA Lead",
"instructions": [
"Review for bugs",
"Check security implications",
"Verify code style",
"Write acceptance criteria",
"Identify edge cases"
]
}
}
}
Recursive parents
A parent file can itself have a parent block. DMtools resolves the entire chain automatically before running the job.
grandparent.json ← parent.json ← child.json (what you run)
Notes
pathis always relative to the file that contains theparentblock, not the working directory.overrideandmergepaths use dot notation to navigate any depth:params.agentParams.instructions.mergepaths must resolve to JSONArray values; non-array paths inmergeare silently skipped.overrideandmergeare optional — omit them to use pure deep-merge inheritance.parentis supported in any job config, not just Teammate.