diff --git a/acmc/main.py b/acmc/main.py
index ec29b5d1ffe3e2bc8da733a7ce16f3328a2cf598..5c0b30a95b92715e625ff712420d147adc801542 100644
--- a/acmc/main.py
+++ b/acmc/main.py
@@ -53,7 +53,7 @@ def phen_export(args):
 
 def phen_publish(args):
     """Handle the `phen publish` command."""
-    phen.publish(args.phen_dir, args.msg, args.remote_url)
+    phen.publish(args.phen_dir, args.msg, args.remote_url, args.increment)
 
 
 def phen_copy(args):
@@ -203,6 +203,14 @@ def main():
         default=str(phen.DEFAULT_PHEN_PATH.resolve()),
         help="Phenotype workspace directory",
     )
+    phen_publish_parser.add_argument(
+        "-i",
+        "--increment",
+        type=str,
+        default=phen.DEFAULT_VERSION_INC,
+        choices=phen.SEMANTIC_VERSION_TYPES,
+        help=f"Version increment: {phen.SEMANTIC_VERSION_TYPES}, default is {phen.DEFAULT_VERSION_INC} increment",
+    )
     phen_publish_parser.add_argument(
         "-m", "--msg", help="Message to include with the published version"
     )
diff --git a/acmc/phen.py b/acmc/phen.py
index 86675bf0d303b8b3f5aac9f88d3bb79346bf29af..d4a95d0946008eba0a856bdd26cd2bfc67128998 100644
--- a/acmc/phen.py
+++ b/acmc/phen.py
@@ -11,6 +11,7 @@ import re
 import logging
 import requests
 import yaml
+import semver
 from cerberus import Validator
 from deepdiff import DeepDiff
 from pathlib import Path
@@ -37,6 +38,8 @@ OMOP_PATH = Path(CONCEPT_SET_DIR) / "omop"
 DEFAULT_PHEN_DIR_LIST = [CONCEPTS_DIR, MAP_DIR, CONCEPT_SET_DIR]
 CONFIG_FILE = "config.yaml"
 VOCAB_VERSION_FILE = "vocab_version.yaml"
+SEMANTIC_VERSION_TYPES = ["major", "minor", "patch"]
+DEFAULT_VERSION_INC = "patch"
 
 DEFAULT_GIT_BRANCH = "main"
 
@@ -58,7 +61,7 @@ CONFIG_SCHEMA = {
             "version": {
                 "type": "string",
                 "required": True,
-                "regex": r"^v\d+\.\d+\.\d+$",  # Enforces 'vN.N.N' format
+                "regex": r"^\d+\.\d+\.\d+$",  # Enforces 'vN.N.N' format
             },
             "omop": {
                 "type": "dict",
@@ -258,15 +261,10 @@ def init(phen_dir, remote_url):
     for d in DEFAULT_PHEN_DIR_LIST:
         create_empty_git_dir(phen_path / d)
 
-    # set initial version based on the number of commits in the repo, depending on how the repo was created
-    # e.g., with a README.md, then there will be some initial commits before the phen config is added
-    next_commit_count = commit_count + 1
-    initial_version = f"v1.0.{next_commit_count}"
-
     # create empty phen config file
     config = {
         "phenotype": {
-            "version": initial_version,
+            "version": "0.0.0",
             "omop": {
                 "vocabulary_id": "",
                 "vocabulary_name": "",
@@ -365,7 +363,7 @@ def validate(phen_dir):
     code_types = parse.CodeTypeParser().code_types
 
     # check the version number is of the format vn.n.n
-    match = re.match(r"v(\d+\.\d+\.\d+)", phenotype["version"])
+    match = re.match(r"(\d+\.\d+\.\d+)", phenotype["version"])
     if not match:
         validation_errors.append(
             f"Invalid version format in configuration file: {phenotype['version']}"
@@ -840,7 +838,35 @@ def map_target_code_type(phen_path, phenotype, target_code_type):
     logger.info(f"Phenotype processed target code type {target_code_type}")
 
 
-def publish(phen_dir, msg, remote_url):
+def generate_version_tag(repo, increment=DEFAULT_VERSION_INC, use_v_prefix=False):
+    # Get all valid semantic version tags
+    versions = []
+    for tag in repo.tags:
+        tag_name = (
+            tag.name.lstrip("v") if use_v_prefix else tag.name
+        )  # Remove 'v' if needed
+        if semver.Version.is_valid(tag_name):
+            versions.append(semver.Version.parse(tag_name))
+
+    # Determine the next version
+    if not versions:
+        new_version = semver.Version(0, 0, 1)
+    else:
+        latest_version = max(versions)
+        if increment == "major":
+            new_version = latest_version.bump_major()
+        elif increment == "minor":
+            new_version = latest_version.bump_minor()
+        else:
+            new_version = latest_version.bump_patch()
+
+    # Create the new tag
+    new_version_str = f"v{new_version}" if use_v_prefix else str(new_version)
+
+    return new_version_str
+
+
+def publish(phen_dir, msg, remote_url, increment=DEFAULT_VERSION_INC):
     """Publishes updates to the phenotype by commiting all changes to the repo directory"""
 
     # Validate config
@@ -862,21 +888,16 @@ def publish(phen_dir, msg, remote_url):
         logger.info("Nothing to publish, no changes to the repo")
         return
 
-    # get major version from configuration file
+    # get next version
+    new_version_str = generate_version_tag(repo, increment)
+    logger.info(f"New version: {new_version_str}")
+
+    # Write version in configuration file
     config_path = phen_path / CONFIG_FILE
     with config_path.open("r") as file:
         config = yaml.safe_load(file)
-    match = re.match(r"v(\d+\.\d+)", config["phenotype"]["version"])
-    major_version = match.group(1)
-
-    # get latest minor version from git commit count
-    commit_count = len(list(repo.iter_commits("HEAD")))
 
-    # set version and write to config file so consistent with repo version
-    next_minor_version = commit_count + 1
-    version = f"v{major_version}.{next_minor_version}"
-    logger.debug(f"New version: {version}")
-    config["phenotype"]["version"] = version
+    config["phenotype"]["version"] = new_version_str
     with open(config_path, "w") as file:
         yaml.dump(
             config,
@@ -887,18 +908,13 @@ def publish(phen_dir, msg, remote_url):
             default_style='"',
         )
 
-    # Add and commit changes to repo
+    # Add and commit changes to repo including version updates
     commit_message = f"Committing updates to phenotype {phen_path}"
     repo.git.add("--all")
     repo.index.commit(commit_message)
 
-    # Create and push the tag
-    if version in repo.tags:
-        raise Exception(f"Tag {version} already exists in repo {phen_path}")
-    if msg is None:
-        msg = f"Release {version}"
-    repo.create_tag(version, message=msg)
-    logger.info(f"New version: {version}")
+    # Add tag to the repo
+    repo.create_tag(new_version_str)
 
     # push to origin if a remote repo
     if remote_url is not None and "origin" not in repo.remotes:
@@ -916,7 +932,7 @@ def publish(phen_dir, msg, remote_url):
         else:
             logger.debug("Remote 'origin' is not set")
     except Exception as e:
-        repo.delete_tag(version)
+        repo.delete_tag(new_version_str)
         repo.git.reset("--soft", "HEAD~1")
         raise e
 
diff --git a/docs/usage.md b/docs/usage.md
index b36484928dcca7219429f45c3c0566af941f5553..e0428261f5f8e49a796dd42500a8ae955f904151 100644
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -108,7 +108,8 @@ The `phen` command is used phenotype-related operations.
   ```
 
   - `-d`, `--phen-dir`: (Optional) Directory of phenotype configuration (the default is ./build/phen).
-  - `-m`, `--msg`: (Optional) Message to include with the published version- 
+  - `-i`, `--increment`: (Optional) Version increment: `major`, `minor`, or `patch`, default is `patch` increment 
+  - `-m`, `--msg`: (Optional) Message to include with the published version
   - `-r`, `--remote_url`: (Optional) URL to a remote git repository, only supports an empty repo without existing commits.
 
 - **Copy Phenotype Configuration**
diff --git a/examples/config1.yaml b/examples/config1.yaml
index 09d0e807b3ff433682ea69a0642bebdec87bdd1e..2709d3f97795ee3e8bfea21ff827f0ff26473f6d 100644
--- a/examples/config1.yaml
+++ b/examples/config1.yaml
@@ -1,5 +1,5 @@
 phenotype:
-  version: "v1.0.1"
+  version: "0.0.0"
   omop:
     vocabulary_id: "ACMC_Example_1"
     vocabulary_name: "ACMC example 1 phenotype"
diff --git a/examples/config2.yaml b/examples/config2.yaml
index 4c6252efb6fa4c7eec6520ddfc963e40d32e9ccc..4a9ad79b598641a869601329b00a0b016cf1e082 100644
--- a/examples/config2.yaml
+++ b/examples/config2.yaml
@@ -1,5 +1,5 @@
 phenotype:
-  version: "v1.0.1"
+  version: "0.0.0"
   omop:
     vocabulary_id: "ACMC_Example_2"
     vocabulary_name: "ACMC example 2 phenotype"
diff --git a/examples/config3.yaml b/examples/config3.yaml
index 764d7d8dd614132d4fed584d42b824a45694be9d..2e07427219e3dc605008007e4c0b9ad66fa8159c 100644
--- a/examples/config3.yaml
+++ b/examples/config3.yaml
@@ -1,5 +1,5 @@
 phenotype:
-  version: "v1.0.1"
+  version: "0.0.0"
   omop:
     vocabulary_id: "ACMC_Example_3"
     vocabulary_name: "ACMC example 3 phenotype"
diff --git a/pyproject.toml b/pyproject.toml
index c340e830567458e16fc57d7c2deae77bfd34d0a8..39f046a78c4a754df4293a128cec7dc64fb2ff1a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -37,7 +37,8 @@ dependencies = [
     "tables", 	
     "pytest",
 	"pyyaml",	
-    "requests",	
+    "requests",
+    "semver", 
     "simpledbf",
     "smmap",
     "sqlalchemy",
diff --git a/tests/test_acmc.py b/tests/test_acmc.py
index a9bda409c29f9c014257d6a39fa654dd84333644..ee5dcf1dbe239e206569991b79540d144e8b681e 100644
--- a/tests/test_acmc.py
+++ b/tests/test_acmc.py
@@ -141,7 +141,7 @@ def test_phen_workflow(tmp_dir, monkeypatch, caplog, config_file):
                 "-td",
                 str(tmp_dir.resolve()),
                 "-v",
-                "v1.0.3",
+                "0.0.1",
             ],
         )
         main.main()
@@ -149,7 +149,7 @@ def test_phen_workflow(tmp_dir, monkeypatch, caplog, config_file):
 
     # diff phenotype
     with caplog.at_level(logging.DEBUG):
-        old_path = tmp_dir / "v1.0.3"
+        old_path = tmp_dir / "0.0.1"
         monkeypatch.setattr(
             sys,
             "argv",
@@ -234,7 +234,7 @@ def test_diff(tmp_dir, monkeypatch, caplog):
                 "-td",
                 str(tmp_dir.resolve()),
                 "-v",
-                "v1.0.3",
+                "0.0.1",
             ],
         )
         main.main()
@@ -260,9 +260,9 @@ def test_diff(tmp_dir, monkeypatch, caplog):
             main.main()
     assert "Phenotype processed successfully" in caplog.text
 
-    # diff phenotype with v1.0.3
+    # diff phenotype with 0.0.1
     with caplog.at_level(logging.DEBUG):
-        old_path = tmp_dir / "v1.0.3"
+        old_path = tmp_dir / "0.0.1"
         monkeypatch.setattr(
             sys,
             "argv",
@@ -280,7 +280,7 @@ def test_diff(tmp_dir, monkeypatch, caplog):
     assert "Phenotypes diff'd successfully" in caplog.text
 
     # check changes
-    with open(phen_path / "v1.0.3_diff.md", "r") as file:
+    with open(phen_path / "0.0.1_diff.md", "r") as file:
         content = file.read()
     assert "Removed concepts ['ABDO_PAIN']" in content
     assert "Added concepts ['DID_NOT_ATTEND']" in content
@@ -306,9 +306,9 @@ def test_diff(tmp_dir, monkeypatch, caplog):
             main.main()
     assert "Phenotype processed successfully" in caplog.text
 
-    # diff phenotype with v1.0.3
+    # diff phenotype with 0.0.1
     with caplog.at_level(logging.DEBUG):
-        old_path = tmp_dir / "v1.0.3"
+        old_path = tmp_dir / "0.0.1"
         monkeypatch.setattr(
             sys,
             "argv",
@@ -325,7 +325,7 @@ def test_diff(tmp_dir, monkeypatch, caplog):
         main.main()
     assert "Phenotypes diff'd successfully" in caplog.text
 
-    with open(phen_path / "v1.0.3_diff.md", "r") as file:
+    with open(phen_path / "0.0.1_diff.md", "r") as file:
         content = file.read()
     assert "Removed concepts ['ABDO_PAIN']" in content
     assert "Added concepts ['DEPRESSION', 'DID_NOT_ATTEND', 'HYPERTENSION']" in content