@beomjk/emdd 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/cli.js +11 -1
- package/dist/commands/list.d.ts +4 -0
- package/dist/commands/list.js +22 -0
- package/dist/graph/types.js +2 -2
- package/dist/mcp-server/index.js +2 -1
- package/dist/rules/emdd-agent.md +40 -0
- package/dist/rules/emdd-rules.md +99 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +4 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -97,7 +97,8 @@ See the [Quick Start Guide](docs/QUICK_START.md) for a full walkthrough.
|
|
|
97
97
|
|
|
98
98
|
| Command | Description |
|
|
99
99
|
|---------|-------------|
|
|
100
|
-
| `emdd init [path]` | Initialize a new EMDD project |
|
|
100
|
+
| `emdd init [path]` | Initialize a new EMDD project (`--tool claude\|cursor\|windsurf\|cline\|copilot\|all`, `--lang en\|ko`) |
|
|
101
|
+
| `emdd list [path]` | List nodes (`--type`, `--status` filters) |
|
|
101
102
|
| `emdd new <type> <slug>` | Create a node (hypothesis, experiment, finding, ...) |
|
|
102
103
|
| `emdd link <source> <target> <relation>` | Add a link between nodes |
|
|
103
104
|
| `emdd update <node-id> --set key=value` | Update node frontmatter |
|
|
@@ -109,8 +110,9 @@ See the [Quick Start Guide](docs/QUICK_START.md) for a full walkthrough.
|
|
|
109
110
|
| `emdd backlog [path]` | List incomplete items across all nodes |
|
|
110
111
|
| `emdd index [path]` | Generate `_index.md` |
|
|
111
112
|
| `emdd graph [path]` | Generate `_graph.mmd` (Mermaid) |
|
|
113
|
+
| `emdd mcp` | Start MCP server (stdio transport) |
|
|
112
114
|
|
|
113
|
-
|
|
115
|
+
The `init` command supports `--lang en|ko` for bilingual project setup.
|
|
114
116
|
|
|
115
117
|
## Phased Adoption
|
|
116
118
|
|
package/dist/cli.js
CHANGED
|
@@ -12,8 +12,10 @@ import { doneCommand } from './commands/done.js';
|
|
|
12
12
|
import { indexCommand } from './commands/index.js';
|
|
13
13
|
import { graphCommand } from './commands/graph.js';
|
|
14
14
|
import { backlogCommand } from './commands/backlog.js';
|
|
15
|
+
import { listCommand } from './commands/list.js';
|
|
15
16
|
import { resolveGraphDir } from './graph/loader.js';
|
|
16
17
|
import { startMcpServer } from './mcp-server/index.js';
|
|
18
|
+
import { VERSION } from './version.js';
|
|
17
19
|
function withCliErrorHandling(fn) {
|
|
18
20
|
return async (...args) => {
|
|
19
21
|
try {
|
|
@@ -30,7 +32,7 @@ const program = new Command();
|
|
|
30
32
|
program
|
|
31
33
|
.name('emdd')
|
|
32
34
|
.description('CLI for Evolving Mindmap-Driven Development')
|
|
33
|
-
.version(
|
|
35
|
+
.version(VERSION);
|
|
34
36
|
program
|
|
35
37
|
.command('init [path]')
|
|
36
38
|
.description('Initialize EMDD project')
|
|
@@ -46,6 +48,14 @@ program
|
|
|
46
48
|
.action(withCliErrorHandling(async (type, slug, options) => {
|
|
47
49
|
await newCommand(type, slug, options);
|
|
48
50
|
}));
|
|
51
|
+
program
|
|
52
|
+
.command('list [path]')
|
|
53
|
+
.description('List nodes, optionally filtered by type and/or status')
|
|
54
|
+
.option('--type <type>', 'Filter by node type')
|
|
55
|
+
.option('--status <status>', 'Filter by status')
|
|
56
|
+
.action(withCliErrorHandling(async (path, options) => {
|
|
57
|
+
await listCommand(path, options);
|
|
58
|
+
}));
|
|
49
59
|
program
|
|
50
60
|
.command('lint [path]')
|
|
51
61
|
.description('Validate graph schema and links')
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { resolveGraphDir } from '../graph/loader.js';
|
|
2
|
+
import { listNodes } from '../graph/operations.js';
|
|
3
|
+
export async function listCommand(targetPath, options) {
|
|
4
|
+
const graphDir = resolveGraphDir(targetPath);
|
|
5
|
+
const filter = {};
|
|
6
|
+
if (options.type)
|
|
7
|
+
filter.type = options.type;
|
|
8
|
+
if (options.status)
|
|
9
|
+
filter.status = options.status.toUpperCase();
|
|
10
|
+
const nodes = await listNodes(graphDir, filter);
|
|
11
|
+
if (nodes.length === 0) {
|
|
12
|
+
console.log('No nodes found.');
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
for (const node of nodes) {
|
|
16
|
+
const status = node.status ?? '-';
|
|
17
|
+
const conf = node.confidence !== null && node.confidence !== undefined
|
|
18
|
+
? ` (${node.confidence.toFixed(2)})`
|
|
19
|
+
: '';
|
|
20
|
+
console.log(`[${node.id}] ${node.title} ${node.type} ${status}${conf}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
package/dist/graph/types.js
CHANGED
|
@@ -50,11 +50,11 @@ export const ID_PREFIXES = {
|
|
|
50
50
|
export const PREFIX_TO_TYPE = Object.fromEntries(Object.entries(ID_PREFIXES).map(([type, prefix]) => [prefix, type]));
|
|
51
51
|
// ── Valid Statuses per Node Type ────────────────────────────────────
|
|
52
52
|
export const VALID_STATUSES = {
|
|
53
|
-
hypothesis: ['PROPOSED', 'TESTING', 'SUPPORTED', 'REFUTED', 'REVISED', 'DEFERRED'],
|
|
53
|
+
hypothesis: ['PROPOSED', 'TESTING', 'SUPPORTED', 'REFUTED', 'REVISED', 'DEFERRED', 'CONTESTED'],
|
|
54
54
|
experiment: ['PLANNED', 'RUNNING', 'COMPLETED', 'FAILED', 'ABANDONED'],
|
|
55
55
|
finding: ['DRAFT', 'VALIDATED', 'PROMOTED', 'RETRACTED'],
|
|
56
56
|
knowledge: ['ACTIVE', 'DISPUTED', 'SUPERSEDED', 'RETRACTED'],
|
|
57
|
-
question: ['OPEN', 'RESOLVED', 'ANSWERED', 'DEFERRED'],
|
|
57
|
+
question: ['OPEN', 'RESOLVED', 'ANSWERED', 'DEFERRED', 'CONVERGED', 'MERGED', 'ABANDONED'],
|
|
58
58
|
decision: ['PROPOSED', 'ACCEPTED', 'SUPERSEDED', 'REVERTED'],
|
|
59
59
|
episode: ['ACTIVE', 'COMPLETED'],
|
|
60
60
|
};
|
package/dist/mcp-server/index.js
CHANGED
|
@@ -11,8 +11,9 @@ import { registerContextLoading } from './prompts/context-loading.js';
|
|
|
11
11
|
import { registerEpisodeCreation } from './prompts/episode-creation.js';
|
|
12
12
|
import { registerConsolidation } from './prompts/consolidation.js';
|
|
13
13
|
import { registerHealthReview } from './prompts/health-review.js';
|
|
14
|
+
import { VERSION } from '../version.js';
|
|
14
15
|
export function createEmddMcpServer() {
|
|
15
|
-
const server = new McpServer({ name: 'emdd', version:
|
|
16
|
+
const server = new McpServer({ name: 'emdd', version: VERSION });
|
|
16
17
|
// Tools
|
|
17
18
|
registerListNodes(server);
|
|
18
19
|
registerReadNode(server);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# EMDD Agent Behavior Guidelines
|
|
2
|
+
|
|
3
|
+
## Session Workflow
|
|
4
|
+
|
|
5
|
+
1. **Session Start**: Read the latest Episode's "What's Next" section. Load prerequisite nodes.
|
|
6
|
+
2. **During Work**: Execute experiments, write code, take notes. Mark surprises with [!].
|
|
7
|
+
3. **Session End**: Write a new Episode. Record what was tried, create Findings, list next steps.
|
|
8
|
+
|
|
9
|
+
## Intervention Rules
|
|
10
|
+
|
|
11
|
+
- During deep work: do not interrupt unless a kill criterion is hit or a crash occurs
|
|
12
|
+
- Suggestions are a menu, not an order — the researcher selects what to pursue
|
|
13
|
+
- After a suggestion is rejected: 24-hour cooldown before re-suggesting
|
|
14
|
+
- Never negate an idea still forming in early exploration stages
|
|
15
|
+
|
|
16
|
+
## Authority Scope
|
|
17
|
+
|
|
18
|
+
**No approval needed:**
|
|
19
|
+
- Recording experiment metrics as Finding/Result nodes
|
|
20
|
+
- Updating Experiment status (PLANNED -> RUNNING -> COMPLETED)
|
|
21
|
+
- Time-based attribute updates (updated field)
|
|
22
|
+
|
|
23
|
+
**Approval required:**
|
|
24
|
+
- Changing Hypothesis confidence
|
|
25
|
+
- Creating new Hypothesis or Question nodes
|
|
26
|
+
- Adding or deleting edges
|
|
27
|
+
- Changing Knowledge status (DISPUTED/RETRACTED)
|
|
28
|
+
|
|
29
|
+
**Forbidden:**
|
|
30
|
+
- Deleting any node (archive/deprecate instead)
|
|
31
|
+
- Creating Decision nodes
|
|
32
|
+
- Modifying kill criteria
|
|
33
|
+
|
|
34
|
+
## Graph Maintenance Tasks
|
|
35
|
+
|
|
36
|
+
- After experiments: update related node statuses and confidence scores (with approval)
|
|
37
|
+
- Check Consolidation triggers after creating Episodes or Findings
|
|
38
|
+
- Identify orphan nodes (nodes with no outgoing links)
|
|
39
|
+
- Detect stale nodes (untested hypotheses older than 3 days)
|
|
40
|
+
- Flag structural gaps between clusters
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# EMDD — Evolving Mindmap-Driven Development
|
|
2
|
+
|
|
3
|
+
You are working in a project that uses the EMDD methodology. EMDD organizes research and exploration as a knowledge graph stored in `graph/` with Markdown + YAML frontmatter files, tracked by Git.
|
|
4
|
+
|
|
5
|
+
## Graph Structure
|
|
6
|
+
|
|
7
|
+
The graph contains 7 node types, each in its own subdirectory:
|
|
8
|
+
|
|
9
|
+
| Node Type | Directory | Purpose |
|
|
10
|
+
|-----------|-----------|---------|
|
|
11
|
+
| Hypothesis | `graph/hypotheses/` | Testable claims with confidence scores |
|
|
12
|
+
| Experiment | `graph/experiments/` | Units of work that test hypotheses |
|
|
13
|
+
| Finding | `graph/findings/` | Observations from experiments |
|
|
14
|
+
| Knowledge | `graph/knowledge/` | Established facts promoted from findings |
|
|
15
|
+
| Question | `graph/questions/` | Open questions driving exploration |
|
|
16
|
+
| Decision | `graph/decisions/` | Recorded choices with rationale |
|
|
17
|
+
| Episode | `graph/episodes/` | Session logs linking work to the graph |
|
|
18
|
+
|
|
19
|
+
Nodes are connected by typed edges (supports, contradicts, spawns, produces, tests, depends_on, extends, promotes, answers, etc.) declared in YAML frontmatter `links:` arrays.
|
|
20
|
+
|
|
21
|
+
## Node File Format
|
|
22
|
+
|
|
23
|
+
Every node is a Markdown file with YAML frontmatter:
|
|
24
|
+
|
|
25
|
+
```yaml
|
|
26
|
+
---
|
|
27
|
+
id: hyp-001
|
|
28
|
+
type: hypothesis
|
|
29
|
+
status: PROPOSED
|
|
30
|
+
confidence: 0.4
|
|
31
|
+
created: 2026-03-15
|
|
32
|
+
updated: 2026-03-15
|
|
33
|
+
created_by: human:yourname
|
|
34
|
+
tags: [topic]
|
|
35
|
+
links:
|
|
36
|
+
- target: know-001
|
|
37
|
+
relation: depends_on
|
|
38
|
+
---
|
|
39
|
+
# Title here
|
|
40
|
+
Body content...
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Required fields vary by type. All nodes need: `id`, `type`, `status`, `created`, `updated`. Hypotheses and findings also need `confidence` (0.0-1.0).
|
|
44
|
+
|
|
45
|
+
## Node ID Convention
|
|
46
|
+
|
|
47
|
+
IDs use type prefix + sequential number: `hyp-001`, `exp-003`, `fnd-012`, `knw-005`, `qst-002`, `dec-001`, `epi-007`.
|
|
48
|
+
|
|
49
|
+
## Episode Writing Protocol
|
|
50
|
+
|
|
51
|
+
Episodes are the primary mechanism for maintaining research continuity. Write an Episode at the end of each work session.
|
|
52
|
+
|
|
53
|
+
**Mandatory sections:**
|
|
54
|
+
- **What I Tried** — what was done this session
|
|
55
|
+
- **What's Next** — planned next steps with prerequisite reading nodes
|
|
56
|
+
|
|
57
|
+
**Optional sections:**
|
|
58
|
+
- What Got Stuck — blockers or wrong turns
|
|
59
|
+
- What Was Deliberately Not Done — deferred items with reasons
|
|
60
|
+
- Questions That Arose — new questions for the graph
|
|
61
|
+
|
|
62
|
+
Each "What's Next" item should list prerequisite reading: the node IDs to load before starting that task. This curates context for the next session.
|
|
63
|
+
|
|
64
|
+
## Consolidation Protocol
|
|
65
|
+
|
|
66
|
+
Consolidation is a mandatory maintenance ceremony. Check triggers after creating Episodes or Findings.
|
|
67
|
+
|
|
68
|
+
**Triggers (run if ANY apply):**
|
|
69
|
+
- 5 or more Finding nodes added since last Consolidation
|
|
70
|
+
- 3 or more Episode nodes added since last Consolidation
|
|
71
|
+
- 0 open Questions (the illusion that research is "done")
|
|
72
|
+
- An Experiment has 5+ Findings attached
|
|
73
|
+
|
|
74
|
+
**Consolidation steps:**
|
|
75
|
+
1. **Promotion** — promote established Findings to Knowledge nodes
|
|
76
|
+
2. **Splitting** — split bloated Experiments into meaningful units
|
|
77
|
+
3. **Question generation** — convert Episode questions into Question nodes
|
|
78
|
+
4. **Hypothesis update** — update confidence based on evidence
|
|
79
|
+
5. **Orphan cleanup** — add connections to unlinked Findings
|
|
80
|
+
|
|
81
|
+
Consolidation is an obligation, not optional. Do not record Consolidation as an Episode. Do not start new exploration during Consolidation.
|
|
82
|
+
|
|
83
|
+
## Key Principles
|
|
84
|
+
|
|
85
|
+
1. **Graph is source of truth** — the graph, not code, is the project's knowledge structure
|
|
86
|
+
2. **Minimum viable structure** — add structure only when needed; if it feels like bureaucracy, reduce it
|
|
87
|
+
3. **Gap-driven exploration** — the most valuable information is in the empty spaces between nodes
|
|
88
|
+
4. **Temporal evolution** — never delete wrong paths; deprecate them. The history of why something failed is itself knowledge
|
|
89
|
+
5. **Riskiest-first** — validate the most uncertain hypotheses first
|
|
90
|
+
6. **Archive, don't delete** — change status to REFUTED/RETRACTED/SUPERSEDED instead of removing nodes
|
|
91
|
+
|
|
92
|
+
## AI Agent Role
|
|
93
|
+
|
|
94
|
+
You are a **gardener** of the graph:
|
|
95
|
+
- Maintain connections, detect duplicates, identify orphans
|
|
96
|
+
- Detect patterns and potential connections the researcher missed
|
|
97
|
+
- Suggest exploration directions based on structural gaps
|
|
98
|
+
- Automate routine tasks (literature search, result summarization)
|
|
99
|
+
- Never make judgment calls — suggest, don't decide
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const VERSION: string;
|
package/dist/version.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@beomjk/emdd",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "CLI for Evolving Mindmap-Driven Development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
],
|
|
15
15
|
"main": "./dist/index.js",
|
|
16
16
|
"scripts": {
|
|
17
|
-
"build": "tsc",
|
|
17
|
+
"build": "tsc && cp src/rules/*.md dist/rules/",
|
|
18
18
|
"dev": "tsx src/cli.ts",
|
|
19
19
|
"test": "vitest",
|
|
20
20
|
"test:run": "vitest run --passWithNoTests",
|