diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..cb7465f8291685dea5dab6d68ce5f188529e873a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+.vscode
+.idea
+.DS_Store
+__pycache__
+*.pyc
+*.zip
+*.out
+bin/
+debug/
+release/
\ No newline at end of file
diff --git a/README.md b/README.md
index 1c577dbd088eadd3e039e2447f42ca2dc57e2217..f89a8287dc18ceb3ce1ad2097aebbf8cef204b83 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,152 @@
 # skill_tree_go
 
-Go 技能树
\ No newline at end of file
+`Go语言技能树`是[技能森林](https://gitcode.net/csdn/skill_tree)的一部分。
+
+## 编辑环境初始化
+
+```
+pip install -r requirements.txt
+```
+
+## 目录结构说明
+技能树编辑仓库的 data 目录是主要的编辑目录,目录的结构是固定的
+
+* 技能树`骨架文件`:
+    * 位置:`data/tree.json`
+    * 说明:该文件是执行 `python main.py` 生成的,请勿人工编辑
+* 技能树`根节点`配置文件:
+    * 位置:`data/config.json`
+    * 说明:可编辑配置关键词等字段,其中 `node_id` 字段是生成的,请勿编辑
+* 技能树`难度节点`:
+    * 位置:`data/xxx`,例如: `data/1.Go语言初阶`
+    * 说明:
+        * 每个技能树有 3 个等级,目录前的序号是必要的,用来保持文件夹目录的顺序
+        * 每个目录下有一个 `config.json` 可配置关键词信息,其中 `node_id` 字段是生成的,请勿编辑
+* 技能树`章节点`:
+    * 位置:`data/xxx/xxx`,例如:`data/1.Go语言初阶/1.Go语言简介`
+    * 说明:
+        * 每个技能树的每个难度等级有 n 个章节,目录前的序号是必要的,用来保持文件夹目录的顺序
+        * 每个目录下有一个 `config.json` 可配置关键词信息,其中 `node_id` 字段是生成的,请勿编辑
+* 技能树`知识节点`:
+    * 位置:`data/xxx/xxx`,例如:`data/1.Go语言初阶/1.Go语言简介`
+    * 说明:
+        * 每个技能树的每章有 n 个知识节点,目录前的序号是必要的,用来保持文件夹目录的顺序
+        * 每个目录下有一个 `config.json`
+            * 其中 `node_id` 字段是生成的,请勿编辑
+            * 其中 `keywords` 可配置关键字字段
+            * 其中 `children` 可配置该`知识节点`下的子树结构信息,参考后面描述
+            * 其中 `export` 可配置该`知识节点`下的导出习题信息,参考后面描述
+
+## `知识节点` 子树信息结构
+
+例如 `data/1.Go语言初阶/1.Go语言简介/1.HelloWorld/config.json` 里配置对该知识节点子树信息结构,这个配置是可选的:
+```json
+{
+    // ...
+
+    "children": [
+    {
+        "XX开发入门": {
+          "keywords": [
+            "XX开发",
+          ],
+          "children": [],
+          "keywords_must": [
+            "XX"
+          ],
+          "keywords_forbid": []
+        }
+    }
+  ],
+}
+```
+
+## `知识节点` 的导出习题编辑
+
+例如 `data/1.Go语言初阶/1.Go语言简介/1.HelloWorld/config.json` 里配置对该知识节点导出的习题
+
+```json
+{
+    // ...
+    "export": [
+        "helloworld.json"
+    ]
+}
+```
+
+helloworld.json 的格式如下:
+```bash
+{
+  "type": "code_options",
+  "author": "xxx",
+  "source": "helloworld.md",
+  "notebook_enable": false,
+  "exercise_id": "xxx"
+}
+```
+
+其中 
+* "type": "code_options" 表示是一个选择题
+* "author" 可以放作者的 CSDN id,
+* "source" 指向了习题 MarkDown文件
+* "notebook_enable" 目前都是false
+* "exercise_id" 是工具生成的,不填
+
+
+习题格式模版如下:
+
+````mardown
+# {标题}
+
+{习题描述}
+
+以下关于上述游戏代码说法[正确/错误]的是?
+
+## 答案
+
+{目标选项}
+
+## 选项
+
+### A
+
+{混淆选项1}
+
+### B
+
+{混淆选项2}
+
+### C
+
+{混淆选项3}
+
+````
+
+## 技能树合成
+
+在根目录下执行 `python main.py` 会合成技能树文件,合成的技能树文件: `data/tree.json`
+* 合成过程中,会自动检查每个目录下 `config.json` 里的 `node_id` 是否存在,不存在则生成
+* 合成过程中,会自动检查每个知识点目录下 `config.json` 里的 `export` 里导出的习题配置,检查是否存在`exercise_id` 字段,如果不存在则生成
+* 在 节 目录下根据需要,可以添加一些子目录用来测试代码。
+* 开始游戏入门技能树构建之旅,GoodLuck! 
+
+## FAQ
+
+**难度目录是固定的么?**
+
+1. data/xxx 目录下的子目录是固定的初/中/高三个难度等级目录
+
+**如何增加章目录?**
+
+1. 在VSCode里打开项目仓库
+2. 在对应的难度等级目录新建章目录,例如在 data/1.xxx初阶/ 下新建章文件夹,data/1.xxx初阶/1.yyy
+3. 在项目根目录下执行 python main.py 脚本,会自动生成章的配置文件 data/1.xxx初阶/1.yyy/config.json
+
+**如何增加节目录?**:
+1. 直接在VSCode里创建文件夹,例如 "data/1.xxx初阶/1.yyy/2.zzz"
+2. 项目根目录下执行 python main.py 会自动为新增节创建配置文件 data/1.xxx初阶/1.yyy/2.zzz/config.json
+
+**如何在节下新增一个习题**:
+3. 在"data/1.xxx初阶/1.yyy/2.zzz" 目录下添加一个 markdown 文件编辑,例如 yyy.md,按照习题markdown格式编辑习题。
+4. md编辑完后,可以再次执行  python main.py 会自动生成同名的 yyy.json,并将 yyy.json 添加到config.json 的export数组里。
+5. yyy.json里的author信息放作者 CSDN ID。
\ No newline at end of file
diff --git "a/data/1.Go\350\257\255\350\250\200\345\210\235\351\230\266/1.Go\350\257\255\350\250\200\345\205\245\351\227\250/1.HelloWorld/config.json" "b/data/1.Go\350\257\255\350\250\200\345\210\235\351\230\266/1.Go\350\257\255\350\250\200\345\205\245\351\227\250/1.HelloWorld/config.json"
new file mode 100644
index 0000000000000000000000000000000000000000..bc9700047b79c69170180ad094260acca58abe54
--- /dev/null
+++ "b/data/1.Go\350\257\255\350\250\200\345\210\235\351\230\266/1.Go\350\257\255\350\250\200\345\205\245\351\227\250/1.HelloWorld/config.json"
@@ -0,0 +1,11 @@
+{
+  "node_id": "go-e703e0c6253d4c4d99f6ddaa139ddd6d",
+  "keywords": [],
+  "children": [],
+  "export": [
+    "helloworld.json"
+  ],
+  "keywords_must": [],
+  "keywords_forbid": [],
+  "group": 0
+}
\ No newline at end of file
diff --git "a/data/1.Go\350\257\255\350\250\200\345\210\235\351\230\266/1.Go\350\257\255\350\250\200\345\205\245\351\227\250/1.HelloWorld/helloworld.json" "b/data/1.Go\350\257\255\350\250\200\345\210\235\351\230\266/1.Go\350\257\255\350\250\200\345\205\245\351\227\250/1.HelloWorld/helloworld.json"
new file mode 100644
index 0000000000000000000000000000000000000000..1da309100c3a285b649a0e09876aa524b82c0025
--- /dev/null
+++ "b/data/1.Go\350\257\255\350\250\200\345\210\235\351\230\266/1.Go\350\257\255\350\250\200\345\205\245\351\227\250/1.HelloWorld/helloworld.json"
@@ -0,0 +1,7 @@
+{
+  "type": "code_options",
+  "author": null,
+  "source": "helloworld.md",
+  "notebook_enable": false,
+  "exercise_id": "4bc685eb97b042a196a815d97c40ff83"
+}
\ No newline at end of file
diff --git "a/data/1.Go\350\257\255\350\250\200\345\210\235\351\230\266/1.Go\350\257\255\350\250\200\345\205\245\351\227\250/1.HelloWorld/helloworld.md" "b/data/1.Go\350\257\255\350\250\200\345\210\235\351\230\266/1.Go\350\257\255\350\250\200\345\205\245\351\227\250/1.HelloWorld/helloworld.md"
new file mode 100644
index 0000000000000000000000000000000000000000..a447c184c7aaa9ee5f088c42158140caf4682c08
--- /dev/null
+++ "b/data/1.Go\350\257\255\350\250\200\345\210\235\351\230\266/1.Go\350\257\255\350\250\200\345\205\245\351\227\250/1.HelloWorld/helloworld.md"
@@ -0,0 +1,21 @@
+# {在此填写标题}
+
+{在此填写题目描述}
+
+## 答案
+
+{在此填写答案}
+
+## 选项
+
+### A
+
+{在此填写选项A}
+
+### B
+
+{在此填写选项B}
+
+### C
+
+{在此填写选项C}
diff --git "a/data/1.Go\350\257\255\350\250\200\345\210\235\351\230\266/1.Go\350\257\255\350\250\200\345\205\245\351\227\250/config.json" "b/data/1.Go\350\257\255\350\250\200\345\210\235\351\230\266/1.Go\350\257\255\350\250\200\345\205\245\351\227\250/config.json"
new file mode 100644
index 0000000000000000000000000000000000000000..dbf7fb7ee7170c03c7b5814eb508ff5f4910a1b6
--- /dev/null
+++ "b/data/1.Go\350\257\255\350\250\200\345\210\235\351\230\266/1.Go\350\257\255\350\250\200\345\205\245\351\227\250/config.json"
@@ -0,0 +1,7 @@
+{
+  "node_id": "go-c6038f5c04c74b47854eea94c9d90b0e",
+  "keywords": [],
+  "keywords_must": [],
+  "keywords_forbid": [],
+  "group": 0
+}
\ No newline at end of file
diff --git "a/data/1.Go\350\257\255\350\250\200\345\210\235\351\230\266/config.json" "b/data/1.Go\350\257\255\350\250\200\345\210\235\351\230\266/config.json"
new file mode 100644
index 0000000000000000000000000000000000000000..2e55576e1904c7e245819572193ccbc8e63a3565
--- /dev/null
+++ "b/data/1.Go\350\257\255\350\250\200\345\210\235\351\230\266/config.json"
@@ -0,0 +1,7 @@
+{
+  "node_id": "go-2bf9c4df33054b06b4396b5f2d611134",
+  "keywords": [],
+  "keywords_must": [],
+  "keywords_forbid": [],
+  "group": 0
+}
\ No newline at end of file
diff --git "a/data/2.Go\350\257\255\350\250\200\344\270\255\351\230\266/config.json" "b/data/2.Go\350\257\255\350\250\200\344\270\255\351\230\266/config.json"
new file mode 100644
index 0000000000000000000000000000000000000000..49e710a978d3902e2d5902d09f0c57e083c39802
--- /dev/null
+++ "b/data/2.Go\350\257\255\350\250\200\344\270\255\351\230\266/config.json"
@@ -0,0 +1,7 @@
+{
+  "node_id": "go-5c91f7058d064bdb8b5e31911ded197f",
+  "keywords": [],
+  "keywords_must": [],
+  "keywords_forbid": [],
+  "group": 0
+}
\ No newline at end of file
diff --git "a/data/3.Go\350\257\255\350\250\200\351\253\230\351\230\266/config.json" "b/data/3.Go\350\257\255\350\250\200\351\253\230\351\230\266/config.json"
new file mode 100644
index 0000000000000000000000000000000000000000..5cd1f846c378863a3f9b30fa2f6d31e2d84fcb36
--- /dev/null
+++ "b/data/3.Go\350\257\255\350\250\200\351\253\230\351\230\266/config.json"
@@ -0,0 +1,7 @@
+{
+  "node_id": "go-23102d3a58ab448886569ff334f5561e",
+  "keywords": [],
+  "keywords_must": [],
+  "keywords_forbid": [],
+  "group": 0
+}
\ No newline at end of file
diff --git a/data/config.json b/data/config.json
new file mode 100644
index 0000000000000000000000000000000000000000..c0abbca05181f325a95a8716a8910568aceb4d73
--- /dev/null
+++ b/data/config.json
@@ -0,0 +1,8 @@
+{
+  "tree_name": "go",
+  "keywords": [],
+  "node_id": "go-049bed572e9f476a8ca281163c820b56",
+  "keywords_must": [],
+  "keywords_forbid": [],
+  "group": 0
+}
\ No newline at end of file
diff --git a/data/tree.json b/data/tree.json
new file mode 100644
index 0000000000000000000000000000000000000000..2bd9cb24a9075d0482321d76fc47187b9c889513
--- /dev/null
+++ b/data/tree.json
@@ -0,0 +1,63 @@
+{
+  "go": {
+    "node_id": "go-049bed572e9f476a8ca281163c820b56",
+    "keywords": [],
+    "children": [
+      {
+        "Go语言初阶": {
+          "node_id": "go-2bf9c4df33054b06b4396b5f2d611134",
+          "keywords": [],
+          "children": [
+            {
+              "Go语言入门": {
+                "node_id": "go-c6038f5c04c74b47854eea94c9d90b0e",
+                "keywords": [],
+                "children": [
+                  {
+                    "HelloWorld": {
+                      "node_id": "go-e703e0c6253d4c4d99f6ddaa139ddd6d",
+                      "keywords": [],
+                      "children": [],
+                      "keywords_must": [],
+                      "keywords_forbid": [],
+                      "group": 0
+                    }
+                  }
+                ],
+                "keywords_must": [],
+                "keywords_forbid": [],
+                "group": 0
+              }
+            }
+          ],
+          "keywords_must": [],
+          "keywords_forbid": [],
+          "group": 0
+        }
+      },
+      {
+        "Go语言中阶": {
+          "node_id": "go-5c91f7058d064bdb8b5e31911ded197f",
+          "keywords": [],
+          "children": [],
+          "keywords_must": [],
+          "keywords_forbid": [],
+          "group": 0
+        }
+      },
+      {
+        "Go语言高阶": {
+          "node_id": "go-23102d3a58ab448886569ff334f5561e",
+          "keywords": [],
+          "children": [],
+          "keywords_must": [],
+          "keywords_forbid": [],
+          "group": 0
+        }
+      }
+    ],
+    "keywords_must": [],
+    "keywords_forbid": [],
+    "group": 0
+  }
+}
\ No newline at end of file
diff --git a/main.py b/main.py
new file mode 100644
index 0000000000000000000000000000000000000000..b99d065d1dd4982fc12f0b5d679fd27ace63b472
--- /dev/null
+++ b/main.py
@@ -0,0 +1,5 @@
+from skill_tree.tree import TreeWalker
+
+if __name__ == '__main__':
+    walker = TreeWalker("data", "go", "Go语言", ignore_keywords=True)
+    walker.walk()
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0abd88a12cb668d836c3bb780e4e88573f4d1d81
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,2 @@
+.pre_commit
+skill-tree-parser
\ No newline at end of file