diff --git a/src/sspec/commands/project.py b/src/sspec/commands/project.py
index 36550bd..85e0cf2 100644
--- a/src/sspec/commands/project.py
+++ b/src/sspec/commands/project.py
@@ -10,29 +10,16 @@ from rich.console import Console
 from rich.table import Table
 
 from sspec import __version__
-from sspec.core import (
-    SCHEMA_VERSION,
-    ChangeStatus,
-    SspecNotFoundError,
-    get_sspec_root,
-    get_template_dir,
-    list_template_skills,
-)
+from sspec.core import (SCHEMA_VERSION, ChangeStatus, SspecNotFoundError,
+                        get_sspec_root, get_template_dir, list_template_skills)
 from sspec.services.agents_service import update_root_agents_block
 from sspec.services.change_service import list_changes
 from sspec.services.meta_service import load_meta, save_meta
 from sspec.services.project_init_service import (
-    ProjectAlreadyInitializedError,
-    initialize_project,
-    sync_skill_locations,
-)
+    ProjectAlreadyInitializedError, initialize_project, sync_skill_locations)
 from sspec.services.project_update_service import (
-    apply_skill_update,
-    collect_orphaned_skills,
-    collect_update_candidates,
-    migrate_legacy_skill_layouts,
-    remove_orphaned_skill,
-)
+    apply_skill_update, collect_orphaned_skills, collect_update_candidates,
+    migrate_legacy_skill_layouts, remove_orphaned_skill)
 
 console = Console()
 
@@ -43,7 +30,7 @@ def _interactive_skill_selection(project_root: Path) -> list[str]:
     Detects existing workspace directories and prompts user to select skill
     installation locations.
     """
-    available_locations = ['.claude', '.github', '.agent']
+    available_locations = ['.claude', '.github', '.agents']
     existing_dirs = [loc for loc in available_locations if (project_root / loc).is_dir()]
 
     console.print()
@@ -58,6 +45,7 @@ def _interactive_skill_selection(project_root: Path) -> list[str]:
         )
         for loc in available_locations
     ]
+    choices.append(questionary.Choice(title='Enter custom path…', value='__custom__'))
 
     selected = questionary.checkbox(
         'Select skill installation locations:',
@@ -66,20 +54,30 @@ def _interactive_skill_selection(project_root: Path) -> list[str]:
     ).ask()
 
     if selected is None:  # User cancelled
-        forced = project_root / '.agent'
+        forced = project_root / '.agents'
         forced.mkdir(parents=True, exist_ok=True)
-        console.print('[yellow]Selection cancelled, force fallback to .agent[/yellow]')
+        console.print('[yellow]Selection cancelled, force fallback to .agents[/yellow]')
         console.print('[dim]You can switch to .claude/.github later by re-sync/update.[/dim]')
-        return ['.agent']
+        return ['.agents']
 
     if not selected:
-        forced = project_root / '.agent'
+        forced = project_root / '.agents'
         forced.mkdir(parents=True, exist_ok=True)
-        console.print('[yellow]No locations selected, force fallback to .agent[/yellow]')
+        console.print('[yellow]No locations selected, force fallback to .agents[/yellow]')
         console.print('[dim]You can switch to .claude/.github later by re-sync/update.[/dim]')
-        return ['.agent']
+        return ['.agents']
+
+    # Handle custom path input
+    result: list[str] = [loc for loc in selected if loc != '__custom__']
+    if '__custom__' in selected:
+        custom = questionary.text(
+            'Enter custom skill location path (relative to project root):',
+            instruction='e.g. .cursor or .windsurf',
+        ).ask()
+        if custom and custom.strip():
+            result.append(custom.strip())
 
-    return selected
+    return result
 
 
 @click.group()
@@ -93,8 +91,8 @@ def project() -> None:
 @click.option(
     '--skill-loc',
     multiple=True,
-    type=click.Choice(['.claude', '.github', '.agent'], case_sensitive=False),
-    help='Skill installation locations (can specify multiple, or use interactive mode)',
+    type=str,
+    help='Skill installation location (can specify multiple). e.g. --skill-loc .claude --skill-loc .cursor',
 )
 def init(force: bool, skill_loc: tuple[str, ...]) -> None:
     """Initialize .sspec directory in current project."""
diff --git a/src/sspec/commands/skill.py b/src/sspec/commands/skill.py
index c4fd2b8..e5dbaff 100644
--- a/src/sspec/commands/skill.py
+++ b/src/sspec/commands/skill.py
@@ -9,15 +9,31 @@ from rich.console import Console
 from rich.table import Table
 
 from sspec.core import SspecNotFoundError, get_sspec_root
-from sspec.services.skill_service import (
-    create_skill_in_hub,
-    dominate_skills_location,
-    list_skills,
-)
+from sspec.services.meta_service import load_meta, save_meta
+from sspec.services.skill_service import (create_skill_in_hub,
+                                          dominate_skills_location,
+                                          list_skills)
 
 console = Console()
 
 
+def _record_dominate_location(sspec_root: Path, dominate_dir: Path) -> None:
+    """Record a newly dominated directory in .meta.json skill_locations."""
+    project_root = sspec_root.parent
+    try:
+        # store the skills/ sub-path so it matches the convention used by init/sync
+        location_path = (dominate_dir / 'skills').relative_to(project_root).as_posix()
+    except ValueError:
+        # dominate_dir is outside project_root — use absolute posix path
+        location_path = (dominate_dir / 'skills').as_posix()
+
+    meta = load_meta(sspec_root)
+    stored: set[str] = set(meta.get('skill_locations', []) or [])
+    stored.add(location_path)
+    meta['skill_locations'] = sorted(stored)
+    save_meta(sspec_root, meta)
+
+
 @click.group()
 def skill() -> None:
     """Skill management operations (new, list)."""
@@ -140,6 +156,9 @@ def dominate(dir_path: Path) -> None:
         console.print(f'[cyan]-[/cyan] Already linked: {rel_target} -> {rel_source}')
         return
 
+    # For all successful operations (linked, relinked, merged) record in meta
+    _record_dominate_location(sspec_root, dominate_dir)
+
     if result.status == 'merged':
         if result.backup_path:
             try:
diff --git a/src/sspec/core.py b/src/sspec/core.py
index 3707fbe..e74297f 100644
--- a/src/sspec/core.py
+++ b/src/sspec/core.py
@@ -10,7 +10,7 @@ from typing import TypedDict
 
 SSPEC_DIR = '.sspec'
 SKILLS_DIR = 'skills'
-WORKSPACE_DIRS = ['.github', '.claude', '.agent']
+WORKSPACE_DIRS = ['.github', '.claude', '.agents']
 SKILL_SUBDIR = 'skills'
 CHANGES_DIR = 'changes'
 REQUEST_DIR = 'requests'
diff --git a/src/sspec/services/meta_service.py b/src/sspec/services/meta_service.py
index 624e383..45a740c 100644
--- a/src/sspec/services/meta_service.py
+++ b/src/sspec/services/meta_service.py
@@ -8,6 +8,29 @@ from typing import Any
 
 META_FILE = '.meta.json'
 
+# Independent schema version for .meta.json structure.
+# Increment when the meta.json field layout changes (NOT tied to AGENTS.md schema).
+META_SCHEMA_VERSION = '1'
+
+
+def get_meta_with_defaults(meta: dict[str, Any]) -> dict[str, Any]:
+    """Return meta with missing fields filled by defaults (non-destructive).
+
+    Merges caller-supplied meta on top of defaults so existing values are preserved.
+    """
+    defaults: dict[str, Any] = {
+        'meta_schema_version': META_SCHEMA_VERSION,
+        'schema_version': '',
+        'sspec_version': '',
+        'created_at': '',
+        'updated_at': '',
+        'file_hashes': {},
+        'managed_skills': [],
+        'skill_locations': [],
+        'skill_install_strategies': {},
+    }
+    return {**defaults, **meta}
+
 
 def load_meta(sspec_root: Path) -> dict[str, Any]:
     """Load metadata from .meta.json.
diff --git a/src/sspec/services/project_init_service.py b/src/sspec/services/project_init_service.py
index f046bc3..f9b5f77 100644
--- a/src/sspec/services/project_init_service.py
+++ b/src/sspec/services/project_init_service.py
@@ -12,18 +12,12 @@ from pathlib import Path
 from typing import Any
 
 from sspec import __version__
-from sspec.core import (
-    SCHEMA_VERSION,
-    SSPEC_DIR,
-    UPDATABLE_FILES,
-    USER_FILES,
-    copy_template,
-    get_template_dir,
-    list_template_skills,
-)
+from sspec.core import (SCHEMA_VERSION, SSPEC_DIR, UPDATABLE_FILES, USER_FILES,
+                        copy_template, get_template_dir, list_template_skills)
 from sspec.libs.hashing import compute_dir_hash, compute_hash
 from sspec.services.agents_service import update_root_agents_block
-from sspec.services.meta_service import load_meta, save_meta
+from sspec.services.meta_service import (META_SCHEMA_VERSION, load_meta,
+                                         save_meta)
 
 
 class ProjectAlreadyInitializedError(RuntimeError):
@@ -76,14 +70,9 @@ def get_skill_targets_from_locations(
 
 
 DEFAULT_GITIGNORE = """
-!project.md
-!spec-docs/**
-!commands/**
-!.meta.json
-changes/**
-requests/**
+# Installed skills (managed by sspec, symlinks or copies — not for VCS)
 skills/**
-asks/**
+# Temporary workspace drafts
 tmp/**
 """.strip()
 
@@ -185,6 +174,7 @@ def initialize_project(
 
     # Create initial .meta.json
     meta_data: dict[str, Any] = {
+        'meta_schema_version': META_SCHEMA_VERSION,
         'schema_version': SCHEMA_VERSION,
         'sspec_version': __version__,
         'created_at': datetime.now().isoformat(),
diff --git a/src/sspec/services/skill_service.py b/src/sspec/services/skill_service.py
index ba0a0e1..a3baf14 100644
--- a/src/sspec/services/skill_service.py
+++ b/src/sspec/services/skill_service.py
@@ -21,7 +21,8 @@ from sspec import __version__
 from sspec.core import SKILL_SUBDIR, SKILLS_DIR, SSPEC_DIR, WORKSPACE_DIRS
 from sspec.libs.hashing import compute_dir_hash
 from sspec.services.meta_service import load_meta, save_meta
-from sspec.skill_installer import check_path_link, detect_path_link, remove_path_link
+from sspec.skill_installer import (check_path_link, detect_path_link,
+                                   remove_path_link)
 
 
 class SkillInfo(TypedDict):
@@ -374,7 +375,8 @@ def create_skill_in_hub(
     skill_file.write_text(template_content, encoding='utf-8')
 
     meta: dict[str, Any] = load_meta(sspec_root)
-    meta['updated_at'] = __version__
+    meta['updated_at'] = datetime.now().isoformat()
     save_meta(sspec_root, meta)
 
     return CreateSkillResult(hub_dir=hub_dir, skill_name=name)
+    return CreateSkillResult(hub_dir=hub_dir, skill_name=name)
diff --git a/tests/test_ask_service.py b/tests/test_ask_service.py
index 901c05c..cf51f1d 100644
--- a/tests/test_ask_service.py
+++ b/tests/test_ask_service.py
@@ -6,16 +6,12 @@ from pathlib import Path
 
 import pytest
 
-from sspec.services.ask_service import (
-    archive_ask,
-    convert_ask_to_md,
-    create_ask_template,
-    execute_ask_prompt,
-    extract_ask_name_from_filename,
-    find_ask_matches,
-    normalize_ask_name,
-    save_ask_answer,
-)
+from sspec.services.ask_service import (archive_ask, convert_ask_to_md,
+                                        create_ask_template,
+                                        execute_ask_prompt,
+                                        extract_ask_name_from_filename,
+                                        find_ask_matches, normalize_ask_name,
+                                        save_ask_answer)
 
 # ---------------------------------------------------------------------------
 # normalize_ask_name
@@ -102,7 +98,7 @@ class TestExecuteAskPrompt:
     def test_prefilled_answer_returned(self, sspec_root: Path):
         path, _ = create_ask_template(sspec_root, 'prefilled')
         content = path.read_text(encoding='utf-8')
-        content = content.replace('user_answer: ""', 'user_answer: "Use Redis"')
+        content = content.replace('USER_FILL_HERE', 'Use Redis')
         path.write_text(content, encoding='utf-8')
 
         answer = execute_ask_prompt(path)
