diff --git a/joj3_config_generator/convert.py b/joj3_config_generator/convert.py
index 719c445..55b0b11 100644
--- a/joj3_config_generator/convert.py
+++ b/joj3_config_generator/convert.py
@@ -4,17 +4,17 @@ from joj3_config_generator.models import (
     ExecutorConfig,
     ExecutorWithConfig,
     ParserConfig,
-    Repo,
+    RepoConfig,
     ResultConfig,
     Stage,
     StageConfig,
-    Task,
+    TaskConfig,
     TeapotConfig,
 )
 
 
 # FIXME: LLM generated convert function, only for demostration
-def convert(repo_conf: Repo, task_conf: Task) -> ResultConfig:
+def convert(repo_conf: RepoConfig, task_conf: TaskConfig) -> ResultConfig:
     # Create the base ResultConf object
     result_conf = ResultConfig(
         name=task_conf.task,
diff --git a/joj3_config_generator/main.py b/joj3_config_generator/main.py
index a8ee683..67cc7ad 100644
--- a/joj3_config_generator/main.py
+++ b/joj3_config_generator/main.py
@@ -7,7 +7,7 @@ import rtoml
 import typer
 
 from joj3_config_generator.convert import convert as convert_conf
-from joj3_config_generator.models import Repo, Task
+from joj3_config_generator.models import RepoConfig, TaskConfig
 from joj3_config_generator.utils.logger import logger
 
 app = typer.Typer(add_completion=False)
@@ -54,7 +54,7 @@ def convert(root: Path = Path(".")) -> None:
         task_toml = task_file.read()
     repo_obj = rtoml.loads(repo_toml)
     task_obj = rtoml.loads(task_toml)
-    result_model = convert_conf(Repo(**repo_obj), Task(**task_obj))
+    result_model = convert_conf(RepoConfig(**repo_obj), TaskConfig(**task_obj))
     result_dict = result_model.model_dump(by_alias=True)
     with open(result_json_path, "w") as result_file:
         json.dump(result_dict, result_file, ensure_ascii=False, indent=4)
diff --git a/joj3_config_generator/models/__init__.py b/joj3_config_generator/models/__init__.py
index 9ecf823..488e47c 100644
--- a/joj3_config_generator/models/__init__.py
+++ b/joj3_config_generator/models/__init__.py
@@ -1,7 +1,8 @@
 from joj3_config_generator.models.joj1 import Case as Case
 from joj3_config_generator.models.joj1 import JOJ1Config as JOJ1Config
 from joj3_config_generator.models.joj1 import Language as Language
-from joj3_config_generator.models.repo import Repo as Repo
+from joj3_config_generator.models.repo import RepoConfig as RepoConfig
+from joj3_config_generator.models.repo import RepoFiles as RepoFiles
 from joj3_config_generator.models.result import Cmd as Cmd
 from joj3_config_generator.models.result import CmdFile as CmdFile
 from joj3_config_generator.models.result import ExecutorConfig as ExecutorConfig
@@ -11,4 +12,4 @@ from joj3_config_generator.models.result import ResultConfig as ResultConfig
 from joj3_config_generator.models.result import Stage as Stage
 from joj3_config_generator.models.result import StageConfig as StageConfig
 from joj3_config_generator.models.result import TeapotConfig as TeapotConfig
-from joj3_config_generator.models.task import Task as Task
+from joj3_config_generator.models.task import TaskConfig as TaskConfig
diff --git a/joj3_config_generator/models/joj1.py b/joj3_config_generator/models/joj1.py
index 2ce5292..deb05de 100644
--- a/joj3_config_generator/models/joj1.py
+++ b/joj3_config_generator/models/joj1.py
@@ -1,4 +1,4 @@
-from typing import Optional
+from typing import List, Optional
 
 from pydantic import BaseModel, Field
 
@@ -24,5 +24,5 @@ class Case(BaseModel):
 
 
 class JOJ1Config(BaseModel):
-    languages: list[Language]
-    cases: list[Case]
+    languages: List[Language]
+    cases: List[Case]
diff --git a/joj3_config_generator/models/repo.py b/joj3_config_generator/models/repo.py
index 0783468..c4183fe 100644
--- a/joj3_config_generator/models/repo.py
+++ b/joj3_config_generator/models/repo.py
@@ -1,18 +1,18 @@
-from typing import Optional
+from typing import List, Optional
 
 from pydantic import BaseModel, Field
 
 
 class RepoFiles(BaseModel):
-    whitelist_patterns: list[str]
+    whitelist_patterns: List[str]
     whitelist_file: Optional[str]
-    required: list[str]
-    immutable: list[str]
+    required: List[str]
+    immutable: List[str]
 
 
-class Repo(BaseModel):
-    teaching_team: list[str]
+class RepoConfig(BaseModel):
+    teaching_team: List[str]
     max_size: float = Field(..., ge=0)
-    release_tags: list[str]
+    release_tags: List[str]
     files: RepoFiles
     sandbox_token: str
diff --git a/joj3_config_generator/models/result.py b/joj3_config_generator/models/result.py
index f1dd8e7..29194b3 100644
--- a/joj3_config_generator/models/result.py
+++ b/joj3_config_generator/models/result.py
@@ -1,4 +1,4 @@
-from typing import Any, Optional
+from typing import Any, List, Optional
 
 import rtoml
 from pydantic import BaseModel, Field
@@ -17,8 +17,8 @@ class CmdFile(BaseModel):
 
 
 class Cmd(BaseModel):
-    args: list[str]
-    env: list[str] = []
+    args: List[str]
+    env: List[str] = []
     stdin: Optional[CmdFile] = None
     stdout: Optional[CmdFile] = None
     stderr: Optional[CmdFile] = None
@@ -33,8 +33,8 @@ class Cmd(BaseModel):
     copy_in: dict[str, CmdFile] = Field({}, serialization_alias="copyIn")
     copy_in_cached: dict[str, str] = Field({}, serialization_alias="copyInCached")
     copy_in_dir: str = Field(".", serialization_alias="copyInDir")
-    copy_out: list[str] = Field([], serialization_alias="copyOut")
-    copy_out_cached: list[str] = Field([], serialization_alias="copyOutCached")
+    copy_out: List[str] = Field([], serialization_alias="copyOut")
+    copy_out_cached: List[str] = Field([], serialization_alias="copyOutCached")
     copy_out_max: int = Field(0, serialization_alias="copyOutMax")
     copy_out_dir: str = Field("", serialization_alias="copyOutDir")
     tty: bool = False
@@ -44,8 +44,8 @@ class Cmd(BaseModel):
 
 
 class OptionalCmd(BaseModel):
-    args: Optional[list[str]] = None
-    env: Optional[list[str]] = None
+    args: Optional[List[str]] = None
+    env: Optional[List[str]] = None
     stdin: Optional[CmdFile] = None
     stdout: Optional[CmdFile] = None
     stderr: Optional[CmdFile] = None
@@ -62,8 +62,8 @@ class OptionalCmd(BaseModel):
         None, serialization_alias="copyInCached"
     )
     copy_in_dir: Optional[str] = Field(None, serialization_alias="copyInDir")
-    copy_out: Optional[list[str]] = Field(None, serialization_alias="copyOut")
-    copy_out_cached: Optional[list[str]] = Field(
+    copy_out: Optional[List[str]] = Field(None, serialization_alias="copyOut")
+    copy_out_cached: Optional[List[str]] = Field(
         None, serialization_alias="copyOutCached"
     )
     copy_out_max: Optional[int] = Field(None, serialization_alias="copyOutMax")
@@ -84,12 +84,12 @@ class Stage(BaseModel):
     name: str
     group: str
     executor: "ExecutorConfig"
-    parsers: list["ParserConfig"]
+    parsers: List["ParserConfig"]
 
 
 class ExecutorWithConfig(BaseModel):
     default: Cmd
-    cases: list[OptionalCmd]
+    cases: List[OptionalCmd]
 
 
 class ExecutorConfig(BaseModel):
@@ -110,7 +110,7 @@ class StageConfig(BaseModel):
     output_path: str = Field(
         "/tmp/joj3_result.json", serialization_alias="outputPath"
     )  # nosec: B108
-    stages: list[Stage]
+    stages: List[Stage]
 
 
 class TeapotConfig(BaseModel):
diff --git a/joj3_config_generator/models/task.py b/joj3_config_generator/models/task.py
index 802555b..adee67d 100644
--- a/joj3_config_generator/models/task.py
+++ b/joj3_config_generator/models/task.py
@@ -1,5 +1,5 @@
 from datetime import datetime
-from typing import Optional
+from typing import List, Optional
 
 from pydantic import BaseModel, Field
 
@@ -12,8 +12,8 @@ class ParserResultDetail(BaseModel):
 
 
 class Files(BaseModel):
-    import_: list[str] = Field(alias="import")
-    export: list[str]
+    import_: List[str] = Field(alias="import")
+    export: List[str]
 
 
 class Stage(BaseModel):
@@ -21,7 +21,7 @@ class Stage(BaseModel):
     command: str  # Command to run
     files: Files  # Files to import and export
     score: int  # Score for the task
-    parsers: list[str]  # list of parsers
+    parsers: List[str]  # list of parsers
     result_detail: ParserResultDetail = (
         ParserResultDetail()
     )  #  for result-detail parser
@@ -31,7 +31,7 @@ class Release(BaseModel):
     deadline: Optional[datetime]  # RFC 3339 formatted date-time with offset
 
 
-class Task(BaseModel):
+class TaskConfig(BaseModel):
     task: str  # Task name (e.g., hw3 ex5)
     release: Release  # Release configuration
-    stages: list[Stage]  # list of stage configurations
+    stages: List[Stage]  # list of stage configurations
diff --git a/tests/conftest.py b/tests/conftest.py
index 6d41010..7d7d69b 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,13 +1,13 @@
 import os
-from typing import Any
+from typing import Any, List
 
 import pytest
 
-from joj3_config_generator.models import Repo, Task
+from joj3_config_generator.models import RepoConfig, TaskConfig
 from tests.utils import read_convert_files
 
 
-def get_test_cases() -> list[tuple[str, Repo, Task, dict[str, Any]]]:
+def get_test_cases() -> List[tuple[str, RepoConfig, TaskConfig, dict[str, Any]]]:
     test_cases = []
     tests_dir = os.path.dirname(os.path.realpath(__file__))
     for dir_name in os.listdir(tests_dir):
@@ -19,5 +19,7 @@ def get_test_cases() -> list[tuple[str, Repo, Task, dict[str, Any]]]:
 
 
 @pytest.fixture(params=get_test_cases(), ids=lambda x: x[0])
-def test_case(request: pytest.FixtureRequest) -> tuple[Repo, Task, dict[str, Any]]:
+def test_case(
+    request: pytest.FixtureRequest,
+) -> tuple[RepoConfig, TaskConfig, dict[str, Any]]:
     return request.param[1:]  # return repo, task, expected_result
diff --git a/tests/test_all_cases.py b/tests/test_all_cases.py
index ca0ddb2..e87bd03 100644
--- a/tests/test_all_cases.py
+++ b/tests/test_all_cases.py
@@ -1,10 +1,10 @@
 from typing import Any
 
 from joj3_config_generator.convert import convert
-from joj3_config_generator.models import Repo, Task
+from joj3_config_generator.models import RepoConfig, TaskConfig
 
 
-def test_convert(test_case: tuple[Repo, Task, dict[str, Any]]) -> None:
+def test_convert(test_case: tuple[RepoConfig, TaskConfig, dict[str, Any]]) -> None:
     repo, task, expected_result = test_case
     result = convert(repo, task).model_dump(by_alias=True)
     assert result == expected_result
diff --git a/tests/utils.py b/tests/utils.py
index b733db7..1d3a5d2 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -4,10 +4,10 @@ from typing import Any
 
 import rtoml
 
-from joj3_config_generator.models import Repo, Task
+from joj3_config_generator.models import RepoConfig, TaskConfig
 
 
-def read_convert_files(root: str) -> tuple[Repo, Task, dict[str, Any]]:
+def read_convert_files(root: str) -> tuple[RepoConfig, TaskConfig, dict[str, Any]]:
     repo_toml_path = os.path.join(root, "repo.toml")
     task_toml_path = os.path.join(root, "task.toml")
     result_json_path = os.path.join(root, "task.json")
@@ -19,4 +19,4 @@ def read_convert_files(root: str) -> tuple[Repo, Task, dict[str, Any]]:
         expected_result: dict[str, Any] = json.load(result_file)
     repo_obj = rtoml.loads(repo_toml)
     task_obj = rtoml.loads(task_toml)
-    return Repo(**repo_obj), Task(**task_obj), expected_result
+    return RepoConfig(**repo_obj), TaskConfig(**task_obj), expected_result